rizzo-css 0.0.52 → 0.0.54

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.
Files changed (42) hide show
  1. package/README.md +8 -7
  2. package/bin/rizzo-css.js +332 -85
  3. package/dist/rizzo.min.css +1 -1
  4. package/package.json +4 -3
  5. package/scaffold/astro-core/README-RIZZO.md +1 -1
  6. package/scaffold/astro-core/src/pages/index.astro +9 -3
  7. package/scaffold/minimal/index.html +13 -0
  8. package/scaffold/starter/index.html +13 -0
  9. package/scaffold/svelte-core/README-RIZZO.md +1 -1
  10. package/scaffold/svelte-core/src/routes/+page.svelte +9 -3
  11. package/scaffold/vanilla/README-RIZZO.md +5 -5
  12. package/scaffold/vanilla/components/accordion.html +22 -0
  13. package/scaffold/vanilla/components/alert.html +22 -0
  14. package/scaffold/vanilla/components/avatar.html +22 -0
  15. package/scaffold/vanilla/components/back-to-top.html +22 -0
  16. package/scaffold/vanilla/components/badge.html +22 -0
  17. package/scaffold/vanilla/components/breadcrumb.html +22 -0
  18. package/scaffold/vanilla/components/button.html +22 -0
  19. package/scaffold/vanilla/components/cards.html +22 -0
  20. package/scaffold/vanilla/components/copy-to-clipboard.html +22 -0
  21. package/scaffold/vanilla/components/divider.html +22 -0
  22. package/scaffold/vanilla/components/docs-sidebar.html +22 -0
  23. package/scaffold/vanilla/components/dropdown.html +22 -0
  24. package/scaffold/vanilla/components/font-switcher.html +22 -0
  25. package/scaffold/vanilla/components/footer.html +22 -0
  26. package/scaffold/vanilla/components/forms.html +22 -0
  27. package/scaffold/vanilla/components/icons.html +22 -0
  28. package/scaffold/vanilla/components/index.html +22 -0
  29. package/scaffold/vanilla/components/modal.html +22 -0
  30. package/scaffold/vanilla/components/navbar.html +22 -0
  31. package/scaffold/vanilla/components/pagination.html +22 -0
  32. package/scaffold/vanilla/components/progress-bar.html +22 -0
  33. package/scaffold/vanilla/components/search.html +22 -0
  34. package/scaffold/vanilla/components/settings.html +22 -0
  35. package/scaffold/vanilla/components/sound-effects.html +22 -0
  36. package/scaffold/vanilla/components/spinner.html +22 -0
  37. package/scaffold/vanilla/components/table.html +22 -0
  38. package/scaffold/vanilla/components/tabs.html +22 -0
  39. package/scaffold/vanilla/components/theme-switcher.html +22 -0
  40. package/scaffold/vanilla/components/toast.html +22 -0
  41. package/scaffold/vanilla/components/tooltip.html +22 -0
  42. package/scaffold/vanilla/index.html +22 -0
package/bin/rizzo-css.js CHANGED
@@ -25,38 +25,100 @@ const SCAFFOLD_README_FILENAME = 'README-RIZZO.md';
25
25
  const SCAFFOLD_LICENSE_FILENAME = 'LICENSE-RIZZO';
26
26
  /** Snippet file written by add command for copy-paste of link and theme. */
27
27
  const RIZZO_SNIPPET_FILE = 'RIZZO-SNIPPET.txt';
28
+ /** Setup instructions + snippets when we skip overwriting; written by init for minimal/starter/full. */
29
+ const RIZZO_SETUP_FILE = 'RIZZO-SETUP.md';
28
30
 
29
31
  const COMMANDS = ['init', 'add', 'theme', 'doctor', 'help'];
30
32
  const FRAMEWORKS = ['vanilla', 'astro', 'svelte'];
31
33
  /** Supported package managers: detection, install/add commands, and --package-manager override. */
32
34
  const VALID_PACKAGE_MANAGERS = ['npm', 'pnpm', 'yarn', 'bun'];
33
35
 
34
- /** Core = everything we ship. Manual = same base, pick which components to include. */
36
+ /** Template options (same for new project and add-to-existing). Each ships CSS, fonts, icons (and sfx for vanilla); we never overwrite existing files. */
35
37
  const TEMPLATES = {
36
38
  vanilla: [
37
- { value: 'core', label: 'Coreindex.html + theme switcher, js/main.js, icons, component showcase, ' + SCAFFOLD_README_FILENAME },
38
- { value: 'manual', label: 'Manualindex.html + CSS; pick which components to add (base = all interactive)' },
39
+ { value: 'minimal', label: 'MinimalCSS, fonts, icons, sfx + RIZZO-SETUP.md (no files overwritten)' },
40
+ { value: 'starter', label: 'StarterSame as Minimal + minimal index only if missing; otherwise snippets in RIZZO-SETUP.md' },
41
+ { value: 'full', label: 'Full — Full app (index, theme switcher, js/main.js, 34 component pages). Same assets; existing files skipped, snippets in RIZZO-SETUP.md' },
39
42
  ],
40
43
  astro: [
41
- { value: 'core', label: 'CoreAstro app + all components (with dependencies so everything works)' },
42
- { value: 'manual', label: 'Manualsame base; pick which components to include (all interactive pre-selected)' },
44
+ { value: 'minimal', label: 'MinimalCSS, fonts, icons, sfx + RIZZO-SETUP.md (no files overwritten)' },
45
+ { value: 'starter', label: 'StarterSame as Minimal + minimal layout/page only if missing; otherwise snippets in RIZZO-SETUP.md' },
46
+ { value: 'full', label: 'Full — Astro app + all or picked components. Same assets; existing files skipped, snippets in RIZZO-SETUP.md' },
43
47
  ],
44
48
  svelte: [
45
- { value: 'core', label: 'CoreSvelteKit app + all components (with dependencies so everything works)' },
46
- { value: 'manual', label: 'Manualsame base; pick which components to include (all interactive pre-selected)' },
49
+ { value: 'minimal', label: 'MinimalCSS, fonts, icons, sfx + RIZZO-SETUP.md (no files overwritten)' },
50
+ { value: 'starter', label: 'StarterSame as Minimal + minimal layout/page only if missing; otherwise snippets in RIZZO-SETUP.md' },
51
+ { value: 'full', label: 'Full — SvelteKit app + all or picked components. Same assets; existing files skipped, snippets in RIZZO-SETUP.md' },
47
52
  ],
48
53
  };
49
54
 
50
- const VANILLA_MANUAL_README = `# Vanilla + Rizzo CSS (manual)
55
+ /** Build RIZZO-SETUP.md content: instructions + snippets. Never overwrites; use for minimal/starter or when files were skipped. */
56
+ function buildRizzoSetupMd(framework, opts) {
57
+ const { linkTag, linkHref, theme, defaultDark, defaultLight, skippedFiles = [], exampleMinimalPage } = opts;
58
+ const fw = framework === 'vanilla' ? 'Vanilla' : framework === 'astro' ? 'Astro' : 'Svelte';
59
+ let md = `# Rizzo CSS setup
51
60
 
52
- Manual setup: HTML + CSS, plus the component pages you chose (base = all interactive components). Scaffolded with \`npx rizzo-css init --framework vanilla --template manual\`.
61
+ This file was generated by \`npx rizzo-css init\` or \`npx rizzo-css add\`. Use it to integrate Rizzo CSS into your project. **We never overwrite your existing files** add the snippets below where needed.
62
+
63
+ ## 1. Link the CSS
64
+
65
+ Add this to your \`<head>\` or root layout:
66
+
67
+ \`\`\`html
68
+ ${linkTag || `<link rel="stylesheet" href="${linkHref || '/css/rizzo.min.css'}" />`}
69
+ \`\`\`
70
+
71
+ ## 2. Set a theme (optional)
72
+
73
+ On your \`<html>\` element:
74
+
75
+ \`\`\`html
76
+ <html lang="en" data-theme="${theme || 'system'}">
77
+ \`\`\`
78
+
79
+ Theme IDs: \`npx rizzo-css theme\`. Default dark: ${defaultDark || 'github-dark-classic'}; default light: ${defaultLight || 'github-light'}.
80
+
81
+ ## 3. Accessibility basics (recommended)
82
+
83
+ - Skip link: \`<a href="#main-content" class="skip-link">Skip to main content</a>\`
84
+ - Main landmark: \`<main id="main-content">\`
85
+
86
+ `;
87
+ if (skippedFiles.length > 0) {
88
+ md += `## Files we didn't overwrite
89
+
90
+ Your project already had these files. Add the following snippets manually if you want the same content as the scaffold:\n\n`;
91
+ for (const { relativePath, content } of skippedFiles) {
92
+ if (!content) continue;
93
+ const ext = relativePath.slice(relativePath.lastIndexOf('.'));
94
+ const lang = ext === '.html' ? 'html' : ext === '.astro' ? 'astro' : ext === '.svelte' ? 'svelte' : ext === '.ts' || ext === '.js' ? 'ts' : 'text';
95
+ md += `### \`${relativePath}\`\n\n\`\`\`${lang}\n${content.substring(0, 8000)}${content.length > 8000 ? '\n...' : ''}\n\`\`\`\n\n`;
96
+ }
97
+ }
98
+ if (exampleMinimalPage) {
99
+ md += `## Example minimal page
100
+
101
+ If you don't have an HTML file yet, you can use this (from \`scaffold/minimal/index.html\`):\n\n\`\`\`html\n${exampleMinimalPage}\n\`\`\`\n\n`;
102
+ }
103
+ md += `## Docs
104
+
105
+ - [Getting started](https://rizzo-css.vercel.app/docs/getting-started)
106
+ - [Components](https://rizzo-css.vercel.app/docs/components)
107
+ - [Theming](https://rizzo-css.vercel.app/docs/theming)
108
+ `;
109
+ return md;
110
+ }
111
+
112
+ const VANILLA_MANUAL_README = `# Vanilla + Rizzo CSS (Full template)
113
+
114
+ Full template: HTML + CSS, plus the component pages you chose (or all 34). Scaffolded with \`npx rizzo-css init --framework vanilla --template full\` (or \`npx rizzo-css add --template full\` for existing projects).
53
115
 
54
116
  - Open \`index.html\` in a browser or serve the folder with any static server.
55
117
  - Edit \`index.html\` and add your content. CSS: \`css/rizzo.min.css\`.
56
118
  - If you picked components, \`components/\` has their HTML pages and \`js/main.js\` is included (open \`components/index.html\` to browse).
57
119
  - Set a theme: \`<html data-theme="github-dark-classic">\` (see \`npx rizzo-css theme\` for all themes).
58
120
 
59
- **If you chose no components:** To add component JavaScript (modal, dropdown, tabs, toast, search, navbar, copy-to-clipboard, theme switcher, etc.), use the [Vanilla component docs](https://rizzo-css.vercel.app/docs/vanilla/components) or run \`npx rizzo-css init\` with Vanilla → **Core** in a temp folder and copy \`js/main.js\` and \`components/\` into this project.
121
+ **If you chose no components:** To add component JavaScript (modal, dropdown, tabs, toast, search, navbar, copy-to-clipboard, theme switcher, etc.), use the [Vanilla component docs](https://rizzo-css.vercel.app/docs/vanilla/components) or run \`npx rizzo-css init\` with Vanilla → **Full** in a temp folder and copy \`js/main.js\` and \`components/\` into this project.
60
122
 
61
123
  Docs: [rizzo-css.vercel.app](https://rizzo-css.vercel.app)
62
124
  `;
@@ -407,7 +469,8 @@ function getPositionalArgs(argv) {
407
469
  const positionals = [];
408
470
  for (let i = 1; i < argv.length; i++) {
409
471
  if (argv[i].startsWith('--')) {
410
- if (!argv[i].includes('=')) i++;
472
+ if (!argv[i].includes('=') && i + 1 < argv.length) i += 2;
473
+ else i++;
411
474
  continue;
412
475
  }
413
476
  positionals.push(argv[i]);
@@ -480,10 +543,10 @@ async function promptPackageManager(projectDir) {
480
543
  return selectMenu(options, '? Package manager (for install and run commands)');
481
544
  }
482
545
 
483
- /** Prompt user to select Core or Manual for the chosen framework. Returns 'core' or 'manual'. */
546
+ /** Prompt user to select template (Minimal, Starter, Full) for the chosen framework. Returns 'minimal' | 'starter' | 'full'. */
484
547
  async function promptTemplate(framework) {
485
548
  const options = TEMPLATES[framework] || TEMPLATES.vanilla;
486
- return selectMenu(options, '? Full or Manual?');
549
+ return selectMenu(options, '? Template (we never overwrite your existing files)?');
487
550
  }
488
551
 
489
552
  function question(prompt) {
@@ -837,7 +900,7 @@ Available commands: init, add, theme, doctor, help
837
900
 
838
901
  Flags summary:
839
902
  init --yes --path <dir> --framework <fw> --template <t> --package-manager <pm> --install --no-install --no-git
840
- add --path <dir> --framework <fw> ... --no-snippet --readme --force --vanilla-js
903
+ add --path <dir> --framework <fw> --template minimal|starter|full --no-snippet --readme --force --vanilla-js
841
904
  theme (no flags)
842
905
  doctor Check config, CSS file, and optional layout link
843
906
  help (no flags)
@@ -849,16 +912,16 @@ Usage (use your package manager):
849
912
  bunx rizzo-css <command> [options]
850
913
 
851
914
  Commands:
852
- init New project = Core (everything) | Manual (pick which components; all pre-selected). Existing = drop in CSS + hand-pick. First: framework, then existing vs new.
853
- add Same as init → existing: drop in CSS + hand-pick components (framework detected or from rizzo-css.json)
915
+ init New or existing: choose template (Minimal | Starter | Full). Same flow for both we never overwrite; skipped content goes into RIZZO-SETUP.md. Full = component picker (all 34 or pick).
916
+ add Same as init → existing: same template choice (Minimal | Starter | Full). Framework detected or from rizzo-css.json.
854
917
  theme List all available themes (use in init or set data-theme on <html>)
855
918
  help Show this help
856
919
 
857
920
  Options (init):
858
- --yes Non-interactive: scaffold new in cwd with defaults (framework: astro, template: core)
921
+ --yes Non-interactive: scaffold new in cwd with defaults (framework: astro, template: full)
859
922
  --path <dir> Project directory (relative to cwd or absolute). Scaffold and run install there. With --yes; interactive: "Enter path" option.
860
923
  --framework <fw> vanilla | astro | svelte (with --yes; otherwise first prompt)
861
- --template <t> core | manual (all frameworks); with --yes defaults to core
924
+ --template <t> minimal | starter | full (or legacy: core | manual; both map to full); with --yes defaults to full
862
925
  --package-manager <pm> npm | pnpm | yarn | bun (with --yes, or skip PM prompt when interactive)
863
926
  --install After scaffolding, run package manager install in project directory (no prompt)
864
927
  --no-install Do not run install and do not prompt
@@ -866,15 +929,16 @@ Options (init):
866
929
  (Git: only init offers or runs git init. Interactive init: "Initialize a git repository? (Y/n)" for all frameworks. With --yes, git init runs unless --no-git. Add (CSS + components) does not prompt for git. Astro/Svelte then get "Run install now? (Y/n)"; Vanilla has no package manager. rizzo-css.json is written only when the project does not already have one.)
867
930
 
868
931
  Options (add):
932
+ --template <t> minimal | starter | full (same as init; Full = component picker, writes RIZZO-SNIPPET.txt)
869
933
  --path <dir> Target directory for rizzo.min.css (overrides config and framework default)
870
934
  --framework <fw> vanilla | astro | svelte (overrides config and detection)
871
935
  --package-manager <pm> npm | pnpm | yarn | bun (override detection for install/print commands)
872
936
  --install-package After copying CSS, run package manager add rizzo-css
873
937
  --no-install Do not run install or add (overrides --install-package)
874
- --no-snippet Do not write RIZZO-SNIPPET.txt (link + theme copy-paste)
938
+ --no-snippet (Full only) Do not write RIZZO-SNIPPET.txt (link + theme copy-paste)
875
939
  --readme Write README-RIZZO.md into the project
876
940
  --force Overwrite existing rizzo.min.css without prompting
877
- --vanilla-js (Vanilla) Copy js/main.js for interactive components (modal, dropdown, tabs, toast, search, navbar, copy-to-clipboard, theme switcher)
941
+ --vanilla-js (Vanilla Full) Copy js/main.js for interactive components (modal, dropdown, tabs, toast, search, navbar, copy-to-clipboard, theme switcher)
878
942
 
879
943
  Package managers:
880
944
  Supported: npm, pnpm, yarn, bun. Detection: lockfiles (pnpm-lock.yaml, yarn.lock, bun.lockb, package-lock.json) or package.json "packageManager"/"devEngines.packageManager". Use --package-manager to override. Yarn 1 (classic) has no dlx; we show npx for yarn so it works everywhere. Yarn 2+ can use yarn dlx instead.
@@ -905,7 +969,7 @@ Examples:
905
969
  npx rizzo-css init --yes --path my-app --framework astro --install
906
970
  npx rizzo-css init --yes --framework astro --package-manager pnpm --install
907
971
  npx rizzo-css init --yes --framework vanilla
908
- npx rizzo-css init --yes --framework svelte --template core
972
+ npx rizzo-css init --yes --framework svelte --template full
909
973
  npx rizzo-css add --package-manager yarn --install-package
910
974
  npx rizzo-css add
911
975
  npx rizzo-css add Button
@@ -913,8 +977,8 @@ Examples:
913
977
  npx rizzo-css add --install-package
914
978
  npx rizzo-css theme
915
979
 
916
- Component dependencies (manual / add):
917
- Some components require others to work. Picking them adds the required ones automatically.
980
+ Component dependencies (Full template):
981
+ Some components require others to work. The component picker adds required ones automatically.
918
982
  Full list of available components and what relies on what: npx rizzo-css help components
919
983
 
920
984
  Docs: https://rizzo-css.vercel.app
@@ -1118,6 +1182,8 @@ async function cmdAdd(argv) {
1118
1182
  const customPath = getFlagValue(argv, '--path');
1119
1183
  const explicitFrameworkRaw = getFlagValue(argv, '--framework');
1120
1184
  const explicitFramework = explicitFrameworkRaw && FRAMEWORKS.includes(explicitFrameworkRaw.toLowerCase()) ? explicitFrameworkRaw.toLowerCase() : null;
1185
+ const templateRaw = getFlagValue(argv, '--template');
1186
+ const template = templateRaw && ['minimal', 'starter', 'full'].includes(templateRaw.toLowerCase()) ? templateRaw.toLowerCase() : undefined;
1121
1187
  const installPackage = hasFlag(argv, '--install-package');
1122
1188
  const noInstall = hasFlag(argv, '--no-install');
1123
1189
  const writeSnippet = !hasFlag(argv, '--no-snippet');
@@ -1133,6 +1199,7 @@ async function cmdAdd(argv) {
1133
1199
  config,
1134
1200
  targetDir: customPath || (config && config.targetDir) || undefined,
1135
1201
  packageManager: pmOverride || undefined,
1202
+ template,
1136
1203
  preselectedComponents: positionals.length > 0 ? positionals : undefined,
1137
1204
  writeSnippet,
1138
1205
  writeReadme,
@@ -1175,6 +1242,52 @@ function getScaffoldVanillaIndex() {
1175
1242
  return join(getPackageRoot(), 'scaffold', 'vanilla', 'index.html');
1176
1243
  }
1177
1244
 
1245
+ /** Path to Minimal template entry (index.html). Used for init/add when template is Minimal (snippet only). */
1246
+ function getMinimalTemplatePath() {
1247
+ return join(getPackageRoot(), 'scaffold', 'minimal', 'index.html');
1248
+ }
1249
+
1250
+ /** Path to Starter template (minimal index.html). Used for init/add when template is Starter. */
1251
+ function getStarterTemplatePath() {
1252
+ return join(getPackageRoot(), 'scaffold', 'starter', 'index.html');
1253
+ }
1254
+
1255
+ /** Load minimal/starter template HTML from scaffold and apply replacements; fallback to inline if file missing. */
1256
+ function getMinimalOrStarterTemplateHtml(opts, templatePath) {
1257
+ const { theme, themeComment, name, framework } = opts;
1258
+ const linkHref = framework === 'vanilla' ? 'css/rizzo.min.css' : '/css/rizzo.min.css';
1259
+ if (existsSync(templatePath)) {
1260
+ let html = readFileSync(templatePath, 'utf8');
1261
+ return html
1262
+ .replace(/\{\{TITLE\}\}/g, name || 'App')
1263
+ .replace(/\{\{DATA_THEME\}\}/g, theme)
1264
+ .replace(/\{\{THEME_LIST_COMMENT\}\}/g, themeComment)
1265
+ .replace(/\{\{LINK_HREF\}\}/g, linkHref);
1266
+ }
1267
+ return `<!DOCTYPE html>
1268
+ <html lang="en" data-theme="${theme}">${themeComment}
1269
+ <head>
1270
+ <meta charset="UTF-8" />
1271
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
1272
+ <title>${name || 'App'}</title>
1273
+ <link rel="stylesheet" href="${linkHref}" />
1274
+ </head>
1275
+ <body>
1276
+ <h1>Hello, Rizzo CSS</h1>
1277
+ <p>Edit this file and add components. Docs: <a href="https://rizzo-css.vercel.app">rizzo-css.vercel.app</a></p>
1278
+ </body>
1279
+ </html>
1280
+ `;
1281
+ }
1282
+
1283
+ function getMinimalTemplateHtml(opts) {
1284
+ return getMinimalOrStarterTemplateHtml(opts, getMinimalTemplatePath());
1285
+ }
1286
+
1287
+ function getStarterTemplateHtml(opts) {
1288
+ return getMinimalOrStarterTemplateHtml(opts, getStarterTemplatePath());
1289
+ }
1290
+
1178
1291
  function getScaffoldVanillaIconsDir() {
1179
1292
  return join(getPackageRoot(), 'scaffold', 'vanilla', 'icons');
1180
1293
  }
@@ -1304,6 +1417,54 @@ function copyDirRecursiveWithReplacements(src, dest, replacements) {
1304
1417
  }
1305
1418
  }
1306
1419
 
1420
+ /**
1421
+ * Like copyDirRecursiveWithReplacements but never overwrites existing files.
1422
+ * Returns { skipped: Array<{ relativePath, content }> } for files that already existed (so caller can write RIZZO-SETUP.md).
1423
+ * relativePath is from projectDir (dest).
1424
+ */
1425
+ function copyDirRecursiveWithReplacementsNoOverwrite(src, dest, replacements, projectDir) {
1426
+ const skipped = [];
1427
+ projectDir = projectDir || dest;
1428
+ const textExtensions = new Set(['.html', '.astro', '.svelte', '.ts', '.js', '.mjs', '.json', '.css', '.md']);
1429
+ function recurse(s, d) {
1430
+ mkdirSync(d, { recursive: true });
1431
+ const entries = readdirSync(s, { withFileTypes: true });
1432
+ for (const e of entries) {
1433
+ const srcPath = join(s, e.name);
1434
+ const destPath = join(d, e.name);
1435
+ if (e.isDirectory()) {
1436
+ recurse(srcPath, destPath);
1437
+ } else {
1438
+ if (existsSync(destPath)) {
1439
+ const rel = pathRelative(projectDir, destPath);
1440
+ let content = '';
1441
+ const ext = srcPath.slice(srcPath.lastIndexOf('.'));
1442
+ if (textExtensions.has(ext)) {
1443
+ content = readFileSync(srcPath, 'utf8');
1444
+ for (const [key, value] of Object.entries(replacements)) {
1445
+ content = content.split(key).join(value);
1446
+ }
1447
+ }
1448
+ skipped.push({ relativePath: rel, content });
1449
+ continue;
1450
+ }
1451
+ const ext = srcPath.slice(srcPath.lastIndexOf('.'));
1452
+ if (textExtensions.has(ext)) {
1453
+ let content = readFileSync(srcPath, 'utf8');
1454
+ for (const [key, value] of Object.entries(replacements)) {
1455
+ content = content.split(key).join(value);
1456
+ }
1457
+ writeFileSync(destPath, content, 'utf8');
1458
+ } else {
1459
+ copyFileSync(srcPath, destPath);
1460
+ }
1461
+ }
1462
+ }
1463
+ }
1464
+ recurse(src, dest);
1465
+ return { skipped };
1466
+ }
1467
+
1307
1468
  function copySvelteComponents(projectDir, selectedNames) {
1308
1469
  const scaffoldDir = getScaffoldSvelteDir();
1309
1470
  if (!existsSync(scaffoldDir)) {
@@ -1419,7 +1580,7 @@ function copyAstroComponents(projectDir, selectedNames) {
1419
1580
  }
1420
1581
  }
1421
1582
 
1422
- /** Add Rizzo CSS and hand-picked components to an existing project in cwd. frameworkOverride: when set (from init), skip framework prompt. options: { config?, targetDir? }. */
1583
+ /** Add Rizzo CSS to an existing project. Same template options as new project: Minimal | Starter | Full. frameworkOverride: when set (from init), skip framework prompt. options: { config?, targetDir?, template? }. */
1423
1584
  async function runAddToExisting(frameworkOverride, options) {
1424
1585
  const cwd = process.cwd();
1425
1586
  const config = (options && options.config) || readRizzoConfig(cwd);
@@ -1438,10 +1599,15 @@ async function runAddToExisting(frameworkOverride, options) {
1438
1599
  framework = await selectMenu(frameworkOptions, frameworkPrompt);
1439
1600
  }
1440
1601
 
1602
+ // Same template choice as new project: Minimal | Starter | Full (we never overwrite existing files)
1603
+ const addTemplate = (options && options.template) || await promptTemplate(framework);
1604
+
1441
1605
  const componentList = framework === 'svelte' ? SVELTE_COMPONENTS : framework === 'astro' ? ASTRO_COMPONENTS : framework === 'vanilla' ? Object.keys(VANILLA_COMPONENT_SLUGS) : [];
1442
1606
  const preselected = options.preselectedComponents && options.preselectedComponents.length > 0 ? options.preselectedComponents : null;
1443
1607
  let selectedComponents;
1444
- if (preselected && componentList.length > 0) {
1608
+ if (addTemplate === 'minimal' || addTemplate === 'starter') {
1609
+ selectedComponents = [];
1610
+ } else if (preselected && componentList.length > 0) {
1445
1611
  const valid = preselected.filter((c) => componentList.includes(c));
1446
1612
  const invalid = preselected.filter((c) => !componentList.includes(c));
1447
1613
  if (invalid.length > 0) {
@@ -1582,7 +1748,11 @@ async function runAddToExisting(frameworkOverride, options) {
1582
1748
  if (!hadConfig) {
1583
1749
  writeRizzoConfig(cwd, { targetDir: configTargetDir, framework, packageManager: pm.agent, theme });
1584
1750
  }
1585
- const writeSnippet = options.writeSnippet !== false;
1751
+ // Same assets and docs as init: RIZZO-SETUP.md for all templates; Full also gets RIZZO-SNIPPET.txt
1752
+ const setupMdContent = buildRizzoSetupMd(framework, { linkHref, theme, defaultDark, defaultLight });
1753
+ writeFileSync(join(cwd, RIZZO_SETUP_FILE), setupMdContent + '\n', 'utf8');
1754
+ copyPackageLicense(cwd);
1755
+ const writeSnippet = options.writeSnippet !== false && addTemplate === 'full';
1586
1756
  if (writeSnippet) {
1587
1757
  const where = framework === 'svelte' ? 'Root layout (e.g. src/app.html)' : framework === 'astro' ? 'Layout (e.g. src/layouts/Layout.astro)' : 'HTML or layout';
1588
1758
  const snippetBody = [
@@ -1602,8 +1772,10 @@ async function runAddToExisting(frameworkOverride, options) {
1602
1772
  }
1603
1773
  }
1604
1774
  console.log('\n✓ Rizzo CSS added to your existing project');
1605
- console.log(' - ' + cssTarget);
1775
+ console.log(' - ' + cssTarget + ' (CSS, fonts' + (framework === 'vanilla' ? ', sfx' : '') + ')');
1776
+ console.log(' - Icons and ' + RIZZO_SETUP_FILE);
1606
1777
  if (!hadConfig) console.log(' - Wrote ' + RIZZO_CONFIG_FILE);
1778
+ console.log(' - Wrote ' + RIZZO_SETUP_FILE + ' (instructions + link + theme)');
1607
1779
  if (writeSnippet) console.log(' - Wrote ' + RIZZO_SNIPPET_FILE + ' (copy-paste link + theme)');
1608
1780
  if (options.writeReadme) console.log(' - Wrote ' + SCAFFOLD_README_FILENAME);
1609
1781
  console.log('\nYou must add the stylesheet link yourself — it is not added automatically.');
@@ -1649,16 +1821,21 @@ async function cmdInit(argv) {
1649
1821
  let selectedPm;
1650
1822
  let selectedTemplate;
1651
1823
  let selectedComponents = [];
1824
+ let fullAllComponents = false;
1652
1825
 
1653
1826
  if (yes) {
1654
1827
  const frameworkArg = getFlagValue(argv, '--framework');
1655
1828
  framework = (frameworkArg && FRAMEWORKS.includes(frameworkArg.toLowerCase())) ? frameworkArg.toLowerCase() : (config && config.framework) || 'astro';
1656
1829
  initMode = 'new';
1657
1830
  const templateArg = getFlagValue(argv, '--template');
1658
- const defaultTemplate = 'core';
1659
- selectedTemplate = (templateArg && (templateArg === 'core' || templateArg === 'manual')) ? templateArg : defaultTemplate;
1660
- if (selectedTemplate === 'core' && (framework === 'astro' || framework === 'svelte')) {
1661
- selectedComponents = framework === 'svelte' ? [...SVELTE_COMPONENTS] : [...ASTRO_COMPONENTS];
1831
+ const defaultTemplate = 'full';
1832
+ const validTemplates = ['minimal', 'starter', 'full', 'core', 'manual'];
1833
+ selectedTemplate = (templateArg && validTemplates.includes(templateArg)) ? (templateArg === 'core' || templateArg === 'manual' ? 'full' : templateArg) : defaultTemplate;
1834
+ if (selectedTemplate === 'full') {
1835
+ fullAllComponents = true;
1836
+ if (framework === 'svelte') selectedComponents = [...SVELTE_COMPONENTS];
1837
+ else if (framework === 'astro') selectedComponents = [...ASTRO_COMPONENTS];
1838
+ else selectedComponents = Object.keys(VANILLA_COMPONENT_SLUGS);
1662
1839
  }
1663
1840
  const projectDir = customProjectPath ? pathResolve(cwd, customProjectPath) : cwd;
1664
1841
  const resolved = resolvePackageManager(projectDir, cwd);
@@ -1707,17 +1884,27 @@ async function cmdInit(argv) {
1707
1884
  }
1708
1885
  }
1709
1886
 
1710
- selectedTemplate = await selectMenu(TEMPLATES[framework] || TEMPLATES.vanilla, '? Core or Manual?');
1887
+ selectedTemplate = await promptTemplate(framework);
1711
1888
 
1712
- if (selectedTemplate === 'core' && (framework === 'astro' || framework === 'svelte')) {
1713
- selectedComponents = framework === 'svelte' ? [...SVELTE_COMPONENTS] : [...ASTRO_COMPONENTS];
1714
- } else if (selectedTemplate === 'manual') {
1715
- const componentList = framework === 'svelte' ? SVELTE_COMPONENTS : ASTRO_COMPONENTS;
1716
- const recommended = RECOMMENDED_COMPONENTS.filter((c) => componentList.includes(c));
1717
- selectedComponents = await promptComponentChoice(componentList, framework, recommended);
1889
+ if (selectedTemplate === 'full') {
1890
+ const addChoice = await selectMenu(
1891
+ [
1892
+ { value: 'all', label: 'All 34 components' },
1893
+ { value: 'pick', label: 'Pick components (choose which to include)' },
1894
+ ],
1895
+ '? Add all components or pick which to include?'
1896
+ );
1897
+ fullAllComponents = (addChoice === 'all');
1898
+ if (fullAllComponents) {
1899
+ selectedComponents = framework === 'svelte' ? [...SVELTE_COMPONENTS] : framework === 'astro' ? [...ASTRO_COMPONENTS] : Object.keys(VANILLA_COMPONENT_SLUGS);
1900
+ } else {
1901
+ const componentList = framework === 'svelte' ? SVELTE_COMPONENTS : framework === 'astro' ? ASTRO_COMPONENTS : Object.keys(VANILLA_COMPONENT_SLUGS);
1902
+ const recommended = RECOMMENDED_COMPONENTS.filter((c) => componentList.includes(c));
1903
+ selectedComponents = await promptComponentChoice(componentList, framework, recommended);
1904
+ }
1718
1905
  }
1719
1906
 
1720
- const wantsThemeSwitcher = (framework === 'vanilla' && selectedTemplate === 'core') || selectedComponents.includes('ThemeSwitcher');
1907
+ const wantsThemeSwitcher = (framework === 'vanilla' && selectedTemplate === 'full') || selectedComponents.includes('ThemeSwitcher');
1721
1908
  if (wantsThemeSwitcher) {
1722
1909
  const themeOut = await promptThemes();
1723
1910
  theme = themeOut.theme;
@@ -1766,11 +1953,11 @@ async function cmdInit(argv) {
1766
1953
  const astroCoreDir = getScaffoldAstroCoreDir();
1767
1954
  const svelteCoreDir = getScaffoldSvelteCoreDir();
1768
1955
  const pathsForScaffold = getFrameworkCssPaths(framework);
1769
- const useHandpickAstro = selectedTemplate === 'manual' && framework === 'astro' && existsSync(astroCoreDir);
1770
- const useHandpickSvelte = selectedTemplate === 'manual' && framework === 'svelte' && existsSync(svelteCoreDir);
1771
- const useAstroBase = selectedTemplate === 'core' && framework === 'astro' && existsSync(astroCoreDir);
1772
- const useSvelteBase = selectedTemplate === 'core' && framework === 'svelte' && existsSync(svelteCoreDir);
1773
- const useVanillaCore = selectedTemplate === 'core' && framework === 'vanilla' && existsSync(getScaffoldVanillaIndex());
1956
+ const useHandpickAstro = selectedTemplate === 'full' && !fullAllComponents && framework === 'astro' && existsSync(astroCoreDir);
1957
+ const useHandpickSvelte = selectedTemplate === 'full' && !fullAllComponents && framework === 'svelte' && existsSync(svelteCoreDir);
1958
+ const useAstroBase = selectedTemplate === 'full' && fullAllComponents && framework === 'astro' && existsSync(astroCoreDir);
1959
+ const useSvelteBase = selectedTemplate === 'full' && fullAllComponents && framework === 'svelte' && existsSync(svelteCoreDir);
1960
+ const useVanillaCore = selectedTemplate === 'full' && fullAllComponents && framework === 'vanilla' && existsSync(getScaffoldVanillaIndex());
1774
1961
 
1775
1962
  // Full gets all required dependencies so everything works; manual gets deps when user picks (see prompt labels).
1776
1963
  let componentsToCopy = selectedComponents;
@@ -1825,25 +2012,15 @@ async function cmdInit(argv) {
1825
2012
  let cssTarget;
1826
2013
  let indexPath;
1827
2014
 
1828
- const minimalHtml = `<!DOCTYPE html>
1829
- <html lang="en" data-theme="${theme}">${themeComment}
1830
- <head>
1831
- <meta charset="UTF-8" />
1832
- <meta name="viewport" content="width=device-width, initial-scale=1" />
1833
- <title>${name || 'App'}</title>
1834
- <link rel="stylesheet" href="${framework === 'vanilla' ? 'css/rizzo.min.css' : '/css/rizzo.min.css'}" />
1835
- </head>
1836
- <body>
1837
- <h1>Hello, Rizzo CSS</h1>
1838
- <p>Edit this file and add components. Docs: <a href="https://rizzo-css.vercel.app">rizzo-css.vercel.app</a></p>
1839
- </body>
1840
- </html>
1841
- `;
2015
+ const minimalHtml = getStarterTemplateHtml({ theme, themeComment, name, framework });
1842
2016
 
1843
2017
  if (useHandpickAstro) {
1844
2018
  mkdirSync(projectDir, { recursive: true });
1845
- copyDirRecursiveWithReplacements(astroCoreDir, projectDir, replacements);
2019
+ const { skipped } = copyDirRecursiveWithReplacementsNoOverwrite(astroCoreDir, projectDir, replacements, projectDir);
1846
2020
  copyRizzoCssAndFontsForAstro(projectDir, cssSource);
2021
+ if (skipped.length > 0) {
2022
+ writeFileSync(join(projectDir, RIZZO_SETUP_FILE), buildRizzoSetupMd('astro', { linkHref: '/css/rizzo.min.css', theme, defaultDark, defaultLight, skippedFiles: skipped }), 'utf8');
2023
+ }
1847
2024
  cssTarget = join(projectDir, 'public', 'css', 'rizzo.min.css');
1848
2025
  if (statSync(cssTarget).size < 5000) {
1849
2026
  console.warn('\nWarning: rizzo.min.css is very small. From repo root run: pnpm build:css');
@@ -1856,8 +2033,11 @@ async function cmdInit(argv) {
1856
2033
  }
1857
2034
  } else if (useAstroBase) {
1858
2035
  mkdirSync(projectDir, { recursive: true });
1859
- copyDirRecursiveWithReplacements(astroCoreDir, projectDir, replacements);
2036
+ const { skipped } = copyDirRecursiveWithReplacementsNoOverwrite(astroCoreDir, projectDir, replacements, projectDir);
1860
2037
  copyRizzoCssAndFontsForAstro(projectDir, cssSource);
2038
+ if (skipped.length > 0) {
2039
+ writeFileSync(join(projectDir, RIZZO_SETUP_FILE), buildRizzoSetupMd('astro', { linkHref: '/css/rizzo.min.css', theme, defaultDark, defaultLight, skippedFiles: skipped }), 'utf8');
2040
+ }
1861
2041
  cssTarget = join(projectDir, 'public', 'css', 'rizzo.min.css');
1862
2042
  if (statSync(cssTarget).size < 5000) {
1863
2043
  console.warn('\nWarning: rizzo.min.css is very small. From repo root run: pnpm build:css');
@@ -1870,8 +2050,11 @@ async function cmdInit(argv) {
1870
2050
  }
1871
2051
  } else if (useHandpickSvelte) {
1872
2052
  mkdirSync(projectDir, { recursive: true });
1873
- copyDirRecursiveWithReplacements(svelteCoreDir, projectDir, replacements);
2053
+ const { skipped } = copyDirRecursiveWithReplacementsNoOverwrite(svelteCoreDir, projectDir, replacements, projectDir);
1874
2054
  copyRizzoCssAndFontsForSvelte(projectDir, cssSource);
2055
+ if (skipped.length > 0) {
2056
+ writeFileSync(join(projectDir, RIZZO_SETUP_FILE), buildRizzoSetupMd('svelte', { linkHref: '/css/rizzo.min.css', theme, defaultDark, defaultLight, skippedFiles: skipped }), 'utf8');
2057
+ }
1875
2058
  cssTarget = join(projectDir, 'static', 'css', 'rizzo.min.css');
1876
2059
  if (statSync(cssTarget).size < 5000) {
1877
2060
  console.warn('\nWarning: rizzo.min.css is very small. From repo root run: pnpm build:css');
@@ -1884,8 +2067,11 @@ async function cmdInit(argv) {
1884
2067
  }
1885
2068
  } else if (useSvelteBase) {
1886
2069
  mkdirSync(projectDir, { recursive: true });
1887
- copyDirRecursiveWithReplacements(svelteCoreDir, projectDir, replacements);
2070
+ const { skipped } = copyDirRecursiveWithReplacementsNoOverwrite(svelteCoreDir, projectDir, replacements, projectDir);
1888
2071
  copyRizzoCssAndFontsForSvelte(projectDir, cssSource);
2072
+ if (skipped.length > 0) {
2073
+ writeFileSync(join(projectDir, RIZZO_SETUP_FILE), buildRizzoSetupMd('svelte', { linkHref: '/css/rizzo.min.css', theme, defaultDark, defaultLight, skippedFiles: skipped }), 'utf8');
2074
+ }
1889
2075
  cssTarget = join(projectDir, 'static', 'css', 'rizzo.min.css');
1890
2076
  if (statSync(cssTarget).size < 5000) {
1891
2077
  console.warn('\nWarning: rizzo.min.css is very small. From repo root run: pnpm build:css');
@@ -1917,7 +2103,12 @@ async function cmdInit(argv) {
1917
2103
  .replace(/\{\{THEME_LIST_COMMENT\}\}/g, themeComment)
1918
2104
  .replace(/\{\{TITLE\}\}/g, name || 'App')
1919
2105
  .replace(/\{\{LINK_HREF\}\}/g, linkHref);
1920
- writeFileSync(indexPath, indexHtml, 'utf8');
2106
+ const vanillaSkipped = [];
2107
+ if (existsSync(indexPath)) {
2108
+ vanillaSkipped.push({ relativePath: 'index.html', content: indexHtml });
2109
+ } else {
2110
+ writeFileSync(indexPath, indexHtml, 'utf8');
2111
+ }
1921
2112
  copyRizzoIcons(projectDir, 'vanilla');
1922
2113
  const vanillaReadme = join(getPackageRoot(), 'scaffold', 'vanilla', SCAFFOLD_README_FILENAME);
1923
2114
  if (existsSync(vanillaReadme)) {
@@ -1932,10 +2123,17 @@ async function cmdInit(argv) {
1932
2123
  }
1933
2124
  const vanillaCoreRepl = { ...replacements, '{{LINK_HREF}}': linkHref };
1934
2125
  copyVanillaComponents(projectDir, Object.keys(VANILLA_COMPONENT_SLUGS), vanillaCoreRepl);
2126
+ if (vanillaSkipped.length > 0) {
2127
+ writeFileSync(join(projectDir, RIZZO_SETUP_FILE), buildRizzoSetupMd('vanilla', { linkHref, theme, defaultDark, defaultLight, skippedFiles: vanillaSkipped }), 'utf8');
2128
+ }
1935
2129
  copyPackageLicense(projectDir);
1936
2130
  copyVanillaGitignore(projectDir);
1937
2131
  } else {
1938
- if (framework === 'svelte') {
2132
+ // Minimal and Starter: same assets as add flow — CSS, fonts, icons, sfx (framework-appropriate)
2133
+ if (framework === 'astro') {
2134
+ copyRizzoCssAndFontsForAstro(projectDir, cssSource);
2135
+ cssTarget = join(projectDir, 'public', 'css', 'rizzo.min.css');
2136
+ } else if (framework === 'svelte') {
1939
2137
  copyRizzoCssAndFontsForSvelte(projectDir, cssSource);
1940
2138
  cssTarget = join(projectDir, 'static', 'css', 'rizzo.min.css');
1941
2139
  } else {
@@ -1944,42 +2142,85 @@ async function cmdInit(argv) {
1944
2142
  mkdirSync(cssDir, { recursive: true });
1945
2143
  copyFileSync(cssSource, cssTarget);
1946
2144
  copyRizzoFonts(dirname(cssTarget));
1947
- if (framework === 'vanilla') copyRizzoSfx(projectDir);
2145
+ copyRizzoSfx(projectDir);
2146
+ }
2147
+ if (selectedTemplate === 'minimal' || selectedTemplate === 'starter') {
2148
+ copyRizzoIcons(projectDir, framework);
1948
2149
  }
1949
2150
  if (statSync(cssTarget).size < 5000) {
1950
2151
  console.warn('\nWarning: rizzo.min.css is very small. From repo root run: pnpm build:css');
1951
2152
  }
1952
- if (framework === 'vanilla' && selectedTemplate === 'manual') {
2153
+ const linkHrefForSetup = framework === 'vanilla' ? 'css/rizzo.min.css' : '/css/rizzo.min.css';
2154
+ const setupMdContent = buildRizzoSetupMd(framework, {
2155
+ linkHref: linkHrefForSetup,
2156
+ theme,
2157
+ defaultDark,
2158
+ defaultLight,
2159
+ ...(selectedTemplate === 'minimal' && { exampleMinimalPage: getMinimalTemplateHtml({ theme, themeComment, name, framework }) }),
2160
+ });
2161
+
2162
+ if (selectedTemplate === 'minimal') {
2163
+ writeFileSync(join(projectDir, RIZZO_SETUP_FILE), setupMdContent, 'utf8');
2164
+ copyPackageLicense(projectDir);
2165
+ } else if (selectedTemplate === 'starter') {
2166
+ const vanillaIndex = join(projectDir, 'index.html');
2167
+ const astroIndex = join(projectDir, 'public', 'index.html');
2168
+ const svelteIndex = join(projectDir, 'static', 'index.html');
2169
+ if (framework === 'vanilla' && !existsSync(vanillaIndex)) {
2170
+ indexPath = vanillaIndex;
2171
+ writeFileSync(vanillaIndex, minimalHtml, 'utf8');
2172
+ } else if (framework === 'astro' && !existsSync(astroIndex)) {
2173
+ mkdirSync(join(projectDir, 'public'), { recursive: true });
2174
+ indexPath = astroIndex;
2175
+ writeFileSync(astroIndex, minimalHtml, 'utf8');
2176
+ } else if (framework === 'svelte' && !existsSync(svelteIndex)) {
2177
+ mkdirSync(join(projectDir, 'static'), { recursive: true });
2178
+ indexPath = svelteIndex;
2179
+ writeFileSync(svelteIndex, minimalHtml, 'utf8');
2180
+ }
2181
+ writeFileSync(join(projectDir, RIZZO_SETUP_FILE), setupMdContent, 'utf8');
2182
+ copyPackageLicense(projectDir);
2183
+ } else if (framework === 'vanilla' && selectedTemplate === 'full' && !fullAllComponents) {
1953
2184
  indexPath = join(projectDir, 'index.html');
1954
- let indexContent = minimalHtml;
1955
- if (selectedComponents.length > 0) {
1956
- mkdirSync(join(projectDir, 'js'), { recursive: true });
1957
- const vanillaJs = join(getPackageRoot(), 'scaffold', 'vanilla', 'js', 'main.js');
1958
- if (existsSync(vanillaJs)) {
1959
- let mainJs = readFileSync(vanillaJs, 'utf8');
1960
- mainJs = mainJs.replace(/\{\{DEFAULT_DARK\}\}/g, defaultDark).replace(/\{\{DEFAULT_LIGHT\}\}/g, defaultLight).replace(/\{\{RIZZO_SOUND_SCRIPT\}\}/g, vanillaSoundScript);
1961
- writeFileSync(join(projectDir, 'js', 'main.js'), mainJs, 'utf8');
2185
+ if (!existsSync(indexPath)) {
2186
+ let indexContent = minimalHtml;
2187
+ if (selectedComponents.length > 0) {
2188
+ mkdirSync(join(projectDir, 'js'), { recursive: true });
2189
+ const vanillaJs = join(getPackageRoot(), 'scaffold', 'vanilla', 'js', 'main.js');
2190
+ if (existsSync(vanillaJs)) {
2191
+ let mainJs = readFileSync(vanillaJs, 'utf8');
2192
+ mainJs = mainJs.replace(/\{\{DEFAULT_DARK\}\}/g, defaultDark).replace(/\{\{DEFAULT_LIGHT\}\}/g, defaultLight).replace(/\{\{RIZZO_SOUND_SCRIPT\}\}/g, vanillaSoundScript);
2193
+ writeFileSync(join(projectDir, 'js', 'main.js'), mainJs, 'utf8');
2194
+ }
2195
+ const vanillaRepl = { ...replacements, '{{LINK_HREF}}': 'css/rizzo.min.css' };
2196
+ copyVanillaComponents(projectDir, selectedComponents, vanillaRepl);
2197
+ copyRizzoIcons(projectDir, 'vanilla');
2198
+ indexContent = minimalHtml.replace('</body>', ' <script src="js/main.js"></script>\n</body>');
1962
2199
  }
1963
- const vanillaRepl = { ...replacements, '{{LINK_HREF}}': 'css/rizzo.min.css' };
1964
- copyVanillaComponents(projectDir, selectedComponents, vanillaRepl);
1965
- copyRizzoIcons(projectDir, 'vanilla');
1966
- indexContent = minimalHtml.replace('</body>', ' <script src="js/main.js"></script>\n</body>');
2200
+ writeFileSync(indexPath, indexContent, 'utf8');
2201
+ } else {
2202
+ writeFileSync(join(projectDir, RIZZO_SETUP_FILE), buildRizzoSetupMd(framework, { linkHref: 'css/rizzo.min.css', theme, defaultDark, defaultLight, skippedFiles: [{ relativePath: 'index.html', content: minimalHtml }] }), 'utf8');
1967
2203
  }
1968
- writeFileSync(indexPath, indexContent, 'utf8');
1969
2204
  writeFileSync(join(projectDir, SCAFFOLD_README_FILENAME), VANILLA_MANUAL_README, 'utf8');
1970
2205
  copyVanillaGitignore(projectDir);
2206
+ copyPackageLicense(projectDir);
1971
2207
  } else if (framework === 'astro') {
1972
2208
  indexPath = join(projectDir, 'public', 'index.html');
1973
2209
  mkdirSync(join(projectDir, 'public'), { recursive: true });
1974
- writeFileSync(indexPath, minimalHtml, 'utf8');
2210
+ if (!existsSync(indexPath)) writeFileSync(indexPath, minimalHtml, 'utf8');
2211
+ else writeFileSync(join(projectDir, RIZZO_SETUP_FILE), buildRizzoSetupMd(framework, { linkHref: '/css/rizzo.min.css', theme, defaultDark, defaultLight, skippedFiles: [{ relativePath: 'public/index.html', content: minimalHtml }] }), 'utf8');
1975
2212
  writeFileSync(join(projectDir, SCAFFOLD_README_FILENAME), FALLBACK_MINIMAL_README, 'utf8');
1976
- } else {
2213
+ copyPackageLicense(projectDir);
2214
+ } else if (framework === 'svelte') {
1977
2215
  indexPath = join(projectDir, 'static', 'index.html');
1978
2216
  mkdirSync(join(projectDir, 'static'), { recursive: true });
1979
- writeFileSync(indexPath, minimalHtml, 'utf8');
2217
+ if (!existsSync(indexPath)) writeFileSync(indexPath, minimalHtml, 'utf8');
2218
+ else writeFileSync(join(projectDir, RIZZO_SETUP_FILE), buildRizzoSetupMd(framework, { linkHref: '/css/rizzo.min.css', theme, defaultDark, defaultLight, skippedFiles: [{ relativePath: 'static/index.html', content: minimalHtml }] }), 'utf8');
1980
2219
  writeFileSync(join(projectDir, SCAFFOLD_README_FILENAME), FALLBACK_MINIMAL_README, 'utf8');
2220
+ copyPackageLicense(projectDir);
2221
+ } else {
2222
+ copyPackageLicense(projectDir);
1981
2223
  }
1982
- copyPackageLicense(projectDir);
1983
2224
  }
1984
2225
 
1985
2226
  console.log('\n✓ Project ready at ' + projectDir);
@@ -1987,11 +2228,16 @@ async function cmdInit(argv) {
1987
2228
  if (indexPath) console.log(' - ' + indexPath);
1988
2229
  if (framework === 'vanilla') {
1989
2230
  if (useVanillaCore) {
1990
- console.log(' - Vanilla JS (core): theme switcher, js/main.js, icons, component showcase, ' + SCAFFOLD_README_FILENAME + '.');
2231
+ console.log(' - Vanilla JS (full): theme switcher, js/main.js, icons, component showcase, ' + SCAFFOLD_README_FILENAME + '.');
2232
+ } else if (selectedTemplate === 'minimal' || selectedTemplate === 'starter') {
2233
+ console.log(' - ' + RIZZO_SETUP_FILE + ' has instructions and snippets.');
1991
2234
  } else {
1992
- console.log(' - Vanilla JS (manual): index.html + CSS only. Add JS from docs or copy from Core.');
2235
+ console.log(' - Vanilla JS (picked components): index.html + CSS. Add JS from docs or ' + RIZZO_SETUP_FILE + '.');
1993
2236
  }
1994
2237
  }
2238
+ if (existsSync(join(projectDir, RIZZO_SETUP_FILE))) {
2239
+ console.log(' - ' + RIZZO_SETUP_FILE + ' (instructions + snippets for anything we didn\'t overwrite)');
2240
+ }
1995
2241
  const pm = getPackageManagerCommands({ agent: selectedPm, command: selectedPm });
1996
2242
  const nextStep = pm.install + ' && ' + pm.run('dev');
1997
2243
  const runPrefix = projectDir !== cwd ? 'cd ' + pathRelative(cwd, projectDir) + ' && ' : '';
@@ -2072,6 +2318,7 @@ function main() {
2072
2318
  }
2073
2319
  if (argv[0] && !COMMANDS.includes(command) && command !== 'h') {
2074
2320
  console.error('Unknown command: ' + argv[0] + '\n');
2321
+ process.exitCode = 1;
2075
2322
  }
2076
2323
  printHelp();
2077
2324
  return;