@rlabs-inc/create-tui 0.1.6 → 0.2.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 +129 -0
- package/dist/index.js +221 -0
- package/package.json +20 -15
- package/templates/counter/README.md +88 -0
- package/templates/counter/package.json +18 -0
- package/templates/counter/src/App.ts +65 -0
- package/templates/counter/src/components/Counter.ts +78 -0
- package/templates/counter/src/components/CounterPanel.ts +74 -0
- package/templates/counter/src/components/Header.ts +55 -0
- package/templates/counter/src/components/HistoryPanel.ts +96 -0
- package/templates/counter/src/components/KeyBindings.ts +60 -0
- package/templates/counter/src/components/StatsPanel.ts +101 -0
- package/templates/counter/src/main.ts +87 -0
- package/templates/counter/src/state/counters.ts +121 -0
- package/templates/counter/tsconfig.json +16 -0
- package/templates/dashboard/README.md +95 -0
- package/templates/dashboard/package.json +18 -0
- package/templates/dashboard/src/App.ts +72 -0
- package/templates/dashboard/src/components/Footer.ts +102 -0
- package/templates/dashboard/src/components/Header.ts +108 -0
- package/templates/dashboard/src/components/LogsPanel.ts +98 -0
- package/templates/dashboard/src/components/MetricsPanel.ts +145 -0
- package/templates/dashboard/src/components/Sidebar.ts +162 -0
- package/templates/dashboard/src/components/TrafficPanel.ts +129 -0
- package/templates/dashboard/src/main.ts +66 -0
- package/templates/dashboard/src/state/logs.ts +42 -0
- package/templates/dashboard/src/state/metrics.ts +129 -0
- package/templates/dashboard/src/state/theme.ts +20 -0
- package/templates/dashboard/tsconfig.json +16 -0
- package/templates/minimal/README.md +98 -0
- package/templates/minimal/package.json +18 -0
- package/templates/minimal/src/App.ts +108 -0
- package/templates/minimal/src/components/Header.ts +52 -0
- package/templates/minimal/src/main.ts +24 -0
- package/templates/minimal/tsconfig.json +16 -0
- package/src/commands/create.ts +0 -300
- package/src/index.ts +0 -75
- package/src/utils/colors.ts +0 -132
- package/src/utils/prompts.ts +0 -273
package/src/utils/prompts.ts
DELETED
|
@@ -1,273 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Simple interactive prompts without external dependencies
|
|
3
|
-
*
|
|
4
|
-
* Uses raw mode to capture key presses for a smooth experience
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import { c, symbols } from './colors'
|
|
8
|
-
|
|
9
|
-
const stdin = process.stdin
|
|
10
|
-
const stdout = process.stdout
|
|
11
|
-
|
|
12
|
-
// Read a line of input
|
|
13
|
-
export async function text(options: {
|
|
14
|
-
message: string
|
|
15
|
-
placeholder?: string
|
|
16
|
-
defaultValue?: string
|
|
17
|
-
validate?: (value: string) => string | true
|
|
18
|
-
}): Promise<string> {
|
|
19
|
-
const { message, placeholder, defaultValue, validate } = options
|
|
20
|
-
|
|
21
|
-
// Print prompt
|
|
22
|
-
stdout.write(`${c.success(symbols.arrow)} ${c.bold(message)}`)
|
|
23
|
-
if (defaultValue) {
|
|
24
|
-
stdout.write(` ${c.muted(`(${defaultValue})`)}`)
|
|
25
|
-
}
|
|
26
|
-
stdout.write(': ')
|
|
27
|
-
|
|
28
|
-
if (placeholder && !defaultValue) {
|
|
29
|
-
stdout.write(c.muted(placeholder))
|
|
30
|
-
stdout.write('\x1b[' + placeholder.length + 'D') // Move cursor back
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
return new Promise((resolve) => {
|
|
34
|
-
let buffer = ''
|
|
35
|
-
let placeholderCleared = false
|
|
36
|
-
|
|
37
|
-
const cleanup = () => {
|
|
38
|
-
stdin.setRawMode(false)
|
|
39
|
-
stdin.removeListener('data', onData)
|
|
40
|
-
stdin.pause()
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
const onData = (data: Buffer) => {
|
|
44
|
-
const char = data.toString()
|
|
45
|
-
const code = data[0]
|
|
46
|
-
|
|
47
|
-
// Clear placeholder on first input
|
|
48
|
-
if (!placeholderCleared && placeholder && buffer === '') {
|
|
49
|
-
stdout.write('\x1b[' + placeholder.length + 'D')
|
|
50
|
-
stdout.write(' '.repeat(placeholder.length))
|
|
51
|
-
stdout.write('\x1b[' + placeholder.length + 'D')
|
|
52
|
-
placeholderCleared = true
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
// Enter
|
|
56
|
-
if (code === 13) {
|
|
57
|
-
stdout.write('\n')
|
|
58
|
-
const result = buffer || defaultValue || ''
|
|
59
|
-
|
|
60
|
-
// Validate
|
|
61
|
-
if (validate) {
|
|
62
|
-
const validationResult = validate(result)
|
|
63
|
-
if (validationResult !== true) {
|
|
64
|
-
stdout.write(`${c.error(symbols.cross)} ${validationResult}\n`)
|
|
65
|
-
stdout.write(`${c.success(symbols.arrow)} ${c.bold(message)}: `)
|
|
66
|
-
buffer = ''
|
|
67
|
-
return
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
cleanup()
|
|
72
|
-
resolve(result)
|
|
73
|
-
return
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
// Ctrl+C
|
|
77
|
-
if (code === 3) {
|
|
78
|
-
stdout.write('\n')
|
|
79
|
-
cleanup()
|
|
80
|
-
process.exit(1)
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
// Backspace
|
|
84
|
-
if (code === 127) {
|
|
85
|
-
if (buffer.length > 0) {
|
|
86
|
-
buffer = buffer.slice(0, -1)
|
|
87
|
-
stdout.write('\b \b')
|
|
88
|
-
}
|
|
89
|
-
return
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
// Printable characters
|
|
93
|
-
if (code >= 32 && code < 127) {
|
|
94
|
-
buffer += char
|
|
95
|
-
stdout.write(char)
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
stdin.resume()
|
|
100
|
-
stdin.setRawMode(true)
|
|
101
|
-
stdin.on('data', onData)
|
|
102
|
-
})
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
// Select from options
|
|
106
|
-
export async function select<T extends string>(options: {
|
|
107
|
-
message: string
|
|
108
|
-
options: { value: T; label: string; hint?: string }[]
|
|
109
|
-
}): Promise<T> {
|
|
110
|
-
const { message, options: choices } = options
|
|
111
|
-
let selectedIndex = 0
|
|
112
|
-
|
|
113
|
-
const render = () => {
|
|
114
|
-
// Clear previous render
|
|
115
|
-
stdout.write('\x1b[?25l') // Hide cursor
|
|
116
|
-
|
|
117
|
-
for (let i = 0; i < choices.length; i++) {
|
|
118
|
-
const choice = choices[i]
|
|
119
|
-
const isSelected = i === selectedIndex
|
|
120
|
-
const prefix = isSelected ? c.success(symbols.arrow) : ' '
|
|
121
|
-
const label = isSelected ? c.bold(choice.label) : choice.label
|
|
122
|
-
const hint = choice.hint ? c.muted(` ${choice.hint}`) : ''
|
|
123
|
-
|
|
124
|
-
stdout.write(` ${prefix} ${label}${hint}\n`)
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
stdout.write(`${c.success(symbols.arrow)} ${c.bold(message)}\n`)
|
|
129
|
-
render()
|
|
130
|
-
|
|
131
|
-
return new Promise((resolve) => {
|
|
132
|
-
const cleanup = () => {
|
|
133
|
-
stdin.setRawMode(false)
|
|
134
|
-
stdin.removeListener('data', onData)
|
|
135
|
-
stdin.pause()
|
|
136
|
-
stdout.write('\x1b[?25h') // Show cursor
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
const onData = (data: Buffer) => {
|
|
140
|
-
const code = data[0]
|
|
141
|
-
|
|
142
|
-
// Ctrl+C
|
|
143
|
-
if (code === 3) {
|
|
144
|
-
stdout.write('\n')
|
|
145
|
-
cleanup()
|
|
146
|
-
process.exit(1)
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
// Up arrow or k
|
|
150
|
-
if ((data[0] === 27 && data[1] === 91 && data[2] === 65) || code === 107) {
|
|
151
|
-
selectedIndex = (selectedIndex - 1 + choices.length) % choices.length
|
|
152
|
-
// Move cursor up and re-render
|
|
153
|
-
stdout.write(`\x1b[${choices.length}A`)
|
|
154
|
-
render()
|
|
155
|
-
return
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
// Down arrow or j
|
|
159
|
-
if ((data[0] === 27 && data[1] === 91 && data[2] === 66) || code === 106) {
|
|
160
|
-
selectedIndex = (selectedIndex + 1) % choices.length
|
|
161
|
-
// Move cursor up and re-render
|
|
162
|
-
stdout.write(`\x1b[${choices.length}A`)
|
|
163
|
-
render()
|
|
164
|
-
return
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
// Enter
|
|
168
|
-
if (code === 13) {
|
|
169
|
-
cleanup()
|
|
170
|
-
// Clear the options
|
|
171
|
-
stdout.write(`\x1b[${choices.length}A`)
|
|
172
|
-
for (let i = 0; i < choices.length; i++) {
|
|
173
|
-
stdout.write('\x1b[2K\n')
|
|
174
|
-
}
|
|
175
|
-
stdout.write(`\x1b[${choices.length}A`)
|
|
176
|
-
stdout.write(` ${c.muted(symbols.check)} ${choices[selectedIndex].label}\n`)
|
|
177
|
-
resolve(choices[selectedIndex].value)
|
|
178
|
-
return
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
stdin.resume()
|
|
183
|
-
stdin.setRawMode(true)
|
|
184
|
-
stdin.on('data', onData)
|
|
185
|
-
})
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
// Confirm yes/no
|
|
189
|
-
export async function confirm(options: {
|
|
190
|
-
message: string
|
|
191
|
-
defaultValue?: boolean
|
|
192
|
-
}): Promise<boolean> {
|
|
193
|
-
const { message, defaultValue = true } = options
|
|
194
|
-
const hint = defaultValue ? c.muted('[Y/n]') : c.muted('[y/N]')
|
|
195
|
-
|
|
196
|
-
stdout.write(`${c.success(symbols.arrow)} ${c.bold(message)} ${hint} `)
|
|
197
|
-
|
|
198
|
-
return new Promise((resolve) => {
|
|
199
|
-
const cleanup = () => {
|
|
200
|
-
stdin.setRawMode(false)
|
|
201
|
-
stdin.removeListener('data', onData)
|
|
202
|
-
stdin.pause()
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
const onData = (data: Buffer) => {
|
|
206
|
-
const char = data.toString().toLowerCase()
|
|
207
|
-
const code = data[0]
|
|
208
|
-
|
|
209
|
-
// Ctrl+C
|
|
210
|
-
if (code === 3) {
|
|
211
|
-
stdout.write('\n')
|
|
212
|
-
cleanup()
|
|
213
|
-
process.exit(1)
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
// Enter (use default)
|
|
217
|
-
if (code === 13) {
|
|
218
|
-
stdout.write(defaultValue ? 'Yes' : 'No')
|
|
219
|
-
stdout.write('\n')
|
|
220
|
-
cleanup()
|
|
221
|
-
resolve(defaultValue)
|
|
222
|
-
return
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
// Y
|
|
226
|
-
if (char === 'y') {
|
|
227
|
-
stdout.write('Yes\n')
|
|
228
|
-
cleanup()
|
|
229
|
-
resolve(true)
|
|
230
|
-
return
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
// N
|
|
234
|
-
if (char === 'n') {
|
|
235
|
-
stdout.write('No\n')
|
|
236
|
-
cleanup()
|
|
237
|
-
resolve(false)
|
|
238
|
-
return
|
|
239
|
-
}
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
stdin.resume()
|
|
243
|
-
stdin.setRawMode(true)
|
|
244
|
-
stdin.on('data', onData)
|
|
245
|
-
})
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
// Spinner
|
|
249
|
-
export function spinner(message: string): { stop: (finalMessage?: string) => void } {
|
|
250
|
-
const frames = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏']
|
|
251
|
-
let i = 0
|
|
252
|
-
let stopped = false
|
|
253
|
-
|
|
254
|
-
stdout.write('\x1b[?25l') // Hide cursor
|
|
255
|
-
|
|
256
|
-
const interval = setInterval(() => {
|
|
257
|
-
if (stopped) return
|
|
258
|
-
stdout.write(`\r${c.info(frames[i])} ${message}`)
|
|
259
|
-
i = (i + 1) % frames.length
|
|
260
|
-
}, 80)
|
|
261
|
-
|
|
262
|
-
return {
|
|
263
|
-
stop: (finalMessage?: string) => {
|
|
264
|
-
stopped = true
|
|
265
|
-
clearInterval(interval)
|
|
266
|
-
stdout.write('\r\x1b[K') // Clear line
|
|
267
|
-
if (finalMessage) {
|
|
268
|
-
stdout.write(`${c.success(symbols.check)} ${finalMessage}\n`)
|
|
269
|
-
}
|
|
270
|
-
stdout.write('\x1b[?25h') // Show cursor
|
|
271
|
-
}
|
|
272
|
-
}
|
|
273
|
-
}
|