shelving
Version:
Toolkit for using data in JavaScript.
30 lines (29 loc) • 2.46 kB
JavaScript
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
import { Bars3Icon, XMarkIcon } from "@heroicons/react/24/solid";
import { useEffect, useState } from "react";
import { Button } from "../form/Button.js";
import { requireMetaURL } from "../misc/MetaContext.js";
import { getClass } from "../util/css.js";
import { LAYOUT_CLASS } from "./Layout.js";
import SIDEBAR_LAYOUT_CSS from "./SidebarLayout.module.css";
/**
* Layout with a fixed-width side column (typically navigation) next to a scrollable main content column.
* - The sidebar is rendered as `<nav>` — it almost always contains the page's primary navigation.
* - On narrow viewports the sidebar becomes an off-canvas drawer toggled by a single menu button that switches between a burger and a close icon.
* - While the drawer is open an overlay dims the rest of the page; clicking the overlay closes the drawer.
* - Inside a `<Navigation>` the drawer closes itself whenever the route changes (e.g. tapping a sidebar link).
* - Use the `--sidebar-layout-width`, `--sidebar-layout-bg`, `--sidebar-layout-border`, and `--sidebar-layout-color-border` custom properties to override defaults.
*/
export function SidebarLayout({ sidebar, children, right = false }) {
const { path } = requireMetaURL();
const [open, setOpen] = useState(false);
// Close the drawer whenever navigation changes the URL — covers tapping a link inside the sidebar.
useEffect(() => {
if (path)
setOpen(false);
}, [path]);
const sidebarEl = (_jsx("nav", { className: getClass(SIDEBAR_LAYOUT_CSS.sidebar, open && SIDEBAR_LAYOUT_CSS.open), children: sidebar }, "sidebar"));
const contentEl = (_jsxs("div", { className: getClass(LAYOUT_CLASS, SIDEBAR_LAYOUT_CSS.content), children: [_jsx("div", { className: SIDEBAR_LAYOUT_CSS.toggle, children: _jsx(Button, { fit: true, title: open ? "Close menu" : "Show menu", onClick: () => setOpen(o => !o), children: open ? _jsx(XMarkIcon, {}) : _jsx(Bars3Icon, {}) }) }), _jsx("div", { className: SIDEBAR_LAYOUT_CSS.contentInner, children: children })] }, path));
const overlayEl = open && (_jsx("button", { type: "button", className: SIDEBAR_LAYOUT_CSS.overlay, "aria-label": "Close menu", onClick: () => setOpen(false) }, "overlay"));
return (_jsx("main", { className: getClass(SIDEBAR_LAYOUT_CSS.main, LAYOUT_CLASS), children: right ? [contentEl, sidebarEl, overlayEl] : [sidebarEl, contentEl, overlayEl] }));
}