UNPKG

@lobehub/ui

Version:

Lobe UI is an open-source UI component library for building AIGC web apps

157 lines (156 loc) • 5.32 kB
"use client"; import FlexBasic_default from "../../Flex/FlexBasic.mjs"; import Button from "../../base-ui/Button/Button.mjs"; import Drawer from "../../base-ui/Drawer/Drawer.mjs"; import { ConsoleShellContext } from "./context.mjs"; import { useIsCompact, useLocalStorage, usePrefersReducedMotion } from "../hooks.mjs"; import { styles } from "./style.mjs"; import { useEffect, useId, useRef, useState } from "react"; import { jsx, jsxs } from "react/jsx-runtime"; import { PanelLeft, X } from "lucide-react"; //#region src/dashboard/ConsoleShell/ConsoleShell.tsx function isTypingTarget(target) { if (!(target instanceof HTMLElement)) return false; const tag = target.tagName; return tag === "INPUT" || tag === "TEXTAREA" || tag === "SELECT" || target.isContentEditable; } function ConsoleShell({ brand, breadcrumb, children, className, collapsed, closeNavigationLabel = "Close navigation", collapseLabel = "Collapse sidebar", defaultCollapsed = false, expandLabel = "Expand sidebar", footer, hotkey = true, navigation, onCollapsedChange, openNavigationLabel = "Open navigation", skipToContentLabel = "Skip to content", storageKey, tools, ...rest }) { const mainId = `console-main-${useId().replaceAll(":", "")}`; const shellRef = useRef(null); const isCompact = useIsCompact(); const reducedMotion = usePrefersReducedMotion(); const [storedCollapsed, setStoredCollapsed] = useLocalStorage(storageKey, defaultCollapsed); const [drawerOpen, setDrawerOpen] = useState(false); const isControlled = collapsed !== void 0; const railCollapsed = isControlled ? collapsed : storedCollapsed; const railed = railCollapsed && !isCompact; const setCollapsed = (next) => { if (!isControlled) setStoredCollapsed(next); onCollapsedChange?.(next); }; const closeNavigation = () => setDrawerOpen(false); const toggleNavigation = () => { if (isCompact) { setDrawerOpen((open) => !open); return; } setCollapsed(!railCollapsed); }; const toggleRef = useRef(toggleNavigation); toggleRef.current = toggleNavigation; useEffect(() => { if (!hotkey) return; const node = shellRef.current; if (!node) return; const onKeyDown = (event) => { if (event.key.toLowerCase() !== "b" || !(event.metaKey || event.ctrlKey) || event.altKey) return; if (event.repeat || isTypingTarget(event.target)) return; if (!node.contains(event.target)) return; event.preventDefault(); toggleRef.current(); }; document.addEventListener("keydown", onKeyDown); return () => document.removeEventListener("keydown", onKeyDown); }, [hotkey]); const stateFor = (rail) => ({ closeNavigation, collapsed: rail, compact: isCompact }); const sidebar = (rail) => /* @__PURE__ */ jsxs(ConsoleShellContext, { value: stateFor(rail), children: [ brand || isCompact ? /* @__PURE__ */ jsxs("div", { className: styles.brand, "data-collapsed": rail, children: [brand, isCompact ? /* @__PURE__ */ jsx(Button, { "aria-label": closeNavigationLabel, className: styles.brandClose, icon: X, type: "text", onClick: closeNavigation }) : null] }) : null, navigation ? /* @__PURE__ */ jsx("div", { className: styles.navSlot, children: navigation }) : null, footer ? /* @__PURE__ */ jsx("div", { className: styles.sidebarBottom, children: footer }) : null ] }); const toggleLabel = isCompact ? openNavigationLabel : railed ? expandLabel : collapseLabel; return /* @__PURE__ */ jsxs("div", { className: className ? `${styles.shell} ${className}` : styles.shell, "data-console-shell": "", ref: shellRef, ...rest, children: [ /* @__PURE__ */ jsx("a", { className: styles.skipLink, href: `#${mainId}`, onClick: (event) => { event.preventDefault(); document.getElementById(mainId)?.focus(); }, children: skipToContentLabel }), /* @__PURE__ */ jsx("aside", { className: styles.sidebar, "data-collapsed": railed, "data-instant": reducedMotion, children: !isCompact && sidebar(railed) }), isCompact ? /* @__PURE__ */ jsx(Drawer, { noHeader: true, classNames: { bodyContent: styles.drawerBody }, closable: false, open: drawerOpen, placement: "left", width: 272, onClose: closeNavigation, children: /* @__PURE__ */ jsx(FlexBasic_default, { height: "100%", children: sidebar(false) }) }) : null, /* @__PURE__ */ jsxs("div", { className: styles.workspace, children: [/* @__PURE__ */ jsxs("header", { className: styles.topbar, children: [ /* @__PURE__ */ jsx(Button, { "aria-label": toggleLabel, icon: PanelLeft, type: "text", onClick: toggleNavigation }), /* @__PURE__ */ jsx("span", { "aria-hidden": true, className: styles.topbarDivider }), /* @__PURE__ */ jsx("div", { className: styles.topbarMain, children: breadcrumb }), tools ? /* @__PURE__ */ jsx("div", { className: styles.tools, children: tools }) : null ] }), /* @__PURE__ */ jsx("main", { className: styles.main, id: mainId, tabIndex: -1, children })] }) ] }); } ConsoleShell.displayName = "ConsoleShell"; //#endregion export { ConsoleShell as default }; //# sourceMappingURL=ConsoleShell.mjs.map