@fumadocs/base-ui 16.11.4 → 16.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/css/generated/docs.css +1 -1
- package/css/generated/flux.css +1 -1
- package/css/generated/glass.css +1 -0
- package/css/generated/home.css +1 -1
- package/css/generated/notebook.css +1 -1
- package/css/generated/shared.css +1 -1
- package/css/lib/base.css +2 -1
- package/css/preset.css +0 -1
- package/dist/.translations/index.d.ts +7 -0
- package/dist/.translations/keys.js +7 -0
- package/dist/components/codeblock.d.ts +2 -1
- package/dist/components/image-zoom.d.ts +2 -2
- package/dist/components/image-zoom.js +1 -1
- package/dist/components/sidebar/base.js +6 -2
- package/dist/components/sidebar/tabs/dropdown.d.ts +2 -3
- package/dist/components/sidebar/tabs/dropdown.js +9 -4
- package/dist/components/tabs.js +0 -1
- package/dist/components/toc/index.js +1 -1
- package/dist/components/ui/popover.js +1 -1
- package/dist/components/ui/tabs.d.ts +1 -1
- package/dist/components/ui/tabs.js +36 -11
- package/dist/layouts/docs/client.js +10 -5
- package/dist/layouts/docs/page/slots/toc.js +17 -11
- package/dist/layouts/docs/slots/sidebar.js +8 -2
- package/dist/layouts/flux/index.d.ts +1 -1
- package/dist/layouts/flux/index.js +2 -2
- package/dist/layouts/flux/page/slots/toc.js +7 -4
- package/dist/layouts/flux/slots/sidebar.js +6 -0
- package/dist/layouts/flux/slots/tab-dropdown.js +8 -2
- package/dist/layouts/glass/index.d.ts +41 -0
- package/dist/layouts/glass/index.js +70 -0
- package/dist/layouts/glass/layout-tabs.js +53 -0
- package/dist/layouts/glass/page/index.d.ts +31 -0
- package/dist/layouts/glass/page/index.js +92 -0
- package/dist/layouts/glass/page/slots/breadcrumb.d.ts +7 -0
- package/dist/layouts/glass/page/slots/breadcrumb.js +44 -0
- package/dist/layouts/glass/page/slots/footer.d.ts +16 -0
- package/dist/layouts/glass/page/slots/footer.js +56 -0
- package/dist/layouts/glass/page/slots/toc.d.ts +19 -0
- package/dist/layouts/glass/page/slots/toc.js +108 -0
- package/dist/layouts/glass/slots/header.d.ts +6 -0
- package/dist/layouts/glass/slots/header.js +73 -0
- package/dist/layouts/glass/slots/sidebar.d.ts +23 -0
- package/dist/layouts/glass/slots/sidebar.js +294 -0
- package/dist/layouts/home/index.js +2 -2
- package/dist/layouts/home/slots/header.js +1 -0
- package/dist/layouts/notebook/client.js +2 -2
- package/dist/layouts/notebook/page/slots/toc.js +17 -11
- package/dist/layouts/notebook/slots/header.js +8 -2
- package/dist/layouts/notebook/slots/sidebar.js +8 -2
- package/dist/layouts/shared/client.d.ts +1 -1
- package/dist/layouts/shared/client.js +1 -1
- package/dist/layouts/shared/index.d.ts +7 -6
- package/dist/layouts/shared/index.js +5 -3
- package/dist/node_modules/.pnpm/{react-medium-image-zoom@5.4.8_react-dom@19.2.7_react@19.2.7__react@19.2.7 → react-medium-image-zoom@5.4.8_react-dom@19.2.8_react@19.2.8__react@19.2.8}/node_modules/react-medium-image-zoom/dist/controlled.d.ts +1 -1
- package/dist/node_modules/.pnpm/{react-medium-image-zoom@5.4.8_react-dom@19.2.7_react@19.2.7__react@19.2.7 → react-medium-image-zoom@5.4.8_react-dom@19.2.8_react@19.2.8__react@19.2.8}/node_modules/react-medium-image-zoom/dist/controlled.js +1 -1
- package/dist/node_modules/.pnpm/{react-medium-image-zoom@5.4.8_react-dom@19.2.7_react@19.2.7__react@19.2.7 → react-medium-image-zoom@5.4.8_react-dom@19.2.8_react@19.2.8__react@19.2.8}/node_modules/react-medium-image-zoom/dist/uncontrolled.d.ts +1 -1
- package/dist/node_modules/.pnpm/{react-medium-image-zoom@5.4.8_react-dom@19.2.7_react@19.2.7__react@19.2.7 → react-medium-image-zoom@5.4.8_react-dom@19.2.8_react@19.2.8__react@19.2.8}/node_modules/react-medium-image-zoom/dist/uncontrolled.js +1 -1
- package/dist/node_modules/.pnpm/{react-medium-image-zoom@5.4.8_react-dom@19.2.7_react@19.2.7__react@19.2.7 → react-medium-image-zoom@5.4.8_react-dom@19.2.8_react@19.2.8__react@19.2.8}/node_modules/react-medium-image-zoom/dist/utils/adjust-svg-ids.js +1 -1
- package/dist/node_modules/.pnpm/{react-medium-image-zoom@5.4.8_react-dom@19.2.7_react@19.2.7__react@19.2.7 → react-medium-image-zoom@5.4.8_react-dom@19.2.8_react@19.2.8__react@19.2.8}/node_modules/react-medium-image-zoom/dist/utils/compute-positioned-style.js +1 -1
- package/dist/node_modules/.pnpm/{react-medium-image-zoom@5.4.8_react-dom@19.2.7_react@19.2.7__react@19.2.7 → react-medium-image-zoom@5.4.8_react-dom@19.2.8_react@19.2.8__react@19.2.8}/node_modules/react-medium-image-zoom/dist/utils/element-tests.js +1 -1
- package/dist/node_modules/.pnpm/{react-medium-image-zoom@5.4.8_react-dom@19.2.7_react@19.2.7__react@19.2.7 → react-medium-image-zoom@5.4.8_react-dom@19.2.8_react@19.2.8__react@19.2.8}/node_modules/react-medium-image-zoom/dist/utils/get-div-img-style.js +1 -1
- package/dist/node_modules/.pnpm/{react-medium-image-zoom@5.4.8_react-dom@19.2.7_react@19.2.7__react@19.2.7 → react-medium-image-zoom@5.4.8_react-dom@19.2.8_react@19.2.8__react@19.2.8}/node_modules/react-medium-image-zoom/dist/utils/get-img-alt.js +1 -1
- package/dist/node_modules/.pnpm/{react-medium-image-zoom@5.4.8_react-dom@19.2.7_react@19.2.7__react@19.2.7 → react-medium-image-zoom@5.4.8_react-dom@19.2.8_react@19.2.8__react@19.2.8}/node_modules/react-medium-image-zoom/dist/utils/get-img-object-fit-style.js +1 -1
- package/dist/node_modules/.pnpm/{react-medium-image-zoom@5.4.8_react-dom@19.2.7_react@19.2.7__react@19.2.7 → react-medium-image-zoom@5.4.8_react-dom@19.2.8_react@19.2.8__react@19.2.8}/node_modules/react-medium-image-zoom/dist/utils/get-img-regular-style.js +1 -1
- package/dist/node_modules/.pnpm/{react-medium-image-zoom@5.4.8_react-dom@19.2.7_react@19.2.7__react@19.2.7 → react-medium-image-zoom@5.4.8_react-dom@19.2.8_react@19.2.8__react@19.2.8}/node_modules/react-medium-image-zoom/dist/utils/get-img-src.js +1 -1
- package/dist/node_modules/.pnpm/{react-medium-image-zoom@5.4.8_react-dom@19.2.7_react@19.2.7__react@19.2.7 → react-medium-image-zoom@5.4.8_react-dom@19.2.8_react@19.2.8__react@19.2.8}/node_modules/react-medium-image-zoom/dist/utils/get-modal-img-transform.js +1 -1
- package/dist/node_modules/.pnpm/{react-medium-image-zoom@5.4.8_react-dom@19.2.7_react@19.2.7__react@19.2.7 → react-medium-image-zoom@5.4.8_react-dom@19.2.8_react@19.2.8__react@19.2.8}/node_modules/react-medium-image-zoom/dist/utils/get-scale.js +1 -1
- package/dist/node_modules/.pnpm/{react-medium-image-zoom@5.4.8_react-dom@19.2.7_react@19.2.7__react@19.2.7 → react-medium-image-zoom@5.4.8_react-dom@19.2.8_react@19.2.8__react@19.2.8}/node_modules/react-medium-image-zoom/dist/utils/get-style-ghost.js +1 -1
- package/dist/node_modules/.pnpm/{react-medium-image-zoom@5.4.8_react-dom@19.2.7_react@19.2.7__react@19.2.7 → react-medium-image-zoom@5.4.8_react-dom@19.2.8_react@19.2.8__react@19.2.8}/node_modules/react-medium-image-zoom/dist/utils/get-style-modal-img.js +1 -1
- package/dist/node_modules/.pnpm/{react-medium-image-zoom@5.4.8_react-dom@19.2.7_react@19.2.7__react@19.2.7 → react-medium-image-zoom@5.4.8_react-dom@19.2.8_react@19.2.8__react@19.2.8}/node_modules/react-medium-image-zoom/dist/utils/get-target-dimension.js +1 -1
- package/dist/node_modules/.pnpm/{react-medium-image-zoom@5.4.8_react-dom@19.2.7_react@19.2.7__react@19.2.7 → react-medium-image-zoom@5.4.8_react-dom@19.2.8_react@19.2.8__react@19.2.8}/node_modules/react-medium-image-zoom/dist/utils/parse-position.js +1 -1
- package/dist/node_modules/.pnpm/{react-medium-image-zoom@5.4.8_react-dom@19.2.7_react@19.2.7__react@19.2.7 → react-medium-image-zoom@5.4.8_react-dom@19.2.8_react@19.2.8__react@19.2.8}/node_modules/react-medium-image-zoom/dist/utils/test-has-scalable-src.js +1 -1
- package/dist/style.css +985 -885
- package/package.json +18 -11
- /package/dist/node_modules/.pnpm/{react-medium-image-zoom@5.4.8_react-dom@19.2.7_react@19.2.7__react@19.2.7 → react-medium-image-zoom@5.4.8_react-dom@19.2.8_react@19.2.8__react@19.2.8}/node_modules/react-medium-image-zoom/dist/index.d.ts +0 -0
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { cn } from "../../../utils/cn.js";
|
|
3
|
+
import { buttonVariants } from "../../../components/ui/button.js";
|
|
4
|
+
import { LayoutTabsDropdown } from "../layout-tabs.js";
|
|
5
|
+
import { useGlassLayout } from "../index.js";
|
|
6
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
7
|
+
import { ChevronsUpDown, LanguagesIcon, MessageCircleIcon, SidebarIcon } from "lucide-react";
|
|
8
|
+
import { useTranslations } from "@fuma-translate/react";
|
|
9
|
+
import { Drawer } from "@base-ui/react/drawer";
|
|
10
|
+
//#region src/layouts/glass/slots/header.tsx
|
|
11
|
+
const baseVariants = "rounded-full bg-fd-popover/80 text-fd-popover-foreground border backdrop-blur-sm shadow-sm";
|
|
12
|
+
function Header({ className, ...props }) {
|
|
13
|
+
const { props: { tabs, aiChat }, slots } = useGlassLayout();
|
|
14
|
+
const t = useTranslations();
|
|
15
|
+
const sidebar = slots.sidebar.use();
|
|
16
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
17
|
+
className: cn("sticky flex flex-row justify-end gap-2 [grid-area:left-margin/left-margin/right/right] z-20 px-4 md:top-0 md:pt-2 md:px-2 md:h-12 md:bg-linear-to-b md:from-fd-background max-md:bottom-0 max-md:mt-auto max-md:h-16 max-md:pb-4 max-md:bg-linear-to-t max-md:from-fd-background", className),
|
|
18
|
+
...props,
|
|
19
|
+
children: [
|
|
20
|
+
sidebar.collapsible && sidebar.collapsed && /* @__PURE__ */ jsx("button", {
|
|
21
|
+
"aria-label": t("Show Sidebar", { note: "sidebar" }),
|
|
22
|
+
className: cn(buttonVariants({
|
|
23
|
+
size: "icon-sm",
|
|
24
|
+
variant: "secondary"
|
|
25
|
+
}), baseVariants, "size-10 me-auto shrink-0 max-md:hidden"),
|
|
26
|
+
onClick: () => sidebar.setCollapsed(false),
|
|
27
|
+
children: /* @__PURE__ */ jsx(SidebarIcon, {})
|
|
28
|
+
}),
|
|
29
|
+
slots.searchTrigger && /* @__PURE__ */ jsx(slots.searchTrigger.sm, {
|
|
30
|
+
color: "secondary",
|
|
31
|
+
size: "icon",
|
|
32
|
+
className: cn(baseVariants, "size-12 shrink-0 md:hidden")
|
|
33
|
+
}),
|
|
34
|
+
tabs.length > 0 && /* @__PURE__ */ jsx(LayoutTabsDropdown, {
|
|
35
|
+
tabs,
|
|
36
|
+
size: "lg",
|
|
37
|
+
className: cn(baseVariants, "min-w-0 ps-4 pe-3 flex-1 [&_svg]:size-5 md:hidden")
|
|
38
|
+
}),
|
|
39
|
+
slots.searchTrigger && /* @__PURE__ */ jsx("div", {
|
|
40
|
+
className: "@container flex justify-end flex-1 max-md:hidden",
|
|
41
|
+
children: /* @__PURE__ */ jsx(slots.searchTrigger.full, { className: cn(baseVariants, "text-fd-muted-foreground ps-3 w-full @sm:max-w-[200px]") })
|
|
42
|
+
}),
|
|
43
|
+
aiChat && !aiChat.open && /* @__PURE__ */ jsxs("button", {
|
|
44
|
+
className: cn(buttonVariants({ variant: "secondary" }), baseVariants, "px-3 gap-2 text-fd-muted-foreground shrink-0 max-md:hidden"),
|
|
45
|
+
onClick: () => aiChat.onOpenChange(true),
|
|
46
|
+
children: [/* @__PURE__ */ jsx(MessageCircleIcon, { className: "size-4" }), t("Ask AI", { note: "AI chat button" })]
|
|
47
|
+
}),
|
|
48
|
+
slots.languageSelect && /* @__PURE__ */ jsxs(slots.languageSelect.root, {
|
|
49
|
+
className: cn(baseVariants, "px-3 rounded-full max-md:hidden"),
|
|
50
|
+
children: [
|
|
51
|
+
/* @__PURE__ */ jsx(LanguagesIcon, { className: "size-4 text-fd-muted-foreground shrink-0" }),
|
|
52
|
+
/* @__PURE__ */ jsx(slots.languageSelect.text, {}),
|
|
53
|
+
/* @__PURE__ */ jsx(ChevronsUpDown, { className: "size-3.5 text-fd-muted-foreground shrink-0" })
|
|
54
|
+
]
|
|
55
|
+
}),
|
|
56
|
+
slots.themeSwitch && /* @__PURE__ */ jsx(slots.themeSwitch, { className: cn(baseVariants, "shrink-0 px-1.5 max-md:hidden") }),
|
|
57
|
+
/* @__PURE__ */ jsx(Drawer.Trigger, {
|
|
58
|
+
handle: slots.sidebar.drawerHandle,
|
|
59
|
+
render: (props, { open }) => /* @__PURE__ */ jsx("button", {
|
|
60
|
+
...props,
|
|
61
|
+
className: cn(buttonVariants({
|
|
62
|
+
variant: "secondary",
|
|
63
|
+
size: "icon"
|
|
64
|
+
}), baseVariants, "shrink-0 size-12 md:hidden"),
|
|
65
|
+
"aria-label": open ? t("Close Sidebar", { note: "aria-label" }) : t("Open Sidebar", { note: "aria-label" }),
|
|
66
|
+
children: /* @__PURE__ */ jsx(SidebarIcon, {})
|
|
67
|
+
})
|
|
68
|
+
})
|
|
69
|
+
]
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
//#endregion
|
|
73
|
+
export { Header };
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { ComponentProps, ReactNode } from "react";
|
|
2
|
+
import { Drawer } from "@base-ui/react/drawer";
|
|
3
|
+
//#region src/layouts/glass/slots/sidebar.d.ts
|
|
4
|
+
declare const drawerHandle: Drawer.Handle<unknown>;
|
|
5
|
+
interface SidebarProviderProps {
|
|
6
|
+
/** @default true */
|
|
7
|
+
collapsible?: boolean;
|
|
8
|
+
children: ReactNode;
|
|
9
|
+
}
|
|
10
|
+
declare function SidebarProvider({ children, collapsible }: SidebarProviderProps): import("react").JSX.Element;
|
|
11
|
+
declare function useSidebar(): {
|
|
12
|
+
collapsible: boolean;
|
|
13
|
+
collapsed: boolean;
|
|
14
|
+
setCollapsed: (v: boolean) => void;
|
|
15
|
+
};
|
|
16
|
+
interface SidebarDrawerProps {
|
|
17
|
+
contentProps?: ComponentProps<'div'>;
|
|
18
|
+
}
|
|
19
|
+
declare function SidebarDrawer({ contentProps }: SidebarDrawerProps): import("react").JSX.Element;
|
|
20
|
+
type SidebarProps = ComponentProps<'aside'>;
|
|
21
|
+
declare function Sidebar({ className, children, ...props }: SidebarProps): import("react").JSX.Element;
|
|
22
|
+
//#endregion
|
|
23
|
+
export { Sidebar, SidebarDrawer, SidebarDrawerProps, SidebarProps, SidebarProvider, SidebarProviderProps, drawerHandle, useSidebar };
|
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { cn } from "../../../utils/cn.js";
|
|
3
|
+
import { buttonVariants } from "../../../components/ui/button.js";
|
|
4
|
+
import { useTreeContext, useTreePath } from "../../../contexts/tree.js";
|
|
5
|
+
import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "../../../components/ui/collapsible.js";
|
|
6
|
+
import { isLinkItemActive } from "../../shared/index.js";
|
|
7
|
+
import { ScrollArea, ScrollViewport } from "../../../components/ui/scroll-area.js";
|
|
8
|
+
import { LayoutTabsDropdown } from "../layout-tabs.js";
|
|
9
|
+
import { useGlassLayout } from "../index.js";
|
|
10
|
+
import Link from "fumadocs-core/link";
|
|
11
|
+
import { usePathname } from "fumadocs-core/framework";
|
|
12
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
13
|
+
import { ChevronDown, ChevronsUpDown, LanguagesIcon, MessageCircleIcon, SidebarIcon, XIcon } from "lucide-react";
|
|
14
|
+
import { cva } from "class-variance-authority";
|
|
15
|
+
import { cloneElement, createContext, use, useMemo, useState } from "react";
|
|
16
|
+
import { useTranslations } from "@fuma-translate/react";
|
|
17
|
+
import { useOnChange } from "fumadocs-core/utils/use-on-change";
|
|
18
|
+
import { Drawer } from "@base-ui/react/drawer";
|
|
19
|
+
//#region src/layouts/glass/slots/sidebar.tsx
|
|
20
|
+
const drawerHandle = Drawer.createHandle();
|
|
21
|
+
const itemTriggerVariants = cva("inline-flex items-center gap-2 rounded-lg px-2.5 py-2 md:py-1.5 [&_svg]:size-4 outline-none focus-visible:ring-2 focus-visible:ring-fd-ring", { variants: { active: {
|
|
22
|
+
true: "bg-fd-primary/10 text-fd-primary",
|
|
23
|
+
false: "text-fd-muted-foreground hover:bg-fd-accent hover:text-fd-accent-foreground"
|
|
24
|
+
} } });
|
|
25
|
+
const Context = createContext(null);
|
|
26
|
+
function SidebarProvider({ children, collapsible = true }) {
|
|
27
|
+
const [collapsed, setCollapsed] = useState(false);
|
|
28
|
+
return /* @__PURE__ */ jsx(Context, {
|
|
29
|
+
value: useMemo(() => ({
|
|
30
|
+
collapsible,
|
|
31
|
+
collapsed,
|
|
32
|
+
setCollapsed
|
|
33
|
+
}), [collapsible, collapsed]),
|
|
34
|
+
children
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
function useSidebar() {
|
|
38
|
+
const v = use(Context);
|
|
39
|
+
if (!v) throw new Error("Missing <SidebarProvider />");
|
|
40
|
+
return v;
|
|
41
|
+
}
|
|
42
|
+
function SidebarDrawer({ contentProps }) {
|
|
43
|
+
const { menuItems, props: { aiChat }, slots } = useGlassLayout();
|
|
44
|
+
const { root } = useTreeContext();
|
|
45
|
+
const t = useTranslations();
|
|
46
|
+
return /* @__PURE__ */ jsx(Drawer.Root, {
|
|
47
|
+
handle: drawerHandle,
|
|
48
|
+
swipeDirection: "right",
|
|
49
|
+
children: /* @__PURE__ */ jsxs(Drawer.Portal, {
|
|
50
|
+
className: "z-40",
|
|
51
|
+
children: [/* @__PURE__ */ jsx(Drawer.Backdrop, { className: "[--bleed:3rem] fixed inset-0 min-h-dvh bg-fd-overlay backdrop-blur-sm opacity-[calc(1-var(--drawer-swipe-progress))] transition-opacity duration-450 ease-[cubic-bezier(0.32,0.72,0,1)] data-swiping:duration-0 data-ending-style:opacity-0 data-starting-style:opacity-0 data-ending-style:duration-[calc(var(--drawer-swipe-strength)*400ms)] supports-[-webkit-touch-callout:none]:absolute" }), /* @__PURE__ */ jsx(Drawer.Viewport, {
|
|
52
|
+
className: "[--viewport-padding:0px] supports-[-webkit-touch-callout:none]:[--viewport-padding:0.625rem] fixed inset-0 flex items-stretch justify-end p-(--viewport-padding)",
|
|
53
|
+
children: /* @__PURE__ */ jsx(Drawer.Popup, {
|
|
54
|
+
id: "nd-mobile-sidebar",
|
|
55
|
+
className: cn("relative [--bleed:3rem] supports-[-webkit-touch-callout:none]:[--bleed:0px] w-[360px] h-full max-w-[calc(100vw-3rem+var(--bleed))] pr-(--bleed) -mr-(--bleed) border-l bg-fd-background text-fd-foreground text-[0.9375rem] outline-none shadow-md touch-auto [transform:translateX(var(--drawer-swipe-movement-x))] transition-transform duration-450 ease-[cubic-bezier(0.32,0.72,0,1)] data-swiping:select-none data-ending-style:[transform:translateX(calc(100%-var(--bleed)+var(--viewport-padding)+2px))] data-starting-style:[transform:translateX(calc(100%-var(--bleed)+var(--viewport-padding)+2px))] supports-[-webkit-touch-callout:none]:border supports-[-webkit-touch-callout:none]:rounded-xl", "[scrollbar-width:none] overflow-y-auto"),
|
|
56
|
+
children: /* @__PURE__ */ jsxs(Drawer.Content, {
|
|
57
|
+
...contentProps,
|
|
58
|
+
className: cn("flex flex-col min-h-full px-3", contentProps?.className),
|
|
59
|
+
children: [
|
|
60
|
+
/* @__PURE__ */ jsxs("div", {
|
|
61
|
+
className: "sticky flex flex-col gap-2 top-0 pt-4 pb-2 bg-fd-background shadow-lg shadow-fd-background",
|
|
62
|
+
children: [/* @__PURE__ */ jsxs("div", {
|
|
63
|
+
className: "flex items-center gap-1.5 ps-2.5",
|
|
64
|
+
children: [
|
|
65
|
+
/* @__PURE__ */ jsx(Drawer.Title, { render: /* @__PURE__ */ jsx(slots.navTitle, { className: "flex items-center font-semibold gap-2 flex-1" }) }),
|
|
66
|
+
aiChat && /* @__PURE__ */ jsxs("button", {
|
|
67
|
+
className: cn(buttonVariants({
|
|
68
|
+
variant: "secondary",
|
|
69
|
+
size: "sm"
|
|
70
|
+
}), "rounded-full h-8 gap-1.5"),
|
|
71
|
+
onClick: () => {
|
|
72
|
+
aiChat.onOpenChange(!aiChat.open);
|
|
73
|
+
drawerHandle.close();
|
|
74
|
+
},
|
|
75
|
+
children: [/* @__PURE__ */ jsx(MessageCircleIcon, { className: "size-4 text-fd-muted-foreground" }), t("Ask AI", { note: "AI chat button" })]
|
|
76
|
+
}),
|
|
77
|
+
/* @__PURE__ */ jsx(Drawer.Close, {
|
|
78
|
+
"aria-label": t("Close Sidebar", { note: "aria-label" }),
|
|
79
|
+
className: cn(buttonVariants({
|
|
80
|
+
variant: "secondary",
|
|
81
|
+
size: "icon-sm"
|
|
82
|
+
}), "rounded-full"),
|
|
83
|
+
children: /* @__PURE__ */ jsx(XIcon, {})
|
|
84
|
+
})
|
|
85
|
+
]
|
|
86
|
+
}), slots.languageSelect && /* @__PURE__ */ jsxs(slots.languageSelect.root, {
|
|
87
|
+
variant: "secondary",
|
|
88
|
+
className: "px-2.5 gap-2 rounded-lg",
|
|
89
|
+
children: [
|
|
90
|
+
/* @__PURE__ */ jsx(LanguagesIcon, { className: "size-4 text-fd-muted-foreground shrink-0" }),
|
|
91
|
+
/* @__PURE__ */ jsx(slots.languageSelect.text, {}),
|
|
92
|
+
/* @__PURE__ */ jsx(ChevronsUpDown, { className: "ms-auto size-3.5 text-fd-muted-foreground shrink-0" })
|
|
93
|
+
]
|
|
94
|
+
})]
|
|
95
|
+
}),
|
|
96
|
+
/* @__PURE__ */ jsxs("div", {
|
|
97
|
+
className: "flex flex-col py-2 flex-1",
|
|
98
|
+
children: [menuItems.map((item, i) => item.type !== "icon" && /* @__PURE__ */ jsx(SidebarLinkItem, { item }, i)), root.children.map((item, i) => cloneElement(renderNode(item), { key: i }))]
|
|
99
|
+
}),
|
|
100
|
+
/* @__PURE__ */ jsxs("div", {
|
|
101
|
+
className: "flex items-center sticky bottom-0 bg-fd-background px-1 pt-2 pb-4 border-t mt-2 empty:hidden",
|
|
102
|
+
children: [menuItems.map((item, i) => item.type === "icon" && /* @__PURE__ */ jsx(SidebarIconLinkItem, { item }, i)), slots.themeSwitch && /* @__PURE__ */ jsx(slots.themeSwitch, { className: "p-0 ms-auto" })]
|
|
103
|
+
})
|
|
104
|
+
]
|
|
105
|
+
})
|
|
106
|
+
})
|
|
107
|
+
})]
|
|
108
|
+
})
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
function Sidebar({ className, children, ...props }) {
|
|
112
|
+
const { menuItems, props: { tabs }, slots } = useGlassLayout();
|
|
113
|
+
const { root } = useTreeContext();
|
|
114
|
+
const { collapsible, collapsed, setCollapsed } = useSidebar();
|
|
115
|
+
const t = useTranslations({ note: "sidebar" });
|
|
116
|
+
return /* @__PURE__ */ jsxs("aside", {
|
|
117
|
+
id: "nd-sidebar",
|
|
118
|
+
className: cn("sticky flex flex-col transition-transform [grid-area:left] my-2 ms-2 z-30 top-2 border rounded-2xl bg-fd-popover/80 text-fd-popover-foreground text-sm backdrop-blur-sm shadow-sm h-[calc(100dvh---spacing(4))] max-md:hidden md:layout:[--fd-left-width:280px]", collapsed && "w-[calc(280px---spacing(2))] -translate-x-[280px] md:layout:[--fd-left-width:0px]", className),
|
|
119
|
+
...props,
|
|
120
|
+
children: [
|
|
121
|
+
/* @__PURE__ */ jsxs("div", {
|
|
122
|
+
className: "flex items-start gap-1 pt-4 px-3.5 empty:hidden",
|
|
123
|
+
children: [/* @__PURE__ */ jsx(slots.navTitle, { className: "flex text-sm items-center font-semibold gap-2 me-auto" }), /* @__PURE__ */ jsxs("div", {
|
|
124
|
+
className: "flex -mt-1.5 -me-1.5 empty:hidden",
|
|
125
|
+
children: [menuItems.map((item, i) => item.type === "icon" && /* @__PURE__ */ jsx(SidebarIconLinkItem, { item }, i)), collapsible && /* @__PURE__ */ jsx("button", {
|
|
126
|
+
"aria-label": collapsed ? t("Show Sidebar") : t("Hide Sidebar"),
|
|
127
|
+
className: cn(buttonVariants({
|
|
128
|
+
variant: "ghost",
|
|
129
|
+
size: "icon-sm"
|
|
130
|
+
}), "text-fd-muted-foreground"),
|
|
131
|
+
onClick: () => setCollapsed(!collapsed),
|
|
132
|
+
children: /* @__PURE__ */ jsx(SidebarIcon, {})
|
|
133
|
+
})]
|
|
134
|
+
})]
|
|
135
|
+
}),
|
|
136
|
+
tabs.length > 0 && /* @__PURE__ */ jsx(LayoutTabsDropdown, {
|
|
137
|
+
tabs,
|
|
138
|
+
className: "min-w-0 bg-fd-secondary text-fd-secondary-foreground rounded-xl px-2.5 py-2 [&_svg]:size-4 border rounded-xl shadow-sm mx-2 mt-2.5 empty:hidden"
|
|
139
|
+
}),
|
|
140
|
+
/* @__PURE__ */ jsx(ScrollArea, {
|
|
141
|
+
className: "min-h-0 flex-1",
|
|
142
|
+
children: /* @__PURE__ */ jsxs(ScrollViewport, {
|
|
143
|
+
className: "flex flex-col p-2 [mask-image:linear-gradient(to_bottom,transparent,white_16px,white_calc(100%-16px),transparent))]",
|
|
144
|
+
children: [menuItems.map((item, i) => item.type !== "icon" && /* @__PURE__ */ jsx(SidebarLinkItem, { item }, i)), root.children.map((item, i) => cloneElement(renderNode(item), { key: i }))]
|
|
145
|
+
})
|
|
146
|
+
}),
|
|
147
|
+
children
|
|
148
|
+
]
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
function SidebarIconLinkItem({ item, className }) {
|
|
152
|
+
return /* @__PURE__ */ jsx(Link, {
|
|
153
|
+
href: item.url,
|
|
154
|
+
external: item.external,
|
|
155
|
+
"aria-label": item.label,
|
|
156
|
+
className: cn(buttonVariants({
|
|
157
|
+
variant: "ghost",
|
|
158
|
+
size: "icon-sm"
|
|
159
|
+
}), "text-fd-muted-foreground", className),
|
|
160
|
+
onClick: () => {
|
|
161
|
+
drawerHandle.close();
|
|
162
|
+
},
|
|
163
|
+
children: item.icon
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
function SidebarLinkItem({ item, className }) {
|
|
167
|
+
const pathname = usePathname();
|
|
168
|
+
const [open, setOpen] = useState(true);
|
|
169
|
+
switch (item.type) {
|
|
170
|
+
case "custom": return /* @__PURE__ */ jsx("div", {
|
|
171
|
+
className,
|
|
172
|
+
children: item.children
|
|
173
|
+
});
|
|
174
|
+
case "menu": {
|
|
175
|
+
const rightIcon = /* @__PURE__ */ jsx(ChevronDown, { className: cn("ms-auto text-fd-muted-foreground size-3.5! transition-transform", !open && "-rotate-90") });
|
|
176
|
+
return /* @__PURE__ */ jsxs(Collapsible, {
|
|
177
|
+
open,
|
|
178
|
+
onOpenChange: setOpen,
|
|
179
|
+
className: cn("mt-4 first:mt-0", className),
|
|
180
|
+
children: [item.url ? /* @__PURE__ */ jsxs("div", {
|
|
181
|
+
className: "flex w-full px-2.5 py-1.5 font-medium",
|
|
182
|
+
children: [/* @__PURE__ */ jsxs(Link, {
|
|
183
|
+
href: item.url,
|
|
184
|
+
external: item.external,
|
|
185
|
+
className: cn("inline-flex items-center gap-2 [&_svg]:size-4", isLinkItemActive(item, pathname) ? "text-fd-primary" : "hover:underline hover:decoration-fd-muted-foreground hover:underline-offset-4 hover:decoration-dashed hover:text-fd-accent-foreground"),
|
|
186
|
+
onClick: () => {
|
|
187
|
+
drawerHandle.close();
|
|
188
|
+
},
|
|
189
|
+
children: [item.icon, item.text]
|
|
190
|
+
}), /* @__PURE__ */ jsx(CollapsibleTrigger, {
|
|
191
|
+
className: "flex-1",
|
|
192
|
+
children: rightIcon
|
|
193
|
+
})]
|
|
194
|
+
}) : /* @__PURE__ */ jsxs(CollapsibleTrigger, {
|
|
195
|
+
className: "w-full px-2.5 py-1.5 font-medium inline-flex items-center gap-2 [&_svg]:size-4",
|
|
196
|
+
children: [
|
|
197
|
+
item.icon,
|
|
198
|
+
item.text,
|
|
199
|
+
rightIcon
|
|
200
|
+
]
|
|
201
|
+
}), /* @__PURE__ */ jsx(CollapsibleContent, {
|
|
202
|
+
className: "flex flex-col",
|
|
203
|
+
children: item.items.map((item, i) => /* @__PURE__ */ jsx(SidebarLinkItem, { item }, i))
|
|
204
|
+
})]
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
default: return /* @__PURE__ */ jsxs(Link, {
|
|
208
|
+
href: item.url,
|
|
209
|
+
external: item.external,
|
|
210
|
+
className: cn(itemTriggerVariants({
|
|
211
|
+
active: isLinkItemActive(item, pathname),
|
|
212
|
+
className
|
|
213
|
+
})),
|
|
214
|
+
onClick: () => {
|
|
215
|
+
drawerHandle.close();
|
|
216
|
+
},
|
|
217
|
+
children: [item.icon, item.text]
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
function renderNode(node) {
|
|
222
|
+
if (node.type === "page") return /* @__PURE__ */ jsx(SidebarItem, { item: node });
|
|
223
|
+
if (node.type === "folder") return /* @__PURE__ */ jsx(SidebarFolder, { folder: node });
|
|
224
|
+
return /* @__PURE__ */ jsxs("p", {
|
|
225
|
+
className: "mt-4 w-full px-2.5 py-1.5 font-medium inline-flex items-center gap-2 [&_svg]:size-4 empty:hidden first:mt-0",
|
|
226
|
+
children: [node.icon, node.name]
|
|
227
|
+
});
|
|
228
|
+
}
|
|
229
|
+
function SidebarItem({ item }) {
|
|
230
|
+
const path = useTreePath();
|
|
231
|
+
return /* @__PURE__ */ jsxs(Link, {
|
|
232
|
+
href: item.url,
|
|
233
|
+
external: item.external,
|
|
234
|
+
className: itemTriggerVariants({ active: isNodeInPath(item, path) }),
|
|
235
|
+
onClick: () => {
|
|
236
|
+
drawerHandle.close();
|
|
237
|
+
},
|
|
238
|
+
children: [item.icon, item.name]
|
|
239
|
+
});
|
|
240
|
+
}
|
|
241
|
+
function SidebarFolder({ folder }) {
|
|
242
|
+
const path = useTreePath();
|
|
243
|
+
const shouldOpen = (folder.defaultOpen ?? true) || isNodeInPath(folder, path);
|
|
244
|
+
const [open, setOpen] = useState(shouldOpen);
|
|
245
|
+
useOnChange(shouldOpen, () => shouldOpen && setOpen(true));
|
|
246
|
+
if (folder.collapsible === false) return /* @__PURE__ */ jsxs(Fragment, { children: [folder.index ? /* @__PURE__ */ jsxs(Link, {
|
|
247
|
+
href: folder.index.url,
|
|
248
|
+
external: folder.index.external,
|
|
249
|
+
className: cn("inline-flex px-2.5 py-1.5 font-medium items-center gap-2 [&_svg]:size-4 mt-4 first:mt-0", isNodeInPath(folder.index, path) ? "text-fd-primary" : "hover:underline hover:decoration-fd-muted-foreground hover:underline-offset-4 hover:decoration-dashed hover:text-fd-accent-foreground"),
|
|
250
|
+
onClick: () => {
|
|
251
|
+
drawerHandle.close();
|
|
252
|
+
},
|
|
253
|
+
children: [folder.icon, folder.name]
|
|
254
|
+
}) : /* @__PURE__ */ jsxs("div", {
|
|
255
|
+
className: "w-full px-3 py-1.5 font-medium inline-flex items-center gap-2 [&_svg]:size-4 mt-4 first:mt-0",
|
|
256
|
+
children: [folder.icon, folder.name]
|
|
257
|
+
}), folder.children.map((item, i) => cloneElement(renderNode(item), { key: i }))] });
|
|
258
|
+
const rightIcon = /* @__PURE__ */ jsx(ChevronDown, { className: cn("ms-auto text-fd-muted-foreground size-3.5! transition-transform", !open && "-rotate-90") });
|
|
259
|
+
return /* @__PURE__ */ jsxs(Collapsible, {
|
|
260
|
+
open,
|
|
261
|
+
onOpenChange: setOpen,
|
|
262
|
+
className: "mt-4 first:mt-0",
|
|
263
|
+
children: [folder.index ? /* @__PURE__ */ jsxs("div", {
|
|
264
|
+
className: "flex w-full px-2.5 py-1.5 font-medium",
|
|
265
|
+
children: [/* @__PURE__ */ jsxs(Link, {
|
|
266
|
+
href: folder.index.url,
|
|
267
|
+
external: folder.index.external,
|
|
268
|
+
className: cn("inline-flex items-center gap-2 [&_svg]:size-4", isNodeInPath(folder.index, path) ? "text-fd-primary" : "hover:underline hover:decoration-fd-muted-foreground hover:underline-offset-4 hover:decoration-dashed hover:text-fd-accent-foreground"),
|
|
269
|
+
onClick: () => {
|
|
270
|
+
drawerHandle.close();
|
|
271
|
+
},
|
|
272
|
+
children: [folder.icon, folder.name]
|
|
273
|
+
}), /* @__PURE__ */ jsx(CollapsibleTrigger, {
|
|
274
|
+
className: "flex-1",
|
|
275
|
+
children: rightIcon
|
|
276
|
+
})]
|
|
277
|
+
}) : /* @__PURE__ */ jsxs(CollapsibleTrigger, {
|
|
278
|
+
className: "w-full px-2.5 py-1.5 font-medium inline-flex items-center gap-2 [&_svg]:size-4",
|
|
279
|
+
children: [
|
|
280
|
+
folder.icon,
|
|
281
|
+
folder.name,
|
|
282
|
+
rightIcon
|
|
283
|
+
]
|
|
284
|
+
}), /* @__PURE__ */ jsx(CollapsibleContent, {
|
|
285
|
+
className: "flex flex-col",
|
|
286
|
+
children: folder.children.map((item, i) => cloneElement(renderNode(item), { key: i }))
|
|
287
|
+
})]
|
|
288
|
+
});
|
|
289
|
+
}
|
|
290
|
+
function isNodeInPath(node, path) {
|
|
291
|
+
return path.some((other) => other.$id === node.$id || other === node);
|
|
292
|
+
}
|
|
293
|
+
//#endregion
|
|
294
|
+
export { Sidebar, SidebarDrawer, SidebarProvider, drawerHandle, useSidebar };
|
|
@@ -12,12 +12,12 @@ function useHomeLayout() {
|
|
|
12
12
|
if (!context) throw new Error("Please use this component under <HomeLayout /> (`fumadocs-ui/layouts/home`).");
|
|
13
13
|
return context;
|
|
14
14
|
}
|
|
15
|
-
const {
|
|
15
|
+
const { useBaseSlots } = baseSlots({ useProps() {
|
|
16
16
|
return useHomeLayout().props;
|
|
17
17
|
} });
|
|
18
18
|
function HomeLayout(props) {
|
|
19
19
|
const { nav: { enabled: navEnabled = true } = {}, slots: defaultSlots, children, i18n: _i18n, githubUrl: _githubUrl, links: _links, themeSwitch: _themeSwitch, searchToggle: _searchToggle, ...rest } = props;
|
|
20
|
-
const { baseSlots, baseProps } =
|
|
20
|
+
const { baseSlots, baseProps } = useBaseSlots(props);
|
|
21
21
|
const linkItems = useLinkItems(props);
|
|
22
22
|
const slots = {
|
|
23
23
|
...baseSlots,
|
|
@@ -52,6 +52,7 @@ function Header(props) {
|
|
|
52
52
|
}, []);
|
|
53
53
|
const list = /* @__PURE__ */ jsxs(NavigationMenu.List, {
|
|
54
54
|
ref: listRef,
|
|
55
|
+
render: /* @__PURE__ */ jsx("div", {}),
|
|
55
56
|
className: "flex h-14 w-full mx-auto max-w-(--fd-layout-width) items-center px-4",
|
|
56
57
|
children: [
|
|
57
58
|
slots.navTitle && /* @__PURE__ */ jsx(slots.navTitle, { className: "inline-flex items-center gap-2.5 font-semibold" }),
|
|
@@ -9,7 +9,7 @@ import { Header } from "./slots/header.js";
|
|
|
9
9
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
10
10
|
import { createContext, use } from "react";
|
|
11
11
|
//#region src/layouts/notebook/client.tsx
|
|
12
|
-
const {
|
|
12
|
+
const { useBaseSlots } = baseSlots({ useProps() {
|
|
13
13
|
return useNotebookLayout().props;
|
|
14
14
|
} });
|
|
15
15
|
const LayoutContext = createContext(null);
|
|
@@ -22,7 +22,7 @@ function LayoutBody(props) {
|
|
|
22
22
|
const { nav: { enabled: navEnabled = true, transparentMode: navTransparentMode = "none" } = {}, sidebar: { defaultOpenLevel, prefetch, ...sidebarProps } = {}, slots: defaultSlots, tabMode = "sidebar", tabs, tree, containerProps, children } = props;
|
|
23
23
|
const isTop = useIsScrollTop({ enabled: navTransparentMode === "top" }) ?? true;
|
|
24
24
|
const isNavTransparent = navTransparentMode === "top" ? isTop : navTransparentMode === "always";
|
|
25
|
-
const { baseSlots, baseProps } =
|
|
25
|
+
const { baseSlots, baseProps } = useBaseSlots(props);
|
|
26
26
|
const linkItems = useLinkItems(props);
|
|
27
27
|
const slots = {
|
|
28
28
|
...baseSlots,
|
|
@@ -33,10 +33,13 @@ function TOC({ container, header, footer, style = "normal", list }) {
|
|
|
33
33
|
className: "inline-flex items-center gap-1.5 text-sm text-fd-muted-foreground",
|
|
34
34
|
children: [/* @__PURE__ */ jsx(Text, { className: "size-4" }), t("On this page")]
|
|
35
35
|
}),
|
|
36
|
-
/* @__PURE__ */ jsx(TOCScrollArea, {
|
|
37
|
-
|
|
38
|
-
children:
|
|
39
|
-
|
|
36
|
+
/* @__PURE__ */ jsx(TOCScrollArea, {
|
|
37
|
+
className: "ms-px",
|
|
38
|
+
children: /* @__PURE__ */ jsxs(TOCItems, {
|
|
39
|
+
...list,
|
|
40
|
+
children: [items.length === 0 && /* @__PURE__ */ jsx(TOCEmpty, {}), items.map((item) => /* @__PURE__ */ jsx(TOCItem, { item }, item.url))]
|
|
41
|
+
})
|
|
42
|
+
}),
|
|
40
43
|
footer
|
|
41
44
|
]
|
|
42
45
|
});
|
|
@@ -79,13 +82,16 @@ function TOCPopover({ container, trigger, content, header, footer, style = "norm
|
|
|
79
82
|
...content,
|
|
80
83
|
children: [
|
|
81
84
|
header,
|
|
82
|
-
/* @__PURE__ */ jsx(TOCScrollArea, {
|
|
83
|
-
|
|
84
|
-
children:
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
85
|
+
/* @__PURE__ */ jsx(TOCScrollArea, {
|
|
86
|
+
className: "ms-px",
|
|
87
|
+
children: /* @__PURE__ */ jsxs(TOCItems, {
|
|
88
|
+
...list,
|
|
89
|
+
children: [items.length === 0 && /* @__PURE__ */ jsx(TOCEmpty, {}), items.map((item) => /* @__PURE__ */ jsx(TOCItem, {
|
|
90
|
+
item,
|
|
91
|
+
onClick: onClickItem
|
|
92
|
+
}, item.url))]
|
|
93
|
+
})
|
|
94
|
+
}),
|
|
89
95
|
footer
|
|
90
96
|
]
|
|
91
97
|
})]
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { cn } from "../../../utils/cn.js";
|
|
3
3
|
import { buttonVariants } from "../../../components/ui/button.js";
|
|
4
|
+
import { useTreePath } from "../../../contexts/tree.js";
|
|
4
5
|
import { Popover, PopoverContent, PopoverTrigger } from "../../../components/ui/popover.js";
|
|
5
6
|
import { LinkItem } from "../../shared/client.js";
|
|
6
7
|
import { isLayoutTabActive } from "../../shared/index.js";
|
|
@@ -101,9 +102,14 @@ function Header(props) {
|
|
|
101
102
|
}
|
|
102
103
|
function LayoutHeaderTabs({ tabs, className, ...props }) {
|
|
103
104
|
const pathname = usePathname();
|
|
105
|
+
const path = useTreePath();
|
|
104
106
|
const selectedIdx = useMemo(() => {
|
|
105
|
-
return tabs.findLastIndex((option) => isLayoutTabActive(option, pathname));
|
|
106
|
-
}, [
|
|
107
|
+
return tabs.findLastIndex((option) => isLayoutTabActive(option, path, pathname));
|
|
108
|
+
}, [
|
|
109
|
+
tabs,
|
|
110
|
+
path,
|
|
111
|
+
pathname
|
|
112
|
+
]);
|
|
107
113
|
return /* @__PURE__ */ jsx("div", {
|
|
108
114
|
className: cn("flex flex-row items-end gap-6", className),
|
|
109
115
|
...props,
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import { cn } from "../../../utils/cn.js";
|
|
3
3
|
import { buttonVariants } from "../../../components/ui/button.js";
|
|
4
4
|
import { mergeRefs } from "../../../utils/merge-refs.js";
|
|
5
|
+
import { useTreePath } from "../../../contexts/tree.js";
|
|
5
6
|
import { Popover, PopoverContent, PopoverTrigger } from "../../../components/ui/popover.js";
|
|
6
7
|
import { LinkItem } from "../../shared/client.js";
|
|
7
8
|
import { isLayoutTabActive } from "../../shared/index.js";
|
|
@@ -242,9 +243,14 @@ function SidebarTabsDropdown({ options, placeholder, ...props }) {
|
|
|
242
243
|
const [open, setOpen] = useState(false);
|
|
243
244
|
const { closeOnRedirect } = useSidebar();
|
|
244
245
|
const pathname = usePathname();
|
|
246
|
+
const path = useTreePath();
|
|
245
247
|
const selected = useMemo(() => {
|
|
246
|
-
return options.findLast((item) => isLayoutTabActive(item, pathname));
|
|
247
|
-
}, [
|
|
248
|
+
return options.findLast((item) => isLayoutTabActive(item, path, pathname));
|
|
249
|
+
}, [
|
|
250
|
+
options,
|
|
251
|
+
path,
|
|
252
|
+
pathname
|
|
253
|
+
]);
|
|
248
254
|
const onClick = () => {
|
|
249
255
|
closeOnRedirect.current = false;
|
|
250
256
|
setOpen(false);
|
|
@@ -28,7 +28,7 @@ interface BaseSlotsProps<P extends BaseLayoutProps = BaseLayoutProps> extends Pi
|
|
|
28
28
|
declare function baseSlots({ useProps }: {
|
|
29
29
|
useProps: () => BaseSlotsProps;
|
|
30
30
|
}): {
|
|
31
|
-
|
|
31
|
+
useBaseSlots(options: BaseLayoutProps): {
|
|
32
32
|
baseSlots: BaseSlots;
|
|
33
33
|
baseProps: BaseSlotsProps;
|
|
34
34
|
};
|
|
@@ -56,7 +56,7 @@ function baseSlots({ useProps }) {
|
|
|
56
56
|
children: title
|
|
57
57
|
});
|
|
58
58
|
}
|
|
59
|
-
return {
|
|
59
|
+
return { useBaseSlots(options) {
|
|
60
60
|
const { locales = [] } = useI18n();
|
|
61
61
|
const { nav, slots = {}, i18n = locales.length > 1, searchToggle: { enabled: searchToggleEnabled = true, ...searchToggle } = {}, themeSwitch: { enabled: themeSwitchEnabled = true, ...themeSwitch } = {} } = options;
|
|
62
62
|
return {
|
|
@@ -2,8 +2,8 @@ import { FullSearchTriggerProps, SearchTriggerProps } from "./slots/search-trigg
|
|
|
2
2
|
import { ThemeSwitchProps } from "./slots/theme-switch.js";
|
|
3
3
|
import { BaseSlots, BaseSlotsProps, LinkItem, baseSlots } from "./client.js";
|
|
4
4
|
import { ComponentProps, FC, ReactNode } from "react";
|
|
5
|
-
import * as PageTree from "fumadocs-core/page-tree";
|
|
6
5
|
import { I18nConfig } from "fumadocs-core/i18n";
|
|
6
|
+
import * as PageTree from "fumadocs-core/page-tree";
|
|
7
7
|
//#region src/layouts/shared/index.d.ts
|
|
8
8
|
interface NavOptions {
|
|
9
9
|
enabled?: boolean;
|
|
@@ -82,7 +82,7 @@ interface GetLayoutTabsOptions {
|
|
|
82
82
|
transform?: (option: LayoutTab, node: PageTree.Folder) => LayoutTab | null;
|
|
83
83
|
}
|
|
84
84
|
declare function getLayoutTabs(tree: PageTree.Root, { transform }?: GetLayoutTabsOptions): LayoutTab[];
|
|
85
|
-
declare function isLayoutTabActive(tab: LayoutTab, pathname: string): boolean;
|
|
85
|
+
declare function isLayoutTabActive(tab: LayoutTab, path: PageTree.Node[], pathname: string): boolean;
|
|
86
86
|
interface Filterable {
|
|
87
87
|
/**
|
|
88
88
|
* Restrict where the item is displayed
|
|
@@ -159,11 +159,12 @@ type LinkItemType = MainItemType | IconItemType | ButtonItemType | MenuItemType
|
|
|
159
159
|
* Get link items with shortcuts
|
|
160
160
|
*/
|
|
161
161
|
declare function resolveLinkItems({ links, githubUrl }: Pick<BaseLayoutProps, 'links' | 'githubUrl'>): LinkItemType[];
|
|
162
|
-
|
|
162
|
+
interface GroupedLinkItems {
|
|
163
|
+
all: LinkItemType[];
|
|
163
164
|
navItems: LinkItemType[];
|
|
164
165
|
menuItems: LinkItemType[];
|
|
165
|
-
|
|
166
|
-
};
|
|
166
|
+
}
|
|
167
|
+
declare function useLinkItems({ githubUrl, links }: Pick<BaseLayoutProps, 'links' | 'githubUrl'>): GroupedLinkItems;
|
|
167
168
|
declare function isLinkItemActive(link: LinkItemType, pathname: string): boolean;
|
|
168
169
|
//#endregion
|
|
169
|
-
export { BaseLayoutProps, type BaseSlots, type BaseSlotsProps, ButtonItemType, CustomItemType, GetLayoutTabsOptions, IconItemType, LayoutTab, LinkItem, LinkItemType, MainItemType, MenuItemType, NavOptions, baseSlots, getLayoutTabs, isLayoutTabActive, isLinkItemActive, resolveLinkItems, useLinkItems };
|
|
170
|
+
export { BaseLayoutProps, type BaseSlots, type BaseSlotsProps, ButtonItemType, CustomItemType, GetLayoutTabsOptions, GroupedLinkItems, IconItemType, LayoutTab, LinkItem, LinkItemType, MainItemType, MenuItemType, NavOptions, baseSlots, getLayoutTabs, isLayoutTabActive, isLinkItemActive, resolveLinkItems, useLinkItems };
|
|
@@ -2,7 +2,6 @@ import { isActive, normalize } from "../../utils/urls.js";
|
|
|
2
2
|
import { LinkItem, baseSlots } from "./client.js";
|
|
3
3
|
import { jsx } from "react/jsx-runtime";
|
|
4
4
|
import { useMemo } from "react";
|
|
5
|
-
import * as PageTree from "fumadocs-core/page-tree";
|
|
6
5
|
//#region src/layouts/shared/index.tsx
|
|
7
6
|
const defaultTransform = (option, node) => {
|
|
8
7
|
if (!node.icon) return option;
|
|
@@ -38,8 +37,11 @@ function getLayoutTabs(tree, { transform = defaultTransform } = {}) {
|
|
|
38
37
|
if (tree.fallback) next(tree.fallback, true);
|
|
39
38
|
return results;
|
|
40
39
|
}
|
|
41
|
-
function isLayoutTabActive(tab, pathname) {
|
|
42
|
-
if (tab.$folder)
|
|
40
|
+
function isLayoutTabActive(tab, path, pathname) {
|
|
41
|
+
if (tab.$folder) {
|
|
42
|
+
const folder = tab.$folder;
|
|
43
|
+
return path.some((node) => node.type === "folder" && (node.$id === folder.$id || node === folder));
|
|
44
|
+
}
|
|
43
45
|
if (tab.urls) return tab.urls.has(normalize(pathname));
|
|
44
46
|
return isActive(tab.url, pathname, true);
|
|
45
47
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
-
//#region ../../node_modules/.pnpm/react-medium-image-zoom@5.4.8_react-dom@19.2.
|
|
2
|
+
//#region ../../node_modules/.pnpm/react-medium-image-zoom@5.4.8_react-dom@19.2.8_react@19.2.8__react@19.2.8/node_modules/react-medium-image-zoom/dist/controlled.d.ts
|
|
3
3
|
type ModalState = 'LOADED' | 'LOADING' | 'UNLOADED' | 'UNLOADING';
|
|
4
4
|
interface ControlledProps {
|
|
5
5
|
a11yNameButtonUnzoom?: string;
|
|
@@ -6,7 +6,7 @@ import { getStyleGhost } from "./utils/get-style-ghost.js";
|
|
|
6
6
|
import { getStyleModalImg } from "./utils/get-style-modal-img.js";
|
|
7
7
|
import React from "react";
|
|
8
8
|
import ReactDOM from "react-dom";
|
|
9
|
-
//#region ../../node_modules/.pnpm/react-medium-image-zoom@5.4.8_react-dom@19.2.
|
|
9
|
+
//#region ../../node_modules/.pnpm/react-medium-image-zoom@5.4.8_react-dom@19.2.8_react@19.2.8__react@19.2.8/node_modules/react-medium-image-zoom/dist/controlled.js
|
|
10
10
|
const IMAGE_QUERY = [
|
|
11
11
|
"img",
|
|
12
12
|
"svg",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ControlledProps } from "./controlled.js";
|
|
2
2
|
import React from "react";
|
|
3
|
-
//#region ../../node_modules/.pnpm/react-medium-image-zoom@5.4.8_react-dom@19.2.
|
|
3
|
+
//#region ../../node_modules/.pnpm/react-medium-image-zoom@5.4.8_react-dom@19.2.8_react@19.2.8__react@19.2.8/node_modules/react-medium-image-zoom/dist/uncontrolled.d.ts
|
|
4
4
|
type UncontrolledProps = Omit<ControlledProps, 'isZoomed'>;
|
|
5
5
|
//#endregion
|
|
6
6
|
export { UncontrolledProps };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Controlled } from "./controlled.js";
|
|
2
2
|
import React from "react";
|
|
3
|
-
//#region ../../node_modules/.pnpm/react-medium-image-zoom@5.4.8_react-dom@19.2.
|
|
3
|
+
//#region ../../node_modules/.pnpm/react-medium-image-zoom@5.4.8_react-dom@19.2.8_react@19.2.8__react@19.2.8/node_modules/react-medium-image-zoom/dist/uncontrolled.js
|
|
4
4
|
function Uncontrolled({ onZoomChange, ...props }) {
|
|
5
5
|
const [isZoomed, setIsZoomed] = React.useState(false);
|
|
6
6
|
const handleZoomChange = React.useCallback((value, { event }) => {
|