@nendlabs/docpage 0.1.1 → 0.1.2
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/dist/cn.js +5 -0
- package/dist/components/api-tabs.js +29 -0
- package/dist/components/code-block.js +53 -0
- package/dist/components/mermaid.js +44 -0
- package/dist/docpage.js +252 -0
- package/dist/hooks/use-active-scroll-section-ids.js +45 -0
- package/dist/hooks/use-color-scheme.js +27 -0
- package/dist/index.js +7 -832
- package/dist/types.js +1 -0
- package/package.json +3 -3
package/dist/cn.js
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useMemo, useState } from "react";
|
|
3
|
+
import { cn } from "../cn";
|
|
4
|
+
import { CodeBlock } from "./code-block";
|
|
5
|
+
function getInitialTabId(tabs, defaultTabId) {
|
|
6
|
+
if (defaultTabId && tabs.some((tab) => tab.id === defaultTabId)) {
|
|
7
|
+
return defaultTabId;
|
|
8
|
+
}
|
|
9
|
+
return tabs[0]?.id ?? "";
|
|
10
|
+
}
|
|
11
|
+
function getTabLabel(tab) {
|
|
12
|
+
if (tab.label)
|
|
13
|
+
return tab.label;
|
|
14
|
+
return tab.id.toUpperCase();
|
|
15
|
+
}
|
|
16
|
+
export function ApiTabs({ tabs, defaultTabId, className }) {
|
|
17
|
+
const [activeId, setActiveId] = useState(() => getInitialTabId(tabs, defaultTabId));
|
|
18
|
+
const activeTab = useMemo(() => {
|
|
19
|
+
return tabs.find((tab) => tab.id === activeId) ?? tabs[0];
|
|
20
|
+
}, [tabs, activeId]);
|
|
21
|
+
if (!activeTab)
|
|
22
|
+
return null;
|
|
23
|
+
return (_jsxs("div", { className: cn("docpage-api space-y-3", className), children: [_jsx("div", { className: "inline-flex rounded border border-border/80 bg-background/60 p-1", children: tabs.map((tab) => {
|
|
24
|
+
const isActive = activeTab.id === tab.id;
|
|
25
|
+
return (_jsx("button", { type: "button", onClick: () => setActiveId(tab.id), className: cn("rounded px-3 py-1 text-[11px] font-semibold tracking-[0.12em] transition-colors", isActive
|
|
26
|
+
? "bg-foreground text-background"
|
|
27
|
+
: "text-muted-foreground hover:text-foreground"), "aria-pressed": isActive, "data-docpage-tab": tab.id, children: getTabLabel(tab) }, tab.id));
|
|
28
|
+
}) }), _jsx(CodeBlock, { code: activeTab.code, language: activeTab.language ?? activeTab.id, preClassName: "text-xs" })] }));
|
|
29
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import hljs from "highlight.js/lib/core";
|
|
3
|
+
import bash from "highlight.js/lib/languages/bash";
|
|
4
|
+
import diff from "highlight.js/lib/languages/diff";
|
|
5
|
+
import javascript from "highlight.js/lib/languages/javascript";
|
|
6
|
+
import json from "highlight.js/lib/languages/json";
|
|
7
|
+
import typescript from "highlight.js/lib/languages/typescript";
|
|
8
|
+
import yaml from "highlight.js/lib/languages/yaml";
|
|
9
|
+
import { useEffect, useMemo, useRef } from "react";
|
|
10
|
+
import { cn } from "../cn";
|
|
11
|
+
let registered = false;
|
|
12
|
+
function registerLanguagesOnce() {
|
|
13
|
+
if (registered)
|
|
14
|
+
return;
|
|
15
|
+
hljs.registerLanguage("bash", bash);
|
|
16
|
+
hljs.registerLanguage("sh", bash);
|
|
17
|
+
hljs.registerLanguage("shell", bash);
|
|
18
|
+
hljs.registerLanguage("diff", diff);
|
|
19
|
+
hljs.registerLanguage("javascript", javascript);
|
|
20
|
+
hljs.registerLanguage("js", javascript);
|
|
21
|
+
hljs.registerLanguage("typescript", typescript);
|
|
22
|
+
hljs.registerLanguage("ts", typescript);
|
|
23
|
+
hljs.registerLanguage("json", json);
|
|
24
|
+
hljs.registerLanguage("yaml", yaml);
|
|
25
|
+
hljs.registerLanguage("yml", yaml);
|
|
26
|
+
registered = true;
|
|
27
|
+
}
|
|
28
|
+
export function CodeBlock({ code, language, caption, className, preClassName, codeClassName, }) {
|
|
29
|
+
const codeRef = useRef(null);
|
|
30
|
+
const languageClass = useMemo(() => {
|
|
31
|
+
if (!language)
|
|
32
|
+
return undefined;
|
|
33
|
+
return language.startsWith("language-") ? language : `language-${language}`;
|
|
34
|
+
}, [language]);
|
|
35
|
+
useEffect(() => {
|
|
36
|
+
registerLanguagesOnce();
|
|
37
|
+
const el = codeRef.current;
|
|
38
|
+
if (!el)
|
|
39
|
+
return;
|
|
40
|
+
try {
|
|
41
|
+
if (el.dataset.highlighted) {
|
|
42
|
+
delete el.dataset.highlighted;
|
|
43
|
+
}
|
|
44
|
+
hljs.highlightElement(el);
|
|
45
|
+
}
|
|
46
|
+
catch (error) {
|
|
47
|
+
if (import.meta.env?.DEV) {
|
|
48
|
+
console.error("docpage: highlight.js failed", error);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}, [code, languageClass]);
|
|
52
|
+
return (_jsxs("figure", { className: cn("docpage-code", className), children: [_jsx("pre", { className: cn("bg-muted/40 overflow-x-auto whitespace-pre-wrap rounded p-3 text-xs leading-6", preClassName), children: _jsx("code", { ref: codeRef, className: cn("hljs", languageClass, codeClassName), children: code }) }), caption ? (_jsx("figcaption", { className: "mt-2 text-xs text-muted-foreground", children: caption })) : null] }));
|
|
53
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useEffect, useId, useRef } from "react";
|
|
3
|
+
export function Mermaid({ chart }) {
|
|
4
|
+
const ref = useRef(null);
|
|
5
|
+
const ridRaw = useId();
|
|
6
|
+
const rid = ridRaw.replace(/:/g, "");
|
|
7
|
+
useEffect(() => {
|
|
8
|
+
let cancelled = false;
|
|
9
|
+
const mql = typeof window !== "undefined" && window.matchMedia
|
|
10
|
+
? window.matchMedia("(prefers-color-scheme: dark)")
|
|
11
|
+
: null;
|
|
12
|
+
async function render() {
|
|
13
|
+
try {
|
|
14
|
+
const mermaid = (await import("mermaid")).default;
|
|
15
|
+
const theme = mql?.matches ? "dark" : "default";
|
|
16
|
+
mermaid.initialize({ startOnLoad: false, theme });
|
|
17
|
+
const { svg } = await mermaid.render(`mmd-${rid}`, chart);
|
|
18
|
+
if (!cancelled && ref.current) {
|
|
19
|
+
ref.current.innerHTML = svg;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
catch (error) {
|
|
23
|
+
if (ref.current) {
|
|
24
|
+
const safeChart = chart.replaceAll("<", "<");
|
|
25
|
+
ref.current.innerHTML = `<pre class="text-xs p-3 rounded bg-muted/40 overflow-x-auto">${safeChart}</pre>`;
|
|
26
|
+
}
|
|
27
|
+
if (import.meta.env?.DEV) {
|
|
28
|
+
console.error("docpage: failed to render mermaid", error);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
void render();
|
|
33
|
+
const onChange = () => {
|
|
34
|
+
if (!cancelled)
|
|
35
|
+
void render();
|
|
36
|
+
};
|
|
37
|
+
mql?.addEventListener?.("change", onChange);
|
|
38
|
+
return () => {
|
|
39
|
+
cancelled = true;
|
|
40
|
+
mql?.removeEventListener?.("change", onChange);
|
|
41
|
+
};
|
|
42
|
+
}, [chart, rid]);
|
|
43
|
+
return _jsx("div", { ref: ref, "data-docpage-mermaid": true });
|
|
44
|
+
}
|
package/dist/docpage.js
ADDED
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { ArrowRight } from "lucide-react";
|
|
3
|
+
import { Children, isValidElement, useEffect, useMemo, useState, } from "react";
|
|
4
|
+
import { MDXProvider } from "@mdx-js/react";
|
|
5
|
+
import { cn } from "./cn";
|
|
6
|
+
import { ApiTabs } from "./components/api-tabs";
|
|
7
|
+
import { CodeBlock } from "./components/code-block";
|
|
8
|
+
import { Mermaid } from "./components/mermaid";
|
|
9
|
+
import { useActiveScrollSectionIds } from "./hooks/use-active-scroll-section-ids";
|
|
10
|
+
import { useColorScheme } from "./hooks/use-color-scheme";
|
|
11
|
+
const TOKEN_VAR_MAP = {
|
|
12
|
+
background: "background",
|
|
13
|
+
foreground: "foreground",
|
|
14
|
+
card: "card",
|
|
15
|
+
cardForeground: "card-foreground",
|
|
16
|
+
popover: "popover",
|
|
17
|
+
popoverForeground: "popover-foreground",
|
|
18
|
+
primary: "primary",
|
|
19
|
+
primaryForeground: "primary-foreground",
|
|
20
|
+
secondary: "secondary",
|
|
21
|
+
secondaryForeground: "secondary-foreground",
|
|
22
|
+
muted: "muted",
|
|
23
|
+
mutedForeground: "muted-foreground",
|
|
24
|
+
accent: "accent",
|
|
25
|
+
accentForeground: "accent-foreground",
|
|
26
|
+
destructive: "destructive",
|
|
27
|
+
destructiveForeground: "destructive-foreground",
|
|
28
|
+
border: "border",
|
|
29
|
+
input: "input",
|
|
30
|
+
ring: "ring",
|
|
31
|
+
chart1: "chart-1",
|
|
32
|
+
chart2: "chart-2",
|
|
33
|
+
chart3: "chart-3",
|
|
34
|
+
chart4: "chart-4",
|
|
35
|
+
chart5: "chart-5",
|
|
36
|
+
radius: "radius",
|
|
37
|
+
};
|
|
38
|
+
function setTokenVars(style, tokens, scheme) {
|
|
39
|
+
if (!tokens)
|
|
40
|
+
return;
|
|
41
|
+
Object.keys(tokens).forEach((key) => {
|
|
42
|
+
const value = tokens[key];
|
|
43
|
+
if (!value)
|
|
44
|
+
return;
|
|
45
|
+
const varKey = TOKEN_VAR_MAP[key];
|
|
46
|
+
style[`--docpage-${varKey}-${scheme}`] = value;
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
function themeToStyle(config) {
|
|
50
|
+
const style = {};
|
|
51
|
+
setTokenVars(style, config.theme?.light, "light");
|
|
52
|
+
setTokenVars(style, config.theme?.dark, "dark");
|
|
53
|
+
return style;
|
|
54
|
+
}
|
|
55
|
+
function startCaseId(id) {
|
|
56
|
+
const withSpaces = id.replace(/[-_]/g, " ").trim();
|
|
57
|
+
if (!withSpaces)
|
|
58
|
+
return id;
|
|
59
|
+
return withSpaces.replace(/\b\w/g, (c) => c.toUpperCase());
|
|
60
|
+
}
|
|
61
|
+
function deriveToc(config) {
|
|
62
|
+
if (config.toc && config.toc.length > 0)
|
|
63
|
+
return config.toc;
|
|
64
|
+
return config.sections.map((section) => {
|
|
65
|
+
const labelFromTitle = typeof section.title === "string" ? section.title : undefined;
|
|
66
|
+
return {
|
|
67
|
+
id: section.id,
|
|
68
|
+
label: section.label ?? labelFromTitle ?? startCaseId(section.id),
|
|
69
|
+
};
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
function useIsWide(minWidthPx) {
|
|
73
|
+
const [isWide, setIsWide] = useState(() => {
|
|
74
|
+
if (typeof window === "undefined" || !window.matchMedia)
|
|
75
|
+
return true;
|
|
76
|
+
return window.matchMedia(`(min-width: ${minWidthPx}px)`).matches;
|
|
77
|
+
});
|
|
78
|
+
useEffect(() => {
|
|
79
|
+
if (!window.matchMedia)
|
|
80
|
+
return;
|
|
81
|
+
const mql = window.matchMedia(`(min-width: ${minWidthPx}px)`);
|
|
82
|
+
const update = (event) => {
|
|
83
|
+
if (event) {
|
|
84
|
+
setIsWide(event.matches);
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
setIsWide(mql.matches);
|
|
88
|
+
};
|
|
89
|
+
update();
|
|
90
|
+
mql.addEventListener?.("change", update);
|
|
91
|
+
return () => mql.removeEventListener?.("change", update);
|
|
92
|
+
}, [minWidthPx]);
|
|
93
|
+
return isWide;
|
|
94
|
+
}
|
|
95
|
+
function Container({ children }) {
|
|
96
|
+
return (_jsx("div", { className: "mx-auto w-full max-w-6xl px-4 sm:px-6 lg:px-8", children: children }));
|
|
97
|
+
}
|
|
98
|
+
function Prose({ children }) {
|
|
99
|
+
return (_jsx("div", { className: cn("docpage-prose mx-auto max-w-3xl text-base leading-7 text-foreground/80", "[&>section>h2]:text-foreground [&_p]:text-foreground/80 [&_li]:text-foreground/80", "[&>section>h2]:mb-6 [&>section>h2]:text-2xl [&>section>h2]:font-semibold [&>section>h2]:tracking-tight", "[&>section>p]:my-4 [&_code]:font-mono [&_code]:text-[0.85em]", "[&_pre]:rounded [&_pre]:p-0 [&_pre]:text-xs [&_pre]:leading-6"), children: children }));
|
|
100
|
+
}
|
|
101
|
+
function getCalloutToneClasses(tone) {
|
|
102
|
+
switch (tone) {
|
|
103
|
+
case "info":
|
|
104
|
+
return "border-primary/30 bg-primary/5";
|
|
105
|
+
case "warn":
|
|
106
|
+
return "border-amber-500/40 bg-amber-500/10";
|
|
107
|
+
case "danger":
|
|
108
|
+
return "border-destructive/50 bg-destructive/10";
|
|
109
|
+
case "neutral":
|
|
110
|
+
default:
|
|
111
|
+
return "border-border/70 bg-muted/20";
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
function renderBlock(block) {
|
|
115
|
+
switch (block.kind) {
|
|
116
|
+
case "p":
|
|
117
|
+
return _jsx("p", { className: "my-4", children: block.text });
|
|
118
|
+
case "ul":
|
|
119
|
+
return (_jsx("ul", { className: "marker:text-muted-foreground list-disc pl-6", children: block.items.map((item, index) => (_jsx("li", { className: "my-2", children: item }, index))) }));
|
|
120
|
+
case "ol":
|
|
121
|
+
return (_jsx("ol", { className: "marker:text-muted-foreground list-decimal pl-6", children: block.items.map((item, index) => (_jsx("li", { className: "my-2", children: item }, index))) }));
|
|
122
|
+
case "labeled-list":
|
|
123
|
+
return (_jsx("ul", { className: "marker:text-muted-foreground list-disc pl-6", children: block.items.map((item, index) => (_jsxs("li", { className: "my-2", children: [_jsxs("strong", { children: [item.label, ":"] }), " ", item.text] }, index))) }));
|
|
124
|
+
case "code":
|
|
125
|
+
return (_jsx("div", { className: "my-6", children: _jsx(CodeBlock, { code: block.code, language: block.language, caption: block.caption }) }));
|
|
126
|
+
case "pre":
|
|
127
|
+
return (_jsx("pre", { className: "bg-muted/40 my-6 whitespace-pre-wrap rounded p-3 text-xs", children: block.code }));
|
|
128
|
+
case "mermaid":
|
|
129
|
+
return (_jsxs("figure", { className: "my-6", children: [_jsx("div", { className: "bg-background rounded border border-border/80 p-4", children: _jsx(Mermaid, { chart: block.chart }) }), block.caption ? (_jsx("figcaption", { className: "mt-2 text-xs text-muted-foreground", children: block.caption })) : null] }));
|
|
130
|
+
case "callout":
|
|
131
|
+
return (_jsxs("div", { className: cn("my-6 rounded-lg border p-4", getCalloutToneClasses(block.tone)), children: [block.title ? (_jsx("div", { className: "text-sm font-semibold text-foreground", children: block.title })) : null, _jsx("div", { className: cn("text-sm leading-relaxed", block.title ? "mt-1" : undefined), children: block.body })] }));
|
|
132
|
+
case "node":
|
|
133
|
+
return _jsx("div", { className: "my-4", children: block.node });
|
|
134
|
+
default:
|
|
135
|
+
return null;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
function getLanguageFromClassName(className) {
|
|
139
|
+
if (!className)
|
|
140
|
+
return undefined;
|
|
141
|
+
if (className.startsWith("language-")) {
|
|
142
|
+
return className.replace("language-", "");
|
|
143
|
+
}
|
|
144
|
+
return className;
|
|
145
|
+
}
|
|
146
|
+
function toCodeString(value) {
|
|
147
|
+
if (typeof value === "string")
|
|
148
|
+
return value;
|
|
149
|
+
if (typeof value === "number" || typeof value === "boolean")
|
|
150
|
+
return String(value);
|
|
151
|
+
if (value == null)
|
|
152
|
+
return "";
|
|
153
|
+
return String(value);
|
|
154
|
+
}
|
|
155
|
+
export function MdxCodeBlockPre(props) {
|
|
156
|
+
const child = Children.count(props.children) === 1 ? Children.only(props.children) : null;
|
|
157
|
+
if (child && isValidElement(child)) {
|
|
158
|
+
const codeChild = child;
|
|
159
|
+
const language = getLanguageFromClassName(codeChild.props.className);
|
|
160
|
+
const code = toCodeString(codeChild.props.children);
|
|
161
|
+
return _jsx(CodeBlock, { code: code, language: language });
|
|
162
|
+
}
|
|
163
|
+
return (_jsx("pre", { ...props, className: cn("bg-muted/40 overflow-x-auto whitespace-pre-wrap rounded p-3 text-xs leading-6", props.className) }));
|
|
164
|
+
}
|
|
165
|
+
function buildMdxComponents(section) {
|
|
166
|
+
const defaults = {
|
|
167
|
+
pre: MdxCodeBlockPre,
|
|
168
|
+
};
|
|
169
|
+
return {
|
|
170
|
+
...defaults,
|
|
171
|
+
...(section.components ?? {}),
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
function getSectionTitle(section, tocMap) {
|
|
175
|
+
if (section.title)
|
|
176
|
+
return section.title;
|
|
177
|
+
const fromToc = tocMap.get(section.id);
|
|
178
|
+
return fromToc ?? startCaseId(section.id);
|
|
179
|
+
}
|
|
180
|
+
function SectionHeading({ title, titleBorder, }) {
|
|
181
|
+
return (_jsx("h2", { className: cn("mb-8 mt-12 text-2xl font-semibold tracking-tight first:mt-0", titleBorder ? "border-muted border-b pb-2" : "pb-2"), children: title }));
|
|
182
|
+
}
|
|
183
|
+
function Nav({ config }) {
|
|
184
|
+
const [scrolled, setScrolled] = useState(false);
|
|
185
|
+
useEffect(() => {
|
|
186
|
+
const onScroll = () => setScrolled(window.scrollY > 8);
|
|
187
|
+
onScroll();
|
|
188
|
+
window.addEventListener("scroll", onScroll, { passive: true });
|
|
189
|
+
return () => window.removeEventListener("scroll", onScroll);
|
|
190
|
+
}, []);
|
|
191
|
+
const signInLabel = config.nav?.signInLabel ?? "sign in";
|
|
192
|
+
const signInHref = config.nav?.signInHref ?? "/login";
|
|
193
|
+
return (_jsx("div", { className: cn("sticky top-0 z-40 w-full backdrop-blur", scrolled ? "border-b border-border/80 bg-background/80" : "bg-background/60"), "data-docpage-nav": true, children: _jsx(Container, { children: _jsxs("div", { className: "flex h-14 items-center justify-between", children: [_jsx(Brand, { brand: config.brand }), config.nav?.rightSlot ? (config.nav.rightSlot) : (_jsxs("a", { href: signInHref, className: cn("group inline-flex items-center rounded-md border border-border/80 px-3 py-1.5 text-xs font-semibold uppercase tracking-[0.2em]", "text-foreground transition hover:border-foreground/60 hover:bg-foreground hover:text-background"), "data-docpage-signin": true, children: [signInLabel, _jsx(ArrowRight, { className: "ml-1 h-4 w-4 transition-transform group-hover:translate-x-0.5" })] }))] }) }) }));
|
|
194
|
+
}
|
|
195
|
+
function Brand({ brand }) {
|
|
196
|
+
const content = brand.logo ? (_jsx("div", { className: "flex items-center gap-2", children: brand.logo })) : (_jsx("span", { className: "text-sm font-semibold tracking-[0.2em] uppercase", children: brand.name }));
|
|
197
|
+
if (!brand.href)
|
|
198
|
+
return content;
|
|
199
|
+
return (_jsx("a", { href: brand.href, className: "inline-flex items-center text-foreground", "data-docpage-brand": true, children: content }));
|
|
200
|
+
}
|
|
201
|
+
function Toc({ entries, activeId, title, }) {
|
|
202
|
+
return (_jsxs("nav", { "aria-label": "Table of contents", className: "text-sm", "data-docpage-toc": true, children: [_jsx("div", { className: "mb-2 font-medium text-foreground", children: title }), _jsx("ol", { className: "space-y-1", children: entries.map((entry) => {
|
|
203
|
+
const isActive = activeId === entry.id;
|
|
204
|
+
return (_jsx("li", { children: _jsx("a", { href: `#${entry.id}`, className: cn("block rounded px-2 py-1 transition-colors", isActive
|
|
205
|
+
? "font-semibold text-foreground"
|
|
206
|
+
: "text-muted-foreground hover:text-foreground"), onClick: () => history.replaceState(null, "", `#${entry.id}`), "data-docpage-toc-link": entry.id, "aria-current": isActive ? "true" : undefined, children: entry.label }) }, entry.id));
|
|
207
|
+
}) })] }));
|
|
208
|
+
}
|
|
209
|
+
function Header({ config }) {
|
|
210
|
+
return (_jsx(Container, { children: _jsxs("header", { className: "py-12", "data-docpage-header": true, children: [config.header.kicker ? (_jsx("div", { className: "mb-3 text-xs font-semibold uppercase tracking-[0.3em] text-muted-foreground", children: config.header.kicker })) : null, _jsx("h1", { className: "mb-2 text-4xl font-bold tracking-tight sm:text-5xl lg:text-6xl", children: config.header.title }), config.header.subtitle ? (_jsx("p", { className: "max-w-2xl text-lg text-muted-foreground", children: config.header.subtitle })) : null] }) }));
|
|
211
|
+
}
|
|
212
|
+
function renderSection(section, tocMap) {
|
|
213
|
+
const title = getSectionTitle(section, tocMap);
|
|
214
|
+
switch (section.kind) {
|
|
215
|
+
case "prose":
|
|
216
|
+
return (_jsxs("section", { id: section.id, className: cn("scroll-mt-24", section.className), "data-docpage-section": section.id, children: [!section.hideTitle ? (_jsx(SectionHeading, { title: title, titleBorder: section.titleBorder })) : null, _jsx("div", { className: "space-y-4", children: section.blocks.map((block, index) => _jsx("div", { children: renderBlock(block) }, index)) })] }, section.id));
|
|
217
|
+
case "tabs":
|
|
218
|
+
return (_jsxs("section", { id: section.id, className: cn("scroll-mt-24", section.className), "data-docpage-section": section.id, children: [!section.hideTitle ? (_jsx(SectionHeading, { title: title, titleBorder: section.titleBorder })) : null, section.intro ? _jsx("p", { className: "mt-4", children: section.intro }) : null, _jsx("div", { className: "mt-4", children: _jsx(ApiTabs, { tabs: section.tabs, defaultTabId: section.defaultTabId }) })] }, section.id));
|
|
219
|
+
case "mdx": {
|
|
220
|
+
const components = buildMdxComponents(section);
|
|
221
|
+
return (_jsxs("section", { id: section.id, className: cn("scroll-mt-24", section.className), "data-docpage-section": section.id, children: [!section.hideTitle ? (_jsx(SectionHeading, { title: title, titleBorder: section.titleBorder })) : null, _jsx("div", { className: "docpage-mdx", children: _jsx(MDXProvider, { components: components, children: _jsx(section.Component, {}) }) })] }, section.id));
|
|
222
|
+
}
|
|
223
|
+
default:
|
|
224
|
+
return null;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
function Footer({ config }) {
|
|
228
|
+
const footer = config.footer;
|
|
229
|
+
if (!footer)
|
|
230
|
+
return null;
|
|
231
|
+
const year = new Date().getFullYear();
|
|
232
|
+
return (_jsx("footer", { className: "border-t border-border/80 py-10 text-sm text-muted-foreground", "data-docpage-footer": true, children: _jsx(Container, { children: _jsxs("div", { className: "flex flex-col items-start justify-between gap-4 md:flex-row md:items-center", children: [footer.links && footer.links.length > 0 ? (_jsx("div", { className: "flex flex-wrap items-center gap-4", children: footer.links.map((link) => (_jsx("a", { className: "hover:text-foreground", href: link.href, children: link.label }, link.href))) })) : null, _jsxs("div", { className: "flex flex-col gap-1 md:items-end", children: [_jsxs("div", { children: ["\u00A9 ", year, " ", footer.copyrightName ?? config.brand.name] }), footer.note ? _jsx("div", { className: "text-xs", children: footer.note }) : null] })] }) }) }));
|
|
233
|
+
}
|
|
234
|
+
export function DocPage({ config, className }) {
|
|
235
|
+
const tocEntries = useMemo(() => deriveToc(config), [config]);
|
|
236
|
+
const tocIds = tocEntries.map((entry) => entry.id);
|
|
237
|
+
const tocTitle = config.tocTitle ?? "Contents";
|
|
238
|
+
const tocMap = useMemo(() => {
|
|
239
|
+
return new Map(tocEntries.map((entry) => [entry.id, entry.label]));
|
|
240
|
+
}, [tocEntries]);
|
|
241
|
+
const tocActiveId = useActiveScrollSectionIds(tocIds, {
|
|
242
|
+
rootMargin: config.options?.tocRootMargin,
|
|
243
|
+
threshold: config.options?.tocThreshold,
|
|
244
|
+
syncToUrl: config.options?.syncTocToUrl ?? true,
|
|
245
|
+
});
|
|
246
|
+
const tocMinWidthPx = config.options?.tocMinWidthPx ?? 768;
|
|
247
|
+
const isWide = useIsWide(tocMinWidthPx);
|
|
248
|
+
const scheme = useColorScheme();
|
|
249
|
+
const themeStyle = themeToStyle(config);
|
|
250
|
+
const mergedStyle = { ...themeStyle, ...(config.style ?? {}) };
|
|
251
|
+
return (_jsxs("div", { className: cn("docpage min-h-[100dvh] bg-background text-foreground", config.className, className), style: mergedStyle, "data-docpage": true, "data-docpage-theme": scheme, children: [_jsx(Nav, { config: config }), _jsx(Header, { config: config }), _jsx(Container, { children: _jsxs("div", { className: "grid grid-cols-1 gap-10 md:grid-cols-[260px_minmax(0,1fr)]", "data-docpage-body": true, children: [_jsx("aside", { className: "hidden max-h-[calc(100vh-7rem)] overflow-auto pr-4 md:sticky md:top-24 md:block", style: isWide ? undefined : { display: "none" }, children: _jsx(Toc, { entries: tocEntries, activeId: tocActiveId, title: tocTitle }) }), _jsx("main", { className: "pb-24", children: _jsx(Prose, { children: config.sections.map((section) => renderSection(section, tocMap)) }) })] }) }), _jsx(Footer, { config: config })] }));
|
|
252
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { useEffect, useMemo, useState } from "react";
|
|
2
|
+
function getInitialActiveId(ids) {
|
|
3
|
+
if (typeof window === "undefined") {
|
|
4
|
+
return ids[0] ?? "";
|
|
5
|
+
}
|
|
6
|
+
const hash = window.location.hash.replace("#", "");
|
|
7
|
+
return hash && ids.includes(hash) ? hash : ids[0] ?? "";
|
|
8
|
+
}
|
|
9
|
+
export function useActiveScrollSectionIds(ids, options) {
|
|
10
|
+
const memoIds = useMemo(() => ids.filter(Boolean), [ids]);
|
|
11
|
+
const [active, setActive] = useState(() => getInitialActiveId(memoIds));
|
|
12
|
+
useEffect(() => {
|
|
13
|
+
if (memoIds.length === 0)
|
|
14
|
+
return;
|
|
15
|
+
const observer = new IntersectionObserver((entries) => {
|
|
16
|
+
const visible = entries
|
|
17
|
+
.filter((entry) => entry.isIntersecting)
|
|
18
|
+
.sort((a, b) => a.boundingClientRect.top > b.boundingClientRect.top ? 1 : -1);
|
|
19
|
+
if (!visible[0])
|
|
20
|
+
return;
|
|
21
|
+
const id = visible[0].target.id;
|
|
22
|
+
if (!id)
|
|
23
|
+
return;
|
|
24
|
+
setActive((prev) => (prev === id ? prev : id));
|
|
25
|
+
}, {
|
|
26
|
+
rootMargin: options?.rootMargin ?? "-20% 0px -70% 0px",
|
|
27
|
+
threshold: options?.threshold ?? [0, 1],
|
|
28
|
+
});
|
|
29
|
+
memoIds.forEach((id) => {
|
|
30
|
+
const el = document.getElementById(id);
|
|
31
|
+
if (el)
|
|
32
|
+
observer.observe(el);
|
|
33
|
+
});
|
|
34
|
+
return () => observer.disconnect();
|
|
35
|
+
}, [memoIds, options?.rootMargin, options?.threshold]);
|
|
36
|
+
useEffect(() => {
|
|
37
|
+
if (!options?.syncToUrl || !active)
|
|
38
|
+
return;
|
|
39
|
+
const current = window.location.hash.replace("#", "");
|
|
40
|
+
if (current !== active) {
|
|
41
|
+
history.replaceState(null, "", `#${active}`);
|
|
42
|
+
}
|
|
43
|
+
}, [active, options?.syncToUrl]);
|
|
44
|
+
return active;
|
|
45
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { useEffect, useState } from "react";
|
|
2
|
+
function getInitialScheme() {
|
|
3
|
+
if (typeof window === "undefined" || !window.matchMedia)
|
|
4
|
+
return "light";
|
|
5
|
+
return window.matchMedia("(prefers-color-scheme: dark)").matches
|
|
6
|
+
? "dark"
|
|
7
|
+
: "light";
|
|
8
|
+
}
|
|
9
|
+
export function useColorScheme() {
|
|
10
|
+
const [scheme, setScheme] = useState(() => getInitialScheme());
|
|
11
|
+
useEffect(() => {
|
|
12
|
+
if (!window.matchMedia)
|
|
13
|
+
return;
|
|
14
|
+
const mql = window.matchMedia("(prefers-color-scheme: dark)");
|
|
15
|
+
const update = (event) => {
|
|
16
|
+
if (event) {
|
|
17
|
+
setScheme(event.matches ? "dark" : "light");
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
setScheme(mql.matches ? "dark" : "light");
|
|
21
|
+
};
|
|
22
|
+
update();
|
|
23
|
+
mql.addEventListener?.("change", update);
|
|
24
|
+
return () => mql.removeEventListener?.("change", update);
|
|
25
|
+
}, []);
|
|
26
|
+
return scheme;
|
|
27
|
+
}
|
package/dist/index.js
CHANGED
|
@@ -1,832 +1,7 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
|
|
9
|
-
for (let key of __getOwnPropNames(mod))
|
|
10
|
-
if (!__hasOwnProp.call(to, key))
|
|
11
|
-
__defProp(to, key, {
|
|
12
|
-
get: () => mod[key],
|
|
13
|
-
enumerable: true
|
|
14
|
-
});
|
|
15
|
-
return to;
|
|
16
|
-
};
|
|
17
|
-
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
18
|
-
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
19
|
-
}) : x)(function(x) {
|
|
20
|
-
if (typeof require !== "undefined")
|
|
21
|
-
return require.apply(this, arguments);
|
|
22
|
-
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
// src/cn.ts
|
|
26
|
-
import { clsx } from "clsx";
|
|
27
|
-
import { twMerge } from "tailwind-merge";
|
|
28
|
-
function cn(...inputs) {
|
|
29
|
-
return twMerge(clsx(inputs));
|
|
30
|
-
}
|
|
31
|
-
// src/docpage.tsx
|
|
32
|
-
import { ArrowRight } from "lucide-react";
|
|
33
|
-
import {
|
|
34
|
-
Children,
|
|
35
|
-
isValidElement,
|
|
36
|
-
useEffect as useEffect5,
|
|
37
|
-
useMemo as useMemo4,
|
|
38
|
-
useState as useState4
|
|
39
|
-
} from "react";
|
|
40
|
-
import { MDXProvider } from "@mdx-js/react";
|
|
41
|
-
|
|
42
|
-
// src/components/api-tabs.tsx
|
|
43
|
-
import { useMemo as useMemo2, useState } from "react";
|
|
44
|
-
|
|
45
|
-
// src/components/code-block.tsx
|
|
46
|
-
import hljs from "highlight.js/lib/core";
|
|
47
|
-
import bash from "highlight.js/lib/languages/bash";
|
|
48
|
-
import diff from "highlight.js/lib/languages/diff";
|
|
49
|
-
import javascript from "highlight.js/lib/languages/javascript";
|
|
50
|
-
import json from "highlight.js/lib/languages/json";
|
|
51
|
-
import typescript from "highlight.js/lib/languages/typescript";
|
|
52
|
-
import yaml from "highlight.js/lib/languages/yaml";
|
|
53
|
-
import { useEffect, useMemo, useRef } from "react";
|
|
54
|
-
import { jsxDEV } from "react/jsx-dev-runtime";
|
|
55
|
-
var registered = false;
|
|
56
|
-
function registerLanguagesOnce() {
|
|
57
|
-
if (registered)
|
|
58
|
-
return;
|
|
59
|
-
hljs.registerLanguage("bash", bash);
|
|
60
|
-
hljs.registerLanguage("sh", bash);
|
|
61
|
-
hljs.registerLanguage("shell", bash);
|
|
62
|
-
hljs.registerLanguage("diff", diff);
|
|
63
|
-
hljs.registerLanguage("javascript", javascript);
|
|
64
|
-
hljs.registerLanguage("js", javascript);
|
|
65
|
-
hljs.registerLanguage("typescript", typescript);
|
|
66
|
-
hljs.registerLanguage("ts", typescript);
|
|
67
|
-
hljs.registerLanguage("json", json);
|
|
68
|
-
hljs.registerLanguage("yaml", yaml);
|
|
69
|
-
hljs.registerLanguage("yml", yaml);
|
|
70
|
-
registered = true;
|
|
71
|
-
}
|
|
72
|
-
function CodeBlock({
|
|
73
|
-
code,
|
|
74
|
-
language,
|
|
75
|
-
caption,
|
|
76
|
-
className,
|
|
77
|
-
preClassName,
|
|
78
|
-
codeClassName
|
|
79
|
-
}) {
|
|
80
|
-
const codeRef = useRef(null);
|
|
81
|
-
const languageClass = useMemo(() => {
|
|
82
|
-
if (!language)
|
|
83
|
-
return;
|
|
84
|
-
return language.startsWith("language-") ? language : `language-${language}`;
|
|
85
|
-
}, [language]);
|
|
86
|
-
useEffect(() => {
|
|
87
|
-
registerLanguagesOnce();
|
|
88
|
-
const el = codeRef.current;
|
|
89
|
-
if (!el)
|
|
90
|
-
return;
|
|
91
|
-
try {
|
|
92
|
-
if (el.dataset.highlighted) {
|
|
93
|
-
delete el.dataset.highlighted;
|
|
94
|
-
}
|
|
95
|
-
hljs.highlightElement(el);
|
|
96
|
-
} catch (error) {
|
|
97
|
-
if (import.meta.env?.DEV) {
|
|
98
|
-
console.error("docpage: highlight.js failed", error);
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
}, [code, languageClass]);
|
|
102
|
-
return /* @__PURE__ */ jsxDEV("figure", {
|
|
103
|
-
className: cn("docpage-code", className),
|
|
104
|
-
children: [
|
|
105
|
-
/* @__PURE__ */ jsxDEV("pre", {
|
|
106
|
-
className: cn("bg-muted/40 overflow-x-auto whitespace-pre-wrap rounded p-3 text-xs leading-6", preClassName),
|
|
107
|
-
children: /* @__PURE__ */ jsxDEV("code", {
|
|
108
|
-
ref: codeRef,
|
|
109
|
-
className: cn("hljs", languageClass, codeClassName),
|
|
110
|
-
children: code
|
|
111
|
-
}, undefined, false, undefined, this)
|
|
112
|
-
}, undefined, false, undefined, this),
|
|
113
|
-
caption ? /* @__PURE__ */ jsxDEV("figcaption", {
|
|
114
|
-
className: "mt-2 text-xs text-muted-foreground",
|
|
115
|
-
children: caption
|
|
116
|
-
}, undefined, false, undefined, this) : null
|
|
117
|
-
]
|
|
118
|
-
}, undefined, true, undefined, this);
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
// src/components/api-tabs.tsx
|
|
122
|
-
import { jsxDEV as jsxDEV2 } from "react/jsx-dev-runtime";
|
|
123
|
-
function getInitialTabId(tabs, defaultTabId) {
|
|
124
|
-
if (defaultTabId && tabs.some((tab) => tab.id === defaultTabId)) {
|
|
125
|
-
return defaultTabId;
|
|
126
|
-
}
|
|
127
|
-
return tabs[0]?.id ?? "";
|
|
128
|
-
}
|
|
129
|
-
function getTabLabel(tab) {
|
|
130
|
-
if (tab.label)
|
|
131
|
-
return tab.label;
|
|
132
|
-
return tab.id.toUpperCase();
|
|
133
|
-
}
|
|
134
|
-
function ApiTabs({ tabs, defaultTabId, className }) {
|
|
135
|
-
const [activeId, setActiveId] = useState(() => getInitialTabId(tabs, defaultTabId));
|
|
136
|
-
const activeTab = useMemo2(() => {
|
|
137
|
-
return tabs.find((tab) => tab.id === activeId) ?? tabs[0];
|
|
138
|
-
}, [tabs, activeId]);
|
|
139
|
-
if (!activeTab)
|
|
140
|
-
return null;
|
|
141
|
-
return /* @__PURE__ */ jsxDEV2("div", {
|
|
142
|
-
className: cn("docpage-api space-y-3", className),
|
|
143
|
-
children: [
|
|
144
|
-
/* @__PURE__ */ jsxDEV2("div", {
|
|
145
|
-
className: "inline-flex rounded border border-border/80 bg-background/60 p-1",
|
|
146
|
-
children: tabs.map((tab) => {
|
|
147
|
-
const isActive = activeTab.id === tab.id;
|
|
148
|
-
return /* @__PURE__ */ jsxDEV2("button", {
|
|
149
|
-
type: "button",
|
|
150
|
-
onClick: () => setActiveId(tab.id),
|
|
151
|
-
className: cn("rounded px-3 py-1 text-[11px] font-semibold tracking-[0.12em] transition-colors", isActive ? "bg-foreground text-background" : "text-muted-foreground hover:text-foreground"),
|
|
152
|
-
"aria-pressed": isActive,
|
|
153
|
-
"data-docpage-tab": tab.id,
|
|
154
|
-
children: getTabLabel(tab)
|
|
155
|
-
}, tab.id, false, undefined, this);
|
|
156
|
-
})
|
|
157
|
-
}, undefined, false, undefined, this),
|
|
158
|
-
/* @__PURE__ */ jsxDEV2(CodeBlock, {
|
|
159
|
-
code: activeTab.code,
|
|
160
|
-
language: activeTab.language ?? activeTab.id,
|
|
161
|
-
preClassName: "text-xs"
|
|
162
|
-
}, undefined, false, undefined, this)
|
|
163
|
-
]
|
|
164
|
-
}, undefined, true, undefined, this);
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
// src/components/mermaid.tsx
|
|
168
|
-
import { useEffect as useEffect2, useId, useRef as useRef2 } from "react";
|
|
169
|
-
import { jsxDEV as jsxDEV3 } from "react/jsx-dev-runtime";
|
|
170
|
-
function Mermaid({ chart }) {
|
|
171
|
-
const ref = useRef2(null);
|
|
172
|
-
const ridRaw = useId();
|
|
173
|
-
const rid = ridRaw.replace(/:/g, "");
|
|
174
|
-
useEffect2(() => {
|
|
175
|
-
let cancelled = false;
|
|
176
|
-
const mql = typeof window !== "undefined" && window.matchMedia ? window.matchMedia("(prefers-color-scheme: dark)") : null;
|
|
177
|
-
async function render() {
|
|
178
|
-
try {
|
|
179
|
-
const mermaid = (await import("mermaid")).default;
|
|
180
|
-
const theme = mql?.matches ? "dark" : "default";
|
|
181
|
-
mermaid.initialize({ startOnLoad: false, theme });
|
|
182
|
-
const { svg } = await mermaid.render(`mmd-${rid}`, chart);
|
|
183
|
-
if (!cancelled && ref.current) {
|
|
184
|
-
ref.current.innerHTML = svg;
|
|
185
|
-
}
|
|
186
|
-
} catch (error) {
|
|
187
|
-
if (ref.current) {
|
|
188
|
-
const safeChart = chart.replaceAll("<", "<");
|
|
189
|
-
ref.current.innerHTML = `<pre class="text-xs p-3 rounded bg-muted/40 overflow-x-auto">${safeChart}</pre>`;
|
|
190
|
-
}
|
|
191
|
-
if (import.meta.env?.DEV) {
|
|
192
|
-
console.error("docpage: failed to render mermaid", error);
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
render();
|
|
197
|
-
const onChange = () => {
|
|
198
|
-
if (!cancelled)
|
|
199
|
-
render();
|
|
200
|
-
};
|
|
201
|
-
mql?.addEventListener?.("change", onChange);
|
|
202
|
-
return () => {
|
|
203
|
-
cancelled = true;
|
|
204
|
-
mql?.removeEventListener?.("change", onChange);
|
|
205
|
-
};
|
|
206
|
-
}, [chart, rid]);
|
|
207
|
-
return /* @__PURE__ */ jsxDEV3("div", {
|
|
208
|
-
ref,
|
|
209
|
-
"data-docpage-mermaid": true
|
|
210
|
-
}, undefined, false, undefined, this);
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
// src/hooks/use-active-scroll-section-ids.tsx
|
|
214
|
-
import { useEffect as useEffect3, useMemo as useMemo3, useState as useState2 } from "react";
|
|
215
|
-
function getInitialActiveId(ids) {
|
|
216
|
-
if (typeof window === "undefined") {
|
|
217
|
-
return ids[0] ?? "";
|
|
218
|
-
}
|
|
219
|
-
const hash = window.location.hash.replace("#", "");
|
|
220
|
-
return hash && ids.includes(hash) ? hash : ids[0] ?? "";
|
|
221
|
-
}
|
|
222
|
-
function useActiveScrollSectionIds(ids, options) {
|
|
223
|
-
const memoIds = useMemo3(() => ids.filter(Boolean), [ids]);
|
|
224
|
-
const [active, setActive] = useState2(() => getInitialActiveId(memoIds));
|
|
225
|
-
useEffect3(() => {
|
|
226
|
-
if (memoIds.length === 0)
|
|
227
|
-
return;
|
|
228
|
-
const observer = new IntersectionObserver((entries) => {
|
|
229
|
-
const visible = entries.filter((entry) => entry.isIntersecting).sort((a, b) => a.boundingClientRect.top > b.boundingClientRect.top ? 1 : -1);
|
|
230
|
-
if (!visible[0])
|
|
231
|
-
return;
|
|
232
|
-
const id = visible[0].target.id;
|
|
233
|
-
if (!id)
|
|
234
|
-
return;
|
|
235
|
-
setActive((prev) => prev === id ? prev : id);
|
|
236
|
-
}, {
|
|
237
|
-
rootMargin: options?.rootMargin ?? "-20% 0px -70% 0px",
|
|
238
|
-
threshold: options?.threshold ?? [0, 1]
|
|
239
|
-
});
|
|
240
|
-
memoIds.forEach((id) => {
|
|
241
|
-
const el = document.getElementById(id);
|
|
242
|
-
if (el)
|
|
243
|
-
observer.observe(el);
|
|
244
|
-
});
|
|
245
|
-
return () => observer.disconnect();
|
|
246
|
-
}, [memoIds, options?.rootMargin, options?.threshold]);
|
|
247
|
-
useEffect3(() => {
|
|
248
|
-
if (!options?.syncToUrl || !active)
|
|
249
|
-
return;
|
|
250
|
-
const current = window.location.hash.replace("#", "");
|
|
251
|
-
if (current !== active) {
|
|
252
|
-
history.replaceState(null, "", `#${active}`);
|
|
253
|
-
}
|
|
254
|
-
}, [active, options?.syncToUrl]);
|
|
255
|
-
return active;
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
// src/hooks/use-color-scheme.tsx
|
|
259
|
-
import { useEffect as useEffect4, useState as useState3 } from "react";
|
|
260
|
-
function getInitialScheme() {
|
|
261
|
-
if (typeof window === "undefined" || !window.matchMedia)
|
|
262
|
-
return "light";
|
|
263
|
-
return window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
|
|
264
|
-
}
|
|
265
|
-
function useColorScheme() {
|
|
266
|
-
const [scheme, setScheme] = useState3(() => getInitialScheme());
|
|
267
|
-
useEffect4(() => {
|
|
268
|
-
if (!window.matchMedia)
|
|
269
|
-
return;
|
|
270
|
-
const mql = window.matchMedia("(prefers-color-scheme: dark)");
|
|
271
|
-
const update = (event) => {
|
|
272
|
-
if (event) {
|
|
273
|
-
setScheme(event.matches ? "dark" : "light");
|
|
274
|
-
return;
|
|
275
|
-
}
|
|
276
|
-
setScheme(mql.matches ? "dark" : "light");
|
|
277
|
-
};
|
|
278
|
-
update();
|
|
279
|
-
mql.addEventListener?.("change", update);
|
|
280
|
-
return () => mql.removeEventListener?.("change", update);
|
|
281
|
-
}, []);
|
|
282
|
-
return scheme;
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
// src/docpage.tsx
|
|
286
|
-
import { jsxDEV as jsxDEV4 } from "react/jsx-dev-runtime";
|
|
287
|
-
var TOKEN_VAR_MAP = {
|
|
288
|
-
background: "background",
|
|
289
|
-
foreground: "foreground",
|
|
290
|
-
card: "card",
|
|
291
|
-
cardForeground: "card-foreground",
|
|
292
|
-
popover: "popover",
|
|
293
|
-
popoverForeground: "popover-foreground",
|
|
294
|
-
primary: "primary",
|
|
295
|
-
primaryForeground: "primary-foreground",
|
|
296
|
-
secondary: "secondary",
|
|
297
|
-
secondaryForeground: "secondary-foreground",
|
|
298
|
-
muted: "muted",
|
|
299
|
-
mutedForeground: "muted-foreground",
|
|
300
|
-
accent: "accent",
|
|
301
|
-
accentForeground: "accent-foreground",
|
|
302
|
-
destructive: "destructive",
|
|
303
|
-
destructiveForeground: "destructive-foreground",
|
|
304
|
-
border: "border",
|
|
305
|
-
input: "input",
|
|
306
|
-
ring: "ring",
|
|
307
|
-
chart1: "chart-1",
|
|
308
|
-
chart2: "chart-2",
|
|
309
|
-
chart3: "chart-3",
|
|
310
|
-
chart4: "chart-4",
|
|
311
|
-
chart5: "chart-5",
|
|
312
|
-
radius: "radius"
|
|
313
|
-
};
|
|
314
|
-
function setTokenVars(style, tokens, scheme) {
|
|
315
|
-
if (!tokens)
|
|
316
|
-
return;
|
|
317
|
-
Object.keys(tokens).forEach((key) => {
|
|
318
|
-
const value = tokens[key];
|
|
319
|
-
if (!value)
|
|
320
|
-
return;
|
|
321
|
-
const varKey = TOKEN_VAR_MAP[key];
|
|
322
|
-
style[`--docpage-${varKey}-${scheme}`] = value;
|
|
323
|
-
});
|
|
324
|
-
}
|
|
325
|
-
function themeToStyle(config) {
|
|
326
|
-
const style = {};
|
|
327
|
-
setTokenVars(style, config.theme?.light, "light");
|
|
328
|
-
setTokenVars(style, config.theme?.dark, "dark");
|
|
329
|
-
return style;
|
|
330
|
-
}
|
|
331
|
-
function startCaseId(id) {
|
|
332
|
-
const withSpaces = id.replace(/[-_]/g, " ").trim();
|
|
333
|
-
if (!withSpaces)
|
|
334
|
-
return id;
|
|
335
|
-
return withSpaces.replace(/\b\w/g, (c) => c.toUpperCase());
|
|
336
|
-
}
|
|
337
|
-
function deriveToc(config) {
|
|
338
|
-
if (config.toc && config.toc.length > 0)
|
|
339
|
-
return config.toc;
|
|
340
|
-
return config.sections.map((section) => {
|
|
341
|
-
const labelFromTitle = typeof section.title === "string" ? section.title : undefined;
|
|
342
|
-
return {
|
|
343
|
-
id: section.id,
|
|
344
|
-
label: section.label ?? labelFromTitle ?? startCaseId(section.id)
|
|
345
|
-
};
|
|
346
|
-
});
|
|
347
|
-
}
|
|
348
|
-
function useIsWide(minWidthPx) {
|
|
349
|
-
const [isWide, setIsWide] = useState4(() => {
|
|
350
|
-
if (typeof window === "undefined" || !window.matchMedia)
|
|
351
|
-
return true;
|
|
352
|
-
return window.matchMedia(`(min-width: ${minWidthPx}px)`).matches;
|
|
353
|
-
});
|
|
354
|
-
useEffect5(() => {
|
|
355
|
-
if (!window.matchMedia)
|
|
356
|
-
return;
|
|
357
|
-
const mql = window.matchMedia(`(min-width: ${minWidthPx}px)`);
|
|
358
|
-
const update = (event) => {
|
|
359
|
-
if (event) {
|
|
360
|
-
setIsWide(event.matches);
|
|
361
|
-
return;
|
|
362
|
-
}
|
|
363
|
-
setIsWide(mql.matches);
|
|
364
|
-
};
|
|
365
|
-
update();
|
|
366
|
-
mql.addEventListener?.("change", update);
|
|
367
|
-
return () => mql.removeEventListener?.("change", update);
|
|
368
|
-
}, [minWidthPx]);
|
|
369
|
-
return isWide;
|
|
370
|
-
}
|
|
371
|
-
function Container({ children }) {
|
|
372
|
-
return /* @__PURE__ */ jsxDEV4("div", {
|
|
373
|
-
className: "mx-auto w-full max-w-6xl px-4 sm:px-6 lg:px-8",
|
|
374
|
-
children
|
|
375
|
-
}, undefined, false, undefined, this);
|
|
376
|
-
}
|
|
377
|
-
function Prose({ children }) {
|
|
378
|
-
return /* @__PURE__ */ jsxDEV4("div", {
|
|
379
|
-
className: cn("docpage-prose mx-auto max-w-3xl text-base leading-7 text-foreground/80", "[&>section>h2]:text-foreground [&_p]:text-foreground/80 [&_li]:text-foreground/80", "[&>section>h2]:mb-6 [&>section>h2]:text-2xl [&>section>h2]:font-semibold [&>section>h2]:tracking-tight", "[&>section>p]:my-4 [&_code]:font-mono [&_code]:text-[0.85em]", "[&_pre]:rounded [&_pre]:p-0 [&_pre]:text-xs [&_pre]:leading-6"),
|
|
380
|
-
children
|
|
381
|
-
}, undefined, false, undefined, this);
|
|
382
|
-
}
|
|
383
|
-
function getCalloutToneClasses(tone) {
|
|
384
|
-
switch (tone) {
|
|
385
|
-
case "info":
|
|
386
|
-
return "border-primary/30 bg-primary/5";
|
|
387
|
-
case "warn":
|
|
388
|
-
return "border-amber-500/40 bg-amber-500/10";
|
|
389
|
-
case "danger":
|
|
390
|
-
return "border-destructive/50 bg-destructive/10";
|
|
391
|
-
case "neutral":
|
|
392
|
-
default:
|
|
393
|
-
return "border-border/70 bg-muted/20";
|
|
394
|
-
}
|
|
395
|
-
}
|
|
396
|
-
function renderBlock(block) {
|
|
397
|
-
switch (block.kind) {
|
|
398
|
-
case "p":
|
|
399
|
-
return /* @__PURE__ */ jsxDEV4("p", {
|
|
400
|
-
className: "my-4",
|
|
401
|
-
children: block.text
|
|
402
|
-
}, undefined, false, undefined, this);
|
|
403
|
-
case "ul":
|
|
404
|
-
return /* @__PURE__ */ jsxDEV4("ul", {
|
|
405
|
-
className: "marker:text-muted-foreground list-disc pl-6",
|
|
406
|
-
children: block.items.map((item, index) => /* @__PURE__ */ jsxDEV4("li", {
|
|
407
|
-
className: "my-2",
|
|
408
|
-
children: item
|
|
409
|
-
}, index, false, undefined, this))
|
|
410
|
-
}, undefined, false, undefined, this);
|
|
411
|
-
case "ol":
|
|
412
|
-
return /* @__PURE__ */ jsxDEV4("ol", {
|
|
413
|
-
className: "marker:text-muted-foreground list-decimal pl-6",
|
|
414
|
-
children: block.items.map((item, index) => /* @__PURE__ */ jsxDEV4("li", {
|
|
415
|
-
className: "my-2",
|
|
416
|
-
children: item
|
|
417
|
-
}, index, false, undefined, this))
|
|
418
|
-
}, undefined, false, undefined, this);
|
|
419
|
-
case "labeled-list":
|
|
420
|
-
return /* @__PURE__ */ jsxDEV4("ul", {
|
|
421
|
-
className: "marker:text-muted-foreground list-disc pl-6",
|
|
422
|
-
children: block.items.map((item, index) => /* @__PURE__ */ jsxDEV4("li", {
|
|
423
|
-
className: "my-2",
|
|
424
|
-
children: [
|
|
425
|
-
/* @__PURE__ */ jsxDEV4("strong", {
|
|
426
|
-
children: [
|
|
427
|
-
item.label,
|
|
428
|
-
":"
|
|
429
|
-
]
|
|
430
|
-
}, undefined, true, undefined, this),
|
|
431
|
-
" ",
|
|
432
|
-
item.text
|
|
433
|
-
]
|
|
434
|
-
}, index, true, undefined, this))
|
|
435
|
-
}, undefined, false, undefined, this);
|
|
436
|
-
case "code":
|
|
437
|
-
return /* @__PURE__ */ jsxDEV4("div", {
|
|
438
|
-
className: "my-6",
|
|
439
|
-
children: /* @__PURE__ */ jsxDEV4(CodeBlock, {
|
|
440
|
-
code: block.code,
|
|
441
|
-
language: block.language,
|
|
442
|
-
caption: block.caption
|
|
443
|
-
}, undefined, false, undefined, this)
|
|
444
|
-
}, undefined, false, undefined, this);
|
|
445
|
-
case "pre":
|
|
446
|
-
return /* @__PURE__ */ jsxDEV4("pre", {
|
|
447
|
-
className: "bg-muted/40 my-6 whitespace-pre-wrap rounded p-3 text-xs",
|
|
448
|
-
children: block.code
|
|
449
|
-
}, undefined, false, undefined, this);
|
|
450
|
-
case "mermaid":
|
|
451
|
-
return /* @__PURE__ */ jsxDEV4("figure", {
|
|
452
|
-
className: "my-6",
|
|
453
|
-
children: [
|
|
454
|
-
/* @__PURE__ */ jsxDEV4("div", {
|
|
455
|
-
className: "bg-background rounded border border-border/80 p-4",
|
|
456
|
-
children: /* @__PURE__ */ jsxDEV4(Mermaid, {
|
|
457
|
-
chart: block.chart
|
|
458
|
-
}, undefined, false, undefined, this)
|
|
459
|
-
}, undefined, false, undefined, this),
|
|
460
|
-
block.caption ? /* @__PURE__ */ jsxDEV4("figcaption", {
|
|
461
|
-
className: "mt-2 text-xs text-muted-foreground",
|
|
462
|
-
children: block.caption
|
|
463
|
-
}, undefined, false, undefined, this) : null
|
|
464
|
-
]
|
|
465
|
-
}, undefined, true, undefined, this);
|
|
466
|
-
case "callout":
|
|
467
|
-
return /* @__PURE__ */ jsxDEV4("div", {
|
|
468
|
-
className: cn("my-6 rounded-lg border p-4", getCalloutToneClasses(block.tone)),
|
|
469
|
-
children: [
|
|
470
|
-
block.title ? /* @__PURE__ */ jsxDEV4("div", {
|
|
471
|
-
className: "text-sm font-semibold text-foreground",
|
|
472
|
-
children: block.title
|
|
473
|
-
}, undefined, false, undefined, this) : null,
|
|
474
|
-
/* @__PURE__ */ jsxDEV4("div", {
|
|
475
|
-
className: cn("text-sm leading-relaxed", block.title ? "mt-1" : undefined),
|
|
476
|
-
children: block.body
|
|
477
|
-
}, undefined, false, undefined, this)
|
|
478
|
-
]
|
|
479
|
-
}, undefined, true, undefined, this);
|
|
480
|
-
case "node":
|
|
481
|
-
return /* @__PURE__ */ jsxDEV4("div", {
|
|
482
|
-
className: "my-4",
|
|
483
|
-
children: block.node
|
|
484
|
-
}, undefined, false, undefined, this);
|
|
485
|
-
default:
|
|
486
|
-
return null;
|
|
487
|
-
}
|
|
488
|
-
}
|
|
489
|
-
function getLanguageFromClassName(className) {
|
|
490
|
-
if (!className)
|
|
491
|
-
return;
|
|
492
|
-
if (className.startsWith("language-")) {
|
|
493
|
-
return className.replace("language-", "");
|
|
494
|
-
}
|
|
495
|
-
return className;
|
|
496
|
-
}
|
|
497
|
-
function toCodeString(value) {
|
|
498
|
-
if (typeof value === "string")
|
|
499
|
-
return value;
|
|
500
|
-
if (typeof value === "number" || typeof value === "boolean")
|
|
501
|
-
return String(value);
|
|
502
|
-
if (value == null)
|
|
503
|
-
return "";
|
|
504
|
-
return String(value);
|
|
505
|
-
}
|
|
506
|
-
function MdxCodeBlockPre(props) {
|
|
507
|
-
const child = Children.count(props.children) === 1 ? Children.only(props.children) : null;
|
|
508
|
-
if (child && isValidElement(child)) {
|
|
509
|
-
const codeChild = child;
|
|
510
|
-
const language = getLanguageFromClassName(codeChild.props.className);
|
|
511
|
-
const code = toCodeString(codeChild.props.children);
|
|
512
|
-
return /* @__PURE__ */ jsxDEV4(CodeBlock, {
|
|
513
|
-
code,
|
|
514
|
-
language
|
|
515
|
-
}, undefined, false, undefined, this);
|
|
516
|
-
}
|
|
517
|
-
return /* @__PURE__ */ jsxDEV4("pre", {
|
|
518
|
-
...props,
|
|
519
|
-
className: cn("bg-muted/40 overflow-x-auto whitespace-pre-wrap rounded p-3 text-xs leading-6", props.className)
|
|
520
|
-
}, undefined, false, undefined, this);
|
|
521
|
-
}
|
|
522
|
-
function buildMdxComponents(section) {
|
|
523
|
-
const defaults = {
|
|
524
|
-
pre: MdxCodeBlockPre
|
|
525
|
-
};
|
|
526
|
-
return {
|
|
527
|
-
...defaults,
|
|
528
|
-
...section.components ?? {}
|
|
529
|
-
};
|
|
530
|
-
}
|
|
531
|
-
function getSectionTitle(section, tocMap) {
|
|
532
|
-
if (section.title)
|
|
533
|
-
return section.title;
|
|
534
|
-
const fromToc = tocMap.get(section.id);
|
|
535
|
-
return fromToc ?? startCaseId(section.id);
|
|
536
|
-
}
|
|
537
|
-
function SectionHeading({
|
|
538
|
-
title,
|
|
539
|
-
titleBorder
|
|
540
|
-
}) {
|
|
541
|
-
return /* @__PURE__ */ jsxDEV4("h2", {
|
|
542
|
-
className: cn("mb-8 mt-12 text-2xl font-semibold tracking-tight first:mt-0", titleBorder ? "border-muted border-b pb-2" : "pb-2"),
|
|
543
|
-
children: title
|
|
544
|
-
}, undefined, false, undefined, this);
|
|
545
|
-
}
|
|
546
|
-
function Nav({ config }) {
|
|
547
|
-
const [scrolled, setScrolled] = useState4(false);
|
|
548
|
-
useEffect5(() => {
|
|
549
|
-
const onScroll = () => setScrolled(window.scrollY > 8);
|
|
550
|
-
onScroll();
|
|
551
|
-
window.addEventListener("scroll", onScroll, { passive: true });
|
|
552
|
-
return () => window.removeEventListener("scroll", onScroll);
|
|
553
|
-
}, []);
|
|
554
|
-
const signInLabel = config.nav?.signInLabel ?? "sign in";
|
|
555
|
-
const signInHref = config.nav?.signInHref ?? "/login";
|
|
556
|
-
return /* @__PURE__ */ jsxDEV4("div", {
|
|
557
|
-
className: cn("sticky top-0 z-40 w-full backdrop-blur", scrolled ? "border-b border-border/80 bg-background/80" : "bg-background/60"),
|
|
558
|
-
"data-docpage-nav": true,
|
|
559
|
-
children: /* @__PURE__ */ jsxDEV4(Container, {
|
|
560
|
-
children: /* @__PURE__ */ jsxDEV4("div", {
|
|
561
|
-
className: "flex h-14 items-center justify-between",
|
|
562
|
-
children: [
|
|
563
|
-
/* @__PURE__ */ jsxDEV4(Brand, {
|
|
564
|
-
brand: config.brand
|
|
565
|
-
}, undefined, false, undefined, this),
|
|
566
|
-
config.nav?.rightSlot ? config.nav.rightSlot : /* @__PURE__ */ jsxDEV4("a", {
|
|
567
|
-
href: signInHref,
|
|
568
|
-
className: cn("group inline-flex items-center rounded-md border border-border/80 px-3 py-1.5 text-xs font-semibold uppercase tracking-[0.2em]", "text-foreground transition hover:border-foreground/60 hover:bg-foreground hover:text-background"),
|
|
569
|
-
"data-docpage-signin": true,
|
|
570
|
-
children: [
|
|
571
|
-
signInLabel,
|
|
572
|
-
/* @__PURE__ */ jsxDEV4(ArrowRight, {
|
|
573
|
-
className: "ml-1 h-4 w-4 transition-transform group-hover:translate-x-0.5"
|
|
574
|
-
}, undefined, false, undefined, this)
|
|
575
|
-
]
|
|
576
|
-
}, undefined, true, undefined, this)
|
|
577
|
-
]
|
|
578
|
-
}, undefined, true, undefined, this)
|
|
579
|
-
}, undefined, false, undefined, this)
|
|
580
|
-
}, undefined, false, undefined, this);
|
|
581
|
-
}
|
|
582
|
-
function Brand({ brand }) {
|
|
583
|
-
const content = brand.logo ? /* @__PURE__ */ jsxDEV4("div", {
|
|
584
|
-
className: "flex items-center gap-2",
|
|
585
|
-
children: brand.logo
|
|
586
|
-
}, undefined, false, undefined, this) : /* @__PURE__ */ jsxDEV4("span", {
|
|
587
|
-
className: "text-sm font-semibold tracking-[0.2em] uppercase",
|
|
588
|
-
children: brand.name
|
|
589
|
-
}, undefined, false, undefined, this);
|
|
590
|
-
if (!brand.href)
|
|
591
|
-
return content;
|
|
592
|
-
return /* @__PURE__ */ jsxDEV4("a", {
|
|
593
|
-
href: brand.href,
|
|
594
|
-
className: "inline-flex items-center text-foreground",
|
|
595
|
-
"data-docpage-brand": true,
|
|
596
|
-
children: content
|
|
597
|
-
}, undefined, false, undefined, this);
|
|
598
|
-
}
|
|
599
|
-
function Toc({
|
|
600
|
-
entries,
|
|
601
|
-
activeId,
|
|
602
|
-
title
|
|
603
|
-
}) {
|
|
604
|
-
return /* @__PURE__ */ jsxDEV4("nav", {
|
|
605
|
-
"aria-label": "Table of contents",
|
|
606
|
-
className: "text-sm",
|
|
607
|
-
"data-docpage-toc": true,
|
|
608
|
-
children: [
|
|
609
|
-
/* @__PURE__ */ jsxDEV4("div", {
|
|
610
|
-
className: "mb-2 font-medium text-foreground",
|
|
611
|
-
children: title
|
|
612
|
-
}, undefined, false, undefined, this),
|
|
613
|
-
/* @__PURE__ */ jsxDEV4("ol", {
|
|
614
|
-
className: "space-y-1",
|
|
615
|
-
children: entries.map((entry) => {
|
|
616
|
-
const isActive = activeId === entry.id;
|
|
617
|
-
return /* @__PURE__ */ jsxDEV4("li", {
|
|
618
|
-
children: /* @__PURE__ */ jsxDEV4("a", {
|
|
619
|
-
href: `#${entry.id}`,
|
|
620
|
-
className: cn("block rounded px-2 py-1 transition-colors", isActive ? "font-semibold text-foreground" : "text-muted-foreground hover:text-foreground"),
|
|
621
|
-
onClick: () => history.replaceState(null, "", `#${entry.id}`),
|
|
622
|
-
"data-docpage-toc-link": entry.id,
|
|
623
|
-
"aria-current": isActive ? "true" : undefined,
|
|
624
|
-
children: entry.label
|
|
625
|
-
}, undefined, false, undefined, this)
|
|
626
|
-
}, entry.id, false, undefined, this);
|
|
627
|
-
})
|
|
628
|
-
}, undefined, false, undefined, this)
|
|
629
|
-
]
|
|
630
|
-
}, undefined, true, undefined, this);
|
|
631
|
-
}
|
|
632
|
-
function Header({ config }) {
|
|
633
|
-
return /* @__PURE__ */ jsxDEV4(Container, {
|
|
634
|
-
children: /* @__PURE__ */ jsxDEV4("header", {
|
|
635
|
-
className: "py-12",
|
|
636
|
-
"data-docpage-header": true,
|
|
637
|
-
children: [
|
|
638
|
-
config.header.kicker ? /* @__PURE__ */ jsxDEV4("div", {
|
|
639
|
-
className: "mb-3 text-xs font-semibold uppercase tracking-[0.3em] text-muted-foreground",
|
|
640
|
-
children: config.header.kicker
|
|
641
|
-
}, undefined, false, undefined, this) : null,
|
|
642
|
-
/* @__PURE__ */ jsxDEV4("h1", {
|
|
643
|
-
className: "mb-2 text-4xl font-bold tracking-tight sm:text-5xl lg:text-6xl",
|
|
644
|
-
children: config.header.title
|
|
645
|
-
}, undefined, false, undefined, this),
|
|
646
|
-
config.header.subtitle ? /* @__PURE__ */ jsxDEV4("p", {
|
|
647
|
-
className: "max-w-2xl text-lg text-muted-foreground",
|
|
648
|
-
children: config.header.subtitle
|
|
649
|
-
}, undefined, false, undefined, this) : null
|
|
650
|
-
]
|
|
651
|
-
}, undefined, true, undefined, this)
|
|
652
|
-
}, undefined, false, undefined, this);
|
|
653
|
-
}
|
|
654
|
-
function renderSection(section, tocMap) {
|
|
655
|
-
const title = getSectionTitle(section, tocMap);
|
|
656
|
-
switch (section.kind) {
|
|
657
|
-
case "prose":
|
|
658
|
-
return /* @__PURE__ */ jsxDEV4("section", {
|
|
659
|
-
id: section.id,
|
|
660
|
-
className: cn("scroll-mt-24", section.className),
|
|
661
|
-
"data-docpage-section": section.id,
|
|
662
|
-
children: [
|
|
663
|
-
!section.hideTitle ? /* @__PURE__ */ jsxDEV4(SectionHeading, {
|
|
664
|
-
title,
|
|
665
|
-
titleBorder: section.titleBorder
|
|
666
|
-
}, undefined, false, undefined, this) : null,
|
|
667
|
-
/* @__PURE__ */ jsxDEV4("div", {
|
|
668
|
-
className: "space-y-4",
|
|
669
|
-
children: section.blocks.map((block, index) => /* @__PURE__ */ jsxDEV4("div", {
|
|
670
|
-
children: renderBlock(block)
|
|
671
|
-
}, index, false, undefined, this))
|
|
672
|
-
}, undefined, false, undefined, this)
|
|
673
|
-
]
|
|
674
|
-
}, section.id, true, undefined, this);
|
|
675
|
-
case "tabs":
|
|
676
|
-
return /* @__PURE__ */ jsxDEV4("section", {
|
|
677
|
-
id: section.id,
|
|
678
|
-
className: cn("scroll-mt-24", section.className),
|
|
679
|
-
"data-docpage-section": section.id,
|
|
680
|
-
children: [
|
|
681
|
-
!section.hideTitle ? /* @__PURE__ */ jsxDEV4(SectionHeading, {
|
|
682
|
-
title,
|
|
683
|
-
titleBorder: section.titleBorder
|
|
684
|
-
}, undefined, false, undefined, this) : null,
|
|
685
|
-
section.intro ? /* @__PURE__ */ jsxDEV4("p", {
|
|
686
|
-
className: "mt-4",
|
|
687
|
-
children: section.intro
|
|
688
|
-
}, undefined, false, undefined, this) : null,
|
|
689
|
-
/* @__PURE__ */ jsxDEV4("div", {
|
|
690
|
-
className: "mt-4",
|
|
691
|
-
children: /* @__PURE__ */ jsxDEV4(ApiTabs, {
|
|
692
|
-
tabs: section.tabs,
|
|
693
|
-
defaultTabId: section.defaultTabId
|
|
694
|
-
}, undefined, false, undefined, this)
|
|
695
|
-
}, undefined, false, undefined, this)
|
|
696
|
-
]
|
|
697
|
-
}, section.id, true, undefined, this);
|
|
698
|
-
case "mdx": {
|
|
699
|
-
const components = buildMdxComponents(section);
|
|
700
|
-
return /* @__PURE__ */ jsxDEV4("section", {
|
|
701
|
-
id: section.id,
|
|
702
|
-
className: cn("scroll-mt-24", section.className),
|
|
703
|
-
"data-docpage-section": section.id,
|
|
704
|
-
children: [
|
|
705
|
-
!section.hideTitle ? /* @__PURE__ */ jsxDEV4(SectionHeading, {
|
|
706
|
-
title,
|
|
707
|
-
titleBorder: section.titleBorder
|
|
708
|
-
}, undefined, false, undefined, this) : null,
|
|
709
|
-
/* @__PURE__ */ jsxDEV4("div", {
|
|
710
|
-
className: "docpage-mdx",
|
|
711
|
-
children: /* @__PURE__ */ jsxDEV4(MDXProvider, {
|
|
712
|
-
components,
|
|
713
|
-
children: /* @__PURE__ */ jsxDEV4(section.Component, {}, undefined, false, undefined, this)
|
|
714
|
-
}, undefined, false, undefined, this)
|
|
715
|
-
}, undefined, false, undefined, this)
|
|
716
|
-
]
|
|
717
|
-
}, section.id, true, undefined, this);
|
|
718
|
-
}
|
|
719
|
-
default:
|
|
720
|
-
return null;
|
|
721
|
-
}
|
|
722
|
-
}
|
|
723
|
-
function Footer({ config }) {
|
|
724
|
-
const footer = config.footer;
|
|
725
|
-
if (!footer)
|
|
726
|
-
return null;
|
|
727
|
-
const year = new Date().getFullYear();
|
|
728
|
-
return /* @__PURE__ */ jsxDEV4("footer", {
|
|
729
|
-
className: "border-t border-border/80 py-10 text-sm text-muted-foreground",
|
|
730
|
-
"data-docpage-footer": true,
|
|
731
|
-
children: /* @__PURE__ */ jsxDEV4(Container, {
|
|
732
|
-
children: /* @__PURE__ */ jsxDEV4("div", {
|
|
733
|
-
className: "flex flex-col items-start justify-between gap-4 md:flex-row md:items-center",
|
|
734
|
-
children: [
|
|
735
|
-
footer.links && footer.links.length > 0 ? /* @__PURE__ */ jsxDEV4("div", {
|
|
736
|
-
className: "flex flex-wrap items-center gap-4",
|
|
737
|
-
children: footer.links.map((link) => /* @__PURE__ */ jsxDEV4("a", {
|
|
738
|
-
className: "hover:text-foreground",
|
|
739
|
-
href: link.href,
|
|
740
|
-
children: link.label
|
|
741
|
-
}, link.href, false, undefined, this))
|
|
742
|
-
}, undefined, false, undefined, this) : null,
|
|
743
|
-
/* @__PURE__ */ jsxDEV4("div", {
|
|
744
|
-
className: "flex flex-col gap-1 md:items-end",
|
|
745
|
-
children: [
|
|
746
|
-
/* @__PURE__ */ jsxDEV4("div", {
|
|
747
|
-
children: [
|
|
748
|
-
"© ",
|
|
749
|
-
year,
|
|
750
|
-
" ",
|
|
751
|
-
footer.copyrightName ?? config.brand.name
|
|
752
|
-
]
|
|
753
|
-
}, undefined, true, undefined, this),
|
|
754
|
-
footer.note ? /* @__PURE__ */ jsxDEV4("div", {
|
|
755
|
-
className: "text-xs",
|
|
756
|
-
children: footer.note
|
|
757
|
-
}, undefined, false, undefined, this) : null
|
|
758
|
-
]
|
|
759
|
-
}, undefined, true, undefined, this)
|
|
760
|
-
]
|
|
761
|
-
}, undefined, true, undefined, this)
|
|
762
|
-
}, undefined, false, undefined, this)
|
|
763
|
-
}, undefined, false, undefined, this);
|
|
764
|
-
}
|
|
765
|
-
function DocPage({ config, className }) {
|
|
766
|
-
const tocEntries = useMemo4(() => deriveToc(config), [config]);
|
|
767
|
-
const tocIds = tocEntries.map((entry) => entry.id);
|
|
768
|
-
const tocTitle = config.tocTitle ?? "Contents";
|
|
769
|
-
const tocMap = useMemo4(() => {
|
|
770
|
-
return new Map(tocEntries.map((entry) => [entry.id, entry.label]));
|
|
771
|
-
}, [tocEntries]);
|
|
772
|
-
const tocActiveId = useActiveScrollSectionIds(tocIds, {
|
|
773
|
-
rootMargin: config.options?.tocRootMargin,
|
|
774
|
-
threshold: config.options?.tocThreshold,
|
|
775
|
-
syncToUrl: config.options?.syncTocToUrl ?? true
|
|
776
|
-
});
|
|
777
|
-
const tocMinWidthPx = config.options?.tocMinWidthPx ?? 768;
|
|
778
|
-
const isWide = useIsWide(tocMinWidthPx);
|
|
779
|
-
const scheme = useColorScheme();
|
|
780
|
-
const themeStyle = themeToStyle(config);
|
|
781
|
-
const mergedStyle = { ...themeStyle, ...config.style ?? {} };
|
|
782
|
-
return /* @__PURE__ */ jsxDEV4("div", {
|
|
783
|
-
className: cn("docpage min-h-[100dvh] bg-background text-foreground", config.className, className),
|
|
784
|
-
style: mergedStyle,
|
|
785
|
-
"data-docpage": true,
|
|
786
|
-
"data-docpage-theme": scheme,
|
|
787
|
-
children: [
|
|
788
|
-
/* @__PURE__ */ jsxDEV4(Nav, {
|
|
789
|
-
config
|
|
790
|
-
}, undefined, false, undefined, this),
|
|
791
|
-
/* @__PURE__ */ jsxDEV4(Header, {
|
|
792
|
-
config
|
|
793
|
-
}, undefined, false, undefined, this),
|
|
794
|
-
/* @__PURE__ */ jsxDEV4(Container, {
|
|
795
|
-
children: /* @__PURE__ */ jsxDEV4("div", {
|
|
796
|
-
className: "grid grid-cols-1 gap-10 md:grid-cols-[260px_minmax(0,1fr)]",
|
|
797
|
-
"data-docpage-body": true,
|
|
798
|
-
children: [
|
|
799
|
-
/* @__PURE__ */ jsxDEV4("aside", {
|
|
800
|
-
className: "hidden max-h-[calc(100vh-7rem)] overflow-auto pr-4 md:sticky md:top-24 md:block",
|
|
801
|
-
style: isWide ? undefined : { display: "none" },
|
|
802
|
-
children: /* @__PURE__ */ jsxDEV4(Toc, {
|
|
803
|
-
entries: tocEntries,
|
|
804
|
-
activeId: tocActiveId,
|
|
805
|
-
title: tocTitle
|
|
806
|
-
}, undefined, false, undefined, this)
|
|
807
|
-
}, undefined, false, undefined, this),
|
|
808
|
-
/* @__PURE__ */ jsxDEV4("main", {
|
|
809
|
-
className: "pb-24",
|
|
810
|
-
children: /* @__PURE__ */ jsxDEV4(Prose, {
|
|
811
|
-
children: config.sections.map((section) => renderSection(section, tocMap))
|
|
812
|
-
}, undefined, false, undefined, this)
|
|
813
|
-
}, undefined, false, undefined, this)
|
|
814
|
-
]
|
|
815
|
-
}, undefined, true, undefined, this)
|
|
816
|
-
}, undefined, false, undefined, this),
|
|
817
|
-
/* @__PURE__ */ jsxDEV4(Footer, {
|
|
818
|
-
config
|
|
819
|
-
}, undefined, false, undefined, this)
|
|
820
|
-
]
|
|
821
|
-
}, undefined, true, undefined, this);
|
|
822
|
-
}
|
|
823
|
-
export {
|
|
824
|
-
useColorScheme,
|
|
825
|
-
useActiveScrollSectionIds,
|
|
826
|
-
cn,
|
|
827
|
-
Mermaid,
|
|
828
|
-
MdxCodeBlockPre,
|
|
829
|
-
DocPage,
|
|
830
|
-
CodeBlock,
|
|
831
|
-
ApiTabs
|
|
832
|
-
};
|
|
1
|
+
export { cn } from "./cn";
|
|
2
|
+
export { DocPage, MdxCodeBlockPre } from "./docpage";
|
|
3
|
+
export { ApiTabs } from "./components/api-tabs";
|
|
4
|
+
export { CodeBlock } from "./components/code-block";
|
|
5
|
+
export { Mermaid } from "./components/mermaid";
|
|
6
|
+
export { useActiveScrollSectionIds } from "./hooks/use-active-scroll-section-ids";
|
|
7
|
+
export { useColorScheme } from "./hooks/use-color-scheme";
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nendlabs/docpage",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "an interactive paper-style project page renderer",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -24,8 +24,8 @@
|
|
|
24
24
|
"types": "./dist/index.d.ts",
|
|
25
25
|
"scripts": {
|
|
26
26
|
"clean": "rm -rf dist",
|
|
27
|
-
"build:js": "
|
|
28
|
-
"build:types": "tsc -p ./tsconfig.build.json",
|
|
27
|
+
"build:js": "tsc -p ./tsconfig.build.js.json",
|
|
28
|
+
"build:types": "tsc -p ./tsconfig.build.types.json",
|
|
29
29
|
"build:styles": "mkdir -p dist/styles && ./node_modules/.bin/tailwindcss -i ./styles/tailwind.css -o ./dist/styles/docpage.css",
|
|
30
30
|
"build:docs": "mkdir -p dist && cp docs/package.md dist/package.md",
|
|
31
31
|
"build": "bun run clean && bun run build:js && bun run build:types && bun run build:styles && bun run build:docs",
|