@marlinjai/clearify 1.11.2 → 1.13.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/README.md +1 -0
- package/dist/config-schema.json +225 -0
- package/dist/node/{chunk-PVTUVUBK.js → chunk-2WML2D77.js} +162 -11
- package/dist/node/{chunk-QTGT76RY.js → chunk-CTL4YL7C.js} +21 -0
- package/dist/node/{chunk-PFX7LHRZ.js → chunk-GWYMXKDL.js} +134 -8
- package/dist/node/{chunk-NGWAMBXS.js → chunk-HZRIVY25.js} +2 -2
- package/dist/node/{chunk-EMM4VLF7.js → chunk-XR4WG237.js} +5 -4
- package/dist/node/core/config.d.ts +78 -2
- package/dist/node/core/config.js +11 -3
- package/dist/node/core/navigation.js +1 -1
- package/dist/node/core/search.d.ts +1 -0
- package/dist/node/node/build.js +4 -4
- package/dist/node/node/check.js +3 -3
- package/dist/node/node/index.js +5 -5
- package/dist/node/types/index.d.ts +24 -2
- package/dist/node/vite-plugin/index.js +3 -3
- package/package.json +4 -2
- package/src/client/App.tsx +59 -16
- package/src/theme/Header.tsx +32 -0
- package/src/theme/admin/AdminDashboard.tsx +129 -0
- package/src/theme/admin/AdminLayout.tsx +240 -0
- package/src/theme/admin/ProjectsManager.tsx +546 -0
- package/src/theme/admin/SectionsManager.tsx +782 -0
- package/src/theme/admin/SiteSettings.tsx +414 -0
- package/src/theme/admin/components/ConfigPreview.tsx +166 -0
- package/src/theme/admin/components/ConfirmDialog.tsx +73 -0
- package/src/theme/admin/components/FormField.tsx +39 -0
- package/src/theme/admin/components/Modal.tsx +93 -0
- package/src/theme/admin/components/Toast.tsx +59 -0
- package/src/theme/admin/components/index.ts +4 -0
|
@@ -2,18 +2,23 @@ import {
|
|
|
2
2
|
parseOpenAPISpec
|
|
3
3
|
} from "./chunk-B2Q23JW3.js";
|
|
4
4
|
import {
|
|
5
|
+
ClearifyDataSchema,
|
|
6
|
+
deepMergeJsonWins,
|
|
7
|
+
loadDataConfig,
|
|
5
8
|
loadUserConfig,
|
|
6
9
|
resolveConfig,
|
|
7
10
|
resolveSections,
|
|
8
|
-
scanHubProjects
|
|
9
|
-
|
|
11
|
+
scanHubProjects,
|
|
12
|
+
writeDataConfig
|
|
13
|
+
} from "./chunk-2WML2D77.js";
|
|
10
14
|
import {
|
|
11
15
|
buildSectionData
|
|
12
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-CTL4YL7C.js";
|
|
13
17
|
|
|
14
18
|
// src/vite-plugin/index.ts
|
|
15
|
-
import { resolve } from "path";
|
|
16
|
-
import {
|
|
19
|
+
import { resolve, dirname } from "path";
|
|
20
|
+
import { fileURLToPath } from "url";
|
|
21
|
+
import { existsSync, readFileSync, readdirSync, statSync } from "fs";
|
|
17
22
|
import { dereference } from "@scalar/openapi-parser";
|
|
18
23
|
var VIRTUAL_CONFIG = "virtual:clearify/config";
|
|
19
24
|
var RESOLVED_VIRTUAL_CONFIG = "\0" + VIRTUAL_CONFIG;
|
|
@@ -29,6 +34,8 @@ var VIRTUAL_OPENAPI_SPEC = "virtual:clearify/openapi-spec";
|
|
|
29
34
|
var RESOLVED_VIRTUAL_OPENAPI_SPEC = "\0" + VIRTUAL_OPENAPI_SPEC;
|
|
30
35
|
var VIRTUAL_HUB = "virtual:clearify/hub";
|
|
31
36
|
var RESOLVED_VIRTUAL_HUB = "\0" + VIRTUAL_HUB;
|
|
37
|
+
var VIRTUAL_ADMIN_ENABLED = "virtual:clearify/admin-enabled";
|
|
38
|
+
var RESOLVED_VIRTUAL_ADMIN_ENABLED = "\0" + VIRTUAL_ADMIN_ENABLED;
|
|
32
39
|
function findFirstNavPath(items) {
|
|
33
40
|
for (const item of items) {
|
|
34
41
|
if (item.path) return item.path;
|
|
@@ -52,7 +59,8 @@ function clearifyPlugin(options = {}) {
|
|
|
52
59
|
function getRootFiles() {
|
|
53
60
|
return {
|
|
54
61
|
changelogPath: resolve(userRoot, "CHANGELOG.md"),
|
|
55
|
-
roadmapPath: resolve(userRoot, "ROADMAP.md")
|
|
62
|
+
roadmapPath: resolve(userRoot, "ROADMAP.md"),
|
|
63
|
+
...config.includeReadme ? { readmePath: resolve(userRoot, "README.md") } : {}
|
|
56
64
|
};
|
|
57
65
|
}
|
|
58
66
|
async function refreshDocs() {
|
|
@@ -241,6 +249,7 @@ ${routeEntries.join(",\n")}
|
|
|
241
249
|
if (id === VIRTUAL_MERMAID_SVGS) return RESOLVED_VIRTUAL_MERMAID_SVGS;
|
|
242
250
|
if (id === VIRTUAL_OPENAPI_SPEC) return RESOLVED_VIRTUAL_OPENAPI_SPEC;
|
|
243
251
|
if (id === VIRTUAL_HUB) return RESOLVED_VIRTUAL_HUB;
|
|
252
|
+
if (id === VIRTUAL_ADMIN_ENABLED) return RESOLVED_VIRTUAL_ADMIN_ENABLED;
|
|
244
253
|
return null;
|
|
245
254
|
},
|
|
246
255
|
async load(id) {
|
|
@@ -266,6 +275,10 @@ ${routeEntries.join(",\n")}
|
|
|
266
275
|
const hubData = config.hub ?? null;
|
|
267
276
|
return `export default ${JSON.stringify(hubData)};`;
|
|
268
277
|
}
|
|
278
|
+
if (id === RESOLVED_VIRTUAL_ADMIN_ENABLED) {
|
|
279
|
+
const enabled = resolvedViteConfig.command === "serve";
|
|
280
|
+
return `export default ${enabled};`;
|
|
281
|
+
}
|
|
269
282
|
return null;
|
|
270
283
|
},
|
|
271
284
|
configureServer(server) {
|
|
@@ -273,7 +286,7 @@ ${routeEntries.join(",\n")}
|
|
|
273
286
|
server.watcher.add(section.docsDir);
|
|
274
287
|
}
|
|
275
288
|
const rootFiles = getRootFiles();
|
|
276
|
-
for (const rootFile of [rootFiles.changelogPath, rootFiles.roadmapPath]) {
|
|
289
|
+
for (const rootFile of [rootFiles.changelogPath, rootFiles.roadmapPath, rootFiles.readmePath]) {
|
|
277
290
|
if (rootFile && existsSync(rootFile)) {
|
|
278
291
|
server.watcher.add(rootFile);
|
|
279
292
|
}
|
|
@@ -395,8 +408,9 @@ ${routeEntries.join(",\n")}
|
|
|
395
408
|
server.watcher.on("all", (event, path) => {
|
|
396
409
|
const isChangelog = path === rootFiles.changelogPath;
|
|
397
410
|
const isRoadmap = path === rootFiles.roadmapPath;
|
|
411
|
+
const isReadme = path === rootFiles.readmePath;
|
|
398
412
|
const isInSection = visibleSections.some((s) => path.startsWith(s.docsDir));
|
|
399
|
-
if (!isChangelog && !isRoadmap && !isInSection) return;
|
|
413
|
+
if (!isChangelog && !isRoadmap && !isReadme && !isInSection) return;
|
|
400
414
|
if (!path.endsWith(".md") && !path.endsWith(".mdx")) return;
|
|
401
415
|
if (event === "add" || event === "unlink" || event === "change") {
|
|
402
416
|
refreshDocs().then(() => {
|
|
@@ -410,6 +424,118 @@ ${routeEntries.join(",\n")}
|
|
|
410
424
|
});
|
|
411
425
|
}
|
|
412
426
|
});
|
|
427
|
+
const dataJsonPath = resolve(userRoot, "clearify.data.json");
|
|
428
|
+
server.watcher.add(dataJsonPath);
|
|
429
|
+
server.watcher.on("change", (changedPath) => {
|
|
430
|
+
if (changedPath === dataJsonPath) {
|
|
431
|
+
for (const resolvedId of [
|
|
432
|
+
RESOLVED_VIRTUAL_CONFIG,
|
|
433
|
+
RESOLVED_VIRTUAL_ROUTES,
|
|
434
|
+
RESOLVED_VIRTUAL_NAVIGATION,
|
|
435
|
+
RESOLVED_VIRTUAL_SEARCH_INDEX
|
|
436
|
+
]) {
|
|
437
|
+
const mod = server.moduleGraph.getModuleById(resolvedId);
|
|
438
|
+
if (mod) server.moduleGraph.invalidateModule(mod);
|
|
439
|
+
}
|
|
440
|
+
server.ws.send({ type: "full-reload" });
|
|
441
|
+
}
|
|
442
|
+
});
|
|
443
|
+
function readJsonBody(req) {
|
|
444
|
+
return new Promise((resolve2, reject) => {
|
|
445
|
+
const chunks = [];
|
|
446
|
+
req.on("data", (chunk) => chunks.push(chunk));
|
|
447
|
+
req.on("end", () => {
|
|
448
|
+
try {
|
|
449
|
+
resolve2(JSON.parse(Buffer.concat(chunks).toString()));
|
|
450
|
+
} catch {
|
|
451
|
+
reject(new Error("Invalid JSON"));
|
|
452
|
+
}
|
|
453
|
+
});
|
|
454
|
+
req.on("error", reject);
|
|
455
|
+
});
|
|
456
|
+
}
|
|
457
|
+
server.middlewares.use(async (req, res, next) => {
|
|
458
|
+
const url = req.url?.split("?") ?? [""];
|
|
459
|
+
const pathname = url[0];
|
|
460
|
+
const query = new URLSearchParams(url[1] ?? "");
|
|
461
|
+
if (!pathname.startsWith("/__clearify/api/")) return next();
|
|
462
|
+
res.setHeader("Content-Type", "application/json");
|
|
463
|
+
try {
|
|
464
|
+
if (req.method === "GET" && pathname === "/__clearify/api/config") {
|
|
465
|
+
res.end(JSON.stringify(config));
|
|
466
|
+
return;
|
|
467
|
+
}
|
|
468
|
+
if (req.method === "GET" && pathname === "/__clearify/api/config/data") {
|
|
469
|
+
const data = loadDataConfig(userRoot);
|
|
470
|
+
res.end(JSON.stringify(data));
|
|
471
|
+
return;
|
|
472
|
+
}
|
|
473
|
+
if (req.method === "PUT" && pathname === "/__clearify/api/config/data") {
|
|
474
|
+
const body = await readJsonBody(req);
|
|
475
|
+
const result = ClearifyDataSchema.safeParse(body);
|
|
476
|
+
if (!result.success) {
|
|
477
|
+
res.statusCode = 400;
|
|
478
|
+
res.end(JSON.stringify({ error: "Validation failed", issues: result.error.issues }));
|
|
479
|
+
return;
|
|
480
|
+
}
|
|
481
|
+
writeDataConfig(userRoot, body);
|
|
482
|
+
res.end(JSON.stringify({ ok: true }));
|
|
483
|
+
return;
|
|
484
|
+
}
|
|
485
|
+
if (req.method === "PATCH" && pathname === "/__clearify/api/config/data") {
|
|
486
|
+
const body = await readJsonBody(req);
|
|
487
|
+
const existing = loadDataConfig(userRoot);
|
|
488
|
+
const merged = deepMergeJsonWins(existing, body);
|
|
489
|
+
const result = ClearifyDataSchema.safeParse(merged);
|
|
490
|
+
if (!result.success) {
|
|
491
|
+
res.statusCode = 400;
|
|
492
|
+
res.end(JSON.stringify({ error: "Validation failed", issues: result.error.issues }));
|
|
493
|
+
return;
|
|
494
|
+
}
|
|
495
|
+
writeDataConfig(userRoot, merged);
|
|
496
|
+
res.end(JSON.stringify({ ok: true }));
|
|
497
|
+
return;
|
|
498
|
+
}
|
|
499
|
+
if (req.method === "GET" && pathname === "/__clearify/api/config/schema") {
|
|
500
|
+
const pkgDir = dirname(fileURLToPath(import.meta.url));
|
|
501
|
+
const schemaPath = resolve(pkgDir, "../../dist/config-schema.json");
|
|
502
|
+
if (existsSync(schemaPath)) {
|
|
503
|
+
res.end(readFileSync(schemaPath, "utf-8"));
|
|
504
|
+
} else {
|
|
505
|
+
res.statusCode = 404;
|
|
506
|
+
res.end(JSON.stringify({ error: "Schema file not found" }));
|
|
507
|
+
}
|
|
508
|
+
return;
|
|
509
|
+
}
|
|
510
|
+
if (req.method === "GET" && pathname === "/__clearify/api/fs/dirs") {
|
|
511
|
+
const rootParam = query.get("root") ?? ".";
|
|
512
|
+
const target = resolve(userRoot, rootParam);
|
|
513
|
+
if (!target.startsWith(userRoot)) {
|
|
514
|
+
res.statusCode = 403;
|
|
515
|
+
res.end(JSON.stringify({ error: "Path outside project root" }));
|
|
516
|
+
return;
|
|
517
|
+
}
|
|
518
|
+
if (!existsSync(target)) {
|
|
519
|
+
res.end(JSON.stringify({ dirs: [] }));
|
|
520
|
+
return;
|
|
521
|
+
}
|
|
522
|
+
const dirs = readdirSync(target).filter((entry) => {
|
|
523
|
+
try {
|
|
524
|
+
return statSync(resolve(target, entry)).isDirectory();
|
|
525
|
+
} catch {
|
|
526
|
+
return false;
|
|
527
|
+
}
|
|
528
|
+
});
|
|
529
|
+
res.end(JSON.stringify({ dirs }));
|
|
530
|
+
return;
|
|
531
|
+
}
|
|
532
|
+
res.statusCode = 404;
|
|
533
|
+
res.end(JSON.stringify({ error: "Not found" }));
|
|
534
|
+
} catch (err) {
|
|
535
|
+
res.statusCode = err.message === "Invalid JSON" ? 400 : 500;
|
|
536
|
+
res.end(JSON.stringify({ error: err.message ?? "Internal server error" }));
|
|
537
|
+
}
|
|
538
|
+
});
|
|
413
539
|
return () => {
|
|
414
540
|
server.middlewares.use((req, _res, next) => {
|
|
415
541
|
if (req.method !== "GET" || !req.headers.accept?.includes("text/html")) {
|
|
@@ -2,10 +2,10 @@ import {
|
|
|
2
2
|
loadUserConfig,
|
|
3
3
|
resolveConfig,
|
|
4
4
|
resolveSections
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-2WML2D77.js";
|
|
6
6
|
import {
|
|
7
7
|
scanDocs
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-CTL4YL7C.js";
|
|
9
9
|
|
|
10
10
|
// src/node/check.ts
|
|
11
11
|
import { resolve, relative } from "path";
|
|
@@ -8,15 +8,15 @@ import {
|
|
|
8
8
|
} from "./chunk-SCZZB7OE.js";
|
|
9
9
|
import {
|
|
10
10
|
clearifyPlugin
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-GWYMXKDL.js";
|
|
12
12
|
import {
|
|
13
13
|
loadUserConfig,
|
|
14
14
|
resolveConfig,
|
|
15
15
|
resolveSections
|
|
16
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-2WML2D77.js";
|
|
17
17
|
import {
|
|
18
18
|
buildSectionData
|
|
19
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-CTL4YL7C.js";
|
|
20
20
|
|
|
21
21
|
// src/node/build.ts
|
|
22
22
|
import { build as viteBuild } from "vite";
|
|
@@ -157,7 +157,8 @@ async function buildSite() {
|
|
|
157
157
|
const productionSections = allSections.filter((s) => !s.draft);
|
|
158
158
|
const rootFiles = {
|
|
159
159
|
changelogPath: resolve(userRoot, "CHANGELOG.md"),
|
|
160
|
-
roadmapPath: resolve(userRoot, "ROADMAP.md")
|
|
160
|
+
roadmapPath: resolve(userRoot, "ROADMAP.md"),
|
|
161
|
+
...config.includeReadme ? { readmePath: resolve(userRoot, "README.md") } : {}
|
|
161
162
|
};
|
|
162
163
|
const sectionDataList = productionSections.map(
|
|
163
164
|
(section) => buildSectionData(section, rootFiles, config.navigation)
|
|
@@ -1,10 +1,86 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { ClearifyConfig, ClearifyDataConfig, ResolvedSection } from '../types/index.js';
|
|
2
3
|
export { defineConfig } from '../types/index.js';
|
|
3
4
|
|
|
5
|
+
/** Zod schema for clearify.data.json — Tier 1+2 visual-config fields, all optional. */
|
|
6
|
+
declare const ClearifyDataSchema: z.ZodObject<{
|
|
7
|
+
name: z.ZodOptional<z.ZodString>;
|
|
8
|
+
siteUrl: z.ZodOptional<z.ZodString>;
|
|
9
|
+
theme: z.ZodOptional<z.ZodObject<{
|
|
10
|
+
primaryColor: z.ZodOptional<z.ZodString>;
|
|
11
|
+
mode: z.ZodOptional<z.ZodEnum<{
|
|
12
|
+
light: "light";
|
|
13
|
+
dark: "dark";
|
|
14
|
+
auto: "auto";
|
|
15
|
+
}>>;
|
|
16
|
+
}, z.core.$strip>>;
|
|
17
|
+
logo: z.ZodOptional<z.ZodObject<{
|
|
18
|
+
light: z.ZodOptional<z.ZodString>;
|
|
19
|
+
dark: z.ZodOptional<z.ZodString>;
|
|
20
|
+
}, z.core.$strip>>;
|
|
21
|
+
links: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
22
|
+
sections: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
23
|
+
label: z.ZodString;
|
|
24
|
+
docsDir: z.ZodString;
|
|
25
|
+
basePath: z.ZodOptional<z.ZodString>;
|
|
26
|
+
draft: z.ZodOptional<z.ZodBoolean>;
|
|
27
|
+
sitemap: z.ZodOptional<z.ZodBoolean>;
|
|
28
|
+
exclude: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
29
|
+
git: z.ZodOptional<z.ZodObject<{
|
|
30
|
+
repo: z.ZodString;
|
|
31
|
+
ref: z.ZodOptional<z.ZodString>;
|
|
32
|
+
path: z.ZodOptional<z.ZodString>;
|
|
33
|
+
sparse: z.ZodOptional<z.ZodBoolean>;
|
|
34
|
+
}, z.core.$strip>>;
|
|
35
|
+
}, z.core.$strip>>>;
|
|
36
|
+
hub: z.ZodOptional<z.ZodObject<{
|
|
37
|
+
projects: z.ZodDefault<z.ZodArray<z.ZodObject<{
|
|
38
|
+
name: z.ZodString;
|
|
39
|
+
description: z.ZodString;
|
|
40
|
+
href: z.ZodOptional<z.ZodString>;
|
|
41
|
+
repo: z.ZodOptional<z.ZodString>;
|
|
42
|
+
status: z.ZodDefault<z.ZodEnum<{
|
|
43
|
+
active: "active";
|
|
44
|
+
beta: "beta";
|
|
45
|
+
planned: "planned";
|
|
46
|
+
deprecated: "deprecated";
|
|
47
|
+
}>>;
|
|
48
|
+
icon: z.ZodOptional<z.ZodString>;
|
|
49
|
+
tags: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
50
|
+
group: z.ZodOptional<z.ZodString>;
|
|
51
|
+
mode: z.ZodOptional<z.ZodEnum<{
|
|
52
|
+
link: "link";
|
|
53
|
+
embed: "embed";
|
|
54
|
+
inject: "inject";
|
|
55
|
+
}>>;
|
|
56
|
+
git: z.ZodOptional<z.ZodObject<{
|
|
57
|
+
repo: z.ZodString;
|
|
58
|
+
ref: z.ZodOptional<z.ZodString>;
|
|
59
|
+
path: z.ZodOptional<z.ZodString>;
|
|
60
|
+
sparse: z.ZodOptional<z.ZodBoolean>;
|
|
61
|
+
}, z.core.$strip>>;
|
|
62
|
+
embedSections: z.ZodOptional<z.ZodUnion<readonly [z.ZodLiteral<"all">, z.ZodLiteral<"public">, z.ZodArray<z.ZodString>]>>;
|
|
63
|
+
injectInto: z.ZodOptional<z.ZodString>;
|
|
64
|
+
docsPath: z.ZodOptional<z.ZodString>;
|
|
65
|
+
}, z.core.$strip>>>;
|
|
66
|
+
scan: z.ZodOptional<z.ZodString>;
|
|
67
|
+
cacheDir: z.ZodOptional<z.ZodString>;
|
|
68
|
+
}, z.core.$strip>>;
|
|
69
|
+
}, z.core.$strip>;
|
|
70
|
+
/**
|
|
71
|
+
* Deep-merge utility where JSON (overlay) values win over base values.
|
|
72
|
+
* Plain objects merge recursively. Arrays are replaced entirely.
|
|
73
|
+
* Undefined values in the overlay are skipped.
|
|
74
|
+
*/
|
|
75
|
+
declare function deepMergeJsonWins<T extends Record<string, any>>(base: T, json: Partial<T>): T;
|
|
76
|
+
/** Load and validate clearify.data.json from a project root. Returns `{}` on missing/invalid file. */
|
|
77
|
+
declare function loadDataConfig(root: string): ClearifyDataConfig;
|
|
78
|
+
/** Validate and atomically write clearify.data.json. */
|
|
79
|
+
declare function writeDataConfig(root: string, data: unknown): void;
|
|
4
80
|
declare const defaultConfig: ClearifyConfig;
|
|
5
81
|
declare function loadUserConfig(root: string): Promise<Partial<ClearifyConfig>>;
|
|
6
82
|
declare function resolveConfig(userConfig?: Partial<ClearifyConfig>, root?: string): ClearifyConfig;
|
|
7
83
|
declare function resolveSections(config: ClearifyConfig, root: string): Promise<ResolvedSection[]>;
|
|
8
84
|
declare function scanHubProjects(config: ClearifyConfig, root: string): Promise<ClearifyConfig>;
|
|
9
85
|
|
|
10
|
-
export { defaultConfig, loadUserConfig, resolveConfig, resolveSections, scanHubProjects };
|
|
86
|
+
export { ClearifyDataSchema, deepMergeJsonWins, defaultConfig, loadDataConfig, loadUserConfig, resolveConfig, resolveSections, scanHubProjects, writeDataConfig };
|
package/dist/node/core/config.js
CHANGED
|
@@ -1,19 +1,27 @@
|
|
|
1
1
|
import {
|
|
2
|
+
ClearifyDataSchema,
|
|
3
|
+
deepMergeJsonWins,
|
|
2
4
|
defaultConfig,
|
|
5
|
+
loadDataConfig,
|
|
3
6
|
loadUserConfig,
|
|
4
7
|
resolveConfig,
|
|
5
8
|
resolveSections,
|
|
6
|
-
scanHubProjects
|
|
7
|
-
|
|
9
|
+
scanHubProjects,
|
|
10
|
+
writeDataConfig
|
|
11
|
+
} from "../chunk-2WML2D77.js";
|
|
8
12
|
import "../chunk-AJBCHKBP.js";
|
|
9
13
|
import {
|
|
10
14
|
defineConfig
|
|
11
15
|
} from "../chunk-V7LLYIRO.js";
|
|
12
16
|
export {
|
|
17
|
+
ClearifyDataSchema,
|
|
18
|
+
deepMergeJsonWins,
|
|
13
19
|
defaultConfig,
|
|
14
20
|
defineConfig,
|
|
21
|
+
loadDataConfig,
|
|
15
22
|
loadUserConfig,
|
|
16
23
|
resolveConfig,
|
|
17
24
|
resolveSections,
|
|
18
|
-
scanHubProjects
|
|
25
|
+
scanHubProjects,
|
|
26
|
+
writeDataConfig
|
|
19
27
|
};
|
|
@@ -29,6 +29,7 @@ interface SectionData {
|
|
|
29
29
|
interface RootFileOptions {
|
|
30
30
|
changelogPath?: string;
|
|
31
31
|
roadmapPath?: string;
|
|
32
|
+
readmePath?: string;
|
|
32
33
|
}
|
|
33
34
|
declare function buildSectionData(section: ResolvedSection, rootFiles?: RootFileOptions, customNavigation?: NavigationItem[] | null): SectionData;
|
|
34
35
|
|
package/dist/node/node/build.js
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import {
|
|
2
2
|
buildSite
|
|
3
|
-
} from "../chunk-
|
|
3
|
+
} from "../chunk-XR4WG237.js";
|
|
4
4
|
import "../chunk-PRTER35L.js";
|
|
5
5
|
import "../chunk-SCZZB7OE.js";
|
|
6
|
-
import "../chunk-
|
|
6
|
+
import "../chunk-GWYMXKDL.js";
|
|
7
7
|
import "../chunk-B2Q23JW3.js";
|
|
8
|
-
import "../chunk-
|
|
8
|
+
import "../chunk-2WML2D77.js";
|
|
9
9
|
import "../chunk-AJBCHKBP.js";
|
|
10
10
|
import "../chunk-V7LLYIRO.js";
|
|
11
|
-
import "../chunk-
|
|
11
|
+
import "../chunk-CTL4YL7C.js";
|
|
12
12
|
import "../chunk-5TD7NQIW.js";
|
|
13
13
|
export {
|
|
14
14
|
buildSite
|
package/dist/node/node/check.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import {
|
|
2
2
|
checkFrontmatter,
|
|
3
3
|
checkLinks
|
|
4
|
-
} from "../chunk-
|
|
5
|
-
import "../chunk-
|
|
4
|
+
} from "../chunk-HZRIVY25.js";
|
|
5
|
+
import "../chunk-2WML2D77.js";
|
|
6
6
|
import "../chunk-AJBCHKBP.js";
|
|
7
7
|
import "../chunk-V7LLYIRO.js";
|
|
8
|
-
import "../chunk-
|
|
8
|
+
import "../chunk-CTL4YL7C.js";
|
|
9
9
|
import "../chunk-5TD7NQIW.js";
|
|
10
10
|
export {
|
|
11
11
|
checkFrontmatter,
|
package/dist/node/node/index.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import {
|
|
2
2
|
buildSite
|
|
3
|
-
} from "../chunk-
|
|
3
|
+
} from "../chunk-XR4WG237.js";
|
|
4
4
|
import {
|
|
5
5
|
remarkMermaidToComponent
|
|
6
6
|
} from "../chunk-PRTER35L.js";
|
|
7
7
|
import "../chunk-SCZZB7OE.js";
|
|
8
8
|
import {
|
|
9
9
|
clearifyPlugin
|
|
10
|
-
} from "../chunk-
|
|
10
|
+
} from "../chunk-GWYMXKDL.js";
|
|
11
11
|
import "../chunk-B2Q23JW3.js";
|
|
12
12
|
import {
|
|
13
13
|
init
|
|
@@ -15,14 +15,14 @@ import {
|
|
|
15
15
|
import {
|
|
16
16
|
checkFrontmatter,
|
|
17
17
|
checkLinks
|
|
18
|
-
} from "../chunk-
|
|
18
|
+
} from "../chunk-HZRIVY25.js";
|
|
19
19
|
import {
|
|
20
20
|
loadUserConfig,
|
|
21
21
|
resolveConfig
|
|
22
|
-
} from "../chunk-
|
|
22
|
+
} from "../chunk-2WML2D77.js";
|
|
23
23
|
import "../chunk-AJBCHKBP.js";
|
|
24
24
|
import "../chunk-V7LLYIRO.js";
|
|
25
|
-
import "../chunk-
|
|
25
|
+
import "../chunk-CTL4YL7C.js";
|
|
26
26
|
import "../chunk-5TD7NQIW.js";
|
|
27
27
|
|
|
28
28
|
// src/node/index.ts
|
|
@@ -61,6 +61,7 @@ interface ClearifyConfig {
|
|
|
61
61
|
hubProject?: Omit<HubProject, 'name'>;
|
|
62
62
|
customCss?: string;
|
|
63
63
|
headTags?: string[];
|
|
64
|
+
includeReadme?: boolean;
|
|
64
65
|
}
|
|
65
66
|
interface NavigationItem {
|
|
66
67
|
label: string;
|
|
@@ -102,15 +103,36 @@ interface HubProject {
|
|
|
102
103
|
group?: string;
|
|
103
104
|
hubUrl?: string;
|
|
104
105
|
hubName?: string;
|
|
105
|
-
mode?: 'link' | 'embed';
|
|
106
|
+
mode?: 'link' | 'embed' | 'inject';
|
|
106
107
|
git?: RemoteGitSource;
|
|
107
108
|
embedSections?: 'all' | 'public' | string[];
|
|
109
|
+
injectInto?: string;
|
|
110
|
+
docsPath?: string;
|
|
108
111
|
}
|
|
109
112
|
interface HubConfig {
|
|
110
113
|
projects: HubProject[];
|
|
111
114
|
scan?: string;
|
|
112
115
|
cacheDir?: string;
|
|
113
116
|
}
|
|
117
|
+
/** Tier 1+2 fields that can live in clearify.data.json for visual editing. */
|
|
118
|
+
interface ClearifyDataConfig {
|
|
119
|
+
name?: string;
|
|
120
|
+
siteUrl?: string;
|
|
121
|
+
theme?: {
|
|
122
|
+
primaryColor?: string;
|
|
123
|
+
mode?: 'light' | 'dark' | 'auto';
|
|
124
|
+
};
|
|
125
|
+
logo?: {
|
|
126
|
+
light?: string;
|
|
127
|
+
dark?: string;
|
|
128
|
+
};
|
|
129
|
+
links?: {
|
|
130
|
+
github?: string;
|
|
131
|
+
[key: string]: string | undefined;
|
|
132
|
+
};
|
|
133
|
+
sections?: SectionConfig[];
|
|
134
|
+
hub?: HubConfig;
|
|
135
|
+
}
|
|
114
136
|
declare function defineConfig(config: Partial<ClearifyConfig>): Partial<ClearifyConfig>;
|
|
115
137
|
|
|
116
|
-
export { type ClearifyConfig, type DocCategory, type HubConfig, type HubProject, type NavigationItem, type PageFrontmatter, type RemoteGitSource, type ResolvedSection, type RouteEntry, type SectionConfig, type SectionNavigation, defineConfig };
|
|
138
|
+
export { type ClearifyConfig, type ClearifyDataConfig, type DocCategory, type HubConfig, type HubProject, type NavigationItem, type PageFrontmatter, type RemoteGitSource, type ResolvedSection, type RouteEntry, type SectionConfig, type SectionNavigation, defineConfig };
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import {
|
|
2
2
|
clearifyPlugin
|
|
3
|
-
} from "../chunk-
|
|
3
|
+
} from "../chunk-GWYMXKDL.js";
|
|
4
4
|
import "../chunk-B2Q23JW3.js";
|
|
5
|
-
import "../chunk-
|
|
5
|
+
import "../chunk-2WML2D77.js";
|
|
6
6
|
import "../chunk-AJBCHKBP.js";
|
|
7
7
|
import "../chunk-V7LLYIRO.js";
|
|
8
|
-
import "../chunk-
|
|
8
|
+
import "../chunk-CTL4YL7C.js";
|
|
9
9
|
import "../chunk-5TD7NQIW.js";
|
|
10
10
|
export {
|
|
11
11
|
clearifyPlugin
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@marlinjai/clearify",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.13.0",
|
|
4
4
|
"description": "An open-source documentation site generator. Turn markdown into beautiful docs.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -14,7 +14,8 @@
|
|
|
14
14
|
"./config": {
|
|
15
15
|
"types": "./dist/node/core/config.d.ts",
|
|
16
16
|
"import": "./dist/node/core/config.js"
|
|
17
|
-
}
|
|
17
|
+
},
|
|
18
|
+
"./config-schema.json": "./dist/config-schema.json"
|
|
18
19
|
},
|
|
19
20
|
"files": [
|
|
20
21
|
"bin",
|
|
@@ -24,6 +25,7 @@
|
|
|
24
25
|
],
|
|
25
26
|
"scripts": {
|
|
26
27
|
"build": "tsup",
|
|
28
|
+
"postbuild": "node scripts/generate-schema.mjs",
|
|
27
29
|
"dev:self": "node bin/clearify.js dev",
|
|
28
30
|
"prepare": "husky",
|
|
29
31
|
"release": "semantic-release"
|
package/src/client/App.tsx
CHANGED
|
@@ -7,12 +7,20 @@ import routes from 'virtual:clearify/routes';
|
|
|
7
7
|
import config from 'virtual:clearify/config';
|
|
8
8
|
// @ts-expect-error virtual module
|
|
9
9
|
import sections from 'virtual:clearify/navigation';
|
|
10
|
+
// @ts-expect-error virtual module
|
|
11
|
+
import adminEnabled from 'virtual:clearify/admin-enabled';
|
|
10
12
|
import { Layout } from '../theme/Layout.js';
|
|
11
13
|
import { Head } from '../theme/Head.js';
|
|
12
14
|
import { NotFound } from '../theme/NotFound.js';
|
|
13
15
|
import { mdxComponents } from '../theme/MDXComponents.js';
|
|
14
16
|
import '../theme/styles/globals.css';
|
|
15
17
|
|
|
18
|
+
const AdminLayout = React.lazy(() => import('../theme/admin/AdminLayout.js'));
|
|
19
|
+
const AdminDashboard = React.lazy(() => import('../theme/admin/AdminDashboard.js'));
|
|
20
|
+
const ProjectsManager = React.lazy(() => import('../theme/admin/ProjectsManager.js'));
|
|
21
|
+
const SectionsManager = React.lazy(() => import('../theme/admin/SectionsManager.js'));
|
|
22
|
+
const SiteSettings = React.lazy(() => import('../theme/admin/SiteSettings.js'));
|
|
23
|
+
|
|
16
24
|
interface RouteEntry {
|
|
17
25
|
path: string;
|
|
18
26
|
component?: () => Promise<any>;
|
|
@@ -74,24 +82,59 @@ function PageWrapper({ loader, fallbackFrontmatter }: { loader: () => Promise<an
|
|
|
74
82
|
);
|
|
75
83
|
}
|
|
76
84
|
|
|
85
|
+
function AdminDisabled() {
|
|
86
|
+
return (
|
|
87
|
+
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', minHeight: '100vh', color: 'var(--clearify-text-secondary)', fontFamily: 'var(--font-sans)' }}>
|
|
88
|
+
Admin panel is only available in dev mode.
|
|
89
|
+
</div>
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
|
|
77
93
|
function AppRoutes() {
|
|
78
94
|
return (
|
|
79
|
-
<
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
<
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
+
<Routes>
|
|
96
|
+
{/* Admin routes — outside Layout, lazy-loaded */}
|
|
97
|
+
{adminEnabled ? (
|
|
98
|
+
<Route
|
|
99
|
+
path="/admin"
|
|
100
|
+
element={
|
|
101
|
+
<React.Suspense fallback={<div style={{ padding: '2rem', color: 'var(--clearify-text-secondary)' }}>Loading...</div>}>
|
|
102
|
+
<AdminLayout />
|
|
103
|
+
</React.Suspense>
|
|
104
|
+
}
|
|
105
|
+
>
|
|
106
|
+
<Route index element={<AdminDashboard />} />
|
|
107
|
+
<Route path="projects" element={<ProjectsManager />} />
|
|
108
|
+
<Route path="sections" element={<SectionsManager />} />
|
|
109
|
+
<Route path="settings" element={<SiteSettings />} />
|
|
110
|
+
</Route>
|
|
111
|
+
) : (
|
|
112
|
+
<Route path="/admin/*" element={<AdminDisabled />} />
|
|
113
|
+
)}
|
|
114
|
+
|
|
115
|
+
{/* Docs routes — wrapped in Layout */}
|
|
116
|
+
<Route
|
|
117
|
+
path="*"
|
|
118
|
+
element={
|
|
119
|
+
<Layout config={config} sections={sections}>
|
|
120
|
+
<Routes>
|
|
121
|
+
{(routes as RouteEntry[]).map((route) =>
|
|
122
|
+
route.redirectTo ? (
|
|
123
|
+
<Route key={route.path} path={route.path} element={<Navigate to={route.redirectTo} replace />} />
|
|
124
|
+
) : (
|
|
125
|
+
<Route
|
|
126
|
+
key={route.path}
|
|
127
|
+
path={route.path}
|
|
128
|
+
element={<PageWrapper loader={route.component!} fallbackFrontmatter={route.frontmatter} />}
|
|
129
|
+
/>
|
|
130
|
+
)
|
|
131
|
+
)}
|
|
132
|
+
<Route path="*" element={<NotFound />} />
|
|
133
|
+
</Routes>
|
|
134
|
+
</Layout>
|
|
135
|
+
}
|
|
136
|
+
/>
|
|
137
|
+
</Routes>
|
|
95
138
|
);
|
|
96
139
|
}
|
|
97
140
|
|