@clarify-labs/cli 0.6.7 → 0.7.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.
@@ -1,4 +1,4 @@
1
- import { existsSync, mkdirSync, mkdtempSync, readFileSync, readdirSync, rmSync, writeFileSync } from "node:fs";
1
+ import { createReadStream, existsSync, mkdirSync, mkdtempSync, readFileSync, readdirSync, rmSync, writeFileSync } from "node:fs";
2
2
  import { dirname, extname, isAbsolute, join, relative, resolve } from "node:path";
3
3
  import mdxPlugin from "@mdx-js/rollup";
4
4
  import tailwindcss from "@tailwindcss/vite";
@@ -11,9 +11,9 @@ import { markdownRemarkPlugins } from "@clarify-labs/renderer";
11
11
  import { remark } from "remark";
12
12
  import matter from "gray-matter";
13
13
  import SwaggerParser from "@apidevtools/swagger-parser";
14
+ import { tmpdir } from "node:os";
14
15
  import { mkdir, writeFile } from "node:fs/promises";
15
16
  import { z } from "zod";
16
- import { tmpdir } from "node:os";
17
17
  import { pathToFileURL } from "node:url";
18
18
  import { build, loadConfigFromFile } from "vite";
19
19
  import { createRequire } from "node:module";
@@ -232,8 +232,80 @@ function createContentArtifactsPlugin() {
232
232
  };
233
233
  }
234
234
  //#endregion
235
+ //#region source/core/theme.ts
236
+ var clarifyThemePresets = {
237
+ default: {
238
+ preset: "default",
239
+ tokens: {
240
+ colors: {
241
+ primary: "#047857",
242
+ accent: "#0D9488",
243
+ background: "#ffffff",
244
+ foreground: "#111827",
245
+ surface: "#ffffff",
246
+ muted: "#64748b",
247
+ border: "rgb(15 23 42 / 0.12)",
248
+ codeBackground: "#f6fbf8"
249
+ },
250
+ radius: {
251
+ sm: "6px",
252
+ md: "10px",
253
+ lg: "14px",
254
+ xl: "18px"
255
+ }
256
+ },
257
+ layout: { maxWidth: "82rem" },
258
+ editor: false
259
+ },
260
+ base: {
261
+ preset: "base",
262
+ tokens: {
263
+ colors: {
264
+ primary: "#18181b",
265
+ accent: "#52525b",
266
+ background: "#ffffff",
267
+ foreground: "#18181b",
268
+ surface: "#ffffff",
269
+ muted: "#71717a",
270
+ border: "rgb(24 24 27 / 0.12)",
271
+ codeBackground: "#f4f4f5"
272
+ },
273
+ radius: {
274
+ sm: "6px",
275
+ md: "8px",
276
+ lg: "12px",
277
+ xl: "16px"
278
+ }
279
+ },
280
+ layout: { maxWidth: "80rem" },
281
+ editor: false
282
+ }
283
+ };
284
+ function resolveThemeConfig(theme = {}) {
285
+ const preset = theme.preset ?? "default";
286
+ const presetTheme = clarifyThemePresets[preset];
287
+ return {
288
+ preset,
289
+ tokens: {
290
+ colors: {
291
+ ...presetTheme.tokens.colors,
292
+ ...theme.tokens?.colors
293
+ },
294
+ radius: {
295
+ ...presetTheme.tokens.radius,
296
+ ...theme.tokens?.radius
297
+ }
298
+ },
299
+ layout: {
300
+ ...presetTheme.layout,
301
+ ...theme.layout
302
+ },
303
+ editor: theme.editor ?? presetTheme.editor
304
+ };
305
+ }
306
+ //#endregion
235
307
  //#region source/plugins/html-shell/index.ts
236
- var THEME_BOOTSTRAP_SCRIPT = `(function(){try{var e=localStorage.getItem('clarify:theme');var t=e==='dark'||e==='light'||e==='system'?e:'system';var r=t==='system'?window.matchMedia('(prefers-color-scheme: dark)').matches:t==='dark';document.documentElement.classList.toggle('dark',r);document.documentElement.style.colorScheme=r?'dark':'light'}catch(e){}})();`;
308
+ var THEME_STORAGE_KEY = "clarify:theme";
237
309
  var REL_ICON_RE = /<link\s+[^>]*rel=["'][^"']*\bicon\b[^"']*["'][^>]*>/i;
238
310
  function inferIconType(href) {
239
311
  const path = href.split(/[?#]/, 1)[0]?.toLowerCase() ?? href.toLowerCase();
@@ -263,6 +335,62 @@ function createIconTags(icon) {
263
335
  if (lightIcon === darkIcon) return [createIconTag(lightIcon)];
264
336
  return [createIconTag(lightIcon, "(prefers-color-scheme: light)"), createIconTag(darkIcon, "(prefers-color-scheme: dark)")];
265
337
  }
338
+ function matchesPresetTheme(theme) {
339
+ const preset = clarifyThemePresets[theme.preset];
340
+ return JSON.stringify({
341
+ tokens: theme.tokens,
342
+ layout: theme.layout
343
+ }) === JSON.stringify({
344
+ tokens: preset.tokens,
345
+ layout: preset.layout
346
+ });
347
+ }
348
+ function effectiveTheme(theme, resolvedTheme) {
349
+ if (resolvedTheme !== "dark" || !matchesPresetTheme(theme)) return theme;
350
+ return {
351
+ ...theme,
352
+ tokens: {
353
+ ...theme.tokens,
354
+ colors: {
355
+ ...theme.tokens.colors,
356
+ background: "#09090b",
357
+ foreground: "#ffffff",
358
+ surface: "#18181b",
359
+ muted: "#a1a1aa",
360
+ border: "rgb(255 255 255 / 0.1)",
361
+ codeBackground: "#18181b"
362
+ }
363
+ }
364
+ };
365
+ }
366
+ function resolveThemeColorValue(value, resolvedTheme) {
367
+ return typeof value === "string" ? value : value[resolvedTheme] ?? value.light ?? value.dark ?? "";
368
+ }
369
+ function themeToCssVariables(theme, resolvedTheme) {
370
+ const resolved = effectiveTheme(theme, resolvedTheme);
371
+ const { colors } = resolved.tokens;
372
+ const { radius } = resolved.tokens;
373
+ return {
374
+ "--clarify-theme-tokens-colors-primary": resolveThemeColorValue(colors.primary, resolvedTheme),
375
+ "--clarify-theme-tokens-colors-accent": resolveThemeColorValue(colors.accent, resolvedTheme),
376
+ "--clarify-theme-tokens-colors-background": resolveThemeColorValue(colors.background, resolvedTheme),
377
+ "--clarify-theme-tokens-colors-foreground": resolveThemeColorValue(colors.foreground, resolvedTheme),
378
+ "--clarify-theme-tokens-colors-surface": resolveThemeColorValue(colors.surface, resolvedTheme),
379
+ "--clarify-theme-tokens-colors-muted": resolveThemeColorValue(colors.muted, resolvedTheme),
380
+ "--clarify-theme-tokens-colors-border": resolveThemeColorValue(colors.border, resolvedTheme),
381
+ "--clarify-theme-tokens-colors-code-background": resolveThemeColorValue(colors.codeBackground, resolvedTheme),
382
+ "--clarify-theme-tokens-radius-sm": radius.sm,
383
+ "--clarify-theme-tokens-radius-md": radius.md,
384
+ "--clarify-theme-tokens-radius-lg": radius.lg,
385
+ "--clarify-theme-tokens-radius-xl": radius.xl,
386
+ "--clarify-theme-layout-max-width": resolved.layout.maxWidth
387
+ };
388
+ }
389
+ function themeBootstrapScript(theme) {
390
+ const darkVariables = themeToCssVariables(theme, "dark");
391
+ const lightVariables = themeToCssVariables(theme, "light");
392
+ return `(function(){try{var e=localStorage.getItem(${JSON.stringify(THEME_STORAGE_KEY)});var t=e==='dark'||e==='light'||e==='system'?e:'system';var r=t==='system'?window.matchMedia('(prefers-color-scheme: dark)').matches:t==='dark';var v=r?${JSON.stringify(darkVariables)}:${JSON.stringify(lightVariables)};var s=document.documentElement.style;for(var k in v)s.setProperty(k,v[k]);document.documentElement.classList.toggle('dark',r);document.documentElement.style.colorScheme=r?'dark':'light'}catch(e){}})();`;
393
+ }
266
394
  function createHtmlShellPlugin() {
267
395
  return {
268
396
  name: "clarify:html-shell",
@@ -273,7 +401,7 @@ function createHtmlShellPlugin() {
273
401
  ...REL_ICON_RE.test(input.html) ? [] : createIconTags(ctx.projectConfig.favicon ?? ctx.projectConfig.logo),
274
402
  {
275
403
  tag: "script",
276
- children: THEME_BOOTSTRAP_SCRIPT,
404
+ children: themeBootstrapScript(ctx.projectConfig.theme),
277
405
  injectTo: "head-prepend"
278
406
  },
279
407
  {
@@ -750,8 +878,10 @@ function generateRoutesModule(routes, resolvedNavigation, projectConfig, mode =
750
878
  const navigation = resolvedNavigation ?? (projectConfig?.tabs ? projectConfig.i18n ? buildLocalizedNavigationFromTabsConfig(routes, projectConfig.tabs, projectConfig.i18n) ?? {} : buildNavigationFromTabsConfig(routes, projectConfig.tabs) : buildNavigation(routes));
751
879
  return `${imports}\n\nexport const routes = [\n${routesArray}\n];\n\nexport const navigation = ${JSON.stringify(navigation, null, 2)};\n`;
752
880
  }
753
- function createRuntimeModule() {
754
- return "export const openApis = {};";
881
+ function createRuntimeModule(options = {}) {
882
+ return `${options.footerComponentSource === "path" && options.imports?.footerComponent ? `import FooterComponent from ${moduleSpecifier(options.imports.footerComponent)};` : ""}
883
+ export const openApis = {};
884
+ export const footerComponent = ${options.footerComponentSource === "path" ? "FooterComponent" : "undefined"};`;
755
885
  }
756
886
  function createClientEntryModule(options = {}) {
757
887
  return `
@@ -759,16 +889,22 @@ import '@clarify-labs/renderer/style.css';
759
889
  import { render } from '@clarify-labs/renderer/client';
760
890
  import { routes, navigation } from '${VIRTUAL_ROUTES}';
761
891
  import { config } from '${VIRTUAL_CONFIG}';
762
- import { openApis } from '${VIRTUAL_RUNTIME}';
763
- render({ config, routes, navigation, openApis, themeEditor: ${JSON.stringify(options.themeEditor ?? false)} });`;
892
+ import { openApis, footerComponent } from '${VIRTUAL_RUNTIME}';
893
+ render({ config, routes, navigation, openApis, footerComponent, themeEditor: ${JSON.stringify(options.themeEditor ?? false)} });`;
764
894
  }
765
895
  function buildVirtualModules(args) {
766
896
  const modules = /* @__PURE__ */ new Map();
767
897
  const clientEntryModule = createClientEntryModule({ themeEditor: args.themeEditor });
898
+ const footerComponent = args.projectConfig.footer;
899
+ const footerComponentSource = typeof footerComponent === "string" ? "path" : void 0;
900
+ const footerComponentImport = typeof footerComponent === "string" ? footerComponent : void 0;
768
901
  modules.set(VIRTUAL_CONFIG, generateConfigModule(args.projectConfig, args.generateOptions));
769
902
  modules.set(VIRTUAL_ROUTES, generateRoutesModule(args.routes, args.navigation, args.projectConfig, "client"));
770
903
  modules.set(VIRTUAL_SERVER_ROUTES, generateRoutesModule(args.routes, args.navigation, args.projectConfig, "server"));
771
- modules.set(VIRTUAL_RUNTIME, createRuntimeModule());
904
+ modules.set(VIRTUAL_RUNTIME, createRuntimeModule({
905
+ footerComponentSource,
906
+ imports: { footerComponent: footerComponentImport }
907
+ }));
772
908
  modules.set(VIRTUAL_CLIENT_ENTRY, clientEntryModule);
773
909
  modules.set(RESOLVED_CLIENT_ENTRY, clientEntryModule);
774
910
  for (const route of args.routes) modules.set(route.virtualModuleId, `export { default } from ${moduleSpecifier(route.filePath)};`);
@@ -777,8 +913,12 @@ function buildVirtualModules(args) {
777
913
  //#endregion
778
914
  //#region source/plugins/openapi/virtual-modules.ts
779
915
  var openApiRegistryModuleId = VIRTUAL_RUNTIME;
780
- function generateOpenAPIRegistryModule(openApis) {
781
- return `export const openApis = ${JSON.stringify(openApis)};`;
916
+ function generateOpenAPIRegistryModule(openApis, runtimeModule = "") {
917
+ const openApisExport = `export const openApis = ${JSON.stringify(openApis)};`;
918
+ const openApisPlaceholder = /export const openApis = \{\};?/;
919
+ if (!runtimeModule) return openApisExport;
920
+ if (openApisPlaceholder.test(runtimeModule)) return runtimeModule.replace(openApisPlaceholder, openApisExport);
921
+ return runtimeModule;
782
922
  }
783
923
  function generateOpenAPIModule(spec, tagFilter) {
784
924
  return `import { createElement } from 'react';
@@ -906,7 +1046,7 @@ function createOpenAPIPlugin() {
906
1046
  return nextRoutes;
907
1047
  },
908
1048
  "modules:before": (modules, ctx) => {
909
- modules.set(openApiRegistryModuleId, generateOpenAPIRegistryModule(Object.fromEntries(Object.entries(specs).map(([moduleId, entry]) => [moduleId, entry.spec]))));
1049
+ modules.set(openApiRegistryModuleId, generateOpenAPIRegistryModule(Object.fromEntries(Object.entries(specs).map(([moduleId, entry]) => [moduleId, entry.spec])), modules.get(openApiRegistryModuleId)));
910
1050
  for (const [moduleId, entry] of Object.entries(specs)) modules.set(moduleId, generateOpenAPIModule(entry.spec, entry.tagFilter));
911
1051
  for (const route of ctx.routes.filter((route) => route.kind === "openapi" && route.diagnostic)) if (route.diagnostic) modules.set(route.virtualModuleId, generateOpenAPIErrorModule(route.diagnostic));
912
1052
  return modules;
@@ -915,6 +1055,180 @@ function createOpenAPIPlugin() {
915
1055
  };
916
1056
  }
917
1057
  //#endregion
1058
+ //#region source/core/search-language.ts
1059
+ function toPagefindLanguage(locale) {
1060
+ return locale?.trim().replace(/_/g, "-").split("-").filter(Boolean).join("-").toLowerCase() || "en";
1061
+ }
1062
+ //#endregion
1063
+ //#region source/core/temp-dir.ts
1064
+ function createClarifyTempDir(name) {
1065
+ return mkdtempSync(join(tmpdir(), `clarify-${name}-`));
1066
+ }
1067
+ function removeClarifyTempDir(path) {
1068
+ if (!path) return;
1069
+ rmSync(path, {
1070
+ recursive: true,
1071
+ force: true
1072
+ });
1073
+ }
1074
+ //#endregion
1075
+ //#region source/plugins/search-index/index.ts
1076
+ var pagefindContentTypes = {
1077
+ ".css": "text/css; charset=utf-8",
1078
+ ".js": "text/javascript; charset=utf-8",
1079
+ ".json": "application/json; charset=utf-8",
1080
+ ".wasm": "application/wasm"
1081
+ };
1082
+ function assertNoPagefindErrors(action, errors) {
1083
+ if (!errors?.length) return;
1084
+ throw new Error(`[clarify] Pagefind ${action} failed:\n${errors.join("\n")}`);
1085
+ }
1086
+ async function generatePagefindIndex(options) {
1087
+ const pagefind = await import("pagefind");
1088
+ const { errors, index } = await pagefind.createIndex({
1089
+ excludeSelectors: [
1090
+ "[data-pagefind-ignore]",
1091
+ "script",
1092
+ "style",
1093
+ "svg"
1094
+ ],
1095
+ includeCharacters: "._-/#:@",
1096
+ keepIndexUrl: false,
1097
+ verbose: false,
1098
+ writePlayground: false
1099
+ });
1100
+ assertNoPagefindErrors("createIndex", errors);
1101
+ if (!index) throw new Error("[clarify] Pagefind did not create an index.");
1102
+ try {
1103
+ const addResult = await index.addDirectory({
1104
+ path: options.sourceRoot ?? options.outputRoot,
1105
+ glob: "**/*.html"
1106
+ });
1107
+ assertNoPagefindErrors("addDirectory", addResult.errors);
1108
+ assertNoPagefindErrors("writeFiles", (await index.writeFiles({ outputPath: join(options.outputRoot, "pagefind") })).errors);
1109
+ return addResult.page_count;
1110
+ } finally {
1111
+ await index.deleteIndex();
1112
+ await pagefind.close();
1113
+ }
1114
+ }
1115
+ function routeSearchContent(route) {
1116
+ return [
1117
+ route.title,
1118
+ route.description,
1119
+ route.keywords?.join(" "),
1120
+ route.sections?.map((section) => section.title).join(" "),
1121
+ route.content
1122
+ ].filter(Boolean).join("\n\n");
1123
+ }
1124
+ async function generateDevSearchIndex(ctx, root) {
1125
+ const pagefind = await import("pagefind");
1126
+ const { errors, index } = await pagefind.createIndex({
1127
+ includeCharacters: "._-/#:@",
1128
+ keepIndexUrl: false,
1129
+ verbose: false,
1130
+ writePlayground: false
1131
+ });
1132
+ assertNoPagefindErrors("createIndex", errors);
1133
+ if (!index) throw new Error("[clarify] Pagefind did not create an index.");
1134
+ try {
1135
+ let pageCount = 0;
1136
+ for (const route of ctx.routes) {
1137
+ const content = routeSearchContent(route);
1138
+ if (!content.trim()) continue;
1139
+ const result = await index.addCustomRecord({
1140
+ url: route.path,
1141
+ content,
1142
+ language: toPagefindLanguage(route.locale ?? ctx.projectConfig.i18n?.defaultLocale),
1143
+ meta: { title: route.title }
1144
+ });
1145
+ assertNoPagefindErrors(`addCustomRecord ${route.path}`, result.errors);
1146
+ pageCount += 1;
1147
+ }
1148
+ assertNoPagefindErrors("writeFiles", (await index.writeFiles({ outputPath: join(root, "pagefind") })).errors);
1149
+ console.log(`[clarify] Dev search index generated for ${pageCount} pages.`);
1150
+ } finally {
1151
+ await index.deleteIndex();
1152
+ await pagefind.close();
1153
+ }
1154
+ }
1155
+ function normalizeDevPagefindPath(rawUrl, routePrefix) {
1156
+ const pathname = rawUrl?.split("?")[0];
1157
+ if (!pathname) return void 0;
1158
+ const normalizedPrefix = routePrefix && routePrefix !== "/" ? `/${routePrefix.replace(/^\/+|\/+$/g, "")}` : "";
1159
+ const pagefindPath = normalizedPrefix && pathname.startsWith(`${normalizedPrefix}/pagefind/`) ? pathname.slice(normalizedPrefix.length) : pathname;
1160
+ return pagefindPath.startsWith("/pagefind/") ? pagefindPath : void 0;
1161
+ }
1162
+ function serveDevPagefind(server, getRoot, ctx) {
1163
+ server.middlewares.use((req, res, next) => {
1164
+ const root = getRoot();
1165
+ const pagefindPath = normalizeDevPagefindPath(req.url, ctx.projectConfig.routePrefix);
1166
+ if (!root || !pagefindPath) {
1167
+ next();
1168
+ return;
1169
+ }
1170
+ const filePath = join(root, pagefindPath);
1171
+ const relativePath = relative(root, filePath);
1172
+ if (relativePath.startsWith("..") || relativePath === "" || !existsSync(filePath)) {
1173
+ next();
1174
+ return;
1175
+ }
1176
+ const contentType = pagefindContentTypes[extname(filePath)] ?? "application/octet-stream";
1177
+ res.setHeader("Content-Type", contentType);
1178
+ createReadStream(filePath).pipe(res);
1179
+ });
1180
+ }
1181
+ function createSearchIndexPlugin() {
1182
+ return {
1183
+ name: "clarify:search-index",
1184
+ hooks: {
1185
+ async "dev:configureServer"(server, ctx) {
1186
+ let currentRoot;
1187
+ const staleRoots = /* @__PURE__ */ new Set();
1188
+ const replaceDevIndex = async () => {
1189
+ const nextRoot = createClarifyTempDir("pagefind");
1190
+ await generateDevSearchIndex(ctx, nextRoot);
1191
+ const previousRoot = currentRoot;
1192
+ currentRoot = nextRoot;
1193
+ if (previousRoot) {
1194
+ staleRoots.add(previousRoot);
1195
+ setTimeout(() => {
1196
+ staleRoots.delete(previousRoot);
1197
+ removeClarifyTempDir(previousRoot);
1198
+ }, 3e4).unref?.();
1199
+ }
1200
+ };
1201
+ serveDevPagefind(server, () => currentRoot, ctx);
1202
+ await replaceDevIndex();
1203
+ let regenerateTimer;
1204
+ const regenerate = (filePath) => {
1205
+ if (!/\.(md|mdx|json|ya?ml)$/i.test(filePath)) return;
1206
+ if (regenerateTimer) clearTimeout(regenerateTimer);
1207
+ regenerateTimer = setTimeout(() => {
1208
+ replaceDevIndex().catch((err) => {
1209
+ console.error("[clarify] Failed to regenerate dev search index:", err);
1210
+ });
1211
+ }, 100);
1212
+ };
1213
+ server.watcher.on("add", regenerate);
1214
+ server.watcher.on("change", regenerate);
1215
+ server.watcher.on("unlink", regenerate);
1216
+ server.httpServer?.once("close", () => {
1217
+ if (regenerateTimer) clearTimeout(regenerateTimer);
1218
+ removeClarifyTempDir(currentRoot);
1219
+ for (const staleRoot of staleRoots) removeClarifyTempDir(staleRoot);
1220
+ });
1221
+ },
1222
+ async "build:done"(ctx) {
1223
+ const outputDirectory = ctx.generateOptions.outputDirectory;
1224
+ if (!outputDirectory) return;
1225
+ const pageCount = await generatePagefindIndex({ outputRoot: resolve(ctx.generateOptions.projectRoot, outputDirectory) });
1226
+ console.log(`[clarify] Search index generated for ${pageCount} pages.`);
1227
+ }
1228
+ }
1229
+ };
1230
+ }
1231
+ //#endregion
918
1232
  //#region source/plugins/seo/artifacts.ts
919
1233
  function trimTrailingSlash(value) {
920
1234
  return value.replace(/\/+$/, "");
@@ -1010,7 +1324,8 @@ function createBuiltinPlugins(options = {}) {
1010
1324
  createOpenAPIPlugin(),
1011
1325
  createSourceLinksPlugin(),
1012
1326
  createContentArtifactsPlugin(),
1013
- createSeoPlugin()
1327
+ createSeoPlugin(),
1328
+ createSearchIndexPlugin()
1014
1329
  ];
1015
1330
  if (options.htmlShell ?? true) plugins.push(createHtmlShellPlugin());
1016
1331
  return plugins;
@@ -1068,11 +1383,12 @@ var clarifyBannerConfigSchema = z.object({
1068
1383
  content: clarifyLocalizedTextSchema,
1069
1384
  dismissible: z.boolean().optional()
1070
1385
  });
1071
- var clarifyFooterConfigSchema = z.object({
1386
+ var clarifyFooterLinksConfigSchema = z.object({
1072
1387
  links: z.array(clarifyNavbarLinkSchema).optional(),
1073
1388
  socials: z.record(z.string(), z.string()).optional(),
1074
1389
  copyright: clarifyLocalizedTextSchema.optional()
1075
- });
1390
+ }).strict();
1391
+ var clarifyFooterConfigSchema = z.union([clarifyFooterLinksConfigSchema, z.string()]);
1076
1392
  var clarifySourceConfigSchema = z.object({
1077
1393
  repository: z.string(),
1078
1394
  branch: z.string().optional(),
@@ -1156,78 +1472,6 @@ var clarifyProjectConfigSchema = z.object({
1156
1472
  tabs: clarifyTabsConfigSchema.optional()
1157
1473
  });
1158
1474
  //#endregion
1159
- //#region source/core/theme.ts
1160
- var clarifyThemePresets = {
1161
- default: {
1162
- preset: "default",
1163
- tokens: {
1164
- colors: {
1165
- primary: "#047857",
1166
- accent: "#0D9488",
1167
- background: "#ffffff",
1168
- foreground: "#111827",
1169
- surface: "#ffffff",
1170
- muted: "#64748b",
1171
- border: "rgb(15 23 42 / 0.12)",
1172
- codeBackground: "#f6fbf8"
1173
- },
1174
- radius: {
1175
- sm: "6px",
1176
- md: "10px",
1177
- lg: "14px",
1178
- xl: "18px"
1179
- }
1180
- },
1181
- layout: { maxWidth: "82rem" },
1182
- editor: false
1183
- },
1184
- base: {
1185
- preset: "base",
1186
- tokens: {
1187
- colors: {
1188
- primary: "#18181b",
1189
- accent: "#52525b",
1190
- background: "#ffffff",
1191
- foreground: "#18181b",
1192
- surface: "#ffffff",
1193
- muted: "#71717a",
1194
- border: "rgb(24 24 27 / 0.12)",
1195
- codeBackground: "#f4f4f5"
1196
- },
1197
- radius: {
1198
- sm: "6px",
1199
- md: "8px",
1200
- lg: "12px",
1201
- xl: "16px"
1202
- }
1203
- },
1204
- layout: { maxWidth: "80rem" },
1205
- editor: false
1206
- }
1207
- };
1208
- function resolveThemeConfig(theme = {}) {
1209
- const preset = theme.preset ?? "default";
1210
- const presetTheme = clarifyThemePresets[preset];
1211
- return {
1212
- preset,
1213
- tokens: {
1214
- colors: {
1215
- ...presetTheme.tokens.colors,
1216
- ...theme.tokens?.colors
1217
- },
1218
- radius: {
1219
- ...presetTheme.tokens.radius,
1220
- ...theme.tokens?.radius
1221
- }
1222
- },
1223
- layout: {
1224
- ...presetTheme.layout,
1225
- ...theme.layout
1226
- },
1227
- editor: theme.editor ?? presetTheme.editor
1228
- };
1229
- }
1230
- //#endregion
1231
1475
  //#region source/core/config.ts
1232
1476
  function formatIssuePath(path) {
1233
1477
  return path.reduce((result, segment) => {
@@ -1521,13 +1765,13 @@ function routeOutputFiles(outputDirectory, route) {
1521
1765
  var SSR_ENTRY_CODE = `import { renderToHTML } from '@clarify-labs/renderer/server';
1522
1766
  import { routes, navigation } from 'virtual:clarify-routes/server';
1523
1767
  import { config } from 'virtual:clarify-config';
1524
- import { openApis } from 'virtual:clarify-runtime';
1768
+ import { openApis, footerComponent } from 'virtual:clarify-runtime';
1525
1769
 
1526
1770
  export function render(url) {
1527
- return renderToHTML({ config, routes, navigation, openApis, url, themeEditor: config.theme.editor });
1771
+ return renderToHTML({ config, routes, navigation, openApis, footerComponent, url, themeEditor: config.theme.editor });
1528
1772
  }`;
1529
1773
  function createTempEntryFile(content) {
1530
- const entryPath = join(mkdtempSync(join(tmpdir(), "clarify-ssr-")), "entry-server.ts");
1774
+ const entryPath = join(createClarifyTempDir("ssr"), "entry-server.ts");
1531
1775
  writeFileSync(entryPath, content, "utf-8");
1532
1776
  return entryPath;
1533
1777
  }
@@ -1567,6 +1811,7 @@ async function renderSSGRoutes(routes, projectConfig, outputDirectory, ssrBundle
1567
1811
  //#endregion
1568
1812
  //#region source/core/user-config.ts
1569
1813
  function defineConfig(config) {
1814
+ validateProjectConfig(config);
1570
1815
  return config;
1571
1816
  }
1572
1817
  var CONFIG_FILENAMES = [
@@ -1817,6 +2062,6 @@ function clarifyPlugin(options = {}) {
1817
2062
  ].flat().filter(Boolean);
1818
2063
  }
1819
2064
  //#endregion
1820
- export { resolveClarifySite as a, createClarifyRuntimeAliases as i, defineConfig as n, loadClarifyConfig as r, clarifyPlugin as t };
2065
+ export { resolveClarifySite as a, createClarifyRuntimeAliases as i, defineConfig as n, createClarifyTempDir as o, loadClarifyConfig as r, clarifyPlugin as t };
1821
2066
 
1822
- //# sourceMappingURL=plugin-Cx9lFenc.js.map
2067
+ //# sourceMappingURL=plugin-BNzlJ4o7.js.map