@assistant-ui/docs-theme 0.0.2 → 0.0.3
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/README.md +89 -5
- package/dist/config.d.ts +1 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +1 -1
- package/dist/config.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/site/constants.d.ts +2 -0
- package/dist/site/constants.d.ts.map +1 -0
- package/dist/site/constants.js +5 -0
- package/dist/site/constants.js.map +1 -0
- package/dist/site/footer.d.ts +13 -0
- package/dist/site/footer.d.ts.map +1 -0
- package/dist/site/footer.js +35 -0
- package/dist/site/footer.js.map +1 -0
- package/dist/site/header.d.ts +13 -0
- package/dist/site/header.d.ts.map +1 -0
- package/dist/site/header.js +81 -0
- package/dist/site/header.js.map +1 -0
- package/dist/site/layout.d.ts +8 -0
- package/dist/site/layout.d.ts.map +1 -0
- package/dist/site/layout.js +21 -0
- package/dist/site/layout.js.map +1 -0
- package/dist/site/page.d.ts +9 -0
- package/dist/site/page.d.ts.map +1 -0
- package/dist/site/page.js +32 -0
- package/dist/site/page.js.map +1 -0
- package/dist/site/pager.d.ts +13 -0
- package/dist/site/pager.d.ts.map +1 -0
- package/dist/site/pager.js +36 -0
- package/dist/site/pager.js.map +1 -0
- package/dist/site/sidebar-navigation.d.ts +13 -0
- package/dist/site/sidebar-navigation.d.ts.map +1 -0
- package/dist/site/sidebar-navigation.js +185 -0
- package/dist/site/sidebar-navigation.js.map +1 -0
- package/dist/site/sidebar.d.ts +16 -0
- package/dist/site/sidebar.d.ts.map +1 -0
- package/dist/site/sidebar.js +46 -0
- package/dist/site/sidebar.js.map +1 -0
- package/dist/site/toc.d.ts +12 -0
- package/dist/site/toc.d.ts.map +1 -0
- package/dist/site/toc.js +92 -0
- package/dist/site/toc.js.map +1 -0
- package/dist/site/tree.d.ts +24 -0
- package/dist/site/tree.d.ts.map +1 -0
- package/dist/site/tree.js +14 -0
- package/dist/site/tree.js.map +1 -0
- package/dist/site/utils.d.ts +2 -0
- package/dist/site/utils.d.ts.map +1 -0
- package/dist/site/utils.js +5 -0
- package/dist/site/utils.js.map +1 -0
- package/dist/ui.d.ts +10 -0
- package/dist/ui.d.ts.map +1 -0
- package/dist/ui.js +9 -0
- package/package.json +21 -11
- package/src/config.ts +1 -1
- package/src/index.ts +1 -1
- package/src/site/constants.ts +1 -0
- package/src/site/footer.tsx +59 -0
- package/src/site/header.test.tsx +89 -0
- package/src/site/header.tsx +117 -0
- package/src/site/layout.tsx +33 -0
- package/src/site/page.tsx +38 -0
- package/src/site/pager.tsx +54 -0
- package/src/site/sidebar-navigation.test.tsx +92 -0
- package/src/site/sidebar-navigation.tsx +267 -0
- package/src/site/sidebar.tsx +77 -0
- package/src/site/toc.test.tsx +187 -0
- package/src/site/toc.tsx +118 -0
- package/src/site/tree.ts +36 -0
- package/src/site/utils.ts +2 -0
- package/src/ui.ts +19 -0
- package/styles/site.css +223 -0
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { cn } from "./utils.js";
|
|
3
|
+
import { findActivePath } from "./tree.js";
|
|
4
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
5
|
+
import Link from "next/link";
|
|
6
|
+
import { ChevronDown } from "lucide-react";
|
|
7
|
+
import { useEffect, useMemo, useRef, useState } from "react";
|
|
8
|
+
import { AnimatePresence, LazyMotion, domAnimation } from "motion/react";
|
|
9
|
+
import * as m from "motion/react-m";
|
|
10
|
+
// src/site/sidebar-navigation.tsx
|
|
11
|
+
function SectionItem({ item, onNavigate, pathname, activePath, isVisible }) {
|
|
12
|
+
if (!isVisible(item)) return null;
|
|
13
|
+
if (item.type === "separator") return /* @__PURE__ */ jsx("p", {
|
|
14
|
+
className: "text-muted-foreground mt-4 mb-1 px-2 text-xs font-medium first:mt-1",
|
|
15
|
+
children: item.name
|
|
16
|
+
});
|
|
17
|
+
if (item.type === "folder") {
|
|
18
|
+
const isActive = item.index && pathname === item.index.url;
|
|
19
|
+
const containsActive = activePath.has(item);
|
|
20
|
+
const hasChildren = item.children.length > 0;
|
|
21
|
+
return /* @__PURE__ */ jsxs("div", { children: [item.index ? /* @__PURE__ */ jsxs(Link, {
|
|
22
|
+
href: item.index.url,
|
|
23
|
+
onClick: onNavigate,
|
|
24
|
+
"data-active": isActive ? "true" : "false",
|
|
25
|
+
className: cn("flex items-center gap-2 rounded-md px-2 py-1.5 text-[13px] transition-colors duration-150", isActive ? "bg-accent/20 text-foreground dark:bg-accent/50 font-medium" : "text-muted-foreground hover:bg-accent/30 hover:text-foreground/90 dark:hover:bg-accent/40"),
|
|
26
|
+
children: [item.icon, /* @__PURE__ */ jsx("span", {
|
|
27
|
+
className: "truncate",
|
|
28
|
+
children: item.name
|
|
29
|
+
})]
|
|
30
|
+
}) : /* @__PURE__ */ jsxs("p", {
|
|
31
|
+
className: "text-muted-foreground mt-3 mb-1 flex items-center gap-2 px-2 text-xs font-medium first:mt-1",
|
|
32
|
+
children: [item.icon, item.name]
|
|
33
|
+
}), hasChildren && (containsActive || !item.index) && /* @__PURE__ */ jsx("div", {
|
|
34
|
+
className: "border-border/50 ml-2 flex flex-col gap-0.5 border-l pl-2",
|
|
35
|
+
children: item.children.map((child) => /* @__PURE__ */ jsx(SectionItem, {
|
|
36
|
+
item: child,
|
|
37
|
+
onNavigate,
|
|
38
|
+
pathname,
|
|
39
|
+
activePath,
|
|
40
|
+
isVisible
|
|
41
|
+
}, child.$id))
|
|
42
|
+
})] });
|
|
43
|
+
}
|
|
44
|
+
const isActive = pathname === item.url;
|
|
45
|
+
return /* @__PURE__ */ jsxs(Link, {
|
|
46
|
+
href: item.url,
|
|
47
|
+
onClick: onNavigate,
|
|
48
|
+
"data-active": isActive ? "true" : "false",
|
|
49
|
+
className: cn("flex items-center gap-2 rounded-md px-2 py-1.5 text-[13px] transition-colors duration-150", isActive ? "bg-accent/20 text-foreground dark:bg-accent/50 font-medium" : "text-muted-foreground hover:bg-accent/30 hover:text-foreground/90 dark:hover:bg-accent/40"),
|
|
50
|
+
children: [item.icon, /* @__PURE__ */ jsx("span", {
|
|
51
|
+
className: "truncate",
|
|
52
|
+
children: item.name
|
|
53
|
+
})]
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
function SidebarSection({ folder, isOpen, onToggle, onNavigate, pathname, activePath, isVisible }) {
|
|
57
|
+
const isActive = folder.index && pathname === folder.index.url;
|
|
58
|
+
return /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsxs("button", {
|
|
59
|
+
type: "button",
|
|
60
|
+
onClick: onToggle,
|
|
61
|
+
"aria-expanded": isOpen,
|
|
62
|
+
className: cn("hover:bg-accent/30 dark:hover:bg-accent/40 flex w-full items-center gap-2 rounded-md px-2 py-2 text-left text-[13px] transition-colors duration-150", isActive || isOpen ? "text-foreground font-medium" : "text-muted-foreground/90"),
|
|
63
|
+
children: [
|
|
64
|
+
/* @__PURE__ */ jsx("span", {
|
|
65
|
+
className: "text-muted-foreground flex size-4 shrink-0 items-center justify-center",
|
|
66
|
+
children: folder.icon
|
|
67
|
+
}),
|
|
68
|
+
/* @__PURE__ */ jsx("span", {
|
|
69
|
+
className: "flex-1 truncate",
|
|
70
|
+
children: folder.name
|
|
71
|
+
}),
|
|
72
|
+
/* @__PURE__ */ jsx(ChevronDown, { className: cn("text-muted-foreground/60 size-3.5 shrink-0 transition-transform duration-200", !isOpen && "-rotate-90") })
|
|
73
|
+
]
|
|
74
|
+
}), /* @__PURE__ */ jsx(AnimatePresence, {
|
|
75
|
+
initial: false,
|
|
76
|
+
children: isOpen && /* @__PURE__ */ jsx(m.div, {
|
|
77
|
+
initial: {
|
|
78
|
+
height: 0,
|
|
79
|
+
opacity: 0
|
|
80
|
+
},
|
|
81
|
+
animate: {
|
|
82
|
+
height: "auto",
|
|
83
|
+
opacity: 1
|
|
84
|
+
},
|
|
85
|
+
exit: {
|
|
86
|
+
height: 0,
|
|
87
|
+
opacity: 0
|
|
88
|
+
},
|
|
89
|
+
transition: {
|
|
90
|
+
duration: .22,
|
|
91
|
+
ease: [
|
|
92
|
+
.16,
|
|
93
|
+
1,
|
|
94
|
+
.3,
|
|
95
|
+
1
|
|
96
|
+
]
|
|
97
|
+
},
|
|
98
|
+
className: "overflow-hidden",
|
|
99
|
+
children: /* @__PURE__ */ jsx("div", {
|
|
100
|
+
className: "border-border/50 mt-0.5 mb-1 ml-4 flex flex-col gap-0.5 border-l pl-2",
|
|
101
|
+
children: folder.children.map((child) => /* @__PURE__ */ jsx(SectionItem, {
|
|
102
|
+
item: child,
|
|
103
|
+
onNavigate,
|
|
104
|
+
pathname,
|
|
105
|
+
activePath,
|
|
106
|
+
isVisible
|
|
107
|
+
}, child.$id))
|
|
108
|
+
})
|
|
109
|
+
})
|
|
110
|
+
})] });
|
|
111
|
+
}
|
|
112
|
+
const visible = () => true;
|
|
113
|
+
function DocsSidebarNavigation({ sections, pathname, activeSectionId, isVisible = visible, onNavigate, banner, footer, platform }) {
|
|
114
|
+
const navRef = useRef(null);
|
|
115
|
+
const activePath = useMemo(() => new Set(findActivePath(sections, pathname)), [sections, pathname]);
|
|
116
|
+
const [openSectionId, setOpenSectionId] = useState(activeSectionId);
|
|
117
|
+
const [sectionScope, setSectionScope] = useState({
|
|
118
|
+
activeSectionId,
|
|
119
|
+
pathname
|
|
120
|
+
});
|
|
121
|
+
if (sectionScope.activeSectionId !== activeSectionId || sectionScope.pathname !== pathname) {
|
|
122
|
+
setSectionScope({
|
|
123
|
+
activeSectionId,
|
|
124
|
+
pathname
|
|
125
|
+
});
|
|
126
|
+
if (activeSectionId) setOpenSectionId(activeSectionId);
|
|
127
|
+
}
|
|
128
|
+
useEffect(() => {
|
|
129
|
+
if (openSectionId !== activeSectionId) return;
|
|
130
|
+
const timer = setTimeout(() => {
|
|
131
|
+
const nav = navRef.current;
|
|
132
|
+
if (!nav) return;
|
|
133
|
+
const active = nav.querySelector("[data-active='true']");
|
|
134
|
+
if (!active) return;
|
|
135
|
+
const navRect = nav.getBoundingClientRect();
|
|
136
|
+
const elRect = active.getBoundingClientRect();
|
|
137
|
+
if (elRect.top < navRect.top || elRect.bottom > navRect.bottom) active.scrollIntoView({
|
|
138
|
+
block: "center",
|
|
139
|
+
behavior: "smooth"
|
|
140
|
+
});
|
|
141
|
+
}, 260);
|
|
142
|
+
return () => clearTimeout(timer);
|
|
143
|
+
}, [
|
|
144
|
+
pathname,
|
|
145
|
+
openSectionId,
|
|
146
|
+
activeSectionId
|
|
147
|
+
]);
|
|
148
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
149
|
+
className: "flex h-full flex-col",
|
|
150
|
+
children: [
|
|
151
|
+
banner && /* @__PURE__ */ jsx("div", {
|
|
152
|
+
className: "shrink-0 px-3 pt-4 lg:hidden",
|
|
153
|
+
children: banner
|
|
154
|
+
}),
|
|
155
|
+
/* @__PURE__ */ jsx("nav", {
|
|
156
|
+
"aria-label": "Docs",
|
|
157
|
+
ref: navRef,
|
|
158
|
+
"data-docs-platform": platform,
|
|
159
|
+
className: cn("sidebar-tree-content flex min-h-0 flex-1 flex-col gap-0.5 overflow-x-hidden overflow-y-auto px-3 pt-2 pb-4 lg:pt-4"),
|
|
160
|
+
children: /* @__PURE__ */ jsx(LazyMotion, {
|
|
161
|
+
features: domAnimation,
|
|
162
|
+
children: sections.map((section) => /* @__PURE__ */ jsx(SidebarSection, {
|
|
163
|
+
folder: section,
|
|
164
|
+
isOpen: openSectionId === section.$id,
|
|
165
|
+
onToggle: () => {
|
|
166
|
+
const id = section.$id ?? null;
|
|
167
|
+
setOpenSectionId(openSectionId !== id ? id : null);
|
|
168
|
+
},
|
|
169
|
+
onNavigate,
|
|
170
|
+
pathname,
|
|
171
|
+
activePath,
|
|
172
|
+
isVisible
|
|
173
|
+
}, section.$id))
|
|
174
|
+
})
|
|
175
|
+
}),
|
|
176
|
+
footer && /* @__PURE__ */ jsx("div", {
|
|
177
|
+
className: "border-border/50 flex shrink-0 items-center gap-1 border-t px-3 py-2",
|
|
178
|
+
children: footer
|
|
179
|
+
})
|
|
180
|
+
]
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
export { DocsSidebarNavigation };
|
|
184
|
+
|
|
185
|
+
//# sourceMappingURL=sidebar-navigation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sidebar-navigation.js","names":[],"sources":["../../src/site/sidebar-navigation.tsx"],"sourcesContent":["\"use client\";\n\nimport { useEffect, useMemo, useRef, useState, type ReactNode } from \"react\";\nimport Link from \"next/link\";\nimport type { DocsNode, DocsFolder } from \"./tree\";\nimport { findActivePath } from \"./tree\";\nimport { ChevronDown } from \"lucide-react\";\nimport { AnimatePresence, domAnimation, LazyMotion } from \"motion/react\";\nimport * as m from \"motion/react-m\";\nimport { cn } from \"./utils\";\n\nfunction SectionItem({\n item,\n onNavigate,\n pathname,\n activePath,\n isVisible,\n}: {\n item: DocsNode;\n onNavigate: () => void;\n pathname: string;\n activePath: ReadonlySet<DocsNode>;\n isVisible: (node: DocsNode) => boolean;\n}) {\n if (!isVisible(item)) return null;\n\n if (item.type === \"separator\") {\n return (\n <p className=\"text-muted-foreground mt-4 mb-1 px-2 text-xs font-medium first:mt-1\">\n {item.name}\n </p>\n );\n }\n\n if (item.type === \"folder\") {\n const isActive = item.index && pathname === item.index.url;\n const containsActive = activePath.has(item);\n const hasChildren = item.children.length > 0;\n\n return (\n <div>\n {item.index ? (\n <Link\n href={item.index.url}\n onClick={onNavigate}\n data-active={isActive ? \"true\" : \"false\"}\n className={cn(\n \"flex items-center gap-2 rounded-md px-2 py-1.5 text-[13px] transition-colors duration-150\",\n isActive\n ? \"bg-accent/20 text-foreground dark:bg-accent/50 font-medium\"\n : \"text-muted-foreground hover:bg-accent/30 hover:text-foreground/90 dark:hover:bg-accent/40\",\n )}\n >\n {item.icon}\n <span className=\"truncate\">{item.name}</span>\n </Link>\n ) : (\n <p className=\"text-muted-foreground mt-3 mb-1 flex items-center gap-2 px-2 text-xs font-medium first:mt-1\">\n {item.icon}\n {item.name}\n </p>\n )}\n {hasChildren && (containsActive || !item.index) && (\n <div className=\"border-border/50 ml-2 flex flex-col gap-0.5 border-l pl-2\">\n {item.children.map((child) => (\n <SectionItem\n key={child.$id}\n item={child}\n onNavigate={onNavigate}\n pathname={pathname}\n activePath={activePath}\n isVisible={isVisible}\n />\n ))}\n </div>\n )}\n </div>\n );\n }\n\n const isActive = pathname === item.url;\n return (\n <Link\n href={item.url}\n onClick={onNavigate}\n data-active={isActive ? \"true\" : \"false\"}\n className={cn(\n \"flex items-center gap-2 rounded-md px-2 py-1.5 text-[13px] transition-colors duration-150\",\n isActive\n ? \"bg-accent/20 text-foreground dark:bg-accent/50 font-medium\"\n : \"text-muted-foreground hover:bg-accent/30 hover:text-foreground/90 dark:hover:bg-accent/40\",\n )}\n >\n {item.icon}\n <span className=\"truncate\">{item.name}</span>\n </Link>\n );\n}\n\nfunction SidebarSection({\n folder,\n isOpen,\n onToggle,\n onNavigate,\n pathname,\n activePath,\n isVisible,\n}: {\n folder: DocsFolder;\n isOpen: boolean;\n onToggle: () => void;\n onNavigate: () => void;\n pathname: string;\n activePath: ReadonlySet<DocsNode>;\n isVisible: (node: DocsNode) => boolean;\n}) {\n const isActive = folder.index && pathname === folder.index.url;\n\n return (\n <div>\n <button\n type=\"button\"\n onClick={onToggle}\n aria-expanded={isOpen}\n className={cn(\n \"hover:bg-accent/30 dark:hover:bg-accent/40 flex w-full items-center gap-2 rounded-md px-2 py-2 text-left text-[13px] transition-colors duration-150\",\n isActive || isOpen\n ? \"text-foreground font-medium\"\n : \"text-muted-foreground/90\",\n )}\n >\n <span className=\"text-muted-foreground flex size-4 shrink-0 items-center justify-center\">\n {folder.icon}\n </span>\n <span className=\"flex-1 truncate\">{folder.name}</span>\n <ChevronDown\n className={cn(\n \"text-muted-foreground/60 size-3.5 shrink-0 transition-transform duration-200\",\n !isOpen && \"-rotate-90\",\n )}\n />\n </button>\n <AnimatePresence initial={false}>\n {isOpen && (\n <m.div\n initial={{ height: 0, opacity: 0 }}\n animate={{ height: \"auto\", opacity: 1 }}\n exit={{ height: 0, opacity: 0 }}\n transition={{ duration: 0.22, ease: [0.16, 1, 0.3, 1] }}\n className=\"overflow-hidden\"\n >\n <div className=\"border-border/50 mt-0.5 mb-1 ml-4 flex flex-col gap-0.5 border-l pl-2\">\n {folder.children.map((child) => (\n <SectionItem\n key={child.$id}\n item={child}\n onNavigate={onNavigate}\n pathname={pathname}\n activePath={activePath}\n isVisible={isVisible}\n />\n ))}\n </div>\n </m.div>\n )}\n </AnimatePresence>\n </div>\n );\n}\n\nconst visible = () => true;\n\nexport function DocsSidebarNavigation({\n sections,\n pathname,\n activeSectionId,\n isVisible = visible,\n onNavigate,\n banner,\n footer,\n platform,\n}: {\n sections: readonly DocsFolder[];\n pathname: string;\n activeSectionId: string | null;\n isVisible?: (node: DocsNode) => boolean;\n onNavigate: () => void;\n banner?: ReactNode;\n footer?: ReactNode;\n platform?: string;\n}) {\n const navRef = useRef<HTMLElement>(null);\n const activePath = useMemo(\n () => new Set(findActivePath(sections, pathname)),\n [sections, pathname],\n );\n\n const [openSectionId, setOpenSectionId] = useState<string | null>(\n activeSectionId,\n );\n\n const [sectionScope, setSectionScope] = useState({\n activeSectionId,\n pathname,\n });\n\n if (\n sectionScope.activeSectionId !== activeSectionId ||\n sectionScope.pathname !== pathname\n ) {\n setSectionScope({ activeSectionId, pathname });\n if (activeSectionId) setOpenSectionId(activeSectionId);\n }\n\n useEffect(() => {\n if (openSectionId !== activeSectionId) return;\n const timer = setTimeout(() => {\n const nav = navRef.current;\n if (!nav) return;\n const active = nav.querySelector<HTMLElement>(\"[data-active='true']\");\n if (!active) return;\n const navRect = nav.getBoundingClientRect();\n const elRect = active.getBoundingClientRect();\n if (elRect.top < navRect.top || elRect.bottom > navRect.bottom) {\n active.scrollIntoView({ block: \"center\", behavior: \"smooth\" });\n }\n }, 260);\n return () => clearTimeout(timer);\n }, [pathname, openSectionId, activeSectionId]);\n\n return (\n <div className=\"flex h-full flex-col\">\n {banner && <div className=\"shrink-0 px-3 pt-4 lg:hidden\">{banner}</div>}\n <nav\n aria-label=\"Docs\"\n ref={navRef}\n data-docs-platform={platform}\n className={cn(\n \"sidebar-tree-content flex min-h-0 flex-1 flex-col gap-0.5 overflow-x-hidden overflow-y-auto px-3 pt-2 pb-4 lg:pt-4\",\n )}\n >\n <LazyMotion features={domAnimation}>\n {sections.map((section) => (\n <SidebarSection\n key={section.$id}\n folder={section}\n isOpen={openSectionId === section.$id}\n onToggle={() => {\n const id = section.$id ?? null;\n setOpenSectionId(openSectionId !== id ? id : null);\n }}\n onNavigate={onNavigate}\n pathname={pathname}\n activePath={activePath}\n isVisible={isVisible}\n />\n ))}\n </LazyMotion>\n </nav>\n {footer && (\n <div className=\"border-border/50 flex shrink-0 items-center gap-1 border-t px-3 py-2\">\n {footer}\n </div>\n )}\n </div>\n );\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { type ReactNode } from "react";
|
|
2
|
+
export declare const DOCS_SIDEBAR_ID = "docs-sidebar";
|
|
3
|
+
interface DocsSidebarContextValue {
|
|
4
|
+
open: boolean;
|
|
5
|
+
setOpen: (open: boolean) => void;
|
|
6
|
+
toggle: () => void;
|
|
7
|
+
}
|
|
8
|
+
export declare function useDocsSidebar(): DocsSidebarContextValue;
|
|
9
|
+
export declare function DocsSidebarProvider({ children }: {
|
|
10
|
+
children: ReactNode;
|
|
11
|
+
}): import("react").JSX.Element;
|
|
12
|
+
export declare function DocsSidebar({ children }: {
|
|
13
|
+
children: ReactNode;
|
|
14
|
+
}): import("react").JSX.Element;
|
|
15
|
+
export {};
|
|
16
|
+
//# sourceMappingURL=sidebar.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sidebar.d.ts","sourceRoot":"","sources":["../../src/site/sidebar.tsx"],"names":[],"mappings":"AAEA,OAAO,EAML,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AAIf,eAAO,MAAM,eAAe,iBAAiB,CAAC;AAU9C,UAAU,uBAAuB;IAC/B,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IACjC,MAAM,EAAE,MAAM,IAAI,CAAC;CACpB;AAID,wBAAgB,cAAc,4BAM7B;AAED,wBAAgB,mBAAmB,CAAC,EAAE,QAAQ,EAAE,EAAE;IAAE,QAAQ,EAAE,SAAS,CAAA;CAAE,+BASxE;AAED,wBAAgB,WAAW,CAAC,EAAE,QAAQ,EAAE,EAAE;IAAE,QAAQ,EAAE,SAAS,CAAA;CAAE,+BA0BhE"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import "./constants.js";
|
|
3
|
+
import { cn } from "./utils.js";
|
|
4
|
+
import { jsx } from "react/jsx-runtime";
|
|
5
|
+
import { createContext, useCallback, useContext, useState, useSyncExternalStore } from "react";
|
|
6
|
+
// src/site/sidebar.tsx
|
|
7
|
+
const DOCS_SIDEBAR_ID = "docs-sidebar";
|
|
8
|
+
const subscribeToViewport = (onChange) => {
|
|
9
|
+
const viewport = window.matchMedia("(max-width: 767px)");
|
|
10
|
+
viewport.addEventListener("change", onChange);
|
|
11
|
+
return () => viewport.removeEventListener("change", onChange);
|
|
12
|
+
};
|
|
13
|
+
const isMobileViewport = () => window.innerWidth < 768;
|
|
14
|
+
const serverViewport = () => false;
|
|
15
|
+
const DocsSidebarContext = createContext(null);
|
|
16
|
+
function useDocsSidebar() {
|
|
17
|
+
const ctx = useContext(DocsSidebarContext);
|
|
18
|
+
if (!ctx) throw new Error("useDocsSidebar must be used within DocsSidebarProvider");
|
|
19
|
+
return ctx;
|
|
20
|
+
}
|
|
21
|
+
function DocsSidebarProvider({ children }) {
|
|
22
|
+
const [open, setOpen] = useState(false);
|
|
23
|
+
const toggle = useCallback(() => setOpen((prev) => !prev), []);
|
|
24
|
+
return /* @__PURE__ */ jsx(DocsSidebarContext.Provider, {
|
|
25
|
+
value: {
|
|
26
|
+
open,
|
|
27
|
+
setOpen,
|
|
28
|
+
toggle
|
|
29
|
+
},
|
|
30
|
+
children
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
function DocsSidebar({ children }) {
|
|
34
|
+
const { open } = useDocsSidebar();
|
|
35
|
+
const isMobile = useSyncExternalStore(subscribeToViewport, isMobileViewport, serverViewport);
|
|
36
|
+
return /* @__PURE__ */ jsx("aside", {
|
|
37
|
+
id: DOCS_SIDEBAR_ID,
|
|
38
|
+
inert: !open && isMobile,
|
|
39
|
+
className: cn("bg-background fixed inset-x-0 top-12 bottom-0 z-40 transition-[opacity,visibility] duration-200", open ? "opacity-100" : "pointer-events-none opacity-0 max-md:invisible", "md:pointer-events-auto md:visible md:right-auto md:left-0 md:z-30 md:w-(--sidebar-width) md:opacity-100"),
|
|
40
|
+
style: { "--sidebar-width": `260px` },
|
|
41
|
+
children
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
export { DOCS_SIDEBAR_ID, DocsSidebar, DocsSidebarProvider, useDocsSidebar };
|
|
45
|
+
|
|
46
|
+
//# sourceMappingURL=sidebar.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sidebar.js","names":[],"sources":["../../src/site/sidebar.tsx"],"sourcesContent":["\"use client\";\n\nimport {\n createContext,\n useCallback,\n useContext,\n useState,\n useSyncExternalStore,\n type ReactNode,\n} from \"react\";\nimport { cn } from \"./utils\";\nimport { DOCS_SIDEBAR_WIDTH } from \"./constants\";\n\nexport const DOCS_SIDEBAR_ID = \"docs-sidebar\";\n\nconst subscribeToViewport = (onChange: () => void) => {\n const viewport = window.matchMedia(\"(max-width: 767px)\");\n viewport.addEventListener(\"change\", onChange);\n return () => viewport.removeEventListener(\"change\", onChange);\n};\nconst isMobileViewport = () => window.innerWidth < 768;\nconst serverViewport = () => false;\n\ninterface DocsSidebarContextValue {\n open: boolean;\n setOpen: (open: boolean) => void;\n toggle: () => void;\n}\n\nconst DocsSidebarContext = createContext<DocsSidebarContextValue | null>(null);\n\nexport function useDocsSidebar() {\n const ctx = useContext(DocsSidebarContext);\n if (!ctx) {\n throw new Error(\"useDocsSidebar must be used within DocsSidebarProvider\");\n }\n return ctx;\n}\n\nexport function DocsSidebarProvider({ children }: { children: ReactNode }) {\n const [open, setOpen] = useState(false);\n const toggle = useCallback(() => setOpen((prev) => !prev), []);\n\n return (\n <DocsSidebarContext.Provider value={{ open, setOpen, toggle }}>\n {children}\n </DocsSidebarContext.Provider>\n );\n}\n\nexport function DocsSidebar({ children }: { children: ReactNode }) {\n const { open } = useDocsSidebar();\n const isMobile = useSyncExternalStore(\n subscribeToViewport,\n isMobileViewport,\n serverViewport,\n );\n\n return (\n <aside\n id={DOCS_SIDEBAR_ID}\n inert={!open && isMobile}\n className={cn(\n \"bg-background fixed inset-x-0 top-12 bottom-0 z-40 transition-[opacity,visibility] duration-200\",\n open ? \"opacity-100\" : \"pointer-events-none opacity-0 max-md:invisible\",\n \"md:pointer-events-auto md:visible md:right-auto md:left-0 md:z-30 md:w-(--sidebar-width) md:opacity-100\",\n )}\n style={\n {\n \"--sidebar-width\": `${DOCS_SIDEBAR_WIDTH}px`,\n } as React.CSSProperties\n }\n >\n {children}\n </aside>\n );\n}\n"],"mappings":";;;;;;AAaA,MAAa,kBAAkB;AAE/B,MAAM,uBAAuB,aAAyB;CACpD,MAAM,WAAW,OAAO,WAAW,oBAAoB;CACvD,SAAS,iBAAiB,UAAU,QAAQ;CAC5C,aAAa,SAAS,oBAAoB,UAAU,QAAQ;AAC9D;AACA,MAAM,yBAAyB,OAAO,aAAa;AACnD,MAAM,uBAAuB;AAQ7B,MAAM,qBAAqB,cAA8C,IAAI;AAE7E,SAAgB,iBAAiB;CAC/B,MAAM,MAAM,WAAW,kBAAkB;CACzC,IAAI,CAAC,KACH,MAAM,IAAI,MAAM,wDAAwD;CAE1E,OAAO;AACT;AAEA,SAAgB,oBAAoB,EAAE,YAAqC;CACzE,MAAM,CAAC,MAAM,WAAW,SAAS,KAAK;CACtC,MAAM,SAAS,kBAAkB,SAAS,SAAS,CAAC,IAAI,GAAG,CAAC,CAAC;CAE7D,OACE,oBAAC,mBAAmB,UAApB;EAA6B,OAAO;GAAE;GAAM;GAAS;EAAO;EACzD;CAC0B,CAAA;AAEjC;AAEA,SAAgB,YAAY,EAAE,YAAqC;CACjE,MAAM,EAAE,SAAS,eAAe;CAChC,MAAM,WAAW,qBACf,qBACA,kBACA,cACF;CAEA,OACE,oBAAC,SAAD;EACE,IAAI;EACJ,OAAO,CAAC,QAAQ;EAChB,WAAW,GACT,mGACA,OAAO,gBAAgB,kDACvB,yGACF;EACA,OACE,EACE,mBAAmB,QACrB;EAGD;CACI,CAAA;AAEX"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { type ReactNode } from "react";
|
|
2
|
+
type TOCItem = {
|
|
3
|
+
title: ReactNode;
|
|
4
|
+
url: string;
|
|
5
|
+
depth: number;
|
|
6
|
+
};
|
|
7
|
+
export declare function DocsTableOfContents({ items, children, }: {
|
|
8
|
+
items: TOCItem[];
|
|
9
|
+
children?: ReactNode;
|
|
10
|
+
}): import("react").JSX.Element | null;
|
|
11
|
+
export {};
|
|
12
|
+
//# sourceMappingURL=toc.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"toc.d.ts","sourceRoot":"","sources":["../../src/site/toc.tsx"],"names":[],"mappings":"AAEA,OAAO,EAA+B,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAGpE,KAAK,OAAO,GAAG;IACb,KAAK,EAAE,SAAS,CAAC;IACjB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAWF,wBAAgB,mBAAmB,CAAC,EAClC,KAAK,EACL,QAAQ,GACT,EAAE;IACD,KAAK,EAAE,OAAO,EAAE,CAAC;IACjB,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB,sCA2FA"}
|
package/dist/site/toc.js
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { cn } from "./utils.js";
|
|
3
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
4
|
+
import { useEffect, useRef, useState } from "react";
|
|
5
|
+
// src/site/toc.tsx
|
|
6
|
+
function headingId(url) {
|
|
7
|
+
const fragment = url.slice(1);
|
|
8
|
+
try {
|
|
9
|
+
return decodeURIComponent(fragment);
|
|
10
|
+
} catch {
|
|
11
|
+
return fragment;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
function DocsTableOfContents({ items, children }) {
|
|
15
|
+
const [activeId, setActiveId] = useState(null);
|
|
16
|
+
const listRef = useRef(null);
|
|
17
|
+
useEffect(() => {
|
|
18
|
+
if (items.length === 0) return;
|
|
19
|
+
const headingIds = items.map((item) => headingId(item.url));
|
|
20
|
+
const viewport = window.matchMedia("(min-width: 1280px)");
|
|
21
|
+
let observer;
|
|
22
|
+
const observeVisibleHeadings = () => {
|
|
23
|
+
observer?.disconnect();
|
|
24
|
+
if (!viewport.matches) return;
|
|
25
|
+
observer = new IntersectionObserver((entries) => {
|
|
26
|
+
for (const entry of entries) if (entry.isIntersecting) {
|
|
27
|
+
setActiveId(entry.target.id);
|
|
28
|
+
break;
|
|
29
|
+
}
|
|
30
|
+
}, {
|
|
31
|
+
rootMargin: "-80px 0px -70% 0px",
|
|
32
|
+
threshold: 0
|
|
33
|
+
});
|
|
34
|
+
for (const id of headingIds) {
|
|
35
|
+
const element = document.getElementById(id);
|
|
36
|
+
if (element) observer.observe(element);
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
observeVisibleHeadings();
|
|
40
|
+
viewport.addEventListener("change", observeVisibleHeadings);
|
|
41
|
+
return () => {
|
|
42
|
+
observer?.disconnect();
|
|
43
|
+
viewport.removeEventListener("change", observeVisibleHeadings);
|
|
44
|
+
};
|
|
45
|
+
}, [items]);
|
|
46
|
+
useEffect(() => {
|
|
47
|
+
if (!activeId || !listRef.current) return;
|
|
48
|
+
const activeElement = Array.from(listRef.current.children).find((item) => item.getAttribute("data-toc-id") === activeId);
|
|
49
|
+
if (activeElement) activeElement.scrollIntoView({
|
|
50
|
+
behavior: "smooth",
|
|
51
|
+
block: "nearest"
|
|
52
|
+
});
|
|
53
|
+
}, [activeId]);
|
|
54
|
+
if (items.length === 0) return null;
|
|
55
|
+
return /* @__PURE__ */ jsx("div", {
|
|
56
|
+
className: "docs-toc w-56 max-xl:hidden",
|
|
57
|
+
children: /* @__PURE__ */ jsxs("div", {
|
|
58
|
+
className: "sticky top-[calc(var(--docs-header-height)_+_1rem)] flex max-h-[calc(100vh_-_var(--docs-header-height)_-_1rem)] flex-col pe-4 pt-4 pb-2",
|
|
59
|
+
children: [
|
|
60
|
+
/* @__PURE__ */ jsx("p", {
|
|
61
|
+
className: "text-muted-foreground mb-3 shrink-0 text-xs",
|
|
62
|
+
children: "On this page"
|
|
63
|
+
}),
|
|
64
|
+
/* @__PURE__ */ jsx("ul", {
|
|
65
|
+
ref: listRef,
|
|
66
|
+
className: "flex min-h-0 flex-1 [scrollbar-width:none] flex-col gap-1 overflow-x-hidden overflow-y-auto [&::-webkit-scrollbar]:hidden",
|
|
67
|
+
children: items.map((item) => {
|
|
68
|
+
const id = headingId(item.url);
|
|
69
|
+
const isActive = activeId === id;
|
|
70
|
+
const indent = Math.max(0, item.depth - 2) * 12;
|
|
71
|
+
return /* @__PURE__ */ jsx("li", {
|
|
72
|
+
"data-toc-id": id,
|
|
73
|
+
children: /* @__PURE__ */ jsx("a", {
|
|
74
|
+
href: item.url,
|
|
75
|
+
style: { paddingLeft: indent || void 0 },
|
|
76
|
+
className: cn("block py-1 text-[13px] leading-snug wrap-break-word transition-colors", isActive ? "text-foreground font-medium" : "text-muted-foreground hover:text-foreground"),
|
|
77
|
+
children: item.title
|
|
78
|
+
})
|
|
79
|
+
}, item.url);
|
|
80
|
+
})
|
|
81
|
+
}),
|
|
82
|
+
/* @__PURE__ */ jsx("div", {
|
|
83
|
+
className: "mt-6 shrink-0",
|
|
84
|
+
children
|
|
85
|
+
})
|
|
86
|
+
]
|
|
87
|
+
})
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
export { DocsTableOfContents };
|
|
91
|
+
|
|
92
|
+
//# sourceMappingURL=toc.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"toc.js","names":[],"sources":["../../src/site/toc.tsx"],"sourcesContent":["\"use client\";\n\nimport { useEffect, useRef, useState, type ReactNode } from \"react\";\nimport { cn } from \"./utils\";\n\ntype TOCItem = {\n title: ReactNode;\n url: string;\n depth: number;\n};\n\nfunction headingId(url: string) {\n const fragment = url.slice(1);\n try {\n return decodeURIComponent(fragment);\n } catch {\n return fragment;\n }\n}\n\nexport function DocsTableOfContents({\n items,\n children,\n}: {\n items: TOCItem[];\n children?: ReactNode;\n}) {\n const [activeId, setActiveId] = useState<string | null>(null);\n const listRef = useRef<HTMLUListElement>(null);\n\n useEffect(() => {\n if (items.length === 0) return;\n\n const headingIds = items.map((item) => headingId(item.url));\n\n const viewport = window.matchMedia(\"(min-width: 1280px)\");\n let observer: IntersectionObserver | undefined;\n const observeVisibleHeadings = () => {\n observer?.disconnect();\n if (!viewport.matches) return;\n observer = new IntersectionObserver(\n (entries) => {\n for (const entry of entries) {\n if (entry.isIntersecting) {\n setActiveId(entry.target.id);\n break;\n }\n }\n },\n { rootMargin: \"-80px 0px -70% 0px\", threshold: 0 },\n );\n for (const id of headingIds) {\n const element = document.getElementById(id);\n if (element) observer.observe(element);\n }\n };\n observeVisibleHeadings();\n viewport.addEventListener(\"change\", observeVisibleHeadings);\n return () => {\n observer?.disconnect();\n viewport.removeEventListener(\"change\", observeVisibleHeadings);\n };\n }, [items]);\n\n useEffect(() => {\n if (!activeId || !listRef.current) return;\n\n const activeElement = Array.from(listRef.current.children).find(\n (item) => item.getAttribute(\"data-toc-id\") === activeId,\n );\n if (activeElement) {\n activeElement.scrollIntoView({\n behavior: \"smooth\",\n block: \"nearest\",\n });\n }\n }, [activeId]);\n\n if (items.length === 0) return null;\n\n return (\n <div className=\"docs-toc w-56 max-xl:hidden\">\n <div className=\"sticky top-[calc(var(--docs-header-height)_+_1rem)] flex max-h-[calc(100vh_-_var(--docs-header-height)_-_1rem)] flex-col pe-4 pt-4 pb-2\">\n <p className=\"text-muted-foreground mb-3 shrink-0 text-xs\">\n On this page\n </p>\n <ul\n ref={listRef}\n className=\"flex min-h-0 flex-1 [scrollbar-width:none] flex-col gap-1 overflow-x-hidden overflow-y-auto [&::-webkit-scrollbar]:hidden\"\n >\n {items.map((item) => {\n const id = headingId(item.url);\n const isActive = activeId === id;\n const indent = Math.max(0, item.depth - 2) * 12;\n\n return (\n <li key={item.url} data-toc-id={id}>\n <a\n href={item.url}\n style={{ paddingLeft: indent || undefined }}\n className={cn(\n \"block py-1 text-[13px] leading-snug wrap-break-word transition-colors\",\n isActive\n ? \"text-foreground font-medium\"\n : \"text-muted-foreground hover:text-foreground\",\n )}\n >\n {item.title}\n </a>\n </li>\n );\n })}\n </ul>\n <div className=\"mt-6 shrink-0\">{children}</div>\n </div>\n </div>\n );\n}\n"],"mappings":";;;;;AAWA,SAAS,UAAU,KAAa;CAC9B,MAAM,WAAW,IAAI,MAAM,CAAC;CAC5B,IAAI;EACF,OAAO,mBAAmB,QAAQ;CACpC,QAAQ;EACN,OAAO;CACT;AACF;AAEA,SAAgB,oBAAoB,EAClC,OACA,YAIC;CACD,MAAM,CAAC,UAAU,eAAe,SAAwB,IAAI;CAC5D,MAAM,UAAU,OAAyB,IAAI;CAE7C,gBAAgB;EACd,IAAI,MAAM,WAAW,GAAG;EAExB,MAAM,aAAa,MAAM,KAAK,SAAS,UAAU,KAAK,GAAG,CAAC;EAE1D,MAAM,WAAW,OAAO,WAAW,qBAAqB;EACxD,IAAI;EACJ,MAAM,+BAA+B;GACnC,UAAU,WAAW;GACrB,IAAI,CAAC,SAAS,SAAS;GACvB,WAAW,IAAI,sBACZ,YAAY;IACX,KAAK,MAAM,SAAS,SAClB,IAAI,MAAM,gBAAgB;KACxB,YAAY,MAAM,OAAO,EAAE;KAC3B;IACF;GAEJ,GACA;IAAE,YAAY;IAAsB,WAAW;GAAE,CACnD;GACA,KAAK,MAAM,MAAM,YAAY;IAC3B,MAAM,UAAU,SAAS,eAAe,EAAE;IAC1C,IAAI,SAAS,SAAS,QAAQ,OAAO;GACvC;EACF;EACA,uBAAuB;EACvB,SAAS,iBAAiB,UAAU,sBAAsB;EAC1D,aAAa;GACX,UAAU,WAAW;GACrB,SAAS,oBAAoB,UAAU,sBAAsB;EAC/D;CACF,GAAG,CAAC,KAAK,CAAC;CAEV,gBAAgB;EACd,IAAI,CAAC,YAAY,CAAC,QAAQ,SAAS;EAEnC,MAAM,gBAAgB,MAAM,KAAK,QAAQ,QAAQ,QAAQ,CAAC,CAAC,MACxD,SAAS,KAAK,aAAa,aAAa,MAAM,QACjD;EACA,IAAI,eACF,cAAc,eAAe;GAC3B,UAAU;GACV,OAAO;EACT,CAAC;CAEL,GAAG,CAAC,QAAQ,CAAC;CAEb,IAAI,MAAM,WAAW,GAAG,OAAO;CAE/B,OACE,oBAAC,OAAD;EAAK,WAAU;EACb,UAAA,qBAAC,OAAD;GAAK,WAAU;GAAf,UAAA;IACE,oBAAC,KAAD;KAAG,WAAU;KAA8C,UAAA;IAExD,CAAA;IACH,oBAAC,MAAD;KACE,KAAK;KACL,WAAU;KAET,UAAA,MAAM,KAAK,SAAS;MACnB,MAAM,KAAK,UAAU,KAAK,GAAG;MAC7B,MAAM,WAAW,aAAa;MAC9B,MAAM,SAAS,KAAK,IAAI,GAAG,KAAK,QAAQ,CAAC,IAAI;MAE7C,OACE,oBAAC,MAAD;OAAmB,eAAa;OAC9B,UAAA,oBAAC,KAAD;QACE,MAAM,KAAK;QACX,OAAO,EAAE,aAAa,UAAU,KAAA,EAAU;QAC1C,WAAW,GACT,yEACA,WACI,gCACA,6CACN;QAEC,UAAA,KAAK;OACL,CAAA;MACD,GAbK,KAAK,GAaV;KAER,CAAC;IACC,CAAA;IACJ,oBAAC,OAAD;KAAK,WAAU;KAAiB;IAAc,CAAA;GAC3C;;CACF,CAAA;AAET"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { ReactNode } from "react";
|
|
2
|
+
interface DocsNodeBase {
|
|
3
|
+
$id?: string;
|
|
4
|
+
name?: ReactNode;
|
|
5
|
+
icon?: ReactNode;
|
|
6
|
+
}
|
|
7
|
+
export interface DocsPage extends DocsNodeBase {
|
|
8
|
+
type: "page";
|
|
9
|
+
name: ReactNode;
|
|
10
|
+
url: string;
|
|
11
|
+
}
|
|
12
|
+
export interface DocsFolder extends DocsNodeBase {
|
|
13
|
+
type: "folder";
|
|
14
|
+
name: ReactNode;
|
|
15
|
+
index?: DocsPage;
|
|
16
|
+
children: DocsNode[];
|
|
17
|
+
}
|
|
18
|
+
export interface DocsSeparator extends DocsNodeBase {
|
|
19
|
+
type: "separator";
|
|
20
|
+
}
|
|
21
|
+
export type DocsNode = DocsPage | DocsFolder | DocsSeparator;
|
|
22
|
+
export declare function findActivePath(nodes: readonly DocsNode[], pathname: string): DocsNode[] | null;
|
|
23
|
+
export {};
|
|
24
|
+
//# sourceMappingURL=tree.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tree.d.ts","sourceRoot":"","sources":["../../src/site/tree.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAEvC,UAAU,YAAY;IACpB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,IAAI,CAAC,EAAE,SAAS,CAAC;CAClB;AACD,MAAM,WAAW,QAAS,SAAQ,YAAY;IAC5C,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,SAAS,CAAC;IAChB,GAAG,EAAE,MAAM,CAAC;CACb;AACD,MAAM,WAAW,UAAW,SAAQ,YAAY;IAC9C,IAAI,EAAE,QAAQ,CAAC;IACf,IAAI,EAAE,SAAS,CAAC;IAChB,KAAK,CAAC,EAAE,QAAQ,CAAC;IACjB,QAAQ,EAAE,QAAQ,EAAE,CAAC;CACtB;AACD,MAAM,WAAW,aAAc,SAAQ,YAAY;IACjD,IAAI,EAAE,WAAW,CAAC;CACnB;AACD,MAAM,MAAM,QAAQ,GAAG,QAAQ,GAAG,UAAU,GAAG,aAAa,CAAC;AAE7D,wBAAgB,cAAc,CAC5B,KAAK,EAAE,SAAS,QAAQ,EAAE,EAC1B,QAAQ,EAAE,MAAM,GACf,QAAQ,EAAE,GAAG,IAAI,CASnB"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
// src/site/tree.ts
|
|
2
|
+
function findActivePath(nodes, pathname) {
|
|
3
|
+
for (const node of nodes) {
|
|
4
|
+
if (node.type === "page" && node.url === pathname) return [node];
|
|
5
|
+
if (node.type !== "folder") continue;
|
|
6
|
+
if (node.index?.url === pathname) return [node, node.index];
|
|
7
|
+
const path = findActivePath(node.children, pathname);
|
|
8
|
+
if (path) return [node, ...path];
|
|
9
|
+
}
|
|
10
|
+
return null;
|
|
11
|
+
}
|
|
12
|
+
export { findActivePath };
|
|
13
|
+
|
|
14
|
+
//# sourceMappingURL=tree.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tree.js","names":[],"sources":["../../src/site/tree.ts"],"sourcesContent":["import type { ReactNode } from \"react\";\n\ninterface DocsNodeBase {\n $id?: string;\n name?: ReactNode;\n icon?: ReactNode;\n}\nexport interface DocsPage extends DocsNodeBase {\n type: \"page\";\n name: ReactNode;\n url: string;\n}\nexport interface DocsFolder extends DocsNodeBase {\n type: \"folder\";\n name: ReactNode;\n index?: DocsPage;\n children: DocsNode[];\n}\nexport interface DocsSeparator extends DocsNodeBase {\n type: \"separator\";\n}\nexport type DocsNode = DocsPage | DocsFolder | DocsSeparator;\n\nexport function findActivePath(\n nodes: readonly DocsNode[],\n pathname: string,\n): DocsNode[] | null {\n for (const node of nodes) {\n if (node.type === \"page\" && node.url === pathname) return [node];\n if (node.type !== \"folder\") continue;\n if (node.index?.url === pathname) return [node, node.index];\n const path = findActivePath(node.children, pathname);\n if (path) return [node, ...path];\n }\n return null;\n}\n"],"mappings":";AAuBA,SAAgB,eACd,OACA,UACmB;CACnB,KAAK,MAAM,QAAQ,OAAO;EACxB,IAAI,KAAK,SAAS,UAAU,KAAK,QAAQ,UAAU,OAAO,CAAC,IAAI;EAC/D,IAAI,KAAK,SAAS,UAAU;EAC5B,IAAI,KAAK,OAAO,QAAQ,UAAU,OAAO,CAAC,MAAM,KAAK,KAAK;EAC1D,MAAM,OAAO,eAAe,KAAK,UAAU,QAAQ;EACnD,IAAI,MAAM,OAAO,CAAC,MAAM,GAAG,IAAI;CACjC;CACA,OAAO;AACT"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/site/utils.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,EAAE,GAAI,GAAG,QAAQ,CAAC,MAAM,GAAG,KAAK,GAAG,SAAS,CAAC,EAAE,WAC1B,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.js","names":[],"sources":["../../src/site/utils.ts"],"sourcesContent":["export const cn = (...values: (string | false | undefined)[]) =>\n values.filter(Boolean).join(\" \");\n"],"mappings":";AAAA,MAAa,MAAM,GAAG,WACpB,OAAO,OAAO,OAAO,CAAC,CAAC,KAAK,GAAG"}
|
package/dist/ui.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export { DocsShell, DocsContent } from "./site/layout.js";
|
|
2
|
+
export { DocsPageShell, DocsBody } from "./site/page.js";
|
|
3
|
+
export { DocsFooter } from "./site/footer.js";
|
|
4
|
+
export { DOCS_SIDEBAR_ID, DocsSidebar, DocsSidebarProvider, useDocsSidebar, } from "./site/sidebar.js";
|
|
5
|
+
export { DocsSidebarNavigation } from "./site/sidebar-navigation.js";
|
|
6
|
+
export { DocsTableOfContents } from "./site/toc.js";
|
|
7
|
+
export type { DocsNode, DocsPage, DocsFolder, DocsSeparator, } from "./site/tree.js";
|
|
8
|
+
export { DocsSiteHeader } from "./site/header.js";
|
|
9
|
+
export { DocsPagerNavigation } from "./site/pager.js";
|
|
10
|
+
//# sourceMappingURL=ui.d.ts.map
|
package/dist/ui.d.ts.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ui.d.ts","sourceRoot":"","sources":["../src/ui.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,yBAAsB;AACvD,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,uBAAoB;AACtD,OAAO,EAAE,UAAU,EAAE,yBAAsB;AAC3C,OAAO,EACL,eAAe,EACf,WAAW,EACX,mBAAmB,EACnB,cAAc,GACf,0BAAuB;AACxB,OAAO,EAAE,qBAAqB,EAAE,qCAAkC;AAClE,OAAO,EAAE,mBAAmB,EAAE,sBAAmB;AACjD,YAAY,EACV,QAAQ,EACR,QAAQ,EACR,UAAU,EACV,aAAa,GACd,uBAAoB;AACrB,OAAO,EAAE,cAAc,EAAE,yBAAsB;AAC/C,OAAO,EAAE,mBAAmB,EAAE,wBAAqB"}
|
package/dist/ui.js
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { DocsFooter } from "./site/footer.js";
|
|
2
|
+
import { DOCS_SIDEBAR_ID, DocsSidebar, DocsSidebarProvider, useDocsSidebar } from "./site/sidebar.js";
|
|
3
|
+
import { DocsSiteHeader } from "./site/header.js";
|
|
4
|
+
import { DocsContent, DocsShell } from "./site/layout.js";
|
|
5
|
+
import { DocsBody, DocsPageShell } from "./site/page.js";
|
|
6
|
+
import { DocsPagerNavigation } from "./site/pager.js";
|
|
7
|
+
import { DocsSidebarNavigation } from "./site/sidebar-navigation.js";
|
|
8
|
+
import { DocsTableOfContents } from "./site/toc.js";
|
|
9
|
+
export { DOCS_SIDEBAR_ID, DocsBody, DocsContent, DocsFooter, DocsPageShell, DocsPagerNavigation, DocsShell, DocsSidebar, DocsSidebarNavigation, DocsSidebarProvider, DocsSiteHeader, DocsTableOfContents, useDocsSidebar };
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@assistant-ui/docs-theme",
|
|
3
|
-
"version": "0.0.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.0.3",
|
|
4
|
+
"description": "Composable assistant-ui documentation UI and theme for Next.js",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "AgentbaseAI Inc.",
|
|
7
7
|
"type": "module",
|
|
@@ -20,7 +20,12 @@
|
|
|
20
20
|
"types": "./dist/provider.d.ts",
|
|
21
21
|
"default": "./dist/provider.js"
|
|
22
22
|
},
|
|
23
|
-
"./styles.css": "./styles/theme.css"
|
|
23
|
+
"./styles.css": "./styles/theme.css",
|
|
24
|
+
"./ui": {
|
|
25
|
+
"types": "./dist/ui.d.ts",
|
|
26
|
+
"default": "./dist/ui.js"
|
|
27
|
+
},
|
|
28
|
+
"./site.css": "./styles/site.css"
|
|
24
29
|
},
|
|
25
30
|
"files": [
|
|
26
31
|
"dist",
|
|
@@ -37,30 +42,32 @@
|
|
|
37
42
|
"lucide-react": "^1.61.0"
|
|
38
43
|
},
|
|
39
44
|
"peerDependencies": {
|
|
40
|
-
"@farming-labs/docs": "0.2.
|
|
41
|
-
"@farming-labs/theme": "0.2.
|
|
42
|
-
"fumadocs-ui": "16.17.
|
|
45
|
+
"@farming-labs/docs": "0.2.137",
|
|
46
|
+
"@farming-labs/theme": "0.2.137",
|
|
47
|
+
"fumadocs-ui": "16.17.8",
|
|
43
48
|
"next": "^16.0.0",
|
|
44
49
|
"next-themes": "^0.4.0",
|
|
45
50
|
"react": "^19.2.0",
|
|
46
|
-
"react-dom": "^19.2.0"
|
|
51
|
+
"react-dom": "^19.2.0",
|
|
52
|
+
"motion": "^14.0.0"
|
|
47
53
|
},
|
|
48
54
|
"devDependencies": {
|
|
49
55
|
"@assistant-ui/x-buildutils": "0.0.32",
|
|
50
|
-
"@farming-labs/docs": "0.2.
|
|
51
|
-
"@farming-labs/theme": "0.2.
|
|
56
|
+
"@farming-labs/docs": "0.2.137",
|
|
57
|
+
"@farming-labs/theme": "0.2.137",
|
|
52
58
|
"@types/node": "^26.6.5",
|
|
53
59
|
"@types/react": "^19.3.0",
|
|
54
60
|
"@types/react-dom": "^19.3.0",
|
|
55
61
|
"@vitest/coverage-v8": "^5.0.5",
|
|
56
|
-
"fumadocs-ui": "16.17.
|
|
62
|
+
"fumadocs-ui": "16.17.8",
|
|
57
63
|
"jsdom": "^30.1.3",
|
|
58
64
|
"next": "^16.4.3",
|
|
59
65
|
"next-themes": "^0.4.6",
|
|
60
66
|
"react": "^19.3.1",
|
|
61
67
|
"react-dom": "^19.3.1",
|
|
62
68
|
"typescript": "^7.0.2",
|
|
63
|
-
"vitest": "^5.0.5"
|
|
69
|
+
"vitest": "^5.0.5",
|
|
70
|
+
"motion": "^14.6.0"
|
|
64
71
|
},
|
|
65
72
|
"publishConfig": {
|
|
66
73
|
"access": "public"
|
|
@@ -80,6 +87,9 @@
|
|
|
80
87
|
},
|
|
81
88
|
"react-dom": {
|
|
82
89
|
"optional": true
|
|
90
|
+
},
|
|
91
|
+
"motion": {
|
|
92
|
+
"optional": true
|
|
83
93
|
}
|
|
84
94
|
},
|
|
85
95
|
"scripts": {
|
package/src/config.ts
CHANGED
package/src/index.ts
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const DOCS_SIDEBAR_WIDTH = 260;
|