@eqtylab/docs 0.3.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.
Files changed (94) hide show
  1. package/README.md +201 -0
  2. package/dist/chunk-55J6XMHW.js +3 -0
  3. package/dist/chunk-55J6XMHW.js.map +1 -0
  4. package/dist/chunk-ATIOPYKE.js +102 -0
  5. package/dist/chunk-ATIOPYKE.js.map +1 -0
  6. package/dist/chunk-GSSSQTEV.js +51 -0
  7. package/dist/chunk-GSSSQTEV.js.map +1 -0
  8. package/dist/chunk-IWKZQ4CW.js +68 -0
  9. package/dist/chunk-IWKZQ4CW.js.map +1 -0
  10. package/dist/chunk-K7PJRTK3.js +113 -0
  11. package/dist/chunk-K7PJRTK3.js.map +1 -0
  12. package/dist/chunk-VJN3HXKM.js +59 -0
  13. package/dist/chunk-VJN3HXKM.js.map +1 -0
  14. package/dist/chunk-ZZ45WAVR.js +20 -0
  15. package/dist/chunk-ZZ45WAVR.js.map +1 -0
  16. package/dist/config.d.ts +78 -0
  17. package/dist/config.js +3 -0
  18. package/dist/config.js.map +1 -0
  19. package/dist/dev.d.ts +6 -0
  20. package/dist/dev.js +84 -0
  21. package/dist/dev.js.map +1 -0
  22. package/dist/env.d.ts +17 -0
  23. package/dist/env.js +3 -0
  24. package/dist/env.js.map +1 -0
  25. package/dist/index.d.ts +12 -0
  26. package/dist/index.js +421 -0
  27. package/dist/index.js.map +1 -0
  28. package/dist/internal/assert-mdx-only.d.ts +1 -0
  29. package/dist/internal/microlighter-grammars.d.ts +3 -0
  30. package/dist/internal/pagefind.d.ts +2 -0
  31. package/dist/internal/rehype-base-url.d.ts +5 -0
  32. package/dist/internal/rehype-base-url.js +3 -0
  33. package/dist/internal/rehype-base-url.js.map +1 -0
  34. package/dist/internal/rehype-code-fence.d.ts +1 -0
  35. package/dist/internal/rehype-prose-scope.d.ts +1 -0
  36. package/dist/internal/rehype-table-columns.d.ts +1 -0
  37. package/dist/internal/scan-consumer-pages.d.ts +7 -0
  38. package/dist/internal/virtual-config.d.ts +3 -0
  39. package/dist/loaders.d.ts +20 -0
  40. package/dist/loaders.js +85 -0
  41. package/dist/loaders.js.map +1 -0
  42. package/dist/nav.d.ts +57 -0
  43. package/dist/nav.js +222 -0
  44. package/dist/nav.js.map +1 -0
  45. package/dist/paths.d.ts +28 -0
  46. package/dist/paths.js +3 -0
  47. package/dist/paths.js.map +1 -0
  48. package/dist/runtime/chrome/GlobalSearch.module.css +26 -0
  49. package/dist/runtime/chrome/GlobalSearch.tsx +422 -0
  50. package/dist/runtime/chrome/Header.astro +105 -0
  51. package/dist/runtime/chrome/LinkIcon.astro +35 -0
  52. package/dist/runtime/chrome/NavDrawer.astro +60 -0
  53. package/dist/runtime/chrome/NavTree.astro +112 -0
  54. package/dist/runtime/chrome/NotFoundBody.tsx +12 -0
  55. package/dist/runtime/chrome/PageFooter.astro +80 -0
  56. package/dist/runtime/chrome/Prose.astro +169 -0
  57. package/dist/runtime/chrome/Sidebar.astro +21 -0
  58. package/dist/runtime/chrome/TableOfContents.astro +86 -0
  59. package/dist/runtime/chrome/ThemeToggle.tsx +85 -0
  60. package/dist/runtime/chrome/TocElbow.astro +30 -0
  61. package/dist/runtime/chrome/TocList.astro +43 -0
  62. package/dist/runtime/components/AlertBridge.astro +16 -0
  63. package/dist/runtime/components/CodeFence.astro +38 -0
  64. package/dist/runtime/components/CodeFenceBridge.astro +20 -0
  65. package/dist/runtime/components/Link.astro +21 -0
  66. package/dist/runtime/components/TableBridge.astro +18 -0
  67. package/dist/runtime/components/index.ts +2 -0
  68. package/dist/runtime/layouts/DocsPage.astro +50 -0
  69. package/dist/runtime/layouts/DocsShell.astro +92 -0
  70. package/dist/runtime/lib/mdx-components.ts +43 -0
  71. package/dist/runtime/lib/nav-data.ts +74 -0
  72. package/dist/runtime/lib/summary.ts +57 -0
  73. package/dist/runtime/lib/theme.ts +84 -0
  74. package/dist/runtime/routes/docs-md.ts +33 -0
  75. package/dist/runtime/routes/docs.astro +92 -0
  76. package/dist/runtime/routes/llms-txt.ts +38 -0
  77. package/dist/runtime/routes/not-found.astro +16 -0
  78. package/dist/runtime/scripts/eq-copy.ts +27 -0
  79. package/dist/runtime/scripts/eq-highlight.ts +24 -0
  80. package/dist/runtime/scripts/eq-nav-drawer.ts +31 -0
  81. package/dist/runtime/scripts/eq-nav-group.ts +52 -0
  82. package/dist/runtime/scripts/eq-toc.ts +166 -0
  83. package/dist/runtime/styles/chrome.css +30 -0
  84. package/dist/runtime/styles/docs.css +21 -0
  85. package/dist/runtime/styles/prose.css +102 -0
  86. package/dist/runtime/styles/theme.css +2 -0
  87. package/dist/runtime/styles/utilities.css +38 -0
  88. package/dist/schema.d.ts +110 -0
  89. package/dist/schema.js +3 -0
  90. package/dist/schema.js.map +1 -0
  91. package/dist/types.d.ts +60 -0
  92. package/dist/types.js +3 -0
  93. package/dist/types.js.map +1 -0
  94. package/package.json +127 -0
@@ -0,0 +1,85 @@
1
+ import { groupSchema, docsSchema } from './chunk-IWKZQ4CW.js';
2
+ import { readFile } from 'fs/promises';
3
+ import path from 'path';
4
+ import { fileURLToPath } from 'url';
5
+ import { defineCollection } from 'astro:content';
6
+ import { glob } from 'astro/loaders';
7
+ import { globSync } from 'tinyglobby';
8
+ import { parse } from 'yaml';
9
+
10
+ var GROUP_GLOB = "**/_group.{yaml,yml,json}";
11
+ var ROOT_GROUP_ID = "~root";
12
+ function docsLoader(options = {}) {
13
+ const base = options.base ?? "content/docs";
14
+ return glob({
15
+ base: `./src/${base}`,
16
+ pattern: ["**/*.mdx", "!**/_*", "!**/_*/**"]
17
+ });
18
+ }
19
+ function groupsLoader(options = {}) {
20
+ const base = options.base ?? "content/docs";
21
+ return {
22
+ name: "@eqtylab/docs:groups",
23
+ async load({ store, parseData, generateDigest, watcher, logger, config }) {
24
+ const rootUrl = new URL(`./${base}/`, config.srcDir);
25
+ const rootDir = fileURLToPath(rootUrl);
26
+ const files = globSync([GROUP_GLOB], { cwd: rootDir, absolute: false });
27
+ const untouched = new Set(store.keys());
28
+ for (const rel of files) {
29
+ const dir = path.posix.dirname(rel.split(path.sep).join("/"));
30
+ const id = dir === "." ? ROOT_GROUP_ID : dir;
31
+ const abs = path.join(rootDir, rel);
32
+ let text;
33
+ try {
34
+ text = await readFile(abs, "utf8");
35
+ } catch (err) {
36
+ logger.warn(`Could not read ${rel}: ${err.message}`);
37
+ continue;
38
+ }
39
+ const digest = generateDigest(text);
40
+ if (store.get(id)?.digest === digest) {
41
+ untouched.delete(id);
42
+ continue;
43
+ }
44
+ let raw;
45
+ try {
46
+ raw = rel.endsWith(".json") ? JSON.parse(text) : parse(text);
47
+ } catch (err) {
48
+ throw new Error(`[@eqtylab/docs] Could not parse ${rel}: ${err.message}`);
49
+ }
50
+ const data = await parseData({
51
+ id,
52
+ data: raw ?? {},
53
+ filePath: path.relative(fileURLToPath(config.root), abs)
54
+ });
55
+ store.set({
56
+ id,
57
+ data,
58
+ digest,
59
+ filePath: path.relative(fileURLToPath(config.root), abs)
60
+ });
61
+ untouched.delete(id);
62
+ }
63
+ for (const id of untouched) store.delete(id);
64
+ if (watcher) {
65
+ watcher.add(rootDir);
66
+ }
67
+ }
68
+ };
69
+ }
70
+ function docsCollections(options = {}) {
71
+ return {
72
+ docs: defineCollection({
73
+ loader: docsLoader(options),
74
+ schema: docsSchema()
75
+ }),
76
+ docsGroups: defineCollection({
77
+ loader: groupsLoader(options),
78
+ schema: groupSchema()
79
+ })
80
+ };
81
+ }
82
+
83
+ export { ROOT_GROUP_ID, docsCollections, docsLoader, groupsLoader };
84
+ //# sourceMappingURL=loaders.js.map
85
+ //# sourceMappingURL=loaders.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/loaders.ts"],"names":["parseYaml"],"mappings":"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","file":"loaders.js","sourcesContent":["/** Astro cannot inject collections from an integration, so these are imported from the consumer's `content.config.ts`. */\nimport { readFile } from 'node:fs/promises';\nimport path from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport { defineCollection } from 'astro:content';\nimport { glob } from 'astro/loaders';\nimport type { Loader, LoaderContext } from 'astro/loaders';\nimport { globSync } from 'tinyglobby';\nimport { parse as parseYaml } from 'yaml';\n\nimport { docsSchema, groupSchema } from './schema.ts';\n\nconst GROUP_GLOB = '**/_group.{yaml,yml,json}';\n\n/** Sentinel id for the content root's own `_group.yaml`; '' is not a valid store key. */\nexport const ROOT_GROUP_ID = '~root';\n\n/**\n * MDX only; stray `.md` files fail in `assertMdxOnly`. The `_*` negation is\n * required: the glob loader has no underscore skipping, so `_group.yaml` would become a page.\n */\nexport function docsLoader(options: { base?: string } = {}): Loader {\n const base = options.base ?? 'content/docs';\n return glob({\n base: `./src/${base}`,\n pattern: ['**/*.mdx', '!**/_*', '!**/_*/**'],\n });\n}\n\nexport function groupsLoader(options: { base?: string } = {}): Loader {\n const base = options.base ?? 'content/docs';\n\n return {\n name: '@eqtylab/docs:groups',\n\n async load({ store, parseData, generateDigest, watcher, logger, config }: LoaderContext) {\n const rootUrl = new URL(`./${base}/`, config.srcDir);\n const rootDir = fileURLToPath(rootUrl);\n\n const files = globSync([GROUP_GLOB], { cwd: rootDir, absolute: false });\n const untouched = new Set(store.keys());\n\n for (const rel of files) {\n const dir = path.posix.dirname(rel.split(path.sep).join('/'));\n const id = dir === '.' ? ROOT_GROUP_ID : dir;\n const abs = path.join(rootDir, rel);\n\n let text: string;\n try {\n text = await readFile(abs, 'utf8');\n } catch (err) {\n logger.warn(`Could not read ${rel}: ${(err as Error).message}`);\n continue;\n }\n\n const digest = generateDigest(text);\n if (store.get(id)?.digest === digest) {\n untouched.delete(id);\n continue;\n }\n\n let raw: unknown;\n try {\n raw = rel.endsWith('.json') ? JSON.parse(text) : parseYaml(text);\n } catch (err) {\n throw new Error(`[@eqtylab/docs] Could not parse ${rel}: ${(err as Error).message}`);\n }\n\n const data = await parseData({\n id,\n data: (raw ?? {}) as Record<string, unknown>,\n filePath: path.relative(fileURLToPath(config.root), abs),\n });\n\n store.set({\n id,\n data,\n digest,\n filePath: path.relative(fileURLToPath(config.root), abs),\n });\n untouched.delete(id);\n }\n\n // Anything left was deleted on disk.\n for (const id of untouched) store.delete(id);\n\n if (watcher) {\n watcher.add(rootDir);\n }\n },\n };\n}\n\n/** Both collections, ready to spread. */\nexport function docsCollections(options: { base?: string } = {}) {\n return {\n docs: defineCollection({\n loader: docsLoader(options),\n schema: docsSchema(),\n }),\n docsGroups: defineCollection({\n loader: groupsLoader(options),\n schema: groupSchema(),\n }),\n };\n}\n"]}
package/dist/nav.d.ts ADDED
@@ -0,0 +1,57 @@
1
+ /**
2
+ * Pure nav-tree construction. Keep it free of fs and `astro:*` imports so it
3
+ * runs in Node and unit tests; prev/next and breadcrumbs derive from this tree.
4
+ */
5
+ import { type PathContext } from './paths.ts';
6
+ import type { DocsBadge, DocsNavEntry, NavNode, TocNode } from './types.ts';
7
+ export type SortMode = 'alpha' | 'filename' | 'manual';
8
+ export interface GroupConfig {
9
+ label?: string;
10
+ icon?: string;
11
+ order: string[];
12
+ sort?: SortMode;
13
+ collapsed?: boolean;
14
+ hidden: boolean;
15
+ badge?: DocsBadge;
16
+ links: Array<{
17
+ label: string;
18
+ href: string;
19
+ external?: boolean;
20
+ icon?: string;
21
+ badge?: DocsBadge;
22
+ attrs: Record<string, string | number | boolean>;
23
+ }>;
24
+ }
25
+ export interface BuildNavOptions {
26
+ entries: DocsNavEntry[];
27
+ /** Keyed by directory relative to the content root; '' is the root group. */
28
+ groups: Map<string, GroupConfig>;
29
+ /** `Astro.url.pathname`. */
30
+ currentPath: string;
31
+ paths: PathContext;
32
+ defaultCollapsed: boolean;
33
+ defaultSort: SortMode;
34
+ /** Appended after folder-derived nodes. Plugin-contributed sections land here. */
35
+ extra?: NavNode[];
36
+ onWarn?: (message: string) => void;
37
+ }
38
+ /** "getting-started" -> "Getting Started" */
39
+ export declare function titleCase(slug: string): string;
40
+ export declare function buildNavTree(options: BuildNavOptions): NavNode[];
41
+ /** Depth-first list of internal, linkable nodes. Drives prev/next. */
42
+ export declare function flattenNav(tree: NavNode[]): NavNode[];
43
+ export declare function prevNextFor(tree: NavNode[], currentPath: string): {
44
+ prev?: NavNode;
45
+ next?: NavNode;
46
+ };
47
+ /** Ancestor chain from the root down to the current page. */
48
+ export declare function breadcrumbsFor(tree: NavNode[], currentPath: string): NavNode[];
49
+ /** Nest a flat heading list into a tree, clamped to [minLevel, maxLevel]. */
50
+ export declare function buildTocTree(headings: Array<{
51
+ depth: number;
52
+ slug: string;
53
+ text: string;
54
+ }>, { minLevel, maxLevel }?: {
55
+ minLevel?: number;
56
+ maxLevel?: number;
57
+ }): TocNode[];
package/dist/nav.js ADDED
@@ -0,0 +1,222 @@
1
+ import { isActive, docsHref, isAncestor } from './chunk-VJN3HXKM.js';
2
+
3
+ // src/nav.ts
4
+ function titleCase(slug) {
5
+ return slug.split(/[-_]/).filter(Boolean).map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(" ");
6
+ }
7
+ function normalizeOrderToken(token) {
8
+ return token.trim().replace(/\/+$/, "").replace(/\.(md|mdx)$/i, "");
9
+ }
10
+ function byLocale(a, b) {
11
+ return a.localeCompare(b, void 0, { numeric: true, sensitivity: "base" });
12
+ }
13
+ function classify(entry) {
14
+ const id = entry.id;
15
+ const segments = id.split("/").filter(Boolean);
16
+ const fileBase = entry.filePath ? (entry.filePath.split("/").pop() ?? "").replace(/\.(md|mdx)$/i, "") : void 0;
17
+ const isIndex = fileBase === "index" || id === "index";
18
+ if (isIndex) {
19
+ const dir = id === "index" ? "" : segments.join("/");
20
+ return { entry, dir, name: segments.at(-1) ?? "", isIndex: true };
21
+ }
22
+ return {
23
+ entry,
24
+ dir: segments.slice(0, -1).join("/"),
25
+ name: segments.at(-1) ?? "",
26
+ isIndex: false
27
+ };
28
+ }
29
+ function ancestorsOf(dir) {
30
+ if (!dir) return [];
31
+ const parts = dir.split("/");
32
+ const out = [];
33
+ for (let i = 1; i <= parts.length; i++) out.push(parts.slice(0, i).join("/"));
34
+ return out;
35
+ }
36
+ function buildNavTree(options) {
37
+ const {
38
+ entries,
39
+ groups,
40
+ currentPath,
41
+ paths,
42
+ defaultCollapsed,
43
+ defaultSort,
44
+ extra = [],
45
+ onWarn
46
+ } = options;
47
+ const visible = entries.filter((e) => !e.draft);
48
+ const classified = visible.map(classify);
49
+ const indexOf = /* @__PURE__ */ new Map();
50
+ const filesIn = /* @__PURE__ */ new Map();
51
+ for (const c of classified) {
52
+ if (c.isIndex) {
53
+ indexOf.set(c.dir, c);
54
+ } else {
55
+ const list = filesIn.get(c.dir);
56
+ if (list) list.push(c);
57
+ else filesIn.set(c.dir, [c]);
58
+ }
59
+ }
60
+ const dirs = /* @__PURE__ */ new Set([""]);
61
+ for (const key of [...filesIn.keys(), ...indexOf.keys(), ...groups.keys()]) {
62
+ dirs.add(key);
63
+ for (const ancestor of ancestorsOf(key)) dirs.add(ancestor);
64
+ }
65
+ dirs.delete("~root");
66
+ const childDirsOf = /* @__PURE__ */ new Map();
67
+ for (const dir of dirs) {
68
+ if (!dir) continue;
69
+ const parent = dir.split("/").slice(0, -1).join("/");
70
+ const list = childDirsOf.get(parent);
71
+ if (list) list.push(dir);
72
+ else childDirsOf.set(parent, [dir]);
73
+ }
74
+ const groupFor = (dir) => groups.get(dir === "" ? "~root" : dir) ?? groups.get(dir);
75
+ const building = /* @__PURE__ */ new Set();
76
+ function pageNode(c) {
77
+ const href = docsHref(c.entry.id, paths);
78
+ return {
79
+ kind: "page",
80
+ name: c.name,
81
+ label: c.entry.label,
82
+ href,
83
+ icon: c.entry.icon,
84
+ badge: c.entry.badge,
85
+ current: isActive(currentPath, href),
86
+ inPath: isActive(currentPath, href)
87
+ };
88
+ }
89
+ function groupNode(dir) {
90
+ if (building.has(dir)) return null;
91
+ building.add(dir);
92
+ try {
93
+ const cfg = groupFor(dir);
94
+ const index = indexOf.get(dir);
95
+ const sortMode = cfg?.sort ?? defaultSort;
96
+ const pages = (filesIn.get(dir) ?? []).filter((c) => !c.entry.hidden).map(pageNode);
97
+ const subgroups = (childDirsOf.get(dir) ?? []).map(groupNode).filter((n) => n !== null);
98
+ const children = orderChildren([...pages, ...subgroups], cfg, sortMode, dir, onWarn);
99
+ for (const link of cfg?.links ?? []) {
100
+ children.push({
101
+ kind: "link",
102
+ name: link.label,
103
+ label: link.label,
104
+ href: link.href,
105
+ icon: link.icon,
106
+ badge: link.badge,
107
+ external: link.external,
108
+ attrs: link.attrs
109
+ });
110
+ }
111
+ if (children.length === 0 && !index) return null;
112
+ if (cfg?.hidden) return null;
113
+ const href = index ? docsHref(index.entry.id, paths) : void 0;
114
+ const label = cfg?.label ?? index?.entry.label ?? titleCase(dir.split("/").pop() ?? "");
115
+ const inPath = (href ? isAncestor(currentPath, href) : false) || children.some((c) => c.inPath);
116
+ return {
117
+ kind: "group",
118
+ name: dir.split("/").pop() ?? "",
119
+ label,
120
+ href,
121
+ icon: cfg?.icon ?? index?.entry.icon,
122
+ badge: cfg?.badge ?? index?.entry.badge,
123
+ current: href ? isActive(currentPath, href) : false,
124
+ inPath,
125
+ // Containing the current page wins over `collapsed: true`.
126
+ open: inPath || !(cfg?.collapsed ?? defaultCollapsed),
127
+ children
128
+ };
129
+ } finally {
130
+ building.delete(dir);
131
+ }
132
+ }
133
+ const root = groupNode("");
134
+ const rootChildren = root?.children ?? [];
135
+ return [...rootChildren, ...extra];
136
+ }
137
+ function orderChildren(children, cfg, sortMode, dir, onWarn) {
138
+ const byName = /* @__PURE__ */ new Map();
139
+ for (const child of children) {
140
+ if (!byName.has(child.name)) byName.set(child.name, child);
141
+ }
142
+ const taken = /* @__PURE__ */ new Set();
143
+ const ordered = [];
144
+ for (const token of cfg?.order ?? []) {
145
+ const key = normalizeOrderToken(token);
146
+ const hit = byName.get(key);
147
+ if (!hit) {
148
+ onWarn?.(
149
+ `_group.yaml in "${dir || "<root>"}": order lists "${token}", but no child is named "${key}". Available: ${[...byName.keys()].join(", ") || "(none)"}`
150
+ );
151
+ continue;
152
+ }
153
+ if (!taken.has(hit)) {
154
+ taken.add(hit);
155
+ ordered.push(hit);
156
+ }
157
+ }
158
+ let rest = children.filter((c) => !taken.has(c));
159
+ if (sortMode === "manual") {
160
+ rest = [];
161
+ } else if (sortMode === "filename") {
162
+ rest.sort((a, b) => byLocale(a.name, b.name));
163
+ } else {
164
+ rest.sort((a, b) => byLocale(a.label, b.label) || byLocale(a.name, b.name));
165
+ }
166
+ return [...ordered, ...rest];
167
+ }
168
+ function flattenNav(tree) {
169
+ const out = [];
170
+ const walk = (nodes) => {
171
+ for (const node of nodes) {
172
+ if (node.href && node.kind !== "link") out.push(node);
173
+ if (node.children?.length) walk(node.children);
174
+ }
175
+ };
176
+ walk(tree);
177
+ return out;
178
+ }
179
+ function prevNextFor(tree, currentPath) {
180
+ const flat = flattenNav(tree);
181
+ const i = flat.findIndex((n) => n.href && isActive(currentPath, n.href));
182
+ if (i === -1) return {};
183
+ return { prev: flat[i - 1], next: flat[i + 1] };
184
+ }
185
+ function breadcrumbsFor(tree, currentPath) {
186
+ const trail = [];
187
+ const walk = (nodes) => {
188
+ for (const node of nodes) {
189
+ const hit = node.href ? isActive(currentPath, node.href) : false;
190
+ if (hit) {
191
+ trail.push(node);
192
+ return true;
193
+ }
194
+ if (node.children?.length) {
195
+ trail.push(node);
196
+ if (walk(node.children)) return true;
197
+ trail.pop();
198
+ }
199
+ }
200
+ return false;
201
+ };
202
+ walk(tree);
203
+ return trail;
204
+ }
205
+ function buildTocTree(headings, { minLevel = 2, maxLevel = 3 } = {}) {
206
+ const roots = [];
207
+ const stack = [];
208
+ for (const h of headings) {
209
+ if (h.depth < minLevel || h.depth > maxLevel) continue;
210
+ const node = { depth: h.depth, slug: h.slug, text: h.text, children: [] };
211
+ while (stack.length && stack.at(-1).depth >= node.depth) stack.pop();
212
+ const parent = stack.at(-1);
213
+ if (parent) parent.children.push(node);
214
+ else roots.push(node);
215
+ stack.push(node);
216
+ }
217
+ return roots;
218
+ }
219
+
220
+ export { breadcrumbsFor, buildNavTree, buildTocTree, flattenNav, prevNextFor, titleCase };
221
+ //# sourceMappingURL=nav.js.map
222
+ //# sourceMappingURL=nav.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/nav.ts"],"names":[],"mappings":"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","file":"nav.js","sourcesContent":["/**\n * Pure nav-tree construction. Keep it free of fs and `astro:*` imports so it\n * runs in Node and unit tests; prev/next and breadcrumbs derive from this tree.\n */\nimport { docsHref, isActive, isAncestor, type PathContext } from './paths.ts';\nimport type { DocsBadge, DocsNavEntry, NavNode, TocNode } from './types.ts';\n\nexport type SortMode = 'alpha' | 'filename' | 'manual';\n\nexport interface GroupConfig {\n label?: string;\n icon?: string;\n order: string[];\n sort?: SortMode;\n collapsed?: boolean;\n hidden: boolean;\n badge?: DocsBadge;\n links: Array<{\n label: string;\n href: string;\n external?: boolean;\n icon?: string;\n badge?: DocsBadge;\n attrs: Record<string, string | number | boolean>;\n }>;\n}\n\nexport interface BuildNavOptions {\n entries: DocsNavEntry[];\n /** Keyed by directory relative to the content root; '' is the root group. */\n groups: Map<string, GroupConfig>;\n /** `Astro.url.pathname`. */\n currentPath: string;\n paths: PathContext;\n defaultCollapsed: boolean;\n defaultSort: SortMode;\n /** Appended after folder-derived nodes. Plugin-contributed sections land here. */\n extra?: NavNode[];\n onWarn?: (message: string) => void;\n}\n\n/** \"getting-started\" -> \"Getting Started\" */\nexport function titleCase(slug: string): string {\n return slug\n .split(/[-_]/)\n .filter(Boolean)\n .map((w) => w.charAt(0).toUpperCase() + w.slice(1))\n .join(' ');\n}\n\n/** Normalise an `order` token so 'foo', 'foo.mdx' and 'foo/' all mean the same child. */\nfunction normalizeOrderToken(token: string): string {\n return token\n .trim()\n .replace(/\\/+$/, '')\n .replace(/\\.(md|mdx)$/i, '');\n}\n\nfunction byLocale(a: string, b: string): number {\n return a.localeCompare(b, undefined, { numeric: true, sensitivity: 'base' });\n}\n\ninterface Classified {\n entry: DocsNavEntry;\n dir: string;\n name: string;\n isIndex: boolean;\n}\n\n/**\n * `isIndex` must come from `filePath`: Astro strips `/index` from ids, so\n * `guides/index.mdx` and `guides.mdx` both arrive as \"guides\".\n */\nfunction classify(entry: DocsNavEntry): Classified {\n const id = entry.id;\n const segments = id.split('/').filter(Boolean);\n const fileBase = entry.filePath\n ? (entry.filePath.split('/').pop() ?? '').replace(/\\.(md|mdx)$/i, '')\n : undefined;\n const isIndex = fileBase === 'index' || id === 'index';\n\n if (isIndex) {\n const dir = id === 'index' ? '' : segments.join('/');\n return { entry, dir, name: segments.at(-1) ?? '', isIndex: true };\n }\n return {\n entry,\n dir: segments.slice(0, -1).join('/'),\n name: segments.at(-1) ?? '',\n isIndex: false,\n };\n}\n\nfunction ancestorsOf(dir: string): string[] {\n if (!dir) return [];\n const parts = dir.split('/');\n const out: string[] = [];\n for (let i = 1; i <= parts.length; i++) out.push(parts.slice(0, i).join('/'));\n return out;\n}\n\nexport function buildNavTree(options: BuildNavOptions): NavNode[] {\n const {\n entries,\n groups,\n currentPath,\n paths,\n defaultCollapsed,\n defaultSort,\n extra = [],\n onWarn,\n } = options;\n\n const visible = entries.filter((e) => !e.draft);\n const classified = visible.map(classify);\n const indexOf = new Map<string, Classified>();\n const filesIn = new Map<string, Classified[]>();\n\n for (const c of classified) {\n if (c.isIndex) {\n indexOf.set(c.dir, c);\n } else {\n const list = filesIn.get(c.dir);\n if (list) list.push(c);\n else filesIn.set(c.dir, [c]);\n }\n }\n\n const dirs = new Set<string>(['']);\n for (const key of [...filesIn.keys(), ...indexOf.keys(), ...groups.keys()]) {\n dirs.add(key);\n for (const ancestor of ancestorsOf(key)) dirs.add(ancestor);\n }\n dirs.delete('~root'); // groups-loader sentinel, never a real directory\n\n const childDirsOf = new Map<string, string[]>();\n for (const dir of dirs) {\n if (!dir) continue;\n const parent = dir.split('/').slice(0, -1).join('/');\n const list = childDirsOf.get(parent);\n if (list) list.push(dir);\n else childDirsOf.set(parent, [dir]);\n }\n\n const groupFor = (dir: string): GroupConfig | undefined =>\n groups.get(dir === '' ? '~root' : dir) ?? groups.get(dir);\n\n const building = new Set<string>();\n\n function pageNode(c: Classified): NavNode {\n const href = docsHref(c.entry.id, paths);\n return {\n kind: 'page',\n name: c.name,\n label: c.entry.label,\n href,\n icon: c.entry.icon,\n badge: c.entry.badge,\n current: isActive(currentPath, href),\n inPath: isActive(currentPath, href),\n };\n }\n\n function groupNode(dir: string): NavNode | null {\n if (building.has(dir)) return null;\n building.add(dir);\n try {\n const cfg = groupFor(dir);\n const index = indexOf.get(dir);\n const sortMode = cfg?.sort ?? defaultSort;\n\n const pages = (filesIn.get(dir) ?? []).filter((c) => !c.entry.hidden).map(pageNode);\n const subgroups = (childDirsOf.get(dir) ?? [])\n .map(groupNode)\n .filter((n): n is NavNode => n !== null);\n\n const children = orderChildren([...pages, ...subgroups], cfg, sortMode, dir, onWarn);\n\n for (const link of cfg?.links ?? []) {\n children.push({\n kind: 'link',\n name: link.label,\n label: link.label,\n href: link.href,\n icon: link.icon,\n badge: link.badge,\n external: link.external,\n attrs: link.attrs,\n });\n }\n\n if (children.length === 0 && !index) return null;\n if (cfg?.hidden) return null;\n\n const href = index ? docsHref(index.entry.id, paths) : undefined;\n const label = cfg?.label ?? index?.entry.label ?? titleCase(dir.split('/').pop() ?? '');\n\n const inPath =\n (href ? isAncestor(currentPath, href) : false) || children.some((c) => c.inPath);\n\n return {\n kind: 'group',\n name: dir.split('/').pop() ?? '',\n label,\n href,\n icon: cfg?.icon ?? index?.entry.icon,\n badge: cfg?.badge ?? index?.entry.badge,\n current: href ? isActive(currentPath, href) : false,\n inPath,\n // Containing the current page wins over `collapsed: true`.\n open: inPath || !(cfg?.collapsed ?? defaultCollapsed),\n children,\n };\n } finally {\n building.delete(dir);\n }\n }\n\n const root = groupNode('');\n const rootChildren = root?.children ?? [];\n return [...rootChildren, ...extra];\n}\n\nfunction orderChildren(\n children: NavNode[],\n cfg: GroupConfig | undefined,\n sortMode: SortMode,\n dir: string,\n onWarn?: (message: string) => void\n): NavNode[] {\n const byName = new Map<string, NavNode>();\n for (const child of children) {\n if (!byName.has(child.name)) byName.set(child.name, child);\n }\n\n const taken = new Set<NavNode>();\n const ordered: NavNode[] = [];\n\n for (const token of cfg?.order ?? []) {\n const key = normalizeOrderToken(token);\n const hit = byName.get(key);\n if (!hit) {\n onWarn?.(\n `_group.yaml in \"${dir || '<root>'}\": order lists \"${token}\", but no child is named \"${key}\". ` +\n `Available: ${[...byName.keys()].join(', ') || '(none)'}`\n );\n continue;\n }\n if (!taken.has(hit)) {\n taken.add(hit);\n ordered.push(hit);\n }\n }\n\n let rest = children.filter((c) => !taken.has(c));\n\n if (sortMode === 'manual') {\n rest = [];\n } else if (sortMode === 'filename') {\n rest.sort((a, b) => byLocale(a.name, b.name));\n } else {\n rest.sort((a, b) => byLocale(a.label, b.label) || byLocale(a.name, b.name));\n }\n\n return [...ordered, ...rest];\n}\n\n/** Depth-first list of internal, linkable nodes. Drives prev/next. */\nexport function flattenNav(tree: NavNode[]): NavNode[] {\n const out: NavNode[] = [];\n const walk = (nodes: NavNode[]) => {\n for (const node of nodes) {\n if (node.href && node.kind !== 'link') out.push(node);\n if (node.children?.length) walk(node.children);\n }\n };\n walk(tree);\n return out;\n}\n\nexport function prevNextFor(\n tree: NavNode[],\n currentPath: string\n): { prev?: NavNode; next?: NavNode } {\n const flat = flattenNav(tree);\n const i = flat.findIndex((n) => n.href && isActive(currentPath, n.href));\n if (i === -1) return {};\n return { prev: flat[i - 1], next: flat[i + 1] };\n}\n\n/** Ancestor chain from the root down to the current page. */\nexport function breadcrumbsFor(tree: NavNode[], currentPath: string): NavNode[] {\n const trail: NavNode[] = [];\n const walk = (nodes: NavNode[]): boolean => {\n for (const node of nodes) {\n const hit = node.href ? isActive(currentPath, node.href) : false;\n if (hit) {\n trail.push(node);\n return true;\n }\n if (node.children?.length) {\n trail.push(node);\n if (walk(node.children)) return true;\n trail.pop();\n }\n }\n return false;\n };\n walk(tree);\n return trail;\n}\n\n/** Nest a flat heading list into a tree, clamped to [minLevel, maxLevel]. */\nexport function buildTocTree(\n headings: Array<{ depth: number; slug: string; text: string }>,\n { minLevel = 2, maxLevel = 3 }: { minLevel?: number; maxLevel?: number } = {}\n): TocNode[] {\n const roots: TocNode[] = [];\n const stack: TocNode[] = [];\n\n for (const h of headings) {\n if (h.depth < minLevel || h.depth > maxLevel) continue;\n const node: TocNode = { depth: h.depth, slug: h.slug, text: h.text, children: [] };\n while (stack.length && (stack.at(-1) as TocNode).depth >= node.depth) stack.pop();\n const parent = stack.at(-1);\n if (parent) parent.children.push(node);\n else roots.push(node);\n stack.push(node);\n }\n return roots;\n}\n"]}
@@ -0,0 +1,28 @@
1
+ /** Every URL the framework emits goes through here; nothing else may concatenate a path. */
2
+ /** Join path segments, collapsing duplicate slashes, always leading with one. */
3
+ export declare function joinPath(...parts: Array<string | undefined | null>): string;
4
+ /** True for anything we must not rewrite: protocol, protocol-relative, fragment, or query. */
5
+ export declare function isExternalHref(href: string): boolean;
6
+ export declare function ensureTrailingSlash(href: string): string;
7
+ /** Astro gives the root `index.mdx` the id "index", not "". */
8
+ export declare function idToPath(id: string): string;
9
+ /** Trim trailing slashes for comparison. Keeps a bare "/" intact. */
10
+ export declare function normalizePath(path: string): string;
11
+ export interface PathContext {
12
+ /** Astro's `import.meta.env.BASE_URL`. Always has a leading slash. */
13
+ base: string;
14
+ /** Mounted-at prefix for docs pages, e.g. "docs". Usually empty. */
15
+ pathPrefix?: string;
16
+ /** Version segment for a pinned build, e.g. "v3.1". Empty for latest-at-root. */
17
+ versionPrefix?: string;
18
+ }
19
+ /** Prefix a site-absolute path with `base`. For assets: favicons, logos, og images. */
20
+ export declare function withBase(path: string, ctx: PathContext): string;
21
+ /** The public URL for a docs collection entry id. */
22
+ export declare function docsHref(id: string, ctx: PathContext): string;
23
+ /** Remove `base` (and version/path prefixes) from a pathname, yielding a docs-relative path. */
24
+ export declare function stripBase(pathname: string, ctx: PathContext): string;
25
+ /** Whether `target` is the page currently being viewed. Base-aware, slash-insensitive. */
26
+ export declare function isActive(currentPathname: string, target: string): boolean;
27
+ /** Whether `target` is the current page or an ancestor of it. Drives group expansion. */
28
+ export declare function isAncestor(currentPathname: string, target: string): boolean;
package/dist/paths.js ADDED
@@ -0,0 +1,3 @@
1
+ export { docsHref, ensureTrailingSlash, idToPath, isActive, isAncestor, isExternalHref, joinPath, normalizePath, stripBase, withBase } from './chunk-VJN3HXKM.js';
2
+ //# sourceMappingURL=paths.js.map
3
+ //# sourceMappingURL=paths.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"paths.js"}
@@ -0,0 +1,26 @@
1
+ @reference '../styles/theme.css';
2
+
3
+ /*
4
+ * All that is left here are the two rules that fight another package's styling. Neither
5
+ * can move inline: one has to outrank Equality's own dialog class at equal specificity,
6
+ * and the other styles an element this component never renders.
7
+ */
8
+
9
+ /* Class doubled to beat Equality's centring, which sits at the same specificity.
10
+ * Never override `transform` here: the entrance animation uses it. */
11
+ .dialog.dialog {
12
+ @apply p-0;
13
+ top: 10vh;
14
+ translate: -50% 0;
15
+ }
16
+
17
+ /**
18
+ * Two assumptions nothing enforces: `packages/ui` still generates an overlay class containing
19
+ * `dialog-overlay`, and Radix still renders that overlay as the dialog's previous sibling. Either
20
+ * changes and the blur silently disappears. `:has` keeps it off every other dialog on the site.
21
+ */
22
+ :global([class*='dialog-overlay']):has(+ .dialog) {
23
+ @apply bg-background/25;
24
+ -webkit-backdrop-filter: blur(18px);
25
+ backdrop-filter: blur(6px);
26
+ }