Skip to content

Commit

Permalink
fix: use ably-ui Header and update legacy icon names in nav work
Browse files Browse the repository at this point in the history
  • Loading branch information
jamiehenson committed Feb 3, 2025
1 parent 6ec5f19 commit 6acc389
Show file tree
Hide file tree
Showing 9 changed files with 86 additions and 150 deletions.
4 changes: 2 additions & 2 deletions src/components/Layout/Breadcrumbs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,10 @@ const Breadcrumbs: React.FC = () => {
<Link to="/" className={cn(linkStyles, 'hidden sm:block')}>
Home
</Link>
<Icon name="icon-gui-disclosure-arrow" size="16px" additionalCSS="rotate-180 sm:rotate-0" />
<Icon name="icon-gui-chevron-right-micro" size="16px" additionalCSS="rotate-180 sm:rotate-0" />
{breadcrumbNodes.map((node, index) => (
<React.Fragment key={hierarchicalKey(node.page.link, index, activePage.tree)}>
{index > 0 ? <Icon name="icon-gui-disclosure-arrow" size="16px" additionalCSS="hidden sm:flex" /> : null}
{index > 0 ? <Icon name="icon-gui-chevron-right-micro" size="16px" additionalCSS="hidden sm:flex" /> : null}
<Link
to={node.page.link}
className={cn(linkStyles, {
Expand Down
10 changes: 5 additions & 5 deletions src/components/Layout/Header.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ describe('Header', () => {

it('renders the header with logo and links', () => {
render(<Header />);
expect(screen.getByAltText('Ably logo')).toBeInTheDocument();
expect(screen.getAllByAltText('Ably logo').length).toBeGreaterThan(0);
expect(screen.getByText('Documentation')).toBeInTheDocument();
expect(screen.getByText('Examples')).toBeInTheDocument();
});
Expand All @@ -57,18 +57,18 @@ describe('Header', () => {

it('toggles the mobile menu when the burger icon is clicked', () => {
render(<Header />);
const burgerIcon = screen.getByText('icon-gui-burger-menu');
const burgerIcon = screen.getByText('icon-gui-bars-3-outline');
fireEvent.click(burgerIcon);
expect(screen.getByText('icon-gui-close')).toBeInTheDocument();
expect(screen.getByText('icon-gui-x-mark-outline')).toBeInTheDocument();
expect(screen.getByText('LeftSidebar')).toBeInTheDocument();
});

it('disables scrolling when the mobile menu is open', () => {
render(<Header />);
const burgerIcon = screen.getByText('icon-gui-burger-menu');
const burgerIcon = screen.getByText('icon-gui-bars-3-outline');
fireEvent.click(burgerIcon);
expect(document.body).toHaveClass('overflow-hidden');
const closeIcon = screen.getByText('icon-gui-close');
const closeIcon = screen.getByText('icon-gui-x-mark-outline');
fireEvent.click(closeIcon);
expect(document.body).not.toHaveClass('overflow-hidden');
});
Expand Down
202 changes: 68 additions & 134 deletions src/components/Layout/Header.tsx
Original file line number Diff line number Diff line change
@@ -1,69 +1,26 @@
import React, { useState, useEffect, useRef, useContext, useMemo } from 'react';
import React, { useState, useEffect, useContext } from 'react';
import { navigate } from '@reach/router';
import TabMenu from '@ably/ui/core/TabMenu';
import Icon from '@ably/ui/core/Icon';
import cn from '@ably/ui/core/utils/cn';
import LinkButton from '@ably/ui/core/LinkButton';
import Logo from '@ably/ui/core/Logo';

import AblyHeader from '@ably/ui/core/Header';
import { SearchBar } from '../SearchBar';
import LeftSidebar from './LeftSidebar';
import UserContext from 'src/contexts/user-context';
import { pathWithBase } from './utils/nav';
import { componentMaxHeight, HEADER_BOTTOM_MARGIN, HEADER_HEIGHT } from './utils/heights';

type HeaderProps = {
hideSearchBar?: boolean;
};

const HeaderLinks: React.FC = () => {
const userContext = useContext(UserContext);
const sessionState = userContext.sessionState;
const signedIn = useMemo(() => sessionState.signedIn || !!process.env.GATSBY_DOCS_SIGNED_IN, [sessionState.signedIn]);

const headerLinkClasses =
'ui-text-menu2 md:ui-text-menu3 !font-bold py-16 text-neutral-1300 dark:text-neutral-000 md:text-neutral-1000 dark:md:text-neutral-300 hover:text-neutral-1300 dark:hover:text-neutral-000 active:text-neutral-1300 dark:active:text-neutral-000 transition-colors';

return (
<div className="flex md:items-center flex-col md:flex-row border-t-[1px] border-neutral-300 md:border-t-0 px-12 pb-12 md:pb-0">
<a
className={cn(headerLinkClasses, 'flex items-center gap-4 md:mr-16 mt-8 md:mt-0')}
href={pathWithBase('/sdks')}
target="_blank"
rel="noopener"
>
SDKs
<Icon name="icon-gui-external-link" />
</a>
<a className={cn(headerLinkClasses, 'md:mr-16 mb-8 md:mb-0')} href="/support">
Support
</a>
{signedIn && sessionState.account ? (
<LinkButton
href={sessionState.account.links?.dashboard.href}
variant="secondary"
className="md:ui-button-secondary-xs"
>
Dashboard
</LinkButton>
) : (
<div className="flex">
<LinkButton href="/login" variant="secondary" className="mr-12 flex-1 md:flex-none md:ui-button-secondary-xs">
Login
</LinkButton>
<LinkButton href="/sign-up" variant="primary" className="flex-1 md:flex-none md:ui-button-primary-xs">
Start free
</LinkButton>
</div>
)}
</div>
);
};

const Header: React.FC<HeaderProps> = ({ hideSearchBar = false }) => {
const [showMenu, setShowMenu] = useState(false);
const menuRef = useRef<HTMLDivElement>(null);
const tabs = ['Documentation', { label: 'Examples', disabled: true }];
const userContext = useContext(UserContext);
const sessionState = {
...userContext.sessionState,
signedIn: userContext.sessionState.signedIn ?? false,
account: userContext.sessionState.account ?? { links: { dashboard: { href: '#' } } },
};

const tabLinks = (index: number) => {
switch (index) {
Expand Down Expand Up @@ -101,91 +58,68 @@ const Header: React.FC<HeaderProps> = ({ hideSearchBar = false }) => {
}, [showMenu]);

return (
<>
<header
role="banner"
className="fixed top-0 left-0 w-full z-10 bg-neutral-000 dark:bg-neutral-1300 border-b border-neutral-300"
style={{ height: HEADER_HEIGHT }}
>
<div className={cn('flex items-center h-full ui-standard-container mx-auto')}>
<Logo additionalLinkAttrs={{ className: 'flex h-full focus-base rounded mr-32' }} />
<div className="flex md:hidden flex-1 items-center justify-end gap-24 h-full">
<button
className="cursor-pointer focus-base rounded"
aria-label="Toggle search"
onClick={() => {
const searchContainer = document.querySelector('#inkeep-search > div');
const searchButton = searchContainer?.shadowRoot?.querySelector('button');
<AblyHeader
nav={
<TabMenu
tabs={tabs}
tabClassName="ui-text-menu3 !px-16"
tabOnClick={(index) => {
navigate(tabLinks(index));
}}
options={{ underline: false, flexibleTabHeight: true }}
/>
}
mobileNav={
<TabMenu
tabs={tabs}
contents={[<LeftSidebar inHeader key="nav-mobile-documentation-tab" />, null]}
rootClassName="h-full overflow-y-hidden min-h-[51px] flex flex-col"
contentClassName="h-full py-16 overflow-y-scroll"
tabClassName="ui-text-menu2 !px-16"
options={{ flexibleTabWidth: true }}
/>
}
searchButton={
<button
className="cursor-pointer focus-base rounded"
aria-label="Toggle search"
onClick={() => {
const searchContainer = document.querySelector('#inkeep-search > div');
const searchButton = searchContainer?.shadowRoot?.querySelector('button');

if (searchButton) {
searchButton.click();
}
}}
>
<Icon name="icon-gui-search" size="1.5rem" />
</button>
<button
className="cursor-pointer focus-base rounded"
onClick={() => setShowMenu(!showMenu)}
aria-expanded={showMenu}
aria-controls="mobile-menu"
aria-label="Toggle menu"
>
<Icon name={showMenu ? 'icon-gui-close' : 'icon-gui-burger-menu'} size="1.5rem" />
</button>
</div>
<div className="hidden md:flex flex-1 items-center h-full">
<TabMenu
tabs={tabs}
tabClassName="ui-text-menu3 !px-16"
tabOnClick={(index) => {
navigate(tabLinks(index));
}}
options={{ underline: false, flexibleTabHeight: true }}
/>
<div className="flex-1 flex justify-center px-16">
{!hideSearchBar ? (
<SearchBar
displayLocation="homepage"
extraStyleOptions={{
wrapperContainer: { width: '100%', maxWidth: '280px' },
inputContainer: { width: '100%', maxWidth: '280px' },
}}
/>
) : null}
</div>
<HeaderLinks />
</div>
</div>
</header>
{showMenu ? (
<>
<div
className="fixed inset-0 bg-neutral-1300 dark:bg-neutral-1300 animate-[fadeInTenPercent_150ms_ease-in-out_forwards]"
onClick={() => setShowMenu(!showMenu)}
onKeyDown={(e) => e.key === 'Escape' && setShowMenu(false)}
role="presentation"
if (searchButton) {
searchButton.click();
}
}}
>
<Icon name="icon-gui-magnifying-glass-outline" size="1.5rem" />
</button>
}
searchButtonVisibility="mobile"
searchBar={
!hideSearchBar ? (
<SearchBar
displayLocation="homepage"
extraStyleOptions={{
wrapperContainer: { width: '100%', maxWidth: '280px' },
inputContainer: { width: '100%', maxWidth: '280px' },
}}
/>
<div
id="mobile-menu"
className="md:hidden fixed flex flex-col top-[76px] overflow-y-hidden left-0 right-0 mx-12 bg-neutral-000 dark:bg-neutral-1300 rounded-2xl ui-shadow-lg-medium z-20"
style={{ maxHeight: componentMaxHeight(HEADER_HEIGHT, HEADER_BOTTOM_MARGIN) }}
ref={menuRef}
role="navigation"
>
<TabMenu
tabs={tabs}
contents={[<LeftSidebar inHeader key="nav-mobile-documentation-tab" />, null]}
rootClassName="h-full overflow-y-hidden min-h-[51px] flex flex-col"
contentClassName="h-full py-16 overflow-y-scroll"
tabClassName="ui-text-menu2 !px-16"
options={{ flexibleTabWidth: true }}
/>
<HeaderLinks />
</div>
</>
) : null}
</>
) : null
}
headerLinks={[
{
href: pathWithBase('/sdks'),
label: 'SDKs',
external: true,
},
{
href: '/support',
label: 'Support',
},
]}
sessionState={sessionState}
/>
);
};

Expand Down
4 changes: 3 additions & 1 deletion src/components/Layout/LanguageSelector.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,9 @@ const LanguageSelectorOption = ({ isOption, setMenuOpen, langParam, ...props }:
</Badge>
{isOption ? (
<div className="w-16 h-16">
{props.data.label === langParam ? <Icon name="icon-gui-tick" size="16px" color="text-neutral-1000" /> : null}
{props.data.label === langParam ? (
<Icon name="icon-gui-check-outline" size="16px" color="text-neutral-1000" />
) : null}
</div>
) : null}
</div>
Expand Down
4 changes: 2 additions & 2 deletions src/components/Layout/LeftSidebar.test.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React from 'react';
import { useLocation } from '@reach/router';
import { render, screen, fireEvent } from '@testing-library/react';
import { render, screen } from '@testing-library/react';
import '@testing-library/jest-dom/extend-expect';
import LeftSidebar from './LeftSidebar';
import { useLayoutContext } from 'src/contexts/layout-context';
Expand Down Expand Up @@ -60,7 +60,7 @@ const mockProducts: [ProductKey, NavProduct][] = [
'pubsub',
{
name: 'Pub/Sub',
icon: { open: 'icon-gui-chevron-up', closed: 'icon-gui-chevron-down' },
icon: { open: 'icon-gui-chevron-up-outline', closed: 'icon-gui-chevron-down-outline' },
content: [
{
name: 'Overview',
Expand Down
2 changes: 1 addition & 1 deletion src/components/Layout/LeftSidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ const NavPage = ({
to={language ? `${page.link}?lang=${language}` : page.link}
>
{page.name}
{page.external ? <Icon name="icon-gui-external-link" additionalCSS="ml-4" /> : null}
{page.external ? <Icon name="icon-gui-arrow-top-right-on-square-outline" additionalCSS="ml-4" /> : null}
</Link>
);
} else {
Expand Down
2 changes: 1 addition & 1 deletion src/components/Layout/utils/nav.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import cn from '@ably/ui/core/utils/cn';
import { AccordionProps } from '@ably/ui/core/Accordion';
import { ProductData, ProductKey } from 'src/data/types';
import { NavProductContent, NavProductPage, NavProductPages } from 'src/data/nav/types';
import { componentMaxHeight, HEADER_BOTTOM_MARGIN, HEADER_HEIGHT } from './heights';
import { componentMaxHeight, HEADER_HEIGHT } from './heights';

export type PageTreeNode = { index: number; page: NavProductPage };

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ exports[`<Pre /> should successfully render code elements with only Realtime la
style="width: 1.25rem; height: 1.25rem;"
>
<use
xlink:href="#sprite-icon-gui-information-circle-outline"
xlink:href="#sprite-icon-gui-info"
/>
</svg>
</div>
Expand Down Expand Up @@ -273,7 +273,7 @@ exports[`<Pre /> should successfully render code elements with only Rest langua
style="width: 1.25rem; height: 1.25rem;"
>
<use
xlink:href="#sprite-icon-gui-information-circle-outline"
xlink:href="#sprite-icon-gui-info"
/>
</svg>
</div>
Expand Down Expand Up @@ -408,7 +408,7 @@ exports[`<Pre /> should successfully render code elements with both Rest and Rea
style="width: 1.25rem; height: 1.25rem;"
>
<use
xlink:href="#sprite-icon-gui-information-circle-outline"
xlink:href="#sprite-icon-gui-info"
/>
</svg>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ exports[`<LocalLanguageAlternatives /> renders correctly 1`] = `
style="width: 1rem; height: 1rem;"
>
<use
xlink:href="#sprite-icon-gui-square-2-stack-outline"
xlink:href="#sprite-icon-gui-copy"
/>
</svg>
</button>
Expand Down

0 comments on commit 6acc389

Please sign in to comment.