kailogger 1.0.1-dark.red → 1.0.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/README.md +60 -48
- package/dist/core/Logger.d.ts +1 -1
- package/dist/core/Logger.js +36 -39
- package/dist/features/Chart.js +8 -9
- package/dist/features/Diff.js +4 -8
- package/dist/features/Encrypt.js +5 -5
- package/dist/features/Notify.js +40 -1
- package/dist/features/Screenshot.js +0 -3
- package/dist/features/Sound.d.ts +1 -0
- package/dist/features/Sound.js +37 -39
- package/dist/features/Timer.js +3 -7
- package/dist/features/Tree.js +5 -8
- package/dist/icon/logo.png +0 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -7
- package/dist/sounds/error.wav +0 -0
- package/dist/sounds/notification.wav +0 -0
- package/dist/sounds/success.wav +0 -0
- package/dist/sounds/warning.wav +0 -0
- package/dist/styles/KaiChroma.d.ts +85 -0
- package/dist/styles/KaiChroma.js +407 -0
- package/dist/styles/palettes.d.ts +21 -57
- package/dist/styles/palettes.js +160 -37
- package/dist/transports/ConsoleTransport.js +2 -2
- package/dist/utils/json.js +8 -11
- package/dist/utils/prettyError.js +16 -18
- package/dist/utils/progress.js +5 -7
- package/dist/utils/prompt.js +3 -3
- package/dist/utils/selection.js +14 -24
- package/dist/utils/spinner.d.ts +1 -1
- package/dist/utils/spinner.js +9 -13
- package/dist/utils/stripAnsi.js +2 -1
- package/dist/utils/table.js +4 -7
- package/examples/demo.js +134 -0
- package/package.json +4 -9
- package/scripts/copy-assets.js +37 -0
- package/src/core/Logger.ts +148 -31
- package/src/features/Chart.ts +25 -5
- package/src/features/Diff.ts +2 -2
- package/src/features/Encrypt.ts +13 -5
- package/src/features/Sound.ts +51 -25
- package/src/features/Timer.ts +3 -3
- package/src/features/Tree.ts +6 -5
- package/src/index.ts +1 -1
- package/src/styles/KaiChroma.ts +370 -0
- package/src/styles/palettes.ts +190 -38
- package/src/transports/ConsoleTransport.ts +2 -2
- package/src/utils/json.ts +14 -6
- package/src/utils/prettyError.ts +26 -13
- package/src/utils/progress.ts +19 -5
- package/src/utils/prompt.ts +6 -2
- package/src/utils/selection.ts +40 -17
- package/src/utils/spinner.ts +11 -7
- package/src/utils/stripAnsi.ts +4 -1
- package/src/utils/table.ts +10 -3
- package/src/styles/gradients.ts +0 -22
|
@@ -0,0 +1,370 @@
|
|
|
1
|
+
import os from 'os';
|
|
2
|
+
|
|
3
|
+
export type Color = [number, number, number];
|
|
4
|
+
export type HexColor = string;
|
|
5
|
+
export type RgbColor = { r: number; g: number; b: number };
|
|
6
|
+
export type HslColor = { h: number; s: number; l: number };
|
|
7
|
+
export type ColorStop = { color: string; position: number };
|
|
8
|
+
export type GradientOptions = {
|
|
9
|
+
interpolation?: 'linear' | 'ease' | 'bezier' | 'smooth';
|
|
10
|
+
direction?: 'horizontal' | 'vertical' | 'diagonal';
|
|
11
|
+
stops?: ColorStop[];
|
|
12
|
+
};
|
|
13
|
+
export type StyleOptions = {
|
|
14
|
+
bold?: boolean;
|
|
15
|
+
dim?: boolean;
|
|
16
|
+
italic?: boolean;
|
|
17
|
+
underline?: boolean;
|
|
18
|
+
inverse?: boolean;
|
|
19
|
+
strikethrough?: boolean;
|
|
20
|
+
blink?: boolean;
|
|
21
|
+
hidden?: boolean;
|
|
22
|
+
};
|
|
23
|
+
const env = process.env;
|
|
24
|
+
const isTTY = process.stdout.isTTY;
|
|
25
|
+
const platform = os.platform();
|
|
26
|
+
const supportLevel = (() => {
|
|
27
|
+
if (env.CI && !env.FORCE_COLOR) return 0;
|
|
28
|
+
if (!isTTY && !env.FORCE_COLOR) return 0;
|
|
29
|
+
if (env.FORCE_COLOR === '0') return 0;
|
|
30
|
+
if (env.FORCE_COLOR === '1') return 1;
|
|
31
|
+
if (env.FORCE_COLOR === '2') return 2;
|
|
32
|
+
if (env.FORCE_COLOR === '3') return 3;
|
|
33
|
+
if (platform === 'win32') {
|
|
34
|
+
if (env.WT_SESSION || env.ConEmuANSI === 'ON') return 3;
|
|
35
|
+
}
|
|
36
|
+
if (env.COLORTERM === 'truecolor' || env.COLORTERM === '24bit') return 3;
|
|
37
|
+
if (env.TERM_PROGRAM === 'iTerm.app') return 3;
|
|
38
|
+
if (env.TERM_PROGRAM === 'Apple_Terminal') return 2;
|
|
39
|
+
if (env.TERM_PROGRAM === 'Hyper') return 3;
|
|
40
|
+
if (env.TERM_PROGRAM === 'vscode') return 3;
|
|
41
|
+
const term = env.TERM || '';
|
|
42
|
+
if (term.includes('truecolor') || term.includes('24bit')) return 3;
|
|
43
|
+
if (term.includes('256color')) return 2;
|
|
44
|
+
if (term === 'xterm' || term === 'screen' || term === 'linux') return 1;
|
|
45
|
+
return isTTY ? 1 : 0;
|
|
46
|
+
})();
|
|
47
|
+
export class KaiChroma {
|
|
48
|
+
private static cache = new Map<string, string>();
|
|
49
|
+
private static readonly MAX_CACHE_SIZE = 1000;
|
|
50
|
+
private static hexToRgb(hex: string): Color {
|
|
51
|
+
const cleanHex = hex.replace(/^#/, '');
|
|
52
|
+
const bigint = parseInt(cleanHex, 16);
|
|
53
|
+
return [(bigint >> 16) & 255, (bigint >> 8) & 255, bigint & 255];
|
|
54
|
+
}
|
|
55
|
+
private static rgbToHex(r: number, g: number, b: number): string {
|
|
56
|
+
return '#' + [r, g, b].map(x => {
|
|
57
|
+
const hex = x.toString(16);
|
|
58
|
+
return hex.length === 1 ? '0' + hex : hex;
|
|
59
|
+
}).join('');
|
|
60
|
+
}
|
|
61
|
+
private static rgbToHsl(r: number, g: number, b: number): HslColor {
|
|
62
|
+
r /= 255; g /= 255; b /= 255;
|
|
63
|
+
const max = Math.max(r, g, b), min = Math.min(r, g, b);
|
|
64
|
+
let h = 0, s = 0, l = (max + min) / 2;
|
|
65
|
+
if (max !== min) {
|
|
66
|
+
const d = max - min;
|
|
67
|
+
s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
|
|
68
|
+
switch (max) {
|
|
69
|
+
case r: h = ((g - b) / d + (g < b ? 6 : 0)) / 6; break;
|
|
70
|
+
case g: h = ((b - r) / d + 2) / 6; break;
|
|
71
|
+
case b: h = ((r - g) / d + 4) / 6; break;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
return { h: h * 360, s: s * 100, l: l * 100 };
|
|
75
|
+
}
|
|
76
|
+
private static hslToRgb(h: number, s: number, l: number): Color {
|
|
77
|
+
h /= 360; s /= 100; l /= 100;
|
|
78
|
+
const hue2rgb = (p: number, q: number, t: number) => {
|
|
79
|
+
if (t < 0) t += 1;
|
|
80
|
+
if (t > 1) t -= 1;
|
|
81
|
+
if (t < 1/6) return p + (q - p) * 6 * t;
|
|
82
|
+
if (t < 1/2) return q;
|
|
83
|
+
if (t < 2/3) return p + (q - p) * (2/3 - t) * 6;
|
|
84
|
+
return p;
|
|
85
|
+
};
|
|
86
|
+
if (s === 0) {
|
|
87
|
+
const val = Math.round(l * 255);
|
|
88
|
+
return [val, val, val];
|
|
89
|
+
}
|
|
90
|
+
const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
|
|
91
|
+
const p = 2 * l - q;
|
|
92
|
+
return [
|
|
93
|
+
Math.round(hue2rgb(p, q, h + 1/3) * 255),
|
|
94
|
+
Math.round(hue2rgb(p, q, h) * 255),
|
|
95
|
+
Math.round(hue2rgb(p, q, h - 1/3) * 255)
|
|
96
|
+
];
|
|
97
|
+
}
|
|
98
|
+
private static rgbToAnsi256(r: number, g: number, b: number): number {
|
|
99
|
+
if (r === g && g === b) {
|
|
100
|
+
if (r < 8) return 16;
|
|
101
|
+
if (r > 248) return 231;
|
|
102
|
+
return Math.round(((r - 8) / 247) * 24) + 232;
|
|
103
|
+
}
|
|
104
|
+
return 16 + (36 * Math.round(r / 255 * 5)) + (6 * Math.round(g / 255 * 5)) + Math.round(b / 255 * 5);
|
|
105
|
+
}
|
|
106
|
+
private static interpolateLinear(start: Color, end: Color, t: number): Color {
|
|
107
|
+
return [
|
|
108
|
+
Math.round(start[0] + (end[0] - start[0]) * t),
|
|
109
|
+
Math.round(start[1] + (end[1] - start[1]) * t),
|
|
110
|
+
Math.round(start[2] + (end[2] - start[2]) * t)
|
|
111
|
+
];
|
|
112
|
+
}
|
|
113
|
+
private static interpolateEase(start: Color, end: Color, t: number): Color {
|
|
114
|
+
const eased = t < 0.5 ? 2 * t * t : -1 + (4 - 2 * t) * t;
|
|
115
|
+
return this.interpolateLinear(start, end, eased);
|
|
116
|
+
}
|
|
117
|
+
private static interpolateBezier(start: Color, end: Color, t: number): Color {
|
|
118
|
+
const bezier = t * t * (3 - 2 * t);
|
|
119
|
+
return this.interpolateLinear(start, end, bezier);
|
|
120
|
+
}
|
|
121
|
+
private static interpolateSmooth(start: Color, end: Color, t: number): Color {
|
|
122
|
+
const smooth = t * t * t * (t * (t * 6 - 15) + 10);
|
|
123
|
+
return this.interpolateLinear(start, end, smooth);
|
|
124
|
+
}
|
|
125
|
+
static hex(hex: string, text: string): string {
|
|
126
|
+
if (supportLevel === 0) return text;
|
|
127
|
+
const cacheKey = `hex:${hex}:${supportLevel}`;
|
|
128
|
+
const [r, g, b] = this.hexToRgb(hex);
|
|
129
|
+
if (supportLevel === 3) {
|
|
130
|
+
return `\x1b[38;2;${r};${g};${b}m${text}\x1b[39m`;
|
|
131
|
+
} else if (supportLevel === 2) {
|
|
132
|
+
return `\x1b[38;5;${this.rgbToAnsi256(r, g, b)}m${text}\x1b[39m`;
|
|
133
|
+
}
|
|
134
|
+
return text;
|
|
135
|
+
}
|
|
136
|
+
static rgb(r: number, g: number, b: number, text: string): string {
|
|
137
|
+
if (supportLevel === 0) return text;
|
|
138
|
+
if (supportLevel === 3) {
|
|
139
|
+
return `\x1b[38;2;${r};${g};${b}m${text}\x1b[39m`;
|
|
140
|
+
} else if (supportLevel === 2) {
|
|
141
|
+
return `\x1b[38;5;${this.rgbToAnsi256(r, g, b)}m${text}\x1b[39m`;
|
|
142
|
+
}
|
|
143
|
+
return text;
|
|
144
|
+
}
|
|
145
|
+
static hsl(h: number, s: number, l: number, text: string): string {
|
|
146
|
+
const [r, g, b] = this.hslToRgb(h, s, l);
|
|
147
|
+
return this.rgb(r, g, b, text);
|
|
148
|
+
}
|
|
149
|
+
static bgHex(hex: string, text: string): string {
|
|
150
|
+
if (supportLevel === 0) return text;
|
|
151
|
+
const [r, g, b] = this.hexToRgb(hex);
|
|
152
|
+
if (supportLevel === 3) {
|
|
153
|
+
return `\x1b[48;2;${r};${g};${b}m${text}\x1b[49m`;
|
|
154
|
+
} else if (supportLevel === 2) {
|
|
155
|
+
return `\x1b[48;5;${this.rgbToAnsi256(r, g, b)}m${text}\x1b[49m`;
|
|
156
|
+
}
|
|
157
|
+
return text;
|
|
158
|
+
}
|
|
159
|
+
static bgRgb(r: number, g: number, b: number, text: string): string {
|
|
160
|
+
if (supportLevel === 0) return text;
|
|
161
|
+
if (supportLevel === 3) {
|
|
162
|
+
return `\x1b[48;2;${r};${g};${b}m${text}\x1b[49m`;
|
|
163
|
+
} else if (supportLevel === 2) {
|
|
164
|
+
return `\x1b[48;5;${this.rgbToAnsi256(r, g, b)}m${text}\x1b[49m`;
|
|
165
|
+
}
|
|
166
|
+
return text;
|
|
167
|
+
}
|
|
168
|
+
static bold(text: string): string { return `\x1b[1m${text}\x1b[22m`; }
|
|
169
|
+
static dim(text: string): string { return `\x1b[2m${text}\x1b[22m`; }
|
|
170
|
+
static italic(text: string): string { return `\x1b[3m${text}\x1b[23m`; }
|
|
171
|
+
static underline(text: string): string { return `\x1b[4m${text}\x1b[24m`; }
|
|
172
|
+
static inverse(text: string): string { return `\x1b[7m${text}\x1b[27m`; }
|
|
173
|
+
static hidden(text: string): string { return `\x1b[8m${text}\x1b[28m`; }
|
|
174
|
+
static strikethrough(text: string): string { return `\x1b[9m${text}\x1b[29m`; }
|
|
175
|
+
static blink(text: string): string { return `\x1b[5m${text}\x1b[25m`; }
|
|
176
|
+
static style(text: string, options: StyleOptions): string {
|
|
177
|
+
let result = text;
|
|
178
|
+
if (options.bold) result = this.bold(result);
|
|
179
|
+
if (options.dim) result = this.dim(result);
|
|
180
|
+
if (options.italic) result = this.italic(result);
|
|
181
|
+
if (options.underline) result = this.underline(result);
|
|
182
|
+
if (options.inverse) result = this.inverse(result);
|
|
183
|
+
if (options.strikethrough) result = this.strikethrough(result);
|
|
184
|
+
if (options.blink) result = this.blink(result);
|
|
185
|
+
if (options.hidden) result = this.hidden(result);
|
|
186
|
+
return result;
|
|
187
|
+
}
|
|
188
|
+
static gradient(colors: string[], text: string, options: GradientOptions = {}): string {
|
|
189
|
+
if (supportLevel === 0) return text;
|
|
190
|
+
if (colors.length < 2) return this.hex(colors[0] || '#ffffff', text);
|
|
191
|
+
const interpolation = options.interpolation || 'linear';
|
|
192
|
+
const rgbColors = colors.map(c => this.hexToRgb(c));
|
|
193
|
+
const chars = [...text];
|
|
194
|
+
const steps = chars.length;
|
|
195
|
+
let output = '';
|
|
196
|
+
const interpolate = (start: Color, end: Color, t: number): Color => {
|
|
197
|
+
switch (interpolation) {
|
|
198
|
+
case 'ease': return this.interpolateEase(start, end, t);
|
|
199
|
+
case 'bezier': return this.interpolateBezier(start, end, t);
|
|
200
|
+
case 'smooth': return this.interpolateSmooth(start, end, t);
|
|
201
|
+
default: return this.interpolateLinear(start, end, t);
|
|
202
|
+
}
|
|
203
|
+
};
|
|
204
|
+
chars.forEach((char, i) => {
|
|
205
|
+
const t = steps <= 1 ? 0 : i / (steps - 1);
|
|
206
|
+
const segmentLength = 1 / (rgbColors.length - 1);
|
|
207
|
+
const segmentIndex = Math.min(Math.floor(t / segmentLength), rgbColors.length - 2);
|
|
208
|
+
const segmentT = (t - (segmentIndex * segmentLength)) / segmentLength;
|
|
209
|
+
const [r, g, b] = interpolate(rgbColors[segmentIndex], rgbColors[segmentIndex + 1], segmentT);
|
|
210
|
+
if (supportLevel === 3) {
|
|
211
|
+
output += `\x1b[38;2;${r};${g};${b}m${char}`;
|
|
212
|
+
} else if (supportLevel === 2) {
|
|
213
|
+
output += `\x1b[38;5;${this.rgbToAnsi256(r, g, b)}m${char}`;
|
|
214
|
+
} else {
|
|
215
|
+
output += char;
|
|
216
|
+
}
|
|
217
|
+
});
|
|
218
|
+
return output + '\x1b[39m';
|
|
219
|
+
}
|
|
220
|
+
static rainbowGradient(text: string): string {
|
|
221
|
+
return this.gradient(
|
|
222
|
+
['#FF0000', '#FF7F00', '#FFFF00', '#00FF00', '#0000FF', '#4B0082', '#9400D3'],
|
|
223
|
+
text,
|
|
224
|
+
{ interpolation: 'smooth' }
|
|
225
|
+
);
|
|
226
|
+
}
|
|
227
|
+
static sunsetGradient(text: string): string {
|
|
228
|
+
return this.gradient(['#FF512F', '#F09819', '#FFD89B'], text, { interpolation: 'ease' });
|
|
229
|
+
}
|
|
230
|
+
static oceanGradient(text: string): string {
|
|
231
|
+
return this.gradient(['#667eea', '#764ba2', '#f093fb'], text, { interpolation: 'bezier' });
|
|
232
|
+
}
|
|
233
|
+
static fireGradient(text: string): string {
|
|
234
|
+
return this.gradient(['#ff0000', '#ff4500', '#ffa500', '#ffff00'], text, { interpolation: 'smooth' });
|
|
235
|
+
}
|
|
236
|
+
static matrixGradient(text: string): string {
|
|
237
|
+
return this.gradient(['#00ff00', '#00cc00', '#009900'], text, { interpolation: 'linear' });
|
|
238
|
+
}
|
|
239
|
+
static lighten(hex: string, amount: number): string {
|
|
240
|
+
const [r, g, b] = this.hexToRgb(hex);
|
|
241
|
+
const hsl = this.rgbToHsl(r, g, b);
|
|
242
|
+
hsl.l = Math.min(100, hsl.l + amount);
|
|
243
|
+
const [nr, ng, nb] = this.hslToRgb(hsl.h, hsl.s, hsl.l);
|
|
244
|
+
return this.rgbToHex(nr, ng, nb);
|
|
245
|
+
}
|
|
246
|
+
static darken(hex: string, amount: number): string {
|
|
247
|
+
return this.lighten(hex, -amount);
|
|
248
|
+
}
|
|
249
|
+
static saturate(hex: string, amount: number): string {
|
|
250
|
+
const [r, g, b] = this.hexToRgb(hex);
|
|
251
|
+
const hsl = this.rgbToHsl(r, g, b);
|
|
252
|
+
hsl.s = Math.min(100, hsl.s + amount);
|
|
253
|
+
const [nr, ng, nb] = this.hslToRgb(hsl.h, hsl.s, hsl.l);
|
|
254
|
+
return this.rgbToHex(nr, ng, nb);
|
|
255
|
+
}
|
|
256
|
+
static desaturate(hex: string, amount: number): string {
|
|
257
|
+
return this.saturate(hex, -amount);
|
|
258
|
+
}
|
|
259
|
+
static rotate(hex: string, degrees: number): string {
|
|
260
|
+
const [r, g, b] = this.hexToRgb(hex);
|
|
261
|
+
const hsl = this.rgbToHsl(r, g, b);
|
|
262
|
+
hsl.h = (hsl.h + degrees) % 360;
|
|
263
|
+
if (hsl.h < 0) hsl.h += 360;
|
|
264
|
+
const [nr, ng, nb] = this.hslToRgb(hsl.h, hsl.s, hsl.l);
|
|
265
|
+
return this.rgbToHex(nr, ng, nb);
|
|
266
|
+
}
|
|
267
|
+
static mix(hex1: string, hex2: string, weight: number = 0.5): string {
|
|
268
|
+
const [r1, g1, b1] = this.hexToRgb(hex1);
|
|
269
|
+
const [r2, g2, b2] = this.hexToRgb(hex2);
|
|
270
|
+
const [r, g, b] = this.interpolateLinear([r1, g1, b1], [r2, g2, b2], weight);
|
|
271
|
+
return this.rgbToHex(r, g, b);
|
|
272
|
+
}
|
|
273
|
+
static analogous(hex: string, count: number = 3): string[] {
|
|
274
|
+
const palette: string[] = [hex];
|
|
275
|
+
const step = 30;
|
|
276
|
+
for (let i = 1; i < count; i++) {
|
|
277
|
+
palette.push(this.rotate(hex, step * i));
|
|
278
|
+
}
|
|
279
|
+
return palette;
|
|
280
|
+
}
|
|
281
|
+
static complementary(hex: string): string[] {
|
|
282
|
+
return [hex, this.rotate(hex, 180)];
|
|
283
|
+
}
|
|
284
|
+
static triadic(hex: string): string[] {
|
|
285
|
+
return [hex, this.rotate(hex, 120), this.rotate(hex, 240)];
|
|
286
|
+
}
|
|
287
|
+
static tetradic(hex: string): string[] {
|
|
288
|
+
return [hex, this.rotate(hex, 90), this.rotate(hex, 180), this.rotate(hex, 270)];
|
|
289
|
+
}
|
|
290
|
+
static monochromatic(hex: string, count: number = 5): string[] {
|
|
291
|
+
const palette: string[] = [];
|
|
292
|
+
const step = 100 / (count - 1);
|
|
293
|
+
for (let i = 0; i < count; i++) {
|
|
294
|
+
palette.push(this.lighten(hex, -50 + step * i));
|
|
295
|
+
}
|
|
296
|
+
return palette;
|
|
297
|
+
}
|
|
298
|
+
static strip(text: string): string {
|
|
299
|
+
return text.replace(/[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/g, '');
|
|
300
|
+
}
|
|
301
|
+
static getSupport(): number {
|
|
302
|
+
return supportLevel;
|
|
303
|
+
}
|
|
304
|
+
static getSupportName(): string {
|
|
305
|
+
const names = ['none', 'basic', '256', 'truecolor'];
|
|
306
|
+
return names[supportLevel];
|
|
307
|
+
}
|
|
308
|
+
static isSupported(): boolean {
|
|
309
|
+
return supportLevel > 0;
|
|
310
|
+
}
|
|
311
|
+
static textLength(text: string): number {
|
|
312
|
+
return this.strip(text).length;
|
|
313
|
+
}
|
|
314
|
+
static box(text: string, color: string = '#ffffff', padding: number = 1): string {
|
|
315
|
+
const lines = text.split('\n');
|
|
316
|
+
const maxLen = Math.max(...lines.map(l => this.textLength(l)));
|
|
317
|
+
const pad = ' '.repeat(padding);
|
|
318
|
+
const width = maxLen + padding * 2;
|
|
319
|
+
const top = this.hex(color, '┌' + '─'.repeat(width) + '┐');
|
|
320
|
+
const bottom = this.hex(color, '└' + '─'.repeat(width) + '┘');
|
|
321
|
+
const content = lines.map(line => {
|
|
322
|
+
const spaces = ' '.repeat(maxLen - this.textLength(line));
|
|
323
|
+
return this.hex(color, '│') + pad + line + spaces + pad + this.hex(color, '│');
|
|
324
|
+
}).join('\n');
|
|
325
|
+
return `${top}\n${content}\n${bottom}`;
|
|
326
|
+
}
|
|
327
|
+
static wave(text: string, colors: string[]): string {
|
|
328
|
+
if (supportLevel === 0) return text;
|
|
329
|
+
const chars = [...text];
|
|
330
|
+
const rgbColors = colors.map(c => this.hexToRgb(c));
|
|
331
|
+
let output = '';
|
|
332
|
+
chars.forEach((char, i) => {
|
|
333
|
+
const colorIndex = Math.floor((Math.sin(i * 0.5) + 1) * (rgbColors.length - 1) / 2);
|
|
334
|
+
const [r, g, b] = rgbColors[colorIndex];
|
|
335
|
+
if (supportLevel === 3) {
|
|
336
|
+
output += `\x1b[38;2;${r};${g};${b}m${char}`;
|
|
337
|
+
} else if (supportLevel === 2) {
|
|
338
|
+
output += `\x1b[38;5;${this.rgbToAnsi256(r, g, b)}m${char}`;
|
|
339
|
+
} else {
|
|
340
|
+
output += char;
|
|
341
|
+
}
|
|
342
|
+
});
|
|
343
|
+
|
|
344
|
+
return output + '\x1b[39m';
|
|
345
|
+
}
|
|
346
|
+
static pulse(text: string, color: string, frames: number = 10): string[] {
|
|
347
|
+
const result: string[] = [];
|
|
348
|
+
const [r, g, b] = this.hexToRgb(color);
|
|
349
|
+
for (let i = 0; i < frames; i++) {
|
|
350
|
+
const brightness = (Math.sin((i / frames) * Math.PI * 2) + 1) / 2;
|
|
351
|
+
const adjustedR = Math.round(r * brightness);
|
|
352
|
+
const adjustedG = Math.round(g * brightness);
|
|
353
|
+
const adjustedB = Math.round(b * brightness);
|
|
354
|
+
result.push(this.rgb(adjustedR, adjustedG, adjustedB, text));
|
|
355
|
+
}
|
|
356
|
+
return result;
|
|
357
|
+
}
|
|
358
|
+
private static clearCacheIfNeeded(): void {
|
|
359
|
+
if (this.cache.size > this.MAX_CACHE_SIZE) {
|
|
360
|
+
const entriesToDelete = this.cache.size - this.MAX_CACHE_SIZE / 2;
|
|
361
|
+
const iterator = this.cache.keys();
|
|
362
|
+
for (let i = 0; i < entriesToDelete; i++) {
|
|
363
|
+
const key = iterator.next().value;
|
|
364
|
+
if (key) this.cache.delete(key);
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
export default KaiChroma;
|
package/src/styles/palettes.ts
CHANGED
|
@@ -1,58 +1,210 @@
|
|
|
1
|
-
|
|
1
|
+
|
|
2
|
+
import { KaiChroma } from './KaiChroma';
|
|
3
|
+
|
|
4
|
+
export type ThemeName =
|
|
5
|
+
| 'zen'
|
|
6
|
+
| 'neon'
|
|
7
|
+
| 'pastel'
|
|
8
|
+
| 'hacker'
|
|
9
|
+
| 'sunset'
|
|
10
|
+
| 'ocean'
|
|
11
|
+
| 'cyberpunk'
|
|
12
|
+
| 'dracula'
|
|
13
|
+
| 'monokai'
|
|
14
|
+
| 'vaporwave'
|
|
15
|
+
| 'midnight'
|
|
16
|
+
| 'forest'
|
|
17
|
+
| 'volcano'
|
|
18
|
+
| 'gold';
|
|
19
|
+
|
|
20
|
+
export interface Theme {
|
|
21
|
+
success: string[]; // Gradient colors
|
|
22
|
+
error: string[];
|
|
23
|
+
warning: string[];
|
|
24
|
+
info: string[];
|
|
25
|
+
debug: string[];
|
|
26
|
+
text: string; // Base text color
|
|
27
|
+
dim: string; // Dimmed color
|
|
28
|
+
accent: string; // Special accent
|
|
29
|
+
bg?: string; // Background recommendation
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export const palettes: Record<ThemeName, Theme> = {
|
|
33
|
+
// 1. Zen (Minimalist, calming)
|
|
2
34
|
zen: {
|
|
3
35
|
success: ['#00b09b', '#96c93d'],
|
|
4
36
|
error: ['#ff416c', '#ff4b2b'],
|
|
5
37
|
warning: ['#f7971e', '#ffd200'],
|
|
6
38
|
info: ['#2193b0', '#6dd5ed'],
|
|
7
39
|
debug: ['#8e2de2', '#4a00e0'],
|
|
8
|
-
|
|
9
|
-
dim: '#888888'
|
|
40
|
+
text: '#ffffff',
|
|
41
|
+
dim: '#888888',
|
|
42
|
+
accent: '#00b09b'
|
|
10
43
|
},
|
|
44
|
+
// 2. Neon (Bright, cyber)
|
|
11
45
|
neon: {
|
|
12
|
-
success: ['#
|
|
13
|
-
error: ['#
|
|
14
|
-
warning: ['#
|
|
15
|
-
info: ['#
|
|
16
|
-
debug: ['#
|
|
17
|
-
|
|
18
|
-
dim: '#
|
|
46
|
+
success: ['#39ff14', '#00ffef'],
|
|
47
|
+
error: ['#ff0055', '#ff0099'],
|
|
48
|
+
warning: ['#ffff00', '#ffae00'],
|
|
49
|
+
info: ['#00ffff', '#0099ff'],
|
|
50
|
+
debug: ['#b300ff', '#8800ff'],
|
|
51
|
+
text: '#f0f0f0',
|
|
52
|
+
dim: '#666666',
|
|
53
|
+
accent: '#39ff14'
|
|
19
54
|
},
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
55
|
+
// 3. Cyberpunk 2077
|
|
56
|
+
cyberpunk: {
|
|
57
|
+
success: ['#00ff9f', '#00b8ff'], // Cyan to Blue
|
|
58
|
+
error: ['#ff003c', '#ff3cac'], // Cyber Red
|
|
59
|
+
warning: ['#fcee0a', '#ffae00'], // Cyber Yellow
|
|
60
|
+
info: ['#0abdc6', '#ea00d9'], // Blue to Pink
|
|
61
|
+
debug: ['#711c91', '#ea00d9'], // Purple
|
|
62
|
+
text: '#fcee0a', // Yellow text
|
|
63
|
+
dim: '#5e4e69',
|
|
64
|
+
accent: '#0abdc6'
|
|
28
65
|
},
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
66
|
+
// 4. Dracula (Dark mode favorite)
|
|
67
|
+
dracula: {
|
|
68
|
+
success: ['#50fa7b', '#8be9fd'],
|
|
69
|
+
error: ['#ff5555', '#ffb86c'],
|
|
70
|
+
warning: ['#ffb86c', '#f1fa8c'],
|
|
71
|
+
info: ['#bd93f9', '#ff79c6'],
|
|
72
|
+
debug: ['#6272a4', '#8be9fd'],
|
|
73
|
+
text: '#f8f8f2',
|
|
74
|
+
dim: '#6272a4',
|
|
75
|
+
accent: '#bd93f9'
|
|
76
|
+
},
|
|
77
|
+
// 5. Monokai
|
|
78
|
+
monokai: {
|
|
79
|
+
success: ['#a6e22e', '#a6e22e'],
|
|
80
|
+
error: ['#f92672', '#f92672'],
|
|
81
|
+
warning: ['#fd971f', '#e6db74'],
|
|
82
|
+
info: ['#66d9ef', '#ae81ff'],
|
|
83
|
+
debug: ['#ae81ff', '#fd971f'],
|
|
84
|
+
text: '#f8f8f2',
|
|
85
|
+
dim: '#75715e',
|
|
86
|
+
accent: '#a6e22e'
|
|
37
87
|
},
|
|
88
|
+
// 6. Vaporwave
|
|
89
|
+
vaporwave: {
|
|
90
|
+
success: ['#00f0ff', '#ff00aa'],
|
|
91
|
+
error: ['#ff2a00', '#ff0066'],
|
|
92
|
+
warning: ['#ffcc00', '#ff9900'],
|
|
93
|
+
info: ['#ff77ff', '#9933ff'],
|
|
94
|
+
debug: ['#9900ff', '#5500aa'],
|
|
95
|
+
text: '#ff99ff',
|
|
96
|
+
dim: '#554477',
|
|
97
|
+
accent: '#00f0ff'
|
|
98
|
+
},
|
|
99
|
+
// 7. Midnight (Deep blues)
|
|
100
|
+
midnight: {
|
|
101
|
+
success: ['#34e89e', '#0f3443'],
|
|
102
|
+
error: ['#cb2d3e', '#ef473a'],
|
|
103
|
+
warning: ['#ffc371', '#ff5f6d'],
|
|
104
|
+
info: ['#56ccf2', '#2f80ed'],
|
|
105
|
+
debug: ['#642b73', '#c6426e'],
|
|
106
|
+
text: '#d1d1d1',
|
|
107
|
+
dim: '#4b5563',
|
|
108
|
+
accent: '#56ccf2'
|
|
109
|
+
},
|
|
110
|
+
// 8. Sunset (Warm)
|
|
38
111
|
sunset: {
|
|
39
112
|
success: ['#11998e', '#38ef7d'],
|
|
40
|
-
error: ['#
|
|
41
|
-
warning: ['#
|
|
42
|
-
info: ['#
|
|
43
|
-
debug: ['#
|
|
44
|
-
|
|
45
|
-
dim: '#
|
|
113
|
+
error: ['#ee0979', '#ff6a00'],
|
|
114
|
+
warning: ['#ff9966', '#ff5e62'],
|
|
115
|
+
info: ['#00c6ff', '#0072ff'],
|
|
116
|
+
debug: ['#8360c3', '#2ebf91'],
|
|
117
|
+
text: '#ffedd5',
|
|
118
|
+
dim: '#7c2d12',
|
|
119
|
+
accent: '#ff9966'
|
|
46
120
|
},
|
|
121
|
+
// 9. Ocean (Blues/Greens)
|
|
47
122
|
ocean: {
|
|
48
|
-
success: ['#
|
|
49
|
-
error: ['#
|
|
123
|
+
success: ['#4cb8c4', '#3cd3ad'],
|
|
124
|
+
error: ['#ff416c', '#ff4b2b'],
|
|
50
125
|
warning: ['#f09819', '#edde5d'],
|
|
51
|
-
info: ['#
|
|
126
|
+
info: ['#2b5876', '#4e4376'],
|
|
52
127
|
debug: ['#1c92d2', '#f2fcfe'],
|
|
53
|
-
|
|
54
|
-
dim: '#
|
|
128
|
+
text: '#e0f2fe',
|
|
129
|
+
dim: '#1e3a8a',
|
|
130
|
+
accent: '#4cb8c4'
|
|
131
|
+
},
|
|
132
|
+
// 10. Pastel (Soft)
|
|
133
|
+
pastel: {
|
|
134
|
+
success: ['#B2F7EF', '#7BDFF2'],
|
|
135
|
+
error: ['#FFB7B2', '#FF9AA2'],
|
|
136
|
+
warning: ['#FFE29A', '#FFDAC1'],
|
|
137
|
+
info: ['#A0E7E5', '#B4F8C8'],
|
|
138
|
+
debug: ['#FBE7C6', '#C3B1E1'],
|
|
139
|
+
text: '#ffffff',
|
|
140
|
+
dim: '#a0a0a0',
|
|
141
|
+
accent: '#B2F7EF'
|
|
142
|
+
},
|
|
143
|
+
// 11. Hacker
|
|
144
|
+
hacker: {
|
|
145
|
+
success: ['#00ff00', '#003300'],
|
|
146
|
+
error: ['#ff0000', '#330000'],
|
|
147
|
+
warning: ['#ffff00', '#333300'],
|
|
148
|
+
info: ['#0000ff', '#000033'],
|
|
149
|
+
debug: ['#ff00ff', '#330033'],
|
|
150
|
+
text: '#00ff00',
|
|
151
|
+
dim: '#004400',
|
|
152
|
+
accent: '#00ff00'
|
|
153
|
+
},
|
|
154
|
+
// 12. Volcano
|
|
155
|
+
volcano: {
|
|
156
|
+
success: ['#FF8008', '#FFC837'],
|
|
157
|
+
error: ['#FF0000', '#950000'],
|
|
158
|
+
warning: ['#FF4B1F', '#1FDDFF'],
|
|
159
|
+
info: ['#ED4264', '#FFEDBC'],
|
|
160
|
+
debug: ['#2C3E50', '#FD746C'],
|
|
161
|
+
text: '#FFD700',
|
|
162
|
+
dim: '#500000',
|
|
163
|
+
accent: '#FF4B1F'
|
|
164
|
+
},
|
|
165
|
+
// 13. Forest
|
|
166
|
+
forest: {
|
|
167
|
+
success: ['#134E5E', '#71B280'],
|
|
168
|
+
error: ['#603813', '#b29f94'],
|
|
169
|
+
warning: ['#eacda3', '#d6ae7b'],
|
|
170
|
+
info: ['#5D4157', '#A8CABA'],
|
|
171
|
+
debug: ['#4DA0B0', '#D39D38'],
|
|
172
|
+
text: '#D4FFD6',
|
|
173
|
+
dim: '#2b3d2b',
|
|
174
|
+
accent: '#71B280'
|
|
175
|
+
},
|
|
176
|
+
// 14. Gold (Luxury)
|
|
177
|
+
gold: {
|
|
178
|
+
success: ['#F2994A', '#F2C94C'],
|
|
179
|
+
error: ['#8e2de2', '#4a00e0'],
|
|
180
|
+
warning: ['#CAC531', '#F3F9A7'],
|
|
181
|
+
info: ['#7F7FD5', '#86A8E7'],
|
|
182
|
+
debug: ['#E0EAFC', '#CFDEF3'],
|
|
183
|
+
text: '#FFD700',
|
|
184
|
+
dim: '#706015',
|
|
185
|
+
accent: '#F2C94C'
|
|
55
186
|
}
|
|
56
187
|
};
|
|
57
188
|
|
|
58
|
-
export
|
|
189
|
+
export class PaletteEngine {
|
|
190
|
+
private currentTheme: ThemeName = 'zen';
|
|
191
|
+
private theme: Theme = palettes.zen;
|
|
192
|
+
|
|
193
|
+
setTheme(name: ThemeName) {
|
|
194
|
+
if (palettes[name]) {
|
|
195
|
+
this.currentTheme = name;
|
|
196
|
+
this.theme = palettes[name];
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
get colors() {
|
|
201
|
+
return this.theme;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
apply(text: string, colors: string[]): string {
|
|
205
|
+
if (colors.length === 1) return KaiChroma.hex(colors[0], text);
|
|
206
|
+
return KaiChroma.gradient(colors, text);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
export const paint = new PaletteEngine();
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
|
|
1
|
+
|
|
2
2
|
import { LogLevel, Transport } from '../types';
|
|
3
|
-
import { paint } from '../styles/
|
|
3
|
+
import { paint } from '../styles/palettes';
|
|
4
4
|
import { palettes, ThemeName } from '../styles/palettes';
|
|
5
5
|
|
|
6
6
|
export class ConsoleTransport implements Transport {
|
package/src/utils/json.ts
CHANGED
|
@@ -1,23 +1,31 @@
|
|
|
1
|
-
|
|
1
|
+
|
|
2
|
+
import { KaiChroma } from '../styles/KaiChroma';
|
|
2
3
|
|
|
3
4
|
export class KaiJson {
|
|
4
5
|
static print(obj: any, theme: any) {
|
|
5
6
|
const jsonStr = JSON.stringify(obj, null, 2);
|
|
7
|
+
|
|
8
|
+
// Manual colorization for full control using KaiChroma
|
|
6
9
|
const colored = jsonStr
|
|
10
|
+
// Strings (keys)
|
|
7
11
|
.replace(/"([^"]+)":/g, (match, key) => {
|
|
8
|
-
return
|
|
12
|
+
return KaiChroma.hex(theme.info[0], `"${key}"`) + ':';
|
|
9
13
|
})
|
|
14
|
+
// String values
|
|
10
15
|
.replace(/: "([^"]*)"/g, (match, val) => {
|
|
11
|
-
return ': ' +
|
|
16
|
+
return ': ' + KaiChroma.hex(theme.success[1], `"${val}"`);
|
|
12
17
|
})
|
|
18
|
+
// Numbers
|
|
13
19
|
.replace(/: (\d+\.?\d*)/g, (match, num) => {
|
|
14
|
-
return ': ' +
|
|
20
|
+
return ': ' + KaiChroma.hex(theme.warning[0], num);
|
|
15
21
|
})
|
|
22
|
+
// Booleans
|
|
16
23
|
.replace(/: (true|false)/g, (match, bool) => {
|
|
17
|
-
return ': ' +
|
|
24
|
+
return ': ' + KaiChroma.hex(theme.error[0], bool);
|
|
18
25
|
})
|
|
26
|
+
// Null
|
|
19
27
|
.replace(/: (null)/g, (match, n) => {
|
|
20
|
-
return ': ' +
|
|
28
|
+
return ': ' + KaiChroma.hex(theme.dim, n);
|
|
21
29
|
});
|
|
22
30
|
|
|
23
31
|
console.log(colored);
|