@zpress/core 0.3.0 → 0.5.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/dist/index.d.ts +117 -16
- package/dist/index.mjs +87 -12
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -69,12 +69,22 @@ export declare interface CardConfig {
|
|
|
69
69
|
};
|
|
70
70
|
}
|
|
71
71
|
|
|
72
|
+
/**
|
|
73
|
+
* All valid color modes — used for validation.
|
|
74
|
+
*/
|
|
75
|
+
export declare const COLOR_MODES: readonly ColorMode[];
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* How dark/light mode is controlled.
|
|
79
|
+
*/
|
|
80
|
+
export declare type ColorMode = 'dark' | 'light' | 'toggle';
|
|
81
|
+
|
|
72
82
|
/**
|
|
73
83
|
* Error produced during config validation in `defineConfig`.
|
|
74
84
|
*/
|
|
75
85
|
export declare interface ConfigError {
|
|
76
86
|
readonly _tag: 'ConfigError';
|
|
77
|
-
readonly type: 'empty_sections' | 'missing_field' | 'duplicate_prefix' | 'invalid_icon' | 'invalid_entry';
|
|
87
|
+
readonly type: 'empty_sections' | 'missing_field' | 'duplicate_prefix' | 'invalid_icon' | 'invalid_entry' | 'invalid_theme';
|
|
78
88
|
readonly message: string;
|
|
79
89
|
}
|
|
80
90
|
|
|
@@ -98,21 +108,15 @@ export declare type ConfigResult<T> = readonly [ConfigError, null] | readonly [n
|
|
|
98
108
|
export declare function createPaths(dir: string): Paths;
|
|
99
109
|
|
|
100
110
|
/**
|
|
101
|
-
* Type-safe config helper
|
|
102
|
-
*
|
|
103
|
-
* Validates the config structure and exits with a clear error message
|
|
104
|
-
* if any issues are found. This is the primary entry point for user-
|
|
105
|
-
* provided config — validation happens at the boundary.
|
|
111
|
+
* Type-safe config helper for user config files.
|
|
106
112
|
*
|
|
107
|
-
*
|
|
108
|
-
*
|
|
109
|
-
*
|
|
110
|
-
*
|
|
111
|
-
* function), `process.exit(1)` is acceptable here: the user must fix
|
|
112
|
-
* their config before any downstream code can run.
|
|
113
|
+
* This is a passthrough that provides type safety and editor
|
|
114
|
+
* autocompletion in `zpress.config.ts`. Validation is deferred to
|
|
115
|
+
* `loadConfig` at CLI runtime, so errors surface with structured
|
|
116
|
+
* feedback rather than a raw `process.exit`.
|
|
113
117
|
*
|
|
114
118
|
* @param config - Raw zpress config object
|
|
115
|
-
* @returns The
|
|
119
|
+
* @returns The config (unchanged)
|
|
116
120
|
*/
|
|
117
121
|
export declare function defineConfig(config: ZpressConfig): ZpressConfig;
|
|
118
122
|
|
|
@@ -251,6 +255,11 @@ export declare interface Entry {
|
|
|
251
255
|
* @default "overview"
|
|
252
256
|
*/
|
|
253
257
|
readonly indexFile?: string;
|
|
258
|
+
/**
|
|
259
|
+
* Iconify icon identifier (e.g. `"pixelarticons:speed-fast"`).
|
|
260
|
+
* Used on home page feature cards when auto-generated from sections.
|
|
261
|
+
*/
|
|
262
|
+
readonly icon?: string;
|
|
254
263
|
/**
|
|
255
264
|
* Card display metadata for the parent section's auto-generated landing page.
|
|
256
265
|
*
|
|
@@ -395,10 +404,14 @@ declare type GlobPattern = string;
|
|
|
395
404
|
export declare function hasGlobChars(s: string): boolean;
|
|
396
405
|
|
|
397
406
|
/**
|
|
398
|
-
* Load zpress config at runtime via c12.
|
|
407
|
+
* Load and validate zpress config at runtime via c12.
|
|
408
|
+
*
|
|
409
|
+
* Returns a `ConfigResult` tuple — the CLI boundary is responsible for
|
|
410
|
+
* surfacing any error and exiting. Validation runs here (not in
|
|
411
|
+
* `defineConfig`) so every consumer gets structured error feedback.
|
|
399
412
|
*
|
|
400
|
-
*
|
|
401
|
-
*
|
|
413
|
+
* @param dir - Repository root directory to search for `zpress.config.*`
|
|
414
|
+
* @returns A `ConfigResult` tuple — `[null, config]` on success or `[ConfigError, null]` on failure
|
|
402
415
|
*/
|
|
403
416
|
export declare function loadConfig(dir: string): Promise<ConfigResult<ZpressConfig>>;
|
|
404
417
|
|
|
@@ -510,6 +523,14 @@ export declare interface Paths {
|
|
|
510
523
|
readonly cacheDir: string;
|
|
511
524
|
}
|
|
512
525
|
|
|
526
|
+
/**
|
|
527
|
+
* Resolve the default color mode for a given theme name.
|
|
528
|
+
*
|
|
529
|
+
* @param theme - Built-in theme identifier
|
|
530
|
+
* @returns The theme's natural color mode
|
|
531
|
+
*/
|
|
532
|
+
export declare function resolveDefaultColorMode(theme: ThemeName): ColorMode;
|
|
533
|
+
|
|
513
534
|
/**
|
|
514
535
|
* Internal resolved node — produced by the resolver, consumed by copy + sidebar/nav generators.
|
|
515
536
|
*/
|
|
@@ -747,11 +768,86 @@ export declare interface SyncResult {
|
|
|
747
768
|
readonly elapsed: number;
|
|
748
769
|
}
|
|
749
770
|
|
|
771
|
+
/**
|
|
772
|
+
* All valid theme names — used for validation.
|
|
773
|
+
*/
|
|
774
|
+
export declare const THEME_NAMES: readonly ThemeName[];
|
|
775
|
+
|
|
776
|
+
/**
|
|
777
|
+
* Optional color overrides keyed to CSS custom properties.
|
|
778
|
+
*
|
|
779
|
+
* Each key maps to one or more `--zp-c-*` / `--rp-c-*` variables.
|
|
780
|
+
* Values must be valid CSS color strings (hex or rgba).
|
|
781
|
+
*/
|
|
782
|
+
export declare interface ThemeColors {
|
|
783
|
+
readonly brand?: string;
|
|
784
|
+
readonly brandLight?: string;
|
|
785
|
+
readonly brandDark?: string;
|
|
786
|
+
readonly brandSoft?: string;
|
|
787
|
+
readonly bg?: string;
|
|
788
|
+
readonly bgAlt?: string;
|
|
789
|
+
readonly bgElv?: string;
|
|
790
|
+
readonly bgSoft?: string;
|
|
791
|
+
readonly text1?: string;
|
|
792
|
+
readonly text2?: string;
|
|
793
|
+
readonly text3?: string;
|
|
794
|
+
readonly divider?: string;
|
|
795
|
+
readonly border?: string;
|
|
796
|
+
readonly homeBg?: string;
|
|
797
|
+
}
|
|
798
|
+
|
|
799
|
+
/**
|
|
800
|
+
* Top-level theme configuration for `zpress.config.ts`.
|
|
801
|
+
*/
|
|
802
|
+
export declare interface ThemeConfig {
|
|
803
|
+
/**
|
|
804
|
+
* Built-in theme to use.
|
|
805
|
+
* @default 'base'
|
|
806
|
+
*/
|
|
807
|
+
readonly name?: ThemeName;
|
|
808
|
+
/**
|
|
809
|
+
* Color mode behavior. Defaults to the theme's natural mode.
|
|
810
|
+
*/
|
|
811
|
+
readonly colorMode?: ColorMode;
|
|
812
|
+
/**
|
|
813
|
+
* Show the theme switcher dropdown in the nav bar.
|
|
814
|
+
* @default false
|
|
815
|
+
*/
|
|
816
|
+
readonly switcher?: boolean;
|
|
817
|
+
/**
|
|
818
|
+
* Partial color overrides applied in light mode (or base mode).
|
|
819
|
+
*/
|
|
820
|
+
readonly colors?: ThemeColors;
|
|
821
|
+
/**
|
|
822
|
+
* Partial color overrides applied only in dark mode.
|
|
823
|
+
*/
|
|
824
|
+
readonly darkColors?: ThemeColors;
|
|
825
|
+
}
|
|
826
|
+
|
|
827
|
+
/**
|
|
828
|
+
* Theme types and default resolution.
|
|
829
|
+
*
|
|
830
|
+
* Defines the built-in theme palette system: theme names, color modes,
|
|
831
|
+
* per-theme color overrides, and the top-level ThemeConfig shape.
|
|
832
|
+
*/
|
|
833
|
+
/**
|
|
834
|
+
* Built-in theme identifiers.
|
|
835
|
+
*/
|
|
836
|
+
export declare type ThemeName = 'base' | 'midnight' | 'arcade';
|
|
837
|
+
|
|
750
838
|
/**
|
|
751
839
|
* URL path (e.g. `"/guides/add-api-route"`)
|
|
752
840
|
*/
|
|
753
841
|
declare type UrlPath = string;
|
|
754
842
|
|
|
843
|
+
/**
|
|
844
|
+
* Validate the entire config, returning the first error found.
|
|
845
|
+
*
|
|
846
|
+
* @param config - Raw zpress config object to validate
|
|
847
|
+
* @returns A `ConfigResult` tuple — `[null, config]` on success or `[ConfigError, null]` on failure
|
|
848
|
+
*/
|
|
849
|
+
export declare function validateConfig(config: ZpressConfig): ConfigResult<ZpressConfig>;
|
|
850
|
+
|
|
755
851
|
/**
|
|
756
852
|
* A named group of workspace items for custom workspace categories.
|
|
757
853
|
*
|
|
@@ -906,6 +1002,11 @@ export declare interface ZpressConfig {
|
|
|
906
1002
|
* Site meta description. Used as the hero headline on the home page.
|
|
907
1003
|
*/
|
|
908
1004
|
readonly description?: string;
|
|
1005
|
+
/**
|
|
1006
|
+
* Theme configuration.
|
|
1007
|
+
* Controls the visual theme, color mode, and optional color overrides.
|
|
1008
|
+
*/
|
|
1009
|
+
readonly theme?: ThemeConfig;
|
|
909
1010
|
/**
|
|
910
1011
|
* Path to a custom favicon file served from `.zpress/public/`.
|
|
911
1012
|
* When omitted, defaults to the auto-generated `/icon.svg`.
|
package/dist/index.mjs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
+
import { P, match } from "ts-pattern";
|
|
1
2
|
import { loadConfig } from "c12";
|
|
2
3
|
import promises from "node:fs/promises";
|
|
3
4
|
import node_path from "node:path";
|
|
4
5
|
import { log } from "@clack/prompts";
|
|
5
|
-
import { P, match } from "ts-pattern";
|
|
6
6
|
import { capitalize, groupBy, isUndefined, omitBy, range, words } from "es-toolkit";
|
|
7
7
|
import { createHash } from "node:crypto";
|
|
8
8
|
import gray_matter from "gray-matter";
|
|
@@ -47,12 +47,20 @@ function collectResults(results) {
|
|
|
47
47
|
[]
|
|
48
48
|
]);
|
|
49
49
|
}
|
|
50
|
+
const THEME_NAMES = [
|
|
51
|
+
'base',
|
|
52
|
+
'midnight',
|
|
53
|
+
'arcade'
|
|
54
|
+
];
|
|
55
|
+
const COLOR_MODES = [
|
|
56
|
+
'dark',
|
|
57
|
+
'light',
|
|
58
|
+
'toggle'
|
|
59
|
+
];
|
|
60
|
+
function resolveDefaultColorMode(theme) {
|
|
61
|
+
return match(theme).with('base', ()=>'toggle').with('midnight', ()=>'dark').with('arcade', ()=>'dark').exhaustive();
|
|
62
|
+
}
|
|
50
63
|
function defineConfig(config) {
|
|
51
|
-
const [err] = validateConfig(config);
|
|
52
|
-
if (err) {
|
|
53
|
-
process.stderr.write(`[zpress] ${err.message}\n`);
|
|
54
|
-
process.exit(1);
|
|
55
|
-
}
|
|
56
64
|
return config;
|
|
57
65
|
}
|
|
58
66
|
function validateConfig(config) {
|
|
@@ -90,6 +98,11 @@ function validateConfig(config) {
|
|
|
90
98
|
featErr,
|
|
91
99
|
null
|
|
92
100
|
];
|
|
101
|
+
const [themeErr] = validateTheme(config.theme);
|
|
102
|
+
if (themeErr) return [
|
|
103
|
+
themeErr,
|
|
104
|
+
null
|
|
105
|
+
];
|
|
93
106
|
return [
|
|
94
107
|
null,
|
|
95
108
|
config
|
|
@@ -222,6 +235,71 @@ function validateFeature(feature) {
|
|
|
222
235
|
if (feature.icon && !feature.icon.includes(':')) return configError('invalid_icon', `Feature "${feature.text}": icon must be an Iconify identifier (e.g. "pixelarticons:speed-fast")`);
|
|
223
236
|
return null;
|
|
224
237
|
}
|
|
238
|
+
function validateThemeColors(colors, label) {
|
|
239
|
+
const colorPattern = /^(?:#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{6})|rgba?\([^)]*\))$/;
|
|
240
|
+
const keys = [
|
|
241
|
+
'brand',
|
|
242
|
+
'brandLight',
|
|
243
|
+
'brandDark',
|
|
244
|
+
'brandSoft',
|
|
245
|
+
'bg',
|
|
246
|
+
'bgAlt',
|
|
247
|
+
'bgElv',
|
|
248
|
+
'bgSoft',
|
|
249
|
+
'text1',
|
|
250
|
+
'text2',
|
|
251
|
+
'text3',
|
|
252
|
+
'divider',
|
|
253
|
+
'border',
|
|
254
|
+
'homeBg'
|
|
255
|
+
];
|
|
256
|
+
const firstError = keys.reduce((acc, key)=>{
|
|
257
|
+
if (acc) return acc;
|
|
258
|
+
const value = colors[key];
|
|
259
|
+
if (void 0 !== value && !colorPattern.test(value)) return configError('invalid_theme', `theme.${label}.${key}: "${value}" is not a valid color (use hex #xxx/#xxxxxx or rgba())`);
|
|
260
|
+
return null;
|
|
261
|
+
}, null);
|
|
262
|
+
if (firstError) return [
|
|
263
|
+
firstError,
|
|
264
|
+
null
|
|
265
|
+
];
|
|
266
|
+
return [
|
|
267
|
+
null,
|
|
268
|
+
true
|
|
269
|
+
];
|
|
270
|
+
}
|
|
271
|
+
function validateTheme(theme) {
|
|
272
|
+
if (void 0 === theme) return [
|
|
273
|
+
null,
|
|
274
|
+
true
|
|
275
|
+
];
|
|
276
|
+
if (void 0 !== theme.name && !THEME_NAMES.includes(theme.name)) return [
|
|
277
|
+
configError('invalid_theme', `theme.name: "${theme.name}" is not a valid theme (use ${THEME_NAMES.map((n)=>`"${n}"`).join(', ')})`),
|
|
278
|
+
null
|
|
279
|
+
];
|
|
280
|
+
if (void 0 !== theme.colorMode && !COLOR_MODES.includes(theme.colorMode)) return [
|
|
281
|
+
configError('invalid_theme', `theme.colorMode: "${theme.colorMode}" is not valid (use ${COLOR_MODES.map((m)=>`"${m}"`).join(', ')})`),
|
|
282
|
+
null
|
|
283
|
+
];
|
|
284
|
+
if (theme.colors) {
|
|
285
|
+
const [colorsErr] = validateThemeColors(theme.colors, 'colors');
|
|
286
|
+
if (colorsErr) return [
|
|
287
|
+
colorsErr,
|
|
288
|
+
null
|
|
289
|
+
];
|
|
290
|
+
}
|
|
291
|
+
if (theme.darkColors) {
|
|
292
|
+
const [darkErr] = validateThemeColors(theme.darkColors, 'darkColors');
|
|
293
|
+
if (darkErr) return [
|
|
294
|
+
darkErr,
|
|
295
|
+
null
|
|
296
|
+
];
|
|
297
|
+
}
|
|
298
|
+
return [
|
|
299
|
+
null,
|
|
300
|
+
true
|
|
301
|
+
];
|
|
302
|
+
}
|
|
225
303
|
async function config_loadConfig(dir) {
|
|
226
304
|
const { config } = await loadConfig({
|
|
227
305
|
cwd: dir,
|
|
@@ -235,10 +313,7 @@ async function config_loadConfig(dir) {
|
|
|
235
313
|
configError('empty_sections', 'Failed to load zpress.config — no sections found'),
|
|
236
314
|
null
|
|
237
315
|
];
|
|
238
|
-
return
|
|
239
|
-
null,
|
|
240
|
-
config
|
|
241
|
-
];
|
|
316
|
+
return validateConfig(config);
|
|
242
317
|
}
|
|
243
318
|
const FIGLET_CHARS = Object.freeze({
|
|
244
319
|
A: [
|
|
@@ -1429,7 +1504,7 @@ function buildFeatures(sections, repoRoot) {
|
|
|
1429
1504
|
return Promise.all(sections.slice(0, 3).map(async (section, index)=>{
|
|
1430
1505
|
const link = section.link ?? findFirstChildLink(section);
|
|
1431
1506
|
const details = await extractSectionDescription(section, repoRoot);
|
|
1432
|
-
const iconId = null;
|
|
1507
|
+
const iconId = section.icon ?? null;
|
|
1433
1508
|
const iconColor = ICON_COLORS[index % ICON_COLORS.length];
|
|
1434
1509
|
return {
|
|
1435
1510
|
title: section.text,
|
|
@@ -2839,4 +2914,4 @@ function createPaths(dir) {
|
|
|
2839
2914
|
cacheDir: node_path.resolve(outputRoot, 'cache')
|
|
2840
2915
|
};
|
|
2841
2916
|
}
|
|
2842
|
-
export { configError, config_loadConfig as loadConfig, createPaths, defineConfig, generateAssets, generateBannerSvg, generateIconSvg, generateLogoSvg, hasGlobChars, loadManifest, resolveEntries, sync, syncError };
|
|
2917
|
+
export { COLOR_MODES, THEME_NAMES, configError, config_loadConfig as loadConfig, createPaths, defineConfig, generateAssets, generateBannerSvg, generateIconSvg, generateLogoSvg, hasGlobChars, loadManifest, resolveDefaultColorMode, resolveEntries, sync, syncError, validateConfig };
|