@dreamlake/dockit 0.1.1 → 0.2.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/components/CodeBlock.js +29 -15
- package/dist/components/Preview.js +110 -3
- package/dist/components/Sidebar.js +4 -3
- package/dist/components/TOC.js +7 -6
- package/dist/components/ThemeToggle.d.ts +3 -0
- package/dist/components/ThemeToggle.js +77 -4
- package/dist/components/Topbar.js +3 -299
- package/dist/components/VersionBadge.d.ts +31 -0
- package/dist/components/VersionBadge.js +315 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.js +5 -1
- package/dist/lib/navigation.d.ts +15 -0
- package/dist/lib/navigation.js +18 -4
- package/dist/renderer/Layout.js +4 -4
- package/dist/renderer/onRenderHtml.js +2 -2
- package/dist/site-config.d.ts +4 -0
- package/dist/site-config.js +2 -1
- package/package.json +1 -1
- package/templates/netlify.example.toml +11 -0
|
@@ -60,22 +60,36 @@ function CodeBlock({ children, filename, lang }) {
|
|
|
60
60
|
},
|
|
61
61
|
children: [
|
|
62
62
|
/* @__PURE__ */ jsx("span", { style: { fontWeight: 600, textTransform: "none", letterSpacing: 0 }, children: filename }),
|
|
63
|
-
lang && /* @__PURE__ */ jsx(
|
|
63
|
+
lang && /* @__PURE__ */ jsx(
|
|
64
|
+
"span",
|
|
65
|
+
{
|
|
66
|
+
className: "uppercase opacity-0 group-hover:opacity-100 focus-within:opacity-100 transition-opacity duration-150",
|
|
67
|
+
style: { fontWeight: 600, letterSpacing: "0.06em" },
|
|
68
|
+
children: lang
|
|
69
|
+
}
|
|
70
|
+
),
|
|
64
71
|
/* @__PURE__ */ jsx("span", { style: { flex: 1 } }),
|
|
65
|
-
/* @__PURE__ */ jsxs(
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
72
|
+
/* @__PURE__ */ jsxs(
|
|
73
|
+
"span",
|
|
74
|
+
{
|
|
75
|
+
className: "inline-flex items-center opacity-0 group-hover:opacity-100 focus-within:opacity-100 transition-opacity duration-150",
|
|
76
|
+
style: { gap: 6 },
|
|
77
|
+
children: [
|
|
78
|
+
/* @__PURE__ */ jsx(
|
|
79
|
+
"button",
|
|
80
|
+
{
|
|
81
|
+
type: "button",
|
|
82
|
+
"aria-pressed": showLines,
|
|
83
|
+
title: showLines ? ":set nonu" : ":set nu",
|
|
84
|
+
onClick: () => setShowLines(!showLines),
|
|
85
|
+
style: headerBtnStyle(showLines),
|
|
86
|
+
children: /* @__PURE__ */ jsx(HashIcon, {})
|
|
87
|
+
}
|
|
88
|
+
),
|
|
89
|
+
/* @__PURE__ */ jsx("button", { type: "button", onClick: copy, style: headerBtnStyle(copied), children: copied ? "Copied" : "Copy" })
|
|
90
|
+
]
|
|
91
|
+
}
|
|
92
|
+
)
|
|
79
93
|
]
|
|
80
94
|
}
|
|
81
95
|
),
|
|
@@ -112,6 +112,48 @@ function HashIcon() {
|
|
|
112
112
|
}
|
|
113
113
|
);
|
|
114
114
|
}
|
|
115
|
+
function MaximizeIcon() {
|
|
116
|
+
return /* @__PURE__ */ jsxs(
|
|
117
|
+
"svg",
|
|
118
|
+
{
|
|
119
|
+
viewBox: "0 0 24 24",
|
|
120
|
+
fill: "none",
|
|
121
|
+
stroke: "currentColor",
|
|
122
|
+
strokeWidth: "2",
|
|
123
|
+
strokeLinecap: "round",
|
|
124
|
+
strokeLinejoin: "round",
|
|
125
|
+
"aria-hidden": true,
|
|
126
|
+
style: { width: 12, height: 12, display: "block" },
|
|
127
|
+
children: [
|
|
128
|
+
/* @__PURE__ */ jsx("polyline", { points: "15 3 21 3 21 9" }),
|
|
129
|
+
/* @__PURE__ */ jsx("polyline", { points: "9 21 3 21 3 15" }),
|
|
130
|
+
/* @__PURE__ */ jsx("line", { x1: "21", y1: "3", x2: "14", y2: "10" }),
|
|
131
|
+
/* @__PURE__ */ jsx("line", { x1: "3", y1: "21", x2: "10", y2: "14" })
|
|
132
|
+
]
|
|
133
|
+
}
|
|
134
|
+
);
|
|
135
|
+
}
|
|
136
|
+
function MinimizeIcon() {
|
|
137
|
+
return /* @__PURE__ */ jsxs(
|
|
138
|
+
"svg",
|
|
139
|
+
{
|
|
140
|
+
viewBox: "0 0 24 24",
|
|
141
|
+
fill: "none",
|
|
142
|
+
stroke: "currentColor",
|
|
143
|
+
strokeWidth: "2",
|
|
144
|
+
strokeLinecap: "round",
|
|
145
|
+
strokeLinejoin: "round",
|
|
146
|
+
"aria-hidden": true,
|
|
147
|
+
style: { width: 12, height: 12, display: "block" },
|
|
148
|
+
children: [
|
|
149
|
+
/* @__PURE__ */ jsx("polyline", { points: "4 14 10 14 10 20" }),
|
|
150
|
+
/* @__PURE__ */ jsx("polyline", { points: "20 10 14 10 14 4" }),
|
|
151
|
+
/* @__PURE__ */ jsx("line", { x1: "14", y1: "10", x2: "21", y2: "3" }),
|
|
152
|
+
/* @__PURE__ */ jsx("line", { x1: "3", y1: "21", x2: "10", y2: "14" })
|
|
153
|
+
]
|
|
154
|
+
}
|
|
155
|
+
);
|
|
156
|
+
}
|
|
115
157
|
function Preview({
|
|
116
158
|
children,
|
|
117
159
|
source,
|
|
@@ -122,8 +164,17 @@ function Preview({
|
|
|
122
164
|
}) {
|
|
123
165
|
const [tab, setTab] = useState(defaultTab);
|
|
124
166
|
const [copied, setCopied] = useState(false);
|
|
167
|
+
const [fullscreen, setFullscreen] = useState(false);
|
|
125
168
|
const [showLines, setShowLines] = useLineNumbers();
|
|
126
169
|
const visibleSource = tab === "data" ? dataSource ?? "" : source;
|
|
170
|
+
useEffect(() => {
|
|
171
|
+
if (!fullscreen) return;
|
|
172
|
+
function onKey(e) {
|
|
173
|
+
if (e.key === "Escape") setFullscreen(false);
|
|
174
|
+
}
|
|
175
|
+
window.addEventListener("keydown", onKey);
|
|
176
|
+
return () => window.removeEventListener("keydown", onKey);
|
|
177
|
+
}, [fullscreen]);
|
|
127
178
|
function copy() {
|
|
128
179
|
navigator.clipboard.writeText(visibleSource).then(
|
|
129
180
|
() => {
|
|
@@ -139,7 +190,20 @@ function Preview({
|
|
|
139
190
|
{
|
|
140
191
|
"data-line-numbers": showLines ? "on" : "off",
|
|
141
192
|
className: "border border-doc-template-faint bg-doc-template-panel",
|
|
142
|
-
style:
|
|
193
|
+
style: fullscreen ? {
|
|
194
|
+
// Full-viewport overlay. `--color-doc-template-bg` is the page
|
|
195
|
+
// surface token so the backdrop matches the site in both light
|
|
196
|
+
// and dark themes.
|
|
197
|
+
position: "fixed",
|
|
198
|
+
inset: 0,
|
|
199
|
+
zIndex: 1e3,
|
|
200
|
+
margin: 0,
|
|
201
|
+
borderRadius: 0,
|
|
202
|
+
background: "var(--color-doc-template-bg)",
|
|
203
|
+
display: "flex",
|
|
204
|
+
flexDirection: "column",
|
|
205
|
+
overflow: "hidden"
|
|
206
|
+
} : { margin: "18px 0 22px", borderRadius: "var(--radius-doc-template)", overflow: "hidden" },
|
|
143
207
|
children: [
|
|
144
208
|
/* @__PURE__ */ jsxs(
|
|
145
209
|
"div",
|
|
@@ -206,11 +270,54 @@ function Preview({
|
|
|
206
270
|
children: copied ? "Copied" : "Copy"
|
|
207
271
|
}
|
|
208
272
|
)
|
|
209
|
-
] })
|
|
273
|
+
] }),
|
|
274
|
+
tab === "preview" && /* @__PURE__ */ jsx("span", { style: { marginLeft: "auto" } }),
|
|
275
|
+
/* @__PURE__ */ jsx(
|
|
276
|
+
"button",
|
|
277
|
+
{
|
|
278
|
+
type: "button",
|
|
279
|
+
"aria-pressed": fullscreen,
|
|
280
|
+
"aria-label": fullscreen ? "Exit fullscreen" : "Enter fullscreen",
|
|
281
|
+
title: fullscreen ? "Exit fullscreen (Esc)" : "Enter fullscreen",
|
|
282
|
+
onClick: () => setFullscreen((f) => !f),
|
|
283
|
+
style: headerBtnStyle(fullscreen),
|
|
284
|
+
children: fullscreen ? /* @__PURE__ */ jsx(MinimizeIcon, {}) : /* @__PURE__ */ jsx(MaximizeIcon, {})
|
|
285
|
+
}
|
|
286
|
+
)
|
|
210
287
|
]
|
|
211
288
|
}
|
|
212
289
|
),
|
|
213
|
-
tab === "preview" ? /* @__PURE__ */
|
|
290
|
+
tab === "preview" ? /* @__PURE__ */ jsxs(
|
|
291
|
+
"div",
|
|
292
|
+
{
|
|
293
|
+
...fullscreen ? { "data-preview-fill": "" } : null,
|
|
294
|
+
style: fullscreen ? {
|
|
295
|
+
// Full-bleed: drop the padding so a wide demo reaches every
|
|
296
|
+
// edge of the overlay. The `[data-preview-fill]` rule below
|
|
297
|
+
// then stretches the demo's own wrapper to this pane's
|
|
298
|
+
// height, so a specimen with a fixed height grows to fill
|
|
299
|
+
// the viewport instead of leaving dead space below it.
|
|
300
|
+
padding: 0,
|
|
301
|
+
flex: 1,
|
|
302
|
+
minHeight: 0,
|
|
303
|
+
width: "100%",
|
|
304
|
+
overflow: "auto"
|
|
305
|
+
} : { padding: 24, minHeight: 80, ...height ? { height } : null },
|
|
306
|
+
children: [
|
|
307
|
+
fullscreen && /* @__PURE__ */ jsx("style", { children: "[data-preview-fill]>:not(style){height:100%!important}" }),
|
|
308
|
+
children
|
|
309
|
+
]
|
|
310
|
+
}
|
|
311
|
+
) : /* @__PURE__ */ jsx(
|
|
312
|
+
"div",
|
|
313
|
+
{
|
|
314
|
+
style: {
|
|
315
|
+
background: "var(--color-doc-template-code)",
|
|
316
|
+
...fullscreen ? { flex: 1, minHeight: 0, overflow: "auto" } : null
|
|
317
|
+
},
|
|
318
|
+
children: /* @__PURE__ */ jsx(HighlightedSource, { code: visibleSource, filename })
|
|
319
|
+
}
|
|
320
|
+
)
|
|
214
321
|
]
|
|
215
322
|
}
|
|
216
323
|
);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { useMemo, useState, useEffect } from "react";
|
|
3
3
|
import { usePageContext } from "vike-react/usePageContext";
|
|
4
|
-
import { groupedPages, groupedVisiblePages } from "../lib/navigation.js";
|
|
4
|
+
import { normalizePath, groupedPages, groupedVisiblePages } from "../lib/navigation.js";
|
|
5
5
|
import { useHiddenToggle } from "../lib/use-hidden-toggle.js";
|
|
6
6
|
import { tabForUrl, urlInTab } from "../lib/tabs.js";
|
|
7
7
|
const SIDEBAR_KEY = "sidebar-collapsed";
|
|
@@ -15,6 +15,7 @@ function loadCollapsed() {
|
|
|
15
15
|
}
|
|
16
16
|
function Sidebar() {
|
|
17
17
|
const { urlPathname } = usePageContext();
|
|
18
|
+
const currentPath = normalizePath(urlPathname);
|
|
18
19
|
const [showHidden] = useHiddenToggle();
|
|
19
20
|
const allGroups = showHidden ? groupedPages : groupedVisiblePages;
|
|
20
21
|
const activeTab = tabForUrl(urlPathname);
|
|
@@ -36,7 +37,7 @@ function Sidebar() {
|
|
|
36
37
|
});
|
|
37
38
|
}
|
|
38
39
|
useEffect(() => {
|
|
39
|
-
const g = groups.find((g2) => g2.items.some((i) => i.path ===
|
|
40
|
+
const g = groups.find((g2) => g2.items.some((i) => i.path === currentPath));
|
|
40
41
|
if (g?.label && collapsed.has(g.label)) {
|
|
41
42
|
setCollapsed((prev) => {
|
|
42
43
|
const next = new Set(prev);
|
|
@@ -84,7 +85,7 @@ function Sidebar() {
|
|
|
84
85
|
"a",
|
|
85
86
|
{
|
|
86
87
|
href: item.path,
|
|
87
|
-
"aria-current": item.path ===
|
|
88
|
+
"aria-current": item.path === currentPath ? "page" : void 0,
|
|
88
89
|
className: "sidebar-link",
|
|
89
90
|
children: [
|
|
90
91
|
/* @__PURE__ */ jsx("span", { style: { flex: 1, minWidth: 0 }, children: item.title }),
|
package/dist/components/TOC.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { jsxs, jsx } from "react/jsx-runtime";
|
|
2
2
|
import { useState, useRef, useEffect, useMemo } from "react";
|
|
3
3
|
import { usePageContext } from "vike-react/usePageContext";
|
|
4
|
-
import {
|
|
4
|
+
import { normalizePath, findPage } from "../lib/navigation.js";
|
|
5
5
|
import { siteConfig } from "../site-config.js";
|
|
6
6
|
const TOC_KEY_PREFIX = "toc-collapsed:";
|
|
7
7
|
const X0 = 4;
|
|
@@ -51,15 +51,16 @@ function scrollToHeading(e, id) {
|
|
|
51
51
|
}
|
|
52
52
|
function TOC() {
|
|
53
53
|
const { urlPathname } = usePageContext();
|
|
54
|
+
const currentPath = normalizePath(urlPathname);
|
|
54
55
|
const mdHref = (() => {
|
|
55
|
-
const meta =
|
|
56
|
+
const meta = findPage(urlPathname);
|
|
56
57
|
if (!meta || meta.noindex) return null;
|
|
57
|
-
return
|
|
58
|
+
return currentPath === "/" ? "/index.md" : `${currentPath}.md`;
|
|
58
59
|
})();
|
|
59
60
|
const editHref = (() => {
|
|
60
|
-
const meta =
|
|
61
|
+
const meta = findPage(urlPathname);
|
|
61
62
|
if (!meta) return null;
|
|
62
|
-
const slug =
|
|
63
|
+
const slug = currentPath === "/" ? "index" : currentPath.replace(/^\//, "");
|
|
63
64
|
const pagesPath = siteConfig.docsPagesPath ?? "docs/pages";
|
|
64
65
|
return `${siteConfig.docsRepoUrl}/edit/${siteConfig.docsBranch}/${pagesPath}/${slug}/+Page.mdx`;
|
|
65
66
|
})();
|
|
@@ -138,7 +139,7 @@ function TOC() {
|
|
|
138
139
|
setHeadings([]);
|
|
139
140
|
return;
|
|
140
141
|
}
|
|
141
|
-
const current =
|
|
142
|
+
const current = findPage(urlPathname);
|
|
142
143
|
const tocLevel = current?.tocLevel ?? 3;
|
|
143
144
|
const selector = tocLevel >= 3 ? "[data-toc-anchor], h3[id]" : "[data-toc-anchor]";
|
|
144
145
|
function collect() {
|
|
@@ -1,2 +1,5 @@
|
|
|
1
1
|
import { JSX } from 'react';
|
|
2
|
+
/** Topbar theme control. The variant comes from `siteConfig.themeToggle`:
|
|
3
|
+
* `'cycle'` (default) renders the single cycling button, `'segmented'`
|
|
4
|
+
* the three-button slider. Both share ThemeProvider state. */
|
|
2
5
|
export declare function ThemeToggle(): JSX.Element;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { useTheme } from "./ThemeProvider.js";
|
|
3
3
|
import { ClientOnly } from "./ClientOnly.js";
|
|
4
|
+
import { siteConfig } from "../site-config.js";
|
|
4
5
|
const SIZE = 24;
|
|
5
6
|
const PAD = 2;
|
|
6
7
|
const SPRING = "cubic-bezier(0.34, 1.45, 0.55, 1)";
|
|
@@ -61,11 +62,11 @@ const DarkIcon = () => /* @__PURE__ */ jsx(
|
|
|
61
62
|
}
|
|
62
63
|
);
|
|
63
64
|
const SEGMENTS = [
|
|
64
|
-
{ value: "light", label: "Light", Icon: LightIcon },
|
|
65
|
+
{ value: "light", label: "Light", Icon: LightIcon, inactiveRotate: -18 },
|
|
65
66
|
{ value: "system", label: "System", Icon: SystemIcon },
|
|
66
|
-
{ value: "dark", label: "Dark", Icon: DarkIcon }
|
|
67
|
+
{ value: "dark", label: "Dark", Icon: DarkIcon, inactiveRotate: 18 }
|
|
67
68
|
];
|
|
68
|
-
function
|
|
69
|
+
function CycleToggle() {
|
|
69
70
|
const { theme, setTheme } = useTheme();
|
|
70
71
|
const idx = Math.max(0, SEGMENTS.findIndex((s) => s.value === theme));
|
|
71
72
|
const current = SEGMENTS[idx];
|
|
@@ -101,8 +102,80 @@ function ToggleInner() {
|
|
|
101
102
|
}
|
|
102
103
|
);
|
|
103
104
|
}
|
|
105
|
+
function SegmentedToggle() {
|
|
106
|
+
const { theme, setTheme } = useTheme();
|
|
107
|
+
const idx = Math.max(0, SEGMENTS.findIndex((s) => s.value === theme));
|
|
108
|
+
return /* @__PURE__ */ jsxs(
|
|
109
|
+
"div",
|
|
110
|
+
{
|
|
111
|
+
role: "group",
|
|
112
|
+
"aria-label": "Theme",
|
|
113
|
+
className: "relative inline-flex items-center bg-doc-template-panel",
|
|
114
|
+
style: { padding: PAD, borderRadius: 999, isolation: "isolate" },
|
|
115
|
+
children: [
|
|
116
|
+
/* @__PURE__ */ jsx(
|
|
117
|
+
"span",
|
|
118
|
+
{
|
|
119
|
+
"aria-hidden": true,
|
|
120
|
+
className: "bg-doc-template-chip",
|
|
121
|
+
style: {
|
|
122
|
+
position: "absolute",
|
|
123
|
+
top: PAD,
|
|
124
|
+
left: PAD,
|
|
125
|
+
width: SIZE,
|
|
126
|
+
height: SIZE,
|
|
127
|
+
borderRadius: 999,
|
|
128
|
+
transform: `translateX(${idx * SIZE}px)`,
|
|
129
|
+
transition: `transform 0.42s ${SPRING}`,
|
|
130
|
+
zIndex: 0,
|
|
131
|
+
willChange: "transform"
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
),
|
|
135
|
+
SEGMENTS.map((seg) => {
|
|
136
|
+
const pressed = seg.value === theme;
|
|
137
|
+
return /* @__PURE__ */ jsx(
|
|
138
|
+
"button",
|
|
139
|
+
{
|
|
140
|
+
type: "button",
|
|
141
|
+
"aria-label": seg.label,
|
|
142
|
+
title: seg.label,
|
|
143
|
+
"aria-pressed": pressed,
|
|
144
|
+
onClick: () => setTheme(seg.value),
|
|
145
|
+
className: pressed ? "inline-flex items-center justify-center bg-transparent border-0 cursor-pointer text-doc-template-ink" : "inline-flex items-center justify-center bg-transparent border-0 cursor-pointer text-doc-template-muted hover:text-doc-template-ink",
|
|
146
|
+
style: {
|
|
147
|
+
position: "relative",
|
|
148
|
+
zIndex: 1,
|
|
149
|
+
width: SIZE,
|
|
150
|
+
height: SIZE,
|
|
151
|
+
borderRadius: 999,
|
|
152
|
+
padding: 0,
|
|
153
|
+
margin: 0,
|
|
154
|
+
transition: "color 0.25s ease"
|
|
155
|
+
},
|
|
156
|
+
children: /* @__PURE__ */ jsx(
|
|
157
|
+
"span",
|
|
158
|
+
{
|
|
159
|
+
style: {
|
|
160
|
+
display: "inline-flex",
|
|
161
|
+
transform: pressed ? "scale(1) rotate(0deg)" : `scale(0.85)${seg.inactiveRotate ? ` rotate(${seg.inactiveRotate}deg)` : ""}`,
|
|
162
|
+
opacity: pressed ? 1 : 0.65,
|
|
163
|
+
transition: `transform 0.42s ${SPRING}, opacity 0.25s ease`
|
|
164
|
+
},
|
|
165
|
+
children: /* @__PURE__ */ jsx(seg.Icon, {})
|
|
166
|
+
}
|
|
167
|
+
)
|
|
168
|
+
},
|
|
169
|
+
seg.value
|
|
170
|
+
);
|
|
171
|
+
})
|
|
172
|
+
]
|
|
173
|
+
}
|
|
174
|
+
);
|
|
175
|
+
}
|
|
104
176
|
function ThemeToggle() {
|
|
105
|
-
|
|
177
|
+
const segmented = siteConfig.themeToggle === "segmented";
|
|
178
|
+
return /* @__PURE__ */ jsx(ClientOnly, { children: segmented ? /* @__PURE__ */ jsx(SegmentedToggle, {}) : /* @__PURE__ */ jsx(CycleToggle, {}) });
|
|
106
179
|
}
|
|
107
180
|
export {
|
|
108
181
|
ThemeToggle
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { jsxs, jsx, Fragment } from "react/jsx-runtime";
|
|
2
2
|
import { useRef, useState, useEffect, useLayoutEffect } from "react";
|
|
3
3
|
import { usePageContext } from "vike-react/usePageContext";
|
|
4
|
-
import {
|
|
4
|
+
import { findPage } from "../lib/navigation.js";
|
|
5
5
|
import { siteConfig } from "../site-config.js";
|
|
6
6
|
import { useMediaQuery } from "../lib/use-media-query.js";
|
|
7
7
|
import { useHiddenToggle } from "../lib/use-hidden-toggle.js";
|
|
8
8
|
import { ThemeToggle } from "./ThemeToggle.js";
|
|
9
|
+
import { VersionBadge } from "./VersionBadge.js";
|
|
9
10
|
import { useMerge } from "../renderer/Layout.js";
|
|
10
11
|
import { TabStrip } from "./TabStrip.js";
|
|
11
12
|
function HiddenRevealChip() {
|
|
@@ -45,303 +46,6 @@ function HiddenRevealChip() {
|
|
|
45
46
|
}
|
|
46
47
|
);
|
|
47
48
|
}
|
|
48
|
-
function VersionBadge({
|
|
49
|
-
label,
|
|
50
|
-
version,
|
|
51
|
-
collapsed,
|
|
52
|
-
dropdown = false
|
|
53
|
-
}) {
|
|
54
|
-
const transition = `opacity 0.4s ease, transform 0.4s ${SPRING}, width 0.4s ${SPRING}, margin 0.4s ${SPRING}, padding 0.4s ${SPRING}`;
|
|
55
|
-
const [open, setOpen] = useState(false);
|
|
56
|
-
const [manifest, setManifest] = useState(null);
|
|
57
|
-
const [displayVersion, setDisplayVersion] = useState(version);
|
|
58
|
-
const wrapperRef = useRef(null);
|
|
59
|
-
useEffect(() => {
|
|
60
|
-
if (!dropdown) return;
|
|
61
|
-
let cancelled = false;
|
|
62
|
-
fetch("/versions.json").then((r) => r.ok ? r.json() : null).then((m) => {
|
|
63
|
-
if (!cancelled && m) setManifest(m);
|
|
64
|
-
}).catch(() => {
|
|
65
|
-
});
|
|
66
|
-
return () => {
|
|
67
|
-
cancelled = true;
|
|
68
|
-
};
|
|
69
|
-
}, [dropdown]);
|
|
70
|
-
useEffect(() => {
|
|
71
|
-
if (typeof window === "undefined") return;
|
|
72
|
-
const host = window.location.hostname;
|
|
73
|
-
const m = host.match(/^v(\d+(?:-\d+)+(?:[a-z]+\d+)?)\./i);
|
|
74
|
-
if (m) {
|
|
75
|
-
setDisplayVersion(m[1].replace(/-/g, "."));
|
|
76
|
-
} else if (host.startsWith("stable.") && manifest?.stable) {
|
|
77
|
-
setDisplayVersion(manifest.stable);
|
|
78
|
-
} else if (manifest?.current) {
|
|
79
|
-
setDisplayVersion(manifest.current);
|
|
80
|
-
}
|
|
81
|
-
}, [manifest]);
|
|
82
|
-
useEffect(() => {
|
|
83
|
-
if (!open) return;
|
|
84
|
-
function onDown(e) {
|
|
85
|
-
if (wrapperRef.current && !wrapperRef.current.contains(e.target)) setOpen(false);
|
|
86
|
-
}
|
|
87
|
-
function onKey(e) {
|
|
88
|
-
if (e.key === "Escape") setOpen(false);
|
|
89
|
-
}
|
|
90
|
-
window.addEventListener("mousedown", onDown);
|
|
91
|
-
window.addEventListener("keydown", onKey);
|
|
92
|
-
return () => {
|
|
93
|
-
window.removeEventListener("mousedown", onDown);
|
|
94
|
-
window.removeEventListener("keydown", onKey);
|
|
95
|
-
};
|
|
96
|
-
}, [open]);
|
|
97
|
-
const labelSegStyle = {
|
|
98
|
-
padding: "2px 6px",
|
|
99
|
-
fontWeight: 600,
|
|
100
|
-
borderTopLeftRadius: 3,
|
|
101
|
-
borderBottomLeftRadius: 3
|
|
102
|
-
};
|
|
103
|
-
const versionSegStyle = {
|
|
104
|
-
padding: "2px 6px",
|
|
105
|
-
background: "color-mix(in srgb, var(--color-doc-template-ink) 5%, var(--color-doc-template-bg))",
|
|
106
|
-
fontWeight: 600,
|
|
107
|
-
borderTopRightRadius: 3,
|
|
108
|
-
borderBottomRightRadius: 3,
|
|
109
|
-
display: "inline-flex",
|
|
110
|
-
alignItems: "center",
|
|
111
|
-
gap: dropdown ? 4 : 0,
|
|
112
|
-
border: 0,
|
|
113
|
-
borderLeft: "1px solid var(--color-doc-template-faint)",
|
|
114
|
-
color: "inherit",
|
|
115
|
-
fontFamily: "inherit",
|
|
116
|
-
fontSize: "inherit",
|
|
117
|
-
letterSpacing: "inherit",
|
|
118
|
-
cursor: dropdown ? "pointer" : "default"
|
|
119
|
-
};
|
|
120
|
-
const wrapperBase = {
|
|
121
|
-
fontFamily: "var(--font-doc-template-mono)",
|
|
122
|
-
fontSize: 10,
|
|
123
|
-
fontWeight: 500,
|
|
124
|
-
letterSpacing: "0.02em",
|
|
125
|
-
marginLeft: 6,
|
|
126
|
-
borderRadius: 4,
|
|
127
|
-
transition,
|
|
128
|
-
...collapsed ? {
|
|
129
|
-
opacity: 0,
|
|
130
|
-
transform: "translateX(-4px)",
|
|
131
|
-
pointerEvents: "none",
|
|
132
|
-
width: 0,
|
|
133
|
-
margin: 0,
|
|
134
|
-
padding: 0,
|
|
135
|
-
overflow: "hidden"
|
|
136
|
-
} : {}
|
|
137
|
-
};
|
|
138
|
-
const chevron = dropdown ? /* @__PURE__ */ jsx(
|
|
139
|
-
"svg",
|
|
140
|
-
{
|
|
141
|
-
width: "8",
|
|
142
|
-
height: "8",
|
|
143
|
-
viewBox: "0 0 24 24",
|
|
144
|
-
fill: "none",
|
|
145
|
-
stroke: "currentColor",
|
|
146
|
-
strokeWidth: "3",
|
|
147
|
-
strokeLinecap: "round",
|
|
148
|
-
strokeLinejoin: "round",
|
|
149
|
-
"aria-hidden": true,
|
|
150
|
-
style: {
|
|
151
|
-
opacity: 0.65,
|
|
152
|
-
transform: open ? "scaleY(-1)" : "none",
|
|
153
|
-
transition: "transform 0.22s ease"
|
|
154
|
-
},
|
|
155
|
-
children: /* @__PURE__ */ jsx("path", { d: "M6 9l6 6 6-6" })
|
|
156
|
-
}
|
|
157
|
-
) : null;
|
|
158
|
-
return /* @__PURE__ */ jsxs(
|
|
159
|
-
"span",
|
|
160
|
-
{
|
|
161
|
-
ref: wrapperRef,
|
|
162
|
-
className: "hidden md:inline-flex items-stretch relative border border-doc-template-faint",
|
|
163
|
-
style: { ...wrapperBase, borderRadius: 4 },
|
|
164
|
-
title: dropdown ? void 0 : `${label} ${version}`,
|
|
165
|
-
children: [
|
|
166
|
-
/* @__PURE__ */ jsx(
|
|
167
|
-
"span",
|
|
168
|
-
{
|
|
169
|
-
className: "inline-flex items-center text-doc-template-muted",
|
|
170
|
-
style: labelSegStyle,
|
|
171
|
-
children: label
|
|
172
|
-
}
|
|
173
|
-
),
|
|
174
|
-
dropdown ? /* @__PURE__ */ jsxs(
|
|
175
|
-
"button",
|
|
176
|
-
{
|
|
177
|
-
type: "button",
|
|
178
|
-
onClick: () => setOpen((o) => !o),
|
|
179
|
-
"aria-haspopup": "listbox",
|
|
180
|
-
"aria-expanded": open,
|
|
181
|
-
title: `Switch ${label} version (current v${displayVersion})`,
|
|
182
|
-
className: "text-doc-template-ink hover:bg-doc-template-search",
|
|
183
|
-
style: versionSegStyle,
|
|
184
|
-
children: [
|
|
185
|
-
"v",
|
|
186
|
-
displayVersion,
|
|
187
|
-
chevron
|
|
188
|
-
]
|
|
189
|
-
}
|
|
190
|
-
) : /* @__PURE__ */ jsxs(
|
|
191
|
-
"span",
|
|
192
|
-
{
|
|
193
|
-
className: "inline-flex items-center text-doc-template-ink",
|
|
194
|
-
style: versionSegStyle,
|
|
195
|
-
children: [
|
|
196
|
-
"v",
|
|
197
|
-
displayVersion
|
|
198
|
-
]
|
|
199
|
-
}
|
|
200
|
-
),
|
|
201
|
-
dropdown && open && manifest && (() => {
|
|
202
|
-
const aliasEntries = manifest.aliases ? Object.entries(manifest.aliases) : [];
|
|
203
|
-
const versionEntries = manifest.versions ?? [];
|
|
204
|
-
const ENTRY_STEP = 0.03;
|
|
205
|
-
const ENTRY_BASE = 0.13;
|
|
206
|
-
let idx = 0;
|
|
207
|
-
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
208
|
-
/* @__PURE__ */ jsxs(
|
|
209
|
-
"svg",
|
|
210
|
-
{
|
|
211
|
-
width: "14",
|
|
212
|
-
height: "11",
|
|
213
|
-
viewBox: "0 0 14 11",
|
|
214
|
-
"aria-hidden": true,
|
|
215
|
-
style: {
|
|
216
|
-
position: "absolute",
|
|
217
|
-
top: "calc(100% + 4.5px)",
|
|
218
|
-
right: 4,
|
|
219
|
-
zIndex: 81,
|
|
220
|
-
display: "block",
|
|
221
|
-
pointerEvents: "none",
|
|
222
|
-
animation: "popover-wedge-in 0.24s ease both"
|
|
223
|
-
},
|
|
224
|
-
children: [
|
|
225
|
-
/* @__PURE__ */ jsx("path", { d: "M0 11 L7 1 L14 11", stroke: "var(--color-doc-template-faint)", strokeWidth: "1", fill: "none" }),
|
|
226
|
-
/* @__PURE__ */ jsx("path", { d: "M1 11 L7 2 L13 11 Z", fill: "var(--color-doc-template-bg)" })
|
|
227
|
-
]
|
|
228
|
-
}
|
|
229
|
-
),
|
|
230
|
-
/* @__PURE__ */ jsxs(
|
|
231
|
-
"div",
|
|
232
|
-
{
|
|
233
|
-
role: "listbox",
|
|
234
|
-
"aria-label": `Past ${label} versions`,
|
|
235
|
-
className: "absolute border border-doc-template-faint bg-doc-template-bg",
|
|
236
|
-
style: {
|
|
237
|
-
top: "calc(100% + 14px)",
|
|
238
|
-
left: 0,
|
|
239
|
-
minWidth: 220,
|
|
240
|
-
maxHeight: "min(360px, 60vh)",
|
|
241
|
-
overflowY: "auto",
|
|
242
|
-
borderRadius: 12,
|
|
243
|
-
// Drop shadow + a "negative" 0-blur shadow above using the page bg
|
|
244
|
-
// color: it paints a bg-colored band into the strip between the
|
|
245
|
-
// popover top and the navbar's bottom border, masking the navbar's
|
|
246
|
-
// 1px box-shadow in the popover's column so the two don't visually
|
|
247
|
-
// collide.
|
|
248
|
-
boxShadow: "0 6px 24px rgb(0 0 0 / 0.10), 0 -5px 3px 0 var(--color-doc-template-bg)",
|
|
249
|
-
padding: 4,
|
|
250
|
-
zIndex: 80,
|
|
251
|
-
fontFamily: "var(--font-doc-template-mono)",
|
|
252
|
-
fontSize: 11,
|
|
253
|
-
animation: "popover-in 0.28s ease both",
|
|
254
|
-
animationDelay: "0.04s",
|
|
255
|
-
transformOrigin: "top right"
|
|
256
|
-
},
|
|
257
|
-
children: [
|
|
258
|
-
aliasEntries.length > 0 && /* @__PURE__ */ jsx(
|
|
259
|
-
"div",
|
|
260
|
-
{
|
|
261
|
-
style: {
|
|
262
|
-
padding: "4px 6px 2px",
|
|
263
|
-
opacity: 0.55,
|
|
264
|
-
fontSize: 9,
|
|
265
|
-
letterSpacing: "0.08em",
|
|
266
|
-
textTransform: "uppercase",
|
|
267
|
-
animation: "popover-entry-in 0.28s ease both",
|
|
268
|
-
animationDelay: `${ENTRY_BASE + idx++ * ENTRY_STEP}s`
|
|
269
|
-
},
|
|
270
|
-
children: "Aliases"
|
|
271
|
-
}
|
|
272
|
-
),
|
|
273
|
-
aliasEntries.map(([name, url]) => /* @__PURE__ */ jsxs(
|
|
274
|
-
"a",
|
|
275
|
-
{
|
|
276
|
-
href: url,
|
|
277
|
-
className: "block text-doc-template-ink no-underline hover:bg-doc-template-search",
|
|
278
|
-
style: {
|
|
279
|
-
padding: "5px 8px",
|
|
280
|
-
borderRadius: 8,
|
|
281
|
-
animation: "popover-entry-in 0.28s ease both",
|
|
282
|
-
animationDelay: `${ENTRY_BASE + idx++ * ENTRY_STEP}s`
|
|
283
|
-
},
|
|
284
|
-
children: [
|
|
285
|
-
name,
|
|
286
|
-
name === "stable" && manifest.stable && /* @__PURE__ */ jsxs("span", { style: { opacity: 0.5, marginLeft: 6 }, children: [
|
|
287
|
-
"v",
|
|
288
|
-
manifest.stable
|
|
289
|
-
] })
|
|
290
|
-
]
|
|
291
|
-
},
|
|
292
|
-
`alias-${name}`
|
|
293
|
-
)),
|
|
294
|
-
versionEntries.length > 0 && /* @__PURE__ */ jsx(
|
|
295
|
-
"div",
|
|
296
|
-
{
|
|
297
|
-
style: {
|
|
298
|
-
padding: "6px 6px 2px",
|
|
299
|
-
opacity: 0.55,
|
|
300
|
-
fontSize: 9,
|
|
301
|
-
letterSpacing: "0.08em",
|
|
302
|
-
textTransform: "uppercase",
|
|
303
|
-
animation: "popover-entry-in 0.28s ease both",
|
|
304
|
-
animationDelay: `${ENTRY_BASE + idx++ * ENTRY_STEP}s`
|
|
305
|
-
},
|
|
306
|
-
children: "Versions"
|
|
307
|
-
}
|
|
308
|
-
),
|
|
309
|
-
versionEntries.map((v) => {
|
|
310
|
-
const isCurrent = v.version === manifest.current;
|
|
311
|
-
return /* @__PURE__ */ jsxs(
|
|
312
|
-
"a",
|
|
313
|
-
{
|
|
314
|
-
href: v.url,
|
|
315
|
-
className: "text-doc-template-ink no-underline hover:bg-doc-template-search flex items-baseline justify-between gap-3",
|
|
316
|
-
style: {
|
|
317
|
-
padding: "5px 8px",
|
|
318
|
-
borderRadius: 8,
|
|
319
|
-
fontWeight: isCurrent ? 700 : 400,
|
|
320
|
-
background: isCurrent ? "color-mix(in srgb, var(--color-doc-template-accent) 12%, transparent)" : void 0,
|
|
321
|
-
animation: "popover-entry-in 0.28s ease both",
|
|
322
|
-
animationDelay: `${ENTRY_BASE + idx++ * ENTRY_STEP}s`
|
|
323
|
-
},
|
|
324
|
-
children: [
|
|
325
|
-
/* @__PURE__ */ jsxs("span", { children: [
|
|
326
|
-
"v",
|
|
327
|
-
v.version,
|
|
328
|
-
isCurrent && /* @__PURE__ */ jsx("span", { style: { opacity: 0.55, marginLeft: 6 }, children: "current" })
|
|
329
|
-
] }),
|
|
330
|
-
v.date && /* @__PURE__ */ jsx("span", { style: { opacity: 0.5, fontVariantNumeric: "tabular-nums", fontSize: 10 }, children: v.date })
|
|
331
|
-
]
|
|
332
|
-
},
|
|
333
|
-
v.version
|
|
334
|
-
);
|
|
335
|
-
})
|
|
336
|
-
]
|
|
337
|
-
}
|
|
338
|
-
)
|
|
339
|
-
] });
|
|
340
|
-
})()
|
|
341
|
-
]
|
|
342
|
-
}
|
|
343
|
-
);
|
|
344
|
-
}
|
|
345
49
|
const SPRING = "cubic-bezier(0.4, 0.7, 0.3, 1)";
|
|
346
50
|
const EXPAND_EASE = "cubic-bezier(0.16, 1, 0.3, 1)";
|
|
347
51
|
const EXPAND_MS = 320;
|
|
@@ -354,7 +58,7 @@ const SEARCH_GUTTER = 24;
|
|
|
354
58
|
const SEARCH_INSET = `max(${SEARCH_GUTTER}px, calc((100vw - ${SEARCH_MAX_W}px) / 2))`;
|
|
355
59
|
function Topbar({ searchOpen, onOpenSearch, onCloseSearch, query, setQuery }) {
|
|
356
60
|
const { urlPathname } = usePageContext();
|
|
357
|
-
const current =
|
|
61
|
+
const current = findPage(urlPathname);
|
|
358
62
|
const inputRef = useRef(null);
|
|
359
63
|
const labelRef = useRef(null);
|
|
360
64
|
const focusTimerRef = useRef(null);
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
export interface VersionBadgeProps {
|
|
2
|
+
/** Left segment text (e.g. the package name). */
|
|
3
|
+
label: string;
|
|
4
|
+
/** Build-time version shown in the right segment (may be overridden on
|
|
5
|
+
* the client from the hostname / manifest — see below). */
|
|
6
|
+
version: string;
|
|
7
|
+
/** Collapse to width 0 (the Topbar drives this from its merged state).
|
|
8
|
+
* Standalone placements can omit it. */
|
|
9
|
+
collapsed?: boolean;
|
|
10
|
+
/** Turn the version segment into a popover listing the deploys from
|
|
11
|
+
* `/versions.json`. */
|
|
12
|
+
dropdown?: boolean;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Two-segment version chip: `[ label | v<version> ]`.
|
|
16
|
+
*
|
|
17
|
+
* With `dropdown: true` the right segment opens a popover listing alias
|
|
18
|
+
* and past-version doc URLs sourced from a `versions.json` manifest
|
|
19
|
+
* (schema: `{ current, stable, aliases, versions: [{version, url, date}] }`).
|
|
20
|
+
*
|
|
21
|
+
* The manifest is fetched from the production origin (`siteConfig.url`)
|
|
22
|
+
* first, so the dropdown on old, immutable version-branch deploys still
|
|
23
|
+
* lists releases published after they were built; the same-origin copy is
|
|
24
|
+
* the fallback (local dev, or when no `url` is configured). Cross-origin
|
|
25
|
+
* fetching needs a CORS header on `/versions.json` — see the
|
|
26
|
+
* `netlify.example.toml` template.
|
|
27
|
+
*
|
|
28
|
+
* Rendered by the Topbar for each `siteConfig.versionChips` entry, and
|
|
29
|
+
* exported from the library index for standalone placement.
|
|
30
|
+
*/
|
|
31
|
+
export declare function VersionBadge({ label, version, collapsed, dropdown, }: VersionBadgeProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,315 @@
|
|
|
1
|
+
import { jsxs, jsx, Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { useState, useRef, useEffect } from "react";
|
|
3
|
+
import { siteConfig } from "../site-config.js";
|
|
4
|
+
const SPRING = "cubic-bezier(0.4, 0.7, 0.3, 1)";
|
|
5
|
+
function VersionBadge({
|
|
6
|
+
label,
|
|
7
|
+
version,
|
|
8
|
+
collapsed = false,
|
|
9
|
+
dropdown = false
|
|
10
|
+
}) {
|
|
11
|
+
const transition = `opacity 0.4s ease, transform 0.4s ${SPRING}, width 0.4s ${SPRING}, margin 0.4s ${SPRING}, padding 0.4s ${SPRING}`;
|
|
12
|
+
const [open, setOpen] = useState(false);
|
|
13
|
+
const [manifest, setManifest] = useState(null);
|
|
14
|
+
const [displayVersion, setDisplayVersion] = useState(version);
|
|
15
|
+
const wrapperRef = useRef(null);
|
|
16
|
+
useEffect(() => {
|
|
17
|
+
if (!dropdown) return;
|
|
18
|
+
let cancelled = false;
|
|
19
|
+
const origin = (siteConfig.url || "").replace(/\/+$/, "");
|
|
20
|
+
const sameOrigin = () => fetch("/versions.json").then((r) => r.ok ? r.json() : null);
|
|
21
|
+
const load = origin ? fetch(`${origin}/versions.json`).then((r) => r.ok ? r.json() : Promise.reject(new Error(String(r.status)))).catch(sameOrigin) : sameOrigin();
|
|
22
|
+
load.then((m) => {
|
|
23
|
+
if (!cancelled && m) setManifest(m);
|
|
24
|
+
}).catch(() => {
|
|
25
|
+
});
|
|
26
|
+
return () => {
|
|
27
|
+
cancelled = true;
|
|
28
|
+
};
|
|
29
|
+
}, [dropdown]);
|
|
30
|
+
useEffect(() => {
|
|
31
|
+
if (typeof window === "undefined") return;
|
|
32
|
+
const host = window.location.hostname;
|
|
33
|
+
const m = host.match(/^v(\d+(?:-\d+)+(?:[a-z]+\d+)?)\./i);
|
|
34
|
+
if (m) {
|
|
35
|
+
setDisplayVersion(m[1].replace(/-/g, "."));
|
|
36
|
+
} else if (host.startsWith("stable.") && manifest?.stable) {
|
|
37
|
+
setDisplayVersion(manifest.stable);
|
|
38
|
+
} else if (manifest?.current) {
|
|
39
|
+
setDisplayVersion(manifest.current);
|
|
40
|
+
}
|
|
41
|
+
}, [manifest]);
|
|
42
|
+
useEffect(() => {
|
|
43
|
+
if (!open) return;
|
|
44
|
+
function onDown(e) {
|
|
45
|
+
if (wrapperRef.current && !wrapperRef.current.contains(e.target)) setOpen(false);
|
|
46
|
+
}
|
|
47
|
+
function onKey(e) {
|
|
48
|
+
if (e.key === "Escape") setOpen(false);
|
|
49
|
+
}
|
|
50
|
+
window.addEventListener("mousedown", onDown);
|
|
51
|
+
window.addEventListener("keydown", onKey);
|
|
52
|
+
return () => {
|
|
53
|
+
window.removeEventListener("mousedown", onDown);
|
|
54
|
+
window.removeEventListener("keydown", onKey);
|
|
55
|
+
};
|
|
56
|
+
}, [open]);
|
|
57
|
+
const labelSegStyle = {
|
|
58
|
+
padding: "2px 6px",
|
|
59
|
+
fontWeight: 600,
|
|
60
|
+
borderTopLeftRadius: 3,
|
|
61
|
+
borderBottomLeftRadius: 3
|
|
62
|
+
};
|
|
63
|
+
const versionSegStyle = {
|
|
64
|
+
padding: "2px 6px",
|
|
65
|
+
background: "color-mix(in srgb, var(--color-doc-template-ink) 5%, var(--color-doc-template-bg))",
|
|
66
|
+
fontWeight: 600,
|
|
67
|
+
borderTopRightRadius: 3,
|
|
68
|
+
borderBottomRightRadius: 3,
|
|
69
|
+
display: "inline-flex",
|
|
70
|
+
alignItems: "center",
|
|
71
|
+
gap: dropdown ? 4 : 0,
|
|
72
|
+
border: 0,
|
|
73
|
+
borderLeft: "1px solid var(--color-doc-template-faint)",
|
|
74
|
+
color: "inherit",
|
|
75
|
+
fontFamily: "inherit",
|
|
76
|
+
fontSize: "inherit",
|
|
77
|
+
letterSpacing: "inherit",
|
|
78
|
+
cursor: dropdown ? "pointer" : "default"
|
|
79
|
+
};
|
|
80
|
+
const wrapperBase = {
|
|
81
|
+
fontFamily: "var(--font-doc-template-mono)",
|
|
82
|
+
fontSize: 10,
|
|
83
|
+
fontWeight: 500,
|
|
84
|
+
letterSpacing: "0.02em",
|
|
85
|
+
marginLeft: 6,
|
|
86
|
+
borderRadius: 4,
|
|
87
|
+
transition,
|
|
88
|
+
...collapsed ? {
|
|
89
|
+
opacity: 0,
|
|
90
|
+
transform: "translateX(-4px)",
|
|
91
|
+
pointerEvents: "none",
|
|
92
|
+
width: 0,
|
|
93
|
+
margin: 0,
|
|
94
|
+
padding: 0,
|
|
95
|
+
overflow: "hidden"
|
|
96
|
+
} : {}
|
|
97
|
+
};
|
|
98
|
+
const chevron = dropdown ? /* @__PURE__ */ jsx(
|
|
99
|
+
"svg",
|
|
100
|
+
{
|
|
101
|
+
width: "8",
|
|
102
|
+
height: "8",
|
|
103
|
+
viewBox: "0 0 24 24",
|
|
104
|
+
fill: "none",
|
|
105
|
+
stroke: "currentColor",
|
|
106
|
+
strokeWidth: "3",
|
|
107
|
+
strokeLinecap: "round",
|
|
108
|
+
strokeLinejoin: "round",
|
|
109
|
+
"aria-hidden": true,
|
|
110
|
+
style: {
|
|
111
|
+
opacity: 0.65,
|
|
112
|
+
transform: open ? "scaleY(-1)" : "none",
|
|
113
|
+
transition: "transform 0.22s ease"
|
|
114
|
+
},
|
|
115
|
+
children: /* @__PURE__ */ jsx("path", { d: "M6 9l6 6 6-6" })
|
|
116
|
+
}
|
|
117
|
+
) : null;
|
|
118
|
+
return /* @__PURE__ */ jsxs(
|
|
119
|
+
"span",
|
|
120
|
+
{
|
|
121
|
+
ref: wrapperRef,
|
|
122
|
+
className: "hidden md:inline-flex items-stretch relative border border-doc-template-faint",
|
|
123
|
+
style: { ...wrapperBase, borderRadius: 4 },
|
|
124
|
+
title: dropdown ? void 0 : `${label} ${version}`,
|
|
125
|
+
children: [
|
|
126
|
+
/* @__PURE__ */ jsx(
|
|
127
|
+
"span",
|
|
128
|
+
{
|
|
129
|
+
className: "inline-flex items-center text-doc-template-muted",
|
|
130
|
+
style: labelSegStyle,
|
|
131
|
+
children: label
|
|
132
|
+
}
|
|
133
|
+
),
|
|
134
|
+
dropdown ? /* @__PURE__ */ jsxs(
|
|
135
|
+
"button",
|
|
136
|
+
{
|
|
137
|
+
type: "button",
|
|
138
|
+
onClick: (e) => {
|
|
139
|
+
e.preventDefault();
|
|
140
|
+
e.stopPropagation();
|
|
141
|
+
setOpen((o) => !o);
|
|
142
|
+
},
|
|
143
|
+
"aria-haspopup": "listbox",
|
|
144
|
+
"aria-expanded": open,
|
|
145
|
+
title: `Switch ${label} version (current v${displayVersion})`,
|
|
146
|
+
className: "text-doc-template-ink hover:bg-doc-template-search",
|
|
147
|
+
style: versionSegStyle,
|
|
148
|
+
children: [
|
|
149
|
+
"v",
|
|
150
|
+
displayVersion,
|
|
151
|
+
chevron
|
|
152
|
+
]
|
|
153
|
+
}
|
|
154
|
+
) : /* @__PURE__ */ jsxs(
|
|
155
|
+
"span",
|
|
156
|
+
{
|
|
157
|
+
className: "inline-flex items-center text-doc-template-ink",
|
|
158
|
+
style: versionSegStyle,
|
|
159
|
+
children: [
|
|
160
|
+
"v",
|
|
161
|
+
displayVersion
|
|
162
|
+
]
|
|
163
|
+
}
|
|
164
|
+
),
|
|
165
|
+
dropdown && open && manifest && (() => {
|
|
166
|
+
const aliasEntries = manifest.aliases ? Object.entries(manifest.aliases) : [];
|
|
167
|
+
const versionEntries = manifest.versions ?? [];
|
|
168
|
+
const ENTRY_STEP = 0.03;
|
|
169
|
+
const ENTRY_BASE = 0.13;
|
|
170
|
+
let idx = 0;
|
|
171
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
172
|
+
/* @__PURE__ */ jsxs(
|
|
173
|
+
"svg",
|
|
174
|
+
{
|
|
175
|
+
width: "14",
|
|
176
|
+
height: "11",
|
|
177
|
+
viewBox: "0 0 14 11",
|
|
178
|
+
"aria-hidden": true,
|
|
179
|
+
style: {
|
|
180
|
+
position: "absolute",
|
|
181
|
+
top: "calc(100% + 4.5px)",
|
|
182
|
+
right: 4,
|
|
183
|
+
zIndex: 81,
|
|
184
|
+
display: "block",
|
|
185
|
+
pointerEvents: "none",
|
|
186
|
+
animation: "popover-wedge-in 0.24s ease both"
|
|
187
|
+
},
|
|
188
|
+
children: [
|
|
189
|
+
/* @__PURE__ */ jsx("path", { d: "M0 11 L7 1 L14 11", stroke: "var(--color-doc-template-faint)", strokeWidth: "1", fill: "none" }),
|
|
190
|
+
/* @__PURE__ */ jsx("path", { d: "M1 11 L7 2 L13 11 Z", fill: "var(--color-doc-template-bg)" })
|
|
191
|
+
]
|
|
192
|
+
}
|
|
193
|
+
),
|
|
194
|
+
/* @__PURE__ */ jsxs(
|
|
195
|
+
"div",
|
|
196
|
+
{
|
|
197
|
+
role: "listbox",
|
|
198
|
+
"aria-label": `Past ${label} versions`,
|
|
199
|
+
className: "absolute border border-doc-template-faint bg-doc-template-bg",
|
|
200
|
+
style: {
|
|
201
|
+
top: "calc(100% + 14px)",
|
|
202
|
+
left: 0,
|
|
203
|
+
minWidth: 220,
|
|
204
|
+
maxHeight: "min(360px, 60vh)",
|
|
205
|
+
overflowY: "auto",
|
|
206
|
+
borderRadius: 12,
|
|
207
|
+
// Drop shadow + a "negative" 0-blur shadow above using the page bg
|
|
208
|
+
// color: it paints a bg-colored band into the strip between the
|
|
209
|
+
// popover top and the navbar's bottom border, masking the navbar's
|
|
210
|
+
// 1px box-shadow in the popover's column so the two don't visually
|
|
211
|
+
// collide.
|
|
212
|
+
boxShadow: "0 6px 24px rgb(0 0 0 / 0.10), 0 -5px 3px 0 var(--color-doc-template-bg)",
|
|
213
|
+
padding: 4,
|
|
214
|
+
zIndex: 80,
|
|
215
|
+
fontFamily: "var(--font-doc-template-mono)",
|
|
216
|
+
fontSize: 11,
|
|
217
|
+
animation: "popover-in 0.28s ease both",
|
|
218
|
+
animationDelay: "0.04s",
|
|
219
|
+
transformOrigin: "top right"
|
|
220
|
+
},
|
|
221
|
+
children: [
|
|
222
|
+
aliasEntries.length > 0 && /* @__PURE__ */ jsx(
|
|
223
|
+
"div",
|
|
224
|
+
{
|
|
225
|
+
style: {
|
|
226
|
+
padding: "4px 6px 2px",
|
|
227
|
+
opacity: 0.55,
|
|
228
|
+
fontSize: 9,
|
|
229
|
+
letterSpacing: "0.08em",
|
|
230
|
+
textTransform: "uppercase",
|
|
231
|
+
animation: "popover-entry-in 0.28s ease both",
|
|
232
|
+
animationDelay: `${ENTRY_BASE + idx++ * ENTRY_STEP}s`
|
|
233
|
+
},
|
|
234
|
+
children: "Aliases"
|
|
235
|
+
}
|
|
236
|
+
),
|
|
237
|
+
aliasEntries.map(([name, url]) => /* @__PURE__ */ jsxs(
|
|
238
|
+
"a",
|
|
239
|
+
{
|
|
240
|
+
href: url,
|
|
241
|
+
className: "block text-doc-template-ink no-underline hover:bg-doc-template-search",
|
|
242
|
+
style: {
|
|
243
|
+
padding: "5px 8px",
|
|
244
|
+
borderRadius: 8,
|
|
245
|
+
animation: "popover-entry-in 0.28s ease both",
|
|
246
|
+
animationDelay: `${ENTRY_BASE + idx++ * ENTRY_STEP}s`
|
|
247
|
+
},
|
|
248
|
+
children: [
|
|
249
|
+
name,
|
|
250
|
+
name === "stable" && manifest.stable && /* @__PURE__ */ jsxs("span", { style: { opacity: 0.5, marginLeft: 6 }, children: [
|
|
251
|
+
"v",
|
|
252
|
+
manifest.stable
|
|
253
|
+
] }),
|
|
254
|
+
name === "latest" && manifest.current && /* @__PURE__ */ jsxs("span", { style: { opacity: 0.5, marginLeft: 6 }, children: [
|
|
255
|
+
"v",
|
|
256
|
+
manifest.current
|
|
257
|
+
] })
|
|
258
|
+
]
|
|
259
|
+
},
|
|
260
|
+
`alias-${name}`
|
|
261
|
+
)),
|
|
262
|
+
versionEntries.length > 0 && /* @__PURE__ */ jsx(
|
|
263
|
+
"div",
|
|
264
|
+
{
|
|
265
|
+
style: {
|
|
266
|
+
padding: "6px 6px 2px",
|
|
267
|
+
opacity: 0.55,
|
|
268
|
+
fontSize: 9,
|
|
269
|
+
letterSpacing: "0.08em",
|
|
270
|
+
textTransform: "uppercase",
|
|
271
|
+
animation: "popover-entry-in 0.28s ease both",
|
|
272
|
+
animationDelay: `${ENTRY_BASE + idx++ * ENTRY_STEP}s`
|
|
273
|
+
},
|
|
274
|
+
children: "Versions"
|
|
275
|
+
}
|
|
276
|
+
),
|
|
277
|
+
versionEntries.map((v) => {
|
|
278
|
+
const isCurrent = v.version === manifest.current;
|
|
279
|
+
return /* @__PURE__ */ jsxs(
|
|
280
|
+
"a",
|
|
281
|
+
{
|
|
282
|
+
href: v.url,
|
|
283
|
+
className: "text-doc-template-ink no-underline hover:bg-doc-template-search flex items-baseline justify-between gap-3",
|
|
284
|
+
style: {
|
|
285
|
+
padding: "5px 8px",
|
|
286
|
+
borderRadius: 8,
|
|
287
|
+
fontWeight: isCurrent ? 700 : 400,
|
|
288
|
+
background: isCurrent ? "color-mix(in srgb, var(--color-doc-template-accent) 12%, transparent)" : void 0,
|
|
289
|
+
animation: "popover-entry-in 0.28s ease both",
|
|
290
|
+
animationDelay: `${ENTRY_BASE + idx++ * ENTRY_STEP}s`
|
|
291
|
+
},
|
|
292
|
+
children: [
|
|
293
|
+
/* @__PURE__ */ jsxs("span", { children: [
|
|
294
|
+
"v",
|
|
295
|
+
v.version,
|
|
296
|
+
isCurrent && /* @__PURE__ */ jsx("span", { style: { opacity: 0.55, marginLeft: 6 }, children: "current" })
|
|
297
|
+
] }),
|
|
298
|
+
v.date && /* @__PURE__ */ jsx("span", { style: { opacity: 0.5, fontVariantNumeric: "tabular-nums", fontSize: 10 }, children: v.date })
|
|
299
|
+
]
|
|
300
|
+
},
|
|
301
|
+
v.version
|
|
302
|
+
);
|
|
303
|
+
})
|
|
304
|
+
]
|
|
305
|
+
}
|
|
306
|
+
)
|
|
307
|
+
] });
|
|
308
|
+
})()
|
|
309
|
+
]
|
|
310
|
+
}
|
|
311
|
+
);
|
|
312
|
+
}
|
|
313
|
+
export {
|
|
314
|
+
VersionBadge
|
|
315
|
+
};
|
package/dist/index.d.ts
CHANGED
|
@@ -18,7 +18,7 @@ import { TabDef as _TabDef } from './lib/tabs';
|
|
|
18
18
|
* })
|
|
19
19
|
*/
|
|
20
20
|
export { siteConfig, defineSiteConfig, type SiteConfig, type VersionChip, } from './site-config';
|
|
21
|
-
export { pages, groupedPages, groupedVisiblePages, initNavigation, getAdjacentPages, type PageMeta, type PageFrontmatter, type PageModule, type NavGroup, } from './lib/navigation';
|
|
21
|
+
export { pages, groupedPages, groupedVisiblePages, initNavigation, getAdjacentPages, normalizePath, findPage, type PageMeta, type PageFrontmatter, type PageModule, type NavGroup, } from './lib/navigation';
|
|
22
22
|
export { searchIndex, rawMarkdown, initSearchIndex, search, type SearchEntry, type SearchHit, } from './lib/search-index';
|
|
23
23
|
export { searchPages, defaultResults, type SearchResult, type SubResult, } from './lib/pagefind-search';
|
|
24
24
|
export { TABS, initTabs, tabForUrl, urlInTab, type TabDef } from './lib/tabs';
|
|
@@ -41,6 +41,7 @@ export { ThemeProvider, useTheme, type Theme } from './components/ThemeProvider'
|
|
|
41
41
|
export { ThemeToggle } from './components/ThemeToggle';
|
|
42
42
|
export { TOC } from './components/TOC';
|
|
43
43
|
export { Topbar } from './components/Topbar';
|
|
44
|
+
export { VersionBadge, type VersionBadgeProps } from './components/VersionBadge';
|
|
44
45
|
export { Layout, useMerge } from './renderer/Layout';
|
|
45
46
|
export interface InitDocsOptions {
|
|
46
47
|
/** Site branding, URLs, version chips, git hash. */
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { defineSiteConfig } from "./site-config.js";
|
|
2
2
|
import { siteConfig } from "./site-config.js";
|
|
3
3
|
import { initNavigation } from "./lib/navigation.js";
|
|
4
|
-
import { getAdjacentPages, groupedPages, groupedVisiblePages, pages } from "./lib/navigation.js";
|
|
4
|
+
import { findPage, getAdjacentPages, groupedPages, groupedVisiblePages, normalizePath, pages } from "./lib/navigation.js";
|
|
5
5
|
import { initSearchIndex } from "./lib/search-index.js";
|
|
6
6
|
import { rawMarkdown, search, searchIndex } from "./lib/search-index.js";
|
|
7
7
|
import { defaultResults, searchPages } from "./lib/pagefind-search.js";
|
|
@@ -26,6 +26,7 @@ import { ThemeProvider, useTheme } from "./components/ThemeProvider.js";
|
|
|
26
26
|
import { ThemeToggle } from "./components/ThemeToggle.js";
|
|
27
27
|
import { TOC } from "./components/TOC.js";
|
|
28
28
|
import { Topbar } from "./components/Topbar.js";
|
|
29
|
+
import { VersionBadge } from "./components/VersionBadge.js";
|
|
29
30
|
import { Layout, useMerge } from "./renderer/Layout.js";
|
|
30
31
|
function initDocs(opts) {
|
|
31
32
|
defineSiteConfig(opts.site);
|
|
@@ -52,9 +53,11 @@ export {
|
|
|
52
53
|
ThemeProvider,
|
|
53
54
|
ThemeToggle,
|
|
54
55
|
Topbar,
|
|
56
|
+
VersionBadge,
|
|
55
57
|
defaultResults,
|
|
56
58
|
defineSiteConfig,
|
|
57
59
|
docKey,
|
|
60
|
+
findPage,
|
|
58
61
|
getAdjacentPages,
|
|
59
62
|
groupedPages,
|
|
60
63
|
groupedVisiblePages,
|
|
@@ -63,6 +66,7 @@ export {
|
|
|
63
66
|
initSearchIndex,
|
|
64
67
|
initTabs,
|
|
65
68
|
mdxComponents,
|
|
69
|
+
normalizePath,
|
|
66
70
|
pages,
|
|
67
71
|
rawMarkdown,
|
|
68
72
|
search,
|
package/dist/lib/navigation.d.ts
CHANGED
|
@@ -29,6 +29,9 @@ export interface PageFrontmatter {
|
|
|
29
29
|
draft?: boolean;
|
|
30
30
|
hidden?: boolean;
|
|
31
31
|
noindex?: boolean;
|
|
32
|
+
/** Shorthand for an internal developer note (studio's flag): implies
|
|
33
|
+
* both `hidden: true` and `noindex: true`. */
|
|
34
|
+
dev?: boolean;
|
|
32
35
|
tocLevel?: 2 | 3;
|
|
33
36
|
fullscreen?: boolean;
|
|
34
37
|
}
|
|
@@ -54,6 +57,18 @@ export declare const groupedPages: NavGroup[];
|
|
|
54
57
|
/** Same shape, but filtered to only-visible pages. Equivalent to
|
|
55
58
|
* `groupedPages` when no page declares `hidden: true`. */
|
|
56
59
|
export declare const groupedVisiblePages: NavGroup[];
|
|
60
|
+
/** Normalize a pathname for comparison against `PageMeta.path`: strip any
|
|
61
|
+
* query/hash and drop a trailing slash (except for root `/`). Vike's
|
|
62
|
+
* prerender and client routing can disagree on the trailing slash — e.g.
|
|
63
|
+
* a `/develop` prerender hydrating at `/develop/` — and a raw `===` match
|
|
64
|
+
* then resolves the page on the server but not the client, which renders
|
|
65
|
+
* *different* DOM (breadcrumb, `aria-current`) on each side and trips
|
|
66
|
+
* React hydration. Normalizing both sides keeps SSR and hydration in step. */
|
|
67
|
+
export declare function normalizePath(url: string): string;
|
|
68
|
+
/** Resolve the `PageMeta` for a pathname, tolerant of a trailing slash.
|
|
69
|
+
* Prefer this over `pages.find(p => p.path === urlPathname)` anywhere the
|
|
70
|
+
* result drives rendered output, so server and client agree. */
|
|
71
|
+
export declare function findPage(urlPathname: string): PageMeta | undefined;
|
|
57
72
|
/**
|
|
58
73
|
* Populate the navigation singletons from the site's eager page glob:
|
|
59
74
|
*
|
package/dist/lib/navigation.js
CHANGED
|
@@ -2,6 +2,16 @@ const pages = [];
|
|
|
2
2
|
const groupedPages = [];
|
|
3
3
|
const groupedVisiblePages = [];
|
|
4
4
|
let sectionOrderList = [];
|
|
5
|
+
function normalizePath(url) {
|
|
6
|
+
if (!url) return "/";
|
|
7
|
+
const clean = url.split("?")[0].split("#")[0];
|
|
8
|
+
if (clean === "/") return "/";
|
|
9
|
+
return clean.replace(/\/+$/, "") || "/";
|
|
10
|
+
}
|
|
11
|
+
function findPage(urlPathname) {
|
|
12
|
+
const norm = normalizePath(urlPathname);
|
|
13
|
+
return pages.find((p) => p.path === norm);
|
|
14
|
+
}
|
|
5
15
|
function groupPages(items) {
|
|
6
16
|
const map = /* @__PURE__ */ new Map();
|
|
7
17
|
for (const p of items) {
|
|
@@ -18,6 +28,7 @@ function initNavigation(modules, sectionOrder = []) {
|
|
|
18
28
|
const fm = mod.frontmatter ?? {};
|
|
19
29
|
const dir = filePath.replace(/^.*?\bpages\//, "").replace(/\/\+Page\.mdx$/, "");
|
|
20
30
|
const path = dir === "index" ? "/" : `/${dir}`;
|
|
31
|
+
const isDev = fm.dev === true;
|
|
21
32
|
return {
|
|
22
33
|
path,
|
|
23
34
|
title: fm.title ?? dir,
|
|
@@ -25,8 +36,8 @@ function initNavigation(modules, sectionOrder = []) {
|
|
|
25
36
|
order: fm.order ?? 99,
|
|
26
37
|
description: fm.description,
|
|
27
38
|
draft: fm.draft === true,
|
|
28
|
-
hidden: fm.hidden === true,
|
|
29
|
-
noindex: fm.noindex === true,
|
|
39
|
+
hidden: fm.hidden === true || isDev,
|
|
40
|
+
noindex: fm.noindex === true || isDev,
|
|
30
41
|
tocLevel: fm.tocLevel,
|
|
31
42
|
fullscreen: fm.fullscreen === true
|
|
32
43
|
};
|
|
@@ -39,9 +50,10 @@ function initNavigation(modules, sectionOrder = []) {
|
|
|
39
50
|
groupedVisiblePages.push(...groupPages(pages.filter((p) => !p.hidden)));
|
|
40
51
|
}
|
|
41
52
|
function getAdjacentPages(path, opts = {}) {
|
|
42
|
-
const
|
|
53
|
+
const norm = normalizePath(path);
|
|
54
|
+
const here = pages.find((p) => p.path === norm);
|
|
43
55
|
const list = opts.includeHidden || here?.hidden ? pages : pages.filter((p) => !p.hidden);
|
|
44
|
-
const idx = list.findIndex((p) => p.path ===
|
|
56
|
+
const idx = list.findIndex((p) => p.path === norm);
|
|
45
57
|
return {
|
|
46
58
|
current: idx >= 0 ? list[idx] : null,
|
|
47
59
|
prev: idx > 0 ? list[idx - 1] : null,
|
|
@@ -49,9 +61,11 @@ function getAdjacentPages(path, opts = {}) {
|
|
|
49
61
|
};
|
|
50
62
|
}
|
|
51
63
|
export {
|
|
64
|
+
findPage,
|
|
52
65
|
getAdjacentPages,
|
|
53
66
|
groupedPages,
|
|
54
67
|
groupedVisiblePages,
|
|
55
68
|
initNavigation,
|
|
69
|
+
normalizePath,
|
|
56
70
|
pages
|
|
57
71
|
};
|
package/dist/renderer/Layout.js
CHANGED
|
@@ -9,14 +9,14 @@ import { TOC } from "../components/TOC.js";
|
|
|
9
9
|
import { DocFooter } from "../components/DocFooter.js";
|
|
10
10
|
import { SearchPalette } from "../components/SearchPalette.js";
|
|
11
11
|
import { mdxComponents } from "../components/mdx-components.js";
|
|
12
|
-
import {
|
|
12
|
+
import { findPage } from "../lib/navigation.js";
|
|
13
13
|
import { siteConfig } from "../site-config.js";
|
|
14
14
|
const SPRING = "cubic-bezier(0.4, 0.7, 0.3, 1)";
|
|
15
15
|
const MergeContext = createContext(false);
|
|
16
16
|
const useMerge = () => useContext(MergeContext);
|
|
17
17
|
function PageBreadcrumb() {
|
|
18
18
|
const { urlPathname } = usePageContext();
|
|
19
|
-
const current =
|
|
19
|
+
const current = findPage(urlPathname);
|
|
20
20
|
const merged = useMerge();
|
|
21
21
|
if (!current) return null;
|
|
22
22
|
return /* @__PURE__ */ jsxs(
|
|
@@ -81,7 +81,7 @@ function HeadSync() {
|
|
|
81
81
|
const { urlPathname } = usePageContext();
|
|
82
82
|
useEffect(() => {
|
|
83
83
|
if (typeof document === "undefined") return;
|
|
84
|
-
const current =
|
|
84
|
+
const current = findPage(urlPathname);
|
|
85
85
|
document.title = current ? `${current.title} — ${siteConfig.brand}` : siteConfig.brand;
|
|
86
86
|
const desc = current?.description ?? "";
|
|
87
87
|
let tag = document.querySelector('meta[name="description"]');
|
|
@@ -111,7 +111,7 @@ function HeadSync() {
|
|
|
111
111
|
}
|
|
112
112
|
function Layout({ children }) {
|
|
113
113
|
const { urlPathname } = usePageContext();
|
|
114
|
-
const current =
|
|
114
|
+
const current = findPage(urlPathname);
|
|
115
115
|
const isFullscreen = current?.fullscreen === true;
|
|
116
116
|
const [searchOpen, setSearchOpen] = useState(false);
|
|
117
117
|
const [searchQuery, setSearchQuery] = useState("");
|
|
@@ -3,14 +3,14 @@ import ReactDOMServer from "react-dom/server";
|
|
|
3
3
|
import { Layout } from "./Layout.js";
|
|
4
4
|
import { PageContextProvider } from "vike-react/usePageContext";
|
|
5
5
|
import { dangerouslySkipEscape, escapeInject } from "vike/server";
|
|
6
|
-
import {
|
|
6
|
+
import { findPage } from "../lib/navigation.js";
|
|
7
7
|
import { siteConfig } from "../site-config.js";
|
|
8
8
|
async function onRenderHtml(pageContext) {
|
|
9
9
|
const { Page, pageProps, urlPathname } = pageContext;
|
|
10
10
|
const html = ReactDOMServer.renderToString(
|
|
11
11
|
/* @__PURE__ */ jsx(PageContextProvider, { pageContext, children: /* @__PURE__ */ jsx(Layout, { children: /* @__PURE__ */ jsx(Page, { ...pageProps }) }) })
|
|
12
12
|
);
|
|
13
|
-
const current =
|
|
13
|
+
const current = findPage(urlPathname);
|
|
14
14
|
const title = current ? `${current.title} — ${siteConfig.brand}` : siteConfig.brand;
|
|
15
15
|
const description = current?.description ?? "";
|
|
16
16
|
const mdHref = current && !current.noindex ? current.path === "/" ? "/index.md" : `${current.path}.md` : null;
|
package/dist/site-config.d.ts
CHANGED
|
@@ -55,6 +55,10 @@ export interface SiteConfig {
|
|
|
55
55
|
* "Edit this page" link (`<docsRepoUrl>/edit/<docsBranch>/<docsPagesPath>/…`).
|
|
56
56
|
* Defaults to 'docs/pages'. */
|
|
57
57
|
docsPagesPath?: string;
|
|
58
|
+
/** Topbar theme control style. `'cycle'` (default) is a single button
|
|
59
|
+
* that steps light → system → dark; `'segmented'` is the three-button
|
|
60
|
+
* slider with a sliding indicator (the uikit/dreamlake docs style). */
|
|
61
|
+
themeToggle?: 'cycle' | 'segmented';
|
|
58
62
|
}
|
|
59
63
|
export declare const siteConfig: SiteConfig;
|
|
60
64
|
/** Merge site-provided values into the singleton (mutates in place). */
|
package/dist/site-config.js
CHANGED
package/package.json
CHANGED
|
@@ -31,3 +31,14 @@ COREPACK_INTEGRITY_KEYS = "0"
|
|
|
31
31
|
|
|
32
32
|
[context.branch-deploy]
|
|
33
33
|
# Applies to every non-production branch push.
|
|
34
|
+
|
|
35
|
+
# ─── Version switcher (VersionBadge) ─────────────────────────────────
|
|
36
|
+
# The version-switcher dropdown on old v/* branch deploys fetches the
|
|
37
|
+
# production manifest cross-origin so its list never goes stale — that
|
|
38
|
+
# needs a CORS header on /versions.json.
|
|
39
|
+
|
|
40
|
+
[[headers]]
|
|
41
|
+
for = "/versions.json"
|
|
42
|
+
|
|
43
|
+
[headers.values]
|
|
44
|
+
Access-Control-Allow-Origin = "*"
|