deepspace 0.9.3 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +25 -0
- package/dist/chunk-DQ4G6VL6.js +1535 -0
- package/dist/chunk-DQ4G6VL6.js.map +1 -0
- package/dist/cli.js +5899 -379
- package/dist/cli.js.map +1 -1
- package/dist/docs-client-core.d.ts +18 -0
- package/dist/docs-client-core.js +386 -0
- package/dist/docs-client-core.js.map +1 -0
- package/dist/docs-react.d.ts +2 -0
- package/dist/docs-react.js +35 -0
- package/dist/docs-react.js.map +1 -0
- package/dist/docs-runtime.js +71 -0
- package/dist/docs-server-core.d.ts +11 -0
- package/dist/docs-server-core.js +48 -0
- package/dist/docs-server-core.js.map +1 -0
- package/dist/docs.d.ts +350 -0
- package/dist/docs.js +5139 -0
- package/dist/docs.js.map +1 -0
- package/dist/index.d.ts +179 -1
- package/dist/index.js +143 -0
- package/dist/index.js.map +1 -1
- package/dist/public-Cp1X8ZQ3.d.ts +230 -0
- package/dist/server.d.ts +240 -13
- package/dist/server.js +1313 -25
- package/dist/server.js.map +1 -1
- package/dist/worker.d.ts +378 -13
- package/dist/worker.js +1377 -29
- package/dist/worker.js.map +1 -1
- package/features/ai-chat/feature.json +1 -1
- package/features/ai-chat/src/ChatPanel.tsx +7 -11
- package/package.json +21 -1
|
@@ -0,0 +1,1535 @@
|
|
|
1
|
+
// src/docs/runtime/app.tsx
|
|
2
|
+
import {
|
|
3
|
+
useCallback,
|
|
4
|
+
useEffect as useEffect7,
|
|
5
|
+
useState as useState6
|
|
6
|
+
} from "react";
|
|
7
|
+
|
|
8
|
+
// src/docs/runtime/article.tsx
|
|
9
|
+
import {
|
|
10
|
+
useEffect as useEffect2,
|
|
11
|
+
useMemo,
|
|
12
|
+
useRef as useRef2,
|
|
13
|
+
useState as useState2
|
|
14
|
+
} from "react";
|
|
15
|
+
|
|
16
|
+
// src/docs/runtime/browser.ts
|
|
17
|
+
async function writeClipboardText(text) {
|
|
18
|
+
try {
|
|
19
|
+
if (navigator.clipboard?.writeText) {
|
|
20
|
+
await navigator.clipboard.writeText(text);
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
} catch {
|
|
24
|
+
}
|
|
25
|
+
const activeElement = document.activeElement instanceof HTMLElement ? document.activeElement : null;
|
|
26
|
+
const textarea = document.createElement("textarea");
|
|
27
|
+
textarea.value = text;
|
|
28
|
+
textarea.readOnly = true;
|
|
29
|
+
textarea.style.position = "fixed";
|
|
30
|
+
textarea.style.inset = "0 auto auto 0";
|
|
31
|
+
textarea.style.opacity = "0";
|
|
32
|
+
textarea.style.pointerEvents = "none";
|
|
33
|
+
document.body.appendChild(textarea);
|
|
34
|
+
textarea.focus({ preventScroll: true });
|
|
35
|
+
textarea.select();
|
|
36
|
+
const copied = document.execCommand("copy");
|
|
37
|
+
textarea.remove();
|
|
38
|
+
activeElement?.focus({ preventScroll: true });
|
|
39
|
+
if (!copied) throw new Error("Unable to copy text");
|
|
40
|
+
}
|
|
41
|
+
function externalProps(href) {
|
|
42
|
+
return isExternal(href) ? { target: "_blank", rel: "noopener noreferrer" } : {};
|
|
43
|
+
}
|
|
44
|
+
function isExternal(href) {
|
|
45
|
+
return /^https?:\/\//i.test(href);
|
|
46
|
+
}
|
|
47
|
+
function safeStorageGet(key) {
|
|
48
|
+
try {
|
|
49
|
+
return localStorage.getItem(key);
|
|
50
|
+
} catch {
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
function safeStorageSet(key, value) {
|
|
55
|
+
try {
|
|
56
|
+
localStorage.setItem(key, value);
|
|
57
|
+
} catch {
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
function errorMessage(error) {
|
|
61
|
+
return error instanceof Error ? error.message : String(error);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// src/docs/runtime/icons.tsx
|
|
65
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
66
|
+
function Icon({ children, ...props }) {
|
|
67
|
+
return /* @__PURE__ */ jsx(
|
|
68
|
+
"svg",
|
|
69
|
+
{
|
|
70
|
+
"aria-hidden": "true",
|
|
71
|
+
fill: "none",
|
|
72
|
+
height: "18",
|
|
73
|
+
viewBox: "0 0 24 24",
|
|
74
|
+
width: "18",
|
|
75
|
+
...props,
|
|
76
|
+
children
|
|
77
|
+
}
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
function OrbitMark(props) {
|
|
81
|
+
return /* @__PURE__ */ jsxs(Icon, { viewBox: "0 0 32 32", ...props, children: [
|
|
82
|
+
/* @__PURE__ */ jsx("path", { d: "M16 2.5c.5 7.7 5.8 13 13.5 13.5-7.7.5-13 5.8-13.5 13.5C15.5 21.8 10.2 16.5 2.5 16 10.2 15.5 15.5 10.2 16 2.5Z", fill: "currentColor" }),
|
|
83
|
+
/* @__PURE__ */ jsx("circle", { cx: "16", cy: "16", fill: "var(--docs-bg)", r: "3.25" }),
|
|
84
|
+
/* @__PURE__ */ jsx("path", { d: "M4.5 22.7c5.6-2 16.4-8.3 22.7-14.1", opacity: ".45", stroke: "currentColor", strokeLinecap: "round" })
|
|
85
|
+
] });
|
|
86
|
+
}
|
|
87
|
+
function SearchIcon(props) {
|
|
88
|
+
return /* @__PURE__ */ jsxs(Icon, { ...props, children: [
|
|
89
|
+
/* @__PURE__ */ jsx("circle", { cx: "11", cy: "11", r: "6.5", stroke: "currentColor", strokeWidth: "1.8" }),
|
|
90
|
+
/* @__PURE__ */ jsx("path", { d: "m16 16 4 4", stroke: "currentColor", strokeLinecap: "round", strokeWidth: "1.8" })
|
|
91
|
+
] });
|
|
92
|
+
}
|
|
93
|
+
function SparkIcon(props) {
|
|
94
|
+
return /* @__PURE__ */ jsxs(Icon, { ...props, children: [
|
|
95
|
+
/* @__PURE__ */ jsx("path", { d: "M12 2.8c.3 5 3.7 8.4 8.7 8.7-5 .3-8.4 3.7-8.7 8.7-.3-5-3.7-8.4-8.7-8.7 5-.3 8.4-3.7 8.7-8.7Z", stroke: "currentColor", strokeLinejoin: "round", strokeWidth: "1.6" }),
|
|
96
|
+
/* @__PURE__ */ jsx("path", { d: "M19 3v4M21 5h-4", stroke: "currentColor", strokeLinecap: "round", strokeWidth: "1.4" })
|
|
97
|
+
] });
|
|
98
|
+
}
|
|
99
|
+
function MenuIcon(props) {
|
|
100
|
+
return /* @__PURE__ */ jsx(Icon, { ...props, children: /* @__PURE__ */ jsx("path", { d: "M4 7h16M4 12h16M4 17h16", stroke: "currentColor", strokeLinecap: "round", strokeWidth: "1.8" }) });
|
|
101
|
+
}
|
|
102
|
+
function CloseIcon(props) {
|
|
103
|
+
return /* @__PURE__ */ jsx(Icon, { ...props, children: /* @__PURE__ */ jsx("path", { d: "m6 6 12 12M18 6 6 18", stroke: "currentColor", strokeLinecap: "round", strokeWidth: "1.8" }) });
|
|
104
|
+
}
|
|
105
|
+
function SunIcon(props) {
|
|
106
|
+
return /* @__PURE__ */ jsxs(Icon, { ...props, children: [
|
|
107
|
+
/* @__PURE__ */ jsx("circle", { cx: "12", cy: "12", r: "3.5", stroke: "currentColor", strokeWidth: "1.6" }),
|
|
108
|
+
/* @__PURE__ */ jsx("path", { d: "M12 2.5v2M12 19.5v2M2.5 12h2M19.5 12h2M5.3 5.3l1.4 1.4M17.3 17.3l1.4 1.4M18.7 5.3l-1.4 1.4M6.7 17.3l-1.4 1.4", stroke: "currentColor", strokeLinecap: "round", strokeWidth: "1.6" })
|
|
109
|
+
] });
|
|
110
|
+
}
|
|
111
|
+
function MoonIcon(props) {
|
|
112
|
+
return /* @__PURE__ */ jsx(Icon, { ...props, children: /* @__PURE__ */ jsx("path", { d: "M19.5 14.8A8 8 0 0 1 9.2 4.5 8 8 0 1 0 19.5 14.8Z", stroke: "currentColor", strokeLinejoin: "round", strokeWidth: "1.6" }) });
|
|
113
|
+
}
|
|
114
|
+
function SystemIcon(props) {
|
|
115
|
+
return /* @__PURE__ */ jsxs(Icon, { ...props, children: [
|
|
116
|
+
/* @__PURE__ */ jsx("rect", { x: "3", y: "4", width: "18", height: "13", rx: "2", stroke: "currentColor", strokeWidth: "1.6" }),
|
|
117
|
+
/* @__PURE__ */ jsx("path", { d: "M8 21h8M12 17v4", stroke: "currentColor", strokeLinecap: "round", strokeWidth: "1.6" })
|
|
118
|
+
] });
|
|
119
|
+
}
|
|
120
|
+
function ChevronRightIcon(props) {
|
|
121
|
+
return /* @__PURE__ */ jsx(Icon, { ...props, children: /* @__PURE__ */ jsx("path", { d: "m9 5 7 7-7 7", stroke: "currentColor", strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "1.8" }) });
|
|
122
|
+
}
|
|
123
|
+
function ChevronDownIcon(props) {
|
|
124
|
+
return /* @__PURE__ */ jsx(Icon, { ...props, children: /* @__PURE__ */ jsx("path", { d: "m5 9 7 7 7-7", stroke: "currentColor", strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "1.8" }) });
|
|
125
|
+
}
|
|
126
|
+
function ExternalIcon(props) {
|
|
127
|
+
return /* @__PURE__ */ jsxs(Icon, { ...props, children: [
|
|
128
|
+
/* @__PURE__ */ jsx("path", { d: "M14 4h6v6M20 4l-9 9", stroke: "currentColor", strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "1.6" }),
|
|
129
|
+
/* @__PURE__ */ jsx("path", { d: "M18 13v5a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h5", stroke: "currentColor", strokeLinecap: "round", strokeWidth: "1.6" })
|
|
130
|
+
] });
|
|
131
|
+
}
|
|
132
|
+
function CopyIcon(props) {
|
|
133
|
+
return /* @__PURE__ */ jsxs(Icon, { ...props, children: [
|
|
134
|
+
/* @__PURE__ */ jsx("rect", { x: "8", y: "8", width: "11", height: "11", rx: "2", stroke: "currentColor", strokeWidth: "1.6" }),
|
|
135
|
+
/* @__PURE__ */ jsx("path", { d: "M16 8V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v8a2 2 0 0 0 2 2h2", stroke: "currentColor", strokeWidth: "1.6" })
|
|
136
|
+
] });
|
|
137
|
+
}
|
|
138
|
+
function CheckIcon(props) {
|
|
139
|
+
return /* @__PURE__ */ jsx(Icon, { ...props, children: /* @__PURE__ */ jsx("path", { d: "m5 12.5 4.2 4L19 7", stroke: "currentColor", strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "1.9" }) });
|
|
140
|
+
}
|
|
141
|
+
function FileIcon(props) {
|
|
142
|
+
return /* @__PURE__ */ jsxs(Icon, { ...props, children: [
|
|
143
|
+
/* @__PURE__ */ jsx("path", { d: "M6 3.5h8l4 4V20a1 1 0 0 1-1 1H6a1 1 0 0 1-1-1V4.5a1 1 0 0 1 1-1Z", stroke: "currentColor", strokeLinejoin: "round", strokeWidth: "1.6" }),
|
|
144
|
+
/* @__PURE__ */ jsx("path", { d: "M14 3.5v4h4M8 12h7M8 16h7", stroke: "currentColor", strokeLinecap: "round", strokeWidth: "1.6" })
|
|
145
|
+
] });
|
|
146
|
+
}
|
|
147
|
+
function MessageIcon(props) {
|
|
148
|
+
return /* @__PURE__ */ jsxs(Icon, { ...props, children: [
|
|
149
|
+
/* @__PURE__ */ jsx("path", { d: "M5.5 18.5 4 21l3.5-1.2A8.5 8.5 0 1 0 5.5 18.5Z", stroke: "currentColor", strokeLinejoin: "round", strokeWidth: "1.6" }),
|
|
150
|
+
/* @__PURE__ */ jsx("path", { d: "M8 10h8M8 14h5", stroke: "currentColor", strokeLinecap: "round", strokeWidth: "1.6" })
|
|
151
|
+
] });
|
|
152
|
+
}
|
|
153
|
+
function TerminalIcon(props) {
|
|
154
|
+
return /* @__PURE__ */ jsxs(Icon, { ...props, children: [
|
|
155
|
+
/* @__PURE__ */ jsx("rect", { x: "3.5", y: "4.5", width: "17", height: "15", rx: "2", stroke: "currentColor", strokeWidth: "1.6" }),
|
|
156
|
+
/* @__PURE__ */ jsx("path", { d: "m7 9 3 3-3 3M12.5 15H17", stroke: "currentColor", strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "1.6" })
|
|
157
|
+
] });
|
|
158
|
+
}
|
|
159
|
+
function EditorIcon(props) {
|
|
160
|
+
return /* @__PURE__ */ jsxs(Icon, { ...props, children: [
|
|
161
|
+
/* @__PURE__ */ jsx("rect", { x: "3.5", y: "4.5", width: "17", height: "15", rx: "2", stroke: "currentColor", strokeWidth: "1.6" }),
|
|
162
|
+
/* @__PURE__ */ jsx("path", { d: "M8 4.5v15M11.5 9h5M11.5 12h5M11.5 15h3", stroke: "currentColor", strokeLinecap: "round", strokeWidth: "1.6" })
|
|
163
|
+
] });
|
|
164
|
+
}
|
|
165
|
+
function SendIcon(props) {
|
|
166
|
+
return /* @__PURE__ */ jsx(Icon, { ...props, children: /* @__PURE__ */ jsx("path", { d: "M12 18V6M7.5 10.5 12 6l4.5 4.5", stroke: "currentColor", strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "1.8" }) });
|
|
167
|
+
}
|
|
168
|
+
function StopIcon(props) {
|
|
169
|
+
return /* @__PURE__ */ jsx(Icon, { ...props, children: /* @__PURE__ */ jsx("rect", { x: "6", y: "6", width: "12", height: "12", rx: "2", fill: "currentColor" }) });
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// src/docs/runtime/page-actions.tsx
|
|
173
|
+
import { useEffect, useRef, useState } from "react";
|
|
174
|
+
import { Fragment, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
175
|
+
function PageActions({
|
|
176
|
+
data,
|
|
177
|
+
onAssistantOpen
|
|
178
|
+
}) {
|
|
179
|
+
const [copied, setCopied] = useState(null);
|
|
180
|
+
const detailsRef = useRef(null);
|
|
181
|
+
const actions = data.config.contextual.actions.filter((action) => {
|
|
182
|
+
if ((action === "copy" || action === "view" || action === "chatgpt" || action === "claude") && data.page.route === "/404") return false;
|
|
183
|
+
if (action === "assistant" && data.config.assistant.access === "disabled") return false;
|
|
184
|
+
if ((action === "mcp" || action === "add-mcp" || action === "cursor" || action === "vscode") && data.config.mcp.access !== "public") return false;
|
|
185
|
+
return true;
|
|
186
|
+
});
|
|
187
|
+
const primary = actions[0];
|
|
188
|
+
useEffect(() => {
|
|
189
|
+
const closeOnPointerDown = (event) => {
|
|
190
|
+
const details = detailsRef.current;
|
|
191
|
+
if (details && !details.contains(event.target)) details.open = false;
|
|
192
|
+
};
|
|
193
|
+
const closeOnEscape = (event) => {
|
|
194
|
+
if (event.key === "Escape" && detailsRef.current?.open) {
|
|
195
|
+
detailsRef.current.open = false;
|
|
196
|
+
detailsRef.current.querySelector("summary")?.focus();
|
|
197
|
+
}
|
|
198
|
+
};
|
|
199
|
+
document.addEventListener("pointerdown", closeOnPointerDown);
|
|
200
|
+
document.addEventListener("keydown", closeOnEscape);
|
|
201
|
+
return () => {
|
|
202
|
+
document.removeEventListener("pointerdown", closeOnPointerDown);
|
|
203
|
+
document.removeEventListener("keydown", closeOnEscape);
|
|
204
|
+
};
|
|
205
|
+
}, []);
|
|
206
|
+
if (!primary) return null;
|
|
207
|
+
const markCopied = (action) => {
|
|
208
|
+
setCopied(action);
|
|
209
|
+
window.setTimeout(() => setCopied((current) => current === action ? null : current), 1600);
|
|
210
|
+
};
|
|
211
|
+
const copyPage = async () => {
|
|
212
|
+
const response = await fetch(data.page.markdownUrl);
|
|
213
|
+
if (!response.ok) return;
|
|
214
|
+
await writeClipboardText(await response.text());
|
|
215
|
+
markCopied("copy");
|
|
216
|
+
};
|
|
217
|
+
const copyMcp = async () => {
|
|
218
|
+
await writeClipboardText(new URL("/mcp", window.location.origin).toString());
|
|
219
|
+
markCopied("mcp");
|
|
220
|
+
};
|
|
221
|
+
const copyMcpInstall = async () => {
|
|
222
|
+
const mcpUrl = new URL("/mcp", window.location.origin).toString();
|
|
223
|
+
await writeClipboardText(`npx add-mcp ${mcpUrl}`);
|
|
224
|
+
markCopied("add-mcp");
|
|
225
|
+
};
|
|
226
|
+
const closeMenu = () => {
|
|
227
|
+
if (detailsRef.current) detailsRef.current.open = false;
|
|
228
|
+
};
|
|
229
|
+
const openAiContext = (provider) => {
|
|
230
|
+
const markdownUrl = new URL(data.page.markdownUrl, window.location.origin).toString();
|
|
231
|
+
const prompt = `Use ${markdownUrl} as context. Explain ${data.page.title} and answer my questions about this documentation page.`;
|
|
232
|
+
const destination = new URL(provider === "chatgpt" ? "https://chatgpt.com/" : "https://claude.ai/new");
|
|
233
|
+
destination.searchParams.set("q", prompt);
|
|
234
|
+
window.open(destination.toString(), "_blank", "noopener,noreferrer");
|
|
235
|
+
closeMenu();
|
|
236
|
+
};
|
|
237
|
+
const openMcpEditor = (editor) => {
|
|
238
|
+
const mcpUrl = new URL("/mcp", window.location.origin).toString();
|
|
239
|
+
const name = data.config.name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/(^-|-$)/g, "") || "docs";
|
|
240
|
+
if (editor === "cursor") {
|
|
241
|
+
const config = window.btoa(JSON.stringify({ url: mcpUrl }));
|
|
242
|
+
window.location.href = `cursor://anysphere.cursor-deeplink/mcp/install?name=${encodeURIComponent(name)}&config=${encodeURIComponent(config)}`;
|
|
243
|
+
} else {
|
|
244
|
+
const config = encodeURIComponent(JSON.stringify({ name, type: "http", url: mcpUrl }));
|
|
245
|
+
window.location.href = `vscode:mcp/install?${config}`;
|
|
246
|
+
}
|
|
247
|
+
closeMenu();
|
|
248
|
+
};
|
|
249
|
+
const content = (icon, label, description, menuItem, external = false) => menuItem ? /* @__PURE__ */ jsxs2(Fragment, { children: [
|
|
250
|
+
/* @__PURE__ */ jsx2("span", { className: "docs-contextual-action-icon", children: icon }),
|
|
251
|
+
/* @__PURE__ */ jsxs2("span", { className: "docs-contextual-action-copy", children: [
|
|
252
|
+
/* @__PURE__ */ jsx2("strong", { children: label }),
|
|
253
|
+
/* @__PURE__ */ jsx2("small", { children: description })
|
|
254
|
+
] }),
|
|
255
|
+
external && /* @__PURE__ */ jsx2(ExternalIcon, { className: "docs-contextual-action-external" })
|
|
256
|
+
] }) : /* @__PURE__ */ jsxs2(Fragment, { children: [
|
|
257
|
+
icon,
|
|
258
|
+
label
|
|
259
|
+
] });
|
|
260
|
+
const renderAction = (action, menuItem = false) => {
|
|
261
|
+
const role = menuItem ? "menuitem" : void 0;
|
|
262
|
+
if (action === "view") {
|
|
263
|
+
return /* @__PURE__ */ jsx2("a", { href: data.page.markdownUrl, onClick: closeMenu, role, children: content(/* @__PURE__ */ jsx2(FileIcon, {}), "View as Markdown", "Open the raw Markdown page", menuItem) }, action);
|
|
264
|
+
}
|
|
265
|
+
if (action === "assistant") {
|
|
266
|
+
return /* @__PURE__ */ jsx2("button", { role, type: "button", onClick: () => {
|
|
267
|
+
closeMenu();
|
|
268
|
+
onAssistantOpen(`Explain the key ideas on ${data.page.title}.`);
|
|
269
|
+
}, children: content(/* @__PURE__ */ jsx2(OrbitMark, {}), "Ask about this page", "Use the DeepSpace agent with page context", menuItem) }, action);
|
|
270
|
+
}
|
|
271
|
+
if (action === "chatgpt" || action === "claude") {
|
|
272
|
+
const label2 = action === "chatgpt" ? "Open in ChatGPT" : "Open in Claude";
|
|
273
|
+
return /* @__PURE__ */ jsx2("button", { role, type: "button", onClick: () => openAiContext(action), children: content(/* @__PURE__ */ jsx2(MessageIcon, {}), label2, "Ask questions about this page", menuItem, true) }, action);
|
|
274
|
+
}
|
|
275
|
+
if (action === "mcp") {
|
|
276
|
+
const label2 = copied === action ? "MCP URL copied" : "Copy MCP server URL";
|
|
277
|
+
return /* @__PURE__ */ jsx2("button", { role, type: "button", onClick: copyMcp, children: content(copied === action ? /* @__PURE__ */ jsx2(CheckIcon, {}) : /* @__PURE__ */ jsx2(CopyIcon, {}), label2, "Copy the same-release documentation endpoint", menuItem) }, action);
|
|
278
|
+
}
|
|
279
|
+
if (action === "add-mcp") {
|
|
280
|
+
const label2 = copied === action ? "Install command copied" : "Copy MCP install command";
|
|
281
|
+
return /* @__PURE__ */ jsx2("button", { role, type: "button", onClick: copyMcpInstall, children: content(copied === action ? /* @__PURE__ */ jsx2(CheckIcon, {}) : /* @__PURE__ */ jsx2(TerminalIcon, {}), label2, "Copy npx command to install MCP server", menuItem) }, action);
|
|
282
|
+
}
|
|
283
|
+
if (action === "cursor" || action === "vscode") {
|
|
284
|
+
const label2 = action === "cursor" ? "Connect to Cursor" : "Connect to VS Code";
|
|
285
|
+
return /* @__PURE__ */ jsx2("button", { role, type: "button", onClick: () => openMcpEditor(action), children: content(/* @__PURE__ */ jsx2(EditorIcon, {}), label2, `Install MCP server in ${action === "cursor" ? "Cursor" : "VS Code"}`, menuItem, true) }, action);
|
|
286
|
+
}
|
|
287
|
+
const label = copied === action ? "Page copied" : "Copy page";
|
|
288
|
+
return /* @__PURE__ */ jsx2("button", { role, type: "button", onClick: copyPage, children: content(copied === action ? /* @__PURE__ */ jsx2(CheckIcon, {}) : /* @__PURE__ */ jsx2(CopyIcon, {}), label, "Copy page as Markdown for LLMs", menuItem) }, action);
|
|
289
|
+
};
|
|
290
|
+
return /* @__PURE__ */ jsxs2("div", { className: "docs-contextual-actions", "aria-label": "Page actions", children: [
|
|
291
|
+
/* @__PURE__ */ jsx2("div", { className: "docs-contextual-primary", "aria-live": "polite", children: renderAction(primary) }),
|
|
292
|
+
actions.length > 0 && /* @__PURE__ */ jsxs2("details", { ref: detailsRef, children: [
|
|
293
|
+
/* @__PURE__ */ jsx2("summary", { "aria-label": "More page actions", children: /* @__PURE__ */ jsx2(ChevronDownIcon, {}) }),
|
|
294
|
+
/* @__PURE__ */ jsx2("div", { "aria-label": "More page actions", className: "docs-contextual-menu", role: "menu", children: actions.map((action) => renderAction(action, true)) })
|
|
295
|
+
] })
|
|
296
|
+
] });
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
// src/docs/runtime/article.tsx
|
|
300
|
+
import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
301
|
+
function Article({
|
|
302
|
+
children,
|
|
303
|
+
data,
|
|
304
|
+
onAssistantOpen
|
|
305
|
+
}) {
|
|
306
|
+
const articleRef = useRef2(null);
|
|
307
|
+
useArticleEnhancements(articleRef, data, onAssistantOpen);
|
|
308
|
+
return /* @__PURE__ */ jsxs3("article", { className: "docs-article", ref: articleRef, children: [
|
|
309
|
+
/* @__PURE__ */ jsx3(Breadcrumbs, { items: data.breadcrumbs }),
|
|
310
|
+
/* @__PURE__ */ jsxs3("header", { className: "docs-article-header", children: [
|
|
311
|
+
/* @__PURE__ */ jsxs3("div", { className: "docs-article-meta", children: [
|
|
312
|
+
data.config.theme.eyebrowStyle !== "none" && /* @__PURE__ */ jsx3("div", { className: "docs-eyebrow", children: data.page.kind === "openapi" ? "API reference" : data.config.theme.eyebrowStyle === "breadcrumbs" ? data.breadcrumbs.join(" / ") : data.breadcrumbs[0] ?? "Documentation" }),
|
|
313
|
+
/* @__PURE__ */ jsx3(PageActions, { data, onAssistantOpen })
|
|
314
|
+
] }),
|
|
315
|
+
/* @__PURE__ */ jsx3("h1", { children: data.page.title }),
|
|
316
|
+
data.page.description && /* @__PURE__ */ jsx3("p", { className: "docs-lede", children: data.page.description })
|
|
317
|
+
] }),
|
|
318
|
+
children ?? /* @__PURE__ */ jsx3("div", { className: "docs-prose", dangerouslySetInnerHTML: { __html: data.page.html } }),
|
|
319
|
+
data.page.openapi?.playground && /* @__PURE__ */ jsx3(ApiPlayground, { operation: data.page.openapi }),
|
|
320
|
+
/* @__PURE__ */ jsxs3("nav", { className: "docs-pagination", "aria-label": "Page navigation", children: [
|
|
321
|
+
data.previous ? /* @__PURE__ */ jsxs3("a", { rel: "prev", href: data.previous.route, children: [
|
|
322
|
+
/* @__PURE__ */ jsx3("small", { children: "Previous" }),
|
|
323
|
+
/* @__PURE__ */ jsxs3("span", { children: [
|
|
324
|
+
/* @__PURE__ */ jsx3(ChevronRightIcon, { className: "is-back" }),
|
|
325
|
+
data.previous.title
|
|
326
|
+
] })
|
|
327
|
+
] }) : /* @__PURE__ */ jsx3("span", {}),
|
|
328
|
+
data.next ? /* @__PURE__ */ jsxs3("a", { rel: "next", href: data.next.route, children: [
|
|
329
|
+
/* @__PURE__ */ jsx3("small", { children: "Next" }),
|
|
330
|
+
/* @__PURE__ */ jsxs3("span", { children: [
|
|
331
|
+
data.next.title,
|
|
332
|
+
/* @__PURE__ */ jsx3(ChevronRightIcon, {})
|
|
333
|
+
] })
|
|
334
|
+
] }) : /* @__PURE__ */ jsx3("span", {})
|
|
335
|
+
] })
|
|
336
|
+
] });
|
|
337
|
+
}
|
|
338
|
+
function Breadcrumbs({ items }) {
|
|
339
|
+
return /* @__PURE__ */ jsx3("nav", { className: "docs-breadcrumbs", "aria-label": "Breadcrumb", children: items.map((item, index) => /* @__PURE__ */ jsxs3("span", { children: [
|
|
340
|
+
index > 0 && /* @__PURE__ */ jsx3(ChevronRightIcon, {}),
|
|
341
|
+
item
|
|
342
|
+
] }, `${item}:${items.slice(0, index + 1).join("/")}`)) });
|
|
343
|
+
}
|
|
344
|
+
function ContextRail({
|
|
345
|
+
data
|
|
346
|
+
}) {
|
|
347
|
+
const headings = useMemo(
|
|
348
|
+
() => data.page.headings.filter((heading) => heading.depth === 2 || heading.depth === 3),
|
|
349
|
+
[data.page.headings]
|
|
350
|
+
);
|
|
351
|
+
const [active, setActive] = useState2(headings[0]?.id ?? "");
|
|
352
|
+
useEffect2(() => setActive(headings[0]?.id ?? ""), [headings]);
|
|
353
|
+
useEffect2(() => {
|
|
354
|
+
if (typeof IntersectionObserver === "undefined") return;
|
|
355
|
+
const elements = headings.map((heading) => document.getElementById(heading.id)).filter(Boolean);
|
|
356
|
+
const observer = new IntersectionObserver((entries) => {
|
|
357
|
+
const visible = entries.filter((entry) => entry.isIntersecting).sort((left, right) => left.boundingClientRect.top - right.boundingClientRect.top);
|
|
358
|
+
if (visible[0]?.target.id) setActive(visible[0].target.id);
|
|
359
|
+
}, { rootMargin: "-88px 0px -68% 0px", threshold: [0, 1] });
|
|
360
|
+
elements.forEach((element) => observer.observe(element));
|
|
361
|
+
return () => observer.disconnect();
|
|
362
|
+
}, [headings]);
|
|
363
|
+
return /* @__PURE__ */ jsx3("aside", { className: "docs-context-rail", "aria-label": "Page context", children: headings.length > 0 && /* @__PURE__ */ jsxs3("nav", { className: "docs-outline", "aria-label": "On this page", children: [
|
|
364
|
+
/* @__PURE__ */ jsx3("h2", { children: "On this page" }),
|
|
365
|
+
headings.map((heading) => /* @__PURE__ */ jsx3(
|
|
366
|
+
"a",
|
|
367
|
+
{
|
|
368
|
+
"aria-current": active === heading.id ? "location" : void 0,
|
|
369
|
+
className: `${heading.depth === 3 ? "depth-3 " : ""}${active === heading.id ? "is-active" : ""}`,
|
|
370
|
+
href: `#${heading.id}`,
|
|
371
|
+
children: heading.text
|
|
372
|
+
},
|
|
373
|
+
heading.id
|
|
374
|
+
))
|
|
375
|
+
] }) });
|
|
376
|
+
}
|
|
377
|
+
function ApiPlayground({ operation }) {
|
|
378
|
+
const [body, setBody] = useState2("");
|
|
379
|
+
const [token, setToken] = useState2("");
|
|
380
|
+
const [responseText, setResponseText] = useState2("No request sent.");
|
|
381
|
+
const [sending, setSending] = useState2(false);
|
|
382
|
+
if (!operation.baseUrl) return null;
|
|
383
|
+
const url = `${operation.baseUrl.replace(/\/$/, "")}${operation.path}`;
|
|
384
|
+
const send = async () => {
|
|
385
|
+
setSending(true);
|
|
386
|
+
setResponseText("Sending request\u2026");
|
|
387
|
+
try {
|
|
388
|
+
const headers = {};
|
|
389
|
+
if (token) headers.Authorization = `Bearer ${token}`;
|
|
390
|
+
if (body.trim()) headers["Content-Type"] = "application/json";
|
|
391
|
+
const response = await fetch(url, {
|
|
392
|
+
method: operation.method,
|
|
393
|
+
headers,
|
|
394
|
+
body: ["GET", "HEAD"].includes(operation.method) ? void 0 : body.trim() || void 0
|
|
395
|
+
});
|
|
396
|
+
const text = await response.text();
|
|
397
|
+
setResponseText(`${response.status} ${response.statusText}
|
|
398
|
+
|
|
399
|
+
${text}`);
|
|
400
|
+
} catch (error) {
|
|
401
|
+
setResponseText(errorMessage(error));
|
|
402
|
+
} finally {
|
|
403
|
+
setSending(false);
|
|
404
|
+
}
|
|
405
|
+
};
|
|
406
|
+
return /* @__PURE__ */ jsxs3("section", { className: "docs-playground", "data-playground": true, children: [
|
|
407
|
+
/* @__PURE__ */ jsxs3("div", { className: "docs-playground-title", children: [
|
|
408
|
+
/* @__PURE__ */ jsxs3("div", { children: [
|
|
409
|
+
/* @__PURE__ */ jsx3("span", { className: `method method-${operation.method.toLowerCase()}`, children: operation.method }),
|
|
410
|
+
/* @__PURE__ */ jsx3("strong", { children: "Try this operation" })
|
|
411
|
+
] }),
|
|
412
|
+
/* @__PURE__ */ jsx3("code", { children: url })
|
|
413
|
+
] }),
|
|
414
|
+
/* @__PURE__ */ jsx3("p", { children: "Requests run in your browser. Tokens stay in memory and never enter search or assistant context." }),
|
|
415
|
+
/* @__PURE__ */ jsxs3("label", { children: [
|
|
416
|
+
/* @__PURE__ */ jsx3("span", { children: "Bearer token" }),
|
|
417
|
+
/* @__PURE__ */ jsx3("input", { type: "password", autoComplete: "off", value: token, onChange: (event) => setToken(event.target.value), placeholder: "Optional" })
|
|
418
|
+
] }),
|
|
419
|
+
/* @__PURE__ */ jsxs3("label", { children: [
|
|
420
|
+
/* @__PURE__ */ jsx3("span", { children: "JSON body" }),
|
|
421
|
+
/* @__PURE__ */ jsx3("textarea", { rows: 7, spellCheck: "false", value: body, onChange: (event) => setBody(event.target.value), placeholder: "{}" })
|
|
422
|
+
] }),
|
|
423
|
+
/* @__PURE__ */ jsx3("button", { type: "button", disabled: sending, onClick: send, children: sending ? "Sending\u2026" : `Send ${operation.method} request` }),
|
|
424
|
+
/* @__PURE__ */ jsx3("pre", { "aria-live": "polite", children: responseText })
|
|
425
|
+
] });
|
|
426
|
+
}
|
|
427
|
+
function useArticleEnhancements(articleRef, data, onAssistantOpen) {
|
|
428
|
+
useEffect2(() => {
|
|
429
|
+
const article = articleRef.current;
|
|
430
|
+
if (!article) return;
|
|
431
|
+
const cleanups = [];
|
|
432
|
+
article.querySelectorAll(".docs-prose pre").forEach((pre) => {
|
|
433
|
+
if (pre.querySelector(".docs-code-actions")) return;
|
|
434
|
+
const controls = document.createElement("div");
|
|
435
|
+
controls.className = "docs-code-actions";
|
|
436
|
+
const copy = document.createElement("button");
|
|
437
|
+
copy.type = "button";
|
|
438
|
+
copy.setAttribute("aria-label", "Copy code");
|
|
439
|
+
copy.textContent = "Copy";
|
|
440
|
+
const copyHandler = async () => {
|
|
441
|
+
await writeClipboardText(pre.querySelector("code")?.textContent ?? pre.textContent ?? "");
|
|
442
|
+
copy.textContent = "Copied";
|
|
443
|
+
window.setTimeout(() => {
|
|
444
|
+
copy.textContent = "Copy";
|
|
445
|
+
}, 1400);
|
|
446
|
+
};
|
|
447
|
+
copy.addEventListener("click", copyHandler);
|
|
448
|
+
controls.appendChild(copy);
|
|
449
|
+
if (data.config.assistant.access !== "disabled") {
|
|
450
|
+
const ask = document.createElement("button");
|
|
451
|
+
ask.type = "button";
|
|
452
|
+
ask.textContent = "Ask";
|
|
453
|
+
ask.setAttribute("aria-label", "Ask the documentation assistant about this code");
|
|
454
|
+
const askHandler = () => {
|
|
455
|
+
const code = pre.querySelector("code")?.textContent?.trim().slice(0, 1200) ?? "";
|
|
456
|
+
onAssistantOpen(`Explain this ${data.page.title} example and the important details:
|
|
457
|
+
|
|
458
|
+
${code}`);
|
|
459
|
+
};
|
|
460
|
+
ask.addEventListener("click", askHandler);
|
|
461
|
+
controls.appendChild(ask);
|
|
462
|
+
cleanups.push(() => ask.removeEventListener("click", askHandler));
|
|
463
|
+
}
|
|
464
|
+
pre.appendChild(controls);
|
|
465
|
+
cleanups.push(() => {
|
|
466
|
+
copy.removeEventListener("click", copyHandler);
|
|
467
|
+
controls.remove();
|
|
468
|
+
});
|
|
469
|
+
});
|
|
470
|
+
article.querySelectorAll("[data-tab-group]").forEach((group, groupIndex) => {
|
|
471
|
+
if (group.querySelector(":scope > .docs-tab-buttons")) return;
|
|
472
|
+
const tabs = Array.from(group.querySelectorAll(":scope > [data-tab]"));
|
|
473
|
+
if (tabs.length === 0) return;
|
|
474
|
+
const controls = document.createElement("div");
|
|
475
|
+
controls.className = "docs-tab-buttons";
|
|
476
|
+
controls.setAttribute("role", "tablist");
|
|
477
|
+
const labels = tabs.map((tab, tabIndex) => tab.dataset.tabTitle ?? `Tab ${tabIndex + 1}`);
|
|
478
|
+
const activate = (activeIndex, broadcast = false) => {
|
|
479
|
+
tabs.forEach((tab, index) => {
|
|
480
|
+
tab.hidden = index !== activeIndex;
|
|
481
|
+
tab.setAttribute("role", "tabpanel");
|
|
482
|
+
});
|
|
483
|
+
Array.from(controls.querySelectorAll("button")).forEach((button, index) => {
|
|
484
|
+
button.setAttribute("aria-selected", index === activeIndex ? "true" : "false");
|
|
485
|
+
button.setAttribute("tabindex", index === activeIndex ? "0" : "-1");
|
|
486
|
+
});
|
|
487
|
+
if (broadcast) {
|
|
488
|
+
const label = labels[activeIndex];
|
|
489
|
+
if (label) {
|
|
490
|
+
safeStorageSet("deepspace-docs-tab-selection", label);
|
|
491
|
+
document.dispatchEvent(new CustomEvent("deepspace-docs-tab-change", {
|
|
492
|
+
detail: { label, source: group }
|
|
493
|
+
}));
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
};
|
|
497
|
+
tabs.forEach((tab, tabIndex) => {
|
|
498
|
+
const button = document.createElement("button");
|
|
499
|
+
button.type = "button";
|
|
500
|
+
button.id = `docs-tab-${groupIndex}-${tabIndex}`;
|
|
501
|
+
button.setAttribute("role", "tab");
|
|
502
|
+
button.textContent = labels[tabIndex];
|
|
503
|
+
tab.setAttribute("aria-labelledby", button.id);
|
|
504
|
+
const click = () => activate(tabIndex, true);
|
|
505
|
+
const keydown = (event) => {
|
|
506
|
+
if (!["ArrowLeft", "ArrowRight", "Home", "End"].includes(event.key)) return;
|
|
507
|
+
event.preventDefault();
|
|
508
|
+
const next = event.key === "Home" ? 0 : event.key === "End" ? tabs.length - 1 : (tabIndex + (event.key === "ArrowRight" ? 1 : -1) + tabs.length) % tabs.length;
|
|
509
|
+
activate(next);
|
|
510
|
+
controls.querySelectorAll("button")[next]?.focus();
|
|
511
|
+
};
|
|
512
|
+
button.addEventListener("click", click);
|
|
513
|
+
button.addEventListener("keydown", keydown);
|
|
514
|
+
controls.appendChild(button);
|
|
515
|
+
cleanups.push(() => {
|
|
516
|
+
button.removeEventListener("click", click);
|
|
517
|
+
button.removeEventListener("keydown", keydown);
|
|
518
|
+
});
|
|
519
|
+
});
|
|
520
|
+
const title = group.querySelector(":scope > .docs-code-group-title");
|
|
521
|
+
if (title) group.insertBefore(controls, title.nextSibling);
|
|
522
|
+
if (!title) group.insertBefore(controls, group.firstChild);
|
|
523
|
+
const sync = (event) => {
|
|
524
|
+
const detail = event.detail;
|
|
525
|
+
if (!detail?.label || detail.source === group) return;
|
|
526
|
+
const matchingIndex = labels.findIndex((label) => label === detail.label);
|
|
527
|
+
if (matchingIndex >= 0) activate(matchingIndex);
|
|
528
|
+
};
|
|
529
|
+
document.addEventListener("deepspace-docs-tab-change", sync);
|
|
530
|
+
const stored = safeStorageGet("deepspace-docs-tab-selection");
|
|
531
|
+
const initial = stored ? labels.findIndex((label) => label === stored) : -1;
|
|
532
|
+
activate(initial >= 0 ? initial : 0);
|
|
533
|
+
cleanups.push(() => {
|
|
534
|
+
document.removeEventListener("deepspace-docs-tab-change", sync);
|
|
535
|
+
controls.remove();
|
|
536
|
+
});
|
|
537
|
+
});
|
|
538
|
+
return () => cleanups.reverse().forEach((cleanup) => cleanup());
|
|
539
|
+
}, [articleRef, data.config.assistant.access, data.page.route, data.page.title, onAssistantOpen]);
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
// src/docs/runtime/assistant.tsx
|
|
543
|
+
import {
|
|
544
|
+
useEffect as useEffect4,
|
|
545
|
+
useRef as useRef3,
|
|
546
|
+
useState as useState3
|
|
547
|
+
} from "react";
|
|
548
|
+
|
|
549
|
+
// src/client/ai-stream.ts
|
|
550
|
+
function parseSseLine(line) {
|
|
551
|
+
if (!line) return null;
|
|
552
|
+
if (line.startsWith(":")) return null;
|
|
553
|
+
if (!line.startsWith("data:")) return null;
|
|
554
|
+
const raw = line.slice(5).replace(/^ /, "").replace(/\r$/, "");
|
|
555
|
+
if (raw === "[DONE]") return null;
|
|
556
|
+
try {
|
|
557
|
+
const parsed = JSON.parse(raw);
|
|
558
|
+
if (!parsed || typeof parsed !== "object") return null;
|
|
559
|
+
return parsed;
|
|
560
|
+
} catch {
|
|
561
|
+
return null;
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
// src/docs/runtime/assistant-history.ts
|
|
566
|
+
function completedDocsAssistantHistory(messages, maxMessages = 12) {
|
|
567
|
+
const pairs = [];
|
|
568
|
+
for (let index = 0; index < messages.length - 1; index += 1) {
|
|
569
|
+
const user = messages[index];
|
|
570
|
+
if (user?.role !== "user" || user.state !== void 0 || !user.text.trim()) continue;
|
|
571
|
+
const assistant = messages[index + 1];
|
|
572
|
+
if (assistant?.role !== "assistant" || assistant.state !== void 0 || !assistant.text.trim()) {
|
|
573
|
+
continue;
|
|
574
|
+
}
|
|
575
|
+
pairs.push([
|
|
576
|
+
{ role: "user", content: user.text },
|
|
577
|
+
{ role: "assistant", content: assistant.text }
|
|
578
|
+
]);
|
|
579
|
+
index += 1;
|
|
580
|
+
}
|
|
581
|
+
const pairLimit = Math.max(0, Math.floor(maxMessages / 2));
|
|
582
|
+
if (pairLimit === 0) return [];
|
|
583
|
+
return pairs.slice(-pairLimit).flat();
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
// src/docs/runtime/dialog.ts
|
|
587
|
+
import { useEffect as useEffect3 } from "react";
|
|
588
|
+
function useDialogFocus(open, ref, onClose, trap = true, restoreId) {
|
|
589
|
+
useEffect3(() => {
|
|
590
|
+
if (!open) return;
|
|
591
|
+
const previous = document.activeElement;
|
|
592
|
+
const element = ref.current;
|
|
593
|
+
const frame = window.requestAnimationFrame(() => {
|
|
594
|
+
const target = element?.querySelector("[data-autofocus]") ?? element?.querySelector("button,a,input,textarea");
|
|
595
|
+
target?.focus();
|
|
596
|
+
});
|
|
597
|
+
const keydown = (event) => {
|
|
598
|
+
if (event.key === "Escape") {
|
|
599
|
+
event.preventDefault();
|
|
600
|
+
onClose();
|
|
601
|
+
return;
|
|
602
|
+
}
|
|
603
|
+
if (!trap || event.key !== "Tab" || !element) return;
|
|
604
|
+
const focusable = Array.from(element.querySelectorAll(
|
|
605
|
+
'a[href],button:not([disabled]),input:not([disabled]),textarea:not([disabled]),[tabindex]:not([tabindex="-1"])'
|
|
606
|
+
));
|
|
607
|
+
if (focusable.length === 0) return;
|
|
608
|
+
const first = focusable[0];
|
|
609
|
+
const last = focusable[focusable.length - 1];
|
|
610
|
+
if (event.shiftKey && document.activeElement === first) {
|
|
611
|
+
event.preventDefault();
|
|
612
|
+
last?.focus();
|
|
613
|
+
} else if (!event.shiftKey && document.activeElement === last) {
|
|
614
|
+
event.preventDefault();
|
|
615
|
+
first?.focus();
|
|
616
|
+
}
|
|
617
|
+
};
|
|
618
|
+
document.addEventListener("keydown", keydown);
|
|
619
|
+
return () => {
|
|
620
|
+
window.cancelAnimationFrame(frame);
|
|
621
|
+
document.removeEventListener("keydown", keydown);
|
|
622
|
+
const restoreTarget = restoreId ? document.getElementById(restoreId) : previous?.isConnected && previous !== document.body && !element?.contains(previous) ? previous : null;
|
|
623
|
+
restoreTarget?.focus();
|
|
624
|
+
};
|
|
625
|
+
}, [onClose, open, ref, restoreId, trap]);
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
// src/docs/runtime/assistant.tsx
|
|
629
|
+
import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
630
|
+
function AssistantLauncher({
|
|
631
|
+
name,
|
|
632
|
+
onOpen,
|
|
633
|
+
onSubmit,
|
|
634
|
+
open
|
|
635
|
+
}) {
|
|
636
|
+
const [input, setInput] = useState3("");
|
|
637
|
+
const submit = (event) => {
|
|
638
|
+
event.preventDefault();
|
|
639
|
+
const question = input.trim();
|
|
640
|
+
if (!question) return;
|
|
641
|
+
setInput("");
|
|
642
|
+
onSubmit(question);
|
|
643
|
+
};
|
|
644
|
+
if (open) return null;
|
|
645
|
+
return /* @__PURE__ */ jsxs4(
|
|
646
|
+
"form",
|
|
647
|
+
{
|
|
648
|
+
className: "docs-assistant-launcher",
|
|
649
|
+
id: "deepspace-docs-assistant-launcher",
|
|
650
|
+
onSubmit: submit,
|
|
651
|
+
children: [
|
|
652
|
+
/* @__PURE__ */ jsxs4("button", { className: "docs-launcher-agent", type: "button", onClick: onOpen, "aria-label": `Open the ${name} documentation agent`, children: [
|
|
653
|
+
"Ask ",
|
|
654
|
+
name
|
|
655
|
+
] }),
|
|
656
|
+
/* @__PURE__ */ jsx4(
|
|
657
|
+
"input",
|
|
658
|
+
{
|
|
659
|
+
"aria-label": `Ask the ${name} documentation agent`,
|
|
660
|
+
id: "deepspace-docs-assistant-launcher-input",
|
|
661
|
+
maxLength: 4e3,
|
|
662
|
+
onChange: (event) => setInput(event.target.value),
|
|
663
|
+
placeholder: "Ask anything\u2026",
|
|
664
|
+
value: input
|
|
665
|
+
}
|
|
666
|
+
),
|
|
667
|
+
/* @__PURE__ */ jsx4("button", { className: "docs-launcher-send", type: "submit", disabled: !input.trim(), "aria-label": "Send question to documentation agent", children: /* @__PURE__ */ jsx4(SendIcon, {}) })
|
|
668
|
+
]
|
|
669
|
+
}
|
|
670
|
+
);
|
|
671
|
+
}
|
|
672
|
+
function DocsAssistant({
|
|
673
|
+
access,
|
|
674
|
+
name,
|
|
675
|
+
onClose,
|
|
676
|
+
open,
|
|
677
|
+
route,
|
|
678
|
+
seed,
|
|
679
|
+
suggestions
|
|
680
|
+
}) {
|
|
681
|
+
const panelRef = useRef3(null);
|
|
682
|
+
const formRef = useRef3(null);
|
|
683
|
+
const messagesRef = useRef3(null);
|
|
684
|
+
const abortRef = useRef3(null);
|
|
685
|
+
const queuedQuestionRef = useRef3(null);
|
|
686
|
+
const handledSeedRef = useRef3(0);
|
|
687
|
+
const [input, setInput] = useState3(seed.value);
|
|
688
|
+
const [messages, setMessages] = useState3([
|
|
689
|
+
{ id: "welcome", role: "assistant", text: `I can search the ${name} documentation and cite the exact pages I use.` }
|
|
690
|
+
]);
|
|
691
|
+
const [sending, setSending] = useState3(false);
|
|
692
|
+
useDialogFocus(open, panelRef, onClose, false, "deepspace-docs-assistant-launcher-input");
|
|
693
|
+
useEffect4(() => {
|
|
694
|
+
if (!open || seed.id === 0 || handledSeedRef.current === seed.id) return;
|
|
695
|
+
handledSeedRef.current = seed.id;
|
|
696
|
+
setInput(seed.value);
|
|
697
|
+
if (!seed.submit || !seed.value.trim()) return;
|
|
698
|
+
queuedQuestionRef.current = seed.value;
|
|
699
|
+
const frame = window.requestAnimationFrame(() => formRef.current?.requestSubmit());
|
|
700
|
+
return () => window.cancelAnimationFrame(frame);
|
|
701
|
+
}, [open, seed]);
|
|
702
|
+
useEffect4(() => {
|
|
703
|
+
const element = messagesRef.current;
|
|
704
|
+
if (element) element.scrollTop = element.scrollHeight;
|
|
705
|
+
}, [messages]);
|
|
706
|
+
useEffect4(() => () => abortRef.current?.abort(), []);
|
|
707
|
+
if (!open) return null;
|
|
708
|
+
const submit = async (event) => {
|
|
709
|
+
event?.preventDefault();
|
|
710
|
+
const question = (queuedQuestionRef.current ?? input).trim();
|
|
711
|
+
queuedQuestionRef.current = null;
|
|
712
|
+
if (!question || sending) return;
|
|
713
|
+
const history = completedDocsAssistantHistory(messages);
|
|
714
|
+
setInput("");
|
|
715
|
+
setSending(true);
|
|
716
|
+
const userId = `user-${Date.now()}`;
|
|
717
|
+
const answerId = `assistant-${Date.now()}`;
|
|
718
|
+
setMessages((current) => [...current, { id: userId, role: "user", text: question }, { id: answerId, role: "assistant", text: "", state: "streaming", status: "Searching this documentation\u2026" }]);
|
|
719
|
+
const controller = new AbortController();
|
|
720
|
+
abortRef.current = controller;
|
|
721
|
+
let timedOut = false;
|
|
722
|
+
const slowTimer = window.setTimeout(() => {
|
|
723
|
+
setMessages((current) => current.map((message) => message.id === answerId ? { ...message, status: "Still working through the documentation\u2026" } : message));
|
|
724
|
+
}, 12e3);
|
|
725
|
+
const timeoutTimer = window.setTimeout(() => {
|
|
726
|
+
timedOut = true;
|
|
727
|
+
controller.abort();
|
|
728
|
+
}, 12e4);
|
|
729
|
+
try {
|
|
730
|
+
const headers = {
|
|
731
|
+
"Content-Type": "application/json",
|
|
732
|
+
"x-deepspace-surface": "docs"
|
|
733
|
+
};
|
|
734
|
+
if (access === "authenticated") {
|
|
735
|
+
const tokenResponse = await fetch("/api/auth/token", { method: "POST", credentials: "include", headers: { "Content-Type": "application/json" } });
|
|
736
|
+
const tokenData = tokenResponse.ok ? await tokenResponse.json().catch(() => null) : null;
|
|
737
|
+
if (!tokenData?.token) throw new Error("Sign in to use the documentation assistant.");
|
|
738
|
+
headers.Authorization = `Bearer ${tokenData.token}`;
|
|
739
|
+
}
|
|
740
|
+
const response = await fetch("/api/ai/docs", {
|
|
741
|
+
method: "POST",
|
|
742
|
+
headers,
|
|
743
|
+
body: JSON.stringify({ question, route, messages: history }),
|
|
744
|
+
signal: controller.signal
|
|
745
|
+
});
|
|
746
|
+
if (!response.ok || !response.body) {
|
|
747
|
+
const body = await response.json().catch(() => null);
|
|
748
|
+
throw new Error(body?.error ?? `Assistant unavailable (${response.status})`);
|
|
749
|
+
}
|
|
750
|
+
const reader = response.body.getReader();
|
|
751
|
+
const decoder = new TextDecoder();
|
|
752
|
+
let buffer = "";
|
|
753
|
+
let answer = "";
|
|
754
|
+
const consumeLine = (line) => {
|
|
755
|
+
const data = parseSseLine(line);
|
|
756
|
+
if (!data) return;
|
|
757
|
+
if (data.type === "text-delta" && typeof data.delta === "string") {
|
|
758
|
+
answer += data.delta;
|
|
759
|
+
setMessages((current) => current.map((message) => message.id === answerId ? { ...message, text: answer, state: "streaming", status: void 0 } : message));
|
|
760
|
+
} else if (data.type === "tool-input-available") {
|
|
761
|
+
const status = data.toolName === "docs_read" ? "Reading the relevant source pages\u2026" : "Searching this documentation\u2026";
|
|
762
|
+
setMessages((current) => current.map((message) => message.id === answerId ? { ...message, status } : message));
|
|
763
|
+
} else if (data.type === "tool-output-available") {
|
|
764
|
+
setMessages((current) => current.map((message) => message.id === answerId ? { ...message, status: "Reviewing the source material\u2026" } : message));
|
|
765
|
+
} else if (data.type === "error") {
|
|
766
|
+
throw new Error(typeof data.errorText === "string" ? data.errorText : "The assistant stream failed.");
|
|
767
|
+
}
|
|
768
|
+
};
|
|
769
|
+
while (true) {
|
|
770
|
+
const chunk = await reader.read();
|
|
771
|
+
if (chunk.done) break;
|
|
772
|
+
buffer += decoder.decode(chunk.value, { stream: true });
|
|
773
|
+
const lines = buffer.split(/\r?\n/);
|
|
774
|
+
buffer = lines.pop() ?? "";
|
|
775
|
+
for (const line of lines) consumeLine(line);
|
|
776
|
+
}
|
|
777
|
+
buffer += decoder.decode();
|
|
778
|
+
consumeLine(buffer);
|
|
779
|
+
setMessages((current) => current.map((message) => message.id === answerId ? { ...message, text: answer || "No answer was returned.", state: void 0 } : message));
|
|
780
|
+
} catch (error) {
|
|
781
|
+
const message = timedOut ? "The documentation search took too long. Try a narrower question." : controller.signal.aborted ? "Response stopped." : errorMessage(error);
|
|
782
|
+
setMessages((current) => current.map((item) => item.id === answerId ? { ...item, text: message, state: "error" } : item));
|
|
783
|
+
} finally {
|
|
784
|
+
window.clearTimeout(slowTimer);
|
|
785
|
+
window.clearTimeout(timeoutTimer);
|
|
786
|
+
abortRef.current = null;
|
|
787
|
+
setSending(false);
|
|
788
|
+
}
|
|
789
|
+
};
|
|
790
|
+
const defaults = suggestions ?? ["How do I get started?", "Show me a complete example", "What should I understand first?"];
|
|
791
|
+
return /* @__PURE__ */ jsxs4(
|
|
792
|
+
"aside",
|
|
793
|
+
{
|
|
794
|
+
"aria-label": "Documentation assistant",
|
|
795
|
+
className: "docs-assistant",
|
|
796
|
+
id: "deepspace-docs-assistant",
|
|
797
|
+
ref: panelRef,
|
|
798
|
+
role: "complementary",
|
|
799
|
+
children: [
|
|
800
|
+
/* @__PURE__ */ jsxs4("header", { children: [
|
|
801
|
+
/* @__PURE__ */ jsx4("div", { children: /* @__PURE__ */ jsxs4("span", { children: [
|
|
802
|
+
/* @__PURE__ */ jsxs4("strong", { id: "deepspace-docs-assistant-title", children: [
|
|
803
|
+
"Ask ",
|
|
804
|
+
name
|
|
805
|
+
] }),
|
|
806
|
+
/* @__PURE__ */ jsx4("small", { children: "Answers from this documentation build" })
|
|
807
|
+
] }) }),
|
|
808
|
+
/* @__PURE__ */ jsx4("button", { type: "button", onClick: onClose, "aria-label": "Close documentation assistant", children: /* @__PURE__ */ jsx4(CloseIcon, {}) })
|
|
809
|
+
] }),
|
|
810
|
+
/* @__PURE__ */ jsxs4("div", { className: "docs-assistant-messages", ref: messagesRef, "aria-live": "polite", children: [
|
|
811
|
+
messages.map((message) => /* @__PURE__ */ jsx4("div", { className: `docs-assistant-message is-${message.role}${message.state ? ` is-${message.state}` : ""}`, children: /* @__PURE__ */ jsxs4("div", { children: [
|
|
812
|
+
message.role === "assistant" ? /* @__PURE__ */ jsx4(AssistantMarkdown, { value: message.text }) : message.text,
|
|
813
|
+
message.state === "streaming" && !message.text && /* @__PURE__ */ jsxs4("span", { className: "docs-assistant-activity", role: "status", children: [
|
|
814
|
+
/* @__PURE__ */ jsx4("span", { "aria-hidden": "true" }),
|
|
815
|
+
message.status ?? "Working\u2026"
|
|
816
|
+
] })
|
|
817
|
+
] }) }, message.id)),
|
|
818
|
+
messages.length === 1 && /* @__PURE__ */ jsxs4("div", { className: "docs-assistant-suggestions", children: [
|
|
819
|
+
/* @__PURE__ */ jsx4("p", { children: "Try asking" }),
|
|
820
|
+
defaults.map((suggestion) => /* @__PURE__ */ jsx4("button", { type: "button", onClick: () => setInput(suggestion), children: suggestion }, suggestion))
|
|
821
|
+
] })
|
|
822
|
+
] }),
|
|
823
|
+
/* @__PURE__ */ jsxs4("form", { className: "docs-assistant-composer", onSubmit: submit, ref: formRef, children: [
|
|
824
|
+
/* @__PURE__ */ jsx4(
|
|
825
|
+
"textarea",
|
|
826
|
+
{
|
|
827
|
+
"aria-label": "Ask a documentation question",
|
|
828
|
+
"data-autofocus": true,
|
|
829
|
+
maxLength: 4e3,
|
|
830
|
+
onChange: (event) => setInput(event.target.value),
|
|
831
|
+
onKeyDown: (event) => {
|
|
832
|
+
if (event.key === "Enter" && !event.shiftKey) {
|
|
833
|
+
event.preventDefault();
|
|
834
|
+
void submit();
|
|
835
|
+
}
|
|
836
|
+
},
|
|
837
|
+
placeholder: "Ask a question about these docs",
|
|
838
|
+
rows: 2,
|
|
839
|
+
value: input
|
|
840
|
+
}
|
|
841
|
+
),
|
|
842
|
+
sending ? /* @__PURE__ */ jsx4("button", { type: "button", onClick: () => abortRef.current?.abort(), "aria-label": "Stop response", children: /* @__PURE__ */ jsx4(StopIcon, {}) }) : /* @__PURE__ */ jsx4("button", { type: "submit", disabled: !input.trim(), "aria-label": "Send question", children: /* @__PURE__ */ jsx4(SendIcon, {}) })
|
|
843
|
+
] }),
|
|
844
|
+
/* @__PURE__ */ jsx4("footer", { children: "Responses cite this deployment and may still contain mistakes." })
|
|
845
|
+
]
|
|
846
|
+
}
|
|
847
|
+
);
|
|
848
|
+
}
|
|
849
|
+
function AssistantMarkdown({ value }) {
|
|
850
|
+
const blocks = [];
|
|
851
|
+
const fence = /```([^\n`]*)\n([\s\S]*?)(?:```|$)/g;
|
|
852
|
+
let cursor = 0;
|
|
853
|
+
for (const match of value.matchAll(fence)) {
|
|
854
|
+
const index = match.index ?? 0;
|
|
855
|
+
if (index > cursor) blocks.push(...renderAssistantText(value.slice(cursor, index), `text-${cursor}`));
|
|
856
|
+
blocks.push(
|
|
857
|
+
/* @__PURE__ */ jsx4(
|
|
858
|
+
AssistantCodeBlock,
|
|
859
|
+
{
|
|
860
|
+
code: (match[2] ?? "").replace(/\n$/, ""),
|
|
861
|
+
language: (match[1] ?? "").trim().split(/\s+/, 1)[0] ?? ""
|
|
862
|
+
},
|
|
863
|
+
`code-${index}`
|
|
864
|
+
)
|
|
865
|
+
);
|
|
866
|
+
cursor = index + match[0].length;
|
|
867
|
+
}
|
|
868
|
+
if (cursor < value.length) blocks.push(...renderAssistantText(value.slice(cursor), `text-${cursor}`));
|
|
869
|
+
return /* @__PURE__ */ jsx4("div", { className: "docs-assistant-markdown", children: blocks });
|
|
870
|
+
}
|
|
871
|
+
function AssistantCodeBlock({ code, language }) {
|
|
872
|
+
const [copied, setCopied] = useState3(false);
|
|
873
|
+
const copy = async () => {
|
|
874
|
+
await writeClipboardText(code);
|
|
875
|
+
setCopied(true);
|
|
876
|
+
window.setTimeout(() => setCopied(false), 1400);
|
|
877
|
+
};
|
|
878
|
+
return /* @__PURE__ */ jsxs4("figure", { className: "docs-assistant-code", children: [
|
|
879
|
+
/* @__PURE__ */ jsxs4("figcaption", { children: [
|
|
880
|
+
/* @__PURE__ */ jsx4("span", { children: language || "Code" }),
|
|
881
|
+
/* @__PURE__ */ jsx4("button", { type: "button", onClick: copy, children: copied ? "Copied" : "Copy" })
|
|
882
|
+
] }),
|
|
883
|
+
/* @__PURE__ */ jsx4("pre", { children: /* @__PURE__ */ jsx4("code", { children: code }) })
|
|
884
|
+
] });
|
|
885
|
+
}
|
|
886
|
+
function renderAssistantText(value, keyPrefix) {
|
|
887
|
+
const lines = value.split("\n");
|
|
888
|
+
const blocks = [];
|
|
889
|
+
let index = 0;
|
|
890
|
+
while (index < lines.length) {
|
|
891
|
+
const line = lines[index]?.trim() ?? "";
|
|
892
|
+
if (!line) {
|
|
893
|
+
index += 1;
|
|
894
|
+
continue;
|
|
895
|
+
}
|
|
896
|
+
const heading = line.match(/^(#{1,4})\s+(.+)$/);
|
|
897
|
+
if (heading) {
|
|
898
|
+
blocks.push(/* @__PURE__ */ jsx4("strong", { className: "docs-assistant-heading", children: renderInlineMarkdown(heading[2]) }, `${keyPrefix}-heading-${index}`));
|
|
899
|
+
index += 1;
|
|
900
|
+
continue;
|
|
901
|
+
}
|
|
902
|
+
const unordered = /^[-*]\s+/.test(line);
|
|
903
|
+
const ordered = /^\d+[.)]\s+/.test(line);
|
|
904
|
+
if (unordered || ordered) {
|
|
905
|
+
const items = [];
|
|
906
|
+
while (index < lines.length) {
|
|
907
|
+
const candidate = lines[index]?.trim() ?? "";
|
|
908
|
+
const match = unordered ? candidate.match(/^[-*]\s+(.+)$/) : candidate.match(/^\d+[.)]\s+(.+)$/);
|
|
909
|
+
if (!match) break;
|
|
910
|
+
items.push(/* @__PURE__ */ jsx4("li", { children: renderInlineMarkdown(match[1]) }, `${keyPrefix}-item-${index}`));
|
|
911
|
+
index += 1;
|
|
912
|
+
}
|
|
913
|
+
blocks.push(unordered ? /* @__PURE__ */ jsx4("ul", { children: items }, `${keyPrefix}-list-${index}`) : /* @__PURE__ */ jsx4("ol", { children: items }, `${keyPrefix}-list-${index}`));
|
|
914
|
+
continue;
|
|
915
|
+
}
|
|
916
|
+
const paragraph = [line];
|
|
917
|
+
index += 1;
|
|
918
|
+
while (index < lines.length) {
|
|
919
|
+
const candidate = lines[index]?.trim() ?? "";
|
|
920
|
+
if (!candidate || /^(?:#{1,4}\s+|[-*]\s+|\d+[.)]\s+)/.test(candidate)) break;
|
|
921
|
+
paragraph.push(candidate);
|
|
922
|
+
index += 1;
|
|
923
|
+
}
|
|
924
|
+
blocks.push(/* @__PURE__ */ jsx4("p", { children: paragraph.map((part, partIndex) => /* @__PURE__ */ jsxs4("span", { children: [
|
|
925
|
+
renderInlineMarkdown(part),
|
|
926
|
+
partIndex < paragraph.length - 1 && " "
|
|
927
|
+
] }, `${partIndex}:${part.slice(0, 18)}`)) }, `${keyPrefix}-paragraph-${index}`));
|
|
928
|
+
}
|
|
929
|
+
return blocks;
|
|
930
|
+
}
|
|
931
|
+
function renderInlineMarkdown(value) {
|
|
932
|
+
const pattern = /(\[[^\]]+\]\((?:https?:\/\/|\/)[^)]+\)|`[^`]+`|\*\*[^*]+\*\*)/g;
|
|
933
|
+
return value.split(pattern).filter(Boolean).map((part, index) => {
|
|
934
|
+
const link = part.match(/^\[([^\]]+)\]\(((?:https?:\/\/|\/)[^)]+)\)$/);
|
|
935
|
+
if (link) return /* @__PURE__ */ jsx4("a", { href: link[2], ...externalProps(link[2]), children: link[1] }, `${index}:${part}`);
|
|
936
|
+
if (part.startsWith("`") && part.endsWith("`")) return /* @__PURE__ */ jsx4("code", { children: part.slice(1, -1) }, `${index}:${part}`);
|
|
937
|
+
if (part.startsWith("**") && part.endsWith("**")) return /* @__PURE__ */ jsx4("strong", { children: part.slice(2, -2) }, `${index}:${part}`);
|
|
938
|
+
return /* @__PURE__ */ jsx4("span", { children: part }, `${index}:${part}`);
|
|
939
|
+
});
|
|
940
|
+
}
|
|
941
|
+
|
|
942
|
+
// src/docs/runtime/navigation.tsx
|
|
943
|
+
import { useEffect as useEffect5, useRef as useRef4, useState as useState4 } from "react";
|
|
944
|
+
import { Fragment as Fragment2, jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
945
|
+
function DocsHeader({
|
|
946
|
+
data,
|
|
947
|
+
onMenuOpen,
|
|
948
|
+
onSearchOpen
|
|
949
|
+
}) {
|
|
950
|
+
return /* @__PURE__ */ jsxs5("header", { className: "docs-header", children: [
|
|
951
|
+
/* @__PURE__ */ jsx5(
|
|
952
|
+
"a",
|
|
953
|
+
{
|
|
954
|
+
className: "docs-brand",
|
|
955
|
+
href: data.config.theme.logoHref ?? "/",
|
|
956
|
+
"aria-label": `${data.config.name} documentation home`,
|
|
957
|
+
...externalProps(data.config.theme.logoHref ?? "/"),
|
|
958
|
+
children: /* @__PURE__ */ jsx5(BrandLogo, { data })
|
|
959
|
+
}
|
|
960
|
+
),
|
|
961
|
+
/* @__PURE__ */ jsx5("div", { className: "docs-header-center", children: /* @__PURE__ */ jsxs5("button", { className: "docs-search-trigger", type: "button", onClick: onSearchOpen, "aria-label": "Search documentation", children: [
|
|
962
|
+
/* @__PURE__ */ jsx5(SearchIcon, {}),
|
|
963
|
+
/* @__PURE__ */ jsx5("span", { children: "Search documentation" }),
|
|
964
|
+
/* @__PURE__ */ jsx5("kbd", { children: "\u2318K" })
|
|
965
|
+
] }) }),
|
|
966
|
+
/* @__PURE__ */ jsx5("nav", { className: "docs-top-links", "aria-label": "Product navigation", children: data.config.links.map((link) => /* @__PURE__ */ jsxs5("a", { href: link.href, ...externalProps(link.href), children: [
|
|
967
|
+
link.label,
|
|
968
|
+
isExternal(link.href) && /* @__PURE__ */ jsx5(ExternalIcon, {})
|
|
969
|
+
] }, `${link.label}:${link.href}`)) }),
|
|
970
|
+
/* @__PURE__ */ jsxs5("div", { className: "docs-mobile-actions", children: [
|
|
971
|
+
/* @__PURE__ */ jsx5("button", { className: "docs-icon-button", type: "button", onClick: onSearchOpen, "aria-label": "Search documentation", children: /* @__PURE__ */ jsx5(SearchIcon, {}) }),
|
|
972
|
+
/* @__PURE__ */ jsx5("button", { className: "docs-icon-button", type: "button", onClick: onMenuOpen, "aria-label": "Open documentation navigation", children: /* @__PURE__ */ jsx5(MenuIcon, {}) })
|
|
973
|
+
] })
|
|
974
|
+
] });
|
|
975
|
+
}
|
|
976
|
+
function BrandLogo({ data }) {
|
|
977
|
+
const { logo, logoDark } = data.config.theme;
|
|
978
|
+
if (logo) {
|
|
979
|
+
return /* @__PURE__ */ jsxs5(Fragment2, { children: [
|
|
980
|
+
/* @__PURE__ */ jsx5("img", { className: "docs-brand-logo docs-brand-logo-light", src: logo, alt: "" }),
|
|
981
|
+
/* @__PURE__ */ jsx5("img", { className: "docs-brand-logo docs-brand-logo-dark", src: logoDark ?? logo, alt: "" }),
|
|
982
|
+
/* @__PURE__ */ jsx5("span", { className: "docs-brand-product", children: "Docs" })
|
|
983
|
+
] });
|
|
984
|
+
}
|
|
985
|
+
return /* @__PURE__ */ jsxs5(Fragment2, { children: [
|
|
986
|
+
/* @__PURE__ */ jsx5("span", { className: "docs-brand-mark", children: /* @__PURE__ */ jsx5(OrbitMark, {}) }),
|
|
987
|
+
/* @__PURE__ */ jsx5("span", { className: "docs-brand-name", children: data.config.name }),
|
|
988
|
+
/* @__PURE__ */ jsx5("span", { className: "docs-brand-product", children: "Docs" })
|
|
989
|
+
] });
|
|
990
|
+
}
|
|
991
|
+
function DesktopSidebar({ data }) {
|
|
992
|
+
return /* @__PURE__ */ jsxs5("aside", { className: "docs-sidebar", "aria-label": "Documentation navigation", children: [
|
|
993
|
+
/* @__PURE__ */ jsx5("nav", { className: "docs-page-tree", children: /* @__PURE__ */ jsx5(NavigationTree, { activeRoute: data.page.route, nodes: data.navigation }) }),
|
|
994
|
+
/* @__PURE__ */ jsxs5("div", { className: "docs-sidebar-footer", children: [
|
|
995
|
+
!data.config.theme.strictMode && /* @__PURE__ */ jsx5(ThemeControls, { defaultMode: data.config.theme.defaultMode ?? "system" }),
|
|
996
|
+
data.config.footer.length > 0 && /* @__PURE__ */ jsx5("nav", { "aria-label": "Documentation footer", children: data.config.footer.map((link) => /* @__PURE__ */ jsx5("a", { href: link.href, ...externalProps(link.href), children: link.label }, `${link.label}:${link.href}`)) }),
|
|
997
|
+
/* @__PURE__ */ jsx5("span", { children: "Built on DeepSpace" })
|
|
998
|
+
] })
|
|
999
|
+
] });
|
|
1000
|
+
}
|
|
1001
|
+
function NavigationTree({
|
|
1002
|
+
activeRoute,
|
|
1003
|
+
depth = 0,
|
|
1004
|
+
nodes
|
|
1005
|
+
}) {
|
|
1006
|
+
return /* @__PURE__ */ jsx5(Fragment2, { children: nodes.map((node) => {
|
|
1007
|
+
if (node.kind === "group") {
|
|
1008
|
+
const active2 = containsRoute(node, activeRoute);
|
|
1009
|
+
if (depth === 0) {
|
|
1010
|
+
return /* @__PURE__ */ jsxs5("section", { className: "docs-nav-section", children: [
|
|
1011
|
+
/* @__PURE__ */ jsx5("h2", { children: node.label }),
|
|
1012
|
+
/* @__PURE__ */ jsx5(NavigationTree, { activeRoute, depth: depth + 1, nodes: node.items })
|
|
1013
|
+
] }, `group:${node.label}`);
|
|
1014
|
+
}
|
|
1015
|
+
return /* @__PURE__ */ jsxs5("details", { className: "docs-nav-folder", open: active2, children: [
|
|
1016
|
+
/* @__PURE__ */ jsxs5("summary", { children: [
|
|
1017
|
+
/* @__PURE__ */ jsx5("span", { children: node.label }),
|
|
1018
|
+
/* @__PURE__ */ jsx5(ChevronDownIcon, {})
|
|
1019
|
+
] }),
|
|
1020
|
+
/* @__PURE__ */ jsx5("div", { children: /* @__PURE__ */ jsx5(NavigationTree, { activeRoute, depth: depth + 1, nodes: node.items }) })
|
|
1021
|
+
] }, `group:${node.label}`);
|
|
1022
|
+
}
|
|
1023
|
+
const href = node.kind === "page" ? node.route : node.href;
|
|
1024
|
+
const active = node.kind === "page" && node.route === activeRoute;
|
|
1025
|
+
return /* @__PURE__ */ jsxs5(
|
|
1026
|
+
"a",
|
|
1027
|
+
{
|
|
1028
|
+
"aria-current": active ? "page" : void 0,
|
|
1029
|
+
className: active ? "docs-nav-link is-active" : "docs-nav-link",
|
|
1030
|
+
href,
|
|
1031
|
+
...externalProps(href),
|
|
1032
|
+
children: [
|
|
1033
|
+
/* @__PURE__ */ jsx5("span", { children: node.label }),
|
|
1034
|
+
isExternal(href) && /* @__PURE__ */ jsx5(ExternalIcon, {})
|
|
1035
|
+
]
|
|
1036
|
+
},
|
|
1037
|
+
`${node.kind}:${href}`
|
|
1038
|
+
);
|
|
1039
|
+
}) });
|
|
1040
|
+
}
|
|
1041
|
+
function MobileNavigation({
|
|
1042
|
+
data,
|
|
1043
|
+
onClose,
|
|
1044
|
+
open
|
|
1045
|
+
}) {
|
|
1046
|
+
const dialogRef = useRef4(null);
|
|
1047
|
+
useDialogFocus(open, dialogRef, onClose);
|
|
1048
|
+
if (!open) return null;
|
|
1049
|
+
return /* @__PURE__ */ jsx5("div", { className: "docs-modal-layer", role: "presentation", onMouseDown: (event) => {
|
|
1050
|
+
if (event.currentTarget === event.target) onClose();
|
|
1051
|
+
}, children: /* @__PURE__ */ jsxs5("div", { className: "docs-mobile-nav", role: "dialog", "aria-modal": "true", "aria-label": "Documentation navigation", ref: dialogRef, children: [
|
|
1052
|
+
/* @__PURE__ */ jsxs5("header", { children: [
|
|
1053
|
+
/* @__PURE__ */ jsx5(
|
|
1054
|
+
"a",
|
|
1055
|
+
{
|
|
1056
|
+
"aria-label": `${data.config.name} documentation home`,
|
|
1057
|
+
className: "docs-brand",
|
|
1058
|
+
href: data.config.theme.logoHref ?? "/",
|
|
1059
|
+
...externalProps(data.config.theme.logoHref ?? "/"),
|
|
1060
|
+
children: /* @__PURE__ */ jsx5(BrandLogo, { data })
|
|
1061
|
+
}
|
|
1062
|
+
),
|
|
1063
|
+
/* @__PURE__ */ jsx5("button", { className: "docs-icon-button", type: "button", onClick: onClose, "aria-label": "Close documentation navigation", "data-autofocus": true, children: /* @__PURE__ */ jsx5(CloseIcon, {}) })
|
|
1064
|
+
] }),
|
|
1065
|
+
/* @__PURE__ */ jsx5("nav", { className: "docs-page-tree", children: /* @__PURE__ */ jsx5(NavigationTree, { activeRoute: data.page.route, nodes: data.navigation }) }),
|
|
1066
|
+
/* @__PURE__ */ jsxs5("footer", { children: [
|
|
1067
|
+
!data.config.theme.strictMode && /* @__PURE__ */ jsx5(ThemeControls, { defaultMode: data.config.theme.defaultMode ?? "system" }),
|
|
1068
|
+
data.config.footer.map((link) => /* @__PURE__ */ jsx5("a", { href: link.href, ...externalProps(link.href), children: link.label }, `${link.label}:${link.href}`))
|
|
1069
|
+
] })
|
|
1070
|
+
] }) });
|
|
1071
|
+
}
|
|
1072
|
+
function ThemeControls({ defaultMode }) {
|
|
1073
|
+
const [mode, setMode] = useState4(defaultMode);
|
|
1074
|
+
useEffect5(() => {
|
|
1075
|
+
const saved = safeStorageGet("deepspace-docs-theme");
|
|
1076
|
+
if (saved === "light" || saved === "dark" || saved === "system") setMode(saved);
|
|
1077
|
+
}, []);
|
|
1078
|
+
useEffect5(() => applyThemeMode(mode), [mode]);
|
|
1079
|
+
const choose = (next) => {
|
|
1080
|
+
setMode(next);
|
|
1081
|
+
safeStorageSet("deepspace-docs-theme", next);
|
|
1082
|
+
};
|
|
1083
|
+
return /* @__PURE__ */ jsxs5("div", { className: "docs-theme-controls", role: "group", "aria-label": "Theme preference", children: [
|
|
1084
|
+
/* @__PURE__ */ jsx5("button", { "aria-pressed": mode === "system", "aria-label": "Use system theme", onClick: () => choose("system"), type: "button", children: /* @__PURE__ */ jsx5(SystemIcon, {}) }),
|
|
1085
|
+
/* @__PURE__ */ jsx5("button", { "aria-pressed": mode === "light", "aria-label": "Use light theme", onClick: () => choose("light"), type: "button", children: /* @__PURE__ */ jsx5(SunIcon, {}) }),
|
|
1086
|
+
/* @__PURE__ */ jsx5("button", { "aria-pressed": mode === "dark", "aria-label": "Use dark theme", onClick: () => choose("dark"), type: "button", children: /* @__PURE__ */ jsx5(MoonIcon, {}) })
|
|
1087
|
+
] });
|
|
1088
|
+
}
|
|
1089
|
+
function containsRoute(node, route) {
|
|
1090
|
+
return node.items.some((item) => item.kind === "page" ? item.route === route : item.kind === "group" && containsRoute(item, route));
|
|
1091
|
+
}
|
|
1092
|
+
function applyThemeMode(mode) {
|
|
1093
|
+
const media = window.matchMedia("(prefers-color-scheme: dark)");
|
|
1094
|
+
const apply = () => {
|
|
1095
|
+
document.documentElement.dataset.themeMode = mode;
|
|
1096
|
+
document.documentElement.dataset.theme = mode === "system" ? media.matches ? "dark" : "light" : mode;
|
|
1097
|
+
};
|
|
1098
|
+
apply();
|
|
1099
|
+
media.addEventListener?.("change", apply);
|
|
1100
|
+
return () => media.removeEventListener?.("change", apply);
|
|
1101
|
+
}
|
|
1102
|
+
|
|
1103
|
+
// src/docs/runtime/search.tsx
|
|
1104
|
+
import {
|
|
1105
|
+
useEffect as useEffect6,
|
|
1106
|
+
useMemo as useMemo2,
|
|
1107
|
+
useRef as useRef5,
|
|
1108
|
+
useState as useState5
|
|
1109
|
+
} from "react";
|
|
1110
|
+
import { Fragment as Fragment3, jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
1111
|
+
function SearchCommand({
|
|
1112
|
+
assistantEnabled,
|
|
1113
|
+
name,
|
|
1114
|
+
onAssistantOpen,
|
|
1115
|
+
onClose,
|
|
1116
|
+
onNavigate,
|
|
1117
|
+
open
|
|
1118
|
+
}) {
|
|
1119
|
+
const dialogRef = useRef5(null);
|
|
1120
|
+
const [index, setIndex] = useState5(null);
|
|
1121
|
+
const [loading, setLoading] = useState5(false);
|
|
1122
|
+
const [query, setQuery] = useState5("");
|
|
1123
|
+
const [activeIndex, setActiveIndex] = useState5(0);
|
|
1124
|
+
useDialogFocus(open, dialogRef, onClose);
|
|
1125
|
+
useEffect6(() => {
|
|
1126
|
+
if (!open || index || loading) return;
|
|
1127
|
+
setLoading(true);
|
|
1128
|
+
fetch("/_docs/search.json").then((response) => response.ok ? response.json() : []).then(setIndex).catch(() => setIndex([])).finally(() => setLoading(false));
|
|
1129
|
+
}, [index, loading, open]);
|
|
1130
|
+
useEffect6(() => {
|
|
1131
|
+
if (!open) {
|
|
1132
|
+
setQuery("");
|
|
1133
|
+
setActiveIndex(0);
|
|
1134
|
+
}
|
|
1135
|
+
}, [open]);
|
|
1136
|
+
const preparedIndex = useMemo2(() => prepareSearchIndex(index ?? []), [index]);
|
|
1137
|
+
const results = useMemo2(() => rankSearch(preparedIndex, query), [preparedIndex, query]);
|
|
1138
|
+
if (!open) return null;
|
|
1139
|
+
const selectableCount = results.length + (assistantEnabled && query.trim() ? 1 : 0);
|
|
1140
|
+
const handleKeyDown = (event) => {
|
|
1141
|
+
if (event.key === "ArrowDown" && selectableCount > 0) {
|
|
1142
|
+
event.preventDefault();
|
|
1143
|
+
setActiveIndex((current) => (current + 1) % selectableCount);
|
|
1144
|
+
} else if (event.key === "ArrowUp" && selectableCount > 0) {
|
|
1145
|
+
event.preventDefault();
|
|
1146
|
+
setActiveIndex((current) => (current - 1 + selectableCount) % selectableCount);
|
|
1147
|
+
} else if (event.key === "Enter") {
|
|
1148
|
+
event.preventDefault();
|
|
1149
|
+
if (activeIndex < results.length && results[activeIndex]) {
|
|
1150
|
+
onClose();
|
|
1151
|
+
if (onNavigate) onNavigate(results[activeIndex].route);
|
|
1152
|
+
else window.location.assign(results[activeIndex].route);
|
|
1153
|
+
} else if (assistantEnabled && query.trim()) {
|
|
1154
|
+
onAssistantOpen(query.trim());
|
|
1155
|
+
}
|
|
1156
|
+
}
|
|
1157
|
+
};
|
|
1158
|
+
return /* @__PURE__ */ jsx6("div", { className: "docs-modal-layer docs-search-layer", role: "presentation", onMouseDown: (event) => {
|
|
1159
|
+
if (event.currentTarget === event.target) onClose();
|
|
1160
|
+
}, children: /* @__PURE__ */ jsxs6("div", { className: "docs-search-dialog", role: "dialog", "aria-modal": "true", "aria-label": "Search documentation", ref: dialogRef, children: [
|
|
1161
|
+
/* @__PURE__ */ jsxs6("label", { className: "docs-search-input", children: [
|
|
1162
|
+
/* @__PURE__ */ jsx6(SearchIcon, {}),
|
|
1163
|
+
/* @__PURE__ */ jsx6(
|
|
1164
|
+
"input",
|
|
1165
|
+
{
|
|
1166
|
+
"aria-activedescendant": selectableCount > 0 ? `docs-search-option-${activeIndex}` : void 0,
|
|
1167
|
+
"aria-controls": "docs-search-results",
|
|
1168
|
+
"aria-expanded": "true",
|
|
1169
|
+
"aria-label": `Search ${name} documentation`,
|
|
1170
|
+
autoComplete: "off",
|
|
1171
|
+
"data-autofocus": true,
|
|
1172
|
+
onChange: (event) => {
|
|
1173
|
+
setQuery(event.target.value);
|
|
1174
|
+
setActiveIndex(0);
|
|
1175
|
+
},
|
|
1176
|
+
onKeyDown: handleKeyDown,
|
|
1177
|
+
placeholder: `Search ${name}`,
|
|
1178
|
+
role: "combobox",
|
|
1179
|
+
value: query
|
|
1180
|
+
}
|
|
1181
|
+
),
|
|
1182
|
+
/* @__PURE__ */ jsx6("kbd", { children: "Esc" })
|
|
1183
|
+
] }),
|
|
1184
|
+
/* @__PURE__ */ jsxs6("div", { className: "docs-search-results", id: "docs-search-results", role: "listbox", "aria-label": "Search results", children: [
|
|
1185
|
+
!query.trim() && /* @__PURE__ */ jsxs6("div", { className: "docs-search-empty", children: [
|
|
1186
|
+
/* @__PURE__ */ jsx6(OrbitMark, {}),
|
|
1187
|
+
/* @__PURE__ */ jsx6("strong", { children: "Find an answer in this commit" }),
|
|
1188
|
+
/* @__PURE__ */ jsx6("span", { children: "Search pages, headings, APIs, and examples." })
|
|
1189
|
+
] }),
|
|
1190
|
+
query.trim() && loading && /* @__PURE__ */ jsx6("div", { className: "docs-search-state", children: "Searching this documentation\u2026" }),
|
|
1191
|
+
query.trim() && !loading && results.length === 0 && /* @__PURE__ */ jsxs6("div", { className: "docs-search-state", children: [
|
|
1192
|
+
"No documentation matched \u201C",
|
|
1193
|
+
query.trim(),
|
|
1194
|
+
"\u201D."
|
|
1195
|
+
] }),
|
|
1196
|
+
results.map((result, resultIndex) => /* @__PURE__ */ jsxs6(
|
|
1197
|
+
"a",
|
|
1198
|
+
{
|
|
1199
|
+
"aria-selected": activeIndex === resultIndex,
|
|
1200
|
+
className: activeIndex === resultIndex ? "docs-search-result is-active" : "docs-search-result",
|
|
1201
|
+
href: result.route,
|
|
1202
|
+
id: `docs-search-option-${resultIndex}`,
|
|
1203
|
+
onClick: onClose,
|
|
1204
|
+
onMouseEnter: () => setActiveIndex(resultIndex),
|
|
1205
|
+
role: "option",
|
|
1206
|
+
children: [
|
|
1207
|
+
/* @__PURE__ */ jsxs6("span", { children: [
|
|
1208
|
+
/* @__PURE__ */ jsx6("strong", { children: highlightMatch(result.title, query) }),
|
|
1209
|
+
/* @__PURE__ */ jsx6("small", { children: result.description ?? result.headings[0] ?? result.text.slice(0, 150) })
|
|
1210
|
+
] }),
|
|
1211
|
+
/* @__PURE__ */ jsx6(ChevronRightIcon, {})
|
|
1212
|
+
]
|
|
1213
|
+
},
|
|
1214
|
+
result.route
|
|
1215
|
+
)),
|
|
1216
|
+
assistantEnabled && query.trim() && /* @__PURE__ */ jsxs6(
|
|
1217
|
+
"button",
|
|
1218
|
+
{
|
|
1219
|
+
"aria-selected": activeIndex === results.length,
|
|
1220
|
+
className: activeIndex === results.length ? "docs-search-assistant is-active" : "docs-search-assistant",
|
|
1221
|
+
id: `docs-search-option-${results.length}`,
|
|
1222
|
+
onClick: () => onAssistantOpen(query.trim()),
|
|
1223
|
+
onMouseEnter: () => setActiveIndex(results.length),
|
|
1224
|
+
role: "option",
|
|
1225
|
+
type: "button",
|
|
1226
|
+
children: [
|
|
1227
|
+
/* @__PURE__ */ jsx6(SparkIcon, {}),
|
|
1228
|
+
/* @__PURE__ */ jsxs6("span", { children: [
|
|
1229
|
+
/* @__PURE__ */ jsx6("strong", { children: "Ask DeepSpace" }),
|
|
1230
|
+
/* @__PURE__ */ jsx6("small", { children: "Answer from the current documentation with citations" })
|
|
1231
|
+
] }),
|
|
1232
|
+
/* @__PURE__ */ jsx6(ChevronRightIcon, {})
|
|
1233
|
+
]
|
|
1234
|
+
}
|
|
1235
|
+
)
|
|
1236
|
+
] }),
|
|
1237
|
+
/* @__PURE__ */ jsxs6("footer", { children: [
|
|
1238
|
+
/* @__PURE__ */ jsxs6("span", { children: [
|
|
1239
|
+
/* @__PURE__ */ jsx6("kbd", { children: "\u2191" }),
|
|
1240
|
+
/* @__PURE__ */ jsx6("kbd", { children: "\u2193" }),
|
|
1241
|
+
" select"
|
|
1242
|
+
] }),
|
|
1243
|
+
/* @__PURE__ */ jsxs6("span", { children: [
|
|
1244
|
+
/* @__PURE__ */ jsx6("kbd", { children: "\u21B5" }),
|
|
1245
|
+
" open"
|
|
1246
|
+
] }),
|
|
1247
|
+
/* @__PURE__ */ jsxs6("span", { children: [
|
|
1248
|
+
/* @__PURE__ */ jsx6("kbd", { children: "esc" }),
|
|
1249
|
+
" close"
|
|
1250
|
+
] })
|
|
1251
|
+
] })
|
|
1252
|
+
] }) });
|
|
1253
|
+
}
|
|
1254
|
+
function prepareSearchIndex(index) {
|
|
1255
|
+
return index.map((entry) => ({
|
|
1256
|
+
entry,
|
|
1257
|
+
title: normalizeSearch(entry.title),
|
|
1258
|
+
headings: normalizeSearch(entry.headings.join(" ")),
|
|
1259
|
+
haystack: normalizeSearch(`${entry.description ?? ""} ${entry.text}`)
|
|
1260
|
+
}));
|
|
1261
|
+
}
|
|
1262
|
+
function rankSearch(index, query) {
|
|
1263
|
+
const normalized = normalizeSearch(query);
|
|
1264
|
+
if (!normalized) return [];
|
|
1265
|
+
const tokens = normalized.split(" ").filter(Boolean);
|
|
1266
|
+
return index.map(({ entry, title, headings, haystack }) => {
|
|
1267
|
+
let score = title === normalized ? 180 : title.startsWith(normalized) ? 110 : title.includes(normalized) ? 75 : 0;
|
|
1268
|
+
if (headings.includes(normalized)) score += 55;
|
|
1269
|
+
for (const token of tokens) {
|
|
1270
|
+
if (title.includes(token)) score += 24;
|
|
1271
|
+
else if (headings.includes(token)) score += 14;
|
|
1272
|
+
else if (haystack.includes(token)) score += 5;
|
|
1273
|
+
else score -= 18;
|
|
1274
|
+
}
|
|
1275
|
+
return { entry, score };
|
|
1276
|
+
}).filter((item) => item.score > 0).sort((left, right) => right.score - left.score || left.entry.route.localeCompare(right.entry.route)).slice(0, 10).map((item) => item.entry);
|
|
1277
|
+
}
|
|
1278
|
+
function highlightMatch(value, query) {
|
|
1279
|
+
const normalizedQuery = query.trim();
|
|
1280
|
+
if (!normalizedQuery) return value;
|
|
1281
|
+
const index = value.toLowerCase().indexOf(normalizedQuery.toLowerCase());
|
|
1282
|
+
if (index < 0) return value;
|
|
1283
|
+
return /* @__PURE__ */ jsxs6(Fragment3, { children: [
|
|
1284
|
+
value.slice(0, index),
|
|
1285
|
+
/* @__PURE__ */ jsx6("mark", { children: value.slice(index, index + normalizedQuery.length) }),
|
|
1286
|
+
value.slice(index + normalizedQuery.length)
|
|
1287
|
+
] });
|
|
1288
|
+
}
|
|
1289
|
+
function normalizeSearch(value) {
|
|
1290
|
+
return value.normalize("NFKD").replace(/[\u0300-\u036f]/g, "").toLowerCase().replace(/[^a-z0-9]+/g, " ").trim();
|
|
1291
|
+
}
|
|
1292
|
+
|
|
1293
|
+
// src/docs/runtime/app.tsx
|
|
1294
|
+
import { Fragment as Fragment4, jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
1295
|
+
function DocsApp({
|
|
1296
|
+
data,
|
|
1297
|
+
children,
|
|
1298
|
+
navigating = false,
|
|
1299
|
+
onNavigate
|
|
1300
|
+
}) {
|
|
1301
|
+
const [mobileNavOpen, setMobileNavOpen] = useState6(false);
|
|
1302
|
+
const [searchOpen, setSearchOpen] = useState6(false);
|
|
1303
|
+
const [assistantOpen, setAssistantOpen] = useState6(false);
|
|
1304
|
+
const [assistantSeed, setAssistantSeed] = useState6({ id: 0, submit: false, value: "" });
|
|
1305
|
+
const openAssistant = useCallback((seed = "", submit = false) => {
|
|
1306
|
+
setAssistantSeed((current) => ({ id: current.id + 1, submit, value: seed }));
|
|
1307
|
+
setSearchOpen(false);
|
|
1308
|
+
setAssistantOpen(true);
|
|
1309
|
+
}, []);
|
|
1310
|
+
useEffect7(() => {
|
|
1311
|
+
const handleKeydown = (event) => {
|
|
1312
|
+
if ((event.metaKey || event.ctrlKey) && event.key.toLowerCase() === "k") {
|
|
1313
|
+
event.preventDefault();
|
|
1314
|
+
setSearchOpen(true);
|
|
1315
|
+
}
|
|
1316
|
+
if ((event.metaKey || event.ctrlKey) && event.key.toLowerCase() === "i") {
|
|
1317
|
+
event.preventDefault();
|
|
1318
|
+
if (data.config.assistant.access !== "disabled") openAssistant();
|
|
1319
|
+
}
|
|
1320
|
+
};
|
|
1321
|
+
document.addEventListener("keydown", handleKeydown);
|
|
1322
|
+
return () => document.removeEventListener("keydown", handleKeydown);
|
|
1323
|
+
}, [data.config.assistant.access, openAssistant]);
|
|
1324
|
+
useEffect7(() => {
|
|
1325
|
+
setMobileNavOpen(false);
|
|
1326
|
+
setSearchOpen(false);
|
|
1327
|
+
}, [data.page.route]);
|
|
1328
|
+
return /* @__PURE__ */ jsxs7(
|
|
1329
|
+
"div",
|
|
1330
|
+
{
|
|
1331
|
+
"aria-busy": navigating || void 0,
|
|
1332
|
+
className: `${assistantOpen ? "docs-app is-assistant-open" : "docs-app"}${navigating ? " is-navigating" : ""}`,
|
|
1333
|
+
children: [
|
|
1334
|
+
/* @__PURE__ */ jsx7("a", { className: "docs-skip-link", href: "#docs-content", children: "Skip to main content" }),
|
|
1335
|
+
/* @__PURE__ */ jsx7(
|
|
1336
|
+
DocsHeader,
|
|
1337
|
+
{
|
|
1338
|
+
data,
|
|
1339
|
+
onMenuOpen: () => setMobileNavOpen(true),
|
|
1340
|
+
onSearchOpen: () => setSearchOpen(true)
|
|
1341
|
+
}
|
|
1342
|
+
),
|
|
1343
|
+
/* @__PURE__ */ jsxs7("div", { className: "docs-frame", children: [
|
|
1344
|
+
/* @__PURE__ */ jsx7(DesktopSidebar, { data }),
|
|
1345
|
+
/* @__PURE__ */ jsx7("main", { className: "docs-main", id: "docs-content", children: /* @__PURE__ */ jsxs7("div", { className: "docs-reader-grid", children: [
|
|
1346
|
+
/* @__PURE__ */ jsx7(Article, { data, onAssistantOpen: openAssistant, children }),
|
|
1347
|
+
/* @__PURE__ */ jsx7(ContextRail, { data })
|
|
1348
|
+
] }) })
|
|
1349
|
+
] }),
|
|
1350
|
+
/* @__PURE__ */ jsx7(
|
|
1351
|
+
MobileNavigation,
|
|
1352
|
+
{
|
|
1353
|
+
data,
|
|
1354
|
+
onClose: () => setMobileNavOpen(false),
|
|
1355
|
+
open: mobileNavOpen
|
|
1356
|
+
}
|
|
1357
|
+
),
|
|
1358
|
+
/* @__PURE__ */ jsx7(
|
|
1359
|
+
SearchCommand,
|
|
1360
|
+
{
|
|
1361
|
+
assistantEnabled: data.config.assistant.access !== "disabled",
|
|
1362
|
+
name: data.config.name,
|
|
1363
|
+
onAssistantOpen: openAssistant,
|
|
1364
|
+
onClose: () => setSearchOpen(false),
|
|
1365
|
+
onNavigate,
|
|
1366
|
+
open: searchOpen
|
|
1367
|
+
}
|
|
1368
|
+
),
|
|
1369
|
+
data.config.assistant.access !== "disabled" && /* @__PURE__ */ jsxs7(Fragment4, { children: [
|
|
1370
|
+
/* @__PURE__ */ jsx7(
|
|
1371
|
+
AssistantLauncher,
|
|
1372
|
+
{
|
|
1373
|
+
name: data.config.name,
|
|
1374
|
+
onOpen: () => openAssistant(),
|
|
1375
|
+
onSubmit: (question) => openAssistant(question, true),
|
|
1376
|
+
open: assistantOpen
|
|
1377
|
+
}
|
|
1378
|
+
),
|
|
1379
|
+
/* @__PURE__ */ jsx7(
|
|
1380
|
+
DocsAssistant,
|
|
1381
|
+
{
|
|
1382
|
+
access: data.config.assistant.access,
|
|
1383
|
+
name: data.config.name,
|
|
1384
|
+
onClose: () => setAssistantOpen(false),
|
|
1385
|
+
open: assistantOpen,
|
|
1386
|
+
route: data.page.route,
|
|
1387
|
+
seed: assistantSeed,
|
|
1388
|
+
suggestions: data.config.assistant.suggestions
|
|
1389
|
+
}
|
|
1390
|
+
)
|
|
1391
|
+
] })
|
|
1392
|
+
]
|
|
1393
|
+
}
|
|
1394
|
+
);
|
|
1395
|
+
}
|
|
1396
|
+
|
|
1397
|
+
// src/docs/runtime/mdx-components.tsx
|
|
1398
|
+
import { Children, createElement, isValidElement } from "react";
|
|
1399
|
+
import { Fragment as Fragment5, jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
1400
|
+
function Callout({ children, title, kind }) {
|
|
1401
|
+
const label = title ?? kind.charAt(0).toUpperCase() + kind.slice(1);
|
|
1402
|
+
return /* @__PURE__ */ jsxs8("aside", { className: `docs-callout docs-callout-${kind}`, children: [
|
|
1403
|
+
/* @__PURE__ */ jsx8("strong", { children: label }),
|
|
1404
|
+
children
|
|
1405
|
+
] });
|
|
1406
|
+
}
|
|
1407
|
+
function Note(props) {
|
|
1408
|
+
return /* @__PURE__ */ jsx8(Callout, { ...props, kind: "note" });
|
|
1409
|
+
}
|
|
1410
|
+
function Tip(props) {
|
|
1411
|
+
return /* @__PURE__ */ jsx8(Callout, { ...props, kind: "tip" });
|
|
1412
|
+
}
|
|
1413
|
+
function Warning(props) {
|
|
1414
|
+
return /* @__PURE__ */ jsx8(Callout, { ...props, kind: "warning" });
|
|
1415
|
+
}
|
|
1416
|
+
function Info(props) {
|
|
1417
|
+
return /* @__PURE__ */ jsx8(Callout, { ...props, kind: "info" });
|
|
1418
|
+
}
|
|
1419
|
+
function Card({ children, href, label, title }) {
|
|
1420
|
+
const content = /* @__PURE__ */ jsxs8(Fragment5, { children: [
|
|
1421
|
+
title ?? label ? /* @__PURE__ */ jsx8("strong", { children: title ?? label }) : null,
|
|
1422
|
+
children
|
|
1423
|
+
] });
|
|
1424
|
+
return href ? /* @__PURE__ */ jsxs8("a", { className: "docs-card", href, children: [
|
|
1425
|
+
content,
|
|
1426
|
+
/* @__PURE__ */ jsx8("span", { "aria-hidden": "true", children: "\u2192" })
|
|
1427
|
+
] }) : /* @__PURE__ */ jsx8("div", { className: "docs-card", children: content });
|
|
1428
|
+
}
|
|
1429
|
+
function Accordion({ children, label, title }) {
|
|
1430
|
+
return /* @__PURE__ */ jsxs8("details", { className: "docs-accordion", children: [
|
|
1431
|
+
/* @__PURE__ */ jsx8("summary", { children: title ?? label ?? "Details" }),
|
|
1432
|
+
children
|
|
1433
|
+
] });
|
|
1434
|
+
}
|
|
1435
|
+
function AccordionGroup({ children }) {
|
|
1436
|
+
return /* @__PURE__ */ jsx8("div", { className: "docs-accordion-group", children });
|
|
1437
|
+
}
|
|
1438
|
+
function Step({ children, label, title }) {
|
|
1439
|
+
return /* @__PURE__ */ jsxs8("section", { className: "docs-step", children: [
|
|
1440
|
+
title ?? label ? /* @__PURE__ */ jsx8("h3", { children: title ?? label }) : null,
|
|
1441
|
+
children
|
|
1442
|
+
] });
|
|
1443
|
+
}
|
|
1444
|
+
function Steps({ children }) {
|
|
1445
|
+
return /* @__PURE__ */ jsx8("div", { className: "docs-steps", children });
|
|
1446
|
+
}
|
|
1447
|
+
function Tab({ children, label, title }) {
|
|
1448
|
+
return /* @__PURE__ */ jsx8("section", { className: "docs-tab", "data-tab": true, "data-tab-title": title ?? label ?? "Tab", children });
|
|
1449
|
+
}
|
|
1450
|
+
function Tabs({ children }) {
|
|
1451
|
+
return /* @__PURE__ */ jsx8("div", { className: "docs-tabs", "data-tab-group": true, children });
|
|
1452
|
+
}
|
|
1453
|
+
function CodeGroup({ children, label, title }) {
|
|
1454
|
+
return /* @__PURE__ */ jsxs8("div", { className: "docs-code-group", "data-tab-group": true, children: [
|
|
1455
|
+
title ?? label ? /* @__PURE__ */ jsx8("div", { className: "docs-code-group-title", children: title ?? label }) : null,
|
|
1456
|
+
Children.toArray(children).map((child, index) => /* @__PURE__ */ jsx8(
|
|
1457
|
+
"section",
|
|
1458
|
+
{
|
|
1459
|
+
className: "docs-tab",
|
|
1460
|
+
"data-tab": true,
|
|
1461
|
+
"data-tab-title": codeBlockTitle(child) ?? `Example ${index + 1}`,
|
|
1462
|
+
children: child
|
|
1463
|
+
},
|
|
1464
|
+
index
|
|
1465
|
+
))
|
|
1466
|
+
] });
|
|
1467
|
+
}
|
|
1468
|
+
function codeBlockTitle(node) {
|
|
1469
|
+
if (!isValidElement(node)) return void 0;
|
|
1470
|
+
const code = node.props.children;
|
|
1471
|
+
if (!isValidElement(code)) return void 0;
|
|
1472
|
+
const title = code.props["data-code-title"];
|
|
1473
|
+
return typeof title === "string" && title ? title : void 0;
|
|
1474
|
+
}
|
|
1475
|
+
function Heading({ level, ...props }) {
|
|
1476
|
+
const id = props.id;
|
|
1477
|
+
return createElement(
|
|
1478
|
+
`h${level}`,
|
|
1479
|
+
props,
|
|
1480
|
+
props.children,
|
|
1481
|
+
id ? /* @__PURE__ */ jsx8("a", { "aria-label": "Link to this section", className: "docs-heading-anchor", href: `#${id}`, children: "#" }) : null
|
|
1482
|
+
);
|
|
1483
|
+
}
|
|
1484
|
+
var docsMdxComponents = {
|
|
1485
|
+
Accordion,
|
|
1486
|
+
AccordionGroup,
|
|
1487
|
+
Card,
|
|
1488
|
+
CodeGroup,
|
|
1489
|
+
Info,
|
|
1490
|
+
Note,
|
|
1491
|
+
Step,
|
|
1492
|
+
Steps,
|
|
1493
|
+
Tab,
|
|
1494
|
+
Tabs,
|
|
1495
|
+
Tip,
|
|
1496
|
+
Warning,
|
|
1497
|
+
h1: (props) => /* @__PURE__ */ jsx8(Heading, { ...props, level: 1 }),
|
|
1498
|
+
h2: (props) => /* @__PURE__ */ jsx8(Heading, { ...props, level: 2 }),
|
|
1499
|
+
h3: (props) => /* @__PURE__ */ jsx8(Heading, { ...props, level: 3 }),
|
|
1500
|
+
h4: (props) => /* @__PURE__ */ jsx8(Heading, { ...props, level: 4 }),
|
|
1501
|
+
h5: (props) => /* @__PURE__ */ jsx8(Heading, { ...props, level: 5 }),
|
|
1502
|
+
h6: (props) => /* @__PURE__ */ jsx8(Heading, { ...props, level: 6 })
|
|
1503
|
+
};
|
|
1504
|
+
|
|
1505
|
+
// src/docs/runtime/public.tsx
|
|
1506
|
+
import { jsx as jsx9 } from "react/jsx-runtime";
|
|
1507
|
+
var DefaultDocs = DocsApp;
|
|
1508
|
+
function DocsContent({
|
|
1509
|
+
data,
|
|
1510
|
+
Page
|
|
1511
|
+
}) {
|
|
1512
|
+
if (!Page) {
|
|
1513
|
+
return /* @__PURE__ */ jsx9("div", { className: "docs-prose", dangerouslySetInnerHTML: { __html: data.page.html } });
|
|
1514
|
+
}
|
|
1515
|
+
return /* @__PURE__ */ jsx9("div", { className: "docs-prose", children: /* @__PURE__ */ jsx9(Page, { components: docsMdxComponents }) });
|
|
1516
|
+
}
|
|
1517
|
+
|
|
1518
|
+
export {
|
|
1519
|
+
DocsApp,
|
|
1520
|
+
Note,
|
|
1521
|
+
Tip,
|
|
1522
|
+
Warning,
|
|
1523
|
+
Info,
|
|
1524
|
+
Card,
|
|
1525
|
+
Accordion,
|
|
1526
|
+
AccordionGroup,
|
|
1527
|
+
Step,
|
|
1528
|
+
Steps,
|
|
1529
|
+
Tab,
|
|
1530
|
+
Tabs,
|
|
1531
|
+
CodeGroup,
|
|
1532
|
+
DefaultDocs,
|
|
1533
|
+
DocsContent
|
|
1534
|
+
};
|
|
1535
|
+
//# sourceMappingURL=chunk-DQ4G6VL6.js.map
|