rizzo-css 0.0.20 → 0.0.22

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 (48) hide show
  1. package/README.md +3 -3
  2. package/bin/rizzo-css.js +179 -53
  3. package/dist/fonts/.gitkeep +0 -0
  4. package/dist/fonts/GeistMono/GeistMonoVF.ttf +0 -0
  5. package/dist/fonts/GeistMono/GeistMonoVF.woff +0 -0
  6. package/dist/fonts/GeistMono/GeistMonoVF.woff2 +0 -0
  7. package/dist/fonts/GeistMono/LICENSE.TXT +92 -0
  8. package/dist/fonts/GeistSans/GeistVF.ttf +0 -0
  9. package/dist/fonts/GeistSans/GeistVF.woff +0 -0
  10. package/dist/fonts/GeistSans/GeistVF.woff2 +0 -0
  11. package/dist/fonts/GeistSans/LICENSE.TXT +92 -0
  12. package/dist/rizzo.min.css +5 -5
  13. package/package.json +1 -1
  14. package/scaffold/astro/Navbar.astro +11 -3
  15. package/scaffold/astro/icons/Cat.astro +27 -0
  16. package/scaffold/astro-minimal/{README.md → RIZZO-README.md} +6 -2
  17. package/scaffold/astro-minimal/src/layouts/Layout.astro +3 -4
  18. package/scaffold/svelte/Navbar.svelte +12 -2
  19. package/scaffold/svelte/icons/Cat.svelte +28 -0
  20. package/scaffold/svelte-minimal/{README.md → RIZZO-README.md} +5 -2
  21. package/scaffold/vanilla/{README.md → RIZZO-README.md} +4 -4
  22. package/scaffold/vanilla/components/accordion.html +20 -0
  23. package/scaffold/vanilla/components/alert.html +20 -0
  24. package/scaffold/vanilla/components/avatar.html +20 -0
  25. package/scaffold/vanilla/components/badge.html +20 -0
  26. package/scaffold/vanilla/components/breadcrumb.html +20 -0
  27. package/scaffold/vanilla/components/button.html +20 -0
  28. package/scaffold/vanilla/components/cards.html +20 -0
  29. package/scaffold/vanilla/components/copy-to-clipboard.html +20 -0
  30. package/scaffold/vanilla/components/divider.html +20 -0
  31. package/scaffold/vanilla/components/dropdown.html +20 -0
  32. package/scaffold/vanilla/components/forms.html +20 -0
  33. package/scaffold/vanilla/components/icons.html +20 -0
  34. package/scaffold/vanilla/components/index.html +20 -0
  35. package/scaffold/vanilla/components/modal.html +20 -0
  36. package/scaffold/vanilla/components/navbar.html +20 -0
  37. package/scaffold/vanilla/components/pagination.html +20 -0
  38. package/scaffold/vanilla/components/progress-bar.html +20 -0
  39. package/scaffold/vanilla/components/search.html +20 -0
  40. package/scaffold/vanilla/components/settings.html +20 -0
  41. package/scaffold/vanilla/components/spinner.html +20 -0
  42. package/scaffold/vanilla/components/table.html +20 -0
  43. package/scaffold/vanilla/components/tabs.html +20 -0
  44. package/scaffold/vanilla/components/theme-switcher.html +20 -0
  45. package/scaffold/vanilla/components/toast.html +20 -0
  46. package/scaffold/vanilla/components/tooltip.html +20 -0
  47. package/scaffold/vanilla/icons/Cat.svg +11 -0
  48. package/scaffold/vanilla/index.html +20 -0
package/README.md CHANGED
@@ -41,7 +41,7 @@ You install **the same package** for every framework: `npm install rizzo-css`. N
41
41
 
42
42
  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
43
 
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 and README; Astro/Svelte minimal include package.json and .env.example.
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 RIZZO-LICENSE and RIZZO-README.md (does not overwrite your project LICENSE/README); Astro/Svelte minimal include package.json and .env.example.
45
45
 
46
46
  ## Use
47
47
 
@@ -56,7 +56,7 @@ import 'rizzo-css';
56
56
  **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
57
 
58
58
  ```html
59
- <!-- unpkg (pin version: replace @latest with @0.0.20 or any version) -->
59
+ <!-- unpkg (pin version: replace @latest with @0.0.22 or any version) -->
60
60
  <link rel="stylesheet" href="https://unpkg.com/rizzo-css@latest/dist/rizzo.min.css" />
61
61
 
62
62
  <!-- or jsDelivr -->
@@ -65,7 +65,7 @@ import 'rizzo-css';
65
65
 
66
66
  Short URLs also work: `https://unpkg.com/rizzo-css@latest` and `https://cdn.jsdelivr.net/npm/rizzo-css@latest` (CDNs serve the default file from package.json). To verify after publish: open the URL in a browser or run `curl -I https://unpkg.com/rizzo-css@latest/dist/rizzo.min.css` and expect `200 OK`.
67
67
 
68
- Use the same class names and HTML structure as in the [component docs](https://rizzo-css.vercel.app/docs/components). **Vanilla JS**, Astro, and Svelte all use the same CSS and BEM markup; Astro/Svelte add framework component files when you hand-pick. Each scaffold has a README; every install includes LICENSE. The **Vanilla** Full includes a Settings panel and toast; **Astro** and **Svelte** Full scaffolds include theme persistence and toast (`showToast`, `removeToast`, `removeAllToasts`).
68
+ Use the same class names and HTML structure as in the [component docs](https://rizzo-css.vercel.app/docs/components). **Vanilla JS**, Astro, and Svelte all use the same CSS and BEM markup; Astro/Svelte add framework component files when you hand-pick. Each scaffold has RIZZO-README.md; every install includes RIZZO-LICENSE. The **Navbar** component in the scaffold includes the default Cat logo in the brand link (optional `logo` prop for a custom image). The **Vanilla** Full includes a Settings panel and toast; **Astro** and **Svelte** Full scaffolds include theme persistence and toast (`showToast`, `removeToast`, `removeAllToasts`).
69
69
 
70
70
  ## Themes
71
71
 
package/bin/rizzo-css.js CHANGED
@@ -6,24 +6,30 @@ const { spawnSync } = require('child_process');
6
6
  const readline = require('readline');
7
7
 
8
8
  const RIZZO_CONFIG_FILE = 'rizzo-css.json';
9
+ /** Scaffold README filename; avoids overwriting an existing project README.md. */
10
+ const SCAFFOLD_README_FILENAME = 'RIZZO-README.md';
11
+ /** Scaffold license filename; avoids overwriting an existing project LICENSE. */
12
+ const SCAFFOLD_LICENSE_FILENAME = 'RIZZO-LICENSE';
9
13
 
10
14
  const COMMANDS = ['init', 'add', 'theme', 'help'];
11
15
  const FRAMEWORKS = ['vanilla', 'astro', 'svelte'];
16
+ /** Supported package managers: detection, install/add commands, and --package-manager override. */
17
+ const VALID_PACKAGE_MANAGERS = ['npm', 'pnpm', 'yarn', 'bun'];
12
18
 
13
19
  /** Full = everything we ship. Minimal = recommended starting set. Manual = you choose. */
14
20
  const TEMPLATES = {
15
21
  vanilla: [
16
- { value: 'full', label: 'Full — index.html + theme switcher, js/main.js, icons, component showcase, README' },
22
+ { value: 'full', label: 'Full — index.html + theme switcher, js/main.js, icons, component showcase, ' + SCAFFOLD_README_FILENAME },
17
23
  { value: 'minimal', label: 'Minimal — index.html + CSS + js/main.js (recommended starter; no showcase)' },
18
24
  { value: 'manual', label: 'Manual — index.html + CSS; pick components to add their pages + js/main.js' },
19
25
  ],
20
26
  astro: [
21
- { value: 'full', label: 'Full — Astro app + all 25 components (config, one page, README, LICENSE, .env.example)' },
27
+ { value: 'full', label: 'Full — Astro app + all 25 components (config, one page, ' + SCAFFOLD_README_FILENAME + ', ' + SCAFFOLD_LICENSE_FILENAME + ', .env.example)' },
22
28
  { value: 'minimal', label: 'Minimal — Astro app + recommended components (Button, Badge, Card, Modal, Tabs, ThemeSwitcher, FormGroup, Alert, Toast, Dropdown)' },
23
29
  { value: 'manual', label: 'Manual — minimal base + pick the components you want' },
24
30
  ],
25
31
  svelte: [
26
- { value: 'full', label: 'Full — SvelteKit app + all 25 components (config, one page, README, LICENSE, .env.example)' },
32
+ { value: 'full', label: 'Full — SvelteKit app + all 25 components (config, one page, ' + SCAFFOLD_README_FILENAME + ', ' + SCAFFOLD_LICENSE_FILENAME + ', .env.example)' },
27
33
  { value: 'minimal', label: 'Minimal — SvelteKit app + recommended components (Button, Badge, Card, Modal, Tabs, ThemeSwitcher, FormGroup, Alert, Toast, Dropdown)' },
28
34
  { value: 'manual', label: 'Manual — minimal base + pick the components you want' },
29
35
  ],
@@ -138,11 +144,52 @@ function getCssPath() {
138
144
  return join(getPackageRoot(), 'dist', 'rizzo.min.css');
139
145
  }
140
146
 
141
- /** Copy the package LICENSE into the project dir. Call after every scaffold so every install includes a license. */
147
+ /** Copy package dist/fonts into <cssTargetDir>/fonts so CSS url(./fonts/...) resolves. cssTargetDir is framework-specific (static/css | css). Not used for Astro; use copyRizzoCssAndFontsForAstro instead. */
148
+ function copyRizzoFonts(cssTargetDir) {
149
+ const fontsSrc = join(getPackageRoot(), 'dist', 'fonts');
150
+ if (!existsSync(fontsSrc)) return;
151
+ const dest = join(cssTargetDir, 'fonts');
152
+ mkdirSync(dest, { recursive: true });
153
+ const entries = readdirSync(fontsSrc, { withFileTypes: true });
154
+ for (const e of entries) {
155
+ const srcPath = join(fontsSrc, e.name);
156
+ const destPath = join(dest, e.name);
157
+ if (e.isDirectory()) {
158
+ copyDirRecursive(srcPath, destPath);
159
+ } else {
160
+ copyFileSync(srcPath, destPath);
161
+ }
162
+ }
163
+ }
164
+
165
+ /** Astro only: copy rizzo.min.css to public/css with font URLs rewritten to /assets/fonts/, and copy fonts to public/assets/fonts. */
166
+ function copyRizzoCssAndFontsForAstro(projectDir, cssSource) {
167
+ const cssDir = join(projectDir, 'public', 'css');
168
+ const cssTarget = join(cssDir, 'rizzo.min.css');
169
+ const fontsDest = join(projectDir, 'public', 'assets', 'fonts');
170
+ mkdirSync(cssDir, { recursive: true });
171
+ mkdirSync(fontsDest, { recursive: true });
172
+ copyFileSync(cssSource, cssTarget);
173
+ let css = readFileSync(cssTarget, 'utf8');
174
+ css = css.replace(/url\(['"]?\.\/fonts\//g, "url('/assets/fonts/");
175
+ writeFileSync(cssTarget, css, 'utf8');
176
+ const fontsSrc = join(getPackageRoot(), 'dist', 'fonts');
177
+ if (existsSync(fontsSrc)) {
178
+ const entries = readdirSync(fontsSrc, { withFileTypes: true });
179
+ for (const e of entries) {
180
+ const srcPath = join(fontsSrc, e.name);
181
+ const destPath = join(fontsDest, e.name);
182
+ if (e.isDirectory()) copyDirRecursive(srcPath, destPath);
183
+ else copyFileSync(srcPath, destPath);
184
+ }
185
+ }
186
+ }
187
+
188
+ /** Copy the package LICENSE into the project dir as RIZZO-LICENSE so we do not overwrite an existing LICENSE. */
142
189
  function copyPackageLicense(projectDir) {
143
190
  const licensePath = join(getPackageRoot(), 'LICENSE');
144
191
  if (existsSync(licensePath)) {
145
- copyFileSync(licensePath, join(projectDir, 'LICENSE'));
192
+ copyFileSync(licensePath, join(projectDir, SCAFFOLD_LICENSE_FILENAME));
146
193
  }
147
194
  }
148
195
 
@@ -187,6 +234,13 @@ function getFlagValue(argv, flag) {
187
234
  return i !== -1 && argv[i + 1] != null ? argv[i + 1] : null;
188
235
  }
189
236
 
237
+ /** Parse --package-manager value; returns npm|pnpm|yarn|bun or null if invalid/absent. */
238
+ function parsePackageManager(value) {
239
+ if (!value || typeof value !== 'string') return null;
240
+ const v = value.toLowerCase().trim();
241
+ return VALID_PACKAGE_MANAGERS.includes(v) ? v : null;
242
+ }
243
+
190
244
  /** Get positional args for a command (excludes --flag and --flag value). Used for e.g. add Button ThemeSwitcher. */
191
245
  function getPositionalArgs(argv) {
192
246
  const positionals = [];
@@ -251,13 +305,16 @@ function getCreateProjectExample(pm, framework) {
251
305
  return 'npm create ' + framework + '@latest my-app';
252
306
  }
253
307
 
254
- /** Prompt user to select package manager (npm, pnpm, yarn, bun). Puts detected first with "(detected)" label. Returns agent string. */
308
+ /** Prompt user to select package manager (npm, pnpm, yarn, bun). Shows "(detected)" only when we actually found a lockfile or packageManager; for new projects with no detection, user chooses. Returns agent string. */
255
309
  async function promptPackageManager(projectDir) {
256
- const detected = resolvePackageManager(projectDir, process.cwd());
310
+ const actuallyDetected = detectPackageManager(projectDir) || detectPackageManager(process.cwd());
311
+ const resolved = actuallyDetected
312
+ ? getPackageManagerCommands(actuallyDetected)
313
+ : null;
257
314
  const agents = ['npm', 'pnpm', 'yarn', 'bun'];
258
315
  const options = agents.map((a) => ({
259
316
  value: a,
260
- label: a === detected.agent ? a + ' (detected)' : a,
317
+ label: (resolved && a === resolved.agent) ? a + ' (detected)' : a,
261
318
  }));
262
319
  return selectMenu(options, '? Package manager (for install and run commands)');
263
320
  }
@@ -278,6 +335,12 @@ function question(prompt) {
278
335
  });
279
336
  }
280
337
 
338
+ /** Prompt yes/no; default yes. Returns true to run, false to skip. */
339
+ async function confirmRunInstall(pm) {
340
+ const answer = await question('\nRun ' + pm.install + ' now? (Y/n) ');
341
+ return answer === '' || /^y(es)?$/i.test(answer);
342
+ }
343
+
281
344
  /** Format label with optional ANSI color (item.color). */
282
345
  function formatLabel(item) {
283
346
  const text = item.label || item.value;
@@ -377,12 +440,13 @@ function getRealValues(items) {
377
440
  return items.map((i) => i.value);
378
441
  }
379
442
 
380
- /** Multi-select menu: circles ○/●, Space toggles, Enter confirms. Optional first two options: Select all / Select none (value __all__ / __none__). Returns array of selected values. */
381
- function multiSelectMenu(options, title) {
443
+ /** Multi-select menu: circles ○/●, Space toggles, Enter confirms. Optional first two options: Select all / Select none (value __all__ / __none__). initialSelected: optional array of values to pre-check. Returns array of selected values. */
444
+ function multiSelectMenu(options, title, initialSelected) {
382
445
  const items = options.map((o) => (typeof o === 'string' ? { value: o, label: o } : o));
383
446
  const isTty = process.stdin.isTTY && process.stdout.isTTY;
384
447
  const withSentinels = hasAllNoneSentinels(items);
385
448
  const realValues = getRealValues(items);
449
+ const initialSet = Array.isArray(initialSelected) ? new Set(initialSelected) : null;
386
450
 
387
451
  if (!isTty) {
388
452
  console.log('\n' + (title || 'Choose (space to toggle, enter when done)') + ':');
@@ -430,6 +494,11 @@ function multiSelectMenu(options, title) {
430
494
  return new Promise((resolve) => {
431
495
  let index = 0;
432
496
  const selected = new Set();
497
+ if (initialSet && initialSet.size > 0) {
498
+ for (let i = 0; i < items.length; i++) {
499
+ if (initialSet.has(items[i].value)) selected.add(i);
500
+ }
501
+ }
433
502
  const lineCount = (title ? 1 : 0) + items.length + 1;
434
503
  const realStart = withSentinels ? 2 : 0;
435
504
 
@@ -558,16 +627,21 @@ Options (init):
558
627
  --yes Non-interactive: scaffold new in cwd with defaults (framework: astro, template: full)
559
628
  --framework <fw> vanilla | astro | svelte (with --yes; otherwise first prompt)
560
629
  --template <t> full | minimal | manual (all frameworks); with --yes defaults to full
561
- --install After scaffolding, run package manager install (new project)
562
- --no-install Do not run install
563
- --write-config Write rizzo-css.json (targetDir, framework, packageManager) in the project
630
+ --package-manager <pm> npm | pnpm | yarn | bun (with --yes, or skip PM prompt when interactive)
631
+ --install After scaffolding, run package manager install (no prompt)
632
+ --no-install Do not run install and do not prompt
633
+ (rizzo-css.json is always written for new and existing projects; interactive run prompts "Run install now? (Y/n)" for Astro/Svelte.)
564
634
 
565
635
  Options (add):
566
636
  --path <dir> Target directory for rizzo.min.css (overrides config and framework default)
567
637
  --framework <fw> vanilla | astro | svelte (overrides config and detection)
638
+ --package-manager <pm> npm | pnpm | yarn | bun (override detection for install/print commands)
568
639
  --install-package After copying CSS, run package manager add rizzo-css
569
640
  --no-install Do not run install or add (overrides --install-package)
570
641
 
642
+ Package managers:
643
+ 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.
644
+
571
645
  Config:
572
646
  Optional rizzo-css.json in project root: { "targetDir", "framework", "packageManager" }.
573
647
  Used by add and init when present. Detection: lockfiles and packageManager field in package.json.
@@ -585,9 +659,11 @@ Use framework CLI first, then add Rizzo CSS (match your package manager):
585
659
 
586
660
  Examples:
587
661
  npx rizzo-css init
588
- npx rizzo-css init --yes --framework astro --install --write-config
662
+ npx rizzo-css init --yes --framework astro --install
663
+ npx rizzo-css init --yes --framework astro --package-manager pnpm --install
589
664
  npx rizzo-css init --yes --framework vanilla
590
665
  npx rizzo-css init --yes --framework svelte --template full
666
+ npx rizzo-css add --package-manager yarn --install-package
591
667
  npx rizzo-css add
592
668
  npx rizzo-css add Button
593
669
  npx rizzo-css add Button ThemeSwitcher --path public/css --framework svelte
@@ -628,9 +704,20 @@ async function promptThemes() {
628
704
  return { theme, defaultDark: DARK_THEMES.includes(defaultDark) ? defaultDark : DARK_THEMES[0], defaultLight: LIGHT_THEMES.includes(defaultLight) ? defaultLight : LIGHT_THEMES[0] };
629
705
  }
630
706
 
631
- /** Ask what to include: CSS only, recommended set, all components, or pick. Returns array of component names. Only call when componentList.length > 0. */
632
- async function promptComponentChoice(componentList, framework) {
707
+ /** Ask what to include: CSS only, recommended set, all components, or pick. Returns array of component names. Only call when componentList.length > 0. initialSelection: when set (e.g. for manual = minimal base), skip the menu and show multi-select with these pre-selected. */
708
+ async function promptComponentChoice(componentList, framework, initialSelection) {
633
709
  const recommended = RECOMMENDED_COMPONENTS.filter((c) => componentList.includes(c));
710
+ if (initialSelection !== undefined) {
711
+ return multiSelectMenu(
712
+ [
713
+ { value: SENTINEL_ALL, label: 'Select all components' },
714
+ { value: SENTINEL_NONE, label: 'Select no components' },
715
+ ...componentList.map((c) => ({ value: c, label: c })),
716
+ ],
717
+ '? Components (minimal set pre-selected) — Space to toggle, Enter to confirm',
718
+ initialSelection
719
+ );
720
+ }
634
721
  const choice = await selectMenu(
635
722
  [
636
723
  { value: 'none', label: 'CSS only — no components' },
@@ -667,11 +754,20 @@ function detectFramework(cwd) {
667
754
  return null;
668
755
  }
669
756
 
670
- /** Default CSS directory and link href for a framework (for add command). */
757
+ /**
758
+ * Framework-specific paths for CSS and static assets. Use these so fonts, sounds, images
759
+ * go in the right place per framework (Astro: public/, SvelteKit: static/, Vanilla: project root).
760
+ * - targetDir: where rizzo.min.css is copied. Fonts: for Astro, public/assets/fonts (CLI rewrites URLs); for Svelte/Vanilla, targetDir/fonts so ./fonts/ resolves.
761
+ * - assetsRoot: root for static assets (Astro: public; use public/assets/fonts, public/assets/sounds).
762
+ */
671
763
  function getFrameworkCssPaths(framework) {
672
- if (framework === 'svelte') return { targetDir: 'static/css', linkHref: '/css/rizzo.min.css' };
673
- if (framework === 'astro') return { targetDir: 'public/css', linkHref: '/css/rizzo.min.css' };
674
- return { targetDir: 'css', linkHref: 'css/rizzo.min.css' };
764
+ if (framework === 'svelte') {
765
+ return { targetDir: 'static/css', linkHref: '/css/rizzo.min.css', fontsDir: 'static/css/fonts', assetsRoot: 'static' };
766
+ }
767
+ if (framework === 'astro') {
768
+ return { targetDir: 'public/css', linkHref: '/css/rizzo.min.css', fontsDir: 'public/assets/fonts', assetsRoot: 'public' };
769
+ }
770
+ return { targetDir: 'css', linkHref: 'css/rizzo.min.css', fontsDir: 'css/fonts', assetsRoot: '' };
675
771
  }
676
772
 
677
773
  /**
@@ -702,16 +798,20 @@ async function cmdAdd(argv) {
702
798
 
703
799
  const cwd = process.cwd();
704
800
  const config = readRizzoConfig(cwd);
801
+ const pmOverride = parsePackageManager(getFlagValue(argv, '--package-manager'));
705
802
  const options = {
706
803
  config,
707
804
  targetDir: customPath || (config && config.targetDir) || undefined,
805
+ packageManager: pmOverride || undefined,
708
806
  preselectedComponents: positionals.length > 0 ? positionals : undefined,
709
807
  };
710
808
  await runAddToExisting(explicitFramework, options);
711
809
  if (installPackage && !noInstall) {
712
- const pm = (config && config.packageManager)
713
- ? getPackageManagerCommands({ agent: config.packageManager, command: config.packageManager })
714
- : resolvePackageManager(cwd);
810
+ const pm = (pmOverride
811
+ ? getPackageManagerCommands({ agent: pmOverride, command: pmOverride })
812
+ : (config && config.packageManager)
813
+ ? getPackageManagerCommands({ agent: config.packageManager, command: config.packageManager })
814
+ : resolvePackageManager(cwd));
715
815
  const addPkg = pm.add('rizzo-css');
716
816
  console.log('\nRunning: ' + addPkg);
717
817
  const code = runInDir(cwd, addPkg);
@@ -1023,10 +1123,17 @@ async function runAddToExisting(frameworkOverride, options) {
1023
1123
 
1024
1124
  const paths = getFrameworkCssPaths(framework);
1025
1125
  const targetDirRaw = (options && options.targetDir) || (config && config.targetDir) || paths.targetDir;
1026
- const targetDir = join(cwd, targetDirRaw);
1027
- const cssTarget = join(targetDir, 'rizzo.min.css');
1028
- mkdirSync(targetDir, { recursive: true });
1029
- copyFileSync(cssSource, cssTarget);
1126
+ let cssTarget;
1127
+ if (framework === 'astro') {
1128
+ copyRizzoCssAndFontsForAstro(cwd, cssSource);
1129
+ cssTarget = join(cwd, 'public', 'css', 'rizzo.min.css');
1130
+ } else {
1131
+ const targetDir = join(cwd, targetDirRaw);
1132
+ cssTarget = join(targetDir, 'rizzo.min.css');
1133
+ mkdirSync(targetDir, { recursive: true });
1134
+ copyFileSync(cssSource, cssTarget);
1135
+ copyRizzoFonts(targetDir);
1136
+ }
1030
1137
 
1031
1138
  copyRizzoIcons(cwd, framework);
1032
1139
  if (framework === 'svelte' && selectedComponents.length > 0) {
@@ -1040,12 +1147,17 @@ async function runAddToExisting(frameworkOverride, options) {
1040
1147
  }
1041
1148
 
1042
1149
  const linkHref = (options && options.targetDir) ? getLinkHrefForTargetDir(framework, options.targetDir) : paths.linkHref;
1043
- const pm = (config && config.packageManager)
1044
- ? getPackageManagerCommands({ agent: config.packageManager, command: config.packageManager })
1045
- : resolvePackageManager(cwd);
1150
+ const pmFromOption = options && options.packageManager && VALID_PACKAGE_MANAGERS.includes(options.packageManager);
1151
+ const pm = pmFromOption
1152
+ ? getPackageManagerCommands({ agent: options.packageManager, command: options.packageManager })
1153
+ : (config && config.packageManager)
1154
+ ? getPackageManagerCommands({ agent: config.packageManager, command: config.packageManager })
1155
+ : resolvePackageManager(cwd);
1046
1156
  const cliExample = pm.dlx('rizzo-css theme');
1157
+ writeRizzoConfig(cwd, { targetDir: targetDirRaw, framework, packageManager: pm.agent });
1047
1158
  console.log('\n✓ Rizzo CSS added to your existing project');
1048
1159
  console.log(' - ' + cssTarget);
1160
+ console.log(' - Wrote ' + RIZZO_CONFIG_FILE);
1049
1161
  console.log('\nYou must add the stylesheet link yourself — it is not added automatically.');
1050
1162
  if (framework === 'svelte') {
1051
1163
  console.log('\nIn your root layout (e.g. src/app.html), add:');
@@ -1081,7 +1193,6 @@ async function cmdInit(argv) {
1081
1193
  const yes = hasFlag(argv, '--yes');
1082
1194
  const runInstallAfterScaffold = hasFlag(argv, '--install');
1083
1195
  const noInstall = hasFlag(argv, '--no-install');
1084
- const writeConfig = hasFlag(argv, '--write-config');
1085
1196
  const cwd = process.cwd();
1086
1197
  const config = readRizzoConfig(cwd);
1087
1198
 
@@ -1107,7 +1218,8 @@ async function cmdInit(argv) {
1107
1218
  }
1108
1219
  const projectDir = cwd;
1109
1220
  const resolved = resolvePackageManager(projectDir, cwd);
1110
- selectedPm = (config && config.packageManager) || resolved.agent || 'npm';
1221
+ const pmArg = getFlagValue(argv, '--package-manager');
1222
+ selectedPm = parsePackageManager(pmArg) || (config && config.packageManager) || resolved.agent || 'npm';
1111
1223
  theme = 'system';
1112
1224
  defaultDark = DARK_THEMES[0];
1113
1225
  defaultLight = LIGHT_THEMES[0];
@@ -1152,7 +1264,8 @@ async function cmdInit(argv) {
1152
1264
  selectedComponents = RECOMMENDED_COMPONENTS.filter((c) => componentList.includes(c));
1153
1265
  } else if (selectedTemplate === 'manual') {
1154
1266
  const componentList = framework === 'svelte' ? SVELTE_COMPONENTS : ASTRO_COMPONENTS;
1155
- selectedComponents = await promptComponentChoice(componentList, framework);
1267
+ const recommended = RECOMMENDED_COMPONENTS.filter((c) => componentList.includes(c));
1268
+ selectedComponents = await promptComponentChoice(componentList, framework, recommended);
1156
1269
  }
1157
1270
 
1158
1271
  const wantsThemeSwitcher = (framework === 'vanilla' && (selectedTemplate === 'full' || selectedTemplate === 'minimal')) || selectedComponents.includes('ThemeSwitcher');
@@ -1168,7 +1281,8 @@ async function cmdInit(argv) {
1168
1281
  }
1169
1282
 
1170
1283
  const projectDirForPm = name ? join(cwd, name) : cwd;
1171
- selectedPm = await promptPackageManager(projectDirForPm);
1284
+ const pmArg = getFlagValue(argv, '--package-manager');
1285
+ selectedPm = parsePackageManager(pmArg) || await promptPackageManager(projectDirForPm);
1172
1286
  }
1173
1287
 
1174
1288
  const projectDir = name ? join(cwd, name) : cwd;
@@ -1179,7 +1293,7 @@ async function cmdInit(argv) {
1179
1293
  process.exit(1);
1180
1294
  }
1181
1295
 
1182
- const themeComment = '\n <!-- Initial: ' + theme + '; dark: ' + defaultDark + '; light: ' + defaultLight + ' (all 14 themes in CSS) -->';
1296
+ const themeComment = ' <!-- Initial: ' + theme + '; dark: ' + defaultDark + '; light: ' + defaultLight + ' (all 14 themes in CSS) -->';
1183
1297
  const projectNamePkg = name
1184
1298
  ? name.replace(/\s+/g, '-').toLowerCase()
1185
1299
  : (framework === 'astro' ? 'my-astro-app' : framework === 'svelte' ? 'my-svelte-app' : 'my-app');
@@ -1223,9 +1337,8 @@ async function cmdInit(argv) {
1223
1337
  if (useHandpickAstro) {
1224
1338
  mkdirSync(projectDir, { recursive: true });
1225
1339
  copyDirRecursiveWithReplacements(astroMinimalDir, projectDir, replacements);
1226
- mkdirSync(join(projectDir, 'public', 'css'), { recursive: true });
1340
+ copyRizzoCssAndFontsForAstro(projectDir, cssSource);
1227
1341
  cssTarget = join(projectDir, 'public', 'css', 'rizzo.min.css');
1228
- copyFileSync(cssSource, cssTarget);
1229
1342
  if (statSync(cssTarget).size < 5000) {
1230
1343
  console.warn('\nWarning: rizzo.min.css is very small. From repo root run: pnpm build:css');
1231
1344
  }
@@ -1237,9 +1350,8 @@ async function cmdInit(argv) {
1237
1350
  } else if (useAstroBase) {
1238
1351
  mkdirSync(projectDir, { recursive: true });
1239
1352
  copyDirRecursiveWithReplacements(astroMinimalDir, projectDir, replacements);
1240
- mkdirSync(join(projectDir, 'public', 'css'), { recursive: true });
1353
+ copyRizzoCssAndFontsForAstro(projectDir, cssSource);
1241
1354
  cssTarget = join(projectDir, 'public', 'css', 'rizzo.min.css');
1242
- copyFileSync(cssSource, cssTarget);
1243
1355
  if (statSync(cssTarget).size < 5000) {
1244
1356
  console.warn('\nWarning: rizzo.min.css is very small. From repo root run: pnpm build:css');
1245
1357
  }
@@ -1254,6 +1366,7 @@ async function cmdInit(argv) {
1254
1366
  mkdirSync(join(projectDir, 'static', 'css'), { recursive: true });
1255
1367
  cssTarget = join(projectDir, 'static', 'css', 'rizzo.min.css');
1256
1368
  copyFileSync(cssSource, cssTarget);
1369
+ copyRizzoFonts(dirname(cssTarget));
1257
1370
  if (statSync(cssTarget).size < 5000) {
1258
1371
  console.warn('\nWarning: rizzo.min.css is very small. From repo root run: pnpm build:css');
1259
1372
  }
@@ -1268,6 +1381,7 @@ async function cmdInit(argv) {
1268
1381
  mkdirSync(join(projectDir, 'static', 'css'), { recursive: true });
1269
1382
  cssTarget = join(projectDir, 'static', 'css', 'rizzo.min.css');
1270
1383
  copyFileSync(cssSource, cssTarget);
1384
+ copyRizzoFonts(dirname(cssTarget));
1271
1385
  if (statSync(cssTarget).size < 5000) {
1272
1386
  console.warn('\nWarning: rizzo.min.css is very small. From repo root run: pnpm build:css');
1273
1387
  }
@@ -1282,6 +1396,7 @@ async function cmdInit(argv) {
1282
1396
  const linkHref = 'css/rizzo.min.css';
1283
1397
  mkdirSync(cssDir, { recursive: true });
1284
1398
  copyFileSync(cssSource, cssTarget);
1399
+ copyRizzoFonts(dirname(cssTarget));
1285
1400
  if (statSync(cssTarget).size < 5000) {
1286
1401
  console.warn('\nWarning: rizzo.min.css is very small. From repo root run: pnpm build:css');
1287
1402
  }
@@ -1297,9 +1412,9 @@ async function cmdInit(argv) {
1297
1412
  .replace(/\{\{LINK_HREF\}\}/g, linkHref);
1298
1413
  writeFileSync(indexPath, indexHtml, 'utf8');
1299
1414
  copyRizzoIcons(projectDir, 'vanilla');
1300
- const vanillaReadme = join(getPackageRoot(), 'scaffold', 'vanilla', 'README.md');
1415
+ const vanillaReadme = join(getPackageRoot(), 'scaffold', 'vanilla', SCAFFOLD_README_FILENAME);
1301
1416
  if (existsSync(vanillaReadme)) {
1302
- copyFileSync(vanillaReadme, join(projectDir, 'README.md'));
1417
+ copyFileSync(vanillaReadme, join(projectDir, SCAFFOLD_README_FILENAME));
1303
1418
  }
1304
1419
  const vanillaJs = join(getPackageRoot(), 'scaffold', 'vanilla', 'js', 'main.js');
1305
1420
  if (existsSync(vanillaJs)) {
@@ -1314,6 +1429,7 @@ async function cmdInit(argv) {
1314
1429
  cssTarget = join(cssDir, 'rizzo.min.css');
1315
1430
  mkdirSync(cssDir, { recursive: true });
1316
1431
  copyFileSync(cssSource, cssTarget);
1432
+ copyRizzoFonts(dirname(cssTarget));
1317
1433
  if (statSync(cssTarget).size < 5000) {
1318
1434
  console.warn('\nWarning: rizzo.min.css is very small. From repo root run: pnpm build:css');
1319
1435
  }
@@ -1330,13 +1446,14 @@ async function cmdInit(argv) {
1330
1446
  const minimalIndexWithScript = minimalHtml.replace('</body>', ' <script src="js/main.js"></script>\n</body>');
1331
1447
  indexPath = join(projectDir, 'index.html');
1332
1448
  writeFileSync(indexPath, minimalIndexWithScript, 'utf8');
1333
- writeFileSync(join(projectDir, 'README.md'), VANILLA_MINIMAL_README, 'utf8');
1449
+ writeFileSync(join(projectDir, SCAFFOLD_README_FILENAME), VANILLA_MINIMAL_README, 'utf8');
1334
1450
  copyPackageLicense(projectDir);
1335
1451
  } else {
1336
1452
  const cssDir = join(projectDir, pathsForScaffold.targetDir);
1337
1453
  cssTarget = join(cssDir, 'rizzo.min.css');
1338
1454
  mkdirSync(cssDir, { recursive: true });
1339
1455
  copyFileSync(cssSource, cssTarget);
1456
+ copyRizzoFonts(dirname(cssTarget));
1340
1457
  if (statSync(cssTarget).size < 5000) {
1341
1458
  console.warn('\nWarning: rizzo.min.css is very small. From repo root run: pnpm build:css');
1342
1459
  }
@@ -1357,17 +1474,17 @@ async function cmdInit(argv) {
1357
1474
  indexContent = minimalHtml.replace('</body>', ' <script src="js/main.js"></script>\n</body>');
1358
1475
  }
1359
1476
  writeFileSync(indexPath, indexContent, 'utf8');
1360
- writeFileSync(join(projectDir, 'README.md'), VANILLA_MANUAL_README, 'utf8');
1477
+ writeFileSync(join(projectDir, SCAFFOLD_README_FILENAME), VANILLA_MANUAL_README, 'utf8');
1361
1478
  } else if (framework === 'astro') {
1362
1479
  indexPath = join(projectDir, 'public', 'index.html');
1363
1480
  mkdirSync(join(projectDir, 'public'), { recursive: true });
1364
1481
  writeFileSync(indexPath, minimalHtml, 'utf8');
1365
- writeFileSync(join(projectDir, 'README.md'), FALLBACK_MINIMAL_README, 'utf8');
1482
+ writeFileSync(join(projectDir, SCAFFOLD_README_FILENAME), FALLBACK_MINIMAL_README, 'utf8');
1366
1483
  } else {
1367
1484
  indexPath = join(projectDir, 'static', 'index.html');
1368
1485
  mkdirSync(join(projectDir, 'static'), { recursive: true });
1369
1486
  writeFileSync(indexPath, minimalHtml, 'utf8');
1370
- writeFileSync(join(projectDir, 'README.md'), FALLBACK_MINIMAL_README, 'utf8');
1487
+ writeFileSync(join(projectDir, SCAFFOLD_README_FILENAME), FALLBACK_MINIMAL_README, 'utf8');
1371
1488
  }
1372
1489
  copyPackageLicense(projectDir);
1373
1490
  }
@@ -1377,7 +1494,7 @@ async function cmdInit(argv) {
1377
1494
  if (indexPath) console.log(' - ' + indexPath);
1378
1495
  if (framework === 'vanilla') {
1379
1496
  if (useVanillaFull) {
1380
- console.log(' - Vanilla JS (full): theme switcher, js/main.js, icons, component showcase, README.');
1497
+ console.log(' - Vanilla JS (full): theme switcher, js/main.js, icons, component showcase, ' + SCAFFOLD_README_FILENAME + '.');
1381
1498
  } else if (useVanillaMinimal) {
1382
1499
  console.log(' - Vanilla JS (minimal): index.html + CSS + js/main.js. Add components from docs or use Full for showcase.');
1383
1500
  } else {
@@ -1387,19 +1504,28 @@ async function cmdInit(argv) {
1387
1504
  const pm = getPackageManagerCommands({ agent: selectedPm, command: selectedPm });
1388
1505
  const nextStep = pm.install + ' && ' + pm.run('dev');
1389
1506
  const runPrefix = name ? 'cd ' + name + ' && ' : '';
1507
+ const hasPackageJson = useHandpickAstro || useHandpickSvelte || useAstroBase || useSvelteBase;
1508
+
1509
+ // Always write rizzo-css.json for new projects (targetDir, framework, packageManager).
1510
+ const pathsForConfig = getFrameworkCssPaths(framework);
1511
+ writeRizzoConfig(projectDir, { targetDir: pathsForConfig.targetDir, framework, packageManager: selectedPm });
1512
+ console.log(' - Wrote ' + RIZZO_CONFIG_FILE);
1390
1513
 
1391
- if (runInstallAfterScaffold && !noInstall && (useHandpickAstro || useHandpickSvelte || useAstroBase || useSvelteBase)) {
1514
+ if (runInstallAfterScaffold && !noInstall && hasPackageJson) {
1392
1515
  console.log('\nRunning: ' + pm.install);
1393
1516
  const code = runInDir(projectDir, pm.install);
1394
1517
  if (code !== 0) {
1395
1518
  console.error('\nInstall failed (exit ' + code + '). Run manually: ' + runPrefix + pm.install);
1396
1519
  }
1397
- }
1398
-
1399
- if (writeConfig) {
1400
- const pathsForConfig = getFrameworkCssPaths(framework);
1401
- writeRizzoConfig(projectDir, { targetDir: pathsForConfig.targetDir, framework, packageManager: selectedPm });
1402
- console.log('\n - Wrote ' + RIZZO_CONFIG_FILE);
1520
+ } else if (!yes && !noInstall && hasPackageJson) {
1521
+ const shouldRun = await confirmRunInstall(pm);
1522
+ if (shouldRun) {
1523
+ console.log('\nRunning: ' + pm.install);
1524
+ const code = runInDir(projectDir, pm.install);
1525
+ if (code !== 0) {
1526
+ console.error('\nInstall failed (exit ' + code + '). Run manually: ' + runPrefix + pm.install);
1527
+ }
1528
+ }
1403
1529
  }
1404
1530
 
1405
1531
  if (useHandpickAstro || useHandpickSvelte) {
File without changes
@@ -0,0 +1,92 @@
1
+ Geist Sans and Geist Mono Font
2
+ (C) 2023 Vercel, made in collaboration with basement.studio
3
+
4
+ This Font Software is licensed under the SIL Open Font License, Version 1.1.
5
+ This license is available with a FAQ at: http://scripts.sil.org/OFL and copied below
6
+
7
+ -----------------------------------------------------------
8
+ SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
9
+ -----------------------------------------------------------
10
+
11
+ PREAMBLE
12
+ The goals of the Open Font License (OFL) are to stimulate worldwide
13
+ development of collaborative font projects, to support the font creation
14
+ efforts of academic and linguistic communities, and to provide a free and
15
+ open framework in which fonts may be shared and improved in partnership
16
+ with others.
17
+
18
+ The OFL allows the licensed fonts to be used, studied, modified and
19
+ redistributed freely as long as they are not sold by themselves. The
20
+ fonts, including any derivative works, can be bundled, embedded,
21
+ redistributed and/or sold with any software provided that any reserved
22
+ names are not used by derivative works. The fonts and derivatives,
23
+ however, cannot be released under any other type of license. The
24
+ requirement for fonts to remain under this license does not apply
25
+ to any document created using the fonts or their derivatives.
26
+
27
+ DEFINITIONS
28
+ "Font Software" refers to the set of files released by the Copyright
29
+ Holder(s) under this license and clearly marked as such. This may
30
+ include source files, build scripts and documentation.
31
+
32
+ "Reserved Font Name" refers to any names specified as such after the
33
+ copyright statement(s).
34
+
35
+ "Original Version" refers to the collection of Font Software components as
36
+ distributed by the Copyright Holder(s).
37
+
38
+ "Modified Version" refers to any derivative made by adding to, deleting,
39
+ or substituting -- in part or in whole -- any of the components of the
40
+ Original Version, by changing formats or by porting the Font Software to a
41
+ new environment.
42
+
43
+ "Author" refers to any designer, engineer, programmer, technical
44
+ writer or other person who contributed to the Font Software.
45
+
46
+ PERMISSION AND CONDITIONS
47
+ Permission is hereby granted, free of charge, to any person obtaining
48
+ a copy of the Font Software, to use, study, copy, merge, embed, modify,
49
+ redistribute, and sell modified and unmodified copies of the Font
50
+ Software, subject to the following conditions:
51
+
52
+ 1) Neither the Font Software nor any of its individual components,
53
+ in Original or Modified Versions, may be sold by itself.
54
+
55
+ 2) Original or Modified Versions of the Font Software may be bundled,
56
+ redistributed and/or sold with any software, provided that each copy
57
+ contains the above copyright notice and this license. These can be
58
+ included either as stand-alone text files, human-readable headers or
59
+ in the appropriate machine-readable metadata fields within text or
60
+ binary files as long as those fields can be easily viewed by the user.
61
+
62
+ 3) No Modified Version of the Font Software may use the Reserved Font
63
+ Name(s) unless explicit written permission is granted by the corresponding
64
+ Copyright Holder. This restriction only applies to the primary font name as
65
+ presented to the users.
66
+
67
+ 4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
68
+ Software shall not be used to promote, endorse or advertise any
69
+ Modified Version, except to acknowledge the contribution(s) of the
70
+ Copyright Holder(s) and the Author(s) or with their explicit written
71
+ permission.
72
+
73
+ 5) The Font Software, modified or unmodified, in part or in whole,
74
+ must be distributed entirely under this license, and must not be
75
+ distributed under any other license. The requirement for fonts to
76
+ remain under this license does not apply to any document created
77
+ using the Font Software.
78
+
79
+ TERMINATION
80
+ This license becomes null and void if any of the above conditions are
81
+ not met.
82
+
83
+ DISCLAIMER
84
+ THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
85
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
86
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
87
+ OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
88
+ COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
89
+ INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
90
+ DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
91
+ FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
92
+ OTHER DEALINGS IN THE FONT SOFTWARE.
Binary file