@dreamlake/dockit 0.1.1 → 0.2.1

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.
@@ -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 { pages } from "../lib/navigation.js";
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 = pages.find((p) => p.path === urlPathname);
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. */