Skip to content

Commit

Permalink
fix(app-layout): prevent display of empty app navigation panel
Browse files Browse the repository at this point in the history
  • Loading branch information
lorumic committed Jul 19, 2024
1 parent b0baa85 commit 2825eb9
Show file tree
Hide file tree
Showing 3 changed files with 104 additions and 75 deletions.
21 changes: 20 additions & 1 deletion src/components/ApplicationLayout/ApplicationLayout.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,9 @@ export const Default: Story = {
]}
aside={
showAside ? (
<AppAside title="Aside panel" pinned={asidePinned}>
<AppAside pinned={asidePinned}>
<Panel
title="Aside panel"
controls={
<>
<Button
Expand Down Expand Up @@ -274,3 +275,21 @@ export const Navigation: Story = {
);
},
};

/**
* App navigation can also be completely opted out of, for some
* particular scenarios (e.g. login page, error pages).
*/
export const NoNavigation: Story = {
render: () => {
return (
<ApplicationLayout>
<Panel title="Application Layout with no navigation">
<Row>
<Col size={12}>Content</Col>
</Row>
</Panel>
</ApplicationLayout>
);
},
};
5 changes: 5 additions & 0 deletions src/components/ApplicationLayout/ApplicationLayout.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -111,3 +111,8 @@ it("collapses the menu using external state", async () => {
await userEvent.click(screen.getByRole("button", { name: "Menu" }));
expect(onCollapseMenu).toHaveBeenCalledWith(false);
});

it("can opt out of app navigation", async () => {
render(<ApplicationLayout />);
expect(document.querySelector(".l-navigation")).toBeNull();
});
153 changes: 79 additions & 74 deletions src/components/ApplicationLayout/ApplicationLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ export type BaseProps<
/**
* The logo to appear in the navigation panels.
*/
logo: NonNullable<PanelProps<PL>["logo"]>;
logo?: PanelProps<PL>["logo"];
/**
* The component to use to render links inside the navigation e.g. when
* using react-router you'd pass `Link` to this prop.
Expand Down Expand Up @@ -96,10 +96,10 @@ export type Props<
> = BaseProps<NI, PL> &
ExclusiveProps<
{
navItems: NonNullable<SideNavigationProps<NI>["items"]>;
navItems?: SideNavigationProps<NI>["items"];
},
{
sideNavigation: ReactNode;
sideNavigation?: ReactNode;
}
>;

Expand Down Expand Up @@ -145,81 +145,86 @@ const ApplicationLayout = <

return (
<Application {...props}>
<AppNavigationBar className={navigationBarClassName}>
<Panel<PL>
dark={dark}
logo={logo}
toggle={{
label: "Menu",
onClick: () => setMenuCollapsed(!menuIsCollapsed),
}}
/>
</AppNavigationBar>
<AppNavigation
className={navigationClassName}
collapsed={menuIsCollapsed}
pinned={menuIsPinned}
>
<Panel<PL>
dark={dark}
controls={
<>
<Button
hasIcon
appearance="base"
className={classNames("u-no-margin u-hide--medium", {
"is-dark": dark,
})}
onClick={(evt) => {
setMenuCollapsed(true);
// The menu stays open while its content has focus, so the
// close button must blur to actually close the menu.
evt.currentTarget.blur();
}}
>
<Icon name="close" className={classNames({ "is-light": dark })}>
Close menu
</Icon>
</Button>
<Button
hasIcon
appearance="base"
className={classNames("u-no-margin u-hide--small", {
"is-dark": dark,
})}
onClick={() => {
setMenuPinned(!menuIsPinned);
}}
>
<Icon
name={menuIsPinned ? "close" : "pin"}
className={classNames({ "is-light": dark })}
>
{menuIsPinned ? "Unpin menu" : "Pin menu"}
</Icon>
</Button>
</>
}
controlsClassName="u-hide--large"
stickyHeader
logo={logo}
>
{navItems ? (
<SideNavigation<NI>
{(navItems || sideNavigation) && (
<>
<AppNavigationBar className={navigationBarClassName}>
<Panel<PL>
dark={dark}
items={navItems}
linkComponent={navLinkComponent}
logo={logo}
toggle={{
label: "Menu",
onClick: () => setMenuCollapsed(!menuIsCollapsed),
}}
/>
) : (
sideNavigation
)}
</Panel>
</AppNavigation>
</AppNavigationBar>
<AppNavigation
className={navigationClassName}
collapsed={menuIsCollapsed}
pinned={menuIsPinned}
>
<Panel<PL>
dark={dark}
controls={
<>
<Button
hasIcon
appearance="base"
className={classNames("u-no-margin u-hide--medium", {
"is-dark": dark,
})}
onClick={(evt) => {
setMenuCollapsed(true);
// The menu stays open while its content has focus, so the
// close button must blur to actually close the menu.
evt.currentTarget.blur();
}}
>
<Icon
name="close"
className={classNames({ "is-light": dark })}
>
Close menu
</Icon>
</Button>
<Button
hasIcon
appearance="base"
className={classNames("u-no-margin u-hide--small", {
"is-dark": dark,
})}
onClick={() => {
setMenuPinned(!menuIsPinned);
}}
>
<Icon
name={menuIsPinned ? "close" : "pin"}
className={classNames({ "is-light": dark })}
>
{menuIsPinned ? "Unpin menu" : "Pin menu"}
</Icon>
</Button>
</>
}
controlsClassName="u-hide--large"
stickyHeader
logo={logo}
>
{navItems ? (
<SideNavigation<NI>
dark={dark}
items={navItems}
linkComponent={navLinkComponent}
/>
) : (
sideNavigation
)}
</Panel>
</AppNavigation>
</>
)}
<AppMain className={mainClassName}>{children}</AppMain>
{aside}
{status ? (
<AppStatus className={statusClassName}>{status}</AppStatus>
) : null}
{status && <AppStatus className={statusClassName}>{status}</AppStatus>}
</Application>
);
};
Expand Down

0 comments on commit 2825eb9

Please sign in to comment.