ansimax 1.0.0 → 1.1.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 +274 -0
- package/LICENSE +201 -21
- package/README.es.md +752 -628
- package/README.md +493 -369
- package/dist/index.d.mts +1256 -336
- package/dist/index.d.ts +1256 -336
- package/dist/index.js +4417 -683
- package/dist/index.mjs +4319 -682
- package/examples/01-cli-installer.ts +96 -0
- package/examples/01-quick-smoke.ts +121 -0
- package/examples/02-colors-gradients.ts +108 -0
- package/examples/02-live-dashboard.ts +152 -0
- package/examples/03-ascii-banners.ts +81 -0
- package/examples/03-pixel-art-game.ts +170 -0
- package/examples/04-interactive-deploy.ts +163 -0
- package/examples/04-trees.ts +117 -0
- package/examples/05-components.ts +96 -0
- package/examples/05-tree-visualizations.ts +183 -0
- package/examples/06-everything-together.ts +466 -0
- package/examples/06-pixel-art.ts +116 -0
- package/examples/07-animations.ts +68 -0
- package/examples/08-loaders.ts +98 -0
- package/examples/09-themes.ts +90 -0
- package/examples/10-everything.ts +133 -0
- package/examples/all-in-one.cjs +210 -0
- package/examples/all-in-one.mjs +203 -0
- package/examples/animations.ts +172 -0
- package/examples/demo.js +213 -0
- package/examples/demo.ts +212 -0
- package/examples/loaders.ts +254 -0
- package/examples/showcase.ts +174 -0
- package/examples/trees-basic.ts +99 -0
- package/examples/tsconfig.json +18 -0
- package/examples/tsconfig.vscode.json +25 -0
- package/package.json +19 -7
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
// ─────────────────────────────────────────────
|
|
2
|
+
// EXAMPLE 3 — Pixel art game loop
|
|
3
|
+
//
|
|
4
|
+
// Demonstrates:
|
|
5
|
+
// - Canvas with dirty-region rendering for FPS
|
|
6
|
+
// - Sprite drawing with alpha blending
|
|
7
|
+
// - Gradient backgrounds with Bayer dithering
|
|
8
|
+
// - Frame-rate locked game loop (drift-corrected)
|
|
9
|
+
// - Braille mode for high-resolution detail
|
|
10
|
+
//
|
|
11
|
+
// A bouncing rocket on a sunset gradient with a star field.
|
|
12
|
+
//
|
|
13
|
+
// Run:
|
|
14
|
+
// npx ts-node examples/03-pixel-art-game.ts
|
|
15
|
+
// ─────────────────────────────────────────────
|
|
16
|
+
|
|
17
|
+
import {
|
|
18
|
+
createCanvas,
|
|
19
|
+
images,
|
|
20
|
+
themes,
|
|
21
|
+
cursor,
|
|
22
|
+
screen,
|
|
23
|
+
write,
|
|
24
|
+
sleep,
|
|
25
|
+
termSize,
|
|
26
|
+
type RGBA,
|
|
27
|
+
} from '../dist/index.js';
|
|
28
|
+
|
|
29
|
+
const WIDTH = 60;
|
|
30
|
+
const HEIGHT = 30;
|
|
31
|
+
|
|
32
|
+
// ── Build static background once ───────────────
|
|
33
|
+
const buildBackground = (): ReturnType<typeof createCanvas> => {
|
|
34
|
+
const canvas = createCanvas(WIDTH, HEIGHT);
|
|
35
|
+
|
|
36
|
+
// Sunset gradient with Bayer dithering for smooth bands
|
|
37
|
+
const gradStr = images.gradientRect({
|
|
38
|
+
width: WIDTH,
|
|
39
|
+
height: HEIGHT,
|
|
40
|
+
colors: ['#1a1a2e', '#16213e', '#fd7272', '#f9ca24'],
|
|
41
|
+
style: 'vertical',
|
|
42
|
+
dither: 'bayer',
|
|
43
|
+
});
|
|
44
|
+
// gradientRect returns rendered text; instead we build pixels manually
|
|
45
|
+
// so we can composite sprites on top.
|
|
46
|
+
for (let y = 0; y < HEIGHT; y++) {
|
|
47
|
+
for (let x = 0; x < WIDTH; x++) {
|
|
48
|
+
// Simple vertical sunset
|
|
49
|
+
const t = y / (HEIGHT - 1);
|
|
50
|
+
const r = Math.round(0x1a + (0xf9 - 0x1a) * t);
|
|
51
|
+
const g = Math.round(0x1a + (0xca - 0x1a) * t);
|
|
52
|
+
const b = Math.round(0x2e + (0x24 - 0x2e) * t);
|
|
53
|
+
canvas.set(x, y, { r, g, b });
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Star field — random white dots in upper half
|
|
58
|
+
for (let i = 0; i < 30; i++) {
|
|
59
|
+
const x = Math.floor(Math.random() * WIDTH);
|
|
60
|
+
const y = Math.floor(Math.random() * (HEIGHT / 2));
|
|
61
|
+
const brightness = 150 + Math.floor(Math.random() * 100);
|
|
62
|
+
canvas.set(x, y, { r: brightness, g: brightness, b: brightness });
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return canvas;
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
// ── Rocket sprite (5×5) with alpha edges for soft blending ──
|
|
69
|
+
const ROCKET = [
|
|
70
|
+
[null, null, { r: 255, g: 255, b: 255 }, null, null ],
|
|
71
|
+
[null, { r: 255, g: 100, b: 100 }, { r: 255, g: 200, b: 200 }, { r: 255, g: 100, b: 100 }, null ],
|
|
72
|
+
[{ r: 200, g: 50, b: 50, a: 0.7 } as RGBA, { r: 255, g: 100, b: 100 }, { r: 255, g: 150, b: 150 }, { r: 255, g: 100, b: 100 }, { r: 200, g: 50, b: 50, a: 0.7 } as RGBA],
|
|
73
|
+
[null, { r: 255, g: 200, b: 50 }, { r: 255, g: 240, b: 100 }, { r: 255, g: 200, b: 50 }, null ],
|
|
74
|
+
[null, null, { r: 255, g: 150, b: 50, a: 0.6 } as RGBA, null, null ],
|
|
75
|
+
];
|
|
76
|
+
|
|
77
|
+
// ── Main loop ──────────────────────────────────
|
|
78
|
+
const main = async (): Promise<void> => {
|
|
79
|
+
const { rows } = termSize();
|
|
80
|
+
if (rows < HEIGHT + 5) {
|
|
81
|
+
console.log(themes.error(`Terminal too small. Needs at least ${HEIGHT + 5} rows.`));
|
|
82
|
+
process.exit(1);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
write(screen.clear());
|
|
86
|
+
write(cursor.hide());
|
|
87
|
+
write(cursor.to(1, 1));
|
|
88
|
+
console.log(themes.banner('ROCKET', { font: 'small' }));
|
|
89
|
+
|
|
90
|
+
const bg = buildBackground();
|
|
91
|
+
|
|
92
|
+
let rocketX = WIDTH / 2;
|
|
93
|
+
let rocketY = HEIGHT - 8;
|
|
94
|
+
let vx = 0.4;
|
|
95
|
+
let vy = -0.25;
|
|
96
|
+
|
|
97
|
+
const ctrl = new AbortController();
|
|
98
|
+
process.on('SIGINT', () => {
|
|
99
|
+
ctrl.abort();
|
|
100
|
+
write(cursor.show());
|
|
101
|
+
write(cursor.to(1, HEIGHT + 8));
|
|
102
|
+
console.log(themes.muted('\nGame stopped.'));
|
|
103
|
+
process.exit(0);
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
// Frame loop — drift-corrected via wall clock
|
|
107
|
+
const FRAME_MS = 60; // ~16 FPS
|
|
108
|
+
const startTime = Date.now();
|
|
109
|
+
let frame = 0;
|
|
110
|
+
|
|
111
|
+
const FPS_HIST: number[] = [];
|
|
112
|
+
let lastFrameTime = Date.now();
|
|
113
|
+
|
|
114
|
+
while (!ctrl.signal.aborted) {
|
|
115
|
+
// Clone background to a frame canvas (so sprites don't mutate the bg)
|
|
116
|
+
const frameCanvas = createCanvas(WIDTH, HEIGHT);
|
|
117
|
+
for (let y = 0; y < HEIGHT; y++) {
|
|
118
|
+
for (let x = 0; x < WIDTH; x++) {
|
|
119
|
+
frameCanvas.set(x, y, bg.get(x, y));
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// Update rocket physics
|
|
124
|
+
rocketX += vx;
|
|
125
|
+
rocketY += vy;
|
|
126
|
+
if (rocketX <= 2 || rocketX >= WIDTH - 5) vx = -vx;
|
|
127
|
+
if (rocketY <= 2 || rocketY >= HEIGHT - 5) vy = -vy;
|
|
128
|
+
|
|
129
|
+
// Draw the rocket with alpha blending
|
|
130
|
+
frameCanvas.drawSprite(Math.round(rocketX), Math.round(rocketY), ROCKET);
|
|
131
|
+
|
|
132
|
+
// FPS calc
|
|
133
|
+
const now = Date.now();
|
|
134
|
+
const delta = now - lastFrameTime;
|
|
135
|
+
lastFrameTime = now;
|
|
136
|
+
if (delta > 0) {
|
|
137
|
+
FPS_HIST.push(1000 / delta);
|
|
138
|
+
if (FPS_HIST.length > 30) FPS_HIST.shift();
|
|
139
|
+
}
|
|
140
|
+
const avgFps = FPS_HIST.reduce((s, n) => s + n, 0) / Math.max(1, FPS_HIST.length);
|
|
141
|
+
|
|
142
|
+
// Render
|
|
143
|
+
write(cursor.to(1, 7));
|
|
144
|
+
write(frameCanvas.render());
|
|
145
|
+
write(cursor.to(1, HEIGHT + 8));
|
|
146
|
+
write(themes.muted(
|
|
147
|
+
`Frame ${frame.toString().padStart(4)} · ` +
|
|
148
|
+
`${avgFps.toFixed(1)} fps · ` +
|
|
149
|
+
`Ctrl+C to exit`,
|
|
150
|
+
));
|
|
151
|
+
|
|
152
|
+
// Drift-correct sleep
|
|
153
|
+
frame++;
|
|
154
|
+
const targetTime = startTime + frame * FRAME_MS;
|
|
155
|
+
const waitMs = Math.max(0, targetTime - Date.now());
|
|
156
|
+
try {
|
|
157
|
+
await sleep(waitMs, { signal: ctrl.signal });
|
|
158
|
+
} catch {
|
|
159
|
+
break;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
write(cursor.show());
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
main().catch((err) => {
|
|
167
|
+
write(cursor.show());
|
|
168
|
+
console.error(themes.error('✗ ' + (err as Error).message));
|
|
169
|
+
process.exit(1);
|
|
170
|
+
});
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
// ─────────────────────────────────────────────
|
|
2
|
+
// EXAMPLE 4 — Interactive prompt with menu + multi-loader
|
|
3
|
+
//
|
|
4
|
+
// Demonstrates:
|
|
5
|
+
// - components.menu (interactive arrow-key navigation)
|
|
6
|
+
// - MENU_CANCELLED handling
|
|
7
|
+
// - loader.multi() — concurrent named operations
|
|
8
|
+
// - configure() side effects + onConfigChange
|
|
9
|
+
// - Theme switching at runtime
|
|
10
|
+
// - createTheme() for isolated theme instances
|
|
11
|
+
//
|
|
12
|
+
// Walks the user through choosing a theme, then runs parallel
|
|
13
|
+
// "deployment" operations under a multi-loader.
|
|
14
|
+
//
|
|
15
|
+
// Run:
|
|
16
|
+
// npx ts-node examples/04-interactive-deploy.ts
|
|
17
|
+
// ─────────────────────────────────────────────
|
|
18
|
+
|
|
19
|
+
import {
|
|
20
|
+
components,
|
|
21
|
+
loader,
|
|
22
|
+
themes,
|
|
23
|
+
createTheme,
|
|
24
|
+
configure,
|
|
25
|
+
onConfigChange,
|
|
26
|
+
sleep,
|
|
27
|
+
MENU_CANCELLED,
|
|
28
|
+
} from '../dist/index.js';
|
|
29
|
+
|
|
30
|
+
const main = async (): Promise<void> => {
|
|
31
|
+
// ── Subscribe to config changes globally ──
|
|
32
|
+
const offChange = onConfigChange((c) => {
|
|
33
|
+
// Each time the theme changes, the global `themes` follows automatically
|
|
34
|
+
// thanks to configure() side effects. We just log it.
|
|
35
|
+
console.log(themes.muted(` [config] theme=${c.theme} colorMode=${c.colorMode}`));
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
// ── Step 1: Banner ─────────────────────────────
|
|
39
|
+
console.log();
|
|
40
|
+
console.log(themes.banner('DEPLOY', { font: 'small' }));
|
|
41
|
+
console.log(components.section(themes.primary('Configure deployment'), { width: 60 }));
|
|
42
|
+
console.log();
|
|
43
|
+
|
|
44
|
+
// ── Step 2: Pick a theme via menu ─────────────
|
|
45
|
+
console.log(themes.text('Select a theme for the output:'));
|
|
46
|
+
console.log();
|
|
47
|
+
|
|
48
|
+
const themeChoices = ['dracula', 'nord', 'monokai', 'matrix', 'cyberpunk'];
|
|
49
|
+
const choice = await components.menu(themeChoices, {
|
|
50
|
+
title: ' Available themes',
|
|
51
|
+
pointer: '▸',
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
if (choice === MENU_CANCELLED) {
|
|
55
|
+
console.log();
|
|
56
|
+
console.log(themes.warning('⚠ Cancelled by user'));
|
|
57
|
+
offChange();
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const themeName = themeChoices[choice as number]!;
|
|
62
|
+
configure({ theme: themeName });
|
|
63
|
+
console.log();
|
|
64
|
+
console.log(themes.accent(`✓ Theme set to ${themeName}`));
|
|
65
|
+
console.log();
|
|
66
|
+
|
|
67
|
+
// ── Step 3: Pick deployment regions (multi-select) ──
|
|
68
|
+
const regionChoices = ['us-east-1', 'us-west-2', 'eu-west-1', 'ap-south-1', 'sa-east-1'];
|
|
69
|
+
console.log(themes.text('Select target regions (Space to toggle, Enter to confirm):'));
|
|
70
|
+
console.log();
|
|
71
|
+
|
|
72
|
+
const regions = await components.menu(regionChoices, {
|
|
73
|
+
title: ' Regions',
|
|
74
|
+
pointer: '▸',
|
|
75
|
+
multiSelect: true,
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
if (regions === MENU_CANCELLED) {
|
|
79
|
+
console.log();
|
|
80
|
+
console.log(themes.warning('⚠ Cancelled by user'));
|
|
81
|
+
offChange();
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const selectedRegions = (regions as number[]).map((i) => regionChoices[i]!);
|
|
86
|
+
if (selectedRegions.length === 0) {
|
|
87
|
+
console.log(themes.warning('⚠ No regions selected — aborting'));
|
|
88
|
+
offChange();
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
console.log();
|
|
93
|
+
console.log(components.box(
|
|
94
|
+
themes.primary('Plan:') + '\n' +
|
|
95
|
+
selectedRegions.map((r) => ` • ${r}`).join('\n'),
|
|
96
|
+
{ borderStyle: 'rounded', padding: 1 },
|
|
97
|
+
));
|
|
98
|
+
console.log();
|
|
99
|
+
|
|
100
|
+
// ── Step 4: Multi-loader for parallel deployments ──
|
|
101
|
+
console.log(themes.text('Starting parallel deployments...'));
|
|
102
|
+
console.log();
|
|
103
|
+
|
|
104
|
+
const m = loader.multi();
|
|
105
|
+
const items = selectedRegions.map((region) => {
|
|
106
|
+
const item = m.add(`Deploying to ${region}`, { color: '#48dbfb' });
|
|
107
|
+
return { region, item };
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
// Run each region in parallel
|
|
111
|
+
await Promise.all(items.map(async ({ region, item }) => {
|
|
112
|
+
// Stage 1: build
|
|
113
|
+
item.update(`[${region}] Building image...`);
|
|
114
|
+
await sleep(400 + Math.random() * 600);
|
|
115
|
+
|
|
116
|
+
// Stage 2: upload
|
|
117
|
+
item.update(`[${region}] Uploading...`);
|
|
118
|
+
await sleep(600 + Math.random() * 800);
|
|
119
|
+
|
|
120
|
+
// Stage 3: switch
|
|
121
|
+
item.update(`[${region}] Switching traffic...`);
|
|
122
|
+
await sleep(300 + Math.random() * 400);
|
|
123
|
+
|
|
124
|
+
// Random failure chance for one region
|
|
125
|
+
if (Math.random() < 0.15) {
|
|
126
|
+
item.fail(`[${region}] Failed: health check timeout`);
|
|
127
|
+
} else {
|
|
128
|
+
item.succeed(`[${region}] Live`);
|
|
129
|
+
}
|
|
130
|
+
}));
|
|
131
|
+
|
|
132
|
+
// Wait for the multi-loader to settle (final renders)
|
|
133
|
+
await sleep(150);
|
|
134
|
+
|
|
135
|
+
// ── Step 5: Multi-tenant theme demo ───────────
|
|
136
|
+
// Create an isolated theme instance for the summary
|
|
137
|
+
// (does not affect global state)
|
|
138
|
+
const summary = createTheme('matrix');
|
|
139
|
+
|
|
140
|
+
console.log();
|
|
141
|
+
console.log(components.section(summary.primary('Deployment summary'), { width: 60 }));
|
|
142
|
+
console.log();
|
|
143
|
+
|
|
144
|
+
console.log(components.timeline(
|
|
145
|
+
selectedRegions.map((r) => ({
|
|
146
|
+
label: `Deployed to ${r}`,
|
|
147
|
+
time: new Date().toLocaleTimeString(),
|
|
148
|
+
done: true,
|
|
149
|
+
})),
|
|
150
|
+
));
|
|
151
|
+
|
|
152
|
+
console.log();
|
|
153
|
+
console.log(summary.muted('Global theme remains: ' + themes.current().name));
|
|
154
|
+
console.log(summary.muted('Isolated summary theme: ' + summary.current().name));
|
|
155
|
+
console.log();
|
|
156
|
+
|
|
157
|
+
offChange();
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
main().catch((err) => {
|
|
161
|
+
console.error(themes.error('✗ ' + (err as Error).message));
|
|
162
|
+
process.exit(1);
|
|
163
|
+
});
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 04 — Trees
|
|
3
|
+
*
|
|
4
|
+
* Run: npx tsx examples/04-trees.ts
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import {
|
|
8
|
+
tree,
|
|
9
|
+
renderTree,
|
|
10
|
+
walkTree,
|
|
11
|
+
findInTree,
|
|
12
|
+
countNodes,
|
|
13
|
+
mapTree,
|
|
14
|
+
filterTree,
|
|
15
|
+
measureTree,
|
|
16
|
+
color,
|
|
17
|
+
type TreeData,
|
|
18
|
+
} from '../src/index.js';
|
|
19
|
+
|
|
20
|
+
console.log();
|
|
21
|
+
console.log(color.bold('━━━ Builder API ━━━'));
|
|
22
|
+
console.log();
|
|
23
|
+
|
|
24
|
+
const project = tree({ label: 'my-app', icon: '📦', color: color.bold });
|
|
25
|
+
const src = project.add({ label: 'src', icon: '📁' });
|
|
26
|
+
src.addLeaf({ label: 'index.ts', icon: '📄' });
|
|
27
|
+
src.addLeaf({ label: 'app.ts', icon: '📄' });
|
|
28
|
+
const utils = src.add({ label: 'utils', icon: '📁' });
|
|
29
|
+
utils.addLeaf({ label: 'helpers.ts', icon: '📄' });
|
|
30
|
+
utils.addLeaf({ label: 'logger.ts', icon: '📄' });
|
|
31
|
+
project.addLeaf({ label: 'package.json', icon: '📦' });
|
|
32
|
+
project.addLeaf({ label: 'README.md', icon: '📝' });
|
|
33
|
+
|
|
34
|
+
console.log(project.render());
|
|
35
|
+
console.log();
|
|
36
|
+
|
|
37
|
+
console.log(color.bold('━━━ Tree styles ━━━'));
|
|
38
|
+
console.log();
|
|
39
|
+
|
|
40
|
+
const styles = ['rounded', 'classic', 'thick', 'double', 'ascii', 'heavy'] as const;
|
|
41
|
+
for (const style of styles) {
|
|
42
|
+
console.log(color.dim(`// style: ${style}`));
|
|
43
|
+
console.log(project.render({ style }));
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
console.log(color.bold('━━━ Palette colors ━━━'));
|
|
47
|
+
console.log();
|
|
48
|
+
|
|
49
|
+
console.log(project.render({
|
|
50
|
+
style: 'rounded',
|
|
51
|
+
palette: [color.cyan, color.green, color.magenta, color.yellow],
|
|
52
|
+
guideColor: color.dim,
|
|
53
|
+
}));
|
|
54
|
+
console.log();
|
|
55
|
+
|
|
56
|
+
console.log(color.bold('━━━ Plain-data API ━━━'));
|
|
57
|
+
console.log();
|
|
58
|
+
|
|
59
|
+
const tree2: TreeData = {
|
|
60
|
+
label: 'dependencies',
|
|
61
|
+
icon: '📦',
|
|
62
|
+
children: [
|
|
63
|
+
{
|
|
64
|
+
label: 'production',
|
|
65
|
+
icon: '🔒',
|
|
66
|
+
children: [
|
|
67
|
+
{ label: 'react@18.2.0', icon: '⚛️' },
|
|
68
|
+
{ label: 'tailwind@3.4.1', icon: '🎨' },
|
|
69
|
+
],
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
label: 'development',
|
|
73
|
+
icon: '🛠️',
|
|
74
|
+
children: [
|
|
75
|
+
{ label: 'typescript@5.4.0', icon: '🔷' },
|
|
76
|
+
{ label: 'jest@29.7.0', icon: '🧪' },
|
|
77
|
+
{ label: 'eslint@8.57.0', icon: '✅' },
|
|
78
|
+
],
|
|
79
|
+
},
|
|
80
|
+
],
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
console.log(renderTree(tree2));
|
|
84
|
+
console.log();
|
|
85
|
+
|
|
86
|
+
console.log(color.bold('━━━ maxDepth truncation ━━━'));
|
|
87
|
+
console.log();
|
|
88
|
+
console.log(color.dim('// maxDepth: 1'));
|
|
89
|
+
console.log(renderTree(tree2, { maxDepth: 1 }));
|
|
90
|
+
console.log();
|
|
91
|
+
|
|
92
|
+
console.log(color.bold('━━━ Algorithms ━━━'));
|
|
93
|
+
console.log();
|
|
94
|
+
console.log(' countNodes:', countNodes(tree2));
|
|
95
|
+
|
|
96
|
+
const found = findInTree(tree2, (n) => n.label.includes('react'));
|
|
97
|
+
console.log(' findInTree (react):', found?.label);
|
|
98
|
+
|
|
99
|
+
console.log(' walkTree paths:');
|
|
100
|
+
walkTree(tree2, (node, depth) => {
|
|
101
|
+
if (depth > 0) console.log(' ' + ' '.repeat(depth) + '→ ' + node.label);
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
const upper = mapTree(tree2, (node) => ({ ...node, label: node.label.toUpperCase() }));
|
|
105
|
+
console.log('\n mapTree (uppercase):');
|
|
106
|
+
console.log(renderTree(upper));
|
|
107
|
+
|
|
108
|
+
const onlyDev = filterTree(tree2, (n) => n.label !== 'production', { prune: true });
|
|
109
|
+
console.log(' filterTree (no production):');
|
|
110
|
+
if (onlyDev) console.log(renderTree(onlyDev));
|
|
111
|
+
|
|
112
|
+
const dim = measureTree(tree2);
|
|
113
|
+
console.log(` measureTree: ${dim.width} × ${dim.height}`);
|
|
114
|
+
console.log();
|
|
115
|
+
|
|
116
|
+
console.log(color.bold(color.green('✓ Trees test complete')));
|
|
117
|
+
console.log();
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 05 — Components (NO interactive menu — tested separately)
|
|
3
|
+
*
|
|
4
|
+
* Run: npx tsx examples/05-components.ts
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { components, box, color } from '../src/index.js';
|
|
8
|
+
|
|
9
|
+
console.log();
|
|
10
|
+
console.log(color.bold('━━━ Tables ━━━'));
|
|
11
|
+
console.log();
|
|
12
|
+
|
|
13
|
+
console.log(components.table([
|
|
14
|
+
['Module', 'Status', 'Coverage', 'Tests'],
|
|
15
|
+
['colors', color.green('● ready'), '100%', '180'],
|
|
16
|
+
['animations', color.green('● ready'), '99%', '245'],
|
|
17
|
+
['loaders', color.green('● ready'), '99%', '210'],
|
|
18
|
+
['frames', color.green('● ready'), '99%', '125'],
|
|
19
|
+
['components', color.green('● ready'), '100%', '198'],
|
|
20
|
+
['themes', color.green('● ready'), '100%', '94'],
|
|
21
|
+
['trees', color.green('● ready'), '100%', '87'],
|
|
22
|
+
], { borderStyle: 'rounded' }));
|
|
23
|
+
console.log();
|
|
24
|
+
|
|
25
|
+
console.log(color.dim('// Table with double border'));
|
|
26
|
+
console.log(components.table([
|
|
27
|
+
['Name', 'Age', 'City'],
|
|
28
|
+
['Ana', '25', 'Madrid'],
|
|
29
|
+
['Carlos', '30', 'Lima'],
|
|
30
|
+
], { borderStyle: 'double' }));
|
|
31
|
+
console.log();
|
|
32
|
+
|
|
33
|
+
console.log(color.bold('━━━ Badges ━━━'));
|
|
34
|
+
console.log();
|
|
35
|
+
console.log(' ',
|
|
36
|
+
components.badge('VERSION', 'v1.1.0'),
|
|
37
|
+
components.badge('BUILD', 'passing'),
|
|
38
|
+
components.badge('LICENSE', 'Apache 2.0'),
|
|
39
|
+
components.badge('NPM', 'ansimax'),
|
|
40
|
+
);
|
|
41
|
+
console.log();
|
|
42
|
+
|
|
43
|
+
console.log(color.bold('━━━ Status ━━━'));
|
|
44
|
+
console.log();
|
|
45
|
+
console.log(components.status('Build started', { type: 'info' }));
|
|
46
|
+
console.log(components.status('Linting passed', { type: 'success' }));
|
|
47
|
+
console.log(components.status('5 deprecation warnings', { type: 'warning' }));
|
|
48
|
+
console.log(components.status('Build failed', { type: 'error' }));
|
|
49
|
+
console.log();
|
|
50
|
+
|
|
51
|
+
console.log(color.bold('━━━ Section ━━━'));
|
|
52
|
+
console.log();
|
|
53
|
+
console.log(components.section('Installation Steps', { width: 60 }));
|
|
54
|
+
console.log();
|
|
55
|
+
console.log(components.section('Configuration', { width: 60 }));
|
|
56
|
+
console.log();
|
|
57
|
+
|
|
58
|
+
console.log(color.bold('━━━ Columns ━━━'));
|
|
59
|
+
console.log();
|
|
60
|
+
console.log(components.columns([
|
|
61
|
+
'Lorem ipsum dolor sit amet',
|
|
62
|
+
'Consectetur adipiscing elit',
|
|
63
|
+
'Sed do eiusmod tempor',
|
|
64
|
+
], { cols: 3, gap: 2, width: 60 }));
|
|
65
|
+
console.log();
|
|
66
|
+
|
|
67
|
+
console.log(color.bold('━━━ Timeline ━━━'));
|
|
68
|
+
console.log();
|
|
69
|
+
console.log(components.timeline([
|
|
70
|
+
{ label: 'Project initialized', done: true, time: '10:00' },
|
|
71
|
+
{ label: 'Dependencies installed', done: true, time: '10:05' },
|
|
72
|
+
{ label: 'Build pipeline configured', done: true, time: '10:15' },
|
|
73
|
+
{ label: 'Tests running', done: false, time: '10:32' },
|
|
74
|
+
{ label: 'Deploy to npm', done: false },
|
|
75
|
+
]));
|
|
76
|
+
console.log();
|
|
77
|
+
|
|
78
|
+
console.log(color.bold('━━━ Static progress bars ━━━'));
|
|
79
|
+
console.log();
|
|
80
|
+
for (const pct of [10, 25, 50, 75, 90, 100]) {
|
|
81
|
+
console.log(' ', `${pct.toString().padStart(3)}%`, components.progressBar(pct, { width: 30 }));
|
|
82
|
+
}
|
|
83
|
+
console.log();
|
|
84
|
+
|
|
85
|
+
console.log(color.bold('━━━ box utility ━━━'));
|
|
86
|
+
console.log();
|
|
87
|
+
console.log(box('Simple box utility', { padding: 1 }));
|
|
88
|
+
console.log();
|
|
89
|
+
console.log(box('Padded + bordered\nwith multiple lines', {
|
|
90
|
+
padding: 2,
|
|
91
|
+
borderStyle: 'rounded',
|
|
92
|
+
}));
|
|
93
|
+
console.log();
|
|
94
|
+
|
|
95
|
+
console.log(color.bold(color.green('✓ Components test complete')));
|
|
96
|
+
console.log();
|