vue-art-e4n 0.0.1
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/cli.js +30 -0
- package/config/architectures.js +54 -0
- package/config/featuresConfig.js +13 -0
- package/config/packages.js +55 -0
- package/config/rules.js +16 -0
- package/core/createPackageJson.js +131 -0
- package/core/createProjectStructure.js +1185 -0
- package/core/featureRules.js +35 -0
- package/core/installPackages.js +92 -0
- package/core/runCLI.js +67 -0
- package/core/selectArchitecture.js +89 -0
- package/core/steps/collectProjectConfig.js +103 -0
- package/core/steps/finalizeProject.js +24 -0
- package/core/steps/reviewAndConfirm.js +242 -0
- package/core/utils/getPackagesList.js +29 -0
- package/helpers/prompts.js +47 -0
- package/helpers/selectArchitecture.js +58 -0
- package/package.json +31 -0
- package/templates/Vue/Hello/331/214World.vue +54 -0
- package/templates/Vue/assets/base.css +86 -0
- package/templates/Vue/assets/logo.svg +1 -0
- package/templates/Vue/assets/main.css +35 -0
- package/templates/Vue/components/E4N.vue +69 -0
- package/templates/Vue/components/TheWelcome.vue +95 -0
- package/templates/Vue/components/WelcomeItem.vue +87 -0
- package/templates/Vue/components/icons/IconCommunity.vue +7 -0
- package/templates/Vue/components/icons/IconDocumentation.vue +7 -0
- package/templates/Vue/components/icons/IconEcosystem.vue +7 -0
- package/templates/Vue/components/icons/IconSupport.vue +7 -0
- package/templates/Vue/components/icons/IconTooling.vue +19 -0
- package/templates/Vuetify/HelloWorld.vue +88 -0
- package/templates/assets/E4N.vue +69 -0
|
@@ -0,0 +1,1185 @@
|
|
|
1
|
+
import fs from "fs-extra";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import { fileURLToPath } from "url";
|
|
4
|
+
import { dirname } from "path";
|
|
5
|
+
|
|
6
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
7
|
+
const __dirname = dirname(__filename);
|
|
8
|
+
const templatesDir = path.join(__dirname, "..", "templates");
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Creates project folders and base files based on framework & architecture.
|
|
12
|
+
*
|
|
13
|
+
* @param {Object} options
|
|
14
|
+
* @param {string} options.projectName
|
|
15
|
+
* @param {"vue"|"nuxt"|"vuetify"} options.framework
|
|
16
|
+
* @param {string} options.architecture
|
|
17
|
+
* @param {string[]} options.features
|
|
18
|
+
*
|
|
19
|
+
* @returns {void}
|
|
20
|
+
*/
|
|
21
|
+
function createVueVuetifyStructure(baseDir, framework, architecture, features) {
|
|
22
|
+
const srcDir = path.join(baseDir, "src");
|
|
23
|
+
fs.ensureDirSync(srcDir);
|
|
24
|
+
|
|
25
|
+
const hasVuetify = framework === "vuetify";
|
|
26
|
+
const useTs = features.includes("ts");
|
|
27
|
+
|
|
28
|
+
if (framework === "vue") {
|
|
29
|
+
// Vue projects
|
|
30
|
+
if (architecture === "simple") {
|
|
31
|
+
fs.ensureDirSync(path.join(srcDir, "components"));
|
|
32
|
+
fs.ensureDirSync(path.join(srcDir, "views"));
|
|
33
|
+
fs.ensureDirSync(path.join(srcDir, "router"));
|
|
34
|
+
fs.ensureDirSync(path.join(srcDir, "store"));
|
|
35
|
+
fs.ensureDirSync(path.join(srcDir, "assets"));
|
|
36
|
+
} else if (architecture === "feature") {
|
|
37
|
+
fs.ensureDirSync(path.join(srcDir, "features", "example"));
|
|
38
|
+
fs.ensureDirSync(path.join(srcDir, "components"));
|
|
39
|
+
fs.ensureDirSync(path.join(srcDir, "views"));
|
|
40
|
+
fs.ensureDirSync(path.join(srcDir, "router"));
|
|
41
|
+
fs.ensureDirSync(path.join(srcDir, "store"));
|
|
42
|
+
fs.ensureDirSync(path.join(srcDir, "assets"));
|
|
43
|
+
} else if (architecture === "atomic") {
|
|
44
|
+
fs.ensureDirSync(path.join(srcDir, "components", "atoms"));
|
|
45
|
+
fs.ensureDirSync(path.join(srcDir, "components", "molecules"));
|
|
46
|
+
fs.ensureDirSync(path.join(srcDir, "components", "organisms"));
|
|
47
|
+
fs.ensureDirSync(path.join(srcDir, "views"));
|
|
48
|
+
fs.ensureDirSync(path.join(srcDir, "assets"));
|
|
49
|
+
} else if (architecture === "enterprise") {
|
|
50
|
+
fs.ensureDirSync(path.join(srcDir, "modules"));
|
|
51
|
+
fs.ensureDirSync(path.join(srcDir, "features"));
|
|
52
|
+
fs.ensureDirSync(path.join(srcDir, "shared"));
|
|
53
|
+
fs.ensureDirSync(path.join(srcDir, "components", "atoms"));
|
|
54
|
+
fs.ensureDirSync(path.join(srcDir, "components", "molecules"));
|
|
55
|
+
fs.ensureDirSync(path.join(srcDir, "components", "organisms"));
|
|
56
|
+
fs.ensureDirSync(path.join(srcDir, "assets"));
|
|
57
|
+
}
|
|
58
|
+
} else if (framework === "vuetify") {
|
|
59
|
+
if (architecture === "simple") {
|
|
60
|
+
fs.ensureDirSync(path.join(srcDir, "components"));
|
|
61
|
+
fs.ensureDirSync(path.join(srcDir, "views"));
|
|
62
|
+
fs.ensureDirSync(path.join(srcDir, "router"));
|
|
63
|
+
fs.ensureDirSync(path.join(srcDir, "store"));
|
|
64
|
+
fs.ensureDirSync(path.join(srcDir, "plugins"));
|
|
65
|
+
fs.ensureDirSync(path.join(srcDir, "assets"));
|
|
66
|
+
} else if (architecture === "feature") {
|
|
67
|
+
fs.ensureDirSync(path.join(srcDir, "features", "example"));
|
|
68
|
+
fs.ensureDirSync(path.join(srcDir, "components"));
|
|
69
|
+
fs.ensureDirSync(path.join(srcDir, "views"));
|
|
70
|
+
fs.ensureDirSync(path.join(srcDir, "router"));
|
|
71
|
+
fs.ensureDirSync(path.join(srcDir, "store"));
|
|
72
|
+
fs.ensureDirSync(path.join(srcDir, "plugins"));
|
|
73
|
+
fs.ensureDirSync(path.join(srcDir, "assets"));
|
|
74
|
+
} else if (architecture === "enterprise") {
|
|
75
|
+
fs.ensureDirSync(path.join(srcDir, "modules"));
|
|
76
|
+
fs.ensureDirSync(path.join(srcDir, "features"));
|
|
77
|
+
fs.ensureDirSync(path.join(srcDir, "shared"));
|
|
78
|
+
fs.ensureDirSync(path.join(srcDir, "components"));
|
|
79
|
+
fs.ensureDirSync(path.join(srcDir, "plugins"));
|
|
80
|
+
fs.ensureDirSync(path.join(srcDir, "assets"));
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Creates directory structure for Nuxt projects based on architecture
|
|
87
|
+
*/
|
|
88
|
+
function createNuxtStructure(baseDir, architecture, features) {
|
|
89
|
+
const useTs = features.includes("ts");
|
|
90
|
+
|
|
91
|
+
if (architecture === "default") {
|
|
92
|
+
fs.ensureDirSync(path.join(baseDir, "pages"));
|
|
93
|
+
fs.ensureDirSync(path.join(baseDir, "components"));
|
|
94
|
+
fs.ensureDirSync(path.join(baseDir, "composables"));
|
|
95
|
+
fs.ensureDirSync(path.join(baseDir, "plugins"));
|
|
96
|
+
fs.ensureDirSync(path.join(baseDir, "middleware"));
|
|
97
|
+
fs.ensureDirSync(path.join(baseDir, "server", "api"));
|
|
98
|
+
fs.ensureDirSync(path.join(baseDir, "assets"));
|
|
99
|
+
} else if (architecture === "feature") {
|
|
100
|
+
fs.ensureDirSync(path.join(baseDir, "pages"));
|
|
101
|
+
fs.ensureDirSync(path.join(baseDir, "features", "example"));
|
|
102
|
+
fs.ensureDirSync(path.join(baseDir, "components"));
|
|
103
|
+
fs.ensureDirSync(path.join(baseDir, "composables"));
|
|
104
|
+
fs.ensureDirSync(path.join(baseDir, "plugins"));
|
|
105
|
+
fs.ensureDirSync(path.join(baseDir, "middleware"));
|
|
106
|
+
fs.ensureDirSync(path.join(baseDir, "server", "api"));
|
|
107
|
+
fs.ensureDirSync(path.join(baseDir, "assets"));
|
|
108
|
+
} else if (architecture === "layered") {
|
|
109
|
+
fs.ensureDirSync(path.join(baseDir, "pages"));
|
|
110
|
+
fs.ensureDirSync(path.join(baseDir, "layers", "domain"));
|
|
111
|
+
fs.ensureDirSync(path.join(baseDir, "layers", "application"));
|
|
112
|
+
fs.ensureDirSync(path.join(baseDir, "layers", "presentation"));
|
|
113
|
+
fs.ensureDirSync(path.join(baseDir, "components"));
|
|
114
|
+
fs.ensureDirSync(path.join(baseDir, "composables"));
|
|
115
|
+
fs.ensureDirSync(path.join(baseDir, "plugins"));
|
|
116
|
+
fs.ensureDirSync(path.join(baseDir, "middleware"));
|
|
117
|
+
fs.ensureDirSync(path.join(baseDir, "server", "api"));
|
|
118
|
+
fs.ensureDirSync(path.join(baseDir, "assets"));
|
|
119
|
+
} else if (architecture === "enterprise") {
|
|
120
|
+
fs.ensureDirSync(path.join(baseDir, "pages"));
|
|
121
|
+
fs.ensureDirSync(path.join(baseDir, "features"));
|
|
122
|
+
fs.ensureDirSync(path.join(baseDir, "layers"));
|
|
123
|
+
fs.ensureDirSync(path.join(baseDir, "modules"));
|
|
124
|
+
fs.ensureDirSync(path.join(baseDir, "shared"));
|
|
125
|
+
fs.ensureDirSync(path.join(baseDir, "components"));
|
|
126
|
+
fs.ensureDirSync(path.join(baseDir, "composables"));
|
|
127
|
+
fs.ensureDirSync(path.join(baseDir, "plugins"));
|
|
128
|
+
fs.ensureDirSync(path.join(baseDir, "middleware"));
|
|
129
|
+
fs.ensureDirSync(path.join(baseDir, "server", "api"));
|
|
130
|
+
fs.ensureDirSync(path.join(baseDir, "assets"));
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
export function createProjectStructure({
|
|
134
|
+
projectName,
|
|
135
|
+
framework,
|
|
136
|
+
architecture,
|
|
137
|
+
features,
|
|
138
|
+
}) {
|
|
139
|
+
const baseDir = path.resolve(process.cwd(), projectName);
|
|
140
|
+
fs.ensureDirSync(baseDir);
|
|
141
|
+
|
|
142
|
+
const useTs = features.includes("ts");
|
|
143
|
+
const hasTailwind = features.includes("tailwind");
|
|
144
|
+
const hasRouter = features.includes("router");
|
|
145
|
+
const hasVuetify =
|
|
146
|
+
framework === "vuetify" || features.includes("vuetifyComponents");
|
|
147
|
+
|
|
148
|
+
fs.writeFileSync(
|
|
149
|
+
path.join(baseDir, ".gitignore"),
|
|
150
|
+
`# Logs
|
|
151
|
+
logs
|
|
152
|
+
*.log
|
|
153
|
+
npm-debug.log*
|
|
154
|
+
yarn-debug.log*
|
|
155
|
+
yarn-error.log*
|
|
156
|
+
pnpm-debug.log*
|
|
157
|
+
lerna-debug.log*
|
|
158
|
+
|
|
159
|
+
# Dependencies
|
|
160
|
+
node_modules
|
|
161
|
+
dist
|
|
162
|
+
dist-ssr
|
|
163
|
+
*.local
|
|
164
|
+
|
|
165
|
+
# Editor directories and files
|
|
166
|
+
.vscode/*
|
|
167
|
+
!.vscode/extensions.json
|
|
168
|
+
.idea
|
|
169
|
+
.DS_Store
|
|
170
|
+
*.suo
|
|
171
|
+
*.ntvs*
|
|
172
|
+
*.njsproj
|
|
173
|
+
*.sln
|
|
174
|
+
*.sw?
|
|
175
|
+
|
|
176
|
+
# Environment variables
|
|
177
|
+
.env
|
|
178
|
+
.env.local
|
|
179
|
+
.env.*.local
|
|
180
|
+
|
|
181
|
+
# Build outputs
|
|
182
|
+
${framework === "nuxt" ? ".nuxt\n.output\n" : ""}`
|
|
183
|
+
);
|
|
184
|
+
fs.writeFileSync(
|
|
185
|
+
path.join(baseDir, "README.md"),
|
|
186
|
+
`# ${projectName}
|
|
187
|
+
|
|
188
|
+
${
|
|
189
|
+
framework === "nuxt"
|
|
190
|
+
? "Nuxt 3"
|
|
191
|
+
: framework === "vuetify"
|
|
192
|
+
? "Vue 3 + Vuetify"
|
|
193
|
+
: "Vue 3"
|
|
194
|
+
} project generated by VueArt CLI.
|
|
195
|
+
|
|
196
|
+
## Features
|
|
197
|
+
|
|
198
|
+
${features.length > 0 ? features.map((f) => `- ${f}`).join("\n") : "- None"}
|
|
199
|
+
|
|
200
|
+
## Getting Started
|
|
201
|
+
|
|
202
|
+
\`\`\`bash
|
|
203
|
+
# Install dependencies
|
|
204
|
+
npm install
|
|
205
|
+
|
|
206
|
+
# Start development server
|
|
207
|
+
npm run dev
|
|
208
|
+
|
|
209
|
+
# Build for production
|
|
210
|
+
npm run build
|
|
211
|
+
\`\`\`
|
|
212
|
+
`
|
|
213
|
+
);
|
|
214
|
+
|
|
215
|
+
if (framework !== "nuxt") {
|
|
216
|
+
createVueVuetifyStructure(baseDir, framework, architecture, features);
|
|
217
|
+
fs.ensureDirSync(path.join(baseDir, "public"));
|
|
218
|
+
const mainExt = useTs ? "ts" : "js";
|
|
219
|
+
const viteConfigExt = useTs ? "ts" : "js";
|
|
220
|
+
const configExt = useTs ? "ts" : "js";
|
|
221
|
+
fs.writeFileSync(
|
|
222
|
+
path.join(baseDir, "index.html"),
|
|
223
|
+
`<!doctype html>
|
|
224
|
+
<html lang="en">
|
|
225
|
+
<head>
|
|
226
|
+
<meta charset="UTF-8" />
|
|
227
|
+
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
|
228
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
229
|
+
<title>${projectName}</title>
|
|
230
|
+
</head>
|
|
231
|
+
<body>
|
|
232
|
+
<div id="app"></div>
|
|
233
|
+
<script type="module" src="/src/main.${mainExt}"></script>
|
|
234
|
+
</body>
|
|
235
|
+
</html>
|
|
236
|
+
`
|
|
237
|
+
);
|
|
238
|
+
fs.writeFileSync(
|
|
239
|
+
path.join(baseDir, "public/favicon.svg"),
|
|
240
|
+
`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
|
|
241
|
+
<circle cx="50" cy="50" r="40" fill="#42b883"/>
|
|
242
|
+
<text x="50" y="60" font-size="40" text-anchor="middle" fill="white">V</text>
|
|
243
|
+
</svg>`
|
|
244
|
+
);
|
|
245
|
+
const assetsDir = path.join(baseDir, "src/assets");
|
|
246
|
+
if (fs.existsSync(assetsDir)) {
|
|
247
|
+
if (hasVuetify) {
|
|
248
|
+
const e4nTemplatePath = path.join(templatesDir, "assets", "E4N.vue");
|
|
249
|
+
if (fs.existsSync(e4nTemplatePath)) {
|
|
250
|
+
const e4nContent = fs.readFileSync(e4nTemplatePath, "utf-8");
|
|
251
|
+
fs.writeFileSync(path.join(assetsDir, "E4N.vue"), e4nContent);
|
|
252
|
+
}
|
|
253
|
+
fs.writeFileSync(
|
|
254
|
+
path.join(assetsDir, "logo.svg"),
|
|
255
|
+
`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 200">
|
|
256
|
+
<rect width="200" height="200" fill="#1867C0"/>
|
|
257
|
+
<path d="M100 50 L150 150 L50 150 Z" fill="white"/>
|
|
258
|
+
<circle cx="100" cy="120" r="20" fill="#1867C0"/>
|
|
259
|
+
</svg>`
|
|
260
|
+
);
|
|
261
|
+
} else {
|
|
262
|
+
const vueLogoPath = path.join(
|
|
263
|
+
templatesDir,
|
|
264
|
+
"Vue",
|
|
265
|
+
"assets",
|
|
266
|
+
"logo.svg"
|
|
267
|
+
);
|
|
268
|
+
if (fs.existsSync(vueLogoPath)) {
|
|
269
|
+
fs.writeFileSync(
|
|
270
|
+
path.join(assetsDir, "logo.svg"),
|
|
271
|
+
fs.readFileSync(vueLogoPath, "utf-8")
|
|
272
|
+
);
|
|
273
|
+
} else {
|
|
274
|
+
fs.writeFileSync(
|
|
275
|
+
path.join(assetsDir, "vue.svg"),
|
|
276
|
+
`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
|
|
277
|
+
<circle cx="50" cy="50" r="40" fill="#42b883"/>
|
|
278
|
+
<text x="50" y="60" font-size="40" text-anchor="middle" fill="white">V</text>
|
|
279
|
+
</svg>`
|
|
280
|
+
);
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
let vitePlugins = ["vue()"];
|
|
285
|
+
if (hasVuetify) {
|
|
286
|
+
vitePlugins.push("vuetify()");
|
|
287
|
+
}
|
|
288
|
+
const viteConfigContent = `import { defineConfig } from 'vite';
|
|
289
|
+
import vue from '@vitejs/plugin-vue';
|
|
290
|
+
${hasVuetify ? "import vuetify from 'vite-plugin-vuetify';\n" : ""}
|
|
291
|
+
export default defineConfig({
|
|
292
|
+
plugins: [${vitePlugins.join(", ")}],
|
|
293
|
+
});`;
|
|
294
|
+
|
|
295
|
+
fs.writeFileSync(
|
|
296
|
+
path.join(baseDir, `vite.config.${viteConfigExt}`),
|
|
297
|
+
viteConfigContent
|
|
298
|
+
);
|
|
299
|
+
if (useTs) {
|
|
300
|
+
fs.writeFileSync(
|
|
301
|
+
path.join(baseDir, "tsconfig.json"),
|
|
302
|
+
`{
|
|
303
|
+
"compilerOptions": {
|
|
304
|
+
"target": "ES2020",
|
|
305
|
+
"useDefineForClassFields": true,
|
|
306
|
+
"module": "ESNext",
|
|
307
|
+
"lib": ["ES2020", "DOM", "DOM.Iterable"],
|
|
308
|
+
"skipLibCheck": true,
|
|
309
|
+
"moduleResolution": "bundler",
|
|
310
|
+
"allowImportingTsExtensions": true,
|
|
311
|
+
"resolveJsonModule": true,
|
|
312
|
+
"isolatedModules": true,
|
|
313
|
+
"noEmit": true,
|
|
314
|
+
"jsx": "preserve",
|
|
315
|
+
"strict": true,
|
|
316
|
+
"noUnusedLocals": true,
|
|
317
|
+
"noUnusedParameters": true,
|
|
318
|
+
"noFallthroughCasesInSwitch": true
|
|
319
|
+
},
|
|
320
|
+
"include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"],
|
|
321
|
+
"references": [{ "path": "./tsconfig.node.json" }]
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
`
|
|
325
|
+
);
|
|
326
|
+
|
|
327
|
+
fs.writeFileSync(
|
|
328
|
+
path.join(baseDir, "tsconfig.node.json"),
|
|
329
|
+
`{
|
|
330
|
+
"compilerOptions": {
|
|
331
|
+
"composite": true,
|
|
332
|
+
"skipLibCheck": true,
|
|
333
|
+
"module": "ESNext",
|
|
334
|
+
"moduleResolution": "bundler",
|
|
335
|
+
"allowSyntheticDefaultImports": true
|
|
336
|
+
},
|
|
337
|
+
"include": ["vite.config.ts"]
|
|
338
|
+
}
|
|
339
|
+
`
|
|
340
|
+
);
|
|
341
|
+
} else {
|
|
342
|
+
fs.writeFileSync(
|
|
343
|
+
path.join(baseDir, "jsconfig.json"),
|
|
344
|
+
`{
|
|
345
|
+
"compilerOptions": {
|
|
346
|
+
"baseUrl": ".",
|
|
347
|
+
"paths": {
|
|
348
|
+
"@/*": ["./src/*"]
|
|
349
|
+
}
|
|
350
|
+
},
|
|
351
|
+
"include": ["src/**/*"]
|
|
352
|
+
}
|
|
353
|
+
`
|
|
354
|
+
);
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
// Router setup (only create router files if router directory exists)
|
|
358
|
+
let routerImport = "";
|
|
359
|
+
let routerUse = "";
|
|
360
|
+
const routerDir = path.join(baseDir, "src/router");
|
|
361
|
+
if (hasRouter && fs.existsSync(routerDir)) {
|
|
362
|
+
const routerExt = useTs ? "ts" : "js";
|
|
363
|
+
|
|
364
|
+
fs.writeFileSync(
|
|
365
|
+
path.join(routerDir, `index.${routerExt}`),
|
|
366
|
+
`import { createRouter, createWebHistory } from 'vue-router';
|
|
367
|
+
import Home from '../views/Home.vue';
|
|
368
|
+
|
|
369
|
+
const routes = [
|
|
370
|
+
{ path: '/', name: 'home', component: Home },
|
|
371
|
+
];
|
|
372
|
+
|
|
373
|
+
export const router = createRouter({
|
|
374
|
+
history: createWebHistory(),
|
|
375
|
+
routes,
|
|
376
|
+
});`
|
|
377
|
+
);
|
|
378
|
+
|
|
379
|
+
const viewsDir = path.join(baseDir, "src/views");
|
|
380
|
+
if (!fs.existsSync(viewsDir)) {
|
|
381
|
+
fs.ensureDirSync(viewsDir);
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
let homeVueContent = "";
|
|
385
|
+
if (hasVuetify) {
|
|
386
|
+
homeVueContent = `<template>
|
|
387
|
+
<v-container class="fill-height">
|
|
388
|
+
<v-row justify="center" align="center">
|
|
389
|
+
<v-col cols="12" class="text-center">
|
|
390
|
+
<h1 class="text-h3 mb-4">Welcome to Vuetify App</h1>
|
|
391
|
+
<p class="text-body-1">This page is generated by VueArt CLI.</p>
|
|
392
|
+
</v-col>
|
|
393
|
+
</v-row>
|
|
394
|
+
</v-container>
|
|
395
|
+
</template>
|
|
396
|
+
|
|
397
|
+
<script${useTs ? ' setup lang="ts"' : " setup"}>
|
|
398
|
+
</script>
|
|
399
|
+
`;
|
|
400
|
+
} else {
|
|
401
|
+
// Read from template file
|
|
402
|
+
const vueTemplatePath = path.join(
|
|
403
|
+
templatesDir,
|
|
404
|
+
"Vue",
|
|
405
|
+
"HelloٌWorld.vue"
|
|
406
|
+
);
|
|
407
|
+
if (fs.existsSync(vueTemplatePath)) {
|
|
408
|
+
homeVueContent = fs.readFileSync(vueTemplatePath, "utf-8");
|
|
409
|
+
// Update import paths to match project structure
|
|
410
|
+
homeVueContent = homeVueContent.replace(
|
|
411
|
+
/from "\.\/components\//g,
|
|
412
|
+
'from "../components/'
|
|
413
|
+
);
|
|
414
|
+
homeVueContent = homeVueContent.replace(
|
|
415
|
+
/from "\.\/assets\//g,
|
|
416
|
+
'from "../assets/'
|
|
417
|
+
);
|
|
418
|
+
// Update script tag if needed
|
|
419
|
+
if (useTs && !homeVueContent.includes('lang="ts"')) {
|
|
420
|
+
homeVueContent = homeVueContent.replace(
|
|
421
|
+
/<script setup>/g,
|
|
422
|
+
'<script setup lang="ts">'
|
|
423
|
+
);
|
|
424
|
+
}
|
|
425
|
+
} else {
|
|
426
|
+
// Fallback if template doesn't exist
|
|
427
|
+
homeVueContent = `<template>
|
|
428
|
+
<main class="va-container">
|
|
429
|
+
<h1 class="va-title">Welcome to Vue 3 App</h1>
|
|
430
|
+
<p class="va-subtitle">This page is generated by VueArt CLI.</p>
|
|
431
|
+
</main>
|
|
432
|
+
</template>
|
|
433
|
+
|
|
434
|
+
<script${useTs ? ' setup lang="ts"' : " setup"}>
|
|
435
|
+
</script>
|
|
436
|
+
`;
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
fs.writeFileSync(path.join(viewsDir, "Home.vue"), homeVueContent);
|
|
441
|
+
|
|
442
|
+
routerImport = `import { router } from './router';\n`;
|
|
443
|
+
routerUse = `.use(router)`;
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
// Store setup (only create store files if store directory exists)
|
|
447
|
+
let storeImports = "";
|
|
448
|
+
let storeUse = "";
|
|
449
|
+
const storeDir = path.join(baseDir, "src/store");
|
|
450
|
+
if (features.includes("pinia") && fs.existsSync(storeDir)) {
|
|
451
|
+
fs.writeFileSync(
|
|
452
|
+
path.join(storeDir, "index.ts"),
|
|
453
|
+
`import { createPinia } from 'pinia';
|
|
454
|
+
|
|
455
|
+
export const store = createPinia();`
|
|
456
|
+
);
|
|
457
|
+
storeImports = `import { store } from './store';\n`;
|
|
458
|
+
storeUse = `.use(store)`;
|
|
459
|
+
} else if (features.includes("vuex") && fs.existsSync(storeDir)) {
|
|
460
|
+
const storeExt = useTs ? "ts" : "js";
|
|
461
|
+
fs.writeFileSync(
|
|
462
|
+
path.join(storeDir, `index.${storeExt}`),
|
|
463
|
+
`import { createStore } from 'vuex';
|
|
464
|
+
|
|
465
|
+
export const store = createStore({
|
|
466
|
+
state: () => ({}),
|
|
467
|
+
mutations: {},
|
|
468
|
+
actions: {},
|
|
469
|
+
});`
|
|
470
|
+
);
|
|
471
|
+
storeImports = `import { store } from './store';\n`;
|
|
472
|
+
storeUse = `.use(store)`;
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
// Vuetify plugin setup (only if plugins directory exists)
|
|
476
|
+
const pluginsDir = path.join(baseDir, "src/plugins");
|
|
477
|
+
if (hasVuetify && fs.existsSync(pluginsDir)) {
|
|
478
|
+
const vuetifyExt = useTs ? "ts" : "js";
|
|
479
|
+
fs.writeFileSync(
|
|
480
|
+
path.join(pluginsDir, `vuetify.${vuetifyExt}`),
|
|
481
|
+
`import { createVuetify } from 'vuetify';
|
|
482
|
+
import * as components from 'vuetify/components';
|
|
483
|
+
import * as directives from 'vuetify/directives';
|
|
484
|
+
import { aliases, mdi } from 'vuetify/iconsets/mdi';
|
|
485
|
+
import '@mdi/font/css/materialdesignicons.css';
|
|
486
|
+
|
|
487
|
+
export default createVuetify({
|
|
488
|
+
components,
|
|
489
|
+
directives,
|
|
490
|
+
icons: {
|
|
491
|
+
defaultSet: 'mdi',
|
|
492
|
+
aliases,
|
|
493
|
+
sets: {
|
|
494
|
+
mdi,
|
|
495
|
+
},
|
|
496
|
+
},
|
|
497
|
+
});`
|
|
498
|
+
);
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
// CSS setup
|
|
502
|
+
let cssImports = "";
|
|
503
|
+
if (hasVuetify) {
|
|
504
|
+
// Vuetify CSS imports
|
|
505
|
+
cssImports = `import 'vuetify/styles';\n`;
|
|
506
|
+
} else if (hasTailwind) {
|
|
507
|
+
fs.writeFileSync(
|
|
508
|
+
path.join(baseDir, "tailwind.config.cjs"),
|
|
509
|
+
`/** @type {import('tailwindcss').Config} */
|
|
510
|
+
module.exports = {
|
|
511
|
+
content: ['./index.html', './src/**/*.{vue,js,ts,jsx,tsx}'],
|
|
512
|
+
theme: {
|
|
513
|
+
extend: {},
|
|
514
|
+
},
|
|
515
|
+
plugins: [],
|
|
516
|
+
};`
|
|
517
|
+
);
|
|
518
|
+
fs.writeFileSync(
|
|
519
|
+
path.join(baseDir, "postcss.config.cjs"),
|
|
520
|
+
`module.exports = {
|
|
521
|
+
plugins: {
|
|
522
|
+
tailwindcss: {},
|
|
523
|
+
autoprefixer: {},
|
|
524
|
+
},
|
|
525
|
+
};`
|
|
526
|
+
);
|
|
527
|
+
// Assets directory should already exist from structure creation, but ensure it
|
|
528
|
+
if (!fs.existsSync(assetsDir)) {
|
|
529
|
+
fs.ensureDirSync(assetsDir);
|
|
530
|
+
}
|
|
531
|
+
fs.writeFileSync(
|
|
532
|
+
path.join(assetsDir, "main.css"),
|
|
533
|
+
`@tailwind base;
|
|
534
|
+
@tailwind components;
|
|
535
|
+
@tailwind utilities;
|
|
536
|
+
|
|
537
|
+
.va-container {
|
|
538
|
+
min-height: 100vh;
|
|
539
|
+
display: flex;
|
|
540
|
+
flex-direction: column;
|
|
541
|
+
align-items: center;
|
|
542
|
+
justify-content: center;
|
|
543
|
+
padding: 2rem;
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
.va-title {
|
|
547
|
+
font-size: 2rem;
|
|
548
|
+
font-weight: 700;
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
.va-subtitle {
|
|
552
|
+
margin-top: 0.5rem;
|
|
553
|
+
color: #64748b;
|
|
554
|
+
}`
|
|
555
|
+
);
|
|
556
|
+
cssImports = `import './assets/main.css';\n`;
|
|
557
|
+
} else {
|
|
558
|
+
// Copy CSS from Vue template if available, otherwise use basic styles
|
|
559
|
+
const vueAssetsDir = path.join(templatesDir, "Vue", "assets");
|
|
560
|
+
if (fs.existsSync(vueAssetsDir)) {
|
|
561
|
+
// Copy base.css
|
|
562
|
+
const baseCssPath = path.join(vueAssetsDir, "base.css");
|
|
563
|
+
if (fs.existsSync(baseCssPath)) {
|
|
564
|
+
fs.writeFileSync(
|
|
565
|
+
path.join(assetsDir, "base.css"),
|
|
566
|
+
fs.readFileSync(baseCssPath, "utf-8")
|
|
567
|
+
);
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
// Copy main.css
|
|
571
|
+
const mainCssPath = path.join(vueAssetsDir, "main.css");
|
|
572
|
+
if (fs.existsSync(mainCssPath)) {
|
|
573
|
+
fs.writeFileSync(
|
|
574
|
+
path.join(assetsDir, "main.css"),
|
|
575
|
+
fs.readFileSync(mainCssPath, "utf-8")
|
|
576
|
+
);
|
|
577
|
+
cssImports = `import './assets/main.css';\n`;
|
|
578
|
+
} else {
|
|
579
|
+
// Fallback to basic style.css
|
|
580
|
+
fs.writeFileSync(
|
|
581
|
+
path.join(baseDir, "src/style.css"),
|
|
582
|
+
`* {
|
|
583
|
+
margin: 0;
|
|
584
|
+
padding: 0;
|
|
585
|
+
box-sizing: border-box;
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
body {
|
|
589
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
.va-container {
|
|
593
|
+
min-height: 100vh;
|
|
594
|
+
display: flex;
|
|
595
|
+
flex-direction: column;
|
|
596
|
+
align-items: center;
|
|
597
|
+
justify-content: center;
|
|
598
|
+
padding: 2rem;
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
.va-title {
|
|
602
|
+
font-size: 2rem;
|
|
603
|
+
font-weight: 700;
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
.va-subtitle {
|
|
607
|
+
margin-top: 0.5rem;
|
|
608
|
+
color: #64748b;
|
|
609
|
+
}`
|
|
610
|
+
);
|
|
611
|
+
cssImports = `import './style.css';\n`;
|
|
612
|
+
}
|
|
613
|
+
} else {
|
|
614
|
+
// Basic style.css if no Tailwind and no template
|
|
615
|
+
fs.writeFileSync(
|
|
616
|
+
path.join(baseDir, "src/style.css"),
|
|
617
|
+
`* {
|
|
618
|
+
margin: 0;
|
|
619
|
+
padding: 0;
|
|
620
|
+
box-sizing: border-box;
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
body {
|
|
624
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
.va-container {
|
|
628
|
+
min-height: 100vh;
|
|
629
|
+
display: flex;
|
|
630
|
+
flex-direction: column;
|
|
631
|
+
align-items: center;
|
|
632
|
+
justify-content: center;
|
|
633
|
+
padding: 2rem;
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
.va-title {
|
|
637
|
+
font-size: 2rem;
|
|
638
|
+
font-weight: 700;
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
.va-subtitle {
|
|
642
|
+
margin-top: 0.5rem;
|
|
643
|
+
color: #64748b;
|
|
644
|
+
}`
|
|
645
|
+
);
|
|
646
|
+
cssImports = `import './style.css';\n`;
|
|
647
|
+
}
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
// main file
|
|
651
|
+
let vuetifyImport = "";
|
|
652
|
+
let vuetifyUse = "";
|
|
653
|
+
if (hasVuetify) {
|
|
654
|
+
vuetifyImport = `import vuetify from './plugins/vuetify';\n`;
|
|
655
|
+
vuetifyUse = `.use(vuetify)`;
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
const mainContent = `import { createApp } from 'vue';
|
|
659
|
+
import App from './App.vue';
|
|
660
|
+
${cssImports}${routerImport}${storeImports}${vuetifyImport}const app = createApp(App)${routerUse}${storeUse}${
|
|
661
|
+
vuetifyUse ? ` ${vuetifyUse}` : ""
|
|
662
|
+
};
|
|
663
|
+
|
|
664
|
+
app.mount('#app');`;
|
|
665
|
+
|
|
666
|
+
fs.writeFileSync(path.join(baseDir, `src/main.${mainExt}`), mainContent);
|
|
667
|
+
|
|
668
|
+
// App.vue
|
|
669
|
+
const appScriptTag = useTs ? '<script setup lang="ts">' : "<script setup>";
|
|
670
|
+
|
|
671
|
+
let appVueContent = "";
|
|
672
|
+
if (hasVuetify) {
|
|
673
|
+
appVueContent = `<template>
|
|
674
|
+
<v-app>
|
|
675
|
+
<v-main>
|
|
676
|
+
<HelloWorld />
|
|
677
|
+
</v-main>
|
|
678
|
+
</v-app>
|
|
679
|
+
</template>
|
|
680
|
+
|
|
681
|
+
${appScriptTag}
|
|
682
|
+
import HelloWorld from './components/HelloWorld.vue';
|
|
683
|
+
</script>
|
|
684
|
+
`;
|
|
685
|
+
} else {
|
|
686
|
+
// Read from template file
|
|
687
|
+
const vueTemplatePath = path.join(templatesDir, "Vue", "HelloٌWorld.vue");
|
|
688
|
+
if (fs.existsSync(vueTemplatePath)) {
|
|
689
|
+
appVueContent = fs.readFileSync(vueTemplatePath, "utf-8");
|
|
690
|
+
// Update import paths to match project structure
|
|
691
|
+
appVueContent = appVueContent.replace(
|
|
692
|
+
/from "\.\/components\//g,
|
|
693
|
+
'from "./components/'
|
|
694
|
+
);
|
|
695
|
+
appVueContent = appVueContent.replace(
|
|
696
|
+
/from "\.\/assets\//g,
|
|
697
|
+
'from "./assets/'
|
|
698
|
+
);
|
|
699
|
+
// Update script tag if needed
|
|
700
|
+
if (useTs && !appVueContent.includes('lang="ts"')) {
|
|
701
|
+
appVueContent = appVueContent.replace(
|
|
702
|
+
/<script setup>/g,
|
|
703
|
+
'<script setup lang="ts">'
|
|
704
|
+
);
|
|
705
|
+
}
|
|
706
|
+
} else {
|
|
707
|
+
// Fallback if template doesn't exist
|
|
708
|
+
appVueContent = `<template>
|
|
709
|
+
<main class="va-container">
|
|
710
|
+
<h1 class="va-title">Welcome to Vue 3 App</h1>
|
|
711
|
+
<p class="va-subtitle">This project is generated by VueArt CLI.</p>
|
|
712
|
+
</main>
|
|
713
|
+
</template>
|
|
714
|
+
|
|
715
|
+
${appScriptTag}
|
|
716
|
+
</script>
|
|
717
|
+
`;
|
|
718
|
+
}
|
|
719
|
+
}
|
|
720
|
+
|
|
721
|
+
fs.writeFileSync(path.join(baseDir, "src/App.vue"), appVueContent);
|
|
722
|
+
|
|
723
|
+
// Sample component (only if components directory exists)
|
|
724
|
+
const componentsDir = path.join(baseDir, "src/components");
|
|
725
|
+
if (fs.existsSync(componentsDir)) {
|
|
726
|
+
let helloWorldContent = "";
|
|
727
|
+
|
|
728
|
+
if (hasVuetify) {
|
|
729
|
+
// Load Vuetify template
|
|
730
|
+
const vuetifyTemplatePath = path.join(
|
|
731
|
+
templatesDir,
|
|
732
|
+
"Vuetify",
|
|
733
|
+
"HelloWorld.vue"
|
|
734
|
+
);
|
|
735
|
+
if (fs.existsSync(vuetifyTemplatePath)) {
|
|
736
|
+
helloWorldContent = fs.readFileSync(vuetifyTemplatePath, "utf-8");
|
|
737
|
+
helloWorldContent = helloWorldContent.replace(
|
|
738
|
+
/logo\.png/g,
|
|
739
|
+
"logo.svg"
|
|
740
|
+
);
|
|
741
|
+
} else {
|
|
742
|
+
helloWorldContent = `<template>
|
|
743
|
+
<v-container>
|
|
744
|
+
<h1>Welcome to Vuetify</h1>
|
|
745
|
+
</v-container>
|
|
746
|
+
</template>
|
|
747
|
+
|
|
748
|
+
${appScriptTag}
|
|
749
|
+
</script>
|
|
750
|
+
`;
|
|
751
|
+
}
|
|
752
|
+
} else {
|
|
753
|
+
const vueTemplatePath = path.join(
|
|
754
|
+
templatesDir,
|
|
755
|
+
"Vue",
|
|
756
|
+
"HelloٌWorld.vue"
|
|
757
|
+
);
|
|
758
|
+
if (fs.existsSync(vueTemplatePath)) {
|
|
759
|
+
// Copy E4N component
|
|
760
|
+
const e4nTemplatePath = path.join(
|
|
761
|
+
templatesDir,
|
|
762
|
+
"Vue",
|
|
763
|
+
"components",
|
|
764
|
+
"E4N.vue"
|
|
765
|
+
);
|
|
766
|
+
if (fs.existsSync(e4nTemplatePath)) {
|
|
767
|
+
const e4nContent = fs.readFileSync(e4nTemplatePath, "utf-8");
|
|
768
|
+
fs.writeFileSync(path.join(componentsDir, "E4N.vue"), e4nContent);
|
|
769
|
+
}
|
|
770
|
+
const theWelcomeTemplatePath = path.join(
|
|
771
|
+
templatesDir,
|
|
772
|
+
"Vue",
|
|
773
|
+
"components",
|
|
774
|
+
"TheWelcome.vue"
|
|
775
|
+
);
|
|
776
|
+
if (fs.existsSync(theWelcomeTemplatePath)) {
|
|
777
|
+
let theWelcomeContent = fs.readFileSync(
|
|
778
|
+
theWelcomeTemplatePath,
|
|
779
|
+
"utf-8"
|
|
780
|
+
);
|
|
781
|
+
theWelcomeContent = theWelcomeContent.replace(
|
|
782
|
+
/from '\.\/WelcomeItem\.vue'/g,
|
|
783
|
+
"from './WelcomeItem.vue'"
|
|
784
|
+
);
|
|
785
|
+
theWelcomeContent = theWelcomeContent.replace(
|
|
786
|
+
/from '\.\/icons\//g,
|
|
787
|
+
"from './icons/"
|
|
788
|
+
);
|
|
789
|
+
if (useTs && !theWelcomeContent.includes('lang="ts"')) {
|
|
790
|
+
theWelcomeContent = theWelcomeContent.replace(
|
|
791
|
+
/<script setup>/g,
|
|
792
|
+
'<script setup lang="ts">'
|
|
793
|
+
);
|
|
794
|
+
}
|
|
795
|
+
fs.writeFileSync(
|
|
796
|
+
path.join(componentsDir, "TheWelcome.vue"),
|
|
797
|
+
theWelcomeContent
|
|
798
|
+
);
|
|
799
|
+
}
|
|
800
|
+
const welcomeItemTemplatePath = path.join(
|
|
801
|
+
templatesDir,
|
|
802
|
+
"Vue",
|
|
803
|
+
"components",
|
|
804
|
+
"WelcomeItem.vue"
|
|
805
|
+
);
|
|
806
|
+
if (fs.existsSync(welcomeItemTemplatePath)) {
|
|
807
|
+
fs.writeFileSync(
|
|
808
|
+
path.join(componentsDir, "WelcomeItem.vue"),
|
|
809
|
+
fs.readFileSync(welcomeItemTemplatePath, "utf-8")
|
|
810
|
+
);
|
|
811
|
+
}
|
|
812
|
+
const iconsTemplateDir = path.join(
|
|
813
|
+
templatesDir,
|
|
814
|
+
"Vue",
|
|
815
|
+
"components",
|
|
816
|
+
"icons"
|
|
817
|
+
);
|
|
818
|
+
const iconsTargetDir = path.join(componentsDir, "icons");
|
|
819
|
+
if (fs.existsSync(iconsTemplateDir)) {
|
|
820
|
+
fs.ensureDirSync(iconsTargetDir);
|
|
821
|
+
const iconFiles = fs.readdirSync(iconsTemplateDir);
|
|
822
|
+
iconFiles.forEach((iconFile) => {
|
|
823
|
+
const iconTemplatePath = path.join(iconsTemplateDir, iconFile);
|
|
824
|
+
const iconTargetPath = path.join(iconsTargetDir, iconFile);
|
|
825
|
+
fs.writeFileSync(
|
|
826
|
+
iconTargetPath,
|
|
827
|
+
fs.readFileSync(iconTemplatePath, "utf-8")
|
|
828
|
+
);
|
|
829
|
+
});
|
|
830
|
+
}
|
|
831
|
+
helloWorldContent = `<template>
|
|
832
|
+
<div class="hello">
|
|
833
|
+
<h2>{{ msg }}</h2>
|
|
834
|
+
</div>
|
|
835
|
+
</template>
|
|
836
|
+
|
|
837
|
+
${appScriptTag}
|
|
838
|
+
${useTs ? "defineProps<{ msg: string }>();" : "defineProps({ msg: String });"}
|
|
839
|
+
</script>
|
|
840
|
+
|
|
841
|
+
<style scoped>
|
|
842
|
+
.hello {
|
|
843
|
+
text-align: center;
|
|
844
|
+
}
|
|
845
|
+
</style>
|
|
846
|
+
`;
|
|
847
|
+
} else {
|
|
848
|
+
helloWorldContent = `<template>
|
|
849
|
+
<div class="hello">
|
|
850
|
+
<h2>{{ msg }}</h2>
|
|
851
|
+
</div>
|
|
852
|
+
</template>
|
|
853
|
+
|
|
854
|
+
${appScriptTag}
|
|
855
|
+
${useTs ? "const msg: string = 'Hello World!';" : "const msg = 'Hello World!';"}
|
|
856
|
+
</script>
|
|
857
|
+
|
|
858
|
+
<style scoped>
|
|
859
|
+
.hello {
|
|
860
|
+
text-align: center;
|
|
861
|
+
}
|
|
862
|
+
</style>
|
|
863
|
+
`;
|
|
864
|
+
}
|
|
865
|
+
}
|
|
866
|
+
|
|
867
|
+
fs.writeFileSync(
|
|
868
|
+
path.join(componentsDir, "HelloWorld.vue"),
|
|
869
|
+
helloWorldContent
|
|
870
|
+
);
|
|
871
|
+
}
|
|
872
|
+
if (architecture === "feature") {
|
|
873
|
+
const exampleFeatureDir = path.join(baseDir, "src/features/example");
|
|
874
|
+
if (fs.existsSync(exampleFeatureDir)) {
|
|
875
|
+
const composableExt = useTs ? "ts" : "js";
|
|
876
|
+
fs.writeFileSync(
|
|
877
|
+
path.join(exampleFeatureDir, `useExample.${composableExt}`),
|
|
878
|
+
`import { ref } from 'vue';
|
|
879
|
+
|
|
880
|
+
export function useExample() {
|
|
881
|
+
const count = ref(0);
|
|
882
|
+
const increment = () => count.value++;
|
|
883
|
+
return { count, increment };
|
|
884
|
+
}`
|
|
885
|
+
);
|
|
886
|
+
|
|
887
|
+
fs.writeFileSync(
|
|
888
|
+
path.join(exampleFeatureDir, "ExampleView.vue"),
|
|
889
|
+
`<template>
|
|
890
|
+
<section class="va-container">
|
|
891
|
+
<h2 class="va-title">Feature: Example</h2>
|
|
892
|
+
<button @click="increment">Count: {{ count }}</button>
|
|
893
|
+
</section>
|
|
894
|
+
</template>
|
|
895
|
+
|
|
896
|
+
${appScriptTag}
|
|
897
|
+
import { useExample } from './useExample${useTs ? "" : ".js"}';
|
|
898
|
+
|
|
899
|
+
const { count, increment } = useExample();
|
|
900
|
+
</script>
|
|
901
|
+
`
|
|
902
|
+
);
|
|
903
|
+
}
|
|
904
|
+
}
|
|
905
|
+
const atomsDir = path.join(baseDir, "src/components/atoms");
|
|
906
|
+
const moleculesDir = path.join(baseDir, "src/components/molecules");
|
|
907
|
+
const organismsDir = path.join(baseDir, "src/components/organisms");
|
|
908
|
+
if (
|
|
909
|
+
fs.existsSync(atomsDir) &&
|
|
910
|
+
fs.existsSync(moleculesDir) &&
|
|
911
|
+
fs.existsSync(organismsDir)
|
|
912
|
+
) {
|
|
913
|
+
fs.writeFileSync(
|
|
914
|
+
path.join(atomsDir, "VaButton.vue"),
|
|
915
|
+
`<template>
|
|
916
|
+
<button class="va-button">
|
|
917
|
+
<slot />
|
|
918
|
+
</button>
|
|
919
|
+
</template>
|
|
920
|
+
|
|
921
|
+
${appScriptTag}
|
|
922
|
+
</script>
|
|
923
|
+
`
|
|
924
|
+
);
|
|
925
|
+
|
|
926
|
+
fs.writeFileSync(
|
|
927
|
+
path.join(moleculesDir, "VaCard.vue"),
|
|
928
|
+
`<template>
|
|
929
|
+
<section class="va-card">
|
|
930
|
+
<header class="va-card__header">
|
|
931
|
+
<slot name="title" />
|
|
932
|
+
</header>
|
|
933
|
+
<div class="va-card__body">
|
|
934
|
+
<slot />
|
|
935
|
+
</div>
|
|
936
|
+
</section>
|
|
937
|
+
</template>
|
|
938
|
+
|
|
939
|
+
${appScriptTag}
|
|
940
|
+
</script>
|
|
941
|
+
`
|
|
942
|
+
);
|
|
943
|
+
|
|
944
|
+
fs.writeFileSync(
|
|
945
|
+
path.join(organismsDir, "VaLayout.vue"),
|
|
946
|
+
`<template>
|
|
947
|
+
<div class="va-layout">
|
|
948
|
+
<header class="va-layout__header">
|
|
949
|
+
<slot name="header" />
|
|
950
|
+
</header>
|
|
951
|
+
<main class="va-layout__content">
|
|
952
|
+
<slot />
|
|
953
|
+
</main>
|
|
954
|
+
</div>
|
|
955
|
+
</template>
|
|
956
|
+
|
|
957
|
+
${appScriptTag}
|
|
958
|
+
</script>
|
|
959
|
+
`
|
|
960
|
+
);
|
|
961
|
+
}
|
|
962
|
+
|
|
963
|
+
// Enterprise structure example files
|
|
964
|
+
if (architecture === "enterprise") {
|
|
965
|
+
const sharedDir = path.join(baseDir, "src/shared");
|
|
966
|
+
if (fs.existsSync(sharedDir)) {
|
|
967
|
+
if (!fs.existsSync(path.join(sharedDir, "components"))) {
|
|
968
|
+
fs.ensureDirSync(path.join(sharedDir, "components"));
|
|
969
|
+
}
|
|
970
|
+
if (!fs.existsSync(path.join(sharedDir, "utils"))) {
|
|
971
|
+
fs.ensureDirSync(path.join(sharedDir, "utils"));
|
|
972
|
+
}
|
|
973
|
+
}
|
|
974
|
+
}
|
|
975
|
+
}
|
|
976
|
+
if (framework === "nuxt") {
|
|
977
|
+
createNuxtStructure(baseDir, architecture, features);
|
|
978
|
+
fs.ensureDirSync(path.join(baseDir, "layouts"));
|
|
979
|
+
fs.ensureDirSync(path.join(baseDir, "public"));
|
|
980
|
+
if (architecture === "feature") {
|
|
981
|
+
const exampleFeatureDir = path.join(baseDir, "features/example");
|
|
982
|
+
if (fs.existsSync(exampleFeatureDir)) {
|
|
983
|
+
const composableExt = useTs ? "ts" : "js";
|
|
984
|
+
fs.writeFileSync(
|
|
985
|
+
path.join(exampleFeatureDir, `useExample.${composableExt}`),
|
|
986
|
+
`export const useExample = () => {
|
|
987
|
+
const count = useState('example', () => 0);
|
|
988
|
+
const increment = () => count.value++;
|
|
989
|
+
return { count, increment };
|
|
990
|
+
};`
|
|
991
|
+
);
|
|
992
|
+
|
|
993
|
+
fs.writeFileSync(
|
|
994
|
+
path.join(exampleFeatureDir, "ExamplePage.vue"),
|
|
995
|
+
`<template>
|
|
996
|
+
<main class="va-container">
|
|
997
|
+
<h2 class="va-title">Feature: Example</h2>
|
|
998
|
+
<button @click="increment">Count: {{ count }}</button>
|
|
999
|
+
</main>
|
|
1000
|
+
</template>
|
|
1001
|
+
|
|
1002
|
+
<script${useTs ? ' setup lang="ts"' : " setup"}>
|
|
1003
|
+
import { useExample } from './useExample${useTs ? "" : ".js"}';
|
|
1004
|
+
|
|
1005
|
+
const { count, increment } = useExample();
|
|
1006
|
+
</script>
|
|
1007
|
+
`
|
|
1008
|
+
);
|
|
1009
|
+
}
|
|
1010
|
+
}
|
|
1011
|
+
|
|
1012
|
+
if (architecture === "layered" || architecture === "enterprise") {
|
|
1013
|
+
const layersDir = path.join(baseDir, "layers");
|
|
1014
|
+
if (fs.existsSync(layersDir)) {
|
|
1015
|
+
const domainDir = path.join(layersDir, "domain");
|
|
1016
|
+
const applicationDir = path.join(layersDir, "application");
|
|
1017
|
+
const presentationDir = path.join(layersDir, "presentation");
|
|
1018
|
+
|
|
1019
|
+
if (!fs.existsSync(path.join(domainDir, "entities"))) {
|
|
1020
|
+
fs.ensureDirSync(path.join(domainDir, "entities"));
|
|
1021
|
+
}
|
|
1022
|
+
if (!fs.existsSync(path.join(domainDir, "repositories"))) {
|
|
1023
|
+
fs.ensureDirSync(path.join(domainDir, "repositories"));
|
|
1024
|
+
}
|
|
1025
|
+
if (!fs.existsSync(path.join(applicationDir, "services"))) {
|
|
1026
|
+
fs.ensureDirSync(path.join(applicationDir, "services"));
|
|
1027
|
+
}
|
|
1028
|
+
if (!fs.existsSync(path.join(applicationDir, "use-cases"))) {
|
|
1029
|
+
fs.ensureDirSync(path.join(applicationDir, "use-cases"));
|
|
1030
|
+
}
|
|
1031
|
+
if (!fs.existsSync(path.join(presentationDir, "components"))) {
|
|
1032
|
+
fs.ensureDirSync(path.join(presentationDir, "components"));
|
|
1033
|
+
}
|
|
1034
|
+
if (!fs.existsSync(path.join(presentationDir, "composables"))) {
|
|
1035
|
+
fs.ensureDirSync(path.join(presentationDir, "composables"));
|
|
1036
|
+
}
|
|
1037
|
+
}
|
|
1038
|
+
}
|
|
1039
|
+
|
|
1040
|
+
if (architecture === "enterprise") {
|
|
1041
|
+
const sharedDir = path.join(baseDir, "shared");
|
|
1042
|
+
if (fs.existsSync(sharedDir)) {
|
|
1043
|
+
if (!fs.existsSync(path.join(sharedDir, "components"))) {
|
|
1044
|
+
fs.ensureDirSync(path.join(sharedDir, "components"));
|
|
1045
|
+
}
|
|
1046
|
+
if (!fs.existsSync(path.join(sharedDir, "composables"))) {
|
|
1047
|
+
fs.ensureDirSync(path.join(sharedDir, "composables"));
|
|
1048
|
+
}
|
|
1049
|
+
if (!fs.existsSync(path.join(sharedDir, "utils"))) {
|
|
1050
|
+
fs.ensureDirSync(path.join(sharedDir, "utils"));
|
|
1051
|
+
}
|
|
1052
|
+
|
|
1053
|
+
if (features.includes("pinia")) {
|
|
1054
|
+
const storeDir = path.join(sharedDir, "store");
|
|
1055
|
+
if (!fs.existsSync(storeDir)) {
|
|
1056
|
+
fs.ensureDirSync(storeDir);
|
|
1057
|
+
}
|
|
1058
|
+
const storeExt = useTs ? "ts" : "js";
|
|
1059
|
+
fs.writeFileSync(
|
|
1060
|
+
path.join(storeDir, `index.${storeExt}`),
|
|
1061
|
+
`import { defineStore } from 'pinia';
|
|
1062
|
+
|
|
1063
|
+
export const useAppStore = defineStore('app', {
|
|
1064
|
+
state: () => ({
|
|
1065
|
+
// Add your state here
|
|
1066
|
+
}),
|
|
1067
|
+
getters: {
|
|
1068
|
+
// Add your getters here
|
|
1069
|
+
},
|
|
1070
|
+
actions: {
|
|
1071
|
+
// Add your actions here
|
|
1072
|
+
},
|
|
1073
|
+
});`
|
|
1074
|
+
);
|
|
1075
|
+
}
|
|
1076
|
+
}
|
|
1077
|
+
}
|
|
1078
|
+
|
|
1079
|
+
const nuxtModules = [];
|
|
1080
|
+
if (hasTailwind) nuxtModules.push("'@nuxt/tailwindcss'");
|
|
1081
|
+
if (features.includes("pwa")) nuxtModules.push("'@nuxt/pwa'");
|
|
1082
|
+
if (features.includes("axios")) nuxtModules.push("'@nuxt/axios'");
|
|
1083
|
+
if (features.includes("i18n")) nuxtModules.push("'@nuxt/i18n'");
|
|
1084
|
+
if (features.includes("auth")) nuxtModules.push("'@nuxt/auth-next'");
|
|
1085
|
+
if (features.includes("pinia")) nuxtModules.push("'@pinia/nuxt'");
|
|
1086
|
+
|
|
1087
|
+
fs.writeFileSync(
|
|
1088
|
+
path.join(baseDir, "nuxt.config.ts"),
|
|
1089
|
+
`// https://nuxt.com/docs/api/configuration/nuxt-config
|
|
1090
|
+
export default defineNuxtConfig({
|
|
1091
|
+
modules: [${nuxtModules.length > 0 ? nuxtModules.join(", ") : ""}],
|
|
1092
|
+
})
|
|
1093
|
+
`
|
|
1094
|
+
);
|
|
1095
|
+
|
|
1096
|
+
fs.writeFileSync(
|
|
1097
|
+
path.join(baseDir, "app.vue"),
|
|
1098
|
+
`<template>
|
|
1099
|
+
<NuxtLayout>
|
|
1100
|
+
<NuxtPage />
|
|
1101
|
+
</NuxtLayout>
|
|
1102
|
+
</template>
|
|
1103
|
+
`
|
|
1104
|
+
);
|
|
1105
|
+
|
|
1106
|
+
fs.writeFileSync(
|
|
1107
|
+
path.join(baseDir, "layouts/default.vue"),
|
|
1108
|
+
`<template>
|
|
1109
|
+
<div>
|
|
1110
|
+
<header>
|
|
1111
|
+
<nav>
|
|
1112
|
+
<NuxtLink to="/">Home</NuxtLink>
|
|
1113
|
+
</nav>
|
|
1114
|
+
</header>
|
|
1115
|
+
<main>
|
|
1116
|
+
<slot />
|
|
1117
|
+
</main>
|
|
1118
|
+
</div>
|
|
1119
|
+
</template>
|
|
1120
|
+
|
|
1121
|
+
<script${useTs ? ' setup lang="ts"' : " setup"}>
|
|
1122
|
+
</script>
|
|
1123
|
+
`
|
|
1124
|
+
);
|
|
1125
|
+
|
|
1126
|
+
fs.writeFileSync(
|
|
1127
|
+
path.join(baseDir, "pages/index.vue"),
|
|
1128
|
+
`<template>
|
|
1129
|
+
<main class="va-container">
|
|
1130
|
+
<h1 class="va-title">Welcome to Nuxt App</h1>
|
|
1131
|
+
<p class="va-subtitle">This page is generated by VueArt CLI.</p>
|
|
1132
|
+
</main>
|
|
1133
|
+
</template>
|
|
1134
|
+
|
|
1135
|
+
<script${useTs ? ' setup lang="ts"' : " setup"}>
|
|
1136
|
+
</script>
|
|
1137
|
+
`
|
|
1138
|
+
);
|
|
1139
|
+
|
|
1140
|
+
fs.writeFileSync(path.join(baseDir, "public/favicon.ico"), "");
|
|
1141
|
+
if (useTs) {
|
|
1142
|
+
fs.writeFileSync(
|
|
1143
|
+
path.join(baseDir, "tsconfig.json"),
|
|
1144
|
+
`{
|
|
1145
|
+
"extends": "./.nuxt/tsconfig.json"
|
|
1146
|
+
}
|
|
1147
|
+
`
|
|
1148
|
+
);
|
|
1149
|
+
}
|
|
1150
|
+
if (hasTailwind) {
|
|
1151
|
+
const nuxtAssetsDir = path.join(baseDir, "assets");
|
|
1152
|
+
if (fs.existsSync(nuxtAssetsDir)) {
|
|
1153
|
+
const cssDir = path.join(nuxtAssetsDir, "css");
|
|
1154
|
+
if (!fs.existsSync(cssDir)) {
|
|
1155
|
+
fs.ensureDirSync(cssDir);
|
|
1156
|
+
}
|
|
1157
|
+
fs.writeFileSync(
|
|
1158
|
+
path.join(cssDir, "main.css"),
|
|
1159
|
+
`@tailwind base;
|
|
1160
|
+
@tailwind components;
|
|
1161
|
+
@tailwind utilities;
|
|
1162
|
+
|
|
1163
|
+
.va-container {
|
|
1164
|
+
min-height: 100vh;
|
|
1165
|
+
display: flex;
|
|
1166
|
+
flex-direction: column;
|
|
1167
|
+
align-items: center;
|
|
1168
|
+
justify-content: center;
|
|
1169
|
+
padding: 2rem;
|
|
1170
|
+
}
|
|
1171
|
+
|
|
1172
|
+
.va-title {
|
|
1173
|
+
font-size: 2rem;
|
|
1174
|
+
font-weight: 700;
|
|
1175
|
+
}
|
|
1176
|
+
|
|
1177
|
+
.va-subtitle {
|
|
1178
|
+
margin-top: 0.5rem;
|
|
1179
|
+
color: #64748b;
|
|
1180
|
+
}`
|
|
1181
|
+
);
|
|
1182
|
+
}
|
|
1183
|
+
}
|
|
1184
|
+
}
|
|
1185
|
+
}
|