@docubook/flame 2.0.0-beta.0 → 2.0.0-beta.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.
Files changed (54) hide show
  1. package/.docu/components/ScrollTo.tsx +17 -11
  2. package/.docu/components/Toc.tsx +32 -7
  3. package/.docu/lib/build.deno.js +6 -9
  4. package/.docu/lib/build.deno.js.map +1 -0
  5. package/.docu/lib/build.impl-BJsi28mD.js +377 -0
  6. package/.docu/lib/build.impl-BJsi28mD.js.map +1 -0
  7. package/.docu/lib/build.impl-yVLaa1eQ.js +2 -0
  8. package/.docu/lib/build.node.js +6 -9
  9. package/.docu/lib/build.node.js.map +1 -0
  10. package/.docu/lib/clean.js +25 -25
  11. package/.docu/lib/clean.js.map +1 -0
  12. package/.docu/lib/deno-DmEaKggj.js +20 -0
  13. package/.docu/lib/deno-DmEaKggj.js.map +1 -0
  14. package/.docu/lib/deploy.deno.js +9 -9
  15. package/.docu/lib/deploy.deno.js.map +1 -0
  16. package/.docu/lib/deploy.node.js +8 -8
  17. package/.docu/lib/deploy.node.js.map +1 -0
  18. package/.docu/lib/deploy.shared-D3UWafa6.js +295 -0
  19. package/.docu/lib/deploy.shared-D3UWafa6.js.map +1 -0
  20. package/.docu/lib/html.shared-DSn-7_6t.js +2467 -0
  21. package/.docu/lib/html.shared-DSn-7_6t.js.map +1 -0
  22. package/.docu/lib/logger-CycvLCrQ.js +312 -0
  23. package/.docu/lib/logger-CycvLCrQ.js.map +1 -0
  24. package/.docu/lib/node-DPTySdwG.js +80 -0
  25. package/.docu/lib/node-DPTySdwG.js.map +1 -0
  26. package/.docu/lib/paths-BtOIPBQ9.js +52 -0
  27. package/.docu/lib/paths-BtOIPBQ9.js.map +1 -0
  28. package/.docu/lib/preview.deno.js +7 -11
  29. package/.docu/lib/preview.deno.js.map +1 -0
  30. package/.docu/lib/preview.impl-CXJS2tQS.js +77 -0
  31. package/.docu/lib/preview.impl-CXJS2tQS.js.map +1 -0
  32. package/.docu/lib/preview.node.js +7 -11
  33. package/.docu/lib/preview.node.js.map +1 -0
  34. package/.docu/lib/server.deno.js +7 -12
  35. package/.docu/lib/server.deno.js.map +1 -0
  36. package/.docu/lib/server.impl-CJuWimfN.js +358 -0
  37. package/.docu/lib/server.impl-CJuWimfN.js.map +1 -0
  38. package/.docu/lib/server.node.js +7 -12
  39. package/.docu/lib/server.node.js.map +1 -0
  40. package/.docu/lib/utils-DA17MyQG.js +167 -0
  41. package/.docu/lib/utils-DA17MyQG.js.map +1 -0
  42. package/.docu/node/hydrate.node.ts +116 -166
  43. package/bin/compile-lib.mjs +30 -28
  44. package/package.json +6 -6
  45. package/.docu/lib/build.impl-S4DS5XPH.js +0 -12
  46. package/.docu/lib/chunk-4IQXHHPF.js +0 -62
  47. package/.docu/lib/chunk-C3RCUTUE.js +0 -470
  48. package/.docu/lib/chunk-D3QTSBR4.js +0 -434
  49. package/.docu/lib/chunk-EOK6KATZ.js +0 -191
  50. package/.docu/lib/chunk-IVM5UM44.js +0 -301
  51. package/.docu/lib/chunk-JMQI3FKV.js +0 -92
  52. package/.docu/lib/chunk-LXJLSXQI.js +0 -2691
  53. package/.docu/lib/chunk-O326MYJE.js +0 -330
  54. package/.docu/lib/chunk-UISOJ4RW.js +0 -114
@@ -1,2691 +0,0 @@
1
- import {
2
- cn,
3
- docsHtmlHref,
4
- formatDate2,
5
- isExternalUrl,
6
- normalizeImporterPath,
7
- scanMdxFiles
8
- } from "./chunk-EOK6KATZ.js";
9
- import {
10
- ASSETS_DIR,
11
- DOCS_DIR,
12
- FRAMEWORK_ROOT,
13
- LIB_DIR,
14
- PROJECT_ROOT,
15
- STYLES_DIR,
16
- cleanOldBundles,
17
- loadDocuConfig
18
- } from "./chunk-4IQXHHPF.js";
19
-
20
- // .docu/node/plugin-loader.ts
21
- import { resolve } from "node:path";
22
- var NPM_PACKAGE_RE = /^(?:@[a-z0-9-~][a-z0-9-._~]*\/)?[a-z0-9-~][a-z0-9-._~]*$/;
23
- function resolveSpecifier(specifier) {
24
- let resolved;
25
- if (specifier.startsWith(".")) {
26
- resolved = resolve(PROJECT_ROOT, specifier);
27
- } else if (specifier.startsWith("/")) {
28
- resolved = specifier;
29
- } else {
30
- if (!NPM_PACKAGE_RE.test(specifier)) {
31
- throw new Error(
32
- `[plugin-loader] Invalid plugin specifier "${specifier}": must be a valid npm package name, relative path, or absolute path`
33
- );
34
- }
35
- return specifier;
36
- }
37
- const root = PROJECT_ROOT.endsWith("/") ? PROJECT_ROOT : PROJECT_ROOT + "/";
38
- if (!resolved.startsWith(root)) {
39
- throw new Error(
40
- `[plugin-loader] Path traversal blocked: "${specifier}" resolves outside project root`
41
- );
42
- }
43
- return resolved;
44
- }
45
- async function loadPlugins(entries = []) {
46
- const plugins = [];
47
- for (const entry of entries) {
48
- const [specifier, options] = Array.isArray(entry) ? entry : [entry, void 0];
49
- const resolved = resolveSpecifier(specifier);
50
- let mod;
51
- try {
52
- mod = await import(resolved);
53
- } catch (err) {
54
- const message = err instanceof Error ? err.message : String(err);
55
- throw new Error(`[plugin-loader] Failed to import plugin "${specifier}": ${message}`, {
56
- cause: err
57
- });
58
- }
59
- const exported = mod.default;
60
- let plugin;
61
- if (typeof exported === "function") {
62
- try {
63
- plugin = exported(options);
64
- } catch (err) {
65
- const message = err instanceof Error ? err.message : String(err);
66
- throw new Error(
67
- `[plugin-loader] Plugin factory "${specifier}" threw during initialization: ${message}`,
68
- { cause: err }
69
- );
70
- }
71
- } else if (exported && typeof exported === "object") {
72
- plugin = exported;
73
- } else {
74
- throw new Error(
75
- `[plugin-loader] Plugin "${specifier}" must export a default function or object. Got: ${typeof exported}`
76
- );
77
- }
78
- if (!plugin.name || typeof plugin.name !== "string") {
79
- throw new Error(
80
- `[plugin-loader] Plugin "${specifier}" must have a valid 'name' property (string). Got: ${typeof plugin.name}`
81
- );
82
- }
83
- if (typeof plugin.setup !== "function") {
84
- throw new Error(
85
- `[plugin-loader] Plugin "${specifier}" (name: "${plugin.name}") must have a 'setup(build)' function.`
86
- );
87
- }
88
- plugins.push(plugin);
89
- }
90
- return plugins;
91
- }
92
-
93
- // .docu/node/plugin-builder.ts
94
- var BuildPluginBuilder = class {
95
- config;
96
- _handleRequest = [];
97
- _injectBody = [];
98
- _injectHead = [];
99
- _onEnd = [];
100
- _onLoad = [];
101
- _onStart = [];
102
- _rehypePlugins = [];
103
- _remarkPlugins = [];
104
- _transformFrontmatter = [];
105
- _transformHtml = [];
106
- constructor(config2) {
107
- this.config = config2;
108
- }
109
- /**
110
- * Collect and deduplicate all `<body>` injection snippets from registered plugins.
111
- * Each callback is executed in registration order; plugin errors are wrapped
112
- * with a descriptive message.
113
- *
114
- * @param context - Current page context passed to each injectBody callback.
115
- * @returns Deduplicated array of HTML strings to inject before `</body>`.
116
- * @throws Error if any injectBody callback throws — wraps original error as cause.
117
- */
118
- collectBody(context) {
119
- const items = [];
120
- for (const cb of this._injectBody) {
121
- try {
122
- const result = cb(context);
123
- if (result) {
124
- this.collectItems(items, result, "injectBody");
125
- }
126
- } catch (err) {
127
- throw new Error(
128
- `[plugin] injectBody callback failed: ${err instanceof Error ? err.message : String(err)}`,
129
- { cause: err }
130
- );
131
- }
132
- }
133
- return [...new Set(items)];
134
- }
135
- /**
136
- * Collect and deduplicate all `<head>` injection snippets from registered plugins.
137
- * Each callback is executed in registration order; plugin errors are wrapped
138
- * with a descriptive message.
139
- *
140
- * @param context - Current page context passed to each injectHead callback.
141
- * @returns Deduplicated array of HTML strings to inject before `</head>`.
142
- * @throws Error if any injectHead callback throws — wraps original error as cause.
143
- */
144
- collectHead(context) {
145
- const items = [];
146
- for (const cb of this._injectHead) {
147
- try {
148
- const result = cb(context);
149
- if (result) {
150
- this.collectItems(items, result, "injectHead");
151
- }
152
- } catch (err) {
153
- throw new Error(
154
- `[plugin] injectHead callback failed: ${err instanceof Error ? err.message : String(err)}`,
155
- { cause: err }
156
- );
157
- }
158
- }
159
- return [...new Set(items)];
160
- }
161
- /**
162
- * Collect all rehype plugin arrays from registered rehypePlugins callbacks.
163
- * Results from all plugins are flattened into a single array.
164
- *
165
- * @returns Flattened array of rehype plugin instances applied after default set.
166
- * @throws Error if any rehypePlugins callback throws — wraps original error as cause.
167
- */
168
- collectRehypePlugins() {
169
- const plugins = [];
170
- for (const cb of this._rehypePlugins) {
171
- try {
172
- plugins.push(...cb());
173
- } catch (err) {
174
- throw new Error(
175
- `[plugin] rehypePlugins callback failed: ${err instanceof Error ? err.message : String(err)}`,
176
- { cause: err }
177
- );
178
- }
179
- }
180
- return plugins;
181
- }
182
- /**
183
- * Collect all remark plugin arrays from registered remarkPlugins callbacks.
184
- * Results from all plugins are flattened into a single array.
185
- *
186
- * @returns Flattened array of remark plugin instances applied after default set.
187
- * @throws Error if any remarkPlugins callback throws — wraps original error as cause.
188
- */
189
- collectRemarkPlugins() {
190
- const plugins = [];
191
- for (const cb of this._remarkPlugins) {
192
- try {
193
- plugins.push(...cb());
194
- } catch (err) {
195
- throw new Error(
196
- `[plugin] remarkPlugins callback failed: ${err instanceof Error ? err.message : String(err)}`,
197
- { cause: err }
198
- );
199
- }
200
- }
201
- return plugins;
202
- }
203
- /**
204
- * Register a callback to intercept incoming requests during development.
205
- * The **first** callback to return a `Response` short-circuits all subsequent handlers.
206
- * Errors inside callbacks are caught and logged — execution continues to next handler.
207
- *
208
- * @param callback - Receives the Request and dev server context. Return Response or void.
209
- *
210
- * @example
211
- * build.handleRequest((req, ctx) => {
212
- * if (new URL(req.url).pathname === "/api/status") {
213
- * return new Response(JSON.stringify({ ok: true }), {
214
- * headers: { "Content-Type": "application/json" },
215
- * });
216
- * }
217
- * });
218
- */
219
- handleRequest(callback) {
220
- this._handleRequest.push(callback);
221
- }
222
- /**
223
- * Register a callback that returns HTML strings to inject before `</body>`.
224
- * Results from all plugins are merged, deduplicated, and served via `collectBody()`.
225
- *
226
- * @param callback - Returns a single HTML string or an array. Called once per page.
227
- *
228
- * @example
229
- * build.injectBody(() => `<div id="chat-widget"></div>`);
230
- */
231
- injectBody(callback) {
232
- this._injectBody.push(callback);
233
- }
234
- /**
235
- * Register a callback that returns HTML strings to inject inside `<head>`.
236
- * Results from all plugins are merged, deduplicated, and served via `collectHead()`.
237
- *
238
- * @param callback - Returns a single HTML string or an array. Called once per page.
239
- *
240
- * @example
241
- * build.injectHead(() => `<script async src="https://cdn.example.com/analytics.js"></script>`);
242
- */
243
- injectHead(callback) {
244
- this._injectHead.push(callback);
245
- }
246
- /**
247
- * Register a callback to run once after all pages are built.
248
- * Receives the resolved config and aggregated page metadata.
249
- * Errors thrown by the callback propagate to the caller via `runOnEnd()`.
250
- *
251
- * @param callback - Receives config and page metadata array. May return a Promise.
252
- *
253
- * @example
254
- * build.onEnd(async (config, pages) => {
255
- * const xml = generateSitemap(pages, config.meta.baseURL);
256
- * const out = ".docu/dist/sitemap.xml";
257
- * // Bun.write on Bun for speed, writeFile on Node/Deno
258
- * await (typeof Bun !== "undefined"
259
- * ? Bun.write(out, xml)
260
- * : writeFile(out, xml));
261
- * });
262
- */
263
- onEnd(callback) {
264
- this._onEnd.push(callback);
265
- }
266
- /**
267
- * Register a callback to transform raw file content before MDX compilation.
268
- * Filtered by regex against the file's relative path — only the **first** matching
269
- * handler's result is used.
270
- * Errors thrown by the callback propagate to the caller via `runOnLoad()`.
271
- *
272
- * @param args.filter - RegExp matched against the file's relative path.
273
- * @param args.namespace - Optional namespace prefix (reserved for future use).
274
- * @param callback - Receives file path and raw content. Return new contents or void.
275
- *
276
- * @example
277
- * build.onLoad({ filter: /\.md$/ }, ({ path, content }) => {
278
- * return { contents: `<!-- preprocessed -->\n${content}`, loader: "mdx" };
279
- * });
280
- */
281
- onLoad(args, callback) {
282
- this._onLoad.push({ ...args, fn: callback });
283
- }
284
- /**
285
- * Register a callback to run once before the build starts.
286
- * Receives the resolved DocuConfig for validation or resource initialization.
287
- * Errors thrown by the callback propagate to the caller via `runOnStart()`.
288
- *
289
- * @param callback - Receives the resolved config. May return a Promise.
290
- *
291
- * @example
292
- * build.onStart((config) => {
293
- * if (!config.meta.baseURL) throw new Error("baseURL required");
294
- * });
295
- */
296
- onStart(callback) {
297
- this._onStart.push(callback);
298
- }
299
- /**
300
- * Register additional rehype (HTML) plugins for the MDX compilation pipeline.
301
- * Results from all plugins are merged and applied **after** the default set.
302
- *
303
- * @param callback - Returns an array of rehype plugins.
304
- *
305
- * @example
306
- * build.rehypePlugins(() => [require("rehype-autolink-headings")]);
307
- */
308
- rehypePlugins(callback) {
309
- this._rehypePlugins.push(callback);
310
- }
311
- /**
312
- * Register additional remark (Markdown) plugins for the MDX compilation pipeline.
313
- * Results from all plugins are merged and applied **after** the default set.
314
- *
315
- * @param callback - Returns an array of remark plugins.
316
- *
317
- * @example
318
- * build.remarkPlugins(() => [require("remark-custom-heading-id")]);
319
- */
320
- remarkPlugins(callback) {
321
- this._remarkPlugins.push(callback);
322
- }
323
- /**
324
- * Execute all registered handleRequest callbacks sequentially.
325
- * Stops and returns the **first** `Response` returned by any callback.
326
- * Errors inside individual callbacks are caught and logged — execution
327
- * continues to the next callback without throwing.
328
- *
329
- * @param req - The incoming HTTP Request.
330
- * @param context - Dev server context (port, hostname).
331
- * @returns A Response if a callback intercepted the request, or null if none did.
332
- */
333
- async runHandleRequest(req, context) {
334
- for (let i = 0; i < this._handleRequest.length; i++) {
335
- try {
336
- const result = await this._handleRequest[i](req, context);
337
- if (result instanceof Response) {
338
- return result;
339
- }
340
- } catch (err) {
341
- console.error(
342
- `[plugin] handleRequest callback #${i + 1} error: ${err instanceof Error ? err.message : String(err)}`
343
- );
344
- }
345
- }
346
- return null;
347
- }
348
- /**
349
- * Execute all registered onEnd callbacks sequentially with the resolved
350
- * config and aggregated page metadata.
351
- * Errors inside individual callbacks are caught and logged — execution
352
- * continues to the next callback without throwing.
353
- *
354
- * @param pages - Array of metadata for every built page.
355
- */
356
- async runOnEnd(pages) {
357
- for (let i = 0; i < this._onEnd.length; i++) {
358
- try {
359
- await this._onEnd[i](this.config, pages);
360
- } catch (err) {
361
- console.error(
362
- `[plugin] onEnd callback #${i + 1} error: ${err instanceof Error ? err.message : String(err)}`
363
- );
364
- }
365
- }
366
- }
367
- /**
368
- * Execute registered onLoad handlers in registration order against a file.
369
- * Only the **first** handler whose `filter` regex matches the path and returns
370
- * a result is applied. If a matching handler throws, the error is logged and
371
- * subsequent handlers are tried.
372
- *
373
- * @param path - Relative path of the file being loaded.
374
- * @param content - Raw file content.
375
- * @returns Transformed content if a matching handler returned it, or null.
376
- */
377
- async runOnLoad(path, content) {
378
- for (const handler of this._onLoad) {
379
- if (handler.filter.test(path)) {
380
- try {
381
- const result = await handler.fn({ path, content });
382
- if (result) return result;
383
- } catch (err) {
384
- console.error(
385
- `[plugin] onLoad handler for filter ${handler.filter} error: ${err instanceof Error ? err.message : String(err)}`
386
- );
387
- }
388
- }
389
- }
390
- return null;
391
- }
392
- /**
393
- * Execute all registered onStart callbacks sequentially.
394
- * Each callback receives the resolved DocuConfig.
395
- * Errors inside individual callbacks are caught and logged — execution
396
- * continues to the next callback without throwing.
397
- */
398
- async runOnStart() {
399
- for (let i = 0; i < this._onStart.length; i++) {
400
- try {
401
- await this._onStart[i](this.config);
402
- } catch (err) {
403
- console.error(
404
- `[plugin] onStart callback #${i + 1} error: ${err instanceof Error ? err.message : String(err)}`
405
- );
406
- }
407
- }
408
- }
409
- /**
410
- * Execute the transformFrontmatter chain in waterfall pattern.
411
- * Each callback receives the **previous** callback's return value (or the
412
- * original frontmatter for the first). Callbacks that return `undefined` or
413
- * `null` pass the current value through unchanged.
414
- * Callbacks that return a non-object (string, number, array) are skipped
415
- * with a console warning — only plain objects are accepted.
416
- * Errors inside individual callbacks are caught and logged — the current
417
- * frontmatter passes through unchanged for that step.
418
- *
419
- * @param frontmatter - Initial frontmatter object parsed from MDX.
420
- * @param context - Page context with slug, filePath, and raw content.
421
- * @returns The final transformed frontmatter object.
422
- */
423
- async runTransformFrontmatterChain(frontmatter, context) {
424
- let result = frontmatter;
425
- for (let i = 0; i < this._transformFrontmatter.length; i++) {
426
- try {
427
- const next = await this._transformFrontmatter[i](result, context);
428
- if (next !== void 0 && next !== null) {
429
- if (typeof next === "object" && !Array.isArray(next)) {
430
- result = next;
431
- } else {
432
- console.warn(
433
- `[plugin] transformFrontmatter callback #${i + 1} returned invalid type (expected a plain object), skipping`
434
- );
435
- }
436
- }
437
- } catch (err) {
438
- console.error(
439
- `[plugin] transformFrontmatter callback #${i + 1} error: ${err instanceof Error ? err.message : String(err)}`
440
- );
441
- }
442
- }
443
- return result;
444
- }
445
- /**
446
- * Execute the transformHtml chain in pipeline pattern.
447
- * Each callback receives the **previous** callback's return value (or the
448
- * original HTML for the first). Every callback **must** return a string.
449
- * Errors inside individual callbacks are caught and logged — the current
450
- * HTML passes through unchanged for that step.
451
- *
452
- * @param html - The initial HTML string.
453
- * @param context - Full page context (slug, filePath, frontmatter, content, config).
454
- * @returns The final transformed HTML string.
455
- */
456
- async runTransformHtmlChain(html, context) {
457
- let result = html;
458
- for (let i = 0; i < this._transformHtml.length; i++) {
459
- try {
460
- result = await this._transformHtml[i](result, context);
461
- } catch (err) {
462
- console.error(
463
- `[plugin] transformHtml callback #${i + 1} error: ${err instanceof Error ? err.message : String(err)}`
464
- );
465
- }
466
- }
467
- return result;
468
- }
469
- /**
470
- * Register a callback to mutate frontmatter before MDX compilation.
471
- * Callbacks are chained in a waterfall: the return value of one is passed
472
- * as input to the next. Return `undefined` to pass through unchanged.
473
- *
474
- * **Note:** Only plain objects are accepted as return values. Returning
475
- * a string, number, or array will be silently skipped with a warning.
476
- * Plugin authors should validate their return values before returning.
477
- *
478
- * @param callback - Receives frontmatter object and page context.
479
- *
480
- * @example
481
- * build.transformFrontmatter((fm, ctx) => {
482
- * const wordCount = ctx.content!.split(/\s+/).length;
483
- * return { ...fm, readingTime: `${Math.ceil(wordCount / 200)} min read` };
484
- * });
485
- */
486
- transformFrontmatter(callback) {
487
- this._transformFrontmatter.push(callback);
488
- }
489
- /**
490
- * Register a callback to transform the final HTML string per page.
491
- * This is the **last** hook before the HTML is written to disk.
492
- * Callbacks are chained in a pipeline: each receives the previous callback's output.
493
- *
494
- * @param callback - Receives HTML string and full page context. Must return HTML.
495
- *
496
- * @example
497
- * build.transformHtml((html, ctx) => {
498
- * return html.replace(/https?:\/\/old-domain\.com\//g, "/");
499
- * });
500
- */
501
- transformHtml(callback) {
502
- this._transformHtml.push(callback);
503
- }
504
- /**
505
- * Collect items from a callback result, filtering only valid strings.
506
- * Non-string items and unexpected types are logged as warnings.
507
- */
508
- collectItems(items, result, hookName) {
509
- if (Array.isArray(result)) {
510
- for (const item of result) {
511
- if (typeof item === "string") {
512
- items.push(item);
513
- } else {
514
- console.warn(
515
- `[plugin] ${hookName} callback returned non-string item (got ${typeof item}), skipping`
516
- );
517
- }
518
- }
519
- } else if (typeof result === "string") {
520
- items.push(result);
521
- } else {
522
- console.warn(
523
- `[plugin] ${hookName} callback returned unexpected type (got ${typeof result}), expected string or string[], skipping`
524
- );
525
- }
526
- }
527
- };
528
-
529
- // .docu/node/hydrate.ts
530
- import { resolveTheme, generateThemeCss, presetRegistry } from "@docubook/themes-colors";
531
-
532
- // .docu/node/fs-scanner.ts
533
- import { readdirSync, statSync } from "node:fs";
534
- import { join, relative, extname, sep } from "node:path";
535
- function toTitleCase(str) {
536
- return str.replace(/-/g, " ").replace(/_/g, " ").replace(/([a-z])([A-Z])/g, "$1 $2").split(" ").map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()).join(" ");
537
- }
538
- function isDocFile(filename) {
539
- const ext = extname(filename).toLowerCase();
540
- return [".mdx", ".md"].includes(ext);
541
- }
542
- function normalizePath(path) {
543
- return path.split(sep).join("/");
544
- }
545
- function scanDir(dirPath, docsRoot) {
546
- const nodes = [];
547
- let entries;
548
- try {
549
- entries = readdirSync(dirPath).sort();
550
- } catch (err) {
551
- if (err.code !== "ENOENT") throw err;
552
- return nodes;
553
- }
554
- for (const entry of entries) {
555
- if (entry.startsWith(".") || entry === "assets") continue;
556
- const absPath = join(dirPath, entry);
557
- try {
558
- const stat2 = statSync(absPath);
559
- if (stat2.isDirectory()) {
560
- const children = scanDir(absPath, docsRoot);
561
- if (children.length > 0) {
562
- nodes.push({
563
- name: entry,
564
- relPath: normalizePath(relative(docsRoot, absPath)),
565
- absPath,
566
- isDirectory: true,
567
- children
568
- });
569
- }
570
- } else if (stat2.isFile() && isDocFile(entry)) {
571
- nodes.push({
572
- name: entry,
573
- relPath: normalizePath(relative(docsRoot, absPath).replace(/\.(mdx|md)$/, "")),
574
- absPath,
575
- isDirectory: false
576
- });
577
- }
578
- } catch (err) {
579
- if (err.code !== "ENOENT") throw err;
580
- continue;
581
- }
582
- }
583
- return nodes;
584
- }
585
- function fileNodesToRoutes(nodes, parentHref = "") {
586
- const routes3 = [];
587
- for (const node of nodes) {
588
- if (!node.isDirectory) {
589
- const baseName = node.name.replace(/\.(mdx|md)$/, "");
590
- const isIndexFile = /^(index|readme)$/i.test(baseName);
591
- if (isIndexFile) continue;
592
- const segment = node.relPath.split("/").pop();
593
- const href = `/${segment}`;
594
- routes3.push({
595
- title: toTitleCase(baseName),
596
- href
597
- });
598
- } else {
599
- const dirTitle = toTitleCase(node.name);
600
- const segment = node.relPath.split("/").pop();
601
- const dirHref = `/${segment}`;
602
- const children = fileNodesToRoutes(node.children || [], dirHref);
603
- if (children.length === 0) continue;
604
- const hasIndexFile = (node.children || []).some(
605
- (c) => !c.isDirectory && /^(index|readme)\.(mdx|md)$/i.test(c.name)
606
- );
607
- if (hasIndexFile) {
608
- routes3.push({
609
- title: dirTitle,
610
- href: dirHref,
611
- ...parentHref === "" && {
612
- context: { title: dirTitle, icon: "CircleHelp", description: dirTitle }
613
- },
614
- items: children
615
- });
616
- } else {
617
- routes3.push({
618
- title: dirTitle,
619
- href: dirHref,
620
- noLink: true,
621
- ...parentHref === "" && {
622
- context: { title: dirTitle, icon: "CircleHelp", description: dirTitle }
623
- },
624
- items: children
625
- });
626
- }
627
- }
628
- }
629
- return routes3;
630
- }
631
- function scanDocsFolder(docsPath = "./docs") {
632
- const absDocsPath = join(process.cwd(), docsPath);
633
- const nodes = scanDir(absDocsPath, absDocsPath);
634
- return fileNodesToRoutes(nodes);
635
- }
636
- function resolveRoutes(docuJsonRoutes) {
637
- if (docuJsonRoutes && docuJsonRoutes.length > 0) {
638
- return docuJsonRoutes;
639
- }
640
- return scanDocsFolder();
641
- }
642
-
643
- // .docu/node/hydrate.ts
644
- var themeRegistry = presetRegistry;
645
- function getThemeConfig() {
646
- if (process.env.FLAME_THEME) {
647
- return process.env.FLAME_THEME;
648
- }
649
- const config2 = loadDocuConfig();
650
- return config2.themes?.colors;
651
- }
652
- function buildThemeCss(baseCss, themeConfig) {
653
- try {
654
- const resolved = resolveTheme(themeConfig, themeRegistry);
655
- return baseCss + "\n" + generateThemeCss(resolved);
656
- } catch (err) {
657
- console.warn(
658
- `[flame] Failed to resolve theme CSS: ${err instanceof Error ? err.message : String(err)}`
659
- );
660
- return baseCss;
661
- }
662
- }
663
- function computeInlineThemeCss() {
664
- try {
665
- const themeColors = getThemeConfig();
666
- if (themeColors) {
667
- const resolved = resolveTheme(themeColors, themeRegistry);
668
- return generateThemeCss(resolved);
669
- }
670
- } catch (err) {
671
- console.warn(
672
- `[flame] Failed to compute inline theme CSS: ${err instanceof Error ? err.message : String(err)}`
673
- );
674
- }
675
- return void 0;
676
- }
677
-
678
- // .docu/node/hydrate.node.ts
679
- import { execFile } from "node:child_process";
680
- import { builtinModules, createRequire } from "node:module";
681
- import { basename, dirname, join as join2, resolve as resolve2 } from "node:path";
682
- import { existsSync, readFileSync, readdirSync as readdirSync2 } from "node:fs";
683
- import { promisify } from "node:util";
684
- import { mkdir, readFile, unlink, writeFile } from "node:fs/promises";
685
- import { createHash } from "node:crypto";
686
- function extractConfigIcons(config2) {
687
- const icons = [];
688
- const pushIf = (s) => {
689
- if (s) icons.push(s);
690
- };
691
- config2.home?.hero?.actions?.forEach((a) => pushIf(a.icon));
692
- config2.home?.features?.forEach((f) => pushIf(f.icon));
693
- (function walk(routes3) {
694
- for (const r of routes3) {
695
- pushIf(r.context?.icon);
696
- if (r.items) walk(r.items);
697
- }
698
- })(config2.routes ?? []);
699
- return [...new Set(icons.filter((n) => /^[A-Z]/.test(n)))];
700
- }
701
- var execFileAsync = promisify(execFile);
702
- function resolveTailwindBin() {
703
- const require2 = createRequire(import.meta.url);
704
- const pkgPath = require2.resolve("@tailwindcss/cli/package.json");
705
- const pkg = require2(pkgPath);
706
- const binRel = typeof pkg.bin === "string" ? pkg.bin : pkg.bin.tailwindcss;
707
- return join2(dirname(pkgPath), binRel);
708
- }
709
- function tailwindCacheKey() {
710
- const globalsPath = join2(STYLES_DIR, "globals.css");
711
- const globalsContent = existsSync(globalsPath) ? readFileSync(globalsPath, "utf-8") : "";
712
- let themeSuffix = "";
713
- try {
714
- const themeColors = getThemeConfig();
715
- if (themeColors) {
716
- themeSuffix = JSON.stringify(themeColors);
717
- }
718
- } catch {
719
- }
720
- return createHash("sha256").update(globalsContent + themeSuffix).digest("hex").slice(0, 16);
721
- }
722
- async function buildTailwindCss(key) {
723
- const cachedFile = `client-${key}.css`;
724
- const cachedPath = join2(ASSETS_DIR, cachedFile);
725
- if (existsSync(cachedPath)) {
726
- const content = readFileSync(cachedPath, "utf-8");
727
- return { file: cachedFile, content };
728
- }
729
- const tmpCss = join2(ASSETS_DIR, `_tmp-${key}.css`);
730
- const bin = resolveTailwindBin();
731
- const twArgs = ["-i", join2(STYLES_DIR, "globals.css"), "-o", tmpCss, "--minify"];
732
- const isDeno = "Deno" in globalThis;
733
- const args = isDeno ? ["run", "-A", bin, ...twArgs] : [bin, ...twArgs];
734
- try {
735
- await execFileAsync(process.execPath, args, { maxBuffer: 16 * 1024 * 1024 });
736
- } catch (err) {
737
- const stderr = err.stderr ?? String(err);
738
- throw new Error(`Tailwind CSS build failed:
739
- ${stderr}`, { cause: err });
740
- }
741
- let cssContent = await readFile(tmpCss, "utf-8");
742
- await unlink(tmpCss);
743
- try {
744
- const themeColors = getThemeConfig();
745
- if (themeColors) {
746
- cssContent = buildThemeCss(cssContent, themeColors);
747
- }
748
- } catch (err) {
749
- console.warn(
750
- `[flame] Failed to resolve theme config, falling back to globals.css only: ${err instanceof Error ? err.message : String(err)}`
751
- );
752
- }
753
- const cssFile = `client-${key}.css`;
754
- const outPath = join2(ASSETS_DIR, cssFile);
755
- if (!existsSync(outPath)) {
756
- await writeFile(outPath, cssContent);
757
- }
758
- return { file: cssFile, content: cssContent };
759
- }
760
- var NODE_BUILTINS_RE = new RegExp(
761
- `^(node:.*|${builtinModules.map((m) => m.replace(/\//g, "\\/")).join("|")})$`
762
- );
763
- var lucideRealEntry;
764
- function getLucideRealEntry() {
765
- if (!lucideRealEntry) {
766
- lucideRealEntry = createRequire(import.meta.url).resolve("lucide-react");
767
- }
768
- return lucideRealEntry;
769
- }
770
- var LUCIDE_IMPORT_RE = /import\s*\{([^}]+)\}\s*from\s*["']lucide-react["']/g;
771
- var LUCIDE_ICON_RE = /^[A-Z]/;
772
- function scanDirLucideIcons(dir, set) {
773
- if (!existsSync(dir)) return;
774
- try {
775
- const entries = readdirSync2(dir, { withFileTypes: true });
776
- for (const e of entries) {
777
- const full = join2(dir, e.name);
778
- if (e.isDirectory()) {
779
- if (e.name !== "node_modules") scanDirLucideIcons(full, set);
780
- } else if (/\.(js|ts|tsx)$/.test(e.name)) {
781
- const content = readFileSync(full, "utf-8");
782
- for (const m of content.matchAll(LUCIDE_IMPORT_RE)) {
783
- for (const s of m[1].split(",")) {
784
- const name = s.trim().split(/\s+as\s+/)[0].trim();
785
- if (LUCIDE_ICON_RE.test(name)) set.add(name);
786
- }
787
- }
788
- }
789
- }
790
- } catch (err) {
791
- console.warn(
792
- `[flame] Failed to scan lucide icons: ${err instanceof Error ? err.message : String(err)}`
793
- );
794
- }
795
- }
796
- function collectAllLucideIcons() {
797
- const icons = /* @__PURE__ */ new Set();
798
- scanDirLucideIcons(join2(FRAMEWORK_ROOT, ".docu/components"), icons);
799
- scanDirLucideIcons(join2(FRAMEWORK_ROOT, ".docu/pages"), icons);
800
- const depDirs = [
801
- join2(FRAMEWORK_ROOT, "..", "mdx-content", "dist"),
802
- join2(FRAMEWORK_ROOT, "..", "ui-react", "dist"),
803
- join2(FRAMEWORK_ROOT, "..", "core", "dist"),
804
- join2(FRAMEWORK_ROOT, "..", "themes-colors", "dist")
805
- ];
806
- for (const d of depDirs) scanDirLucideIcons(resolve2(d), icons);
807
- return [...icons];
808
- }
809
- async function buildClientBundle(mdxSources = {}) {
810
- await mkdir(ASSETS_DIR, { recursive: true });
811
- const twKey = tailwindCacheKey();
812
- await cleanOldBundles(/* @__PURE__ */ new Set([`client-${twKey}.css`]));
813
- const nodeEnv = process.env.NODE_ENV || "development";
814
- const esbuild = await import("esbuild");
815
- const { build } = esbuild;
816
- const entryPath = join2(LIB_DIR, "client.ts");
817
- const workingDir = process.cwd();
818
- let result;
819
- try {
820
- result = await build({
821
- entryPoints: [entryPath],
822
- bundle: true,
823
- outdir: ASSETS_DIR,
824
- entryNames: "client-[hash]",
825
- platform: "browser",
826
- format: "esm",
827
- minify: nodeEnv === "production",
828
- define: { "process.env.NODE_ENV": JSON.stringify(nodeEnv) },
829
- jsx: "automatic",
830
- jsxDev: nodeEnv !== "production",
831
- metafile: true,
832
- logLevel: "silent",
833
- plugins: [
834
- {
835
- name: "node-builtin-stub",
836
- setup(build2) {
837
- build2.onResolve({ filter: NODE_BUILTINS_RE }, (args) => ({
838
- path: args.path,
839
- namespace: "node-stub"
840
- }));
841
- build2.onLoad({ filter: /.*/, namespace: "node-stub" }, () => ({
842
- contents: "module.exports = {};",
843
- loader: "js"
844
- }));
845
- }
846
- },
847
- {
848
- name: "lucide-optimize",
849
- setup(build2) {
850
- build2.onResolve({ filter: /^lucide-react$/ }, (args) => {
851
- if (args.namespace === "lucide-virt") {
852
- return { path: getLucideRealEntry(), namespace: "file" };
853
- }
854
- if (args.importer) {
855
- const normalized = normalizeImporterPath(args.importer);
856
- if (normalized.includes("/markdown/dist/")) {
857
- return { path: getLucideRealEntry(), namespace: "file" };
858
- }
859
- }
860
- return { path: args.path, namespace: "lucide-virt" };
861
- });
862
- build2.onLoad({ filter: /.*/, namespace: "lucide-virt" }, () => {
863
- const scanned = collectAllLucideIcons();
864
- const configured = extractConfigIcons(loadDocuConfig());
865
- const allIcons = [.../* @__PURE__ */ new Set([...scanned, ...configured])];
866
- return {
867
- contents: `export { ${allIcons.join(", ")} } from "lucide-react";`,
868
- loader: "js"
869
- };
870
- });
871
- }
872
- },
873
- {
874
- name: "docu-config",
875
- setup(build2) {
876
- build2.onResolve({ filter: /client-routes$/ }, (args) => ({
877
- path: args.path,
878
- namespace: "client-routes"
879
- }));
880
- build2.onLoad({ filter: /.*/, namespace: "client-routes" }, () => {
881
- const config2 = loadDocuConfig();
882
- const resolved = {
883
- ...config2,
884
- routes: resolveRoutes(config2.routes)
885
- };
886
- return {
887
- contents: [
888
- `import type { DocuRoute, DocuConfig } from "./types";`,
889
- `const docuConfig = ${JSON.stringify(resolved)};`,
890
- `export const routes = docuConfig.routes || [];`,
891
- `export const config = docuConfig;`
892
- ].join("\n"),
893
- loader: "ts"
894
- };
895
- });
896
- }
897
- },
898
- {
899
- // Serves per-page compiled MDX (program format) as real modules so
900
- // the client hydrates the content island without `new Function`.
901
- // client.ts imports `{ mdxModules } from "./mdx-manifest"`.
902
- name: "mdx-hydrate",
903
- setup(build2) {
904
- const require2 = createRequire(import.meta.url);
905
- const mdxModuleDeps = {
906
- "react/jsx-runtime": require2.resolve("react/jsx-runtime"),
907
- "react/jsx-dev-runtime": require2.resolve("react/jsx-dev-runtime"),
908
- "@mdx-js/react": require2.resolve("@mdx-js/react")
909
- };
910
- build2.onResolve(
911
- { filter: /^(react\/jsx-runtime|react\/jsx-dev-runtime|@mdx-js\/react)$/ },
912
- (args) => {
913
- if (args.namespace !== "mdx-module") return;
914
- return { path: mdxModuleDeps[args.path], namespace: "file" };
915
- }
916
- );
917
- build2.onResolve({ filter: /^mdx-module:/ }, (args) => ({
918
- path: args.path,
919
- namespace: "mdx-module"
920
- }));
921
- build2.onLoad({ filter: /.*/, namespace: "mdx-module" }, (args) => {
922
- const slug = args.path.slice("mdx-module:".length);
923
- const contents = mdxSources[slug];
924
- if (contents == null) {
925
- return {
926
- errors: [{ text: `unknown mdx module: ${slug}` }],
927
- contents: "",
928
- loader: "js"
929
- };
930
- }
931
- return { contents, loader: "js" };
932
- });
933
- build2.onResolve({ filter: /mdx-manifest$/ }, (args) => ({
934
- path: args.path,
935
- namespace: "mdx-manifest"
936
- }));
937
- build2.onLoad({ filter: /.*/, namespace: "mdx-manifest" }, () => {
938
- const slugs = Object.keys(mdxSources).sort();
939
- const imports = slugs.map((slug, i) => {
940
- const key = slug.replace(/["\\]/g, "");
941
- return `import * as _mdx${i} from "mdx-module:${key}";`;
942
- }).join("\n");
943
- const map = slugs.map((slug, i) => `${JSON.stringify(slug)}: _mdx${i}`).join(", ");
944
- return {
945
- contents: `${imports}
946
- export const mdxModules = { ${map} };
947
- `,
948
- loader: "js"
949
- };
950
- });
951
- }
952
- }
953
- ]
954
- });
955
- } finally {
956
- await esbuild.stop();
957
- }
958
- const { outputs } = result.metafile;
959
- const jsOutput = Object.keys(outputs).find((p) => {
960
- const o = outputs[p];
961
- return o.entryPoint && resolve2(workingDir, o.entryPoint) === entryPath;
962
- });
963
- if (!jsOutput) {
964
- throw new Error("Client bundle produced no output files");
965
- }
966
- const jsFile = basename(jsOutput);
967
- const { file: cssFile } = await buildTailwindCss(twKey);
968
- await writeFile(join2(ASSETS_DIR, "manifest.json"), JSON.stringify({ js: jsFile, css: cssFile }));
969
- return { js: jsFile, css: cssFile };
970
- }
971
-
972
- // .docu/node/git.ts
973
- import { execFile as execFile2 } from "node:child_process";
974
- import { stat } from "node:fs/promises";
975
- function runGit(args) {
976
- return new Promise((resolve4, reject) => {
977
- execFile2("git", args, { maxBuffer: 16 * 1024 * 1024 }, (err, stdout) => {
978
- if (err) reject(err);
979
- else resolve4(stdout);
980
- });
981
- });
982
- }
983
- function sanitizePath(filePath) {
984
- const cleanPath = filePath.replace(/^\//, "");
985
- if (!cleanPath || !/^[a-zA-Z0-9\-_/.\s]+$/.test(cleanPath) || /(^|\/)\.\.($|\/)/.test(cleanPath))
986
- return null;
987
- return cleanPath;
988
- }
989
- async function getGitLastModified(filePath) {
990
- const cleanPath = sanitizePath(filePath);
991
- if (!cleanPath) return null;
992
- try {
993
- const text = await runGit(["log", "-1", "--format=%cI", "--", cleanPath]);
994
- const date = text.trim();
995
- return date || null;
996
- } catch {
997
- return null;
998
- }
999
- }
1000
- async function getFilesystemMtime(filePath) {
1001
- try {
1002
- const stats = await stat(filePath);
1003
- return stats.mtime.toISOString();
1004
- } catch {
1005
- return null;
1006
- }
1007
- }
1008
- async function getGitLastModifiedBatch(filePaths) {
1009
- const result = /* @__PURE__ */ new Map();
1010
- if (filePaths.length === 0) return result;
1011
- const safePaths = [];
1012
- for (const fp of filePaths) {
1013
- const cleanPath = sanitizePath(fp);
1014
- if (!cleanPath) {
1015
- console.warn(`[git] getGitLastModifiedBatch: skipping invalid path "${fp}"`);
1016
- continue;
1017
- }
1018
- safePaths.push(cleanPath);
1019
- }
1020
- if (safePaths.length === 0) return result;
1021
- try {
1022
- const text = await runGit([
1023
- "log",
1024
- "--format=%cI",
1025
- "--name-only",
1026
- "--diff-filter=ACMR",
1027
- ...safePaths
1028
- ]);
1029
- let currentDate = "";
1030
- for (const line of text.split("\n")) {
1031
- const trimmed = line.trim();
1032
- if (!trimmed) continue;
1033
- if (/^\d{4}-\d{2}-\d{2}T/.test(trimmed)) {
1034
- currentDate = trimmed;
1035
- } else if (currentDate && !result.has(trimmed)) {
1036
- result.set(trimmed, currentDate);
1037
- }
1038
- }
1039
- } catch (err) {
1040
- console.error("Failed to get git last modified batch for", filePaths, err);
1041
- }
1042
- return result;
1043
- }
1044
-
1045
- // .docu/node/mdx.ts
1046
- import React from "react";
1047
- import { z } from "zod";
1048
- import {
1049
- serialize,
1050
- extractTocsFromRawMdx,
1051
- extractFrontmatterWithContent,
1052
- createDefaultRehypePlugins,
1053
- createDefaultRemarkPlugins,
1054
- MDXRemote
1055
- } from "@docubook/core";
1056
- import { createMdxComponents } from "@docubook/markdown";
1057
- function appendHtml(value) {
1058
- if (typeof value !== "string") return null;
1059
- if (/^https?:\/\//.test(value)) return null;
1060
- if (!value.startsWith("/docs/")) return null;
1061
- if (value.includes("#")) return null;
1062
- if (value.endsWith(".html")) return null;
1063
- return `${value}.html`;
1064
- }
1065
- function rehypeDocsHtmlLinks() {
1066
- return (tree) => {
1067
- function walk(node) {
1068
- if (node.type === "element" && node.tagName === "a") {
1069
- const fixed = appendHtml(node.properties?.href);
1070
- if (fixed) node.properties.href = fixed;
1071
- }
1072
- if (node.children) {
1073
- for (const child of node.children) walk(child);
1074
- }
1075
- }
1076
- walk(tree);
1077
- return tree;
1078
- };
1079
- }
1080
- function remarkMdxJsxDocsHtmlLinks() {
1081
- return (tree) => {
1082
- function walk(node) {
1083
- if ((node.type === "mdxJsxFlowElement" || node.type === "mdxJsxTextElement") && node.attributes) {
1084
- for (const attr of node.attributes) {
1085
- if (attr.type === "mdxJsxAttribute" && attr.name === "href") {
1086
- const fixed = appendHtml(attr.value);
1087
- if (fixed) attr.value = fixed;
1088
- }
1089
- }
1090
- }
1091
- if (node.children) {
1092
- for (const child of node.children) walk(child);
1093
- }
1094
- }
1095
- walk(tree);
1096
- return tree;
1097
- };
1098
- }
1099
- var frontmatterSchema = z.object({
1100
- title: z.coerce.string().optional(),
1101
- description: z.coerce.string().optional(),
1102
- image: z.coerce.string().optional(),
1103
- date: z.coerce.string().optional()
1104
- }).passthrough();
1105
- function frontmatterField(frontmatter, key) {
1106
- return typeof frontmatter[key] === "string" ? frontmatter[key] : "";
1107
- }
1108
- async function serializeWithDocPlugins(rawMdx, opts = {}, pre) {
1109
- const { strippedContent, frontmatter } = pre ?? extractFrontmatterWithContent(rawMdx, opts.frontmatterSchema);
1110
- const defaultRemark = createDefaultRemarkPlugins();
1111
- const defaultRehype = createDefaultRehypePlugins();
1112
- const finalRemark = [...defaultRemark, remarkMdxJsxDocsHtmlLinks, ...opts.remarkPlugins ?? []];
1113
- const finalRehype = [...defaultRehype, rehypeDocsHtmlLinks, ...opts.rehypePlugins ?? []];
1114
- return serialize(strippedContent, {
1115
- outputFormat: opts.outputFormat,
1116
- format: "md",
1117
- mdxOptions: {
1118
- rehypePlugins: finalRehype,
1119
- remarkPlugins: finalRemark
1120
- }
1121
- }).then((serialized) => ({ ...serialized, frontmatter, strippedContent }));
1122
- }
1123
- async function compileMdx(rawMdx, filePath, gitDates, remarkPlugins, rehypePlugins, frontmatterSchema2, pre) {
1124
- const tocs = extractTocsFromRawMdx(rawMdx);
1125
- const frontmatter = pre?.frontmatter ?? extractFrontmatterWithContent(rawMdx, frontmatterSchema2).frontmatter;
1126
- const serialized = await serializeWithDocPlugins(
1127
- rawMdx,
1128
- { remarkPlugins, rehypePlugins, frontmatterSchema: frontmatterSchema2 },
1129
- pre
1130
- );
1131
- const components = createMdxComponents();
1132
- const content = React.createElement(MDXRemote, {
1133
- compiledSource: serialized.compiledSource,
1134
- scope: {},
1135
- frontmatter: {},
1136
- components
1137
- });
1138
- const date = frontmatter.date || gitDates?.get(filePath) || await getGitLastModified(filePath) || await getFilesystemMtime(filePath) || void 0;
1139
- return {
1140
- content,
1141
- compiledSource: serialized.compiledSource,
1142
- frontmatter: { ...frontmatter, date },
1143
- tocs
1144
- };
1145
- }
1146
- var pageFrontmatter = /* @__PURE__ */ new Map();
1147
- function registerPageFrontmatter(href, frontmatter) {
1148
- pageFrontmatter.set(href, frontmatter);
1149
- }
1150
- function getPageFrontmatter(href) {
1151
- return pageFrontmatter.get(href);
1152
- }
1153
- var pageStripped = /* @__PURE__ */ new Map();
1154
- function registerPageStripped(href, stripped) {
1155
- pageStripped.set(href, stripped);
1156
- }
1157
- function getPageStripped(href) {
1158
- return pageStripped.get(href);
1159
- }
1160
- var pageContent = /* @__PURE__ */ new Map();
1161
- function registerPageContent(href, raw) {
1162
- pageContent.set(href, raw);
1163
- }
1164
- function getPageContent(href) {
1165
- return pageContent.get(href);
1166
- }
1167
- async function compileMdxModule(rawMdx, remarkPlugins, rehypePlugins, href) {
1168
- const serialized = await serializeWithDocPlugins(rawMdx, {
1169
- outputFormat: "program",
1170
- remarkPlugins,
1171
- rehypePlugins
1172
- });
1173
- if (href) {
1174
- registerPageFrontmatter(href, serialized.frontmatter);
1175
- registerPageStripped(href, serialized.strippedContent);
1176
- }
1177
- return serialized.compiledSource;
1178
- }
1179
-
1180
- // .docu/node/search-indexer.ts
1181
- import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2 } from "node:fs/promises";
1182
- import { resolve as resolve3, join as join3 } from "node:path";
1183
- import { extractFrontmatterWithContent as extractFrontmatterWithContent2 } from "@docubook/core";
1184
- var docuConfig = loadDocuConfig();
1185
- function getSectionTitle(filePath) {
1186
- const parts = filePath.split("/");
1187
- if (parts.length > 1) {
1188
- const section = docuConfig.routes?.find(
1189
- (r) => r.href === `/${parts[0]}` || r.href === parts[0]
1190
- );
1191
- if (section) return section.title;
1192
- }
1193
- return docuConfig.meta?.title || "Docs";
1194
- }
1195
- function slugify(text) {
1196
- return text.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
1197
- }
1198
- function stripJsx(content) {
1199
- let result = content;
1200
- let prev = "";
1201
- while (result !== prev) {
1202
- prev = result;
1203
- result = result.replace(/<[A-Z][\w.]*[\s\S]*?\/>/g, "").replace(/<[A-Z][\w.]*[\s\S]*?>([\s\S]*?)<\/[A-Z][\w.]*>/g, "$1");
1204
- }
1205
- return result;
1206
- }
1207
- function extractRecords(filePath, raw) {
1208
- const { frontmatter, strippedContent: content } = extractFrontmatterWithContent2(raw);
1209
- const records = [];
1210
- const url = docsHtmlHref(`/docs/${filePath}`);
1211
- const lvl0 = getSectionTitle(filePath);
1212
- const lvl1 = frontmatterField(frontmatter, "title") || null;
1213
- const hierarchy = {
1214
- lvl0,
1215
- lvl1,
1216
- lvl2: null,
1217
- lvl3: null,
1218
- lvl4: null,
1219
- lvl5: null,
1220
- lvl6: null
1221
- };
1222
- if (lvl1) {
1223
- records.push({
1224
- url,
1225
- hierarchy: { ...hierarchy },
1226
- content: frontmatterField(frontmatter, "description") || null,
1227
- type: "lvl1"
1228
- });
1229
- }
1230
- const plainContent = stripJsx(content);
1231
- const lines = plainContent.split("\n");
1232
- let currentParagraph = [];
1233
- let inCodeBlock = false;
1234
- const flushParagraph = () => {
1235
- if (currentParagraph.length > 0) {
1236
- const text = currentParagraph.join(" ").trim();
1237
- if (text) {
1238
- records.push({
1239
- url: buildAnchorUrl(),
1240
- hierarchy: { ...hierarchy },
1241
- content: text,
1242
- type: "content"
1243
- });
1244
- }
1245
- currentParagraph = [];
1246
- }
1247
- };
1248
- const buildAnchorUrl = () => {
1249
- for (let i = 6; i >= 2; i--) {
1250
- const key = `lvl${i}`;
1251
- if (hierarchy[key]) return `${url}#${slugify(hierarchy[key])}`;
1252
- }
1253
- return url;
1254
- };
1255
- for (const line of lines) {
1256
- const trimmed = line.trim();
1257
- if (trimmed.startsWith("```")) {
1258
- inCodeBlock = !inCodeBlock;
1259
- continue;
1260
- }
1261
- if (inCodeBlock) continue;
1262
- if (/^import\s+[\w{*]/.test(trimmed) || /^export\s+[\w{*]/.test(trimmed)) continue;
1263
- const headingMatch = trimmed.match(/^(#{1,6})\s+(.+)$/);
1264
- if (headingMatch) {
1265
- flushParagraph();
1266
- const level = headingMatch[1].length;
1267
- const title = headingMatch[2].replace(/[*`[\]]/g, "").trim();
1268
- for (let i = level; i <= 6; i++) {
1269
- hierarchy[`lvl${i}`] = null;
1270
- }
1271
- hierarchy[`lvl${level}`] = title;
1272
- if (level === 1 && !hierarchy.lvl1) {
1273
- hierarchy.lvl1 = title;
1274
- }
1275
- if (level >= 2) {
1276
- records.push({
1277
- url: `${url}#${slugify(title)}`,
1278
- hierarchy: { ...hierarchy },
1279
- content: null,
1280
- type: `lvl${level}`
1281
- });
1282
- }
1283
- continue;
1284
- }
1285
- if (trimmed === "" || trimmed === "---") {
1286
- flushParagraph();
1287
- continue;
1288
- }
1289
- if (/^\|.+\|/.test(trimmed)) continue;
1290
- const cleaned = trimmed.replace(/^[-*+]\s+/, "").replace(/^\d+\.\s+/, "").replace(/^>\s+/, "").replace(/\*\*([^*]+)\*\*/g, "$1").replace(/\*([^*]+)\*/g, "$1").replace(/`([^`]+)`/g, "$1").replace(/\[([^\]]+)\]\([^)]+\)/g, "$1").trim();
1291
- if (cleaned) currentParagraph.push(cleaned);
1292
- }
1293
- flushParagraph();
1294
- return records;
1295
- }
1296
- async function generateSearchIndex(docsDir, outputDir) {
1297
- const docs = resolve3(docsDir || DOCS_DIR);
1298
- const dist = resolve3(outputDir || ASSETS_DIR);
1299
- await mkdir2(dist, { recursive: true });
1300
- const mdxFiles = await scanMdxFiles(docs);
1301
- const results = await Promise.all(
1302
- mdxFiles.map(async (file) => {
1303
- const raw = getPageContent(`/${file.path}`) ?? await readFile2(file.absPath, "utf-8");
1304
- return extractRecords(file.path, raw);
1305
- })
1306
- );
1307
- const allRecords = results.flat();
1308
- await writeFile2(join3(dist, "search-index.json"), JSON.stringify(allRecords));
1309
- return allRecords.length;
1310
- }
1311
-
1312
- // .docu/node/sentry.ts
1313
- var sentry = null;
1314
- var initialized = false;
1315
- async function initSentry() {
1316
- const dsn = process.env.SENTRY_DSN;
1317
- if (!dsn) return;
1318
- try {
1319
- sentry = await import("@sentry/bun");
1320
- sentry.init({
1321
- dsn,
1322
- environment: process.env.NODE_ENV || "development",
1323
- release: process.env.SENTRY_RELEASE || void 0
1324
- });
1325
- initialized = true;
1326
- } catch {
1327
- sentry = null;
1328
- initialized = false;
1329
- }
1330
- }
1331
- function captureException(err, context) {
1332
- if (!initialized || !sentry) return;
1333
- sentry.captureException(err, context ? { extra: context } : void 0);
1334
- }
1335
-
1336
- // .docu/pages/docs/[[...slug]].tsx
1337
- import { ChevronLeft, ChevronRight } from "lucide-react";
1338
-
1339
- // .docu/components/Breadcrumb.tsx
1340
- import {
1341
- Breadcrumb,
1342
- BreadcrumbItem,
1343
- BreadcrumbList,
1344
- BreadcrumbPage
1345
- } from "@docubook/ui-react/breadcrumbs";
1346
- import { jsx, jsxs } from "react/jsx-runtime";
1347
- function toTitleCase2(input) {
1348
- return input.split("-").map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
1349
- }
1350
- function DocsBreadcrumb({ paths }) {
1351
- return /* @__PURE__ */ jsx(Breadcrumb, { className: "py-4", children: /* @__PURE__ */ jsxs(BreadcrumbList, { children: [
1352
- /* @__PURE__ */ jsx(BreadcrumbItem, { children: /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: "Docs" }) }),
1353
- paths.map((path, index) => /* @__PURE__ */ jsx(BreadcrumbItem, { children: index < paths.length - 1 ? /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: toTitleCase2(path) }) : /* @__PURE__ */ jsx(BreadcrumbPage, { className: "text-base-content", children: toTitleCase2(path) }) }, `${path}-${index}`))
1354
- ] }) });
1355
- }
1356
-
1357
- // .docu/node/route.ts
1358
- import { readFileSync as readFileSync2 } from "node:fs";
1359
- import { join as join4 } from "node:path";
1360
- import { extractFrontmatter } from "@docubook/core";
1361
- var docuConfig2 = loadDocuConfig();
1362
- var routes = resolveRoutes(docuConfig2.routes);
1363
- function flattenRoutes() {
1364
- const paths = [];
1365
- function traverse(route, section = "") {
1366
- const fullPath = route.href.startsWith(section) ? route.href : `${section}${route.href}`.replace(/\/+/g, "/");
1367
- if (route.href && !route.noLink) {
1368
- paths.push(fullPath);
1369
- }
1370
- if (route.items) {
1371
- route.items.forEach((item) => traverse(item, fullPath));
1372
- }
1373
- }
1374
- routes.forEach((route) => traverse(route));
1375
- return paths;
1376
- }
1377
- function getRouteMap() {
1378
- const map = /* @__PURE__ */ new Map();
1379
- function traverse(route, section = "") {
1380
- const fullPath = route.href.startsWith(section) ? route.href : `${section}${route.href}`.replace(/\/+/g, "/");
1381
- map.set(fullPath, route.title);
1382
- if (route.items) {
1383
- route.items.forEach((item) => traverse(item, fullPath));
1384
- }
1385
- }
1386
- routes.forEach((route) => traverse(route));
1387
- return map;
1388
- }
1389
- function readPageFrontmatter(href) {
1390
- const registered = getPageFrontmatter(href);
1391
- if (registered) return registered;
1392
- let fm = {};
1393
- const rel = href.replace(/^\/|$/g, "");
1394
- for (const ext of [".mdx", ".md"]) {
1395
- for (const file of [join4(DOCS_DIR, `${rel}${ext}`), join4(DOCS_DIR, `${rel}/index${ext}`)]) {
1396
- try {
1397
- fm = extractFrontmatter(readFileSync2(file, "utf-8"));
1398
- break;
1399
- } catch {
1400
- }
1401
- }
1402
- if (Object.keys(fm).length) break;
1403
- }
1404
- registerPageFrontmatter(href, fm);
1405
- return fm;
1406
- }
1407
- function getPreviousNext(pathname) {
1408
- const normalizedPath = pathname.replace(/^\/|$/g, "");
1409
- if (normalizedPath === "docs" || normalizedPath === "") {
1410
- const paths2 = flattenRoutes();
1411
- const routeMap2 = getRouteMap();
1412
- const first = paths2[0];
1413
- if (!first) return { prev: null, next: null };
1414
- const fm = readPageFrontmatter(first);
1415
- return {
1416
- prev: null,
1417
- next: {
1418
- href: first,
1419
- title: fm.title || routeMap2.get(first) || "",
1420
- description: fm.description || ""
1421
- }
1422
- };
1423
- }
1424
- const paths = flattenRoutes();
1425
- const index = paths.findIndex((href) => href === `/${normalizedPath}` || href === normalizedPath);
1426
- if (index === -1) {
1427
- return { prev: null, next: null };
1428
- }
1429
- const routeMap = getRouteMap();
1430
- const prevHref = index > 0 ? paths[index - 1] : null;
1431
- const nextHref = index < paths.length - 1 ? paths[index + 1] : null;
1432
- const prevFm = prevHref ? readPageFrontmatter(prevHref) : null;
1433
- const nextFm = nextHref ? readPageFrontmatter(nextHref) : null;
1434
- return {
1435
- prev: prevHref ? { href: prevHref, title: prevFm?.title || routeMap.get(prevHref) || "" } : null,
1436
- next: nextHref ? {
1437
- href: nextHref,
1438
- title: nextFm?.title || routeMap.get(nextHref) || "",
1439
- description: nextFm?.description || ""
1440
- } : null
1441
- };
1442
- }
1443
-
1444
- // .docu/components/Pagination.tsx
1445
- import { PaginationDocs } from "@docubook/ui-react/pagination";
1446
- import { jsx as jsx2 } from "react/jsx-runtime";
1447
- function Pagination({
1448
- pathname,
1449
- className,
1450
- prevIcon,
1451
- nextIcon,
1452
- linkClassName
1453
- }) {
1454
- const { prev, next } = getPreviousNext(pathname);
1455
- if (!prev && !next) {
1456
- return null;
1457
- }
1458
- return /* @__PURE__ */ jsx2(
1459
- PaginationDocs,
1460
- {
1461
- prev: prev ? { href: docsHtmlHref(`/docs${prev.href}`), title: prev.title } : void 0,
1462
- next: next ? {
1463
- href: docsHtmlHref(`/docs${next.href}`),
1464
- title: next.title,
1465
- description: next.description
1466
- } : void 0,
1467
- className,
1468
- prevIcon,
1469
- nextIcon,
1470
- linkClassName
1471
- }
1472
- );
1473
- }
1474
-
1475
- // .docu/components/Typography.tsx
1476
- import { jsx as jsx3 } from "react/jsx-runtime";
1477
- function Typography({ children }) {
1478
- return /* @__PURE__ */ jsx3("div", { className: "prose prose-zinc dark:prose-invert prose-code:font-code dark:prose-code:bg-stone-900/25 prose-code:bg-stone-50 prose-pre:bg-background max-lg:prose-headings:scroll-mt-16 prose-headings:scroll-mt-4 prose-code:text-sm prose-code:leading-6 dark:prose-code:text-white prose-code:text-stone-800 prose-code:p-1 prose-code:rounded-md prose-code:border prose-img:rounded-md prose-img:border prose-code:before:content-none prose-code:after:content-none prose-code:px-1.5 prose-code:overflow-x-auto prose-img:my-3 prose-h2:my-4 prose-h2:mt-8 w-full max-w-full! pt-2", children });
1479
- }
1480
-
1481
- // .docu/components/EditWith.tsx
1482
- import { SquarePen } from "lucide-react";
1483
-
1484
- // .docu/node/helpers.ts
1485
- var docuConfig3 = loadDocuConfig();
1486
- function getEditLink(url, filePath) {
1487
- const configPath = docuConfig3?.repo?.path || detectPlatformPath(url);
1488
- const encodedPath = filePath.replace(/^\//, "").split("/").map(encodeURIComponent).join("/");
1489
- return `${url}/${configPath}`.replace("{filePath}", encodedPath);
1490
- }
1491
- function detectPlatformPath(url) {
1492
- try {
1493
- const host = new URL(url).hostname;
1494
- if (host === "github.com") return "blob/main/{filePath}";
1495
- if (host === "gitlab.com") return "-/blob/main/{filePath}";
1496
- if (host === "bitbucket.org") return "src/main/{filePath}";
1497
- if (host === "gitea.com") return "src/branch/main/{filePath}";
1498
- if (host === "codeberg.org") return "src/branch/main/{filePath}";
1499
- return "src/branch/main/{filePath}";
1500
- } catch {
1501
- return "blob/main/{filePath}";
1502
- }
1503
- }
1504
- function isEditEnabled() {
1505
- return docuConfig3?.repo?.edit ?? false;
1506
- }
1507
- function getRepoUrl() {
1508
- return docuConfig3?.repo?.url || "";
1509
- }
1510
- function getSocialLinks() {
1511
- return docuConfig3?.footer?.social || [];
1512
- }
1513
-
1514
- // .docu/components/EditWith.tsx
1515
- import { jsx as jsx4, jsxs as jsxs2 } from "react/jsx-runtime";
1516
- function EditWith({
1517
- filePath,
1518
- text = "Edit this page",
1519
- className = ""
1520
- }) {
1521
- if (!isEditEnabled()) return null;
1522
- const repoUrl = getRepoUrl();
1523
- if (!repoUrl) return null;
1524
- const editUrl = getEditLink(repoUrl, filePath);
1525
- return /* @__PURE__ */ jsx4("div", { className: `text-right text-sm ${className}`, children: /* @__PURE__ */ jsxs2(
1526
- "a",
1527
- {
1528
- href: editUrl,
1529
- target: "_blank",
1530
- rel: "noopener noreferrer",
1531
- "aria-label": "Edit this page",
1532
- className: "flex items-center gap-1 no-underline",
1533
- children: [
1534
- /* @__PURE__ */ jsx4(SquarePen, { className: "h-4 w-4" }),
1535
- text
1536
- ]
1537
- }
1538
- ) });
1539
- }
1540
-
1541
- // .docu/components/Social.tsx
1542
- import { jsx as jsx5 } from "react/jsx-runtime";
1543
- function createIcon(pathData) {
1544
- return function Icon({ className = "", size = 20 }) {
1545
- return /* @__PURE__ */ jsx5(
1546
- "svg",
1547
- {
1548
- className,
1549
- width: size,
1550
- height: size,
1551
- viewBox: "0 0 24 24",
1552
- xmlns: "http://www.w3.org/2000/svg",
1553
- fill: "currentColor",
1554
- children: /* @__PURE__ */ jsx5("path", { d: pathData })
1555
- }
1556
- );
1557
- };
1558
- }
1559
- var GithubIcon = createIcon(
1560
- "M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"
1561
- );
1562
- var BitbucketIcon = createIcon(
1563
- "M.778 1.213a.768.768 0 00-.768.892l3.263 19.81c.084.5.515.868 1.022.873H19.95a.772.772 0 00.77-.646l3.27-20.03a.768.768 0 00-.768-.891zM14.52 15.53H9.522L8.17 8.466h7.561z"
1564
- );
1565
- var GitlabIcon = createIcon(
1566
- "m23.6004 9.5927-.0337-.0862L20.3.9814a.851.851 0 0 0-.3362-.405.8748.8748 0 0 0-.9997.0539.8748.8748 0 0 0-.29.4399l-2.2055 6.748H7.5375l-2.2057-6.748a.8573.8573 0 0 0-.29-.4412.8748.8748 0 0 0-.9997-.0537.8585.8585 0 0 0-.3362.4049L.4332 9.5015l-.0325.0862a6.0657 6.0657 0 0 0 2.0119 7.0105l.0113.0087.03.0213 4.976 3.7264 2.462 1.8633 1.4995 1.1321a1.0085 1.0085 0 0 0 1.2197 0l1.4995-1.1321 2.4619-1.8633 5.006-3.7489.0125-.01a6.0682 6.0682 0 0 0 2.0094-7.003z"
1567
- );
1568
- var NpmIcon = createIcon(
1569
- "M1.763 0C.786 0 0 .786 0 1.763v20.474C0 23.214.786 24 1.763 24h20.474c.977 0 1.763-.786 1.763-1.763V1.763C24 .786 23.214 0 22.237 0zM5.13 5.323l13.837.019-.009 13.836h-3.464l.01-10.382h-3.456L12.04 19.17H5.113z"
1570
- );
1571
- var YoutubeIcon = createIcon(
1572
- "M23.498 6.186a3.016 3.016 0 0 0-2.122-2.136C19.505 3.545 12 3.545 12 3.545s-7.505 0-9.377.505A3.017 3.017 0 0 0 .502 6.186C0 8.07 0 12 0 12s0 3.93.502 5.814a3.016 3.016 0 0 0 2.122 2.136c1.871.505 9.376.505 9.376.505s7.505 0 9.377-.505a3.015 3.015 0 0 0 2.122-2.136C24 15.93 24 12 24 12s0-3.93-.502-5.814zM9.545 15.568V8.432L15.818 12l-6.273 3.568z"
1573
- );
1574
- var TwitterIcon = createIcon(
1575
- "M14.234 10.162 22.977 0h-2.072l-7.591 8.824L7.251 0H.258l9.168 13.343L.258 24H2.33l8.016-9.318L16.749 24h6.993zm-2.837 3.299-.929-1.329L3.076 1.56h3.182l5.965 8.532.929 1.329 7.754 11.09h-3.182z"
1576
- );
1577
- var InstagramIcon = createIcon(
1578
- "M7.0301.084c-1.2768.0602-2.1487.264-2.911.5634-.7888.3075-1.4575.72-2.1228 1.3877-.6652.6677-1.075 1.3368-1.3802 2.127-.2954.7638-.4956 1.6365-.552 2.914-.0564 1.2775-.0689 1.6882-.0626 4.947.0062 3.2586.0206 3.6671.0825 4.9473.061 1.2765.264 2.1482.5635 2.9107.308.7889.72 1.4573 1.388 2.1228.6679.6655 1.3365 1.0743 2.1285 1.38.7632.295 1.6361.4961 2.9134.552 1.2773.056 1.6884.069 4.9462.0627 3.2578-.0062 3.668-.0207 4.9478-.0814 1.28-.0607 2.147-.2652 2.9098-.5633.7889-.3086 1.4578-.72 2.1228-1.3881.665-.6682 1.0745-1.3378 1.3795-2.1284.2957-.7632.4966-1.636.552-2.9124.056-1.2809.0692-1.6898.063-4.948-.0063-3.2583-.021-3.6668-.0817-4.9465-.0607-1.2797-.264-2.1487-.5633-2.9117-.3084-.7889-.72-1.4568-1.3876-2.1228C21.2982 1.33 20.628.9208 19.8378.6165 19.074.321 18.2017.1197 16.9244.0645 15.6471.0093 15.236-.005 11.977.0014 8.718.0076 8.31.0215 7.0301.0839m.1402 21.6932c-1.17-.0509-1.8053-.2453-2.2287-.408-.5606-.216-.96-.4771-1.3819-.895-.422-.4178-.6811-.8186-.9-1.378-.1644-.4234-.3624-1.058-.4171-2.228-.0595-1.2645-.072-1.6442-.079-4.848-.007-3.2037.0053-3.583.0607-4.848.05-1.169.2456-1.805.408-2.2282.216-.5613.4762-.96.895-1.3816.4188-.4217.8184-.6814 1.3783-.9003.423-.1651 1.0575-.3614 2.227-.4171 1.2655-.06 1.6447-.072 4.848-.079 3.2033-.007 3.5835.005 4.8495.0608 1.169.0508 1.8053.2445 2.228.408.5608.216.96.4754 1.3816.895.4217.4194.6816.8176.9005 1.3787.1653.4217.3617 1.056.4169 2.2263.0602 1.2655.0739 1.645.0796 4.848.0058 3.203-.0055 3.5834-.061 4.848-.051 1.17-.245 1.8055-.408 2.2294-.216.5604-.4763.96-.8954 1.3814-.419.4215-.8181.6811-1.3783.9-.4224.1649-1.0577.3617-2.2262.4174-1.2656.0595-1.6448.072-4.8493.079-3.2045.007-3.5825-.006-4.848-.0608M16.953 5.5864A1.44 1.44 0 1 0 18.39 4.144a1.44 1.44 0 0 0-1.437 1.4424M5.8385 12.012c.0067 3.4032 2.7706 6.1557 6.173 6.1493 3.4026-.0065 6.157-2.7701 6.1506-6.1733-.0065-3.4032-2.771-6.1565-6.174-6.1498-3.403.0067-6.156 2.771-6.1496 6.1738M8 12.0077a4 4 0 1 1 4.008 3.9921A3.9996 3.9996 0 0 1 8 12.0077"
1579
- );
1580
- var LinkedinIcon = createIcon(
1581
- "M20.447 20.452h-3.554v-5.569c0-1.328-.027-3.037-1.852-3.037-1.853 0-2.136 1.445-2.136 2.939v5.667H9.351V9h3.414v1.561h.046c.477-.9 1.637-1.85 3.37-1.85 3.601 0 4.267 2.37 4.267 5.455v6.528zM5.337 7.433c-1.144 0-2.063-.926-2.063-2.065 0-1.138.92-2.063 2.063-2.063 1.14 0 2.064.925 2.064 2.063 0 1.139-.925 2.065-2.064 2.065zm1.782 13.019H3.555V9h3.564v11.452zM22.225 0H1.771C.792 0 0 .774 0 1.729v20.542C0 23.226.792 24 1.771 24h20.451C23.2 24 24 23.226 24 22.271V1.729C24 .774 23.2 0 22.222 0h.003z"
1582
- );
1583
- var FacebookIcon = createIcon(
1584
- "M9.101 23.691v-7.98H6.627v-3.667h2.474v-1.58c0-4.085 1.848-5.978 5.858-5.978.401 0 .955.042 1.468.103a8.68 8.68 0 0 1 1.141.195v3.325a8.623 8.623 0 0 0-.653-.036 26.805 26.805 0 0 0-.733-.009c-.707 0-1.259.096-1.675.309a1.686 1.686 0 0 0-.679.622c-.258.42-.374.995-.374 1.752v1.297h3.919l-.386 2.103-.287 1.564h-3.246v8.245C19.396 23.238 24 18.179 24 12.044c0-6.627-5.373-12-12-12s-12 5.373-12 12c0 5.628 3.874 10.35 9.101 11.647Z"
1585
- );
1586
- var TelegramIcon = createIcon(
1587
- "M11.944 0A12 12 0 0 0 0 12a12 12 0 0 0 12 12 12 12 0 0 0 12-12A12 12 0 0 0 12 0a12 12 0 0 0-.056 0zm4.962 7.224c.1-.002.321.023.465.14a.506.506 0 0 1 .171.325c.016.093.036.306.02.472-.18 1.898-.962 6.502-1.36 8.627-.168.9-.499 1.201-.82 1.23-.696.065-1.225-.46-1.9-.902-1.056-.693-1.653-1.124-2.678-1.8-1.185-.78-.417-1.21.258-1.91.177-.184 3.247-2.977 3.307-3.23.007-.032.014-.15-.056-.212s-.174-.041-.249-.024c-.106.024-1.793 1.14-5.061 3.345-.48.33-.913.49-1.302.48-.428-.008-1.252-.241-1.865-.44-.752-.245-1.349-.374-1.297-.789.027-.216.325-.437.893-.663 3.498-1.524 5.83-2.529 6.998-3.014 3.332-1.386 4.025-1.627 4.476-1.635z"
1588
- );
1589
- var DiscordIcon = createIcon(
1590
- "M20.317 4.3698a19.7913 19.7913 0 00-4.8851-1.5152.0741.0741 0 00-.0785.0371c-.211.3753-.4447.8648-.6083 1.2495-1.8447-.2762-3.68-.2762-5.4868 0-.1636-.3933-.4058-.8742-.6177-1.2495a.077.077 0 00-.0785-.037 19.7363 0 00-4.8852 1.515.0699.0699 0 00-.0321.0277C.5334 9.0458-.319 13.5799.0992 18.0578a.0824.0824 0 00.0312.0561c2.0528 1.5076 4.0413 2.4228 5.9929 3.0294a.0777.0777 0 00.0842-.0276c.4616-.6304.8731-1.2952 1.226-1.9942a.076.076 0 00-.0416-.1057c-.6528-.2476-1.2743-.5495-1.8722-.8923a.077.077 0 01-.0076-.1277c.1258-.0943.2517-.1923.3718-.2914a.0743.0743 0 01.0776-.0105c3.9278 1.7933 8.18 1.7933 12.0614 0a.0739.0739 0 01.0785.0095c.1202.099.246.1981.3728.2924a.077.077 0 01-.0066.1276 12.2986 12.2986 0 01-1.873.8914.0766.0766 0 00-.0407.1067c.3604.698.7719 1.3628 1.225 1.9932a.076.076 0 00.0842.0286c1.961-.6067 3.9495-1.5219 6.0023-3.0294a.077.077 0 00.0313-.0552c.5004-5.177-.8382-9.6739-3.5485-13.6604a.061.061 0 00-.0312-.0286zM8.02 15.3312c-1.1825 0-2.1569-1.0857-2.1569-2.419 0-1.3332.9555-2.4189 2.157-2.4189 1.2108 0 2.1757 1.0952 2.1568 2.419 0 1.3332-.9555 2.4189-2.1569 2.4189zm7.9748 0c-1.1825 0-2.1569-1.0857-2.1569-2.419 0-1.3332.9554-2.4189 2.1569-2.4189 1.2108 0 2.1757 1.0952 2.1568 2.419 0 1.3332-.946 2.4189-2.1568 2.4189Z"
1591
- );
1592
- var ThreadsIcon = createIcon(
1593
- "M12.186 24h-.007c-3.581-.024-6.334-1.205-8.184-3.509C2.35 18.44 1.5 15.586 1.472 12.01v-.017c.03-3.579.879-6.43 2.525-8.482C5.845 1.205 8.6.024 12.18 0h.014c2.746.02 5.043.725 6.826 2.098 1.677 1.29 2.858 3.13 3.509 5.467l-2.04.569c-1.104-3.96-3.898-5.984-8.304-6.015-2.91.022-5.11.936-6.54 2.717C4.307 6.504 3.616 8.914 3.589 12c.027 3.086.718 5.496 2.057 7.164 1.43 1.783 3.631 2.698 6.54 2.717 2.623-.02 4.358-.631 5.8-2.045 1.647-1.613 1.618-3.593 1.09-4.798-.31-.71-.873-1.3-1.634-1.75-.192 1.352-.622 2.446-1.284 3.272-.886 1.102-2.14 1.704-3.73 1.79-1.202.065-2.361-.218-3.259-.801-1.063-.689-1.685-1.74-1.752-2.964-.065-1.19.408-2.285 1.33-3.082.88-.76 2.119-1.207 3.583-1.291a13.853 13.853 0 0 1 3.02.142c-.126-.742-.375-1.332-.75-1.757-.513-.586-1.308-.883-2.359-.89h-.029c-.844 0-1.992.232-2.721 1.32L7.734 7.847c.98-1.454 2.568-2.256 4.478-2.256h.044c3.194.02 5.097 1.975 5.287 5.388.108.046.216.094.321.142 1.49.7 2.58 1.761 3.154 3.07.797 1.82.871 4.79-1.548 7.158-1.85 1.81-4.094 2.628-7.277 2.65Zm1.003-11.69c-.242 0-.487.007-.739.021-1.836.103-2.98.946-2.916 2.143.067 1.256 1.452 1.839 2.784 1.767 1.224-.065 2.818-.543 3.086-3.71a10.5 10.5 0 0 0-2.215-.221z"
1594
- );
1595
- var MastodonIcon = createIcon(
1596
- "M23.268 5.313c-.35-2.578-2.617-4.61-5.304-5.004C17.51.242 15.792 0 11.813 0h-.03c-3.98 0-4.835.242-5.288.309C3.882.692 1.496 2.518.917 5.127.64 6.412.61 7.837.661 9.143c.074 1.874.088 3.745.26 5.611.118 1.24.325 2.47.62 3.68.55 2.237 2.777 4.098 4.96 4.857 2.336.792 4.849.923 7.256.38.265-.061.527-.132.786-.213.585-.184 1.27-.39 1.774-.753a.057.057 0 0 0 .023-.043v-1.809a.052.052 0 0 0-.02-.041.053.053 0 0 0-.046-.01 20.282 20.282 0 0 1-4.709.545c-2.73 0-3.463-1.284-3.674-1.818a5.593 5.593 0 0 1-.319-1.433.053.053 0 0 1 .066-.054c1.517.363 3.072.546 4.632.546.376 0 .75 0 1.125-.01 1.57-.044 3.224-.124 4.768-.422.038-.008.077-.015.11-.024 2.435-.464 4.753-1.92 4.989-5.604.008-.145.03-1.52.03-1.67.002-.512.167-3.63-.024-5.545zm-3.748 9.195h-2.561V8.29c0-1.309-.55-1.976-1.67-1.976-1.23 0-1.846.79-1.846 2.35v3.403h-2.546V8.663c0-1.56-.617-2.35-1.848-2.35-1.112 0-1.668.668-1.67 1.977v6.218H4.822V8.102c0-1.31.337-2.35 1.011-3.12.696-.77 1.608-1.164 2.74-1.164 1.311 0 2.302.5 2.962 1.498l.638 1.06.638-1.06c.66-.999 1.65-1.498 2.96-1.498 1.13 0 2.043.395 2.74 1.164.675.77 1.012 1.81 1.012 3.12z"
1597
- );
1598
- var iconMap = {
1599
- github: GithubIcon,
1600
- gitlab: GitlabIcon,
1601
- bitbucket: BitbucketIcon,
1602
- npm: NpmIcon,
1603
- youtube: YoutubeIcon,
1604
- twitter: TwitterIcon,
1605
- x: TwitterIcon,
1606
- instagram: InstagramIcon,
1607
- linkedin: LinkedinIcon,
1608
- facebook: FacebookIcon,
1609
- telegram: TelegramIcon,
1610
- discord: DiscordIcon,
1611
- threads: ThreadsIcon,
1612
- mastodon: MastodonIcon
1613
- };
1614
- function getSocialIcon(name) {
1615
- const key = name.toLowerCase().replace(/\s+/g, "");
1616
- return iconMap[key] || null;
1617
- }
1618
- function Social({ className = "", size = 16 }) {
1619
- const socialLinks = getSocialLinks();
1620
- if (!socialLinks?.length) return null;
1621
- return /* @__PURE__ */ jsx5("div", { className: `flex gap-1 ${className}`, children: socialLinks.map((link) => {
1622
- const Icon = getSocialIcon(link.name);
1623
- return /* @__PURE__ */ jsx5(
1624
- "a",
1625
- {
1626
- href: link.url,
1627
- target: "_blank",
1628
- rel: "noopener noreferrer",
1629
- "aria-label": link.name,
1630
- className: "btn-xs btn-circle btn-ghost text-muted-foreground",
1631
- children: Icon && /* @__PURE__ */ jsx5(Icon, { size })
1632
- },
1633
- link.name
1634
- );
1635
- }) });
1636
- }
1637
-
1638
- // .docu/components/Footer.tsx
1639
- import { jsx as jsx6, jsxs as jsxs3 } from "react/jsx-runtime";
1640
- function Footer() {
1641
- return /* @__PURE__ */ jsxs3("footer", { className: "text-muted-foreground mt-auto flex w-full flex-col items-start gap-4 py-6 sm:flex-row sm:items-center sm:justify-between", children: [
1642
- /* @__PURE__ */ jsx6(Social, {}),
1643
- /* @__PURE__ */ jsx6("aside", { className: "sm:ml-auto", children: /* @__PURE__ */ jsxs3("p", { className: "text-xs", children: [
1644
- "Made with",
1645
- " ",
1646
- /* @__PURE__ */ jsx6(
1647
- "a",
1648
- {
1649
- href: "https://docubook.pro",
1650
- target: "_blank",
1651
- rel: "noopener noreferrer",
1652
- className: "link link-hover text-muted-foreground font-medium",
1653
- children: "DocuBook"
1654
- }
1655
- )
1656
- ] }) })
1657
- ] });
1658
- }
1659
-
1660
- // .docu/components/Toc.tsx
1661
- import { useState as useState2, useCallback as useCallback2, useEffect as useEffect2, useRef } from "react";
1662
- import { ListIcon } from "lucide-react";
1663
-
1664
- // .docu/components/ScrollTo.tsx
1665
- import { ArrowUpIcon } from "lucide-react";
1666
- import { useEffect, useState, useCallback } from "react";
1667
- import { jsx as jsx7, jsxs as jsxs4 } from "react/jsx-runtime";
1668
- function ScrollTo({ className, showIcon = true }) {
1669
- const [isVisible, setIsVisible] = useState(false);
1670
- const checkScroll = useCallback(() => {
1671
- const container = document.getElementById("scroll-container");
1672
- const scrollY = container ? container.scrollTop : window.scrollY;
1673
- const scrollHeight = container ? container.scrollHeight : document.documentElement.scrollHeight;
1674
- const threshold = scrollHeight * 0.3;
1675
- const shouldShow = scrollY > threshold;
1676
- if (shouldShow !== isVisible) {
1677
- setIsVisible(shouldShow);
1678
- }
1679
- }, [isVisible]);
1680
- useEffect(() => {
1681
- let timeoutId;
1682
- const handleScroll = () => {
1683
- if (timeoutId) clearTimeout(timeoutId);
1684
- timeoutId = setTimeout(checkScroll, 100);
1685
- };
1686
- const container = document.getElementById("scroll-container") || window;
1687
- container.addEventListener("scroll", handleScroll, { passive: true });
1688
- return () => {
1689
- container.removeEventListener("scroll", handleScroll);
1690
- if (timeoutId) clearTimeout(timeoutId);
1691
- };
1692
- }, [checkScroll]);
1693
- const scrollToTop = useCallback((e) => {
1694
- e.preventDefault();
1695
- const container = document.getElementById("scroll-container");
1696
- if (container) {
1697
- container.scrollTo({ top: 0, behavior: "smooth" });
1698
- } else {
1699
- window.scrollTo({ top: 0, behavior: "smooth" });
1700
- }
1701
- }, []);
1702
- return /* @__PURE__ */ jsx7(
1703
- "div",
1704
- {
1705
- className: cn(
1706
- "border-base-300 mt-4 border-t pt-4",
1707
- "transition-opacity duration-300",
1708
- isVisible ? "opacity-100" : "pointer-events-none opacity-0",
1709
- className
1710
- ),
1711
- children: /* @__PURE__ */ jsxs4(
1712
- "a",
1713
- {
1714
- href: "#",
1715
- onClick: scrollToTop,
1716
- className: cn(
1717
- "inline-flex items-center text-sm",
1718
- "link link-hover text-base-content/60 hover:text-base-content",
1719
- "transition-all duration-200 hover:translate-y-px"
1720
- ),
1721
- "aria-label": "Scroll to top",
1722
- children: [
1723
- showIcon && /* @__PURE__ */ jsx7(ArrowUpIcon, { className: "mr-1 h-3.5 w-3.5 shrink-0" }),
1724
- /* @__PURE__ */ jsx7("span", { children: "Scroll to Top" })
1725
- ]
1726
- }
1727
- )
1728
- }
1729
- );
1730
- }
1731
-
1732
- // .docu/components/Toc.tsx
1733
- import { jsx as jsx8, jsxs as jsxs5 } from "react/jsx-runtime";
1734
- function Toc({ tocs }) {
1735
- const [activeId, setActiveId] = useState2(null);
1736
- const clickedIdRef = useRef(null);
1737
- const clickTimerRef = useRef(null);
1738
- const activeIdRef = useRef(null);
1739
- useEffect2(() => {
1740
- activeIdRef.current = activeId;
1741
- }, [activeId]);
1742
- const getAnchorOffset = useCallback2(() => {
1743
- if (typeof window === "undefined") return 100;
1744
- const first = tocs[0] ? document.getElementById(tocs[0].href.slice(1)) : null;
1745
- const margin = first ? parseFloat(getComputedStyle(first).scrollMarginTop) : 0;
1746
- return margin || 100;
1747
- }, [tocs]);
1748
- useEffect2(() => {
1749
- if (typeof window === "undefined" || window.innerWidth < 1024) return;
1750
- if (!tocs.length) return;
1751
- const isDesktop = window.innerWidth >= 1024;
1752
- const container = isDesktop ? document.getElementById("scroll-container") : null;
1753
- const scrollTarget = container || window;
1754
- const offset = getAnchorOffset();
1755
- const handleScroll = () => {
1756
- if (clickedIdRef.current) return;
1757
- let currentId = null;
1758
- for (const toc of tocs) {
1759
- const id = toc.href.slice(1);
1760
- const el = document.getElementById(id);
1761
- if (!el) continue;
1762
- const top = container ? el.offsetTop - container.scrollTop : el.getBoundingClientRect().top;
1763
- if (top <= offset) {
1764
- currentId = id;
1765
- } else {
1766
- break;
1767
- }
1768
- }
1769
- if (currentId && currentId !== activeIdRef.current) {
1770
- setActiveId(currentId);
1771
- history.replaceState(null, "", `#${currentId}`);
1772
- }
1773
- };
1774
- handleScroll();
1775
- let throttleTimer = null;
1776
- const listener = tocs.length > 30 ? () => {
1777
- if (throttleTimer) return;
1778
- throttleTimer = setTimeout(() => {
1779
- throttleTimer = null;
1780
- handleScroll();
1781
- }, 50);
1782
- } : handleScroll;
1783
- scrollTarget.addEventListener("scroll", listener, { passive: true });
1784
- return () => {
1785
- scrollTarget.removeEventListener("scroll", listener);
1786
- if (throttleTimer) clearTimeout(throttleTimer);
1787
- };
1788
- }, [tocs, getAnchorOffset]);
1789
- const handleLinkClick = useCallback2((id) => {
1790
- clickedIdRef.current = id;
1791
- setActiveId(id);
1792
- history.replaceState(null, "", `#${id}`);
1793
- if (clickTimerRef.current) clearTimeout(clickTimerRef.current);
1794
- clickTimerRef.current = setTimeout(() => {
1795
- clickedIdRef.current = null;
1796
- }, 1e3);
1797
- }, []);
1798
- useEffect2(() => {
1799
- return () => {
1800
- if (clickTimerRef.current) clearTimeout(clickTimerRef.current);
1801
- };
1802
- }, []);
1803
- if (!tocs.length) return null;
1804
- return /* @__PURE__ */ jsxs5("div", { className: "flex w-full flex-col gap-2", children: [
1805
- /* @__PURE__ */ jsxs5("div", { className: "flex items-center gap-2", children: [
1806
- /* @__PURE__ */ jsx8(ListIcon, { className: "h-4 w-4" }),
1807
- /* @__PURE__ */ jsx8("h3", { className: "text-sm font-medium", children: "On this page" })
1808
- ] }),
1809
- /* @__PURE__ */ jsx8("div", { className: "relative", children: /* @__PURE__ */ jsxs5("div", { className: "relative text-sm", children: [
1810
- /* @__PURE__ */ jsx8("div", { className: "bg-base-300 absolute top-0 left-0 h-full w-px" }),
1811
- /* @__PURE__ */ jsx8("div", { className: "flex flex-col", children: tocs.map(({ href, level, text }) => {
1812
- const id = href.slice(1);
1813
- const isActive = activeId === id;
1814
- const levelPadding = (level - 2) * 16;
1815
- return /* @__PURE__ */ jsxs5(
1816
- "div",
1817
- {
1818
- className: cn(
1819
- "relative flex items-center transition-all duration-200",
1820
- isActive && "bg-primary/5"
1821
- ),
1822
- children: [
1823
- /* @__PURE__ */ jsxs5(
1824
- "div",
1825
- {
1826
- className: cn(
1827
- "flex shrink-0 items-center px-1 py-2 transition-all duration-200",
1828
- isActive && "border-primary -ml-px border-l-[3px]"
1829
- ),
1830
- children: [
1831
- /* @__PURE__ */ jsx8(
1832
- "div",
1833
- {
1834
- className: cn(
1835
- "h-px transition-colors duration-200",
1836
- isActive ? "bg-primary w-3" : "bg-base-300 w-2"
1837
- )
1838
- }
1839
- ),
1840
- /* @__PURE__ */ jsx8(
1841
- "div",
1842
- {
1843
- className: cn(
1844
- "h-1.5 w-1.5 shrink-0 rounded-full transition-colors duration-300",
1845
- isActive ? "bg-primary" : "bg-base-300"
1846
- )
1847
- }
1848
- )
1849
- ]
1850
- }
1851
- ),
1852
- /* @__PURE__ */ jsx8(
1853
- "a",
1854
- {
1855
- href,
1856
- onClick: (e) => {
1857
- e.preventDefault();
1858
- handleLinkClick(id);
1859
- const el = document.getElementById(id);
1860
- if (el) {
1861
- const offset = getAnchorOffset();
1862
- const scroller = window.innerWidth >= 1024 ? document.getElementById("scroll-container") : null;
1863
- const elTop = el.getBoundingClientRect().top;
1864
- if (scroller) {
1865
- scroller.scrollTo({
1866
- top: elTop - scroller.getBoundingClientRect().top + scroller.scrollTop - offset,
1867
- behavior: "smooth"
1868
- });
1869
- } else {
1870
- window.scrollTo({
1871
- top: elTop + window.scrollY - offset,
1872
- behavior: "smooth"
1873
- });
1874
- }
1875
- }
1876
- },
1877
- className: cn(
1878
- "flex flex-1 items-center py-2 transition-all duration-200",
1879
- isActive ? "text-primary font-medium" : "text-base-content/60 hover:text-base-content"
1880
- ),
1881
- style: { paddingLeft: `${levelPadding + 6}px` },
1882
- children: /* @__PURE__ */ jsx8("span", { className: "line-clamp-2 text-sm break-words", children: text })
1883
- }
1884
- )
1885
- ]
1886
- },
1887
- href
1888
- );
1889
- }) })
1890
- ] }) }),
1891
- /* @__PURE__ */ jsx8(ScrollTo, { className: "mt-2" })
1892
- ] });
1893
- }
1894
-
1895
- // .docu/pages/docs/[[...slug]].tsx
1896
- import { jsx as jsx9, jsxs as jsxs6 } from "react/jsx-runtime";
1897
- function DocsPage({
1898
- slug,
1899
- title,
1900
- description,
1901
- date,
1902
- content,
1903
- tocs,
1904
- filePath,
1905
- repoUrl,
1906
- mdxSlug,
1907
- compiledSource
1908
- }) {
1909
- const pathname = slug.join("/");
1910
- const tocsJson = JSON.stringify(tocs);
1911
- return /* @__PURE__ */ jsx9("div", { className: "flex w-full flex-1 px-0 pb-4 lg:h-[calc(100vh-4rem)] lg:px-8 lg:pb-8", children: /* @__PURE__ */ jsxs6(
1912
- "div",
1913
- {
1914
- id: "scroll-container",
1915
- className: "bg-base-100 border-base-300 relative flex w-full flex-col items-start rounded-b-3xl border shadow-md max-lg:scroll-p-54 lg:h-full lg:flex-row lg:overflow-y-auto lg:rounded-xl",
1916
- children: [
1917
- /* @__PURE__ */ jsx9(
1918
- "div",
1919
- {
1920
- id: "mobile-bar-island",
1921
- className: "sticky top-0 z-50 w-full lg:hidden",
1922
- "data-tocs": tocsJson,
1923
- "data-title": title,
1924
- "data-repo": repoUrl || ""
1925
- }
1926
- ),
1927
- /* @__PURE__ */ jsxs6("div", { className: "flex w-full flex-col lg:flex-row 2xl:mx-auto 2xl:max-w-[1300px]", children: [
1928
- /* @__PURE__ */ jsxs6(
1929
- "div",
1930
- {
1931
- className: `w-full min-w-0 ${tocs.length > 0 ? "flex-[7]" : "mx-auto max-w-[820px]"} px-4 py-6 lg:px-12 lg:py-10`,
1932
- children: [
1933
- /* @__PURE__ */ jsx9(DocsBreadcrumb, { paths: slug }),
1934
- /* @__PURE__ */ jsxs6(Typography, { children: [
1935
- /* @__PURE__ */ jsx9("h1", { className: "-mt-0.5 text-3xl", children: title }),
1936
- description && /* @__PURE__ */ jsx9("p", { className: "text-muted-foreground -mt-4 text-[16.5px]", children: description }),
1937
- /* @__PURE__ */ jsx9(
1938
- "div",
1939
- {
1940
- id: "mdx-content-island",
1941
- "data-mdx-slug": mdxSlug,
1942
- dangerouslySetInnerHTML: { __html: content }
1943
- }
1944
- ),
1945
- compiledSource && /* @__PURE__ */ jsx9(
1946
- "script",
1947
- {
1948
- id: "mdx-compiled-source",
1949
- type: "application/json",
1950
- dangerouslySetInnerHTML: {
1951
- __html: JSON.stringify(compiledSource).replace(/<\//g, "\\u003C/")
1952
- }
1953
- }
1954
- ),
1955
- /* @__PURE__ */ jsxs6("div", { className: "border-base-300 my-8 flex items-center border-b-2 border-dashed", children: [
1956
- /* @__PURE__ */ jsx9(EditWith, { className: "text-muted-foreground", filePath }),
1957
- date && /* @__PURE__ */ jsxs6("p", { className: "text-muted-foreground ml-auto text-[13px]", children: [
1958
- "Last updated ",
1959
- formatDate2(date)
1960
- ] })
1961
- ] }),
1962
- /* @__PURE__ */ jsx9(
1963
- Pagination,
1964
- {
1965
- pathname,
1966
- prevIcon: /* @__PURE__ */ jsx9(ChevronLeft, { className: "h-3 w-3" }),
1967
- nextIcon: /* @__PURE__ */ jsx9(ChevronRight, { className: "h-3 w-3" })
1968
- }
1969
- ),
1970
- /* @__PURE__ */ jsx9(Footer, {})
1971
- ] })
1972
- ]
1973
- }
1974
- ),
1975
- tocs.length > 0 && /* @__PURE__ */ jsx9(
1976
- "div",
1977
- {
1978
- id: "toc-island",
1979
- "data-tocs": tocsJson,
1980
- className: "sticky top-4 hidden h-[calc(100vh-8rem)] min-w-[240px] flex-[3] self-start lg:flex lg:px-4 lg:py-6",
1981
- children: /* @__PURE__ */ jsx9(Toc, { tocs })
1982
- }
1983
- )
1984
- ] })
1985
- ]
1986
- }
1987
- ) });
1988
- }
1989
-
1990
- // .docu/pages/404.tsx
1991
- import { jsx as jsx10, jsxs as jsxs7 } from "react/jsx-runtime";
1992
- function NotFoundPage() {
1993
- return /* @__PURE__ */ jsx10("div", { className: "flex w-full flex-1 px-4 py-8 lg:h-[calc(100vh-4rem)] lg:px-8 lg:py-4", children: /* @__PURE__ */ jsxs7("div", { className: "bg-base-100 border-base-300 flex min-h-[50vh] w-full flex-col items-center justify-center rounded-xl border shadow-md lg:min-h-0 lg:flex-1", children: [
1994
- /* @__PURE__ */ jsx10("h1", { className: "text-6xl font-bold", children: "404" }),
1995
- /* @__PURE__ */ jsx10("p", { className: "text-base-content/60 py-4 text-xl", children: "Page not found" }),
1996
- /* @__PURE__ */ jsx10("a", { href: "/docs/", className: "btn btn-primary mt-2", children: "Go to Docs" })
1997
- ] }) });
1998
- }
1999
-
2000
- // .docu/components/Lucide.tsx
2001
- import * as LucideIcons from "lucide-react";
2002
- import { jsx as jsx11 } from "react/jsx-runtime";
2003
- function getLucideIcon(name) {
2004
- if (!name) return null;
2005
- const icon = LucideIcons[name];
2006
- return icon || null;
2007
- }
2008
- function renderLucideIcon(name, className) {
2009
- const Icon = getLucideIcon(name);
2010
- return Icon ? /* @__PURE__ */ jsx11(Icon, { className }) : null;
2011
- }
2012
-
2013
- // .docu/components/home/Hero.tsx
2014
- import { jsx as jsx12, jsxs as jsxs8 } from "react/jsx-runtime";
2015
- function isExternalLink(link) {
2016
- return /^https?:\/\//.test(link);
2017
- }
2018
- function renderActionButtonIcon(iconName, className) {
2019
- if (!iconName) return null;
2020
- const lucideIcon = renderLucideIcon(iconName, className);
2021
- if (lucideIcon) return lucideIcon;
2022
- const SocialIcon = getSocialIcon(iconName);
2023
- if (SocialIcon) return /* @__PURE__ */ jsx12(SocialIcon, { className });
2024
- return null;
2025
- }
2026
- function ActionButton({ action }) {
2027
- const themeClasses = {
2028
- primary: "bg-primary text-primary-foreground hover:bg-primary/90",
2029
- secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/90",
2030
- ghost: "bg-transparent text-muted-foreground border border-base-300 hover:bg-base-200"
2031
- };
2032
- const isExternal = isExternalLink(action.link);
2033
- return /* @__PURE__ */ jsxs8(
2034
- "a",
2035
- {
2036
- href: action.link,
2037
- target: isExternal ? "_blank" : void 0,
2038
- rel: isExternal ? "noopener noreferrer" : void 0,
2039
- className: cn(
2040
- "inline-flex items-center gap-2 rounded-lg px-6 py-3 text-sm font-medium transition-colors",
2041
- themeClasses[action.theme || "primary"]
2042
- ),
2043
- children: [
2044
- renderActionButtonIcon(action.icon, "h-4 w-4"),
2045
- action.text
2046
- ]
2047
- }
2048
- );
2049
- }
2050
- function Hero({ hero, className }) {
2051
- const { tagline, headline, description, actions } = hero;
2052
- return /* @__PURE__ */ jsx12("div", { className: cn("mx-auto max-w-4xl px-6 py-32 sm:py-44", className), children: /* @__PURE__ */ jsxs8("div", { className: "text-center", children: [
2053
- tagline && /* @__PURE__ */ jsx12("p", { className: "text-primary mb-4 text-lg font-semibold", children: tagline }),
2054
- /* @__PURE__ */ jsx12("h1", { className: "text-5xl font-semibold tracking-tight text-balance sm:text-7xl", children: headline }),
2055
- description && /* @__PURE__ */ jsx12("p", { className: "text-muted-foreground mt-8 text-lg text-pretty sm:text-xl", children: description }),
2056
- actions && actions.length > 0 && /* @__PURE__ */ jsx12("div", { className: "mt-10 flex flex-wrap items-center justify-center gap-4", children: actions.map((action, index) => /* @__PURE__ */ jsx12(ActionButton, { action }, index)) })
2057
- ] }) });
2058
- }
2059
-
2060
- // .docu/components/home/Features.tsx
2061
- import { jsx as jsx13, jsxs as jsxs9 } from "react/jsx-runtime";
2062
- function FeatureCard({ feature, index }) {
2063
- const Wrapper = feature.link ? "a" : "div";
2064
- const wrapperProps = feature.link ? { href: feature.link } : {};
2065
- const patternId = `grid-${index}`;
2066
- return /* @__PURE__ */ jsxs9(
2067
- Wrapper,
2068
- {
2069
- ...wrapperProps,
2070
- className: cn(
2071
- "border-base-200 bg-base-100 hover:border-primary/40 group relative overflow-hidden rounded-2xl border p-6 transition-all hover:shadow-lg",
2072
- feature.link && "cursor-pointer"
2073
- ),
2074
- children: [
2075
- /* @__PURE__ */ jsxs9(
2076
- "svg",
2077
- {
2078
- className: "absolute inset-0 h-full w-full",
2079
- xmlns: "http://www.w3.org/2000/svg",
2080
- style: { color: "var(--color-primary)" },
2081
- "aria-hidden": "true",
2082
- children: [
2083
- /* @__PURE__ */ jsx13("defs", { children: /* @__PURE__ */ jsx13("pattern", { id: patternId, width: "40", height: "40", patternUnits: "userSpaceOnUse", children: /* @__PURE__ */ jsx13(
2084
- "path",
2085
- {
2086
- d: "M 40 0 L 0 0 0 40",
2087
- fill: "none",
2088
- stroke: "currentColor",
2089
- strokeWidth: "0.5",
2090
- opacity: "0.15"
2091
- }
2092
- ) }) }),
2093
- /* @__PURE__ */ jsx13("rect", { width: "100%", height: "100%", fill: `url(#${patternId})` })
2094
- ]
2095
- }
2096
- ),
2097
- /* @__PURE__ */ jsxs9("div", { className: "relative z-10", children: [
2098
- feature.icon && /* @__PURE__ */ jsx13("div", { className: "bg-primary/10 mb-4 inline-flex h-12 w-12 items-center justify-center rounded-lg", children: renderLucideIcon(feature.icon, "h-6 w-6 text-primary") }),
2099
- /* @__PURE__ */ jsx13("h3", { className: "mb-2 text-lg font-semibold", children: feature.title }),
2100
- /* @__PURE__ */ jsx13("p", { className: "text-muted-foreground text-sm", children: feature.description })
2101
- ] })
2102
- ]
2103
- }
2104
- );
2105
- }
2106
- function Features({ features, className }) {
2107
- if (!features || features.length === 0) return null;
2108
- return /* @__PURE__ */ jsx13("div", { className: cn("mx-auto max-w-5xl px-6 pb-24", className), children: /* @__PURE__ */ jsx13("div", { className: "grid grid-cols-1 gap-6 sm:grid-cols-2 lg:grid-cols-3", children: features.map((feature, index) => /* @__PURE__ */ jsx13(FeatureCard, { feature, index }, index)) }) });
2109
- }
2110
-
2111
- // .docu/pages/index.tsx
2112
- import { jsx as jsx14, jsxs as jsxs10 } from "react/jsx-runtime";
2113
- var docuConfig4 = loadDocuConfig();
2114
- function IndexPage() {
2115
- const { meta, home } = docuConfig4;
2116
- const routes3 = docuConfig4.routes || [];
2117
- const linkWithHtml = (link) => {
2118
- if (isExternalUrl(link)) return link;
2119
- if (link.startsWith("/docs/")) return `${link}.html`;
2120
- return link;
2121
- };
2122
- const features = home?.features?.map((f) => ({
2123
- ...f,
2124
- link: f.link ? linkWithHtml(f.link) : void 0
2125
- })) || routes3.filter((r) => r.context).map((route) => ({
2126
- icon: route.context?.icon,
2127
- title: route.context?.title || route.title,
2128
- description: route.context?.description || "",
2129
- link: docsHtmlHref(`/docs${route.href}${route.items?.[0]?.href || ""}`)
2130
- }));
2131
- const hero = home?.hero ? {
2132
- ...home.hero,
2133
- actions: home.hero.actions?.map((a) => ({
2134
- ...a,
2135
- link: linkWithHtml(a.link)
2136
- }))
2137
- } : {
2138
- headline: meta.title,
2139
- description: meta.description
2140
- };
2141
- return /* @__PURE__ */ jsxs10("div", { className: "bg-base-100 relative isolate min-h-screen overflow-hidden", children: [
2142
- /* @__PURE__ */ jsx14("div", { className: "absolute top-4 right-4 z-10", id: "theme-island" }),
2143
- /* @__PURE__ */ jsx14(
2144
- "div",
2145
- {
2146
- "aria-hidden": "true",
2147
- className: "pointer-events-none absolute -top-40 left-1/2 -z-10 -translate-x-1/2 blur-3xl sm:-top-80",
2148
- children: /* @__PURE__ */ jsx14(
2149
- "div",
2150
- {
2151
- style: {
2152
- clipPath: "polygon(74.1% 44.1%, 100% 61.6%, 97.5% 26.9%, 85.5% 0.1%, 80.7% 2%, 72.5% 32.5%, 60.2% 62.4%, 52.4% 68.1%, 47.5% 58.3%, 45.2% 34.5%, 27.5% 76.7%, 0.1% 64.9%, 17.9% 100%, 27.6% 76.8%, 76.1% 97.7%, 74.1% 44.1%)"
2153
- },
2154
- className: "from-primary to-accent h-[40rem] w-[80rem] bg-gradient-to-tr opacity-20"
2155
- }
2156
- )
2157
- }
2158
- ),
2159
- /* @__PURE__ */ jsx14(Hero, { hero }),
2160
- /* @__PURE__ */ jsx14(Features, { features }),
2161
- /* @__PURE__ */ jsx14(
2162
- "div",
2163
- {
2164
- "aria-hidden": "true",
2165
- className: "pointer-events-none absolute bottom-0 left-1/2 -z-10 translate-x-1/4 blur-3xl",
2166
- children: /* @__PURE__ */ jsx14(
2167
- "div",
2168
- {
2169
- style: {
2170
- clipPath: "polygon(74.1% 44.1%, 100% 61.6%, 97.5% 26.9%, 85.5% 0.1%, 80.7% 2%, 72.5% 32.5%, 60.2% 62.4%, 52.4% 68.1%, 47.5% 58.3%, 45.2% 34.5%, 27.5% 76.7%, 0.1% 64.9%, 17.9% 100%, 27.6% 76.8%, 76.1% 97.7%, 74.1% 44.1%)"
2171
- },
2172
- className: "from-accent to-primary h-[30rem] w-[70rem] bg-gradient-to-tr opacity-20"
2173
- }
2174
- )
2175
- }
2176
- )
2177
- ] });
2178
- }
2179
-
2180
- // .docu/components/DocsLayout.tsx
2181
- import React2 from "react";
2182
-
2183
- // .docu/components/Menu.tsx
2184
- import { useState as useState4 } from "react";
2185
-
2186
- // .docu/components/Sublink.tsx
2187
- import {
2188
- createContext,
2189
- useContext,
2190
- useState as useState3,
2191
- useRef as useRef2,
2192
- useEffect as useEffect3,
2193
- useCallback as useCallback3
2194
- } from "react";
2195
- import { ChevronDown } from "lucide-react";
2196
-
2197
- // .docu/components/Anchor.tsx
2198
- import { ArrowUpRight } from "lucide-react";
2199
- import { jsx as jsx15, jsxs as jsxs11 } from "react/jsx-runtime";
2200
- function Anchor({
2201
- href = "",
2202
- className = "",
2203
- activeClassName = "",
2204
- activeWhen,
2205
- disabled = false,
2206
- children,
2207
- ...props
2208
- }) {
2209
- const isActive = (() => {
2210
- if (!activeWhen || typeof window === "undefined") return false;
2211
- const pathname = window.location.pathname;
2212
- if (typeof activeWhen === "string")
2213
- return pathname === activeWhen || pathname.endsWith(activeWhen);
2214
- if (activeWhen instanceof RegExp) return activeWhen.test(pathname);
2215
- if (typeof activeWhen === "function") return activeWhen(pathname);
2216
- return false;
2217
- })();
2218
- const isExternal = isExternalUrl(href);
2219
- const activeClass = isActive ? activeClassName : "";
2220
- const baseClasses = cn(
2221
- "hover:underline transition-colors",
2222
- className,
2223
- activeClass,
2224
- disabled && "cursor-not-allowed opacity-50"
2225
- );
2226
- if (disabled) {
2227
- return /* @__PURE__ */ jsx15("span", { className: baseClasses, children });
2228
- }
2229
- if (isExternal) {
2230
- return /* @__PURE__ */ jsxs11("a", { href, className: baseClasses, target: "_blank", rel: "noopener noreferrer", ...props, children: [
2231
- children,
2232
- /* @__PURE__ */ jsx15(ArrowUpRight, { className: "ml-0.5 inline-block h-3.5 w-3.5" })
2233
- ] });
2234
- }
2235
- return /* @__PURE__ */ jsx15("a", { href, className: baseClasses, ...props, children });
2236
- }
2237
-
2238
- // .docu/node/client-routes.ts
2239
- var docuConfig5 = loadDocuConfig();
2240
- var routes2 = resolveRoutes(docuConfig5.routes || []);
2241
- var config = docuConfig5;
2242
-
2243
- // .docu/components/Sublink.tsx
2244
- import { jsx as jsx16, jsxs as jsxs12 } from "react/jsx-runtime";
2245
- var GroupAccordionContext = createContext({ openId: null, open: () => {
2246
- }, toggle: () => {
2247
- } });
2248
- function GroupAccordionProvider({ children }) {
2249
- const [openId, setOpenId] = useState3(null);
2250
- const open = useCallback3((id) => setOpenId(id), []);
2251
- const toggle = useCallback3((id) => setOpenId((prev) => prev === id ? null : id), []);
2252
- return /* @__PURE__ */ jsx16(GroupAccordionContext.Provider, { value: { openId, open, toggle }, children });
2253
- }
2254
- function Sublink({
2255
- title,
2256
- href,
2257
- items,
2258
- noLink,
2259
- level,
2260
- onNavigate,
2261
- parentHref = "",
2262
- pathname: pathnameProp
2263
- }) {
2264
- const fullHref = parentHref ? `${parentHref}${href}` : `/docs${href}`;
2265
- const currentPathname = pathnameProp || (typeof window !== "undefined" ? window.location.pathname : "/docs");
2266
- const isSeparator = config.sidebar?.context === "separator";
2267
- const { openId, open, toggle } = useContext(GroupAccordionContext);
2268
- const isAccordionGroup = Boolean(items) && (isSeparator || level >= 1);
2269
- const treeLevel = level + (isSeparator ? 2 : 1);
2270
- const [isOpen, setIsOpen] = useState3(() => {
2271
- if (isAccordionGroup) return false;
2272
- if (level === 0) return true;
2273
- return false;
2274
- });
2275
- const effectiveOpen = isAccordionGroup ? openId === fullHref : isOpen;
2276
- const handleToggle = () => {
2277
- if (isAccordionGroup) toggle(fullHref);
2278
- else setIsOpen((o) => !o);
2279
- };
2280
- const isInsideActive = currentPathname.startsWith(fullHref) && currentPathname !== fullHref;
2281
- useEffect3(() => {
2282
- if (isAccordionGroup && isInsideActive) open(fullHref);
2283
- }, [isAccordionGroup, isInsideActive, fullHref, open]);
2284
- const levelPadding = cn(level === 1 && "pl-4", level === 2 && "pl-8", level >= 3 && "pl-12");
2285
- const isActive = currentPathname === fullHref || currentPathname === `${fullHref}.html`;
2286
- const activeRef = useRef2(null);
2287
- useEffect3(() => {
2288
- if (isActive && activeRef.current) {
2289
- activeRef.current.scrollIntoView({ block: "nearest" });
2290
- }
2291
- }, [isActive]);
2292
- if (!items) {
2293
- const link = /* @__PURE__ */ jsx16(
2294
- Anchor,
2295
- {
2296
- href: docsHtmlHref(fullHref),
2297
- className: "text-foreground hover:text-foreground/80 text-sm transition-colors",
2298
- activeClassName: "text-primary font-medium",
2299
- activeWhen: (path) => path === fullHref || path === `${fullHref}.html`,
2300
- onClick: onNavigate,
2301
- children: title
2302
- }
2303
- );
2304
- if (level >= 1) {
2305
- if (config.sidebar?.context === "separator") {
2306
- const sectionOffsets = { 1: 16, 2: 32 };
2307
- let overlap = 14;
2308
- for (let l = 1; l < level; l++) {
2309
- overlap += sectionOffsets[l] ?? 48;
2310
- }
2311
- return /* @__PURE__ */ jsx16(
2312
- "div",
2313
- {
2314
- ref: activeRef,
2315
- className: cn("border-l-2", isActive ? "border-primary" : "border-transparent"),
2316
- style: { marginLeft: `-${overlap}px` },
2317
- children: /* @__PURE__ */ jsx16("div", { className: cn("py-1 pl-3", levelPadding), children: link })
2318
- }
2319
- );
2320
- }
2321
- return /* @__PURE__ */ jsx16(
2322
- "div",
2323
- {
2324
- ref: activeRef,
2325
- className: cn(
2326
- "py-1",
2327
- levelPadding,
2328
- "border-l-2",
2329
- isActive ? "border-primary" : "border-base-300"
2330
- ),
2331
- children: link
2332
- }
2333
- );
2334
- }
2335
- return /* @__PURE__ */ jsx16("div", { ref: activeRef, className: cn("py-1", levelPadding), children: link });
2336
- }
2337
- return /* @__PURE__ */ jsxs12("div", { ref: isActive ? activeRef : void 0, className: cn("flex flex-col", levelPadding), children: [
2338
- /* @__PURE__ */ jsxs12(
2339
- "button",
2340
- {
2341
- type: "button",
2342
- onClick: handleToggle,
2343
- className: cn(
2344
- "flex w-full cursor-pointer items-center justify-between py-1 text-left text-sm transition-colors",
2345
- // Only the top-level section label (routes-tree level 1) is bold.
2346
- // Deeper groups (e.g. Search at level 2) are children that happen to
2347
- // have items — style them like links, no header weight.
2348
- noLink && treeLevel === 1 ? "text-base-content font-semibold" : "text-foreground hover:text-foreground/80"
2349
- ),
2350
- children: [
2351
- noLink ? /* @__PURE__ */ jsx16("span", { children: title }) : /* @__PURE__ */ jsx16(
2352
- Anchor,
2353
- {
2354
- href: docsHtmlHref(fullHref),
2355
- className: "text-foreground hover:text-foreground/80 transition-colors",
2356
- activeClassName: "text-primary",
2357
- activeWhen: (path) => path === fullHref || path === `${fullHref}.html`,
2358
- onClick: onNavigate,
2359
- children: title
2360
- }
2361
- ),
2362
- /* @__PURE__ */ jsx16(
2363
- ChevronDown,
2364
- {
2365
- className: cn(
2366
- "text-base-content/40 h-4 w-4 shrink-0 transition-transform duration-200",
2367
- // Tree convention: closed = chevron pointing right (expandable),
2368
- // open = pointing down — a 90° turn instead of the 180° flip.
2369
- effectiveOpen ? "rotate-0" : "-rotate-90"
2370
- )
2371
- }
2372
- )
2373
- ]
2374
- }
2375
- ),
2376
- effectiveOpen && /* @__PURE__ */ jsx16("div", { className: "flex flex-col py-1", children: items.map((item) => /* @__PURE__ */ jsx16(
2377
- Sublink,
2378
- {
2379
- ...item,
2380
- href: item.href,
2381
- level: level + 1,
2382
- onNavigate,
2383
- parentHref: fullHref,
2384
- pathname: pathnameProp
2385
- },
2386
- `${fullHref}${item.href}`
2387
- )) })
2388
- ] });
2389
- }
2390
-
2391
- // .docu/components/SidebarGroupHeader.tsx
2392
- import { jsx as jsx17, jsxs as jsxs13 } from "react/jsx-runtime";
2393
- function SidebarGroupHeader({ icon, title }) {
2394
- return /* @__PURE__ */ jsxs13("div", { className: "sidebar-group-header mb-1.5 flex items-center gap-2.5 font-medium text-gray-900 dark:text-gray-200", children: [
2395
- icon && /* @__PURE__ */ jsx17("span", { className: "flex h-4 w-4 shrink-0 items-center justify-center", children: renderLucideIcon(icon, "h-3.5 w-3.5") }),
2396
- /* @__PURE__ */ jsx17("h3", { className: "sidebar-title font-[inherit] text-[length:inherit] leading-[inherit]", children: /* @__PURE__ */ jsx17("span", { children: title }) })
2397
- ] });
2398
- }
2399
-
2400
- // .docu/components/Menu.tsx
2401
- import { jsx as jsx18, jsxs as jsxs14 } from "react/jsx-runtime";
2402
- function getCurrentContext(path) {
2403
- if (!path.startsWith("/docs")) return void 0;
2404
- const match = path.match(/^\/docs\/([^/]+)/);
2405
- return match ? match[1] : void 0;
2406
- }
2407
- function getContextRoute(contextPath, routeList) {
2408
- return routeList.find((route) => {
2409
- const normalizedHref = route.href.replace(/^\/+|\/+$/, "");
2410
- return normalizedHref === contextPath;
2411
- });
2412
- }
2413
- function Menu({ onNavigate, className = "", pathname, routes: routes3 = [] }) {
2414
- const menuRoutes = routes3;
2415
- const [currentPath] = useState4(
2416
- () => pathname || (typeof window !== "undefined" ? window.location.pathname : "/docs")
2417
- );
2418
- if (!currentPath.startsWith("/docs")) return null;
2419
- const mode = config.sidebar?.context || "dropdown";
2420
- const navProps = {
2421
- "aria-label": "Documentation navigation",
2422
- className: cn("transition-all duration-200", className)
2423
- };
2424
- const renderBorderItem = (item, parentRouteHref, key) => {
2425
- const fullHref = `/docs${parentRouteHref}${item.href}`;
2426
- const isActive = currentPath === fullHref || currentPath === `${fullHref}.html`;
2427
- return /* @__PURE__ */ jsx18("li", { children: /* @__PURE__ */ jsx18(
2428
- "div",
2429
- {
2430
- className: cn(
2431
- "-ml-[14px] border-l-2",
2432
- isActive ? "border-primary" : "border-transparent"
2433
- ),
2434
- children: /* @__PURE__ */ jsx18("div", { className: "pl-3", children: /* @__PURE__ */ jsx18(
2435
- Sublink,
2436
- {
2437
- ...item,
2438
- href: item.href,
2439
- level: 0,
2440
- onNavigate,
2441
- parentHref: `/docs${parentRouteHref}`
2442
- }
2443
- ) })
2444
- }
2445
- ) }, key);
2446
- };
2447
- const sharedUlClasses = "border-base-300 flex flex-col gap-0.5 border-l-2 pb-0.5 pl-3 pt-0.5";
2448
- if (mode === "separator") {
2449
- const contextRoutes = menuRoutes.filter((r) => r.context);
2450
- if (contextRoutes.length === 0) {
2451
- return /* @__PURE__ */ jsx18(GroupAccordionProvider, { children: /* @__PURE__ */ jsx18("nav", { ...navProps, children: /* @__PURE__ */ jsx18("ul", { className: sharedUlClasses, children: menuRoutes.map((route) => renderBorderItem(route, "", route.href)) }) }) });
2452
- }
2453
- return /* @__PURE__ */ jsx18(GroupAccordionProvider, { children: /* @__PURE__ */ jsx18("nav", { ...navProps, children: contextRoutes.map((route, i) => /* @__PURE__ */ jsxs14("div", { className: i > 0 ? "mt-6 lg:mt-8" : "", children: [
2454
- /* @__PURE__ */ jsx18(
2455
- SidebarGroupHeader,
2456
- {
2457
- icon: route.context?.icon,
2458
- title: route.context?.title || route.title
2459
- }
2460
- ),
2461
- /* @__PURE__ */ jsx18("ul", { className: sharedUlClasses, children: route.items?.map((item) => renderBorderItem(item, route.href, item.href)) })
2462
- ] }, route.href)) }) });
2463
- }
2464
- const isDocsRoot = currentPath === "/docs" || currentPath === "/docs/";
2465
- const currentContext = isDocsRoot ? menuRoutes[0]?.href.replace(/^\/+|\/+$/, "") : getCurrentContext(currentPath);
2466
- const contextRoute = isDocsRoot && menuRoutes[0] ? currentContext ? getContextRoute(currentContext, menuRoutes) : menuRoutes[0] : currentContext ? getContextRoute(currentContext, menuRoutes) : void 0;
2467
- if (!contextRoute) return null;
2468
- return /* @__PURE__ */ jsx18(GroupAccordionProvider, { children: /* @__PURE__ */ jsx18("nav", { ...navProps, children: /* @__PURE__ */ jsx18("ul", { className: "flex flex-col gap-0.5 py-4", children: /* @__PURE__ */ jsx18("li", { children: /* @__PURE__ */ jsx18(
2469
- Sublink,
2470
- {
2471
- ...contextRoute,
2472
- href: contextRoute.href,
2473
- level: 0,
2474
- onNavigate,
2475
- parentHref: "/docs"
2476
- }
2477
- ) }, contextRoute.title) }) }) });
2478
- }
2479
-
2480
- // .docu/components/DocsLayout.tsx
2481
- var docuConfig6 = loadDocuConfig();
2482
- function DocsLayout({ children, repoUrl, pathname = "/docs" }) {
2483
- return React2.createElement(
2484
- "div",
2485
- { className: "docs-layout flex flex-col min-h-screen w-full" },
2486
- React2.createElement(
2487
- "div",
2488
- { className: "flex flex-1 items-start w-full" },
2489
- React2.createElement(
2490
- "aside",
2491
- {
2492
- id: "sidebar-island",
2493
- className: "sticky top-0 hidden h-screen w-[280px] shrink-0 flex-col lg:flex border-r border-base-200 bg-base-100",
2494
- "data-tocs": "[]",
2495
- "data-title": "",
2496
- "data-repo": repoUrl || ""
2497
- },
2498
- // SSR sidebar content — Menu rendered server-side
2499
- React2.createElement(
2500
- "div",
2501
- { className: "flex h-full flex-col overflow-y-auto px-4" },
2502
- React2.createElement(Menu, { pathname, routes: docuConfig6.routes || [] })
2503
- )
2504
- ),
2505
- React2.createElement(
2506
- "main",
2507
- { className: "flex-1 min-w-0 min-h-screen flex flex-col" },
2508
- React2.createElement(
2509
- "div",
2510
- { className: "hidden lg:flex items-center justify-end gap-6 h-14 px-8" },
2511
- React2.createElement(
2512
- "nav",
2513
- { className: "flex items-center gap-6 text-sm font-medium text-base-content/80" },
2514
- ...(docuConfig6.navbar?.menu || []).map((item) => {
2515
- const isExternal = /^https?:\/\//.test(item.href);
2516
- const isDocsActive = item.href === "/docs";
2517
- return React2.createElement(
2518
- "a",
2519
- {
2520
- key: item.title,
2521
- href: item.href,
2522
- className: `flex items-center gap-1 hover:text-base-content transition-colors${isDocsActive ? " text-primary font-semibold" : ""}`,
2523
- ...isExternal ? { target: "_blank", rel: "noopener noreferrer" } : {}
2524
- },
2525
- item.title,
2526
- isExternal ? React2.createElement(
2527
- "svg",
2528
- {
2529
- xmlns: "http://www.w3.org/2000/svg",
2530
- width: "14",
2531
- height: "14",
2532
- viewBox: "0 0 24 24",
2533
- fill: "none",
2534
- stroke: "currentColor",
2535
- strokeWidth: "2",
2536
- strokeLinecap: "round",
2537
- strokeLinejoin: "round"
2538
- },
2539
- React2.createElement("path", { d: "M7 7h10v10" }),
2540
- React2.createElement("path", { d: "M7 17 17 7" })
2541
- ) : null
2542
- );
2543
- })
2544
- )
2545
- ),
2546
- React2.createElement("div", { className: "flex-1 w-full" }, children)
2547
- )
2548
- )
2549
- );
2550
- }
2551
-
2552
- // .docu/node/escapeHtml.ts
2553
- var ESCAPE_RE = /[&<>"']/g;
2554
- var ESCAPE_MAP = {
2555
- "&": "&amp;",
2556
- "<": "&lt;",
2557
- ">": "&gt;",
2558
- '"': "&quot;",
2559
- "'": "&#x27;"
2560
- };
2561
- function escapeHtml(input) {
2562
- return input.replace(ESCAPE_RE, (ch) => ESCAPE_MAP[ch]);
2563
- }
2564
-
2565
- // .docu/node/html.shared.ts
2566
- function htmlShell(opts) {
2567
- const {
2568
- title,
2569
- description,
2570
- body,
2571
- favicon,
2572
- css,
2573
- js,
2574
- nonce,
2575
- csp,
2576
- extraScripts,
2577
- themeCss,
2578
- depth = 0,
2579
- headExtra,
2580
- bodyExtra,
2581
- absoluteAssets = false
2582
- } = opts;
2583
- const nonceAttr = nonce ? ` nonce="${escapeHtml(nonce)}"` : "";
2584
- const themeStyle = themeCss ? `
2585
- <style${nonceAttr}>${escapeHtml(themeCss)}</style>` : "";
2586
- const headInjection = headExtra?.length ? `
2587
- ${headExtra.join("\n ")}` : "";
2588
- const bodyInjection = bodyExtra?.length ? `
2589
- ${bodyExtra.join("\n ")}` : "";
2590
- const depthPrefix = depth === 0 ? "" : "../".repeat(depth);
2591
- const assetPrefix = absoluteAssets ? "/assets/" : depthPrefix + "assets/";
2592
- const resolvePath = (path) => absoluteAssets ? path : path.startsWith("/") ? depthPrefix + path.slice(1) : path;
2593
- let seoTags = "";
2594
- if (opts.seo) {
2595
- const s = opts.seo;
2596
- const e = escapeHtml;
2597
- seoTags = `
2598
- <meta property="og:title" content="${e(title)}" />
2599
- <meta property="og:description" content="${e(description)}" />
2600
- <meta property="og:url" content="${e(s.url)}" />
2601
- <meta property="og:type" content="website" />
2602
- <meta property="og:site_name" content="${e(s.siteName)}" />
2603
- <meta name="twitter:card" content="summary_large_image" />
2604
- <link rel="canonical" href="${e(s.url)}" />`;
2605
- if (s.image) {
2606
- seoTags += `
2607
- <meta property="og:image" content="${e(s.image)}" />`;
2608
- }
2609
- }
2610
- return `<!DOCTYPE html>
2611
- <html lang="en">
2612
- <head>
2613
- <meta charset="UTF-8">
2614
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
2615
- <title>${escapeHtml(title)}</title>
2616
- <meta name="description" content="${escapeHtml(description)}">
2617
- ${favicon ? `<link rel="icon" type="image/x-icon" href="${escapeHtml(resolvePath(favicon))}">` : ""}${themeStyle}
2618
- <link rel="preload" href="${escapeHtml(assetPrefix + css)}" as="style">
2619
- <link rel="stylesheet" href="${escapeHtml(assetPrefix + css)}">
2620
- ${csp ? `<meta http-equiv="Content-Security-Policy" content="${escapeHtml(csp)}">` : ""}
2621
- ${seoTags}
2622
- <script${nonceAttr}>try{if(localStorage.getItem("theme")==="dark")document.documentElement.classList.add("dark")}catch(e){}</script>${headInjection}
2623
- </head>
2624
- <body>
2625
- <div id="root">${body}</div>
2626
- <link rel="modulepreload" href="${escapeHtml(assetPrefix + js)}">
2627
- <script type="module"${nonceAttr} src="${escapeHtml(assetPrefix + js)}"></script>${extraScripts ? `
2628
- ${extraScripts}` : ""}${bodyInjection}
2629
- </body>
2630
- </html>`;
2631
- }
2632
- function errorHtml(message, stack) {
2633
- const msg = escapeHtml(message || "Unknown error");
2634
- const st = escapeHtml(stack || "");
2635
- return `<!DOCTYPE html>
2636
- <html lang="en">
2637
- <head>
2638
- <meta charset="utf-8">
2639
- <title>Server Error</title>
2640
- <style>
2641
- *{margin:0;padding:0;box-sizing:border-box}
2642
- body{padding:2rem;font-family:ui-monospace,monospace;background:#1a1a2e;color:#e0e0e0}
2643
- h1{color:#ff6b6b;font-size:1.5rem;margin-bottom:1rem}
2644
- pre{background:#0d0d1a;border:1px solid #333;border-radius:8px;padding:1.5rem;overflow-x:auto;font-size:14px;line-height:1.6;white-space:pre-wrap;word-break:break-word}
2645
- .msg{color:#ff6b6b;font-weight:bold}
2646
- </style>
2647
- </head>
2648
- <body>
2649
- <h1>\u{1F525} Server Error</h1>
2650
- <pre><span class="msg">${msg}</span>${st ? `
2651
-
2652
- ${st}` : ""}</pre>
2653
- </body>
2654
- </html>`;
2655
- }
2656
- function hmrScript(nonce) {
2657
- return `<script nonce="${escapeHtml(nonce)}">
2658
- (function(){
2659
- const es = new EventSource("/__hmr");
2660
- es.onmessage = function(e) {
2661
- if (e.data === "reload") window.location.reload();
2662
- };
2663
- es.onerror = function() { es.close(); setTimeout(() => { window.location.reload(); }, 2000); };
2664
- })();
2665
- </script>`;
2666
- }
2667
-
2668
- export {
2669
- loadPlugins,
2670
- BuildPluginBuilder,
2671
- computeInlineThemeCss,
2672
- buildClientBundle,
2673
- getGitLastModifiedBatch,
2674
- frontmatterField,
2675
- compileMdx,
2676
- getPageFrontmatter,
2677
- getPageStripped,
2678
- registerPageContent,
2679
- getPageContent,
2680
- compileMdxModule,
2681
- generateSearchIndex,
2682
- initSentry,
2683
- captureException,
2684
- DocsPage,
2685
- NotFoundPage,
2686
- IndexPage,
2687
- DocsLayout,
2688
- htmlShell,
2689
- errorHtml,
2690
- hmrScript
2691
- };