Skip to content

Commit

Permalink
Merge pull request #214 from newrelic/cayla/search-box
Browse files Browse the repository at this point in the history
Add a search box and filter down links that match the search term
  • Loading branch information
timglaser authored Jun 24, 2020
2 parents c77e3f1 + d42b4c1 commit f46b7b7
Show file tree
Hide file tree
Showing 10 changed files with 372 additions and 195 deletions.
6 changes: 6 additions & 0 deletions src/components/FeatherIcon.js
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,12 @@ const ICONS = {
github: (
<path d="M9 19c-5 1.5-5-2.5-7-3m14 6v-3.87a3.37 3.37 0 0 0-.94-2.61c3.14-.35 6.44-1.54 6.44-7A5.44 5.44 0 0 0 20 4.77 5.07 5.07 0 0 0 19.91 1S18.73.65 16 2.48a13.38 13.38 0 0 0-7 0C6.27.65 5.09 1 5.09 1A5.07 5.07 0 0 0 5 4.77a5.44 5.44 0 0 0-1.5 3.78c0 5.42 3.3 6.61 6.44 7A3.37 3.37 0 0 0 9 18.13V22" />
),
search: (
<>
<circle cx="11" cy="11" r="8" />
<line x1="21" y1="21" x2="16.65" y2="16.65" />
</>
),
'upload-cloud': (
<>
<polyline points="16 16 12 12 8 16" />
Expand Down
138 changes: 33 additions & 105 deletions src/components/Navigation.js
Original file line number Diff line number Diff line change
@@ -1,127 +1,55 @@
import React, { Fragment, useState, useContext } from 'react';
import React from 'react';
import PropTypes from 'prop-types';
import { Link } from 'gatsby';
import cx from 'classnames';
import { BreadcrumbContext } from './BreadcrumbContext';
import FeatherIcon from './FeatherIcon';
import NewRelicIcon from './NewRelicIcon';
import NavigationItems from './NavigationItems';
import pages from '../data/sidenav.json';

import matchSearchString from '../utils/matchSearchString';
import styles from './Navigation.module.scss';

// recursively create navigation
const renderNav = (pages, depthLevel = 0) => {
// TODO: Refactor this function into a component
// eslint-disable-next-line react-hooks/rules-of-hooks
const crumbs = useContext(BreadcrumbContext).flatMap((x) => x.displayName);
const isHomePage = crumbs.length === 0 && depthLevel === 0;
const iconLibrary = {
'Collect data': 'collectData',
'Build apps': 'buildApps',
'Automate workflows': 'automation',
'Explore docs': 'developerDocs',
};

const groupedPages = pages.reduce((groups, page) => {
const { group = '' } = page;

return {
...groups,
[group]: [...(groups[group] || []), page],
};
}, {});

return Object.entries(groupedPages).map(([group, pages]) => (
<Fragment key={group}>
{group && (
<li className={cx(styles.navLink, styles.groupName)}>{group}</li>
)}
{pages.map((page) => {
const [isExpanded, setIsExpanded] = useState(
isHomePage || crumbs.includes(page.displayName)
);
const isCurrentPage = crumbs[crumbs.length - 1] === page.displayName;
const headerIcon = depthLevel === 0 && (
<NewRelicIcon
className={styles.headerIcon}
name={iconLibrary[page.displayName]}
/>
);

return (
<li key={page.displayName} data-depth={depthLevel}>
{page.url ? (
<Link
className={cx(
{
[styles.isCurrentPage]: isCurrentPage,
},
styles.navLink
)}
to={page.url}
>
<span>
{headerIcon}
{page.displayName}
</span>
{isCurrentPage && (
<FeatherIcon
className={styles.currentPageIndicator}
name="chevron-right"
/>
)}
</Link>
) : (
<button
type="button"
className={styles.navLink}
onClick={() => setIsExpanded(!isExpanded)}
onKeyPress={() => setIsExpanded(!isExpanded)}
tabIndex={0}
>
{depthLevel > 0 && (
<FeatherIcon
className={cx(
{ [styles.isExpanded]: isExpanded },
styles.nestedChevron
)}
name="chevron-right"
/>
)}
{headerIcon}
{page.displayName}
</button>
)}
{page.children && (
<ul
className={cx(styles.nestedNav, {
[styles.isExpanded]: isExpanded,
})}
>
{renderNav(page.children, depthLevel + 1)}
</ul>
)}
</li>
);
})}
</Fragment>
));
const filterPageNames = (pages, searchTerm, parent = []) => {
return [
...new Set(
pages.flatMap((page) => {
if (page.children) {
return filterPageNames(page.children, searchTerm, [
...parent,
page.displayName,
]);
} else if (matchSearchString(page.displayName, searchTerm)) {
return [...parent, page.displayName];
} else if (parent.some((el) => matchSearchString(el, searchTerm))) {
return [...parent];
}
})
),
];
};

const Navigation = ({ className }) => {
const Navigation = ({ className, searchTerm }) => {
const searchTermSanitized = searchTerm.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
const filteredPageNames =
searchTerm !== '' ? filterPageNames(pages, searchTermSanitized) : undefined;

return (
<nav
className={cx(styles.container, className)}
role="navigation"
aria-label="Navigation"
>
<ul className={styles.listNav}>{renderNav(pages)}</ul>
<ul className={styles.listNav}>
<NavigationItems
searchTerm={searchTermSanitized}
pages={pages}
filteredPageNames={filteredPageNames}
/>
</ul>
</nav>
);
};

Navigation.propTypes = {
className: PropTypes.string,
searchTerm: PropTypes.string,
};

export default Navigation;
82 changes: 1 addition & 81 deletions src/components/Navigation.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -2,87 +2,7 @@
font-size: 0.875rem;
}

.listNav,
.nestedNav {
list-style: none;
}

.nestedNav {
padding-left: 1rem;
display: none;

&.isExpanded {
display: block;
}

[data-depth] > & {
padding-left: calc(0.5rem + 1em);
}
}

.listNav {
list-style: none;
padding-left: 0;
}

.navLink {
color: var(--color-neutrals-900);
margin-bottom: 1rem;
display: flex;
align-items: center;
justify-content: space-between;
text-decoration: none;
transition: 0.1s;

&:not(.isCurrentPage):hover {
color: var(--color-neutrals-600);
}

[data-depth='0'] > & {
font-weight: bold;
}
}

.headerIcon {
margin-right: 0.5rem;
}

button.navLink {
color: var(--color-neutrals-900);
background: inherit;
border: none;
padding: 0;
font-size: inherit;
font-weight: inherit;

&:focus {
outline: none;
}
}

.currentPageIndicator {
stroke-width: 4;
}

.nestedChevron {
margin-right: 0.5rem;
stroke-width: 4;
transition: 0.2s;
&.isExpanded {
transform: rotate(90deg);
}
}

.groupName {
color: var(--color-neutrals-600);
font-weight: bold;
font-size: 0.75rem;
text-transform: uppercase;

&:not(:first-child) {
margin-top: 2rem;
}
}

.isCurrentPage {
font-weight: bold;
}
Loading

0 comments on commit f46b7b7

Please sign in to comment.