@kamod-ch/preactpress 1.0.2 → 2.0.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/client/app.d.ts.map +1 -1
- package/dist/client/app.js +54 -7
- package/dist/client/app.js.map +1 -1
- package/dist/client/loadPage.d.ts +1 -0
- package/dist/client/loadPage.d.ts.map +1 -1
- package/dist/client/loadPage.js +3 -0
- package/dist/client/loadPage.js.map +1 -1
- package/dist/client/mermaid.d.ts +2 -0
- package/dist/client/mermaid.d.ts.map +1 -0
- package/dist/client/mermaid.js +68 -0
- package/dist/client/mermaid.js.map +1 -0
- package/dist/client/theme-default/Layout.d.ts.map +1 -1
- package/dist/client/theme-default/Layout.js +43 -0
- package/dist/client/theme-default/Layout.js.map +1 -1
- package/dist/node/markdown.d.ts.map +1 -1
- package/dist/node/markdown.js +24 -6
- package/dist/node/markdown.js.map +1 -1
- package/dist/shared/scrollRestoration.d.ts +11 -0
- package/dist/shared/scrollRestoration.d.ts.map +1 -0
- package/dist/shared/scrollRestoration.js +88 -0
- package/dist/shared/scrollRestoration.js.map +1 -0
- package/dist/shared/search.d.ts.map +1 -1
- package/dist/shared/search.js +4 -1
- package/dist/shared/search.js.map +1 -1
- package/package.json +2 -1
- package/src/client/app.tsx +59 -7
- package/src/client/loadPage.ts +4 -0
- package/src/client/mermaid.ts +74 -0
- package/src/client/theme-default/Layout.tsx +43 -0
- package/src/client/theme-default/styles.css +181 -5
- package/src/shared/scrollRestoration.ts +101 -0
- package/src/shared/search.ts +5 -1
- package/templates/docs/.preactpress/config.ts +5 -0
- package/templates/docs/examples/cloudflare-pages.md +117 -0
- package/templates/docs/examples/custom-theme.md +266 -0
- package/templates/docs/examples/mermaid.md +53 -0
- package/templates/docs/examples/preact-signals.md +102 -0
- package/templates/docs/examples/rss.md +104 -0
- package/templates/docs/guide/custom-themes.md +1 -1
- package/templates/docs/guide/deploy.md +2 -0
- package/templates/docs/guide/markdown-and-mdx.md +1 -1
- package/templates/docs/markdown-examples.md +10 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scrollRestoration.d.ts","sourceRoot":"","sources":["../../src/shared/scrollRestoration.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,gBAAgB,cAAc,CAAC;AAI5C,wBAAgB,sBAAsB,IAAI,MAAM,IAAI,CAgBnD;AAED,wBAAgB,qBAAqB,IAAI,IAAI,CAM5C;AAED,wBAAgB,kCAAkC,IAAI,IAAI,CAEzD;AAED,wBAAgB,6BAA6B,IAAI,MAAM,CAItD;AAED,wBAAgB,qBAAqB,IAAI,IAAI,CAG5C;AAED,wBAAsB,gCAAgC,IAAI,OAAO,CAAC,IAAI,CAAC,CAEtE;AAED,wBAAsB,sBAAsB,IAAI,OAAO,CAAC,IAAI,CAAC,CAE5D;AAuCD,wBAAgB,qBAAqB,IAAI,IAAI,CAE5C;AAED,wBAAgB,8BAA8B,IAAI,OAAO,CAMxD"}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
export const SCROLL_STATE_KEY = "ppScrollY";
|
|
2
|
+
let skipScrollRestoreOnce = false;
|
|
3
|
+
export function setupScrollRestoration() {
|
|
4
|
+
if (typeof window === "undefined")
|
|
5
|
+
return () => { };
|
|
6
|
+
if ("scrollRestoration" in window.history) {
|
|
7
|
+
window.history.scrollRestoration = "manual";
|
|
8
|
+
}
|
|
9
|
+
const onScroll = () => {
|
|
10
|
+
persistScrollPosition();
|
|
11
|
+
};
|
|
12
|
+
window.addEventListener("scroll", onScroll, { passive: true });
|
|
13
|
+
window.addEventListener("pagehide", persistScrollPosition);
|
|
14
|
+
return () => {
|
|
15
|
+
window.removeEventListener("scroll", onScroll);
|
|
16
|
+
window.removeEventListener("pagehide", persistScrollPosition);
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
export function persistScrollPosition() {
|
|
20
|
+
if (typeof window === "undefined")
|
|
21
|
+
return;
|
|
22
|
+
const scrollY = window.scrollY;
|
|
23
|
+
const state = window.history.state ?? {};
|
|
24
|
+
if (state[SCROLL_STATE_KEY] === scrollY)
|
|
25
|
+
return;
|
|
26
|
+
window.history.replaceState({ ...state, [SCROLL_STATE_KEY]: scrollY }, "");
|
|
27
|
+
}
|
|
28
|
+
export function saveScrollPositionBeforeNavigation() {
|
|
29
|
+
persistScrollPosition();
|
|
30
|
+
}
|
|
31
|
+
export function readScrollPositionFromHistory() {
|
|
32
|
+
if (typeof window === "undefined")
|
|
33
|
+
return 0;
|
|
34
|
+
const scrollY = window.history.state?.[SCROLL_STATE_KEY];
|
|
35
|
+
return typeof scrollY === "number" && Number.isFinite(scrollY) ? scrollY : 0;
|
|
36
|
+
}
|
|
37
|
+
export function restoreScrollPosition() {
|
|
38
|
+
if (typeof window === "undefined")
|
|
39
|
+
return;
|
|
40
|
+
window.scrollTo({ top: readScrollPositionFromHistory(), left: 0, behavior: "auto" });
|
|
41
|
+
}
|
|
42
|
+
export async function restoreScrollPositionAfterLayout() {
|
|
43
|
+
await scrollAfterLayout(readScrollPositionFromHistory());
|
|
44
|
+
}
|
|
45
|
+
export async function scrollToTopAfterLayout() {
|
|
46
|
+
await scrollAfterLayout(0);
|
|
47
|
+
}
|
|
48
|
+
async function scrollAfterLayout(top) {
|
|
49
|
+
if (typeof window === "undefined")
|
|
50
|
+
return;
|
|
51
|
+
await nextAnimationFrame();
|
|
52
|
+
await nextAnimationFrame();
|
|
53
|
+
await waitForImagesToSettle();
|
|
54
|
+
await nextAnimationFrame();
|
|
55
|
+
const html = document.documentElement;
|
|
56
|
+
const previous = html.style.scrollBehavior;
|
|
57
|
+
html.style.scrollBehavior = "auto";
|
|
58
|
+
window.scrollTo({ top, left: 0, behavior: "auto" });
|
|
59
|
+
html.style.scrollBehavior = previous;
|
|
60
|
+
}
|
|
61
|
+
function nextAnimationFrame() {
|
|
62
|
+
return new Promise((resolve) => requestAnimationFrame(() => resolve()));
|
|
63
|
+
}
|
|
64
|
+
async function waitForImagesToSettle(timeoutMs = 1500) {
|
|
65
|
+
if (typeof document === "undefined")
|
|
66
|
+
return;
|
|
67
|
+
const images = Array.from(document.images).filter((image) => !image.complete);
|
|
68
|
+
if (images.length === 0)
|
|
69
|
+
return;
|
|
70
|
+
await Promise.race([
|
|
71
|
+
Promise.allSettled(images.map((image) => new Promise((resolve) => {
|
|
72
|
+
image.addEventListener("load", () => resolve(), { once: true });
|
|
73
|
+
image.addEventListener("error", () => resolve(), { once: true });
|
|
74
|
+
}))),
|
|
75
|
+
new Promise((resolve) => setTimeout(resolve, timeoutMs)),
|
|
76
|
+
]);
|
|
77
|
+
}
|
|
78
|
+
export function skipNextScrollRestore() {
|
|
79
|
+
skipScrollRestoreOnce = true;
|
|
80
|
+
}
|
|
81
|
+
export function consumeScrollRestoreOnPopstate() {
|
|
82
|
+
if (skipScrollRestoreOnce) {
|
|
83
|
+
skipScrollRestoreOnce = false;
|
|
84
|
+
return false;
|
|
85
|
+
}
|
|
86
|
+
return true;
|
|
87
|
+
}
|
|
88
|
+
//# sourceMappingURL=scrollRestoration.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scrollRestoration.js","sourceRoot":"","sources":["../../src/shared/scrollRestoration.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"search.d.ts","sourceRoot":"","sources":["../../src/shared/search.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"search.d.ts","sourceRoot":"","sources":["../../src/shared/search.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,cAAc,GAAG,OAAO,GAAG,SAAS,CAAC;AAEjD,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,oBAAoB;IACnC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,0BAA0B,CAAC,EAAE,OAAO,CAAC;IACrC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,gCAAgC,CAAC,EAAE,MAAM,CAAC;IAC1C,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,gBAAgB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC3C,4DAA4D;IAC5D,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,oBAAoB,CAAC,CAAC,CAAC;CACzD;AAED,MAAM,WAAW,mBAAmB;IAClC,QAAQ,EAAE,SAAS,CAAC;IACpB,OAAO,EAAE,oBAAoB,CAAC;CAC/B;AAED,oFAAoF;AACpF,MAAM,MAAM,YAAY,GAAG,OAAO,GAAG,iBAAiB,GAAG,mBAAmB,CAAC;AAE7E,wBAAgB,qBAAqB,CAAC,MAAM,CAAC,EAAE,YAAY,GAAG,cAAc,GAAG,KAAK,CAInF;AAED,wBAAgB,oBAAoB,CAAC,MAAM,CAAC,EAAE,YAAY,GAAG,OAAO,CAEnE;AAED,wBAAgB,sBAAsB,CAAC,MAAM,CAAC,EAAE,YAAY,GAAG,OAAO,CAErE;AAED,wBAAgB,wBAAwB,CAAC,MAAM,CAAC,EAAE,YAAY,GAAG,oBAAoB,GAAG,SAAS,CAGhG;AAED,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,oBAAoB,EAC7B,SAAS,CAAC,EAAE,MAAM,GACjB,oBAAoB,CAQtB;AAED,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,oBAAoB,GAAG;IACzE,KAAK,EAAE,OAAO,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAUA;AAED,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,UAAO,GAAG,MAAM,CAS3F;AAED,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAgB3E"}
|
package/dist/shared/search.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { saveScrollPositionBeforeNavigation, skipNextScrollRestore } from "./scrollRestoration.js";
|
|
1
2
|
export function resolveSearchProvider(search) {
|
|
2
3
|
if (search === true)
|
|
3
4
|
return "local";
|
|
@@ -56,8 +57,10 @@ export function navigateDocSearchResult(itemUrl, base) {
|
|
|
56
57
|
window.location.assign(href);
|
|
57
58
|
return;
|
|
58
59
|
}
|
|
60
|
+
saveScrollPositionBeforeNavigation();
|
|
59
61
|
window.history.pushState({}, "", href);
|
|
62
|
+
skipNextScrollRestore();
|
|
60
63
|
window.dispatchEvent(new PopStateEvent("popstate"));
|
|
61
|
-
window.scrollTo({ top: 0 });
|
|
64
|
+
window.scrollTo({ top: 0, behavior: "auto" });
|
|
62
65
|
}
|
|
63
66
|
//# sourceMappingURL=search.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"search.js","sourceRoot":"","sources":["../../src/shared/search.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"search.js","sourceRoot":"","sources":["../../src/shared/search.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kamod-ch/preactpress",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"description": "Vite and Preact powered static site generator",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"markdown",
|
|
@@ -103,6 +103,7 @@
|
|
|
103
103
|
"markdown-it": "^14.2.0",
|
|
104
104
|
"markdown-it-emoji": "^3.0.0",
|
|
105
105
|
"markdown-it-mathjax3": "^5.2.0",
|
|
106
|
+
"mermaid": "^11.16.0",
|
|
106
107
|
"minimist": "^1.2.8",
|
|
107
108
|
"node-html-parser": "^7.1.0",
|
|
108
109
|
"picocolors": "^1.1.1",
|
package/src/client/app.tsx
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { useEffect, useState } from "preact/hooks";
|
|
1
|
+
import { useEffect, useRef, useState } from "preact/hooks";
|
|
2
2
|
import Layout from "virtual:preactpress-layout";
|
|
3
3
|
import { pagesMeta, routes } from "virtual:preactpress-pages";
|
|
4
4
|
import { i18n, mpa, site, themeConfig } from "virtual:preactpress-site";
|
|
@@ -6,7 +6,15 @@ import type { PageView } from "./types.js";
|
|
|
6
6
|
import type { ResolvedLocale } from "../node/siteConfig.js";
|
|
7
7
|
import { usePageHead } from "./usePageHead.js";
|
|
8
8
|
import { normalizeRoute, routeFromPathname } from "../shared/route.js";
|
|
9
|
-
import {
|
|
9
|
+
import {
|
|
10
|
+
consumeScrollRestoreOnPopstate,
|
|
11
|
+
restoreScrollPositionAfterLayout,
|
|
12
|
+
saveScrollPositionBeforeNavigation,
|
|
13
|
+
scrollToTopAfterLayout,
|
|
14
|
+
setupScrollRestoration,
|
|
15
|
+
} from "../shared/scrollRestoration.js";
|
|
16
|
+
import { getCachedPage, loadPage, prefetchPage, seedPage } from "./loadPage.js";
|
|
17
|
+
import { renderMermaidDiagrams } from "./mermaid.js";
|
|
10
18
|
import { setupViewportPrefetch } from "./prefetchLinks.js";
|
|
11
19
|
import {
|
|
12
20
|
localeFromRoute,
|
|
@@ -55,6 +63,10 @@ function loadingPage(route: string): PageView {
|
|
|
55
63
|
export function App({ routePath, initialPage }: { routePath: string; initialPage?: PageView }) {
|
|
56
64
|
const [currentRoute, setCurrentRoute] = useState(() => normalizeRoute(routePath));
|
|
57
65
|
const [page, setPage] = useState<PageView>(() => initialPage ?? loadingPage(routePath));
|
|
66
|
+
const pendingScrollRestore = useRef(false);
|
|
67
|
+
const pendingScrollTop = useRef(false);
|
|
68
|
+
const [scrollRestoreNonce, setScrollRestoreNonce] = useState(0);
|
|
69
|
+
const [scrollTopNonce, setScrollTopNonce] = useState(0);
|
|
58
70
|
const availableRoutes = new Set(routes);
|
|
59
71
|
const activeLocale = localeFromRoute(currentRoute, i18n);
|
|
60
72
|
const activeSite = siteForRoute(site, currentRoute, i18n);
|
|
@@ -66,10 +78,20 @@ export function App({ routePath, initialPage }: { routePath: string; initialPage
|
|
|
66
78
|
|
|
67
79
|
useEffect(() => {
|
|
68
80
|
let cancelled = false;
|
|
69
|
-
|
|
81
|
+
const cached = getCachedPage(currentRoute);
|
|
82
|
+
if (!cached) setPage(loadingPage(currentRoute));
|
|
70
83
|
void loadPage(currentRoute, site.base)
|
|
71
84
|
.then((loaded) => {
|
|
72
|
-
if (!cancelled)
|
|
85
|
+
if (!cancelled) {
|
|
86
|
+
setPage(loaded);
|
|
87
|
+
if (pendingScrollRestore.current) {
|
|
88
|
+
pendingScrollRestore.current = false;
|
|
89
|
+
setScrollRestoreNonce((nonce) => nonce + 1);
|
|
90
|
+
} else if (pendingScrollTop.current) {
|
|
91
|
+
pendingScrollTop.current = false;
|
|
92
|
+
setScrollTopNonce((nonce) => nonce + 1);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
73
95
|
})
|
|
74
96
|
.catch(() => {
|
|
75
97
|
if (!cancelled) {
|
|
@@ -81,6 +103,13 @@ export function App({ routePath, initialPage }: { routePath: string; initialPage
|
|
|
81
103
|
meta: {},
|
|
82
104
|
headings: [],
|
|
83
105
|
});
|
|
106
|
+
if (pendingScrollRestore.current) {
|
|
107
|
+
pendingScrollRestore.current = false;
|
|
108
|
+
setScrollRestoreNonce((nonce) => nonce + 1);
|
|
109
|
+
} else if (pendingScrollTop.current) {
|
|
110
|
+
pendingScrollTop.current = false;
|
|
111
|
+
setScrollTopNonce((nonce) => nonce + 1);
|
|
112
|
+
}
|
|
84
113
|
}
|
|
85
114
|
});
|
|
86
115
|
return () => {
|
|
@@ -88,6 +117,16 @@ export function App({ routePath, initialPage }: { routePath: string; initialPage
|
|
|
88
117
|
};
|
|
89
118
|
}, [activeSite.description, currentRoute]);
|
|
90
119
|
|
|
120
|
+
useEffect(() => {
|
|
121
|
+
if (scrollRestoreNonce === 0) return;
|
|
122
|
+
void restoreScrollPositionAfterLayout();
|
|
123
|
+
}, [scrollRestoreNonce]);
|
|
124
|
+
|
|
125
|
+
useEffect(() => {
|
|
126
|
+
if (scrollTopNonce === 0) return;
|
|
127
|
+
void scrollToTopAfterLayout();
|
|
128
|
+
}, [scrollTopNonce]);
|
|
129
|
+
|
|
91
130
|
useEffect(() => {
|
|
92
131
|
const prefetch = (route: string) => prefetchPage(route, site.base);
|
|
93
132
|
const stopViewportPrefetch = setupViewportPrefetch(routeFromHref, prefetch);
|
|
@@ -95,7 +134,13 @@ export function App({ routePath, initialPage }: { routePath: string; initialPage
|
|
|
95
134
|
return () => stopViewportPrefetch();
|
|
96
135
|
}
|
|
97
136
|
|
|
98
|
-
const
|
|
137
|
+
const stopScrollRestoration = setupScrollRestoration();
|
|
138
|
+
const onPopState = () => {
|
|
139
|
+
if (consumeScrollRestoreOnPopstate()) {
|
|
140
|
+
pendingScrollRestore.current = true;
|
|
141
|
+
}
|
|
142
|
+
setCurrentRoute(routeFromLocation());
|
|
143
|
+
};
|
|
99
144
|
const onClick = (event: MouseEvent) => {
|
|
100
145
|
if (
|
|
101
146
|
event.defaultPrevented ||
|
|
@@ -117,9 +162,11 @@ export function App({ routePath, initialPage }: { routePath: string; initialPage
|
|
|
117
162
|
return;
|
|
118
163
|
}
|
|
119
164
|
event.preventDefault();
|
|
165
|
+
saveScrollPositionBeforeNavigation();
|
|
166
|
+
pendingScrollTop.current = true;
|
|
120
167
|
window.history.pushState({}, "", url);
|
|
121
168
|
setCurrentRoute(route);
|
|
122
|
-
window.scrollTo({ top: 0 });
|
|
169
|
+
window.scrollTo({ top: 0, left: 0, behavior: "auto" });
|
|
123
170
|
};
|
|
124
171
|
const onMouseEnter = (event: MouseEvent) => {
|
|
125
172
|
const link = anchorFromEvent(event);
|
|
@@ -131,6 +178,7 @@ export function App({ routePath, initialPage }: { routePath: string; initialPage
|
|
|
131
178
|
document.addEventListener("click", onClick);
|
|
132
179
|
document.addEventListener("mouseenter", onMouseEnter, true);
|
|
133
180
|
return () => {
|
|
181
|
+
stopScrollRestoration();
|
|
134
182
|
stopViewportPrefetch();
|
|
135
183
|
window.removeEventListener("popstate", onPopState);
|
|
136
184
|
document.removeEventListener("click", onClick);
|
|
@@ -138,9 +186,13 @@ export function App({ routePath, initialPage }: { routePath: string; initialPage
|
|
|
138
186
|
};
|
|
139
187
|
}, [currentRoute, mpa]);
|
|
140
188
|
|
|
189
|
+
useEffect(() => {
|
|
190
|
+
void renderMermaidDiagrams();
|
|
191
|
+
}, [currentRoute, page]);
|
|
192
|
+
|
|
141
193
|
useEffect(() => {
|
|
142
194
|
if (currentRoute !== normalizeRoute(routePath)) {
|
|
143
|
-
document.getElementById("content")?.focus();
|
|
195
|
+
document.getElementById("content")?.focus({ preventScroll: true });
|
|
144
196
|
}
|
|
145
197
|
}, [currentRoute, routePath]);
|
|
146
198
|
|
package/src/client/loadPage.ts
CHANGED
|
@@ -23,6 +23,10 @@ export function seedPage(route: string, page: PageView | undefined): void {
|
|
|
23
23
|
if (page) cache.set(route, page);
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
+
export function getCachedPage(route: string): PageView | undefined {
|
|
27
|
+
return cache.get(route);
|
|
28
|
+
}
|
|
29
|
+
|
|
26
30
|
async function loadMarkdownPage(route: string, base: string): Promise<PageView> {
|
|
27
31
|
const meta = pagesMeta[route];
|
|
28
32
|
const url = import.meta.env.DEV
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
let renderRun = 0;
|
|
2
|
+
|
|
3
|
+
function isDarkTheme(): boolean {
|
|
4
|
+
if (typeof document === "undefined" || typeof window === "undefined") return false;
|
|
5
|
+
const explicit = document.documentElement.dataset.theme;
|
|
6
|
+
if (explicit === "dark") return true;
|
|
7
|
+
if (explicit === "light") return false;
|
|
8
|
+
return window.matchMedia?.("(prefers-color-scheme: dark)").matches ?? false;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function mermaidSourceFromElement(element: HTMLElement): string {
|
|
12
|
+
if (element.dataset.mermaidSource) return element.dataset.mermaidSource;
|
|
13
|
+
return element.textContent ?? "";
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function normalizeMermaidBlocks(): HTMLElement[] {
|
|
17
|
+
const blocks = Array.from(document.querySelectorAll<HTMLElement>(".pp-mermaid"));
|
|
18
|
+
|
|
19
|
+
for (const code of document.querySelectorAll<HTMLElement>(
|
|
20
|
+
'pre > code.language-mermaid, pre > code[class*="language-mermaid"]',
|
|
21
|
+
)) {
|
|
22
|
+
const pre = code.parentElement;
|
|
23
|
+
if (!pre || pre.dataset.mermaidNormalized === "true") continue;
|
|
24
|
+
|
|
25
|
+
const block = document.createElement("div");
|
|
26
|
+
block.className = "pp-mermaid";
|
|
27
|
+
block.dataset.mermaidSource = code.textContent ?? "";
|
|
28
|
+
block.textContent = code.textContent ?? "";
|
|
29
|
+
pre.replaceWith(block);
|
|
30
|
+
pre.dataset.mermaidNormalized = "true";
|
|
31
|
+
blocks.push(block);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
return blocks;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export async function renderMermaidDiagrams(): Promise<void> {
|
|
38
|
+
if (typeof document === "undefined") return;
|
|
39
|
+
|
|
40
|
+
const blocks = normalizeMermaidBlocks().filter(
|
|
41
|
+
(block) => block.dataset.mermaidRendered !== "true",
|
|
42
|
+
);
|
|
43
|
+
if (blocks.length === 0) return;
|
|
44
|
+
|
|
45
|
+
const run = ++renderRun;
|
|
46
|
+
const { default: mermaid } = await import("mermaid");
|
|
47
|
+
if (run !== renderRun) return;
|
|
48
|
+
|
|
49
|
+
mermaid.initialize({
|
|
50
|
+
startOnLoad: false,
|
|
51
|
+
securityLevel: "strict",
|
|
52
|
+
theme: isDarkTheme() ? "dark" : "default",
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
await Promise.all(
|
|
56
|
+
blocks.map(async (block, index) => {
|
|
57
|
+
const source = mermaidSourceFromElement(block).trim();
|
|
58
|
+
if (!source) return;
|
|
59
|
+
|
|
60
|
+
try {
|
|
61
|
+
const id = `pp-mermaid-${run}-${index}`;
|
|
62
|
+
const { svg } = await mermaid.render(id, source);
|
|
63
|
+
if (run !== renderRun) return;
|
|
64
|
+
block.innerHTML = svg;
|
|
65
|
+
block.dataset.mermaidRendered = "true";
|
|
66
|
+
block.dataset.mermaidSource = source;
|
|
67
|
+
} catch (error) {
|
|
68
|
+
block.dataset.mermaidError = "true";
|
|
69
|
+
block.textContent = source;
|
|
70
|
+
console.warn("Failed to render Mermaid diagram", error);
|
|
71
|
+
}
|
|
72
|
+
}),
|
|
73
|
+
);
|
|
74
|
+
}
|
|
@@ -150,6 +150,49 @@ const Layout: FunctionalComponent<LayoutProps> = ({
|
|
|
150
150
|
setMobileMenuOpen(false);
|
|
151
151
|
}, [routePath]);
|
|
152
152
|
|
|
153
|
+
useEffect(() => {
|
|
154
|
+
const copyText = async (text: string) => {
|
|
155
|
+
if (navigator.clipboard?.writeText) {
|
|
156
|
+
await navigator.clipboard.writeText(text);
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
const textarea = document.createElement("textarea");
|
|
160
|
+
textarea.value = text;
|
|
161
|
+
textarea.setAttribute("readonly", "");
|
|
162
|
+
textarea.style.position = "fixed";
|
|
163
|
+
textarea.style.top = "-9999px";
|
|
164
|
+
document.body.append(textarea);
|
|
165
|
+
textarea.select();
|
|
166
|
+
document.execCommand("copy");
|
|
167
|
+
textarea.remove();
|
|
168
|
+
};
|
|
169
|
+
|
|
170
|
+
const onClick = (event: MouseEvent) => {
|
|
171
|
+
const target = event.target;
|
|
172
|
+
const candidate = target instanceof Element ? target.closest(".pp-code-copy") : null;
|
|
173
|
+
if (!(candidate instanceof HTMLButtonElement)) return;
|
|
174
|
+
const button = candidate;
|
|
175
|
+
const code = button.closest(".pp-code-block")?.querySelector("code")?.textContent ?? "";
|
|
176
|
+
if (!code) return;
|
|
177
|
+
|
|
178
|
+
event.preventDefault();
|
|
179
|
+
void copyText(code).then(() => {
|
|
180
|
+
const icon = button.querySelector(".pp-code-copy-icon");
|
|
181
|
+
if (icon && button.dataset.checkIcon) icon.innerHTML = button.dataset.checkIcon;
|
|
182
|
+
button.classList.add("copied");
|
|
183
|
+
button.setAttribute("aria-label", button.dataset.copiedLabel ?? "Copied");
|
|
184
|
+
window.setTimeout(() => {
|
|
185
|
+
if (icon && button.dataset.copyIcon) icon.innerHTML = button.dataset.copyIcon;
|
|
186
|
+
button.classList.remove("copied");
|
|
187
|
+
button.setAttribute("aria-label", "Copy code");
|
|
188
|
+
}, 2000);
|
|
189
|
+
});
|
|
190
|
+
};
|
|
191
|
+
|
|
192
|
+
document.addEventListener("click", onClick);
|
|
193
|
+
return () => document.removeEventListener("click", onClick);
|
|
194
|
+
}, []);
|
|
195
|
+
|
|
153
196
|
useEffect(() => {
|
|
154
197
|
if (!mobileMenuOpen) return;
|
|
155
198
|
|
|
@@ -759,14 +759,188 @@ body::selection {
|
|
|
759
759
|
margin: 16px 0;
|
|
760
760
|
}
|
|
761
761
|
|
|
762
|
+
.pp-doc-content .pp-mermaid {
|
|
763
|
+
margin: 1.25rem 0;
|
|
764
|
+
padding: 1.25rem;
|
|
765
|
+
overflow: auto;
|
|
766
|
+
border: 1px solid color-mix(in srgb, var(--pp-border) 82%, transparent);
|
|
767
|
+
border-radius: 14px;
|
|
768
|
+
background: var(--pp-code-bg);
|
|
769
|
+
color: var(--pp-code-text);
|
|
770
|
+
text-align: center;
|
|
771
|
+
}
|
|
772
|
+
|
|
773
|
+
.pp-doc-content .pp-mermaid[data-mermaid-error="true"] {
|
|
774
|
+
text-align: left;
|
|
775
|
+
white-space: pre;
|
|
776
|
+
}
|
|
777
|
+
|
|
778
|
+
.pp-doc-content .pp-mermaid svg {
|
|
779
|
+
max-width: 100%;
|
|
780
|
+
height: auto;
|
|
781
|
+
}
|
|
782
|
+
|
|
783
|
+
.pp-doc-content .pp-code-block {
|
|
784
|
+
position: relative;
|
|
785
|
+
margin: 1.25rem 0;
|
|
786
|
+
border: 1px solid color-mix(in srgb, var(--pp-border) 82%, transparent);
|
|
787
|
+
border-radius: 14px;
|
|
788
|
+
background: var(--pp-code-bg);
|
|
789
|
+
box-shadow:
|
|
790
|
+
0 14px 34px color-mix(in srgb, #000 8%, transparent),
|
|
791
|
+
inset 0 1px 0 color-mix(in srgb, #fff 45%, transparent);
|
|
792
|
+
overflow: hidden;
|
|
793
|
+
}
|
|
794
|
+
|
|
762
795
|
.pp-doc-content pre {
|
|
763
|
-
padding: 16px;
|
|
764
|
-
border-radius:
|
|
796
|
+
padding: 16px 18px;
|
|
797
|
+
border-radius: 0;
|
|
765
798
|
overflow: auto;
|
|
766
|
-
border:
|
|
799
|
+
border: 0;
|
|
767
800
|
background: var(--pp-code-bg);
|
|
768
801
|
color: var(--pp-code-text);
|
|
769
|
-
line-height: 1.
|
|
802
|
+
line-height: 1.38;
|
|
803
|
+
}
|
|
804
|
+
|
|
805
|
+
.pp-doc-content .pp-code-block pre {
|
|
806
|
+
margin: 0;
|
|
807
|
+
max-height: min(68vh, 720px);
|
|
808
|
+
padding-top: 2.7rem;
|
|
809
|
+
padding-right: 3.75rem;
|
|
810
|
+
line-height: 0;
|
|
811
|
+
scrollbar-width: thin;
|
|
812
|
+
scrollbar-color: color-mix(in srgb, var(--pp-muted) 40%, transparent) transparent;
|
|
813
|
+
}
|
|
814
|
+
|
|
815
|
+
.pp-doc-content .pp-code-block .shiki.shiki-themes.vitesse-light.vitesse-dark {
|
|
816
|
+
padding-bottom: 1rem;
|
|
817
|
+
}
|
|
818
|
+
|
|
819
|
+
.pp-doc-content .pp-code-block pre code {
|
|
820
|
+
display: block;
|
|
821
|
+
min-width: max-content;
|
|
822
|
+
font-size: 0.9rem;
|
|
823
|
+
line-height: 1.32;
|
|
824
|
+
tab-size: 2;
|
|
825
|
+
}
|
|
826
|
+
|
|
827
|
+
.pp-doc-content .pp-code-block .line {
|
|
828
|
+
display: block;
|
|
829
|
+
line-height: 0;
|
|
830
|
+
counter-increment: pp-code-line;
|
|
831
|
+
}
|
|
832
|
+
|
|
833
|
+
.pp-doc-content .pp-code-block code {
|
|
834
|
+
counter-reset: pp-code-line;
|
|
835
|
+
}
|
|
836
|
+
|
|
837
|
+
.pp-doc-content .pp-code-block .line::before {
|
|
838
|
+
content: counter(pp-code-line);
|
|
839
|
+
display: inline-block;
|
|
840
|
+
width: 2rem;
|
|
841
|
+
margin-right: 1rem;
|
|
842
|
+
color: color-mix(in srgb, var(--pp-muted) 42%, transparent);
|
|
843
|
+
font-variant-numeric: tabular-nums;
|
|
844
|
+
text-align: right;
|
|
845
|
+
user-select: none;
|
|
846
|
+
}
|
|
847
|
+
|
|
848
|
+
.pp-doc-content .pp-code-block[data-language="plaintext"] pre {
|
|
849
|
+
padding-top: 18px;
|
|
850
|
+
}
|
|
851
|
+
|
|
852
|
+
.pp-doc-content .pp-code-lang {
|
|
853
|
+
position: absolute;
|
|
854
|
+
top: 12px;
|
|
855
|
+
left: 14px;
|
|
856
|
+
z-index: 2;
|
|
857
|
+
max-width: calc(100% - 4.75rem);
|
|
858
|
+
overflow: hidden;
|
|
859
|
+
border: 1px solid color-mix(in srgb, var(--pp-border) 72%, transparent);
|
|
860
|
+
border-radius: 999px;
|
|
861
|
+
padding: 0.18rem 0.55rem;
|
|
862
|
+
background: color-mix(in srgb, var(--pp-bg) 72%, transparent);
|
|
863
|
+
color: var(--pp-muted);
|
|
864
|
+
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
|
|
865
|
+
font-size: 0.72rem;
|
|
866
|
+
line-height: 1.35;
|
|
867
|
+
text-overflow: ellipsis;
|
|
868
|
+
text-transform: uppercase;
|
|
869
|
+
letter-spacing: 0.04em;
|
|
870
|
+
backdrop-filter: blur(12px);
|
|
871
|
+
}
|
|
872
|
+
|
|
873
|
+
.pp-doc-content .shiki,
|
|
874
|
+
.pp-doc-content .shiki span {
|
|
875
|
+
color: var(--shiki-light, var(--pp-code-text)) !important;
|
|
876
|
+
background-color: var(--shiki-light-bg, var(--pp-code-bg)) !important;
|
|
877
|
+
}
|
|
878
|
+
|
|
879
|
+
@media (prefers-color-scheme: dark) {
|
|
880
|
+
:root:not([data-theme]) .pp-doc-content .shiki,
|
|
881
|
+
:root:not([data-theme]) .pp-doc-content .shiki span {
|
|
882
|
+
color: var(--shiki-dark, var(--pp-code-text)) !important;
|
|
883
|
+
background-color: var(--shiki-dark-bg, var(--pp-code-bg)) !important;
|
|
884
|
+
}
|
|
885
|
+
}
|
|
886
|
+
|
|
887
|
+
:root[data-theme="dark"] .pp-doc-content .shiki,
|
|
888
|
+
:root[data-theme="dark"] .pp-doc-content .shiki span {
|
|
889
|
+
color: var(--shiki-dark, var(--pp-code-text)) !important;
|
|
890
|
+
background-color: var(--shiki-dark-bg, var(--pp-code-bg)) !important;
|
|
891
|
+
}
|
|
892
|
+
|
|
893
|
+
.pp-doc-content .pp-code-copy {
|
|
894
|
+
position: absolute;
|
|
895
|
+
top: 10px;
|
|
896
|
+
right: 10px;
|
|
897
|
+
z-index: 2;
|
|
898
|
+
display: grid;
|
|
899
|
+
place-items: center;
|
|
900
|
+
width: 34px;
|
|
901
|
+
height: 34px;
|
|
902
|
+
padding: 0;
|
|
903
|
+
border: 1px solid color-mix(in srgb, var(--pp-border) 72%, transparent);
|
|
904
|
+
border-radius: 10px;
|
|
905
|
+
background: color-mix(in srgb, var(--pp-bg) 72%, transparent);
|
|
906
|
+
color: var(--pp-muted);
|
|
907
|
+
opacity: 0;
|
|
908
|
+
transform: translateY(-3px) scale(0.96);
|
|
909
|
+
cursor: pointer;
|
|
910
|
+
backdrop-filter: blur(12px);
|
|
911
|
+
transition:
|
|
912
|
+
opacity 0.18s ease,
|
|
913
|
+
transform 0.18s ease,
|
|
914
|
+
color 0.18s ease,
|
|
915
|
+
border-color 0.18s ease,
|
|
916
|
+
background 0.18s ease;
|
|
917
|
+
}
|
|
918
|
+
|
|
919
|
+
.pp-doc-content .pp-code-block:hover .pp-code-copy,
|
|
920
|
+
.pp-doc-content .pp-code-copy:focus-visible,
|
|
921
|
+
.pp-doc-content .pp-code-copy.copied {
|
|
922
|
+
opacity: 1;
|
|
923
|
+
transform: translateY(0) scale(1);
|
|
924
|
+
}
|
|
925
|
+
|
|
926
|
+
.pp-doc-content .pp-code-copy:hover,
|
|
927
|
+
.pp-doc-content .pp-code-copy.copied {
|
|
928
|
+
color: var(--pp-accent);
|
|
929
|
+
border-color: color-mix(in srgb, var(--pp-accent) 44%, var(--pp-border));
|
|
930
|
+
background: color-mix(in srgb, var(--pp-bg) 88%, var(--pp-accent) 12%);
|
|
931
|
+
}
|
|
932
|
+
|
|
933
|
+
.pp-doc-content .pp-code-copy svg {
|
|
934
|
+
width: 17px;
|
|
935
|
+
height: 17px;
|
|
936
|
+
fill: currentColor;
|
|
937
|
+
}
|
|
938
|
+
|
|
939
|
+
.pp-doc-content.pp-code-wrap .pp-code-block pre code,
|
|
940
|
+
.pp-doc-content .pp-code-block.pp-code-wrap pre code {
|
|
941
|
+
min-width: 0;
|
|
942
|
+
white-space: pre-wrap;
|
|
943
|
+
overflow-wrap: anywhere;
|
|
770
944
|
}
|
|
771
945
|
|
|
772
946
|
.pp-doc-content :not(pre) > code {
|
|
@@ -970,9 +1144,11 @@ body::selection {
|
|
|
970
1144
|
display: block;
|
|
971
1145
|
}
|
|
972
1146
|
|
|
973
|
-
.pp-doc-content .pp-code-group-block .
|
|
1147
|
+
.pp-doc-content .pp-code-group-block .pp-code-block {
|
|
974
1148
|
margin: 0;
|
|
1149
|
+
border: 0;
|
|
975
1150
|
border-radius: 0;
|
|
1151
|
+
box-shadow: none;
|
|
976
1152
|
}
|
|
977
1153
|
|
|
978
1154
|
.pp-doc-content table {
|