rizzo-css 0.0.22 → 0.0.24
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.
- package/README.md +4 -4
- package/bin/rizzo-css.js +244 -48
- package/package.json +1 -1
- package/scaffold/astro/Navbar.astro +7 -0
- package/scaffold/astro/Settings.astro +374 -5
- package/scaffold/astro-minimal/{RIZZO-README.md → README-RIZZO.md} +2 -2
- package/scaffold/astro-minimal/src/layouts/Layout.astro +1 -2
- package/scaffold/svelte-minimal/{RIZZO-README.md → README-RIZZO.md} +4 -4
- package/scaffold/vanilla/{RIZZO-README.md → README-RIZZO.md} +3 -3
- package/scaffold/vanilla/components/accordion.html +12 -0
- package/scaffold/vanilla/components/alert.html +12 -0
- package/scaffold/vanilla/components/avatar.html +12 -0
- package/scaffold/vanilla/components/badge.html +12 -0
- package/scaffold/vanilla/components/breadcrumb.html +12 -0
- package/scaffold/vanilla/components/button.html +12 -0
- package/scaffold/vanilla/components/cards.html +12 -0
- package/scaffold/vanilla/components/copy-to-clipboard.html +12 -0
- package/scaffold/vanilla/components/divider.html +12 -0
- package/scaffold/vanilla/components/dropdown.html +12 -0
- package/scaffold/vanilla/components/forms.html +12 -0
- package/scaffold/vanilla/components/icons.html +12 -0
- package/scaffold/vanilla/components/index.html +12 -0
- package/scaffold/vanilla/components/modal.html +12 -0
- package/scaffold/vanilla/components/navbar.html +12 -0
- package/scaffold/vanilla/components/pagination.html +12 -0
- package/scaffold/vanilla/components/progress-bar.html +12 -0
- package/scaffold/vanilla/components/search.html +12 -0
- package/scaffold/vanilla/components/settings.html +12 -0
- package/scaffold/vanilla/components/spinner.html +12 -0
- package/scaffold/vanilla/components/table.html +12 -0
- package/scaffold/vanilla/components/tabs.html +12 -0
- package/scaffold/vanilla/components/theme-switcher.html +12 -0
- package/scaffold/vanilla/components/toast.html +12 -0
- package/scaffold/vanilla/components/tooltip.html +12 -0
- package/scaffold/vanilla/index.html +12 -0
package/README.md
CHANGED
|
@@ -12,7 +12,7 @@ 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), then package manager. 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** (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`:
|
|
16
16
|
|
|
17
17
|
```bash
|
|
18
18
|
npm create svelte@latest my-app && cd my-app && npx rizzo-css add
|
|
@@ -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 RIZZO
|
|
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.
|
|
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.
|
|
59
|
+
<!-- unpkg (pin version: replace @latest with @0.0.24 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 RIZZO
|
|
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 README-RIZZO.md; every install includes LICENSE-RIZZO. 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
|
@@ -7,9 +7,9 @@ const readline = require('readline');
|
|
|
7
7
|
|
|
8
8
|
const RIZZO_CONFIG_FILE = 'rizzo-css.json';
|
|
9
9
|
/** Scaffold README filename; avoids overwriting an existing project README.md. */
|
|
10
|
-
const SCAFFOLD_README_FILENAME = 'RIZZO
|
|
10
|
+
const SCAFFOLD_README_FILENAME = 'README-RIZZO.md';
|
|
11
11
|
/** Scaffold license filename; avoids overwriting an existing project LICENSE. */
|
|
12
|
-
const SCAFFOLD_LICENSE_FILENAME = 'RIZZO
|
|
12
|
+
const SCAFFOLD_LICENSE_FILENAME = 'LICENSE-RIZZO';
|
|
13
13
|
|
|
14
14
|
const COMMANDS = ['init', 'add', 'theme', 'help'];
|
|
15
15
|
const FRAMEWORKS = ['vanilla', 'astro', 'svelte'];
|
|
@@ -24,14 +24,14 @@ const TEMPLATES = {
|
|
|
24
24
|
{ value: 'manual', label: 'Manual — index.html + CSS; pick components to add their pages + js/main.js' },
|
|
25
25
|
],
|
|
26
26
|
astro: [
|
|
27
|
-
{ value: 'full', label: 'Full — Astro app + all
|
|
28
|
-
{ value: 'minimal', label: 'Minimal — Astro app + recommended
|
|
29
|
-
{ value: 'manual', label: 'Manual — minimal base + pick
|
|
27
|
+
{ value: 'full', label: 'Full — Astro app + all components (with dependencies so everything works)' },
|
|
28
|
+
{ value: 'minimal', label: 'Minimal — Astro app + recommended set (includes any required dependencies)' },
|
|
29
|
+
{ value: 'manual', label: 'Manual — minimal base + pick components (list shows which add others)' },
|
|
30
30
|
],
|
|
31
31
|
svelte: [
|
|
32
|
-
{ value: 'full', label: 'Full — SvelteKit app + all
|
|
33
|
-
{ value: 'minimal', label: 'Minimal — SvelteKit app + recommended
|
|
34
|
-
{ value: 'manual', label: 'Manual — minimal base + pick
|
|
32
|
+
{ value: 'full', label: 'Full — SvelteKit app + all components (with dependencies so everything works)' },
|
|
33
|
+
{ value: 'minimal', label: 'Minimal — SvelteKit app + recommended set (includes any required dependencies)' },
|
|
34
|
+
{ value: 'manual', label: 'Manual — minimal base + pick components (list shows which add others)' },
|
|
35
35
|
],
|
|
36
36
|
};
|
|
37
37
|
|
|
@@ -112,6 +112,61 @@ const RECOMMENDED_COMPONENTS = [
|
|
|
112
112
|
'Button', 'Badge', 'Card', 'Modal', 'Tabs', 'ThemeSwitcher', 'FormGroup', 'Alert', 'Toast', 'Dropdown',
|
|
113
113
|
];
|
|
114
114
|
|
|
115
|
+
// Component dependencies per framework: when user selects a component, these are copied automatically so it works.
|
|
116
|
+
// Manual users can run: npx rizzo-css help components
|
|
117
|
+
const COMPONENT_DEPS = {
|
|
118
|
+
astro: { Settings: ['ThemeSwitcher'], Toast: ['Alert'] },
|
|
119
|
+
svelte: { Settings: ['ThemeSwitcher'], Toast: ['Alert'] },
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
function getComponentDeps(framework, componentName) {
|
|
123
|
+
const deps = COMPONENT_DEPS[framework];
|
|
124
|
+
return (deps && deps[componentName]) ? deps[componentName] : [];
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/** Returns a short label for the picker, e.g. " (adds ThemeSwitcher)" or "". */
|
|
128
|
+
function getComponentDependencyLabel(framework, componentName) {
|
|
129
|
+
const deps = getComponentDeps(framework, componentName);
|
|
130
|
+
if (deps.length === 0) return '';
|
|
131
|
+
return ' (adds ' + deps.join(', ') + ')';
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/** Expand a list of component names with all required dependencies. Used for full, minimal, and add so everything works. */
|
|
135
|
+
function expandWithDeps(framework, names) {
|
|
136
|
+
const depsMap = COMPONENT_DEPS[framework];
|
|
137
|
+
if (!depsMap) return [...names];
|
|
138
|
+
const out = new Set(names);
|
|
139
|
+
let added = true;
|
|
140
|
+
while (added) {
|
|
141
|
+
added = false;
|
|
142
|
+
for (const name of out) {
|
|
143
|
+
const req = depsMap[name];
|
|
144
|
+
if (req) for (const d of req) {
|
|
145
|
+
if (!out.has(d)) { out.add(d); added = true; }
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
return [...names].filter((n) => out.has(n)).concat([...out].filter((n) => !names.includes(n)));
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/** Log which components were added automatically because others require them. Call before copy when expanded.length > selected.length. */
|
|
153
|
+
function logAddedDeps(selected, expanded, framework) {
|
|
154
|
+
const added = expanded.filter((n) => !selected.includes(n));
|
|
155
|
+
if (added.length === 0) return;
|
|
156
|
+
const depsMap = COMPONENT_DEPS[framework];
|
|
157
|
+
if (!depsMap) return;
|
|
158
|
+
const byRequirement = [];
|
|
159
|
+
for (const name of added) {
|
|
160
|
+
for (const [parent, deps] of Object.entries(depsMap)) {
|
|
161
|
+
if (deps.includes(name) && selected.includes(parent)) {
|
|
162
|
+
byRequirement.push(name + ' (required by ' + parent + ')');
|
|
163
|
+
break;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
if (byRequirement.length) console.log('\n Also adding: ' + byRequirement.join('; '));
|
|
168
|
+
}
|
|
169
|
+
|
|
115
170
|
// Vanilla scaffold: component name (same as ASTRO_COMPONENTS) -> components/*.html slug. Navbar, Settings, Search, Icons are vanilla-only.
|
|
116
171
|
const VANILLA_COMPONENT_SLUGS = {
|
|
117
172
|
Button: 'button', Badge: 'badge', Card: 'cards', Divider: 'divider', Spinner: 'spinner', ProgressBar: 'progress-bar',
|
|
@@ -185,7 +240,30 @@ function copyRizzoCssAndFontsForAstro(projectDir, cssSource) {
|
|
|
185
240
|
}
|
|
186
241
|
}
|
|
187
242
|
|
|
188
|
-
/**
|
|
243
|
+
/** SvelteKit only: copy rizzo.min.css to static/css with font URLs rewritten to /assets/fonts/, and copy fonts to static/assets/fonts. */
|
|
244
|
+
function copyRizzoCssAndFontsForSvelte(projectDir, cssSource) {
|
|
245
|
+
const cssDir = join(projectDir, 'static', 'css');
|
|
246
|
+
const cssTarget = join(cssDir, 'rizzo.min.css');
|
|
247
|
+
const fontsDest = join(projectDir, 'static', 'assets', 'fonts');
|
|
248
|
+
mkdirSync(cssDir, { recursive: true });
|
|
249
|
+
mkdirSync(fontsDest, { recursive: true });
|
|
250
|
+
copyFileSync(cssSource, cssTarget);
|
|
251
|
+
let css = readFileSync(cssTarget, 'utf8');
|
|
252
|
+
css = css.replace(/url\(['"]?\.\/fonts\//g, "url('/assets/fonts/");
|
|
253
|
+
writeFileSync(cssTarget, css, 'utf8');
|
|
254
|
+
const fontsSrc = join(getPackageRoot(), 'dist', 'fonts');
|
|
255
|
+
if (existsSync(fontsSrc)) {
|
|
256
|
+
const entries = readdirSync(fontsSrc, { withFileTypes: true });
|
|
257
|
+
for (const e of entries) {
|
|
258
|
+
const srcPath = join(fontsSrc, e.name);
|
|
259
|
+
const destPath = join(fontsDest, e.name);
|
|
260
|
+
if (e.isDirectory()) copyDirRecursive(srcPath, destPath);
|
|
261
|
+
else copyFileSync(srcPath, destPath);
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
/** Copy the package LICENSE into the project dir as LICENSE-RIZZO so we do not overwrite an existing LICENSE. */
|
|
189
267
|
function copyPackageLicense(projectDir) {
|
|
190
268
|
const licensePath = join(getPackageRoot(), 'LICENSE');
|
|
191
269
|
if (existsSync(licensePath)) {
|
|
@@ -208,11 +286,17 @@ function readRizzoConfig(cwd) {
|
|
|
208
286
|
} catch (_) { return null; }
|
|
209
287
|
}
|
|
210
288
|
|
|
211
|
-
/** Write rizzo-css.json to cwd. config: { targetDir?, framework?, packageManager? }. */
|
|
289
|
+
/** Write rizzo-css.json to cwd. config: { targetDir?, framework?, packageManager? }. Preserves unknown keys from existing file. */
|
|
212
290
|
function writeRizzoConfig(cwd, config) {
|
|
213
291
|
if (!cwd || !existsSync(cwd)) return;
|
|
214
292
|
const configPath = join(cwd, RIZZO_CONFIG_FILE);
|
|
215
|
-
|
|
293
|
+
let obj = {};
|
|
294
|
+
if (existsSync(configPath)) {
|
|
295
|
+
try {
|
|
296
|
+
const raw = JSON.parse(readFileSync(configPath, 'utf8'));
|
|
297
|
+
if (raw && typeof raw === 'object') obj = { ...raw };
|
|
298
|
+
} catch (_) { /* ignore */ }
|
|
299
|
+
}
|
|
216
300
|
if (config.targetDir != null) obj.targetDir = config.targetDir;
|
|
217
301
|
if (config.framework != null) obj.framework = config.framework;
|
|
218
302
|
if (config.packageManager != null) obj.packageManager = config.packageManager;
|
|
@@ -366,9 +450,10 @@ function selectMenu(options, title) {
|
|
|
366
450
|
});
|
|
367
451
|
}
|
|
368
452
|
|
|
453
|
+
const HINT = ' \u2191\u2193 move \u00b7 Enter select \u00b7 1-9 pick';
|
|
369
454
|
return new Promise((resolve) => {
|
|
370
455
|
let index = 0;
|
|
371
|
-
const lineCount = (title ? 1 : 0) + items.length + 1
|
|
456
|
+
const lineCount = (title ? 1 : 0) + items.length + 2; // +1 blank +1 hint
|
|
372
457
|
|
|
373
458
|
const render = (first) => {
|
|
374
459
|
const lines = (title ? [title] : []).concat(
|
|
@@ -377,15 +462,25 @@ function selectMenu(options, title) {
|
|
|
377
462
|
const prefix = i === index ? C.cyan + '>' + C.reset + ' ' : ' ';
|
|
378
463
|
return prefix + circle + formatLabel(item);
|
|
379
464
|
})
|
|
380
|
-
);
|
|
465
|
+
).concat(['', HINT]);
|
|
381
466
|
if (!first) {
|
|
382
467
|
process.stdout.write('\u001b[' + lineCount + 'A');
|
|
383
468
|
}
|
|
384
469
|
process.stdout.write('\u001b[?25l');
|
|
385
|
-
process.stdout.write(lines.join('\n') + '\n
|
|
470
|
+
process.stdout.write(lines.join('\n') + '\n');
|
|
386
471
|
process.stdout.write('\u001b[?25h');
|
|
387
472
|
};
|
|
388
473
|
|
|
474
|
+
const selectByNumber = (num) => {
|
|
475
|
+
const n = num === 0 ? 10 : num; // 0 = 10th item
|
|
476
|
+
const idx = n >= 1 && n <= items.length ? n - 1 : index;
|
|
477
|
+
process.stdin.setRawMode(false);
|
|
478
|
+
process.stdin.removeListener('data', onData);
|
|
479
|
+
process.stdin.pause();
|
|
480
|
+
process.stdout.write('\n');
|
|
481
|
+
resolve(items[idx].value);
|
|
482
|
+
};
|
|
483
|
+
|
|
389
484
|
process.stdin.setRawMode(true);
|
|
390
485
|
process.stdin.resume();
|
|
391
486
|
process.stdin.setEncoding('utf8');
|
|
@@ -408,6 +503,16 @@ function selectMenu(options, title) {
|
|
|
408
503
|
resolve(items[index].value);
|
|
409
504
|
return;
|
|
410
505
|
}
|
|
506
|
+
if (ch >= '1' && ch <= '9') {
|
|
507
|
+
buf = '';
|
|
508
|
+
selectByNumber(parseInt(ch, 10));
|
|
509
|
+
return;
|
|
510
|
+
}
|
|
511
|
+
if (ch === '0' && items.length >= 10) {
|
|
512
|
+
buf = '';
|
|
513
|
+
selectByNumber(10);
|
|
514
|
+
return;
|
|
515
|
+
}
|
|
411
516
|
buf += ch;
|
|
412
517
|
const isUp = buf === '\u001b[A' || buf === '\u001bOA' || (buf.length >= 2 && buf.endsWith('A') && buf.startsWith('\u001b'));
|
|
413
518
|
const isDown = buf === '\u001b[B' || buf === '\u001bOB' || (buf.length >= 2 && buf.endsWith('B') && buf.startsWith('\u001b'));
|
|
@@ -499,7 +604,8 @@ function multiSelectMenu(options, title, initialSelected) {
|
|
|
499
604
|
if (initialSet.has(items[i].value)) selected.add(i);
|
|
500
605
|
}
|
|
501
606
|
}
|
|
502
|
-
const
|
|
607
|
+
const HINT = ' \u2191\u2193 move \u00b7 Space toggle \u00b7 a all \u00b7 n none \u00b7 Enter confirm';
|
|
608
|
+
const lineCount = (title ? 1 : 0) + items.length + 2; // +1 blank +1 hint
|
|
503
609
|
const realStart = withSentinels ? 2 : 0;
|
|
504
610
|
|
|
505
611
|
const finish = () => {
|
|
@@ -527,15 +633,24 @@ function multiSelectMenu(options, title, initialSelected) {
|
|
|
527
633
|
const prefix = i === index ? C.cyan + '>' + C.reset + ' ' : ' ';
|
|
528
634
|
return prefix + circle + formatLabel(item);
|
|
529
635
|
})
|
|
530
|
-
);
|
|
636
|
+
).concat(['', HINT]);
|
|
531
637
|
if (!first) {
|
|
532
638
|
process.stdout.write('\u001b[' + lineCount + 'A');
|
|
533
639
|
}
|
|
534
640
|
process.stdout.write('\u001b[?25l');
|
|
535
|
-
process.stdout.write(lines.join('\n') + '\n
|
|
641
|
+
process.stdout.write(lines.join('\n') + '\n');
|
|
536
642
|
process.stdout.write('\u001b[?25h');
|
|
537
643
|
};
|
|
538
644
|
|
|
645
|
+
const toggleByNumber = (num) => {
|
|
646
|
+
const n = num === 0 ? 10 : num;
|
|
647
|
+
const idx = n >= 1 && n <= items.length ? n - 1 : -1;
|
|
648
|
+
if (idx < realStart) return; // don't toggle "Select all" / "Select none"
|
|
649
|
+
if (selected.has(idx)) selected.delete(idx);
|
|
650
|
+
else selected.add(idx);
|
|
651
|
+
render(false);
|
|
652
|
+
};
|
|
653
|
+
|
|
539
654
|
process.stdin.setRawMode(true);
|
|
540
655
|
process.stdin.resume();
|
|
541
656
|
process.stdin.setEncoding('utf8');
|
|
@@ -576,6 +691,16 @@ function multiSelectMenu(options, title, initialSelected) {
|
|
|
576
691
|
render(false);
|
|
577
692
|
return;
|
|
578
693
|
}
|
|
694
|
+
if (ch >= '1' && ch <= '9') {
|
|
695
|
+
buf = '';
|
|
696
|
+
toggleByNumber(parseInt(ch, 10));
|
|
697
|
+
return;
|
|
698
|
+
}
|
|
699
|
+
if (ch === '0' && items.length >= 10) {
|
|
700
|
+
buf = '';
|
|
701
|
+
toggleByNumber(10);
|
|
702
|
+
return;
|
|
703
|
+
}
|
|
579
704
|
if (ch === 'a' || ch === 'A') {
|
|
580
705
|
buf = '';
|
|
581
706
|
for (let i = realStart; i < items.length; i++) selected.add(i);
|
|
@@ -611,6 +736,14 @@ function printHelp() {
|
|
|
611
736
|
console.log(`
|
|
612
737
|
rizzo-css CLI — Add Rizzo CSS to your project (Vanilla, Astro, Svelte)
|
|
613
738
|
|
|
739
|
+
Available commands: init, add, theme, help
|
|
740
|
+
|
|
741
|
+
Flags summary:
|
|
742
|
+
init --yes --framework <fw> --template <t> --package-manager <pm> --install --no-install
|
|
743
|
+
add --path <dir> --framework <fw> --package-manager <pm> --install-package --no-install
|
|
744
|
+
theme (no flags)
|
|
745
|
+
help (no flags)
|
|
746
|
+
|
|
614
747
|
Usage (use your package manager):
|
|
615
748
|
npx rizzo-css <command> [options]
|
|
616
749
|
pnpm dlx rizzo-css <command> [options]
|
|
@@ -642,6 +775,11 @@ Options (add):
|
|
|
642
775
|
Package managers:
|
|
643
776
|
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
777
|
|
|
778
|
+
Interactive prompts (when no --yes/flag provided):
|
|
779
|
+
Single-choice: ↑/↓ move, Enter select, 1-9 pick by number (0 = 10th).
|
|
780
|
+
Multi-choice: ↑/↓ move, Space toggle, a = all, n = none, Enter confirm, 1-9 toggle by number.
|
|
781
|
+
Ctrl+C to exit.
|
|
782
|
+
|
|
645
783
|
Config:
|
|
646
784
|
Optional rizzo-css.json in project root: { "targetDir", "framework", "packageManager" }.
|
|
647
785
|
Used by add and init when present. Detection: lockfiles and packageManager field in package.json.
|
|
@@ -670,10 +808,43 @@ Examples:
|
|
|
670
808
|
npx rizzo-css add --install-package
|
|
671
809
|
npx rizzo-css theme
|
|
672
810
|
|
|
811
|
+
Component dependencies (manual / add):
|
|
812
|
+
Some components require others to work. Picking them adds the required ones automatically.
|
|
813
|
+
Full list of available components and what relies on what: npx rizzo-css help components
|
|
814
|
+
|
|
673
815
|
Docs: https://rizzo-css.vercel.app
|
|
674
816
|
`);
|
|
675
817
|
}
|
|
676
818
|
|
|
819
|
+
function printHelpComponents() {
|
|
820
|
+
const list = ASTRO_COMPONENTS.map((name) => {
|
|
821
|
+
const deps = getComponentDeps('astro', name);
|
|
822
|
+
return deps.length ? name + ' (adds ' + deps.join(', ') + ')' : name;
|
|
823
|
+
});
|
|
824
|
+
const line1 = list.slice(0, 10).join(', ');
|
|
825
|
+
const line2 = list.slice(10, 20).join(', ');
|
|
826
|
+
const line3 = list.slice(20).join(', ');
|
|
827
|
+
console.log(`
|
|
828
|
+
Components — full list and what relies on what
|
|
829
|
+
|
|
830
|
+
Available to pick (Astro & Svelte; same list):
|
|
831
|
+
` + line1 + (line2 ? ',\n ' + line2 : '') + (line3 ? ',\n ' + line3 : '') + `
|
|
832
|
+
|
|
833
|
+
Dependencies (when you pick the component on the left, the right is added automatically):
|
|
834
|
+
Settings → ThemeSwitcher (and themes.ts)
|
|
835
|
+
Toast → Alert
|
|
836
|
+
|
|
837
|
+
ThemeSwitcher and ThemeIcon: when selected, themes.ts (and Svelte theme.ts) is copied so they work.
|
|
838
|
+
Icons: copied whenever you add any component.
|
|
839
|
+
|
|
840
|
+
Full = all components above; dependencies are included so everything works.
|
|
841
|
+
Minimal = recommended set; any component in that set that requires others gets them.
|
|
842
|
+
Manual = you pick; the picker shows e.g. "Settings (adds ThemeSwitcher)". Required deps are added when you confirm.
|
|
843
|
+
|
|
844
|
+
To see this again: npx rizzo-css help components
|
|
845
|
+
`);
|
|
846
|
+
}
|
|
847
|
+
|
|
677
848
|
function cmdTheme() {
|
|
678
849
|
process.stdout.write('\nDark themes (set data-theme on <html>):\n');
|
|
679
850
|
DARK_THEMES.forEach((t) => process.stdout.write(' ' + t + '\n'));
|
|
@@ -704,6 +875,11 @@ async function promptThemes() {
|
|
|
704
875
|
return { theme, defaultDark: DARK_THEMES.includes(defaultDark) ? defaultDark : DARK_THEMES[0], defaultLight: LIGHT_THEMES.includes(defaultLight) ? defaultLight : LIGHT_THEMES[0] };
|
|
705
876
|
}
|
|
706
877
|
|
|
878
|
+
function componentOptionLabel(framework, name) {
|
|
879
|
+
const suffix = getComponentDependencyLabel(framework, name);
|
|
880
|
+
return name + suffix;
|
|
881
|
+
}
|
|
882
|
+
|
|
707
883
|
/** 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
884
|
async function promptComponentChoice(componentList, framework, initialSelection) {
|
|
709
885
|
const recommended = RECOMMENDED_COMPONENTS.filter((c) => componentList.includes(c));
|
|
@@ -712,7 +888,7 @@ async function promptComponentChoice(componentList, framework, initialSelection)
|
|
|
712
888
|
[
|
|
713
889
|
{ value: SENTINEL_ALL, label: 'Select all components' },
|
|
714
890
|
{ value: SENTINEL_NONE, label: 'Select no components' },
|
|
715
|
-
...componentList.map((c) => ({ value: c, label: c })),
|
|
891
|
+
...componentList.map((c) => ({ value: c, label: componentOptionLabel(framework, c) })),
|
|
716
892
|
],
|
|
717
893
|
'? Components (minimal set pre-selected) — Space to toggle, Enter to confirm',
|
|
718
894
|
initialSelection
|
|
@@ -734,9 +910,9 @@ async function promptComponentChoice(componentList, framework, initialSelection)
|
|
|
734
910
|
[
|
|
735
911
|
{ value: SENTINEL_ALL, label: 'Select all components' },
|
|
736
912
|
{ value: SENTINEL_NONE, label: 'Select no components' },
|
|
737
|
-
...componentList.map((c) => ({ value: c, label: c })),
|
|
913
|
+
...componentList.map((c) => ({ value: c, label: componentOptionLabel(framework, c) })),
|
|
738
914
|
],
|
|
739
|
-
'? Components — Space to toggle, Enter to confirm'
|
|
915
|
+
'? Components — Space to toggle, Enter to confirm. Items like "Settings (adds ThemeSwitcher)" add those deps automatically. List: npx rizzo-css help components'
|
|
740
916
|
);
|
|
741
917
|
}
|
|
742
918
|
|
|
@@ -757,12 +933,12 @@ function detectFramework(cwd) {
|
|
|
757
933
|
/**
|
|
758
934
|
* Framework-specific paths for CSS and static assets. Use these so fonts, sounds, images
|
|
759
935
|
* go in the right place per framework (Astro: public/, SvelteKit: static/, Vanilla: project root).
|
|
760
|
-
* - targetDir: where rizzo.min.css is copied. Fonts:
|
|
761
|
-
* - assetsRoot: root for static assets (Astro: public;
|
|
936
|
+
* - targetDir: where rizzo.min.css is copied. Fonts: Astro public/assets/fonts, Svelte static/assets/fonts (CLI rewrites URLs); Vanilla targetDir/fonts.
|
|
937
|
+
* - assetsRoot: root for static assets (Astro: public; Svelte: static; Vanilla: '').
|
|
762
938
|
*/
|
|
763
939
|
function getFrameworkCssPaths(framework) {
|
|
764
940
|
if (framework === 'svelte') {
|
|
765
|
-
return { targetDir: 'static/css', linkHref: '/css/rizzo.min.css', fontsDir: 'static/
|
|
941
|
+
return { targetDir: 'static/css', linkHref: '/css/rizzo.min.css', fontsDir: 'static/assets/fonts', assetsRoot: 'static' };
|
|
766
942
|
}
|
|
767
943
|
if (framework === 'astro') {
|
|
768
944
|
return { targetDir: 'public/css', linkHref: '/css/rizzo.min.css', fontsDir: 'public/assets/fonts', assetsRoot: 'public' };
|
|
@@ -990,7 +1166,7 @@ function copySvelteComponents(projectDir, selectedNames) {
|
|
|
990
1166
|
if (existsSync(iconsSrc) && (toCopy.length > 0 || copyIconsOnly)) {
|
|
991
1167
|
copyDirRecursive(iconsSrc, join(targetDir, 'icons'));
|
|
992
1168
|
}
|
|
993
|
-
if (toCopy.includes('ThemeSwitcher')) {
|
|
1169
|
+
if (toCopy.includes('ThemeSwitcher') || toCopy.includes('ThemeIcon')) {
|
|
994
1170
|
const themesSrc = join(scaffoldDir, 'themes.ts');
|
|
995
1171
|
const themeSrc = join(scaffoldDir, 'theme.ts');
|
|
996
1172
|
if (existsSync(themesSrc)) copyFileSync(themesSrc, join(targetDir, 'themes.ts'));
|
|
@@ -1035,7 +1211,7 @@ function copyAstroComponents(projectDir, selectedNames) {
|
|
|
1035
1211
|
if (existsSync(iconsSrc) && (toCopy.length > 0 || copyIconsOnly)) {
|
|
1036
1212
|
copyDirRecursive(iconsSrc, join(targetDir, 'icons'));
|
|
1037
1213
|
}
|
|
1038
|
-
if (toCopy.includes('ThemeSwitcher')) {
|
|
1214
|
+
if (toCopy.includes('ThemeSwitcher') || toCopy.includes('ThemeIcon')) {
|
|
1039
1215
|
const themesSrc = join(scaffoldDir, 'themes.ts');
|
|
1040
1216
|
if (existsSync(themesSrc)) {
|
|
1041
1217
|
copyFileSync(themesSrc, join(targetDir, 'themes.ts'));
|
|
@@ -1127,6 +1303,9 @@ async function runAddToExisting(frameworkOverride, options) {
|
|
|
1127
1303
|
if (framework === 'astro') {
|
|
1128
1304
|
copyRizzoCssAndFontsForAstro(cwd, cssSource);
|
|
1129
1305
|
cssTarget = join(cwd, 'public', 'css', 'rizzo.min.css');
|
|
1306
|
+
} else if (framework === 'svelte') {
|
|
1307
|
+
copyRizzoCssAndFontsForSvelte(cwd, cssSource);
|
|
1308
|
+
cssTarget = join(cwd, 'static', 'css', 'rizzo.min.css');
|
|
1130
1309
|
} else {
|
|
1131
1310
|
const targetDir = join(cwd, targetDirRaw);
|
|
1132
1311
|
cssTarget = join(targetDir, 'rizzo.min.css');
|
|
@@ -1137,16 +1316,20 @@ async function runAddToExisting(frameworkOverride, options) {
|
|
|
1137
1316
|
|
|
1138
1317
|
copyRizzoIcons(cwd, framework);
|
|
1139
1318
|
if (framework === 'svelte' && selectedComponents.length > 0) {
|
|
1140
|
-
|
|
1319
|
+
const expanded = expandWithDeps('svelte', selectedComponents);
|
|
1320
|
+
logAddedDeps(selectedComponents, expanded, 'svelte');
|
|
1321
|
+
copySvelteComponents(cwd, expanded);
|
|
1141
1322
|
} else if (framework === 'astro' && selectedComponents.length > 0) {
|
|
1142
|
-
|
|
1323
|
+
const expanded = expandWithDeps('astro', selectedComponents);
|
|
1324
|
+
logAddedDeps(selectedComponents, expanded, 'astro');
|
|
1325
|
+
copyAstroComponents(cwd, expanded);
|
|
1143
1326
|
} else if (framework === 'vanilla' && selectedComponents.length > 0) {
|
|
1144
1327
|
const linkHrefForVanilla = (options && options.targetDir) ? getLinkHrefForTargetDir(framework, options.targetDir) : paths.linkHref;
|
|
1145
1328
|
const vanillaRepl = { '{{LINK_HREF}}': linkHrefForVanilla, '{{DATA_THEME}}': theme };
|
|
1146
1329
|
copyVanillaComponents(cwd, selectedComponents, vanillaRepl);
|
|
1147
1330
|
}
|
|
1148
1331
|
|
|
1149
|
-
const linkHref = (options && options.targetDir) ? getLinkHrefForTargetDir(framework, options.targetDir) : paths.linkHref;
|
|
1332
|
+
const linkHref = (framework === 'astro' || framework === 'svelte') ? paths.linkHref : ((options && options.targetDir) ? getLinkHrefForTargetDir(framework, options.targetDir) : paths.linkHref);
|
|
1150
1333
|
const pmFromOption = options && options.packageManager && VALID_PACKAGE_MANAGERS.includes(options.packageManager);
|
|
1151
1334
|
const pm = pmFromOption
|
|
1152
1335
|
? getPackageManagerCommands({ agent: options.packageManager, command: options.packageManager })
|
|
@@ -1154,7 +1337,8 @@ async function runAddToExisting(frameworkOverride, options) {
|
|
|
1154
1337
|
? getPackageManagerCommands({ agent: config.packageManager, command: config.packageManager })
|
|
1155
1338
|
: resolvePackageManager(cwd);
|
|
1156
1339
|
const cliExample = pm.dlx('rizzo-css theme');
|
|
1157
|
-
|
|
1340
|
+
const configTargetDir = framework === 'astro' ? 'public/css' : framework === 'svelte' ? 'static/css' : targetDirRaw;
|
|
1341
|
+
writeRizzoConfig(cwd, { targetDir: configTargetDir, framework, packageManager: pm.agent });
|
|
1158
1342
|
console.log('\n✓ Rizzo CSS added to your existing project');
|
|
1159
1343
|
console.log(' - ' + cssTarget);
|
|
1160
1344
|
console.log(' - Wrote ' + RIZZO_CONFIG_FILE);
|
|
@@ -1316,6 +1500,13 @@ async function cmdInit(argv) {
|
|
|
1316
1500
|
const useVanillaFull = selectedTemplate === 'full' && framework === 'vanilla' && existsSync(getScaffoldVanillaIndex());
|
|
1317
1501
|
const useVanillaMinimal = selectedTemplate === 'minimal' && framework === 'vanilla';
|
|
1318
1502
|
|
|
1503
|
+
// Full and minimal get all required dependencies so everything works; manual gets deps when user picks (see prompt labels).
|
|
1504
|
+
let componentsToCopy = selectedComponents;
|
|
1505
|
+
if ((framework === 'astro' || framework === 'svelte') && selectedComponents.length > 0) {
|
|
1506
|
+
componentsToCopy = expandWithDeps(framework, selectedComponents);
|
|
1507
|
+
logAddedDeps(selectedComponents, componentsToCopy, framework);
|
|
1508
|
+
}
|
|
1509
|
+
|
|
1319
1510
|
let cssTarget;
|
|
1320
1511
|
let indexPath;
|
|
1321
1512
|
|
|
@@ -1343,9 +1534,9 @@ async function cmdInit(argv) {
|
|
|
1343
1534
|
console.warn('\nWarning: rizzo.min.css is very small. From repo root run: pnpm build:css');
|
|
1344
1535
|
}
|
|
1345
1536
|
copyPackageLicense(projectDir);
|
|
1346
|
-
if (
|
|
1537
|
+
if (componentsToCopy.length > 0) {
|
|
1347
1538
|
copyRizzoIcons(projectDir, 'astro');
|
|
1348
|
-
copyAstroComponents(projectDir,
|
|
1539
|
+
copyAstroComponents(projectDir, componentsToCopy);
|
|
1349
1540
|
}
|
|
1350
1541
|
} else if (useAstroBase) {
|
|
1351
1542
|
mkdirSync(projectDir, { recursive: true });
|
|
@@ -1356,39 +1547,35 @@ async function cmdInit(argv) {
|
|
|
1356
1547
|
console.warn('\nWarning: rizzo.min.css is very small. From repo root run: pnpm build:css');
|
|
1357
1548
|
}
|
|
1358
1549
|
copyPackageLicense(projectDir);
|
|
1359
|
-
if (
|
|
1550
|
+
if (componentsToCopy.length > 0) {
|
|
1360
1551
|
copyRizzoIcons(projectDir, 'astro');
|
|
1361
|
-
copyAstroComponents(projectDir,
|
|
1552
|
+
copyAstroComponents(projectDir, componentsToCopy);
|
|
1362
1553
|
}
|
|
1363
1554
|
} else if (useHandpickSvelte) {
|
|
1364
1555
|
mkdirSync(projectDir, { recursive: true });
|
|
1365
1556
|
copyDirRecursiveWithReplacements(svelteMinimalDir, projectDir, replacements);
|
|
1366
|
-
|
|
1557
|
+
copyRizzoCssAndFontsForSvelte(projectDir, cssSource);
|
|
1367
1558
|
cssTarget = join(projectDir, 'static', 'css', 'rizzo.min.css');
|
|
1368
|
-
copyFileSync(cssSource, cssTarget);
|
|
1369
|
-
copyRizzoFonts(dirname(cssTarget));
|
|
1370
1559
|
if (statSync(cssTarget).size < 5000) {
|
|
1371
1560
|
console.warn('\nWarning: rizzo.min.css is very small. From repo root run: pnpm build:css');
|
|
1372
1561
|
}
|
|
1373
1562
|
copyPackageLicense(projectDir);
|
|
1374
|
-
if (
|
|
1563
|
+
if (componentsToCopy.length > 0) {
|
|
1375
1564
|
copyRizzoIcons(projectDir, 'svelte');
|
|
1376
|
-
copySvelteComponents(projectDir,
|
|
1565
|
+
copySvelteComponents(projectDir, componentsToCopy);
|
|
1377
1566
|
}
|
|
1378
1567
|
} else if (useSvelteBase) {
|
|
1379
1568
|
mkdirSync(projectDir, { recursive: true });
|
|
1380
1569
|
copyDirRecursiveWithReplacements(svelteMinimalDir, projectDir, replacements);
|
|
1381
|
-
|
|
1570
|
+
copyRizzoCssAndFontsForSvelte(projectDir, cssSource);
|
|
1382
1571
|
cssTarget = join(projectDir, 'static', 'css', 'rizzo.min.css');
|
|
1383
|
-
copyFileSync(cssSource, cssTarget);
|
|
1384
|
-
copyRizzoFonts(dirname(cssTarget));
|
|
1385
1572
|
if (statSync(cssTarget).size < 5000) {
|
|
1386
1573
|
console.warn('\nWarning: rizzo.min.css is very small. From repo root run: pnpm build:css');
|
|
1387
1574
|
}
|
|
1388
1575
|
copyPackageLicense(projectDir);
|
|
1389
|
-
if (
|
|
1576
|
+
if (componentsToCopy.length > 0) {
|
|
1390
1577
|
copyRizzoIcons(projectDir, 'svelte');
|
|
1391
|
-
copySvelteComponents(projectDir,
|
|
1578
|
+
copySvelteComponents(projectDir, componentsToCopy);
|
|
1392
1579
|
}
|
|
1393
1580
|
} else if (useVanillaFull) {
|
|
1394
1581
|
const cssDir = join(projectDir, pathsForScaffold.targetDir);
|
|
@@ -1449,11 +1636,16 @@ async function cmdInit(argv) {
|
|
|
1449
1636
|
writeFileSync(join(projectDir, SCAFFOLD_README_FILENAME), VANILLA_MINIMAL_README, 'utf8');
|
|
1450
1637
|
copyPackageLicense(projectDir);
|
|
1451
1638
|
} else {
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1639
|
+
if (framework === 'svelte') {
|
|
1640
|
+
copyRizzoCssAndFontsForSvelte(projectDir, cssSource);
|
|
1641
|
+
cssTarget = join(projectDir, 'static', 'css', 'rizzo.min.css');
|
|
1642
|
+
} else {
|
|
1643
|
+
const cssDir = join(projectDir, pathsForScaffold.targetDir);
|
|
1644
|
+
cssTarget = join(cssDir, 'rizzo.min.css');
|
|
1645
|
+
mkdirSync(cssDir, { recursive: true });
|
|
1646
|
+
copyFileSync(cssSource, cssTarget);
|
|
1647
|
+
copyRizzoFonts(dirname(cssTarget));
|
|
1648
|
+
}
|
|
1457
1649
|
if (statSync(cssTarget).size < 5000) {
|
|
1458
1650
|
console.warn('\nWarning: rizzo.min.css is very small. From repo root run: pnpm build:css');
|
|
1459
1651
|
}
|
|
@@ -1553,6 +1745,10 @@ function main() {
|
|
|
1553
1745
|
const command = (argv[0] || 'help').toLowerCase().replace(/^--?/, '');
|
|
1554
1746
|
|
|
1555
1747
|
if (command === 'help' || command === 'h' || !COMMANDS.includes(command)) {
|
|
1748
|
+
if (argv[1] === 'components') {
|
|
1749
|
+
printHelpComponents();
|
|
1750
|
+
return;
|
|
1751
|
+
}
|
|
1556
1752
|
if (argv[0] && !COMMANDS.includes(command) && command !== 'h') {
|
|
1557
1753
|
console.error('Unknown command: ' + argv[0] + '\n');
|
|
1558
1754
|
}
|
package/package.json
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
import Cat from './icons/Cat.astro';
|
|
3
|
+
import Gear from './icons/Gear.astro';
|
|
3
4
|
interface Props { siteName?: string; logo?: string; }
|
|
4
5
|
const { siteName = 'Site', logo } = Astro.props;
|
|
5
6
|
---
|
|
@@ -15,6 +16,12 @@ const { siteName = 'Site', logo } = Astro.props;
|
|
|
15
16
|
{siteName}
|
|
16
17
|
</a>
|
|
17
18
|
</div>
|
|
19
|
+
<div class="navbar__actions-desktop">
|
|
20
|
+
<button type="button" class="navbar__settings-btn" aria-label="Open settings" onclick="window.openSettings && window.openSettings()">
|
|
21
|
+
<Gear class="navbar__settings-icon" width={20} height={20} />
|
|
22
|
+
<span class="navbar__settings-label">Settings</span>
|
|
23
|
+
</button>
|
|
24
|
+
</div>
|
|
18
25
|
<button type="button" class="navbar__toggle" aria-label="Toggle menu" aria-expanded="false">
|
|
19
26
|
<span class="navbar__toggle-icon" aria-hidden="true"><span></span><span></span><span></span></span>
|
|
20
27
|
</button>
|