UNPKG

fumadocs-ui

Version:

The Radix UI version of Fumadocs UI

240 lines (239 loc) 9.86 kB
"use client"; import { cn } from "../../../utils/cn.js"; import { buttonVariants } from "../../../components/ui/button.js"; import { LinkItem } from "../../shared/client.js"; import "../../shared/index.js"; import { useIsScrollTop } from "../../../utils/use-is-scroll-top.js"; import { NavigationMenu, NavigationMenuContent, NavigationMenuItem, NavigationMenuLink, NavigationMenuList, NavigationMenuTrigger, NavigationMenuViewport } from "../../../components/ui/navigation-menu.js"; import { useHomeLayout } from "../index.js"; import Link from "fumadocs-core/link"; import { Fragment, jsx, jsxs } from "react/jsx-runtime"; import { ChevronDown, Languages } from "lucide-react"; import { cva } from "class-variance-authority"; import { Fragment as Fragment$1, useState } from "react"; import { useTranslations } from "@fuma-translate/react"; //#region src/layouts/home/slots/header.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(props) { const { navItems, menuItems, slots, props: { nav } } = useHomeLayout(); const t = useTranslations({ note: "mobile menu" }); if (nav?.component) return nav.component; return /* @__PURE__ */ jsxs(HeaderNavigationMenu, { transparentMode: nav?.transparentMode, ...props, children: [ slots.navTitle && /* @__PURE__ */ jsx(slots.navTitle, { 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: [ slots.searchTrigger && /* @__PURE__ */ jsx(slots.searchTrigger.full, { hideIfDisabled: true, className: "w-full rounded-full ps-2.5 max-w-[240px]" }), slots.themeSwitch && /* @__PURE__ */ jsx(slots.themeSwitch, {}), slots.languageSelect && /* @__PURE__ */ jsx(slots.languageSelect.root, { 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("div", { className: "flex flex-row items-center ms-auto -me-1.5 lg:hidden", children: [slots.searchTrigger && /* @__PURE__ */ jsx(slots.searchTrigger.sm, { hideIfDisabled: true, className: "p-2" }), /* @__PURE__ */ jsx(NavigationMenuItem, { asChild: true, children: /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx(NavigationMenuTrigger, { "aria-label": t("Toggle Menu", { note: "aria-label" }), 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" }), slots.languageSelect && /* @__PURE__ */ jsxs(slots.languageSelect.root, { children: [ /* @__PURE__ */ jsx(Languages, { className: "size-5" }), slots.languageSelect.text && /* @__PURE__ */ jsx(slots.languageSelect.text, {}), /* @__PURE__ */ jsx(ChevronDown, { className: "size-3 text-fd-muted-foreground" }) ] }), slots.themeSwitch && /* @__PURE__ */ jsx(slots.themeSwitch, {}) ] })] })] }) })] }) ] }); } 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 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 };