@nexpress/theme-docs 0.1.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/LICENSE +21 -0
- package/dist/components/error.d.ts +25 -0
- package/dist/components/error.js +115 -0
- package/dist/components/error.js.map +1 -0
- package/dist/components/members-error.d.ts +27 -0
- package/dist/components/members-error.js +118 -0
- package/dist/components/members-error.js.map +1 -0
- package/dist/index.d.ts +156 -0
- package/dist/index.js +813 -0
- package/dist/index.js.map +1 -0
- package/package.json +73 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,813 @@
|
|
|
1
|
+
// src/index.ts
|
|
2
|
+
import { defineTheme } from "@nexpress/theme";
|
|
3
|
+
|
|
4
|
+
// src/header.tsx
|
|
5
|
+
import { NavMenu } from "@nexpress/next";
|
|
6
|
+
|
|
7
|
+
// src/settings-helpers.ts
|
|
8
|
+
import { getCachedThemeSettings } from "@nexpress/next";
|
|
9
|
+
|
|
10
|
+
// src/settings.ts
|
|
11
|
+
import { z } from "zod";
|
|
12
|
+
var docsSettingsSchema = z.object({
|
|
13
|
+
version: z.string().default("v1").describe(
|
|
14
|
+
"Currently-displayed version label, shown in the masthead. Update on each release."
|
|
15
|
+
),
|
|
16
|
+
githubRepo: z.string().url().optional().describe(
|
|
17
|
+
"Optional repository URL \u2014 when set, page templates render an 'Edit on GitHub' link in the prev/next bar."
|
|
18
|
+
),
|
|
19
|
+
sidebarHeading: z.string().default("Documentation").describe("Heading shown above the hierarchical sidebar nav."),
|
|
20
|
+
showTableOfContents: z.boolean().default(true).describe("Render the in-page TOC sidebar on doc pages."),
|
|
21
|
+
searchPlaceholder: z.string().default("Search the docs\u2026").describe("Placeholder text for the search input in the masthead.")
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
// src/settings-helpers.ts
|
|
25
|
+
async function resolveDocsSettings() {
|
|
26
|
+
const raw = await getCachedThemeSettings("docs");
|
|
27
|
+
const parsed = docsSettingsSchema.safeParse(raw);
|
|
28
|
+
if (parsed.success) return parsed.data;
|
|
29
|
+
return docsSettingsSchema.parse({});
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// src/header.tsx
|
|
33
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
34
|
+
async function DocsHeader() {
|
|
35
|
+
const settings = await resolveDocsSettings();
|
|
36
|
+
return /* @__PURE__ */ jsx("header", { className: "np-docs-header", children: /* @__PURE__ */ jsxs("div", { className: "np-docs-header-inner", children: [
|
|
37
|
+
/* @__PURE__ */ jsxs("a", { href: "/", className: "np-docs-brand", children: [
|
|
38
|
+
/* @__PURE__ */ jsx("span", { className: "np-docs-brand-name", children: "Docs" }),
|
|
39
|
+
/* @__PURE__ */ jsx("span", { className: "np-docs-brand-version", children: settings.version })
|
|
40
|
+
] }),
|
|
41
|
+
/* @__PURE__ */ jsx(
|
|
42
|
+
"form",
|
|
43
|
+
{
|
|
44
|
+
action: "/docs/search",
|
|
45
|
+
method: "get",
|
|
46
|
+
className: "np-docs-search-form",
|
|
47
|
+
role: "search",
|
|
48
|
+
children: /* @__PURE__ */ jsx(
|
|
49
|
+
"input",
|
|
50
|
+
{
|
|
51
|
+
type: "search",
|
|
52
|
+
name: "q",
|
|
53
|
+
placeholder: settings.searchPlaceholder,
|
|
54
|
+
className: "np-docs-search-input",
|
|
55
|
+
"aria-label": "Search the docs"
|
|
56
|
+
}
|
|
57
|
+
)
|
|
58
|
+
}
|
|
59
|
+
),
|
|
60
|
+
/* @__PURE__ */ jsxs("nav", { className: "np-docs-nav", "aria-label": "Primary", children: [
|
|
61
|
+
/* @__PURE__ */ jsx(NavMenu, { location: "primary", className: "np-docs-primary-nav" }),
|
|
62
|
+
settings.githubRepo ? /* @__PURE__ */ jsx(
|
|
63
|
+
"a",
|
|
64
|
+
{
|
|
65
|
+
href: settings.githubRepo,
|
|
66
|
+
className: "np-docs-github-link",
|
|
67
|
+
target: "_blank",
|
|
68
|
+
rel: "noreferrer",
|
|
69
|
+
children: "GitHub"
|
|
70
|
+
}
|
|
71
|
+
) : null
|
|
72
|
+
] })
|
|
73
|
+
] }) });
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// src/members-not-found.tsx
|
|
77
|
+
import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
78
|
+
function DocsMembersNotFound() {
|
|
79
|
+
return /* @__PURE__ */ jsxs2(
|
|
80
|
+
"div",
|
|
81
|
+
{
|
|
82
|
+
className: "np-docs-members-not-found",
|
|
83
|
+
style: {
|
|
84
|
+
maxWidth: 520,
|
|
85
|
+
margin: "5rem auto",
|
|
86
|
+
padding: "0 1.5rem"
|
|
87
|
+
},
|
|
88
|
+
children: [
|
|
89
|
+
/* @__PURE__ */ jsx2(
|
|
90
|
+
"p",
|
|
91
|
+
{
|
|
92
|
+
style: {
|
|
93
|
+
margin: 0,
|
|
94
|
+
fontSize: "0.75rem",
|
|
95
|
+
textTransform: "uppercase",
|
|
96
|
+
letterSpacing: "0.12em",
|
|
97
|
+
color: "var(--np-color-muted-foreground)",
|
|
98
|
+
fontFamily: "var(--np-font-mono, ui-monospace, monospace)"
|
|
99
|
+
},
|
|
100
|
+
children: "404 \xB7 account"
|
|
101
|
+
}
|
|
102
|
+
),
|
|
103
|
+
/* @__PURE__ */ jsx2(
|
|
104
|
+
"h1",
|
|
105
|
+
{
|
|
106
|
+
style: {
|
|
107
|
+
margin: "0.75rem 0 0",
|
|
108
|
+
fontSize: "1.875rem",
|
|
109
|
+
fontFamily: "var(--np-font-heading)",
|
|
110
|
+
fontWeight: 600,
|
|
111
|
+
lineHeight: 1.2
|
|
112
|
+
},
|
|
113
|
+
children: "That account link is no longer valid."
|
|
114
|
+
}
|
|
115
|
+
),
|
|
116
|
+
/* @__PURE__ */ jsx2(
|
|
117
|
+
"p",
|
|
118
|
+
{
|
|
119
|
+
style: {
|
|
120
|
+
margin: "1.25rem 0 0",
|
|
121
|
+
color: "var(--np-color-muted-foreground)",
|
|
122
|
+
fontSize: "0.9375rem",
|
|
123
|
+
lineHeight: 1.6
|
|
124
|
+
},
|
|
125
|
+
children: "Verification and password-reset links are single-use and expire after a short window. Open the sign-in page and request a fresh one."
|
|
126
|
+
}
|
|
127
|
+
),
|
|
128
|
+
/* @__PURE__ */ jsx2("p", { style: { margin: "1.75rem 0 0" }, children: /* @__PURE__ */ jsx2(
|
|
129
|
+
"a",
|
|
130
|
+
{
|
|
131
|
+
href: "/members/login",
|
|
132
|
+
style: {
|
|
133
|
+
display: "inline-block",
|
|
134
|
+
padding: "0.5rem 1.25rem",
|
|
135
|
+
borderRadius: "0.375rem",
|
|
136
|
+
background: "var(--np-color-primary)",
|
|
137
|
+
color: "var(--np-color-primary-foreground)",
|
|
138
|
+
textDecoration: "none",
|
|
139
|
+
fontSize: "0.875rem",
|
|
140
|
+
fontWeight: 500
|
|
141
|
+
},
|
|
142
|
+
children: "Go to sign in"
|
|
143
|
+
}
|
|
144
|
+
) })
|
|
145
|
+
]
|
|
146
|
+
}
|
|
147
|
+
);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// src/members-shell.tsx
|
|
151
|
+
import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
152
|
+
function DocsMembersShell({ children }) {
|
|
153
|
+
return /* @__PURE__ */ jsxs3("div", { className: "np-docs np-docs-shell", children: [
|
|
154
|
+
/* @__PURE__ */ jsx3(DocsHeader, {}),
|
|
155
|
+
/* @__PURE__ */ jsx3("div", { className: "np-docs-members", children: /* @__PURE__ */ jsx3("div", { className: "np-docs-members-column", children }) })
|
|
156
|
+
] });
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// src/not-found.tsx
|
|
160
|
+
import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
161
|
+
function DocsNotFound() {
|
|
162
|
+
return /* @__PURE__ */ jsxs4(
|
|
163
|
+
"div",
|
|
164
|
+
{
|
|
165
|
+
className: "np-docs-not-found",
|
|
166
|
+
style: {
|
|
167
|
+
maxWidth: 560,
|
|
168
|
+
margin: "5rem auto",
|
|
169
|
+
padding: "0 1.5rem"
|
|
170
|
+
},
|
|
171
|
+
children: [
|
|
172
|
+
/* @__PURE__ */ jsx4(
|
|
173
|
+
"p",
|
|
174
|
+
{
|
|
175
|
+
style: {
|
|
176
|
+
margin: 0,
|
|
177
|
+
fontSize: "0.75rem",
|
|
178
|
+
textTransform: "uppercase",
|
|
179
|
+
letterSpacing: "0.08em",
|
|
180
|
+
color: "var(--np-color-muted-foreground)"
|
|
181
|
+
},
|
|
182
|
+
children: "404 \u2014 Not found"
|
|
183
|
+
}
|
|
184
|
+
),
|
|
185
|
+
/* @__PURE__ */ jsx4("h1", { style: { margin: "0.75rem 0 0.5rem", fontSize: "1.75rem" }, children: "That page isn't in the docs." }),
|
|
186
|
+
/* @__PURE__ */ jsx4(
|
|
187
|
+
"p",
|
|
188
|
+
{
|
|
189
|
+
style: {
|
|
190
|
+
margin: "0.75rem 0 1.5rem",
|
|
191
|
+
color: "var(--np-color-muted-foreground)"
|
|
192
|
+
},
|
|
193
|
+
children: "It may have been renamed or merged into another section. Try the search bar in the header, or head to the homepage."
|
|
194
|
+
}
|
|
195
|
+
),
|
|
196
|
+
/* @__PURE__ */ jsx4(
|
|
197
|
+
"a",
|
|
198
|
+
{
|
|
199
|
+
href: "/",
|
|
200
|
+
style: {
|
|
201
|
+
display: "inline-block",
|
|
202
|
+
padding: "0.4rem 1rem",
|
|
203
|
+
borderRadius: "0.375rem",
|
|
204
|
+
background: "var(--np-color-primary)",
|
|
205
|
+
color: "var(--np-color-primary-foreground)",
|
|
206
|
+
textDecoration: "none",
|
|
207
|
+
fontWeight: 500
|
|
208
|
+
},
|
|
209
|
+
children: "Homepage"
|
|
210
|
+
}
|
|
211
|
+
)
|
|
212
|
+
]
|
|
213
|
+
}
|
|
214
|
+
);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// src/routes/doc-detail.tsx
|
|
218
|
+
import { findDocuments as findDocuments2 } from "@nexpress/core";
|
|
219
|
+
import { notFound } from "next/navigation";
|
|
220
|
+
|
|
221
|
+
// src/templates/doc-page.tsx
|
|
222
|
+
import { findDocuments } from "@nexpress/core";
|
|
223
|
+
import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
224
|
+
async function DocPageTemplate({
|
|
225
|
+
doc: rawDoc
|
|
226
|
+
}) {
|
|
227
|
+
const doc = rawDoc;
|
|
228
|
+
const settings = await resolveDocsSettings();
|
|
229
|
+
const navInfo = await loadPrevNext(doc);
|
|
230
|
+
return /* @__PURE__ */ jsxs5("article", { className: "np-docs-page", children: [
|
|
231
|
+
/* @__PURE__ */ jsx5("header", { children: /* @__PURE__ */ jsx5("h1", { children: doc.title }) }),
|
|
232
|
+
/* @__PURE__ */ jsx5("div", { className: "np-docs-body", children: /* @__PURE__ */ jsx5("pre", { style: { whiteSpace: "pre-wrap", fontFamily: "inherit" }, children: typeof doc.body === "string" ? doc.body : "Doc body unavailable." }) }),
|
|
233
|
+
settings.githubRepo ? /* @__PURE__ */ jsx5("p", { style: { marginTop: "2rem" }, children: /* @__PURE__ */ jsx5(
|
|
234
|
+
"a",
|
|
235
|
+
{
|
|
236
|
+
href: `${settings.githubRepo}/edit/main/docs/${doc.slug}.md`,
|
|
237
|
+
target: "_blank",
|
|
238
|
+
rel: "noreferrer",
|
|
239
|
+
style: {
|
|
240
|
+
fontSize: "0.875rem",
|
|
241
|
+
color: "var(--np-color-muted-foreground)"
|
|
242
|
+
},
|
|
243
|
+
children: "\u270F\uFE0F Edit on GitHub"
|
|
244
|
+
}
|
|
245
|
+
) }) : null,
|
|
246
|
+
/* @__PURE__ */ jsxs5("nav", { className: "np-docs-prev-next", "aria-label": "Pagination", children: [
|
|
247
|
+
navInfo.prev ? /* @__PURE__ */ jsxs5("a", { href: `/docs/${navInfo.prev.slug}`, children: [
|
|
248
|
+
/* @__PURE__ */ jsx5("span", { className: "np-docs-prev-next-label", children: "\u2190 Previous" }),
|
|
249
|
+
navInfo.prev.title
|
|
250
|
+
] }) : /* @__PURE__ */ jsx5("span", {}),
|
|
251
|
+
navInfo.next ? /* @__PURE__ */ jsxs5(
|
|
252
|
+
"a",
|
|
253
|
+
{
|
|
254
|
+
href: `/docs/${navInfo.next.slug}`,
|
|
255
|
+
style: { textAlign: "right" },
|
|
256
|
+
children: [
|
|
257
|
+
/* @__PURE__ */ jsx5("span", { className: "np-docs-prev-next-label", children: "Next \u2192" }),
|
|
258
|
+
navInfo.next.title
|
|
259
|
+
]
|
|
260
|
+
}
|
|
261
|
+
) : /* @__PURE__ */ jsx5("span", {})
|
|
262
|
+
] })
|
|
263
|
+
] });
|
|
264
|
+
}
|
|
265
|
+
async function loadPrevNext(current) {
|
|
266
|
+
const result = await findDocuments("docs", {
|
|
267
|
+
where: { status: "published" },
|
|
268
|
+
sort: "order",
|
|
269
|
+
limit: 500
|
|
270
|
+
});
|
|
271
|
+
const docs = result.docs;
|
|
272
|
+
const idx = docs.findIndex((d) => d.id === current.id);
|
|
273
|
+
if (idx < 0) return { prev: null, next: null };
|
|
274
|
+
return {
|
|
275
|
+
prev: idx > 0 ? docs[idx - 1] ?? null : null,
|
|
276
|
+
next: idx < docs.length - 1 ? docs[idx + 1] ?? null : null
|
|
277
|
+
};
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
// src/routes/doc-detail.tsx
|
|
281
|
+
import { jsx as jsx6 } from "react/jsx-runtime";
|
|
282
|
+
async function DocsDetailRoute({
|
|
283
|
+
params,
|
|
284
|
+
blockCtx
|
|
285
|
+
}) {
|
|
286
|
+
const slug = typeof params.slug === "string" ? params.slug : "";
|
|
287
|
+
if (!slug) notFound();
|
|
288
|
+
const result = await findDocuments2("docs", {
|
|
289
|
+
where: { slug, status: "published" },
|
|
290
|
+
limit: 1
|
|
291
|
+
});
|
|
292
|
+
const doc = result.docs[0];
|
|
293
|
+
if (!doc) notFound();
|
|
294
|
+
const templateProps = {
|
|
295
|
+
doc,
|
|
296
|
+
blockCtx
|
|
297
|
+
};
|
|
298
|
+
return /* @__PURE__ */ jsx6(DocPageTemplate, { ...templateProps });
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
// src/search.tsx
|
|
302
|
+
import { getCollectionConfig, searchCollections } from "@nexpress/core";
|
|
303
|
+
import { jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
304
|
+
function resolveResultUrl(collection, doc) {
|
|
305
|
+
try {
|
|
306
|
+
const config = getCollectionConfig(collection);
|
|
307
|
+
const urlPath = config.seo?.urlPath;
|
|
308
|
+
if (typeof urlPath === "function") {
|
|
309
|
+
const result = urlPath(doc);
|
|
310
|
+
if (typeof result === "string" && result.length > 0) return result;
|
|
311
|
+
}
|
|
312
|
+
} catch {
|
|
313
|
+
}
|
|
314
|
+
const slug = typeof doc.slug === "string" ? doc.slug : "";
|
|
315
|
+
return slug ? `/${collection}/${slug}` : "#";
|
|
316
|
+
}
|
|
317
|
+
async function DocsSearch({
|
|
318
|
+
searchParams
|
|
319
|
+
}) {
|
|
320
|
+
const raw = searchParams.q;
|
|
321
|
+
const query = typeof raw === "string" ? raw.trim() : "";
|
|
322
|
+
if (query.length === 0) {
|
|
323
|
+
return /* @__PURE__ */ jsxs6("div", { className: "np-docs-search", children: [
|
|
324
|
+
/* @__PURE__ */ jsx7("h1", { children: "Search" }),
|
|
325
|
+
/* @__PURE__ */ jsx7("p", { style: { color: "var(--np-color-muted-foreground)" }, children: "Enter a query in the masthead search box to find pages." })
|
|
326
|
+
] });
|
|
327
|
+
}
|
|
328
|
+
const result = await searchCollections({ q: query, limit: 20 });
|
|
329
|
+
return /* @__PURE__ */ jsxs6("div", { className: "np-docs-search", children: [
|
|
330
|
+
/* @__PURE__ */ jsxs6("h1", { children: [
|
|
331
|
+
"Search results for \u201C",
|
|
332
|
+
query,
|
|
333
|
+
"\u201D"
|
|
334
|
+
] }),
|
|
335
|
+
result.results.length === 0 ? /* @__PURE__ */ jsx7("p", { style: { color: "var(--np-color-muted-foreground)" }, children: "No matches." }) : /* @__PURE__ */ jsx7("ul", { style: { listStyle: "none", padding: 0, margin: "1.5rem 0 0" }, children: result.results.map((item, i) => {
|
|
336
|
+
const doc = item.doc;
|
|
337
|
+
const slug = typeof doc.slug === "string" ? doc.slug : null;
|
|
338
|
+
const title = typeof doc.title === "string" ? doc.title : slug ?? "Untitled";
|
|
339
|
+
const url = resolveResultUrl(item.collection, doc);
|
|
340
|
+
return /* @__PURE__ */ jsxs6(
|
|
341
|
+
"li",
|
|
342
|
+
{
|
|
343
|
+
style: {
|
|
344
|
+
padding: "1rem 0",
|
|
345
|
+
borderBottom: "1px solid var(--np-color-border)"
|
|
346
|
+
},
|
|
347
|
+
children: [
|
|
348
|
+
/* @__PURE__ */ jsx7(
|
|
349
|
+
"p",
|
|
350
|
+
{
|
|
351
|
+
style: {
|
|
352
|
+
margin: 0,
|
|
353
|
+
fontSize: "0.75rem",
|
|
354
|
+
textTransform: "uppercase",
|
|
355
|
+
letterSpacing: "0.08em",
|
|
356
|
+
color: "var(--np-color-muted-foreground)"
|
|
357
|
+
},
|
|
358
|
+
children: item.collection
|
|
359
|
+
}
|
|
360
|
+
),
|
|
361
|
+
/* @__PURE__ */ jsx7("h2", { style: { margin: "0.25rem 0 0.5rem", fontSize: "1.125rem" }, children: /* @__PURE__ */ jsx7(
|
|
362
|
+
"a",
|
|
363
|
+
{
|
|
364
|
+
href: url,
|
|
365
|
+
style: { color: "inherit", textDecoration: "none" },
|
|
366
|
+
children: title
|
|
367
|
+
}
|
|
368
|
+
) }),
|
|
369
|
+
typeof doc.excerpt === "string" ? /* @__PURE__ */ jsx7(
|
|
370
|
+
"p",
|
|
371
|
+
{
|
|
372
|
+
style: {
|
|
373
|
+
margin: 0,
|
|
374
|
+
color: "var(--np-color-muted-foreground)"
|
|
375
|
+
},
|
|
376
|
+
children: doc.excerpt
|
|
377
|
+
}
|
|
378
|
+
) : null
|
|
379
|
+
]
|
|
380
|
+
},
|
|
381
|
+
`${item.collection}:${doc.id ?? i}`
|
|
382
|
+
);
|
|
383
|
+
}) })
|
|
384
|
+
] });
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
// src/shell.tsx
|
|
388
|
+
import { jsx as jsx8 } from "react/jsx-runtime";
|
|
389
|
+
function DocsShell({ children }) {
|
|
390
|
+
return /* @__PURE__ */ jsx8("div", { className: "np-docs-shell", children: /* @__PURE__ */ jsx8("div", { className: "np-docs-grid", children }) });
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
// src/sidebar.tsx
|
|
394
|
+
import { findDocuments as findDocuments3 } from "@nexpress/core";
|
|
395
|
+
import { jsx as jsx9, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
396
|
+
async function DocsSidebar() {
|
|
397
|
+
const settings = await resolveDocsSettings();
|
|
398
|
+
const result = await findDocuments3("docs", {
|
|
399
|
+
where: { status: "published" },
|
|
400
|
+
sort: "order",
|
|
401
|
+
limit: 500
|
|
402
|
+
});
|
|
403
|
+
const tree = buildTree(result.docs);
|
|
404
|
+
return /* @__PURE__ */ jsxs7("aside", { className: "np-docs-sidebar", "aria-label": "Docs navigation", children: [
|
|
405
|
+
/* @__PURE__ */ jsx9("h2", { children: settings.sidebarHeading }),
|
|
406
|
+
/* @__PURE__ */ jsx9(NavTree, { nodes: tree })
|
|
407
|
+
] });
|
|
408
|
+
}
|
|
409
|
+
function buildTree(rawDocs) {
|
|
410
|
+
const docs = rawDocs;
|
|
411
|
+
const byId = /* @__PURE__ */ new Map();
|
|
412
|
+
for (const d of docs) {
|
|
413
|
+
if (typeof d.id !== "string") continue;
|
|
414
|
+
if (typeof d.slug !== "string") continue;
|
|
415
|
+
byId.set(d.id, {
|
|
416
|
+
id: d.id,
|
|
417
|
+
slug: d.slug,
|
|
418
|
+
title: typeof d.title === "string" ? d.title : d.slug,
|
|
419
|
+
parent: typeof d.parent === "string" ? d.parent : null,
|
|
420
|
+
order: typeof d.order === "number" ? d.order : 0,
|
|
421
|
+
children: []
|
|
422
|
+
});
|
|
423
|
+
}
|
|
424
|
+
const roots = [];
|
|
425
|
+
for (const node of byId.values()) {
|
|
426
|
+
if (node.parent && byId.has(node.parent)) {
|
|
427
|
+
byId.get(node.parent).children.push(node);
|
|
428
|
+
} else {
|
|
429
|
+
roots.push(node);
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
const sortRec = (list) => {
|
|
433
|
+
list.sort((a, b) => a.order - b.order);
|
|
434
|
+
for (const n of list) sortRec(n.children);
|
|
435
|
+
};
|
|
436
|
+
sortRec(roots);
|
|
437
|
+
return roots;
|
|
438
|
+
}
|
|
439
|
+
function NavTree({ nodes }) {
|
|
440
|
+
return /* @__PURE__ */ jsx9("ul", { children: nodes.map((n) => /* @__PURE__ */ jsxs7("li", { children: [
|
|
441
|
+
/* @__PURE__ */ jsx9("a", { href: `/docs/${n.slug}`, children: n.title }),
|
|
442
|
+
n.children.length > 0 ? /* @__PURE__ */ jsx9(NavTree, { nodes: n.children }) : null
|
|
443
|
+
] }, n.id)) });
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
// src/styles.ts
|
|
447
|
+
var docsCss = `
|
|
448
|
+
.np-docs-shell {
|
|
449
|
+
display: flex;
|
|
450
|
+
flex-direction: column;
|
|
451
|
+
min-height: 100vh;
|
|
452
|
+
background: var(--np-color-background);
|
|
453
|
+
color: var(--np-color-foreground);
|
|
454
|
+
font-family: var(--np-font-body, system-ui, sans-serif);
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
.np-docs-header {
|
|
458
|
+
position: sticky;
|
|
459
|
+
top: 0;
|
|
460
|
+
z-index: 50;
|
|
461
|
+
background: var(--np-color-background);
|
|
462
|
+
border-bottom: 1px solid var(--np-color-border);
|
|
463
|
+
backdrop-filter: blur(8px);
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
.np-docs-header-inner {
|
|
467
|
+
max-width: 1200px;
|
|
468
|
+
margin: 0 auto;
|
|
469
|
+
padding: 0.75rem 1.5rem;
|
|
470
|
+
display: grid;
|
|
471
|
+
grid-template-columns: auto 1fr auto;
|
|
472
|
+
gap: 1.5rem;
|
|
473
|
+
align-items: center;
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
.np-docs-brand {
|
|
477
|
+
display: flex;
|
|
478
|
+
align-items: baseline;
|
|
479
|
+
gap: 0.5rem;
|
|
480
|
+
font-weight: 600;
|
|
481
|
+
text-decoration: none;
|
|
482
|
+
color: var(--np-color-foreground);
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
.np-docs-brand-version {
|
|
486
|
+
font-size: 0.75rem;
|
|
487
|
+
font-family: ui-monospace, "SF Mono", Menlo, monospace;
|
|
488
|
+
color: var(--np-color-muted-foreground);
|
|
489
|
+
background: var(--np-color-muted);
|
|
490
|
+
padding: 0.125rem 0.375rem;
|
|
491
|
+
border-radius: 0.25rem;
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
.np-docs-search-form {
|
|
495
|
+
flex: 1;
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
.np-docs-search-input {
|
|
499
|
+
width: 100%;
|
|
500
|
+
padding: 0.4rem 0.75rem;
|
|
501
|
+
border: 1px solid var(--np-color-border);
|
|
502
|
+
border-radius: 0.375rem;
|
|
503
|
+
background: var(--np-color-card);
|
|
504
|
+
color: var(--np-color-foreground);
|
|
505
|
+
font-size: 0.875rem;
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
.np-docs-search-input:focus {
|
|
509
|
+
outline: 2px solid var(--np-color-primary);
|
|
510
|
+
outline-offset: -2px;
|
|
511
|
+
border-color: transparent;
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
.np-docs-nav {
|
|
515
|
+
display: flex;
|
|
516
|
+
align-items: center;
|
|
517
|
+
gap: 1rem;
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
.np-docs-primary-nav {
|
|
521
|
+
display: flex;
|
|
522
|
+
list-style: none;
|
|
523
|
+
margin: 0;
|
|
524
|
+
padding: 0;
|
|
525
|
+
gap: 1rem;
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
.np-docs-primary-nav a {
|
|
529
|
+
color: var(--np-color-muted-foreground);
|
|
530
|
+
text-decoration: none;
|
|
531
|
+
font-size: 0.875rem;
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
.np-docs-primary-nav a:hover {
|
|
535
|
+
color: var(--np-color-foreground);
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
.np-docs-github-link {
|
|
539
|
+
font-size: 0.875rem;
|
|
540
|
+
color: var(--np-color-muted-foreground);
|
|
541
|
+
text-decoration: none;
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
.np-docs-grid {
|
|
545
|
+
flex: 1;
|
|
546
|
+
display: grid;
|
|
547
|
+
grid-template-columns: 240px minmax(0, 1fr);
|
|
548
|
+
max-width: 1200px;
|
|
549
|
+
margin: 0 auto;
|
|
550
|
+
width: 100%;
|
|
551
|
+
gap: 2.5rem;
|
|
552
|
+
padding: 2rem 1.5rem;
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
@media (max-width: 768px) {
|
|
556
|
+
.np-docs-grid {
|
|
557
|
+
grid-template-columns: 1fr;
|
|
558
|
+
}
|
|
559
|
+
.np-docs-sidebar {
|
|
560
|
+
display: none;
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
.np-docs-sidebar {
|
|
565
|
+
position: sticky;
|
|
566
|
+
top: 4rem;
|
|
567
|
+
align-self: start;
|
|
568
|
+
max-height: calc(100vh - 5rem);
|
|
569
|
+
overflow-y: auto;
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
.np-docs-sidebar h2 {
|
|
573
|
+
font-size: 0.75rem;
|
|
574
|
+
text-transform: uppercase;
|
|
575
|
+
letter-spacing: 0.08em;
|
|
576
|
+
color: var(--np-color-muted-foreground);
|
|
577
|
+
margin: 0 0 0.75rem;
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
.np-docs-sidebar ul {
|
|
581
|
+
list-style: none;
|
|
582
|
+
padding: 0;
|
|
583
|
+
margin: 0;
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
.np-docs-sidebar li {
|
|
587
|
+
margin: 0.125rem 0;
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
.np-docs-sidebar a {
|
|
591
|
+
display: block;
|
|
592
|
+
padding: 0.25rem 0.5rem;
|
|
593
|
+
border-radius: 0.25rem;
|
|
594
|
+
color: var(--np-color-muted-foreground);
|
|
595
|
+
text-decoration: none;
|
|
596
|
+
font-size: 0.875rem;
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
.np-docs-sidebar a:hover {
|
|
600
|
+
background: var(--np-color-muted);
|
|
601
|
+
color: var(--np-color-foreground);
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
.np-docs-sidebar a[data-current="true"] {
|
|
605
|
+
background: color-mix(in oklch, var(--np-color-primary) 12%, transparent);
|
|
606
|
+
color: var(--np-color-primary);
|
|
607
|
+
font-weight: 500;
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
.np-docs-sidebar ul ul {
|
|
611
|
+
margin-left: 0.75rem;
|
|
612
|
+
border-left: 1px solid var(--np-color-border);
|
|
613
|
+
padding-left: 0.5rem;
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
.np-docs-page {
|
|
617
|
+
max-width: 720px;
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
.np-docs-page h1 {
|
|
621
|
+
font-size: 2rem;
|
|
622
|
+
margin: 0 0 0.5rem;
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
.np-docs-prev-next {
|
|
626
|
+
display: grid;
|
|
627
|
+
grid-template-columns: 1fr 1fr;
|
|
628
|
+
gap: 1rem;
|
|
629
|
+
margin-top: 3rem;
|
|
630
|
+
padding-top: 1.5rem;
|
|
631
|
+
border-top: 1px solid var(--np-color-border);
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
.np-docs-prev-next a {
|
|
635
|
+
display: block;
|
|
636
|
+
padding: 0.75rem 1rem;
|
|
637
|
+
border: 1px solid var(--np-color-border);
|
|
638
|
+
border-radius: 0.5rem;
|
|
639
|
+
color: var(--np-color-foreground);
|
|
640
|
+
text-decoration: none;
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
.np-docs-prev-next a:hover {
|
|
644
|
+
border-color: var(--np-color-primary);
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
.np-docs-prev-next-label {
|
|
648
|
+
display: block;
|
|
649
|
+
font-size: 0.75rem;
|
|
650
|
+
color: var(--np-color-muted-foreground);
|
|
651
|
+
margin-bottom: 0.25rem;
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
/* M.* member surface \u2014 narrow auth-form column under the
|
|
655
|
+
masthead, no sidebar (the docs sidebar is hierarchical
|
|
656
|
+
doc nav, useless on auth forms). */
|
|
657
|
+
.np-docs-members {
|
|
658
|
+
display: flex;
|
|
659
|
+
justify-content: center;
|
|
660
|
+
min-height: 60vh;
|
|
661
|
+
padding: 3rem 1.5rem;
|
|
662
|
+
}
|
|
663
|
+
.np-docs-members-column {
|
|
664
|
+
width: 100%;
|
|
665
|
+
max-width: 440px;
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
/* Member form token overrides \u2014 docs aesthetic: slightly
|
|
669
|
+
rounded corners, neutral palette, monospace label accent. */
|
|
670
|
+
.np-docs .np-members-form {
|
|
671
|
+
--np-member-form-input-bg: var(--np-color-background);
|
|
672
|
+
--np-member-form-input-border: var(--np-color-border);
|
|
673
|
+
--np-member-form-input-border-focus: var(--np-color-primary);
|
|
674
|
+
--np-member-form-input-radius: 0.375rem;
|
|
675
|
+
--np-member-form-button-radius: 0.375rem;
|
|
676
|
+
}
|
|
677
|
+
.np-docs .np-members-form .np-form-label {
|
|
678
|
+
font-family: var(--np-font-mono, ui-monospace, monospace);
|
|
679
|
+
font-size: 0.8125rem;
|
|
680
|
+
}
|
|
681
|
+
`;
|
|
682
|
+
|
|
683
|
+
// src/index.ts
|
|
684
|
+
var docsTheme = defineTheme({
|
|
685
|
+
manifest: {
|
|
686
|
+
id: "docs",
|
|
687
|
+
name: "Docs",
|
|
688
|
+
version: "0.1.0",
|
|
689
|
+
description: "Documentation theme \u2014 hierarchical sidebar, prev/next nav, search masthead. Pairs with a `docs` collection that has parent/order fields.",
|
|
690
|
+
author: { name: "NexPress" },
|
|
691
|
+
nexpress: { minVersion: "0.1.0" },
|
|
692
|
+
requires: {
|
|
693
|
+
collections: {
|
|
694
|
+
docs: {
|
|
695
|
+
createIfAbsent: true,
|
|
696
|
+
fields: {
|
|
697
|
+
title: { type: "text", required: true },
|
|
698
|
+
body: { type: "richText" },
|
|
699
|
+
parent: {
|
|
700
|
+
type: "relationship",
|
|
701
|
+
relationTo: "docs",
|
|
702
|
+
hard: false
|
|
703
|
+
},
|
|
704
|
+
order: { type: "number" }
|
|
705
|
+
}
|
|
706
|
+
}
|
|
707
|
+
}
|
|
708
|
+
},
|
|
709
|
+
settingsSchema: docsSettingsSchema
|
|
710
|
+
},
|
|
711
|
+
impl: {
|
|
712
|
+
shell: DocsShell,
|
|
713
|
+
slots: {
|
|
714
|
+
header: DocsHeader,
|
|
715
|
+
sidebar: DocsSidebar
|
|
716
|
+
},
|
|
717
|
+
css: docsCss,
|
|
718
|
+
tokens: {
|
|
719
|
+
// Docs lean cool/neutral with a sharp accent — distinct
|
|
720
|
+
// from magazine's warm cream so a side-by-side preview
|
|
721
|
+
// makes the swap obvious.
|
|
722
|
+
colors: {
|
|
723
|
+
primary: "oklch(0.55 0.18 260)",
|
|
724
|
+
primaryForeground: "oklch(0.985 0.005 260)",
|
|
725
|
+
background: "oklch(0.99 0.005 260)",
|
|
726
|
+
foreground: "oklch(0.18 0.025 260)",
|
|
727
|
+
muted: "oklch(0.95 0.012 260)",
|
|
728
|
+
mutedForeground: "oklch(0.5 0.025 260)",
|
|
729
|
+
border: "oklch(0.9 0.012 260)",
|
|
730
|
+
card: "oklch(0.985 0.008 260)",
|
|
731
|
+
cardForeground: "oklch(0.18 0.025 260)",
|
|
732
|
+
accent: "oklch(0.92 0.05 260)",
|
|
733
|
+
accentForeground: "oklch(0.18 0.025 260)"
|
|
734
|
+
}
|
|
735
|
+
},
|
|
736
|
+
templates: {
|
|
737
|
+
docs: {
|
|
738
|
+
default: {
|
|
739
|
+
label: "Doc page",
|
|
740
|
+
description: "Hierarchical sidebar + body + prev/next nav. Optional 'Edit on GitHub' link when settings.githubRepo is set.",
|
|
741
|
+
component: DocPageTemplate
|
|
742
|
+
}
|
|
743
|
+
}
|
|
744
|
+
},
|
|
745
|
+
routes: [
|
|
746
|
+
// F.2 — docs theme's scoped search route. Lives at
|
|
747
|
+
// `/docs/search` rather than `/search` (#609): the host's
|
|
748
|
+
// reference app has an app-explicit `/search` page route
|
|
749
|
+
// that takes precedence over theme routes per the locked
|
|
750
|
+
// dispatch order (app file > page > theme > plugin). The
|
|
751
|
+
// theme can't override the universal search page, so it
|
|
752
|
+
// scopes its own search to a `/docs/*` namespace and the
|
|
753
|
+
// operator gets both routes: framework `/search` + docs
|
|
754
|
+
// theme `/docs/search`.
|
|
755
|
+
//
|
|
756
|
+
// Order matters: search comes first so `/docs/search` is
|
|
757
|
+
// matched as a literal rather than `{ slug: "search" }`
|
|
758
|
+
// by the parametric detail route below (dispatcher is
|
|
759
|
+
// first-match-wins).
|
|
760
|
+
{ pattern: "/docs/search", component: DocsSearch },
|
|
761
|
+
// Doc detail dispatch (#614). The sidebar + template emit
|
|
762
|
+
// `/docs/<slug>` links; without this route those 404 in
|
|
763
|
+
// the reference app — the catch-all only resolves `pages`
|
|
764
|
+
// rows, not arbitrary `docs` collection rows. The
|
|
765
|
+
// component looks up the docs row by slug and renders
|
|
766
|
+
// through `templates.docs.default` (DocPageTemplate).
|
|
767
|
+
{ pattern: "/docs/:slug", component: DocsDetailRoute }
|
|
768
|
+
],
|
|
769
|
+
navLocations: {
|
|
770
|
+
primary: {
|
|
771
|
+
label: "Primary header nav",
|
|
772
|
+
description: "Inline links beside the masthead search box.",
|
|
773
|
+
maxItems: 5
|
|
774
|
+
}
|
|
775
|
+
},
|
|
776
|
+
notFound: DocsNotFound,
|
|
777
|
+
// M.* adoption (2026-05-11). Docs gains purpose-built member
|
|
778
|
+
// chrome: drops the docs sidebar (hierarchical doc nav is
|
|
779
|
+
// useless on auth forms), keeps the masthead, narrows the
|
|
780
|
+
// content column. Without this, the fallback chain would
|
|
781
|
+
// walk back to `impl.shell` (the 3-column grid) and the
|
|
782
|
+
// sidebar slot would surface alongside an auth form.
|
|
783
|
+
// - `shell`: DocsMembersShell (header + narrow column, no
|
|
784
|
+
// sidebar).
|
|
785
|
+
// - `notFound`: DocsMembersNotFound (stale-auth-link framing
|
|
786
|
+
// with /members/login CTA, monospace accent matching the
|
|
787
|
+
// theme).
|
|
788
|
+
// - `error`: forward-compat type marker; the actual render
|
|
789
|
+
// goes through `./components/members-error`'s client
|
|
790
|
+
// subpath, lazy-imported by
|
|
791
|
+
// `apps/web/src/app/(member)/error.tsx`'s registry
|
|
792
|
+
// (F.7.1 delegation — Next mandates `error.tsx` is "use
|
|
793
|
+
// client").
|
|
794
|
+
members: {
|
|
795
|
+
shell: DocsMembersShell,
|
|
796
|
+
notFound: DocsMembersNotFound
|
|
797
|
+
}
|
|
798
|
+
}
|
|
799
|
+
});
|
|
800
|
+
export {
|
|
801
|
+
DocPageTemplate,
|
|
802
|
+
DocsHeader,
|
|
803
|
+
DocsMembersNotFound,
|
|
804
|
+
DocsMembersShell,
|
|
805
|
+
DocsNotFound,
|
|
806
|
+
DocsSearch,
|
|
807
|
+
DocsShell,
|
|
808
|
+
DocsSidebar,
|
|
809
|
+
docsCss,
|
|
810
|
+
docsSettingsSchema,
|
|
811
|
+
docsTheme
|
|
812
|
+
};
|
|
813
|
+
//# sourceMappingURL=index.js.map
|