rizzo-css 0.0.54 → 0.0.56

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 (251) hide show
  1. package/README.md +11 -7
  2. package/bin/rizzo-css.js +314 -141
  3. package/dist/rizzo.min.css +40 -16
  4. package/package.json +6 -6
  5. package/scaffold/astro/AlertDialog.astro +86 -0
  6. package/scaffold/astro/AspectRatio.astro +22 -0
  7. package/scaffold/astro/ButtonGroup.astro +16 -0
  8. package/scaffold/astro/Collapsible.astro +69 -0
  9. package/scaffold/astro/ContextMenu.astro +58 -0
  10. package/scaffold/astro/CopyToClipboard.astro +4 -0
  11. package/scaffold/astro/Dashboard.astro +74 -0
  12. package/scaffold/astro/Empty.astro +23 -0
  13. package/scaffold/astro/HoverCard.astro +64 -0
  14. package/scaffold/astro/Kbd.astro +14 -0
  15. package/scaffold/astro/Label.astro +24 -0
  16. package/scaffold/astro/Modal.astro +17 -2
  17. package/scaffold/astro/Popover.astro +62 -0
  18. package/scaffold/astro/ResizableHandle.astro +16 -0
  19. package/scaffold/astro/ResizablePane.astro +20 -0
  20. package/scaffold/astro/ResizablePaneGroup.astro +84 -0
  21. package/scaffold/astro/ScrollArea.astro +19 -0
  22. package/scaffold/astro/Separator.astro +18 -0
  23. package/scaffold/astro/Settings.astro +10 -2
  24. package/scaffold/astro/Sheet.astro +90 -0
  25. package/scaffold/astro/Skeleton.astro +16 -0
  26. package/scaffold/astro/Slider.astro +75 -0
  27. package/scaffold/astro/SoundEffects.astro +1 -0
  28. package/scaffold/astro/Switch.astro +37 -0
  29. package/scaffold/astro/Tabs.astro +1 -1
  30. package/scaffold/astro/ThemeSwitcher.astro +11 -4
  31. package/scaffold/astro/Toggle.astro +35 -0
  32. package/scaffold/astro/ToggleGroup.astro +24 -0
  33. package/scaffold/astro/base/README-RIZZO.md +55 -0
  34. package/scaffold/{astro-core → astro/base}/src/pages/index.astro +1 -1
  35. package/scaffold/astro/variants/dashboard/src/layouts/Layout.astro +85 -0
  36. package/scaffold/astro/variants/dashboard/src/pages/index.astro +110 -0
  37. package/scaffold/astro/variants/docs/src/layouts/Layout.astro +81 -0
  38. package/scaffold/astro/variants/docs/src/pages/docs/getting-started.astro +36 -0
  39. package/scaffold/astro/variants/docs/src/pages/index.astro +38 -0
  40. package/scaffold/{astro-core → astro/variants/full}/README-RIZZO.md +2 -1
  41. package/scaffold/astro/variants/full/astro.config.mjs +5 -0
  42. package/scaffold/astro/variants/full/dist/_noop-middleware.mjs +3 -0
  43. package/scaffold/astro/variants/full/dist/chunks/astro/server_9Mzx7luy.mjs +6023 -0
  44. package/scaffold/astro/variants/full/dist/chunks/astro_BOYUKg7r.mjs +1 -0
  45. package/scaffold/astro/variants/full/dist/favicon.svg +18 -0
  46. package/scaffold/astro/variants/full/dist/manifest_DXpJmqSX.mjs +154 -0
  47. package/scaffold/astro/variants/full/dist/noop-entrypoint.mjs +3 -0
  48. package/scaffold/astro/variants/full/dist/pages/index.astro.mjs +87 -0
  49. package/scaffold/astro/variants/full/dist/renderers.mjs +3 -0
  50. package/scaffold/astro/variants/full/gitignore +24 -0
  51. package/scaffold/astro/variants/full/node_modules/.astro/data-store.json +1 -0
  52. package/scaffold/astro/variants/full/node_modules/.vite/deps/_metadata.json +31 -0
  53. package/scaffold/astro/variants/full/node_modules/.vite/deps/astro___aria-query.js +6776 -0
  54. package/scaffold/astro/variants/full/node_modules/.vite/deps/astro___aria-query.js.map +7 -0
  55. package/scaffold/astro/variants/full/node_modules/.vite/deps/astro___axobject-query.js +3754 -0
  56. package/scaffold/astro/variants/full/node_modules/.vite/deps/astro___axobject-query.js.map +7 -0
  57. package/scaffold/astro/variants/full/node_modules/.vite/deps/astro___cssesc.js +99 -0
  58. package/scaffold/astro/variants/full/node_modules/.vite/deps/astro___cssesc.js.map +7 -0
  59. package/scaffold/astro/variants/full/node_modules/.vite/deps/chunk-BUSYA2B4.js +8 -0
  60. package/scaffold/astro/variants/full/node_modules/.vite/deps/chunk-BUSYA2B4.js.map +7 -0
  61. package/scaffold/astro/variants/full/node_modules/.vite/deps/package.json +3 -0
  62. package/scaffold/astro/variants/full/package.json +13 -0
  63. package/scaffold/astro/variants/full/public/.gitkeep +0 -0
  64. package/scaffold/astro/variants/full/public/favicon.svg +18 -0
  65. package/scaffold/astro/variants/full/src/components/rizzo/CopyToClipboard.astro +157 -0
  66. package/scaffold/astro/variants/full/src/components/rizzo/icons/Check.astro +29 -0
  67. package/scaffold/astro/variants/full/src/components/rizzo/icons/Copy.astro +30 -0
  68. package/scaffold/astro/variants/full/src/layouts/Layout.astro +34 -0
  69. package/scaffold/astro/variants/full/src/pages/index.astro +107 -0
  70. package/scaffold/astro/variants/full/tsconfig.json +5 -0
  71. package/scaffold/landing/index.html +13 -0
  72. package/scaffold/shared/navbar-vanilla.html +59 -0
  73. package/scaffold/shared/sound-effects-inline.js +6 -1
  74. package/scaffold/svelte/AlertDialog.svelte +55 -0
  75. package/scaffold/svelte/AspectRatio.svelte +21 -0
  76. package/scaffold/svelte/BackToTop.svelte +1 -0
  77. package/scaffold/svelte/ButtonGroup.svelte +16 -0
  78. package/scaffold/svelte/Collapsible.svelte +57 -0
  79. package/scaffold/svelte/ContextMenu.svelte +60 -0
  80. package/scaffold/svelte/Dashboard.svelte +87 -0
  81. package/scaffold/svelte/Empty.svelte +36 -0
  82. package/scaffold/svelte/HoverCard.svelte +55 -0
  83. package/scaffold/svelte/Kbd.svelte +13 -0
  84. package/scaffold/svelte/Label.svelte +19 -0
  85. package/scaffold/svelte/Popover.svelte +59 -0
  86. package/scaffold/svelte/ResizableHandle.svelte +13 -0
  87. package/scaffold/svelte/ResizablePane.svelte +16 -0
  88. package/scaffold/svelte/ResizablePaneGroup.svelte +92 -0
  89. package/scaffold/svelte/ScrollArea.svelte +18 -0
  90. package/scaffold/svelte/Separator.svelte +14 -0
  91. package/scaffold/svelte/Sheet.svelte +62 -0
  92. package/scaffold/svelte/Skeleton.svelte +19 -0
  93. package/scaffold/svelte/Slider.svelte +57 -0
  94. package/scaffold/svelte/SoundEffects.svelte +3 -0
  95. package/scaffold/svelte/Switch.svelte +35 -0
  96. package/scaffold/svelte/Tabs.svelte +1 -1
  97. package/scaffold/svelte/Toggle.svelte +41 -0
  98. package/scaffold/svelte/ToggleGroup.svelte +30 -0
  99. package/scaffold/svelte/base/README-RIZZO.md +55 -0
  100. package/scaffold/{svelte-core → svelte/base}/src/routes/+page.svelte +1 -1
  101. package/scaffold/svelte/base/static/.gitkeep +0 -0
  102. package/scaffold/svelte/index.ts +21 -0
  103. package/scaffold/svelte/variants/dashboard/src/routes/+layout.svelte +64 -0
  104. package/scaffold/svelte/variants/dashboard/src/routes/+page.svelte +104 -0
  105. package/scaffold/svelte/variants/docs/src/routes/+layout.svelte +60 -0
  106. package/scaffold/svelte/variants/docs/src/routes/+page.svelte +34 -0
  107. package/scaffold/svelte/variants/docs/src/routes/docs/getting-started/+page.svelte +31 -0
  108. package/scaffold/{svelte-core → svelte/variants/full}/README-RIZZO.md +2 -1
  109. package/scaffold/svelte/variants/full/gitignore +10 -0
  110. package/scaffold/svelte/variants/full/package.json +20 -0
  111. package/scaffold/svelte/variants/full/src/app.d.ts +11 -0
  112. package/scaffold/svelte/variants/full/src/app.html +16 -0
  113. package/scaffold/svelte/variants/full/src/routes/+layout.svelte +10 -0
  114. package/scaffold/svelte/variants/full/src/routes/+page.svelte +105 -0
  115. package/scaffold/svelte/variants/full/static/.gitkeep +0 -0
  116. package/scaffold/svelte/variants/full/svelte.config.js +10 -0
  117. package/scaffold/svelte/variants/full/tsconfig.json +11 -0
  118. package/scaffold/vanilla/README-RIZZO.md +8 -6
  119. package/scaffold/vanilla/components/accordion.html +63 -64
  120. package/scaffold/vanilla/components/alert-dialog.html +644 -0
  121. package/scaffold/vanilla/components/alert.html +63 -64
  122. package/scaffold/vanilla/components/aspect-ratio.html +644 -0
  123. package/scaffold/vanilla/components/avatar.html +63 -64
  124. package/scaffold/vanilla/components/back-to-top.html +63 -64
  125. package/scaffold/vanilla/components/badge.html +63 -64
  126. package/scaffold/vanilla/components/breadcrumb.html +63 -64
  127. package/scaffold/vanilla/components/button-group.html +644 -0
  128. package/scaffold/vanilla/components/button.html +63 -64
  129. package/scaffold/vanilla/components/cards.html +63 -64
  130. package/scaffold/vanilla/components/collapsible.html +644 -0
  131. package/scaffold/vanilla/components/context-menu.html +644 -0
  132. package/scaffold/vanilla/components/copy-to-clipboard.html +63 -64
  133. package/scaffold/vanilla/components/dashboard.html +644 -0
  134. package/scaffold/vanilla/components/divider.html +63 -64
  135. package/scaffold/vanilla/components/docs-sidebar.html +63 -64
  136. package/scaffold/vanilla/components/dropdown.html +63 -64
  137. package/scaffold/vanilla/components/empty.html +644 -0
  138. package/scaffold/vanilla/components/font-switcher.html +63 -64
  139. package/scaffold/vanilla/components/footer.html +63 -64
  140. package/scaffold/vanilla/components/forms.html +63 -64
  141. package/scaffold/vanilla/components/hover-card.html +644 -0
  142. package/scaffold/vanilla/components/icons.html +63 -64
  143. package/scaffold/vanilla/components/index.html +83 -64
  144. package/scaffold/vanilla/components/kbd.html +644 -0
  145. package/scaffold/vanilla/components/label.html +644 -0
  146. package/scaffold/vanilla/components/modal.html +63 -64
  147. package/scaffold/vanilla/components/navbar.html +63 -64
  148. package/scaffold/vanilla/components/pagination.html +63 -64
  149. package/scaffold/vanilla/components/popover.html +644 -0
  150. package/scaffold/vanilla/components/progress-bar.html +63 -64
  151. package/scaffold/vanilla/components/resizable.html +644 -0
  152. package/scaffold/vanilla/components/scroll-area.html +644 -0
  153. package/scaffold/vanilla/components/search.html +63 -64
  154. package/scaffold/vanilla/components/separator.html +644 -0
  155. package/scaffold/vanilla/components/settings.html +63 -64
  156. package/scaffold/vanilla/components/sheet.html +644 -0
  157. package/scaffold/vanilla/components/skeleton.html +644 -0
  158. package/scaffold/vanilla/components/slider.html +644 -0
  159. package/scaffold/vanilla/components/sound-effects.html +63 -64
  160. package/scaffold/vanilla/components/spinner.html +63 -64
  161. package/scaffold/vanilla/components/switch.html +644 -0
  162. package/scaffold/vanilla/components/table.html +63 -64
  163. package/scaffold/vanilla/components/tabs.html +63 -64
  164. package/scaffold/vanilla/components/theme-switcher.html +63 -64
  165. package/scaffold/vanilla/components/toast.html +63 -64
  166. package/scaffold/vanilla/components/toggle-group.html +644 -0
  167. package/scaffold/vanilla/components/toggle.html +644 -0
  168. package/scaffold/vanilla/components/tooltip.html +63 -64
  169. package/scaffold/vanilla/index.html +65 -66
  170. package/scaffold/vanilla/variants/dashboard/index.html +45 -0
  171. package/scaffold/vanilla/variants/docs/getting-started.html +35 -0
  172. package/scaffold/vanilla/variants/docs/index.html +36 -0
  173. package/scaffold/vanilla/variants/full/components/accordion.html +592 -0
  174. package/scaffold/vanilla/variants/full/components/alert.html +592 -0
  175. package/scaffold/vanilla/variants/full/components/avatar.html +592 -0
  176. package/scaffold/vanilla/variants/full/components/back-to-top.html +592 -0
  177. package/scaffold/vanilla/variants/full/components/badge.html +592 -0
  178. package/scaffold/vanilla/variants/full/components/breadcrumb.html +592 -0
  179. package/scaffold/vanilla/variants/full/components/button.html +592 -0
  180. package/scaffold/vanilla/variants/full/components/cards.html +592 -0
  181. package/scaffold/vanilla/variants/full/components/copy-to-clipboard.html +592 -0
  182. package/scaffold/vanilla/variants/full/components/dashboard.html +592 -0
  183. package/scaffold/vanilla/variants/full/components/divider.html +592 -0
  184. package/scaffold/vanilla/variants/full/components/docs-sidebar.html +592 -0
  185. package/scaffold/vanilla/variants/full/components/dropdown.html +592 -0
  186. package/scaffold/vanilla/variants/full/components/font-switcher.html +592 -0
  187. package/scaffold/vanilla/variants/full/components/footer.html +592 -0
  188. package/scaffold/vanilla/variants/full/components/forms.html +592 -0
  189. package/scaffold/vanilla/variants/full/components/icons.html +592 -0
  190. package/scaffold/vanilla/variants/full/components/index.html +625 -0
  191. package/scaffold/vanilla/variants/full/components/modal.html +592 -0
  192. package/scaffold/vanilla/variants/full/components/navbar.html +592 -0
  193. package/scaffold/vanilla/variants/full/components/pagination.html +592 -0
  194. package/scaffold/vanilla/variants/full/components/progress-bar.html +592 -0
  195. package/scaffold/vanilla/variants/full/components/search.html +592 -0
  196. package/scaffold/vanilla/variants/full/components/settings.html +592 -0
  197. package/scaffold/vanilla/variants/full/components/skeleton.html +592 -0
  198. package/scaffold/vanilla/variants/full/components/sound-effects.html +592 -0
  199. package/scaffold/vanilla/variants/full/components/spinner.html +592 -0
  200. package/scaffold/vanilla/variants/full/components/switch.html +592 -0
  201. package/scaffold/vanilla/variants/full/components/table.html +592 -0
  202. package/scaffold/vanilla/variants/full/components/tabs.html +592 -0
  203. package/scaffold/vanilla/variants/full/components/theme-switcher.html +592 -0
  204. package/scaffold/vanilla/variants/full/components/toast.html +592 -0
  205. package/scaffold/vanilla/variants/full/components/tooltip.html +592 -0
  206. package/scaffold/vanilla/variants/full/index.html +682 -0
  207. package/scaffold/vanilla/variants/full/js/main.js +989 -0
  208. package/scaffold/astro-core/.astro/content-assets.mjs +0 -1
  209. package/scaffold/astro-core/.astro/content-modules.mjs +0 -1
  210. package/scaffold/astro-core/.astro/content.d.ts +0 -199
  211. package/scaffold/astro-core/.astro/types.d.ts +0 -2
  212. package/scaffold/astro-core/.env.example +0 -3
  213. package/scaffold/svelte-core/.env.example +0 -3
  214. /package/scaffold/{astro-core → astro/base}/astro.config.mjs +0 -0
  215. /package/scaffold/{astro-core → astro/base}/dist/.gitkeep +0 -0
  216. /package/scaffold/{astro-core → astro/base}/dist/_noop-middleware.mjs +0 -0
  217. /package/scaffold/{astro-core → astro/base}/dist/chunks/astro/server_9Mzx7luy.mjs +0 -0
  218. /package/scaffold/{astro-core → astro/base}/dist/chunks/astro_BOYUKg7r.mjs +0 -0
  219. /package/scaffold/{astro-core → astro/base}/dist/favicon.svg +0 -0
  220. /package/scaffold/{astro-core → astro/base}/dist/manifest_DXpJmqSX.mjs +0 -0
  221. /package/scaffold/{astro-core → astro/base}/dist/noop-entrypoint.mjs +0 -0
  222. /package/scaffold/{astro-core → astro/base}/dist/pages/index.astro.mjs +0 -0
  223. /package/scaffold/{astro-core → astro/base}/dist/renderers.mjs +0 -0
  224. /package/scaffold/{astro-core → astro/base}/gitignore +0 -0
  225. /package/scaffold/{astro-core → astro/base}/node_modules/.astro/data-store.json +0 -0
  226. /package/scaffold/{astro-core → astro/base}/node_modules/.vite/deps/_metadata.json +0 -0
  227. /package/scaffold/{astro-core → astro/base}/node_modules/.vite/deps/astro___aria-query.js +0 -0
  228. /package/scaffold/{astro-core → astro/base}/node_modules/.vite/deps/astro___aria-query.js.map +0 -0
  229. /package/scaffold/{astro-core → astro/base}/node_modules/.vite/deps/astro___axobject-query.js +0 -0
  230. /package/scaffold/{astro-core → astro/base}/node_modules/.vite/deps/astro___axobject-query.js.map +0 -0
  231. /package/scaffold/{astro-core → astro/base}/node_modules/.vite/deps/astro___cssesc.js +0 -0
  232. /package/scaffold/{astro-core → astro/base}/node_modules/.vite/deps/astro___cssesc.js.map +0 -0
  233. /package/scaffold/{astro-core → astro/base}/node_modules/.vite/deps/chunk-BUSYA2B4.js +0 -0
  234. /package/scaffold/{astro-core → astro/base}/node_modules/.vite/deps/chunk-BUSYA2B4.js.map +0 -0
  235. /package/scaffold/{astro-core → astro/base}/node_modules/.vite/deps/package.json +0 -0
  236. /package/scaffold/{astro-core → astro/base}/package.json +0 -0
  237. /package/scaffold/{astro-core → astro/base}/public/.gitkeep +0 -0
  238. /package/scaffold/{astro-core → astro/base}/public/favicon.svg +0 -0
  239. /package/scaffold/{astro-core → astro/base}/src/components/rizzo/CopyToClipboard.astro +0 -0
  240. /package/scaffold/{astro-core → astro/base}/src/components/rizzo/icons/Check.astro +0 -0
  241. /package/scaffold/{astro-core → astro/base}/src/components/rizzo/icons/Copy.astro +0 -0
  242. /package/scaffold/{astro-core → astro/base}/src/layouts/Layout.astro +0 -0
  243. /package/scaffold/{astro-core → astro/base}/tsconfig.json +0 -0
  244. /package/scaffold/{svelte-core/static → astro/variants/full/dist}/.gitkeep +0 -0
  245. /package/scaffold/{svelte-core → svelte/base}/gitignore +0 -0
  246. /package/scaffold/{svelte-core → svelte/base}/package.json +0 -0
  247. /package/scaffold/{svelte-core → svelte/base}/src/app.d.ts +0 -0
  248. /package/scaffold/{svelte-core → svelte/base}/src/app.html +0 -0
  249. /package/scaffold/{svelte-core → svelte/base}/src/routes/+layout.svelte +0 -0
  250. /package/scaffold/{svelte-core → svelte/base}/svelte.config.js +0 -0
  251. /package/scaffold/{svelte-core → svelte/base}/tsconfig.json +0 -0
package/bin/rizzo-css.js CHANGED
@@ -25,7 +25,7 @@ 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. */
28
+ /** Setup instructions + snippets when we skip overwriting; written by init for landing/docs/dashboard/full. */
29
29
  const RIZZO_SETUP_FILE = 'RIZZO-SETUP.md';
30
30
 
31
31
  const COMMANDS = ['init', 'add', 'theme', 'doctor', 'help'];
@@ -33,26 +33,15 @@ const FRAMEWORKS = ['vanilla', 'astro', 'svelte'];
33
33
  /** Supported package managers: detection, install/add commands, and --package-manager override. */
34
34
  const VALID_PACKAGE_MANAGERS = ['npm', 'pnpm', 'yarn', 'bun'];
35
35
 
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. */
37
- const TEMPLATES = {
38
- vanilla: [
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' },
42
- ],
43
- astro: [
44
- { value: 'minimal', label: 'Minimal — CSS, fonts, icons, sfx + RIZZO-SETUP.md (no files overwritten)' },
45
- { value: 'starter', label: 'Starter — Same 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' },
47
- ],
48
- svelte: [
49
- { value: 'minimal', label: 'Minimal — CSS, fonts, icons, sfx + RIZZO-SETUP.md (no files overwritten)' },
50
- { value: 'starter', label: 'Starter — Same 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' },
52
- ],
53
- };
36
+ /** Template options for create new and add to existing. All get full framework + Rizzo; template chooses starter content. */
37
+ const TEMPLATES = [
38
+ { value: 'landing', label: 'Landing — Marketing/hero page with features and CTAs' },
39
+ { value: 'docs', label: 'DocsDocumentation site with sidebar and sample doc page' },
40
+ { value: 'dashboard', label: 'DashboardApp dashboard with sidebar, stat cards, and table' },
41
+ { value: 'full', label: 'Full — Clone of the Rizzo docs site (home, docs, components, themes)' },
42
+ ];
54
43
 
55
- /** Build RIZZO-SETUP.md content: instructions + snippets. Never overwrites; use for minimal/starter or when files were skipped. */
44
+ /** Build RIZZO-SETUP.md content: instructions + snippets. Never overwrites; use for landing or when files were skipped. */
56
45
  function buildRizzoSetupMd(framework, opts) {
57
46
  const { linkTag, linkHref, theme, defaultDark, defaultLight, skippedFiles = [], exampleMinimalPage } = opts;
58
47
  const fw = framework === 'vanilla' ? 'Vanilla' : framework === 'astro' ? 'Astro' : 'Svelte';
@@ -96,9 +85,9 @@ Your project already had these files. Add the following snippets manually if you
96
85
  }
97
86
  }
98
87
  if (exampleMinimalPage) {
99
- md += `## Example minimal page
88
+ md += `## Example landing page
100
89
 
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`;
90
+ If you don't have an HTML file yet, you can use this (from \`scaffold/landing/index.html\`):\n\n\`\`\`html\n${exampleMinimalPage}\n\`\`\`\n\n`;
102
91
  }
103
92
  md += `## Docs
104
93
 
@@ -111,7 +100,7 @@ If you don't have an HTML file yet, you can use this (from \`scaffold/minimal/in
111
100
 
112
101
  const VANILLA_MANUAL_README = `# Vanilla + Rizzo CSS (Full template)
113
102
 
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).
103
+ Full template: HTML + CSS, plus the component pages you chose (or all). Scaffolded with \`npx rizzo-css init --framework vanilla --template full\` (or \`npx rizzo-css add --template full\` for existing projects).
115
104
 
116
105
  - Open \`index.html\` in a browser or serve the folder with any static server.
117
106
  - Edit \`index.html\` and add your content. CSS: \`css/rizzo.min.css\`.
@@ -153,29 +142,35 @@ const LIGHT_THEMES = [
153
142
  'semi-light-purple',
154
143
  ];
155
144
  const THEMES = [...DARK_THEMES, ...LIGHT_THEMES];
156
- // Components available for scaffold (must match scaffold/svelte and scaffold/astro)
145
+ // Components available for scaffold (must match scaffold/svelte and scaffold/astro; missing files are skipped on copy)
157
146
  const SVELTE_COMPONENTS = [
158
- 'Button', 'Badge', 'Card', 'Divider', 'DocsSidebar', 'Footer', 'Spinner', 'ProgressBar', 'Avatar', 'Alert',
147
+ 'Button', 'Badge', 'Card', 'Dashboard', 'Divider', 'DocsSidebar', 'Footer', 'Spinner', 'ProgressBar', 'Avatar', 'Alert',
159
148
  'BackToTop', 'Breadcrumb', 'FormGroup', 'Input', 'Checkbox', 'Textarea', 'Select', 'Radio',
160
149
  'CopyToClipboard', 'Tooltip', 'Pagination', 'Tabs', 'Accordion', 'Dropdown',
161
150
  'Modal', 'Toast', 'Table', 'ThemeSwitcher', 'FontSwitcher', 'SoundEffects',
162
- 'Navbar', 'Settings', 'Search', 'Icons',
151
+ 'Navbar', 'Settings', 'Search', 'Icons', 'Skeleton', 'Switch',
152
+ 'Label', 'Kbd', 'Collapsible', 'AlertDialog', 'AspectRatio', 'ButtonGroup', 'Empty', 'Separator',
153
+ 'Slider', 'Sheet', 'Popover', 'Toggle', 'ToggleGroup', 'ScrollArea', 'HoverCard', 'ContextMenu', 'ResizablePaneGroup', 'ResizablePane', 'ResizableHandle',
163
154
  ];
164
155
  const ASTRO_COMPONENTS = [
165
- 'Button', 'Badge', 'Card', 'Divider', 'DocsSidebar', 'Footer', 'Spinner', 'ProgressBar', 'Avatar', 'Alert',
156
+ 'Button', 'Badge', 'Card', 'Dashboard', 'Divider', 'DocsSidebar', 'Footer', 'Spinner', 'ProgressBar', 'Avatar', 'Alert',
166
157
  'BackToTop', 'Breadcrumb', 'FormGroup', 'Input', 'Checkbox', 'Textarea', 'Select', 'Radio',
167
158
  'CopyToClipboard', 'Tooltip', 'Pagination', 'Tabs', 'Accordion', 'Dropdown',
168
159
  'Modal', 'Toast', 'Table', 'ThemeSwitcher', 'FontSwitcher', 'SoundEffects',
169
- 'Navbar', 'Settings', 'Search', 'Icons',
160
+ 'Navbar', 'Settings', 'Search', 'Icons', 'Skeleton', 'Switch',
161
+ 'Label', 'Kbd', 'Collapsible', 'AlertDialog', 'AspectRatio', 'ButtonGroup', 'Empty', 'Separator',
162
+ 'Slider', 'Sheet', 'Popover', 'Toggle', 'ToggleGroup', 'ScrollArea', 'HoverCard', 'ContextMenu', 'ResizablePaneGroup', 'ResizablePane', 'ResizableHandle',
170
163
  ];
171
164
 
172
165
  // Base set for Manual: all interactive components we ship (so manual has a full working set). Full includes everything (same list).
173
166
  const RECOMMENDED_COMPONENTS = [
174
- 'Button', 'Badge', 'Card', 'Divider', 'DocsSidebar', 'Footer', 'Spinner', 'ProgressBar', 'Avatar', 'Alert',
167
+ 'Button', 'Badge', 'Card', 'Dashboard', 'Divider', 'DocsSidebar', 'Footer', 'Spinner', 'ProgressBar', 'Avatar', 'Alert',
175
168
  'BackToTop', 'Breadcrumb', 'FormGroup', 'Input', 'Checkbox', 'Textarea', 'Select', 'Radio',
176
169
  'CopyToClipboard', 'Tooltip', 'Pagination', 'Tabs', 'Accordion', 'Dropdown',
177
170
  'Modal', 'Toast', 'Table', 'ThemeSwitcher', 'FontSwitcher', 'SoundEffects',
178
- 'Navbar', 'Search', 'Settings', 'Icons',
171
+ 'Navbar', 'Search', 'Settings', 'Icons', 'Skeleton', 'Switch',
172
+ 'Label', 'Kbd', 'Collapsible', 'AlertDialog', 'AspectRatio', 'ButtonGroup', 'Empty', 'Separator',
173
+ 'Slider', 'Sheet', 'Popover', 'Toggle', 'ToggleGroup', 'ScrollArea', 'HoverCard', 'ContextMenu', 'ResizablePaneGroup', 'ResizablePane', 'ResizableHandle',
179
174
  ];
180
175
 
181
176
  // Vanilla components that need js/main.js for interactivity.
@@ -236,15 +231,16 @@ function logAddedDeps(selected, expanded, framework) {
236
231
  if (byRequirement.length) console.log('\n Also adding: ' + byRequirement.join('; '));
237
232
  }
238
233
 
239
- // Vanilla scaffold: component name (same as ASTRO_COMPONENTS) -> components/*.html slug.
234
+ // Vanilla scaffold: component name (same as ASTRO_COMPONENTS) -> components/*.html slug. New components (label, kbd, etc.) have stub pages in scaffold/vanilla/components/.
240
235
  const VANILLA_COMPONENT_SLUGS = {
241
- Accordion: 'accordion', Alert: 'alert', Avatar: 'avatar', BackToTop: 'back-to-top', Badge: 'badge', Breadcrumb: 'breadcrumb', Button: 'button',
242
- Card: 'cards', Checkbox: 'forms', CopyToClipboard: 'copy-to-clipboard', Divider: 'divider', DocsSidebar: 'docs-sidebar', Dropdown: 'dropdown',
243
- Footer: 'footer', FormGroup: 'forms', Input: 'forms', Modal: 'modal', Pagination: 'pagination', ProgressBar: 'progress-bar',
244
- Radio: 'forms', Search: 'search', Select: 'forms', Settings: 'settings', Spinner: 'spinner', Table: 'table',
245
- Tabs: 'tabs', Textarea: 'forms', ThemeSwitcher: 'theme-switcher', Toast: 'toast', Tooltip: 'tooltip',
246
- FontSwitcher: 'font-switcher', SoundEffects: 'sound-effects',
247
- Navbar: 'navbar', Icons: 'icons',
236
+ Accordion: 'accordion', Alert: 'alert', AlertDialog: 'alert-dialog', AspectRatio: 'aspect-ratio', Avatar: 'avatar', BackToTop: 'back-to-top', Badge: 'badge', Breadcrumb: 'breadcrumb', Button: 'button', ButtonGroup: 'button-group',
237
+ Card: 'cards', Checkbox: 'forms', Collapsible: 'collapsible', ContextMenu: 'context-menu', CopyToClipboard: 'copy-to-clipboard', Dashboard: 'dashboard', Divider: 'divider', DocsSidebar: 'docs-sidebar', Dropdown: 'dropdown',
238
+ Empty: 'empty', Footer: 'footer', FormGroup: 'forms', HoverCard: 'hover-card', Input: 'forms', Icons: 'icons', Kbd: 'kbd', Label: 'label',
239
+ Modal: 'modal', Navbar: 'navbar', Pagination: 'pagination', Popover: 'popover', ProgressBar: 'progress-bar',
240
+ Radio: 'forms', ResizableHandle: 'resizable', ResizablePane: 'resizable', ResizablePaneGroup: 'resizable', ScrollArea: 'scroll-area', Search: 'search', Separator: 'separator', Select: 'forms', Settings: 'settings', Sheet: 'sheet',
241
+ Skeleton: 'skeleton', Slider: 'slider', SoundEffects: 'sound-effects', Spinner: 'spinner', Switch: 'switch', Table: 'table',
242
+ Tabs: 'tabs', Textarea: 'forms', ThemeSwitcher: 'theme-switcher', Toast: 'toast', Toggle: 'toggle', ToggleGroup: 'toggle-group', Tooltip: 'tooltip',
243
+ FontSwitcher: 'font-switcher',
248
244
  };
249
245
 
250
246
  // ANSI colors for CLI (framework logo colors)
@@ -464,10 +460,11 @@ function parsePackageManager(value) {
464
460
  return VALID_PACKAGE_MANAGERS.includes(v) ? v : null;
465
461
  }
466
462
 
467
- /** Get positional args for a command (excludes --flag and --flag value). Used for e.g. add Button ThemeSwitcher. */
468
- function getPositionalArgs(argv) {
463
+ /** Get positional args for a command (excludes --flag and --flag value). Used for e.g. add Button ThemeSwitcher. startIndex: skip this many args (e.g. 3 to skip node, script, command name). */
464
+ function getPositionalArgs(argv, startIndex) {
465
+ const start = startIndex == null ? 1 : startIndex;
469
466
  const positionals = [];
470
- for (let i = 1; i < argv.length; i++) {
467
+ for (let i = start; i < argv.length; i++) {
471
468
  if (argv[i].startsWith('--')) {
472
469
  if (!argv[i].includes('=') && i + 1 < argv.length) i += 2;
473
470
  else i++;
@@ -543,10 +540,35 @@ async function promptPackageManager(projectDir) {
543
540
  return selectMenu(options, '? Package manager (for install and run commands)');
544
541
  }
545
542
 
546
- /** Prompt user to select template (Minimal, Starter, Full) for the chosen framework. Returns 'minimal' | 'starter' | 'full'. */
547
- async function promptTemplate(framework) {
548
- const options = TEMPLATES[framework] || TEMPLATES.vanilla;
549
- return selectMenu(options, '? Template (we never overwrite your existing files)?');
543
+ /** Prompt user to select template (Landing, Docs, Dashboard, Full) for create new or add to existing. Returns 'landing' | 'docs' | 'dashboard' | 'full'. */
544
+ async function promptTemplate() {
545
+ return selectMenu(TEMPLATES, '? Which template? (all get full framework + Rizzo)');
546
+ }
547
+
548
+ /** Path to variant overlay (docs, dashboard, or full). Landing uses base as-is so no overlay. Framework scaffolds live under scaffold/<framework>/variants/<variation>. */
549
+ function getVariantDir(framework, variation) {
550
+ if (variation !== 'docs' && variation !== 'dashboard' && variation !== 'full') return null;
551
+ const dir = join(getPackageRoot(), 'scaffold', framework, 'variants', variation);
552
+ return existsSync(dir) ? dir : null;
553
+ }
554
+
555
+ /** When template is Full we copy the entire full variant (site clone) instead of base + overlay. Returns true if full variant exists. */
556
+ function hasFullVariant(framework) {
557
+ return getVariantDir(framework, 'full') !== null;
558
+ }
559
+
560
+ /** Copy variant overlay onto project (after base). Applies replacements. Overwrites matching paths. */
561
+ function copyVariantOverlay(projectDir, framework, variation, replacements) {
562
+ const variantDir = getVariantDir(framework, variation);
563
+ if (!variantDir) return;
564
+ copyDirRecursiveWithReplacements(variantDir, projectDir, replacements);
565
+ }
566
+
567
+ /** Copy variant overlay with no-overwrite (for add to existing). Returns { skipped } like copyDirRecursiveWithReplacementsNoOverwrite. */
568
+ function copyVariantOverlayNoOverwrite(projectDir, framework, variation, replacements) {
569
+ const variantDir = getVariantDir(framework, variation);
570
+ if (!variantDir) return { skipped: [] };
571
+ return copyDirRecursiveWithReplacementsNoOverwrite(variantDir, projectDir, replacements, projectDir);
550
572
  }
551
573
 
552
574
  function question(prompt) {
@@ -900,7 +922,7 @@ Available commands: init, add, theme, doctor, help
900
922
 
901
923
  Flags summary:
902
924
  init --yes --path <dir> --framework <fw> --template <t> --package-manager <pm> --install --no-install --no-git
903
- add --path <dir> --framework <fw> --template minimal|starter|full --no-snippet --readme --force --vanilla-js
925
+ add --path <dir> --framework <fw> --template landing|docs|dashboard|full --no-snippet --readme --force --vanilla-js
904
926
  theme (no flags)
905
927
  doctor Check config, CSS file, and optional layout link
906
928
  help (no flags)
@@ -912,16 +934,16 @@ Usage (use your package manager):
912
934
  bunx rizzo-css <command> [options]
913
935
 
914
936
  Commands:
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.
937
+ init New or existing. Create new → template (Landing | Docs | Dashboard | Full); all get full framework + Rizzo. Then component picker (all 56 or pick; Full = site clone skips picker). We never overwrite; skipped content in RIZZO-SETUP.md.
938
+ add Add to existing: same template as create new (Landing | Docs | Dashboard | Full). Never overwrites existing or config files. Framework detected or from rizzo-css.json.
917
939
  theme List all available themes (use in init or set data-theme on <html>)
918
940
  help Show this help
919
941
 
920
942
  Options (init):
921
- --yes Non-interactive: scaffold new in cwd with defaults (framework: astro, template: full)
943
+ --yes Non-interactive: scaffold new in cwd with defaults (framework: astro, template: landing)
922
944
  --path <dir> Project directory (relative to cwd or absolute). Scaffold and run install there. With --yes; interactive: "Enter path" option.
923
945
  --framework <fw> vanilla | astro | svelte (with --yes; otherwise first prompt)
924
- --template <t> minimal | starter | full (or legacy: core | manual; both map to full); with --yes defaults to full
946
+ --template <t> create new: landing | docs | dashboard | full (default: landing). add: same four options.
925
947
  --package-manager <pm> npm | pnpm | yarn | bun (with --yes, or skip PM prompt when interactive)
926
948
  --install After scaffolding, run package manager install in project directory (no prompt)
927
949
  --no-install Do not run install and do not prompt
@@ -929,7 +951,7 @@ Options (init):
929
951
  (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.)
930
952
 
931
953
  Options (add):
932
- --template <t> minimal | starter | full (same as init; Full = component picker, writes RIZZO-SNIPPET.txt)
954
+ --template <t> landing | docs | dashboard | full (same as init; Full = site clone)
933
955
  --path <dir> Target directory for rizzo.min.css (overrides config and framework default)
934
956
  --framework <fw> vanilla | astro | svelte (overrides config and detection)
935
957
  --package-manager <pm> npm | pnpm | yarn | bun (override detection for install/print commands)
@@ -969,7 +991,7 @@ Examples:
969
991
  npx rizzo-css init --yes --path my-app --framework astro --install
970
992
  npx rizzo-css init --yes --framework astro --package-manager pnpm --install
971
993
  npx rizzo-css init --yes --framework vanilla
972
- npx rizzo-css init --yes --framework svelte --template full
994
+ npx rizzo-css init --yes --framework svelte --template landing
973
995
  npx rizzo-css add --package-manager yarn --install-package
974
996
  npx rizzo-css add
975
997
  npx rizzo-css add Button
@@ -1094,7 +1116,7 @@ function componentOptionLabel(framework, name) {
1094
1116
  return name + suffix;
1095
1117
  }
1096
1118
 
1097
- /** Ask what to include: CSS only, all 29 interactive, all components, or pick. Returns array of component names. Only call when componentList.length > 0. initialSelection: when set (e.g. for manual = all 29 pre-selected), skip the menu and show multi-select with these pre-selected. */
1119
+ /** Ask what to include: CSS only, all interactive (recommended), all components, or pick. Returns array of component names. Only call when componentList.length > 0. initialSelection: when set (e.g. for manual = all 29 pre-selected), skip the menu and show multi-select with these pre-selected. */
1098
1120
  async function promptComponentChoice(componentList, framework, initialSelection) {
1099
1121
  const recommended = RECOMMENDED_COMPONENTS.filter((c) => componentList.includes(c));
1100
1122
  if (initialSelection !== undefined) {
@@ -1183,14 +1205,15 @@ async function cmdAdd(argv) {
1183
1205
  const explicitFrameworkRaw = getFlagValue(argv, '--framework');
1184
1206
  const explicitFramework = explicitFrameworkRaw && FRAMEWORKS.includes(explicitFrameworkRaw.toLowerCase()) ? explicitFrameworkRaw.toLowerCase() : null;
1185
1207
  const templateRaw = getFlagValue(argv, '--template');
1186
- const template = templateRaw && ['minimal', 'starter', 'full'].includes(templateRaw.toLowerCase()) ? templateRaw.toLowerCase() : undefined;
1208
+ const validAddTemplates = ['landing', 'docs', 'dashboard', 'full']; // same four as create new
1209
+ const template = templateRaw && validAddTemplates.includes(templateRaw.toLowerCase()) ? templateRaw.toLowerCase() : undefined;
1187
1210
  const installPackage = hasFlag(argv, '--install-package');
1188
1211
  const noInstall = hasFlag(argv, '--no-install');
1189
1212
  const writeSnippet = !hasFlag(argv, '--no-snippet');
1190
1213
  const writeReadme = hasFlag(argv, '--readme');
1191
1214
  const force = hasFlag(argv, '--force');
1192
1215
  const copyVanillaJs = hasFlag(argv, '--vanilla-js');
1193
- const positionals = getPositionalArgs(argv);
1216
+ const positionals = getPositionalArgs(argv, 3);
1194
1217
 
1195
1218
  const cwd = process.cwd();
1196
1219
  const config = readRizzoConfig(cwd);
@@ -1242,20 +1265,18 @@ function getScaffoldVanillaIndex() {
1242
1265
  return join(getPackageRoot(), 'scaffold', 'vanilla', 'index.html');
1243
1266
  }
1244
1267
 
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');
1268
+ /** Path to Landing template (simple index.html). Used when template is Landing (single-page snippet). */
1269
+ function getLandingTemplatePath() {
1270
+ const landingPath = join(getPackageRoot(), 'scaffold', 'landing', 'index.html');
1271
+ if (existsSync(landingPath)) return landingPath;
1272
+ return join(getPackageRoot(), 'scaffold', 'minimal', 'index.html'); // fallback
1248
1273
  }
1249
1274
 
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) {
1275
+ /** Load landing template HTML from scaffold and apply replacements; fallback to inline if file missing. */
1276
+ function getLandingTemplateHtml(opts) {
1257
1277
  const { theme, themeComment, name, framework } = opts;
1258
1278
  const linkHref = framework === 'vanilla' ? 'css/rizzo.min.css' : '/css/rizzo.min.css';
1279
+ const templatePath = getLandingTemplatePath();
1259
1280
  if (existsSync(templatePath)) {
1260
1281
  let html = readFileSync(templatePath, 'utf8');
1261
1282
  return html
@@ -1280,14 +1301,6 @@ function getMinimalOrStarterTemplateHtml(opts, templatePath) {
1280
1301
  `;
1281
1302
  }
1282
1303
 
1283
- function getMinimalTemplateHtml(opts) {
1284
- return getMinimalOrStarterTemplateHtml(opts, getMinimalTemplatePath());
1285
- }
1286
-
1287
- function getStarterTemplateHtml(opts) {
1288
- return getMinimalOrStarterTemplateHtml(opts, getStarterTemplatePath());
1289
- }
1290
-
1291
1304
  function getScaffoldVanillaIconsDir() {
1292
1305
  return join(getPackageRoot(), 'scaffold', 'vanilla', 'icons');
1293
1306
  }
@@ -1296,11 +1309,23 @@ function getScaffoldVanillaComponentsDir() {
1296
1309
  return join(getPackageRoot(), 'scaffold', 'vanilla', 'components');
1297
1310
  }
1298
1311
 
1312
+ /** Read shared navbar snippet and fill {{TITLE}} and {{NAVBAR_BRAND_HREF}}. Same component as Astro/Svelte (flat links: Docs, Components, Blocks, Themes, Colors). */
1313
+ function getNavbarHtmlVanilla(title, brandHref) {
1314
+ const path = join(getPackageRoot(), 'scaffold', 'shared', 'navbar-vanilla.html');
1315
+ if (!existsSync(path)) return '';
1316
+ let html = readFileSync(path, 'utf8');
1317
+ return html.replace(/\{\{TITLE\}\}/g, title || 'App').replace(/\{\{NAVBAR_BRAND_HREF\}\}/g, brandHref || '#');
1318
+ }
1319
+
1299
1320
  /** Copy selected Vanilla component HTML files into projectDir/components/, with replacements. Writes a simple components/index.html. */
1300
1321
  function copyVanillaComponents(projectDir, selectedNames, replacements) {
1301
1322
  const srcDir = getScaffoldVanillaComponentsDir();
1302
1323
  if (!existsSync(srcDir)) return;
1303
1324
  const linkHref = replacements['{{LINK_HREF}}'] || 'css/rizzo.min.css';
1325
+ const title = replacements['{{TITLE}}'] || 'App';
1326
+ if (!replacements['{{NAVBAR_HTML}}']) {
1327
+ replacements['{{NAVBAR_HTML}}'] = getNavbarHtmlVanilla(title, '../index.html');
1328
+ }
1304
1329
  const slugsToCopy = [];
1305
1330
  const seen = new Set();
1306
1331
  for (const name of selectedNames) {
@@ -1324,6 +1349,7 @@ function copyVanillaComponents(projectDir, selectedNames, replacements) {
1324
1349
  }
1325
1350
  }
1326
1351
  const indexLinks = slugsToCopy.map((s) => ' <li><a href="' + s + '.html">' + s + '</a></li>').join('\n');
1352
+ const navHtml = getNavbarHtmlVanilla(title, '../index.html');
1327
1353
  const indexHtml = `<!DOCTYPE html>
1328
1354
  <html lang="en" data-theme="${replacements['{{DATA_THEME}}'] || 'github-dark-classic'}">
1329
1355
  <head>
@@ -1333,7 +1359,9 @@ function copyVanillaComponents(projectDir, selectedNames, replacements) {
1333
1359
  <link rel="stylesheet" href="../${linkHref}" />
1334
1360
  </head>
1335
1361
  <body>
1336
- <main style="padding: var(--spacing-6); max-width: 60ch;">
1362
+ <a href="#main-content" class="skip-link">Skip to main content</a>
1363
+ ${navHtml}
1364
+ <main id="main-content" style="padding: var(--spacing-6); max-width: 60ch;">
1337
1365
  <h1>Components</h1>
1338
1366
  <ul>
1339
1367
  ${indexLinks}
@@ -1371,11 +1399,11 @@ function copyRizzoIcons(projectDir, framework) {
1371
1399
  }
1372
1400
 
1373
1401
  function getScaffoldAstroCoreDir() {
1374
- return join(getPackageRoot(), 'scaffold', 'astro-core');
1402
+ return join(getPackageRoot(), 'scaffold', 'astro', 'base');
1375
1403
  }
1376
1404
 
1377
1405
  function getScaffoldSvelteCoreDir() {
1378
- return join(getPackageRoot(), 'scaffold', 'svelte-core');
1406
+ return join(getPackageRoot(), 'scaffold', 'svelte', 'base');
1379
1407
  }
1380
1408
 
1381
1409
  function copyDirRecursive(src, dest) {
@@ -1580,7 +1608,7 @@ function copyAstroComponents(projectDir, selectedNames) {
1580
1608
  }
1581
1609
  }
1582
1610
 
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? }. */
1611
+ /** Add Rizzo CSS to an existing project. Same variation as create new: Landing | Docs | Dashboard. We never overwrite existing files (including config files). frameworkOverride: when set (from init), skip framework prompt. options: { config?, targetDir?, template? } — template is variation: landing|docs|dashboard (or full→landing). */
1584
1612
  async function runAddToExisting(frameworkOverride, options) {
1585
1613
  const cwd = process.cwd();
1586
1614
  const config = (options && options.config) || readRizzoConfig(cwd);
@@ -1599,15 +1627,16 @@ async function runAddToExisting(frameworkOverride, options) {
1599
1627
  framework = await selectMenu(frameworkOptions, frameworkPrompt);
1600
1628
  }
1601
1629
 
1602
- // Same template choice as new project: Minimal | Starter | Full (we never overwrite existing files)
1603
- const addTemplate = (options && options.template) || await promptTemplate(framework);
1630
+ // Same choice as create new: template (Landing | Docs | Dashboard | Full). --template accepts landing|docs|dashboard|full.
1631
+ let selectedVariation = (options && options.template) || null;
1632
+ if (!selectedVariation || !['landing', 'docs', 'dashboard', 'full'].includes(selectedVariation)) {
1633
+ selectedVariation = await promptTemplate();
1634
+ }
1604
1635
 
1605
1636
  const componentList = framework === 'svelte' ? SVELTE_COMPONENTS : framework === 'astro' ? ASTRO_COMPONENTS : framework === 'vanilla' ? Object.keys(VANILLA_COMPONENT_SLUGS) : [];
1606
1637
  const preselected = options.preselectedComponents && options.preselectedComponents.length > 0 ? options.preselectedComponents : null;
1607
1638
  let selectedComponents;
1608
- if (addTemplate === 'minimal' || addTemplate === 'starter') {
1609
- selectedComponents = [];
1610
- } else if (preselected && componentList.length > 0) {
1639
+ if (preselected && componentList.length > 0) {
1611
1640
  const valid = preselected.filter((c) => componentList.includes(c));
1612
1641
  const invalid = preselected.filter((c) => !componentList.includes(c));
1613
1642
  if (invalid.length > 0) {
@@ -1626,6 +1655,7 @@ async function runAddToExisting(frameworkOverride, options) {
1626
1655
  : [];
1627
1656
  }
1628
1657
 
1658
+ // Only ask about theming when ThemeSwitcher is selected (we will inject theme into layout/config).
1629
1659
  let theme, defaultDark, defaultLight;
1630
1660
  const wantsThemeSwitcher = selectedComponents.includes('ThemeSwitcher');
1631
1661
  if (wantsThemeSwitcher && !preselected) {
@@ -1634,7 +1664,7 @@ async function runAddToExisting(frameworkOverride, options) {
1634
1664
  { value: true, label: 'Yes — choose default dark, default light, and initial theme' },
1635
1665
  { value: false, label: 'No — use defaults (github-dark-classic / github-light)' },
1636
1666
  ],
1637
- '? Set default themes for ThemeSwitcher? (same as create-new flow)'
1667
+ '? Set default themes for ThemeSwitcher?'
1638
1668
  );
1639
1669
  if (setDefaults) {
1640
1670
  const out = await promptThemes();
@@ -1682,6 +1712,66 @@ async function runAddToExisting(frameworkOverride, options) {
1682
1712
  } else {
1683
1713
  options._overwriteCss = true;
1684
1714
  }
1715
+
1716
+ // For Astro/Svelte add: copy base + variant with no-overwrite. For Vanilla add with docs/dashboard/full: copy variant overlay.
1717
+ let addSkippedFiles = [];
1718
+ const astroCoreDir = getScaffoldAstroCoreDir();
1719
+ const svelteCoreDir = getScaffoldSvelteCoreDir();
1720
+ const themeCommentAdd = ' <!-- Initial: ' + theme + '; dark: ' + defaultDark + '; light: ' + defaultLight + ' (all 14 themes in CSS) -->';
1721
+ if (framework === 'vanilla' && getVariantDir('vanilla', selectedVariation)) {
1722
+ const vanillaRepl = { '{{LINK_HREF}}': 'css/rizzo.min.css', '{{TITLE}}': 'App', '{{DATA_THEME}}': theme, '{{THEME_LIST_COMMENT}}': themeCommentAdd };
1723
+ const variantResult = copyVariantOverlayNoOverwrite(cwd, 'vanilla', selectedVariation, vanillaRepl);
1724
+ if (variantResult && variantResult.skipped) addSkippedFiles = variantResult.skipped;
1725
+ } else if ((framework === 'astro' && existsSync(astroCoreDir)) || (framework === 'svelte' && existsSync(svelteCoreDir))) {
1726
+ const themeComment = themeCommentAdd;
1727
+ const replacements = {
1728
+ '{{DATA_THEME}}': theme,
1729
+ '{{DEFAULT_DARK}}': defaultDark,
1730
+ '{{DEFAULT_LIGHT}}': defaultLight,
1731
+ '{{THEME_LIST_COMMENT}}': themeComment,
1732
+ '{{TITLE}}': 'App',
1733
+ '{{PROJECT_NAME}}': 'app',
1734
+ '{{RIZZO_SOUND_SCRIPT}}': '',
1735
+ };
1736
+ const componentsToCopy = selectedComponents.length > 0 ? expandWithDeps(framework, selectedComponents) : [];
1737
+ if (framework === 'astro') {
1738
+ const hasNavbar = componentsToCopy.includes('Navbar');
1739
+ const hasSettings = componentsToCopy.includes('Settings');
1740
+ const hasSound = hasSettings || componentsToCopy.includes('SoundEffects');
1741
+ const layoutImports = [];
1742
+ if (hasNavbar) layoutImports.push("import Navbar from '../components/rizzo/Navbar.astro';");
1743
+ if (hasSettings) layoutImports.push("import Settings from '../components/rizzo/Settings.astro';");
1744
+ replacements['{{RIZZO_LAYOUT_IMPORTS}}'] = layoutImports.length ? '\n' + layoutImports.join('\n') + '\n' : '\n';
1745
+ replacements['{{RIZZO_LAYOUT_BODY_TOP}}'] = hasNavbar ? '\n <Navbar />' : '';
1746
+ replacements['{{RIZZO_LAYOUT_BODY_BOTTOM}}'] = hasSettings ? '\n <Settings />' : '';
1747
+ if (hasSound) {
1748
+ const soundPath = join(getPackageRoot(), 'scaffold', 'shared', 'sound-effects-inline.js');
1749
+ if (existsSync(soundPath)) {
1750
+ replacements['{{RIZZO_SOUND_SCRIPT}}'] = '\n <script is:inline>\n' + readFileSync(soundPath, 'utf8') + '\n </script>';
1751
+ }
1752
+ }
1753
+ }
1754
+ if (framework === 'svelte') {
1755
+ const hasSound = componentsToCopy.includes('Settings') || componentsToCopy.includes('SoundEffects');
1756
+ if (hasSound) {
1757
+ const soundPath = join(getPackageRoot(), 'scaffold', 'shared', 'sound-effects-inline.js');
1758
+ if (existsSync(soundPath)) {
1759
+ replacements['{{RIZZO_SOUND_SCRIPT}}'] = '\n <script>\n' + readFileSync(soundPath, 'utf8') + '\n </script>';
1760
+ }
1761
+ }
1762
+ }
1763
+ mkdirSync(cwd, { recursive: true });
1764
+ if (framework === 'astro') {
1765
+ const baseResult = copyDirRecursiveWithReplacementsNoOverwrite(astroCoreDir, cwd, replacements, cwd);
1766
+ const variantResult = copyVariantOverlayNoOverwrite(cwd, 'astro', selectedVariation, replacements);
1767
+ addSkippedFiles = baseResult.skipped.concat(variantResult.skipped || []);
1768
+ } else if (framework === 'svelte') {
1769
+ const baseResult = copyDirRecursiveWithReplacementsNoOverwrite(svelteCoreDir, cwd, replacements, cwd);
1770
+ const variantResult = copyVariantOverlayNoOverwrite(cwd, 'svelte', selectedVariation, replacements);
1771
+ addSkippedFiles = baseResult.skipped.concat(variantResult.skipped || []);
1772
+ }
1773
+ }
1774
+
1685
1775
  if (options._overwriteCss) {
1686
1776
  if (framework === 'astro') {
1687
1777
  copyRizzoCssAndFontsForAstro(cwd, cssSource);
@@ -1748,11 +1838,11 @@ async function runAddToExisting(frameworkOverride, options) {
1748
1838
  if (!hadConfig) {
1749
1839
  writeRizzoConfig(cwd, { targetDir: configTargetDir, framework, packageManager: pm.agent, theme });
1750
1840
  }
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 });
1841
+ // Same assets and docs as create new. Include any skipped files (from base/variant copy) in RIZZO-SETUP.md.
1842
+ const setupMdContent = buildRizzoSetupMd(framework, { linkHref, theme, defaultDark, defaultLight, skippedFiles: addSkippedFiles.length > 0 ? addSkippedFiles : undefined });
1753
1843
  writeFileSync(join(cwd, RIZZO_SETUP_FILE), setupMdContent + '\n', 'utf8');
1754
1844
  copyPackageLicense(cwd);
1755
- const writeSnippet = options.writeSnippet !== false && addTemplate === 'full';
1845
+ const writeSnippet = options.writeSnippet !== false;
1756
1846
  if (writeSnippet) {
1757
1847
  const where = framework === 'svelte' ? 'Root layout (e.g. src/app.html)' : framework === 'astro' ? 'Layout (e.g. src/layouts/Layout.astro)' : 'HTML or layout';
1758
1848
  const snippetBody = [
@@ -1774,6 +1864,9 @@ async function runAddToExisting(frameworkOverride, options) {
1774
1864
  console.log('\n✓ Rizzo CSS added to your existing project');
1775
1865
  console.log(' - ' + cssTarget + ' (CSS, fonts' + (framework === 'vanilla' ? ', sfx' : '') + ')');
1776
1866
  console.log(' - Icons and ' + RIZZO_SETUP_FILE);
1867
+ if (selectedVariation && selectedVariation !== 'landing') {
1868
+ console.log(' - Variation: ' + selectedVariation + ' (layout + starter content; existing files not overwritten).');
1869
+ }
1777
1870
  if (!hadConfig) console.log(' - Wrote ' + RIZZO_CONFIG_FILE);
1778
1871
  console.log(' - Wrote ' + RIZZO_SETUP_FILE + ' (instructions + link + theme)');
1779
1872
  if (writeSnippet) console.log(' - Wrote ' + RIZZO_SNIPPET_FILE + ' (copy-paste link + theme)');
@@ -1820,6 +1913,7 @@ async function cmdInit(argv) {
1820
1913
  let theme, defaultDark, defaultLight;
1821
1914
  let selectedPm;
1822
1915
  let selectedTemplate;
1916
+ let selectedVariation = 'landing'; // For create new: landing | docs | dashboard (all get full setup)
1823
1917
  let selectedComponents = [];
1824
1918
  let fullAllComponents = false;
1825
1919
 
@@ -1828,9 +1922,11 @@ async function cmdInit(argv) {
1828
1922
  framework = (frameworkArg && FRAMEWORKS.includes(frameworkArg.toLowerCase())) ? frameworkArg.toLowerCase() : (config && config.framework) || 'astro';
1829
1923
  initMode = 'new';
1830
1924
  const templateArg = getFlagValue(argv, '--template');
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;
1925
+ const defaultTemplate = 'landing';
1926
+ const validTemplates = ['landing', 'docs', 'dashboard', 'full'];
1927
+ const rawTemplate = (templateArg && validTemplates.includes(templateArg)) ? templateArg : defaultTemplate;
1928
+ selectedVariation = rawTemplate;
1929
+ selectedTemplate = 'full'; // all four templates get full framework + Rizzo
1834
1930
  if (selectedTemplate === 'full') {
1835
1931
  fullAllComponents = true;
1836
1932
  if (framework === 'svelte') selectedComponents = [...SVELTE_COMPONENTS];
@@ -1884,12 +1980,18 @@ async function cmdInit(argv) {
1884
1980
  }
1885
1981
  }
1886
1982
 
1887
- selectedTemplate = await promptTemplate(framework);
1983
+ // Create new: choose template (Landing | Docs | Dashboard | Full)
1984
+ selectedVariation = await promptTemplate();
1985
+ selectedTemplate = 'full'; // all templates get full framework + Rizzo
1888
1986
 
1889
- if (selectedTemplate === 'full') {
1987
+ // Full template = site clone (no component picker); Landing/Docs/Dashboard = choose all or pick components
1988
+ if (selectedVariation === 'full' && hasFullVariant(framework)) {
1989
+ fullAllComponents = true;
1990
+ selectedComponents = framework === 'svelte' ? [...SVELTE_COMPONENTS] : framework === 'astro' ? [...ASTRO_COMPONENTS] : Object.keys(VANILLA_COMPONENT_SLUGS);
1991
+ } else if (selectedVariation !== 'full' || !hasFullVariant(framework)) {
1890
1992
  const addChoice = await selectMenu(
1891
1993
  [
1892
- { value: 'all', label: 'All 34 components' },
1994
+ { value: 'all', label: 'All components' },
1893
1995
  { value: 'pick', label: 'Pick components (choose which to include)' },
1894
1996
  ],
1895
1997
  '? Add all components or pick which to include?'
@@ -1953,11 +2055,13 @@ async function cmdInit(argv) {
1953
2055
  const astroCoreDir = getScaffoldAstroCoreDir();
1954
2056
  const svelteCoreDir = getScaffoldSvelteCoreDir();
1955
2057
  const pathsForScaffold = getFrameworkCssPaths(framework);
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());
2058
+ const useFullVariant = selectedVariation === 'full' && hasFullVariant(framework);
2059
+ const useHandpickAstro = selectedTemplate === 'full' && !fullAllComponents && framework === 'astro' && existsSync(astroCoreDir) && !useFullVariant;
2060
+ const useHandpickSvelte = selectedTemplate === 'full' && !fullAllComponents && framework === 'svelte' && existsSync(svelteCoreDir) && !useFullVariant;
2061
+ const useAstroBase = selectedTemplate === 'full' && fullAllComponents && framework === 'astro' && existsSync(astroCoreDir) && !useFullVariant;
2062
+ const useSvelteBase = selectedTemplate === 'full' && fullAllComponents && framework === 'svelte' && existsSync(svelteCoreDir) && !useFullVariant;
2063
+ const useVanillaCore = selectedTemplate === 'full' && fullAllComponents && framework === 'vanilla' && existsSync(getScaffoldVanillaIndex()) && !useFullVariant && selectedVariation === 'landing';
2064
+ const useVanillaWithOverlay = selectedTemplate === 'full' && framework === 'vanilla' && (selectedVariation === 'docs' || selectedVariation === 'dashboard') && getVariantDir('vanilla', selectedVariation);
1961
2065
 
1962
2066
  // Full gets all required dependencies so everything works; manual gets deps when user picks (see prompt labels).
1963
2067
  let componentsToCopy = selectedComponents;
@@ -1966,7 +2070,7 @@ async function cmdInit(argv) {
1966
2070
  logAddedDeps(selectedComponents, componentsToCopy, framework);
1967
2071
  }
1968
2072
  let vanillaSoundScript = '';
1969
- if (framework === 'vanilla' && (useVanillaCore || componentsToCopy.includes('Settings') || componentsToCopy.includes('SoundEffects'))) {
2073
+ if (framework === 'vanilla' && (useVanillaCore || useVanillaWithOverlay || componentsToCopy.includes('Settings') || componentsToCopy.includes('SoundEffects'))) {
1970
2074
  const soundPath = join(getPackageRoot(), 'scaffold', 'shared', 'sound-effects-inline.js');
1971
2075
  if (existsSync(soundPath)) {
1972
2076
  let script = readFileSync(soundPath, 'utf8');
@@ -1975,17 +2079,20 @@ async function cmdInit(argv) {
1975
2079
  }
1976
2080
  }
1977
2081
 
1978
- // Astro layout: inject Navbar and Settings when those components are selected so the settings menu works.
1979
- if ((framework === 'astro') && (useHandpickAstro || useAstroBase)) {
1980
- const hasNavbar = componentsToCopy.includes('Navbar');
1981
- const hasSettings = componentsToCopy.includes('Settings');
1982
- const hasSound = useAstroBase || hasSettings || componentsToCopy.includes('SoundEffects');
2082
+ // Astro layout: inject Navbar, Settings, Footer when Full variant or when those components are selected.
2083
+ const astroFullLayout = (framework === 'astro') && (useFullVariant || useHandpickAstro || useAstroBase);
2084
+ if (astroFullLayout) {
2085
+ const hasNavbar = useFullVariant || componentsToCopy.includes('Navbar');
2086
+ const hasSettings = useFullVariant || componentsToCopy.includes('Settings');
2087
+ const hasFooter = useFullVariant || componentsToCopy.includes('Footer');
2088
+ const hasSound = useFullVariant || useAstroBase || hasSettings || componentsToCopy.includes('SoundEffects');
1983
2089
  const layoutImports = [];
1984
2090
  if (hasNavbar) layoutImports.push("import Navbar from '../components/rizzo/Navbar.astro';");
1985
2091
  if (hasSettings) layoutImports.push("import Settings from '../components/rizzo/Settings.astro';");
2092
+ if (hasFooter) layoutImports.push("import Footer from '../components/rizzo/Footer.astro';");
1986
2093
  replacements['{{RIZZO_LAYOUT_IMPORTS}}'] = layoutImports.length ? '\n' + layoutImports.join('\n') + '\n' : '\n';
1987
2094
  replacements['{{RIZZO_LAYOUT_BODY_TOP}}'] = hasNavbar ? '\n <Navbar />' : '';
1988
- replacements['{{RIZZO_LAYOUT_BODY_BOTTOM}}'] = hasSettings ? '\n <Settings />' : '';
2095
+ replacements['{{RIZZO_LAYOUT_BODY_BOTTOM}}'] = [hasSettings ? '\n <Settings />' : '', hasFooter ? '\n <Footer />' : ''].filter(Boolean).join('');
1989
2096
  if (hasSound) {
1990
2097
  const soundPath = join(getPackageRoot(), 'scaffold', 'shared', 'sound-effects-inline.js');
1991
2098
  if (existsSync(soundPath)) {
@@ -1998,6 +2105,13 @@ async function cmdInit(argv) {
1998
2105
  replacements['{{RIZZO_LAYOUT_BODY_BOTTOM}}'] = '';
1999
2106
  }
2000
2107
 
2108
+ if (useFullVariant && framework === 'svelte') {
2109
+ const soundPath = join(getPackageRoot(), 'scaffold', 'shared', 'sound-effects-inline.js');
2110
+ if (existsSync(soundPath)) {
2111
+ replacements['{{RIZZO_SOUND_SCRIPT}}'] = '\n <script>\n' + readFileSync(soundPath, 'utf8') + '\n </script>';
2112
+ }
2113
+ }
2114
+
2001
2115
  // Svelte app.html: inject sound script when Settings or SoundEffects is included (identical behavior to Astro).
2002
2116
  if ((framework === 'svelte') && (useHandpickSvelte || useSvelteBase)) {
2003
2117
  const hasSound = useSvelteBase || componentsToCopy.includes('Settings') || componentsToCopy.includes('SoundEffects');
@@ -2012,11 +2126,57 @@ async function cmdInit(argv) {
2012
2126
  let cssTarget;
2013
2127
  let indexPath;
2014
2128
 
2015
- const minimalHtml = getStarterTemplateHtml({ theme, themeComment, name, framework });
2129
+ const landingHtml = getLandingTemplateHtml({ theme, themeComment, name, framework });
2016
2130
 
2017
- if (useHandpickAstro) {
2131
+ if (useFullVariant && framework === 'astro') {
2132
+ mkdirSync(projectDir, { recursive: true });
2133
+ const fullDir = getVariantDir('astro', 'full');
2134
+ copyDirRecursiveWithReplacements(fullDir, projectDir, replacements);
2135
+ copyRizzoCssAndFontsForAstro(projectDir, cssSource);
2136
+ copyAstroComponents(projectDir, componentsToCopy);
2137
+ cssTarget = join(projectDir, 'public', 'css', 'rizzo.min.css');
2138
+ if (existsSync(cssTarget) && statSync(cssTarget).size < 5000) {
2139
+ console.warn('\nWarning: rizzo.min.css is very small. From repo root run: pnpm build:css');
2140
+ }
2141
+ copyPackageLicense(projectDir);
2142
+ copyAstroGitignore(projectDir);
2143
+ copyRizzoIcons(projectDir, 'astro');
2144
+ } else if (useFullVariant && framework === 'svelte') {
2145
+ mkdirSync(projectDir, { recursive: true });
2146
+ const fullDir = getVariantDir('svelte', 'full');
2147
+ copyDirRecursiveWithReplacements(fullDir, projectDir, replacements);
2148
+ copyRizzoCssAndFontsForSvelte(projectDir, cssSource);
2149
+ copySvelteComponents(projectDir, componentsToCopy);
2150
+ cssTarget = join(projectDir, 'static', 'css', 'rizzo.min.css');
2151
+ if (existsSync(cssTarget) && statSync(cssTarget).size < 5000) {
2152
+ console.warn('\nWarning: rizzo.min.css is very small. From repo root run: pnpm build:css');
2153
+ }
2154
+ copyPackageLicense(projectDir);
2155
+ copySvelteGitignore(projectDir);
2156
+ copyRizzoIcons(projectDir, 'svelte');
2157
+ } else if (useFullVariant && framework === 'vanilla') {
2158
+ mkdirSync(projectDir, { recursive: true });
2159
+ replacements['{{LINK_HREF}}'] = pathsForScaffold.linkHref || 'css/rizzo.min.css';
2160
+ replacements['{{NAVBAR_HTML}}'] = getNavbarHtmlVanilla(name || 'App', 'index.html');
2161
+ const fullDir = getVariantDir('vanilla', 'full');
2162
+ copyDirRecursiveWithReplacements(fullDir, projectDir, replacements);
2163
+ copyVanillaComponents(projectDir, Object.keys(VANILLA_COMPONENT_SLUGS), replacements);
2164
+ const cssDir = join(projectDir, pathsForScaffold.targetDir);
2165
+ cssTarget = join(cssDir, 'rizzo.min.css');
2166
+ mkdirSync(cssDir, { recursive: true });
2167
+ copyFileSync(cssSource, cssTarget);
2168
+ copyRizzoFonts(dirname(cssTarget));
2169
+ copyRizzoSfx(projectDir);
2170
+ if (existsSync(cssTarget) && statSync(cssTarget).size < 5000) {
2171
+ console.warn('\nWarning: rizzo.min.css is very small. From repo root run: pnpm build:css');
2172
+ }
2173
+ copyPackageLicense(projectDir);
2174
+ copyVanillaGitignore(projectDir);
2175
+ copyRizzoIcons(projectDir, 'vanilla');
2176
+ } else if (useHandpickAstro) {
2018
2177
  mkdirSync(projectDir, { recursive: true });
2019
2178
  const { skipped } = copyDirRecursiveWithReplacementsNoOverwrite(astroCoreDir, projectDir, replacements, projectDir);
2179
+ copyVariantOverlay(projectDir, 'astro', selectedVariation, replacements);
2020
2180
  copyRizzoCssAndFontsForAstro(projectDir, cssSource);
2021
2181
  if (skipped.length > 0) {
2022
2182
  writeFileSync(join(projectDir, RIZZO_SETUP_FILE), buildRizzoSetupMd('astro', { linkHref: '/css/rizzo.min.css', theme, defaultDark, defaultLight, skippedFiles: skipped }), 'utf8');
@@ -2034,6 +2194,7 @@ async function cmdInit(argv) {
2034
2194
  } else if (useAstroBase) {
2035
2195
  mkdirSync(projectDir, { recursive: true });
2036
2196
  const { skipped } = copyDirRecursiveWithReplacementsNoOverwrite(astroCoreDir, projectDir, replacements, projectDir);
2197
+ copyVariantOverlay(projectDir, 'astro', selectedVariation, replacements);
2037
2198
  copyRizzoCssAndFontsForAstro(projectDir, cssSource);
2038
2199
  if (skipped.length > 0) {
2039
2200
  writeFileSync(join(projectDir, RIZZO_SETUP_FILE), buildRizzoSetupMd('astro', { linkHref: '/css/rizzo.min.css', theme, defaultDark, defaultLight, skippedFiles: skipped }), 'utf8');
@@ -2051,6 +2212,7 @@ async function cmdInit(argv) {
2051
2212
  } else if (useHandpickSvelte) {
2052
2213
  mkdirSync(projectDir, { recursive: true });
2053
2214
  const { skipped } = copyDirRecursiveWithReplacementsNoOverwrite(svelteCoreDir, projectDir, replacements, projectDir);
2215
+ copyVariantOverlay(projectDir, 'svelte', selectedVariation, replacements);
2054
2216
  copyRizzoCssAndFontsForSvelte(projectDir, cssSource);
2055
2217
  if (skipped.length > 0) {
2056
2218
  writeFileSync(join(projectDir, RIZZO_SETUP_FILE), buildRizzoSetupMd('svelte', { linkHref: '/css/rizzo.min.css', theme, defaultDark, defaultLight, skippedFiles: skipped }), 'utf8');
@@ -2068,6 +2230,7 @@ async function cmdInit(argv) {
2068
2230
  } else if (useSvelteBase) {
2069
2231
  mkdirSync(projectDir, { recursive: true });
2070
2232
  const { skipped } = copyDirRecursiveWithReplacementsNoOverwrite(svelteCoreDir, projectDir, replacements, projectDir);
2233
+ copyVariantOverlay(projectDir, 'svelte', selectedVariation, replacements);
2071
2234
  copyRizzoCssAndFontsForSvelte(projectDir, cssSource);
2072
2235
  if (skipped.length > 0) {
2073
2236
  writeFileSync(join(projectDir, RIZZO_SETUP_FILE), buildRizzoSetupMd('svelte', { linkHref: '/css/rizzo.min.css', theme, defaultDark, defaultLight, skippedFiles: skipped }), 'utf8');
@@ -2082,7 +2245,7 @@ async function cmdInit(argv) {
2082
2245
  copyRizzoIcons(projectDir, 'svelte');
2083
2246
  copySvelteComponents(projectDir, componentsToCopy);
2084
2247
  }
2085
- } else if (useVanillaCore) {
2248
+ } else if (useVanillaCore || useVanillaWithOverlay) {
2086
2249
  const cssDir = join(projectDir, pathsForScaffold.targetDir);
2087
2250
  cssTarget = join(cssDir, 'rizzo.min.css');
2088
2251
  const linkHref = 'css/rizzo.min.css';
@@ -2093,21 +2256,28 @@ async function cmdInit(argv) {
2093
2256
  if (statSync(cssTarget).size < 5000) {
2094
2257
  console.warn('\nWarning: rizzo.min.css is very small. From repo root run: pnpm build:css');
2095
2258
  }
2096
- const vanillaScaffoldPath = getScaffoldVanillaIndex();
2097
- indexPath = join(projectDir, 'index.html');
2098
- let indexHtml = readFileSync(vanillaScaffoldPath, 'utf8');
2099
- indexHtml = indexHtml
2100
- .replace(/\{\{DATA_THEME\}\}/g, theme)
2101
- .replace(/\{\{DEFAULT_DARK\}\}/g, defaultDark)
2102
- .replace(/\{\{DEFAULT_LIGHT\}\}/g, defaultLight)
2103
- .replace(/\{\{THEME_LIST_COMMENT\}\}/g, themeComment)
2104
- .replace(/\{\{TITLE\}\}/g, name || 'App')
2105
- .replace(/\{\{LINK_HREF\}\}/g, linkHref);
2106
2259
  const vanillaSkipped = [];
2107
- if (existsSync(indexPath)) {
2108
- vanillaSkipped.push({ relativePath: 'index.html', content: indexHtml });
2260
+ if (useVanillaWithOverlay) {
2261
+ copyVariantOverlay(projectDir, 'vanilla', selectedVariation, { ...replacements, '{{LINK_HREF}}': linkHref, '{{TITLE}}': name || 'App', '{{DATA_THEME}}': theme, '{{THEME_LIST_COMMENT}}': themeComment });
2262
+ indexPath = join(projectDir, 'index.html');
2109
2263
  } else {
2110
- writeFileSync(indexPath, indexHtml, 'utf8');
2264
+ const vanillaScaffoldPath = getScaffoldVanillaIndex();
2265
+ indexPath = join(projectDir, 'index.html');
2266
+ let indexHtml = readFileSync(vanillaScaffoldPath, 'utf8');
2267
+ const navbarForIndex = getNavbarHtmlVanilla(name || 'App', 'index.html');
2268
+ indexHtml = indexHtml
2269
+ .replace(/\{\{DATA_THEME\}\}/g, theme)
2270
+ .replace(/\{\{DEFAULT_DARK\}\}/g, defaultDark)
2271
+ .replace(/\{\{DEFAULT_LIGHT\}\}/g, defaultLight)
2272
+ .replace(/\{\{THEME_LIST_COMMENT\}\}/g, themeComment)
2273
+ .replace(/\{\{TITLE\}\}/g, name || 'App')
2274
+ .replace(/\{\{LINK_HREF\}\}/g, linkHref)
2275
+ .replace(/\{\{NAVBAR_HTML\}\}/g, navbarForIndex);
2276
+ if (existsSync(indexPath)) {
2277
+ vanillaSkipped.push({ relativePath: 'index.html', content: indexHtml });
2278
+ } else {
2279
+ writeFileSync(indexPath, indexHtml, 'utf8');
2280
+ }
2111
2281
  }
2112
2282
  copyRizzoIcons(projectDir, 'vanilla');
2113
2283
  const vanillaReadme = join(getPackageRoot(), 'scaffold', 'vanilla', SCAFFOLD_README_FILENAME);
@@ -2122,14 +2292,15 @@ async function cmdInit(argv) {
2122
2292
  writeFileSync(join(projectDir, 'js', 'main.js'), mainJs, 'utf8');
2123
2293
  }
2124
2294
  const vanillaCoreRepl = { ...replacements, '{{LINK_HREF}}': linkHref };
2125
- copyVanillaComponents(projectDir, Object.keys(VANILLA_COMPONENT_SLUGS), vanillaCoreRepl);
2295
+ const vanillaComponentSet = (useVanillaCore || fullAllComponents) ? Object.keys(VANILLA_COMPONENT_SLUGS) : selectedComponents;
2296
+ copyVanillaComponents(projectDir, vanillaComponentSet, vanillaCoreRepl);
2126
2297
  if (vanillaSkipped.length > 0) {
2127
2298
  writeFileSync(join(projectDir, RIZZO_SETUP_FILE), buildRizzoSetupMd('vanilla', { linkHref, theme, defaultDark, defaultLight, skippedFiles: vanillaSkipped }), 'utf8');
2128
2299
  }
2129
2300
  copyPackageLicense(projectDir);
2130
2301
  copyVanillaGitignore(projectDir);
2131
2302
  } else {
2132
- // Minimal and Starter: same assets as add flow CSS, fonts, icons, sfx (framework-appropriate)
2303
+ // Add-to-existing (landing) or Vanilla create new with picked components: CSS, fonts, icons, sfx (framework-appropriate)
2133
2304
  if (framework === 'astro') {
2134
2305
  copyRizzoCssAndFontsForAstro(projectDir, cssSource);
2135
2306
  cssTarget = join(projectDir, 'public', 'css', 'rizzo.min.css');
@@ -2144,7 +2315,7 @@ async function cmdInit(argv) {
2144
2315
  copyRizzoFonts(dirname(cssTarget));
2145
2316
  copyRizzoSfx(projectDir);
2146
2317
  }
2147
- if (selectedTemplate === 'minimal' || selectedTemplate === 'starter') {
2318
+ if (selectedTemplate === 'landing') {
2148
2319
  copyRizzoIcons(projectDir, framework);
2149
2320
  }
2150
2321
  if (statSync(cssTarget).size < 5000) {
@@ -2156,34 +2327,33 @@ async function cmdInit(argv) {
2156
2327
  theme,
2157
2328
  defaultDark,
2158
2329
  defaultLight,
2159
- ...(selectedTemplate === 'minimal' && { exampleMinimalPage: getMinimalTemplateHtml({ theme, themeComment, name, framework }) }),
2330
+ ...(selectedTemplate === 'landing' && { exampleMinimalPage: getLandingTemplateHtml({ theme, themeComment, name, framework }) }),
2160
2331
  });
2161
2332
 
2162
- if (selectedTemplate === 'minimal') {
2163
- writeFileSync(join(projectDir, RIZZO_SETUP_FILE), setupMdContent, 'utf8');
2164
- copyPackageLicense(projectDir);
2165
- } else if (selectedTemplate === 'starter') {
2333
+ if (selectedTemplate === 'landing') {
2166
2334
  const vanillaIndex = join(projectDir, 'index.html');
2335
+ const landingHtmlForAdd = getLandingTemplateHtml({ theme, themeComment, name, framework });
2167
2336
  const astroIndex = join(projectDir, 'public', 'index.html');
2168
2337
  const svelteIndex = join(projectDir, 'static', 'index.html');
2169
2338
  if (framework === 'vanilla' && !existsSync(vanillaIndex)) {
2170
2339
  indexPath = vanillaIndex;
2171
- writeFileSync(vanillaIndex, minimalHtml, 'utf8');
2340
+ writeFileSync(vanillaIndex, landingHtmlForAdd, 'utf8');
2172
2341
  } else if (framework === 'astro' && !existsSync(astroIndex)) {
2173
2342
  mkdirSync(join(projectDir, 'public'), { recursive: true });
2174
2343
  indexPath = astroIndex;
2175
- writeFileSync(astroIndex, minimalHtml, 'utf8');
2344
+ writeFileSync(astroIndex, landingHtmlForAdd, 'utf8');
2176
2345
  } else if (framework === 'svelte' && !existsSync(svelteIndex)) {
2177
2346
  mkdirSync(join(projectDir, 'static'), { recursive: true });
2178
2347
  indexPath = svelteIndex;
2179
- writeFileSync(svelteIndex, minimalHtml, 'utf8');
2348
+ writeFileSync(svelteIndex, landingHtmlForAdd, 'utf8');
2180
2349
  }
2181
2350
  writeFileSync(join(projectDir, RIZZO_SETUP_FILE), setupMdContent, 'utf8');
2182
2351
  copyPackageLicense(projectDir);
2352
+ if (framework === 'vanilla') copyVanillaGitignore(projectDir);
2183
2353
  } else if (framework === 'vanilla' && selectedTemplate === 'full' && !fullAllComponents) {
2184
2354
  indexPath = join(projectDir, 'index.html');
2185
2355
  if (!existsSync(indexPath)) {
2186
- let indexContent = minimalHtml;
2356
+ let indexContent = landingHtml;
2187
2357
  if (selectedComponents.length > 0) {
2188
2358
  mkdirSync(join(projectDir, 'js'), { recursive: true });
2189
2359
  const vanillaJs = join(getPackageRoot(), 'scaffold', 'vanilla', 'js', 'main.js');
@@ -2195,11 +2365,11 @@ async function cmdInit(argv) {
2195
2365
  const vanillaRepl = { ...replacements, '{{LINK_HREF}}': 'css/rizzo.min.css' };
2196
2366
  copyVanillaComponents(projectDir, selectedComponents, vanillaRepl);
2197
2367
  copyRizzoIcons(projectDir, 'vanilla');
2198
- indexContent = minimalHtml.replace('</body>', ' <script src="js/main.js"></script>\n</body>');
2368
+ indexContent = landingHtml.replace('</body>', ' <script src="js/main.js"></script>\n</body>');
2199
2369
  }
2200
2370
  writeFileSync(indexPath, indexContent, 'utf8');
2201
2371
  } 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');
2372
+ writeFileSync(join(projectDir, RIZZO_SETUP_FILE), buildRizzoSetupMd(framework, { linkHref: 'css/rizzo.min.css', theme, defaultDark, defaultLight, skippedFiles: [{ relativePath: 'index.html', content: landingHtml }] }), 'utf8');
2203
2373
  }
2204
2374
  writeFileSync(join(projectDir, SCAFFOLD_README_FILENAME), VANILLA_MANUAL_README, 'utf8');
2205
2375
  copyVanillaGitignore(projectDir);
@@ -2207,15 +2377,15 @@ async function cmdInit(argv) {
2207
2377
  } else if (framework === 'astro') {
2208
2378
  indexPath = join(projectDir, 'public', 'index.html');
2209
2379
  mkdirSync(join(projectDir, 'public'), { recursive: true });
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');
2380
+ if (!existsSync(indexPath)) writeFileSync(indexPath, landingHtml, 'utf8');
2381
+ else writeFileSync(join(projectDir, RIZZO_SETUP_FILE), buildRizzoSetupMd(framework, { linkHref: '/css/rizzo.min.css', theme, defaultDark, defaultLight, skippedFiles: [{ relativePath: 'public/index.html', content: landingHtml }] }), 'utf8');
2212
2382
  writeFileSync(join(projectDir, SCAFFOLD_README_FILENAME), FALLBACK_MINIMAL_README, 'utf8');
2213
2383
  copyPackageLicense(projectDir);
2214
2384
  } else if (framework === 'svelte') {
2215
2385
  indexPath = join(projectDir, 'static', 'index.html');
2216
2386
  mkdirSync(join(projectDir, 'static'), { recursive: true });
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');
2387
+ if (!existsSync(indexPath)) writeFileSync(indexPath, landingHtml, 'utf8');
2388
+ else writeFileSync(join(projectDir, RIZZO_SETUP_FILE), buildRizzoSetupMd(framework, { linkHref: '/css/rizzo.min.css', theme, defaultDark, defaultLight, skippedFiles: [{ relativePath: 'static/index.html', content: landingHtml }] }), 'utf8');
2219
2389
  writeFileSync(join(projectDir, SCAFFOLD_README_FILENAME), FALLBACK_MINIMAL_README, 'utf8');
2220
2390
  copyPackageLicense(projectDir);
2221
2391
  } else {
@@ -2227,9 +2397,9 @@ async function cmdInit(argv) {
2227
2397
  console.log(' - ' + cssTarget);
2228
2398
  if (indexPath) console.log(' - ' + indexPath);
2229
2399
  if (framework === 'vanilla') {
2230
- if (useVanillaCore) {
2231
- console.log(' - Vanilla JS (full): theme switcher, js/main.js, icons, component showcase, ' + SCAFFOLD_README_FILENAME + '.');
2232
- } else if (selectedTemplate === 'minimal' || selectedTemplate === 'starter') {
2400
+ if (useVanillaCore || useVanillaWithOverlay) {
2401
+ console.log(' - Vanilla JS (full): theme switcher, js/main.js, icons, component showcase, ' + SCAFFOLD_README_FILENAME + '.' + (useVanillaWithOverlay ? ' (' + selectedVariation + ' template)' : ''));
2402
+ } else if (selectedTemplate === 'landing') {
2233
2403
  console.log(' - ' + RIZZO_SETUP_FILE + ' has instructions and snippets.');
2234
2404
  } else {
2235
2405
  console.log(' - Vanilla JS (picked components): index.html + CSS. Add JS from docs or ' + RIZZO_SETUP_FILE + '.');
@@ -2296,6 +2466,9 @@ async function cmdInit(argv) {
2296
2466
  const createExample = getCreateProjectExample(pm, framework);
2297
2467
  console.log('\n - Basic template (CSS + index). To get a full app: ' + createExample + ', then cd into the project and run ' + pm.dlx('rizzo-css add') + '.');
2298
2468
  }
2469
+ if (selectedVariation && selectedVariation !== 'landing') {
2470
+ console.log(' - Variation: ' + selectedVariation + ' (layout + starter content).');
2471
+ }
2299
2472
  if (hasPackageJson) {
2300
2473
  console.log('\nNext: ' + runPrefix + nextStep);
2301
2474
  } else if (framework === 'vanilla') {