UNPKG

fumadocs-ui

Version:

The Radix UI version of Fumadocs UI

159 lines (156 loc) 6.58 kB
'use client'; import { useSidebar } from "../../components/sidebar/base.js"; import { Popover, PopoverContent, PopoverTrigger } from "../../components/ui/popover.js"; import { isTabActive } from "../../components/sidebar/tabs/dropdown.js"; import Link from "fumadocs-core/link"; import { usePathname } from "fumadocs-core/framework"; import { cn } from "@fumadocs/ui/cn"; import { jsx, jsxs } from "react/jsx-runtime"; import { ChevronDown } from "lucide-react"; import { Fragment as Fragment$1, createContext, use, useMemo, useRef, useState } from "react"; import { useIsScrollTop } from "@fumadocs/ui/hooks/use-is-scroll-top"; import { LinkItem } from "@fumadocs/ui/link-item"; //#region src/layouts/notebook/client.tsx const LayoutContext = createContext(null); function LayoutContextProvider({ navTransparentMode = "none", navMode, tabMode, children }) { const isTop = useIsScrollTop({ enabled: navTransparentMode === "top" }) ?? true; const isNavTransparent = navTransparentMode === "top" ? isTop : navTransparentMode === "always"; return /* @__PURE__ */ jsx(LayoutContext, { value: useMemo(() => ({ isNavTransparent, navMode, tabMode }), [ isNavTransparent, navMode, tabMode ]), children }); } function LayoutHeader(props) { const { open } = useSidebar(); const { isNavTransparent } = use(LayoutContext); return /* @__PURE__ */ jsx("header", { "data-transparent": isNavTransparent && !open, ...props, children: props.children }); } function LayoutBody({ className, style, children, ...props }) { const { navMode } = use(LayoutContext); const { collapsed } = useSidebar(); const pageCol = "calc(var(--fd-layout-width,97rem) - var(--fd-sidebar-col) - var(--fd-toc-width))"; return /* @__PURE__ */ jsx("div", { id: "nd-notebook-layout", className: cn("grid overflow-x-clip min-h-(--fd-docs-height) transition-[grid-template-columns] auto-cols-auto auto-rows-auto [--fd-docs-height:100dvh] [--fd-header-height:0px] [--fd-toc-popover-height:0px] [--fd-sidebar-width:0px] [--fd-toc-width:0px]", className), style: { gridTemplate: navMode === "top" ? `". header header header ." "sidebar sidebar toc-popover toc-popover ." "sidebar sidebar main toc ." 1fr / minmax(min-content, 1fr) var(--fd-sidebar-col) minmax(0, ${pageCol}) var(--fd-toc-width) minmax(min-content, 1fr)` : `"sidebar sidebar header header ." "sidebar sidebar toc-popover toc-popover ." "sidebar sidebar main toc ." 1fr / minmax(min-content, 1fr) var(--fd-sidebar-col) minmax(0, ${pageCol}) var(--fd-toc-width) minmax(min-content, 1fr)`, "--fd-docs-row-1": "var(--fd-banner-height, 0px)", "--fd-docs-row-2": "calc(var(--fd-docs-row-1) + var(--fd-header-height))", "--fd-docs-row-3": "calc(var(--fd-docs-row-2) + var(--fd-toc-popover-height))", "--fd-sidebar-col": collapsed ? "0px" : "var(--fd-sidebar-width)", ...style }, ...props, children }); } function LayoutHeaderTabs({ options, className, ...props }) { const pathname = usePathname(); const selectedIdx = useMemo(() => { return options.findLastIndex((option) => isTabActive(option, pathname)); }, [options, pathname]); return /* @__PURE__ */ jsx("div", { className: cn("flex flex-row items-end gap-6", className), ...props, children: options.map((option, i) => { const { title, url, unlisted, props: { className: className$1, ...rest } = {} } = option; const isSelected = selectedIdx === i; return /* @__PURE__ */ jsx(Link, { href: url, className: cn("inline-flex border-b-2 border-transparent transition-colors items-center pb-1.5 font-medium gap-2 text-fd-muted-foreground text-sm text-nowrap hover:text-fd-accent-foreground", unlisted && !isSelected && "hidden", isSelected && "border-fd-primary text-fd-primary", className$1), ...rest, children: title }, i); }) }); } function NavbarLinkItem({ item, className, ...props }) { if (item.type === "custom") return item.children; if (item.type === "menu") return /* @__PURE__ */ jsx(NavbarLinkItemMenu, { item, className, ...props }); return /* @__PURE__ */ jsx(LinkItem, { item, className: cn("text-sm text-fd-muted-foreground transition-colors hover:text-fd-accent-foreground data-[active=true]:text-fd-primary", className), ...props, children: item.text }); } function NavbarLinkItemMenu({ item, hoverDelay = 50, className, ...props }) { const [open, setOpen] = useState(false); const timeoutRef = useRef(null); const freezeUntil = useRef(null); const delaySetOpen = (value) => { if (timeoutRef.current) { clearTimeout(timeoutRef.current); timeoutRef.current = null; } timeoutRef.current = window.setTimeout(() => { setOpen(value); freezeUntil.current = Date.now() + 300; }, hoverDelay); }; const onPointerEnter = (e) => { if (e.pointerType === "touch") return; delaySetOpen(true); }; const onPointerLeave = (e) => { if (e.pointerType === "touch") return; delaySetOpen(false); }; function isTouchDevice() { return "ontouchstart" in window || navigator.maxTouchPoints > 0; } return /* @__PURE__ */ jsxs(Popover, { open, onOpenChange: (value) => { if (freezeUntil.current === null || Date.now() >= freezeUntil.current) setOpen(value); }, children: [/* @__PURE__ */ jsxs(PopoverTrigger, { className: cn("inline-flex items-center gap-1.5 p-1 text-sm text-fd-muted-foreground transition-colors has-data-[active=true]:text-fd-primary data-[state=open]:text-fd-accent-foreground focus-visible:outline-none", className), onPointerEnter, onPointerLeave, ...props, children: [item.url ? /* @__PURE__ */ jsx(LinkItem, { item, children: item.text }) : item.text, /* @__PURE__ */ jsx(ChevronDown, { className: "size-3" })] }), /* @__PURE__ */ jsx(PopoverContent, { className: "flex flex-col p-1 text-fd-muted-foreground text-start", onPointerEnter, onPointerLeave, children: item.items.map((child, i) => { if (child.type === "custom") return /* @__PURE__ */ jsx(Fragment$1, { children: child.children }, i); return /* @__PURE__ */ jsxs(LinkItem, { item: child, className: "inline-flex items-center gap-2 rounded-md p-2 transition-colors hover:bg-fd-accent hover:text-fd-accent-foreground data-[active=true]:text-fd-primary [&_svg]:size-4", onClick: () => { if (isTouchDevice()) setOpen(false); }, children: [child.icon, child.text] }, i); }) })] }); } //#endregion export { LayoutBody, LayoutContext, LayoutContextProvider, LayoutHeader, LayoutHeaderTabs, NavbarLinkItem }; //# sourceMappingURL=client.js.map