@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.
Files changed (39) hide show
  1. package/README.md +129 -0
  2. package/dist/index.js +221 -0
  3. package/package.json +20 -15
  4. package/templates/counter/README.md +88 -0
  5. package/templates/counter/package.json +18 -0
  6. package/templates/counter/src/App.ts +65 -0
  7. package/templates/counter/src/components/Counter.ts +78 -0
  8. package/templates/counter/src/components/CounterPanel.ts +74 -0
  9. package/templates/counter/src/components/Header.ts +55 -0
  10. package/templates/counter/src/components/HistoryPanel.ts +96 -0
  11. package/templates/counter/src/components/KeyBindings.ts +60 -0
  12. package/templates/counter/src/components/StatsPanel.ts +101 -0
  13. package/templates/counter/src/main.ts +87 -0
  14. package/templates/counter/src/state/counters.ts +121 -0
  15. package/templates/counter/tsconfig.json +16 -0
  16. package/templates/dashboard/README.md +95 -0
  17. package/templates/dashboard/package.json +18 -0
  18. package/templates/dashboard/src/App.ts +72 -0
  19. package/templates/dashboard/src/components/Footer.ts +102 -0
  20. package/templates/dashboard/src/components/Header.ts +108 -0
  21. package/templates/dashboard/src/components/LogsPanel.ts +98 -0
  22. package/templates/dashboard/src/components/MetricsPanel.ts +145 -0
  23. package/templates/dashboard/src/components/Sidebar.ts +162 -0
  24. package/templates/dashboard/src/components/TrafficPanel.ts +129 -0
  25. package/templates/dashboard/src/main.ts +66 -0
  26. package/templates/dashboard/src/state/logs.ts +42 -0
  27. package/templates/dashboard/src/state/metrics.ts +129 -0
  28. package/templates/dashboard/src/state/theme.ts +20 -0
  29. package/templates/dashboard/tsconfig.json +16 -0
  30. package/templates/minimal/README.md +98 -0
  31. package/templates/minimal/package.json +18 -0
  32. package/templates/minimal/src/App.ts +108 -0
  33. package/templates/minimal/src/components/Header.ts +52 -0
  34. package/templates/minimal/src/main.ts +24 -0
  35. package/templates/minimal/tsconfig.json +16 -0
  36. package/src/commands/create.ts +0 -300
  37. package/src/index.ts +0 -75
  38. package/src/utils/colors.ts +0 -132
  39. package/src/utils/prompts.ts +0 -273
@@ -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
- }