@bismawy/pi-arnative 0.3.10 → 0.5.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/CHANGELOG.md +54 -0
- package/README.md +59 -45
- package/extensions/animations.ts +213 -0
- package/extensions/arnative.ts +422 -99
- package/extensions/footer.ts +327 -65
- package/extensions/section-headers.ts +35 -17
- package/extensions/timestamps.ts +1 -1
- package/extensions/tools.ts +31 -12
- package/extensions/ui-render-tweaks.ts +36 -4
- package/extensions/usage.ts +483 -89
- package/lib/ansi.ts +89 -6
- package/lib/box.ts +90 -5
- package/lib/shortcuts.ts +62 -13
- package/lib/spinner.ts +270 -0
- package/lib/usage-store.ts +96 -4
- package/package.json +4 -3
- package/themes/arnative-cyberpunk.json +34 -33
- package/themes/arnative-dracula.json +26 -25
- package/themes/arnative-emerald.json +6 -5
- package/themes/arnative-gruvbox.json +26 -25
- package/themes/arnative-matrix.json +22 -21
- package/themes/arnative-nord.json +23 -22
- package/themes/arnative-sun.json +7 -6
- package/themes/arnative-synthwave.json +34 -33
- package/themes/arnative-violet.json +8 -7
- package/themes/arnative-zinc.json +6 -5
- package/themes/arnative.json +7 -6
- package/themes/gen-themes.mjs +121 -52
package/themes/gen-themes.mjs
CHANGED
|
@@ -17,8 +17,9 @@ import { parseOklch, oklchToRgb } from "../lib/color.ts";
|
|
|
17
17
|
import { assert } from "../lib/check.ts";
|
|
18
18
|
|
|
19
19
|
const HERE = dirname(fileURLToPath(import.meta.url));
|
|
20
|
-
|
|
21
|
-
|
|
20
|
+
// Pi 1.2.0 moved the published schema to pi.dev; older releases validated this
|
|
21
|
+
// reference only as a string, so the new URL is safe on both.
|
|
22
|
+
const SCHEMA = "https://pi.dev/schemas/theme.schema.json";
|
|
22
23
|
|
|
23
24
|
// --- color helpers ---------------------------------------------------------
|
|
24
25
|
|
|
@@ -38,16 +39,26 @@ const THINKING = { off: 0.4, minimal: 0.47, low: 0.55, medium: 0.63, high: 0.71,
|
|
|
38
39
|
const SEMANTIC = { success: 145, error: 25, warning: 85 };
|
|
39
40
|
const SYNTAX_OFFSET = { keyword: 0, func: 45, variable: -45, string: 120, number: 180, type: 90 };
|
|
40
41
|
|
|
41
|
-
/** Default hue for a role used outside `syntax*` (heading/link/label). */
|
|
42
|
-
const ACCENT_OFFSET = {
|
|
42
|
+
/** Default hue for a role used outside `syntax*` (heading/link/label/code/bullet/border). */
|
|
43
|
+
const ACCENT_OFFSET = {
|
|
44
|
+
heading: 0,
|
|
45
|
+
link: 0,
|
|
46
|
+
label: 60,
|
|
47
|
+
code: 0,
|
|
48
|
+
bullet: 0,
|
|
49
|
+
border: 0,
|
|
50
|
+
selected: 0,
|
|
51
|
+
searchMatch: 0,
|
|
52
|
+
};
|
|
43
53
|
|
|
44
54
|
// --- theme parameters ------------------------------------------------------
|
|
45
55
|
|
|
46
56
|
/**
|
|
47
|
-
* `accent` is the seed color (OKLCH, hue + reference lightness/chroma)
|
|
48
|
-
*
|
|
49
|
-
* `
|
|
50
|
-
*
|
|
57
|
+
* `accent` is the seed/focus color (OKLCH, hue + reference lightness/chroma);
|
|
58
|
+
* `primary` and `secondary` define the theme's core signature and dual-tone balance;
|
|
59
|
+
* `chroma` is the normalized accent chroma.
|
|
60
|
+
* `hues` overrides the derived hue per role (keyword/func/… /heading/link/label/code/…)
|
|
61
|
+
* to keep rich multi-colored palettes (cyberpunk, synthwave, dracula, etc.) authentic.
|
|
51
62
|
*/
|
|
52
63
|
const THEMES = {
|
|
53
64
|
arnative: {
|
|
@@ -56,6 +67,8 @@ const THEMES = {
|
|
|
56
67
|
canvasL: 0.27,
|
|
57
68
|
neutralHue: 232,
|
|
58
69
|
neutralChroma: 0.012,
|
|
70
|
+
primary: "oklch(82% 0.14 218)",
|
|
71
|
+
secondary: "oklch(78% 0.11 282)",
|
|
59
72
|
hues: { heading: 75, label: 282 },
|
|
60
73
|
},
|
|
61
74
|
"arnative-sun": {
|
|
@@ -64,6 +77,8 @@ const THEMES = {
|
|
|
64
77
|
canvasL: 0.27,
|
|
65
78
|
neutralHue: 70,
|
|
66
79
|
neutralChroma: 0.012,
|
|
80
|
+
primary: "oklch(84% 0.15 70)",
|
|
81
|
+
secondary: "oklch(78% 0.12 35)",
|
|
67
82
|
hues: { heading: 60, label: 330 },
|
|
68
83
|
},
|
|
69
84
|
"arnative-zinc": {
|
|
@@ -72,6 +87,8 @@ const THEMES = {
|
|
|
72
87
|
canvasL: 0.26,
|
|
73
88
|
neutralHue: 285,
|
|
74
89
|
neutralChroma: 0.005,
|
|
90
|
+
primary: "oklch(86% 0.015 285)",
|
|
91
|
+
secondary: "oklch(72% 0.025 240)",
|
|
75
92
|
hues: { heading: 285, label: 285 },
|
|
76
93
|
},
|
|
77
94
|
"arnative-violet": {
|
|
@@ -80,6 +97,8 @@ const THEMES = {
|
|
|
80
97
|
canvasL: 0.27,
|
|
81
98
|
neutralHue: 295,
|
|
82
99
|
neutralChroma: 0.012,
|
|
100
|
+
primary: "oklch(82% 0.15 294)",
|
|
101
|
+
secondary: "oklch(78% 0.11 215)",
|
|
83
102
|
hues: { heading: 295, label: 330 },
|
|
84
103
|
},
|
|
85
104
|
"arnative-emerald": {
|
|
@@ -88,80 +107,119 @@ const THEMES = {
|
|
|
88
107
|
canvasL: 0.27,
|
|
89
108
|
neutralHue: 165,
|
|
90
109
|
neutralChroma: 0.012,
|
|
110
|
+
primary: "oklch(84% 0.13 165)",
|
|
111
|
+
secondary: "oklch(78% 0.10 195)",
|
|
91
112
|
hues: { heading: 165, label: 200 },
|
|
92
113
|
},
|
|
93
114
|
"arnative-matrix": {
|
|
94
115
|
accent: "oklch(86.9% 0.2776 144.466116)",
|
|
95
116
|
chroma: 0.22,
|
|
96
|
-
canvasL: 0.
|
|
117
|
+
canvasL: 0.24,
|
|
97
118
|
neutralHue: 145,
|
|
98
119
|
neutralChroma: 0.02,
|
|
120
|
+
primary: "oklch(88% 0.24 145)",
|
|
121
|
+
secondary: "oklch(76% 0.16 165)",
|
|
122
|
+
surfaceMsg: "oklch(24% 0.035 145)",
|
|
99
123
|
hues: {
|
|
100
124
|
heading: 145, link: 145, label: 145,
|
|
101
125
|
keyword: 145, func: 145, variable: 145, string: 145, number: 145, type: 145,
|
|
102
126
|
},
|
|
103
127
|
},
|
|
104
128
|
"arnative-cyberpunk": {
|
|
105
|
-
accent: "oklch(
|
|
129
|
+
accent: "oklch(76% 0.22 355)",
|
|
106
130
|
chroma: 0.2,
|
|
107
|
-
canvasL: 0.
|
|
131
|
+
canvasL: 0.24,
|
|
108
132
|
neutralHue: 275,
|
|
109
133
|
neutralChroma: 0.02,
|
|
134
|
+
primary: "oklch(88% 0.18 95)",
|
|
135
|
+
secondary: "oklch(82% 0.16 200)",
|
|
136
|
+
surfaceMsg: "oklch(24% 0.035 200)",
|
|
137
|
+
borderAccent: "secondary",
|
|
138
|
+
headingColor: "primary",
|
|
139
|
+
codeColor: "secondary",
|
|
140
|
+
bulletColor: "primary",
|
|
141
|
+
keywordColor: "secondary",
|
|
110
142
|
hues: {
|
|
111
|
-
heading:
|
|
112
|
-
keyword:
|
|
143
|
+
heading: 95, link: 200, label: 200, code: 200, bullet: 95, border: 200, selected: 200, searchMatch: 95,
|
|
144
|
+
keyword: 200, func: 95, variable: 355, string: 140, number: 45, type: 200,
|
|
113
145
|
},
|
|
114
146
|
},
|
|
115
147
|
"arnative-synthwave": {
|
|
116
|
-
accent: "oklch(
|
|
148
|
+
accent: "oklch(80% 0.18 50)",
|
|
117
149
|
chroma: 0.17,
|
|
118
|
-
canvasL: 0.
|
|
150
|
+
canvasL: 0.24,
|
|
119
151
|
neutralHue: 300,
|
|
120
152
|
neutralChroma: 0.015,
|
|
153
|
+
primary: "oklch(78% 0.19 339)",
|
|
154
|
+
secondary: "oklch(82% 0.16 185)",
|
|
155
|
+
surfaceMsg: "oklch(24% 0.03 300)",
|
|
156
|
+
borderAccent: "secondary",
|
|
157
|
+
codeColor: "secondary",
|
|
158
|
+
bulletColor: "primary",
|
|
121
159
|
hues: {
|
|
122
|
-
heading:
|
|
123
|
-
keyword:
|
|
160
|
+
heading: 50, link: 185, label: 185, code: 185, bullet: 339, border: 185, selected: 185, searchMatch: 50,
|
|
161
|
+
keyword: 185, func: 50, variable: 339, string: 45, number: 339, type: 290,
|
|
124
162
|
},
|
|
125
163
|
},
|
|
126
164
|
"arnative-gruvbox": {
|
|
127
|
-
accent: "oklch(
|
|
165
|
+
accent: "oklch(76% 0.15 45)",
|
|
128
166
|
chroma: 0.14,
|
|
129
167
|
canvasL: 0.24,
|
|
130
168
|
neutralHue: 70,
|
|
131
169
|
neutralChroma: 0.015,
|
|
170
|
+
primary: "oklch(84% 0.14 83)",
|
|
171
|
+
secondary: "oklch(78% 0.10 175)",
|
|
172
|
+
borderAccent: "secondary",
|
|
173
|
+
headingColor: "primary",
|
|
174
|
+
codeColor: "secondary",
|
|
175
|
+
bulletColor: "accent",
|
|
132
176
|
hues: {
|
|
133
|
-
heading:
|
|
134
|
-
keyword:
|
|
177
|
+
heading: 83, link: 175, label: 175, code: 175, bullet: 45, border: 83, selected: 83, searchMatch: 83,
|
|
178
|
+
keyword: 45, func: 83, variable: 175, string: 145, number: 45, type: 83,
|
|
135
179
|
},
|
|
136
180
|
},
|
|
137
181
|
"arnative-nord": {
|
|
138
|
-
accent: "oklch(
|
|
182
|
+
accent: "oklch(74% 0.09 310)",
|
|
139
183
|
chroma: 0.07,
|
|
140
184
|
canvasL: 0.3,
|
|
141
185
|
neutralHue: 240,
|
|
142
186
|
neutralChroma: 0.01,
|
|
187
|
+
primary: "oklch(78% 0.08 217)",
|
|
188
|
+
secondary: "oklch(82% 0.09 195)",
|
|
189
|
+
borderAccent: "secondary",
|
|
190
|
+
codeColor: "secondary",
|
|
191
|
+
bulletColor: "primary",
|
|
143
192
|
hues: {
|
|
144
|
-
heading:
|
|
145
|
-
keyword:
|
|
193
|
+
heading: 75, link: 195, label: 195, code: 195, bullet: 217, border: 217, selected: 217, searchMatch: 75,
|
|
194
|
+
keyword: 217, func: 195, variable: 217, string: 145, number: 310, type: 195,
|
|
146
195
|
},
|
|
147
196
|
},
|
|
148
197
|
"arnative-dracula": {
|
|
149
|
-
accent: "oklch(
|
|
198
|
+
accent: "oklch(76% 0.18 330)",
|
|
150
199
|
chroma: 0.14,
|
|
151
200
|
canvasL: 0.29,
|
|
152
201
|
neutralHue: 285,
|
|
153
202
|
neutralChroma: 0.012,
|
|
203
|
+
primary: "oklch(78% 0.15 295)",
|
|
204
|
+
secondary: "oklch(82% 0.13 190)",
|
|
205
|
+
borderAccent: "secondary",
|
|
206
|
+
codeColor: "secondary",
|
|
207
|
+
bulletColor: "accent",
|
|
154
208
|
hues: {
|
|
155
|
-
heading:
|
|
156
|
-
keyword: 330, func:
|
|
209
|
+
heading: 85, link: 190, label: 190, code: 190, bullet: 330, border: 295, selected: 295, searchMatch: 85,
|
|
210
|
+
keyword: 330, func: 140, variable: 190, string: 85, number: 295, type: 190,
|
|
157
211
|
},
|
|
158
212
|
},
|
|
159
213
|
};
|
|
160
214
|
|
|
161
215
|
// --- role order (matches the pi theme schema) ------------------------------
|
|
162
|
-
|
|
216
|
+
//
|
|
217
|
+
// Only tokens pi's schema declares may appear as keys here: since 1.2.0 the
|
|
218
|
+
// `colors` object is validated with `additionalProperties: false`, and an extra
|
|
219
|
+
// key rejects the whole theme at startup. Arnative's own colors (`accentSoft`,
|
|
220
|
+
// `primary`, `secondary`, …) live in `vars` and are referenced from these roles.
|
|
163
221
|
const ROLE_ORDER = [
|
|
164
|
-
"accent", "
|
|
222
|
+
"accent", "border", "borderAccent", "borderMuted", "success", "error", "warning",
|
|
165
223
|
"muted", "dim", "text", "thinkingText",
|
|
166
224
|
"selectedBg", "scrollbarTrack", "scrollbarThumb", "searchMatchBg", "searchMatchText",
|
|
167
225
|
"userMessageBg", "userMessageText", "customMessageBg", "customMessageText", "customMessageLabel",
|
|
@@ -189,26 +247,37 @@ function derive(spec) {
|
|
|
189
247
|
const roleHue = (role) => hue(H[role]);
|
|
190
248
|
const sem = (role) => hue(SEMANTIC[role]);
|
|
191
249
|
|
|
250
|
+
const primarySeed = spec.primary ? parseOklch(spec.primary) : null;
|
|
251
|
+
const secondarySeed = spec.secondary ? parseOklch(spec.secondary) : null;
|
|
252
|
+
const primaryVal = primarySeed ? oklch(primarySeed.L, primarySeed.C, primarySeed.H) : oklch(0.82, c, h);
|
|
253
|
+
const secondaryVal = secondarySeed ? oklch(secondarySeed.L, secondarySeed.C, secondarySeed.H) : oklch(0.78, Math.min(c * 0.8, 0.12), roleHue("label"));
|
|
254
|
+
|
|
192
255
|
const vars = {
|
|
193
256
|
fg: oklch(NEUTRAL.fg, nc, nh),
|
|
194
257
|
fgMuted: oklch(NEUTRAL.fgMuted, nc, nh),
|
|
195
258
|
fgDim: oklch(NEUTRAL.fgDim, nc, nh),
|
|
196
259
|
fgFaint: oklch(NEUTRAL.fgFaint, nc, nh),
|
|
260
|
+
primary: primaryVal,
|
|
261
|
+
secondary: secondaryVal,
|
|
197
262
|
accent: oklch(0.78, c, h),
|
|
198
|
-
|
|
263
|
+
// Derived from the accent's GAMUT-CLAMPED chroma, not the raw spec chroma. Pi's schema
|
|
264
|
+
// forbids custom keys in `colors`, so extensions resolve the soft tier at runtime by
|
|
265
|
+
// softening the resolved `accent` (see `softOf` in lib/ansi.ts). Building it from the
|
|
266
|
+
// same clamped chroma makes the declared value and the runtime one agree; using `c`
|
|
267
|
+
// drifts wherever the raw chroma is out of gamut at the accent's lightness.
|
|
268
|
+
accentSoft: oklch(0.82, oklchToRgb(0.78, c, h).chroma * 0.18, h),
|
|
199
269
|
accentBorder: oklch(0.82, c * 0.6, h),
|
|
200
270
|
success: oklch(0.78, Math.min(c, 0.15), sem("success")),
|
|
201
271
|
error: oklch(0.76, Math.min(c, 0.15), sem("error")),
|
|
202
272
|
warning: oklch(0.86, Math.min(c, 0.14), sem("warning")),
|
|
203
|
-
surfaceMsg: oklch(base, nc * 0.5, nh),
|
|
273
|
+
surfaceMsg: spec.surfaceMsg ?? oklch(base, nc * 0.5, nh),
|
|
204
274
|
};
|
|
205
275
|
|
|
206
|
-
const accentLiteral = oklch(0.8, c * 0.7, h);
|
|
276
|
+
const accentLiteral = oklch(0.8, Math.min(c * 0.7, 0.14), h);
|
|
207
277
|
const roles = {
|
|
208
278
|
accent: "accent",
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
borderAccent: "accentBorder",
|
|
279
|
+
border: oklch(0.55, Math.min(c * 0.35, 0.08), roleHue("border")),
|
|
280
|
+
borderAccent: spec.borderAccent ?? "accentBorder",
|
|
212
281
|
borderMuted: "fgFaint",
|
|
213
282
|
success: "success",
|
|
214
283
|
error: "error",
|
|
@@ -218,45 +287,45 @@ function derive(spec) {
|
|
|
218
287
|
text: "fg",
|
|
219
288
|
thinkingText: "fgMuted",
|
|
220
289
|
|
|
221
|
-
selectedBg: oklch(base + 0.07, c * 0.25,
|
|
290
|
+
selectedBg: oklch(base + 0.07, Math.min(c * 0.25, 0.06), roleHue("selected")),
|
|
222
291
|
scrollbarTrack: "fgFaint",
|
|
223
292
|
scrollbarThumb: "accentSoft",
|
|
224
|
-
searchMatchBg: oklch(base + 0.14, c * 0.45,
|
|
293
|
+
searchMatchBg: oklch(base + 0.14, Math.min(c * 0.45, 0.10), roleHue("searchMatch")),
|
|
225
294
|
searchMatchText: "fg",
|
|
226
295
|
userMessageBg: "surfaceMsg",
|
|
227
296
|
userMessageText: "fg",
|
|
228
|
-
customMessageBg: oklch(base + 0.01, c * 0.4, roleHue("label")),
|
|
297
|
+
customMessageBg: oklch(base + 0.01, Math.min(c * 0.4, 0.05), roleHue("label")),
|
|
229
298
|
customMessageText: "fg",
|
|
230
|
-
customMessageLabel: oklch(0.78, c * 0.7, roleHue("label")),
|
|
299
|
+
customMessageLabel: spec.labelColor ?? oklch(0.78, Math.min(c * 0.7, 0.14), roleHue("label")),
|
|
231
300
|
|
|
232
|
-
toolPendingBg: oklch(base - 0.02, c * 0.3, h),
|
|
233
|
-
toolSuccessBg: oklch(base - 0.03, c * 0.4, sem("success")),
|
|
234
|
-
toolErrorBg: oklch(base - 0.03, c * 0.4, sem("error")),
|
|
301
|
+
toolPendingBg: oklch(base - 0.02, Math.min(c * 0.3, 0.05), h),
|
|
302
|
+
toolSuccessBg: oklch(base - 0.03, Math.min(c * 0.4, 0.06), sem("success")),
|
|
303
|
+
toolErrorBg: oklch(base - 0.03, Math.min(c * 0.4, 0.06), sem("error")),
|
|
235
304
|
toolTitle: "fg",
|
|
236
305
|
toolOutput: "fgMuted",
|
|
237
306
|
|
|
238
|
-
mdHeading: oklch(0.88, c * 0.6, roleHue("heading")),
|
|
239
|
-
mdLink: oklch(0.8, c * 0.7, roleHue("link")),
|
|
307
|
+
mdHeading: spec.headingColor ?? oklch(0.88, Math.min(c * 0.6, 0.14), roleHue("heading")),
|
|
308
|
+
mdLink: spec.linkColor ?? oklch(0.8, Math.min(c * 0.7, 0.14), roleHue("link")),
|
|
240
309
|
mdLinkUrl: "fgDim",
|
|
241
|
-
mdCode: accentLiteral,
|
|
310
|
+
mdCode: spec.codeColor ?? accentLiteral,
|
|
242
311
|
mdCodeBlock: "success",
|
|
243
312
|
mdCodeBlockBorder: "fgMuted",
|
|
244
313
|
mdQuote: "fgMuted",
|
|
245
314
|
mdQuoteBorder: "fgMuted",
|
|
246
315
|
mdHr: "fgFaint",
|
|
247
|
-
mdListBullet: accentLiteral,
|
|
316
|
+
mdListBullet: spec.bulletColor ?? accentLiteral,
|
|
248
317
|
|
|
249
318
|
toolDiffAdded: "success",
|
|
250
319
|
toolDiffRemoved: "error",
|
|
251
320
|
toolDiffContext: "fgMuted",
|
|
252
321
|
|
|
253
322
|
syntaxComment: "fgDim",
|
|
254
|
-
syntaxKeyword: accentLiteral,
|
|
255
|
-
syntaxFunction: oklch(0.86, c * 0.8, roleHue("func")),
|
|
256
|
-
syntaxVariable: oklch(0.84, c * 0.55, roleHue("variable")),
|
|
257
|
-
syntaxString: oklch(0.82, c * 0.7, roleHue("string")),
|
|
258
|
-
syntaxNumber: oklch(0.8, c * 0.7, roleHue("number")),
|
|
259
|
-
syntaxType: oklch(0.8, c * 0.8, roleHue("type")),
|
|
323
|
+
syntaxKeyword: spec.keywordColor ?? accentLiteral,
|
|
324
|
+
syntaxFunction: oklch(0.86, Math.min(c * 0.8, 0.16), roleHue("func")),
|
|
325
|
+
syntaxVariable: oklch(0.84, Math.min(c * 0.55, 0.14), roleHue("variable")),
|
|
326
|
+
syntaxString: oklch(0.82, Math.min(c * 0.7, 0.16), roleHue("string")),
|
|
327
|
+
syntaxNumber: oklch(0.8, Math.min(c * 0.7, 0.15), roleHue("number")),
|
|
328
|
+
syntaxType: oklch(0.8, Math.min(c * 0.8, 0.16), roleHue("type")),
|
|
260
329
|
syntaxOperator: "fg",
|
|
261
330
|
syntaxPunctuation: "fgMuted",
|
|
262
331
|
|
|
@@ -274,7 +343,7 @@ function derive(spec) {
|
|
|
274
343
|
const exp = {
|
|
275
344
|
pageBg: oklch(base - 0.06, nc, nh),
|
|
276
345
|
cardBg: oklch(base - 0.03, nc, nh),
|
|
277
|
-
infoBg: oklch(base + 0.05, c * 0.25, h),
|
|
346
|
+
infoBg: oklch(base + 0.05, Math.min(c * 0.25, 0.06), h),
|
|
278
347
|
};
|
|
279
348
|
|
|
280
349
|
// Roles must match ROLE_ORDER exactly and each value must be a var name or a literal.
|