rizzo-css 0.0.27 → 0.0.29

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 (34) hide show
  1. package/README.md +9 -4
  2. package/bin/rizzo-css.js +195 -38
  3. package/package.json +1 -1
  4. package/scaffold/astro-minimal/gitignore +24 -0
  5. package/scaffold/svelte-minimal/gitignore +10 -0
  6. package/scaffold/vanilla/README-RIZZO.md +1 -1
  7. package/scaffold/vanilla/components/accordion.html +12 -0
  8. package/scaffold/vanilla/components/alert.html +12 -0
  9. package/scaffold/vanilla/components/avatar.html +12 -0
  10. package/scaffold/vanilla/components/badge.html +12 -0
  11. package/scaffold/vanilla/components/breadcrumb.html +12 -0
  12. package/scaffold/vanilla/components/button.html +12 -0
  13. package/scaffold/vanilla/components/cards.html +12 -0
  14. package/scaffold/vanilla/components/copy-to-clipboard.html +12 -0
  15. package/scaffold/vanilla/components/divider.html +12 -0
  16. package/scaffold/vanilla/components/dropdown.html +12 -0
  17. package/scaffold/vanilla/components/forms.html +12 -0
  18. package/scaffold/vanilla/components/icons.html +12 -0
  19. package/scaffold/vanilla/components/index.html +12 -0
  20. package/scaffold/vanilla/components/modal.html +12 -0
  21. package/scaffold/vanilla/components/navbar.html +12 -0
  22. package/scaffold/vanilla/components/pagination.html +12 -0
  23. package/scaffold/vanilla/components/progress-bar.html +12 -0
  24. package/scaffold/vanilla/components/search.html +12 -0
  25. package/scaffold/vanilla/components/settings.html +12 -0
  26. package/scaffold/vanilla/components/spinner.html +12 -0
  27. package/scaffold/vanilla/components/table.html +12 -0
  28. package/scaffold/vanilla/components/tabs.html +12 -0
  29. package/scaffold/vanilla/components/theme-switcher.html +12 -0
  30. package/scaffold/vanilla/components/toast.html +12 -0
  31. package/scaffold/vanilla/components/tooltip.html +12 -0
  32. package/scaffold/vanilla/gitignore +27 -0
  33. package/scaffold/vanilla/index.html +12 -0
  34. package/scaffold/vanilla/js/main.js +33 -0
package/README.md CHANGED
@@ -12,14 +12,19 @@ pnpm add rizzo-css
12
12
  yarn add rizzo-css
13
13
  ```
14
14
 
15
- **Quick start (no install):** `npx rizzo-css init` — choose **framework** (Vanilla, Astro, or Svelte), then **add to existing** or **create new**. **Existing** (or `npx rizzo-css add`) → drop in CSS + hand-pick components; you must add the `<link>` yourself (CLI prints the exact tag). **New** → choose **Full** (everything) | **Minimal** (recommended) | **Manual** (pick components; list shows which add others, e.g. Settings adds ThemeSwitcher), then package manager. Full and Minimal include all required dependencies so every component works. Run `npx rizzo-css help components` for the dependency list. Non-interactive: `npx rizzo-css init --yes --framework vanilla|astro|svelte`. Optional **rizzo-css.json** and `add --install-package`. All get the **same CSS and component styles**. To use the **official Svelte or Astro create command** plus Rizzo, create the app first, then run `npx rizzo-css add`:
15
+ **Quick start (no install):** `npx rizzo-css init` — choose **framework** (Vanilla, Astro, or Svelte), then **add to existing** or **create new**. **Existing** (or `npx rizzo-css add`) → drop in CSS + hand-pick components; you must add the `<link>` yourself (CLI prints the exact tag). **New** → choose **Full** | **Minimal** (recommended) | **Manual** (pick components; list shows which add others, e.g. Navbar adds Search and Settings, Settings adds ThemeSwitcher), then package manager. Full and Minimal include all required dependencies so every component works. Run `npx rizzo-css help components` for the dependency list. Non-interactive: `npx rizzo-css init --yes --framework vanilla|astro|svelte`. Optional **rizzo-css.json** and `add --install-package`. All get the **same CSS and component styles**. To use the **official Svelte or Astro create command** plus Rizzo, create the app first, then run `npx rizzo-css add`:
16
16
 
17
17
  ```bash
18
18
  npm create svelte@latest my-app && cd my-app && npx rizzo-css add
19
19
  npm create astro@latest my-app && cd my-app && npx rizzo-css add
20
20
  ```
21
21
 
22
- `add` auto-detects Svelte/Astro and copies CSS to the right place (`static/css` or `public/css`). `npx rizzo-css theme` lists themes.
22
+ `add` writes **RIZZO-SNIPPET.txt** (link + theme) by default; use `--no-snippet` to skip. `npx rizzo-css doctor` checks config and CSS path. `npx rizzo-css theme` lists themes.
23
+
24
+ | | **Create new** (`init` → new) | **Add to existing** (`add` or `init` → existing) |
25
+ |---|------------------------------|--------------------------------------------------|
26
+ | Writes | Scaffold, CSS, config, LICENSE-RIZZO, README-RIZZO, .gitignore | CSS, components, config, optional RIZZO-SNIPPET.txt |
27
+ | Link | Already in scaffold | You add it (CLI prints the tag) |
23
28
 
24
29
  ## One package, any framework
25
30
 
@@ -41,7 +46,7 @@ You install **the same package** for every framework: `npm install rizzo-css`. N
41
46
 
42
47
  With `npx rizzo-css add --path <dir>`, the CLI still suggests the correct href for your framework (e.g. Astro/Svelte get a leading `/` path).
43
48
 
44
- Scaffolds in the package: `scaffold/vanilla/` (Full or Manual), `scaffold/astro-minimal/`, `scaffold/svelte-minimal/`, plus `scaffold/astro/` and `scaffold/svelte/` (component templates for hand-pick). Use `npx rizzo-css init` and choose **Create new project** to get a **Full** or **Manual** scaffold; the stylesheet link is in the layout. **Add to existing** (or `add` command) drops in CSS + hand-pick components; **you must add the stylesheet `<link>` yourself** — the CLI prints the exact tag. Every scaffold includes LICENSE-RIZZO and README-RIZZO.md (does not overwrite your project LICENSE/README); Astro/Svelte minimal include package.json and .env.example.
49
+ Scaffolds in the package: `scaffold/vanilla/` (Full or Manual), `scaffold/astro-minimal/`, `scaffold/svelte-minimal/`, plus `scaffold/astro/` and `scaffold/svelte/` (component templates for hand-pick). Use `npx rizzo-css init` and choose **Create new project** to get a **Full** or **Manual** scaffold; the stylesheet link is in the layout. **Add to existing** (or `add` command) drops in CSS + hand-pick components; **you must add the stylesheet `<link>` yourself** — the CLI prints the exact tag. Every scaffold includes LICENSE-RIZZO, README-RIZZO.md, and .gitignore (does not overwrite your project files); Astro/Svelte minimal include package.json and .env.example.
45
50
 
46
51
  ## Use
47
52
 
@@ -56,7 +61,7 @@ import 'rizzo-css';
56
61
  **Without a bundler (plain HTML):** Use a CDN. Both unpkg and jsDelivr resolve the package root to the built CSS (via the `unpkg` / `jsdelivr` fields in this package). For reliability or to pin a version, use the explicit path:
57
62
 
58
63
  ```html
59
- <!-- unpkg (pin version: replace @latest with @0.0.27 or any version) -->
64
+ <!-- unpkg (pin version: replace @latest with @0.0.29 or any version) -->
60
65
  <link rel="stylesheet" href="https://unpkg.com/rizzo-css@latest/dist/rizzo.min.css" />
61
66
 
62
67
  <!-- or jsDelivr -->
package/bin/rizzo-css.js CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- const { copyFileSync, mkdirSync, writeFileSync, existsSync, readFileSync, readdirSync, statSync } = require('fs');
3
+ const { copyFileSync, mkdirSync, writeFileSync, existsSync, readFileSync, readdirSync, statSync, unlinkSync } = require('fs');
4
4
  const { join, dirname } = require('path');
5
5
  const { spawnSync } = require('child_process');
6
6
  const readline = require('readline');
@@ -10,8 +10,10 @@ const RIZZO_CONFIG_FILE = 'rizzo-css.json';
10
10
  const SCAFFOLD_README_FILENAME = 'README-RIZZO.md';
11
11
  /** Scaffold license filename; avoids overwriting an existing project LICENSE. */
12
12
  const SCAFFOLD_LICENSE_FILENAME = 'LICENSE-RIZZO';
13
+ /** Snippet file written by add command for copy-paste of link and theme. */
14
+ const RIZZO_SNIPPET_FILE = 'RIZZO-SNIPPET.txt';
13
15
 
14
- const COMMANDS = ['init', 'add', 'theme', 'help'];
16
+ const COMMANDS = ['init', 'add', 'theme', 'doctor', 'help'];
15
17
  const FRAMEWORKS = ['vanilla', 'astro', 'svelte'];
16
18
  /** Supported package managers: detection, install/add commands, and --package-manager override. */
17
19
  const VALID_PACKAGE_MANAGERS = ['npm', 'pnpm', 'yarn', 'bun'];
@@ -112,11 +114,14 @@ const RECOMMENDED_COMPONENTS = [
112
114
  'Button', 'Badge', 'Card', 'Modal', 'Tabs', 'ThemeSwitcher', 'FormGroup', 'Alert', 'Toast', 'Dropdown',
113
115
  ];
114
116
 
117
+ // Vanilla components that need js/main.js for interactivity (modal, dropdown, tabs, toast, theme switcher).
118
+ const VANILLA_JS_COMPONENTS = ['Modal', 'Dropdown', 'Tabs', 'Toast', 'ThemeSwitcher'];
119
+
115
120
  // Component dependencies per framework: when user selects a component, these are copied automatically so it works.
116
121
  // Manual users can run: npx rizzo-css help components
117
122
  const COMPONENT_DEPS = {
118
- astro: { Settings: ['ThemeSwitcher'], Toast: ['Alert'] },
119
- svelte: { Settings: ['ThemeSwitcher'], Toast: ['Alert'] },
123
+ astro: { Settings: ['ThemeSwitcher'], Toast: ['Alert'], Navbar: ['Search', 'Settings'] },
124
+ svelte: { Settings: ['ThemeSwitcher'], Toast: ['Alert'], Navbar: ['Search', 'Settings'] },
120
125
  };
121
126
 
122
127
  function getComponentDeps(framework, componentName) {
@@ -271,31 +276,38 @@ function copyPackageLicense(projectDir) {
271
276
  }
272
277
  }
273
278
 
274
- /** Copy scaffold vanilla .gitignore into project so new vanilla projects have sensible defaults. */
279
+ /** Name of the scaffold gitignore file (no leading dot so npm pack includes it). Copied to project as .gitignore. */
280
+ const SCAFFOLD_GITIGNORE_FILE = 'gitignore';
281
+
282
+ /** Copy scaffold vanilla gitignore into project as .gitignore so new vanilla projects have sensible defaults. */
275
283
  function copyVanillaGitignore(projectDir) {
276
- const gitignorePath = join(getPackageRoot(), 'scaffold', 'vanilla', '.gitignore');
284
+ const gitignorePath = join(getPackageRoot(), 'scaffold', 'vanilla', SCAFFOLD_GITIGNORE_FILE);
277
285
  if (existsSync(gitignorePath)) {
278
286
  copyFileSync(gitignorePath, join(projectDir, '.gitignore'));
279
287
  }
280
288
  }
281
289
 
282
- /** Copy Astro minimal scaffold .gitignore into project (full and minimal templates). */
290
+ /** Copy Astro minimal scaffold gitignore into project as .gitignore (full and minimal templates). */
283
291
  function copyAstroGitignore(projectDir) {
284
- const gitignorePath = join(getScaffoldAstroMinimalDir(), '.gitignore');
292
+ const gitignorePath = join(getScaffoldAstroMinimalDir(), SCAFFOLD_GITIGNORE_FILE);
285
293
  if (existsSync(gitignorePath)) {
286
294
  copyFileSync(gitignorePath, join(projectDir, '.gitignore'));
295
+ const copiedAsFile = join(projectDir, SCAFFOLD_GITIGNORE_FILE);
296
+ if (existsSync(copiedAsFile)) unlinkSync(copiedAsFile);
287
297
  }
288
298
  }
289
299
 
290
- /** Copy Svelte minimal scaffold .gitignore into project (full and minimal templates). */
300
+ /** Copy Svelte minimal scaffold gitignore into project as .gitignore (full and minimal templates). */
291
301
  function copySvelteGitignore(projectDir) {
292
- const gitignorePath = join(getScaffoldSvelteMinimalDir(), '.gitignore');
302
+ const gitignorePath = join(getScaffoldSvelteMinimalDir(), SCAFFOLD_GITIGNORE_FILE);
293
303
  if (existsSync(gitignorePath)) {
294
304
  copyFileSync(gitignorePath, join(projectDir, '.gitignore'));
305
+ const copiedAsFile = join(projectDir, SCAFFOLD_GITIGNORE_FILE);
306
+ if (existsSync(copiedAsFile)) unlinkSync(copiedAsFile);
295
307
  }
296
308
  }
297
309
 
298
- /** Read rizzo-css.json from cwd. Returns { targetDir?, framework?, packageManager? } or null. */
310
+ /** Read rizzo-css.json from cwd. Returns { targetDir?, framework?, packageManager?, theme? } or null. Preserves unknown keys. */
299
311
  function readRizzoConfig(cwd) {
300
312
  if (!cwd || !existsSync(cwd)) return null;
301
313
  const configPath = join(cwd, RIZZO_CONFIG_FILE);
@@ -306,6 +318,7 @@ function readRizzoConfig(cwd) {
306
318
  if (typeof raw.targetDir === 'string') out.targetDir = raw.targetDir;
307
319
  if (typeof raw.framework === 'string' && FRAMEWORKS.includes(raw.framework)) out.framework = raw.framework;
308
320
  if (typeof raw.packageManager === 'string' && ['npm', 'pnpm', 'yarn', 'bun'].includes(raw.packageManager)) out.packageManager = raw.packageManager;
321
+ if (typeof raw.theme === 'string') out.theme = raw.theme;
309
322
  return Object.keys(out).length ? out : null;
310
323
  } catch (_) { return null; }
311
324
  }
@@ -324,6 +337,7 @@ function writeRizzoConfig(cwd, config) {
324
337
  if (config.targetDir != null) obj.targetDir = config.targetDir;
325
338
  if (config.framework != null) obj.framework = config.framework;
326
339
  if (config.packageManager != null) obj.packageManager = config.packageManager;
340
+ if (config.theme != null) obj.theme = config.theme;
327
341
  writeFileSync(configPath, JSON.stringify(obj, null, 2) + '\n', 'utf8');
328
342
  }
329
343
 
@@ -449,6 +463,24 @@ async function confirmRunInstall(pm) {
449
463
  return answer === '' || /^y(es)?$/i.test(answer);
450
464
  }
451
465
 
466
+ /** Ask user to copy js/main.js for vanilla interactive components. */
467
+ async function confirmCopyVanillaJs() {
468
+ const answer = await question('\nCopy js/main.js for modal, dropdown, tabs, toast, theme switcher? (Y/n) ');
469
+ return answer === '' || /^y(es)?$/i.test(answer);
470
+ }
471
+
472
+ /** True if directory looks like an existing project (has package.json, src/, or index.html). */
473
+ function isDirNonEmpty(dir) {
474
+ if (!dir || !existsSync(dir)) return false;
475
+ return existsSync(join(dir, 'package.json')) || existsSync(join(dir, 'src')) || existsSync(join(dir, 'index.html'));
476
+ }
477
+
478
+ /** Ask user to confirm creating in a non-empty directory. */
479
+ async function confirmNonEmptyDir(projectDir) {
480
+ const answer = await question('\nCurrent directory is not empty. Continue? (y/N) ');
481
+ return /^y(es)?$/i.test(answer);
482
+ }
483
+
452
484
  /** Format label with optional ANSI color (item.color). */
453
485
  function formatLabel(item) {
454
486
  const text = item.label || item.value;
@@ -740,12 +772,13 @@ function printHelp() {
740
772
  console.log(`
741
773
  rizzo-css CLI — Add Rizzo CSS to your project (Vanilla, Astro, Svelte)
742
774
 
743
- Available commands: init, add, theme, help
775
+ Available commands: init, add, theme, doctor, help
744
776
 
745
777
  Flags summary:
746
778
  init --yes --framework <fw> --template <t> --package-manager <pm> --install --no-install
747
- add --path <dir> --framework <fw> --package-manager <pm> --install-package --no-install
779
+ add --path <dir> --framework <fw> ... --no-snippet --readme --force --vanilla-js
748
780
  theme (no flags)
781
+ doctor Check config, CSS file, and optional layout link
749
782
  help (no flags)
750
783
 
751
784
  Usage (use your package manager):
@@ -775,6 +808,10 @@ Options (add):
775
808
  --package-manager <pm> npm | pnpm | yarn | bun (override detection for install/print commands)
776
809
  --install-package After copying CSS, run package manager add rizzo-css
777
810
  --no-install Do not run install or add (overrides --install-package)
811
+ --no-snippet Do not write RIZZO-SNIPPET.txt (link + theme copy-paste)
812
+ --readme Write README-RIZZO.md into the project
813
+ --force Overwrite existing rizzo.min.css without prompting
814
+ --vanilla-js (Vanilla) Copy js/main.js for interactive components (modal, dropdown, tabs, toast, theme switcher)
778
815
 
779
816
  Package managers:
780
817
  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.
@@ -835,12 +872,18 @@ Available to pick (Astro & Svelte; same list):
835
872
  ` + line1 + (line2 ? ',\n ' + line2 : '') + (line3 ? ',\n ' + line3 : '') + `
836
873
 
837
874
  Dependencies (when you pick the component on the left, the right is added automatically):
875
+ Navbar → Search, Settings (navbar includes search bar; Settings so gear button works)
838
876
  Settings → ThemeSwitcher (and themes.ts)
839
877
  Toast → Alert
840
878
 
841
879
  ThemeSwitcher and ThemeIcon: when selected, themes.ts (and Svelte theme.ts) is copied so they work.
842
880
  Icons: copied whenever you add any component.
843
881
 
882
+ Where components are copied:
883
+ Astro → src/components/rizzo/ (import from there)
884
+ Svelte → src/lib/rizzo/ (import from '$lib/rizzo')
885
+ Vanilla → components/ (HTML) (for interactivity add js/main.js; use --vanilla-js on add)
886
+
844
887
  Full = all components above; dependencies are included so everything works.
845
888
  Minimal = recommended set; any component in that set that requires others gets them.
846
889
  Manual = you pick; the picker shows e.g. "Settings (adds ThemeSwitcher)". Required deps are added when you confirm.
@@ -857,6 +900,45 @@ function cmdTheme() {
857
900
  process.stdout.write('\nExample: <html lang="en" data-theme="github-dark-classic">\n\n');
858
901
  }
859
902
 
903
+ /** Check project for Rizzo CSS: config, CSS file, optional link in layout. */
904
+ function cmdDoctor() {
905
+ const cwd = process.cwd();
906
+ const config = readRizzoConfig(cwd);
907
+ console.log('\nRizzo CSS doctor\n');
908
+ let ok = true;
909
+ if (!config) {
910
+ console.log(' ✗ No ' + RIZZO_CONFIG_FILE + '. Run: npx rizzo-css add or init');
911
+ ok = false;
912
+ } else {
913
+ console.log(' ✓ ' + RIZZO_CONFIG_FILE + ' (framework: ' + (config.framework || '?') + ')');
914
+ const fw = config.framework || 'vanilla';
915
+ const paths = getFrameworkCssPaths(fw);
916
+ const targetDir = (config.targetDir || paths.targetDir);
917
+ const cssPath = fw === 'astro' ? join(cwd, 'public', 'css', 'rizzo.min.css') : fw === 'svelte' ? join(cwd, 'static', 'css', 'rizzo.min.css') : join(cwd, targetDir, 'rizzo.min.css');
918
+ if (!existsSync(cssPath)) {
919
+ console.log(' ✗ CSS not found at ' + cssPath);
920
+ ok = false;
921
+ } else {
922
+ console.log(' ✓ CSS at ' + cssPath);
923
+ }
924
+ const layoutPaths = fw === 'svelte' ? ['src/app.html'] : fw === 'astro' ? ['src/layouts/Layout.astro', 'src/layouts/BaseLayout.astro'] : [];
925
+ for (const lp of layoutPaths) {
926
+ const full = join(cwd, lp);
927
+ if (existsSync(full)) {
928
+ const content = readFileSync(full, 'utf8');
929
+ if (!content.includes('rizzo') && !content.includes('rizzo.min.css')) {
930
+ console.log(' ? Layout ' + lp + ' may not include the stylesheet — add <link rel="stylesheet" href="' + (fw === 'svelte' ? '/css/rizzo.min.css' : '/css/rizzo.min.css') + '" />');
931
+ } else {
932
+ console.log(' ✓ Layout ' + lp + ' includes Rizzo link');
933
+ }
934
+ break;
935
+ }
936
+ }
937
+ }
938
+ if (config && config.theme) console.log(' Theme (from config): ' + config.theme);
939
+ console.log(ok ? '\nAll checks passed.\n' : '\nFix the items above, then run your dev server.\n');
940
+ }
941
+
860
942
  /** Prompt for default dark theme, default light theme, and initial theme. Returns { theme, defaultDark, defaultLight }. */
861
943
  async function promptThemes() {
862
944
  const defaultDark = await selectMenu(
@@ -974,6 +1056,10 @@ async function cmdAdd(argv) {
974
1056
  const explicitFramework = explicitFrameworkRaw && FRAMEWORKS.includes(explicitFrameworkRaw.toLowerCase()) ? explicitFrameworkRaw.toLowerCase() : null;
975
1057
  const installPackage = hasFlag(argv, '--install-package');
976
1058
  const noInstall = hasFlag(argv, '--no-install');
1059
+ const writeSnippet = !hasFlag(argv, '--no-snippet');
1060
+ const writeReadme = hasFlag(argv, '--readme');
1061
+ const force = hasFlag(argv, '--force');
1062
+ const copyVanillaJs = hasFlag(argv, '--vanilla-js');
977
1063
  const positionals = getPositionalArgs(argv);
978
1064
 
979
1065
  const cwd = process.cwd();
@@ -984,6 +1070,10 @@ async function cmdAdd(argv) {
984
1070
  targetDir: customPath || (config && config.targetDir) || undefined,
985
1071
  packageManager: pmOverride || undefined,
986
1072
  preselectedComponents: positionals.length > 0 ? positionals : undefined,
1073
+ writeSnippet,
1074
+ writeReadme,
1075
+ force,
1076
+ copyVanillaJs,
987
1077
  };
988
1078
  await runAddToExisting(explicitFramework, options);
989
1079
  if (installPackage && !noInstall) {
@@ -1320,17 +1410,37 @@ async function runAddToExisting(frameworkOverride, options) {
1320
1410
  const targetDirRaw = (options && options.targetDir) || (config && config.targetDir) || paths.targetDir;
1321
1411
  let cssTarget;
1322
1412
  if (framework === 'astro') {
1323
- copyRizzoCssAndFontsForAstro(cwd, cssSource);
1324
1413
  cssTarget = join(cwd, 'public', 'css', 'rizzo.min.css');
1325
1414
  } else if (framework === 'svelte') {
1326
- copyRizzoCssAndFontsForSvelte(cwd, cssSource);
1327
1415
  cssTarget = join(cwd, 'static', 'css', 'rizzo.min.css');
1328
1416
  } else {
1329
1417
  const targetDir = join(cwd, targetDirRaw);
1330
1418
  cssTarget = join(targetDir, 'rizzo.min.css');
1331
- mkdirSync(targetDir, { recursive: true });
1332
- copyFileSync(cssSource, cssTarget);
1333
- copyRizzoFonts(targetDir);
1419
+ }
1420
+ const cssExists = existsSync(cssTarget);
1421
+ if (cssExists && !options.force) {
1422
+ const answer = await question('\nCSS already exists at ' + cssTarget + '. Overwrite? (y/N) ');
1423
+ if (answer !== '' && !/^y(es)?$/i.test(answer)) {
1424
+ console.log('Skipping CSS copy. Updating config and components only.');
1425
+ } else {
1426
+ options._overwriteCss = true;
1427
+ }
1428
+ } else if (cssExists && options.force) {
1429
+ options._overwriteCss = true;
1430
+ } else {
1431
+ options._overwriteCss = true;
1432
+ }
1433
+ if (options._overwriteCss) {
1434
+ if (framework === 'astro') {
1435
+ copyRizzoCssAndFontsForAstro(cwd, cssSource);
1436
+ } else if (framework === 'svelte') {
1437
+ copyRizzoCssAndFontsForSvelte(cwd, cssSource);
1438
+ } else {
1439
+ const targetDir = join(cwd, targetDirRaw);
1440
+ mkdirSync(targetDir, { recursive: true });
1441
+ copyFileSync(cssSource, cssTarget);
1442
+ copyRizzoFonts(dirname(cssTarget));
1443
+ }
1334
1444
  }
1335
1445
 
1336
1446
  copyRizzoIcons(cwd, framework);
@@ -1346,6 +1456,20 @@ async function runAddToExisting(frameworkOverride, options) {
1346
1456
  const linkHrefForVanilla = (options && options.targetDir) ? getLinkHrefForTargetDir(framework, options.targetDir) : paths.linkHref;
1347
1457
  const vanillaRepl = { '{{LINK_HREF}}': linkHrefForVanilla, '{{DATA_THEME}}': theme };
1348
1458
  copyVanillaComponents(cwd, selectedComponents, vanillaRepl);
1459
+ const needsJs = selectedComponents.some((c) => VANILLA_JS_COMPONENTS.includes(c));
1460
+ const vanillaJsPath = join(cwd, 'js', 'main.js');
1461
+ if (needsJs && !existsSync(vanillaJsPath) && (options.copyVanillaJs || (!preselected && (await confirmCopyVanillaJs())))) {
1462
+ const vanillaJsSrc = join(getPackageRoot(), 'scaffold', 'vanilla', 'js', 'main.js');
1463
+ if (existsSync(vanillaJsSrc)) {
1464
+ mkdirSync(join(cwd, 'js'), { recursive: true });
1465
+ let mainJs = readFileSync(vanillaJsSrc, 'utf8');
1466
+ mainJs = mainJs.replace(/\{\{DEFAULT_DARK\}\}/g, defaultDark).replace(/\{\{DEFAULT_LIGHT\}\}/g, defaultLight);
1467
+ writeFileSync(vanillaJsPath, mainJs, 'utf8');
1468
+ console.log(' - Wrote js/main.js (for modal, dropdown, tabs, toast, theme switcher)');
1469
+ }
1470
+ } else if (needsJs && !existsSync(vanillaJsPath)) {
1471
+ options._vanillaJsHint = true;
1472
+ }
1349
1473
  }
1350
1474
 
1351
1475
  const linkHref = (framework === 'astro' || framework === 'svelte') ? paths.linkHref : ((options && options.targetDir) ? getLinkHrefForTargetDir(framework, options.targetDir) : paths.linkHref);
@@ -1357,38 +1481,56 @@ async function runAddToExisting(frameworkOverride, options) {
1357
1481
  : resolvePackageManager(cwd);
1358
1482
  const cliExample = pm.dlx('rizzo-css theme');
1359
1483
  const configTargetDir = framework === 'astro' ? 'public/css' : framework === 'svelte' ? 'static/css' : targetDirRaw;
1360
- writeRizzoConfig(cwd, { targetDir: configTargetDir, framework, packageManager: pm.agent });
1484
+ writeRizzoConfig(cwd, { targetDir: configTargetDir, framework, packageManager: pm.agent, theme });
1485
+ const writeSnippet = options.writeSnippet !== false;
1486
+ if (writeSnippet) {
1487
+ const where = framework === 'svelte' ? 'Root layout (e.g. src/app.html)' : framework === 'astro' ? 'Layout (e.g. src/layouts/Layout.astro)' : 'HTML or layout';
1488
+ const snippetBody = [
1489
+ 'Add to ' + where + ':',
1490
+ '',
1491
+ ' <link rel="stylesheet" href="' + linkHref + '" />',
1492
+ '',
1493
+ 'On <html>: data-theme="' + theme + '"',
1494
+ 'Themes: ' + cliExample,
1495
+ ].join('\n');
1496
+ writeFileSync(join(cwd, RIZZO_SNIPPET_FILE), snippetBody + '\n', 'utf8');
1497
+ }
1498
+ if (options.writeReadme) {
1499
+ const readmePath = join(getPackageRoot(), 'scaffold', 'vanilla', SCAFFOLD_README_FILENAME);
1500
+ if (existsSync(readmePath)) {
1501
+ copyFileSync(readmePath, join(cwd, SCAFFOLD_README_FILENAME));
1502
+ }
1503
+ }
1361
1504
  console.log('\n✓ Rizzo CSS added to your existing project');
1362
1505
  console.log(' - ' + cssTarget);
1363
1506
  console.log(' - Wrote ' + RIZZO_CONFIG_FILE);
1507
+ if (writeSnippet) console.log(' - Wrote ' + RIZZO_SNIPPET_FILE + ' (copy-paste link + theme)');
1508
+ if (options.writeReadme) console.log(' - Wrote ' + SCAFFOLD_README_FILENAME);
1364
1509
  console.log('\nYou must add the stylesheet link yourself — it is not added automatically.');
1365
- if (framework === 'svelte') {
1510
+ if (selectedComponents.length === 0) {
1511
+ console.log('\n <link rel="stylesheet" href="' + linkHref + '" />');
1512
+ console.log(' data-theme="' + theme + '" on <html> — list themes: ' + cliExample);
1513
+ } else if (framework === 'svelte') {
1366
1514
  console.log('\nIn your root layout (e.g. src/app.html), add:');
1367
1515
  console.log(' <link rel="stylesheet" href="' + linkHref + '" />');
1368
- console.log('\nSet a theme on <html>: data-theme="' + theme + '" (see: ' + cliExample + ')');
1369
- console.log(' For theme "system": default dark ' + defaultDark + ', default light ' + defaultLight);
1370
- if (selectedComponents.length > 0) {
1371
- console.log(' Components are in src/lib/rizzo — import from \'$lib/rizzo\'.');
1372
- }
1516
+ console.log(' data-theme="' + theme + '" on <html> (themes: ' + cliExample + ')');
1517
+ console.log(' Components: src/lib/rizzo import from \'$lib/rizzo\'.');
1373
1518
  } else if (framework === 'astro') {
1374
1519
  console.log('\nIn your layout (e.g. src/layouts/Layout.astro), add:');
1375
1520
  console.log(' <link rel="stylesheet" href="' + linkHref + '" />');
1376
- console.log('\nSet a theme on <html>: data-theme="' + theme + '" (see: ' + cliExample + ')');
1377
- console.log(' For theme "system": default dark ' + defaultDark + ', default light ' + defaultLight);
1378
- if (selectedComponents.length > 0) {
1379
- console.log(' Components are in src/components/rizzo — import from there.');
1380
- }
1521
+ console.log(' data-theme="' + theme + '" on <html> (themes: ' + cliExample + ')');
1522
+ console.log(' Components: src/components/rizzo import from there.');
1381
1523
  } else {
1382
1524
  console.log('\nIn your HTML or layout, add:');
1383
1525
  console.log(' <link rel="stylesheet" href="' + linkHref + '" />');
1384
- console.log('\nSet a theme on <html>: data-theme="' + theme + '" (see: ' + cliExample + ')');
1385
- console.log(' For theme "system": default dark ' + defaultDark + ', default light ' + defaultLight);
1386
- if (selectedComponents.length > 0) {
1387
- console.log(' Component HTML files are in components/.');
1526
+ console.log(' data-theme="' + theme + '" on <html> (themes: ' + cliExample + ')');
1527
+ console.log(' Component HTML files are in components/.');
1528
+ if (options._vanillaJsHint) {
1529
+ console.log(' For interactive components (modal, dropdown, tabs, toast, theme switcher), add js/main.js — run again with --vanilla-js or copy from a Full scaffold.');
1388
1530
  }
1389
1531
  }
1390
- console.log('\nTo install the package (CLI + components): ' + pm.add('rizzo-css'));
1391
- console.log('\nDocs: https://rizzo-css.vercel.app\n');
1532
+ console.log('\nTo install the package: ' + pm.add('rizzo-css'));
1533
+ console.log('\nNext: add the link above, then run your dev server. Docs: https://rizzo-css.vercel.app\n');
1392
1534
  }
1393
1535
 
1394
1536
  async function cmdInit(argv) {
@@ -1412,7 +1554,8 @@ async function cmdInit(argv) {
1412
1554
  framework = (frameworkArg && FRAMEWORKS.includes(frameworkArg.toLowerCase())) ? frameworkArg.toLowerCase() : (config && config.framework) || 'astro';
1413
1555
  initMode = 'new';
1414
1556
  const templateArg = getFlagValue(argv, '--template');
1415
- selectedTemplate = (templateArg && (templateArg === 'full' || templateArg === 'minimal' || templateArg === 'manual')) ? templateArg : 'full';
1557
+ const defaultTemplate = framework === 'vanilla' ? 'minimal' : 'full';
1558
+ selectedTemplate = (templateArg && (templateArg === 'full' || templateArg === 'minimal' || templateArg === 'manual')) ? templateArg : defaultTemplate;
1416
1559
  if (selectedTemplate === 'full' && (framework === 'astro' || framework === 'svelte')) {
1417
1560
  selectedComponents = framework === 'svelte' ? [...SVELTE_COMPONENTS] : [...ASTRO_COMPONENTS];
1418
1561
  } else if (selectedTemplate === 'minimal' && (framework === 'astro' || framework === 'svelte')) {
@@ -1489,6 +1632,13 @@ async function cmdInit(argv) {
1489
1632
  }
1490
1633
 
1491
1634
  const projectDir = name ? join(cwd, name) : cwd;
1635
+ if (projectDir === cwd && isDirNonEmpty(cwd) && !yes) {
1636
+ const ok = await confirmNonEmptyDir(projectDir);
1637
+ if (!ok) {
1638
+ console.log('Aborted.');
1639
+ return;
1640
+ }
1641
+ }
1492
1642
  const cssSource = getCssPath();
1493
1643
 
1494
1644
  if (!existsSync(cssSource)) {
@@ -1742,7 +1892,7 @@ async function cmdInit(argv) {
1742
1892
 
1743
1893
  // Always write rizzo-css.json for new projects (targetDir, framework, packageManager).
1744
1894
  const pathsForConfig = getFrameworkCssPaths(framework);
1745
- writeRizzoConfig(projectDir, { targetDir: pathsForConfig.targetDir, framework, packageManager: selectedPm });
1895
+ writeRizzoConfig(projectDir, { targetDir: pathsForConfig.targetDir, framework, packageManager: selectedPm, theme });
1746
1896
  console.log(' - Wrote ' + RIZZO_CONFIG_FILE);
1747
1897
 
1748
1898
  if (runInstallAfterScaffold && !noInstall && hasPackageJson) {
@@ -1779,6 +1929,8 @@ async function cmdInit(argv) {
1779
1929
  const createExample = getCreateProjectExample(pm, framework);
1780
1930
  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') + '.');
1781
1931
  }
1932
+ if (hasPackageJson) console.log('\nNext: ' + runPrefix + nextStep);
1933
+ else if (framework === 'vanilla') console.log('\nNext: open index.html or serve the folder.');
1782
1934
  console.log('\nDocs: https://rizzo-css.vercel.app\n');
1783
1935
  }
1784
1936
 
@@ -1803,6 +1955,11 @@ function main() {
1803
1955
  return;
1804
1956
  }
1805
1957
 
1958
+ if (command === 'doctor') {
1959
+ cmdDoctor();
1960
+ return;
1961
+ }
1962
+
1806
1963
  if (command === 'add') {
1807
1964
  cmdAdd(argv).catch((err) => {
1808
1965
  console.error(err);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rizzo-css",
3
- "version": "0.0.27",
3
+ "version": "0.0.29",
4
4
  "scripts": {
5
5
  "prepublishOnly": "cd ../.. && pnpm run lint:css:fix && pnpm run build:css && node scripts/copy-scaffold.js && node scripts/prepare-vanilla-scaffold.js"
6
6
  },
@@ -0,0 +1,24 @@
1
+ # Astro default .gitignore (same as npm create astro@latest)
2
+ # build output
3
+ dist/
4
+ # generated types
5
+ .astro/
6
+
7
+ # dependencies
8
+ node_modules/
9
+
10
+ # logs
11
+ npm-debug.log*
12
+ yarn-debug.log*
13
+ yarn-error.log*
14
+ pnpm-debug.log*
15
+
16
+ # environment variables
17
+ .env
18
+ .env.production
19
+
20
+ # macOS-specific files
21
+ .DS_Store
22
+
23
+ # jetbrains setting folder
24
+ .idea/
@@ -0,0 +1,10 @@
1
+ node_modules
2
+ .output
3
+ .vercel
4
+ .netlify
5
+ /.svelte-kit
6
+ /build
7
+ .DS_Store
8
+ .env
9
+ .env.*
10
+ !.env.example
@@ -13,7 +13,7 @@ If you prefer to load CSS from a CDN instead of the local file, replace the `<li
13
13
  - `<link rel="stylesheet" href="https://unpkg.com/rizzo-css@latest/dist/rizzo.min.css" />`
14
14
  - Or jsDelivr: `https://cdn.jsdelivr.net/npm/rizzo-css@latest/dist/rizzo.min.css`
15
15
 
16
- (Replace `@latest` with a specific version, e.g. `@0.0.27`, in production.)
16
+ (Replace `@latest` with a specific version, e.g. `@0.0.29`, in production.)
17
17
 
18
18
  The CLI replaces placeholders in `index.html` (e.g. `{{DATA_THEME}}`, `{{TITLE}}`) when you run `rizzo-css init`. The theme selected during init is used on first load when you have no saved preference in the browser.
19
19
 
@@ -0,0 +1,27 @@
1
+ # Vanilla / static site default .gitignore (Rizzo CSS scaffold)
2
+
3
+ # OS files
4
+ .DS_Store
5
+ Thumbs.db
6
+
7
+ # Editor / IDE
8
+ .idea/
9
+ .vscode/
10
+ *.swp
11
+ *.swo
12
+ *~
13
+
14
+ # Environment
15
+ .env
16
+ .env.*
17
+ !.env.example
18
+
19
+ # Logs
20
+ *.log
21
+ npm-debug.log*
22
+ yarn-debug.log*
23
+ yarn-error.log*
24
+ pnpm-debug.log*
25
+
26
+ # Optional: if you add Node/npm later
27
+ node_modules/
@@ -731,6 +731,38 @@
731
731
  document.querySelectorAll('[data-accordion]').forEach(initOne);
732
732
  }
733
733
 
734
+ function initNavbarMobile() {
735
+ document.querySelectorAll('.navbar').forEach(function (navbar) {
736
+ var toggle = navbar.querySelector('.navbar__toggle');
737
+ var menu = navbar.querySelector('.navbar__menu');
738
+ if (!toggle || !menu) return;
739
+ function setMenuOpen(open) {
740
+ menu.classList.toggle('navbar__menu--open', open);
741
+ navbar.classList.toggle('navbar--menu-open', open);
742
+ toggle.setAttribute('aria-expanded', open ? 'true' : 'false');
743
+ menu.setAttribute('aria-hidden', open ? 'false' : 'true');
744
+ }
745
+ toggle.addEventListener('click', function () {
746
+ setMenuOpen(!menu.classList.contains('navbar__menu--open'));
747
+ });
748
+ menu.querySelectorAll('.navbar__link').forEach(function (link) {
749
+ link.addEventListener('click', function () { setMenuOpen(false); });
750
+ });
751
+ });
752
+ document.addEventListener('keydown', function (e) {
753
+ if (e.key === 'Escape') {
754
+ document.querySelectorAll('.navbar__menu.navbar__menu--open').forEach(function (menu) {
755
+ var navbar = menu.closest('.navbar');
756
+ var toggle = navbar && navbar.querySelector('.navbar__toggle');
757
+ menu.classList.remove('navbar__menu--open');
758
+ navbar.classList.remove('navbar--menu-open');
759
+ if (toggle) toggle.setAttribute('aria-expanded', 'false');
760
+ menu.setAttribute('aria-hidden', 'true');
761
+ });
762
+ }
763
+ });
764
+ }
765
+
734
766
  function run() {
735
767
  initTheme();
736
768
  initSettings();
@@ -738,6 +770,7 @@
738
770
  initModals();
739
771
  initDropdowns();
740
772
  initAccordions();
773
+ initNavbarMobile();
741
774
  }
742
775
 
743
776
  if (document.readyState === 'loading') {