@skilly-hand/skilly-hand 0.3.0 → 0.5.0
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 +33 -0
- package/README.md +10 -0
- package/package.json +4 -1
- package/packages/cli/src/bin.js +383 -137
- package/packages/core/src/index.js +42 -8
- package/packages/core/src/terminal.js +76 -69
- package/packages/core/src/ui/brand.js +31 -0
- package/packages/core/src/ui/index.js +3 -0
- package/packages/core/src/ui/layout.js +289 -0
- package/packages/core/src/ui/theme.js +120 -0
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
// Color level detection and palette creation.
|
|
2
|
+
// Level 0: no color Level 1: basic ANSI Level 2: 256-color Level 3: truecolor
|
|
3
|
+
|
|
4
|
+
function normalizeBooleanEnv(value) {
|
|
5
|
+
if (value === undefined || value === null) return null;
|
|
6
|
+
const normalized = String(value).trim().toLowerCase();
|
|
7
|
+
if (normalized === "" || normalized === "0" || normalized === "false" || normalized === "no") return false;
|
|
8
|
+
return true;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function detectColorLevel({ env = process.env, stream = process.stdout } = {}) {
|
|
12
|
+
if (normalizeBooleanEnv(env.NO_COLOR)) return 0;
|
|
13
|
+
|
|
14
|
+
const force = env.FORCE_COLOR;
|
|
15
|
+
if (force !== undefined) {
|
|
16
|
+
const level = parseInt(force, 10);
|
|
17
|
+
if (!isNaN(level)) return Math.min(Math.max(level, 0), 3);
|
|
18
|
+
if (normalizeBooleanEnv(force) === true) return 1;
|
|
19
|
+
if (normalizeBooleanEnv(force) === false) return 0;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
if (!stream?.isTTY) return 0;
|
|
23
|
+
if (env.CI) return 0;
|
|
24
|
+
|
|
25
|
+
const colorterm = (env.COLORTERM || "").toLowerCase();
|
|
26
|
+
if (colorterm === "truecolor" || colorterm === "24bit") return 3;
|
|
27
|
+
|
|
28
|
+
const term = env.TERM || "";
|
|
29
|
+
const termProgram = env.TERM_PROGRAM || "";
|
|
30
|
+
if (term.includes("256color") || termProgram === "iTerm.app" || termProgram === "vscode") return 2;
|
|
31
|
+
|
|
32
|
+
return 1;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// ANSI wrap helpers
|
|
36
|
+
function wrapBasic(code) {
|
|
37
|
+
return (value) => `\x1b[${code}m${String(value)}\x1b[0m`;
|
|
38
|
+
}
|
|
39
|
+
function wrap256(code) {
|
|
40
|
+
return (value) => `\x1b[38;5;${code}m${String(value)}\x1b[0m`;
|
|
41
|
+
}
|
|
42
|
+
function wrapRgb(r, g, b) {
|
|
43
|
+
return (value) => `\x1b[38;2;${r};${g};${b}m${String(value)}\x1b[0m`;
|
|
44
|
+
}
|
|
45
|
+
function wrapBg256(code) {
|
|
46
|
+
return (value) => `\x1b[48;5;${code}m${String(value)}\x1b[0m`;
|
|
47
|
+
}
|
|
48
|
+
function wrapBgRgb(r, g, b) {
|
|
49
|
+
return (value) => `\x1b[48;2;${r};${g};${b}m${String(value)}\x1b[0m`;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const PALETTE = {
|
|
53
|
+
primary: { l3: [0, 184, 169], l2: 38, l1: 36 },
|
|
54
|
+
accent: { l3: [77, 208, 225], l2: 51, l1: 36 },
|
|
55
|
+
muted: { l3: [0, 150, 136], l2: 30, l1: 2 },
|
|
56
|
+
success: { l3: [80, 200, 120], l2: 40, l1: 32 },
|
|
57
|
+
warn: { l3: [255, 185, 0], l2: 214, l1: 33 },
|
|
58
|
+
error: { l3: [240, 80, 80], l2: 196, l1: 31 },
|
|
59
|
+
info: { l3: [60, 130, 220], l2: 33, l1: 34 },
|
|
60
|
+
magenta: { l3: [200, 100, 200], l2: 141, l1: 35 },
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
const PALETTE_BG = {
|
|
64
|
+
primary: { l3: [0, 184, 169], l2: 38 },
|
|
65
|
+
success: { l3: [40, 140, 80], l2: 28 },
|
|
66
|
+
warn: { l3: [160, 100, 0], l2: 136 },
|
|
67
|
+
error: { l3: [160, 40, 40], l2: 124 },
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
const identity = (value) => String(value);
|
|
71
|
+
|
|
72
|
+
export function createTheme(level) {
|
|
73
|
+
if (level === 0) {
|
|
74
|
+
const noop = identity;
|
|
75
|
+
return {
|
|
76
|
+
level,
|
|
77
|
+
primary: noop, accent: noop, muted: noop,
|
|
78
|
+
success: noop, warn: noop, error: noop, info: noop, magenta: noop,
|
|
79
|
+
bold: noop, dim: noop, reset: noop, italic: noop,
|
|
80
|
+
bgPrimary: noop, bgSuccess: noop, bgWarn: noop, bgError: noop,
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function makeColor(slot) {
|
|
85
|
+
const p = PALETTE[slot];
|
|
86
|
+
if (level === 3) return wrapRgb(...p.l3);
|
|
87
|
+
if (level === 2) return wrap256(p.l2);
|
|
88
|
+
// level 1: muted is dim, rest are basic codes
|
|
89
|
+
if (slot === "muted") return wrapBasic(2);
|
|
90
|
+
return wrapBasic(p.l1);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function makeBg(slot) {
|
|
94
|
+
const p = PALETTE_BG[slot];
|
|
95
|
+
if (!p) return identity;
|
|
96
|
+
if (level === 3) return wrapBgRgb(...p.l3);
|
|
97
|
+
if (level === 2) return wrapBg256(p.l2);
|
|
98
|
+
return identity;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
return {
|
|
102
|
+
level,
|
|
103
|
+
primary: makeColor("primary"),
|
|
104
|
+
accent: makeColor("accent"),
|
|
105
|
+
muted: makeColor("muted"),
|
|
106
|
+
success: makeColor("success"),
|
|
107
|
+
warn: makeColor("warn"),
|
|
108
|
+
error: makeColor("error"),
|
|
109
|
+
info: makeColor("info"),
|
|
110
|
+
magenta: makeColor("magenta"),
|
|
111
|
+
bold: wrapBasic(1),
|
|
112
|
+
dim: wrapBasic(2),
|
|
113
|
+
italic: wrapBasic(3),
|
|
114
|
+
reset: wrapBasic(0),
|
|
115
|
+
bgPrimary: makeBg("primary"),
|
|
116
|
+
bgSuccess: makeBg("success"),
|
|
117
|
+
bgWarn: makeBg("warn"),
|
|
118
|
+
bgError: makeBg("error"),
|
|
119
|
+
};
|
|
120
|
+
}
|