ctheme 0.1.0 → 0.1.2
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/DEVELOPMENT.md +262 -0
- package/README.md +8 -0
- package/bin/ctheme.js +56 -190
- package/package.json +6 -3
- package/scripts/postinstall.js +57 -0
package/DEVELOPMENT.md
ADDED
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
# Development
|
|
2
|
+
|
|
3
|
+
## Purpose
|
|
4
|
+
|
|
5
|
+
`ctheme` is a terminal theming CLI.
|
|
6
|
+
|
|
7
|
+
Scope:
|
|
8
|
+
|
|
9
|
+
- terminal color themes
|
|
10
|
+
- terminal font selection
|
|
11
|
+
- live Apple Terminal profile switching
|
|
12
|
+
- config snippet generation for Ghostty, Kitty, and WezTerm
|
|
13
|
+
- custom theme authoring
|
|
14
|
+
- Google Fonts discovery and install helpers
|
|
15
|
+
|
|
16
|
+
Out of scope:
|
|
17
|
+
|
|
18
|
+
- editor themes
|
|
19
|
+
- app chrome theming
|
|
20
|
+
- IDE plugins
|
|
21
|
+
- Codex-specific config behavior
|
|
22
|
+
|
|
23
|
+
## Repository Layout
|
|
24
|
+
|
|
25
|
+
```text
|
|
26
|
+
bin/ctheme.js Main CLI entrypoint and all runtime logic
|
|
27
|
+
README.md User-facing docs
|
|
28
|
+
DEVELOPMENT.md Contributor docs
|
|
29
|
+
package.json npm package metadata
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
This project is intentionally small. Most behavior lives in one file so it stays easy to ship and debug.
|
|
33
|
+
|
|
34
|
+
## Runtime State
|
|
35
|
+
|
|
36
|
+
`ctheme` keeps its own state under:
|
|
37
|
+
|
|
38
|
+
```text
|
|
39
|
+
~/.ctheme/themes
|
|
40
|
+
~/.ctheme/snippets
|
|
41
|
+
~/.ctheme/snippets/.ctheme-state.json
|
|
42
|
+
~/Library/Fonts/pretty-code
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
What each path is for:
|
|
46
|
+
|
|
47
|
+
- `~/.ctheme/themes`: saved custom theme JSON palettes
|
|
48
|
+
- `~/.ctheme/snippets`: generated terminal config snippets and AppleScript files
|
|
49
|
+
- `~/.ctheme/snippets/.ctheme-state.json`: restore state for `ctheme reset`
|
|
50
|
+
- `~/Library/Fonts/pretty-code`: Google Fonts installed by the CLI
|
|
51
|
+
|
|
52
|
+
Relevant env vars:
|
|
53
|
+
|
|
54
|
+
```text
|
|
55
|
+
CTHEME_HOME
|
|
56
|
+
CTHEME_THEME_DIR
|
|
57
|
+
CTHEME_SNIPPET_DIR
|
|
58
|
+
CTHEME_SKIP_FONT_BOOTSTRAP
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## Command Map
|
|
62
|
+
|
|
63
|
+
Main commands:
|
|
64
|
+
|
|
65
|
+
- `ctheme use <theme>`: apply a theme live to the current terminal when supported
|
|
66
|
+
- `ctheme reset`: restore the original terminal state
|
|
67
|
+
- `ctheme list`: list bundled and saved themes
|
|
68
|
+
- `ctheme preview <theme>`: inspect palette colors in the current shell
|
|
69
|
+
- `ctheme make`: create a theme from flags or launch the wizard
|
|
70
|
+
- `ctheme wizard`: force the interactive onboarding flow
|
|
71
|
+
- `ctheme init <name>`: create a starter theme file
|
|
72
|
+
- `ctheme term <target>`: generate or apply terminal-target snippets
|
|
73
|
+
- `ctheme font ...`: search, install, and list fonts
|
|
74
|
+
|
|
75
|
+
## Internal Architecture
|
|
76
|
+
|
|
77
|
+
### 1. Presets
|
|
78
|
+
|
|
79
|
+
Bundled presets are plain palette objects in `PRESETS`.
|
|
80
|
+
|
|
81
|
+
Each preset should carry:
|
|
82
|
+
|
|
83
|
+
- colors
|
|
84
|
+
- terminal font
|
|
85
|
+
- UI font
|
|
86
|
+
- code font
|
|
87
|
+
|
|
88
|
+
The bundled presets should feel visibly distinct. Avoid making every theme share the same font pairing.
|
|
89
|
+
|
|
90
|
+
### 2. Theme Building
|
|
91
|
+
|
|
92
|
+
`buildTheme()` turns a palette into the normalized theme object used by preview and terminal rendering.
|
|
93
|
+
|
|
94
|
+
Important rule:
|
|
95
|
+
|
|
96
|
+
- readability wins over palette purity
|
|
97
|
+
|
|
98
|
+
Light themes in particular are normalized through contrast helpers so accents and syntax colors remain readable.
|
|
99
|
+
|
|
100
|
+
### 3. Terminal Writers
|
|
101
|
+
|
|
102
|
+
Target-specific renderers:
|
|
103
|
+
|
|
104
|
+
- `renderAppleTerminalProfile()`
|
|
105
|
+
- `renderGhosttySnippet()`
|
|
106
|
+
- `renderKittySnippet()`
|
|
107
|
+
- `renderWeztermSnippet()`
|
|
108
|
+
|
|
109
|
+
Target-specific application:
|
|
110
|
+
|
|
111
|
+
- Apple Terminal applies live through AppleScript
|
|
112
|
+
- Ghostty and Kitty get include lines appended
|
|
113
|
+
- WezTerm writes a standalone file when safe
|
|
114
|
+
|
|
115
|
+
### 4. Wizard Flow
|
|
116
|
+
|
|
117
|
+
The wizard is implemented in `runMakeWizard()`.
|
|
118
|
+
|
|
119
|
+
Current flow:
|
|
120
|
+
|
|
121
|
+
1. pick a base preset
|
|
122
|
+
2. name the theme
|
|
123
|
+
3. adjust colors
|
|
124
|
+
4. choose fonts
|
|
125
|
+
5. review summary
|
|
126
|
+
6. save
|
|
127
|
+
7. optionally install fonts
|
|
128
|
+
8. optionally apply live
|
|
129
|
+
|
|
130
|
+
When changing the wizard:
|
|
131
|
+
|
|
132
|
+
- keep prompts short
|
|
133
|
+
- always show a default
|
|
134
|
+
- keep blank input as “accept default”
|
|
135
|
+
- prefer a summary/confirmation before writing files
|
|
136
|
+
|
|
137
|
+
### 5. Font Helpers
|
|
138
|
+
|
|
139
|
+
Font listing uses macOS AppKit through JXA.
|
|
140
|
+
|
|
141
|
+
Google Fonts install flow:
|
|
142
|
+
|
|
143
|
+
1. search metadata from `fonts.google.com`
|
|
144
|
+
2. resolve family path from `google/fonts`
|
|
145
|
+
3. download font files into `~/Library/Fonts/pretty-code`
|
|
146
|
+
|
|
147
|
+
Do not bundle font files in the repo.
|
|
148
|
+
|
|
149
|
+
### 6. Install Bootstrap
|
|
150
|
+
|
|
151
|
+
`npm install -g ctheme` runs `scripts/postinstall.js`.
|
|
152
|
+
|
|
153
|
+
That script:
|
|
154
|
+
|
|
155
|
+
- runs on macOS only
|
|
156
|
+
- best-effort installs the curated default font pack
|
|
157
|
+
- never hard-fails the package install because of a font download problem
|
|
158
|
+
|
|
159
|
+
Skip it with:
|
|
160
|
+
|
|
161
|
+
```bash
|
|
162
|
+
CTHEME_SKIP_FONT_BOOTSTRAP=1 npm install -g ctheme
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
## Local Development
|
|
166
|
+
|
|
167
|
+
Install the CLI locally:
|
|
168
|
+
|
|
169
|
+
```bash
|
|
170
|
+
npm install -g . --force
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
Basic smoke checks:
|
|
174
|
+
|
|
175
|
+
```bash
|
|
176
|
+
ctheme --help
|
|
177
|
+
ctheme list
|
|
178
|
+
ctheme preview solarized
|
|
179
|
+
ctheme font list
|
|
180
|
+
ctheme status
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
## Manual Test Matrix
|
|
184
|
+
|
|
185
|
+
### Apple Terminal
|
|
186
|
+
|
|
187
|
+
```bash
|
|
188
|
+
ctheme use solarized
|
|
189
|
+
ctheme use harbor --default
|
|
190
|
+
ctheme reset
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
Verify:
|
|
194
|
+
|
|
195
|
+
- theme applies immediately
|
|
196
|
+
- `--default` changes startup/default profile
|
|
197
|
+
- `reset` restores the saved profile or `Basic`
|
|
198
|
+
|
|
199
|
+
### Wizard
|
|
200
|
+
|
|
201
|
+
```bash
|
|
202
|
+
ctheme wizard
|
|
203
|
+
ctheme make
|
|
204
|
+
ctheme make mytheme --preset harbor --terminal-font "Space Mono"
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
Verify:
|
|
208
|
+
|
|
209
|
+
- defaults are shown
|
|
210
|
+
- summary appears before writing
|
|
211
|
+
- saved JSON lands in `~/.ctheme/themes`
|
|
212
|
+
- `ctheme use mytheme` picks up the saved terminal font
|
|
213
|
+
|
|
214
|
+
### Fonts
|
|
215
|
+
|
|
216
|
+
```bash
|
|
217
|
+
ctheme font search "mono"
|
|
218
|
+
ctheme font install "IBM Plex Mono"
|
|
219
|
+
ctheme font list
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
Verify:
|
|
223
|
+
|
|
224
|
+
- search returns real families
|
|
225
|
+
- install downloads files into `~/Library/Fonts/pretty-code`
|
|
226
|
+
- list prints real family names, not ObjC bridge values
|
|
227
|
+
|
|
228
|
+
### Pack/Publish
|
|
229
|
+
|
|
230
|
+
```bash
|
|
231
|
+
npm test
|
|
232
|
+
npm pack --dry-run
|
|
233
|
+
npm publish --dry-run
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
## Release Process
|
|
237
|
+
|
|
238
|
+
1. update version in `package.json`
|
|
239
|
+
2. run smoke tests
|
|
240
|
+
3. run `npm pack --dry-run`
|
|
241
|
+
4. run `npm publish --dry-run`
|
|
242
|
+
5. commit
|
|
243
|
+
6. push `main`
|
|
244
|
+
7. publish for real with `npm publish`
|
|
245
|
+
|
|
246
|
+
## Contribution Rules
|
|
247
|
+
|
|
248
|
+
- Keep the product terminal-focused.
|
|
249
|
+
- Prefer short commands over complicated command trees.
|
|
250
|
+
- Preserve live-apply behavior wherever possible.
|
|
251
|
+
- When a target cannot reload live, say that clearly.
|
|
252
|
+
- Avoid growing the tool into a general desktop-theme manager.
|
|
253
|
+
- Do not reintroduce Codex/editor/app-specific behavior.
|
|
254
|
+
- Do not add hidden state outside `~/.ctheme` and the managed fonts directory.
|
|
255
|
+
|
|
256
|
+
## Git Hygiene
|
|
257
|
+
|
|
258
|
+
This repo should stay self-contained.
|
|
259
|
+
|
|
260
|
+
- commit from `/Users/arjunkshah21/Downloads/pretty-code`
|
|
261
|
+
- push to `origin main`
|
|
262
|
+
- do not mix unrelated parent-directory changes into this repo
|
package/README.md
CHANGED
|
@@ -18,6 +18,12 @@ From npm:
|
|
|
18
18
|
npm install -g ctheme
|
|
19
19
|
```
|
|
20
20
|
|
|
21
|
+
On macOS, install also preloads the curated default font pack used by the bundled themes. If you want to skip that during install:
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
CTHEME_SKIP_FONT_BOOTSTRAP=1 npm install -g ctheme
|
|
25
|
+
```
|
|
26
|
+
|
|
21
27
|
From GitHub:
|
|
22
28
|
|
|
23
29
|
```bash
|
|
@@ -71,6 +77,7 @@ The wizard walks through:
|
|
|
71
77
|
- terminal font
|
|
72
78
|
- UI font
|
|
73
79
|
- code font
|
|
80
|
+
- theme summary before save
|
|
74
81
|
- optional Google Fonts install
|
|
75
82
|
- optional live apply
|
|
76
83
|
|
|
@@ -149,6 +156,7 @@ solarized, solarized-dark, velvet
|
|
|
149
156
|
```
|
|
150
157
|
|
|
151
158
|
Bundled themes intentionally vary their font pairings so they do not all feel the same.
|
|
159
|
+
The npm install bootstrap preinstalls the curated font set those presets rely on, so the bundled themes render correctly immediately on macOS.
|
|
152
160
|
|
|
153
161
|
## Contributing
|
|
154
162
|
|
package/bin/ctheme.js
CHANGED
|
@@ -94,9 +94,9 @@ const BUILTIN_THEMES = [
|
|
|
94
94
|
];
|
|
95
95
|
|
|
96
96
|
const FONT_CHOICES = {
|
|
97
|
-
ui: ["Manrope", "Space Grotesk", "Outfit", "Sora", "Plus Jakarta Sans", "Newsreader", "Fraunces"],
|
|
98
|
-
code: ["IBM Plex Mono", "Space Mono", "DM Mono", "Source Code Pro", "Fira Code", "JetBrains Mono"],
|
|
99
|
-
terminal: ["IBM Plex Mono", "Space Mono", "DM Mono", "Source Code Pro", "Fira Code", "JetBrains Mono"]
|
|
97
|
+
ui: ["Manrope", "Space Grotesk", "Outfit", "Sora", "Plus Jakarta Sans", "Newsreader", "Fraunces", "Bricolage Grotesque", "Urbanist", "Source Sans 3", "IBM Plex Sans", "Instrument Serif", "Syne"],
|
|
98
|
+
code: ["IBM Plex Mono", "Space Mono", "DM Mono", "Source Code Pro", "Fira Code", "JetBrains Mono", "Roboto Mono", "Azeret Mono", "Victor Mono", "Ubuntu Mono"],
|
|
99
|
+
terminal: ["IBM Plex Mono", "Space Mono", "DM Mono", "Source Code Pro", "Fira Code", "JetBrains Mono", "Roboto Mono", "Azeret Mono", "Victor Mono", "Ubuntu Mono"]
|
|
100
100
|
};
|
|
101
101
|
|
|
102
102
|
const PRESETS = {
|
|
@@ -117,7 +117,7 @@ const PRESETS = {
|
|
|
117
117
|
cyan: "#39c5cf"
|
|
118
118
|
},
|
|
119
119
|
paper: {
|
|
120
|
-
fonts: { terminal: "
|
|
120
|
+
fonts: { terminal: "Source Code Pro", ui: "Newsreader", code: "Source Code Pro" },
|
|
121
121
|
accent: "#005cc5",
|
|
122
122
|
bg: "#fff8e8",
|
|
123
123
|
surface: "#fffdf7",
|
|
@@ -149,7 +149,7 @@ const PRESETS = {
|
|
|
149
149
|
cyan: "#7dcfff"
|
|
150
150
|
},
|
|
151
151
|
mint: {
|
|
152
|
-
fonts: { terminal: "
|
|
152
|
+
fonts: { terminal: "Roboto Mono", ui: "Plus Jakarta Sans", code: "Roboto Mono" },
|
|
153
153
|
accent: "#2bb673",
|
|
154
154
|
bg: "#081411",
|
|
155
155
|
surface: "#10201b",
|
|
@@ -165,7 +165,7 @@ const PRESETS = {
|
|
|
165
165
|
cyan: "#5ad1e6"
|
|
166
166
|
},
|
|
167
167
|
obsidian: {
|
|
168
|
-
fonts: { terminal: "
|
|
168
|
+
fonts: { terminal: "Azeret Mono", ui: "Outfit", code: "Azeret Mono" },
|
|
169
169
|
accent: "#58a6ff",
|
|
170
170
|
bg: "#05070a",
|
|
171
171
|
surface: "#0e131a",
|
|
@@ -181,7 +181,7 @@ const PRESETS = {
|
|
|
181
181
|
cyan: "#7dd3fc"
|
|
182
182
|
},
|
|
183
183
|
glacier: {
|
|
184
|
-
fonts: { terminal: "Space Mono", ui: "
|
|
184
|
+
fonts: { terminal: "Space Mono", ui: "Urbanist", code: "Space Mono" },
|
|
185
185
|
accent: "#7aa2f7",
|
|
186
186
|
bg: "#0a1220",
|
|
187
187
|
surface: "#121c2f",
|
|
@@ -197,7 +197,7 @@ const PRESETS = {
|
|
|
197
197
|
cyan: "#7dcfff"
|
|
198
198
|
},
|
|
199
199
|
cobalt: {
|
|
200
|
-
fonts: { terminal: "
|
|
200
|
+
fonts: { terminal: "Victor Mono", ui: "Bricolage Grotesque", code: "Victor Mono" },
|
|
201
201
|
accent: "#4da3ff",
|
|
202
202
|
bg: "#09111f",
|
|
203
203
|
surface: "#10203a",
|
|
@@ -229,7 +229,7 @@ const PRESETS = {
|
|
|
229
229
|
cyan: "#8bd3dd"
|
|
230
230
|
},
|
|
231
231
|
lotus: {
|
|
232
|
-
fonts: { terminal: "
|
|
232
|
+
fonts: { terminal: "Ubuntu Mono", ui: "Instrument Serif", code: "Ubuntu Mono" },
|
|
233
233
|
accent: "#d16d9e",
|
|
234
234
|
bg: "#fff7f3",
|
|
235
235
|
surface: "#fffdfb",
|
|
@@ -245,7 +245,7 @@ const PRESETS = {
|
|
|
245
245
|
cyan: "#4d8ca1"
|
|
246
246
|
},
|
|
247
247
|
dune: {
|
|
248
|
-
fonts: { terminal: "
|
|
248
|
+
fonts: { terminal: "Fira Code", ui: "Syne", code: "Fira Code" },
|
|
249
249
|
accent: "#d97706",
|
|
250
250
|
bg: "#16110c",
|
|
251
251
|
surface: "#231912",
|
|
@@ -261,7 +261,7 @@ const PRESETS = {
|
|
|
261
261
|
cyan: "#67e8f9"
|
|
262
262
|
},
|
|
263
263
|
forest: {
|
|
264
|
-
fonts: { terminal: "IBM Plex Mono", ui: "
|
|
264
|
+
fonts: { terminal: "IBM Plex Mono", ui: "IBM Plex Sans", code: "IBM Plex Mono" },
|
|
265
265
|
accent: "#7ccf7a",
|
|
266
266
|
bg: "#08100b",
|
|
267
267
|
surface: "#112016",
|
|
@@ -277,7 +277,7 @@ const PRESETS = {
|
|
|
277
277
|
cyan: "#6ee7b7"
|
|
278
278
|
},
|
|
279
279
|
aurora: {
|
|
280
|
-
fonts: { terminal: "Space Mono", ui: "
|
|
280
|
+
fonts: { terminal: "Space Mono", ui: "Urbanist", code: "Space Mono" },
|
|
281
281
|
accent: "#7c5cff",
|
|
282
282
|
bg: "#0f0a1f",
|
|
283
283
|
surface: "#181131",
|
|
@@ -293,7 +293,7 @@ const PRESETS = {
|
|
|
293
293
|
cyan: "#7bdff2"
|
|
294
294
|
},
|
|
295
295
|
espresso: {
|
|
296
|
-
fonts: { terminal: "
|
|
296
|
+
fonts: { terminal: "Victor Mono", ui: "Instrument Serif", code: "Victor Mono" },
|
|
297
297
|
accent: "#c67c4e",
|
|
298
298
|
bg: "#120d0b",
|
|
299
299
|
surface: "#1d1512",
|
|
@@ -325,7 +325,7 @@ const PRESETS = {
|
|
|
325
325
|
cyan: "#bde0fe"
|
|
326
326
|
},
|
|
327
327
|
neon: {
|
|
328
|
-
fonts: { terminal: "
|
|
328
|
+
fonts: { terminal: "Azeret Mono", ui: "Bricolage Grotesque", code: "Azeret Mono" },
|
|
329
329
|
accent: "#00f5d4",
|
|
330
330
|
bg: "#090414",
|
|
331
331
|
surface: "#130a24",
|
|
@@ -341,7 +341,7 @@ const PRESETS = {
|
|
|
341
341
|
cyan: "#00bbf9"
|
|
342
342
|
},
|
|
343
343
|
harbor: {
|
|
344
|
-
fonts: { terminal: "
|
|
344
|
+
fonts: { terminal: "Roboto Mono", ui: "Plus Jakarta Sans", code: "Roboto Mono" },
|
|
345
345
|
accent: "#3ba4c9",
|
|
346
346
|
bg: "#f4f8fb",
|
|
347
347
|
surface: "#ffffff",
|
|
@@ -389,7 +389,7 @@ const PRESETS = {
|
|
|
389
389
|
cyan: "#2aa198"
|
|
390
390
|
},
|
|
391
391
|
velvet: {
|
|
392
|
-
fonts: { terminal: "
|
|
392
|
+
fonts: { terminal: "Ubuntu Mono", ui: "Fraunces", code: "Ubuntu Mono" },
|
|
393
393
|
accent: "#d4a5ff",
|
|
394
394
|
bg: "#140d18",
|
|
395
395
|
surface: "#211328",
|
|
@@ -406,179 +406,6 @@ const PRESETS = {
|
|
|
406
406
|
}
|
|
407
407
|
};
|
|
408
408
|
|
|
409
|
-
const APP_PRESETS = {
|
|
410
|
-
evergreen: {
|
|
411
|
-
codeThemeId: "everforest",
|
|
412
|
-
theme: {
|
|
413
|
-
accent: "#93b259",
|
|
414
|
-
contrast: 45,
|
|
415
|
-
fonts: { code: "IBM Plex Mono", ui: "Manrope" },
|
|
416
|
-
ink: "#5c6a72",
|
|
417
|
-
opaqueWindows: true,
|
|
418
|
-
semanticColors: {
|
|
419
|
-
diffAdded: "#8da101",
|
|
420
|
-
diffRemoved: "#f85552",
|
|
421
|
-
skill: "#df69ba"
|
|
422
|
-
},
|
|
423
|
-
surface: "#fdf6e3"
|
|
424
|
-
},
|
|
425
|
-
variant: "light"
|
|
426
|
-
},
|
|
427
|
-
"evergreen-dark": {
|
|
428
|
-
codeThemeId: "everforest",
|
|
429
|
-
theme: {
|
|
430
|
-
accent: "#a7c080",
|
|
431
|
-
contrast: 60,
|
|
432
|
-
fonts: { code: "IBM Plex Mono", ui: "Manrope" },
|
|
433
|
-
ink: "#d3c6aa",
|
|
434
|
-
opaqueWindows: true,
|
|
435
|
-
semanticColors: {
|
|
436
|
-
diffAdded: "#a7c080",
|
|
437
|
-
diffRemoved: "#e67e80",
|
|
438
|
-
skill: "#d699b6"
|
|
439
|
-
},
|
|
440
|
-
surface: "#2d353b"
|
|
441
|
-
},
|
|
442
|
-
variant: "dark"
|
|
443
|
-
},
|
|
444
|
-
solarized: {
|
|
445
|
-
codeThemeId: "solarized",
|
|
446
|
-
theme: {
|
|
447
|
-
accent: "#268bd2",
|
|
448
|
-
contrast: 45,
|
|
449
|
-
fonts: { code: "Source Code Pro", ui: "Manrope" },
|
|
450
|
-
ink: "#586e75",
|
|
451
|
-
opaqueWindows: true,
|
|
452
|
-
semanticColors: {
|
|
453
|
-
diffAdded: "#859900",
|
|
454
|
-
diffRemoved: "#dc322f",
|
|
455
|
-
skill: "#d33682"
|
|
456
|
-
},
|
|
457
|
-
surface: "#fdf6e3"
|
|
458
|
-
},
|
|
459
|
-
variant: "light"
|
|
460
|
-
},
|
|
461
|
-
"solarized-dark": {
|
|
462
|
-
codeThemeId: "solarized",
|
|
463
|
-
theme: {
|
|
464
|
-
accent: "#268bd2",
|
|
465
|
-
contrast: 60,
|
|
466
|
-
fonts: { code: "Source Code Pro", ui: "Manrope" },
|
|
467
|
-
ink: "#839496",
|
|
468
|
-
opaqueWindows: false,
|
|
469
|
-
semanticColors: {
|
|
470
|
-
diffAdded: "#859900",
|
|
471
|
-
diffRemoved: "#dc322f",
|
|
472
|
-
skill: "#d33682"
|
|
473
|
-
},
|
|
474
|
-
surface: "#002b36"
|
|
475
|
-
},
|
|
476
|
-
variant: "dark"
|
|
477
|
-
},
|
|
478
|
-
nord: {
|
|
479
|
-
codeThemeId: "nord",
|
|
480
|
-
theme: {
|
|
481
|
-
accent: "#5e81ac",
|
|
482
|
-
contrast: 48,
|
|
483
|
-
fonts: { code: "Space Mono", ui: "Manrope" },
|
|
484
|
-
ink: "#4c566a",
|
|
485
|
-
opaqueWindows: true,
|
|
486
|
-
semanticColors: {
|
|
487
|
-
diffAdded: "#a3be8c",
|
|
488
|
-
diffRemoved: "#bf616a",
|
|
489
|
-
skill: "#b48ead"
|
|
490
|
-
},
|
|
491
|
-
surface: "#eceff4"
|
|
492
|
-
},
|
|
493
|
-
variant: "light"
|
|
494
|
-
},
|
|
495
|
-
"nord-dark": {
|
|
496
|
-
codeThemeId: "nord",
|
|
497
|
-
theme: {
|
|
498
|
-
accent: "#88c0d0",
|
|
499
|
-
contrast: 60,
|
|
500
|
-
fonts: { code: "Space Mono", ui: "Manrope" },
|
|
501
|
-
ink: "#e5e9f0",
|
|
502
|
-
opaqueWindows: true,
|
|
503
|
-
semanticColors: {
|
|
504
|
-
diffAdded: "#a3be8c",
|
|
505
|
-
diffRemoved: "#bf616a",
|
|
506
|
-
skill: "#b48ead"
|
|
507
|
-
},
|
|
508
|
-
surface: "#2e3440"
|
|
509
|
-
},
|
|
510
|
-
variant: "dark"
|
|
511
|
-
},
|
|
512
|
-
rosepine: {
|
|
513
|
-
codeThemeId: "rose-pine-dawn",
|
|
514
|
-
theme: {
|
|
515
|
-
accent: "#56949f",
|
|
516
|
-
contrast: 44,
|
|
517
|
-
fonts: { code: "DM Mono", ui: "Manrope" },
|
|
518
|
-
ink: "#575279",
|
|
519
|
-
opaqueWindows: true,
|
|
520
|
-
semanticColors: {
|
|
521
|
-
diffAdded: "#286983",
|
|
522
|
-
diffRemoved: "#b4637a",
|
|
523
|
-
skill: "#907aa9"
|
|
524
|
-
},
|
|
525
|
-
surface: "#faf4ed"
|
|
526
|
-
},
|
|
527
|
-
variant: "light"
|
|
528
|
-
},
|
|
529
|
-
"rosepine-dark": {
|
|
530
|
-
codeThemeId: "rose-pine",
|
|
531
|
-
theme: {
|
|
532
|
-
accent: "#9ccfd8",
|
|
533
|
-
contrast: 58,
|
|
534
|
-
fonts: { code: "DM Mono", ui: "Manrope" },
|
|
535
|
-
ink: "#e0def4",
|
|
536
|
-
opaqueWindows: true,
|
|
537
|
-
semanticColors: {
|
|
538
|
-
diffAdded: "#31748f",
|
|
539
|
-
diffRemoved: "#eb6f92",
|
|
540
|
-
skill: "#c4a7e7"
|
|
541
|
-
},
|
|
542
|
-
surface: "#191724"
|
|
543
|
-
},
|
|
544
|
-
variant: "dark"
|
|
545
|
-
},
|
|
546
|
-
graphite: {
|
|
547
|
-
codeThemeId: "github",
|
|
548
|
-
theme: {
|
|
549
|
-
accent: "#586069",
|
|
550
|
-
contrast: 42,
|
|
551
|
-
fonts: { code: "IBM Plex Mono", ui: "Manrope" },
|
|
552
|
-
ink: "#24292f",
|
|
553
|
-
opaqueWindows: true,
|
|
554
|
-
semanticColors: {
|
|
555
|
-
diffAdded: "#1a7f37",
|
|
556
|
-
diffRemoved: "#cf222e",
|
|
557
|
-
skill: "#8250df"
|
|
558
|
-
},
|
|
559
|
-
surface: "#f6f8fa"
|
|
560
|
-
},
|
|
561
|
-
variant: "light"
|
|
562
|
-
},
|
|
563
|
-
"graphite-dark": {
|
|
564
|
-
codeThemeId: "github",
|
|
565
|
-
theme: {
|
|
566
|
-
accent: "#7d8590",
|
|
567
|
-
contrast: 58,
|
|
568
|
-
fonts: { code: "IBM Plex Mono", ui: "Manrope" },
|
|
569
|
-
ink: "#c9d1d9",
|
|
570
|
-
opaqueWindows: true,
|
|
571
|
-
semanticColors: {
|
|
572
|
-
diffAdded: "#3fb950",
|
|
573
|
-
diffRemoved: "#f85149",
|
|
574
|
-
skill: "#d2a8ff"
|
|
575
|
-
},
|
|
576
|
-
surface: "#0d1117"
|
|
577
|
-
},
|
|
578
|
-
variant: "dark"
|
|
579
|
-
}
|
|
580
|
-
};
|
|
581
|
-
|
|
582
409
|
async function main() {
|
|
583
410
|
try {
|
|
584
411
|
const args = process.argv.slice(2);
|
|
@@ -862,11 +689,13 @@ async function runMakeWizard(initialName, flags) {
|
|
|
862
689
|
|
|
863
690
|
try {
|
|
864
691
|
const availablePresets = Object.keys(PRESETS).sort();
|
|
865
|
-
console.log(
|
|
692
|
+
console.log("Theme wizard");
|
|
693
|
+
console.log("Press Enter to keep the default shown in brackets.");
|
|
866
694
|
console.log(`Presets: ${availablePresets.join(", ")}`);
|
|
867
695
|
console.log(`UI font ideas: ${FONT_CHOICES.ui.join(", ")}`);
|
|
868
696
|
console.log(`Code/terminal font ideas: ${FONT_CHOICES.code.join(", ")}`);
|
|
869
697
|
|
|
698
|
+
console.log("\nStep 1: Base");
|
|
870
699
|
const basePresetName = await promptWithDefault(
|
|
871
700
|
rl,
|
|
872
701
|
"Base preset",
|
|
@@ -876,6 +705,7 @@ async function runMakeWizard(initialName, flags) {
|
|
|
876
705
|
const defaultName = initialName || `${basePresetName}-custom`;
|
|
877
706
|
const themeName = await promptWithDefault(rl, "Theme name", defaultName);
|
|
878
707
|
|
|
708
|
+
console.log("\nStep 2: Colors");
|
|
879
709
|
const accent = await promptWithDefault(rl, "Accent color", flags.accent || preset.accent);
|
|
880
710
|
const bg = await promptWithDefault(rl, "Background color", flags.bg || preset.bg);
|
|
881
711
|
const surface = await promptWithDefault(rl, "Surface color", flags.surface || preset.surface);
|
|
@@ -888,6 +718,7 @@ async function runMakeWizard(initialName, flags) {
|
|
|
888
718
|
const muted = await promptWithDefault(rl, "Muted color", flags.muted || preset.muted);
|
|
889
719
|
const dim = await promptWithDefault(rl, "Dim color", flags.dim || preset.dim);
|
|
890
720
|
|
|
721
|
+
console.log("\nStep 3: Fonts");
|
|
891
722
|
const fonts = {
|
|
892
723
|
terminal: await promptWithDefault(
|
|
893
724
|
rl,
|
|
@@ -906,6 +737,26 @@ async function runMakeWizard(initialName, flags) {
|
|
|
906
737
|
)
|
|
907
738
|
};
|
|
908
739
|
|
|
740
|
+
console.log("\nTheme summary:");
|
|
741
|
+
printThemeSummary({
|
|
742
|
+
name: themeName,
|
|
743
|
+
preset: basePresetName,
|
|
744
|
+
accent,
|
|
745
|
+
bg,
|
|
746
|
+
surface,
|
|
747
|
+
surfaceAlt,
|
|
748
|
+
fg,
|
|
749
|
+
muted,
|
|
750
|
+
dim,
|
|
751
|
+
fonts
|
|
752
|
+
});
|
|
753
|
+
|
|
754
|
+
const shouldWrite = await promptYesNo(rl, "Save this theme?", true);
|
|
755
|
+
if (!shouldWrite) {
|
|
756
|
+
console.log("Cancelled.");
|
|
757
|
+
return;
|
|
758
|
+
}
|
|
759
|
+
|
|
909
760
|
const autoInstallFonts = await promptYesNo(rl, "Install any missing Google fonts automatically?", true);
|
|
910
761
|
if (autoInstallFonts) {
|
|
911
762
|
installFontsBestEffort([fonts.terminal, fonts.ui, fonts.code]);
|
|
@@ -1367,6 +1218,21 @@ function installFontsBestEffort(fonts) {
|
|
|
1367
1218
|
}
|
|
1368
1219
|
}
|
|
1369
1220
|
|
|
1221
|
+
function printThemeSummary(theme) {
|
|
1222
|
+
console.log(` name: ${theme.name}`);
|
|
1223
|
+
console.log(` preset: ${theme.preset}`);
|
|
1224
|
+
console.log(` accent: ${theme.accent}`);
|
|
1225
|
+
console.log(` bg: ${theme.bg}`);
|
|
1226
|
+
console.log(` surface: ${theme.surface}`);
|
|
1227
|
+
console.log(` surface alt: ${theme.surfaceAlt}`);
|
|
1228
|
+
console.log(` text: ${theme.fg}`);
|
|
1229
|
+
console.log(` muted: ${theme.muted}`);
|
|
1230
|
+
console.log(` dim: ${theme.dim}`);
|
|
1231
|
+
console.log(` terminal font: ${theme.fonts.terminal}`);
|
|
1232
|
+
console.log(` ui font: ${theme.fonts.ui}`);
|
|
1233
|
+
console.log(` code font: ${theme.fonts.code}`);
|
|
1234
|
+
}
|
|
1235
|
+
|
|
1370
1236
|
function writeThemeAssets(paths, name, palette) {
|
|
1371
1237
|
ensureDir(paths.paletteDir);
|
|
1372
1238
|
fs.writeFileSync(path.join(paths.paletteDir, `${name}.json`), `${JSON.stringify(palette, null, 2)}\n`, "utf8");
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ctheme",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "Theme manager for making terminals look better with colors, fonts, and live profile switching",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -20,13 +20,16 @@
|
|
|
20
20
|
],
|
|
21
21
|
"files": [
|
|
22
22
|
"bin",
|
|
23
|
-
"
|
|
23
|
+
"DEVELOPMENT.md",
|
|
24
|
+
"README.md",
|
|
25
|
+
"scripts"
|
|
24
26
|
],
|
|
25
27
|
"bin": {
|
|
26
28
|
"ctheme": "bin/ctheme.js"
|
|
27
29
|
},
|
|
28
30
|
"scripts": {
|
|
29
|
-
"test": "node ./bin/ctheme.js --help"
|
|
31
|
+
"test": "node ./bin/ctheme.js --help",
|
|
32
|
+
"postinstall": "node ./scripts/postinstall.js"
|
|
30
33
|
},
|
|
31
34
|
"engines": {
|
|
32
35
|
"node": ">=18"
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const { spawnSync } = require("child_process");
|
|
4
|
+
const path = require("path");
|
|
5
|
+
|
|
6
|
+
const DEFAULT_FONTS = [
|
|
7
|
+
"Azeret Mono",
|
|
8
|
+
"Bricolage Grotesque",
|
|
9
|
+
"DM Mono",
|
|
10
|
+
"Fira Code",
|
|
11
|
+
"Fraunces",
|
|
12
|
+
"IBM Plex Mono",
|
|
13
|
+
"IBM Plex Sans",
|
|
14
|
+
"Instrument Serif",
|
|
15
|
+
"JetBrains Mono",
|
|
16
|
+
"Newsreader",
|
|
17
|
+
"Outfit",
|
|
18
|
+
"Plus Jakarta Sans",
|
|
19
|
+
"Roboto Mono",
|
|
20
|
+
"Sora",
|
|
21
|
+
"Source Code Pro",
|
|
22
|
+
"Source Sans 3",
|
|
23
|
+
"Space Grotesk",
|
|
24
|
+
"Space Mono",
|
|
25
|
+
"Syne",
|
|
26
|
+
"Ubuntu Mono",
|
|
27
|
+
"Urbanist",
|
|
28
|
+
"Victor Mono"
|
|
29
|
+
];
|
|
30
|
+
|
|
31
|
+
if (process.env.CTHEME_SKIP_FONT_BOOTSTRAP === "1") {
|
|
32
|
+
console.log("ctheme: skipping default font bootstrap");
|
|
33
|
+
process.exit(0);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
if (process.platform !== "darwin") {
|
|
37
|
+
console.log("ctheme: skipping default font bootstrap on non-macOS");
|
|
38
|
+
process.exit(0);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const cliPath = path.join(__dirname, "..", "bin", "ctheme.js");
|
|
42
|
+
console.log(`ctheme: installing bundled default fonts (${DEFAULT_FONTS.length})`);
|
|
43
|
+
|
|
44
|
+
for (const family of DEFAULT_FONTS) {
|
|
45
|
+
const result = spawnSync(process.execPath, [cliPath, "font", "install", family], {
|
|
46
|
+
stdio: "inherit",
|
|
47
|
+
env: {
|
|
48
|
+
...process.env,
|
|
49
|
+
CTHEME_SKIP_FONT_BOOTSTRAP: "1"
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
if (result.status !== 0) {
|
|
54
|
+
console.log(`ctheme: skipped ${family}`);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|