rizzo-css 0.0.53 → 0.0.55

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 (252) hide show
  1. package/README.md +13 -8
  2. package/bin/rizzo-css.js +522 -120
  3. package/dist/rizzo.min.css +40 -16
  4. package/package.json +5 -4
  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/minimal/index.html +13 -0
  73. package/scaffold/shared/navbar-vanilla.html +59 -0
  74. package/scaffold/shared/sound-effects-inline.js +6 -1
  75. package/scaffold/starter/index.html +13 -0
  76. package/scaffold/svelte/AlertDialog.svelte +55 -0
  77. package/scaffold/svelte/AspectRatio.svelte +21 -0
  78. package/scaffold/svelte/BackToTop.svelte +1 -0
  79. package/scaffold/svelte/ButtonGroup.svelte +16 -0
  80. package/scaffold/svelte/Collapsible.svelte +57 -0
  81. package/scaffold/svelte/ContextMenu.svelte +60 -0
  82. package/scaffold/svelte/Dashboard.svelte +87 -0
  83. package/scaffold/svelte/Empty.svelte +36 -0
  84. package/scaffold/svelte/HoverCard.svelte +55 -0
  85. package/scaffold/svelte/Kbd.svelte +13 -0
  86. package/scaffold/svelte/Label.svelte +19 -0
  87. package/scaffold/svelte/Popover.svelte +59 -0
  88. package/scaffold/svelte/ResizableHandle.svelte +13 -0
  89. package/scaffold/svelte/ResizablePane.svelte +16 -0
  90. package/scaffold/svelte/ResizablePaneGroup.svelte +92 -0
  91. package/scaffold/svelte/ScrollArea.svelte +18 -0
  92. package/scaffold/svelte/Separator.svelte +14 -0
  93. package/scaffold/svelte/Sheet.svelte +62 -0
  94. package/scaffold/svelte/Skeleton.svelte +19 -0
  95. package/scaffold/svelte/Slider.svelte +57 -0
  96. package/scaffold/svelte/SoundEffects.svelte +3 -0
  97. package/scaffold/svelte/Switch.svelte +35 -0
  98. package/scaffold/svelte/Tabs.svelte +1 -1
  99. package/scaffold/svelte/Toggle.svelte +41 -0
  100. package/scaffold/svelte/ToggleGroup.svelte +30 -0
  101. package/scaffold/svelte/base/README-RIZZO.md +55 -0
  102. package/scaffold/{svelte-core → svelte/base}/src/routes/+page.svelte +1 -1
  103. package/scaffold/svelte/base/static/.gitkeep +0 -0
  104. package/scaffold/svelte/index.ts +21 -0
  105. package/scaffold/svelte/variants/dashboard/src/routes/+layout.svelte +64 -0
  106. package/scaffold/svelte/variants/dashboard/src/routes/+page.svelte +104 -0
  107. package/scaffold/svelte/variants/docs/src/routes/+layout.svelte +60 -0
  108. package/scaffold/svelte/variants/docs/src/routes/+page.svelte +34 -0
  109. package/scaffold/svelte/variants/docs/src/routes/docs/getting-started/+page.svelte +31 -0
  110. package/scaffold/{svelte-core → svelte/variants/full}/README-RIZZO.md +2 -1
  111. package/scaffold/svelte/variants/full/gitignore +10 -0
  112. package/scaffold/svelte/variants/full/package.json +20 -0
  113. package/scaffold/svelte/variants/full/src/app.d.ts +11 -0
  114. package/scaffold/svelte/variants/full/src/app.html +16 -0
  115. package/scaffold/svelte/variants/full/src/routes/+layout.svelte +1 -0
  116. package/scaffold/svelte/variants/full/src/routes/+page.svelte +105 -0
  117. package/scaffold/svelte/variants/full/static/.gitkeep +0 -0
  118. package/scaffold/svelte/variants/full/svelte.config.js +10 -0
  119. package/scaffold/svelte/variants/full/tsconfig.json +11 -0
  120. package/scaffold/vanilla/README-RIZZO.md +7 -6
  121. package/scaffold/vanilla/components/accordion.html +71 -64
  122. package/scaffold/vanilla/components/alert-dialog.html +640 -0
  123. package/scaffold/vanilla/components/alert.html +71 -64
  124. package/scaffold/vanilla/components/aspect-ratio.html +640 -0
  125. package/scaffold/vanilla/components/avatar.html +71 -64
  126. package/scaffold/vanilla/components/back-to-top.html +71 -64
  127. package/scaffold/vanilla/components/badge.html +71 -64
  128. package/scaffold/vanilla/components/breadcrumb.html +71 -64
  129. package/scaffold/vanilla/components/button-group.html +640 -0
  130. package/scaffold/vanilla/components/button.html +71 -64
  131. package/scaffold/vanilla/components/cards.html +71 -64
  132. package/scaffold/vanilla/components/collapsible.html +640 -0
  133. package/scaffold/vanilla/components/context-menu.html +640 -0
  134. package/scaffold/vanilla/components/copy-to-clipboard.html +71 -64
  135. package/scaffold/vanilla/components/dashboard.html +640 -0
  136. package/scaffold/vanilla/components/divider.html +71 -64
  137. package/scaffold/vanilla/components/docs-sidebar.html +71 -64
  138. package/scaffold/vanilla/components/dropdown.html +71 -64
  139. package/scaffold/vanilla/components/empty.html +640 -0
  140. package/scaffold/vanilla/components/font-switcher.html +71 -64
  141. package/scaffold/vanilla/components/footer.html +71 -64
  142. package/scaffold/vanilla/components/forms.html +71 -64
  143. package/scaffold/vanilla/components/hover-card.html +640 -0
  144. package/scaffold/vanilla/components/icons.html +71 -64
  145. package/scaffold/vanilla/components/index.html +91 -64
  146. package/scaffold/vanilla/components/kbd.html +640 -0
  147. package/scaffold/vanilla/components/label.html +640 -0
  148. package/scaffold/vanilla/components/modal.html +71 -64
  149. package/scaffold/vanilla/components/navbar.html +71 -64
  150. package/scaffold/vanilla/components/pagination.html +71 -64
  151. package/scaffold/vanilla/components/popover.html +640 -0
  152. package/scaffold/vanilla/components/progress-bar.html +71 -64
  153. package/scaffold/vanilla/components/resizable.html +640 -0
  154. package/scaffold/vanilla/components/scroll-area.html +640 -0
  155. package/scaffold/vanilla/components/search.html +71 -64
  156. package/scaffold/vanilla/components/separator.html +640 -0
  157. package/scaffold/vanilla/components/settings.html +71 -64
  158. package/scaffold/vanilla/components/sheet.html +640 -0
  159. package/scaffold/vanilla/components/skeleton.html +640 -0
  160. package/scaffold/vanilla/components/slider.html +640 -0
  161. package/scaffold/vanilla/components/sound-effects.html +71 -64
  162. package/scaffold/vanilla/components/spinner.html +71 -64
  163. package/scaffold/vanilla/components/switch.html +640 -0
  164. package/scaffold/vanilla/components/table.html +71 -64
  165. package/scaffold/vanilla/components/tabs.html +71 -64
  166. package/scaffold/vanilla/components/theme-switcher.html +71 -64
  167. package/scaffold/vanilla/components/toast.html +71 -64
  168. package/scaffold/vanilla/components/toggle-group.html +640 -0
  169. package/scaffold/vanilla/components/toggle.html +640 -0
  170. package/scaffold/vanilla/components/tooltip.html +71 -64
  171. package/scaffold/vanilla/index.html +73 -66
  172. package/scaffold/vanilla/variants/dashboard/index.html +45 -0
  173. package/scaffold/vanilla/variants/docs/index.html +36 -0
  174. package/scaffold/vanilla/variants/full/components/accordion.html +592 -0
  175. package/scaffold/vanilla/variants/full/components/alert.html +592 -0
  176. package/scaffold/vanilla/variants/full/components/avatar.html +592 -0
  177. package/scaffold/vanilla/variants/full/components/back-to-top.html +592 -0
  178. package/scaffold/vanilla/variants/full/components/badge.html +592 -0
  179. package/scaffold/vanilla/variants/full/components/breadcrumb.html +592 -0
  180. package/scaffold/vanilla/variants/full/components/button.html +592 -0
  181. package/scaffold/vanilla/variants/full/components/cards.html +592 -0
  182. package/scaffold/vanilla/variants/full/components/copy-to-clipboard.html +592 -0
  183. package/scaffold/vanilla/variants/full/components/dashboard.html +592 -0
  184. package/scaffold/vanilla/variants/full/components/divider.html +592 -0
  185. package/scaffold/vanilla/variants/full/components/docs-sidebar.html +592 -0
  186. package/scaffold/vanilla/variants/full/components/dropdown.html +592 -0
  187. package/scaffold/vanilla/variants/full/components/font-switcher.html +592 -0
  188. package/scaffold/vanilla/variants/full/components/footer.html +592 -0
  189. package/scaffold/vanilla/variants/full/components/forms.html +592 -0
  190. package/scaffold/vanilla/variants/full/components/icons.html +592 -0
  191. package/scaffold/vanilla/variants/full/components/index.html +625 -0
  192. package/scaffold/vanilla/variants/full/components/modal.html +592 -0
  193. package/scaffold/vanilla/variants/full/components/navbar.html +592 -0
  194. package/scaffold/vanilla/variants/full/components/pagination.html +592 -0
  195. package/scaffold/vanilla/variants/full/components/progress-bar.html +592 -0
  196. package/scaffold/vanilla/variants/full/components/search.html +592 -0
  197. package/scaffold/vanilla/variants/full/components/settings.html +592 -0
  198. package/scaffold/vanilla/variants/full/components/skeleton.html +592 -0
  199. package/scaffold/vanilla/variants/full/components/sound-effects.html +592 -0
  200. package/scaffold/vanilla/variants/full/components/spinner.html +592 -0
  201. package/scaffold/vanilla/variants/full/components/switch.html +592 -0
  202. package/scaffold/vanilla/variants/full/components/table.html +592 -0
  203. package/scaffold/vanilla/variants/full/components/tabs.html +592 -0
  204. package/scaffold/vanilla/variants/full/components/theme-switcher.html +592 -0
  205. package/scaffold/vanilla/variants/full/components/toast.html +592 -0
  206. package/scaffold/vanilla/variants/full/components/tooltip.html +592 -0
  207. package/scaffold/vanilla/variants/full/index.html +682 -0
  208. package/scaffold/vanilla/variants/full/js/main.js +989 -0
  209. package/scaffold/astro-core/.astro/content-assets.mjs +0 -1
  210. package/scaffold/astro-core/.astro/content-modules.mjs +0 -1
  211. package/scaffold/astro-core/.astro/content.d.ts +0 -199
  212. package/scaffold/astro-core/.astro/types.d.ts +0 -2
  213. package/scaffold/astro-core/.env.example +0 -3
  214. package/scaffold/svelte-core/.env.example +0 -3
  215. /package/scaffold/{astro-core → astro/base}/astro.config.mjs +0 -0
  216. /package/scaffold/{astro-core → astro/base}/dist/.gitkeep +0 -0
  217. /package/scaffold/{astro-core → astro/base}/dist/_noop-middleware.mjs +0 -0
  218. /package/scaffold/{astro-core → astro/base}/dist/chunks/astro/server_9Mzx7luy.mjs +0 -0
  219. /package/scaffold/{astro-core → astro/base}/dist/chunks/astro_BOYUKg7r.mjs +0 -0
  220. /package/scaffold/{astro-core → astro/base}/dist/favicon.svg +0 -0
  221. /package/scaffold/{astro-core → astro/base}/dist/manifest_DXpJmqSX.mjs +0 -0
  222. /package/scaffold/{astro-core → astro/base}/dist/noop-entrypoint.mjs +0 -0
  223. /package/scaffold/{astro-core → astro/base}/dist/pages/index.astro.mjs +0 -0
  224. /package/scaffold/{astro-core → astro/base}/dist/renderers.mjs +0 -0
  225. /package/scaffold/{astro-core → astro/base}/gitignore +0 -0
  226. /package/scaffold/{astro-core → astro/base}/node_modules/.astro/data-store.json +0 -0
  227. /package/scaffold/{astro-core → astro/base}/node_modules/.vite/deps/_metadata.json +0 -0
  228. /package/scaffold/{astro-core → astro/base}/node_modules/.vite/deps/astro___aria-query.js +0 -0
  229. /package/scaffold/{astro-core → astro/base}/node_modules/.vite/deps/astro___aria-query.js.map +0 -0
  230. /package/scaffold/{astro-core → astro/base}/node_modules/.vite/deps/astro___axobject-query.js +0 -0
  231. /package/scaffold/{astro-core → astro/base}/node_modules/.vite/deps/astro___axobject-query.js.map +0 -0
  232. /package/scaffold/{astro-core → astro/base}/node_modules/.vite/deps/astro___cssesc.js +0 -0
  233. /package/scaffold/{astro-core → astro/base}/node_modules/.vite/deps/astro___cssesc.js.map +0 -0
  234. /package/scaffold/{astro-core → astro/base}/node_modules/.vite/deps/chunk-BUSYA2B4.js +0 -0
  235. /package/scaffold/{astro-core → astro/base}/node_modules/.vite/deps/chunk-BUSYA2B4.js.map +0 -0
  236. /package/scaffold/{astro-core → astro/base}/node_modules/.vite/deps/package.json +0 -0
  237. /package/scaffold/{astro-core → astro/base}/package.json +0 -0
  238. /package/scaffold/{astro-core → astro/base}/public/.gitkeep +0 -0
  239. /package/scaffold/{astro-core → astro/base}/public/favicon.svg +0 -0
  240. /package/scaffold/{astro-core → astro/base}/src/components/rizzo/CopyToClipboard.astro +0 -0
  241. /package/scaffold/{astro-core → astro/base}/src/components/rizzo/icons/Check.astro +0 -0
  242. /package/scaffold/{astro-core → astro/base}/src/components/rizzo/icons/Copy.astro +0 -0
  243. /package/scaffold/{astro-core → astro/base}/src/layouts/Layout.astro +0 -0
  244. /package/scaffold/{astro-core → astro/base}/tsconfig.json +0 -0
  245. /package/scaffold/{svelte-core/static → astro/variants/full/dist}/.gitkeep +0 -0
  246. /package/scaffold/{svelte-core → svelte/base}/gitignore +0 -0
  247. /package/scaffold/{svelte-core → svelte/base}/package.json +0 -0
  248. /package/scaffold/{svelte-core → svelte/base}/src/app.d.ts +0 -0
  249. /package/scaffold/{svelte-core → svelte/base}/src/app.html +0 -0
  250. /package/scaffold/{svelte-core → svelte/base}/src/routes/+layout.svelte +0 -0
  251. /package/scaffold/{svelte-core → svelte/base}/svelte.config.js +0 -0
  252. /package/scaffold/{svelte-core → svelte/base}/tsconfig.json +0 -0
package/bin/rizzo-css.js CHANGED
@@ -25,38 +25,89 @@ 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 landing/docs/dashboard/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. */
35
- const TEMPLATES = {
36
- 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
- ],
40
- astro: [
41
- { value: 'core', label: 'Core — Astro app + all components (with dependencies so everything works)' },
42
- { value: 'manual', label: 'Manual same base; pick which components to include (all interactive pre-selected)' },
43
- ],
44
- svelte: [
45
- { value: 'core', label: 'Core SvelteKit app + all components (with dependencies so everything works)' },
46
- { value: 'manual', label: 'Manual same base; pick which components to include (all interactive pre-selected)' },
47
- ],
48
- };
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
+ ];
43
+
44
+ /** Build RIZZO-SETUP.md content: instructions + snippets. Never overwrites; use for landing or when files were skipped. */
45
+ function buildRizzoSetupMd(framework, opts) {
46
+ const { linkTag, linkHref, theme, defaultDark, defaultLight, skippedFiles = [], exampleMinimalPage } = opts;
47
+ const fw = framework === 'vanilla' ? 'Vanilla' : framework === 'astro' ? 'Astro' : 'Svelte';
48
+ let md = `# Rizzo CSS setup
49
+
50
+ 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.
51
+
52
+ ## 1. Link the CSS
53
+
54
+ Add this to your \`<head>\` or root layout:
55
+
56
+ \`\`\`html
57
+ ${linkTag || `<link rel="stylesheet" href="${linkHref || '/css/rizzo.min.css'}" />`}
58
+ \`\`\`
59
+
60
+ ## 2. Set a theme (optional)
61
+
62
+ On your \`<html>\` element:
63
+
64
+ \`\`\`html
65
+ <html lang="en" data-theme="${theme || 'system'}">
66
+ \`\`\`
49
67
 
50
- const VANILLA_MANUAL_README = `# Vanilla + Rizzo CSS (manual)
68
+ Theme IDs: \`npx rizzo-css theme\`. Default dark: ${defaultDark || 'github-dark-classic'}; default light: ${defaultLight || 'github-light'}.
51
69
 
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\`.
70
+ ## 3. Accessibility basics (recommended)
71
+
72
+ - Skip link: \`<a href="#main-content" class="skip-link">Skip to main content</a>\`
73
+ - Main landmark: \`<main id="main-content">\`
74
+
75
+ `;
76
+ if (skippedFiles.length > 0) {
77
+ md += `## Files we didn't overwrite
78
+
79
+ Your project already had these files. Add the following snippets manually if you want the same content as the scaffold:\n\n`;
80
+ for (const { relativePath, content } of skippedFiles) {
81
+ if (!content) continue;
82
+ const ext = relativePath.slice(relativePath.lastIndexOf('.'));
83
+ const lang = ext === '.html' ? 'html' : ext === '.astro' ? 'astro' : ext === '.svelte' ? 'svelte' : ext === '.ts' || ext === '.js' ? 'ts' : 'text';
84
+ md += `### \`${relativePath}\`\n\n\`\`\`${lang}\n${content.substring(0, 8000)}${content.length > 8000 ? '\n...' : ''}\n\`\`\`\n\n`;
85
+ }
86
+ }
87
+ if (exampleMinimalPage) {
88
+ md += `## Example landing page
89
+
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`;
91
+ }
92
+ md += `## Docs
93
+
94
+ - [Getting started](https://rizzo-css.vercel.app/docs/getting-started)
95
+ - [Components](https://rizzo-css.vercel.app/docs/components)
96
+ - [Theming](https://rizzo-css.vercel.app/docs/theming)
97
+ `;
98
+ return md;
99
+ }
100
+
101
+ const VANILLA_MANUAL_README = `# Vanilla + Rizzo CSS (Full template)
102
+
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).
53
104
 
54
105
  - Open \`index.html\` in a browser or serve the folder with any static server.
55
106
  - Edit \`index.html\` and add your content. CSS: \`css/rizzo.min.css\`.
56
107
  - If you picked components, \`components/\` has their HTML pages and \`js/main.js\` is included (open \`components/index.html\` to browse).
57
108
  - Set a theme: \`<html data-theme="github-dark-classic">\` (see \`npx rizzo-css theme\` for all themes).
58
109
 
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.
110
+ **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
111
 
61
112
  Docs: [rizzo-css.vercel.app](https://rizzo-css.vercel.app)
62
113
  `;
@@ -91,29 +142,35 @@ const LIGHT_THEMES = [
91
142
  'semi-light-purple',
92
143
  ];
93
144
  const THEMES = [...DARK_THEMES, ...LIGHT_THEMES];
94
- // 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)
95
146
  const SVELTE_COMPONENTS = [
96
- 'Button', 'Badge', 'Card', 'Divider', 'DocsSidebar', 'Footer', 'Spinner', 'ProgressBar', 'Avatar', 'Alert',
147
+ 'Button', 'Badge', 'Card', 'Dashboard', 'Divider', 'DocsSidebar', 'Footer', 'Spinner', 'ProgressBar', 'Avatar', 'Alert',
97
148
  'BackToTop', 'Breadcrumb', 'FormGroup', 'Input', 'Checkbox', 'Textarea', 'Select', 'Radio',
98
149
  'CopyToClipboard', 'Tooltip', 'Pagination', 'Tabs', 'Accordion', 'Dropdown',
99
150
  'Modal', 'Toast', 'Table', 'ThemeSwitcher', 'FontSwitcher', 'SoundEffects',
100
- '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',
101
154
  ];
102
155
  const ASTRO_COMPONENTS = [
103
- 'Button', 'Badge', 'Card', 'Divider', 'DocsSidebar', 'Footer', 'Spinner', 'ProgressBar', 'Avatar', 'Alert',
156
+ 'Button', 'Badge', 'Card', 'Dashboard', 'Divider', 'DocsSidebar', 'Footer', 'Spinner', 'ProgressBar', 'Avatar', 'Alert',
104
157
  'BackToTop', 'Breadcrumb', 'FormGroup', 'Input', 'Checkbox', 'Textarea', 'Select', 'Radio',
105
158
  'CopyToClipboard', 'Tooltip', 'Pagination', 'Tabs', 'Accordion', 'Dropdown',
106
159
  'Modal', 'Toast', 'Table', 'ThemeSwitcher', 'FontSwitcher', 'SoundEffects',
107
- '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',
108
163
  ];
109
164
 
110
165
  // Base set for Manual: all interactive components we ship (so manual has a full working set). Full includes everything (same list).
111
166
  const RECOMMENDED_COMPONENTS = [
112
- 'Button', 'Badge', 'Card', 'Divider', 'DocsSidebar', 'Footer', 'Spinner', 'ProgressBar', 'Avatar', 'Alert',
167
+ 'Button', 'Badge', 'Card', 'Dashboard', 'Divider', 'DocsSidebar', 'Footer', 'Spinner', 'ProgressBar', 'Avatar', 'Alert',
113
168
  'BackToTop', 'Breadcrumb', 'FormGroup', 'Input', 'Checkbox', 'Textarea', 'Select', 'Radio',
114
169
  'CopyToClipboard', 'Tooltip', 'Pagination', 'Tabs', 'Accordion', 'Dropdown',
115
170
  'Modal', 'Toast', 'Table', 'ThemeSwitcher', 'FontSwitcher', 'SoundEffects',
116
- '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',
117
174
  ];
118
175
 
119
176
  // Vanilla components that need js/main.js for interactivity.
@@ -174,15 +231,16 @@ function logAddedDeps(selected, expanded, framework) {
174
231
  if (byRequirement.length) console.log('\n Also adding: ' + byRequirement.join('; '));
175
232
  }
176
233
 
177
- // 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/.
178
235
  const VANILLA_COMPONENT_SLUGS = {
179
- Accordion: 'accordion', Alert: 'alert', Avatar: 'avatar', BackToTop: 'back-to-top', Badge: 'badge', Breadcrumb: 'breadcrumb', Button: 'button',
180
- Card: 'cards', Checkbox: 'forms', CopyToClipboard: 'copy-to-clipboard', Divider: 'divider', DocsSidebar: 'docs-sidebar', Dropdown: 'dropdown',
181
- Footer: 'footer', FormGroup: 'forms', Input: 'forms', Modal: 'modal', Pagination: 'pagination', ProgressBar: 'progress-bar',
182
- Radio: 'forms', Search: 'search', Select: 'forms', Settings: 'settings', Spinner: 'spinner', Table: 'table',
183
- Tabs: 'tabs', Textarea: 'forms', ThemeSwitcher: 'theme-switcher', Toast: 'toast', Tooltip: 'tooltip',
184
- FontSwitcher: 'font-switcher', SoundEffects: 'sound-effects',
185
- 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',
186
244
  };
187
245
 
188
246
  // ANSI colors for CLI (framework logo colors)
@@ -402,12 +460,14 @@ function parsePackageManager(value) {
402
460
  return VALID_PACKAGE_MANAGERS.includes(v) ? v : null;
403
461
  }
404
462
 
405
- /** Get positional args for a command (excludes --flag and --flag value). Used for e.g. add Button ThemeSwitcher. */
406
- 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;
407
466
  const positionals = [];
408
- for (let i = 1; i < argv.length; i++) {
467
+ for (let i = start; i < argv.length; i++) {
409
468
  if (argv[i].startsWith('--')) {
410
- if (!argv[i].includes('=')) i++;
469
+ if (!argv[i].includes('=') && i + 1 < argv.length) i += 2;
470
+ else i++;
411
471
  continue;
412
472
  }
413
473
  positionals.push(argv[i]);
@@ -480,10 +540,35 @@ async function promptPackageManager(projectDir) {
480
540
  return selectMenu(options, '? Package manager (for install and run commands)');
481
541
  }
482
542
 
483
- /** Prompt user to select Core or Manual for the chosen framework. Returns 'core' or 'manual'. */
484
- async function promptTemplate(framework) {
485
- const options = TEMPLATES[framework] || TEMPLATES.vanilla;
486
- return selectMenu(options, '? Full or Manual?');
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);
487
572
  }
488
573
 
489
574
  function question(prompt) {
@@ -837,7 +922,7 @@ Available commands: init, add, theme, doctor, help
837
922
 
838
923
  Flags summary:
839
924
  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
925
+ add --path <dir> --framework <fw> --template landing|docs|dashboard|full --no-snippet --readme --force --vanilla-js
841
926
  theme (no flags)
842
927
  doctor Check config, CSS file, and optional layout link
843
928
  help (no flags)
@@ -849,16 +934,16 @@ Usage (use your package manager):
849
934
  bunx rizzo-css <command> [options]
850
935
 
851
936
  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)
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.
854
939
  theme List all available themes (use in init or set data-theme on <html>)
855
940
  help Show this help
856
941
 
857
942
  Options (init):
858
- --yes Non-interactive: scaffold new in cwd with defaults (framework: astro, template: core)
943
+ --yes Non-interactive: scaffold new in cwd with defaults (framework: astro, template: landing)
859
944
  --path <dir> Project directory (relative to cwd or absolute). Scaffold and run install there. With --yes; interactive: "Enter path" option.
860
945
  --framework <fw> vanilla | astro | svelte (with --yes; otherwise first prompt)
861
- --template <t> core | manual (all frameworks); with --yes defaults to core
946
+ --template <t> create new: landing | docs | dashboard | full (default: landing). add: same four options.
862
947
  --package-manager <pm> npm | pnpm | yarn | bun (with --yes, or skip PM prompt when interactive)
863
948
  --install After scaffolding, run package manager install in project directory (no prompt)
864
949
  --no-install Do not run install and do not prompt
@@ -866,15 +951,16 @@ Options (init):
866
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.)
867
952
 
868
953
  Options (add):
954
+ --template <t> landing | docs | dashboard | full (same as init; Full = site clone)
869
955
  --path <dir> Target directory for rizzo.min.css (overrides config and framework default)
870
956
  --framework <fw> vanilla | astro | svelte (overrides config and detection)
871
957
  --package-manager <pm> npm | pnpm | yarn | bun (override detection for install/print commands)
872
958
  --install-package After copying CSS, run package manager add rizzo-css
873
959
  --no-install Do not run install or add (overrides --install-package)
874
- --no-snippet Do not write RIZZO-SNIPPET.txt (link + theme copy-paste)
960
+ --no-snippet (Full only) Do not write RIZZO-SNIPPET.txt (link + theme copy-paste)
875
961
  --readme Write README-RIZZO.md into the project
876
962
  --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)
963
+ --vanilla-js (Vanilla Full) Copy js/main.js for interactive components (modal, dropdown, tabs, toast, search, navbar, copy-to-clipboard, theme switcher)
878
964
 
879
965
  Package managers:
880
966
  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 +991,7 @@ Examples:
905
991
  npx rizzo-css init --yes --path my-app --framework astro --install
906
992
  npx rizzo-css init --yes --framework astro --package-manager pnpm --install
907
993
  npx rizzo-css init --yes --framework vanilla
908
- npx rizzo-css init --yes --framework svelte --template core
994
+ npx rizzo-css init --yes --framework svelte --template landing
909
995
  npx rizzo-css add --package-manager yarn --install-package
910
996
  npx rizzo-css add
911
997
  npx rizzo-css add Button
@@ -913,8 +999,8 @@ Examples:
913
999
  npx rizzo-css add --install-package
914
1000
  npx rizzo-css theme
915
1001
 
916
- Component dependencies (manual / add):
917
- Some components require others to work. Picking them adds the required ones automatically.
1002
+ Component dependencies (Full template):
1003
+ Some components require others to work. The component picker adds required ones automatically.
918
1004
  Full list of available components and what relies on what: npx rizzo-css help components
919
1005
 
920
1006
  Docs: https://rizzo-css.vercel.app
@@ -1030,7 +1116,7 @@ function componentOptionLabel(framework, name) {
1030
1116
  return name + suffix;
1031
1117
  }
1032
1118
 
1033
- /** 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. */
1034
1120
  async function promptComponentChoice(componentList, framework, initialSelection) {
1035
1121
  const recommended = RECOMMENDED_COMPONENTS.filter((c) => componentList.includes(c));
1036
1122
  if (initialSelection !== undefined) {
@@ -1118,13 +1204,16 @@ async function cmdAdd(argv) {
1118
1204
  const customPath = getFlagValue(argv, '--path');
1119
1205
  const explicitFrameworkRaw = getFlagValue(argv, '--framework');
1120
1206
  const explicitFramework = explicitFrameworkRaw && FRAMEWORKS.includes(explicitFrameworkRaw.toLowerCase()) ? explicitFrameworkRaw.toLowerCase() : null;
1207
+ const templateRaw = getFlagValue(argv, '--template');
1208
+ const validAddTemplates = ['landing', 'docs', 'dashboard', 'full']; // same four as create new
1209
+ const template = templateRaw && validAddTemplates.includes(templateRaw.toLowerCase()) ? templateRaw.toLowerCase() : undefined;
1121
1210
  const installPackage = hasFlag(argv, '--install-package');
1122
1211
  const noInstall = hasFlag(argv, '--no-install');
1123
1212
  const writeSnippet = !hasFlag(argv, '--no-snippet');
1124
1213
  const writeReadme = hasFlag(argv, '--readme');
1125
1214
  const force = hasFlag(argv, '--force');
1126
1215
  const copyVanillaJs = hasFlag(argv, '--vanilla-js');
1127
- const positionals = getPositionalArgs(argv);
1216
+ const positionals = getPositionalArgs(argv, 3);
1128
1217
 
1129
1218
  const cwd = process.cwd();
1130
1219
  const config = readRizzoConfig(cwd);
@@ -1133,6 +1222,7 @@ async function cmdAdd(argv) {
1133
1222
  config,
1134
1223
  targetDir: customPath || (config && config.targetDir) || undefined,
1135
1224
  packageManager: pmOverride || undefined,
1225
+ template,
1136
1226
  preselectedComponents: positionals.length > 0 ? positionals : undefined,
1137
1227
  writeSnippet,
1138
1228
  writeReadme,
@@ -1175,6 +1265,42 @@ function getScaffoldVanillaIndex() {
1175
1265
  return join(getPackageRoot(), 'scaffold', 'vanilla', 'index.html');
1176
1266
  }
1177
1267
 
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
1273
+ }
1274
+
1275
+ /** Load landing template HTML from scaffold and apply replacements; fallback to inline if file missing. */
1276
+ function getLandingTemplateHtml(opts) {
1277
+ const { theme, themeComment, name, framework } = opts;
1278
+ const linkHref = framework === 'vanilla' ? 'css/rizzo.min.css' : '/css/rizzo.min.css';
1279
+ const templatePath = getLandingTemplatePath();
1280
+ if (existsSync(templatePath)) {
1281
+ let html = readFileSync(templatePath, 'utf8');
1282
+ return html
1283
+ .replace(/\{\{TITLE\}\}/g, name || 'App')
1284
+ .replace(/\{\{DATA_THEME\}\}/g, theme)
1285
+ .replace(/\{\{THEME_LIST_COMMENT\}\}/g, themeComment)
1286
+ .replace(/\{\{LINK_HREF\}\}/g, linkHref);
1287
+ }
1288
+ return `<!DOCTYPE html>
1289
+ <html lang="en" data-theme="${theme}">${themeComment}
1290
+ <head>
1291
+ <meta charset="UTF-8" />
1292
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
1293
+ <title>${name || 'App'}</title>
1294
+ <link rel="stylesheet" href="${linkHref}" />
1295
+ </head>
1296
+ <body>
1297
+ <h1>Hello, Rizzo CSS</h1>
1298
+ <p>Edit this file and add components. Docs: <a href="https://rizzo-css.vercel.app">rizzo-css.vercel.app</a></p>
1299
+ </body>
1300
+ </html>
1301
+ `;
1302
+ }
1303
+
1178
1304
  function getScaffoldVanillaIconsDir() {
1179
1305
  return join(getPackageRoot(), 'scaffold', 'vanilla', 'icons');
1180
1306
  }
@@ -1183,11 +1309,23 @@ function getScaffoldVanillaComponentsDir() {
1183
1309
  return join(getPackageRoot(), 'scaffold', 'vanilla', 'components');
1184
1310
  }
1185
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
+
1186
1320
  /** Copy selected Vanilla component HTML files into projectDir/components/, with replacements. Writes a simple components/index.html. */
1187
1321
  function copyVanillaComponents(projectDir, selectedNames, replacements) {
1188
1322
  const srcDir = getScaffoldVanillaComponentsDir();
1189
1323
  if (!existsSync(srcDir)) return;
1190
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
+ }
1191
1329
  const slugsToCopy = [];
1192
1330
  const seen = new Set();
1193
1331
  for (const name of selectedNames) {
@@ -1211,6 +1349,7 @@ function copyVanillaComponents(projectDir, selectedNames, replacements) {
1211
1349
  }
1212
1350
  }
1213
1351
  const indexLinks = slugsToCopy.map((s) => ' <li><a href="' + s + '.html">' + s + '</a></li>').join('\n');
1352
+ const navHtml = replacements['{{NAVBAR_HTML}}'] || '';
1214
1353
  const indexHtml = `<!DOCTYPE html>
1215
1354
  <html lang="en" data-theme="${replacements['{{DATA_THEME}}'] || 'github-dark-classic'}">
1216
1355
  <head>
@@ -1220,7 +1359,9 @@ function copyVanillaComponents(projectDir, selectedNames, replacements) {
1220
1359
  <link rel="stylesheet" href="../${linkHref}" />
1221
1360
  </head>
1222
1361
  <body>
1223
- <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;">
1224
1365
  <h1>Components</h1>
1225
1366
  <ul>
1226
1367
  ${indexLinks}
@@ -1258,11 +1399,11 @@ function copyRizzoIcons(projectDir, framework) {
1258
1399
  }
1259
1400
 
1260
1401
  function getScaffoldAstroCoreDir() {
1261
- return join(getPackageRoot(), 'scaffold', 'astro-core');
1402
+ return join(getPackageRoot(), 'scaffold', 'astro', 'base');
1262
1403
  }
1263
1404
 
1264
1405
  function getScaffoldSvelteCoreDir() {
1265
- return join(getPackageRoot(), 'scaffold', 'svelte-core');
1406
+ return join(getPackageRoot(), 'scaffold', 'svelte', 'base');
1266
1407
  }
1267
1408
 
1268
1409
  function copyDirRecursive(src, dest) {
@@ -1304,6 +1445,54 @@ function copyDirRecursiveWithReplacements(src, dest, replacements) {
1304
1445
  }
1305
1446
  }
1306
1447
 
1448
+ /**
1449
+ * Like copyDirRecursiveWithReplacements but never overwrites existing files.
1450
+ * Returns { skipped: Array<{ relativePath, content }> } for files that already existed (so caller can write RIZZO-SETUP.md).
1451
+ * relativePath is from projectDir (dest).
1452
+ */
1453
+ function copyDirRecursiveWithReplacementsNoOverwrite(src, dest, replacements, projectDir) {
1454
+ const skipped = [];
1455
+ projectDir = projectDir || dest;
1456
+ const textExtensions = new Set(['.html', '.astro', '.svelte', '.ts', '.js', '.mjs', '.json', '.css', '.md']);
1457
+ function recurse(s, d) {
1458
+ mkdirSync(d, { recursive: true });
1459
+ const entries = readdirSync(s, { withFileTypes: true });
1460
+ for (const e of entries) {
1461
+ const srcPath = join(s, e.name);
1462
+ const destPath = join(d, e.name);
1463
+ if (e.isDirectory()) {
1464
+ recurse(srcPath, destPath);
1465
+ } else {
1466
+ if (existsSync(destPath)) {
1467
+ const rel = pathRelative(projectDir, destPath);
1468
+ let content = '';
1469
+ const ext = srcPath.slice(srcPath.lastIndexOf('.'));
1470
+ if (textExtensions.has(ext)) {
1471
+ content = readFileSync(srcPath, 'utf8');
1472
+ for (const [key, value] of Object.entries(replacements)) {
1473
+ content = content.split(key).join(value);
1474
+ }
1475
+ }
1476
+ skipped.push({ relativePath: rel, content });
1477
+ continue;
1478
+ }
1479
+ const ext = srcPath.slice(srcPath.lastIndexOf('.'));
1480
+ if (textExtensions.has(ext)) {
1481
+ let content = readFileSync(srcPath, 'utf8');
1482
+ for (const [key, value] of Object.entries(replacements)) {
1483
+ content = content.split(key).join(value);
1484
+ }
1485
+ writeFileSync(destPath, content, 'utf8');
1486
+ } else {
1487
+ copyFileSync(srcPath, destPath);
1488
+ }
1489
+ }
1490
+ }
1491
+ }
1492
+ recurse(src, dest);
1493
+ return { skipped };
1494
+ }
1495
+
1307
1496
  function copySvelteComponents(projectDir, selectedNames) {
1308
1497
  const scaffoldDir = getScaffoldSvelteDir();
1309
1498
  if (!existsSync(scaffoldDir)) {
@@ -1419,7 +1608,7 @@ function copyAstroComponents(projectDir, selectedNames) {
1419
1608
  }
1420
1609
  }
1421
1610
 
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? }. */
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). */
1423
1612
  async function runAddToExisting(frameworkOverride, options) {
1424
1613
  const cwd = process.cwd();
1425
1614
  const config = (options && options.config) || readRizzoConfig(cwd);
@@ -1438,6 +1627,12 @@ async function runAddToExisting(frameworkOverride, options) {
1438
1627
  framework = await selectMenu(frameworkOptions, frameworkPrompt);
1439
1628
  }
1440
1629
 
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
+ }
1635
+
1441
1636
  const componentList = framework === 'svelte' ? SVELTE_COMPONENTS : framework === 'astro' ? ASTRO_COMPONENTS : framework === 'vanilla' ? Object.keys(VANILLA_COMPONENT_SLUGS) : [];
1442
1637
  const preselected = options.preselectedComponents && options.preselectedComponents.length > 0 ? options.preselectedComponents : null;
1443
1638
  let selectedComponents;
@@ -1460,6 +1655,7 @@ async function runAddToExisting(frameworkOverride, options) {
1460
1655
  : [];
1461
1656
  }
1462
1657
 
1658
+ // Only ask about theming when ThemeSwitcher is selected (we will inject theme into layout/config).
1463
1659
  let theme, defaultDark, defaultLight;
1464
1660
  const wantsThemeSwitcher = selectedComponents.includes('ThemeSwitcher');
1465
1661
  if (wantsThemeSwitcher && !preselected) {
@@ -1468,7 +1664,7 @@ async function runAddToExisting(frameworkOverride, options) {
1468
1664
  { value: true, label: 'Yes — choose default dark, default light, and initial theme' },
1469
1665
  { value: false, label: 'No — use defaults (github-dark-classic / github-light)' },
1470
1666
  ],
1471
- '? Set default themes for ThemeSwitcher? (same as create-new flow)'
1667
+ '? Set default themes for ThemeSwitcher?'
1472
1668
  );
1473
1669
  if (setDefaults) {
1474
1670
  const out = await promptThemes();
@@ -1516,6 +1712,66 @@ async function runAddToExisting(frameworkOverride, options) {
1516
1712
  } else {
1517
1713
  options._overwriteCss = true;
1518
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
+
1519
1775
  if (options._overwriteCss) {
1520
1776
  if (framework === 'astro') {
1521
1777
  copyRizzoCssAndFontsForAstro(cwd, cssSource);
@@ -1582,6 +1838,10 @@ async function runAddToExisting(frameworkOverride, options) {
1582
1838
  if (!hadConfig) {
1583
1839
  writeRizzoConfig(cwd, { targetDir: configTargetDir, framework, packageManager: pm.agent, theme });
1584
1840
  }
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 });
1843
+ writeFileSync(join(cwd, RIZZO_SETUP_FILE), setupMdContent + '\n', 'utf8');
1844
+ copyPackageLicense(cwd);
1585
1845
  const writeSnippet = options.writeSnippet !== false;
1586
1846
  if (writeSnippet) {
1587
1847
  const where = framework === 'svelte' ? 'Root layout (e.g. src/app.html)' : framework === 'astro' ? 'Layout (e.g. src/layouts/Layout.astro)' : 'HTML or layout';
@@ -1602,8 +1862,13 @@ async function runAddToExisting(frameworkOverride, options) {
1602
1862
  }
1603
1863
  }
1604
1864
  console.log('\n✓ Rizzo CSS added to your existing project');
1605
- console.log(' - ' + cssTarget);
1865
+ console.log(' - ' + cssTarget + ' (CSS, fonts' + (framework === 'vanilla' ? ', sfx' : '') + ')');
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
+ }
1606
1870
  if (!hadConfig) console.log(' - Wrote ' + RIZZO_CONFIG_FILE);
1871
+ console.log(' - Wrote ' + RIZZO_SETUP_FILE + ' (instructions + link + theme)');
1607
1872
  if (writeSnippet) console.log(' - Wrote ' + RIZZO_SNIPPET_FILE + ' (copy-paste link + theme)');
1608
1873
  if (options.writeReadme) console.log(' - Wrote ' + SCAFFOLD_README_FILENAME);
1609
1874
  console.log('\nYou must add the stylesheet link yourself — it is not added automatically.');
@@ -1648,17 +1913,25 @@ async function cmdInit(argv) {
1648
1913
  let theme, defaultDark, defaultLight;
1649
1914
  let selectedPm;
1650
1915
  let selectedTemplate;
1916
+ let selectedVariation = 'landing'; // For create new: landing | docs | dashboard (all get full setup)
1651
1917
  let selectedComponents = [];
1918
+ let fullAllComponents = false;
1652
1919
 
1653
1920
  if (yes) {
1654
1921
  const frameworkArg = getFlagValue(argv, '--framework');
1655
1922
  framework = (frameworkArg && FRAMEWORKS.includes(frameworkArg.toLowerCase())) ? frameworkArg.toLowerCase() : (config && config.framework) || 'astro';
1656
1923
  initMode = 'new';
1657
1924
  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];
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
1930
+ if (selectedTemplate === 'full') {
1931
+ fullAllComponents = true;
1932
+ if (framework === 'svelte') selectedComponents = [...SVELTE_COMPONENTS];
1933
+ else if (framework === 'astro') selectedComponents = [...ASTRO_COMPONENTS];
1934
+ else selectedComponents = Object.keys(VANILLA_COMPONENT_SLUGS);
1662
1935
  }
1663
1936
  const projectDir = customProjectPath ? pathResolve(cwd, customProjectPath) : cwd;
1664
1937
  const resolved = resolvePackageManager(projectDir, cwd);
@@ -1707,17 +1980,33 @@ async function cmdInit(argv) {
1707
1980
  }
1708
1981
  }
1709
1982
 
1710
- selectedTemplate = await selectMenu(TEMPLATES[framework] || TEMPLATES.vanilla, '? Core or Manual?');
1711
-
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);
1983
+ // Create new: choose template (Landing | Docs | Dashboard | Full)
1984
+ selectedVariation = await promptTemplate();
1985
+ selectedTemplate = 'full'; // all templates get full framework + Rizzo
1986
+
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)) {
1992
+ const addChoice = await selectMenu(
1993
+ [
1994
+ { value: 'all', label: 'All components' },
1995
+ { value: 'pick', label: 'Pick components (choose which to include)' },
1996
+ ],
1997
+ '? Add all components or pick which to include?'
1998
+ );
1999
+ fullAllComponents = (addChoice === 'all');
2000
+ if (fullAllComponents) {
2001
+ selectedComponents = framework === 'svelte' ? [...SVELTE_COMPONENTS] : framework === 'astro' ? [...ASTRO_COMPONENTS] : Object.keys(VANILLA_COMPONENT_SLUGS);
2002
+ } else {
2003
+ const componentList = framework === 'svelte' ? SVELTE_COMPONENTS : framework === 'astro' ? ASTRO_COMPONENTS : Object.keys(VANILLA_COMPONENT_SLUGS);
2004
+ const recommended = RECOMMENDED_COMPONENTS.filter((c) => componentList.includes(c));
2005
+ selectedComponents = await promptComponentChoice(componentList, framework, recommended);
2006
+ }
1718
2007
  }
1719
2008
 
1720
- const wantsThemeSwitcher = (framework === 'vanilla' && selectedTemplate === 'core') || selectedComponents.includes('ThemeSwitcher');
2009
+ const wantsThemeSwitcher = (framework === 'vanilla' && selectedTemplate === 'full') || selectedComponents.includes('ThemeSwitcher');
1721
2010
  if (wantsThemeSwitcher) {
1722
2011
  const themeOut = await promptThemes();
1723
2012
  theme = themeOut.theme;
@@ -1766,11 +2055,13 @@ async function cmdInit(argv) {
1766
2055
  const astroCoreDir = getScaffoldAstroCoreDir();
1767
2056
  const svelteCoreDir = getScaffoldSvelteCoreDir();
1768
2057
  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());
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' && fullAllComponents && framework === 'vanilla' && (selectedVariation === 'docs' || selectedVariation === 'dashboard') && getVariantDir('vanilla', selectedVariation);
1774
2065
 
1775
2066
  // Full gets all required dependencies so everything works; manual gets deps when user picks (see prompt labels).
1776
2067
  let componentsToCopy = selectedComponents;
@@ -1825,25 +2116,56 @@ async function cmdInit(argv) {
1825
2116
  let cssTarget;
1826
2117
  let indexPath;
1827
2118
 
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
- `;
2119
+ const landingHtml = getLandingTemplateHtml({ theme, themeComment, name, framework });
1842
2120
 
1843
- if (useHandpickAstro) {
2121
+ if (useFullVariant && framework === 'astro') {
2122
+ mkdirSync(projectDir, { recursive: true });
2123
+ const fullDir = getVariantDir('astro', 'full');
2124
+ copyDirRecursiveWithReplacements(fullDir, projectDir, replacements);
2125
+ copyRizzoCssAndFontsForAstro(projectDir, cssSource);
2126
+ cssTarget = join(projectDir, 'public', 'css', 'rizzo.min.css');
2127
+ if (existsSync(cssTarget) && statSync(cssTarget).size < 5000) {
2128
+ console.warn('\nWarning: rizzo.min.css is very small. From repo root run: pnpm build:css');
2129
+ }
2130
+ copyPackageLicense(projectDir);
2131
+ copyAstroGitignore(projectDir);
2132
+ copyRizzoIcons(projectDir, 'astro');
2133
+ } else if (useFullVariant && framework === 'svelte') {
2134
+ mkdirSync(projectDir, { recursive: true });
2135
+ const fullDir = getVariantDir('svelte', 'full');
2136
+ copyDirRecursiveWithReplacements(fullDir, projectDir, replacements);
2137
+ copyRizzoCssAndFontsForSvelte(projectDir, cssSource);
2138
+ cssTarget = join(projectDir, 'static', 'css', 'rizzo.min.css');
2139
+ if (existsSync(cssTarget) && statSync(cssTarget).size < 5000) {
2140
+ console.warn('\nWarning: rizzo.min.css is very small. From repo root run: pnpm build:css');
2141
+ }
2142
+ copyPackageLicense(projectDir);
2143
+ copySvelteGitignore(projectDir);
2144
+ copyRizzoIcons(projectDir, 'svelte');
2145
+ } else if (useFullVariant && framework === 'vanilla') {
2146
+ mkdirSync(projectDir, { recursive: true });
2147
+ const fullDir = getVariantDir('vanilla', 'full');
2148
+ copyDirRecursiveWithReplacements(fullDir, projectDir, replacements);
2149
+ const cssDir = join(projectDir, pathsForScaffold.targetDir);
2150
+ cssTarget = join(cssDir, 'rizzo.min.css');
2151
+ mkdirSync(cssDir, { recursive: true });
2152
+ copyFileSync(cssSource, cssTarget);
2153
+ copyRizzoFonts(dirname(cssTarget));
2154
+ copyRizzoSfx(projectDir);
2155
+ if (existsSync(cssTarget) && statSync(cssTarget).size < 5000) {
2156
+ console.warn('\nWarning: rizzo.min.css is very small. From repo root run: pnpm build:css');
2157
+ }
2158
+ copyPackageLicense(projectDir);
2159
+ copyVanillaGitignore(projectDir);
2160
+ copyRizzoIcons(projectDir, 'vanilla');
2161
+ } else if (useHandpickAstro) {
1844
2162
  mkdirSync(projectDir, { recursive: true });
1845
- copyDirRecursiveWithReplacements(astroCoreDir, projectDir, replacements);
2163
+ const { skipped } = copyDirRecursiveWithReplacementsNoOverwrite(astroCoreDir, projectDir, replacements, projectDir);
2164
+ copyVariantOverlay(projectDir, 'astro', selectedVariation, replacements);
1846
2165
  copyRizzoCssAndFontsForAstro(projectDir, cssSource);
2166
+ if (skipped.length > 0) {
2167
+ writeFileSync(join(projectDir, RIZZO_SETUP_FILE), buildRizzoSetupMd('astro', { linkHref: '/css/rizzo.min.css', theme, defaultDark, defaultLight, skippedFiles: skipped }), 'utf8');
2168
+ }
1847
2169
  cssTarget = join(projectDir, 'public', 'css', 'rizzo.min.css');
1848
2170
  if (statSync(cssTarget).size < 5000) {
1849
2171
  console.warn('\nWarning: rizzo.min.css is very small. From repo root run: pnpm build:css');
@@ -1856,8 +2178,12 @@ async function cmdInit(argv) {
1856
2178
  }
1857
2179
  } else if (useAstroBase) {
1858
2180
  mkdirSync(projectDir, { recursive: true });
1859
- copyDirRecursiveWithReplacements(astroCoreDir, projectDir, replacements);
2181
+ const { skipped } = copyDirRecursiveWithReplacementsNoOverwrite(astroCoreDir, projectDir, replacements, projectDir);
2182
+ copyVariantOverlay(projectDir, 'astro', selectedVariation, replacements);
1860
2183
  copyRizzoCssAndFontsForAstro(projectDir, cssSource);
2184
+ if (skipped.length > 0) {
2185
+ writeFileSync(join(projectDir, RIZZO_SETUP_FILE), buildRizzoSetupMd('astro', { linkHref: '/css/rizzo.min.css', theme, defaultDark, defaultLight, skippedFiles: skipped }), 'utf8');
2186
+ }
1861
2187
  cssTarget = join(projectDir, 'public', 'css', 'rizzo.min.css');
1862
2188
  if (statSync(cssTarget).size < 5000) {
1863
2189
  console.warn('\nWarning: rizzo.min.css is very small. From repo root run: pnpm build:css');
@@ -1870,8 +2196,12 @@ async function cmdInit(argv) {
1870
2196
  }
1871
2197
  } else if (useHandpickSvelte) {
1872
2198
  mkdirSync(projectDir, { recursive: true });
1873
- copyDirRecursiveWithReplacements(svelteCoreDir, projectDir, replacements);
2199
+ const { skipped } = copyDirRecursiveWithReplacementsNoOverwrite(svelteCoreDir, projectDir, replacements, projectDir);
2200
+ copyVariantOverlay(projectDir, 'svelte', selectedVariation, replacements);
1874
2201
  copyRizzoCssAndFontsForSvelte(projectDir, cssSource);
2202
+ if (skipped.length > 0) {
2203
+ writeFileSync(join(projectDir, RIZZO_SETUP_FILE), buildRizzoSetupMd('svelte', { linkHref: '/css/rizzo.min.css', theme, defaultDark, defaultLight, skippedFiles: skipped }), 'utf8');
2204
+ }
1875
2205
  cssTarget = join(projectDir, 'static', 'css', 'rizzo.min.css');
1876
2206
  if (statSync(cssTarget).size < 5000) {
1877
2207
  console.warn('\nWarning: rizzo.min.css is very small. From repo root run: pnpm build:css');
@@ -1884,8 +2214,12 @@ async function cmdInit(argv) {
1884
2214
  }
1885
2215
  } else if (useSvelteBase) {
1886
2216
  mkdirSync(projectDir, { recursive: true });
1887
- copyDirRecursiveWithReplacements(svelteCoreDir, projectDir, replacements);
2217
+ const { skipped } = copyDirRecursiveWithReplacementsNoOverwrite(svelteCoreDir, projectDir, replacements, projectDir);
2218
+ copyVariantOverlay(projectDir, 'svelte', selectedVariation, replacements);
1888
2219
  copyRizzoCssAndFontsForSvelte(projectDir, cssSource);
2220
+ if (skipped.length > 0) {
2221
+ writeFileSync(join(projectDir, RIZZO_SETUP_FILE), buildRizzoSetupMd('svelte', { linkHref: '/css/rizzo.min.css', theme, defaultDark, defaultLight, skippedFiles: skipped }), 'utf8');
2222
+ }
1889
2223
  cssTarget = join(projectDir, 'static', 'css', 'rizzo.min.css');
1890
2224
  if (statSync(cssTarget).size < 5000) {
1891
2225
  console.warn('\nWarning: rizzo.min.css is very small. From repo root run: pnpm build:css');
@@ -1910,14 +2244,24 @@ async function cmdInit(argv) {
1910
2244
  const vanillaScaffoldPath = getScaffoldVanillaIndex();
1911
2245
  indexPath = join(projectDir, 'index.html');
1912
2246
  let indexHtml = readFileSync(vanillaScaffoldPath, 'utf8');
2247
+ const navbarForIndex = getNavbarHtmlVanilla(name || 'App', 'index.html');
1913
2248
  indexHtml = indexHtml
1914
2249
  .replace(/\{\{DATA_THEME\}\}/g, theme)
1915
2250
  .replace(/\{\{DEFAULT_DARK\}\}/g, defaultDark)
1916
2251
  .replace(/\{\{DEFAULT_LIGHT\}\}/g, defaultLight)
1917
2252
  .replace(/\{\{THEME_LIST_COMMENT\}\}/g, themeComment)
1918
2253
  .replace(/\{\{TITLE\}\}/g, name || 'App')
1919
- .replace(/\{\{LINK_HREF\}\}/g, linkHref);
1920
- writeFileSync(indexPath, indexHtml, 'utf8');
2254
+ .replace(/\{\{LINK_HREF\}\}/g, linkHref)
2255
+ .replace(/\{\{NAVBAR_HTML\}\}/g, navbarForIndex);
2256
+ const vanillaSkipped = [];
2257
+ if (existsSync(indexPath)) {
2258
+ vanillaSkipped.push({ relativePath: 'index.html', content: indexHtml });
2259
+ } else {
2260
+ writeFileSync(indexPath, indexHtml, 'utf8');
2261
+ }
2262
+ if (useVanillaWithOverlay) {
2263
+ copyVariantOverlay(projectDir, 'vanilla', selectedVariation, { ...replacements, '{{LINK_HREF}}': linkHref, '{{TITLE}}': name || 'App', '{{DATA_THEME}}': theme, '{{THEME_LIST_COMMENT}}': themeComment });
2264
+ }
1921
2265
  copyRizzoIcons(projectDir, 'vanilla');
1922
2266
  const vanillaReadme = join(getPackageRoot(), 'scaffold', 'vanilla', SCAFFOLD_README_FILENAME);
1923
2267
  if (existsSync(vanillaReadme)) {
@@ -1932,10 +2276,17 @@ async function cmdInit(argv) {
1932
2276
  }
1933
2277
  const vanillaCoreRepl = { ...replacements, '{{LINK_HREF}}': linkHref };
1934
2278
  copyVanillaComponents(projectDir, Object.keys(VANILLA_COMPONENT_SLUGS), vanillaCoreRepl);
2279
+ if (vanillaSkipped.length > 0) {
2280
+ writeFileSync(join(projectDir, RIZZO_SETUP_FILE), buildRizzoSetupMd('vanilla', { linkHref, theme, defaultDark, defaultLight, skippedFiles: vanillaSkipped }), 'utf8');
2281
+ }
1935
2282
  copyPackageLicense(projectDir);
1936
2283
  copyVanillaGitignore(projectDir);
1937
2284
  } else {
1938
- if (framework === 'svelte') {
2285
+ // Add-to-existing (landing) or Vanilla create new with picked components: CSS, fonts, icons, sfx (framework-appropriate)
2286
+ if (framework === 'astro') {
2287
+ copyRizzoCssAndFontsForAstro(projectDir, cssSource);
2288
+ cssTarget = join(projectDir, 'public', 'css', 'rizzo.min.css');
2289
+ } else if (framework === 'svelte') {
1939
2290
  copyRizzoCssAndFontsForSvelte(projectDir, cssSource);
1940
2291
  cssTarget = join(projectDir, 'static', 'css', 'rizzo.min.css');
1941
2292
  } else {
@@ -1944,42 +2295,84 @@ async function cmdInit(argv) {
1944
2295
  mkdirSync(cssDir, { recursive: true });
1945
2296
  copyFileSync(cssSource, cssTarget);
1946
2297
  copyRizzoFonts(dirname(cssTarget));
1947
- if (framework === 'vanilla') copyRizzoSfx(projectDir);
2298
+ copyRizzoSfx(projectDir);
2299
+ }
2300
+ if (selectedTemplate === 'landing') {
2301
+ copyRizzoIcons(projectDir, framework);
1948
2302
  }
1949
2303
  if (statSync(cssTarget).size < 5000) {
1950
2304
  console.warn('\nWarning: rizzo.min.css is very small. From repo root run: pnpm build:css');
1951
2305
  }
1952
- if (framework === 'vanilla' && selectedTemplate === 'manual') {
2306
+ const linkHrefForSetup = framework === 'vanilla' ? 'css/rizzo.min.css' : '/css/rizzo.min.css';
2307
+ const setupMdContent = buildRizzoSetupMd(framework, {
2308
+ linkHref: linkHrefForSetup,
2309
+ theme,
2310
+ defaultDark,
2311
+ defaultLight,
2312
+ ...(selectedTemplate === 'landing' && { exampleMinimalPage: getLandingTemplateHtml({ theme, themeComment, name, framework }) }),
2313
+ });
2314
+
2315
+ if (selectedTemplate === 'landing') {
2316
+ const vanillaIndex = join(projectDir, 'index.html');
2317
+ const landingHtmlForAdd = getLandingTemplateHtml({ theme, themeComment, name, framework });
2318
+ const astroIndex = join(projectDir, 'public', 'index.html');
2319
+ const svelteIndex = join(projectDir, 'static', 'index.html');
2320
+ if (framework === 'vanilla' && !existsSync(vanillaIndex)) {
2321
+ indexPath = vanillaIndex;
2322
+ writeFileSync(vanillaIndex, landingHtmlForAdd, 'utf8');
2323
+ } else if (framework === 'astro' && !existsSync(astroIndex)) {
2324
+ mkdirSync(join(projectDir, 'public'), { recursive: true });
2325
+ indexPath = astroIndex;
2326
+ writeFileSync(astroIndex, landingHtmlForAdd, 'utf8');
2327
+ } else if (framework === 'svelte' && !existsSync(svelteIndex)) {
2328
+ mkdirSync(join(projectDir, 'static'), { recursive: true });
2329
+ indexPath = svelteIndex;
2330
+ writeFileSync(svelteIndex, landingHtmlForAdd, 'utf8');
2331
+ }
2332
+ writeFileSync(join(projectDir, RIZZO_SETUP_FILE), setupMdContent, 'utf8');
2333
+ copyPackageLicense(projectDir);
2334
+ if (framework === 'vanilla') copyVanillaGitignore(projectDir);
2335
+ } else if (framework === 'vanilla' && selectedTemplate === 'full' && !fullAllComponents) {
1953
2336
  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');
2337
+ if (!existsSync(indexPath)) {
2338
+ let indexContent = landingHtml;
2339
+ if (selectedComponents.length > 0) {
2340
+ mkdirSync(join(projectDir, 'js'), { recursive: true });
2341
+ const vanillaJs = join(getPackageRoot(), 'scaffold', 'vanilla', 'js', 'main.js');
2342
+ if (existsSync(vanillaJs)) {
2343
+ let mainJs = readFileSync(vanillaJs, 'utf8');
2344
+ mainJs = mainJs.replace(/\{\{DEFAULT_DARK\}\}/g, defaultDark).replace(/\{\{DEFAULT_LIGHT\}\}/g, defaultLight).replace(/\{\{RIZZO_SOUND_SCRIPT\}\}/g, vanillaSoundScript);
2345
+ writeFileSync(join(projectDir, 'js', 'main.js'), mainJs, 'utf8');
2346
+ }
2347
+ const vanillaRepl = { ...replacements, '{{LINK_HREF}}': 'css/rizzo.min.css' };
2348
+ copyVanillaComponents(projectDir, selectedComponents, vanillaRepl);
2349
+ copyRizzoIcons(projectDir, 'vanilla');
2350
+ indexContent = landingHtml.replace('</body>', ' <script src="js/main.js"></script>\n</body>');
1962
2351
  }
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>');
2352
+ writeFileSync(indexPath, indexContent, 'utf8');
2353
+ } else {
2354
+ writeFileSync(join(projectDir, RIZZO_SETUP_FILE), buildRizzoSetupMd(framework, { linkHref: 'css/rizzo.min.css', theme, defaultDark, defaultLight, skippedFiles: [{ relativePath: 'index.html', content: landingHtml }] }), 'utf8');
1967
2355
  }
1968
- writeFileSync(indexPath, indexContent, 'utf8');
1969
2356
  writeFileSync(join(projectDir, SCAFFOLD_README_FILENAME), VANILLA_MANUAL_README, 'utf8');
1970
2357
  copyVanillaGitignore(projectDir);
2358
+ copyPackageLicense(projectDir);
1971
2359
  } else if (framework === 'astro') {
1972
2360
  indexPath = join(projectDir, 'public', 'index.html');
1973
2361
  mkdirSync(join(projectDir, 'public'), { recursive: true });
1974
- writeFileSync(indexPath, minimalHtml, 'utf8');
2362
+ if (!existsSync(indexPath)) writeFileSync(indexPath, landingHtml, 'utf8');
2363
+ 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');
1975
2364
  writeFileSync(join(projectDir, SCAFFOLD_README_FILENAME), FALLBACK_MINIMAL_README, 'utf8');
1976
- } else {
2365
+ copyPackageLicense(projectDir);
2366
+ } else if (framework === 'svelte') {
1977
2367
  indexPath = join(projectDir, 'static', 'index.html');
1978
2368
  mkdirSync(join(projectDir, 'static'), { recursive: true });
1979
- writeFileSync(indexPath, minimalHtml, 'utf8');
2369
+ if (!existsSync(indexPath)) writeFileSync(indexPath, landingHtml, 'utf8');
2370
+ 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');
1980
2371
  writeFileSync(join(projectDir, SCAFFOLD_README_FILENAME), FALLBACK_MINIMAL_README, 'utf8');
2372
+ copyPackageLicense(projectDir);
2373
+ } else {
2374
+ copyPackageLicense(projectDir);
1981
2375
  }
1982
- copyPackageLicense(projectDir);
1983
2376
  }
1984
2377
 
1985
2378
  console.log('\n✓ Project ready at ' + projectDir);
@@ -1987,11 +2380,16 @@ async function cmdInit(argv) {
1987
2380
  if (indexPath) console.log(' - ' + indexPath);
1988
2381
  if (framework === 'vanilla') {
1989
2382
  if (useVanillaCore) {
1990
- console.log(' - Vanilla JS (core): theme switcher, js/main.js, icons, component showcase, ' + SCAFFOLD_README_FILENAME + '.');
2383
+ console.log(' - Vanilla JS (full): theme switcher, js/main.js, icons, component showcase, ' + SCAFFOLD_README_FILENAME + '.');
2384
+ } else if (selectedTemplate === 'landing') {
2385
+ console.log(' - ' + RIZZO_SETUP_FILE + ' has instructions and snippets.');
1991
2386
  } else {
1992
- console.log(' - Vanilla JS (manual): index.html + CSS only. Add JS from docs or copy from Core.');
2387
+ console.log(' - Vanilla JS (picked components): index.html + CSS. Add JS from docs or ' + RIZZO_SETUP_FILE + '.');
1993
2388
  }
1994
2389
  }
2390
+ if (existsSync(join(projectDir, RIZZO_SETUP_FILE))) {
2391
+ console.log(' - ' + RIZZO_SETUP_FILE + ' (instructions + snippets for anything we didn\'t overwrite)');
2392
+ }
1995
2393
  const pm = getPackageManagerCommands({ agent: selectedPm, command: selectedPm });
1996
2394
  const nextStep = pm.install + ' && ' + pm.run('dev');
1997
2395
  const runPrefix = projectDir !== cwd ? 'cd ' + pathRelative(cwd, projectDir) + ' && ' : '';
@@ -2050,6 +2448,9 @@ async function cmdInit(argv) {
2050
2448
  const createExample = getCreateProjectExample(pm, framework);
2051
2449
  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') + '.');
2052
2450
  }
2451
+ if (selectedVariation && selectedVariation !== 'landing') {
2452
+ console.log(' - Variation: ' + selectedVariation + ' (layout + starter content).');
2453
+ }
2053
2454
  if (hasPackageJson) {
2054
2455
  console.log('\nNext: ' + runPrefix + nextStep);
2055
2456
  } else if (framework === 'vanilla') {
@@ -2072,6 +2473,7 @@ function main() {
2072
2473
  }
2073
2474
  if (argv[0] && !COMMANDS.includes(command) && command !== 'h') {
2074
2475
  console.error('Unknown command: ' + argv[0] + '\n');
2476
+ process.exitCode = 1;
2075
2477
  }
2076
2478
  printHelp();
2077
2479
  return;