@rokkit/cli 1.1.4 → 1.1.6
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/src/doctor.d.ts +37 -1
- package/dist/src/init.d.ts +41 -18
- package/package.json +1 -1
- package/src/doctor.js +173 -5
- package/src/init.js +164 -23
package/dist/src/doctor.d.ts
CHANGED
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Build the default named-token starter config source used by `doctor --fix`.
|
|
3
|
+
* @returns {string}
|
|
4
|
+
*/
|
|
5
|
+
export function defaultStarterSource(): string;
|
|
1
6
|
/**
|
|
2
7
|
* Run all doctor checks against the given filesystem adapter.
|
|
3
8
|
* @param {{ exists: (p: string) => boolean, read: (p: string) => string, resolve: (p: string) => string }} fs
|
|
@@ -15,10 +20,41 @@ export function runChecks(fs: {
|
|
|
15
20
|
fix: string;
|
|
16
21
|
autoFix?: string;
|
|
17
22
|
}>;
|
|
23
|
+
/**
|
|
24
|
+
* Scan files for legacy z-scale utilities and suggest named-token equivalents.
|
|
25
|
+
* Advisory only — z-scale still resolves via the preset's back-compat layer.
|
|
26
|
+
* @param {Array<{ path: string, content: string }>} files
|
|
27
|
+
* @returns {{ count: number, byFile: Array<{ path: string, hits: Array<{ token: string, suggestion: string }> }> }}
|
|
28
|
+
*/
|
|
29
|
+
export function findLegacyZUtilities(files: Array<{
|
|
30
|
+
path: string;
|
|
31
|
+
content: string;
|
|
32
|
+
}>): {
|
|
33
|
+
count: number;
|
|
34
|
+
byFile: Array<{
|
|
35
|
+
path: string;
|
|
36
|
+
hits: Array<{
|
|
37
|
+
token: string;
|
|
38
|
+
suggestion: string;
|
|
39
|
+
}>;
|
|
40
|
+
}>;
|
|
41
|
+
};
|
|
42
|
+
/**
|
|
43
|
+
* Validate a parsed rokkit config for the named-token system. All advisory (warn).
|
|
44
|
+
* @param {Record<string, unknown> | null} config
|
|
45
|
+
* @returns {Array<{ id: string, label: string, status: 'warn', fixable: false, fix: string }>}
|
|
46
|
+
*/
|
|
47
|
+
export function validateConfigShape(config: Record<string, unknown> | null): Array<{
|
|
48
|
+
id: string;
|
|
49
|
+
label: string;
|
|
50
|
+
status: "warn";
|
|
51
|
+
fixable: false;
|
|
52
|
+
fix: string;
|
|
53
|
+
}>;
|
|
18
54
|
/**
|
|
19
55
|
* Interactive doctor command — validates project setup.
|
|
20
56
|
* @param {{ fix?: boolean }} [opts]
|
|
21
57
|
*/
|
|
22
58
|
export function doctor(opts?: {
|
|
23
59
|
fix?: boolean;
|
|
24
|
-
}): void
|
|
60
|
+
}): Promise<void>;
|
package/dist/src/init.d.ts
CHANGED
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Serialize a rokkit config object to a JS module string with a header comment.
|
|
3
|
+
* @param {Record<string, unknown>} config
|
|
4
|
+
* @returns {string}
|
|
5
|
+
*/
|
|
6
|
+
export function serializeRokkitConfig(config: Record<string, unknown>): string;
|
|
1
7
|
/**
|
|
2
8
|
* Detect if the current directory is a SvelteKit project.
|
|
3
9
|
* @param {string} cwd
|
|
@@ -22,25 +28,42 @@ export function generateChartConfig({ chartColors, chartShades }: {
|
|
|
22
28
|
chartColors: string;
|
|
23
29
|
chartShades: string;
|
|
24
30
|
}): Record<string, unknown>;
|
|
31
|
+
/**
|
|
32
|
+
* Build the Zen-Sumi OKLCH starter (ink-on-paper, dual-palette dark mode).
|
|
33
|
+
* @param {{ themes?: string[], defaultTheme?: string, switcher?: string,
|
|
34
|
+
* includeChart?: boolean, chartColors?: string, chartShades?: string }} [opts]
|
|
35
|
+
* @returns {Record<string, unknown>}
|
|
36
|
+
*/
|
|
37
|
+
export function generateZenSumiConfig(opts?: {
|
|
38
|
+
themes?: string[];
|
|
39
|
+
defaultTheme?: string;
|
|
40
|
+
switcher?: string;
|
|
41
|
+
includeChart?: boolean;
|
|
42
|
+
chartColors?: string;
|
|
43
|
+
chartShades?: string;
|
|
44
|
+
}): Record<string, unknown>;
|
|
45
|
+
/**
|
|
46
|
+
* Build a Rokkit config object from the user's init choices.
|
|
47
|
+
* Emits the named-token `skin` shape (skin + colorSpace + tokens), plus
|
|
48
|
+
* optional `icons` and `chart` sections.
|
|
49
|
+
* @param {{ palette: string, customColors?: Record<string, string>, icons?: string,
|
|
50
|
+
* iconPath?: string, iconStyle?: string, themes: string[], defaultTheme?: string,
|
|
51
|
+
* switcher: string, includeChart?: boolean, chartColors?: string, chartShades?: string }} opts
|
|
52
|
+
* @returns {Record<string, unknown>}
|
|
53
|
+
*/
|
|
25
54
|
export function generateConfig({ palette, customColors, icons, iconPath, iconStyle, themes, defaultTheme, switcher, includeChart, chartColors, chartShades }: {
|
|
26
|
-
palette:
|
|
27
|
-
customColors
|
|
28
|
-
icons
|
|
29
|
-
iconPath
|
|
30
|
-
iconStyle
|
|
31
|
-
themes:
|
|
32
|
-
defaultTheme
|
|
33
|
-
switcher:
|
|
34
|
-
includeChart
|
|
35
|
-
chartColors
|
|
36
|
-
chartShades
|
|
37
|
-
}):
|
|
38
|
-
colors: Record<string, unknown>;
|
|
39
|
-
themes: any;
|
|
40
|
-
defaultTheme: any;
|
|
41
|
-
switcher: any;
|
|
42
|
-
storageKey: string;
|
|
43
|
-
};
|
|
55
|
+
palette: string;
|
|
56
|
+
customColors?: Record<string, string>;
|
|
57
|
+
icons?: string;
|
|
58
|
+
iconPath?: string;
|
|
59
|
+
iconStyle?: string;
|
|
60
|
+
themes: string[];
|
|
61
|
+
defaultTheme?: string;
|
|
62
|
+
switcher: string;
|
|
63
|
+
includeChart?: boolean;
|
|
64
|
+
chartColors?: string;
|
|
65
|
+
chartShades?: string;
|
|
66
|
+
}): Record<string, unknown>;
|
|
44
67
|
/**
|
|
45
68
|
* Generate the content for uno.config.js.
|
|
46
69
|
* @returns {string}
|
package/package.json
CHANGED
package/src/doctor.js
CHANGED
|
@@ -1,7 +1,15 @@
|
|
|
1
1
|
/* eslint-disable no-console */
|
|
2
|
-
import { existsSync, readFileSync, writeFileSync } from 'fs'
|
|
3
|
-
import { resolve } from 'path'
|
|
4
|
-
import {
|
|
2
|
+
import { existsSync, readFileSync, writeFileSync, readdirSync } from 'fs'
|
|
3
|
+
import { resolve, extname } from 'path'
|
|
4
|
+
import { loadConfig as loadParsedConfig } from './config.js'
|
|
5
|
+
import {
|
|
6
|
+
generateUnoConfig,
|
|
7
|
+
generateAppCssImports,
|
|
8
|
+
generateInitScript,
|
|
9
|
+
generateChartConfig,
|
|
10
|
+
generateConfig,
|
|
11
|
+
serializeRokkitConfig
|
|
12
|
+
} from './init.js'
|
|
5
13
|
|
|
6
14
|
const KNOWN_THEMES = [
|
|
7
15
|
'rokkit',
|
|
@@ -11,6 +19,23 @@ const KNOWN_THEMES = [
|
|
|
11
19
|
'zen-sumi'
|
|
12
20
|
]
|
|
13
21
|
|
|
22
|
+
/**
|
|
23
|
+
* Build the default named-token starter config source used by `doctor --fix`.
|
|
24
|
+
* @returns {string}
|
|
25
|
+
*/
|
|
26
|
+
export function defaultStarterSource() {
|
|
27
|
+
const config = generateConfig({
|
|
28
|
+
palette: 'default',
|
|
29
|
+
icons: 'rokkit',
|
|
30
|
+
themes: ['rokkit'],
|
|
31
|
+
switcher: 'manual',
|
|
32
|
+
includeChart: true,
|
|
33
|
+
chartColors: 'default',
|
|
34
|
+
chartShades: 'standard'
|
|
35
|
+
})
|
|
36
|
+
return serializeRokkitConfig(config)
|
|
37
|
+
}
|
|
38
|
+
|
|
14
39
|
/**
|
|
15
40
|
* Check config file existence
|
|
16
41
|
* @param {Object} fs
|
|
@@ -163,7 +188,7 @@ function createFsAdapter(cwd) {
|
|
|
163
188
|
*/
|
|
164
189
|
function applyGenerateConfig(cwd, label) {
|
|
165
190
|
const configPath = resolve(cwd, 'rokkit.config.js')
|
|
166
|
-
writeFileSync(configPath,
|
|
191
|
+
writeFileSync(configPath, defaultStarterSource())
|
|
167
192
|
console.info(` Fixed: ${label}`)
|
|
168
193
|
}
|
|
169
194
|
|
|
@@ -331,16 +356,159 @@ function handleResults(checks, cwd, failures, fix) {
|
|
|
331
356
|
}
|
|
332
357
|
}
|
|
333
358
|
|
|
359
|
+
// z-slot → named token (matches @rokkit/core Z_COLLAPSE maps).
|
|
360
|
+
const SURFACE_Z = {
|
|
361
|
+
z0: 'paper', z1: 'paper-soft', z2: 'paper-mute', z3: 'paper-mute', z4: 'paper-edge',
|
|
362
|
+
z5: 'ink-soft', z6: 'ink-soft', z7: 'ink-mute', z8: 'ink-mute', z9: 'ink', z10: 'ink'
|
|
363
|
+
}
|
|
364
|
+
const INK_Z = {
|
|
365
|
+
z0: 'ink', z1: 'ink-mute', z2: 'ink-mute', z3: 'ink-soft', z4: 'ink-soft',
|
|
366
|
+
z5: 'paper-edge', z6: 'paper-edge', z7: 'paper-mute', z8: 'paper-mute', z9: 'paper-soft', z10: 'paper'
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
/**
|
|
370
|
+
* Map a z-scale role+slot to its nearest named token.
|
|
371
|
+
* @param {string} role
|
|
372
|
+
* @param {string} z — e.g. 'z5'
|
|
373
|
+
* @returns {string}
|
|
374
|
+
*/
|
|
375
|
+
function suggestNamedToken(role, z) {
|
|
376
|
+
if (role === 'surface') return SURFACE_Z[z]
|
|
377
|
+
if (role === 'ink') return INK_Z[z]
|
|
378
|
+
// accent + status roles collapse z0–z2 to their `-soft` tint (matches
|
|
379
|
+
// @rokkit/core theme.ts getZAliasesOther: zNum <= 2). primary has no `-soft`.
|
|
380
|
+
if (role !== 'primary' && Number(z.slice(1)) <= 2) return `${role}-soft`
|
|
381
|
+
return role
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
const Z_UTILITY_RE =
|
|
385
|
+
/\b(bg|text|border(?:-[tblr])?|fill|stroke|ring|outline|divide)-(surface|ink|primary|accent|success|warning|danger|error|info)-(z(?:10|[0-9]))\b/g
|
|
386
|
+
|
|
387
|
+
/**
|
|
388
|
+
* Scan files for legacy z-scale utilities and suggest named-token equivalents.
|
|
389
|
+
* Advisory only — z-scale still resolves via the preset's back-compat layer.
|
|
390
|
+
* @param {Array<{ path: string, content: string }>} files
|
|
391
|
+
* @returns {{ count: number, byFile: Array<{ path: string, hits: Array<{ token: string, suggestion: string }> }> }}
|
|
392
|
+
*/
|
|
393
|
+
export function findLegacyZUtilities(files) {
|
|
394
|
+
const byFile = []
|
|
395
|
+
let count = 0
|
|
396
|
+
for (const { path: filePath, content } of files) {
|
|
397
|
+
const hits = []
|
|
398
|
+
for (const match of content.matchAll(Z_UTILITY_RE)) {
|
|
399
|
+
const [token, prefix, role, z] = match
|
|
400
|
+
hits.push({ token, suggestion: `${prefix}-${suggestNamedToken(role, z)}` })
|
|
401
|
+
}
|
|
402
|
+
if (hits.length > 0) {
|
|
403
|
+
byFile.push({ path: filePath, hits })
|
|
404
|
+
count += hits.length
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
return { count, byFile }
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
const SCAN_EXTS = new Set(['.svelte', '.css', '.ts', '.js'])
|
|
411
|
+
|
|
412
|
+
/**
|
|
413
|
+
* Recursively gather scannable source files under cwd/src.
|
|
414
|
+
* Skips node_modules, symlinks (avoids recursion loops), and uno.config.js
|
|
415
|
+
* (its safelist legitimately lists z-utilities).
|
|
416
|
+
* @param {string} cwd
|
|
417
|
+
* @returns {Array<{ path: string, content: string }>}
|
|
418
|
+
*/
|
|
419
|
+
function gatherSrcFiles(cwd) {
|
|
420
|
+
const root = resolve(cwd, 'src')
|
|
421
|
+
if (!existsSync(root)) return []
|
|
422
|
+
const out = []
|
|
423
|
+
const walk = (dir) => {
|
|
424
|
+
for (const dirent of readdirSync(dir, { withFileTypes: true })) {
|
|
425
|
+
if (dirent.isSymbolicLink() || dirent.name === 'node_modules') continue
|
|
426
|
+
const full = resolve(dir, dirent.name)
|
|
427
|
+
if (dirent.isDirectory()) {
|
|
428
|
+
walk(full)
|
|
429
|
+
} else if (dirent.isFile() && SCAN_EXTS.has(extname(dirent.name)) && !full.endsWith('uno.config.js')) {
|
|
430
|
+
out.push({ path: full.slice(cwd.length + 1), content: readFileSync(full, 'utf-8') })
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
walk(root)
|
|
435
|
+
return out
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
/**
|
|
439
|
+
* Validate a parsed rokkit config for the named-token system. All advisory (warn).
|
|
440
|
+
* @param {Record<string, unknown> | null} config
|
|
441
|
+
* @returns {Array<{ id: string, label: string, status: 'warn', fixable: false, fix: string }>}
|
|
442
|
+
*/
|
|
443
|
+
export function validateConfigShape(config) {
|
|
444
|
+
if (!config) return []
|
|
445
|
+
const checks = []
|
|
446
|
+
const usesColorsAlias =
|
|
447
|
+
typeof config.colors === 'object' && config.colors !== null && !Array.isArray(config.colors) && !config.skin
|
|
448
|
+
const colormap = config.skins?.default ?? config.skin ?? config.colors ?? {}
|
|
449
|
+
|
|
450
|
+
if (!('ink' in colormap)) {
|
|
451
|
+
checks.push({
|
|
452
|
+
id: 'skin-ink-role',
|
|
453
|
+
label: 'skin defines an `ink` role',
|
|
454
|
+
status: 'warn',
|
|
455
|
+
fixable: false,
|
|
456
|
+
fix: "Add `ink: '<palette>'` (reusing the surface palette is fine) — without it, ink-* text tokens fall back to the surface palette."
|
|
457
|
+
})
|
|
458
|
+
}
|
|
459
|
+
if (config.colorSpace === 'oklch' && Object.keys(config.palettes ?? {}).length === 0) {
|
|
460
|
+
checks.push({
|
|
461
|
+
id: 'oklch-needs-palettes',
|
|
462
|
+
label: 'colorSpace `oklch` has a `palettes` block',
|
|
463
|
+
status: 'warn',
|
|
464
|
+
fixable: false,
|
|
465
|
+
fix: 'oklch values need a `palettes` block of bare "L C H" components; Tailwind named colors are rgb.'
|
|
466
|
+
})
|
|
467
|
+
}
|
|
468
|
+
if (usesColorsAlias) {
|
|
469
|
+
checks.push({
|
|
470
|
+
id: 'colors-alias',
|
|
471
|
+
label: 'config uses `skin` (not the legacy `colors` alias)',
|
|
472
|
+
status: 'warn',
|
|
473
|
+
fixable: false,
|
|
474
|
+
fix: 'Rename `colors:` to `skin:` — `colors` is a back-compat alias.'
|
|
475
|
+
})
|
|
476
|
+
}
|
|
477
|
+
return checks
|
|
478
|
+
}
|
|
479
|
+
|
|
334
480
|
/**
|
|
335
481
|
* Interactive doctor command — validates project setup.
|
|
336
482
|
* @param {{ fix?: boolean }} [opts]
|
|
337
483
|
*/
|
|
338
|
-
export function doctor(opts = {}) {
|
|
484
|
+
export async function doctor(opts = {}) {
|
|
339
485
|
const cwd = process.cwd()
|
|
340
486
|
const checks = runChecks(createFsAdapter(cwd))
|
|
341
487
|
|
|
342
488
|
console.info('Rokkit Doctor\n')
|
|
343
489
|
const failures = printChecks(checks)
|
|
490
|
+
|
|
491
|
+
const parsed = await loadParsedConfig({ cwd })
|
|
492
|
+
const shapeChecks = validateConfigShape(parsed)
|
|
493
|
+
if (shapeChecks.length > 0) {
|
|
494
|
+
console.info('\nConfig shape:')
|
|
495
|
+
for (const c of shapeChecks) {
|
|
496
|
+
console.info(` WARN ${c.label}`)
|
|
497
|
+
console.info(` ${c.fix}`)
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
const { count, byFile } = findLegacyZUtilities(gatherSrcFiles(cwd))
|
|
502
|
+
if (count > 0) {
|
|
503
|
+
console.info(`\nLegacy z-scale utilities (advisory — ${count} in ${byFile.length} file(s)):`)
|
|
504
|
+
for (const { path: filePath, hits } of byFile.slice(0, 10)) {
|
|
505
|
+
const examples = [...new Map(hits.map((h) => [h.token, h.suggestion]))]
|
|
506
|
+
const shown = examples.slice(0, 3).map(([t, s]) => `${t} → ${s}`).join(', ')
|
|
507
|
+
console.info(` ${filePath}: ${shown}${examples.length > 3 ? ', …' : ''}`)
|
|
508
|
+
}
|
|
509
|
+
console.info(' Named tokens are preferred; z-scale still works via back-compat.')
|
|
510
|
+
}
|
|
511
|
+
|
|
344
512
|
handleResults(checks, cwd, failures, opts.fix ?? false)
|
|
345
513
|
console.info('')
|
|
346
514
|
}
|
package/src/init.js
CHANGED
|
@@ -8,6 +8,42 @@ import { detectPackageManager, buildInstallCommand } from './upgrade.js'
|
|
|
8
8
|
const ROKKIT_PACKAGES = ['@rokkit/ui', '@rokkit/unocss', '@rokkit/themes', '@rokkit/icons']
|
|
9
9
|
const LOCKFILES = ['bun.lock', 'bun.lockb', 'pnpm-lock.yaml', 'yarn.lock', 'package-lock.json']
|
|
10
10
|
|
|
11
|
+
const NAMED_TOKEN_HEADER = `/**
|
|
12
|
+
* Rokkit token configuration — consumed by presetRokkit() in uno.config.js.
|
|
13
|
+
*
|
|
14
|
+
* Maps semantic roles (surface, ink, primary, accent, status…) to palettes.
|
|
15
|
+
* The preset emits the named-token vocabulary used throughout components:
|
|
16
|
+
*
|
|
17
|
+
* Surface bg-paper · bg-paper-soft · bg-paper-mute · border-paper-edge
|
|
18
|
+
* Text text-ink · text-ink-mute · text-ink-soft · text-ink-faint
|
|
19
|
+
* Accent bg-primary · text-on-primary · bg-accent · bg-accent-soft
|
|
20
|
+
* Status bg-success-soft · text-success (+ warning / danger / error / info)
|
|
21
|
+
*
|
|
22
|
+
* Tokens flip automatically under [data-mode="dark"]. The older z-scale
|
|
23
|
+
* utilities (bg-surface-z0, text-primary-z5) still resolve for back-compat,
|
|
24
|
+
* but new code should prefer the named tokens above.
|
|
25
|
+
*
|
|
26
|
+
* tokens: 'core' emits the named vocabulary; 'extended' also emits the full
|
|
27
|
+
* 11-shade palette ladder per role (for charts / data-viz).
|
|
28
|
+
*/
|
|
29
|
+
`
|
|
30
|
+
|
|
31
|
+
const OKLCH_PALETTES_NOTE = `/**
|
|
32
|
+
* palettes: bare OKLCH "L C H" components (colorSpace: 'oklch'). surface/ink use
|
|
33
|
+
* a { light, dark } dual palette — kami (warm paper) in light, sumi (ink) in dark.
|
|
34
|
+
*/
|
|
35
|
+
`
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Serialize a rokkit config object to a JS module string with a header comment.
|
|
39
|
+
* @param {Record<string, unknown>} config
|
|
40
|
+
* @returns {string}
|
|
41
|
+
*/
|
|
42
|
+
export function serializeRokkitConfig(config) {
|
|
43
|
+
const palettesNote = config.palettes ? OKLCH_PALETTES_NOTE : ''
|
|
44
|
+
return `${NAMED_TOKEN_HEADER}${palettesNote}export default ${JSON.stringify(config, null, 2)}\n`
|
|
45
|
+
}
|
|
46
|
+
|
|
11
47
|
/**
|
|
12
48
|
* Detect if the current directory is a SvelteKit project.
|
|
13
49
|
* @param {string} cwd
|
|
@@ -61,12 +97,23 @@ const CHART_SHADE_PRESETS = {
|
|
|
61
97
|
soft: { light: { fill: '400', stroke: '600' }, dark: { fill: '600', stroke: '300' } }
|
|
62
98
|
}
|
|
63
99
|
|
|
100
|
+
// Base rgb skin — named-token roles only (no secondary/tertiary; ink defaults to surface).
|
|
101
|
+
const DEFAULT_SKIN_BASE = {
|
|
102
|
+
primary: 'orange',
|
|
103
|
+
accent: 'sky',
|
|
104
|
+
surface: 'slate',
|
|
105
|
+
success: 'green',
|
|
106
|
+
warning: 'yellow',
|
|
107
|
+
danger: 'red',
|
|
108
|
+
error: 'red',
|
|
109
|
+
info: 'cyan'
|
|
110
|
+
}
|
|
111
|
+
|
|
64
112
|
const SKIN_PRESETS = {
|
|
65
|
-
default: {
|
|
66
|
-
vibrant: { primary: 'blue',
|
|
113
|
+
default: {},
|
|
114
|
+
vibrant: { primary: 'blue', accent: 'sky', surface: 'slate' },
|
|
67
115
|
seaweed: {
|
|
68
116
|
primary: 'sky',
|
|
69
|
-
secondary: 'green',
|
|
70
117
|
accent: 'blue',
|
|
71
118
|
surface: 'zinc',
|
|
72
119
|
danger: 'rose',
|
|
@@ -77,26 +124,66 @@ const SKIN_PRESETS = {
|
|
|
77
124
|
}
|
|
78
125
|
}
|
|
79
126
|
|
|
80
|
-
const DEFAULT_COLORS = {
|
|
81
|
-
primary: 'orange',
|
|
82
|
-
secondary: 'pink',
|
|
83
|
-
accent: 'sky',
|
|
84
|
-
surface: 'slate',
|
|
85
|
-
success: 'green',
|
|
86
|
-
warning: 'yellow',
|
|
87
|
-
danger: 'red',
|
|
88
|
-
error: 'red',
|
|
89
|
-
info: 'cyan'
|
|
90
|
-
}
|
|
91
|
-
|
|
92
127
|
/**
|
|
93
|
-
*
|
|
94
|
-
*
|
|
95
|
-
*
|
|
128
|
+
* Resolve a named-token rgb skin from a preset or custom colors.
|
|
129
|
+
* `ink` defaults to the `surface` palette. Only the named-token roles are
|
|
130
|
+
* emitted; `secondary`/`tertiary` are intentionally omitted (no named token
|
|
131
|
+
* reads them). A consumer who needs them can add them to their config's skin
|
|
132
|
+
* directly — @rokkit/unocss's loadConfig merges extra roles through.
|
|
133
|
+
* @param {string} palette
|
|
134
|
+
* @param {Record<string, string>} [customColors]
|
|
135
|
+
* @returns {Record<string, string>}
|
|
96
136
|
*/
|
|
97
|
-
function
|
|
98
|
-
|
|
99
|
-
|
|
137
|
+
function resolveSkin(palette, customColors) {
|
|
138
|
+
const merged =
|
|
139
|
+
palette === 'custom'
|
|
140
|
+
? { ...DEFAULT_SKIN_BASE, ...customColors }
|
|
141
|
+
: { ...DEFAULT_SKIN_BASE, ...(SKIN_PRESETS[palette] || {}) }
|
|
142
|
+
return {
|
|
143
|
+
surface: merged.surface,
|
|
144
|
+
ink: merged.ink ?? merged.surface,
|
|
145
|
+
primary: merged.primary,
|
|
146
|
+
accent: merged.accent,
|
|
147
|
+
success: merged.success,
|
|
148
|
+
warning: merged.warning,
|
|
149
|
+
danger: merged.danger,
|
|
150
|
+
error: merged.error,
|
|
151
|
+
info: merged.info
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// Zen-Sumi OKLCH palettes — bare "L C H" components (colorSpace: 'oklch').
|
|
156
|
+
const ZEN_SUMI_PALETTES = {
|
|
157
|
+
kami: {
|
|
158
|
+
50: '0.985 0.005 85', 100: '0.975 0.008 85', 200: '0.955 0.010 85',
|
|
159
|
+
300: '0.920 0.012 85', 400: '0.850 0.010 70', 500: '0.750 0.008 50',
|
|
160
|
+
600: '0.580 0.010 50', 700: '0.380 0.012 50', 800: '0.280 0.012 50',
|
|
161
|
+
900: '0.220 0.012 50', 950: '0.170 0.010 50'
|
|
162
|
+
},
|
|
163
|
+
sumi: {
|
|
164
|
+
50: '0.170 0.010 50', 100: '0.210 0.012 50', 200: '0.250 0.012 50',
|
|
165
|
+
300: '0.320 0.012 50', 400: '0.420 0.010 50', 500: '0.570 0.010 50',
|
|
166
|
+
600: '0.420 0.012 85', 700: '0.600 0.010 85', 800: '0.780 0.008 85',
|
|
167
|
+
900: '0.940 0.008 85', 950: '0.975 0.008 85'
|
|
168
|
+
},
|
|
169
|
+
shu: {
|
|
170
|
+
50: '0.970 0.020 35', 100: '0.940 0.040 35', 200: '0.880 0.070 35',
|
|
171
|
+
300: '0.800 0.100 35', 400: '0.700 0.130 35', 500: '0.580 0.150 35',
|
|
172
|
+
600: '0.500 0.140 35', 700: '0.420 0.120 35', 800: '0.350 0.100 35',
|
|
173
|
+
900: '0.280 0.080 35', 950: '0.220 0.060 35'
|
|
174
|
+
},
|
|
175
|
+
hisui: {
|
|
176
|
+
50: '0.970 0.015 160', 100: '0.940 0.030 160', 200: '0.880 0.050 160',
|
|
177
|
+
300: '0.800 0.065 160', 400: '0.720 0.075 160', 500: '0.620 0.080 160',
|
|
178
|
+
600: '0.540 0.075 160', 700: '0.460 0.065 160', 800: '0.380 0.055 160',
|
|
179
|
+
900: '0.300 0.045 160', 950: '0.240 0.035 160'
|
|
180
|
+
},
|
|
181
|
+
kohaku: {
|
|
182
|
+
50: '0.980 0.020 75', 100: '0.950 0.040 75', 200: '0.900 0.070 75',
|
|
183
|
+
300: '0.850 0.095 75', 400: '0.790 0.110 75', 500: '0.720 0.120 75',
|
|
184
|
+
600: '0.640 0.110 75', 700: '0.560 0.095 75', 800: '0.470 0.080 75',
|
|
185
|
+
900: '0.380 0.065 75', 950: '0.300 0.050 75'
|
|
186
|
+
}
|
|
100
187
|
}
|
|
101
188
|
|
|
102
189
|
/**
|
|
@@ -111,6 +198,53 @@ export function generateChartConfig({ chartColors, chartShades }) {
|
|
|
111
198
|
}
|
|
112
199
|
}
|
|
113
200
|
|
|
201
|
+
/**
|
|
202
|
+
* Build the Zen-Sumi OKLCH starter (ink-on-paper, dual-palette dark mode).
|
|
203
|
+
* @param {{ themes?: string[], defaultTheme?: string, switcher?: string,
|
|
204
|
+
* includeChart?: boolean, chartColors?: string, chartShades?: string }} [opts]
|
|
205
|
+
* @returns {Record<string, unknown>}
|
|
206
|
+
*/
|
|
207
|
+
export function generateZenSumiConfig(opts = {}) {
|
|
208
|
+
const { themes, defaultTheme, switcher, includeChart, chartColors, chartShades } = opts
|
|
209
|
+
const config = {
|
|
210
|
+
palettes: ZEN_SUMI_PALETTES,
|
|
211
|
+
colorSpace: 'oklch',
|
|
212
|
+
tokens: 'core',
|
|
213
|
+
skin: {
|
|
214
|
+
surface: { light: 'kami', dark: 'sumi' },
|
|
215
|
+
ink: { light: 'kami', dark: 'sumi' },
|
|
216
|
+
primary: 'shu',
|
|
217
|
+
accent: 'shu',
|
|
218
|
+
success: 'hisui',
|
|
219
|
+
warning: 'kohaku',
|
|
220
|
+
danger: 'shu',
|
|
221
|
+
error: 'shu',
|
|
222
|
+
info: 'kohaku'
|
|
223
|
+
},
|
|
224
|
+
shape: { radius: 'soft' },
|
|
225
|
+
typography: {
|
|
226
|
+
display: "'Fraunces', 'Iowan Old Style', Georgia, serif",
|
|
227
|
+
sans: "'Inter', system-ui, -apple-system, sans-serif",
|
|
228
|
+
mono: "'JetBrains Mono', 'SF Mono', Menlo, monospace"
|
|
229
|
+
},
|
|
230
|
+
themes: themes && themes.length ? themes : ['rokkit', 'zen-sumi'],
|
|
231
|
+
defaultTheme: defaultTheme || 'zen-sumi',
|
|
232
|
+
switcher: switcher || 'full',
|
|
233
|
+
storageKey: 'rokkit-theme'
|
|
234
|
+
}
|
|
235
|
+
if (includeChart) config.chart = generateChartConfig({ chartColors, chartShades })
|
|
236
|
+
return config
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* Build a Rokkit config object from the user's init choices.
|
|
241
|
+
* Emits the named-token `skin` shape (skin + colorSpace + tokens), plus
|
|
242
|
+
* optional `icons` and `chart` sections.
|
|
243
|
+
* @param {{ palette: string, customColors?: Record<string, string>, icons?: string,
|
|
244
|
+
* iconPath?: string, iconStyle?: string, themes: string[], defaultTheme?: string,
|
|
245
|
+
* switcher: string, includeChart?: boolean, chartColors?: string, chartShades?: string }} opts
|
|
246
|
+
* @returns {Record<string, unknown>}
|
|
247
|
+
*/
|
|
114
248
|
export function generateConfig({
|
|
115
249
|
palette,
|
|
116
250
|
customColors,
|
|
@@ -124,8 +258,14 @@ export function generateConfig({
|
|
|
124
258
|
chartColors,
|
|
125
259
|
chartShades
|
|
126
260
|
}) {
|
|
261
|
+
if (palette === 'zen-sumi') {
|
|
262
|
+
return generateZenSumiConfig({ themes, defaultTheme, switcher, includeChart, chartColors, chartShades })
|
|
263
|
+
}
|
|
264
|
+
|
|
127
265
|
const config = {
|
|
128
|
-
|
|
266
|
+
skin: resolveSkin(palette, customColors),
|
|
267
|
+
colorSpace: 'rgb',
|
|
268
|
+
tokens: 'core',
|
|
129
269
|
themes,
|
|
130
270
|
defaultTheme: defaultTheme || themes[0],
|
|
131
271
|
switcher,
|
|
@@ -205,6 +345,7 @@ const PROMPTS_CONFIG = [
|
|
|
205
345
|
{ title: 'Default (orange/pink/sky)', value: 'default' },
|
|
206
346
|
{ title: 'Vibrant (blue/purple/sky)', value: 'vibrant' },
|
|
207
347
|
{ title: 'Seaweed (sky/green/blue)', value: 'seaweed' },
|
|
348
|
+
{ title: 'Zen-Sumi (OKLCH ink-on-paper)', value: 'zen-sumi' },
|
|
208
349
|
{ title: 'Custom', value: 'custom' }
|
|
209
350
|
]
|
|
210
351
|
},
|
|
@@ -327,7 +468,7 @@ function writeRokkitConfig(cwd, config) {
|
|
|
327
468
|
console.warn(' rokkit.config.js already exists — skipping')
|
|
328
469
|
return
|
|
329
470
|
}
|
|
330
|
-
writeFileSync(configPath,
|
|
471
|
+
writeFileSync(configPath, serializeRokkitConfig(config))
|
|
331
472
|
console.info(' Created rokkit.config.js')
|
|
332
473
|
}
|
|
333
474
|
|