Skip to content

Commit 0e4f649

Browse files
authored
Improve create-y-sweet-app (#340)
- Fix npm's `bin` settings and add shebang - Fix argument parsing - Add interactive menu for choosing framework when used with no command line options - Add `README.md` for `create-y-sweet-app` package and framework templates.
1 parent 8f6ab6f commit 0e4f649

50 files changed

Lines changed: 195 additions & 42 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 13 additions & 0 deletions

js-pkg/create-y-sweet-app/package.json

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
{
22
"name": "create-y-sweet-app",
33
"version": "1.0.0",
4-
"main": "src/run.js",
54
"type": "module",
65
"bin": {
7-
"create-y-sweet-app": "./src/run.js"
6+
"create-y-sweet-app": "src/run.js"
87
},
98
"repository": {
109
"type": "git",

js-pkg/create-y-sweet-app/src/cli.js

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import readline from 'node:readline'
2+
13
const SPINNER_FRAMES = [
24
'☀️',
35
'☀️',
@@ -60,3 +62,104 @@ export function gray(text) {
6062
export function bold(text) {
6163
return `\x1b[1m${text}\x1b[0m`
6264
}
65+
66+
/**
67+
* @param {string} prompt
68+
* @param {string} defaultValue
69+
* @returns {Promise<string>}
70+
*/
71+
export function question(prompt, defaultValue = '') {
72+
return new Promise((resolve) => {
73+
const rl = readline.createInterface({
74+
input: process.stdin,
75+
output: process.stdout,
76+
})
77+
78+
rl.question(prompt, (result) => {
79+
rl.close()
80+
resolve(result || defaultValue)
81+
})
82+
})
83+
}
84+
85+
/**
86+
* Creates an interactive multiple choice selection menu without clearing console
87+
* @param {string} prompt - The question to display above choices
88+
* @param {string[]} choices - Array of options user can choose from
89+
* @returns {Promise<string>} - Returns selected choice
90+
*/
91+
export function select(prompt, choices) {
92+
return new Promise((resolve) => {
93+
let selected = 0
94+
let lines = 0 // track number of lines we've rendered
95+
96+
function render() {
97+
// move cursor up to clear previous render
98+
if (lines > 0) process.stdout.write(`\x1B[${lines}A`)
99+
100+
// render prompt and choices
101+
console.log(bold(prompt) + '\n')
102+
choices.forEach((choice, i) => {
103+
const indicator = i === selected ? '❯' : ' '
104+
console.log(`${indicator} ${choice}`)
105+
})
106+
107+
// store number of lines we just rendered
108+
lines = choices.length + 2 // +2 for prompt and blank line
109+
}
110+
111+
function cleanup() {
112+
// remove event listener
113+
process.stdin.off('data', onData)
114+
115+
// clean up the menu
116+
process.stdout.write(`\x1B[${lines}A`) // Move up
117+
process.stdout.write(`\x1B[J`) // Clear to bottom
118+
119+
// restore cursor and normal mode
120+
process.stdout.write('\x1B[?25h')
121+
process.stdin.setRawMode(false)
122+
process.stdin.pause()
123+
}
124+
125+
/** @param {Buffer} data */
126+
function onData(data) {
127+
const key = data.toString()
128+
129+
switch (key) {
130+
case '\u001b[A': {
131+
selected = (selected + choices.length - 1) % choices.length
132+
render()
133+
break
134+
}
135+
136+
case '\u001b[B': {
137+
selected = (selected + 1) % choices.length
138+
render()
139+
break
140+
}
141+
142+
case '\r': {
143+
cleanup()
144+
console.log(bold(prompt) + ' ' + choices[selected])
145+
resolve(choices[selected])
146+
break
147+
}
148+
149+
case '\u0003': {
150+
cleanup()
151+
return process.exit(1)
152+
}
153+
}
154+
}
155+
156+
// hide cursor and enable raw mode
157+
process.stdout.write('\x1B[?25l')
158+
process.stdin.setRawMode(true)
159+
process.stdin.resume()
160+
161+
render()
162+
163+
process.stdin.on('data', onData)
164+
})
165+
}

js-pkg/create-y-sweet-app/src/templates/nextjs/.env.local renamed to js-pkg/create-y-sweet-app/src/frameworks/nextjs/.env.local

File renamed without changes.

js-pkg/create-y-sweet-app/src/templates/nextjs/.gitignore renamed to js-pkg/create-y-sweet-app/src/frameworks/nextjs/.gitignore

File renamed without changes.

js-pkg/create-y-sweet-app/src/templates/nextjs/.prettierrc renamed to js-pkg/create-y-sweet-app/src/frameworks/nextjs/.prettierrc

File renamed without changes.
Lines changed: 21 additions & 0 deletions

js-pkg/create-y-sweet-app/src/templates/nextjs/app/favicon.ico renamed to js-pkg/create-y-sweet-app/src/frameworks/nextjs/app/favicon.ico

File renamed without changes.

js-pkg/create-y-sweet-app/src/templates/nextjs/app/globals.css renamed to js-pkg/create-y-sweet-app/src/frameworks/nextjs/app/globals.css

File renamed without changes.

js-pkg/create-y-sweet-app/src/templates/nextjs/app/layout.tsx renamed to js-pkg/create-y-sweet-app/src/frameworks/nextjs/app/layout.tsx

File renamed without changes.

0 commit comments

Comments
 (0)