rizzo-css 0.0.15 → 0.0.17

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 (41) hide show
  1. package/README.md +2 -2
  2. package/bin/rizzo-css.js +381 -120
  3. package/dist/rizzo.min.css +8 -5
  4. package/package.json +3 -2
  5. package/scaffold/astro/ThemeIcon.astro +50 -0
  6. package/scaffold/astro-app/src/components/CliCommandTabs.astro +90 -0
  7. package/scaffold/astro-app/src/components/PackageInstallTabs.astro +87 -0
  8. package/scaffold/astro-app/src/components/ThemeIcon.astro +50 -0
  9. package/scaffold/astro-app/src/pages/components/theme-switcher.astro +1 -0
  10. package/scaffold/svelte/ThemeIcon.svelte +54 -0
  11. package/scaffold/svelte/index.ts +2 -0
  12. package/scaffold/svelte-app/src/lib/rizzo/ThemeIcon.svelte +54 -0
  13. package/scaffold/svelte-app/src/lib/rizzo/index.ts +2 -0
  14. package/scaffold/svelte-app/src/lib/rizzo-docs/pages/ThemeSwitcherDoc.svelte +8 -0
  15. package/scaffold/vanilla/README.md +1 -1
  16. package/scaffold/vanilla/components/accordion.html +16 -0
  17. package/scaffold/vanilla/components/alert.html +16 -0
  18. package/scaffold/vanilla/components/avatar.html +16 -0
  19. package/scaffold/vanilla/components/badge.html +16 -0
  20. package/scaffold/vanilla/components/breadcrumb.html +16 -0
  21. package/scaffold/vanilla/components/button.html +16 -0
  22. package/scaffold/vanilla/components/cards.html +16 -0
  23. package/scaffold/vanilla/components/copy-to-clipboard.html +16 -0
  24. package/scaffold/vanilla/components/divider.html +16 -0
  25. package/scaffold/vanilla/components/dropdown.html +16 -0
  26. package/scaffold/vanilla/components/forms.html +16 -0
  27. package/scaffold/vanilla/components/icons.html +16 -0
  28. package/scaffold/vanilla/components/index.html +16 -0
  29. package/scaffold/vanilla/components/modal.html +16 -0
  30. package/scaffold/vanilla/components/navbar.html +16 -0
  31. package/scaffold/vanilla/components/pagination.html +16 -0
  32. package/scaffold/vanilla/components/progress-bar.html +16 -0
  33. package/scaffold/vanilla/components/search.html +16 -0
  34. package/scaffold/vanilla/components/settings.html +16 -0
  35. package/scaffold/vanilla/components/spinner.html +16 -0
  36. package/scaffold/vanilla/components/table.html +16 -0
  37. package/scaffold/vanilla/components/tabs.html +16 -0
  38. package/scaffold/vanilla/components/theme-switcher.html +16 -0
  39. package/scaffold/vanilla/components/toast.html +16 -0
  40. package/scaffold/vanilla/components/tooltip.html +16 -0
  41. package/scaffold/vanilla/index.html +16 -0
package/bin/rizzo-css.js CHANGED
@@ -2,10 +2,29 @@
2
2
 
3
3
  const { copyFileSync, mkdirSync, writeFileSync, existsSync, readFileSync, readdirSync, statSync } = require('fs');
4
4
  const { join, dirname } = require('path');
5
+ const { spawnSync } = require('child_process');
5
6
  const readline = require('readline');
6
7
 
8
+ const RIZZO_CONFIG_FILE = 'rizzo-css.json';
9
+
7
10
  const COMMANDS = ['init', 'add', 'theme', 'help'];
8
11
  const FRAMEWORKS = ['vanilla', 'astro', 'svelte'];
12
+
13
+ /** Template options per framework for "create new". full-app = full Astro/Svelte app scaffold; full = vanilla with theme switcher + js; minimal = CSS + single HTML only. */
14
+ const TEMPLATES = {
15
+ vanilla: [
16
+ { value: 'full', label: 'Full — index.html + theme switcher, js/main.js, icons, README' },
17
+ { value: 'minimal', label: 'Minimal — index.html + CSS link only' },
18
+ ],
19
+ astro: [
20
+ { value: 'full-app', label: 'Full app — complete Astro project with Rizzo CSS' },
21
+ { value: 'minimal', label: 'Minimal — public/css + index.html with CSS link' },
22
+ ],
23
+ svelte: [
24
+ { value: 'full-app', label: 'Full app — complete SvelteKit project with Rizzo CSS' },
25
+ { value: 'minimal', label: 'Minimal — static/css + index.html with CSS link' },
26
+ ],
27
+ };
9
28
  // Dark and light themes (order matches scaffold optgroups and config/themes.ts)
10
29
  const DARK_THEMES = [
11
30
  'github-dark-classic',
@@ -67,6 +86,115 @@ function getCssPath() {
67
86
  return join(getPackageRoot(), 'dist', 'rizzo.min.css');
68
87
  }
69
88
 
89
+ /** Read rizzo-css.json from cwd. Returns { targetDir?, framework?, packageManager? } or null. */
90
+ function readRizzoConfig(cwd) {
91
+ if (!cwd || !existsSync(cwd)) return null;
92
+ const configPath = join(cwd, RIZZO_CONFIG_FILE);
93
+ if (!existsSync(configPath)) return null;
94
+ try {
95
+ const raw = JSON.parse(readFileSync(configPath, 'utf8'));
96
+ const out = {};
97
+ if (typeof raw.targetDir === 'string') out.targetDir = raw.targetDir;
98
+ if (typeof raw.framework === 'string' && FRAMEWORKS.includes(raw.framework)) out.framework = raw.framework;
99
+ if (typeof raw.packageManager === 'string' && ['npm', 'pnpm', 'yarn', 'bun'].includes(raw.packageManager)) out.packageManager = raw.packageManager;
100
+ return Object.keys(out).length ? out : null;
101
+ } catch (_) { return null; }
102
+ }
103
+
104
+ /** Write rizzo-css.json to cwd. config: { targetDir?, framework?, packageManager? }. */
105
+ function writeRizzoConfig(cwd, config) {
106
+ if (!cwd || !existsSync(cwd)) return;
107
+ const configPath = join(cwd, RIZZO_CONFIG_FILE);
108
+ const obj = {};
109
+ if (config.targetDir != null) obj.targetDir = config.targetDir;
110
+ if (config.framework != null) obj.framework = config.framework;
111
+ if (config.packageManager != null) obj.packageManager = config.packageManager;
112
+ writeFileSync(configPath, JSON.stringify(obj, null, 2) + '\n', 'utf8');
113
+ }
114
+
115
+ /** Run a command in cwd. command is the full string (e.g. "pnpm add rizzo-css"). Returns exit code. */
116
+ function runInDir(cwd, command) {
117
+ const result = spawnSync(command, { cwd, shell: true, stdio: 'inherit' });
118
+ return result.status != null ? result.status : result.signal ? 1 : 0;
119
+ }
120
+
121
+ function hasFlag(argv, flag) {
122
+ return argv.indexOf(flag) !== -1;
123
+ }
124
+
125
+ function getFlagValue(argv, flag) {
126
+ const i = argv.indexOf(flag);
127
+ return i !== -1 && argv[i + 1] != null ? argv[i + 1] : null;
128
+ }
129
+
130
+ /** Package manager detection (manual: lockfiles + packageManager field). Returns { agent, command } or null if none found. */
131
+ function detectPackageManager(cwd) {
132
+ if (!cwd || !existsSync(cwd)) return null;
133
+ if (existsSync(join(cwd, 'pnpm-lock.yaml'))) return { agent: 'pnpm', command: 'pnpm' };
134
+ if (existsSync(join(cwd, 'yarn.lock'))) return { agent: 'yarn', command: 'yarn' };
135
+ if (existsSync(join(cwd, 'bun.lockb'))) return { agent: 'bun', command: 'bun' };
136
+ if (existsSync(join(cwd, 'package-lock.json')) || existsSync(join(cwd, 'npm-shrinkwrap.json'))) return { agent: 'npm', command: 'npm' };
137
+ const pkgPath = join(cwd, 'package.json');
138
+ if (existsSync(pkgPath)) {
139
+ try {
140
+ const pkg = JSON.parse(readFileSync(pkgPath, 'utf8'));
141
+ const pm = pkg.packageManager || (pkg.devEngines && pkg.devEngines.packageManager);
142
+ if (typeof pm === 'string') {
143
+ const name = (pm.split('@')[0] || '').toLowerCase();
144
+ if (['npm', 'pnpm', 'yarn', 'bun'].includes(name)) return { agent: name, command: name };
145
+ }
146
+ } catch (_) { /* ignore */ }
147
+ }
148
+ return null;
149
+ }
150
+
151
+ /** Get install and run commands for a package manager. pm: { agent, command } from detectPackageManager. */
152
+ function getPackageManagerCommands(pm) {
153
+ if (!pm) pm = { agent: 'npm', command: 'npm' };
154
+ const c = pm.command;
155
+ return {
156
+ agent: pm.agent,
157
+ install: c + ' install',
158
+ run: (script) => (pm.agent === 'npm' ? c + ' run ' + script : c + ' run ' + script),
159
+ add: (pkg) => (pm.agent === 'npm' ? c + ' install ' + pkg : c + ' add ' + pkg),
160
+ addDev: (pkg) => (pm.agent === 'npm' ? c + ' install -D ' + pkg : pm.agent === 'bun' ? c + ' add -d ' + pkg : c + ' add -D ' + pkg),
161
+ dlx: (pkgAndArgs) => (pm.agent === 'npm' ? 'npx ' + pkgAndArgs : pm.agent === 'pnpm' ? 'pnpm dlx ' + pkgAndArgs : pm.agent === 'yarn' ? 'yarn dlx ' + pkgAndArgs : 'bunx ' + pkgAndArgs),
162
+ };
163
+ }
164
+
165
+ /** Detect package manager for a project dir, falling back to cwd then default npm. */
166
+ function resolvePackageManager(projectDir, fallbackCwd) {
167
+ const pm = detectPackageManager(projectDir) || detectPackageManager(fallbackCwd || process.cwd());
168
+ return getPackageManagerCommands(pm || { agent: 'npm', command: 'npm' });
169
+ }
170
+
171
+ /** Example command to create a new framework project (e.g. create-astro, create-svelte). */
172
+ function getCreateProjectExample(pm, framework) {
173
+ const createPkg = 'create-' + framework + '@latest';
174
+ if (pm.agent === 'npm') return 'npm create ' + framework + '@latest my-app';
175
+ if (pm.agent === 'pnpm') return 'pnpm dlx ' + createPkg + ' my-app';
176
+ if (pm.agent === 'yarn') return 'yarn create ' + framework + ' my-app';
177
+ if (pm.agent === 'bun') return 'bun create ' + framework + ' my-app';
178
+ return 'npm create ' + framework + '@latest my-app';
179
+ }
180
+
181
+ /** Prompt user to select package manager (npm, pnpm, yarn, bun). Puts detected first with "(detected)" label. Returns agent string. */
182
+ async function promptPackageManager(projectDir) {
183
+ const detected = resolvePackageManager(projectDir, process.cwd());
184
+ const agents = ['npm', 'pnpm', 'yarn', 'bun'];
185
+ const options = agents.map((a) => ({
186
+ value: a,
187
+ label: a === detected.agent ? a + ' (detected)' : a,
188
+ }));
189
+ return selectMenu(options, '? Package manager (for install and run commands)');
190
+ }
191
+
192
+ /** Prompt user to select template for the chosen framework. Returns template value (full-app, full, or minimal). */
193
+ async function promptTemplate(framework) {
194
+ const options = TEMPLATES[framework] || TEMPLATES.vanilla;
195
+ return selectMenu(options, '? Template');
196
+ }
197
+
70
198
  function question(prompt) {
71
199
  const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
72
200
  return new Promise((resolve) => {
@@ -339,29 +467,57 @@ function multiSelectMenu(options, title) {
339
467
 
340
468
  function printHelp() {
341
469
  console.log(`
342
- rizzo-css CLI — Add Rizzo CSS to your project
470
+ rizzo-css CLI — Add Rizzo CSS to your project (Vanilla, Astro, Svelte)
343
471
 
344
- Usage:
472
+ Usage (use your package manager):
345
473
  npx rizzo-css <command> [options]
474
+ pnpm dlx rizzo-css <command> [options]
475
+ yarn dlx rizzo-css <command> [options]
476
+ bunx rizzo-css <command> [options]
346
477
 
347
478
  Commands:
348
- init Add Rizzo to existing project or scaffold new one (first: framework, then existing vs new)
349
- add Copy Rizzo CSS into the current project (auto-detects Svelte/Astro)
479
+ init Add Rizzo to existing project or scaffold new one (framework existing vs new → themes/components/PM)
480
+ add Copy Rizzo CSS into the current project (auto-detects Vanilla/Astro/Svelte; use rizzo-css.json if present)
350
481
  theme List all available themes (use in init or set data-theme on <html>)
351
482
  help Show this help
352
483
 
353
- Use framework CLI first, then add Rizzo CSS:
354
- npm create svelte@latest my-app
355
- cd my-app && npx rizzo-css add
356
-
357
- npm create astro@latest my-app
358
- cd my-app && npx rizzo-css add
484
+ Options (init):
485
+ --yes Non-interactive: scaffold new in cwd with defaults (framework: astro, template: full-app, no components)
486
+ --framework <fw> vanilla | astro | svelte (with --yes; otherwise first prompt)
487
+ --template <t> full-app (Astro/Svelte) or full | minimal (Vanilla); with --yes defaults to full-app or full
488
+ --install After scaffolding, run package manager install (full-app only)
489
+ --no-install Do not run install
490
+ --write-config Write rizzo-css.json (targetDir, framework, packageManager) in the project
491
+
492
+ Options (add):
493
+ --path <dir> Target directory for rizzo.min.css (overrides config and framework default)
494
+ --framework <fw> vanilla | astro | svelte (overrides config and detection)
495
+ --install-package After copying CSS, run package manager add rizzo-css
496
+ --no-install Do not run install or add (overrides --install-package)
497
+
498
+ Config:
499
+ Optional rizzo-css.json in project root: { "targetDir", "framework", "packageManager" }.
500
+ Used by add and init when present. Detection: lockfiles and packageManager field in package.json.
501
+
502
+ Use framework CLI first, then add Rizzo CSS (match your package manager):
503
+ For Vanilla: npx rizzo-css init --yes --framework vanilla
504
+ npm create svelte@latest my-app && cd my-app && npx rizzo-css add
505
+ pnpm dlx create-svelte@latest my-app && cd my-app && pnpm dlx rizzo-css add
506
+ yarn create svelte my-app && cd my-app && yarn dlx rizzo-css add
507
+ bun create svelte my-app && cd my-app && bunx rizzo-css add
508
+ npm create astro@latest my-app && cd my-app && npx rizzo-css add
509
+ pnpm dlx create-astro@latest my-app && cd my-app && pnpm dlx rizzo-css add
510
+ yarn create astro my-app && cd my-app && yarn dlx rizzo-css add
511
+ bun create astro my-app && cd my-app && bunx rizzo-css add
359
512
 
360
513
  Examples:
361
514
  npx rizzo-css init
515
+ npx rizzo-css init --yes --framework astro --install --write-config
516
+ npx rizzo-css init --yes --framework vanilla
517
+ npx rizzo-css init --yes --framework svelte --template minimal
362
518
  npx rizzo-css add
363
- npx rizzo-css add --path public/css
364
- npx rizzo-css add --framework svelte
519
+ npx rizzo-css add --install-package
520
+ npx rizzo-css add --path public/css --framework svelte
365
521
  npx rizzo-css theme
366
522
 
367
523
  Docs: https://rizzo-css.vercel.app
@@ -463,16 +619,17 @@ function getLinkHrefForTargetDir(framework, targetDir) {
463
619
  }
464
620
 
465
621
  function cmdAdd(argv) {
466
- const pathIdx = argv.indexOf('--path');
467
- const customPath = pathIdx !== -1 && argv[pathIdx + 1] ? argv[pathIdx + 1] : null;
468
- const frameworkIdx = argv.indexOf('--framework');
469
- const explicitFramework = frameworkIdx !== -1 && argv[frameworkIdx + 1] ? argv[frameworkIdx + 1].toLowerCase() : null;
622
+ const customPath = getFlagValue(argv, '--path');
623
+ const explicitFrameworkRaw = getFlagValue(argv, '--framework');
624
+ const explicitFramework = explicitFrameworkRaw && FRAMEWORKS.includes(explicitFrameworkRaw.toLowerCase()) ? explicitFrameworkRaw.toLowerCase() : null;
625
+ const installPackage = hasFlag(argv, '--install-package');
626
+ const noInstall = hasFlag(argv, '--no-install');
627
+
470
628
  const cwd = process.cwd();
471
- const framework = explicitFramework && FRAMEWORKS.includes(explicitFramework)
472
- ? explicitFramework
473
- : (explicitFramework === null ? detectFramework(cwd) : null);
629
+ const config = readRizzoConfig(cwd);
630
+ let framework = explicitFramework || (config && config.framework) || detectFramework(cwd);
474
631
  const paths = getFrameworkCssPaths(framework);
475
- const targetDir = customPath || paths.targetDir;
632
+ const targetDir = customPath || (config && config.targetDir) || paths.targetDir;
476
633
  const targetFile = join(cwd, targetDir, 'rizzo.min.css');
477
634
  const cssSource = getCssPath();
478
635
 
@@ -481,27 +638,47 @@ function cmdAdd(argv) {
481
638
  process.exit(1);
482
639
  }
483
640
 
641
+ const pm = (config && config.packageManager)
642
+ ? getPackageManagerCommands({ agent: config.packageManager, command: config.packageManager })
643
+ : resolvePackageManager(cwd);
644
+ const addPkg = pm.add('rizzo-css');
645
+ const linkHref = customPath ? getLinkHrefForTargetDir(framework, targetDir) : paths.linkHref;
646
+ const cliExample = pm.dlx('rizzo-css theme');
647
+ const initExample = pm.dlx('rizzo-css init');
648
+
484
649
  mkdirSync(join(cwd, targetDir), { recursive: true });
485
650
  copyFileSync(cssSource, targetFile);
486
- const linkHref = customPath ? getLinkHrefForTargetDir(framework, targetDir) : paths.linkHref;
487
651
  console.log('\n✓ Rizzo CSS copied to ' + targetFile);
652
+
653
+ if (installPackage && !noInstall) {
654
+ console.log('\nRunning: ' + addPkg);
655
+ const code = runInDir(cwd, addPkg);
656
+ if (code !== 0) {
657
+ console.error('\nInstall failed (exit ' + code + '). You can run manually: ' + addPkg);
658
+ }
659
+ }
660
+
488
661
  if (framework === 'svelte') {
489
662
  console.log('\nDetected Svelte/SvelteKit. Add to your root layout (e.g. src/app.html):\n');
490
663
  console.log(' <link rel="stylesheet" href="' + linkHref + '" />');
491
- console.log('\nSet a theme on <html>: data-theme="github-dark-classic" (see: npx rizzo-css theme)');
492
- console.log('\nTo add Rizzo Svelte components later: copy from this package\'s scaffold or run npx rizzo-css init and pick Svelte + components in an empty folder, then copy the generated files.\n');
664
+ console.log('\nSet a theme on <html>: data-theme="github-dark-classic" (see: ' + cliExample + ')');
665
+ console.log('\nTo add Rizzo Svelte components later: copy from this package\'s scaffold or run ' + initExample + ' and pick Svelte + components in an empty folder, then copy the generated files.\n');
493
666
  } else if (framework === 'astro') {
494
667
  console.log('\nDetected Astro. Add to your layout (e.g. src/layouts/Layout.astro):\n');
495
668
  console.log(' <link rel="stylesheet" href="' + linkHref + '" />');
496
- console.log('\nSet a theme on <html>: data-theme="github-dark-classic" (see: npx rizzo-css theme)\n');
669
+ console.log('\nSet a theme on <html>: data-theme="github-dark-classic" (see: ' + cliExample + ')\n');
497
670
  } else {
498
671
  console.log('\nAdd to your HTML or layout:\n');
499
672
  console.log(' <link rel="stylesheet" href="' + linkHref + '" />');
500
673
  if (framework === 'vanilla') {
501
674
  console.log('\nVanilla JS: same CSS and component classes as Astro/Svelte. Use the same BEM markup from the docs.');
502
675
  }
503
- console.log('\nSet a theme on <html>: data-theme="github-dark-classic" (see: npx rizzo-css theme)\n');
676
+ console.log('\nSet a theme on <html>: data-theme="github-dark-classic" (see: ' + cliExample + ')');
504
677
  }
678
+ if (!installPackage || noInstall) {
679
+ console.log('\nTo install the package (CLI + components): ' + addPkg);
680
+ }
681
+ console.log('\nDocs: https://rizzo-css.vercel.app\n');
505
682
  }
506
683
 
507
684
  function getScaffoldSvelteDir() {
@@ -670,10 +847,11 @@ function copyAstroComponents(projectDir, selectedNames) {
670
847
  }
671
848
  }
672
849
 
673
- /** Add Rizzo CSS (and optional components) to an existing project in cwd. frameworkOverride: when set (from init), skip framework prompt. */
674
- async function runAddToExisting(frameworkOverride) {
850
+ /** Add Rizzo CSS (and optional components) to an existing project in cwd. frameworkOverride: when set (from init), skip framework prompt. options: { config? }. */
851
+ async function runAddToExisting(frameworkOverride, options) {
675
852
  const cwd = process.cwd();
676
- let framework = frameworkOverride;
853
+ const config = (options && options.config) || readRizzoConfig(cwd);
854
+ let framework = frameworkOverride || (config && config.framework);
677
855
  if (framework == null) {
678
856
  const detected = detectFramework(cwd);
679
857
  const frameworkOptions = [
@@ -739,13 +917,17 @@ async function runAddToExisting(frameworkOverride) {
739
917
  }
740
918
 
741
919
  const linkHref = paths.linkHref;
920
+ const pm = (config && config.packageManager)
921
+ ? getPackageManagerCommands({ agent: config.packageManager, command: config.packageManager })
922
+ : resolvePackageManager(cwd);
923
+ const cliExample = pm.dlx('rizzo-css theme');
742
924
  console.log('\n✓ Rizzo CSS added to your existing project');
743
925
  console.log(' - ' + cssTarget);
744
926
  console.log('\nYou must add the stylesheet link yourself — it is not added automatically.');
745
927
  if (framework === 'svelte') {
746
928
  console.log('\nIn your root layout (e.g. src/app.html), add:');
747
929
  console.log(' <link rel="stylesheet" href="' + linkHref + '" />');
748
- console.log('\nSet a theme on <html>: data-theme="' + theme + '" (see: npx rizzo-css theme)');
930
+ console.log('\nSet a theme on <html>: data-theme="' + theme + '" (see: ' + cliExample + ')');
749
931
  console.log(' For theme "system": default dark ' + defaultDark + ', default light ' + defaultLight);
750
932
  if (selectedComponents.length > 0) {
751
933
  console.log(' Components are in src/lib/rizzo — import from \'$lib/rizzo\'.');
@@ -753,7 +935,7 @@ async function runAddToExisting(frameworkOverride) {
753
935
  } else if (framework === 'astro') {
754
936
  console.log('\nIn your layout (e.g. src/layouts/Layout.astro), add:');
755
937
  console.log(' <link rel="stylesheet" href="' + linkHref + '" />');
756
- console.log('\nSet a theme on <html>: data-theme="' + theme + '" (see: npx rizzo-css theme)');
938
+ console.log('\nSet a theme on <html>: data-theme="' + theme + '" (see: ' + cliExample + ')');
757
939
  console.log(' For theme "system": default dark ' + defaultDark + ', default light ' + defaultLight);
758
940
  if (selectedComponents.length > 0) {
759
941
  console.log(' Components are in src/components/rizzo — import from there.');
@@ -761,52 +943,92 @@ async function runAddToExisting(frameworkOverride) {
761
943
  } else {
762
944
  console.log('\nIn your HTML or layout, add:');
763
945
  console.log(' <link rel="stylesheet" href="' + linkHref + '" />');
764
- console.log('\nSet a theme on <html>: data-theme="' + theme + '" (see: npx rizzo-css theme)');
946
+ console.log('\nSet a theme on <html>: data-theme="' + theme + '" (see: ' + cliExample + ')');
765
947
  console.log(' For theme "system": default dark ' + defaultDark + ', default light ' + defaultLight);
766
948
  }
949
+ console.log('\nTo install the package (CLI + components): ' + pm.add('rizzo-css'));
767
950
  console.log('\nDocs: https://rizzo-css.vercel.app\n');
768
951
  }
769
952
 
770
- async function cmdInit() {
771
- const framework = await selectMenu(
772
- [
773
- { value: 'vanilla', label: 'Vanilla JS (HTML + CSS + same styles & components)', color: C.vanilla },
774
- { value: 'astro', label: 'Astro', color: C.astro },
775
- { value: 'svelte', label: 'Svelte', color: C.svelte },
776
- ],
777
- '? Framework all get the same CSS and component styles'
778
- );
953
+ async function cmdInit(argv) {
954
+ argv = argv || [];
955
+ const yes = hasFlag(argv, '--yes');
956
+ const runInstallAfterScaffold = hasFlag(argv, '--install');
957
+ const noInstall = hasFlag(argv, '--no-install');
958
+ const writeConfig = hasFlag(argv, '--write-config');
959
+ const cwd = process.cwd();
960
+ const config = readRizzoConfig(cwd);
779
961
 
780
- const initMode = await selectMenu(
781
- [
782
- { value: 'existing', label: 'Add to existing project (current directory)' },
783
- { value: 'new', label: 'Create new project (scaffold)' },
784
- ],
785
- '? Add to existing project or create a new one?'
786
- );
962
+ let framework;
963
+ let initMode;
964
+ let name = '';
965
+ let theme, defaultDark, defaultLight;
966
+ let selectedComponents = [];
967
+ let selectedPm;
968
+ let selectedTemplate;
969
+
970
+ if (yes) {
971
+ const frameworkArg = getFlagValue(argv, '--framework');
972
+ framework = (frameworkArg && FRAMEWORKS.includes(frameworkArg.toLowerCase())) ? frameworkArg.toLowerCase() : (config && config.framework) || 'astro';
973
+ initMode = 'new';
974
+ const templateArg = getFlagValue(argv, '--template');
975
+ selectedTemplate = (templateArg && (templateArg === 'full-app' || templateArg === 'full' || templateArg === 'minimal')) ? templateArg : (framework === 'vanilla' ? 'full' : 'full-app');
976
+ if (framework === 'vanilla' && selectedTemplate === 'full-app') selectedTemplate = 'full';
977
+ const projectDir = cwd;
978
+ const resolved = resolvePackageManager(projectDir, cwd);
979
+ selectedPm = (config && config.packageManager) || resolved.agent || 'npm';
980
+ theme = 'system';
981
+ defaultDark = DARK_THEMES[0];
982
+ defaultLight = LIGHT_THEMES[0];
983
+ } else {
984
+ framework = await selectMenu(
985
+ [
986
+ { value: 'vanilla', label: 'Vanilla JS (HTML + CSS + same styles & components)', color: C.vanilla },
987
+ { value: 'astro', label: 'Astro', color: C.astro },
988
+ { value: 'svelte', label: 'Svelte', color: C.svelte },
989
+ ],
990
+ '? Framework — all get the same CSS and component styles'
991
+ );
787
992
 
788
- if (initMode === 'existing') {
789
- await runAddToExisting(framework);
790
- return;
791
- }
993
+ initMode = await selectMenu(
994
+ [
995
+ { value: 'existing', label: 'Add to existing project (current directory)' },
996
+ { value: 'new', label: 'Create new project (scaffold)' },
997
+ ],
998
+ '? Add to existing project or create a new one?'
999
+ );
792
1000
 
793
- const projectChoice = await selectMenu(
794
- [
795
- { value: 'cwd', label: 'Current directory' },
796
- { value: 'name', label: 'Enter project name (new folder)' },
797
- ],
798
- '? Project location'
799
- );
800
- const name = projectChoice === 'name' ? await question('Project name (folder name): ') : '';
1001
+ if (initMode === 'existing') {
1002
+ await runAddToExisting(framework, { config });
1003
+ return;
1004
+ }
801
1005
 
802
- const { theme, defaultDark, defaultLight } = await promptThemes();
1006
+ const projectChoice = await selectMenu(
1007
+ [
1008
+ { value: 'cwd', label: 'Current directory' },
1009
+ { value: 'name', label: 'Enter project name (new folder)' },
1010
+ ],
1011
+ '? Project location'
1012
+ );
1013
+ name = projectChoice === 'name' ? await question('Project name (folder name): ') : '';
803
1014
 
804
- const componentList = framework === 'svelte' ? SVELTE_COMPONENTS : framework === 'astro' ? ASTRO_COMPONENTS : [];
805
- const selectedComponents = componentList.length > 0
806
- ? await promptComponentChoice(componentList, framework)
807
- : [];
1015
+ selectedTemplate = await promptTemplate(framework);
1016
+
1017
+ const themeOut = await promptThemes();
1018
+ theme = themeOut.theme;
1019
+ defaultDark = themeOut.defaultDark;
1020
+ defaultLight = themeOut.defaultLight;
808
1021
 
809
- const projectDir = name ? join(process.cwd(), name) : process.cwd();
1022
+ const componentList = framework === 'svelte' ? SVELTE_COMPONENTS : framework === 'astro' ? ASTRO_COMPONENTS : [];
1023
+ selectedComponents = componentList.length > 0
1024
+ ? await promptComponentChoice(componentList, framework)
1025
+ : [];
1026
+
1027
+ const projectDirForPm = name ? join(cwd, name) : cwd;
1028
+ selectedPm = await promptPackageManager(projectDirForPm);
1029
+ }
1030
+
1031
+ const projectDir = name ? join(cwd, name) : cwd;
810
1032
  const cssSource = getCssPath();
811
1033
 
812
1034
  if (!existsSync(cssSource)) {
@@ -829,11 +1051,30 @@ async function cmdInit() {
829
1051
 
830
1052
  const astroAppDir = getScaffoldAstroAppDir();
831
1053
  const svelteAppDir = getScaffoldSvelteAppDir();
1054
+ const pathsForScaffold = getFrameworkCssPaths(framework);
1055
+ const useAstroApp = framework === 'astro' && selectedTemplate === 'full-app' && existsSync(astroAppDir);
1056
+ const useSvelteApp = framework === 'svelte' && selectedTemplate === 'full-app' && existsSync(svelteAppDir);
1057
+ const useVanillaFull = framework === 'vanilla' && selectedTemplate === 'full' && existsSync(getScaffoldVanillaIndex());
832
1058
 
833
1059
  let cssTarget;
834
1060
  let indexPath;
835
1061
 
836
- if (framework === 'astro' && existsSync(astroAppDir)) {
1062
+ const minimalHtml = `<!DOCTYPE html>
1063
+ <html lang="en" data-theme="${theme}">${themeComment}
1064
+ <head>
1065
+ <meta charset="UTF-8" />
1066
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
1067
+ <title>${name || 'App'}</title>
1068
+ <link rel="stylesheet" href="${framework === 'vanilla' ? 'css/rizzo.min.css' : '/css/rizzo.min.css'}" />
1069
+ </head>
1070
+ <body>
1071
+ <h1>Hello, Rizzo CSS</h1>
1072
+ <p>Edit this file and add components. Docs: <a href="https://rizzo-css.vercel.app">rizzo-css.vercel.app</a></p>
1073
+ </body>
1074
+ </html>
1075
+ `;
1076
+
1077
+ if (useAstroApp) {
837
1078
  mkdirSync(projectDir, { recursive: true });
838
1079
  copyDirRecursiveWithReplacements(astroAppDir, projectDir, replacements);
839
1080
  mkdirSync(join(projectDir, 'public', 'css'), { recursive: true });
@@ -846,7 +1087,7 @@ async function cmdInit() {
846
1087
  if (selectedComponents.length > 0) {
847
1088
  copyAstroComponents(projectDir, selectedComponents);
848
1089
  }
849
- } else if (framework === 'svelte' && existsSync(svelteAppDir)) {
1090
+ } else if (useSvelteApp) {
850
1091
  mkdirSync(projectDir, { recursive: true });
851
1092
  copyDirRecursiveWithReplacements(svelteAppDir, projectDir, replacements);
852
1093
  mkdirSync(join(projectDir, 'static', 'css'), { recursive: true });
@@ -859,62 +1100,63 @@ async function cmdInit() {
859
1100
  if (selectedComponents.length > 0) {
860
1101
  copySvelteComponents(projectDir, selectedComponents);
861
1102
  }
862
- } else {
863
- const cssDir = framework === 'astro' ? join(projectDir, 'public', 'css') : join(projectDir, 'css');
1103
+ } else if (useVanillaFull) {
1104
+ const cssDir = join(projectDir, pathsForScaffold.targetDir);
864
1105
  cssTarget = join(cssDir, 'rizzo.min.css');
865
- const linkHref = framework === 'astro' ? '/css/rizzo.min.css' : 'css/rizzo.min.css';
1106
+ const linkHref = 'css/rizzo.min.css';
866
1107
  mkdirSync(cssDir, { recursive: true });
867
1108
  copyFileSync(cssSource, cssTarget);
868
1109
  if (statSync(cssTarget).size < 5000) {
869
1110
  console.warn('\nWarning: rizzo.min.css is very small. From repo root run: pnpm build:css');
870
1111
  }
871
-
872
1112
  const vanillaScaffoldPath = getScaffoldVanillaIndex();
873
1113
  indexPath = join(projectDir, 'index.html');
874
- if (framework === 'vanilla' && existsSync(vanillaScaffoldPath)) {
875
- let indexHtml = readFileSync(vanillaScaffoldPath, 'utf8');
876
- indexHtml = indexHtml
877
- .replace(/\{\{DATA_THEME\}\}/g, theme)
878
- .replace(/\{\{DEFAULT_DARK\}\}/g, defaultDark)
879
- .replace(/\{\{DEFAULT_LIGHT\}\}/g, defaultLight)
880
- .replace(/\{\{THEME_LIST_COMMENT\}\}/g, themeComment)
881
- .replace(/\{\{TITLE\}\}/g, name || 'App')
882
- .replace(/\{\{LINK_HREF\}\}/g, linkHref);
883
- writeFileSync(indexPath, indexHtml, 'utf8');
884
- } else {
885
- const indexHtml = `<!DOCTYPE html>
886
- <html lang="en" data-theme="${theme}">${themeComment}
887
- <head>
888
- <meta charset="UTF-8" />
889
- <meta name="viewport" content="width=device-width, initial-scale=1" />
890
- <title>${name || 'App'}</title>
891
- <link rel="stylesheet" href="${linkHref}" />
892
- </head>
893
- <body>
894
- <h1>Hello, Rizzo CSS</h1>
895
- <p>Edit this file and add components. Docs: <a href="https://rizzo-css.vercel.app">rizzo-css.vercel.app</a></p>
896
- </body>
897
- </html>
898
- `;
899
- writeFileSync(indexPath, indexHtml, 'utf8');
1114
+ let indexHtml = readFileSync(vanillaScaffoldPath, 'utf8');
1115
+ indexHtml = indexHtml
1116
+ .replace(/\{\{DATA_THEME\}\}/g, theme)
1117
+ .replace(/\{\{DEFAULT_DARK\}\}/g, defaultDark)
1118
+ .replace(/\{\{DEFAULT_LIGHT\}\}/g, defaultLight)
1119
+ .replace(/\{\{THEME_LIST_COMMENT\}\}/g, themeComment)
1120
+ .replace(/\{\{TITLE\}\}/g, name || 'App')
1121
+ .replace(/\{\{LINK_HREF\}\}/g, linkHref);
1122
+ writeFileSync(indexPath, indexHtml, 'utf8');
1123
+ copyRizzoIcons(projectDir, 'vanilla');
1124
+ const vanillaReadme = join(getPackageRoot(), 'scaffold', 'vanilla', 'README.md');
1125
+ if (existsSync(vanillaReadme)) {
1126
+ copyFileSync(vanillaReadme, join(projectDir, 'README.md'));
1127
+ }
1128
+ const vanillaJs = join(getPackageRoot(), 'scaffold', 'vanilla', 'js', 'main.js');
1129
+ if (existsSync(vanillaJs)) {
1130
+ mkdirSync(join(projectDir, 'js'), { recursive: true });
1131
+ let mainJs = readFileSync(vanillaJs, 'utf8');
1132
+ mainJs = mainJs.replace(/\{\{DEFAULT_DARK\}\}/g, defaultDark).replace(/\{\{DEFAULT_LIGHT\}\}/g, defaultLight);
1133
+ writeFileSync(join(projectDir, 'js', 'main.js'), mainJs, 'utf8');
1134
+ }
1135
+ } else {
1136
+ const cssDir = join(projectDir, pathsForScaffold.targetDir);
1137
+ cssTarget = join(cssDir, 'rizzo.min.css');
1138
+ mkdirSync(cssDir, { recursive: true });
1139
+ copyFileSync(cssSource, cssTarget);
1140
+ if (statSync(cssTarget).size < 5000) {
1141
+ console.warn('\nWarning: rizzo.min.css is very small. From repo root run: pnpm build:css');
900
1142
  }
901
- copyRizzoIcons(projectDir, framework);
902
1143
  if (framework === 'vanilla') {
903
- const vanillaReadme = join(getPackageRoot(), 'scaffold', 'vanilla', 'README.md');
904
- if (existsSync(vanillaReadme)) {
905
- copyFileSync(vanillaReadme, join(projectDir, 'README.md'));
906
- }
907
- const vanillaJs = join(getPackageRoot(), 'scaffold', 'vanilla', 'js', 'main.js');
908
- if (existsSync(vanillaJs)) {
909
- mkdirSync(join(projectDir, 'js'), { recursive: true });
910
- let mainJs = readFileSync(vanillaJs, 'utf8');
911
- mainJs = mainJs.replace(/\{\{DEFAULT_DARK\}\}/g, defaultDark).replace(/\{\{DEFAULT_LIGHT\}\}/g, defaultLight);
912
- writeFileSync(join(projectDir, 'js', 'main.js'), mainJs, 'utf8');
913
- }
1144
+ indexPath = join(projectDir, 'index.html');
1145
+ writeFileSync(indexPath, minimalHtml, 'utf8');
1146
+ } else if (framework === 'astro') {
1147
+ indexPath = join(projectDir, 'public', 'index.html');
1148
+ mkdirSync(join(projectDir, 'public'), { recursive: true });
1149
+ writeFileSync(indexPath, minimalHtml, 'utf8');
1150
+ } else {
1151
+ indexPath = join(projectDir, 'static', 'index.html');
1152
+ mkdirSync(join(projectDir, 'static'), { recursive: true });
1153
+ writeFileSync(indexPath, minimalHtml, 'utf8');
914
1154
  }
915
1155
  if (framework === 'svelte' && selectedComponents.length > 0) {
1156
+ copyRizzoIcons(projectDir, 'svelte');
916
1157
  copySvelteComponents(projectDir, selectedComponents);
917
1158
  } else if (framework === 'astro' && selectedComponents.length > 0) {
1159
+ copyRizzoIcons(projectDir, 'astro');
918
1160
  copyAstroComponents(projectDir, selectedComponents);
919
1161
  }
920
1162
  }
@@ -923,23 +1165,42 @@ async function cmdInit() {
923
1165
  console.log(' - ' + cssTarget);
924
1166
  if (indexPath) console.log(' - ' + indexPath);
925
1167
  if (framework === 'vanilla') {
926
- console.log(' - Vanilla JS: same CSS and component styles; index includes theme switcher and sample components.');
927
- console.log(' - js/main.js (theme, toast, settings, tabs, modal, dropdown, accordion)');
928
- console.log(' - Icons: ' + join(projectDir, 'icons') + ' (SVG files)');
929
- console.log(' - README.md (setup and CDN/local options)');
1168
+ if (useVanillaFull) {
1169
+ console.log(' - Vanilla JS (full): theme switcher, js/main.js, icons, README.');
1170
+ } else {
1171
+ console.log(' - Vanilla JS (minimal): index.html + CSS link. Open index.html in a browser or add your own app.');
1172
+ }
930
1173
  }
1174
+ const pm = getPackageManagerCommands({ agent: selectedPm, command: selectedPm });
1175
+ const nextStep = pm.install + ' && ' + pm.run('dev');
931
1176
  const runPrefix = name ? 'cd ' + name + ' && ' : '';
932
- if (framework === 'astro' && existsSync(astroAppDir)) {
933
- console.log(' - Default Astro project with Rizzo CSS. Run: ' + runPrefix + 'pnpm install && pnpm dev');
1177
+
1178
+ if (runInstallAfterScaffold && !noInstall && (useAstroApp || useSvelteApp)) {
1179
+ console.log('\nRunning: ' + pm.install);
1180
+ const code = runInDir(projectDir, pm.install);
1181
+ if (code !== 0) {
1182
+ console.error('\nInstall failed (exit ' + code + '). Run manually: ' + runPrefix + pm.install);
1183
+ }
1184
+ }
1185
+
1186
+ if (writeConfig) {
1187
+ const pathsForConfig = getFrameworkCssPaths(framework);
1188
+ writeRizzoConfig(projectDir, { targetDir: pathsForConfig.targetDir, framework, packageManager: selectedPm });
1189
+ console.log('\n - Wrote ' + RIZZO_CONFIG_FILE);
1190
+ }
1191
+
1192
+ if (useAstroApp) {
1193
+ console.log(' - Full Astro project with Rizzo CSS. Run: ' + runPrefix + nextStep);
934
1194
  console.log(' - Icons: src/components/rizzo/icons/ (Astro components)');
935
1195
  }
936
- if (framework === 'svelte' && existsSync(svelteAppDir)) {
937
- console.log(' - Default SvelteKit project with Rizzo CSS. Run: ' + runPrefix + 'pnpm install && pnpm dev');
1196
+ if (useSvelteApp) {
1197
+ console.log(' - Full SvelteKit project with Rizzo CSS. Run: ' + runPrefix + nextStep);
938
1198
  console.log(' - Install dependencies first (required before dev). Icons: src/lib/rizzo/icons/ (Svelte components)');
939
1199
  }
940
- if ((framework === 'svelte' || framework === 'astro') && !existsSync(framework === 'astro' ? astroAppDir : svelteAppDir)) {
1200
+ if ((framework === 'astro' || framework === 'svelte') && !useAstroApp && !useSvelteApp) {
941
1201
  const fw = framework === 'svelte' ? 'Svelte' : 'Astro';
942
- console.log('\nTip: To use the official ' + fw + ' scaffold, create a project with their CLI (e.g. npm create ' + framework + '@latest my-app), then run npx rizzo-css add in that folder.');
1202
+ const createExample = getCreateProjectExample(pm, framework);
1203
+ console.log('\n - Minimal template (CSS + index). To get a full app: ' + createExample + ', then cd into the project and run ' + pm.dlx('rizzo-css add') + '.');
943
1204
  }
944
1205
  console.log('\nDocs: https://rizzo-css.vercel.app\n');
945
1206
  }
@@ -967,7 +1228,7 @@ function main() {
967
1228
  }
968
1229
 
969
1230
  if (command === 'init') {
970
- cmdInit().catch((err) => {
1231
+ cmdInit(argv).catch((err) => {
971
1232
  console.error(err);
972
1233
  process.exit(1);
973
1234
  });