@kljj04/cli-kit 1.0.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/README.md +110 -0
- package/package.json +20 -0
- package/src/box.js +0 -0
- package/src/color.js +78 -0
- package/src/index.js +12 -0
- package/src/print.js +7 -0
- package/src/progress.js +13 -0
- package/src/spinner.js +24 -0
- package/src/table.js +27 -0
package/README.md
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
# @kljj04/cli-kit
|
|
2
|
+
|
|
3
|
+
All-in-one terminal styling library for Node.js.
|
|
4
|
+
RGB truecolor, boxes, tables, spinners, and progress bars — all in one package.
|
|
5
|
+
|
|
6
|
+
## Install
|
|
7
|
+
|
|
8
|
+
```bash
|
|
9
|
+
npm install @kljj04/cli-kit
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
## Usage
|
|
13
|
+
|
|
14
|
+
All styling follows the same chain pattern:
|
|
15
|
+
|
|
16
|
+
```js
|
|
17
|
+
kit.color(R, G, B).style(...styles).context(value)
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
- **`color(r, g, b)`** — RGB truecolor (0–255 each)
|
|
21
|
+
- **`style(...args)`** — one or more text styles, plus an optional output type
|
|
22
|
+
- **`context(value)`** — the content to render
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## Text Styles
|
|
27
|
+
|
|
28
|
+
Pass any of these as arguments to `.style()`:
|
|
29
|
+
|
|
30
|
+
| Style | Description |
|
|
31
|
+
|---|---|
|
|
32
|
+
| `bold` | Bold text |
|
|
33
|
+
| `dim` | Dimmed text |
|
|
34
|
+
| `italic` | Italic text |
|
|
35
|
+
| `underline` | Underlined text |
|
|
36
|
+
| `inverse` | Inverted colors |
|
|
37
|
+
| `strikethrough` | Strikethrough text |
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
## Output Types
|
|
42
|
+
|
|
43
|
+
Pass one of these as an argument to `.style()` to change the output format.
|
|
44
|
+
Default is `print` if omitted.
|
|
45
|
+
|
|
46
|
+
### `print` (default)
|
|
47
|
+
|
|
48
|
+
```js
|
|
49
|
+
kit.color(255, 100, 50).style('bold').context('Hello!')
|
|
50
|
+
kit.color(255, 100, 50).style('bold', 'print').context('Hello!')
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### `box`
|
|
54
|
+
|
|
55
|
+
Wraps the text in a Unicode box. Supports multiline strings.
|
|
56
|
+
|
|
57
|
+
```js
|
|
58
|
+
kit.color(100, 200, 255).style('box').context('Hello!')
|
|
59
|
+
kit.color(100, 200, 255).style('bold', 'box').context('Line one\nLine two')
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
```
|
|
63
|
+
┌────────┐
|
|
64
|
+
│ Hello! │
|
|
65
|
+
└────────┘
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### `spinner`
|
|
69
|
+
|
|
70
|
+
Returns a spinner object. Call `.stop(text)` to stop it.
|
|
71
|
+
|
|
72
|
+
```js
|
|
73
|
+
const s = kit.color(0, 255, 200).style('spinner').context('Loading...')
|
|
74
|
+
setTimeout(() => s.stop('Done!'), 2000)
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### `progress`
|
|
78
|
+
|
|
79
|
+
Pass a number from 0 to 100.
|
|
80
|
+
|
|
81
|
+
```js
|
|
82
|
+
kit.color(255, 200, 0).style('progress').context(72)
|
|
83
|
+
// [██████████████████████░░░░░░░░] 72%
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### `table`
|
|
87
|
+
|
|
88
|
+
Pass an array of objects. Keys become headers.
|
|
89
|
+
|
|
90
|
+
```js
|
|
91
|
+
kit.color(200, 150, 255).style('table').context([
|
|
92
|
+
{ name: 'Alice', age: 20, role: 'dev' },
|
|
93
|
+
{ name: 'Bob', age: 25, role: 'designer' },
|
|
94
|
+
])
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
```
|
|
98
|
+
┌───────┬─────┬──────────┐
|
|
99
|
+
│ name │ age │ role │
|
|
100
|
+
┼───────┼─────┼──────────┼
|
|
101
|
+
│ Alice │ 20 │ dev │
|
|
102
|
+
│ Bob │ 25 │ designer │
|
|
103
|
+
└───────┴─────┴──────────┘
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
---
|
|
107
|
+
|
|
108
|
+
## License
|
|
109
|
+
|
|
110
|
+
MIT
|
package/package.json
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@kljj04/cli-kit",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "All-in-one terminal styling library. Colors, boxes, tables, spinners, and progress bars.",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"test": "node test.js"
|
|
8
|
+
},
|
|
9
|
+
"keywords": [
|
|
10
|
+
"cli", "terminal", "color", "truecolor", "rgb",
|
|
11
|
+
"box", "table", "spinner", "progress", "styling"
|
|
12
|
+
],
|
|
13
|
+
"author": "kljj04",
|
|
14
|
+
"license": "MIT",
|
|
15
|
+
"files": [
|
|
16
|
+
"index.js",
|
|
17
|
+
"src/",
|
|
18
|
+
"README.md"
|
|
19
|
+
]
|
|
20
|
+
}
|
package/src/box.js
ADDED
|
File without changes
|
package/src/color.js
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
const STYLES = {
|
|
2
|
+
bold: '\x1b[1m',
|
|
3
|
+
dim: '\x1b[2m',
|
|
4
|
+
italic: '\x1b[3m',
|
|
5
|
+
underline: '\x1b[4m',
|
|
6
|
+
inverse: '\x1b[7m',
|
|
7
|
+
strikethrough: '\x1b[9m',
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
const RESET = '\x1b[0m';
|
|
11
|
+
|
|
12
|
+
function rgb(r, g, b) {
|
|
13
|
+
return `\x1b[38;2;${r};${g};${b}m`;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function bgRgb(r, g, b) {
|
|
17
|
+
return `\x1b[48;2;${r};${g};${b}m`;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
class KitBuilder {
|
|
21
|
+
constructor() {
|
|
22
|
+
this._r = 255;
|
|
23
|
+
this._g = 255;
|
|
24
|
+
this._b = 255;
|
|
25
|
+
this._styles = [];
|
|
26
|
+
this._outputType = 'print';
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
color(r, g, b) {
|
|
30
|
+
this._r = r;
|
|
31
|
+
this._g = g;
|
|
32
|
+
this._b = b;
|
|
33
|
+
return this;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
style(...args) {
|
|
37
|
+
const outputTypes = ['print', 'box', 'spinner', 'progress', 'table'];
|
|
38
|
+
args.forEach(arg => {
|
|
39
|
+
if (outputTypes.includes(arg)) {
|
|
40
|
+
this._outputType = arg;
|
|
41
|
+
} else if (STYLES[arg]) {
|
|
42
|
+
this._styles.push(arg);
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
return this;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
_buildPrefix() {
|
|
49
|
+
const colorCode = rgb(this._r, this._g, this._b);
|
|
50
|
+
const styleCodes = this._styles.map(s => STYLES[s]).join('');
|
|
51
|
+
return `${colorCode}${styleCodes}`;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
context(value) {
|
|
55
|
+
const prefix = this._buildPrefix();
|
|
56
|
+
switch (this._outputType) {
|
|
57
|
+
case 'print':
|
|
58
|
+
require('./print').print(prefix, value);
|
|
59
|
+
break;
|
|
60
|
+
case 'box':
|
|
61
|
+
require('./box').box(prefix, value);
|
|
62
|
+
break;
|
|
63
|
+
case 'spinner':
|
|
64
|
+
return require('./spinner').spinner(prefix, value);
|
|
65
|
+
case 'progress':
|
|
66
|
+
require('./progress').progress(prefix, value);
|
|
67
|
+
break;
|
|
68
|
+
case 'table':
|
|
69
|
+
require('./table').table(prefix, value);
|
|
70
|
+
break;
|
|
71
|
+
}
|
|
72
|
+
// reset for next use
|
|
73
|
+
this._styles = [];
|
|
74
|
+
this._outputType = 'print';
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
module.exports = { KitBuilder, rgb, bgRgb, STYLES, RESET };
|
package/src/index.js
ADDED
package/src/print.js
ADDED
package/src/progress.js
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
const { RESET } = require('./color');
|
|
2
|
+
|
|
3
|
+
function progress(prefix, value) {
|
|
4
|
+
const pct = Math.min(100, Math.max(0, Number(value)));
|
|
5
|
+
const width = 30;
|
|
6
|
+
const filled = Math.round((pct / 100) * width);
|
|
7
|
+
const empty = width - filled;
|
|
8
|
+
|
|
9
|
+
const bar = '█'.repeat(filled) + '░'.repeat(empty);
|
|
10
|
+
console.log(`${prefix}[${bar}] ${pct}%${RESET}`);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
module.exports = { progress };
|
package/src/spinner.js
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
const { RESET } = require('./color');
|
|
2
|
+
|
|
3
|
+
const FRAMES = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
|
|
4
|
+
|
|
5
|
+
function spinner(prefix, text) {
|
|
6
|
+
let i = 0;
|
|
7
|
+
process.stdout.write('\x1b[?25l'); // 커서 숨기기
|
|
8
|
+
|
|
9
|
+
const interval = setInterval(() => {
|
|
10
|
+
process.stdout.write(`\r${prefix}${FRAMES[i % FRAMES.length]} ${text}${RESET}`);
|
|
11
|
+
i++;
|
|
12
|
+
}, 80);
|
|
13
|
+
|
|
14
|
+
return {
|
|
15
|
+
stop(finalText = '') {
|
|
16
|
+
clearInterval(interval);
|
|
17
|
+
process.stdout.write(`\r${' '.repeat(text.length + 4)}\r`);
|
|
18
|
+
if (finalText) console.log(`${prefix}✔ ${finalText}${RESET}`);
|
|
19
|
+
process.stdout.write('\x1b[?25h'); // 커서 복원
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
module.exports = { spinner };
|
package/src/table.js
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
const { RESET } = require('./color');
|
|
2
|
+
|
|
3
|
+
function table(prefix, data) {
|
|
4
|
+
if (!Array.isArray(data) || data.length === 0) return;
|
|
5
|
+
|
|
6
|
+
const headers = Object.keys(data[0]);
|
|
7
|
+
const colWidths = headers.map(h =>
|
|
8
|
+
Math.max(h.length, ...data.map(row => String(row[h] ?? '').length))
|
|
9
|
+
);
|
|
10
|
+
|
|
11
|
+
const hr = '┼' + colWidths.map(w => '─'.repeat(w + 2)).join('┼') + '┼';
|
|
12
|
+
const topBorder = '┌' + colWidths.map(w => '─'.repeat(w + 2)).join('┬') + '┐';
|
|
13
|
+
const bottomBorder = '└' + colWidths.map(w => '─'.repeat(w + 2)).join('┴') + '┘';
|
|
14
|
+
|
|
15
|
+
const row = (cells) =>
|
|
16
|
+
'│' + cells.map((c, i) => ` ${String(c).padEnd(colWidths[i])} `).join('│') + '│';
|
|
17
|
+
|
|
18
|
+
console.log(`${prefix}${topBorder}${RESET}`);
|
|
19
|
+
console.log(`${prefix}${row(headers)}${RESET}`);
|
|
20
|
+
console.log(`${prefix}${hr}${RESET}`);
|
|
21
|
+
data.forEach(r => {
|
|
22
|
+
console.log(`${prefix}${row(headers.map(h => r[h] ?? ''))}${RESET}`);
|
|
23
|
+
});
|
|
24
|
+
console.log(`${prefix}${bottomBorder}${RESET}`);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
module.exports = { table };
|