muscle-config 1.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/LICENSE +21 -0
- package/README.md +430 -0
- package/dist/commands/create.command.js +104 -0
- package/dist/config/projectConfig.js +1 -0
- package/dist/features/architecture.feature.js +49 -0
- package/dist/features/css.feature.js +107 -0
- package/dist/features/feature.interface.js +1 -0
- package/dist/features/git.feature.js +52 -0
- package/dist/features/mui.feature.js +138 -0
- package/dist/features/prettier.feature.js +73 -0
- package/dist/features/tailwind.feature.js +116 -0
- package/dist/generators/architecture.generator.js +75 -0
- package/dist/generators/css-plain.generator.js +215 -0
- package/dist/generators/css.generator.js +45 -0
- package/dist/generators/mui.generator.js +176 -0
- package/dist/generators/react.generator.js +38 -0
- package/dist/generators/tailwind.config.generator.js +17 -0
- package/dist/generators/toggle.generator.js +26 -0
- package/dist/index.js +11 -0
- package/dist/prompts/architecture.prompt.js +131 -0
- package/dist/prompts/css.prompt.js +217 -0
- package/dist/prompts/directory.prompt.js +16 -0
- package/dist/prompts/framework.prompt.js +15 -0
- package/dist/prompts/git.prompt.js +23 -0
- package/dist/prompts/mui.prompt.js +104 -0
- package/dist/prompts/prettier.prompt.js +42 -0
- package/dist/prompts/projectName.prompt.js +13 -0
- package/dist/prompts/styling.prompt.js +17 -0
- package/dist/prompts/tailwind.prompt.js +175 -0
- package/dist/templates/react/css/App.jsx +41 -0
- package/dist/templates/react/css/App.tsx +41 -0
- package/dist/templates/react/mui/App.jsx +42 -0
- package/dist/templates/react/mui/App.tsx +42 -0
- package/dist/templates/react/tailwind-v4/index.css +20 -0
- package/dist/templates/react/tailwind-v4/vite.config.js +7 -0
- package/dist/templates/react/tailwind-v4/vite.config.ts +7 -0
- package/dist/utils/directory.js +43 -0
- package/dist/utils/install.js +7 -0
- package/dist/utils/logger.js +10 -0
- package/dist/utils/rollback.js +63 -0
- package/dist/utils/spinner.js +13 -0
- package/dist/utils/welcome.js +46 -0
- package/package.json +57 -0
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
import inquirer from "inquirer";
|
|
2
|
+
import chalk from "chalk";
|
|
3
|
+
const colorChoices = [
|
|
4
|
+
{
|
|
5
|
+
name: chalk.bgHex("#6366f1").white(" indigo ") + " Indigo",
|
|
6
|
+
value: "indigo",
|
|
7
|
+
},
|
|
8
|
+
{
|
|
9
|
+
name: chalk.bgHex("#10b981").black(" emerald ") + " Emerald",
|
|
10
|
+
value: "emerald",
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
name: chalk.bgHex("#737373").white(" neutral ") + " Neutral",
|
|
14
|
+
value: "neutral",
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
name: chalk.bgHex("#e11d48").white(" custom ") + " Custom HEX",
|
|
18
|
+
value: "custom",
|
|
19
|
+
},
|
|
20
|
+
{ name: " Skip", value: "none" },
|
|
21
|
+
];
|
|
22
|
+
const fontChoices = [
|
|
23
|
+
{ name: "Inter — clean, modern, readable", value: "inter" },
|
|
24
|
+
{ name: "Poppins — rounded, great for dashboards", value: "poppins" },
|
|
25
|
+
{ name: "Cairo — elegant, great for bilingual apps", value: "cairo" },
|
|
26
|
+
{ name: "Skip", value: "none" },
|
|
27
|
+
];
|
|
28
|
+
// Beginner Mode
|
|
29
|
+
async function askBeginner() {
|
|
30
|
+
const { reset } = await inquirer.prompt([
|
|
31
|
+
{
|
|
32
|
+
type: "confirm",
|
|
33
|
+
name: "reset",
|
|
34
|
+
message: "Modern CSS reset (box-sizing, margin 0, etc.)?",
|
|
35
|
+
default: true,
|
|
36
|
+
},
|
|
37
|
+
]);
|
|
38
|
+
const { colorPreset } = await inquirer.prompt([
|
|
39
|
+
{
|
|
40
|
+
type: "list",
|
|
41
|
+
name: "colorPreset",
|
|
42
|
+
message: "Choose a primary color:",
|
|
43
|
+
choices: colorChoices,
|
|
44
|
+
},
|
|
45
|
+
]);
|
|
46
|
+
let customColor;
|
|
47
|
+
if (colorPreset === "custom") {
|
|
48
|
+
const res = await inquirer.prompt([
|
|
49
|
+
{
|
|
50
|
+
type: "input",
|
|
51
|
+
name: "customColor",
|
|
52
|
+
message: "Enter HEX color:",
|
|
53
|
+
default: "#6366f1",
|
|
54
|
+
},
|
|
55
|
+
]);
|
|
56
|
+
customColor = res.customColor;
|
|
57
|
+
}
|
|
58
|
+
const { wantDarkMode } = await inquirer.prompt([
|
|
59
|
+
{
|
|
60
|
+
type: "confirm",
|
|
61
|
+
name: "wantDarkMode",
|
|
62
|
+
message: "Enable dark mode?",
|
|
63
|
+
default: true,
|
|
64
|
+
},
|
|
65
|
+
]);
|
|
66
|
+
return {
|
|
67
|
+
reset,
|
|
68
|
+
colorPreset,
|
|
69
|
+
customColor,
|
|
70
|
+
darkMode: wantDarkMode ? "media" : false,
|
|
71
|
+
darkModeToggle: false,
|
|
72
|
+
font: "none",
|
|
73
|
+
separateFiles: false,
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
// Advanced Mode
|
|
77
|
+
async function askAdvanced() {
|
|
78
|
+
const { reset } = await inquirer.prompt([
|
|
79
|
+
{
|
|
80
|
+
type: "confirm",
|
|
81
|
+
name: "reset",
|
|
82
|
+
message: "Add a CSS reset?",
|
|
83
|
+
default: true,
|
|
84
|
+
},
|
|
85
|
+
]);
|
|
86
|
+
const { colorPreset } = await inquirer.prompt([
|
|
87
|
+
{
|
|
88
|
+
type: "list",
|
|
89
|
+
name: "colorPreset",
|
|
90
|
+
message: "Choose a primary color:",
|
|
91
|
+
choices: colorChoices,
|
|
92
|
+
},
|
|
93
|
+
]);
|
|
94
|
+
let customColor;
|
|
95
|
+
if (colorPreset === "custom") {
|
|
96
|
+
const res = await inquirer.prompt([
|
|
97
|
+
{
|
|
98
|
+
type: "input",
|
|
99
|
+
name: "customColor",
|
|
100
|
+
message: "Enter HEX color:",
|
|
101
|
+
default: "#6366f1",
|
|
102
|
+
},
|
|
103
|
+
]);
|
|
104
|
+
customColor = res.customColor;
|
|
105
|
+
}
|
|
106
|
+
const { wantDarkMode } = await inquirer.prompt([
|
|
107
|
+
{
|
|
108
|
+
type: "confirm",
|
|
109
|
+
name: "wantDarkMode",
|
|
110
|
+
message: "Enable dark mode?",
|
|
111
|
+
default: true,
|
|
112
|
+
},
|
|
113
|
+
]);
|
|
114
|
+
let darkMode = false;
|
|
115
|
+
let darkModeToggle = false;
|
|
116
|
+
if (wantDarkMode) {
|
|
117
|
+
const { strategy } = await inquirer.prompt([
|
|
118
|
+
{
|
|
119
|
+
type: "list",
|
|
120
|
+
name: "strategy",
|
|
121
|
+
message: "Dark mode strategy:",
|
|
122
|
+
choices: [
|
|
123
|
+
{ name: "Manual toggle (class) (recommended)", value: "class" },
|
|
124
|
+
{ name: "System preference (media)", value: "media" },
|
|
125
|
+
],
|
|
126
|
+
},
|
|
127
|
+
]);
|
|
128
|
+
darkMode = strategy;
|
|
129
|
+
if (strategy === "class") {
|
|
130
|
+
const { toggle } = await inquirer.prompt([
|
|
131
|
+
{
|
|
132
|
+
type: "confirm",
|
|
133
|
+
name: "toggle",
|
|
134
|
+
message: "Add ThemeToggle component?",
|
|
135
|
+
default: true,
|
|
136
|
+
},
|
|
137
|
+
]);
|
|
138
|
+
darkModeToggle = toggle;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
const { font } = await inquirer.prompt([
|
|
142
|
+
{
|
|
143
|
+
type: "list",
|
|
144
|
+
name: "font",
|
|
145
|
+
message: "Choose a default font:",
|
|
146
|
+
choices: fontChoices,
|
|
147
|
+
},
|
|
148
|
+
]);
|
|
149
|
+
const { separateFiles } = await inquirer.prompt([
|
|
150
|
+
{
|
|
151
|
+
type: "confirm",
|
|
152
|
+
name: "separateFiles",
|
|
153
|
+
message: "Generate separate CSS files? (variables, reset, typography)",
|
|
154
|
+
default: false,
|
|
155
|
+
},
|
|
156
|
+
]);
|
|
157
|
+
return {
|
|
158
|
+
reset,
|
|
159
|
+
colorPreset,
|
|
160
|
+
customColor,
|
|
161
|
+
darkMode,
|
|
162
|
+
darkModeToggle,
|
|
163
|
+
font,
|
|
164
|
+
separateFiles,
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
// Css Configuration
|
|
168
|
+
export async function askCssConfig() {
|
|
169
|
+
const { mode } = await inquirer.prompt([
|
|
170
|
+
{
|
|
171
|
+
type: "list",
|
|
172
|
+
name: "mode",
|
|
173
|
+
message: "CSS configuration mode?",
|
|
174
|
+
choices: [
|
|
175
|
+
{ name: "Beginner (recommended)", value: "beginner" },
|
|
176
|
+
{ name: "Advanced (full control)", value: "advanced" },
|
|
177
|
+
{ name: "Skip (use Vite default)", value: "skip" },
|
|
178
|
+
],
|
|
179
|
+
},
|
|
180
|
+
]);
|
|
181
|
+
if (mode === "skip") {
|
|
182
|
+
return {
|
|
183
|
+
mode,
|
|
184
|
+
reset: false,
|
|
185
|
+
colorPreset: "none",
|
|
186
|
+
darkMode: false,
|
|
187
|
+
darkModeToggle: false,
|
|
188
|
+
font: "none",
|
|
189
|
+
separateFiles: false,
|
|
190
|
+
demo: false,
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
const answers = mode === "beginner" ? await askBeginner() : await askAdvanced();
|
|
194
|
+
let demo = false;
|
|
195
|
+
if (answers.darkModeToggle) {
|
|
196
|
+
const { wantDemo } = await inquirer.prompt([
|
|
197
|
+
{
|
|
198
|
+
type: "confirm",
|
|
199
|
+
name: "wantDemo",
|
|
200
|
+
message: "Override App.jsx with a CSS demo template?",
|
|
201
|
+
default: true,
|
|
202
|
+
},
|
|
203
|
+
]);
|
|
204
|
+
demo = wantDemo;
|
|
205
|
+
}
|
|
206
|
+
return {
|
|
207
|
+
mode,
|
|
208
|
+
reset: false,
|
|
209
|
+
colorPreset: "none",
|
|
210
|
+
darkMode: false,
|
|
211
|
+
darkModeToggle: false,
|
|
212
|
+
font: "none",
|
|
213
|
+
separateFiles: false,
|
|
214
|
+
demo,
|
|
215
|
+
...answers,
|
|
216
|
+
};
|
|
217
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import inquirer from "inquirer";
|
|
2
|
+
export async function askDirectoryMode() {
|
|
3
|
+
const { directoryMode } = await inquirer.prompt([
|
|
4
|
+
{
|
|
5
|
+
type: "list",
|
|
6
|
+
name: "directoryMode",
|
|
7
|
+
message: "Where would you like to create the project?",
|
|
8
|
+
choices: [
|
|
9
|
+
{ name: "Create in a new folder", value: "new" },
|
|
10
|
+
{ name: "Use current directory", value: "current" },
|
|
11
|
+
],
|
|
12
|
+
default: "new",
|
|
13
|
+
},
|
|
14
|
+
]);
|
|
15
|
+
return directoryMode;
|
|
16
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import inquirer from "inquirer";
|
|
2
|
+
export async function askFramework() {
|
|
3
|
+
const { framework } = await inquirer.prompt([
|
|
4
|
+
{
|
|
5
|
+
type: "list",
|
|
6
|
+
name: "framework",
|
|
7
|
+
message: "Choose your React setup:",
|
|
8
|
+
choices: [
|
|
9
|
+
{ name: "React + TypeScript", value: "react-ts" },
|
|
10
|
+
{ name: "React + JavaScript", value: "react-js" },
|
|
11
|
+
],
|
|
12
|
+
},
|
|
13
|
+
]);
|
|
14
|
+
return framework;
|
|
15
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import inquirer from "inquirer";
|
|
2
|
+
export async function askGitConfig() {
|
|
3
|
+
const { init } = await inquirer.prompt([
|
|
4
|
+
{
|
|
5
|
+
type: "confirm",
|
|
6
|
+
name: "init",
|
|
7
|
+
message: "Initialize a Git repository?",
|
|
8
|
+
default: true,
|
|
9
|
+
},
|
|
10
|
+
]);
|
|
11
|
+
if (!init) {
|
|
12
|
+
return { init: false, initialCommit: false };
|
|
13
|
+
}
|
|
14
|
+
const { initialCommit } = await inquirer.prompt([
|
|
15
|
+
{
|
|
16
|
+
type: "confirm",
|
|
17
|
+
name: "initialCommit",
|
|
18
|
+
message: "Create an initial commit?",
|
|
19
|
+
default: true,
|
|
20
|
+
},
|
|
21
|
+
]);
|
|
22
|
+
return { init, initialCommit };
|
|
23
|
+
}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import chalk from "chalk";
|
|
2
|
+
import inquirer from "inquirer";
|
|
3
|
+
const colorChoices = [
|
|
4
|
+
{
|
|
5
|
+
name: chalk.bgHex("#1976d2").white(" blue ") + " Blue (MUI default)",
|
|
6
|
+
value: "blue",
|
|
7
|
+
},
|
|
8
|
+
{
|
|
9
|
+
name: chalk.bgHex("#9c27b0").white(" purple ") + " Purple",
|
|
10
|
+
value: "purple",
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
name: chalk.bgHex("#2e7d32").white(" green ") + " Green",
|
|
14
|
+
value: "green",
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
name: chalk.bgHex("#e11d48").white(" custom ") + " Custom HEX",
|
|
18
|
+
value: "custom",
|
|
19
|
+
},
|
|
20
|
+
];
|
|
21
|
+
export async function askMuiConfig() {
|
|
22
|
+
const { themeMode } = await inquirer.prompt([
|
|
23
|
+
{
|
|
24
|
+
type: "list",
|
|
25
|
+
name: "themeMode",
|
|
26
|
+
message: "Default theme mode:",
|
|
27
|
+
choices: [
|
|
28
|
+
{ name: "Light", value: "light" },
|
|
29
|
+
{ name: "Dark", value: "dark" },
|
|
30
|
+
{ name: "System preference", value: "system" },
|
|
31
|
+
],
|
|
32
|
+
},
|
|
33
|
+
]);
|
|
34
|
+
const { darkModeToggle } = await inquirer.prompt([
|
|
35
|
+
{
|
|
36
|
+
type: "confirm",
|
|
37
|
+
name: "darkModeToggle",
|
|
38
|
+
message: "Add dark mode toggle component? (recommended — required for demo)",
|
|
39
|
+
default: true,
|
|
40
|
+
},
|
|
41
|
+
]);
|
|
42
|
+
const { colorPreset } = await inquirer.prompt([
|
|
43
|
+
{
|
|
44
|
+
type: "list",
|
|
45
|
+
name: "colorPreset",
|
|
46
|
+
message: "Choose a primary color:",
|
|
47
|
+
choices: colorChoices,
|
|
48
|
+
},
|
|
49
|
+
]);
|
|
50
|
+
let customColor;
|
|
51
|
+
if (colorPreset === "custom") {
|
|
52
|
+
const res = await inquirer.prompt([
|
|
53
|
+
{
|
|
54
|
+
type: "input",
|
|
55
|
+
name: "customColor",
|
|
56
|
+
message: "Enter HEX color:",
|
|
57
|
+
default: "#1976d2",
|
|
58
|
+
},
|
|
59
|
+
]);
|
|
60
|
+
customColor = res.customColor;
|
|
61
|
+
}
|
|
62
|
+
const { icons } = await inquirer.prompt([
|
|
63
|
+
{
|
|
64
|
+
type: "confirm",
|
|
65
|
+
name: "icons",
|
|
66
|
+
message: "Add MUI Icons package? (@mui/icons-material)",
|
|
67
|
+
default: true,
|
|
68
|
+
},
|
|
69
|
+
]);
|
|
70
|
+
const { font } = await inquirer.prompt([
|
|
71
|
+
{
|
|
72
|
+
type: "list",
|
|
73
|
+
name: "font",
|
|
74
|
+
message: "Choose a default font:",
|
|
75
|
+
choices: [
|
|
76
|
+
{ name: "Inter — clean, modern, readable", value: "inter" },
|
|
77
|
+
{ name: "Poppins — rounded, great for dashboards", value: "poppins" },
|
|
78
|
+
{ name: "Cairo — elegant, great for bilingual apps", value: "cairo" },
|
|
79
|
+
{ name: "Skip", value: "none" },
|
|
80
|
+
],
|
|
81
|
+
},
|
|
82
|
+
]);
|
|
83
|
+
let demo = false;
|
|
84
|
+
if (darkModeToggle) {
|
|
85
|
+
const { wantDemo } = await inquirer.prompt([
|
|
86
|
+
{
|
|
87
|
+
type: "confirm",
|
|
88
|
+
name: "wantDemo",
|
|
89
|
+
message: "Override App.jsx with a MUI demo template?",
|
|
90
|
+
default: true,
|
|
91
|
+
},
|
|
92
|
+
]);
|
|
93
|
+
demo = wantDemo;
|
|
94
|
+
}
|
|
95
|
+
return {
|
|
96
|
+
themeMode,
|
|
97
|
+
darkModeToggle,
|
|
98
|
+
colorPreset,
|
|
99
|
+
customColor,
|
|
100
|
+
icons,
|
|
101
|
+
font,
|
|
102
|
+
demo,
|
|
103
|
+
};
|
|
104
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import inquirer from "inquirer";
|
|
2
|
+
export async function askPrettierConfig() {
|
|
3
|
+
const { enabled } = await inquirer.prompt([
|
|
4
|
+
{
|
|
5
|
+
type: "confirm",
|
|
6
|
+
name: "enabled",
|
|
7
|
+
message: "Add Prettier?",
|
|
8
|
+
default: true,
|
|
9
|
+
},
|
|
10
|
+
]);
|
|
11
|
+
if (!enabled) {
|
|
12
|
+
return { enabled: false, singleQuote: true, semi: true, tabWidth: 2 };
|
|
13
|
+
}
|
|
14
|
+
const { singleQuote } = await inquirer.prompt([
|
|
15
|
+
{
|
|
16
|
+
type: "confirm",
|
|
17
|
+
name: "singleQuote",
|
|
18
|
+
message: "Use single quotes?",
|
|
19
|
+
default: true,
|
|
20
|
+
},
|
|
21
|
+
]);
|
|
22
|
+
const { semi } = await inquirer.prompt([
|
|
23
|
+
{
|
|
24
|
+
type: "confirm",
|
|
25
|
+
name: "semi",
|
|
26
|
+
message: "Use semicolons?",
|
|
27
|
+
default: true,
|
|
28
|
+
},
|
|
29
|
+
]);
|
|
30
|
+
const { tabWidth } = await inquirer.prompt([
|
|
31
|
+
{
|
|
32
|
+
type: "list",
|
|
33
|
+
name: "tabWidth",
|
|
34
|
+
message: "Tab width:",
|
|
35
|
+
choices: [
|
|
36
|
+
{ name: "2 spaces (recommended)", value: 2 },
|
|
37
|
+
{ name: "4 spaces", value: 4 },
|
|
38
|
+
],
|
|
39
|
+
},
|
|
40
|
+
]);
|
|
41
|
+
return { enabled, singleQuote, semi, tabWidth };
|
|
42
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import inquirer from "inquirer";
|
|
2
|
+
export async function askProjectName() {
|
|
3
|
+
const { projectName } = await inquirer.prompt([
|
|
4
|
+
{
|
|
5
|
+
type: "input",
|
|
6
|
+
name: "projectName",
|
|
7
|
+
message: "Project name:",
|
|
8
|
+
default: "my-app",
|
|
9
|
+
validate: (input) => input ? true : "Project name cannot be empty",
|
|
10
|
+
},
|
|
11
|
+
]);
|
|
12
|
+
return projectName;
|
|
13
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import inquirer from "inquirer";
|
|
2
|
+
export async function askStyling() {
|
|
3
|
+
const { styling } = await inquirer.prompt([
|
|
4
|
+
{
|
|
5
|
+
type: "list",
|
|
6
|
+
name: "styling",
|
|
7
|
+
message: "Choose your styling solution:",
|
|
8
|
+
choices: [
|
|
9
|
+
{ name: "Tailwind CSS v4", value: "tailwind" },
|
|
10
|
+
{ name: "MUI (Material UI)", value: "mui" },
|
|
11
|
+
{ name: "None (plain CSS)", value: "css" },
|
|
12
|
+
{ name: "Skip", value: "none" },
|
|
13
|
+
],
|
|
14
|
+
},
|
|
15
|
+
]);
|
|
16
|
+
return styling;
|
|
17
|
+
}
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
import inquirer from "inquirer";
|
|
2
|
+
import chalk from "chalk";
|
|
3
|
+
const colorChoices = [
|
|
4
|
+
{
|
|
5
|
+
name: chalk.bgHex("#6366f1").white(" indigo ") + " Indigo",
|
|
6
|
+
value: "indigo",
|
|
7
|
+
},
|
|
8
|
+
{
|
|
9
|
+
name: chalk.bgHex("#10b981").black(" emerald ") + " Emerald",
|
|
10
|
+
value: "emerald",
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
name: chalk.bgHex("#737373").white(" neutral ") + " Neutral",
|
|
14
|
+
value: "neutral",
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
name: chalk.bgHex("#e11d48").white(" custom ") + " Custom HEX",
|
|
18
|
+
value: "custom",
|
|
19
|
+
},
|
|
20
|
+
{ name: " Skip", value: "none" },
|
|
21
|
+
];
|
|
22
|
+
const fontChoices = [
|
|
23
|
+
{ name: "Inter — default for most apps", value: "inter" },
|
|
24
|
+
{ name: "Poppins — great for dashboards & landing pages", value: "poppins" },
|
|
25
|
+
{ name: "Cairo — works great for bilingual apps", value: "cairo" },
|
|
26
|
+
{ name: "Skip", value: "none" },
|
|
27
|
+
];
|
|
28
|
+
// Beginner mode asks only essential questions with simplified options
|
|
29
|
+
async function askBeginner() {
|
|
30
|
+
const { wantDarkMode } = await inquirer.prompt([
|
|
31
|
+
{
|
|
32
|
+
type: "confirm",
|
|
33
|
+
name: "wantDarkMode",
|
|
34
|
+
message: "Enable Dark Mode?",
|
|
35
|
+
default: true,
|
|
36
|
+
},
|
|
37
|
+
]);
|
|
38
|
+
let darkMode = false;
|
|
39
|
+
let darkModeToggle = false;
|
|
40
|
+
if (wantDarkMode) {
|
|
41
|
+
darkMode = "class";
|
|
42
|
+
darkModeToggle = true;
|
|
43
|
+
}
|
|
44
|
+
const { colorPreset } = await inquirer.prompt([
|
|
45
|
+
{
|
|
46
|
+
type: "list",
|
|
47
|
+
name: "colorPreset",
|
|
48
|
+
message: "Choose a primary color:",
|
|
49
|
+
choices: colorChoices,
|
|
50
|
+
},
|
|
51
|
+
]);
|
|
52
|
+
let customColor;
|
|
53
|
+
if (colorPreset === "custom") {
|
|
54
|
+
const res = await inquirer.prompt([
|
|
55
|
+
{
|
|
56
|
+
type: "input",
|
|
57
|
+
name: "customColor",
|
|
58
|
+
message: "Enter HEX color:",
|
|
59
|
+
default: "#6366f1",
|
|
60
|
+
},
|
|
61
|
+
]);
|
|
62
|
+
customColor = res.customColor;
|
|
63
|
+
}
|
|
64
|
+
return {
|
|
65
|
+
darkMode,
|
|
66
|
+
darkModeToggle,
|
|
67
|
+
colorPreset,
|
|
68
|
+
customColor,
|
|
69
|
+
font: "none",
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
// Advanced mode provides more granular control over Tailwind configuration
|
|
73
|
+
async function askAdvanced() {
|
|
74
|
+
const { wantDarkMode } = await inquirer.prompt([
|
|
75
|
+
{
|
|
76
|
+
type: "confirm",
|
|
77
|
+
name: "wantDarkMode",
|
|
78
|
+
message: "Enable Dark Mode?",
|
|
79
|
+
default: true,
|
|
80
|
+
},
|
|
81
|
+
]);
|
|
82
|
+
let darkMode = false;
|
|
83
|
+
let darkModeToggle = false;
|
|
84
|
+
if (wantDarkMode) {
|
|
85
|
+
const { strategy } = await inquirer.prompt([
|
|
86
|
+
{
|
|
87
|
+
type: "list",
|
|
88
|
+
name: "strategy",
|
|
89
|
+
message: "Dark Mode strategy:",
|
|
90
|
+
choices: [
|
|
91
|
+
{ name: "Manual toggle (class) (recommended)", value: "class" },
|
|
92
|
+
{ name: "System preference (media)", value: "media" },
|
|
93
|
+
],
|
|
94
|
+
},
|
|
95
|
+
]);
|
|
96
|
+
darkMode = strategy;
|
|
97
|
+
if (strategy === "class") {
|
|
98
|
+
const { toggle } = await inquirer.prompt([
|
|
99
|
+
{
|
|
100
|
+
type: "confirm",
|
|
101
|
+
name: "toggle",
|
|
102
|
+
message: "Add ThemeToggle component?",
|
|
103
|
+
default: true,
|
|
104
|
+
},
|
|
105
|
+
]);
|
|
106
|
+
darkModeToggle = toggle;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
const { colorPreset } = await inquirer.prompt([
|
|
110
|
+
{
|
|
111
|
+
type: "list",
|
|
112
|
+
name: "colorPreset",
|
|
113
|
+
message: "Choose a primary color:",
|
|
114
|
+
choices: colorChoices,
|
|
115
|
+
},
|
|
116
|
+
]);
|
|
117
|
+
let customColor;
|
|
118
|
+
if (colorPreset === "custom") {
|
|
119
|
+
const res = await inquirer.prompt([
|
|
120
|
+
{
|
|
121
|
+
type: "input",
|
|
122
|
+
name: "customColor",
|
|
123
|
+
message: "Enter HEX color:",
|
|
124
|
+
default: "#6366f1",
|
|
125
|
+
},
|
|
126
|
+
]);
|
|
127
|
+
customColor = res.customColor;
|
|
128
|
+
}
|
|
129
|
+
const { font } = await inquirer.prompt([
|
|
130
|
+
{
|
|
131
|
+
type: "list",
|
|
132
|
+
name: "font",
|
|
133
|
+
message: "Choose default font:",
|
|
134
|
+
choices: fontChoices,
|
|
135
|
+
},
|
|
136
|
+
]);
|
|
137
|
+
return {
|
|
138
|
+
darkMode,
|
|
139
|
+
darkModeToggle,
|
|
140
|
+
colorPreset,
|
|
141
|
+
customColor,
|
|
142
|
+
font,
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
export async function askTailwindConfig() {
|
|
146
|
+
const { mode } = await inquirer.prompt([
|
|
147
|
+
{
|
|
148
|
+
type: "list",
|
|
149
|
+
name: "mode",
|
|
150
|
+
message: "Tailwind configuration mode?",
|
|
151
|
+
choices: [
|
|
152
|
+
{ name: "Beginner (recommended)", value: "beginner" },
|
|
153
|
+
{ name: "Advanced (full control)", value: "advanced" },
|
|
154
|
+
],
|
|
155
|
+
},
|
|
156
|
+
]);
|
|
157
|
+
const answers = mode === "beginner" ? await askBeginner() : await askAdvanced();
|
|
158
|
+
const { prettierTailwind } = await inquirer.prompt([
|
|
159
|
+
{
|
|
160
|
+
type: "confirm",
|
|
161
|
+
name: "prettierTailwind",
|
|
162
|
+
message: "Add Prettier plugin for Tailwind class sorting? (recommended)",
|
|
163
|
+
default: true,
|
|
164
|
+
},
|
|
165
|
+
]);
|
|
166
|
+
return {
|
|
167
|
+
mode,
|
|
168
|
+
darkMode: false,
|
|
169
|
+
darkModeToggle: false,
|
|
170
|
+
colorPreset: "none",
|
|
171
|
+
font: "none",
|
|
172
|
+
prettierTailwind,
|
|
173
|
+
...answers,
|
|
174
|
+
};
|
|
175
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import ThemeToggle from "./components/ThemeToggle";
|
|
2
|
+
|
|
3
|
+
export default function App() {
|
|
4
|
+
return (
|
|
5
|
+
<div style={{
|
|
6
|
+
minHeight: "100vh",
|
|
7
|
+
display: "flex",
|
|
8
|
+
flexDirection: "column",
|
|
9
|
+
alignItems: "center",
|
|
10
|
+
justifyContent: "center",
|
|
11
|
+
gap: "1.5rem",
|
|
12
|
+
fontFamily: "var(--font-base, system-ui)",
|
|
13
|
+
backgroundColor: "var(--bg, #ffffff)",
|
|
14
|
+
color: "var(--text, #171717)",
|
|
15
|
+
}}>
|
|
16
|
+
<h1>CSS is ready 🎉</h1>
|
|
17
|
+
|
|
18
|
+
<p style={{ color: "var(--color-muted, #555)" }}>
|
|
19
|
+
Your CSS variables and reset are set up and ready to use.
|
|
20
|
+
</p>
|
|
21
|
+
|
|
22
|
+
<ThemeToggle />
|
|
23
|
+
|
|
24
|
+
<button style={{
|
|
25
|
+
padding: "0.5rem 1.25rem",
|
|
26
|
+
backgroundColor: "var(--color-primary, #6366f1)",
|
|
27
|
+
color: "#fff",
|
|
28
|
+
border: "none",
|
|
29
|
+
borderRadius: "var(--radius, 0.5rem)",
|
|
30
|
+
cursor: "pointer",
|
|
31
|
+
fontSize: "1rem",
|
|
32
|
+
}}>
|
|
33
|
+
Everything is working
|
|
34
|
+
</button>
|
|
35
|
+
|
|
36
|
+
<small style={{ color: "var(--color-muted, #999)" }}>
|
|
37
|
+
You can delete this demo and start building your app.
|
|
38
|
+
</small>
|
|
39
|
+
</div>
|
|
40
|
+
);
|
|
41
|
+
}
|