wad-lab 1.0.1 → 1.0.3
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/bin/index.js
CHANGED
|
@@ -28,73 +28,123 @@ const templates = [
|
|
|
28
28
|
];
|
|
29
29
|
|
|
30
30
|
let selectedIndex = 0;
|
|
31
|
+
const selectedValues = new Set();
|
|
31
32
|
const templatesRoot = path.join(__dirname, '..', 'templates');
|
|
33
|
+
let isPrompting = false;
|
|
32
34
|
|
|
33
35
|
function renderMenu() {
|
|
34
36
|
console.clear();
|
|
35
37
|
console.log('=== WAD LAB STARTER TEMPLATES ===');
|
|
36
|
-
console.log('Use [UP / DOWN] arrow keys to
|
|
38
|
+
console.log('Use [UP / DOWN] arrow keys to move');
|
|
39
|
+
console.log('Press [SPACE] to select / deselect (multi-select supported)');
|
|
40
|
+
console.log('Press [ENTER] to confirm and proceed\n');
|
|
37
41
|
|
|
38
42
|
templates.forEach((t, i) => {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
43
|
+
const isCursor = i === selectedIndex;
|
|
44
|
+
const isChecked = selectedValues.has(t.value);
|
|
45
|
+
const box = isChecked ? '[x]' : '[ ]';
|
|
46
|
+
const prefix = isCursor ? '> ' : ' ';
|
|
47
|
+
console.log(prefix + box + ' ' + t.name);
|
|
44
48
|
});
|
|
45
49
|
|
|
46
50
|
console.log('\nPress Ctrl+C to cancel.');
|
|
47
51
|
}
|
|
48
52
|
|
|
49
|
-
function
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
if (
|
|
53
|
-
|
|
54
|
-
console.log('\nSuccessfully unpacked ALL templates into: ' + destDir);
|
|
55
|
-
} else {
|
|
56
|
-
const src = path.join(templatesRoot, choice);
|
|
57
|
-
const dest = path.join(destDir, choice);
|
|
58
|
-
fs.cpSync(src, dest, { recursive: true });
|
|
59
|
-
console.log('\nSuccessfully unpacked [' + choice + '] into: ' + dest);
|
|
53
|
+
function promptFolderName(choices) {
|
|
54
|
+
isPrompting = true;
|
|
55
|
+
process.stdin.removeAllListeners('keypress');
|
|
56
|
+
if (process.stdin.isTTY) {
|
|
57
|
+
process.stdin.setRawMode(false);
|
|
60
58
|
}
|
|
61
|
-
|
|
59
|
+
|
|
60
|
+
const isAll = choices.includes('all');
|
|
61
|
+
const defaultFolder = isAll || choices.length > 1 ? 'wad-templates' : choices[0];
|
|
62
|
+
|
|
63
|
+
const rl = readline.createInterface({
|
|
64
|
+
input: process.stdin,
|
|
65
|
+
output: process.stdout
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
console.log('\nSelected to unpack: ' + choices.join(', '));
|
|
69
|
+
rl.question(`Enter destination folder name (default: "${defaultFolder}"): `, (answer) => {
|
|
70
|
+
rl.close();
|
|
71
|
+
const folder = answer.trim() || defaultFolder;
|
|
72
|
+
const destDir = path.resolve(process.cwd(), folder);
|
|
73
|
+
|
|
74
|
+
if (!fs.existsSync(destDir)) {
|
|
75
|
+
fs.mkdirSync(destDir, { recursive: true });
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
if (isAll) {
|
|
79
|
+
fs.cpSync(templatesRoot, destDir, { recursive: true });
|
|
80
|
+
console.log('\nSuccessfully unpacked ALL templates into: ' + destDir);
|
|
81
|
+
} else {
|
|
82
|
+
choices.forEach(c => {
|
|
83
|
+
const src = path.join(templatesRoot, c);
|
|
84
|
+
const dest = path.join(destDir, c);
|
|
85
|
+
fs.cpSync(src, dest, { recursive: true });
|
|
86
|
+
console.log('Unpacked [' + c + '] into: ' + dest);
|
|
87
|
+
});
|
|
88
|
+
console.log('\nSuccessfully unpacked all chosen templates into: ' + destDir);
|
|
89
|
+
}
|
|
90
|
+
process.exit(0);
|
|
91
|
+
});
|
|
62
92
|
}
|
|
63
93
|
|
|
64
94
|
if (process.argv[2]) {
|
|
65
95
|
const arg = process.argv[2];
|
|
66
96
|
const found = templates.find(t => t.value === arg);
|
|
67
97
|
if (found) {
|
|
68
|
-
|
|
98
|
+
promptFolderName([found.value]);
|
|
69
99
|
} else {
|
|
70
100
|
console.error('Unknown template: ' + arg);
|
|
71
101
|
process.exit(1);
|
|
72
102
|
}
|
|
73
|
-
}
|
|
103
|
+
} else {
|
|
104
|
+
readline.emitKeypressEvents(process.stdin);
|
|
105
|
+
if (process.stdin.isTTY) {
|
|
106
|
+
process.stdin.setRawMode(true);
|
|
107
|
+
}
|
|
74
108
|
|
|
75
|
-
|
|
76
|
-
if (process.stdin.isTTY) {
|
|
77
|
-
process.stdin.setRawMode(true);
|
|
78
|
-
}
|
|
109
|
+
renderMenu();
|
|
79
110
|
|
|
80
|
-
|
|
111
|
+
process.stdin.on('keypress', (str, key) => {
|
|
112
|
+
if (isPrompting) return;
|
|
81
113
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
}
|
|
114
|
+
if (key.ctrl && key.name === 'c') {
|
|
115
|
+
process.exit(0);
|
|
116
|
+
}
|
|
86
117
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
118
|
+
if (key.name === 'up') {
|
|
119
|
+
selectedIndex = (selectedIndex - 1 + templates.length) % templates.length;
|
|
120
|
+
renderMenu();
|
|
121
|
+
} else if (key.name === 'down') {
|
|
122
|
+
selectedIndex = (selectedIndex + 1) % templates.length;
|
|
123
|
+
renderMenu();
|
|
124
|
+
} else if (key.name === 'space') {
|
|
125
|
+
const currentVal = templates[selectedIndex].value;
|
|
126
|
+
if (currentVal === 'all') {
|
|
127
|
+
if (selectedValues.has('all')) {
|
|
128
|
+
selectedValues.clear();
|
|
129
|
+
} else {
|
|
130
|
+
selectedValues.clear();
|
|
131
|
+
selectedValues.add('all');
|
|
132
|
+
}
|
|
133
|
+
} else {
|
|
134
|
+
selectedValues.delete('all');
|
|
135
|
+
if (selectedValues.has(currentVal)) {
|
|
136
|
+
selectedValues.delete(currentVal);
|
|
137
|
+
} else {
|
|
138
|
+
selectedValues.add(currentVal);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
renderMenu();
|
|
142
|
+
} else if (key.name === 'return' || key.name === 'enter') {
|
|
143
|
+
let chosen = Array.from(selectedValues);
|
|
144
|
+
if (chosen.length === 0) {
|
|
145
|
+
chosen = [templates[selectedIndex].value];
|
|
146
|
+
}
|
|
147
|
+
promptFolderName(chosen);
|
|
96
148
|
}
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
}
|
|
100
|
-
});
|
|
149
|
+
});
|
|
150
|
+
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "wad-lab",
|
|
3
|
-
"version": "1.0.
|
|
4
|
-
"description": "Interactive CLI for WAD Lab starter templates
|
|
3
|
+
"version": "1.0.3",
|
|
4
|
+
"description": "Interactive CLI for WAD Lab starter templates with multi-select support",
|
|
5
5
|
"bin": {
|
|
6
6
|
"wad-lab": "./bin/index.js"
|
|
7
7
|
},
|
|
@@ -2,26 +2,7 @@
|
|
|
2
2
|
<html>
|
|
3
3
|
<head>
|
|
4
4
|
<title>Form Validation Demo</title>
|
|
5
|
-
<style>
|
|
6
|
-
body {
|
|
7
|
-
font-family: sans-serif;
|
|
8
|
-
margin: 20px;
|
|
9
|
-
}
|
|
10
|
-
input:focus {
|
|
11
|
-
outline: 2px solid black;
|
|
12
|
-
}
|
|
13
|
-
input:invalid {
|
|
14
|
-
border: 1px solid gray;
|
|
15
|
-
}
|
|
16
|
-
p::before {
|
|
17
|
-
content: "• ";
|
|
18
|
-
}
|
|
19
|
-
table, th, td {
|
|
20
|
-
border: 1px solid black;
|
|
21
|
-
border-collapse: collapse;
|
|
22
|
-
padding: 4px 8px;
|
|
23
|
-
}
|
|
24
|
-
</style>
|
|
5
|
+
<link rel="stylesheet" href="style.css">
|
|
25
6
|
</head>
|
|
26
7
|
<body>
|
|
27
8
|
<h2>Item Entry Form</h2>
|
|
@@ -56,45 +37,6 @@
|
|
|
56
37
|
<tbody id="tableBody"></tbody>
|
|
57
38
|
</table>
|
|
58
39
|
|
|
59
|
-
<script>
|
|
60
|
-
function validateAndSubmit(e) {
|
|
61
|
-
e.preventDefault();
|
|
62
|
-
|
|
63
|
-
const name = document.getElementById("name").value.trim();
|
|
64
|
-
const description = document.getElementById("description").value.trim();
|
|
65
|
-
const price = document.getElementById("price").value.trim();
|
|
66
|
-
const errorMsg = document.getElementById("errorMsg");
|
|
67
|
-
|
|
68
|
-
errorMsg.innerText = "";
|
|
69
|
-
|
|
70
|
-
if (name.length < 2) {
|
|
71
|
-
errorMsg.innerText = "Name must be at least 2 characters.";
|
|
72
|
-
return false;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
const priceNum = parseFloat(price);
|
|
76
|
-
if (isNaN(priceNum) || priceNum <= 0) {
|
|
77
|
-
errorMsg.innerText = "Price must be a positive number.";
|
|
78
|
-
return false;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
const tbody = document.getElementById("tableBody");
|
|
82
|
-
const row = document.createElement("tr");
|
|
83
|
-
|
|
84
|
-
row.innerHTML = "<td>" + name + "</td>" +
|
|
85
|
-
"<td>" + description + "</td>" +
|
|
86
|
-
"<td>" + priceNum.toFixed(2) + "</td>" +
|
|
87
|
-
"<td><button onclick='deleteRow(this)'>Delete</button></td>";
|
|
88
|
-
|
|
89
|
-
tbody.appendChild(row);
|
|
90
|
-
|
|
91
|
-
document.getElementById("itemForm").reset();
|
|
92
|
-
return true;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
function deleteRow(btn) {
|
|
96
|
-
btn.parentElement.parentElement.remove();
|
|
97
|
-
}
|
|
98
|
-
</script>
|
|
40
|
+
<script src="script.js"></script>
|
|
99
41
|
</body>
|
|
100
42
|
</html>
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
function validateAndSubmit(e) {
|
|
2
|
+
e.preventDefault();
|
|
3
|
+
|
|
4
|
+
const name = document.getElementById("name").value.trim();
|
|
5
|
+
const description = document.getElementById("description").value.trim();
|
|
6
|
+
const price = document.getElementById("price").value.trim();
|
|
7
|
+
const errorMsg = document.getElementById("errorMsg");
|
|
8
|
+
|
|
9
|
+
errorMsg.innerText = "";
|
|
10
|
+
|
|
11
|
+
if (name.length < 2) {
|
|
12
|
+
errorMsg.innerText = "Name must be at least 2 characters.";
|
|
13
|
+
return false;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const priceNum = parseFloat(price);
|
|
17
|
+
if (isNaN(priceNum) || priceNum <= 0) {
|
|
18
|
+
errorMsg.innerText = "Price must be a positive number.";
|
|
19
|
+
return false;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const tbody = document.getElementById("tableBody");
|
|
23
|
+
const row = document.createElement("tr");
|
|
24
|
+
|
|
25
|
+
row.innerHTML = "<td>" + name + "</td>" +
|
|
26
|
+
"<td>" + description + "</td>" +
|
|
27
|
+
"<td>" + priceNum.toFixed(2) + "</td>" +
|
|
28
|
+
"<td><button onclick='deleteRow(this)'>Delete</button></td>";
|
|
29
|
+
|
|
30
|
+
tbody.appendChild(row);
|
|
31
|
+
|
|
32
|
+
document.getElementById("itemForm").reset();
|
|
33
|
+
return true;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function deleteRow(btn) {
|
|
37
|
+
btn.parentElement.parentElement.remove();
|
|
38
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
body {
|
|
2
|
+
font-family: sans-serif;
|
|
3
|
+
margin: 20px;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
input:focus {
|
|
7
|
+
outline: 2px solid black;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
input:invalid {
|
|
11
|
+
border: 1px solid gray;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
p::before {
|
|
15
|
+
content: "• ";
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
table, th, td {
|
|
19
|
+
border: 1px solid black;
|
|
20
|
+
border-collapse: collapse;
|
|
21
|
+
padding: 4px 8px;
|
|
22
|
+
}
|