@diskette/palette 0.21.2 → 0.22.1

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 CHANGED
@@ -87,20 +87,24 @@ whiteAlpha.p3.whiteA5 // 'color(display-p3 1 1 1 / 0.3)'
87
87
 
88
88
  ## CLI
89
89
 
90
- The package includes a CLI for generating CSS files.
91
-
92
- ### `palette generate`
93
-
94
- Generate CSS files for color palettes.
90
+ The package includes an interactive CLI for generating CSS files.
95
91
 
96
92
  ```bash
97
- palette generate blue,red,slate -a -o ./styles
93
+ npx @diskette/palette
98
94
  ```
99
95
 
96
+ The CLI guides you through:
97
+
98
+ 1. **Select accent colors** - Choose from all available accent colors with color swatches, plus alpha colors (blackAlpha, whiteAlpha)
99
+ 2. **Select gray colors** - Natural pairings are pre-selected based on your accent choices
100
+ 3. **Output directory** - Where to save the generated files (default: `./palette`)
101
+ 4. **Generate accents.css?** - Include `[data-accent-color]` and `[data-gray-color]` selectors
102
+ 5. **Generate Tailwind v4 config?** - Include `@theme inline` mappings in `index.css`
103
+
104
+ Example output:
105
+
100
106
  ```
101
- styles/
102
- ├── index.css # Imports + Tailwind v4 @theme mappings
103
- ├── accents.css # [data-accent-color] selectors (-a flag)
107
+ palette/
104
108
  ├── blue.css # Light theme: --blue-1 through --blue-12, --blue-a1 through --blue-a12
105
109
  ├── blue-dark.css # Dark theme variants
106
110
  ├── red.css
@@ -108,21 +112,9 @@ styles/
108
112
  ├── slate.css
109
113
  ├── slate-dark.css
110
114
  ├── black-alpha.css # --black-a1 through --black-a12
111
- └── white-alpha.css # --white-a1 through --white-a12
112
- ```
113
-
114
- **Options:**
115
- - `-o, --output <dir>` - Output directory (required)
116
- - `-a, --accents` - Generate `accents.css` with `[data-accent-color]` and `[data-gray-color]` selectors
117
-
118
- ### `palette list`
119
-
120
- List available colors.
121
-
122
- ```bash
123
- palette list # List all colors
124
- palette list --accent # List only accent colors
125
- palette list --gray # List only gray colors
115
+ ├── white-alpha.css # --white-a1 through --white-a12
116
+ ├── accents.css # [data-accent-color] selectors (optional)
117
+ └── index.css # Tailwind v4 @theme mappings (optional)
126
118
  ```
127
119
 
128
120
  ## Available Colors
package/dist/cli/cli.d.ts CHANGED
@@ -1 +1 @@
1
- export declare function writeIfNotExists(path: string, data: string | NodeJS.ArrayBufferView): boolean;
1
+ export {};
package/dist/cli/cli.js CHANGED
@@ -1,78 +1,95 @@
1
- import { defineCommand, runMain } from 'citty';
2
- import { existsSync, mkdirSync, writeFileSync } from 'node:fs';
3
- import { resolve } from 'node:path';
4
- import * as palette from "../colors/index.js";
5
- import { css } from "../css.js";
6
- import { accentColors, grayColors } from "../types.js";
7
- import { getPackageJson } from "./utils.js";
8
- const alphaColors = ['blackAlpha', 'whiteAlpha'];
9
- // Combined list of all colors (deduplicated since 'gray' appears in both)
10
- const allColors = [
11
- ...new Set([...accentColors, ...grayColors]),
12
- ...alphaColors,
13
- ];
14
- const { pkg, packageJsonPath } = getPackageJson(import.meta.url) ?? {};
15
- const main = defineCommand({
16
- meta: {
17
- name: 'palette',
18
- version: pkg?.version,
19
- description: pkg?.description ?? '',
20
- },
21
- args: {
22
- colors: {
23
- type: 'positional',
24
- description: 'Colors',
1
+ import * as p from '@clack/prompts';
2
+ import chalk from 'chalk';
3
+ import { mkdirSync } from 'node:fs';
4
+ import { relative, resolve } from 'node:path';
5
+ import { accentColors, grayColors, } from "../types.js";
6
+ import { getMatchingGrayColor } from "../utils.js";
7
+ import { alphaColors, capitalize, getColorHex, writeAccentsFile, writeColorFiles, writeTailwindFile, } from "./utils.js";
8
+ const accentOptions = {
9
+ Accents: accentColors
10
+ .filter((c) => c !== 'gray')
11
+ .map((c) => {
12
+ const hex = getColorHex(c);
13
+ const swatch = hex ? chalk.bgHex(hex)(' ') + ' ' : '';
14
+ return { value: c, label: `${swatch}${capitalize(c)}` };
15
+ }),
16
+ Alpha: alphaColors.map((c) => {
17
+ const [label] = c.split('Alpha');
18
+ return { value: c, label: capitalize(label) };
19
+ }),
20
+ };
21
+ const grayOptions = grayColors.map((c) => {
22
+ const hex = getColorHex(c);
23
+ const swatch = hex ? chalk.bgHex(hex)(' ') + ' ' : '';
24
+ return { value: c, label: `${swatch}${capitalize(c)}` };
25
+ });
26
+ async function main() {
27
+ p.intro(`palette v0.22.1`);
28
+ const results = await p.group({
29
+ colors: () => p.groupMultiselect({
30
+ message: 'Select accent colors',
31
+ options: accentOptions,
25
32
  required: true,
33
+ initialValues: [...alphaColors],
34
+ }),
35
+ grays: ({ results }) => {
36
+ // Get matching grays for selected accent colors
37
+ const selectedAccents = (results.colors ?? []).filter((c) => accentColors.includes(c));
38
+ const matchingGrays = [
39
+ ...new Set(selectedAccents.map(getMatchingGrayColor)),
40
+ ];
41
+ return p.multiselect({
42
+ message: 'Select gray colors (natural pairings pre-selected)',
43
+ options: grayOptions,
44
+ initialValues: matchingGrays,
45
+ required: false,
46
+ });
26
47
  },
27
- output: {
28
- type: 'string',
29
- alias: 'o',
30
- description: 'Output directory',
31
- },
32
- accents: {
33
- type: 'boolean',
34
- alias: 'a',
35
- description: 'Generate accents.css with [data-accent-color] selectors',
36
- },
37
- tailwind: {
38
- type: 'boolean',
39
- alias: 't',
40
- description: 'Generate index.css with Tailwind v4 @theme mappings',
48
+ output: () => p.text({
49
+ message: 'Output directory',
50
+ placeholder: './palette',
51
+ defaultValue: './palette',
52
+ }),
53
+ accents: () => p.confirm({
54
+ message: 'Generate accents.css?',
55
+ initialValue: true,
56
+ }),
57
+ tailwind: () => p.confirm({
58
+ message: 'Generate Tailwind v4 config?',
59
+ initialValue: false,
60
+ }),
61
+ }, {
62
+ onCancel: () => {
63
+ p.cancel('Operation cancelled.');
64
+ process.exit(0);
41
65
  },
42
- },
43
- run({ args }) {
44
- const selected = args._.filter((c) => allColors.includes(c));
45
- const outputPath = resolve(process.cwd(), args.output);
46
- mkdirSync(outputPath, { recursive: true });
47
- for (const name of selected) {
48
- if (alphaColors.includes(name)) {
49
- const alphaName = name;
50
- const config = palette[alphaName];
51
- const fileName = alphaName === 'blackAlpha' ? 'black-alpha' : 'white-alpha';
52
- writeIfNotExists(`${outputPath}/${fileName}.css`, css.alpha(config));
53
- }
54
- else {
55
- const color = palette[name];
56
- writeIfNotExists(`${outputPath}/${name}.css`, css.palette(color, { schemes: ['light'], alpha: true }));
57
- writeIfNotExists(`${outputPath}/${name}-dark.css`, css.palette(color, { schemes: ['dark'], alpha: true }));
58
- }
59
- }
60
- if (args.accents) {
61
- const accentColorNames = selected.filter((c) => !alphaColors.includes(c));
62
- writeIfNotExists(`${outputPath}/accents.css`, css.accents(accentColorNames));
63
- }
64
- if (args.tailwind) {
65
- const tailwindColorNames = selected.map((c) => c === 'blackAlpha' ? 'black' : c === 'whiteAlpha' ? 'white' : c);
66
- writeIfNotExists(`${outputPath}/index.css`, css.tailwind(tailwindColorNames, { accents: args.accents }));
67
- }
68
- console.log(`\nCSS saved to ${outputPath}`);
69
- },
70
- });
71
- runMain(main);
72
- export function writeIfNotExists(path, data) {
73
- if (existsSync(path)) {
74
- return false;
66
+ });
67
+ const selectedGrays = (results.grays ?? []);
68
+ const allColors = [...results.colors, ...selectedGrays];
69
+ if (allColors.length === 0) {
70
+ p.cancel('No colors selected.');
71
+ process.exit(0);
72
+ }
73
+ const cwd = process.cwd();
74
+ const outputPath = resolve(cwd, results.output);
75
+ mkdirSync(outputPath, { recursive: true });
76
+ const s = p.spinner();
77
+ s.start('Generating CSS files...');
78
+ writeColorFiles(allColors, outputPath);
79
+ if (results.accents) {
80
+ writeAccentsFile(allColors, outputPath);
81
+ }
82
+ if (results.tailwind) {
83
+ writeTailwindFile(allColors, outputPath, results.accents);
75
84
  }
76
- writeFileSync(path, data);
77
- return true;
85
+ s.stop();
86
+ const rel = relative(cwd, outputPath);
87
+ const display = rel.startsWith('..') ? rel : `./${rel}`;
88
+ const extras = [
89
+ results.accents && 'accents.css',
90
+ results.tailwind && 'index.css',
91
+ ].filter(Boolean);
92
+ p.log.success(`Generated ${allColors.length} color${allColors.length > 1 ? 's' : ''}${extras.length ? ` + ${extras.join(', ')}` : ''}`);
93
+ p.outro(`Saved to ${display}`);
78
94
  }
95
+ main();
@@ -1,3 +1,6 @@
1
+ import { type Color } from '../types.ts';
2
+ export declare const alphaColors: readonly ["blackAlpha", "whiteAlpha"];
3
+ export type AlphaColor = (typeof alphaColors)[number];
1
4
  /**
2
5
  * get package.json content from startDir
3
6
  * @param cwd
@@ -7,3 +10,13 @@ export declare const getPackageJson: (cwd: string) => {
7
10
  pkg: any;
8
11
  packageJsonPath: string;
9
12
  } | undefined;
13
+ export declare function writeColorFiles(selected: string[], outputPath: string): void;
14
+ export declare function writeAlphaColorFile(name: AlphaColor, outputPath: string): void;
15
+ export declare function writePaletteColorFiles(name: Color, outputPath: string): void;
16
+ export declare function writeAccentsFile(selected: string[], outputPath: string): void;
17
+ export declare function writeTailwindFile(selected: string[], outputPath: string, includeAccents: boolean): void;
18
+ export declare function writeIfNotExists(path: string, data: string | NodeJS.ArrayBufferView): boolean;
19
+ export declare const capitalize: (s: string) => string;
20
+ /** Get hex color (step 9) for a palette color */
21
+ export declare const getColorHex: (name: string) => string | null;
22
+ export declare function invariant(condition: unknown, message?: string | Error): asserts condition;
package/dist/cli/utils.js CHANGED
@@ -1,7 +1,12 @@
1
- import fs from 'node:fs';
1
+ import fs, { existsSync, writeFileSync } from 'node:fs';
2
2
  import { createRequire } from 'node:module';
3
3
  import path from 'node:path';
4
4
  import * as url from 'node:url';
5
+ import * as colors from "../colors/index.js";
6
+ import * as palette from "../colors/index.js";
7
+ import { css } from "../css.js";
8
+ import {} from "../types.js";
9
+ export const alphaColors = ['blackAlpha', 'whiteAlpha'];
5
10
  const require = createRequire(import.meta.url);
6
11
  /**
7
12
  * get package.json content from startDir
@@ -42,3 +47,54 @@ const findPackageJson = (startDir) => {
42
47
  currentDir = parentDir;
43
48
  }
44
49
  };
50
+ export function writeColorFiles(selected, outputPath) {
51
+ for (const name of selected) {
52
+ if (alphaColors.includes(name)) {
53
+ writeAlphaColorFile(name, outputPath);
54
+ }
55
+ else {
56
+ writePaletteColorFiles(name, outputPath);
57
+ }
58
+ }
59
+ }
60
+ export function writeAlphaColorFile(name, outputPath) {
61
+ const config = palette[name];
62
+ const fileName = name === 'blackAlpha' ? 'black-alpha' : 'white-alpha';
63
+ writeIfNotExists(`${outputPath}/${fileName}.css`, css.alpha(config));
64
+ }
65
+ export function writePaletteColorFiles(name, outputPath) {
66
+ const color = palette[name];
67
+ writeIfNotExists(`${outputPath}/${name}.css`, css.palette(color, { schemes: ['light'], alpha: true }));
68
+ writeIfNotExists(`${outputPath}/${name}-dark.css`, css.palette(color, { schemes: ['dark'], alpha: true }));
69
+ }
70
+ export function writeAccentsFile(selected, outputPath) {
71
+ const accentColorNames = selected.filter((c) => !alphaColors.includes(c));
72
+ writeIfNotExists(`${outputPath}/accents.css`, css.accents(accentColorNames));
73
+ }
74
+ export function writeTailwindFile(selected, outputPath, includeAccents) {
75
+ const tailwindColorNames = selected.map((c) => c === 'blackAlpha' ? 'black' : c === 'whiteAlpha' ? 'white' : c);
76
+ writeIfNotExists(`${outputPath}/index.css`, css.tailwind(tailwindColorNames, { accents: includeAccents }));
77
+ }
78
+ export function writeIfNotExists(path, data) {
79
+ if (existsSync(path)) {
80
+ return false;
81
+ }
82
+ writeFileSync(path, data);
83
+ return true;
84
+ }
85
+ export const capitalize = (s) => s.charAt(0).toUpperCase() + s.slice(1);
86
+ /** Get hex color (step 9) for a palette color */
87
+ export const getColorHex = (name) => {
88
+ const color = colors[name];
89
+ invariant(color, `${color} is missing its step 9`);
90
+ return color?.dark?.srgb?.solid?.[8] ?? null;
91
+ };
92
+ export function invariant(condition, message) {
93
+ if (condition) {
94
+ return;
95
+ }
96
+ if (message && typeof message === 'string') {
97
+ throw new Error(message);
98
+ }
99
+ throw message;
100
+ }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@diskette/palette",
3
3
  "type": "module",
4
- "version": "0.21.2",
4
+ "version": "0.22.1",
5
5
  "bin": {
6
6
  "palette": "./dist/cli/cli.js"
7
7
  },
@@ -23,19 +23,22 @@
23
23
  "dist"
24
24
  ],
25
25
  "dependencies": {
26
- "citty": "^0.1.6"
26
+ "@clack/prompts": "1.0.0-alpha.8",
27
+ "chalk": "^5.6.2"
27
28
  },
28
29
  "devDependencies": {
29
- "@changesets/cli": "^2.29.7",
30
+ "@changesets/cli": "^2.29.8",
30
31
  "@diskette/fs": "^0.17.0",
31
- "@types/node": "^24.3.0",
32
+ "@types/node": "^24.10.2",
33
+ "@types/react": "^19.2.7",
32
34
  "magicast": "^0.5.1",
33
- "oxlint": "^1.16.0",
34
- "oxlint-tsgolint": "^0.2.0",
35
- "prettier": "^3.6.2",
36
- "tsx": "^4.20.5",
35
+ "oxlint": "^1.32.0",
36
+ "oxlint-tsgolint": "^0.8.5",
37
+ "prettier": "^3.7.4",
38
+ "react": "^19.2.1",
39
+ "tsx": "^4.21.0",
37
40
  "typescript": "^5.9.2",
38
- "vitest": "^4.0.14"
41
+ "vitest": "^4.0.15"
39
42
  },
40
43
  "repository": {
41
44
  "type": "git",
@@ -48,10 +51,10 @@
48
51
  },
49
52
  "license": "MIT",
50
53
  "scripts": {
51
- "build": "rm -rf dist && tsc -p tsconfig.build.json",
54
+ "build": "rm -rf dist && tsc -p tsconfig.build.json && node scripts/inject-meta.ts",
52
55
  "typecheck": "tsc",
53
56
  "test": "vitest run",
54
57
  "lint": "oxlint --type-aware src",
55
- "release": "changeset version && changeset publish && git push --follow-tags"
58
+ "release": "changeset version && pnpm build && changeset publish && git push --follow-tags"
56
59
  }
57
60
  }