create-velocity-astro 1.0.1 → 1.0.4
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/README.md +34 -9
- package/dist/index.js +126 -42
- package/dist/index.js.map +1 -1
- package/package.json +4 -5
- package/templates/base/src/pages/404.astro +29 -0
- package/templates/base/src/pages/blog/[...slug].astro +32 -0
- package/templates/base/src/pages/blog/index.astro +58 -0
- package/templates/base/src/pages/index.astro +36 -0
- package/templates/i18n/src/components/blog/RelatedPosts.astro +73 -0
- package/templates/i18n/src/content/blog/en/welcome-to-velocity.mdx +40 -0
- package/templates/i18n/src/content/blog/es/bienvenido-a-velocity.mdx +40 -0
- package/templates/i18n/src/content/blog/fr/bienvenue-sur-velocity.mdx +40 -0
- package/templates/i18n/src/i18n/translations/en.ts +15 -0
- package/templates/i18n/src/i18n/translations/es.ts +15 -0
- package/templates/i18n/src/i18n/translations/fr.ts +15 -0
- package/templates/i18n/src/layouts/BlogLayout.astro +133 -0
- package/templates/i18n/src/pages/[lang]/blog/[...slug].astro +55 -0
- package/templates/i18n/src/pages/[lang]/blog/index.astro +176 -0
- package/templates/i18n/src/pages/blog/[...slug].astro +36 -0
- package/templates/i18n/src/pages/blog/index.astro +160 -0
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# create-velocity-astro
|
|
2
2
|
|
|
3
|
-
Scaffold production-ready [Velocity](https://github.com/
|
|
3
|
+
Scaffold production-ready [Velocity](https://github.com/southwellmedia-dev/velocity) projects in seconds.
|
|
4
4
|
|
|
5
5
|
Velocity is an opinionated Astro 6 + Tailwind CSS v4 starter kit used by Southwell Media to deliver production client sites.
|
|
6
6
|
|
|
@@ -24,6 +24,8 @@ bun create velocity-astro my-site
|
|
|
24
24
|
|
|
25
25
|
| Flag | Description |
|
|
26
26
|
|------|-------------|
|
|
27
|
+
| `--demo` | Include demo landing page and sample content |
|
|
28
|
+
| `--components` | Include UI component library (buttons, forms, cards, etc.) |
|
|
27
29
|
| `--i18n` | Add internationalization support with locale routing |
|
|
28
30
|
| `--yes`, `-y` | Skip prompts and use default options |
|
|
29
31
|
| `--help`, `-h` | Show help message |
|
|
@@ -31,23 +33,46 @@ bun create velocity-astro my-site
|
|
|
31
33
|
|
|
32
34
|
## Examples
|
|
33
35
|
|
|
34
|
-
### Create a
|
|
36
|
+
### Create a minimal project
|
|
35
37
|
|
|
36
38
|
```bash
|
|
37
39
|
npm create velocity-astro@latest my-site
|
|
38
40
|
```
|
|
39
41
|
|
|
40
|
-
|
|
42
|
+
This gives you a clean starter with:
|
|
43
|
+
- Basic index, blog, and 404 pages
|
|
44
|
+
- Layouts and configuration
|
|
45
|
+
- SEO components
|
|
46
|
+
- Tailwind CSS v4 setup
|
|
47
|
+
|
|
48
|
+
### Create a project with demo content
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
npm create velocity-astro@latest my-site --demo
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Includes the full demo landing page with:
|
|
55
|
+
- Hero, features, CTA sections
|
|
56
|
+
- Sample blog posts
|
|
57
|
+
- About and contact pages
|
|
58
|
+
|
|
59
|
+
### Include the UI component library
|
|
41
60
|
|
|
42
61
|
```bash
|
|
43
|
-
npm create velocity-astro@latest my-site --
|
|
62
|
+
npm create velocity-astro@latest my-site --components
|
|
44
63
|
```
|
|
45
64
|
|
|
46
|
-
|
|
47
|
-
-
|
|
48
|
-
-
|
|
49
|
-
-
|
|
50
|
-
-
|
|
65
|
+
Adds 27+ production-ready components:
|
|
66
|
+
- Button, Input, Textarea, Select, Checkbox, Radio
|
|
67
|
+
- Card, Alert, Badge, Avatar, Skeleton
|
|
68
|
+
- Dialog, Dropdown, Tabs, Tooltip
|
|
69
|
+
- And more...
|
|
70
|
+
|
|
71
|
+
### Full-featured project
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
npm create velocity-astro@latest my-site --demo --components --i18n
|
|
75
|
+
```
|
|
51
76
|
|
|
52
77
|
### Skip prompts with defaults
|
|
53
78
|
|
package/dist/index.js
CHANGED
|
@@ -63,27 +63,59 @@ function getInstallCommand(pm) {
|
|
|
63
63
|
}
|
|
64
64
|
|
|
65
65
|
// src/prompts.ts
|
|
66
|
-
async function runPrompts(
|
|
66
|
+
async function runPrompts(defaults = {}) {
|
|
67
67
|
const detectedPm = detectPackageManager();
|
|
68
68
|
const answers = await p.group(
|
|
69
69
|
{
|
|
70
70
|
projectName: () => p.text({
|
|
71
71
|
message: "What is your project name?",
|
|
72
|
-
placeholder:
|
|
73
|
-
defaultValue:
|
|
72
|
+
placeholder: defaults.projectName || "my-velocity-site",
|
|
73
|
+
defaultValue: defaults.projectName,
|
|
74
74
|
validate: (value) => {
|
|
75
|
-
const name = value ||
|
|
75
|
+
const name = value || defaults.projectName || "my-velocity-site";
|
|
76
76
|
const result = validateProjectName(toValidProjectName(name));
|
|
77
77
|
if (!result.valid) return result.message;
|
|
78
78
|
}
|
|
79
79
|
}),
|
|
80
|
-
|
|
80
|
+
demo: defaults.demo !== void 0 ? () => Promise.resolve(defaults.demo) : () => p.select({
|
|
81
|
+
message: "Include demo landing page and sample content?",
|
|
82
|
+
options: [
|
|
83
|
+
{
|
|
84
|
+
value: false,
|
|
85
|
+
label: "No",
|
|
86
|
+
hint: "Minimal starter with basic pages"
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
value: true,
|
|
90
|
+
label: "Yes",
|
|
91
|
+
hint: "Full demo with landing page, blog posts"
|
|
92
|
+
}
|
|
93
|
+
],
|
|
94
|
+
initialValue: false
|
|
95
|
+
}),
|
|
96
|
+
components: defaults.components !== void 0 ? () => Promise.resolve(defaults.components) : () => p.select({
|
|
97
|
+
message: "Include UI component library?",
|
|
98
|
+
options: [
|
|
99
|
+
{
|
|
100
|
+
value: false,
|
|
101
|
+
label: "No",
|
|
102
|
+
hint: "Just the basics"
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
value: true,
|
|
106
|
+
label: "Yes",
|
|
107
|
+
hint: "Buttons, forms, cards, dialogs, etc."
|
|
108
|
+
}
|
|
109
|
+
],
|
|
110
|
+
initialValue: true
|
|
111
|
+
}),
|
|
112
|
+
i18n: defaults.i18n !== void 0 ? () => Promise.resolve(defaults.i18n) : () => p.select({
|
|
81
113
|
message: "Add internationalization (i18n)?",
|
|
82
114
|
options: [
|
|
83
115
|
{
|
|
84
116
|
value: false,
|
|
85
117
|
label: "No",
|
|
86
|
-
hint: "English only
|
|
118
|
+
hint: "English only"
|
|
87
119
|
},
|
|
88
120
|
{
|
|
89
121
|
value: true,
|
|
@@ -128,7 +160,9 @@ async function runPrompts(defaultProjectName, defaultI18n) {
|
|
|
128
160
|
}
|
|
129
161
|
);
|
|
130
162
|
return {
|
|
131
|
-
projectName: toValidProjectName(answers.projectName ||
|
|
163
|
+
projectName: toValidProjectName(answers.projectName || defaults.projectName || "my-velocity-site"),
|
|
164
|
+
demo: answers.demo,
|
|
165
|
+
components: answers.components,
|
|
132
166
|
i18n: answers.i18n,
|
|
133
167
|
packageManager: answers.packageManager
|
|
134
168
|
};
|
|
@@ -159,7 +193,7 @@ function showSuccess(message) {
|
|
|
159
193
|
}
|
|
160
194
|
|
|
161
195
|
// src/scaffold.ts
|
|
162
|
-
import { existsSync as existsSync2, mkdirSync, readdirSync, copyFileSync, readFileSync, writeFileSync,
|
|
196
|
+
import { existsSync as existsSync2, mkdirSync, readdirSync, copyFileSync, readFileSync, writeFileSync, rmSync } from "fs";
|
|
163
197
|
import { join } from "path";
|
|
164
198
|
import * as p2 from "@clack/prompts";
|
|
165
199
|
import { execa as execa2 } from "execa";
|
|
@@ -170,26 +204,13 @@ import { existsSync } from "fs";
|
|
|
170
204
|
import { resolve, dirname } from "path";
|
|
171
205
|
import { fileURLToPath } from "url";
|
|
172
206
|
var __dirname2 = dirname(fileURLToPath(import.meta.url));
|
|
173
|
-
|
|
174
|
-
"
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
".
|
|
179
|
-
|
|
180
|
-
".wrangler",
|
|
181
|
-
"pnpm-lock.yaml",
|
|
182
|
-
"package-lock.json",
|
|
183
|
-
"yarn.lock",
|
|
184
|
-
"bun.lockb",
|
|
185
|
-
"packages",
|
|
186
|
-
"pnpm-workspace.yaml",
|
|
187
|
-
".claude",
|
|
188
|
-
".playwright-mcp",
|
|
189
|
-
"southwell-astro-boilerplate-docs.md",
|
|
190
|
-
"southwell-astro-boilerplate-prd.md",
|
|
191
|
-
"nul"
|
|
192
|
-
];
|
|
207
|
+
function getBaseTemplatePath() {
|
|
208
|
+
const templatePath = resolve(__dirname2, "..", "templates", "base");
|
|
209
|
+
if (existsSync(templatePath)) {
|
|
210
|
+
return templatePath;
|
|
211
|
+
}
|
|
212
|
+
throw new Error("Could not find base template. Package may be corrupted.");
|
|
213
|
+
}
|
|
193
214
|
function getI18nTemplatePath() {
|
|
194
215
|
const templatePath = resolve(__dirname2, "..", "templates", "i18n");
|
|
195
216
|
if (existsSync(templatePath)) {
|
|
@@ -214,29 +235,49 @@ async function initGit(targetDir) {
|
|
|
214
235
|
}
|
|
215
236
|
|
|
216
237
|
// src/scaffold.ts
|
|
217
|
-
var TEMPLATE_REPO = "github:
|
|
218
|
-
|
|
238
|
+
var TEMPLATE_REPO = "github:southwellmedia-dev/velocity";
|
|
239
|
+
var CLEANUP_ITEMS = [
|
|
240
|
+
"pnpm-lock.yaml",
|
|
241
|
+
"package-lock.json",
|
|
242
|
+
"yarn.lock",
|
|
243
|
+
"bun.lockb",
|
|
244
|
+
".git"
|
|
245
|
+
];
|
|
246
|
+
var DEMO_CONTENT = [
|
|
247
|
+
"src/components/landing",
|
|
248
|
+
"src/pages/about.astro",
|
|
249
|
+
"src/pages/contact.astro",
|
|
250
|
+
"src/content/blog",
|
|
251
|
+
"src/content/faqs",
|
|
252
|
+
"src/content/authors",
|
|
253
|
+
"src/content/pages"
|
|
254
|
+
];
|
|
255
|
+
var COMPONENTS_CONTENT = [
|
|
256
|
+
"src/components/ui",
|
|
257
|
+
"src/components/patterns",
|
|
258
|
+
"src/pages/components.astro"
|
|
259
|
+
];
|
|
260
|
+
function copyTemplateFiles(src, dest) {
|
|
219
261
|
if (!existsSync2(dest)) {
|
|
220
262
|
mkdirSync(dest, { recursive: true });
|
|
221
263
|
}
|
|
222
264
|
const entries = readdirSync(src, { withFileTypes: true });
|
|
223
265
|
for (const entry of entries) {
|
|
224
|
-
if (ignore.includes(entry.name)) continue;
|
|
225
266
|
const srcPath = join(src, entry.name);
|
|
226
267
|
const destPath = join(dest, entry.name);
|
|
227
268
|
if (entry.isDirectory()) {
|
|
228
|
-
copyTemplateFiles(srcPath, destPath
|
|
269
|
+
copyTemplateFiles(srcPath, destPath);
|
|
229
270
|
} else {
|
|
230
271
|
copyFileSync(srcPath, destPath);
|
|
231
272
|
}
|
|
232
273
|
}
|
|
233
274
|
}
|
|
234
|
-
function
|
|
235
|
-
for (const item of
|
|
275
|
+
function removeItems(targetDir, items) {
|
|
276
|
+
for (const item of items) {
|
|
236
277
|
const itemPath = join(targetDir, item);
|
|
237
278
|
if (existsSync2(itemPath)) {
|
|
238
279
|
try {
|
|
239
|
-
|
|
280
|
+
rmSync(itemPath, { recursive: true, force: true });
|
|
240
281
|
} catch {
|
|
241
282
|
}
|
|
242
283
|
}
|
|
@@ -255,12 +296,30 @@ function updatePackageJson(targetDir, projectName) {
|
|
|
255
296
|
delete pkg.homepage;
|
|
256
297
|
writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + "\n");
|
|
257
298
|
}
|
|
299
|
+
function applyBaseTemplate(targetDir) {
|
|
300
|
+
const baseTemplate = getBaseTemplatePath();
|
|
301
|
+
if (existsSync2(baseTemplate)) {
|
|
302
|
+
copyTemplateFiles(baseTemplate, targetDir);
|
|
303
|
+
}
|
|
304
|
+
}
|
|
258
305
|
function applyI18nOverlay(targetDir) {
|
|
259
306
|
const i18nTemplate = getI18nTemplatePath();
|
|
260
|
-
copyTemplateFiles(i18nTemplate, targetDir
|
|
307
|
+
copyTemplateFiles(i18nTemplate, targetDir);
|
|
308
|
+
}
|
|
309
|
+
function createContentDirectories(targetDir) {
|
|
310
|
+
const contentDirs = [
|
|
311
|
+
"src/content/blog"
|
|
312
|
+
];
|
|
313
|
+
for (const dir of contentDirs) {
|
|
314
|
+
const dirPath = join(targetDir, dir);
|
|
315
|
+
if (!existsSync2(dirPath)) {
|
|
316
|
+
mkdirSync(dirPath, { recursive: true });
|
|
317
|
+
writeFileSync(join(dirPath, ".gitkeep"), "");
|
|
318
|
+
}
|
|
319
|
+
}
|
|
261
320
|
}
|
|
262
321
|
async function scaffold(options) {
|
|
263
|
-
const { projectName, targetDir, i18n, packageManager } = options;
|
|
322
|
+
const { projectName, targetDir, demo, components, i18n, packageManager } = options;
|
|
264
323
|
const spinner2 = p2.spinner();
|
|
265
324
|
spinner2.start("Downloading template from GitHub...");
|
|
266
325
|
try {
|
|
@@ -268,7 +327,7 @@ async function scaffold(options) {
|
|
|
268
327
|
dir: targetDir,
|
|
269
328
|
force: true
|
|
270
329
|
});
|
|
271
|
-
|
|
330
|
+
removeItems(targetDir, CLEANUP_ITEMS);
|
|
272
331
|
spinner2.stop("Template downloaded");
|
|
273
332
|
} catch (error) {
|
|
274
333
|
spinner2.stop("Failed to download template");
|
|
@@ -277,6 +336,18 @@ async function scaffold(options) {
|
|
|
277
336
|
${error instanceof Error ? error.message : ""}`
|
|
278
337
|
);
|
|
279
338
|
}
|
|
339
|
+
if (!demo) {
|
|
340
|
+
spinner2.start("Configuring minimal template...");
|
|
341
|
+
removeItems(targetDir, DEMO_CONTENT);
|
|
342
|
+
applyBaseTemplate(targetDir);
|
|
343
|
+
createContentDirectories(targetDir);
|
|
344
|
+
spinner2.stop("Minimal template configured");
|
|
345
|
+
}
|
|
346
|
+
if (!components) {
|
|
347
|
+
spinner2.start("Removing UI component library...");
|
|
348
|
+
removeItems(targetDir, COMPONENTS_CONTENT);
|
|
349
|
+
spinner2.stop("UI components removed");
|
|
350
|
+
}
|
|
280
351
|
if (i18n) {
|
|
281
352
|
spinner2.start("Adding i18n support...");
|
|
282
353
|
try {
|
|
@@ -335,6 +406,8 @@ ${pc2.bold("Usage:")}
|
|
|
335
406
|
bun create velocity-astro [project-name] [options]
|
|
336
407
|
|
|
337
408
|
${pc2.bold("Options:")}
|
|
409
|
+
--demo Include demo landing page and sample content
|
|
410
|
+
--components Include UI component library
|
|
338
411
|
--i18n Add internationalization support
|
|
339
412
|
--yes, -y Skip prompts and use defaults
|
|
340
413
|
--help, -h Show this help message
|
|
@@ -342,13 +415,14 @@ ${pc2.bold("Options:")}
|
|
|
342
415
|
|
|
343
416
|
${pc2.bold("Examples:")}
|
|
344
417
|
npm create velocity-astro@latest my-site
|
|
418
|
+
npm create velocity-astro@latest my-site --demo --components
|
|
345
419
|
npm create velocity-astro@latest my-site --i18n
|
|
346
420
|
pnpm create velocity-astro my-site -y
|
|
347
421
|
`;
|
|
348
|
-
var VERSION = "1.0.
|
|
422
|
+
var VERSION = "1.0.3";
|
|
349
423
|
async function run(argv) {
|
|
350
424
|
const args = mri(argv, {
|
|
351
|
-
boolean: ["i18n", "help", "version", "yes"],
|
|
425
|
+
boolean: ["demo", "components", "i18n", "help", "version", "yes"],
|
|
352
426
|
alias: {
|
|
353
427
|
h: "help",
|
|
354
428
|
v: "version",
|
|
@@ -375,17 +449,25 @@ async function run(argv) {
|
|
|
375
449
|
await scaffold({
|
|
376
450
|
projectName: projectName2,
|
|
377
451
|
targetDir: targetDir2,
|
|
452
|
+
demo: args.demo || false,
|
|
453
|
+
components: args.components !== false,
|
|
454
|
+
// Default to true
|
|
378
455
|
i18n: args.i18n || false,
|
|
379
456
|
packageManager: "pnpm"
|
|
380
457
|
});
|
|
381
458
|
showOutro(projectName2, "pnpm");
|
|
382
459
|
return;
|
|
383
460
|
}
|
|
384
|
-
const answers = await runPrompts(
|
|
461
|
+
const answers = await runPrompts({
|
|
462
|
+
projectName: argProjectName,
|
|
463
|
+
demo: args.demo,
|
|
464
|
+
components: args.components,
|
|
465
|
+
i18n: args.i18n
|
|
466
|
+
});
|
|
385
467
|
if (typeof answers === "symbol") {
|
|
386
468
|
return;
|
|
387
469
|
}
|
|
388
|
-
const { projectName, i18n, packageManager } = answers;
|
|
470
|
+
const { projectName, demo, components, i18n, packageManager } = answers;
|
|
389
471
|
const targetDir = resolve2(process.cwd(), projectName);
|
|
390
472
|
if (existsSync4(targetDir) && !isEmptyDir(targetDir)) {
|
|
391
473
|
const shouldOverwrite = await p3.confirm({
|
|
@@ -401,6 +483,8 @@ async function run(argv) {
|
|
|
401
483
|
await scaffold({
|
|
402
484
|
projectName,
|
|
403
485
|
targetDir,
|
|
486
|
+
demo,
|
|
487
|
+
components,
|
|
404
488
|
i18n,
|
|
405
489
|
packageManager
|
|
406
490
|
});
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/cli.ts","../src/prompts.ts","../src/utils/validate.ts","../src/utils/package-manager.ts","../src/scaffold.ts","../src/template.ts","../src/utils/git.ts","../src/utils/fs.ts","../src/index.ts"],"sourcesContent":["import mri from 'mri';\nimport { resolve } from 'node:path';\nimport { existsSync } from 'node:fs';\nimport * as p from '@clack/prompts';\nimport pc from 'picocolors';\nimport type { CliOptions } from './types.js';\nimport { runPrompts, showIntro, showOutro, showError } from './prompts.js';\nimport { scaffold } from './scaffold.js';\nimport { isEmptyDir } from './utils/fs.js';\nimport { toValidProjectName } from './utils/validate.js';\n\nconst HELP_TEXT = `\n${pc.bold('create-velocity-astro')} - Create a new Velocity project\n\n${pc.bold('Usage:')}\n npm create velocity-astro@latest [project-name] [options]\n pnpm create velocity-astro [project-name] [options]\n yarn create velocity-astro [project-name] [options]\n bun create velocity-astro [project-name] [options]\n\n${pc.bold('Options:')}\n --i18n Add internationalization support\n --yes, -y Skip prompts and use defaults\n --help, -h Show this help message\n --version, -v Show version number\n\n${pc.bold('Examples:')}\n npm create velocity-astro@latest my-site\n npm create velocity-astro@latest my-site --i18n\n pnpm create velocity-astro my-site -y\n`;\n\nconst VERSION = '1.0.0';\n\nexport async function run(argv: string[]): Promise<void> {\n const args = mri<CliOptions>(argv, {\n boolean: ['i18n', 'help', 'version', 'yes'],\n alias: {\n h: 'help',\n v: 'version',\n y: 'yes',\n },\n });\n\n // Handle help\n if (args.help) {\n console.log(HELP_TEXT);\n return;\n }\n\n // Handle version\n if (args.version) {\n console.log(VERSION);\n return;\n }\n\n showIntro();\n\n // Get project name from args or prompt\n const argProjectName = args._[0] as string | undefined;\n\n // Skip prompts mode\n if (args.yes) {\n const projectName = toValidProjectName(argProjectName || 'my-velocity-site');\n const targetDir = resolve(process.cwd(), projectName);\n\n if (existsSync(targetDir) && !isEmptyDir(targetDir)) {\n showError(`Directory \"${projectName}\" already exists and is not empty.`);\n process.exit(1);\n }\n\n await scaffold({\n projectName,\n targetDir,\n i18n: args.i18n || false,\n packageManager: 'pnpm',\n });\n\n showOutro(projectName, 'pnpm');\n return;\n }\n\n // Interactive mode\n const answers = await runPrompts(argProjectName, args.i18n);\n\n // User cancelled\n if (typeof answers === 'symbol') {\n return;\n }\n\n const { projectName, i18n, packageManager } = answers;\n const targetDir = resolve(process.cwd(), projectName);\n\n // Check if directory exists and is not empty\n if (existsSync(targetDir) && !isEmptyDir(targetDir)) {\n const shouldOverwrite = await p.confirm({\n message: `Directory \"${projectName}\" already exists. Continue and overwrite?`,\n initialValue: false,\n });\n\n if (!shouldOverwrite || p.isCancel(shouldOverwrite)) {\n p.cancel('Operation cancelled.');\n process.exit(0);\n }\n }\n\n // Run scaffold\n try {\n await scaffold({\n projectName,\n targetDir,\n i18n,\n packageManager,\n });\n\n showOutro(projectName, packageManager);\n } catch (error) {\n showError(error instanceof Error ? error.message : 'An unexpected error occurred');\n process.exit(1);\n }\n}\n","import * as p from '@clack/prompts';\nimport pc from 'picocolors';\nimport type { PackageManager, PromptAnswers } from './types.js';\nimport { validateProjectName, toValidProjectName } from './utils/validate.js';\nimport { detectPackageManager } from './utils/package-manager.js';\n\nexport async function runPrompts(\n defaultProjectName?: string,\n defaultI18n?: boolean\n): Promise<PromptAnswers | symbol> {\n const detectedPm = detectPackageManager();\n\n const answers = await p.group(\n {\n projectName: () =>\n p.text({\n message: 'What is your project name?',\n placeholder: defaultProjectName || 'my-velocity-site',\n defaultValue: defaultProjectName,\n validate: (value) => {\n const name = value || defaultProjectName || 'my-velocity-site';\n const result = validateProjectName(toValidProjectName(name));\n if (!result.valid) return result.message;\n },\n }),\n\n i18n:\n defaultI18n !== undefined\n ? () => Promise.resolve(defaultI18n)\n : () =>\n p.select({\n message: 'Add internationalization (i18n)?',\n options: [\n {\n value: false,\n label: 'No',\n hint: 'English only (default)',\n },\n {\n value: true,\n label: 'Yes',\n hint: 'Locale routing, translations',\n },\n ],\n initialValue: false,\n }),\n\n packageManager: () =>\n p.select({\n message: 'Which package manager?',\n options: [\n {\n value: 'pnpm' as PackageManager,\n label: 'pnpm',\n hint: detectedPm === 'pnpm' ? 'detected' : 'recommended',\n },\n {\n value: 'npm' as PackageManager,\n label: 'npm',\n hint: detectedPm === 'npm' ? 'detected' : undefined,\n },\n {\n value: 'yarn' as PackageManager,\n label: 'yarn',\n hint: detectedPm === 'yarn' ? 'detected' : undefined,\n },\n {\n value: 'bun' as PackageManager,\n label: 'bun',\n hint: detectedPm === 'bun' ? 'detected' : undefined,\n },\n ],\n initialValue: detectedPm,\n }),\n },\n {\n onCancel: () => {\n p.cancel('Operation cancelled.');\n process.exit(0);\n },\n }\n );\n\n return {\n projectName: toValidProjectName(answers.projectName || defaultProjectName || 'my-velocity-site'),\n i18n: answers.i18n as boolean,\n packageManager: answers.packageManager as PackageManager,\n };\n}\n\nexport function showIntro(): void {\n console.log();\n p.intro(pc.bgCyan(pc.black(' Create Velocity ')));\n}\n\nexport function showOutro(projectName: string, packageManager: PackageManager): void {\n const runCmd = packageManager === 'npm' ? 'npm run' : packageManager;\n\n p.note(\n [\n `cd ${projectName}`,\n `${runCmd} dev`,\n ].join('\\n'),\n 'Next steps'\n );\n\n p.outro(pc.green('Happy building!'));\n}\n\nexport function showError(message: string): void {\n p.log.error(pc.red(message));\n}\n\nexport function showWarning(message: string): void {\n p.log.warn(pc.yellow(message));\n}\n\nexport function showSuccess(message: string): void {\n p.log.success(pc.green(message));\n}\n\nexport function showStep(message: string): void {\n p.log.step(message);\n}\n","/**\n * Validates a project name for npm package naming conventions\n */\nexport function validateProjectName(name: string): { valid: boolean; message?: string } {\n if (!name || name.trim() === '') {\n return { valid: false, message: 'Project name cannot be empty' };\n }\n\n // Must be lowercase\n if (name !== name.toLowerCase()) {\n return { valid: false, message: 'Project name must be lowercase' };\n }\n\n // Cannot start with . or _\n if (name.startsWith('.') || name.startsWith('_')) {\n return { valid: false, message: 'Project name cannot start with . or _' };\n }\n\n // Cannot contain spaces\n if (/\\s/.test(name)) {\n return { valid: false, message: 'Project name cannot contain spaces' };\n }\n\n // Cannot contain special characters except - and @/\n if (!/^(@[a-z0-9-~][a-z0-9-._~]*\\/)?[a-z0-9-~][a-z0-9-._~]*$/.test(name)) {\n return {\n valid: false,\n message: 'Project name can only contain lowercase letters, numbers, hyphens, and underscores',\n };\n }\n\n // Length check\n if (name.length > 214) {\n return { valid: false, message: 'Project name must be 214 characters or fewer' };\n }\n\n return { valid: true };\n}\n\n/**\n * Sanitizes a string to be a valid project name\n */\nexport function toValidProjectName(name: string): string {\n return name\n .trim()\n .toLowerCase()\n .replace(/\\s+/g, '-')\n .replace(/[^a-z0-9-_~.]/g, '-')\n .replace(/^[-._]+/, '')\n .replace(/[-._]+$/, '')\n .replace(/-+/g, '-');\n}\n","import type { PackageManager } from '../types.js';\n\n/**\n * Detects the package manager used to run this command\n */\nexport function detectPackageManager(): PackageManager {\n const userAgent = process.env.npm_config_user_agent || '';\n\n if (userAgent.startsWith('pnpm')) return 'pnpm';\n if (userAgent.startsWith('yarn')) return 'yarn';\n if (userAgent.startsWith('bun')) return 'bun';\n return 'npm';\n}\n\n/**\n * Gets the install command for a package manager\n */\nexport function getInstallCommand(pm: PackageManager): string {\n switch (pm) {\n case 'pnpm':\n return 'pnpm install';\n case 'yarn':\n return 'yarn';\n case 'bun':\n return 'bun install';\n case 'npm':\n default:\n return 'npm install';\n }\n}\n\n/**\n * Gets the run command for a package manager\n */\nexport function getRunCommand(pm: PackageManager): string {\n switch (pm) {\n case 'pnpm':\n return 'pnpm';\n case 'yarn':\n return 'yarn';\n case 'bun':\n return 'bun';\n case 'npm':\n default:\n return 'npm run';\n }\n}\n","import { existsSync, mkdirSync, readdirSync, copyFileSync, readFileSync, writeFileSync, unlinkSync } from 'node:fs';\nimport { join } from 'node:path';\nimport * as p from '@clack/prompts';\nimport { execa } from 'execa';\nimport { downloadTemplate } from 'giget';\nimport type { ScaffoldOptions } from './types.js';\nimport { getI18nTemplatePath, TEMPLATE_IGNORE } from './template.js';\nimport { getInstallCommand } from './utils/package-manager.js';\nimport { initGit } from './utils/git.js';\nimport { showSuccess, showWarning } from './prompts.js';\n\n// GitHub repository for the Velocity template\nconst TEMPLATE_REPO = 'github:southwell-media/velocity';\n\n/**\n * Copies template files recursively, excluding ignored paths\n */\nfunction copyTemplateFiles(src: string, dest: string, ignore: string[]): void {\n if (!existsSync(dest)) {\n mkdirSync(dest, { recursive: true });\n }\n\n const entries = readdirSync(src, { withFileTypes: true });\n\n for (const entry of entries) {\n if (ignore.includes(entry.name)) continue;\n\n const srcPath = join(src, entry.name);\n const destPath = join(dest, entry.name);\n\n if (entry.isDirectory()) {\n copyTemplateFiles(srcPath, destPath, ignore);\n } else {\n copyFileSync(srcPath, destPath);\n }\n }\n}\n\n/**\n * Removes files/directories that shouldn't be in the template\n */\nfunction cleanupTemplate(targetDir: string): void {\n for (const item of TEMPLATE_IGNORE) {\n const itemPath = join(targetDir, item);\n if (existsSync(itemPath)) {\n try {\n // Try to remove file\n unlinkSync(itemPath);\n } catch {\n // If it's a directory, we'll leave it (rmSync would need recursive)\n // These are mostly already excluded by giget or don't exist\n }\n }\n }\n}\n\n/**\n * Updates the package.json with the new project name\n */\nfunction updatePackageJson(targetDir: string, projectName: string): void {\n const pkgPath = join(targetDir, 'package.json');\n\n if (!existsSync(pkgPath)) {\n throw new Error('package.json not found in template');\n }\n\n const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8'));\n pkg.name = projectName;\n pkg.version = '0.1.0';\n delete pkg.repository;\n delete pkg.bugs;\n delete pkg.homepage;\n\n writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + '\\n');\n}\n\n/**\n * Applies the i18n overlay to the project\n */\nfunction applyI18nOverlay(targetDir: string): void {\n const i18nTemplate = getI18nTemplatePath();\n copyTemplateFiles(i18nTemplate, targetDir, []);\n}\n\n/**\n * Main scaffold function\n */\nexport async function scaffold(options: ScaffoldOptions): Promise<void> {\n const { projectName, targetDir, i18n, packageManager } = options;\n const spinner = p.spinner();\n\n // Step 1: Download base template from GitHub\n spinner.start('Downloading template from GitHub...');\n\n try {\n await downloadTemplate(TEMPLATE_REPO, {\n dir: targetDir,\n force: true,\n });\n cleanupTemplate(targetDir);\n spinner.stop('Template downloaded');\n } catch (error) {\n spinner.stop('Failed to download template');\n throw new Error(\n `Could not download template from GitHub. Please check your internet connection.\\n${error instanceof Error ? error.message : ''}`\n );\n }\n\n // Step 2: Apply i18n overlay if requested\n if (i18n) {\n spinner.start('Adding i18n support...');\n try {\n applyI18nOverlay(targetDir);\n spinner.stop('i18n support added');\n } catch (error) {\n spinner.stop('Failed to add i18n support');\n throw error;\n }\n }\n\n // Step 3: Update package.json\n spinner.start('Configuring project...');\n try {\n updatePackageJson(targetDir, projectName);\n spinner.stop('Project configured');\n } catch (error) {\n spinner.stop('Failed to configure project');\n throw error;\n }\n\n // Step 4: Initialize git\n spinner.start('Initializing git repository...');\n const gitInitialized = await initGit(targetDir);\n if (gitInitialized) {\n spinner.stop('Git repository initialized');\n } else {\n spinner.stop('Git not available, skipping');\n }\n\n // Step 5: Install dependencies\n spinner.start(`Installing dependencies with ${packageManager}...`);\n try {\n const installCmd = getInstallCommand(packageManager);\n const [cmd, ...args] = installCmd.split(' ');\n await execa(cmd!, args, { cwd: targetDir });\n spinner.stop('Dependencies installed');\n } catch {\n spinner.stop('Failed to install dependencies');\n showWarning(`Run \"${getInstallCommand(packageManager)}\" manually to install dependencies`);\n }\n\n showSuccess(`Project \"${projectName}\" created successfully!`);\n}\n","import { existsSync } from 'node:fs';\nimport { resolve, dirname } from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nconst __dirname = dirname(fileURLToPath(import.meta.url));\n\n/**\n * Files and directories to exclude/remove from the downloaded template\n */\nexport const TEMPLATE_IGNORE = [\n 'node_modules',\n '.git',\n 'dist',\n '.astro',\n '.vercel',\n '.netlify',\n '.wrangler',\n 'pnpm-lock.yaml',\n 'package-lock.json',\n 'yarn.lock',\n 'bun.lockb',\n 'packages',\n 'pnpm-workspace.yaml',\n '.claude',\n '.playwright-mcp',\n 'southwell-astro-boilerplate-docs.md',\n 'southwell-astro-boilerplate-prd.md',\n 'nul',\n];\n\n/**\n * Resolves the path to the i18n overlay template\n */\nexport function getI18nTemplatePath(): string {\n // In the package templates directory\n const templatePath = resolve(__dirname, '..', 'templates', 'i18n');\n\n if (existsSync(templatePath)) {\n return templatePath;\n }\n\n throw new Error('Could not find i18n template. Package may be corrupted.');\n}\n","import { execa } from 'execa';\n\n/**\n * Initializes a git repository in the target directory\n */\nexport async function initGit(targetDir: string): Promise<boolean> {\n try {\n await execa('git', ['init'], { cwd: targetDir });\n await execa('git', ['add', '-A'], { cwd: targetDir });\n await execa('git', ['commit', '-m', 'Initial commit from create-velocity'], {\n cwd: targetDir,\n });\n return true;\n } catch {\n // Git may not be installed or configured\n return false;\n }\n}\n\n/**\n * Checks if git is available\n */\nexport async function isGitInstalled(): Promise<boolean> {\n try {\n await execa('git', ['--version']);\n return true;\n } catch {\n return false;\n }\n}\n","import { existsSync, mkdirSync, readdirSync, statSync, copyFileSync, readFileSync, writeFileSync } from 'node:fs';\nimport { join, dirname } from 'node:path';\n\n/**\n * Recursively copies a directory\n */\nexport function copyDirectory(src: string, dest: string, overwrite = false): void {\n if (!existsSync(src)) {\n throw new Error(`Source directory does not exist: ${src}`);\n }\n\n if (!existsSync(dest)) {\n mkdirSync(dest, { recursive: true });\n }\n\n const entries = readdirSync(src, { withFileTypes: true });\n\n for (const entry of entries) {\n const srcPath = join(src, entry.name);\n const destPath = join(dest, entry.name);\n\n if (entry.isDirectory()) {\n copyDirectory(srcPath, destPath, overwrite);\n } else {\n if (overwrite || !existsSync(destPath)) {\n const destDir = dirname(destPath);\n if (!existsSync(destDir)) {\n mkdirSync(destDir, { recursive: true });\n }\n copyFileSync(srcPath, destPath);\n }\n }\n }\n}\n\n/**\n * Checks if a directory is empty\n */\nexport function isEmptyDir(path: string): boolean {\n if (!existsSync(path)) return true;\n const files = readdirSync(path);\n return files.length === 0 || (files.length === 1 && files[0] === '.git');\n}\n\n/**\n * Reads a JSON file and parses it\n */\nexport function readJson<T = Record<string, unknown>>(path: string): T {\n const content = readFileSync(path, 'utf-8');\n return JSON.parse(content) as T;\n}\n\n/**\n * Writes an object as JSON to a file\n */\nexport function writeJson(path: string, data: unknown): void {\n writeFileSync(path, JSON.stringify(data, null, 2) + '\\n');\n}\n\n/**\n * Checks if path exists and is a directory\n */\nexport function isDirectory(path: string): boolean {\n return existsSync(path) && statSync(path).isDirectory();\n}\n","import { run } from './cli.js';\n\nrun(process.argv.slice(2)).catch((error) => {\n console.error(error);\n process.exit(1);\n});\n"],"mappings":"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","names":["resolve","existsSync","p","pc","existsSync","p","execa","__dirname","existsSync","spinner","execa","existsSync","mkdirSync","readdirSync","copyFileSync","readFileSync","writeFileSync","join","dirname","existsSync","readdirSync","pc","projectName","targetDir","resolve","existsSync"]}
|
|
1
|
+
{"version":3,"sources":["../src/cli.ts","../src/prompts.ts","../src/utils/validate.ts","../src/utils/package-manager.ts","../src/scaffold.ts","../src/template.ts","../src/utils/git.ts","../src/utils/fs.ts","../src/index.ts"],"sourcesContent":["import mri from 'mri';\nimport { resolve } from 'node:path';\nimport { existsSync } from 'node:fs';\nimport * as p from '@clack/prompts';\nimport pc from 'picocolors';\nimport type { CliOptions } from './types.js';\nimport { runPrompts, showIntro, showOutro, showError } from './prompts.js';\nimport { scaffold } from './scaffold.js';\nimport { isEmptyDir } from './utils/fs.js';\nimport { toValidProjectName } from './utils/validate.js';\n\nconst HELP_TEXT = `\n${pc.bold('create-velocity-astro')} - Create a new Velocity project\n\n${pc.bold('Usage:')}\n npm create velocity-astro@latest [project-name] [options]\n pnpm create velocity-astro [project-name] [options]\n yarn create velocity-astro [project-name] [options]\n bun create velocity-astro [project-name] [options]\n\n${pc.bold('Options:')}\n --demo Include demo landing page and sample content\n --components Include UI component library\n --i18n Add internationalization support\n --yes, -y Skip prompts and use defaults\n --help, -h Show this help message\n --version, -v Show version number\n\n${pc.bold('Examples:')}\n npm create velocity-astro@latest my-site\n npm create velocity-astro@latest my-site --demo --components\n npm create velocity-astro@latest my-site --i18n\n pnpm create velocity-astro my-site -y\n`;\n\nconst VERSION = '1.0.3';\n\nexport async function run(argv: string[]): Promise<void> {\n const args = mri<CliOptions>(argv, {\n boolean: ['demo', 'components', 'i18n', 'help', 'version', 'yes'],\n alias: {\n h: 'help',\n v: 'version',\n y: 'yes',\n },\n });\n\n // Handle help\n if (args.help) {\n console.log(HELP_TEXT);\n return;\n }\n\n // Handle version\n if (args.version) {\n console.log(VERSION);\n return;\n }\n\n showIntro();\n\n // Get project name from args or prompt\n const argProjectName = args._[0] as string | undefined;\n\n // Skip prompts mode\n if (args.yes) {\n const projectName = toValidProjectName(argProjectName || 'my-velocity-site');\n const targetDir = resolve(process.cwd(), projectName);\n\n if (existsSync(targetDir) && !isEmptyDir(targetDir)) {\n showError(`Directory \"${projectName}\" already exists and is not empty.`);\n process.exit(1);\n }\n\n await scaffold({\n projectName,\n targetDir,\n demo: args.demo || false,\n components: args.components !== false, // Default to true\n i18n: args.i18n || false,\n packageManager: 'pnpm',\n });\n\n showOutro(projectName, 'pnpm');\n return;\n }\n\n // Interactive mode\n const answers = await runPrompts({\n projectName: argProjectName,\n demo: args.demo,\n components: args.components,\n i18n: args.i18n,\n });\n\n // User cancelled\n if (typeof answers === 'symbol') {\n return;\n }\n\n const { projectName, demo, components, i18n, packageManager } = answers;\n const targetDir = resolve(process.cwd(), projectName);\n\n // Check if directory exists and is not empty\n if (existsSync(targetDir) && !isEmptyDir(targetDir)) {\n const shouldOverwrite = await p.confirm({\n message: `Directory \"${projectName}\" already exists. Continue and overwrite?`,\n initialValue: false,\n });\n\n if (!shouldOverwrite || p.isCancel(shouldOverwrite)) {\n p.cancel('Operation cancelled.');\n process.exit(0);\n }\n }\n\n // Run scaffold\n try {\n await scaffold({\n projectName,\n targetDir,\n demo,\n components,\n i18n,\n packageManager,\n });\n\n showOutro(projectName, packageManager);\n } catch (error) {\n showError(error instanceof Error ? error.message : 'An unexpected error occurred');\n process.exit(1);\n }\n}\n","import * as p from '@clack/prompts';\nimport pc from 'picocolors';\nimport type { PackageManager, PromptAnswers } from './types.js';\nimport { validateProjectName, toValidProjectName } from './utils/validate.js';\nimport { detectPackageManager } from './utils/package-manager.js';\n\ninterface PromptDefaults {\n projectName?: string;\n demo?: boolean;\n components?: boolean;\n i18n?: boolean;\n}\n\nexport async function runPrompts(defaults: PromptDefaults = {}): Promise<PromptAnswers | symbol> {\n const detectedPm = detectPackageManager();\n\n const answers = await p.group(\n {\n projectName: () =>\n p.text({\n message: 'What is your project name?',\n placeholder: defaults.projectName || 'my-velocity-site',\n defaultValue: defaults.projectName,\n validate: (value) => {\n const name = value || defaults.projectName || 'my-velocity-site';\n const result = validateProjectName(toValidProjectName(name));\n if (!result.valid) return result.message;\n },\n }),\n\n demo:\n defaults.demo !== undefined\n ? () => Promise.resolve(defaults.demo)\n : () =>\n p.select({\n message: 'Include demo landing page and sample content?',\n options: [\n {\n value: false,\n label: 'No',\n hint: 'Minimal starter with basic pages',\n },\n {\n value: true,\n label: 'Yes',\n hint: 'Full demo with landing page, blog posts',\n },\n ],\n initialValue: false,\n }),\n\n components:\n defaults.components !== undefined\n ? () => Promise.resolve(defaults.components)\n : () =>\n p.select({\n message: 'Include UI component library?',\n options: [\n {\n value: false,\n label: 'No',\n hint: 'Just the basics',\n },\n {\n value: true,\n label: 'Yes',\n hint: 'Buttons, forms, cards, dialogs, etc.',\n },\n ],\n initialValue: true,\n }),\n\n i18n:\n defaults.i18n !== undefined\n ? () => Promise.resolve(defaults.i18n)\n : () =>\n p.select({\n message: 'Add internationalization (i18n)?',\n options: [\n {\n value: false,\n label: 'No',\n hint: 'English only',\n },\n {\n value: true,\n label: 'Yes',\n hint: 'Locale routing, translations',\n },\n ],\n initialValue: false,\n }),\n\n packageManager: () =>\n p.select({\n message: 'Which package manager?',\n options: [\n {\n value: 'pnpm' as PackageManager,\n label: 'pnpm',\n hint: detectedPm === 'pnpm' ? 'detected' : 'recommended',\n },\n {\n value: 'npm' as PackageManager,\n label: 'npm',\n hint: detectedPm === 'npm' ? 'detected' : undefined,\n },\n {\n value: 'yarn' as PackageManager,\n label: 'yarn',\n hint: detectedPm === 'yarn' ? 'detected' : undefined,\n },\n {\n value: 'bun' as PackageManager,\n label: 'bun',\n hint: detectedPm === 'bun' ? 'detected' : undefined,\n },\n ],\n initialValue: detectedPm,\n }),\n },\n {\n onCancel: () => {\n p.cancel('Operation cancelled.');\n process.exit(0);\n },\n }\n );\n\n return {\n projectName: toValidProjectName(answers.projectName || defaults.projectName || 'my-velocity-site'),\n demo: answers.demo as boolean,\n components: answers.components as boolean,\n i18n: answers.i18n as boolean,\n packageManager: answers.packageManager as PackageManager,\n };\n}\n\nexport function showIntro(): void {\n console.log();\n p.intro(pc.bgCyan(pc.black(' Create Velocity ')));\n}\n\nexport function showOutro(projectName: string, packageManager: PackageManager): void {\n const runCmd = packageManager === 'npm' ? 'npm run' : packageManager;\n\n p.note(\n [\n `cd ${projectName}`,\n `${runCmd} dev`,\n ].join('\\n'),\n 'Next steps'\n );\n\n p.outro(pc.green('Happy building!'));\n}\n\nexport function showError(message: string): void {\n p.log.error(pc.red(message));\n}\n\nexport function showWarning(message: string): void {\n p.log.warn(pc.yellow(message));\n}\n\nexport function showSuccess(message: string): void {\n p.log.success(pc.green(message));\n}\n\nexport function showStep(message: string): void {\n p.log.step(message);\n}\n","/**\n * Validates a project name for npm package naming conventions\n */\nexport function validateProjectName(name: string): { valid: boolean; message?: string } {\n if (!name || name.trim() === '') {\n return { valid: false, message: 'Project name cannot be empty' };\n }\n\n // Must be lowercase\n if (name !== name.toLowerCase()) {\n return { valid: false, message: 'Project name must be lowercase' };\n }\n\n // Cannot start with . or _\n if (name.startsWith('.') || name.startsWith('_')) {\n return { valid: false, message: 'Project name cannot start with . or _' };\n }\n\n // Cannot contain spaces\n if (/\\s/.test(name)) {\n return { valid: false, message: 'Project name cannot contain spaces' };\n }\n\n // Cannot contain special characters except - and @/\n if (!/^(@[a-z0-9-~][a-z0-9-._~]*\\/)?[a-z0-9-~][a-z0-9-._~]*$/.test(name)) {\n return {\n valid: false,\n message: 'Project name can only contain lowercase letters, numbers, hyphens, and underscores',\n };\n }\n\n // Length check\n if (name.length > 214) {\n return { valid: false, message: 'Project name must be 214 characters or fewer' };\n }\n\n return { valid: true };\n}\n\n/**\n * Sanitizes a string to be a valid project name\n */\nexport function toValidProjectName(name: string): string {\n return name\n .trim()\n .toLowerCase()\n .replace(/\\s+/g, '-')\n .replace(/[^a-z0-9-_~.]/g, '-')\n .replace(/^[-._]+/, '')\n .replace(/[-._]+$/, '')\n .replace(/-+/g, '-');\n}\n","import type { PackageManager } from '../types.js';\n\n/**\n * Detects the package manager used to run this command\n */\nexport function detectPackageManager(): PackageManager {\n const userAgent = process.env.npm_config_user_agent || '';\n\n if (userAgent.startsWith('pnpm')) return 'pnpm';\n if (userAgent.startsWith('yarn')) return 'yarn';\n if (userAgent.startsWith('bun')) return 'bun';\n return 'npm';\n}\n\n/**\n * Gets the install command for a package manager\n */\nexport function getInstallCommand(pm: PackageManager): string {\n switch (pm) {\n case 'pnpm':\n return 'pnpm install';\n case 'yarn':\n return 'yarn';\n case 'bun':\n return 'bun install';\n case 'npm':\n default:\n return 'npm install';\n }\n}\n\n/**\n * Gets the run command for a package manager\n */\nexport function getRunCommand(pm: PackageManager): string {\n switch (pm) {\n case 'pnpm':\n return 'pnpm';\n case 'yarn':\n return 'yarn';\n case 'bun':\n return 'bun';\n case 'npm':\n default:\n return 'npm run';\n }\n}\n","import { existsSync, mkdirSync, readdirSync, copyFileSync, readFileSync, writeFileSync, rmSync } from 'node:fs';\nimport { join } from 'node:path';\nimport * as p from '@clack/prompts';\nimport { execa } from 'execa';\nimport { downloadTemplate } from 'giget';\nimport type { ScaffoldOptions } from './types.js';\nimport { getI18nTemplatePath, getBaseTemplatePath } from './template.js';\nimport { getInstallCommand } from './utils/package-manager.js';\nimport { initGit } from './utils/git.js';\nimport { showSuccess, showWarning } from './prompts.js';\n\n// GitHub repository for the Velocity template\nconst TEMPLATE_REPO = 'github:southwellmedia-dev/velocity';\n\n// Files/directories to remove after download\nconst CLEANUP_ITEMS = [\n 'pnpm-lock.yaml',\n 'package-lock.json',\n 'yarn.lock',\n 'bun.lockb',\n '.git',\n];\n\n// Demo-specific content to remove when --demo is false\nconst DEMO_CONTENT = [\n 'src/components/landing',\n 'src/pages/about.astro',\n 'src/pages/contact.astro',\n 'src/content/blog',\n 'src/content/faqs',\n 'src/content/authors',\n 'src/content/pages',\n];\n\n// UI component library content to remove when --components is false\nconst COMPONENTS_CONTENT = [\n 'src/components/ui',\n 'src/components/patterns',\n 'src/pages/components.astro',\n];\n\n/**\n * Copies template files recursively\n */\nfunction copyTemplateFiles(src: string, dest: string): void {\n if (!existsSync(dest)) {\n mkdirSync(dest, { recursive: true });\n }\n\n const entries = readdirSync(src, { withFileTypes: true });\n\n for (const entry of entries) {\n const srcPath = join(src, entry.name);\n const destPath = join(dest, entry.name);\n\n if (entry.isDirectory()) {\n copyTemplateFiles(srcPath, destPath);\n } else {\n copyFileSync(srcPath, destPath);\n }\n }\n}\n\n/**\n * Removes files/directories from the target\n */\nfunction removeItems(targetDir: string, items: string[]): void {\n for (const item of items) {\n const itemPath = join(targetDir, item);\n if (existsSync(itemPath)) {\n try {\n rmSync(itemPath, { recursive: true, force: true });\n } catch {\n // Ignore errors - item may not exist or be locked\n }\n }\n }\n}\n\n/**\n * Updates the package.json with the new project name\n */\nfunction updatePackageJson(targetDir: string, projectName: string): void {\n const pkgPath = join(targetDir, 'package.json');\n\n if (!existsSync(pkgPath)) {\n throw new Error('package.json not found in template');\n }\n\n const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8'));\n pkg.name = projectName;\n pkg.version = '0.1.0';\n delete pkg.repository;\n delete pkg.bugs;\n delete pkg.homepage;\n\n writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + '\\n');\n}\n\n/**\n * Applies base template (minimal pages) when demo is not selected\n */\nfunction applyBaseTemplate(targetDir: string): void {\n const baseTemplate = getBaseTemplatePath();\n if (existsSync(baseTemplate)) {\n copyTemplateFiles(baseTemplate, targetDir);\n }\n}\n\n/**\n * Applies the i18n overlay to the project\n */\nfunction applyI18nOverlay(targetDir: string): void {\n const i18nTemplate = getI18nTemplatePath();\n copyTemplateFiles(i18nTemplate, targetDir);\n}\n\n/**\n * Creates empty content directories with .gitkeep files\n */\nfunction createContentDirectories(targetDir: string): void {\n const contentDirs = [\n 'src/content/blog',\n ];\n\n for (const dir of contentDirs) {\n const dirPath = join(targetDir, dir);\n if (!existsSync(dirPath)) {\n mkdirSync(dirPath, { recursive: true });\n writeFileSync(join(dirPath, '.gitkeep'), '');\n }\n }\n}\n\n/**\n * Main scaffold function\n */\nexport async function scaffold(options: ScaffoldOptions): Promise<void> {\n const { projectName, targetDir, demo, components, i18n, packageManager } = options;\n const spinner = p.spinner();\n\n // Step 1: Download base template from GitHub\n spinner.start('Downloading template from GitHub...');\n\n try {\n await downloadTemplate(TEMPLATE_REPO, {\n dir: targetDir,\n force: true,\n });\n removeItems(targetDir, CLEANUP_ITEMS);\n spinner.stop('Template downloaded');\n } catch (error) {\n spinner.stop('Failed to download template');\n throw new Error(\n `Could not download template from GitHub. Please check your internet connection.\\n${error instanceof Error ? error.message : ''}`\n );\n }\n\n // Step 2: Remove demo content if not requested\n if (!demo) {\n spinner.start('Configuring minimal template...');\n removeItems(targetDir, DEMO_CONTENT);\n applyBaseTemplate(targetDir);\n createContentDirectories(targetDir);\n spinner.stop('Minimal template configured');\n }\n\n // Step 3: Remove UI components if not requested\n if (!components) {\n spinner.start('Removing UI component library...');\n removeItems(targetDir, COMPONENTS_CONTENT);\n spinner.stop('UI components removed');\n }\n\n // Step 4: Apply i18n overlay if requested\n if (i18n) {\n spinner.start('Adding i18n support...');\n try {\n applyI18nOverlay(targetDir);\n spinner.stop('i18n support added');\n } catch (error) {\n spinner.stop('Failed to add i18n support');\n throw error;\n }\n }\n\n // Step 5: Update package.json\n spinner.start('Configuring project...');\n try {\n updatePackageJson(targetDir, projectName);\n spinner.stop('Project configured');\n } catch (error) {\n spinner.stop('Failed to configure project');\n throw error;\n }\n\n // Step 6: Initialize git\n spinner.start('Initializing git repository...');\n const gitInitialized = await initGit(targetDir);\n if (gitInitialized) {\n spinner.stop('Git repository initialized');\n } else {\n spinner.stop('Git not available, skipping');\n }\n\n // Step 7: Install dependencies\n spinner.start(`Installing dependencies with ${packageManager}...`);\n try {\n const installCmd = getInstallCommand(packageManager);\n const [cmd, ...args] = installCmd.split(' ');\n await execa(cmd!, args, { cwd: targetDir });\n spinner.stop('Dependencies installed');\n } catch {\n spinner.stop('Failed to install dependencies');\n showWarning(`Run \"${getInstallCommand(packageManager)}\" manually to install dependencies`);\n }\n\n showSuccess(`Project \"${projectName}\" created successfully!`);\n}\n","import { existsSync } from 'node:fs';\nimport { resolve, dirname } from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nconst __dirname = dirname(fileURLToPath(import.meta.url));\n\n/**\n * Resolves the path to the base template (minimal pages)\n */\nexport function getBaseTemplatePath(): string {\n const templatePath = resolve(__dirname, '..', 'templates', 'base');\n\n if (existsSync(templatePath)) {\n return templatePath;\n }\n\n throw new Error('Could not find base template. Package may be corrupted.');\n}\n\n/**\n * Resolves the path to the i18n overlay template\n */\nexport function getI18nTemplatePath(): string {\n const templatePath = resolve(__dirname, '..', 'templates', 'i18n');\n\n if (existsSync(templatePath)) {\n return templatePath;\n }\n\n throw new Error('Could not find i18n template. Package may be corrupted.');\n}\n","import { execa } from 'execa';\n\n/**\n * Initializes a git repository in the target directory\n */\nexport async function initGit(targetDir: string): Promise<boolean> {\n try {\n await execa('git', ['init'], { cwd: targetDir });\n await execa('git', ['add', '-A'], { cwd: targetDir });\n await execa('git', ['commit', '-m', 'Initial commit from create-velocity'], {\n cwd: targetDir,\n });\n return true;\n } catch {\n // Git may not be installed or configured\n return false;\n }\n}\n\n/**\n * Checks if git is available\n */\nexport async function isGitInstalled(): Promise<boolean> {\n try {\n await execa('git', ['--version']);\n return true;\n } catch {\n return false;\n }\n}\n","import { existsSync, mkdirSync, readdirSync, statSync, copyFileSync, readFileSync, writeFileSync } from 'node:fs';\nimport { join, dirname } from 'node:path';\n\n/**\n * Recursively copies a directory\n */\nexport function copyDirectory(src: string, dest: string, overwrite = false): void {\n if (!existsSync(src)) {\n throw new Error(`Source directory does not exist: ${src}`);\n }\n\n if (!existsSync(dest)) {\n mkdirSync(dest, { recursive: true });\n }\n\n const entries = readdirSync(src, { withFileTypes: true });\n\n for (const entry of entries) {\n const srcPath = join(src, entry.name);\n const destPath = join(dest, entry.name);\n\n if (entry.isDirectory()) {\n copyDirectory(srcPath, destPath, overwrite);\n } else {\n if (overwrite || !existsSync(destPath)) {\n const destDir = dirname(destPath);\n if (!existsSync(destDir)) {\n mkdirSync(destDir, { recursive: true });\n }\n copyFileSync(srcPath, destPath);\n }\n }\n }\n}\n\n/**\n * Checks if a directory is empty\n */\nexport function isEmptyDir(path: string): boolean {\n if (!existsSync(path)) return true;\n const files = readdirSync(path);\n return files.length === 0 || (files.length === 1 && files[0] === '.git');\n}\n\n/**\n * Reads a JSON file and parses it\n */\nexport function readJson<T = Record<string, unknown>>(path: string): T {\n const content = readFileSync(path, 'utf-8');\n return JSON.parse(content) as T;\n}\n\n/**\n * Writes an object as JSON to a file\n */\nexport function writeJson(path: string, data: unknown): void {\n writeFileSync(path, JSON.stringify(data, null, 2) + '\\n');\n}\n\n/**\n * Checks if path exists and is a directory\n */\nexport function isDirectory(path: string): boolean {\n return existsSync(path) && statSync(path).isDirectory();\n}\n","import { run } from './cli.js';\n\nrun(process.argv.slice(2)).catch((error) => {\n console.error(error);\n process.exit(1);\n});\n"],"mappings":"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","names":["resolve","existsSync","p","pc","existsSync","p","execa","__dirname","existsSync","spinner","execa","existsSync","mkdirSync","readdirSync","copyFileSync","readFileSync","writeFileSync","join","dirname","existsSync","readdirSync","pc","projectName","targetDir","resolve","existsSync"]}
|
package/package.json
CHANGED
|
@@ -1,18 +1,17 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-velocity-astro",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.4",
|
|
4
4
|
"description": "Create Velocity - A CLI to scaffold production-ready Astro 6 + Tailwind v4 projects",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"author": "Southwell Media <info@southwellmedia.com>",
|
|
8
|
-
"homepage": "https://github.com/
|
|
8
|
+
"homepage": "https://github.com/southwellmedia-dev/velocity#readme",
|
|
9
9
|
"repository": {
|
|
10
10
|
"type": "git",
|
|
11
|
-
"url": "git+https://github.com/
|
|
12
|
-
"directory": "packages/create-velocity"
|
|
11
|
+
"url": "git+https://github.com/southwellmedia-dev/velocity.git"
|
|
13
12
|
},
|
|
14
13
|
"bugs": {
|
|
15
|
-
"url": "https://github.com/
|
|
14
|
+
"url": "https://github.com/southwellmedia-dev/velocity/issues"
|
|
16
15
|
},
|
|
17
16
|
"keywords": [
|
|
18
17
|
"create",
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
---
|
|
2
|
+
import PageLayout from '@/layouts/PageLayout.astro';
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
<PageLayout
|
|
6
|
+
title="Page Not Found"
|
|
7
|
+
description="The page you're looking for doesn't exist."
|
|
8
|
+
noindex={true}
|
|
9
|
+
>
|
|
10
|
+
<section class="py-24 md:py-32">
|
|
11
|
+
<div class="container mx-auto px-4 text-center">
|
|
12
|
+
<p class="text-7xl font-bold text-primary">404</p>
|
|
13
|
+
<h1 class="mt-4 text-3xl font-bold tracking-tight sm:text-4xl">
|
|
14
|
+
Page not found
|
|
15
|
+
</h1>
|
|
16
|
+
<p class="mt-4 text-muted-foreground">
|
|
17
|
+
Sorry, we couldn't find the page you're looking for.
|
|
18
|
+
</p>
|
|
19
|
+
<div class="mt-8">
|
|
20
|
+
<a
|
|
21
|
+
href="/"
|
|
22
|
+
class="inline-flex items-center justify-center rounded-md bg-primary px-6 py-3 text-sm font-medium text-primary-foreground shadow transition-colors hover:bg-primary/90"
|
|
23
|
+
>
|
|
24
|
+
Go back home
|
|
25
|
+
</a>
|
|
26
|
+
</div>
|
|
27
|
+
</div>
|
|
28
|
+
</section>
|
|
29
|
+
</PageLayout>
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
---
|
|
2
|
+
import BlogLayout from '@/layouts/BlogLayout.astro';
|
|
3
|
+
import { getCollection, render } from 'astro:content';
|
|
4
|
+
|
|
5
|
+
export async function getStaticPaths() {
|
|
6
|
+
const posts = await getCollection('blog', ({ data }) => {
|
|
7
|
+
return import.meta.env.PROD ? data.draft !== true : true;
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
return posts.map((post) => ({
|
|
11
|
+
params: { slug: post.id },
|
|
12
|
+
props: { post },
|
|
13
|
+
}));
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const { post } = Astro.props;
|
|
17
|
+
const { Content } = await render(post);
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
<BlogLayout
|
|
21
|
+
title={post.data.title}
|
|
22
|
+
description={post.data.description}
|
|
23
|
+
publishedAt={post.data.publishedAt}
|
|
24
|
+
updatedAt={post.data.updatedAt}
|
|
25
|
+
author={post.data.author}
|
|
26
|
+
image={post.data.image}
|
|
27
|
+
imageAlt={post.data.imageAlt}
|
|
28
|
+
tags={post.data.tags}
|
|
29
|
+
slug={post.id}
|
|
30
|
+
>
|
|
31
|
+
<Content />
|
|
32
|
+
</BlogLayout>
|