@domphy/press 0.19.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/build-6Q2QN246.js +1370 -0
- package/dist/cli.js +92 -0
- package/dist/index.d.ts +203 -0
- package/dist/index.js +272 -0
- package/dist/index.js.map +1 -0
- package/dist/islands.js +1 -0
- package/dist/serve-LQBYPP6C.js +105 -0
- package/package.json +78 -0
|
@@ -0,0 +1,1370 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/build.ts
|
|
4
|
+
import {
|
|
5
|
+
cpSync,
|
|
6
|
+
existsSync,
|
|
7
|
+
mkdirSync,
|
|
8
|
+
readFileSync as readFileSync2,
|
|
9
|
+
rmSync,
|
|
10
|
+
writeFileSync
|
|
11
|
+
} from "fs";
|
|
12
|
+
import { dirname as dirname2, join as join2, relative as relative2, resolve as resolve2 } from "path";
|
|
13
|
+
import { fileURLToPath } from "url";
|
|
14
|
+
import { execSync } from "child_process";
|
|
15
|
+
import { createApp, defineRoutes } from "@domphy/app";
|
|
16
|
+
import { themeCSS } from "@domphy/theme";
|
|
17
|
+
|
|
18
|
+
// src/highlight.ts
|
|
19
|
+
import { createHighlighter as createShiki } from "shiki";
|
|
20
|
+
var THEME = "github-light";
|
|
21
|
+
var LANGUAGES = [
|
|
22
|
+
"typescript",
|
|
23
|
+
"javascript",
|
|
24
|
+
"tsx",
|
|
25
|
+
"jsx",
|
|
26
|
+
"json",
|
|
27
|
+
"bash",
|
|
28
|
+
"shellscript",
|
|
29
|
+
"html",
|
|
30
|
+
"css",
|
|
31
|
+
"vue",
|
|
32
|
+
"svelte",
|
|
33
|
+
"markdown",
|
|
34
|
+
"diff",
|
|
35
|
+
"yaml",
|
|
36
|
+
"ruby",
|
|
37
|
+
"python",
|
|
38
|
+
"go",
|
|
39
|
+
"rust",
|
|
40
|
+
"sql"
|
|
41
|
+
];
|
|
42
|
+
var ALIASES = {
|
|
43
|
+
ts: "typescript",
|
|
44
|
+
js: "javascript",
|
|
45
|
+
sh: "bash",
|
|
46
|
+
shell: "bash",
|
|
47
|
+
zsh: "bash",
|
|
48
|
+
md: "markdown",
|
|
49
|
+
yml: "yaml",
|
|
50
|
+
htm: "html",
|
|
51
|
+
rb: "ruby",
|
|
52
|
+
py: "python"
|
|
53
|
+
};
|
|
54
|
+
var pending = null;
|
|
55
|
+
function escapeHtml(text2) {
|
|
56
|
+
return text2.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
57
|
+
}
|
|
58
|
+
function unwrapCode(html) {
|
|
59
|
+
const match = html.match(/<code[^>]*>([\s\S]*)<\/code>/);
|
|
60
|
+
return match ? match[1] : html;
|
|
61
|
+
}
|
|
62
|
+
function parseFenceInfo(info) {
|
|
63
|
+
const rawLang = (info.match(/^(\S+)/) ?? [])[1] ?? "";
|
|
64
|
+
const lang = ALIASES[rawLang.toLowerCase()] ?? rawLang.toLowerCase();
|
|
65
|
+
const lineNumbers = info.includes(":line-numbers");
|
|
66
|
+
const titleMatch = info.match(/\[([^\]]*[a-zA-Z.][^\]]*)\]/);
|
|
67
|
+
const title = titleMatch ? titleMatch[1] : null;
|
|
68
|
+
const rangeMatch = info.match(/\{([0-9,\s\-]+)\}/);
|
|
69
|
+
const highlightLines = /* @__PURE__ */ new Set();
|
|
70
|
+
if (rangeMatch) {
|
|
71
|
+
for (const part of rangeMatch[1].split(",")) {
|
|
72
|
+
const range = part.trim().split("-").map(Number);
|
|
73
|
+
if (range.length === 1 && !isNaN(range[0])) highlightLines.add(range[0]);
|
|
74
|
+
else if (range.length === 2) for (let i = range[0]; i <= range[1]; i++) highlightLines.add(i);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
return { lang, highlightLines, lineNumbers, title };
|
|
78
|
+
}
|
|
79
|
+
var CODE_ANNOTATION_RE = /\s*\/\/ \[!code ([^\]]+)\]\s*$/;
|
|
80
|
+
var ANNOTATION_CLASSES = {
|
|
81
|
+
"++": "diff add",
|
|
82
|
+
"--": "diff remove",
|
|
83
|
+
highlight: "highlighted",
|
|
84
|
+
focus: "focus",
|
|
85
|
+
error: "highlighted error",
|
|
86
|
+
warning: "highlighted warning"
|
|
87
|
+
};
|
|
88
|
+
function extractAnnotations(code) {
|
|
89
|
+
const lines = code.split("\n");
|
|
90
|
+
const lineClasses = /* @__PURE__ */ new Map();
|
|
91
|
+
const cleanLines = [];
|
|
92
|
+
let hasFocus = false;
|
|
93
|
+
for (const line of lines) {
|
|
94
|
+
const match = CODE_ANNOTATION_RE.exec(line);
|
|
95
|
+
if (match) {
|
|
96
|
+
const keyword = match[1].trim();
|
|
97
|
+
const cls = ANNOTATION_CLASSES[keyword];
|
|
98
|
+
if (cls) {
|
|
99
|
+
if (cls.includes("focus")) hasFocus = true;
|
|
100
|
+
lineClasses.set(cleanLines.length + 1, cls);
|
|
101
|
+
}
|
|
102
|
+
cleanLines.push(line.replace(CODE_ANNOTATION_RE, ""));
|
|
103
|
+
} else {
|
|
104
|
+
cleanLines.push(line);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return { cleanCode: cleanLines.join("\n"), lineClasses, hasFocus };
|
|
108
|
+
}
|
|
109
|
+
function annotateLines(html, lineClasses, highlightLines, hasFocus, lineNumbers) {
|
|
110
|
+
let lineIndex = 0;
|
|
111
|
+
return html.replace(/<span class="line">/g, () => {
|
|
112
|
+
lineIndex++;
|
|
113
|
+
const annotationCls = lineClasses.get(lineIndex) ?? "";
|
|
114
|
+
const classes = ["line"];
|
|
115
|
+
if (annotationCls) classes.push(...annotationCls.split(" "));
|
|
116
|
+
else if (highlightLines.has(lineIndex)) classes.push("highlighted");
|
|
117
|
+
if (hasFocus && !annotationCls.includes("focus")) classes.push("dimmed");
|
|
118
|
+
const numHtml = lineNumbers ? `<span class="line-number">${lineIndex}</span>` : "";
|
|
119
|
+
return `${numHtml}<span class="${classes.join(" ")}">`;
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
async function createHighlighter() {
|
|
123
|
+
if (!pending) pending = createShiki({ themes: [THEME], langs: LANGUAGES });
|
|
124
|
+
const highlighter = await pending;
|
|
125
|
+
const loaded = new Set(highlighter.getLoadedLanguages());
|
|
126
|
+
return (code, lang) => {
|
|
127
|
+
const resolved = ALIASES[lang?.toLowerCase()] ?? lang?.toLowerCase();
|
|
128
|
+
if (!resolved || !loaded.has(resolved)) return escapeHtml(code);
|
|
129
|
+
return unwrapCode(highlighter.codeToHtml(code, { lang: resolved, theme: THEME }));
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
function renderFence(code, info, highlight) {
|
|
133
|
+
const { lang, highlightLines, lineNumbers, title } = parseFenceInfo(info);
|
|
134
|
+
if (lang === "mermaid") {
|
|
135
|
+
return `<div class="dp-mermaid language-mermaid">${escapeHtml(code.trim())}</div>`;
|
|
136
|
+
}
|
|
137
|
+
const { cleanCode, lineClasses, hasFocus } = extractAnnotations(code);
|
|
138
|
+
const innerHtml = highlight(cleanCode.trimEnd(), lang);
|
|
139
|
+
const annotated = annotateLines(innerHtml, lineClasses, highlightLines, hasFocus, lineNumbers);
|
|
140
|
+
const hasAnnotations = highlightLines.size > 0 || lineClasses.size > 0;
|
|
141
|
+
const titleHtml = title ? `<div class="code-block-title"><span>${escapeHtml(title)}</span></div>` : "";
|
|
142
|
+
const preClass = [
|
|
143
|
+
lineNumbers ? "line-numbers" : "",
|
|
144
|
+
hasAnnotations ? "has-annotations" : "",
|
|
145
|
+
hasFocus ? "has-focus" : ""
|
|
146
|
+
].filter(Boolean).join(" ");
|
|
147
|
+
const langClass = lang ? `language-${lang}` : "";
|
|
148
|
+
return `<div class="code-block ${langClass}">${titleHtml}<div class="code-block-inner"><pre class="${preClass}"><code>${annotated}</code></pre><button class="code-copy-btn" type="button" aria-label="Copy code" data-copy>\u2398</button></div></div>`;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// src/layout.ts
|
|
152
|
+
import { navLink } from "@domphy/app";
|
|
153
|
+
import { toolbar, toolbarSpacer } from "@domphy/ui";
|
|
154
|
+
|
|
155
|
+
// src/routes.ts
|
|
156
|
+
import { readdirSync, statSync } from "fs";
|
|
157
|
+
import { join, posix, relative, sep } from "path";
|
|
158
|
+
var NON_PAGE_DIRS = /* @__PURE__ */ new Set(["snippets", "demos", "node_modules", ".git"]);
|
|
159
|
+
function routeForFile(srcRelativePath) {
|
|
160
|
+
const posixPath = srcRelativePath.split(sep).join(posix.sep);
|
|
161
|
+
const withoutExt = posixPath.replace(/\.md$/, "");
|
|
162
|
+
const segments = withoutExt.split("/");
|
|
163
|
+
const last = segments[segments.length - 1];
|
|
164
|
+
if (last === "index") {
|
|
165
|
+
segments.pop();
|
|
166
|
+
return segments.length === 0 ? "/" : `/${segments.join("/")}/`;
|
|
167
|
+
}
|
|
168
|
+
return `/${segments.join("/")}`;
|
|
169
|
+
}
|
|
170
|
+
function outFileForRoute(route) {
|
|
171
|
+
if (route === "/") return "index.html";
|
|
172
|
+
const trimmed = route.replace(/^\/+/, "").replace(/\/+$/, "");
|
|
173
|
+
return `${trimmed}/index.html`;
|
|
174
|
+
}
|
|
175
|
+
function listMarkdown(dir) {
|
|
176
|
+
const found = [];
|
|
177
|
+
for (const name of readdirSync(dir)) {
|
|
178
|
+
const full = join(dir, name);
|
|
179
|
+
const stats = statSync(full);
|
|
180
|
+
if (stats.isDirectory()) {
|
|
181
|
+
if (NON_PAGE_DIRS.has(name) || name.startsWith(".")) continue;
|
|
182
|
+
found.push(...listMarkdown(full));
|
|
183
|
+
} else if (name.endsWith(".md") && name.toLowerCase() !== "readme.md") {
|
|
184
|
+
found.push(full);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
return found;
|
|
188
|
+
}
|
|
189
|
+
function discoverPages(srcDir) {
|
|
190
|
+
const files = listMarkdown(srcDir);
|
|
191
|
+
const pages = files.map((filePath) => {
|
|
192
|
+
const rel = relative(srcDir, filePath);
|
|
193
|
+
const route = routeForFile(rel);
|
|
194
|
+
return { route, outFile: outFileForRoute(route), filePath };
|
|
195
|
+
});
|
|
196
|
+
pages.sort((a, b) => a.route.localeCompare(b.route));
|
|
197
|
+
return pages;
|
|
198
|
+
}
|
|
199
|
+
function flattenSidebar(items) {
|
|
200
|
+
const out = [];
|
|
201
|
+
for (const item of items) {
|
|
202
|
+
if (item.link) out.push({ text: item.text, link: item.link });
|
|
203
|
+
if (item.items) out.push(...flattenSidebar(item.items));
|
|
204
|
+
}
|
|
205
|
+
return out;
|
|
206
|
+
}
|
|
207
|
+
function sidebarForRoute(route, config) {
|
|
208
|
+
let bestPrefix = "";
|
|
209
|
+
for (const prefix of Object.keys(config.themeConfig.sidebar)) {
|
|
210
|
+
if (route.startsWith(prefix) && prefix.length > bestPrefix.length) {
|
|
211
|
+
bestPrefix = prefix;
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
return bestPrefix ? config.themeConfig.sidebar[bestPrefix] : [];
|
|
215
|
+
}
|
|
216
|
+
function prevNextForRoute(route, config) {
|
|
217
|
+
const flat = flattenSidebar(sidebarForRoute(route, config));
|
|
218
|
+
const index = flat.findIndex(
|
|
219
|
+
(item) => item.link === route || item.link === route.replace(/\/$/, "") || `${item.link}/` === route
|
|
220
|
+
);
|
|
221
|
+
if (index === -1) return {};
|
|
222
|
+
return {
|
|
223
|
+
prev: index > 0 ? flat[index - 1] : void 0,
|
|
224
|
+
next: index < flat.length - 1 ? flat[index + 1] : void 0
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
// src/layout.ts
|
|
229
|
+
var SOCIAL_LABELS = {
|
|
230
|
+
github: "GitHub",
|
|
231
|
+
twitter: "Twitter",
|
|
232
|
+
discord: "Discord",
|
|
233
|
+
youtube: "YouTube",
|
|
234
|
+
linkedin: "LinkedIn",
|
|
235
|
+
mastodon: "Mastodon",
|
|
236
|
+
npm: "npm",
|
|
237
|
+
bluesky: "Bluesky"
|
|
238
|
+
};
|
|
239
|
+
function socialLinkEl(social) {
|
|
240
|
+
const name = social.icon.toLowerCase();
|
|
241
|
+
const isUrl = social.icon.startsWith("http") || social.icon.startsWith("/");
|
|
242
|
+
const innerEl = isUrl ? { img: null, src: social.icon, alt: social.ariaLabel ?? name, width: "18", height: "18" } : { span: "", class: `dp-social-icon dp-icon-${name}`, ariaHidden: "true" };
|
|
243
|
+
return {
|
|
244
|
+
a: [innerEl],
|
|
245
|
+
href: social.link,
|
|
246
|
+
class: `dp-social-link dp-social-${name}`,
|
|
247
|
+
ariaLabel: social.ariaLabel ?? SOCIAL_LABELS[name] ?? social.icon,
|
|
248
|
+
target: "_blank",
|
|
249
|
+
rel: "noopener noreferrer"
|
|
250
|
+
};
|
|
251
|
+
}
|
|
252
|
+
function pageLink(text2, href, className) {
|
|
253
|
+
return { a: text2, href, class: className, $: [navLink({ href })] };
|
|
254
|
+
}
|
|
255
|
+
function navDropdown(item) {
|
|
256
|
+
return {
|
|
257
|
+
div: [
|
|
258
|
+
{ span: item.text, class: "dp-nav-dropdown-label" },
|
|
259
|
+
{ div: item.items.map((child) => pageLink(child.text, child.link)), class: "dp-nav-dropdown-menu" }
|
|
260
|
+
],
|
|
261
|
+
class: "dp-nav-dropdown"
|
|
262
|
+
};
|
|
263
|
+
}
|
|
264
|
+
function announcementBar(config) {
|
|
265
|
+
const bar = config.themeConfig.announcementBar;
|
|
266
|
+
if (!bar) return null;
|
|
267
|
+
const idAttr = bar.id ? bar.id : "";
|
|
268
|
+
const children = [
|
|
269
|
+
{ span: bar.text, class: "dp-announcement-text" }
|
|
270
|
+
];
|
|
271
|
+
if (bar.dismissible !== false) {
|
|
272
|
+
children.push({ button: "\u2715", type: "button", class: "dp-announcement-close", dataDismissAnnouncement: "", ariaLabel: "Dismiss" });
|
|
273
|
+
}
|
|
274
|
+
return {
|
|
275
|
+
div: children,
|
|
276
|
+
class: "dp-announcement",
|
|
277
|
+
...idAttr ? { dataId: idAttr } : {}
|
|
278
|
+
};
|
|
279
|
+
}
|
|
280
|
+
function header(config) {
|
|
281
|
+
const searchEnabled = config.themeConfig.search !== false;
|
|
282
|
+
const logoEl = config.themeConfig.logo ? { a: [{ img: null, src: config.themeConfig.logo, alt: config.title, class: "dp-logo-img" }], href: config.base, class: "dp-logo" } : { a: config.title, href: config.base, class: "dp-logo" };
|
|
283
|
+
const socialEls = (config.themeConfig.socialLinks ?? []).map(socialLinkEl);
|
|
284
|
+
return {
|
|
285
|
+
header: [
|
|
286
|
+
logoEl,
|
|
287
|
+
toolbarSpacer(),
|
|
288
|
+
{
|
|
289
|
+
nav: config.themeConfig.nav.map(
|
|
290
|
+
(item) => item.items ? navDropdown(item) : pageLink(item.text, item.link)
|
|
291
|
+
),
|
|
292
|
+
$: [toolbar({ gap: 4 })],
|
|
293
|
+
class: "dp-nav",
|
|
294
|
+
ariaLabel: "Primary"
|
|
295
|
+
},
|
|
296
|
+
{
|
|
297
|
+
div: [
|
|
298
|
+
...searchEnabled ? [{
|
|
299
|
+
div: [{
|
|
300
|
+
input: null,
|
|
301
|
+
type: "search",
|
|
302
|
+
placeholder: typeof config.themeConfig.search === "object" && config.themeConfig.search.placeholder || "Search...",
|
|
303
|
+
class: "dp-search-static",
|
|
304
|
+
ariaLabel: "Search documentation"
|
|
305
|
+
}],
|
|
306
|
+
dataIsland: "search",
|
|
307
|
+
class: "dp-search-slot"
|
|
308
|
+
}] : [],
|
|
309
|
+
...socialEls,
|
|
310
|
+
{ button: "\u25D0", type: "button", class: "dp-theme-toggle", ariaLabel: "Toggle dark mode", dataThemeToggle: "" },
|
|
311
|
+
{ button: "\u2630", type: "button", class: "dp-menu-toggle", ariaLabel: "Toggle menu", dataMenuToggle: "" }
|
|
312
|
+
],
|
|
313
|
+
$: [toolbar({ gap: 2 })],
|
|
314
|
+
class: "dp-header-actions"
|
|
315
|
+
}
|
|
316
|
+
],
|
|
317
|
+
$: [toolbar({ gap: 4 })],
|
|
318
|
+
class: "dp-header"
|
|
319
|
+
};
|
|
320
|
+
}
|
|
321
|
+
function sidebarBadge(badge) {
|
|
322
|
+
return { span: badge.text, class: `dp-badge dp-badge-${badge.type ?? "tip"}` };
|
|
323
|
+
}
|
|
324
|
+
function pageLinkWithBadge(text2, href, badge) {
|
|
325
|
+
if (!badge) return pageLink(text2, href);
|
|
326
|
+
return {
|
|
327
|
+
a: [{ span: text2 }, sidebarBadge(badge)],
|
|
328
|
+
href,
|
|
329
|
+
$: [navLink({ href })],
|
|
330
|
+
class: "dp-sidebar-link-with-badge"
|
|
331
|
+
};
|
|
332
|
+
}
|
|
333
|
+
function sidebarGroup(group) {
|
|
334
|
+
const children = [];
|
|
335
|
+
const isCollapsible = group.items && group.items.length > 0;
|
|
336
|
+
if (group.link) {
|
|
337
|
+
children.push(pageLinkWithBadge(group.text, group.link, group.badge));
|
|
338
|
+
} else {
|
|
339
|
+
const titleChildren = [
|
|
340
|
+
{ span: group.text }
|
|
341
|
+
];
|
|
342
|
+
if (group.badge) titleChildren.push(sidebarBadge(group.badge));
|
|
343
|
+
if (isCollapsible) {
|
|
344
|
+
titleChildren.push({
|
|
345
|
+
button: group.collapsed ? "\u203A" : "\u2039",
|
|
346
|
+
type: "button",
|
|
347
|
+
class: "dp-sidebar-toggle",
|
|
348
|
+
ariaLabel: group.collapsed ? "Expand" : "Collapse",
|
|
349
|
+
dataSidebarToggle: ""
|
|
350
|
+
});
|
|
351
|
+
}
|
|
352
|
+
children.push({ div: titleChildren, class: "dp-sidebar-title" });
|
|
353
|
+
}
|
|
354
|
+
if (group.items) {
|
|
355
|
+
const itemsEl = [];
|
|
356
|
+
for (const item of group.items) {
|
|
357
|
+
if (item.items) {
|
|
358
|
+
itemsEl.push({ div: item.text, class: "dp-sidebar-subtitle" });
|
|
359
|
+
for (const leaf of item.items) {
|
|
360
|
+
if (leaf.link) itemsEl.push(pageLinkWithBadge(leaf.text, leaf.link, leaf.badge));
|
|
361
|
+
}
|
|
362
|
+
} else if (item.link) {
|
|
363
|
+
itemsEl.push(pageLinkWithBadge(item.text, item.link, item.badge));
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
children.push({ div: itemsEl, class: "dp-sidebar-items" });
|
|
367
|
+
}
|
|
368
|
+
const groupClass = ["dp-sidebar-group", isCollapsible && group.collapsed ? "collapsed" : ""].filter(Boolean).join(" ");
|
|
369
|
+
return { div: children, class: groupClass };
|
|
370
|
+
}
|
|
371
|
+
function sidebar(ctx) {
|
|
372
|
+
const groups = sidebarForRoute(ctx.route, ctx.config);
|
|
373
|
+
return { nav: groups.map(sidebarGroup), class: "dp-sidebar", ariaLabel: "Documentation" };
|
|
374
|
+
}
|
|
375
|
+
function tocAside(ctx) {
|
|
376
|
+
if (ctx.frontmatter.aside === false) return null;
|
|
377
|
+
const [minLevel, maxLevel] = ctx.config.themeConfig.outline?.level ?? [2, 3];
|
|
378
|
+
const entries = ctx.toc.filter((e) => e.level >= minLevel && e.level <= maxLevel);
|
|
379
|
+
if (entries.length === 0) return null;
|
|
380
|
+
return {
|
|
381
|
+
aside: [
|
|
382
|
+
{ div: "On this page", class: "dp-aside-title" },
|
|
383
|
+
{ nav: entries.map((e) => ({ a: e.text, href: `#${e.slug}`, class: `dp-toc-${e.level}` })), class: "dp-toc" }
|
|
384
|
+
],
|
|
385
|
+
class: "dp-aside"
|
|
386
|
+
};
|
|
387
|
+
}
|
|
388
|
+
function prevNext(ctx) {
|
|
389
|
+
const { prev, next } = prevNextForRoute(ctx.route, ctx.config);
|
|
390
|
+
if (!prev && !next) return null;
|
|
391
|
+
return {
|
|
392
|
+
nav: [
|
|
393
|
+
prev ? { a: [{ small: "Previous" }, { span: prev.text }], href: prev.link, class: "prev" } : { span: "" },
|
|
394
|
+
next ? { a: [{ small: "Next" }, { span: next.text }], href: next.link, class: "next" } : { span: "" }
|
|
395
|
+
],
|
|
396
|
+
class: "dp-prevnext",
|
|
397
|
+
ariaLabel: "Page navigation"
|
|
398
|
+
};
|
|
399
|
+
}
|
|
400
|
+
function docFooter(ctx) {
|
|
401
|
+
const { editLink } = ctx.config.themeConfig;
|
|
402
|
+
const showLastUpdated = ctx.config.lastUpdated;
|
|
403
|
+
const hasEdit = editLink && ctx.filePath;
|
|
404
|
+
const hasDate = showLastUpdated && ctx.lastUpdated;
|
|
405
|
+
if (!hasEdit && !hasDate && !ctx.readingTime) return null;
|
|
406
|
+
const children = [];
|
|
407
|
+
if (hasDate) {
|
|
408
|
+
const date = new Date(ctx.lastUpdated);
|
|
409
|
+
const formatted = date.toLocaleDateString("en-US", { year: "numeric", month: "long", day: "numeric" });
|
|
410
|
+
children.push({ span: [`Last updated: `, { time: formatted, dateTime: ctx.lastUpdated, class: "dp-last-updated-date" }], class: "dp-last-updated" });
|
|
411
|
+
}
|
|
412
|
+
if (ctx.readingTime) {
|
|
413
|
+
children.push({ span: `${ctx.readingTime} min read`, class: "dp-reading-time" });
|
|
414
|
+
}
|
|
415
|
+
if (hasEdit) {
|
|
416
|
+
const pattern = editLink.pattern;
|
|
417
|
+
const href = pattern.replace(/:path/g, ctx.filePath);
|
|
418
|
+
children.push({ a: editLink.text ?? "Edit this page", href, class: "dp-edit-link", target: "_blank", rel: "noopener noreferrer" });
|
|
419
|
+
}
|
|
420
|
+
return { div: children, class: "dp-doc-footer" };
|
|
421
|
+
}
|
|
422
|
+
function pageBadge(frontmatter) {
|
|
423
|
+
const badge = frontmatter.badge;
|
|
424
|
+
if (!badge) return null;
|
|
425
|
+
const text2 = typeof badge === "string" ? badge : badge.text ?? "";
|
|
426
|
+
const type = typeof badge === "object" ? badge.type ?? "tip" : "tip";
|
|
427
|
+
if (!text2) return null;
|
|
428
|
+
return { span: text2, class: `dp-badge dp-badge-${type} dp-page-badge` };
|
|
429
|
+
}
|
|
430
|
+
function pageShell(ctx) {
|
|
431
|
+
const main = [];
|
|
432
|
+
const badge = pageBadge(ctx.frontmatter);
|
|
433
|
+
if (badge) main.push({ div: [badge], class: "dp-page-badge-row" });
|
|
434
|
+
main.push({ div: ctx.body, class: "dp-content" });
|
|
435
|
+
const pn = prevNext(ctx);
|
|
436
|
+
if (pn) main.push(pn);
|
|
437
|
+
const footer = docFooter(ctx);
|
|
438
|
+
if (footer) main.push(footer);
|
|
439
|
+
const shellChildren = [sidebar(ctx), { main, class: "dp-main" }];
|
|
440
|
+
const aside = tocAside(ctx);
|
|
441
|
+
if (aside) shellChildren.push(aside);
|
|
442
|
+
const bar = announcementBar(ctx.config);
|
|
443
|
+
return {
|
|
444
|
+
div: [
|
|
445
|
+
...bar ? [bar] : [],
|
|
446
|
+
header(ctx.config),
|
|
447
|
+
{ div: shellChildren, class: "dp-shell" },
|
|
448
|
+
{ footer: ctx.config.themeConfig.footerMessage ?? "", class: "dp-footer" }
|
|
449
|
+
]
|
|
450
|
+
};
|
|
451
|
+
}
|
|
452
|
+
function heroSection(hero) {
|
|
453
|
+
const children = [];
|
|
454
|
+
if (hero.name) children.push({ div: hero.name, class: "dp-hero-name" });
|
|
455
|
+
if (hero.text) children.push({ h1: hero.text, class: "dp-hero-text" });
|
|
456
|
+
if (hero.tagline) children.push({ p: hero.tagline, class: "dp-hero-tagline" });
|
|
457
|
+
if (hero.actions?.length) {
|
|
458
|
+
children.push({ div: hero.actions.map((a) => ({ a: a.text, href: a.link, class: `dp-hero-action ${a.theme ?? "brand"}` })), class: "dp-hero-actions" });
|
|
459
|
+
}
|
|
460
|
+
return { section: children, class: "dp-hero" };
|
|
461
|
+
}
|
|
462
|
+
function featuresSection(features) {
|
|
463
|
+
return {
|
|
464
|
+
div: features.map((f) => {
|
|
465
|
+
const inner = [];
|
|
466
|
+
if (f.icon) inner.push({ div: f.icon, class: "dp-feature-icon" });
|
|
467
|
+
inner.push({ div: f.title, class: "dp-feature-title" });
|
|
468
|
+
inner.push({ p: f.details, class: "dp-feature-details" });
|
|
469
|
+
const el = { div: inner, class: "dp-feature" };
|
|
470
|
+
return f.link ? { a: [el], href: f.link, class: "dp-feature-link" } : el;
|
|
471
|
+
}),
|
|
472
|
+
class: "dp-features"
|
|
473
|
+
};
|
|
474
|
+
}
|
|
475
|
+
function homeShell(ctx) {
|
|
476
|
+
const main = [];
|
|
477
|
+
const hero = ctx.frontmatter.hero;
|
|
478
|
+
const features = ctx.frontmatter.features;
|
|
479
|
+
if (hero) main.push(heroSection(hero));
|
|
480
|
+
if (features?.length) main.push(featuresSection(features));
|
|
481
|
+
main.push({ div: ctx.body, class: "dp-content dp-home" });
|
|
482
|
+
const bar = announcementBar(ctx.config);
|
|
483
|
+
return {
|
|
484
|
+
div: [
|
|
485
|
+
...bar ? [bar] : [],
|
|
486
|
+
header(ctx.config),
|
|
487
|
+
{ main, class: "dp-main dp-main-home" },
|
|
488
|
+
{ footer: ctx.config.themeConfig.footerMessage ?? "", class: "dp-footer" }
|
|
489
|
+
]
|
|
490
|
+
};
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
// src/pipeline.ts
|
|
494
|
+
import { readFileSync } from "fs";
|
|
495
|
+
import { dirname, extname, isAbsolute, resolve } from "path";
|
|
496
|
+
import { splitFrontmatter, tokensToDomphy } from "@domphy/markdown";
|
|
497
|
+
import MarkdownIt from "markdown-it";
|
|
498
|
+
import container from "markdown-it-container";
|
|
499
|
+
import markUntyped from "markdown-it-mark";
|
|
500
|
+
import subUntyped from "markdown-it-sub";
|
|
501
|
+
import supUntyped from "markdown-it-sup";
|
|
502
|
+
import includeUntyped from "markdown-it-include";
|
|
503
|
+
import emojiPkg from "markdown-it-emoji";
|
|
504
|
+
var include = includeUntyped;
|
|
505
|
+
var markPlugin = markUntyped;
|
|
506
|
+
var subPlugin = subUntyped;
|
|
507
|
+
var supPlugin = supUntyped;
|
|
508
|
+
var emojiPlugin = emojiPkg.full ?? emojiPkg;
|
|
509
|
+
var CODE_IMPORT_PATTERN = /^<<<\s+(\S+?)(?:\s+\[([^\]]*)\])?\s*$/gm;
|
|
510
|
+
var EXT_LANG = {
|
|
511
|
+
".ts": "ts",
|
|
512
|
+
".tsx": "tsx",
|
|
513
|
+
".js": "js",
|
|
514
|
+
".jsx": "jsx",
|
|
515
|
+
".mjs": "js",
|
|
516
|
+
".cjs": "js",
|
|
517
|
+
".json": "json",
|
|
518
|
+
".css": "css",
|
|
519
|
+
".html": "html",
|
|
520
|
+
".vue": "vue",
|
|
521
|
+
".md": "markdown",
|
|
522
|
+
".sh": "bash",
|
|
523
|
+
".bash": "bash",
|
|
524
|
+
".yml": "yaml",
|
|
525
|
+
".yaml": "yaml",
|
|
526
|
+
".rb": "ruby",
|
|
527
|
+
".py": "python",
|
|
528
|
+
".go": "go",
|
|
529
|
+
".rs": "rust"
|
|
530
|
+
};
|
|
531
|
+
function resolveSpecifier(spec, fileDir, docsDir) {
|
|
532
|
+
if (spec.startsWith("@/")) return resolve(dirname(docsDir), spec.slice(2));
|
|
533
|
+
if (isAbsolute(spec)) return spec;
|
|
534
|
+
return resolve(fileDir, spec);
|
|
535
|
+
}
|
|
536
|
+
function expandCodeImports(body, fileDir, docsDir) {
|
|
537
|
+
return body.replace(CODE_IMPORT_PATTERN, (_whole, rawPath, label) => {
|
|
538
|
+
const absolute = resolveSpecifier(rawPath, fileDir, docsDir);
|
|
539
|
+
const fence = "```";
|
|
540
|
+
let contents;
|
|
541
|
+
try {
|
|
542
|
+
contents = readFileSync(absolute, "utf8");
|
|
543
|
+
} catch {
|
|
544
|
+
return [fence, `Could not import: ${rawPath}`, fence].join("\n");
|
|
545
|
+
}
|
|
546
|
+
const language = EXT_LANG[extname(absolute).toLowerCase()] ?? "";
|
|
547
|
+
const info = label ? `${language} [${label}]` : language;
|
|
548
|
+
return [fence + info, contents.trimEnd(), fence].join("\n");
|
|
549
|
+
});
|
|
550
|
+
}
|
|
551
|
+
function stripScriptBlocks(source) {
|
|
552
|
+
return source.replace(/<script\b[^>]*>[\s\S]*?<\/script>/gi, "").replace(/^\s*\n/, "");
|
|
553
|
+
}
|
|
554
|
+
var ADMONITION_TITLES = {
|
|
555
|
+
tip: "TIP",
|
|
556
|
+
warning: "WARNING",
|
|
557
|
+
info: "INFO",
|
|
558
|
+
danger: "DANGER",
|
|
559
|
+
note: "NOTE",
|
|
560
|
+
abstract: "ABSTRACT",
|
|
561
|
+
success: "SUCCESS",
|
|
562
|
+
question: "QUESTION",
|
|
563
|
+
failure: "FAILURE",
|
|
564
|
+
bug: "BUG",
|
|
565
|
+
example: "EXAMPLE",
|
|
566
|
+
quote: "QUOTE"
|
|
567
|
+
};
|
|
568
|
+
function containerTitle(info, type) {
|
|
569
|
+
return info.slice(info.indexOf(type) + type.length).trim();
|
|
570
|
+
}
|
|
571
|
+
function buildTitleTokens(Token, tag, openType, closeType, className, title) {
|
|
572
|
+
const open = new Token(openType, tag, 1);
|
|
573
|
+
open.block = true;
|
|
574
|
+
if (className) open.attrSet("class", className);
|
|
575
|
+
const inline = new Token("inline", "", 0);
|
|
576
|
+
inline.content = title;
|
|
577
|
+
inline.children = [];
|
|
578
|
+
const text2 = new Token("text", "", 0);
|
|
579
|
+
text2.content = title;
|
|
580
|
+
inline.children.push(text2);
|
|
581
|
+
const close = new Token(closeType, tag, -1);
|
|
582
|
+
close.block = true;
|
|
583
|
+
return [open, inline, close];
|
|
584
|
+
}
|
|
585
|
+
function buildHtmlBlock(Token, content) {
|
|
586
|
+
const token = new Token("html_block", "", 0);
|
|
587
|
+
token.content = content;
|
|
588
|
+
token.block = true;
|
|
589
|
+
return token;
|
|
590
|
+
}
|
|
591
|
+
function buildCodeGroupTokens(Token, tokens, openIndex, closeIndex, groupId) {
|
|
592
|
+
const open = tokens[openIndex];
|
|
593
|
+
open.tag = "div";
|
|
594
|
+
open.attrSet("class", "code-group");
|
|
595
|
+
const close = tokens[closeIndex];
|
|
596
|
+
close.tag = "div";
|
|
597
|
+
const fences = [];
|
|
598
|
+
for (let i = openIndex + 1; i < closeIndex; i++) {
|
|
599
|
+
const token = tokens[i];
|
|
600
|
+
if (token.type !== "fence") continue;
|
|
601
|
+
const info = (token.info ?? "").trim();
|
|
602
|
+
const labelMatch = info.match(/\[([^\]]+)\]/);
|
|
603
|
+
const language = info.split(/\s+/, 1)[0] ?? "";
|
|
604
|
+
fences.push({ token, label: labelMatch ? labelMatch[1] : language || "Code" });
|
|
605
|
+
}
|
|
606
|
+
if (fences.length === 0) return tokens.slice(openIndex, closeIndex + 1);
|
|
607
|
+
const inputsHtml = fences.map(
|
|
608
|
+
(_, i) => `<input type="radio" name="cg-${groupId}" id="cgt-${groupId}-${i}"${i === 0 ? " checked" : ""}>`
|
|
609
|
+
).join("");
|
|
610
|
+
const labelsHtml = fences.map(
|
|
611
|
+
(fence, i) => `<label for="cgt-${groupId}-${i}">${escapeHtml(fence.label)}</label>`
|
|
612
|
+
).join("");
|
|
613
|
+
const inner = [
|
|
614
|
+
buildHtmlBlock(Token, `${inputsHtml}<div class="tabs">${labelsHtml}</div>`),
|
|
615
|
+
buildHtmlBlock(Token, `<div class="blocks">`)
|
|
616
|
+
];
|
|
617
|
+
fences.forEach((fence) => {
|
|
618
|
+
fence.token.info = (fence.token.info ?? "").replace(/\[[^\]]*\]/, "").trim();
|
|
619
|
+
inner.push(fence.token);
|
|
620
|
+
});
|
|
621
|
+
inner.push(buildHtmlBlock(Token, `</div>`));
|
|
622
|
+
return [open, ...inner, close];
|
|
623
|
+
}
|
|
624
|
+
function shapeContainers(tokens) {
|
|
625
|
+
if (tokens.length === 0) return tokens;
|
|
626
|
+
const Token = tokens[0].constructor;
|
|
627
|
+
const output = [];
|
|
628
|
+
let groupCounter = 0;
|
|
629
|
+
const ALL_ADMONITIONS = Object.keys(ADMONITION_TITLES).join("|");
|
|
630
|
+
const admonitionRe = new RegExp(`^container_(${ALL_ADMONITIONS})_open$`);
|
|
631
|
+
const admonitionCloseRe = new RegExp(`^container_(${ALL_ADMONITIONS})_close$`);
|
|
632
|
+
for (let i = 0; i < tokens.length; i++) {
|
|
633
|
+
const token = tokens[i];
|
|
634
|
+
const admonition = token.type.match(admonitionRe);
|
|
635
|
+
if (admonition) {
|
|
636
|
+
const type = admonition[1];
|
|
637
|
+
token.tag = "div";
|
|
638
|
+
token.attrSet("class", `custom-block ${type}`);
|
|
639
|
+
const custom = containerTitle(token.info.trim(), type);
|
|
640
|
+
output.push(token);
|
|
641
|
+
output.push(...buildTitleTokens(Token, "p", "paragraph_open", "paragraph_close", "custom-block-title", custom || ADMONITION_TITLES[type] || type.toUpperCase()));
|
|
642
|
+
continue;
|
|
643
|
+
}
|
|
644
|
+
if (admonitionCloseRe.test(token.type)) {
|
|
645
|
+
token.tag = "div";
|
|
646
|
+
output.push(token);
|
|
647
|
+
continue;
|
|
648
|
+
}
|
|
649
|
+
if (token.type === "container_details_open") {
|
|
650
|
+
token.tag = "details";
|
|
651
|
+
token.attrSet("class", "custom-block details");
|
|
652
|
+
output.push(token);
|
|
653
|
+
output.push(...buildTitleTokens(Token, "summary", "summary_open", "summary_close", null, containerTitle(token.info.trim(), "details") || "Details"));
|
|
654
|
+
continue;
|
|
655
|
+
}
|
|
656
|
+
if (token.type === "container_details_close") {
|
|
657
|
+
token.tag = "details";
|
|
658
|
+
output.push(token);
|
|
659
|
+
continue;
|
|
660
|
+
}
|
|
661
|
+
if (token.type === "container_steps_open") {
|
|
662
|
+
token.tag = "div";
|
|
663
|
+
token.attrSet("class", "custom-block steps");
|
|
664
|
+
output.push(token);
|
|
665
|
+
continue;
|
|
666
|
+
}
|
|
667
|
+
if (token.type === "container_steps_close") {
|
|
668
|
+
token.tag = "div";
|
|
669
|
+
output.push(token);
|
|
670
|
+
continue;
|
|
671
|
+
}
|
|
672
|
+
if (token.type === "container_code-group_open") {
|
|
673
|
+
let depth = 0, closeIndex = -1;
|
|
674
|
+
for (let j = i; j < tokens.length; j++) {
|
|
675
|
+
if (tokens[j].type === "container_code-group_open") depth++;
|
|
676
|
+
else if (tokens[j].type === "container_code-group_close") {
|
|
677
|
+
depth--;
|
|
678
|
+
if (depth === 0) {
|
|
679
|
+
closeIndex = j;
|
|
680
|
+
break;
|
|
681
|
+
}
|
|
682
|
+
}
|
|
683
|
+
}
|
|
684
|
+
if (closeIndex === -1) {
|
|
685
|
+
output.push(token);
|
|
686
|
+
continue;
|
|
687
|
+
}
|
|
688
|
+
output.push(...buildCodeGroupTokens(Token, tokens, i, closeIndex, groupCounter++));
|
|
689
|
+
i = closeIndex;
|
|
690
|
+
continue;
|
|
691
|
+
}
|
|
692
|
+
output.push(token);
|
|
693
|
+
}
|
|
694
|
+
return output;
|
|
695
|
+
}
|
|
696
|
+
function shapeTaskLists(tokens) {
|
|
697
|
+
if (tokens.length === 0) return tokens;
|
|
698
|
+
const Token = tokens[0].constructor;
|
|
699
|
+
for (let i = 1; i < tokens.length; i++) {
|
|
700
|
+
const token = tokens[i];
|
|
701
|
+
if (token.type !== "inline" || !token.children?.length) continue;
|
|
702
|
+
const prev = tokens[i - 1];
|
|
703
|
+
if (prev?.type !== "list_item_open") continue;
|
|
704
|
+
const firstChild = token.children[0];
|
|
705
|
+
if (firstChild.type !== "text") continue;
|
|
706
|
+
const text2 = firstChild.content;
|
|
707
|
+
const isTask = text2.startsWith("[ ] ") || text2.startsWith("[x] ") || text2.startsWith("[X] ");
|
|
708
|
+
if (!isTask) continue;
|
|
709
|
+
const checked = text2[1].toLowerCase() === "x";
|
|
710
|
+
firstChild.content = text2.slice(4);
|
|
711
|
+
token.content = token.content.replace(/^\[[ xX]\] /, "");
|
|
712
|
+
prev.attrSet("class", ((prev.attrGet("class") ?? "") + " task-list-item").trim());
|
|
713
|
+
const checkToken = new Token("html_inline", "", 0);
|
|
714
|
+
checkToken.content = `<input type="checkbox"${checked ? " checked" : ""} disabled class="task-list-check" aria-label="${checked ? "done" : "todo"}">`;
|
|
715
|
+
token.children.unshift(checkToken);
|
|
716
|
+
}
|
|
717
|
+
return tokens;
|
|
718
|
+
}
|
|
719
|
+
function createParser(docsDir, highlight) {
|
|
720
|
+
const md = new MarkdownIt({ html: true, linkify: true, typographer: false });
|
|
721
|
+
md.enable(["strikethrough", "table"]);
|
|
722
|
+
md.use(include, { root: docsDir });
|
|
723
|
+
md.use(markPlugin);
|
|
724
|
+
md.use(subPlugin);
|
|
725
|
+
md.use(supPlugin);
|
|
726
|
+
md.use(emojiPlugin);
|
|
727
|
+
const noopRender = () => "";
|
|
728
|
+
const ADMONITION_NAMES = Object.keys(ADMONITION_TITLES);
|
|
729
|
+
for (const name of [...ADMONITION_NAMES, "details", "code-group", "steps"]) {
|
|
730
|
+
md.use(container, name, { render: noopRender });
|
|
731
|
+
}
|
|
732
|
+
md.core.ruler.push("press_containers", (state) => {
|
|
733
|
+
state.tokens = shapeContainers(state.tokens);
|
|
734
|
+
return true;
|
|
735
|
+
});
|
|
736
|
+
md.core.ruler.push("press_task_lists", (state) => {
|
|
737
|
+
state.tokens = shapeTaskLists(state.tokens);
|
|
738
|
+
return true;
|
|
739
|
+
});
|
|
740
|
+
md.core.ruler.push("press_fences", (state) => {
|
|
741
|
+
for (const token of state.tokens) {
|
|
742
|
+
if (token.type !== "fence") continue;
|
|
743
|
+
const html = renderFence(token.content, token.info ?? "", highlight);
|
|
744
|
+
token.type = "html_block";
|
|
745
|
+
token.content = html;
|
|
746
|
+
token.tag = "";
|
|
747
|
+
}
|
|
748
|
+
return true;
|
|
749
|
+
});
|
|
750
|
+
md.core.ruler.push("press_external_links", (state) => {
|
|
751
|
+
for (const token of state.tokens) {
|
|
752
|
+
if (token.type !== "inline" || !token.children) continue;
|
|
753
|
+
for (const child of token.children) {
|
|
754
|
+
if (child.type !== "link_open") continue;
|
|
755
|
+
const href = child.attrGet("href") ?? "";
|
|
756
|
+
if (href.startsWith("http://") || href.startsWith("https://")) {
|
|
757
|
+
child.attrSet("target", "_blank");
|
|
758
|
+
child.attrSet("rel", "noopener noreferrer");
|
|
759
|
+
}
|
|
760
|
+
}
|
|
761
|
+
}
|
|
762
|
+
return true;
|
|
763
|
+
});
|
|
764
|
+
md.core.ruler.push("press_image_lazy", (state) => {
|
|
765
|
+
for (const token of state.tokens) {
|
|
766
|
+
if (token.type !== "inline" || !token.children) continue;
|
|
767
|
+
for (const child of token.children) {
|
|
768
|
+
if (child.type === "image") child.attrSet("loading", "lazy");
|
|
769
|
+
}
|
|
770
|
+
}
|
|
771
|
+
return true;
|
|
772
|
+
});
|
|
773
|
+
return md;
|
|
774
|
+
}
|
|
775
|
+
function titleFromFilePath(filePath) {
|
|
776
|
+
const base = filePath.split(/[\\/]/).pop() ?? filePath;
|
|
777
|
+
const name = base.replace(/\.md$/i, "");
|
|
778
|
+
if (name.toLowerCase() === "index") {
|
|
779
|
+
const parts = filePath.split(/[\\/]/).filter(Boolean);
|
|
780
|
+
return parts[parts.length - 2] ?? name;
|
|
781
|
+
}
|
|
782
|
+
return name;
|
|
783
|
+
}
|
|
784
|
+
function firstH1(toc) {
|
|
785
|
+
return toc.find((e) => e.level === 1)?.text;
|
|
786
|
+
}
|
|
787
|
+
function injectHeadingAnchors(elements) {
|
|
788
|
+
return elements.map((el) => {
|
|
789
|
+
if (!el || typeof el !== "object" || Array.isArray(el)) return el;
|
|
790
|
+
const rec = el;
|
|
791
|
+
const tag = Object.keys(rec).find((k) => /^h[1-6]$/.test(k));
|
|
792
|
+
if (tag && typeof rec.id === "string") {
|
|
793
|
+
const id = rec.id;
|
|
794
|
+
const children = Array.isArray(rec[tag]) ? [...rec[tag]] : rec[tag] != null ? [rec[tag]] : [];
|
|
795
|
+
children.push({ a: "#", href: `#${id}`, class: "header-anchor", ariaHidden: "true" });
|
|
796
|
+
return { ...rec, [tag]: children };
|
|
797
|
+
}
|
|
798
|
+
const tag2 = Object.keys(rec).find((k) => /^[a-z][a-z0-9]*$/.test(k) && k !== "style" && k !== "class" && !k.startsWith("data") && !k.startsWith("on") && !k.startsWith("aria") && !k.startsWith("_") && k !== "$" && k !== "href" && k !== "src" && k !== "id" && k !== "type" && k !== "name");
|
|
799
|
+
if (tag2 && Array.isArray(rec[tag2])) {
|
|
800
|
+
return { ...rec, [tag2]: injectHeadingAnchors(rec[tag2]) };
|
|
801
|
+
}
|
|
802
|
+
return el;
|
|
803
|
+
});
|
|
804
|
+
}
|
|
805
|
+
async function renderDoc(source, options) {
|
|
806
|
+
const { filePath, docsDir, highlight } = options;
|
|
807
|
+
const fileDir = dirname(filePath);
|
|
808
|
+
const { frontmatter, content } = splitFrontmatter(source);
|
|
809
|
+
const stripped = stripScriptBlocks(content);
|
|
810
|
+
const expanded = expandCodeImports(stripped, fileDir, docsDir);
|
|
811
|
+
const md = createParser(docsDir, highlight);
|
|
812
|
+
const tokens = md.parse(expanded, {});
|
|
813
|
+
const { body, toc } = tokensToDomphy(tokens, { highlight });
|
|
814
|
+
const withAnchors = injectHeadingAnchors(body);
|
|
815
|
+
const frontmatterTitle = typeof frontmatter.title === "string" ? frontmatter.title : void 0;
|
|
816
|
+
const title = frontmatterTitle ?? firstH1(toc) ?? titleFromFilePath(filePath);
|
|
817
|
+
return { frontmatter, body: withAnchors, toc, islands: [], title };
|
|
818
|
+
}
|
|
819
|
+
|
|
820
|
+
// src/search.ts
|
|
821
|
+
import { ElementNode, RecordState } from "@domphy/core";
|
|
822
|
+
import { themeColor, themeSpacing } from "@domphy/theme";
|
|
823
|
+
import { card, inputSearch, link, menu, small } from "@domphy/ui";
|
|
824
|
+
var FIELD_TITLE = 3;
|
|
825
|
+
var FIELD_HEADING = 2;
|
|
826
|
+
var FIELD_BODY = 1;
|
|
827
|
+
function tokenize(text2) {
|
|
828
|
+
const tokens = [];
|
|
829
|
+
for (const raw of text2.toLowerCase().split(/[^\p{L}\p{N}]+/u)) {
|
|
830
|
+
if (raw.length >= 2) tokens.push(raw);
|
|
831
|
+
}
|
|
832
|
+
return tokens;
|
|
833
|
+
}
|
|
834
|
+
function indexText(postings, entryIndex, text2, fieldWeight) {
|
|
835
|
+
for (const term of tokenize(text2)) {
|
|
836
|
+
let perEntry = postings.get(term);
|
|
837
|
+
if (!perEntry) {
|
|
838
|
+
perEntry = /* @__PURE__ */ new Map();
|
|
839
|
+
postings.set(term, perEntry);
|
|
840
|
+
}
|
|
841
|
+
const existing = perEntry.get(entryIndex);
|
|
842
|
+
if (existing === void 0 || fieldWeight > existing) perEntry.set(entryIndex, fieldWeight);
|
|
843
|
+
}
|
|
844
|
+
}
|
|
845
|
+
function buildSearchIndex(docs) {
|
|
846
|
+
const entries = [];
|
|
847
|
+
const postings = /* @__PURE__ */ new Map();
|
|
848
|
+
for (const doc of docs) {
|
|
849
|
+
const pageIndex = entries.length;
|
|
850
|
+
entries.push({ route: doc.route, pageTitle: doc.title, heading: doc.title, slug: "", isPage: true });
|
|
851
|
+
indexText(postings, pageIndex, doc.title, FIELD_TITLE);
|
|
852
|
+
indexText(postings, pageIndex, doc.text, FIELD_BODY);
|
|
853
|
+
for (const entry of doc.toc) {
|
|
854
|
+
const sectionIndex = entries.length;
|
|
855
|
+
entries.push({ route: doc.route, pageTitle: doc.title, heading: entry.text, slug: entry.slug, isPage: false });
|
|
856
|
+
indexText(postings, sectionIndex, entry.text, FIELD_HEADING);
|
|
857
|
+
}
|
|
858
|
+
}
|
|
859
|
+
const serializedPostings = {};
|
|
860
|
+
for (const [term, perEntry] of Array.from(postings.entries()).sort((a, b) => a[0] < b[0] ? -1 : 1)) {
|
|
861
|
+
serializedPostings[term] = Array.from(perEntry.entries()).sort((a, b) => a[0] - b[0]).map(([i, w]) => [i, w]);
|
|
862
|
+
}
|
|
863
|
+
return JSON.stringify({ entries, postings: serializedPostings });
|
|
864
|
+
}
|
|
865
|
+
|
|
866
|
+
// src/theme.ts
|
|
867
|
+
import { themeColor as themeColor2, themeSpacing as themeSpacing2 } from "@domphy/theme";
|
|
868
|
+
var tc = (tone, color) => themeColor2(null, tone, color);
|
|
869
|
+
var ts = (n) => themeSpacing2(n);
|
|
870
|
+
var bg = tc("inherit");
|
|
871
|
+
var bgSoft = tc("shift-1");
|
|
872
|
+
var bgMute = tc("shift-2");
|
|
873
|
+
var border = tc("shift-3");
|
|
874
|
+
var textSoft = tc("shift-6");
|
|
875
|
+
var text = tc("shift-9");
|
|
876
|
+
var textStrong = tc("shift-11");
|
|
877
|
+
var brand = tc("shift-9", "primary");
|
|
878
|
+
var brandHover = tc("shift-10", "primary");
|
|
879
|
+
var headerH = ts(14);
|
|
880
|
+
var sidebarW = ts(62);
|
|
881
|
+
var asideW = ts(56);
|
|
882
|
+
var contentMax = ts(190);
|
|
883
|
+
function pressCSS() {
|
|
884
|
+
return `
|
|
885
|
+
/* ------------------------------------------------------------------ reset */
|
|
886
|
+
*,*::before,*::after{box-sizing:border-box}
|
|
887
|
+
html{scroll-behavior:smooth;scroll-padding-top:calc(${headerH} + ${ts(4)})}
|
|
888
|
+
body{margin:0;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;background:${bg};color:${text};line-height:1.6;font-size:16px}
|
|
889
|
+
a{color:${brand};text-decoration:none}
|
|
890
|
+
a:hover{text-decoration:underline}
|
|
891
|
+
|
|
892
|
+
/* -------------------------------------------------------- announcement bar */
|
|
893
|
+
.dp-announcement{display:flex;align-items:center;justify-content:center;gap:${ts(3)};padding:${ts(2.5)} ${ts(6)};background:${brand};color:${bg};font-size:14px;font-weight:500;text-align:center}
|
|
894
|
+
.dp-announcement a{color:${bg};font-weight:700}
|
|
895
|
+
.dp-announcement-close{background:none;border:none;color:${bg};cursor:pointer;font-size:14px;opacity:.7;padding:${ts(0.5)} ${ts(1.5)};border-radius:${ts(1)};flex-shrink:0}
|
|
896
|
+
.dp-announcement-close:hover{opacity:1}
|
|
897
|
+
|
|
898
|
+
/* ------------------------------------------------------------------ header */
|
|
899
|
+
.dp-logo{font-weight:700;font-size:18px;color:${textStrong};white-space:nowrap;flex-shrink:0}
|
|
900
|
+
.dp-logo:hover{text-decoration:none}
|
|
901
|
+
.dp-logo-img{height:${ts(7)};width:auto;display:block}
|
|
902
|
+
.dp-nav a{color:${textSoft};font-size:14px;font-weight:500;white-space:nowrap;line-height:1}
|
|
903
|
+
.dp-nav a:hover,.dp-nav a[aria-current="page"]{color:${brand};text-decoration:none}
|
|
904
|
+
.dp-nav-dropdown{position:relative;display:flex;align-items:center}
|
|
905
|
+
.dp-nav-dropdown-label{color:${textSoft};font-size:14px;font-weight:500;cursor:pointer;user-select:none}
|
|
906
|
+
.dp-nav-dropdown-label::after{content:" \u25BE";font-size:10px;opacity:.6}
|
|
907
|
+
.dp-nav-dropdown-menu{display:none;position:absolute;top:calc(100% + ${ts(2)});right:0;background:${bgSoft};border:1px solid ${border};border-radius:${ts(2)};padding:${ts(1.5)};min-width:${ts(40)};z-index:100;flex-direction:column;gap:${ts(0.5)};box-shadow:0 4px 16px rgba(0,0,0,.1)}
|
|
908
|
+
.dp-nav-dropdown-menu a{display:block;padding:${ts(1.25)} ${ts(2.5)};border-radius:${ts(1.25)};font-size:13px}
|
|
909
|
+
.dp-nav-dropdown-menu a:hover{background:${bgMute}}
|
|
910
|
+
.dp-nav-dropdown:hover .dp-nav-dropdown-menu,.dp-nav-dropdown:focus-within .dp-nav-dropdown-menu{display:flex}
|
|
911
|
+
.dp-header-actions{flex-shrink:0}
|
|
912
|
+
.dp-search-slot{width:${ts(50)}}
|
|
913
|
+
.dp-search-static{width:100%;height:${ts(8)};padding:0 ${ts(2.5)};border:1px solid ${border};border-radius:${ts(1.5)};background:${bgSoft};color:${textSoft};font-size:13px;font-family:inherit;outline:none;cursor:pointer}
|
|
914
|
+
.dp-search-static::placeholder{color:${textSoft}}
|
|
915
|
+
.dp-theme-toggle,.dp-menu-toggle{border:1px solid ${border};background:${bgSoft};color:${text};border-radius:${ts(2)};width:${ts(8.5)};height:${ts(8.5)};cursor:pointer;font-size:16px}
|
|
916
|
+
.dp-menu-toggle{display:none}
|
|
917
|
+
|
|
918
|
+
/* ------------------------------------------------------------ social links */
|
|
919
|
+
.dp-social-link{display:inline-flex;align-items:center;justify-content:center;width:${ts(8.5)};height:${ts(8.5)};border-radius:${ts(2)};color:${textSoft};background:${bgSoft};border:1px solid ${border};font-size:10px;font-weight:700;flex-shrink:0}
|
|
920
|
+
.dp-social-link:hover{color:${text};border-color:${textSoft};text-decoration:none}
|
|
921
|
+
.dp-social-icon{display:block;width:${ts(4)};height:${ts(4)};background:currentColor;flex-shrink:0}
|
|
922
|
+
.dp-icon-github{-webkit-mask:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M12 2C6.477 2 2 6.477 2 12c0 4.42 2.865 8.17 6.839 9.49.5.092.682-.217.682-.482 0-.237-.008-.866-.013-1.7-2.782.603-3.369-1.342-3.369-1.342-.454-1.155-1.11-1.463-1.11-1.463-.908-.62.069-.608.069-.608 1.003.07 1.531 1.03 1.531 1.03.892 1.529 2.341 1.088 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.11-4.555-4.943 0-1.091.39-1.984 1.029-2.683-.103-.253-.446-1.27.098-2.647 0 0 .84-.269 2.75 1.025A9.578 9.578 0 0 1 12 6.836c.85.004 1.705.115 2.504.337 1.909-1.294 2.747-1.025 2.747-1.025.546 1.377.202 2.394.1 2.647.64.699 1.028 1.592 1.028 2.683 0 3.842-2.339 4.687-4.566 4.935.359.309.678.919.678 1.852 0 1.336-.012 2.415-.012 2.741 0 .267.18.578.688.48C19.138 20.167 22 16.418 22 12c0-5.523-4.477-10-10-10z'/%3E%3C/svg%3E") center/contain no-repeat;mask:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M12 2C6.477 2 2 6.477 2 12c0 4.42 2.865 8.17 6.839 9.49.5.092.682-.217.682-.482 0-.237-.008-.866-.013-1.7-2.782.603-3.369-1.342-3.369-1.342-.454-1.155-1.11-1.463-1.11-1.463-.908-.62.069-.608.069-.608 1.003.07 1.531 1.03 1.531 1.03.892 1.529 2.341 1.088 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.11-4.555-4.943 0-1.091.39-1.984 1.029-2.683-.103-.253-.446-1.27.098-2.647 0 0 .84-.269 2.75 1.025A9.578 9.578 0 0 1 12 6.836c.85.004 1.705.115 2.504.337 1.909-1.294 2.747-1.025 2.747-1.025.546 1.377.202 2.394.1 2.647.64.699 1.028 1.592 1.028 2.683 0 3.842-2.339 4.687-4.566 4.935.359.309.678.919.678 1.852 0 1.336-.012 2.415-.012 2.741 0 .267.18.578.688.48C19.138 20.167 22 16.418 22 12c0-5.523-4.477-10-10-10z'/%3E%3C/svg%3E") center/contain no-repeat}
|
|
923
|
+
.dp-icon-twitter{-webkit-mask:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-4.714-6.231-5.401 6.231H2.744l7.737-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z'/%3E%3C/svg%3E") center/contain no-repeat;mask:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-4.714-6.231-5.401 6.231H2.744l7.737-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z'/%3E%3C/svg%3E") center/contain no-repeat}
|
|
924
|
+
.dp-icon-discord{-webkit-mask:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M20.317 4.37a19.791 19.791 0 0 0-4.885-1.515.074.074 0 0 0-.079.037c-.21.375-.444.864-.608 1.25a18.27 18.27 0 0 0-5.487 0 12.64 12.64 0 0 0-.617-1.25.077.077 0 0 0-.079-.037A19.736 19.736 0 0 0 3.677 4.37a.07.07 0 0 0-.032.027C.533 9.046-.32 13.58.099 18.057c.01.044.032.084.064.107a19.9 19.9 0 0 0 5.993 3.03.078.078 0 0 0 .084-.028 14.09 14.09 0 0 0 1.226-1.994.076.076 0 0 0-.041-.106 13.107 13.107 0 0 1-1.872-.892.077.077 0 0 1-.008-.128 10.2 10.2 0 0 0 .372-.292.074.074 0 0 1 .077-.01c3.928 1.793 8.18 1.793 12.062 0a.074.074 0 0 1 .078.01 10.2 10.2 0 0 0 .373.292.077.077 0 0 1-.006.127 12.299 12.299 0 0 1-1.873.892.077.077 0 0 0-.041.107c.36.698.772 1.362 1.225 1.993a.076.076 0 0 0 .084.028 19.839 19.839 0 0 0 6.002-3.03.077.077 0 0 0 .032-.054c.5-5.177-.838-9.674-3.549-13.66a.061.061 0 0 0-.031-.03z'/%3E%3C/svg%3E") center/contain no-repeat;mask:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M20.317 4.37a19.791 19.791 0 0 0-4.885-1.515.074.074 0 0 0-.079.037c-.21.375-.444.864-.608 1.25a18.27 18.27 0 0 0-5.487 0 12.64 12.64 0 0 0-.617-1.25.077.077 0 0 0-.079-.037A19.736 19.736 0 0 0 3.677 4.37a.07.07 0 0 0-.032.027C.533 9.046-.32 13.58.099 18.057c.01.044.032.084.064.107a19.9 19.9 0 0 0 5.993 3.03.078.078 0 0 0 .084-.028 14.09 14.09 0 0 0 1.226-1.994.076.076 0 0 0-.041-.106 13.107 13.107 0 0 1-1.872-.892.077.077 0 0 1-.008-.128 10.2 10.2 0 0 0 .372-.292.074.074 0 0 1 .077-.01c3.928 1.793 8.18 1.793 12.062 0a.074.074 0 0 1 .078.01 10.2 10.2 0 0 0 .373.292.077.077 0 0 1-.006.127 12.299 12.299 0 0 1-1.873.892.077.077 0 0 0-.041.107c.36.698.772 1.362 1.225 1.993a.076.076 0 0 0 .084.028 19.839 19.839 0 0 0 6.002-3.03.077.077 0 0 0 .032-.054c.5-5.177-.838-9.674-3.549-13.66a.061.061 0 0 0-.031-.03z'/%3E%3C/svg%3E") center/contain no-repeat}
|
|
925
|
+
|
|
926
|
+
/* ------------------------------------------------------------------ layout */
|
|
927
|
+
.dp-shell{display:grid;grid-template-columns:${sidebarW} minmax(0,1fr) ${asideW};align-items:start;max-width:1440px;margin:0 auto}
|
|
928
|
+
.dp-sidebar{position:sticky;top:${headerH};max-height:calc(100vh - ${headerH});overflow-y:auto;padding:${ts(6)} ${ts(3)} ${ts(12)} ${ts(6)};border-right:1px solid ${border}}
|
|
929
|
+
.dp-sidebar-group{margin-bottom:${ts(3.5)}}
|
|
930
|
+
.dp-sidebar-title{display:flex;align-items:center;gap:${ts(1.5)};font-size:13px;font-weight:700;color:${textStrong};margin:${ts(2)} 0 ${ts(1)}}
|
|
931
|
+
.dp-sidebar-subtitle{font-size:12px;color:${textSoft};padding:${ts(1)} ${ts(3)};font-weight:600}
|
|
932
|
+
.dp-sidebar-items{display:flex;flex-direction:column}
|
|
933
|
+
.dp-sidebar-toggle{margin-left:auto;background:none;border:none;cursor:pointer;color:${textSoft};font-size:14px;padding:0 ${ts(1)};line-height:1}
|
|
934
|
+
.dp-sidebar-toggle:hover{color:${text}}
|
|
935
|
+
.dp-sidebar-group.collapsed .dp-sidebar-items{display:none}
|
|
936
|
+
.dp-sidebar a{display:flex;align-items:center;gap:${ts(1.5)};padding:${ts(1.25)} ${ts(3)};font-size:14px;color:${textSoft};border-radius:${ts(1.5)}}
|
|
937
|
+
.dp-sidebar a:hover{color:${text};text-decoration:none}
|
|
938
|
+
.dp-sidebar a[aria-current="page"]{color:${brand};font-weight:600;background:${bgSoft}}
|
|
939
|
+
.dp-sidebar-link-with-badge{display:flex;align-items:center}
|
|
940
|
+
.dp-main{padding:${ts(8)} ${ts(12)} ${ts(20)};min-width:0}
|
|
941
|
+
.dp-content{max-width:${contentMax}}
|
|
942
|
+
.dp-aside{position:sticky;top:${headerH};max-height:calc(100vh - ${headerH});overflow-y:auto;padding:${ts(8)} ${ts(6)};font-size:13px}
|
|
943
|
+
.dp-aside-title{font-weight:700;margin-bottom:${ts(2)};color:${text}}
|
|
944
|
+
.dp-toc a{display:block;padding:${ts(0.75)} 0;color:${textSoft}}
|
|
945
|
+
.dp-toc a:hover{color:${brand};text-decoration:none}
|
|
946
|
+
.dp-toc-2{padding-left:0}
|
|
947
|
+
.dp-toc-3{padding-left:${ts(3)}}
|
|
948
|
+
.dp-toc-4{padding-left:${ts(6)}}
|
|
949
|
+
|
|
950
|
+
/* ------------------------------------------------------------------ badges */
|
|
951
|
+
.dp-badge{display:inline-block;padding:${ts(0.5)} ${ts(1.75)};border-radius:${ts(2.5)};font-size:11px;font-weight:700;line-height:1.4;white-space:nowrap;vertical-align:middle}
|
|
952
|
+
.dp-badge-tip{background:color-mix(in srgb,${brand} 12%,${bg});color:${brand}}
|
|
953
|
+
.dp-badge-info{background:${bgMute};color:${textSoft}}
|
|
954
|
+
.dp-badge-warning{background:color-mix(in srgb,${tc("shift-9", "warning")} 12%,${bg});color:${tc("shift-9", "warning")}}
|
|
955
|
+
.dp-badge-danger{background:color-mix(in srgb,${tc("shift-9", "danger")} 12%,${bg});color:${tc("shift-9", "danger")}}
|
|
956
|
+
.dp-page-badge{margin-left:${ts(2)}}
|
|
957
|
+
.dp-page-badge-row{margin-bottom:${ts(-2)}}
|
|
958
|
+
|
|
959
|
+
/* ------------------------------------------------------------------- prose */
|
|
960
|
+
.dp-content h1{font-size:30px;font-weight:700;line-height:1.25;margin:0 0 ${ts(6)};letter-spacing:-.02em;color:${textStrong}}
|
|
961
|
+
.dp-content h2{font-size:22px;font-weight:700;margin:${ts(11)} 0 ${ts(4)};padding-top:${ts(5)};border-top:1px solid ${border};letter-spacing:-.01em;color:${textStrong}}
|
|
962
|
+
.dp-content h3{font-size:18px;font-weight:600;margin:${ts(7)} 0 ${ts(3)};color:${textStrong}}
|
|
963
|
+
.dp-content h4{font-size:16px;font-weight:600;margin:${ts(5.5)} 0 ${ts(2)};color:${textStrong}}
|
|
964
|
+
.dp-content p{margin:${ts(4)} 0}
|
|
965
|
+
.dp-content ul,.dp-content ol{margin:${ts(4)} 0;padding-left:1.4em}
|
|
966
|
+
.dp-content li{margin:${ts(1.5)} 0}
|
|
967
|
+
.dp-content a{font-weight:500}
|
|
968
|
+
.dp-content strong{font-weight:600;color:${textStrong}}
|
|
969
|
+
.dp-content em{font-style:italic}
|
|
970
|
+
.dp-content mark{background:color-mix(in srgb,${tc("shift-6", "warning")} 40%,${bg});color:inherit;padding:${ts(0.25)} ${ts(0.75)};border-radius:${ts(0.75)}}
|
|
971
|
+
.dp-content sup{font-size:.75em;vertical-align:super}
|
|
972
|
+
.dp-content sub{font-size:.75em;vertical-align:sub}
|
|
973
|
+
.dp-content del{opacity:.5}
|
|
974
|
+
.dp-content blockquote{margin:${ts(4)} 0;padding:0 ${ts(4)};border-left:3px solid ${border};color:${textSoft}}
|
|
975
|
+
.dp-content img{max-width:100%;height:auto;border-radius:${ts(1.5)}}
|
|
976
|
+
.dp-content hr{border:none;border-top:1px solid ${border};margin:${ts(8)} 0}
|
|
977
|
+
.dp-content :not(pre)>code{font-family:ui-monospace,SFMono-Regular,"SF Mono",Menlo,monospace;font-size:.85em;background:${bgMute};padding:${ts(0.75)} ${ts(1.5)};border-radius:${ts(1)}}
|
|
978
|
+
.dp-content pre{margin:${ts(4)} 0;padding:${ts(4)} ${ts(5)};background:${bgSoft};border:1px solid ${border};border-radius:${ts(2)};overflow-x:auto;font-size:13.5px;line-height:1.5}
|
|
979
|
+
.dp-content pre code{font-family:ui-monospace,SFMono-Regular,"SF Mono",Menlo,monospace;background:none;padding:0}
|
|
980
|
+
.dp-content table{border-collapse:collapse;margin:${ts(4)} 0;display:block;overflow-x:auto}
|
|
981
|
+
.dp-content th,.dp-content td{border:1px solid ${border};padding:${ts(2)} ${ts(3.5)};text-align:left}
|
|
982
|
+
.dp-content th{background:${bgSoft};font-weight:600}
|
|
983
|
+
|
|
984
|
+
/* -------------------------------------------------------- heading anchors */
|
|
985
|
+
.header-anchor{opacity:0;margin-left:${ts(2)};font-weight:400;font-size:.85em;color:${textSoft};transition:opacity .15s}
|
|
986
|
+
:is(h1,h2,h3,h4,h5,h6):hover .header-anchor{opacity:1}
|
|
987
|
+
.header-anchor:hover{color:${brand};text-decoration:none}
|
|
988
|
+
|
|
989
|
+
/* -------------------------------------------------------- external links */
|
|
990
|
+
.dp-content a[target="_blank"]::after{content:" \u2197";font-size:.75em;opacity:.6}
|
|
991
|
+
|
|
992
|
+
/* --------------------------------------------------------------- task lists */
|
|
993
|
+
.task-list-item{list-style:none;margin-left:-1.4em;padding-left:1.8em;position:relative}
|
|
994
|
+
.task-list-check{position:absolute;left:0;top:.25em;width:14px;height:14px;cursor:default;accent-color:${brand}}
|
|
995
|
+
|
|
996
|
+
/* ------------------------------------------------------------ code blocks */
|
|
997
|
+
.code-block{margin:${ts(4)} 0;border:1px solid ${border};border-radius:${ts(2)};overflow:hidden}
|
|
998
|
+
.code-block-title{display:flex;align-items:center;padding:${ts(1.5)} ${ts(4)};background:${bgMute};border-bottom:1px solid ${border};font-size:12px;font-family:ui-monospace,SFMono-Regular,"SF Mono",Menlo,monospace;color:${textSoft}}
|
|
999
|
+
.code-block-inner{position:relative}
|
|
1000
|
+
.code-block pre{margin:0;padding:${ts(4)} ${ts(5)};background:${bgSoft};border:none;border-radius:0;overflow-x:auto;font-size:13.5px;line-height:1.5;font-family:ui-monospace,SFMono-Regular,"SF Mono",Menlo,monospace}
|
|
1001
|
+
.code-block code{font-family:inherit;background:none;padding:0;font-size:inherit}
|
|
1002
|
+
.code-block .line{display:inline-block;width:100%}
|
|
1003
|
+
.code-block .line.highlighted{background:color-mix(in srgb,${brand} 10%,transparent)}
|
|
1004
|
+
.code-block .line.diff.add{background:color-mix(in srgb,${tc("shift-7", "success")} 12%,transparent)}
|
|
1005
|
+
.code-block .line.diff.add::before{content:"+ ";color:${tc("shift-7", "success")}}
|
|
1006
|
+
.code-block .line.diff.remove{background:color-mix(in srgb,${tc("shift-9", "danger")} 10%,transparent);opacity:.7}
|
|
1007
|
+
.code-block .line.diff.remove::before{content:"- ";color:${tc("shift-9", "danger")}}
|
|
1008
|
+
.code-block .line.highlighted.error{background:color-mix(in srgb,${tc("shift-9", "error")} 10%,transparent)}
|
|
1009
|
+
.code-block .line.highlighted.warning{background:color-mix(in srgb,${tc("shift-7", "warning")} 10%,transparent)}
|
|
1010
|
+
.code-block pre.has-focus .line:not(.focus){opacity:.4;filter:blur(.4px);transition:opacity .2s,filter .2s}
|
|
1011
|
+
.code-block pre.has-focus:hover .line{opacity:1;filter:none}
|
|
1012
|
+
.code-block .line-number{display:inline-block;min-width:2.5em;margin-right:1em;color:${textSoft};text-align:right;user-select:none;font-size:.9em}
|
|
1013
|
+
.code-copy-btn{position:absolute;top:${ts(2)};right:${ts(2)};padding:${ts(1)} ${ts(2)};border-radius:${ts(1.25)};border:1px solid ${border};background:${bgSoft};color:${textSoft};cursor:pointer;font-size:13px;opacity:0;transition:opacity .15s}
|
|
1014
|
+
.code-block-inner:hover .code-copy-btn{opacity:1}
|
|
1015
|
+
.code-copy-btn:hover{background:${bgMute};color:${text}}
|
|
1016
|
+
|
|
1017
|
+
/* ------------------------------------------------------------- code groups */
|
|
1018
|
+
.code-group{margin:${ts(4)} 0;border:1px solid ${border};border-radius:${ts(2)};overflow:hidden}
|
|
1019
|
+
.code-group>input[type="radio"]{position:absolute;opacity:0;pointer-events:none;width:0;height:0}
|
|
1020
|
+
.code-group .tabs{display:flex;gap:${ts(0.5)};padding:${ts(1.5)} ${ts(2)};background:${bgSoft};border-bottom:1px solid ${border};flex-wrap:wrap}
|
|
1021
|
+
.code-group .tabs label{padding:${ts(1)} ${ts(3)};font-size:13px;font-weight:500;color:${textSoft};border-radius:${ts(1.25)};cursor:pointer}
|
|
1022
|
+
.code-group .blocks>.code-block{display:none;margin:0;border:none;border-radius:0}
|
|
1023
|
+
.code-group .blocks>.code-block pre{border-radius:0}
|
|
1024
|
+
${Array.from({ length: 8 }, (_, i) => `.code-group>input:nth-of-type(${i + 1}):checked~.blocks>.code-block:nth-child(${i + 1})`).join(",\n")}{display:block}
|
|
1025
|
+
${Array.from({ length: 8 }, (_, i) => `.code-group>input:nth-of-type(${i + 1}):checked~.tabs>label:nth-child(${i + 1})`).join(",\n")}{color:${brand};background:${bgMute}}
|
|
1026
|
+
|
|
1027
|
+
/* --------------------------------------------------------- custom blocks */
|
|
1028
|
+
.custom-block{margin:${ts(4)} 0;padding:${ts(3)} ${ts(4)};border-radius:${ts(2)};border:1px solid transparent;font-size:14.5px}
|
|
1029
|
+
.custom-block p{margin:${ts(2)} 0}
|
|
1030
|
+
.custom-block-title{font-weight:700;margin:0 0 ${ts(1)} !important;font-size:13px}
|
|
1031
|
+
.custom-block.tip,.custom-block.success{background:color-mix(in srgb,${brand} 8%,${bg});border-color:color-mix(in srgb,${brand} 28%,transparent)}
|
|
1032
|
+
.custom-block.info,.custom-block.note,.custom-block.abstract{background:${bgSoft};border-color:${border}}
|
|
1033
|
+
.custom-block.warning,.custom-block.question{background:color-mix(in srgb,${tc("shift-6", "warning")} 10%,${bg});border-color:${tc("shift-6", "warning")}}
|
|
1034
|
+
.custom-block.danger,.custom-block.failure,.custom-block.bug{background:color-mix(in srgb,${tc("shift-7", "danger")} 10%,${bg});border-color:${tc("shift-7", "danger")}}
|
|
1035
|
+
.custom-block.example{background:color-mix(in srgb,${tc("shift-7", "secondary")} 10%,${bg});border-color:${tc("shift-7", "secondary")}}
|
|
1036
|
+
.custom-block.quote{background:${bgSoft};border-color:${border};border-left-width:4px;border-radius:0 ${ts(2)} ${ts(2)} 0}
|
|
1037
|
+
details.custom-block summary{cursor:pointer;font-weight:600}
|
|
1038
|
+
|
|
1039
|
+
/* ------------------------------------------------------------------- steps */
|
|
1040
|
+
.custom-block.steps{background:none;border:none;padding:0}
|
|
1041
|
+
.custom-block.steps>ol{counter-reset:step;list-style:none;padding:0;margin:0}
|
|
1042
|
+
.custom-block.steps>ol>li{counter-increment:step;display:grid;grid-template-columns:${ts(9)} 1fr;gap:0 ${ts(4)};margin-bottom:${ts(6)}}
|
|
1043
|
+
.custom-block.steps>ol>li::before{content:counter(step);display:flex;align-items:center;justify-content:center;width:${ts(7.5)};height:${ts(7.5)};border-radius:50%;background:${brand};color:${bg};font-size:13px;font-weight:700;flex-shrink:0}
|
|
1044
|
+
|
|
1045
|
+
/* ----------------------------------------------------------------- mermaid */
|
|
1046
|
+
.dp-mermaid{margin:${ts(5)} 0;text-align:center;overflow-x:auto}
|
|
1047
|
+
.dp-mermaid svg{max-width:100%;height:auto}
|
|
1048
|
+
|
|
1049
|
+
/* --------------------------------------------------------------- doc footer */
|
|
1050
|
+
.dp-doc-footer{display:flex;align-items:center;gap:${ts(4)};flex-wrap:wrap;margin-top:${ts(8)};padding-top:${ts(5)};border-top:1px solid ${border};font-size:13px;color:${textSoft}}
|
|
1051
|
+
.dp-edit-link{font-weight:500;font-size:13px}
|
|
1052
|
+
.dp-reading-time::before{content:"\u{1F4D6} "}
|
|
1053
|
+
|
|
1054
|
+
/* --------------------------------------------------------------- prev/next */
|
|
1055
|
+
.dp-prevnext{display:flex;justify-content:space-between;gap:${ts(4)};margin-top:${ts(12)};padding-top:${ts(6)};border-top:1px solid ${border}}
|
|
1056
|
+
.dp-prevnext a{display:block;padding:${ts(3)} ${ts(4)};border:1px solid ${border};border-radius:${ts(2)};font-weight:600;flex:1}
|
|
1057
|
+
.dp-prevnext a:hover{border-color:${brand};text-decoration:none}
|
|
1058
|
+
.dp-prevnext .next{text-align:right}
|
|
1059
|
+
.dp-prevnext small{display:block;color:${textSoft};font-weight:400;font-size:12px}
|
|
1060
|
+
|
|
1061
|
+
/* ----------------------------------------------------------------- footer */
|
|
1062
|
+
.dp-footer{padding:${ts(6)} ${ts(12)};border-top:1px solid ${border};color:${textSoft};font-size:13px}
|
|
1063
|
+
|
|
1064
|
+
/* ---------------------------------------------------------------- home page */
|
|
1065
|
+
.dp-main-home{max-width:1100px;margin:0 auto;padding:${ts(12)} ${ts(6)} ${ts(20)}}
|
|
1066
|
+
.dp-hero{text-align:center;padding:${ts(10)} 0 ${ts(6)}}
|
|
1067
|
+
.dp-hero-name{font-size:56px;font-weight:800;line-height:1.1;letter-spacing:-.03em;background:linear-gradient(120deg,${brand},${tc("shift-7", "secondary")});-webkit-background-clip:text;background-clip:text;color:transparent}
|
|
1068
|
+
.dp-hero-text{font-size:30px;font-weight:700;margin:${ts(3)} 0 0;color:${textStrong}}
|
|
1069
|
+
.dp-hero-tagline{font-size:18px;color:${textSoft};max-width:${ts(160)};margin:${ts(5)} auto 0}
|
|
1070
|
+
.dp-hero-actions{display:flex;gap:${ts(3)};justify-content:center;margin-top:${ts(7)};flex-wrap:wrap}
|
|
1071
|
+
.dp-hero-action{padding:${ts(2.5)} ${ts(5.5)};border-radius:${ts(5.5)};font-weight:600;font-size:15px}
|
|
1072
|
+
.dp-hero-action.brand{background:${brand};color:${bg}}
|
|
1073
|
+
.dp-hero-action.brand:hover{background:${brandHover};text-decoration:none}
|
|
1074
|
+
.dp-hero-action.alt{background:${bgSoft};color:${text};border:1px solid ${border}}
|
|
1075
|
+
.dp-hero-action.alt:hover{border-color:${brand};text-decoration:none}
|
|
1076
|
+
.dp-features{display:grid;grid-template-columns:repeat(auto-fit,minmax(${ts(60)},1fr));gap:${ts(4)};margin:${ts(10)} 0}
|
|
1077
|
+
.dp-feature{padding:${ts(5)};background:${bgSoft};border:1px solid ${border};border-radius:${ts(3)}}
|
|
1078
|
+
.dp-feature-icon{font-size:28px;margin-bottom:${ts(3)}}
|
|
1079
|
+
.dp-feature-title{font-weight:700;font-size:17px;margin-bottom:${ts(2)};color:${textStrong}}
|
|
1080
|
+
.dp-feature-details{font-size:14px;color:${textSoft};margin:0;line-height:1.5}
|
|
1081
|
+
.dp-feature-link{display:block;color:inherit}
|
|
1082
|
+
.dp-feature-link:hover{text-decoration:none}
|
|
1083
|
+
.dp-feature-link:hover .dp-feature{border-color:${brand}}
|
|
1084
|
+
.dp-home{max-width:${contentMax};margin:0 auto}
|
|
1085
|
+
|
|
1086
|
+
/* ---------------------------------------------------------------- shiki dark */
|
|
1087
|
+
html[data-theme="dark"] .shiki,html[data-theme="dark"] .shiki span{color:var(--shiki-dark,inherit) !important}
|
|
1088
|
+
|
|
1089
|
+
/* -------------------------------------------------------------- responsive */
|
|
1090
|
+
@media(max-width:1200px){
|
|
1091
|
+
.dp-shell{grid-template-columns:${sidebarW} minmax(0,1fr)}
|
|
1092
|
+
.dp-aside{display:none}
|
|
1093
|
+
}
|
|
1094
|
+
@media(max-width:860px){
|
|
1095
|
+
.dp-shell{grid-template-columns:1fr}
|
|
1096
|
+
.dp-menu-toggle{display:block}
|
|
1097
|
+
.dp-sidebar{position:fixed;top:${headerH};left:0;bottom:0;width:80%;max-width:${ts(80)};background:${bg};z-index:25;transform:translateX(-100%);transition:transform .2s ease;max-height:none}
|
|
1098
|
+
html[data-sidebar="open"] .dp-sidebar{transform:translateX(0)}
|
|
1099
|
+
.dp-nav{display:none}
|
|
1100
|
+
.dp-main{padding:${ts(6)} ${ts(5)} ${ts(16)}}
|
|
1101
|
+
.dp-search-slot{width:${ts(35)}}
|
|
1102
|
+
}
|
|
1103
|
+
`;
|
|
1104
|
+
}
|
|
1105
|
+
|
|
1106
|
+
// src/build.ts
|
|
1107
|
+
var here = dirname2(fileURLToPath(import.meta.url));
|
|
1108
|
+
function flattenText(node, out) {
|
|
1109
|
+
if (node == null) return;
|
|
1110
|
+
if (typeof node === "string") {
|
|
1111
|
+
if (!node.trimStart().startsWith("<")) out.push(node);
|
|
1112
|
+
return;
|
|
1113
|
+
}
|
|
1114
|
+
if (typeof node === "number") {
|
|
1115
|
+
out.push(String(node));
|
|
1116
|
+
return;
|
|
1117
|
+
}
|
|
1118
|
+
if (Array.isArray(node)) {
|
|
1119
|
+
for (const child of node) flattenText(child, out);
|
|
1120
|
+
return;
|
|
1121
|
+
}
|
|
1122
|
+
if (typeof node === "object") {
|
|
1123
|
+
for (const [key, value] of Object.entries(node)) {
|
|
1124
|
+
if (key.startsWith("_") || key === "$" || key === "style") continue;
|
|
1125
|
+
if (key === "class" || key.startsWith("data") || key === "href" || key === "id") continue;
|
|
1126
|
+
flattenText(value, out);
|
|
1127
|
+
}
|
|
1128
|
+
}
|
|
1129
|
+
}
|
|
1130
|
+
function parseStyleString(value) {
|
|
1131
|
+
const style = {};
|
|
1132
|
+
for (const decl of value.split(";")) {
|
|
1133
|
+
const colon = decl.indexOf(":");
|
|
1134
|
+
if (colon === -1) continue;
|
|
1135
|
+
const prop = decl.slice(0, colon).trim();
|
|
1136
|
+
const val = decl.slice(colon + 1).trim();
|
|
1137
|
+
if (!prop || !val) continue;
|
|
1138
|
+
style[prop.replace(/-([a-z])/g, (_m, c) => c.toUpperCase())] = val;
|
|
1139
|
+
}
|
|
1140
|
+
return style;
|
|
1141
|
+
}
|
|
1142
|
+
function sanitizeStyles(node) {
|
|
1143
|
+
if (Array.isArray(node)) {
|
|
1144
|
+
for (const child of node) sanitizeStyles(child);
|
|
1145
|
+
return;
|
|
1146
|
+
}
|
|
1147
|
+
if (!node || typeof node !== "object") return;
|
|
1148
|
+
const record = node;
|
|
1149
|
+
if (typeof record.style === "string") record.style = parseStyleString(record.style);
|
|
1150
|
+
for (const value of Object.values(record)) {
|
|
1151
|
+
if (value && (typeof value === "object" || Array.isArray(value))) sanitizeStyles(value);
|
|
1152
|
+
}
|
|
1153
|
+
}
|
|
1154
|
+
function firstParagraphText(body) {
|
|
1155
|
+
for (const node of body) {
|
|
1156
|
+
if (!node || typeof node !== "object" || Array.isArray(node)) continue;
|
|
1157
|
+
const record = node;
|
|
1158
|
+
if ("p" in record) {
|
|
1159
|
+
const parts = [];
|
|
1160
|
+
flattenText(record.p, parts);
|
|
1161
|
+
const text2 = parts.join(" ").replace(/\s+/g, " ").trim();
|
|
1162
|
+
if (text2.length > 10) return text2.slice(0, 160);
|
|
1163
|
+
}
|
|
1164
|
+
}
|
|
1165
|
+
return "";
|
|
1166
|
+
}
|
|
1167
|
+
function estimateReadingTime(textContent) {
|
|
1168
|
+
return Math.max(1, Math.round(textContent.split(/\s+/).length / 200));
|
|
1169
|
+
}
|
|
1170
|
+
function getLastUpdated(filePath) {
|
|
1171
|
+
try {
|
|
1172
|
+
const result = execSync(`git log -1 --format="%aI" -- "${filePath}"`, {
|
|
1173
|
+
encoding: "utf8",
|
|
1174
|
+
stdio: ["pipe", "pipe", "ignore"],
|
|
1175
|
+
timeout: 5e3
|
|
1176
|
+
}).trim();
|
|
1177
|
+
return result || void 0;
|
|
1178
|
+
} catch {
|
|
1179
|
+
return void 0;
|
|
1180
|
+
}
|
|
1181
|
+
}
|
|
1182
|
+
async function buildIslandsBundle(outDir, searchEnabled) {
|
|
1183
|
+
if (!searchEnabled) return;
|
|
1184
|
+
const islandsSource = join2(here, "islands.js");
|
|
1185
|
+
const entrySource = `import{bootstrap}from${JSON.stringify(islandsSource)};bootstrap({search:{kind:"search",id:"search"}});`;
|
|
1186
|
+
const tmpEntry = join2(outDir, "_press_islands_entry.js");
|
|
1187
|
+
mkdirSync(outDir, { recursive: true });
|
|
1188
|
+
writeFileSync(tmpEntry, entrySource, "utf8");
|
|
1189
|
+
const { build: esbuildBuild } = await import("esbuild");
|
|
1190
|
+
await esbuildBuild({
|
|
1191
|
+
entryPoints: { "press-islands": tmpEntry },
|
|
1192
|
+
bundle: true,
|
|
1193
|
+
splitting: false,
|
|
1194
|
+
format: "esm",
|
|
1195
|
+
outdir: join2(outDir, "assets"),
|
|
1196
|
+
entryNames: "[name]",
|
|
1197
|
+
minify: true,
|
|
1198
|
+
sourcemap: false,
|
|
1199
|
+
target: "es2020",
|
|
1200
|
+
define: { "process.env.NODE_ENV": '"production"' },
|
|
1201
|
+
logLevel: "error"
|
|
1202
|
+
});
|
|
1203
|
+
rmSync(tmpEntry);
|
|
1204
|
+
}
|
|
1205
|
+
function buildSitemap(routes, hostname) {
|
|
1206
|
+
const urls = routes.map((route) => {
|
|
1207
|
+
const loc = route === "/" ? `${hostname}/` : `${hostname}${route}`.replace(/\/+$/, "") + "/";
|
|
1208
|
+
return ` <url><loc>${loc}</loc></url>`;
|
|
1209
|
+
});
|
|
1210
|
+
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
1211
|
+
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
|
1212
|
+
${urls.join("\n")}
|
|
1213
|
+
</urlset>`;
|
|
1214
|
+
}
|
|
1215
|
+
var RUNTIME_SCRIPT = `(function(){
|
|
1216
|
+
try{var t=localStorage.getItem('dp-theme');if(t)document.documentElement.setAttribute('data-theme',t);}catch(_){}
|
|
1217
|
+
addEventListener('click',function(e){
|
|
1218
|
+
var el=e.target.closest&&e.target.closest('[data-theme-toggle]');
|
|
1219
|
+
if(el){var d=document.documentElement;var n=d.getAttribute('data-theme')==='dark'?'':'dark';d.setAttribute('data-theme',n);try{localStorage.setItem('dp-theme',n);}catch(_){}return;}
|
|
1220
|
+
var m=e.target.closest&&e.target.closest('[data-menu-toggle]');
|
|
1221
|
+
if(m){var d2=document.documentElement;d2.setAttribute('data-sidebar',d2.getAttribute('data-sidebar')==='open'?'':'open');return;}
|
|
1222
|
+
var cp=e.target.closest&&e.target.closest('[data-copy]');
|
|
1223
|
+
if(cp){var ci=cp.closest('.code-block-inner');var ce=ci&&ci.querySelector('code');if(ce){navigator.clipboard&&navigator.clipboard.writeText(ce.textContent||'').then(function(){cp.textContent='\u2713';setTimeout(function(){cp.textContent='\u2398';},2000);}).catch(function(){});}return;}
|
|
1224
|
+
var st=e.target.closest&&e.target.closest('[data-sidebar-toggle]');
|
|
1225
|
+
if(st){var gr=st.closest('.dp-sidebar-group');if(gr)gr.classList.toggle('collapsed');return;}
|
|
1226
|
+
var da=e.target.closest&&e.target.closest('[data-dismiss-announcement]');
|
|
1227
|
+
if(da){var bar=document.querySelector('.dp-announcement');if(bar){var id=bar.getAttribute('data-id');if(id)try{localStorage.setItem('dp-dismiss-'+id,'1');}catch(_){}bar.remove();}return;}
|
|
1228
|
+
});
|
|
1229
|
+
addEventListener('DOMContentLoaded',function(){
|
|
1230
|
+
try{document.querySelectorAll('.dp-announcement[data-id]').forEach(function(b){if(localStorage.getItem('dp-dismiss-'+b.getAttribute('data-id')))b.remove();});}catch(_){}
|
|
1231
|
+
});
|
|
1232
|
+
})();`;
|
|
1233
|
+
function mermaidHeadScript(mermaid) {
|
|
1234
|
+
const cdn = typeof mermaid === "object" && mermaid.cdn ? mermaid.cdn : "https://cdn.jsdelivr.net/npm/mermaid@11/dist/mermaid.esm.min.mjs";
|
|
1235
|
+
return `<script type="module">import mermaid from '${cdn}';mermaid.initialize({startOnLoad:false,theme:document.documentElement.getAttribute('data-theme')==='dark'?'dark':'default'});document.addEventListener('DOMContentLoaded',()=>mermaid.run({querySelector:'.dp-mermaid'}));</script>`;
|
|
1236
|
+
}
|
|
1237
|
+
function htmlDocument(result, config, searchEnabled, generatedCss, pageHead, lang) {
|
|
1238
|
+
const islandsScript = searchEnabled ? `
|
|
1239
|
+
<script type="module" src="${config.base}assets/press-islands.js"></script>` : "";
|
|
1240
|
+
const mermaidScript = config.themeConfig.mermaid ? mermaidHeadScript(config.themeConfig.mermaid) : "";
|
|
1241
|
+
return `<!DOCTYPE html>
|
|
1242
|
+
<html lang="${lang}">
|
|
1243
|
+
<head>
|
|
1244
|
+
<meta charset="utf-8">
|
|
1245
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
1246
|
+
${result.head}
|
|
1247
|
+
${config.head.join("\n")}
|
|
1248
|
+
${pageHead.join("\n")}
|
|
1249
|
+
${mermaidScript}
|
|
1250
|
+
<style>${generatedCss}</style>
|
|
1251
|
+
<style id="domphy-style">${result.css}</style>
|
|
1252
|
+
<script>${RUNTIME_SCRIPT}</script>
|
|
1253
|
+
</head>
|
|
1254
|
+
<body>
|
|
1255
|
+
<div id="domphy-app">${result.html}</div>${islandsScript}
|
|
1256
|
+
</body>
|
|
1257
|
+
</html>`;
|
|
1258
|
+
}
|
|
1259
|
+
async function buildSite(options) {
|
|
1260
|
+
const { config, srcDir, outDir, publicDir } = options;
|
|
1261
|
+
const searchEnabled = config.themeConfig.search !== false;
|
|
1262
|
+
const showLastUpdated = !!config.lastUpdated;
|
|
1263
|
+
const pages = discoverPages(srcDir);
|
|
1264
|
+
const localePages = pages.map((p) => ({ ...p, localeKey: "/" }));
|
|
1265
|
+
if (config.locales) {
|
|
1266
|
+
for (const [localeKey, locale] of Object.entries(config.locales)) {
|
|
1267
|
+
if (localeKey === "/") continue;
|
|
1268
|
+
const localeDir = resolve2(srcDir, localeKey.replace(/^\//, "").replace(/\/$/, ""));
|
|
1269
|
+
if (!existsSync(localeDir)) continue;
|
|
1270
|
+
for (const p of discoverPages(localeDir)) {
|
|
1271
|
+
const prefix = localeKey.replace(/\/$/, "");
|
|
1272
|
+
localePages.push({ filePath: p.filePath, route: prefix + p.route, outFile: p.outFile === "index.html" ? localeKey.replace(/^\//, "") + "index.html" : localeKey.replace(/^\//, "") + p.outFile, localeKey });
|
|
1273
|
+
}
|
|
1274
|
+
}
|
|
1275
|
+
}
|
|
1276
|
+
console.log(`Discovered ${localePages.length} pages.`);
|
|
1277
|
+
const highlight = await createHighlighter();
|
|
1278
|
+
const generatedCss = themeCSS() + pressCSS();
|
|
1279
|
+
const built = [];
|
|
1280
|
+
const searchDocs = [];
|
|
1281
|
+
for (const page of localePages) {
|
|
1282
|
+
const source = readFileSync2(page.filePath, "utf8");
|
|
1283
|
+
const doc = await renderDoc(source, { filePath: page.filePath, docsDir: srcDir, repoRoot: srcDir, highlight });
|
|
1284
|
+
sanitizeStyles(doc.body);
|
|
1285
|
+
const textParts = [];
|
|
1286
|
+
flattenText(doc.body, textParts);
|
|
1287
|
+
const textContent = textParts.join(" ").replace(/\s+/g, " ").trim();
|
|
1288
|
+
const readingTime = estimateReadingTime(textContent);
|
|
1289
|
+
const lastUpdated = showLastUpdated ? getLastUpdated(page.filePath) : void 0;
|
|
1290
|
+
const relPath = relative2(srcDir, page.filePath).replace(/\\/g, "/");
|
|
1291
|
+
built.push({ route: page.route, outFile: page.outFile, title: doc.title, localeKey: page.localeKey, doc, lastUpdated, readingTime, filePath: page.filePath, relPath });
|
|
1292
|
+
searchDocs.push({ route: page.route, title: doc.title, text: textContent.slice(0, 2e4), toc: doc.toc });
|
|
1293
|
+
}
|
|
1294
|
+
const pageHeadMap = /* @__PURE__ */ new Map();
|
|
1295
|
+
const pageLangMap = /* @__PURE__ */ new Map();
|
|
1296
|
+
const appRoutes = defineRoutes(
|
|
1297
|
+
built.map((page) => {
|
|
1298
|
+
const localeConfig = config.locales?.[page.localeKey];
|
|
1299
|
+
const mergedTheme = localeConfig?.themeConfig ? { ...config.themeConfig, ...localeConfig.themeConfig } : config.themeConfig;
|
|
1300
|
+
const mergedConfig = { ...config, themeConfig: mergedTheme };
|
|
1301
|
+
const lang = localeConfig?.lang ?? "en";
|
|
1302
|
+
const ctx = {
|
|
1303
|
+
route: page.route,
|
|
1304
|
+
title: page.title,
|
|
1305
|
+
body: page.doc.body,
|
|
1306
|
+
toc: page.doc.toc,
|
|
1307
|
+
frontmatter: page.doc.frontmatter,
|
|
1308
|
+
config: mergedConfig,
|
|
1309
|
+
lastUpdated: page.lastUpdated,
|
|
1310
|
+
readingTime: page.readingTime,
|
|
1311
|
+
filePath: page.relPath
|
|
1312
|
+
};
|
|
1313
|
+
const isHome = page.route === "/" || page.localeKey !== "/" && page.route === page.localeKey;
|
|
1314
|
+
const description = typeof page.doc.frontmatter.description === "string" ? page.doc.frontmatter.description : firstParagraphText(page.doc.body) || config.description;
|
|
1315
|
+
const siteTitle = localeConfig?.title ?? config.title;
|
|
1316
|
+
const pageTitle = page.title === siteTitle ? siteTitle : `${page.title} | ${siteTitle}`;
|
|
1317
|
+
const canonical = page.route === "/" ? `${config.hostname}/` : `${config.hostname}${page.route}/`;
|
|
1318
|
+
const pageHead = Array.isArray(page.doc.frontmatter.head) ? page.doc.frontmatter.head.filter((s) => typeof s === "string") : [];
|
|
1319
|
+
pageHeadMap.set(page.route, pageHead);
|
|
1320
|
+
pageLangMap.set(page.route, lang);
|
|
1321
|
+
return {
|
|
1322
|
+
path: page.route,
|
|
1323
|
+
metadata: {
|
|
1324
|
+
title: pageTitle,
|
|
1325
|
+
description,
|
|
1326
|
+
metadataBase: config.hostname,
|
|
1327
|
+
openGraph: { title: pageTitle, description, url: page.route === "/" ? "/" : `${page.route}/`, siteName: siteTitle, type: "website" },
|
|
1328
|
+
twitter: { card: "summary", title: pageTitle, description },
|
|
1329
|
+
alternates: { canonical }
|
|
1330
|
+
},
|
|
1331
|
+
page: () => isHome ? homeShell(ctx) : pageShell(ctx)
|
|
1332
|
+
};
|
|
1333
|
+
})
|
|
1334
|
+
);
|
|
1335
|
+
const app = createApp(appRoutes);
|
|
1336
|
+
rmSync(outDir, { recursive: true, force: true });
|
|
1337
|
+
mkdirSync(outDir, { recursive: true });
|
|
1338
|
+
const failures = [];
|
|
1339
|
+
let totalBytes = 0;
|
|
1340
|
+
for (const page of built) {
|
|
1341
|
+
try {
|
|
1342
|
+
const result = await app.renderToString(page.route);
|
|
1343
|
+
const pageHead = pageHeadMap.get(page.route) ?? [];
|
|
1344
|
+
const lang = pageLangMap.get(page.route) ?? "en";
|
|
1345
|
+
const html = htmlDocument(result, config, searchEnabled, generatedCss, pageHead, lang);
|
|
1346
|
+
const outPath = join2(outDir, page.outFile);
|
|
1347
|
+
mkdirSync(dirname2(outPath), { recursive: true });
|
|
1348
|
+
writeFileSync(outPath, html, "utf8");
|
|
1349
|
+
totalBytes += html.length;
|
|
1350
|
+
if (result.status !== 200) console.warn(` ! ${page.route} -> status ${result.status}`);
|
|
1351
|
+
} catch (error) {
|
|
1352
|
+
failures.push({ route: page.route, error: String(error.message || error) });
|
|
1353
|
+
}
|
|
1354
|
+
}
|
|
1355
|
+
if (failures.length > 0) {
|
|
1356
|
+
console.warn(`
|
|
1357
|
+
${failures.length} page(s) failed:`);
|
|
1358
|
+
for (const failure of failures) console.warn(` \u2717 ${failure.route}: ${failure.error}`);
|
|
1359
|
+
}
|
|
1360
|
+
await buildIslandsBundle(outDir, searchEnabled);
|
|
1361
|
+
writeFileSync(join2(outDir, "search-index.json"), buildSearchIndex(searchDocs), "utf8");
|
|
1362
|
+
if (publicDir && existsSync(publicDir)) cpSync(publicDir, outDir, { recursive: true });
|
|
1363
|
+
if (config.hostname) {
|
|
1364
|
+
writeFileSync(join2(outDir, "sitemap.xml"), buildSitemap(built.map((p) => p.route), config.hostname), "utf8");
|
|
1365
|
+
}
|
|
1366
|
+
console.log(`Built ${built.length} pages (${(totalBytes / 1024).toFixed(0)} KB) \u2192 ${outDir}`);
|
|
1367
|
+
}
|
|
1368
|
+
export {
|
|
1369
|
+
buildSite
|
|
1370
|
+
};
|