rizzo-css 0.0.26 → 0.0.28

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 (33) hide show
  1. package/README.md +7 -2
  2. package/bin/rizzo-css.js +232 -30
  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 +10 -0
  8. package/scaffold/vanilla/components/alert.html +10 -0
  9. package/scaffold/vanilla/components/avatar.html +10 -0
  10. package/scaffold/vanilla/components/badge.html +10 -0
  11. package/scaffold/vanilla/components/breadcrumb.html +10 -0
  12. package/scaffold/vanilla/components/button.html +10 -0
  13. package/scaffold/vanilla/components/cards.html +10 -0
  14. package/scaffold/vanilla/components/copy-to-clipboard.html +10 -0
  15. package/scaffold/vanilla/components/divider.html +10 -0
  16. package/scaffold/vanilla/components/dropdown.html +10 -0
  17. package/scaffold/vanilla/components/forms.html +10 -0
  18. package/scaffold/vanilla/components/icons.html +10 -0
  19. package/scaffold/vanilla/components/index.html +10 -0
  20. package/scaffold/vanilla/components/modal.html +10 -0
  21. package/scaffold/vanilla/components/navbar.html +10 -0
  22. package/scaffold/vanilla/components/pagination.html +10 -0
  23. package/scaffold/vanilla/components/progress-bar.html +10 -0
  24. package/scaffold/vanilla/components/search.html +10 -0
  25. package/scaffold/vanilla/components/settings.html +10 -0
  26. package/scaffold/vanilla/components/spinner.html +10 -0
  27. package/scaffold/vanilla/components/table.html +10 -0
  28. package/scaffold/vanilla/components/tabs.html +10 -0
  29. package/scaffold/vanilla/components/theme-switcher.html +10 -0
  30. package/scaffold/vanilla/components/toast.html +10 -0
  31. package/scaffold/vanilla/components/tooltip.html +10 -0
  32. package/scaffold/vanilla/gitignore +27 -0
  33. package/scaffold/vanilla/index.html +10 -0
package/README.md CHANGED
@@ -19,7 +19,12 @@ 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
 
@@ -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.26 or any version) -->
64
+ <!-- unpkg (pin version: replace @latest with @0.0.28 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,6 +114,9 @@ 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 = {
@@ -271,7 +276,38 @@ function copyPackageLicense(projectDir) {
271
276
  }
272
277
  }
273
278
 
274
- /** Read rizzo-css.json from cwd. Returns { targetDir?, framework?, packageManager? } or null. */
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. */
283
+ function copyVanillaGitignore(projectDir) {
284
+ const gitignorePath = join(getPackageRoot(), 'scaffold', 'vanilla', SCAFFOLD_GITIGNORE_FILE);
285
+ if (existsSync(gitignorePath)) {
286
+ copyFileSync(gitignorePath, join(projectDir, '.gitignore'));
287
+ }
288
+ }
289
+
290
+ /** Copy Astro minimal scaffold gitignore into project as .gitignore (full and minimal templates). */
291
+ function copyAstroGitignore(projectDir) {
292
+ const gitignorePath = join(getScaffoldAstroMinimalDir(), SCAFFOLD_GITIGNORE_FILE);
293
+ if (existsSync(gitignorePath)) {
294
+ copyFileSync(gitignorePath, join(projectDir, '.gitignore'));
295
+ const copiedAsFile = join(projectDir, SCAFFOLD_GITIGNORE_FILE);
296
+ if (existsSync(copiedAsFile)) unlinkSync(copiedAsFile);
297
+ }
298
+ }
299
+
300
+ /** Copy Svelte minimal scaffold gitignore into project as .gitignore (full and minimal templates). */
301
+ function copySvelteGitignore(projectDir) {
302
+ const gitignorePath = join(getScaffoldSvelteMinimalDir(), SCAFFOLD_GITIGNORE_FILE);
303
+ if (existsSync(gitignorePath)) {
304
+ copyFileSync(gitignorePath, join(projectDir, '.gitignore'));
305
+ const copiedAsFile = join(projectDir, SCAFFOLD_GITIGNORE_FILE);
306
+ if (existsSync(copiedAsFile)) unlinkSync(copiedAsFile);
307
+ }
308
+ }
309
+
310
+ /** Read rizzo-css.json from cwd. Returns { targetDir?, framework?, packageManager?, theme? } or null. Preserves unknown keys. */
275
311
  function readRizzoConfig(cwd) {
276
312
  if (!cwd || !existsSync(cwd)) return null;
277
313
  const configPath = join(cwd, RIZZO_CONFIG_FILE);
@@ -282,6 +318,7 @@ function readRizzoConfig(cwd) {
282
318
  if (typeof raw.targetDir === 'string') out.targetDir = raw.targetDir;
283
319
  if (typeof raw.framework === 'string' && FRAMEWORKS.includes(raw.framework)) out.framework = raw.framework;
284
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;
285
322
  return Object.keys(out).length ? out : null;
286
323
  } catch (_) { return null; }
287
324
  }
@@ -300,6 +337,7 @@ function writeRizzoConfig(cwd, config) {
300
337
  if (config.targetDir != null) obj.targetDir = config.targetDir;
301
338
  if (config.framework != null) obj.framework = config.framework;
302
339
  if (config.packageManager != null) obj.packageManager = config.packageManager;
340
+ if (config.theme != null) obj.theme = config.theme;
303
341
  writeFileSync(configPath, JSON.stringify(obj, null, 2) + '\n', 'utf8');
304
342
  }
305
343
 
@@ -425,6 +463,24 @@ async function confirmRunInstall(pm) {
425
463
  return answer === '' || /^y(es)?$/i.test(answer);
426
464
  }
427
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
+
428
484
  /** Format label with optional ANSI color (item.color). */
429
485
  function formatLabel(item) {
430
486
  const text = item.label || item.value;
@@ -716,12 +772,13 @@ function printHelp() {
716
772
  console.log(`
717
773
  rizzo-css CLI — Add Rizzo CSS to your project (Vanilla, Astro, Svelte)
718
774
 
719
- Available commands: init, add, theme, help
775
+ Available commands: init, add, theme, doctor, help
720
776
 
721
777
  Flags summary:
722
778
  init --yes --framework <fw> --template <t> --package-manager <pm> --install --no-install
723
- add --path <dir> --framework <fw> --package-manager <pm> --install-package --no-install
779
+ add --path <dir> --framework <fw> ... --no-snippet --readme --force --vanilla-js
724
780
  theme (no flags)
781
+ doctor Check config, CSS file, and optional layout link
725
782
  help (no flags)
726
783
 
727
784
  Usage (use your package manager):
@@ -751,6 +808,10 @@ Options (add):
751
808
  --package-manager <pm> npm | pnpm | yarn | bun (override detection for install/print commands)
752
809
  --install-package After copying CSS, run package manager add rizzo-css
753
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)
754
815
 
755
816
  Package managers:
756
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.
@@ -817,6 +878,11 @@ Dependencies (when you pick the component on the left, the right is added automa
817
878
  ThemeSwitcher and ThemeIcon: when selected, themes.ts (and Svelte theme.ts) is copied so they work.
818
879
  Icons: copied whenever you add any component.
819
880
 
881
+ Where components are copied:
882
+ Astro → src/components/rizzo/ (import from there)
883
+ Svelte → src/lib/rizzo/ (import from '$lib/rizzo')
884
+ Vanilla → components/ (HTML) (for interactivity add js/main.js; use --vanilla-js on add)
885
+
820
886
  Full = all components above; dependencies are included so everything works.
821
887
  Minimal = recommended set; any component in that set that requires others gets them.
822
888
  Manual = you pick; the picker shows e.g. "Settings (adds ThemeSwitcher)". Required deps are added when you confirm.
@@ -833,6 +899,45 @@ function cmdTheme() {
833
899
  process.stdout.write('\nExample: <html lang="en" data-theme="github-dark-classic">\n\n');
834
900
  }
835
901
 
902
+ /** Check project for Rizzo CSS: config, CSS file, optional link in layout. */
903
+ function cmdDoctor() {
904
+ const cwd = process.cwd();
905
+ const config = readRizzoConfig(cwd);
906
+ console.log('\nRizzo CSS doctor\n');
907
+ let ok = true;
908
+ if (!config) {
909
+ console.log(' ✗ No ' + RIZZO_CONFIG_FILE + '. Run: npx rizzo-css add or init');
910
+ ok = false;
911
+ } else {
912
+ console.log(' ✓ ' + RIZZO_CONFIG_FILE + ' (framework: ' + (config.framework || '?') + ')');
913
+ const fw = config.framework || 'vanilla';
914
+ const paths = getFrameworkCssPaths(fw);
915
+ const targetDir = (config.targetDir || paths.targetDir);
916
+ 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');
917
+ if (!existsSync(cssPath)) {
918
+ console.log(' ✗ CSS not found at ' + cssPath);
919
+ ok = false;
920
+ } else {
921
+ console.log(' ✓ CSS at ' + cssPath);
922
+ }
923
+ const layoutPaths = fw === 'svelte' ? ['src/app.html'] : fw === 'astro' ? ['src/layouts/Layout.astro', 'src/layouts/BaseLayout.astro'] : [];
924
+ for (const lp of layoutPaths) {
925
+ const full = join(cwd, lp);
926
+ if (existsSync(full)) {
927
+ const content = readFileSync(full, 'utf8');
928
+ if (!content.includes('rizzo') && !content.includes('rizzo.min.css')) {
929
+ console.log(' ? Layout ' + lp + ' may not include the stylesheet — add <link rel="stylesheet" href="' + (fw === 'svelte' ? '/css/rizzo.min.css' : '/css/rizzo.min.css') + '" />');
930
+ } else {
931
+ console.log(' ✓ Layout ' + lp + ' includes Rizzo link');
932
+ }
933
+ break;
934
+ }
935
+ }
936
+ }
937
+ if (config && config.theme) console.log(' Theme (from config): ' + config.theme);
938
+ console.log(ok ? '\nAll checks passed.\n' : '\nFix the items above, then run your dev server.\n');
939
+ }
940
+
836
941
  /** Prompt for default dark theme, default light theme, and initial theme. Returns { theme, defaultDark, defaultLight }. */
837
942
  async function promptThemes() {
838
943
  const defaultDark = await selectMenu(
@@ -950,6 +1055,10 @@ async function cmdAdd(argv) {
950
1055
  const explicitFramework = explicitFrameworkRaw && FRAMEWORKS.includes(explicitFrameworkRaw.toLowerCase()) ? explicitFrameworkRaw.toLowerCase() : null;
951
1056
  const installPackage = hasFlag(argv, '--install-package');
952
1057
  const noInstall = hasFlag(argv, '--no-install');
1058
+ const writeSnippet = !hasFlag(argv, '--no-snippet');
1059
+ const writeReadme = hasFlag(argv, '--readme');
1060
+ const force = hasFlag(argv, '--force');
1061
+ const copyVanillaJs = hasFlag(argv, '--vanilla-js');
953
1062
  const positionals = getPositionalArgs(argv);
954
1063
 
955
1064
  const cwd = process.cwd();
@@ -960,6 +1069,10 @@ async function cmdAdd(argv) {
960
1069
  targetDir: customPath || (config && config.targetDir) || undefined,
961
1070
  packageManager: pmOverride || undefined,
962
1071
  preselectedComponents: positionals.length > 0 ? positionals : undefined,
1072
+ writeSnippet,
1073
+ writeReadme,
1074
+ force,
1075
+ copyVanillaJs,
963
1076
  };
964
1077
  await runAddToExisting(explicitFramework, options);
965
1078
  if (installPackage && !noInstall) {
@@ -985,6 +1098,10 @@ function getScaffoldAstroDir() {
985
1098
  return join(getPackageRoot(), 'scaffold', 'astro');
986
1099
  }
987
1100
 
1101
+ function getScaffoldUtilsDir() {
1102
+ return join(getPackageRoot(), 'scaffold', 'utils');
1103
+ }
1104
+
988
1105
  function getScaffoldVanillaIndex() {
989
1106
  return join(getPackageRoot(), 'scaffold', 'vanilla', 'index.html');
990
1107
  }
@@ -1196,6 +1313,17 @@ function copyAstroComponents(projectDir, selectedNames) {
1196
1313
  if (existsSync(themesSrc)) {
1197
1314
  copyFileSync(themesSrc, join(targetDir, 'themes.ts'));
1198
1315
  }
1316
+ // ThemeSwitcher.astro imports '../utils/theme' -> need src/components/utils/theme.ts in project
1317
+ const utilsDir = getScaffoldUtilsDir();
1318
+ const themeSrc = join(utilsDir, 'theme.ts');
1319
+ if (existsSync(themeSrc)) {
1320
+ const componentsDir = join(projectDir, 'src', 'components');
1321
+ const projectUtilsDir = join(componentsDir, 'utils');
1322
+ mkdirSync(projectUtilsDir, { recursive: true });
1323
+ let themeContent = readFileSync(themeSrc, 'utf8');
1324
+ themeContent = themeContent.replace(/from ['"]\.\.\/astro\/themes['"]/g, "from '../rizzo/themes'");
1325
+ writeFileSync(join(projectUtilsDir, 'theme.ts'), themeContent);
1326
+ }
1199
1327
  }
1200
1328
  if (count > 0 || copyIconsOnly) {
1201
1329
  const msg = copyIconsOnly ? 'Icons' : count + ' Astro components + icons';
@@ -1281,17 +1409,37 @@ async function runAddToExisting(frameworkOverride, options) {
1281
1409
  const targetDirRaw = (options && options.targetDir) || (config && config.targetDir) || paths.targetDir;
1282
1410
  let cssTarget;
1283
1411
  if (framework === 'astro') {
1284
- copyRizzoCssAndFontsForAstro(cwd, cssSource);
1285
1412
  cssTarget = join(cwd, 'public', 'css', 'rizzo.min.css');
1286
1413
  } else if (framework === 'svelte') {
1287
- copyRizzoCssAndFontsForSvelte(cwd, cssSource);
1288
1414
  cssTarget = join(cwd, 'static', 'css', 'rizzo.min.css');
1289
1415
  } else {
1290
1416
  const targetDir = join(cwd, targetDirRaw);
1291
1417
  cssTarget = join(targetDir, 'rizzo.min.css');
1292
- mkdirSync(targetDir, { recursive: true });
1293
- copyFileSync(cssSource, cssTarget);
1294
- copyRizzoFonts(targetDir);
1418
+ }
1419
+ const cssExists = existsSync(cssTarget);
1420
+ if (cssExists && !options.force) {
1421
+ const answer = await question('\nCSS already exists at ' + cssTarget + '. Overwrite? (y/N) ');
1422
+ if (answer !== '' && !/^y(es)?$/i.test(answer)) {
1423
+ console.log('Skipping CSS copy. Updating config and components only.');
1424
+ } else {
1425
+ options._overwriteCss = true;
1426
+ }
1427
+ } else if (cssExists && options.force) {
1428
+ options._overwriteCss = true;
1429
+ } else {
1430
+ options._overwriteCss = true;
1431
+ }
1432
+ if (options._overwriteCss) {
1433
+ if (framework === 'astro') {
1434
+ copyRizzoCssAndFontsForAstro(cwd, cssSource);
1435
+ } else if (framework === 'svelte') {
1436
+ copyRizzoCssAndFontsForSvelte(cwd, cssSource);
1437
+ } else {
1438
+ const targetDir = join(cwd, targetDirRaw);
1439
+ mkdirSync(targetDir, { recursive: true });
1440
+ copyFileSync(cssSource, cssTarget);
1441
+ copyRizzoFonts(dirname(cssTarget));
1442
+ }
1295
1443
  }
1296
1444
 
1297
1445
  copyRizzoIcons(cwd, framework);
@@ -1307,6 +1455,20 @@ async function runAddToExisting(frameworkOverride, options) {
1307
1455
  const linkHrefForVanilla = (options && options.targetDir) ? getLinkHrefForTargetDir(framework, options.targetDir) : paths.linkHref;
1308
1456
  const vanillaRepl = { '{{LINK_HREF}}': linkHrefForVanilla, '{{DATA_THEME}}': theme };
1309
1457
  copyVanillaComponents(cwd, selectedComponents, vanillaRepl);
1458
+ const needsJs = selectedComponents.some((c) => VANILLA_JS_COMPONENTS.includes(c));
1459
+ const vanillaJsPath = join(cwd, 'js', 'main.js');
1460
+ if (needsJs && !existsSync(vanillaJsPath) && (options.copyVanillaJs || (!preselected && (await confirmCopyVanillaJs())))) {
1461
+ const vanillaJsSrc = join(getPackageRoot(), 'scaffold', 'vanilla', 'js', 'main.js');
1462
+ if (existsSync(vanillaJsSrc)) {
1463
+ mkdirSync(join(cwd, 'js'), { recursive: true });
1464
+ let mainJs = readFileSync(vanillaJsSrc, 'utf8');
1465
+ mainJs = mainJs.replace(/\{\{DEFAULT_DARK\}\}/g, defaultDark).replace(/\{\{DEFAULT_LIGHT\}\}/g, defaultLight);
1466
+ writeFileSync(vanillaJsPath, mainJs, 'utf8');
1467
+ console.log(' - Wrote js/main.js (for modal, dropdown, tabs, toast, theme switcher)');
1468
+ }
1469
+ } else if (needsJs && !existsSync(vanillaJsPath)) {
1470
+ options._vanillaJsHint = true;
1471
+ }
1310
1472
  }
1311
1473
 
1312
1474
  const linkHref = (framework === 'astro' || framework === 'svelte') ? paths.linkHref : ((options && options.targetDir) ? getLinkHrefForTargetDir(framework, options.targetDir) : paths.linkHref);
@@ -1318,38 +1480,56 @@ async function runAddToExisting(frameworkOverride, options) {
1318
1480
  : resolvePackageManager(cwd);
1319
1481
  const cliExample = pm.dlx('rizzo-css theme');
1320
1482
  const configTargetDir = framework === 'astro' ? 'public/css' : framework === 'svelte' ? 'static/css' : targetDirRaw;
1321
- writeRizzoConfig(cwd, { targetDir: configTargetDir, framework, packageManager: pm.agent });
1483
+ writeRizzoConfig(cwd, { targetDir: configTargetDir, framework, packageManager: pm.agent, theme });
1484
+ const writeSnippet = options.writeSnippet !== false;
1485
+ if (writeSnippet) {
1486
+ const where = framework === 'svelte' ? 'Root layout (e.g. src/app.html)' : framework === 'astro' ? 'Layout (e.g. src/layouts/Layout.astro)' : 'HTML or layout';
1487
+ const snippetBody = [
1488
+ 'Add to ' + where + ':',
1489
+ '',
1490
+ ' <link rel="stylesheet" href="' + linkHref + '" />',
1491
+ '',
1492
+ 'On <html>: data-theme="' + theme + '"',
1493
+ 'Themes: ' + cliExample,
1494
+ ].join('\n');
1495
+ writeFileSync(join(cwd, RIZZO_SNIPPET_FILE), snippetBody + '\n', 'utf8');
1496
+ }
1497
+ if (options.writeReadme) {
1498
+ const readmePath = join(getPackageRoot(), 'scaffold', 'vanilla', SCAFFOLD_README_FILENAME);
1499
+ if (existsSync(readmePath)) {
1500
+ copyFileSync(readmePath, join(cwd, SCAFFOLD_README_FILENAME));
1501
+ }
1502
+ }
1322
1503
  console.log('\n✓ Rizzo CSS added to your existing project');
1323
1504
  console.log(' - ' + cssTarget);
1324
1505
  console.log(' - Wrote ' + RIZZO_CONFIG_FILE);
1506
+ if (writeSnippet) console.log(' - Wrote ' + RIZZO_SNIPPET_FILE + ' (copy-paste link + theme)');
1507
+ if (options.writeReadme) console.log(' - Wrote ' + SCAFFOLD_README_FILENAME);
1325
1508
  console.log('\nYou must add the stylesheet link yourself — it is not added automatically.');
1326
- if (framework === 'svelte') {
1509
+ if (selectedComponents.length === 0) {
1510
+ console.log('\n <link rel="stylesheet" href="' + linkHref + '" />');
1511
+ console.log(' data-theme="' + theme + '" on <html> — list themes: ' + cliExample);
1512
+ } else if (framework === 'svelte') {
1327
1513
  console.log('\nIn your root layout (e.g. src/app.html), add:');
1328
1514
  console.log(' <link rel="stylesheet" href="' + linkHref + '" />');
1329
- console.log('\nSet a theme on <html>: data-theme="' + theme + '" (see: ' + cliExample + ')');
1330
- console.log(' For theme "system": default dark ' + defaultDark + ', default light ' + defaultLight);
1331
- if (selectedComponents.length > 0) {
1332
- console.log(' Components are in src/lib/rizzo — import from \'$lib/rizzo\'.');
1333
- }
1515
+ console.log(' data-theme="' + theme + '" on <html> (themes: ' + cliExample + ')');
1516
+ console.log(' Components: src/lib/rizzo import from \'$lib/rizzo\'.');
1334
1517
  } else if (framework === 'astro') {
1335
1518
  console.log('\nIn your layout (e.g. src/layouts/Layout.astro), add:');
1336
1519
  console.log(' <link rel="stylesheet" href="' + linkHref + '" />');
1337
- console.log('\nSet a theme on <html>: data-theme="' + theme + '" (see: ' + cliExample + ')');
1338
- console.log(' For theme "system": default dark ' + defaultDark + ', default light ' + defaultLight);
1339
- if (selectedComponents.length > 0) {
1340
- console.log(' Components are in src/components/rizzo — import from there.');
1341
- }
1520
+ console.log(' data-theme="' + theme + '" on <html> (themes: ' + cliExample + ')');
1521
+ console.log(' Components: src/components/rizzo import from there.');
1342
1522
  } else {
1343
1523
  console.log('\nIn your HTML or layout, add:');
1344
1524
  console.log(' <link rel="stylesheet" href="' + linkHref + '" />');
1345
- console.log('\nSet a theme on <html>: data-theme="' + theme + '" (see: ' + cliExample + ')');
1346
- console.log(' For theme "system": default dark ' + defaultDark + ', default light ' + defaultLight);
1347
- if (selectedComponents.length > 0) {
1348
- console.log(' Component HTML files are in components/.');
1525
+ console.log(' data-theme="' + theme + '" on <html> (themes: ' + cliExample + ')');
1526
+ console.log(' Component HTML files are in components/.');
1527
+ if (options._vanillaJsHint) {
1528
+ 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.');
1349
1529
  }
1350
1530
  }
1351
- console.log('\nTo install the package (CLI + components): ' + pm.add('rizzo-css'));
1352
- console.log('\nDocs: https://rizzo-css.vercel.app\n');
1531
+ console.log('\nTo install the package: ' + pm.add('rizzo-css'));
1532
+ console.log('\nNext: add the link above, then run your dev server. Docs: https://rizzo-css.vercel.app\n');
1353
1533
  }
1354
1534
 
1355
1535
  async function cmdInit(argv) {
@@ -1373,7 +1553,8 @@ async function cmdInit(argv) {
1373
1553
  framework = (frameworkArg && FRAMEWORKS.includes(frameworkArg.toLowerCase())) ? frameworkArg.toLowerCase() : (config && config.framework) || 'astro';
1374
1554
  initMode = 'new';
1375
1555
  const templateArg = getFlagValue(argv, '--template');
1376
- selectedTemplate = (templateArg && (templateArg === 'full' || templateArg === 'minimal' || templateArg === 'manual')) ? templateArg : 'full';
1556
+ const defaultTemplate = framework === 'vanilla' ? 'minimal' : 'full';
1557
+ selectedTemplate = (templateArg && (templateArg === 'full' || templateArg === 'minimal' || templateArg === 'manual')) ? templateArg : defaultTemplate;
1377
1558
  if (selectedTemplate === 'full' && (framework === 'astro' || framework === 'svelte')) {
1378
1559
  selectedComponents = framework === 'svelte' ? [...SVELTE_COMPONENTS] : [...ASTRO_COMPONENTS];
1379
1560
  } else if (selectedTemplate === 'minimal' && (framework === 'astro' || framework === 'svelte')) {
@@ -1450,6 +1631,13 @@ async function cmdInit(argv) {
1450
1631
  }
1451
1632
 
1452
1633
  const projectDir = name ? join(cwd, name) : cwd;
1634
+ if (projectDir === cwd && isDirNonEmpty(cwd) && !yes) {
1635
+ const ok = await confirmNonEmptyDir(projectDir);
1636
+ if (!ok) {
1637
+ console.log('Aborted.');
1638
+ return;
1639
+ }
1640
+ }
1453
1641
  const cssSource = getCssPath();
1454
1642
 
1455
1643
  if (!existsSync(cssSource)) {
@@ -1530,6 +1718,7 @@ async function cmdInit(argv) {
1530
1718
  console.warn('\nWarning: rizzo.min.css is very small. From repo root run: pnpm build:css');
1531
1719
  }
1532
1720
  copyPackageLicense(projectDir);
1721
+ copyAstroGitignore(projectDir);
1533
1722
  if (componentsToCopy.length > 0) {
1534
1723
  copyRizzoIcons(projectDir, 'astro');
1535
1724
  copyAstroComponents(projectDir, componentsToCopy);
@@ -1543,6 +1732,7 @@ async function cmdInit(argv) {
1543
1732
  console.warn('\nWarning: rizzo.min.css is very small. From repo root run: pnpm build:css');
1544
1733
  }
1545
1734
  copyPackageLicense(projectDir);
1735
+ copyAstroGitignore(projectDir);
1546
1736
  if (componentsToCopy.length > 0) {
1547
1737
  copyRizzoIcons(projectDir, 'astro');
1548
1738
  copyAstroComponents(projectDir, componentsToCopy);
@@ -1556,6 +1746,7 @@ async function cmdInit(argv) {
1556
1746
  console.warn('\nWarning: rizzo.min.css is very small. From repo root run: pnpm build:css');
1557
1747
  }
1558
1748
  copyPackageLicense(projectDir);
1749
+ copySvelteGitignore(projectDir);
1559
1750
  if (componentsToCopy.length > 0) {
1560
1751
  copyRizzoIcons(projectDir, 'svelte');
1561
1752
  copySvelteComponents(projectDir, componentsToCopy);
@@ -1569,6 +1760,7 @@ async function cmdInit(argv) {
1569
1760
  console.warn('\nWarning: rizzo.min.css is very small. From repo root run: pnpm build:css');
1570
1761
  }
1571
1762
  copyPackageLicense(projectDir);
1763
+ copySvelteGitignore(projectDir);
1572
1764
  if (componentsToCopy.length > 0) {
1573
1765
  copyRizzoIcons(projectDir, 'svelte');
1574
1766
  copySvelteComponents(projectDir, componentsToCopy);
@@ -1607,6 +1799,7 @@ async function cmdInit(argv) {
1607
1799
  writeFileSync(join(projectDir, 'js', 'main.js'), mainJs, 'utf8');
1608
1800
  }
1609
1801
  copyPackageLicense(projectDir);
1802
+ copyVanillaGitignore(projectDir);
1610
1803
  } else if (useVanillaMinimal) {
1611
1804
  const cssDir = join(projectDir, pathsForScaffold.targetDir);
1612
1805
  cssTarget = join(cssDir, 'rizzo.min.css');
@@ -1631,6 +1824,7 @@ async function cmdInit(argv) {
1631
1824
  writeFileSync(indexPath, minimalIndexWithScript, 'utf8');
1632
1825
  writeFileSync(join(projectDir, SCAFFOLD_README_FILENAME), VANILLA_MINIMAL_README, 'utf8');
1633
1826
  copyPackageLicense(projectDir);
1827
+ copyVanillaGitignore(projectDir);
1634
1828
  } else {
1635
1829
  if (framework === 'svelte') {
1636
1830
  copyRizzoCssAndFontsForSvelte(projectDir, cssSource);
@@ -1663,6 +1857,7 @@ async function cmdInit(argv) {
1663
1857
  }
1664
1858
  writeFileSync(indexPath, indexContent, 'utf8');
1665
1859
  writeFileSync(join(projectDir, SCAFFOLD_README_FILENAME), VANILLA_MANUAL_README, 'utf8');
1860
+ copyVanillaGitignore(projectDir);
1666
1861
  } else if (framework === 'astro') {
1667
1862
  indexPath = join(projectDir, 'public', 'index.html');
1668
1863
  mkdirSync(join(projectDir, 'public'), { recursive: true });
@@ -1696,7 +1891,7 @@ async function cmdInit(argv) {
1696
1891
 
1697
1892
  // Always write rizzo-css.json for new projects (targetDir, framework, packageManager).
1698
1893
  const pathsForConfig = getFrameworkCssPaths(framework);
1699
- writeRizzoConfig(projectDir, { targetDir: pathsForConfig.targetDir, framework, packageManager: selectedPm });
1894
+ writeRizzoConfig(projectDir, { targetDir: pathsForConfig.targetDir, framework, packageManager: selectedPm, theme });
1700
1895
  console.log(' - Wrote ' + RIZZO_CONFIG_FILE);
1701
1896
 
1702
1897
  if (runInstallAfterScaffold && !noInstall && hasPackageJson) {
@@ -1733,6 +1928,8 @@ async function cmdInit(argv) {
1733
1928
  const createExample = getCreateProjectExample(pm, framework);
1734
1929
  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') + '.');
1735
1930
  }
1931
+ if (hasPackageJson) console.log('\nNext: ' + runPrefix + nextStep);
1932
+ else if (framework === 'vanilla') console.log('\nNext: open index.html or serve the folder.');
1736
1933
  console.log('\nDocs: https://rizzo-css.vercel.app\n');
1737
1934
  }
1738
1935
 
@@ -1757,6 +1954,11 @@ function main() {
1757
1954
  return;
1758
1955
  }
1759
1956
 
1957
+ if (command === 'doctor') {
1958
+ cmdDoctor();
1959
+ return;
1960
+ }
1961
+
1760
1962
  if (command === 'add') {
1761
1963
  cmdAdd(argv).catch((err) => {
1762
1964
  console.error(err);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rizzo-css",
3
- "version": "0.0.26",
3
+ "version": "0.0.28",
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.26`, in production.)
16
+ (Replace `@latest` with a specific version, e.g. `@0.0.28`, 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/