@tayacrystals/lore 0.1.3 → 1.0.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.
- package/LICENSE +21 -0
- package/README.md +30 -0
- package/package.json +46 -36
- package/src/build.ts +149 -0
- package/src/config.ts +25 -0
- package/src/dev.ts +112 -0
- package/src/files.ts +193 -0
- package/src/i18n.ts +49 -0
- package/src/icons.ts +59 -0
- package/src/index.ts +28 -0
- package/src/mdx.ts +281 -0
- package/src/parse.ts +51 -0
- package/src/routing.ts +47 -0
- package/src/serve.ts +72 -0
- package/src/template.ts +753 -0
- package/src/types.ts +52 -0
- package/src/version.ts +33 -0
- package/components/docs/Breadcrumbs.astro +0 -41
- package/components/docs/PrevNext.astro +0 -50
- package/components/docs/Sidebar.astro +0 -28
- package/components/docs/SidebarGroup.astro +0 -72
- package/components/docs/SidebarItem.astro +0 -26
- package/components/docs/TableOfContents.astro +0 -82
- package/components/global/SearchModal.astro +0 -159
- package/components/mdx/Accordion.astro +0 -20
- package/components/mdx/Callout.astro +0 -53
- package/components/mdx/Card.astro +0 -26
- package/components/mdx/CardGrid.astro +0 -16
- package/components/mdx/CodeTabs.astro +0 -129
- package/components/mdx/FileTree.astro +0 -117
- package/components/mdx/Step.astro +0 -18
- package/components/mdx/Steps.astro +0 -6
- package/components/mdx/Tab.astro +0 -11
- package/components/mdx/Tabs.astro +0 -73
- package/components.ts +0 -11
- package/config.ts +0 -42
- package/index.ts +0 -2
- package/integration.ts +0 -68
- package/layouts/DocsLayout.astro +0 -277
- package/loaders.ts +0 -5
- package/routes/docs.astro +0 -211
- package/schema.ts +0 -13
- package/styles/global.css +0 -78
- package/styles/prose.css +0 -148
- package/utils/navigation.ts +0 -35
- package/utils/rehype-file-tree.ts +0 -229
- package/utils/sidebar.ts +0 -107
- package/utils/toc.ts +0 -28
- package/virtual.d.ts +0 -9
- package/vite-plugin.ts +0 -28
package/layouts/DocsLayout.astro
DELETED
|
@@ -1,277 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
import "../styles/global.css";
|
|
3
|
-
import "../styles/prose.css";
|
|
4
|
-
import "virtual:lore/user-css";
|
|
5
|
-
import { Icon } from "astro-icon/components";
|
|
6
|
-
import Sidebar from "../components/docs/Sidebar.astro";
|
|
7
|
-
import TableOfContents from "../components/docs/TableOfContents.astro";
|
|
8
|
-
import Breadcrumbs from "../components/docs/Breadcrumbs.astro";
|
|
9
|
-
import PrevNext from "../components/docs/PrevNext.astro";
|
|
10
|
-
import SearchModal from "../components/global/SearchModal.astro";
|
|
11
|
-
import type { SidebarEntry } from "../utils/sidebar";
|
|
12
|
-
import type { TocItem } from "../utils/toc";
|
|
13
|
-
import type { FlatNavItem } from "../utils/navigation";
|
|
14
|
-
import config from "virtual:lore/config";
|
|
15
|
-
|
|
16
|
-
interface Props {
|
|
17
|
-
title: string;
|
|
18
|
-
description?: string;
|
|
19
|
-
sidebar: SidebarEntry[];
|
|
20
|
-
toc: TocItem[];
|
|
21
|
-
showToc: boolean;
|
|
22
|
-
prev: FlatNavItem | null;
|
|
23
|
-
next: FlatNavItem | null;
|
|
24
|
-
lastUpdated?: Date | null;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
const { title, description, sidebar, toc, showToc, prev, next, lastUpdated } = Astro.props;
|
|
28
|
-
const BASE_URL = import.meta.env.BASE_URL || "/";
|
|
29
|
-
const currentPath = Astro.url.pathname.replace(/\/$/, "") || `${BASE_URL}docs`;
|
|
30
|
-
const siteTitle = config.title;
|
|
31
|
-
const githubUrl = config.social?.github;
|
|
32
|
-
const primaryHue = config.primaryHue;
|
|
33
|
-
---
|
|
34
|
-
|
|
35
|
-
<!doctype html>
|
|
36
|
-
<html lang="en">
|
|
37
|
-
<head>
|
|
38
|
-
<meta charset="utf-8" />
|
|
39
|
-
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
40
|
-
<meta name="description" content={description || "Documentation"} />
|
|
41
|
-
<link rel="icon" type="image/svg+xml" href={`${BASE_URL}favicon.svg`} />
|
|
42
|
-
<meta name="generator" content={Astro.generator} />
|
|
43
|
-
<title>{`${title} - ${siteTitle}`}</title>
|
|
44
|
-
<style set:html={`:root { --fd-hue: ${primaryHue}; }`}></style>
|
|
45
|
-
<script is:inline>
|
|
46
|
-
(function () {
|
|
47
|
-
const stored = localStorage.getItem("theme");
|
|
48
|
-
if (
|
|
49
|
-
stored === "dark" ||
|
|
50
|
-
(!stored && window.matchMedia("(prefers-color-scheme: dark)").matches)
|
|
51
|
-
) {
|
|
52
|
-
document.documentElement.classList.add("dark");
|
|
53
|
-
}
|
|
54
|
-
})();
|
|
55
|
-
</script>
|
|
56
|
-
</head>
|
|
57
|
-
<body class="min-h-screen">
|
|
58
|
-
<!-- Desktop sidebar (fixed left panel) -->
|
|
59
|
-
<aside
|
|
60
|
-
id="docs-sidebar"
|
|
61
|
-
class="hidden lg:flex fixed top-0 bottom-0 w-(--width-sidebar) flex-col bg-fd-background z-30"
|
|
62
|
-
style="left: max(0px, calc((100vw - var(--max-width-layout)) / 2))"
|
|
63
|
-
>
|
|
64
|
-
<!-- Sidebar header -->
|
|
65
|
-
<div class="flex items-center justify-between h-(--height-header) px-4 shrink-0">
|
|
66
|
-
<a href={BASE_URL} class="flex items-center gap-2 font-semibold text-[15px]">
|
|
67
|
-
<Icon name="lucide:book-open" class="w-5 h-5 text-fd-primary" />
|
|
68
|
-
<span>{siteTitle}</span>
|
|
69
|
-
</a>
|
|
70
|
-
</div>
|
|
71
|
-
|
|
72
|
-
<!-- Search trigger -->
|
|
73
|
-
<div class="px-3 mb-3 shrink-0">
|
|
74
|
-
<button
|
|
75
|
-
id="search-trigger"
|
|
76
|
-
class="flex items-center gap-2 w-full text-sm text-fd-muted-foreground hover:text-fd-foreground bg-fd-muted/60 hover:bg-fd-muted rounded-lg px-3 py-2 transition-colors border border-fd-border"
|
|
77
|
-
>
|
|
78
|
-
<Icon name="lucide:search" class="w-4 h-4 shrink-0" />
|
|
79
|
-
<span class="flex-1 text-left">Search</span>
|
|
80
|
-
<span class="flex items-center gap-0.5 text-[10px] font-mono">
|
|
81
|
-
<kbd class="rounded border border-fd-border bg-fd-background px-1 py-0.5">⌘</kbd>
|
|
82
|
-
<kbd class="rounded border border-fd-border bg-fd-background px-1 py-0.5">K</kbd>
|
|
83
|
-
</span>
|
|
84
|
-
</button>
|
|
85
|
-
</div>
|
|
86
|
-
|
|
87
|
-
<!-- Navigation -->
|
|
88
|
-
<nav class="flex-1 overflow-y-auto px-3 pb-4 scrollbar-thin" aria-label="Documentation sidebar">
|
|
89
|
-
<Sidebar entries={sidebar} currentPath={currentPath} />
|
|
90
|
-
</nav>
|
|
91
|
-
|
|
92
|
-
<!-- Sidebar footer -->
|
|
93
|
-
<div class="flex items-center gap-1 px-3 py-3 border-t border-fd-border shrink-0">
|
|
94
|
-
{githubUrl && (
|
|
95
|
-
<a
|
|
96
|
-
href={githubUrl}
|
|
97
|
-
target="_blank"
|
|
98
|
-
rel="noopener noreferrer"
|
|
99
|
-
class="inline-flex items-center justify-center w-8 h-8 rounded-md hover:bg-fd-muted transition-colors text-fd-muted-foreground hover:text-fd-foreground"
|
|
100
|
-
aria-label="GitHub"
|
|
101
|
-
>
|
|
102
|
-
<Icon name="lucide:github" class="w-4 h-4" />
|
|
103
|
-
</a>
|
|
104
|
-
)}
|
|
105
|
-
<button
|
|
106
|
-
id="theme-toggle"
|
|
107
|
-
class="inline-flex items-center justify-center w-8 h-8 rounded-md hover:bg-fd-muted transition-colors text-fd-muted-foreground hover:text-fd-foreground"
|
|
108
|
-
aria-label="Toggle dark mode"
|
|
109
|
-
>
|
|
110
|
-
<Icon name="lucide:sun" class="w-4 h-4 hidden dark:block" />
|
|
111
|
-
<Icon name="lucide:moon" class="w-4 h-4 block dark:hidden" />
|
|
112
|
-
</button>
|
|
113
|
-
</div>
|
|
114
|
-
</aside>
|
|
115
|
-
|
|
116
|
-
<!-- Mobile header -->
|
|
117
|
-
<header class="lg:hidden sticky top-0 z-40 flex items-center justify-between h-(--height-header) px-4 bg-fd-background/80 backdrop-blur-lg border-b border-fd-border">
|
|
118
|
-
<div class="flex items-center gap-3">
|
|
119
|
-
<button
|
|
120
|
-
id="mobile-sidebar-toggle"
|
|
121
|
-
class="inline-flex items-center justify-center w-8 h-8 rounded-md hover:bg-fd-muted transition-colors"
|
|
122
|
-
aria-label="Toggle sidebar"
|
|
123
|
-
>
|
|
124
|
-
<Icon name="lucide:menu" class="w-4.5 h-4.5" />
|
|
125
|
-
</button>
|
|
126
|
-
<a href={BASE_URL} class="font-semibold text-sm">{siteTitle}</a>
|
|
127
|
-
</div>
|
|
128
|
-
<div class="flex items-center gap-1">
|
|
129
|
-
<button
|
|
130
|
-
id="search-trigger-mobile"
|
|
131
|
-
class="inline-flex items-center justify-center w-8 h-8 rounded-md hover:bg-fd-muted transition-colors"
|
|
132
|
-
aria-label="Search"
|
|
133
|
-
>
|
|
134
|
-
<Icon name="lucide:search" class="w-4 h-4" />
|
|
135
|
-
</button>
|
|
136
|
-
</div>
|
|
137
|
-
</header>
|
|
138
|
-
|
|
139
|
-
<!-- Main content area -->
|
|
140
|
-
<div class="max-w-(--max-width-layout) mx-auto lg:pl-(--width-sidebar)">
|
|
141
|
-
<div class="flex">
|
|
142
|
-
<!-- Article content -->
|
|
143
|
-
<article class="min-w-0 flex-1 px-6 lg:px-10 py-8 lg:py-10">
|
|
144
|
-
<Breadcrumbs />
|
|
145
|
-
|
|
146
|
-
<div class="fd-prose">
|
|
147
|
-
<h1>{title}</h1>
|
|
148
|
-
{description && <p class="text-fd-muted-foreground text-base mt-1 mb-6">{description}</p>}
|
|
149
|
-
<slot />
|
|
150
|
-
</div>
|
|
151
|
-
|
|
152
|
-
<PrevNext prev={prev} next={next} />
|
|
153
|
-
|
|
154
|
-
{lastUpdated && (
|
|
155
|
-
<div class="mt-8 text-xs text-fd-muted-foreground">
|
|
156
|
-
Last updated on {lastUpdated.toLocaleDateString("en-US", { year: "numeric", month: "long", day: "numeric" })}
|
|
157
|
-
</div>
|
|
158
|
-
)}
|
|
159
|
-
</article>
|
|
160
|
-
|
|
161
|
-
<!-- Table of contents -->
|
|
162
|
-
{
|
|
163
|
-
showToc && toc.length > 0 && (
|
|
164
|
-
<aside class="hidden xl:block w-(--width-toc) shrink-0 py-10">
|
|
165
|
-
<div class="sticky top-(--height-header) pt-2">
|
|
166
|
-
<TableOfContents items={toc} />
|
|
167
|
-
</div>
|
|
168
|
-
</aside>
|
|
169
|
-
)
|
|
170
|
-
}
|
|
171
|
-
</div>
|
|
172
|
-
</div>
|
|
173
|
-
|
|
174
|
-
<!-- Mobile sidebar overlay -->
|
|
175
|
-
<div id="mobile-sidebar-overlay" class="lg:hidden fixed inset-0 z-50 hidden">
|
|
176
|
-
<div class="absolute inset-0 bg-black/50 backdrop-blur-sm" id="mobile-sidebar-backdrop"></div>
|
|
177
|
-
<div
|
|
178
|
-
class="absolute left-0 top-0 bottom-0 w-72 bg-fd-background overflow-y-auto transform transition-transform duration-200 -translate-x-full flex flex-col"
|
|
179
|
-
id="mobile-sidebar-panel"
|
|
180
|
-
>
|
|
181
|
-
<!-- Mobile sidebar header -->
|
|
182
|
-
<div class="flex items-center justify-between h-(--height-header) px-4 shrink-0">
|
|
183
|
-
<a href={BASE_URL} class="flex items-center gap-2 font-semibold text-[15px]">
|
|
184
|
-
<Icon name="lucide:book-open" class="w-5 h-5 text-fd-primary" />
|
|
185
|
-
<span>{siteTitle}</span>
|
|
186
|
-
</a>
|
|
187
|
-
<button id="mobile-sidebar-close" class="p-1 rounded hover:bg-fd-muted" aria-label="Close">
|
|
188
|
-
<Icon name="lucide:x" class="w-5 h-5" />
|
|
189
|
-
</button>
|
|
190
|
-
</div>
|
|
191
|
-
|
|
192
|
-
<!-- Mobile search -->
|
|
193
|
-
<div class="px-3 mb-3 shrink-0">
|
|
194
|
-
<button
|
|
195
|
-
id="search-trigger-mobile-sidebar"
|
|
196
|
-
class="flex items-center gap-2 w-full text-sm text-fd-muted-foreground hover:text-fd-foreground bg-fd-muted/60 hover:bg-fd-muted rounded-lg px-3 py-2 transition-colors border border-fd-border"
|
|
197
|
-
>
|
|
198
|
-
<Icon name="lucide:search" class="w-4 h-4 shrink-0" />
|
|
199
|
-
<span>Search</span>
|
|
200
|
-
</button>
|
|
201
|
-
</div>
|
|
202
|
-
|
|
203
|
-
<!-- Mobile nav -->
|
|
204
|
-
<nav class="flex-1 overflow-y-auto px-3 pb-4 scrollbar-thin">
|
|
205
|
-
<Sidebar entries={sidebar} currentPath={currentPath} />
|
|
206
|
-
</nav>
|
|
207
|
-
|
|
208
|
-
<!-- Mobile sidebar footer -->
|
|
209
|
-
<div class="flex items-center gap-1 px-3 py-3 border-t border-fd-border shrink-0">
|
|
210
|
-
{githubUrl && (
|
|
211
|
-
<a
|
|
212
|
-
href={githubUrl}
|
|
213
|
-
target="_blank"
|
|
214
|
-
rel="noopener noreferrer"
|
|
215
|
-
class="inline-flex items-center justify-center w-8 h-8 rounded-md hover:bg-fd-muted transition-colors text-fd-muted-foreground hover:text-fd-foreground"
|
|
216
|
-
aria-label="GitHub"
|
|
217
|
-
>
|
|
218
|
-
<Icon name="lucide:github" class="w-4 h-4" />
|
|
219
|
-
</a>
|
|
220
|
-
)}
|
|
221
|
-
<button
|
|
222
|
-
id="mobile-theme-toggle"
|
|
223
|
-
class="inline-flex items-center justify-center w-8 h-8 rounded-md hover:bg-fd-muted transition-colors text-fd-muted-foreground hover:text-fd-foreground"
|
|
224
|
-
aria-label="Toggle dark mode"
|
|
225
|
-
>
|
|
226
|
-
<Icon name="lucide:sun" class="w-4 h-4 hidden dark:block" />
|
|
227
|
-
<Icon name="lucide:moon" class="w-4 h-4 block dark:hidden" />
|
|
228
|
-
</button>
|
|
229
|
-
</div>
|
|
230
|
-
</div>
|
|
231
|
-
</div>
|
|
232
|
-
|
|
233
|
-
<SearchModal />
|
|
234
|
-
|
|
235
|
-
<script>
|
|
236
|
-
// Theme toggle (desktop + mobile)
|
|
237
|
-
function toggleTheme() {
|
|
238
|
-
const isDark = document.documentElement.classList.toggle("dark");
|
|
239
|
-
localStorage.setItem("theme", isDark ? "dark" : "light");
|
|
240
|
-
}
|
|
241
|
-
document.getElementById("theme-toggle")?.addEventListener("click", toggleTheme);
|
|
242
|
-
document.getElementById("mobile-theme-toggle")?.addEventListener("click", toggleTheme);
|
|
243
|
-
|
|
244
|
-
// Mobile sidebar
|
|
245
|
-
const toggle = document.getElementById("mobile-sidebar-toggle");
|
|
246
|
-
const overlay = document.getElementById("mobile-sidebar-overlay");
|
|
247
|
-
const backdrop = document.getElementById("mobile-sidebar-backdrop");
|
|
248
|
-
const panel = document.getElementById("mobile-sidebar-panel");
|
|
249
|
-
const close = document.getElementById("mobile-sidebar-close");
|
|
250
|
-
|
|
251
|
-
function openSidebar() {
|
|
252
|
-
overlay?.classList.remove("hidden");
|
|
253
|
-
requestAnimationFrame(() => {
|
|
254
|
-
panel?.classList.remove("-translate-x-full");
|
|
255
|
-
});
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
function closeSidebar() {
|
|
259
|
-
panel?.classList.add("-translate-x-full");
|
|
260
|
-
setTimeout(() => overlay?.classList.add("hidden"), 200);
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
toggle?.addEventListener("click", openSidebar);
|
|
264
|
-
backdrop?.addEventListener("click", closeSidebar);
|
|
265
|
-
close?.addEventListener("click", closeSidebar);
|
|
266
|
-
|
|
267
|
-
// Mobile sidebar search trigger
|
|
268
|
-
document.getElementById("search-trigger-mobile-sidebar")?.addEventListener("click", () => {
|
|
269
|
-
closeSidebar();
|
|
270
|
-
const dialog = document.getElementById("search-dialog") as HTMLDialogElement;
|
|
271
|
-
const input = document.getElementById("search-input") as HTMLInputElement;
|
|
272
|
-
dialog?.showModal();
|
|
273
|
-
input?.focus();
|
|
274
|
-
});
|
|
275
|
-
</script>
|
|
276
|
-
</body>
|
|
277
|
-
</html>
|
package/loaders.ts
DELETED
package/routes/docs.astro
DELETED
|
@@ -1,211 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
import { getCollection, render } from "astro:content";
|
|
3
|
-
import DocsLayout from "../layouts/DocsLayout.astro";
|
|
4
|
-
import { buildSidebar } from "../utils/sidebar";
|
|
5
|
-
import type { TocItem } from "../utils/toc";
|
|
6
|
-
import { flattenSidebar, getPrevNext } from "../utils/navigation";
|
|
7
|
-
import config from "virtual:lore/config";
|
|
8
|
-
import type { SidebarGroupConfig } from "../config";
|
|
9
|
-
|
|
10
|
-
interface DocsEntry {
|
|
11
|
-
id: string;
|
|
12
|
-
data: {
|
|
13
|
-
title: string;
|
|
14
|
-
description?: string;
|
|
15
|
-
order: number;
|
|
16
|
-
group?: string;
|
|
17
|
-
icon?: string;
|
|
18
|
-
toc: boolean;
|
|
19
|
-
draft: boolean;
|
|
20
|
-
};
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
export async function getStaticPaths() {
|
|
24
|
-
const entries: DocsEntry[] = await getCollection("docs", ({ data }: DocsEntry) => !data.draft);
|
|
25
|
-
|
|
26
|
-
// Content entry paths
|
|
27
|
-
// Map subfolder index files (e.g. "getting-started/index") to their parent path
|
|
28
|
-
const entryPaths = entries.map((entry: DocsEntry) => ({
|
|
29
|
-
params: {
|
|
30
|
-
slug: entry.id === "index"
|
|
31
|
-
? undefined
|
|
32
|
-
: entry.id.endsWith("/index")
|
|
33
|
-
? entry.id.slice(0, -"/index".length)
|
|
34
|
-
: entry.id,
|
|
35
|
-
},
|
|
36
|
-
props: { entry, isSection: false as const },
|
|
37
|
-
}));
|
|
38
|
-
|
|
39
|
-
// Collect ALL intermediate path prefixes as group slugs
|
|
40
|
-
const groupSlugs = new Set<string>();
|
|
41
|
-
for (const entry of entries) {
|
|
42
|
-
const parts = entry.id.split("/");
|
|
43
|
-
// Build up path prefixes: e.g. "a/b/c.mdx" -> "a", "a/b"
|
|
44
|
-
for (let i = 1; i < parts.length; i++) {
|
|
45
|
-
groupSlugs.add(parts.slice(0, i).join("/"));
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
// Only create section pages for groups that don't have a matching content entry
|
|
50
|
-
const entryIds = new Set(entries.map((e: DocsEntry) => e.id));
|
|
51
|
-
const indexSlugs = new Set(
|
|
52
|
-
entries
|
|
53
|
-
.filter((e: DocsEntry) => e.id.endsWith("/index"))
|
|
54
|
-
.map((e: DocsEntry) => e.id.slice(0, -"/index".length)),
|
|
55
|
-
);
|
|
56
|
-
const sectionPaths = [...groupSlugs]
|
|
57
|
-
.filter((slug) => !entryIds.has(slug) && !indexSlugs.has(slug))
|
|
58
|
-
.map((slug) => ({
|
|
59
|
-
params: { slug },
|
|
60
|
-
props: { groupSlug: slug, isSection: true as const },
|
|
61
|
-
}));
|
|
62
|
-
|
|
63
|
-
return [...entryPaths, ...sectionPaths];
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
const allEntries: DocsEntry[] = await getCollection("docs");
|
|
67
|
-
const sidebar = buildSidebar(allEntries, config.sidebar);
|
|
68
|
-
const flatItems = flattenSidebar(sidebar);
|
|
69
|
-
const currentPath = Astro.url.pathname.replace(/\/$/, "") || "/docs";
|
|
70
|
-
const { prev, next } = getPrevNext(flatItems, currentPath);
|
|
71
|
-
|
|
72
|
-
let title: string;
|
|
73
|
-
let description: string | undefined;
|
|
74
|
-
let toc: TocItem[] = [];
|
|
75
|
-
let showToc = true;
|
|
76
|
-
let Content: any = null;
|
|
77
|
-
let sectionItems: { label: string; href: string; description?: string }[] = [];
|
|
78
|
-
let lastUpdated: Date | null = null;
|
|
79
|
-
|
|
80
|
-
if (Astro.props.isSection) {
|
|
81
|
-
// Section listing page
|
|
82
|
-
const groupSlug = Astro.props.groupSlug;
|
|
83
|
-
|
|
84
|
-
// Traverse nested config to find label for this group
|
|
85
|
-
const slugParts = groupSlug.split("/");
|
|
86
|
-
let currentConfig: Record<string, SidebarGroupConfig> = config.sidebar ?? {};
|
|
87
|
-
let label = slugParts[slugParts.length - 1];
|
|
88
|
-
for (const part of slugParts) {
|
|
89
|
-
const found = currentConfig[part];
|
|
90
|
-
if (found) {
|
|
91
|
-
label = found.label;
|
|
92
|
-
currentConfig = found.children ?? {};
|
|
93
|
-
} else {
|
|
94
|
-
// Use titleCase fallback
|
|
95
|
-
label = part.replace(/[-_]/g, " ").replace(/\b\w/g, (c: string) => c.toUpperCase());
|
|
96
|
-
break;
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
title = label;
|
|
101
|
-
description = `Browse all pages in ${title}.`;
|
|
102
|
-
showToc = false;
|
|
103
|
-
|
|
104
|
-
// Get direct children entries (one level deep)
|
|
105
|
-
const groupEntries = allEntries
|
|
106
|
-
.filter((e) => {
|
|
107
|
-
if (e.data.draft) return false;
|
|
108
|
-
if (!e.id.startsWith(groupSlug + "/")) return false;
|
|
109
|
-
const rest = e.id.slice(groupSlug.length + 1);
|
|
110
|
-
return !rest.includes("/"); // direct children only
|
|
111
|
-
})
|
|
112
|
-
.sort((a, b) => a.data.order - b.data.order);
|
|
113
|
-
|
|
114
|
-
sectionItems = groupEntries.map((e) => ({
|
|
115
|
-
label: e.data.title,
|
|
116
|
-
href: `/docs/${e.id}`,
|
|
117
|
-
description: e.data.description,
|
|
118
|
-
}));
|
|
119
|
-
|
|
120
|
-
// Also add sub-group links
|
|
121
|
-
const subGroups = new Set<string>();
|
|
122
|
-
for (const entry of allEntries) {
|
|
123
|
-
if (entry.data.draft) continue;
|
|
124
|
-
if (!entry.id.startsWith(groupSlug + "/")) continue;
|
|
125
|
-
const rest = entry.id.slice(groupSlug.length + 1);
|
|
126
|
-
const parts = rest.split("/");
|
|
127
|
-
if (parts.length > 1) {
|
|
128
|
-
subGroups.add(parts[0]);
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
for (const sub of subGroups) {
|
|
133
|
-
const subSlug = `${groupSlug}/${sub}`;
|
|
134
|
-
// Traverse config tree to find the label for this specific sub-group
|
|
135
|
-
let subLabel = sub.replace(/[-_]/g, " ").replace(/\b\w/g, (c: string) => c.toUpperCase());
|
|
136
|
-
let cfg = config.sidebar as Record<string, SidebarGroupConfig>;
|
|
137
|
-
for (const part of subSlug.split("/")) {
|
|
138
|
-
const found = cfg[part];
|
|
139
|
-
if (found) {
|
|
140
|
-
cfg = found.children ?? {};
|
|
141
|
-
// Only use label from the final segment (the sub-group itself)
|
|
142
|
-
if (part === sub) {
|
|
143
|
-
subLabel = found.label;
|
|
144
|
-
}
|
|
145
|
-
} else {
|
|
146
|
-
break;
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
sectionItems.push({
|
|
151
|
-
label: subLabel,
|
|
152
|
-
href: `/docs/${subSlug}`,
|
|
153
|
-
description: `Browse ${subLabel} pages.`,
|
|
154
|
-
});
|
|
155
|
-
}
|
|
156
|
-
} else {
|
|
157
|
-
// Regular content page
|
|
158
|
-
const { entry } = Astro.props;
|
|
159
|
-
title = entry.data.title;
|
|
160
|
-
description = entry.data.description;
|
|
161
|
-
const rendered = await render(entry);
|
|
162
|
-
Content = rendered.Content;
|
|
163
|
-
toc = (await import("../utils/toc")).buildToc(rendered.headings);
|
|
164
|
-
showToc = entry.data.toc;
|
|
165
|
-
|
|
166
|
-
// Get last git commit date for this file
|
|
167
|
-
try {
|
|
168
|
-
const { execSync } = await import("child_process");
|
|
169
|
-
const timestamp = execSync(
|
|
170
|
-
`git log -1 --format=%cI -- "src/content/docs/${entry.id}.mdx" "src/content/docs/${entry.id}.md"`,
|
|
171
|
-
{ encoding: "utf-8", timeout: 5000 },
|
|
172
|
-
).trim();
|
|
173
|
-
if (timestamp) {
|
|
174
|
-
lastUpdated = new Date(timestamp);
|
|
175
|
-
}
|
|
176
|
-
} catch {
|
|
177
|
-
// Fallback: no git date available
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
---
|
|
181
|
-
|
|
182
|
-
<DocsLayout
|
|
183
|
-
title={title}
|
|
184
|
-
description={description}
|
|
185
|
-
sidebar={sidebar}
|
|
186
|
-
toc={toc}
|
|
187
|
-
showToc={showToc}
|
|
188
|
-
prev={prev}
|
|
189
|
-
next={next}
|
|
190
|
-
lastUpdated={lastUpdated}
|
|
191
|
-
>
|
|
192
|
-
{Content ? (
|
|
193
|
-
<Content />
|
|
194
|
-
) : (
|
|
195
|
-
<ul class="not-prose list-none p-0 m-0 space-y-3">
|
|
196
|
-
{sectionItems.map((item) => (
|
|
197
|
-
<li>
|
|
198
|
-
<a
|
|
199
|
-
href={item.href}
|
|
200
|
-
class="block rounded-lg border border-fd-border p-4 hover:bg-fd-muted/50 transition-colors no-underline"
|
|
201
|
-
>
|
|
202
|
-
<span class="font-medium text-fd-foreground">{item.label}</span>
|
|
203
|
-
{item.description && (
|
|
204
|
-
<span class="block text-sm text-fd-muted-foreground mt-1">{item.description}</span>
|
|
205
|
-
)}
|
|
206
|
-
</a>
|
|
207
|
-
</li>
|
|
208
|
-
))}
|
|
209
|
-
</ul>
|
|
210
|
-
)}
|
|
211
|
-
</DocsLayout>
|
package/schema.ts
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { z } from "zod";
|
|
2
|
-
|
|
3
|
-
export function docsSchema() {
|
|
4
|
-
return z.object({
|
|
5
|
-
title: z.string(),
|
|
6
|
-
description: z.string().optional(),
|
|
7
|
-
order: z.number().default(999),
|
|
8
|
-
group: z.string().optional(),
|
|
9
|
-
icon: z.string().optional(),
|
|
10
|
-
toc: z.boolean().default(true),
|
|
11
|
-
draft: z.boolean().default(false),
|
|
12
|
-
});
|
|
13
|
-
}
|
package/styles/global.css
DELETED
|
@@ -1,78 +0,0 @@
|
|
|
1
|
-
@import "tailwindcss";
|
|
2
|
-
@source "../components";
|
|
3
|
-
@source "../layouts";
|
|
4
|
-
@source "../routes";
|
|
5
|
-
@import "@fontsource-variable/inter";
|
|
6
|
-
@import "@fontsource/geist-mono";
|
|
7
|
-
|
|
8
|
-
@theme {
|
|
9
|
-
--font-sans: "Inter Variable", ui-sans-serif, system-ui, sans-serif;
|
|
10
|
-
--font-mono: "Geist Mono", ui-monospace, monospace;
|
|
11
|
-
|
|
12
|
-
--color-fd-background: oklch(0.985 0 0);
|
|
13
|
-
--color-fd-foreground: oklch(0.145 0 0);
|
|
14
|
-
--color-fd-muted: oklch(0.955 0 0);
|
|
15
|
-
--color-fd-muted-foreground: oklch(0.46 0 0);
|
|
16
|
-
--color-fd-border: oklch(0.915 0 0);
|
|
17
|
-
--color-fd-primary: oklch(0.6 0.16 var(--fd-hue));
|
|
18
|
-
--color-fd-primary-foreground: oklch(0.98 0 0);
|
|
19
|
-
--color-fd-accent: oklch(0.96 0 0);
|
|
20
|
-
--color-fd-accent-foreground: oklch(0.145 0 0);
|
|
21
|
-
--color-fd-card: oklch(0.985 0 0);
|
|
22
|
-
--color-fd-card-foreground: oklch(0.145 0 0);
|
|
23
|
-
--color-fd-popover: oklch(0.985 0 0);
|
|
24
|
-
--color-fd-popover-foreground: oklch(0.145 0 0);
|
|
25
|
-
--color-fd-ring: oklch(0.6 0.16 var(--fd-hue));
|
|
26
|
-
|
|
27
|
-
--radius-lg: 0.75rem;
|
|
28
|
-
--radius-md: 0.5rem;
|
|
29
|
-
--radius-sm: 0.375rem;
|
|
30
|
-
|
|
31
|
-
--width-sidebar: 17rem;
|
|
32
|
-
--width-toc: 14rem;
|
|
33
|
-
--width-content: 50rem;
|
|
34
|
-
--height-header: 3.5rem;
|
|
35
|
-
--max-width-layout: 88rem;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
.dark {
|
|
39
|
-
--color-fd-background: oklch(0.13 0 0);
|
|
40
|
-
--color-fd-foreground: oklch(0.92 0 0);
|
|
41
|
-
--color-fd-muted: oklch(0.18 0 0);
|
|
42
|
-
--color-fd-muted-foreground: oklch(0.55 0 0);
|
|
43
|
-
--color-fd-border: oklch(0.2 0 0);
|
|
44
|
-
--color-fd-primary: oklch(0.7 0.16 var(--fd-hue));
|
|
45
|
-
--color-fd-primary-foreground: oklch(0.1 0 0);
|
|
46
|
-
--color-fd-accent: oklch(0.16 0 0);
|
|
47
|
-
--color-fd-accent-foreground: oklch(0.92 0 0);
|
|
48
|
-
--color-fd-card: oklch(0.15 0 0);
|
|
49
|
-
--color-fd-card-foreground: oklch(0.92 0 0);
|
|
50
|
-
--color-fd-popover: oklch(0.15 0 0);
|
|
51
|
-
--color-fd-popover-foreground: oklch(0.92 0 0);
|
|
52
|
-
--color-fd-ring: oklch(0.7 0.16 var(--fd-hue));
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
@layer base {
|
|
56
|
-
* {
|
|
57
|
-
border-color: var(--color-fd-border);
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
body {
|
|
61
|
-
font-family: var(--font-sans);
|
|
62
|
-
background-color: var(--color-fd-background);
|
|
63
|
-
color: var(--color-fd-foreground);
|
|
64
|
-
-webkit-font-smoothing: antialiased;
|
|
65
|
-
-moz-osx-font-smoothing: grayscale;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
::selection {
|
|
69
|
-
background-color: oklch(0.6 0.16 var(--fd-hue) / 0.2);
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
@layer utilities {
|
|
74
|
-
.scrollbar-thin {
|
|
75
|
-
scrollbar-width: thin;
|
|
76
|
-
scrollbar-color: var(--color-fd-border) transparent;
|
|
77
|
-
}
|
|
78
|
-
}
|