UNPKG

fumadocs-ui

Version:

The Radix UI version of Fumadocs UI

262 lines (259 loc) 10.4 kB
'use client'; import { buttonVariants } from "../../components/ui/button.js"; import { NavigationMenu, NavigationMenuContent, NavigationMenuItem, NavigationMenuLink, NavigationMenuList, NavigationMenuTrigger, NavigationMenuViewport } from "../../components/ui/navigation-menu.js"; import { LargeSearchToggle, SearchToggle } from "../shared/search-toggle.js"; import { renderTitleNav, resolveLinkItems } from "../shared/index.js"; import { LanguageToggle, LanguageToggleText } from "../shared/language-toggle.js"; import { ThemeToggle } from "../shared/theme-toggle.js"; import Link from "fumadocs-core/link"; import { cn } from "@fumadocs/ui/cn"; import { Fragment, jsx, jsxs } from "react/jsx-runtime"; import { ChevronDown, Languages } from "lucide-react"; import { Fragment as Fragment$1, useMemo, useState } from "react"; import { cva } from "class-variance-authority"; import { useIsScrollTop } from "@fumadocs/ui/hooks/use-is-scroll-top"; import { LinkItem } from "@fumadocs/ui/link-item"; //#region src/layouts/home/client.tsx const navItemVariants = cva("[&_svg]:size-4", { variants: { variant: { main: "inline-flex items-center gap-1 p-2 text-fd-muted-foreground transition-colors hover:text-fd-accent-foreground data-[active=true]:text-fd-primary", button: buttonVariants({ color: "secondary", className: "gap-1.5" }), icon: buttonVariants({ color: "ghost", size: "icon" }) } }, defaultVariants: { variant: "main" } }); function Header({ nav = {}, i18n = false, links, githubUrl, themeSwitch = {}, searchToggle = {} }) { const { navItems, menuItems } = useMemo(() => { const navItems$1 = []; const menuItems$1 = []; for (const item of resolveLinkItems({ links, githubUrl })) switch (item.on ?? "all") { case "menu": menuItems$1.push(item); break; case "nav": navItems$1.push(item); break; default: navItems$1.push(item); menuItems$1.push(item); } return { navItems: navItems$1, menuItems: menuItems$1 }; }, [links, githubUrl]); return /* @__PURE__ */ jsxs(HeaderNavigationMenu, { transparentMode: nav.transparentMode, children: [ renderTitleNav(nav, { className: "inline-flex items-center gap-2.5 font-semibold" }), nav.children, /* @__PURE__ */ jsx("ul", { className: "flex flex-row items-center gap-2 px-6 max-sm:hidden", children: navItems.filter((item) => !isSecondary(item)).map((item, i) => /* @__PURE__ */ jsx(NavigationMenuLinkItem, { item, className: "text-sm" }, i)) }), /* @__PURE__ */ jsxs("div", { className: "flex flex-row items-center justify-end gap-1.5 flex-1 max-lg:hidden", children: [ searchToggle.enabled !== false && (searchToggle.components?.lg ?? /* @__PURE__ */ jsx(LargeSearchToggle, { className: "w-full rounded-full ps-2.5 max-w-[240px]", hideIfDisabled: true })), themeSwitch.enabled !== false && (themeSwitch.component ?? /* @__PURE__ */ jsx(ThemeToggle, { mode: themeSwitch?.mode })), i18n && /* @__PURE__ */ jsx(LanguageToggle, { children: /* @__PURE__ */ jsx(Languages, { className: "size-5" }) }), /* @__PURE__ */ jsx("ul", { className: "flex flex-row gap-2 items-center empty:hidden", children: navItems.filter(isSecondary).map((item, i) => /* @__PURE__ */ jsx(NavigationMenuLinkItem, { className: cn(item.type === "icon" && "-mx-1 first:ms-0 last:me-0"), item }, i)) }) ] }), /* @__PURE__ */ jsxs("ul", { className: "flex flex-row items-center ms-auto -me-1.5 lg:hidden", children: [searchToggle.enabled !== false && (searchToggle.components?.sm ?? /* @__PURE__ */ jsx(SearchToggle, { className: "p-2", hideIfDisabled: true })), /* @__PURE__ */ jsxs(NavigationMenuItem, { children: [/* @__PURE__ */ jsx(NavigationMenuTrigger, { "aria-label": "Toggle Menu", className: cn(buttonVariants({ size: "icon", color: "ghost", className: "group [&_svg]:size-5.5" })), onPointerMove: nav.enableHoverToOpen ? void 0 : (e) => e.preventDefault(), children: /* @__PURE__ */ jsx(ChevronDown, { className: "transition-transform duration-300 group-data-[state=open]:rotate-180" }) }), /* @__PURE__ */ jsxs(NavigationMenuContent, { className: "flex flex-col p-4 sm:flex-row sm:items-center sm:justify-end", children: [menuItems.filter((item) => !isSecondary(item)).map((item, i) => /* @__PURE__ */ jsx(MobileNavigationMenuLinkItem, { item, className: "sm:hidden" }, i)), /* @__PURE__ */ jsxs("div", { className: "-ms-1.5 flex flex-row items-center gap-2 max-sm:mt-2", children: [ menuItems.filter(isSecondary).map((item, i) => /* @__PURE__ */ jsx(MobileNavigationMenuLinkItem, { item, className: cn(item.type === "icon" && "-mx-1 first:ms-0") }, i)), /* @__PURE__ */ jsx("div", { role: "separator", className: "flex-1" }), i18n && /* @__PURE__ */ jsxs(LanguageToggle, { children: [ /* @__PURE__ */ jsx(Languages, { className: "size-5" }), /* @__PURE__ */ jsx(LanguageToggleText, {}), /* @__PURE__ */ jsx(ChevronDown, { className: "size-3 text-fd-muted-foreground" }) ] }), themeSwitch.enabled !== false && (themeSwitch.component ?? /* @__PURE__ */ jsx(ThemeToggle, { mode: themeSwitch?.mode })) ] })] })] })] }) ] }); } function isSecondary(item) { if ("secondary" in item && item.secondary != null) return item.secondary; return item.type === "icon"; } function HeaderNavigationMenu({ transparentMode = "none", ...props }) { const [value, setValue] = useState(""); const isTop = useIsScrollTop({ enabled: transparentMode === "top" }) ?? true; const isTransparent = transparentMode === "top" ? isTop : transparentMode === "always"; return /* @__PURE__ */ jsx(NavigationMenu, { value, onValueChange: setValue, asChild: true, children: /* @__PURE__ */ jsx("header", { id: "nd-nav", ...props, className: cn("sticky h-14 top-0 z-40", props.className), children: /* @__PURE__ */ jsxs("div", { className: cn("backdrop-blur-lg border-b transition-colors *:mx-auto *:max-w-(--fd-layout-width)", value.length > 0 && "max-lg:shadow-lg max-lg:rounded-b-2xl", (!isTransparent || value.length > 0) && "bg-fd-background/80"), children: [/* @__PURE__ */ jsx(NavigationMenuList, { className: "flex h-14 w-full items-center px-4", asChild: true, children: /* @__PURE__ */ jsx("nav", { children: props.children }) }), /* @__PURE__ */ jsx(NavigationMenuViewport, {})] }) }) }); } function NavigationMenuLinkItem({ item, ...props }) { if (item.type === "custom") return /* @__PURE__ */ jsx("div", { ...props, children: item.children }); if (item.type === "menu") { const children = item.items.map((child, j) => { if (child.type === "custom") return /* @__PURE__ */ jsx(Fragment$1, { children: child.children }, j); const { banner = child.icon ? /* @__PURE__ */ jsx("div", { className: "w-fit rounded-md border bg-fd-muted p-1 [&_svg]:size-4", children: child.icon }) : null, ...rest } = child.menu ?? {}; return /* @__PURE__ */ jsx(NavigationMenuLink, { asChild: true, children: /* @__PURE__ */ jsx(Link, { href: child.url, external: child.external, ...rest, className: cn("flex flex-col gap-2 rounded-lg border bg-fd-card p-3 transition-colors hover:bg-fd-accent/80 hover:text-fd-accent-foreground", rest.className), children: rest.children ?? /* @__PURE__ */ jsxs(Fragment, { children: [ banner, /* @__PURE__ */ jsx("p", { className: "text-base font-medium", children: child.text }), /* @__PURE__ */ jsx("p", { className: "text-sm text-fd-muted-foreground empty:hidden", children: child.description }) ] }) }) }, `${j}-${child.url}`); }); return /* @__PURE__ */ jsxs(NavigationMenuItem, { ...props, children: [/* @__PURE__ */ jsx(NavigationMenuTrigger, { className: cn(navItemVariants(), "rounded-md"), children: item.url ? /* @__PURE__ */ jsx(Link, { href: item.url, external: item.external, children: item.text }) : item.text }), /* @__PURE__ */ jsx(NavigationMenuContent, { className: "grid grid-cols-1 gap-2 p-4 md:grid-cols-2 lg:grid-cols-3", children })] }); } return /* @__PURE__ */ jsx(NavigationMenuItem, { ...props, children: /* @__PURE__ */ jsx(NavigationMenuLink, { asChild: true, children: /* @__PURE__ */ jsx(LinkItem, { item, "aria-label": item.type === "icon" ? item.label : void 0, className: cn(navItemVariants({ variant: item.type })), children: item.type === "icon" ? item.icon : item.text }) }) }); } function MobileNavigationMenuLinkItem({ item, ...props }) { if (item.type === "custom") return /* @__PURE__ */ jsx("div", { className: cn("grid", props.className), children: item.children }); if (item.type === "menu") { const header = /* @__PURE__ */ jsxs(Fragment, { children: [item.icon, item.text] }); return /* @__PURE__ */ jsxs("div", { className: cn("mb-4 flex flex-col", props.className), children: [/* @__PURE__ */ jsx("p", { className: "mb-1 text-sm text-fd-muted-foreground", children: item.url ? /* @__PURE__ */ jsx(NavigationMenuLink, { asChild: true, children: /* @__PURE__ */ jsx(Link, { href: item.url, external: item.external, children: header }) }) : header }), item.items.map((child, i) => /* @__PURE__ */ jsx(MobileNavigationMenuLinkItem, { item: child }, i))] }); } return /* @__PURE__ */ jsx(NavigationMenuLink, { asChild: true, children: /* @__PURE__ */ jsxs(LinkItem, { item, className: cn({ main: "inline-flex items-center gap-2 py-1.5 transition-colors hover:text-fd-popover-foreground/50 data-[active=true]:font-medium data-[active=true]:text-fd-primary [&_svg]:size-4", icon: buttonVariants({ size: "icon", color: "ghost" }), button: buttonVariants({ color: "secondary", className: "gap-1.5 [&_svg]:size-4" }) }[item.type ?? "main"], props.className), "aria-label": item.type === "icon" ? item.label : void 0, children: [item.icon, item.type === "icon" ? void 0 : item.text] }) }); } //#endregion export { Header, navItemVariants }; //# sourceMappingURL=client.js.map