@dogsbay/ssg 0.0.0-stage → 0.2.0-beta.129
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/LICENSE +201 -0
- package/NOTICE +17 -0
- package/README.md +39 -2
- package/dist/package/THIRD-PARTY-NOTICES.txt +589 -0
- package/dist/package/browser.mjs +4690 -0
- package/dist/package/chunks/chunk-3BM23K4O.mjs +84 -0
- package/dist/package/chunks/chunk-UZZEKSEQ.mjs +47 -0
- package/dist/package/chunks/katex-assets-7BGR6WCR.mjs +7 -0
- package/dist/package/chunks/prebuilt-css-default-MOOPVBZ5.mjs +2161 -0
- package/dist/package/chunks/prebuilt-css-mintlify-HAG54PAM.mjs +2161 -0
- package/dist/package/chunks/tailwind-fallback-KPRFHW3C.mjs +7 -0
- package/dist/package/chunks/topicmap-PY3WDCSI.mjs +53 -0
- package/dist/package/client.mjs +683 -0
- package/dist/package/css.mjs +421 -0
- package/dist/package/types/client/data-script.d.ts +6 -0
- package/dist/package/types/client/elements.d.ts +16 -0
- package/dist/package/types/client/highlight.d.ts +1 -0
- package/dist/package/types/client/image-zoom.d.ts +2 -0
- package/dist/package/types/client/mount.d.ts +27 -0
- package/dist/package/types/client/pagefind.d.ts +14 -0
- package/dist/package/types/client/search.d.ts +13 -0
- package/dist/package/types/client/targets.d.ts +6 -0
- package/dist/package/types/core/blog.d.ts +53 -0
- package/dist/package/types/core/build.d.ts +283 -0
- package/dist/package/types/core/canonical.d.ts +63 -0
- package/dist/package/types/core/config.d.ts +286 -0
- package/dist/package/types/core/detach.d.ts +55 -0
- package/dist/package/types/core/dev.d.ts +63 -0
- package/dist/package/types/core/diagrams.d.ts +93 -0
- package/dist/package/types/core/links.d.ts +39 -0
- package/dist/package/types/core/merman.d.ts +28 -0
- package/dist/package/types/core/nav.d.ts +35 -0
- package/dist/package/types/core/paths.d.ts +24 -0
- package/dist/package/types/core/pele.d.ts +15 -0
- package/dist/package/types/core/preprocess.d.ts +14 -0
- package/dist/package/types/core/resolve.d.ts +95 -0
- package/dist/package/types/core/site-files.d.ts +121 -0
- package/dist/package/types/core/strings.d.ts +1 -0
- package/dist/package/types/core/taxonomy.d.ts +39 -0
- package/dist/package/types/core/topicmap.d.ts +28 -0
- package/dist/package/types/core/yaml.d.ts +1 -0
- package/dist/package/types/generated/assets.d.ts +7 -0
- package/dist/package/types/generated/css-assets.d.ts +2 -0
- package/dist/package/types/generated/katex-assets.d.ts +3 -0
- package/dist/package/types/generated/prebuilt-css-default.d.ts +1 -0
- package/dist/package/types/generated/prebuilt-css-mintlify.d.ts +1 -0
- package/dist/package/types/package/browser.d.ts +29 -0
- package/dist/package/types/package/client.d.ts +17 -0
- package/dist/package/types/package/css.d.ts +6 -0
- package/dist/package/types/package/prebuilt.d.ts +2 -0
- package/dist/package/types/theme/classes.d.ts +7 -0
- package/dist/package/types/theme/compose.d.ts +99 -0
- package/dist/package/types/theme/css-build.d.ts +16 -0
- package/dist/package/types/theme/docs-layout/link-icons.d.ts +33 -0
- package/dist/package/types/theme/docs-layout/tag-list-data.d.ts +126 -0
- package/dist/package/types/theme/page.d.ts +34 -0
- package/dist/package/types/theme/pagefind.d.ts +10 -0
- package/dist/package/types/theme/regions.d.ts +84 -0
- package/dist/package/types/theme/seo.d.ts +57 -0
- package/package.json +92 -4
|
@@ -0,0 +1,683 @@
|
|
|
1
|
+
// src/client/elements.ts
|
|
2
|
+
import "@dogsbay/elements/db-tabs";
|
|
3
|
+
import "@dogsbay/elements/db-accordion";
|
|
4
|
+
import "@dogsbay/elements/db-details-sheet";
|
|
5
|
+
import "@dogsbay/elements/db-code-block";
|
|
6
|
+
import "@dogsbay/elements/db-nav-tree";
|
|
7
|
+
import "@dogsbay/elements/db-toc";
|
|
8
|
+
import "@dogsbay/elements/db-dialog";
|
|
9
|
+
import "@dogsbay/elements/db-combobox";
|
|
10
|
+
import "@dogsbay/elements/db-select";
|
|
11
|
+
import "@dogsbay/elements/db-popover";
|
|
12
|
+
import "@dogsbay/elements/db-tooltip";
|
|
13
|
+
|
|
14
|
+
// node_modules/@dogsbay/ui/src/sidebar/sidebar.ts
|
|
15
|
+
import { ScrollLock } from "@dogsbay/primitives/scroll-lock";
|
|
16
|
+
var SIDEBAR_STORAGE_KEY = "sidebar_state";
|
|
17
|
+
var SIDEBAR_KEYBOARD_SHORTCUT = "b";
|
|
18
|
+
var MOBILE_BREAKPOINT = 768;
|
|
19
|
+
var instances = /* @__PURE__ */ new WeakMap();
|
|
20
|
+
function getStoredState(key) {
|
|
21
|
+
try {
|
|
22
|
+
return localStorage.getItem(key);
|
|
23
|
+
} catch {
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
function setStoredState(key, value) {
|
|
28
|
+
try {
|
|
29
|
+
localStorage.setItem(key, value);
|
|
30
|
+
} catch {
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
function initSidebar(provider) {
|
|
34
|
+
if (instances.has(provider)) return;
|
|
35
|
+
const sidebar = provider.querySelector(
|
|
36
|
+
"[data-component='sidebar']"
|
|
37
|
+
);
|
|
38
|
+
if (!sidebar) return;
|
|
39
|
+
const collapsible = sidebar.dataset.collapsible || "offcanvas";
|
|
40
|
+
const side = sidebar.dataset.side || "left";
|
|
41
|
+
const defaultOpen = sidebar.dataset.defaultOpen !== "false";
|
|
42
|
+
const storedState = getStoredState(SIDEBAR_STORAGE_KEY);
|
|
43
|
+
const initialOpen = storedState !== null ? storedState === "true" : defaultOpen;
|
|
44
|
+
const desktopSidebar = sidebar.querySelector(
|
|
45
|
+
"[data-sidebar-desktop]"
|
|
46
|
+
);
|
|
47
|
+
const mobileSidebar = sidebar.querySelector(
|
|
48
|
+
"[data-sidebar-mobile]"
|
|
49
|
+
);
|
|
50
|
+
const mobileBackdrop = sidebar.querySelector(
|
|
51
|
+
"[data-sidebar-mobile-backdrop]"
|
|
52
|
+
);
|
|
53
|
+
const mediaQuery = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`);
|
|
54
|
+
const instance = {
|
|
55
|
+
provider,
|
|
56
|
+
sidebar,
|
|
57
|
+
desktopSidebar,
|
|
58
|
+
mobileSidebar,
|
|
59
|
+
mobileBackdrop,
|
|
60
|
+
collapsible,
|
|
61
|
+
side,
|
|
62
|
+
open: initialOpen,
|
|
63
|
+
openMobile: false,
|
|
64
|
+
isMobile: mediaQuery.matches,
|
|
65
|
+
mediaQuery
|
|
66
|
+
};
|
|
67
|
+
instances.set(provider, instance);
|
|
68
|
+
updateDesktopState(instance);
|
|
69
|
+
const handleMediaChange = (e) => {
|
|
70
|
+
instance.isMobile = e.matches;
|
|
71
|
+
if (!e.matches && instance.openMobile) {
|
|
72
|
+
closeMobile(provider);
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
mediaQuery.addEventListener("change", handleMediaChange);
|
|
76
|
+
const handleKeyDown = (e) => {
|
|
77
|
+
if (e.key === SIDEBAR_KEYBOARD_SHORTCUT && (e.metaKey || e.ctrlKey)) {
|
|
78
|
+
e.preventDefault();
|
|
79
|
+
toggleSidebar(provider);
|
|
80
|
+
} else if (e.key === "Escape" && instance.openMobile) {
|
|
81
|
+
e.preventDefault();
|
|
82
|
+
closeMobile(provider);
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
document.addEventListener("keydown", handleKeyDown);
|
|
86
|
+
bindTriggers(provider, instance);
|
|
87
|
+
if (mobileBackdrop) {
|
|
88
|
+
mobileBackdrop.addEventListener("click", () => {
|
|
89
|
+
closeMobile(provider);
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
const rail = sidebar.querySelector("[data-part='rail']");
|
|
93
|
+
if (rail) {
|
|
94
|
+
rail.addEventListener("click", () => {
|
|
95
|
+
toggleSidebar(provider);
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
function bindTriggers(provider, instance) {
|
|
100
|
+
provider.querySelectorAll("[data-part='sidebar-trigger']").forEach((el) => {
|
|
101
|
+
el.addEventListener("click", () => {
|
|
102
|
+
toggleSidebar(provider);
|
|
103
|
+
});
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
function toggleSidebar(provider) {
|
|
107
|
+
const instance = instances.get(provider);
|
|
108
|
+
if (!instance) return;
|
|
109
|
+
if (instance.isMobile) {
|
|
110
|
+
if (instance.openMobile) {
|
|
111
|
+
closeMobile(provider);
|
|
112
|
+
} else {
|
|
113
|
+
openMobile(provider);
|
|
114
|
+
}
|
|
115
|
+
} else {
|
|
116
|
+
instance.open = !instance.open;
|
|
117
|
+
updateDesktopState(instance);
|
|
118
|
+
setStoredState(SIDEBAR_STORAGE_KEY, String(instance.open));
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
function updateDesktopState(instance) {
|
|
122
|
+
const state = instance.open ? "expanded" : "collapsed";
|
|
123
|
+
instance.provider.setAttribute("data-state", state);
|
|
124
|
+
instance.sidebar.setAttribute("data-state", state);
|
|
125
|
+
if (instance.desktopSidebar) {
|
|
126
|
+
instance.desktopSidebar.setAttribute("data-state", state);
|
|
127
|
+
if (!instance.open) {
|
|
128
|
+
instance.desktopSidebar.setAttribute(
|
|
129
|
+
"data-collapsible",
|
|
130
|
+
instance.collapsible
|
|
131
|
+
);
|
|
132
|
+
} else {
|
|
133
|
+
instance.desktopSidebar.setAttribute("data-collapsible", "");
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
function openMobile(provider) {
|
|
138
|
+
const instance = instances.get(provider);
|
|
139
|
+
if (!instance || instance.openMobile || !instance.mobileSidebar) return;
|
|
140
|
+
instance.openMobile = true;
|
|
141
|
+
const sidebarInner = instance.desktopSidebar?.querySelector(
|
|
142
|
+
"[data-sidebar='sidebar-inner']"
|
|
143
|
+
);
|
|
144
|
+
if (sidebarInner) {
|
|
145
|
+
while (sidebarInner.firstChild) {
|
|
146
|
+
instance.mobileSidebar.appendChild(sidebarInner.firstChild);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
instance.mobileSidebar.hidden = false;
|
|
150
|
+
instance.mobileSidebar.setAttribute("data-state", "open");
|
|
151
|
+
if (instance.mobileBackdrop) {
|
|
152
|
+
instance.mobileBackdrop.hidden = false;
|
|
153
|
+
}
|
|
154
|
+
ScrollLock.activate();
|
|
155
|
+
requestAnimationFrame(() => {
|
|
156
|
+
const focusable = instance.mobileSidebar?.querySelector(
|
|
157
|
+
'a, button, [tabindex]:not([tabindex="-1"])'
|
|
158
|
+
);
|
|
159
|
+
focusable?.focus();
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
function closeMobile(provider) {
|
|
163
|
+
const instance = instances.get(provider);
|
|
164
|
+
if (!instance || !instance.openMobile || !instance.mobileSidebar) return;
|
|
165
|
+
instance.openMobile = false;
|
|
166
|
+
const sidebarInner = instance.desktopSidebar?.querySelector(
|
|
167
|
+
"[data-sidebar='sidebar-inner']"
|
|
168
|
+
);
|
|
169
|
+
if (sidebarInner && instance.mobileSidebar) {
|
|
170
|
+
while (instance.mobileSidebar.firstChild) {
|
|
171
|
+
sidebarInner.appendChild(instance.mobileSidebar.firstChild);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
instance.mobileSidebar.setAttribute("data-state", "closed");
|
|
175
|
+
instance.mobileSidebar.hidden = true;
|
|
176
|
+
if (instance.mobileBackdrop) {
|
|
177
|
+
instance.mobileBackdrop.hidden = true;
|
|
178
|
+
}
|
|
179
|
+
ScrollLock.deactivate();
|
|
180
|
+
const trigger = instance.provider.querySelector(
|
|
181
|
+
"[data-part='sidebar-trigger']"
|
|
182
|
+
);
|
|
183
|
+
trigger?.focus();
|
|
184
|
+
}
|
|
185
|
+
function init() {
|
|
186
|
+
document.querySelectorAll("[data-component='sidebar-provider']").forEach((el) => {
|
|
187
|
+
initSidebar(el);
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
if (document.readyState === "loading") {
|
|
191
|
+
document.addEventListener("DOMContentLoaded", init);
|
|
192
|
+
} else {
|
|
193
|
+
init();
|
|
194
|
+
}
|
|
195
|
+
document.addEventListener("astro:page-load", init);
|
|
196
|
+
|
|
197
|
+
// src/client/search.ts
|
|
198
|
+
import { loadDetails, parseQuery as parseQuery2, scriptData, search } from "@dogsbay/search/query";
|
|
199
|
+
|
|
200
|
+
// src/client/pagefind.ts
|
|
201
|
+
import { parseQuery } from "@dogsbay/search/query";
|
|
202
|
+
function pagefindSearch(unitRoot) {
|
|
203
|
+
let mod;
|
|
204
|
+
const unitPath = new URL(unitRoot || "./", location.href).pathname;
|
|
205
|
+
return async (q) => {
|
|
206
|
+
mod ??= import(new URL(`${unitRoot}pagefind/pagefind.js`, location.href).href).catch((e) => {
|
|
207
|
+
mod = void 0;
|
|
208
|
+
throw e;
|
|
209
|
+
});
|
|
210
|
+
const words = q.replace(/(?<!\S)-?(tag|section):("[^"]*"?|\S*)/gi, " ").trim();
|
|
211
|
+
const found = words ? await (await mod).search(words) : null;
|
|
212
|
+
const hits = found?.results ?? [];
|
|
213
|
+
const toResult = async (h, i) => {
|
|
214
|
+
const d = await h.data();
|
|
215
|
+
const url = d.url.startsWith(unitPath) ? d.url.slice(unitPath.length) : d.url.replace(/^\/+/, "");
|
|
216
|
+
const headings = (d.sub_results ?? []).map((s) => [s.title, s.url.split("#")[1] ?? ""]).filter(([, id]) => id);
|
|
217
|
+
return { id: i, title: d.meta.title ?? url, url, section: "", score: hits.length - i, fragment: [text(d.excerpt), headings], sections: headings.slice(0, 3) };
|
|
218
|
+
};
|
|
219
|
+
const first = await Promise.all(hits.slice(0, 10).map(toResult));
|
|
220
|
+
const more = Promise.all(hits.slice(10, 30).map((h, i) => toResult(h, i + 10)));
|
|
221
|
+
more.catch(() => {
|
|
222
|
+
});
|
|
223
|
+
return { results: first, more, total: hits.length, highlight: parseQuery(q).highlight };
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
function text(html) {
|
|
227
|
+
return new DOMParser().parseFromString(html, "text/html").body.textContent ?? "";
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
// src/client/search.ts
|
|
231
|
+
function initSearch(opts) {
|
|
232
|
+
const { signal } = opts;
|
|
233
|
+
const dialog = document.getElementById("db-search");
|
|
234
|
+
if (!dialog) return;
|
|
235
|
+
const input = dialog.querySelector("[data-db-search-input]");
|
|
236
|
+
const list = dialog.querySelector("[data-part='listbox']");
|
|
237
|
+
const status = dialog.querySelector("[data-db-search-status]");
|
|
238
|
+
const hint = status.textContent ?? "";
|
|
239
|
+
const data = scriptData(`${opts.unitRoot}_dogsbay/search/`, opts.loadScript, window);
|
|
240
|
+
const engine = document.body.dataset.search ?? "builtin";
|
|
241
|
+
const served = location.protocol !== "file:";
|
|
242
|
+
const pagefind = engine === "pagefind" || engine === "both" && served ? pagefindSearch(opts.unitRoot) : void 0;
|
|
243
|
+
const needsServer = engine === "pagefind" && !served;
|
|
244
|
+
dialog.addEventListener("db-dialog:open", () => {
|
|
245
|
+
input.focus();
|
|
246
|
+
input.select();
|
|
247
|
+
if (needsServer) status.textContent = list.dataset.needsServer ?? "";
|
|
248
|
+
else if (!pagefind) void data.meta().catch(() => status.textContent = "Search index could not be loaded.");
|
|
249
|
+
}, { signal });
|
|
250
|
+
document.addEventListener("keydown", (e) => {
|
|
251
|
+
const typing = e.target.closest("input, textarea, select, [contenteditable]");
|
|
252
|
+
if (e.key === "/" && !typing || e.key.toLowerCase() === "k" && (e.metaKey || e.ctrlKey)) {
|
|
253
|
+
e.preventDefault();
|
|
254
|
+
if (!dialog.open) dialog.show();
|
|
255
|
+
else input.focus();
|
|
256
|
+
}
|
|
257
|
+
}, { signal });
|
|
258
|
+
list.addEventListener("click", (e) => {
|
|
259
|
+
if (e.target.closest("a")) dialog.close("api");
|
|
260
|
+
}, { signal });
|
|
261
|
+
let seq = 0;
|
|
262
|
+
let parsed;
|
|
263
|
+
let timer;
|
|
264
|
+
input.addEventListener("input", () => {
|
|
265
|
+
clearTimeout(timer);
|
|
266
|
+
timer = setTimeout(() => void run(++seq), 80);
|
|
267
|
+
}, { signal });
|
|
268
|
+
const pending = /* @__PURE__ */ new Map();
|
|
269
|
+
const observer = typeof IntersectionObserver === "function" ? new IntersectionObserver((entries) => {
|
|
270
|
+
for (const e of entries)
|
|
271
|
+
if (e.isIntersecting) {
|
|
272
|
+
pending.get(e.target)?.();
|
|
273
|
+
pending.delete(e.target);
|
|
274
|
+
observer.unobserve(e.target);
|
|
275
|
+
}
|
|
276
|
+
}) : void 0;
|
|
277
|
+
const run = async (mine) => {
|
|
278
|
+
const q = input.value.trim();
|
|
279
|
+
if (!q) {
|
|
280
|
+
observer?.disconnect();
|
|
281
|
+
pending.clear();
|
|
282
|
+
filterBar.hidden = true;
|
|
283
|
+
list.replaceChildren();
|
|
284
|
+
status.textContent = hint;
|
|
285
|
+
return;
|
|
286
|
+
}
|
|
287
|
+
if (needsServer) return;
|
|
288
|
+
try {
|
|
289
|
+
if (pagefind) {
|
|
290
|
+
const found = await pagefind(q);
|
|
291
|
+
if (mine !== seq) return;
|
|
292
|
+
render(q, found.results, found.highlight, found.total);
|
|
293
|
+
const more = await found.more;
|
|
294
|
+
if (mine === seq && more.length) append(q, more, found.highlight);
|
|
295
|
+
} else {
|
|
296
|
+
const found = await search(q, data);
|
|
297
|
+
if (mine !== seq) return;
|
|
298
|
+
parsed = found.parsed;
|
|
299
|
+
render(q, found.results.slice(0, 30), found.parsed.highlight, found.results.length, found.results);
|
|
300
|
+
}
|
|
301
|
+
} catch {
|
|
302
|
+
if (mine === seq) status.textContent = "Search index could not be loaded.";
|
|
303
|
+
}
|
|
304
|
+
};
|
|
305
|
+
const filterBar = document.createElement("div");
|
|
306
|
+
filterBar.setAttribute("role", "group");
|
|
307
|
+
filterBar.setAttribute("aria-label", list.dataset.filterSection ?? "Filter by section");
|
|
308
|
+
filterBar.className = "flex flex-wrap gap-1 px-3 pb-2";
|
|
309
|
+
filterBar.hidden = true;
|
|
310
|
+
list.before(filterBar);
|
|
311
|
+
signal?.addEventListener("abort", () => {
|
|
312
|
+
clearTimeout(timer);
|
|
313
|
+
seq++;
|
|
314
|
+
observer?.disconnect();
|
|
315
|
+
pending.clear();
|
|
316
|
+
filterBar.remove();
|
|
317
|
+
});
|
|
318
|
+
const bare = (name) => name.replace(/"/g, "");
|
|
319
|
+
const sectionToken = (name) => `section:"${bare(name)}"`;
|
|
320
|
+
let refocus;
|
|
321
|
+
const filters = (q, all) => {
|
|
322
|
+
const counts = /* @__PURE__ */ new Map();
|
|
323
|
+
for (const r of all) if (r.section) counts.set(r.section, (counts.get(r.section) ?? 0) + 1);
|
|
324
|
+
const active = [...q.matchAll(/section:"([^"]*)"/gi)].map((m) => m[1].toLowerCase());
|
|
325
|
+
const isActive = (name) => active.includes(bare(name).toLowerCase());
|
|
326
|
+
const names = [...counts].sort((a, b) => b[1] - a[1]).slice(0, 6).map(([n]) => n);
|
|
327
|
+
for (const a of active) if (!names.some((n) => bare(n).toLowerCase() === a)) names.push(a);
|
|
328
|
+
filterBar.replaceChildren(
|
|
329
|
+
...names.length > 1 || active.length ? names.map((name) => {
|
|
330
|
+
const b = document.createElement("button");
|
|
331
|
+
b.type = "button";
|
|
332
|
+
const on = isActive(name);
|
|
333
|
+
b.setAttribute("aria-pressed", String(on));
|
|
334
|
+
b.className = "rounded-full border px-2.5 py-0.5 text-xs hover:bg-accent aria-pressed:bg-primary aria-pressed:text-primary-foreground";
|
|
335
|
+
b.textContent = name;
|
|
336
|
+
b.addEventListener("click", () => {
|
|
337
|
+
const token = sectionToken(name);
|
|
338
|
+
const rest = input.value.replace(new RegExp(`\\s*section:"${bare(name).replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}"`, "i"), "").trim();
|
|
339
|
+
input.value = on ? rest : `${rest} ${token}`.trim();
|
|
340
|
+
refocus = name;
|
|
341
|
+
input.dispatchEvent(new Event("input", { bubbles: true }));
|
|
342
|
+
}, { signal });
|
|
343
|
+
return b;
|
|
344
|
+
}) : []
|
|
345
|
+
);
|
|
346
|
+
filterBar.hidden = !filterBar.childElementCount;
|
|
347
|
+
if (refocus !== void 0) {
|
|
348
|
+
const again = [...filterBar.querySelectorAll("button")].find((b) => b.textContent === refocus);
|
|
349
|
+
(again ?? input).focus();
|
|
350
|
+
refocus = void 0;
|
|
351
|
+
}
|
|
352
|
+
};
|
|
353
|
+
const render = (q, results, terms, total, all = results) => {
|
|
354
|
+
observer?.disconnect();
|
|
355
|
+
pending.clear();
|
|
356
|
+
filters(q, all);
|
|
357
|
+
list.replaceChildren(...items(q, results, terms));
|
|
358
|
+
status.textContent = total ? `${total} result${total === 1 ? "" : "s"}` : `${list.dataset.noResults} \u201C${q}\u201D`;
|
|
359
|
+
};
|
|
360
|
+
const append = (q, results, terms) => list.append(...items(q, results, terms));
|
|
361
|
+
const items = (q, results, terms) => {
|
|
362
|
+
const items2 = [];
|
|
363
|
+
for (const r of results) {
|
|
364
|
+
const page = option(r.url, terms, "block rounded-md p-3 hover:bg-accent");
|
|
365
|
+
const t = document.createElement("div");
|
|
366
|
+
t.className = "font-medium";
|
|
367
|
+
t.append(...highlight(r.title, terms));
|
|
368
|
+
page.a.appendChild(t);
|
|
369
|
+
if (r.section) {
|
|
370
|
+
const s = document.createElement("div");
|
|
371
|
+
s.className = "text-xs text-muted-foreground";
|
|
372
|
+
s.textContent = r.section;
|
|
373
|
+
page.a.appendChild(s);
|
|
374
|
+
}
|
|
375
|
+
const excerpt = document.createElement("div");
|
|
376
|
+
excerpt.className = "mt-1 line-clamp-2 text-xs text-muted-foreground";
|
|
377
|
+
page.a.appendChild(excerpt);
|
|
378
|
+
items2.push(page.li);
|
|
379
|
+
const fill = () => {
|
|
380
|
+
if (!r.fragment) return [];
|
|
381
|
+
if (r.fragment[0]) excerpt.replaceChildren(...highlight(r.fragment[0], terms));
|
|
382
|
+
return (r.sections ?? []).map(([text2, id]) => {
|
|
383
|
+
const sub = option(`${r.url}#${id}`, terms, "ml-4 block rounded-md border-l px-3 py-1.5 text-sm hover:bg-accent");
|
|
384
|
+
sub.a.append(...highlight(text2, terms));
|
|
385
|
+
return sub.li;
|
|
386
|
+
});
|
|
387
|
+
};
|
|
388
|
+
if (r.fragment) items2.push(...fill());
|
|
389
|
+
else if (observer) {
|
|
390
|
+
const p = parsed ?? parseQuery2(q);
|
|
391
|
+
pending.set(page.li, () => void loadDetails(p, [r], data).then(() => page.li.after(...fill()), () => {
|
|
392
|
+
}));
|
|
393
|
+
observer.observe(page.li);
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
return items2;
|
|
397
|
+
};
|
|
398
|
+
const option = (url, terms, className) => {
|
|
399
|
+
const li = document.createElement("li");
|
|
400
|
+
li.setAttribute("role", "none");
|
|
401
|
+
li.className = "mb-1";
|
|
402
|
+
const a = document.createElement("a");
|
|
403
|
+
a.setAttribute("data-part", "option");
|
|
404
|
+
a.dataset.value = url;
|
|
405
|
+
a.href = withHighlight(opts.unitRoot + url, terms);
|
|
406
|
+
a.tabIndex = -1;
|
|
407
|
+
a.className = className;
|
|
408
|
+
li.appendChild(a);
|
|
409
|
+
return { li, a };
|
|
410
|
+
};
|
|
411
|
+
}
|
|
412
|
+
function withHighlight(href, terms) {
|
|
413
|
+
if (!terms.length) return href;
|
|
414
|
+
const hash = href.indexOf("#");
|
|
415
|
+
const [path, frag] = hash < 0 ? [href, ""] : [href.slice(0, hash), href.slice(hash)];
|
|
416
|
+
return `${path}${path.includes("?") ? "&" : "?"}h=${encodeURIComponent(terms.join(" "))}${frag}`;
|
|
417
|
+
}
|
|
418
|
+
function highlight(text2, terms) {
|
|
419
|
+
if (!terms.length) return [document.createTextNode(text2)];
|
|
420
|
+
const re = new RegExp(`(${terms.map((t) => t.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")).join("|")})`, "gi");
|
|
421
|
+
return text2.split(re).map((part, i) => {
|
|
422
|
+
if (i % 2 === 0) return document.createTextNode(part);
|
|
423
|
+
const m = document.createElement("mark");
|
|
424
|
+
m.textContent = part;
|
|
425
|
+
return m;
|
|
426
|
+
});
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
// src/client/highlight.ts
|
|
430
|
+
var MAX_MARKS = 500;
|
|
431
|
+
var CJK = /[\p{Script=Han}\p{Script=Hiragana}\p{Script=Katakana}\p{Script=Hangul}]/u;
|
|
432
|
+
function initHighlights(signal) {
|
|
433
|
+
let terms;
|
|
434
|
+
try {
|
|
435
|
+
terms = (new URLSearchParams(location.search).get("h") ?? "").split(/\s+/).filter((t) => t.length > 0);
|
|
436
|
+
} catch {
|
|
437
|
+
return;
|
|
438
|
+
}
|
|
439
|
+
const article = document.querySelector("#db-content article") ?? document.querySelector("#db-content");
|
|
440
|
+
if (!terms.length || !article) return;
|
|
441
|
+
const esc = (t) => t.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
442
|
+
const byLength = [...terms].sort((a, b) => b.length - a.length);
|
|
443
|
+
const cjk = byLength.filter((t) => CJK.test(t)).map(esc);
|
|
444
|
+
const words = byLength.filter((t) => !CJK.test(t)).map(esc);
|
|
445
|
+
const parts = [words.length ? `(?<![\\p{L}\\p{N}])(?:${words.join("|")})` : "", cjk.length ? `(?:${cjk.join("|")})` : ""].filter(Boolean);
|
|
446
|
+
const re = new RegExp(`(${parts.join("|")})`, "giu");
|
|
447
|
+
const marks = [];
|
|
448
|
+
const walker = document.createTreeWalker(article, NodeFilter.SHOW_TEXT, {
|
|
449
|
+
acceptNode: (n) => n.parentElement?.closest("script, style, mark, button, [aria-hidden='true']") ? NodeFilter.FILTER_REJECT : NodeFilter.FILTER_ACCEPT
|
|
450
|
+
});
|
|
451
|
+
const nodes = [];
|
|
452
|
+
for (let n = walker.nextNode(); n; n = walker.nextNode()) nodes.push(n);
|
|
453
|
+
for (const node of nodes) {
|
|
454
|
+
if (marks.length >= MAX_MARKS) break;
|
|
455
|
+
const text2 = node.data;
|
|
456
|
+
re.lastIndex = 0;
|
|
457
|
+
if (!re.test(text2)) continue;
|
|
458
|
+
re.lastIndex = 0;
|
|
459
|
+
const frag = document.createDocumentFragment();
|
|
460
|
+
let at = 0;
|
|
461
|
+
for (const m of text2.matchAll(re)) {
|
|
462
|
+
frag.append(text2.slice(at, m.index));
|
|
463
|
+
const mark = document.createElement("mark");
|
|
464
|
+
mark.className = "db-search-hl";
|
|
465
|
+
mark.textContent = m[0];
|
|
466
|
+
frag.append(mark);
|
|
467
|
+
marks.push(mark);
|
|
468
|
+
at = m.index + m[0].length;
|
|
469
|
+
}
|
|
470
|
+
frag.append(text2.slice(at));
|
|
471
|
+
node.replaceWith(frag);
|
|
472
|
+
}
|
|
473
|
+
cleanUrl();
|
|
474
|
+
if (!marks.length) return;
|
|
475
|
+
const label = document.querySelector("[data-clear-highlights]")?.dataset.clearHighlights ?? "Clear highlights";
|
|
476
|
+
const bar = document.createElement("div");
|
|
477
|
+
bar.className = "not-prose mb-4";
|
|
478
|
+
const button = document.createElement("button");
|
|
479
|
+
button.type = "button";
|
|
480
|
+
button.className = "inline-flex h-8 items-center rounded-md border px-3 text-sm hover:bg-accent";
|
|
481
|
+
button.textContent = label;
|
|
482
|
+
button.addEventListener("click", () => {
|
|
483
|
+
for (const m of marks) m.replaceWith(document.createTextNode(m.textContent ?? ""));
|
|
484
|
+
article.normalize();
|
|
485
|
+
bar.remove();
|
|
486
|
+
document.getElementById("db-content")?.focus({ preventScroll: true });
|
|
487
|
+
}, { signal });
|
|
488
|
+
bar.append(button);
|
|
489
|
+
article.prepend(bar);
|
|
490
|
+
if (!location.hash) marks[0].scrollIntoView({ block: "center" });
|
|
491
|
+
}
|
|
492
|
+
function cleanUrl() {
|
|
493
|
+
try {
|
|
494
|
+
const url = new URL(location.href);
|
|
495
|
+
url.searchParams.delete("h");
|
|
496
|
+
history.replaceState(history.state, "", url.toString());
|
|
497
|
+
} catch {
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
// src/client/image-zoom.ts
|
|
502
|
+
import mediumZoom from "medium-zoom";
|
|
503
|
+
var shared;
|
|
504
|
+
function initImageZoom(signal) {
|
|
505
|
+
const raw = document.body.dataset.imageZoom;
|
|
506
|
+
if (!raw) return;
|
|
507
|
+
let opts;
|
|
508
|
+
try {
|
|
509
|
+
opts = JSON.parse(raw);
|
|
510
|
+
} catch {
|
|
511
|
+
return;
|
|
512
|
+
}
|
|
513
|
+
const images = [...document.querySelectorAll('img[data-zoomable="true"]')];
|
|
514
|
+
if (!images.length) return;
|
|
515
|
+
const zoom = shared ??= mediumZoom();
|
|
516
|
+
zoom.update(opts);
|
|
517
|
+
zoom.attach(...images);
|
|
518
|
+
signal?.addEventListener("abort", () => {
|
|
519
|
+
void zoom.close();
|
|
520
|
+
zoom.detach(...images);
|
|
521
|
+
});
|
|
522
|
+
const on = { signal };
|
|
523
|
+
let byKeyboard = false;
|
|
524
|
+
const isKey = (e) => e.key === "Enter" || e.key === " ";
|
|
525
|
+
for (const img of images) {
|
|
526
|
+
if (!img.alt) continue;
|
|
527
|
+
img.tabIndex = 0;
|
|
528
|
+
img.addEventListener("keydown", (e) => {
|
|
529
|
+
if (!isKey(e)) return;
|
|
530
|
+
e.preventDefault();
|
|
531
|
+
byKeyboard = true;
|
|
532
|
+
zoom.open({ target: img });
|
|
533
|
+
}, on);
|
|
534
|
+
img.addEventListener("medium-zoom:opened", () => {
|
|
535
|
+
const zoomed = document.querySelector(".medium-zoom-image--opened");
|
|
536
|
+
if (!byKeyboard || !zoomed) return;
|
|
537
|
+
zoomed.tabIndex = -1;
|
|
538
|
+
zoomed.addEventListener("keydown", (e) => {
|
|
539
|
+
if (!isKey(e)) return;
|
|
540
|
+
e.preventDefault();
|
|
541
|
+
zoom.close();
|
|
542
|
+
});
|
|
543
|
+
zoomed.focus();
|
|
544
|
+
}, on);
|
|
545
|
+
img.addEventListener("medium-zoom:closed", () => {
|
|
546
|
+
if (byKeyboard) img.focus();
|
|
547
|
+
byKeyboard = false;
|
|
548
|
+
}, on);
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
// src/client/targets.ts
|
|
553
|
+
function isRelativeTarget(t) {
|
|
554
|
+
return !/^[\x00-\x20]*([a-z][a-z0-9+.-]*:|[\\/])/i.test(t.replace(/[\t\n\r]/g, ""));
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
// src/client/mount.ts
|
|
558
|
+
var loaded = /* @__PURE__ */ new Map();
|
|
559
|
+
function loadScript(src) {
|
|
560
|
+
let p = loaded.get(src);
|
|
561
|
+
if (!p) {
|
|
562
|
+
p = new Promise((resolve, reject) => {
|
|
563
|
+
const s = document.createElement("script");
|
|
564
|
+
s.src = src;
|
|
565
|
+
s.onload = () => resolve();
|
|
566
|
+
s.onerror = () => {
|
|
567
|
+
loaded.delete(src);
|
|
568
|
+
reject(new Error(`could not load ${src}`));
|
|
569
|
+
};
|
|
570
|
+
document.head.appendChild(s);
|
|
571
|
+
});
|
|
572
|
+
loaded.set(src, p);
|
|
573
|
+
}
|
|
574
|
+
return p;
|
|
575
|
+
}
|
|
576
|
+
function initTheme(signal) {
|
|
577
|
+
document.querySelectorAll("[data-component='theme-toggle']").forEach((btn) => {
|
|
578
|
+
const sync = () => btn.setAttribute("aria-pressed", String(document.documentElement.classList.contains("dark")));
|
|
579
|
+
sync();
|
|
580
|
+
btn.addEventListener("click", () => {
|
|
581
|
+
const dark = !document.documentElement.classList.contains("dark");
|
|
582
|
+
document.documentElement.classList.toggle("dark", dark);
|
|
583
|
+
try {
|
|
584
|
+
localStorage.setItem("theme", dark ? "dark" : "light");
|
|
585
|
+
} catch {
|
|
586
|
+
}
|
|
587
|
+
sync();
|
|
588
|
+
}, { signal });
|
|
589
|
+
});
|
|
590
|
+
}
|
|
591
|
+
function initPageActions(signal) {
|
|
592
|
+
document.addEventListener("click", async (e) => {
|
|
593
|
+
const btn = e.target.closest("[data-copy-markdown]");
|
|
594
|
+
if (!btn) return;
|
|
595
|
+
const md = (document.getElementById("db-page-markdown")?.textContent ?? "").replace(/<\\\/(script)/gi, "</$1").replace(/<\\!--/g, "<!--");
|
|
596
|
+
try {
|
|
597
|
+
await navigator.clipboard.writeText(md);
|
|
598
|
+
const label = btn.dataset.label ??= btn.textContent ?? "";
|
|
599
|
+
btn.textContent = "Copied";
|
|
600
|
+
clearTimeout(Number(btn.dataset.timer));
|
|
601
|
+
btn.dataset.timer = String(setTimeout(() => btn.textContent = label, 1500));
|
|
602
|
+
} catch {
|
|
603
|
+
}
|
|
604
|
+
btn.closest("db-popover")?.close?.("close-press");
|
|
605
|
+
}, { signal });
|
|
606
|
+
}
|
|
607
|
+
function initSwitchers(siteRoot, signal) {
|
|
608
|
+
const page = document.body.dataset.page ?? "index.html";
|
|
609
|
+
document.querySelectorAll("select[data-db-switch]").forEach((sel) => {
|
|
610
|
+
sel.addEventListener("change", async () => {
|
|
611
|
+
const opt = sel.selectedOptions[0];
|
|
612
|
+
const prefix = opt?.dataset.prefix ?? "";
|
|
613
|
+
const target = sel.value;
|
|
614
|
+
if (!isRelativeTarget(target) || !isRelativeTarget(prefix)) return;
|
|
615
|
+
try {
|
|
616
|
+
const at = prefix ? `${siteRoot}${prefix}/` : siteRoot;
|
|
617
|
+
await loadScript(`${at}_dogsbay/pages.js`);
|
|
618
|
+
const pages = window.__DOGSBAY_PAGES__?.[prefix];
|
|
619
|
+
location.href = pages && !pages.includes(page) ? `${at}index.html` : target;
|
|
620
|
+
} catch {
|
|
621
|
+
location.href = target;
|
|
622
|
+
}
|
|
623
|
+
}, { signal });
|
|
624
|
+
});
|
|
625
|
+
}
|
|
626
|
+
function initAnchors(signal) {
|
|
627
|
+
document.addEventListener("click", (e) => {
|
|
628
|
+
const a = e.target.closest("a.db-anchor");
|
|
629
|
+
if (!a || location.protocol === "file:") return;
|
|
630
|
+
navigator.clipboard?.writeText(a.href).catch(() => {
|
|
631
|
+
});
|
|
632
|
+
}, { signal });
|
|
633
|
+
}
|
|
634
|
+
var providers = /* @__PURE__ */ new Set();
|
|
635
|
+
function closeDetached() {
|
|
636
|
+
for (const p of providers) if (!p.isConnected) closeMobile(p);
|
|
637
|
+
}
|
|
638
|
+
function wireSidebars() {
|
|
639
|
+
document.querySelectorAll("[data-component='sidebar-provider']").forEach((p) => {
|
|
640
|
+
initSidebar(p);
|
|
641
|
+
providers.add(p);
|
|
642
|
+
});
|
|
643
|
+
document.removeEventListener("keydown", closeDetached);
|
|
644
|
+
document.addEventListener("keydown", closeDetached);
|
|
645
|
+
}
|
|
646
|
+
var current;
|
|
647
|
+
function mount(o = {}) {
|
|
648
|
+
current?.unmount();
|
|
649
|
+
const ac = new AbortController();
|
|
650
|
+
const { signal } = ac;
|
|
651
|
+
const body = document.body;
|
|
652
|
+
const unitRoot = body.dataset.unitRoot ?? "";
|
|
653
|
+
const siteRoot = body.dataset.siteRoot ?? "";
|
|
654
|
+
if (o.nav !== void 0) window.__DOGSBAY_NAV__ = o.nav;
|
|
655
|
+
wireSidebars();
|
|
656
|
+
if (o.theme !== false) initTheme(signal);
|
|
657
|
+
initPageActions(signal);
|
|
658
|
+
if (o.switchers !== false) initSwitchers(siteRoot, signal);
|
|
659
|
+
initAnchors(signal);
|
|
660
|
+
if (o.search !== false) initSearch({ unitRoot, loadScript, signal });
|
|
661
|
+
initHighlights(signal);
|
|
662
|
+
initImageZoom(signal);
|
|
663
|
+
const page = {
|
|
664
|
+
unmount() {
|
|
665
|
+
if (signal.aborted) return;
|
|
666
|
+
ac.abort();
|
|
667
|
+
for (const p of providers) closeMobile(p);
|
|
668
|
+
if (current === page) current = void 0;
|
|
669
|
+
}
|
|
670
|
+
};
|
|
671
|
+
return current = page;
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
// src/client/data-script.ts
|
|
675
|
+
function readDataScript(text2) {
|
|
676
|
+
const m = /^\s*window\.__DOGSBAY_[A-Z_]+__\s*=\s*([\s\S]*?);?\s*$/.exec(text2);
|
|
677
|
+
if (!m) throw new Error("readDataScript: not a _dogsbay data script (window.__DOGSBAY_\u2026__=\u2026;)");
|
|
678
|
+
return JSON.parse(m[1]);
|
|
679
|
+
}
|
|
680
|
+
export {
|
|
681
|
+
mount,
|
|
682
|
+
readDataScript
|
|
683
|
+
};
|