create-buntui 0.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/package.json +22 -0
- package/src/index.ts +10 -0
- package/src/scaffold.ts +25 -0
- package/src/setup-ui.ts +145 -0
- package/templates/basic/index.ts +30 -0
- package/templates/basic/package.json +10 -0
package/package.json
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "create-buntui",
|
|
3
|
+
"version": "0.0.0",
|
|
4
|
+
"repository": {
|
|
5
|
+
"type": "git",
|
|
6
|
+
"url": "git+https://github.com/AlphaFoxz/buntui.git",
|
|
7
|
+
"directory": "packages/create-buntui"
|
|
8
|
+
},
|
|
9
|
+
"bin": {
|
|
10
|
+
"create-buntui": "./src/index.ts"
|
|
11
|
+
},
|
|
12
|
+
"files": [
|
|
13
|
+
"src/",
|
|
14
|
+
"templates/"
|
|
15
|
+
],
|
|
16
|
+
"scripts": {
|
|
17
|
+
"build": "echo 'No build step required'"
|
|
18
|
+
},
|
|
19
|
+
"dependencies": {
|
|
20
|
+
"@buntui/core": "^0.0.0"
|
|
21
|
+
}
|
|
22
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import process from 'node:process';
|
|
2
|
+
import {createApp} from '@buntui/core';
|
|
3
|
+
import {setupUI} from './setup-ui';
|
|
4
|
+
|
|
5
|
+
const args = process.argv.slice(2);
|
|
6
|
+
const defaultName = args[0];
|
|
7
|
+
|
|
8
|
+
const app = createApp({logLevel: 'warning', clearLog: true});
|
|
9
|
+
setupUI(app, defaultName);
|
|
10
|
+
app.start();
|
package/src/scaffold.ts
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import {execSync} from 'node:child_process';
|
|
4
|
+
|
|
5
|
+
const templateDir = path.resolve(import.meta.dir, '..', 'templates', 'basic');
|
|
6
|
+
|
|
7
|
+
export function scaffold(projectName: string, targetDir: string): void {
|
|
8
|
+
const outputDir = path.resolve(targetDir, projectName);
|
|
9
|
+
|
|
10
|
+
if (fs.existsSync(outputDir)) {
|
|
11
|
+
throw new Error(`Directory already exists: ${outputDir}`);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
fs.mkdirSync(outputDir, {recursive: true});
|
|
15
|
+
|
|
16
|
+
const files = fs.readdirSync(templateDir);
|
|
17
|
+
for (const file of files) {
|
|
18
|
+
const src = path.join(templateDir, file);
|
|
19
|
+
const content = fs.readFileSync(src, 'utf-8');
|
|
20
|
+
const rendered = content.replaceAll('{{name}}', projectName);
|
|
21
|
+
fs.writeFileSync(path.join(outputDir, file), rendered, 'utf-8');
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
execSync('bun install', {cwd: outputDir, stdio: 'inherit'});
|
|
25
|
+
}
|
package/src/setup-ui.ts
ADDED
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
import process from 'node:process';
|
|
3
|
+
import {
|
|
4
|
+
createBox,
|
|
5
|
+
createTextWidget,
|
|
6
|
+
createInputWidget,
|
|
7
|
+
createButtonWidget,
|
|
8
|
+
type createApp,
|
|
9
|
+
} from '@buntui/core';
|
|
10
|
+
import {scaffold} from './scaffold';
|
|
11
|
+
|
|
12
|
+
type TuiApp = ReturnType<typeof createApp>;
|
|
13
|
+
|
|
14
|
+
const ACCENT = 'rgb(122, 162, 247)';
|
|
15
|
+
const BG = 'rgb(26, 27, 38)';
|
|
16
|
+
const SURFACE = 'rgb(36, 40, 59)';
|
|
17
|
+
const TEXT = 'rgb(192, 202, 229)';
|
|
18
|
+
const TEXT_DIM = 'rgb(86, 95, 137)';
|
|
19
|
+
|
|
20
|
+
export function setupUI(app: TuiApp, defaultName?: string): void {
|
|
21
|
+
const scene = app.createScene({
|
|
22
|
+
setup() {
|
|
23
|
+
/* No-op */
|
|
24
|
+
},
|
|
25
|
+
}, {bgHexRgb: BG, visible: true});
|
|
26
|
+
|
|
27
|
+
// Title bar
|
|
28
|
+
scene.mount(createTextWidget({
|
|
29
|
+
x: 0,
|
|
30
|
+
y: 0,
|
|
31
|
+
width: '100%',
|
|
32
|
+
height: 1,
|
|
33
|
+
value: ' Create Buntui App',
|
|
34
|
+
colorFg: ACCENT,
|
|
35
|
+
colorBg: BG,
|
|
36
|
+
}));
|
|
37
|
+
|
|
38
|
+
// Container box
|
|
39
|
+
const box = createBox({
|
|
40
|
+
x: '25%',
|
|
41
|
+
y: '20%',
|
|
42
|
+
width: '50%',
|
|
43
|
+
height: 12,
|
|
44
|
+
colorBg: SURFACE,
|
|
45
|
+
borderColor: ACCENT,
|
|
46
|
+
borderStyle: 'solid',
|
|
47
|
+
});
|
|
48
|
+
const input = createInputWidget({
|
|
49
|
+
x: '0%',
|
|
50
|
+
y: '22%',
|
|
51
|
+
value: defaultName ?? 'my-buntui-app',
|
|
52
|
+
colorFg: TEXT,
|
|
53
|
+
colorBg: BG,
|
|
54
|
+
borderColorUnfocused: TEXT_DIM,
|
|
55
|
+
borderColorFocused: ACCENT,
|
|
56
|
+
borderStyle: 'solid',
|
|
57
|
+
placeholder: 'Type something...',
|
|
58
|
+
label: 'Project name',
|
|
59
|
+
});
|
|
60
|
+
box.addChild(input);
|
|
61
|
+
scene.mount(box);
|
|
62
|
+
|
|
63
|
+
// Create button
|
|
64
|
+
const createBtn = createButtonWidget({
|
|
65
|
+
x: '35%',
|
|
66
|
+
y: '50%',
|
|
67
|
+
width: 12,
|
|
68
|
+
height: 3,
|
|
69
|
+
value: ' Create ',
|
|
70
|
+
colorFgNormal: BG,
|
|
71
|
+
colorBgNormal: ACCENT,
|
|
72
|
+
borderColorNormal: ACCENT,
|
|
73
|
+
borderStyleNormal: 'solid',
|
|
74
|
+
colorFgFocused: BG,
|
|
75
|
+
colorBgFocused: 'rgb(157, 122, 247)',
|
|
76
|
+
borderColorFocused: 'rgb(157, 122, 247)',
|
|
77
|
+
borderStyleFocused: 'solid',
|
|
78
|
+
colorFgPressed: BG,
|
|
79
|
+
colorBgPressed: 'rgb(91, 110, 181)',
|
|
80
|
+
borderColorPressed: 'rgb(91, 110, 181)',
|
|
81
|
+
borderStylePressed: 'solid',
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
// Cancel button
|
|
85
|
+
const cancelBtn = createButtonWidget({
|
|
86
|
+
x: '50%',
|
|
87
|
+
y: '50%',
|
|
88
|
+
width: 12,
|
|
89
|
+
height: 3,
|
|
90
|
+
value: ' Cancel ',
|
|
91
|
+
colorFgNormal: TEXT_DIM,
|
|
92
|
+
colorBgNormal: SURFACE,
|
|
93
|
+
borderColorNormal: TEXT_DIM,
|
|
94
|
+
borderStyleNormal: 'solid',
|
|
95
|
+
colorFgFocused: TEXT,
|
|
96
|
+
colorBgFocused: 'rgb(59, 66, 91)',
|
|
97
|
+
borderColorFocused: TEXT,
|
|
98
|
+
borderStyleFocused: 'solid',
|
|
99
|
+
colorFgPressed: TEXT_DIM,
|
|
100
|
+
colorBgPressed: 'rgb(42, 48, 69)',
|
|
101
|
+
borderColorPressed: 'rgb(42, 48, 69)',
|
|
102
|
+
borderStylePressed: 'solid',
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
// Status text
|
|
106
|
+
const status = createTextWidget({
|
|
107
|
+
x: '27%',
|
|
108
|
+
y: '60%',
|
|
109
|
+
width: '46%',
|
|
110
|
+
height: 1,
|
|
111
|
+
value: '',
|
|
112
|
+
colorFg: TEXT_DIM,
|
|
113
|
+
colorBg: BG,
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
createBtn.on('click', () => {
|
|
117
|
+
const name = input.value.trim();
|
|
118
|
+
if (!name) {
|
|
119
|
+
status.updateValue(' Please enter a project name');
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
status.updateValue(' Creating project...');
|
|
124
|
+
try {
|
|
125
|
+
scaffold(name, process.cwd());
|
|
126
|
+
status.updateValue(` Project "${name}" created successfully!`);
|
|
127
|
+
setTimeout(() => {
|
|
128
|
+
app.dispose();
|
|
129
|
+
process.exit(0);
|
|
130
|
+
}, 1500);
|
|
131
|
+
} catch (error) {
|
|
132
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
133
|
+
status.updateValue(` ${message}`);
|
|
134
|
+
}
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
cancelBtn.on('click', () => {
|
|
138
|
+
app.dispose();
|
|
139
|
+
process.exit(0);
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
scene.mount(createBtn);
|
|
143
|
+
scene.mount(cancelBtn);
|
|
144
|
+
scene.mount(status);
|
|
145
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import {createApp, createTextWidget, createBox} from 'buntui';
|
|
2
|
+
|
|
3
|
+
const app = createApp();
|
|
4
|
+
const scene = app.createScene({
|
|
5
|
+
setup() {},
|
|
6
|
+
}, {bgHexRgb: 0x1A_1B_26, visible: true});
|
|
7
|
+
|
|
8
|
+
const title = createTextWidget({
|
|
9
|
+
x: 0,
|
|
10
|
+
y: 0,
|
|
11
|
+
width: '100%',
|
|
12
|
+
height: 1,
|
|
13
|
+
value: 'Hello from {{name}}!',
|
|
14
|
+
colorFg: 0x7A_A2_F7,
|
|
15
|
+
colorBg: 0x1A_1B_26,
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
const box = createBox({
|
|
19
|
+
x: '10%',
|
|
20
|
+
y: '20%',
|
|
21
|
+
width: '80%',
|
|
22
|
+
height: '60%',
|
|
23
|
+
colorBg: 0x24_28_3B,
|
|
24
|
+
borderColor: 0x7A_A2_F7,
|
|
25
|
+
borderStyle: 'solid',
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
scene.mount(box);
|
|
29
|
+
scene.mount(title);
|
|
30
|
+
app.start();
|