@birdapi/velinstyle 0.7.0 → 0.8.0
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.de.md +26 -4
- package/README.md +26 -4
- package/cli/blueprint.js +8 -0
- package/cli/blueprints/bottom-nav-mobile.html +17 -0
- package/cli/blueprints/cookie-consent.html +9 -0
- package/cli/blueprints/empty-state.html +5 -0
- package/cli/blueprints/filter-bar.html +15 -0
- package/cli/blueprints/notification-center.html +13 -0
- package/cli/blueprints/onboarding.html +23 -0
- package/cli/blueprints/pricing-table.html +20 -0
- package/cli/blueprints/settings-panel.html +20 -0
- package/cli/index.js +116 -1
- package/cli/layout-audit.js +325 -0
- package/cli/scaffold-recipes.json +70 -0
- package/cli/scaffold.js +155 -0
- package/cli/scanner.js +68 -0
- package/components/index.js +19 -0
- package/components/sanitize.js +29 -3
- package/components/shadow-a11y-styles.js +18 -0
- package/components/velin-announcer.js +35 -0
- package/components/velin-bottom-nav.js +89 -0
- package/components/velin-combobox.js +149 -0
- package/components/velin-command.js +127 -0
- package/components/velin-counter.js +152 -0
- package/components/velin-flip.js +220 -0
- package/components/velin-icon.js +43 -9
- package/components/velin-live-dot.js +85 -0
- package/components/velin-menubar.js +83 -0
- package/components/velin-rating.js +91 -0
- package/components/velin-reveal.js +80 -0
- package/components/velin-segmented-control.js +108 -0
- package/components/velin-sheet.js +107 -0
- package/components/velin-sparkline.js +207 -0
- package/components/velin-theme-toggle.js +277 -60
- package/dist/velinstyle-components.iife.js +1629 -69
- package/dist/velinstyle-components.js +1649 -69
- package/dist/velinstyle-components.min.js +424 -80
- package/dist/velinstyle.css +472 -3
- package/dist/velinstyle.min.css +1 -1
- package/package.json +3 -2
- package/src/a11y/security.css +18 -0
- package/src/base/reset.css +12 -1
- package/src/components/nav.css +152 -151
- package/src/tokens/motion.css +7 -0
- package/src/utilities/animation.css +97 -1
- package/src/utilities/chart-animation.css +101 -0
- package/src/utilities/filter-effects.css +103 -0
- package/src/utilities/safe-area.css +39 -0
- package/src/velinstyle.css +3 -0
package/README.de.md
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
<br>
|
|
9
9
|
|
|
10
10
|
[](LICENSE)
|
|
11
|
-
[](CHANGELOG.md)
|
|
12
12
|
[](docs/a11y.html)
|
|
13
13
|
[]()
|
|
14
14
|
[]()
|
|
@@ -73,8 +73,8 @@ Unter Zeitdruck landen **Barrierefreiheit** und **konsistentes Theming** oft ers
|
|
|
73
73
|
<tr><td align="center">🎨</td><td><strong>OKLCH + 13 Theme-Presets</strong></td><td>Perzeptuell gleichmässige Farben; Dark Mode per Token-Swap</td></tr>
|
|
74
74
|
<tr><td align="center">📦</td><td><strong>~46 KB CSS + ~66 KB JS (min)</strong></td><td>Schlank im Vergleich zu vielen All-in-One-Stacks</td></tr>
|
|
75
75
|
<tr><td align="center">📐</td><td><strong>Container Queries + Utilities</strong></td><td>Bausteine passen sich <em>ihrem</em> Container an, nicht nur dem Viewport</td></tr>
|
|
76
|
-
<tr><td align="center">🧩</td><td><strong>25 CSS-Module ·
|
|
77
|
-
<tr><td align="center">🛠️</td><td><strong>Optionale CLI</strong></td><td><code>init</code>, <code>build</code>, <code>icons</code>, <code>scan</code>, <code>prefix</code>, <code>blueprint</code>, <code>tokens build</code></td></tr>
|
|
76
|
+
<tr><td align="center">🧩</td><td><strong>25 CSS-Module · 29 Web Components</strong></td><td>Modals, Tabs, Drawer, Toasts, Icons—APIs in <a href="docs/css-components.html">CSS</a> & <a href="docs/components.html">WC-Docs</a></td></tr>
|
|
77
|
+
<tr><td align="center">🛠️</td><td><strong>Optionale CLI</strong></td><td><code>init</code>, <code>build</code>, <code>icons</code>, <code>scan</code>, <code>prefix</code>, <code>blueprint</code>, <code>scaffold</code>, <code>layout</code>, <code>tokens build</code></td></tr>
|
|
78
78
|
<tr><td align="center">🌍</td><td><strong>RTL-ready</strong></td><td>Logical Properties und layout-orientierte Defaults · <a href="samples/rtl.html">RTL-Beispiel</a></td></tr>
|
|
79
79
|
</tbody>
|
|
80
80
|
</table>
|
|
@@ -225,7 +225,29 @@ Alle Befehle: `npx velinstyle <befehl>` · `npx velinstyle --help`
|
|
|
225
225
|
</details>
|
|
226
226
|
|
|
227
227
|
<details>
|
|
228
|
-
<summary><strong>
|
|
228
|
+
<summary><strong>scaffold</strong> — Prompt → HTML (0.8.0)</summary>
|
|
229
|
+
|
|
230
|
+
- **`npx velinstyle scaffold list-intents`**
|
|
231
|
+
- **`npx velinstyle scaffold "Navbar mit Suche" -o nav.html`**
|
|
232
|
+
- **`npx velinstyle scaffold "…" --json`** — für Agenten/CI
|
|
233
|
+
|
|
234
|
+
Siehe [docs/guides/prompt-scaffolding.html](docs/guides/prompt-scaffolding.html).
|
|
235
|
+
|
|
236
|
+
</details>
|
|
237
|
+
|
|
238
|
+
<details>
|
|
239
|
+
<summary><strong>layout</strong> — Responsive-Audit (0.8.0)</summary>
|
|
240
|
+
|
|
241
|
+
- **`npx velinstyle layout audit [pfad]`**
|
|
242
|
+
- **`npx velinstyle layout suggest [pfad]`**
|
|
243
|
+
- **`npx velinstyle layout fix [pfad] --write`**
|
|
244
|
+
|
|
245
|
+
Siehe [docs/guides/responsive-layout.html](docs/guides/responsive-layout.html).
|
|
246
|
+
|
|
247
|
+
</details>
|
|
248
|
+
|
|
249
|
+
<details>
|
|
250
|
+
<summary><strong>blueprint</strong> — 22 HTML-Snippets</summary>
|
|
229
251
|
|
|
230
252
|
- **`npx velinstyle blueprint list`**
|
|
231
253
|
- **`npx velinstyle blueprint <name> -o datei.html`**
|
package/README.md
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
<br>
|
|
9
9
|
|
|
10
10
|
[](LICENSE)
|
|
11
|
-
[](CHANGELOG.md)
|
|
12
12
|
[](docs/a11y.html)
|
|
13
13
|
[]()
|
|
14
14
|
[]()
|
|
@@ -73,8 +73,8 @@ Teams ship UI under pressure. **Accessibility** and **consistent theming** are o
|
|
|
73
73
|
<tr><td align="center">🎨</td><td><strong>OKLCH + 13 theme presets</strong></td><td>Perceptually uniform colors; dark mode via token swap</td></tr>
|
|
74
74
|
<tr><td align="center">📦</td><td><strong>~46 KB CSS + ~66 KB JS (min)</strong></td><td>Lean defaults vs. heavier all-in-one stacks</td></tr>
|
|
75
75
|
<tr><td align="center">📐</td><td><strong>Container Queries + utilities</strong></td><td>Components adapt to <em>their</em> container, not only the viewport</td></tr>
|
|
76
|
-
<tr><td align="center">🧩</td><td><strong>25 CSS modules ·
|
|
77
|
-
<tr><td align="center">🛠️</td><td><strong>Optional CLI</strong></td><td><code>init</code>, <code>build</code>, <code>icons</code>, <code>scan</code>, <code>prefix</code>, <code>blueprint</code>, <code>tokens build</code></td></tr>
|
|
76
|
+
<tr><td align="center">🧩</td><td><strong>25 CSS modules · 29 Web Components</strong></td><td>Modals, tabs, drawers, toasts, icons—documented APIs in <a href="docs/css-components.html">CSS</a> & <a href="docs/components.html">WC docs</a></td></tr>
|
|
77
|
+
<tr><td align="center">🛠️</td><td><strong>Optional CLI</strong></td><td><code>init</code>, <code>build</code>, <code>icons</code>, <code>scan</code>, <code>prefix</code>, <code>blueprint</code>, <code>scaffold</code>, <code>layout</code>, <code>tokens build</code></td></tr>
|
|
78
78
|
<tr><td align="center">🌍</td><td><strong>RTL-ready</strong></td><td>Logical properties and layout-minded defaults · <a href="samples/rtl.html">RTL sample</a></td></tr>
|
|
79
79
|
</tbody>
|
|
80
80
|
</table>
|
|
@@ -225,7 +225,29 @@ All commands: `npx velinstyle <command>` · `npx velinstyle --help`
|
|
|
225
225
|
</details>
|
|
226
226
|
|
|
227
227
|
<details>
|
|
228
|
-
<summary><strong>
|
|
228
|
+
<summary><strong>scaffold</strong> — prompt → HTML (0.8.0)</summary>
|
|
229
|
+
|
|
230
|
+
- **`npx velinstyle scaffold list-intents`**
|
|
231
|
+
- **`npx velinstyle scaffold "Navbar with search" -o nav.html`**
|
|
232
|
+
- **`npx velinstyle scaffold "…" --json`** — for agents/CI
|
|
233
|
+
|
|
234
|
+
See [docs/guides/prompt-scaffolding.html](docs/guides/prompt-scaffolding.html).
|
|
235
|
+
|
|
236
|
+
</details>
|
|
237
|
+
|
|
238
|
+
<details>
|
|
239
|
+
<summary><strong>layout</strong> — responsive audit (0.8.0)</summary>
|
|
240
|
+
|
|
241
|
+
- **`npx velinstyle layout audit [path]`**
|
|
242
|
+
- **`npx velinstyle layout suggest [path]`**
|
|
243
|
+
- **`npx velinstyle layout fix [path] --write`**
|
|
244
|
+
|
|
245
|
+
See [docs/guides/responsive-layout.html](docs/guides/responsive-layout.html).
|
|
246
|
+
|
|
247
|
+
</details>
|
|
248
|
+
|
|
249
|
+
<details>
|
|
250
|
+
<summary><strong>blueprint</strong> — 22 HTML snippets</summary>
|
|
229
251
|
|
|
230
252
|
- **`npx velinstyle blueprint list`**
|
|
231
253
|
- **`npx velinstyle blueprint <name> -o snippet.html`**
|
package/cli/blueprint.js
CHANGED
|
@@ -18,6 +18,14 @@ const BLUEPRINTS = {
|
|
|
18
18
|
'search-field': 'search-field.html',
|
|
19
19
|
'sidebar-layout': 'sidebar-layout.html',
|
|
20
20
|
'table-responsive': 'table-responsive.html',
|
|
21
|
+
'bottom-nav-mobile': 'bottom-nav-mobile.html',
|
|
22
|
+
'empty-state': 'empty-state.html',
|
|
23
|
+
'cookie-consent': 'cookie-consent.html',
|
|
24
|
+
'filter-bar': 'filter-bar.html',
|
|
25
|
+
'notification-center': 'notification-center.html',
|
|
26
|
+
'settings-panel': 'settings-panel.html',
|
|
27
|
+
onboarding: 'onboarding.html',
|
|
28
|
+
'pricing-table': 'pricing-table.html',
|
|
21
29
|
};
|
|
22
30
|
|
|
23
31
|
export function listBlueprints() {
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
<nav class="velin-pb-safe" aria-label="Primary">
|
|
2
|
+
<velin-bottom-nav current="home">
|
|
3
|
+
<a href="#home" data-nav="home" current>Home</a>
|
|
4
|
+
<a href="#search" data-nav="search">Search</a>
|
|
5
|
+
<a href="#profile" data-nav="profile">Profile</a>
|
|
6
|
+
</velin-bottom-nav>
|
|
7
|
+
</nav>
|
|
8
|
+
<script type="module">
|
|
9
|
+
import '../../dist/velinstyle-components.min.js';
|
|
10
|
+
const nav = document.querySelector('velin-bottom-nav');
|
|
11
|
+
nav?.querySelectorAll('a').forEach((link) => {
|
|
12
|
+
link.addEventListener('click', (e) => {
|
|
13
|
+
e.preventDefault();
|
|
14
|
+
nav.setAttribute('current', link.dataset.nav || '');
|
|
15
|
+
});
|
|
16
|
+
});
|
|
17
|
+
</script>
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
<aside class="velin-p-4 velin-border velin-rounded-lg velin-pb-safe" role="region" aria-label="Cookie consent">
|
|
2
|
+
<div class="velin-user-content">
|
|
3
|
+
<p class="velin-mbe-3">We use essential cookies only. No third-party trackers in this demo.</p>
|
|
4
|
+
</div>
|
|
5
|
+
<div class="velin-flex velin-gap-3">
|
|
6
|
+
<button type="button" class="velin-btn velin-btn--primary">Accept</button>
|
|
7
|
+
<button type="button" class="velin-btn velin-btn--outline">Decline</button>
|
|
8
|
+
</div>
|
|
9
|
+
</aside>
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
<section class="velin-p-8 velin-text-center" aria-labelledby="empty-title">
|
|
2
|
+
<h2 id="empty-title" class="velin-text-xl velin-font-bold velin-mbe-2">No items yet</h2>
|
|
3
|
+
<p class="velin-text-muted velin-mbe-4">Create your first entry to see it listed here.</p>
|
|
4
|
+
<button type="button" class="velin-btn velin-btn--primary">Create item</button>
|
|
5
|
+
</section>
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
<form class="velin-flex velin-flex-wrap velin-gap-3 velin-p-4 velin-border-b" role="search" aria-label="Filter list">
|
|
2
|
+
<label class="velin-flex velin-flex-col velin-gap-1">
|
|
3
|
+
<span class="velin-text-sm">Query</span>
|
|
4
|
+
<input type="search" class="velin-input" name="q" placeholder="Search…" />
|
|
5
|
+
</label>
|
|
6
|
+
<label class="velin-flex velin-flex-col velin-gap-1">
|
|
7
|
+
<span class="velin-text-sm">Status</span>
|
|
8
|
+
<select class="velin-select" name="status">
|
|
9
|
+
<option value="">All</option>
|
|
10
|
+
<option value="open">Open</option>
|
|
11
|
+
<option value="done">Done</option>
|
|
12
|
+
</select>
|
|
13
|
+
</label>
|
|
14
|
+
<button type="submit" class="velin-btn velin-btn--primary velin-self-end">Apply</button>
|
|
15
|
+
</form>
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
<section class="velin-p-4" aria-labelledby="notif-title">
|
|
2
|
+
<h2 id="notif-title" class="velin-text-lg velin-font-bold velin-mbe-4">Notifications</h2>
|
|
3
|
+
<ul class="velin-flex velin-flex-col velin-gap-3" role="list">
|
|
4
|
+
<li class="velin-p-3 velin-border velin-rounded-lg">
|
|
5
|
+
<p class="velin-font-medium">Backup complete</p>
|
|
6
|
+
<p class="velin-text-sm velin-text-muted">2 minutes ago</p>
|
|
7
|
+
</li>
|
|
8
|
+
<li class="velin-p-3 velin-border velin-rounded-lg">
|
|
9
|
+
<p class="velin-font-medium">New comment</p>
|
|
10
|
+
<p class="velin-text-sm velin-text-muted">1 hour ago</p>
|
|
11
|
+
</li>
|
|
12
|
+
</ul>
|
|
13
|
+
</section>
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
<velin-stepper-wc id="onboard" labels="Welcome,Profile,Done" active="0">
|
|
2
|
+
<section class="velin-p-6">
|
|
3
|
+
<h2 class="velin-text-xl velin-mbe-2">Welcome</h2>
|
|
4
|
+
<p class="velin-mbe-4">Set up your workspace in a few steps.</p>
|
|
5
|
+
<button type="button" class="velin-btn velin-btn--primary" data-next>Continue</button>
|
|
6
|
+
</section>
|
|
7
|
+
<section class="velin-p-6">
|
|
8
|
+
<h2 class="velin-text-xl velin-mbe-2">Profile</h2>
|
|
9
|
+
<input type="text" class="velin-input velin-mbe-4" placeholder="Your name" aria-label="Name" />
|
|
10
|
+
<button type="button" class="velin-btn velin-btn--primary" data-next>Continue</button>
|
|
11
|
+
</section>
|
|
12
|
+
<section class="velin-p-6">
|
|
13
|
+
<h2 class="velin-text-xl velin-mbe-2">Done</h2>
|
|
14
|
+
<p>You are ready to go.</p>
|
|
15
|
+
</section>
|
|
16
|
+
</velin-stepper-wc>
|
|
17
|
+
<script type="module">
|
|
18
|
+
import '../../dist/velinstyle-components.min.js';
|
|
19
|
+
const stepper = document.getElementById('onboard');
|
|
20
|
+
document.querySelectorAll('[data-next]').forEach((btn) => {
|
|
21
|
+
btn.addEventListener('click', () => stepper?.next());
|
|
22
|
+
});
|
|
23
|
+
</script>
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
<div class="velin-grid velin-gap-4" style="grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));">
|
|
2
|
+
<article class="velin-p-6 velin-border velin-rounded-lg velin-text-center">
|
|
3
|
+
<h3 class="velin-text-lg velin-font-bold">Starter</h3>
|
|
4
|
+
<p class="velin-text-3xl velin-font-bold velin-mbs-2 velin-mbe-4">$0</p>
|
|
5
|
+
<ul class="velin-text-sm velin-mbe-4" role="list">
|
|
6
|
+
<li>1 project</li>
|
|
7
|
+
<li>Community support</li>
|
|
8
|
+
</ul>
|
|
9
|
+
<button type="button" class="velin-btn velin-btn--outline velin-w-full">Choose</button>
|
|
10
|
+
</article>
|
|
11
|
+
<article class="velin-p-6 velin-border velin-rounded-lg velin-text-center velin-border-primary">
|
|
12
|
+
<h3 class="velin-text-lg velin-font-bold">Pro</h3>
|
|
13
|
+
<p class="velin-text-3xl velin-font-bold velin-mbs-2 velin-mbe-4">$12</p>
|
|
14
|
+
<ul class="velin-text-sm velin-mbe-4" role="list">
|
|
15
|
+
<li>Unlimited projects</li>
|
|
16
|
+
<li>Priority support</li>
|
|
17
|
+
</ul>
|
|
18
|
+
<button type="button" class="velin-btn velin-btn--primary velin-w-full">Choose</button>
|
|
19
|
+
</article>
|
|
20
|
+
</div>
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
<velin-sheet id="settings-sheet" title="Settings">
|
|
2
|
+
<form class="velin-flex velin-flex-col velin-gap-4 velin-p-4">
|
|
3
|
+
<label class="velin-flex velin-flex-col velin-gap-1">
|
|
4
|
+
<span>Display name</span>
|
|
5
|
+
<input type="text" class="velin-input" name="name" autocomplete="name" />
|
|
6
|
+
</label>
|
|
7
|
+
<label class="velin-flex velin-items-center velin-gap-2">
|
|
8
|
+
<input type="checkbox" class="velin-checkbox" name="notify" />
|
|
9
|
+
<span>Email notifications</span>
|
|
10
|
+
</label>
|
|
11
|
+
<button type="submit" class="velin-btn velin-btn--primary">Save</button>
|
|
12
|
+
</form>
|
|
13
|
+
</velin-sheet>
|
|
14
|
+
<button type="button" class="velin-btn velin-btn--outline" id="open-settings">Open settings</button>
|
|
15
|
+
<script type="module">
|
|
16
|
+
import '../../dist/velinstyle-components.min.js';
|
|
17
|
+
document.getElementById('open-settings')?.addEventListener('click', () => {
|
|
18
|
+
document.getElementById('settings-sheet')?.open?.();
|
|
19
|
+
});
|
|
20
|
+
</script>
|
package/cli/index.js
CHANGED
|
@@ -49,6 +49,7 @@ const LAYER_FILES = {
|
|
|
49
49
|
'utilities/scroll.css', 'utilities/color-mix.css', 'utilities/scroll-animation.css',
|
|
50
50
|
'utilities/view-transition.css', 'utilities/scope.css', 'utilities/anchor.css',
|
|
51
51
|
'utilities/filter.css', 'utilities/container-style.css', 'utilities/state.css',
|
|
52
|
+
'utilities/safe-area.css',
|
|
52
53
|
],
|
|
53
54
|
helpers: ['helpers/helpers.css'],
|
|
54
55
|
};
|
|
@@ -79,7 +80,7 @@ function hasFlag(flag, alias) {
|
|
|
79
80
|
|
|
80
81
|
function help() {
|
|
81
82
|
console.log(`
|
|
82
|
-
${C.bold('VelinStyle CLI')} v0.
|
|
83
|
+
${C.bold('VelinStyle CLI')} v0.8.0
|
|
83
84
|
|
|
84
85
|
${C.bold('Usage:')}
|
|
85
86
|
velinstyle init Create velinstyle.config.js
|
|
@@ -90,6 +91,8 @@ function help() {
|
|
|
90
91
|
velinstyle scan [path] Security & accessibility scanner
|
|
91
92
|
velinstyle prefix [path] Add missing velin- prefix (dry-run; use --write)
|
|
92
93
|
velinstyle blueprint [name] Print HTML blueprint (run: velinstyle blueprint list)
|
|
94
|
+
velinstyle scaffold "<prompt>" Generate layout HTML from a text description
|
|
95
|
+
velinstyle layout <sub> Responsive layout audit and fixes
|
|
93
96
|
velinstyle tokens build Generate CSS variables from tokens.json
|
|
94
97
|
|
|
95
98
|
${C.bold('Icons subcommands:')}
|
|
@@ -107,6 +110,16 @@ function help() {
|
|
|
107
110
|
velinstyle blueprint list Print all blueprint ids
|
|
108
111
|
velinstyle blueprint <name> [--output, -o <file>]
|
|
109
112
|
|
|
113
|
+
${C.bold('Scaffold (0.8.0):')}
|
|
114
|
+
velinstyle scaffold "<prompt>" Compose blueprints from natural language
|
|
115
|
+
velinstyle scaffold list-intents Show supported intent keywords
|
|
116
|
+
velinstyle scaffold "<prompt>" -o out.html [--json]
|
|
117
|
+
|
|
118
|
+
${C.bold('Layout (0.8.0):')}
|
|
119
|
+
velinstyle layout audit [path] Report flex/grid/responsive issues
|
|
120
|
+
velinstyle layout suggest [path] Audit with fix suggestions
|
|
121
|
+
velinstyle layout fix [path] Apply safe fixes (--dry-run default, --write)
|
|
122
|
+
|
|
110
123
|
${C.bold('Tokens:')}
|
|
111
124
|
velinstyle tokens build [--input <path>] [--output, -o <file>]
|
|
112
125
|
|
|
@@ -497,6 +510,104 @@ async function prefixCmd() {
|
|
|
497
510
|
}
|
|
498
511
|
}
|
|
499
512
|
|
|
513
|
+
async function scaffoldCmd() {
|
|
514
|
+
const sub = args[1];
|
|
515
|
+
const { scaffoldFromPrompt, listIntents } = await import('./scaffold.js');
|
|
516
|
+
if (sub === 'list-intents') {
|
|
517
|
+
console.log(`\n ${C.bold('Scaffold intents:')}\n`);
|
|
518
|
+
for (const i of listIntents()) {
|
|
519
|
+
console.log(` ${C.cyan(i.id)} — ${i.blueprints.join(' + ')}`);
|
|
520
|
+
console.log(C.dim(` keywords: ${i.keywords.slice(0, 5).join(', ')}…`));
|
|
521
|
+
}
|
|
522
|
+
console.log('');
|
|
523
|
+
return;
|
|
524
|
+
}
|
|
525
|
+
const promptParts = [];
|
|
526
|
+
let i = 1;
|
|
527
|
+
while (i < args.length) {
|
|
528
|
+
const a = args[i];
|
|
529
|
+
if (a.startsWith('-')) break;
|
|
530
|
+
if (a !== 'scaffold') promptParts.push(a);
|
|
531
|
+
i += 1;
|
|
532
|
+
}
|
|
533
|
+
const prompt = promptParts.join(' ').trim() || sub;
|
|
534
|
+
if (!prompt || prompt === 'list-intents') {
|
|
535
|
+
console.log('Usage: velinstyle scaffold "<description>" [-o file.html] [--json]');
|
|
536
|
+
return;
|
|
537
|
+
}
|
|
538
|
+
const r = scaffoldFromPrompt(prompt);
|
|
539
|
+
if (!r.ok) {
|
|
540
|
+
console.log(C.red(r.error));
|
|
541
|
+
process.exit(1);
|
|
542
|
+
}
|
|
543
|
+
const out = getArg('--output', '-o');
|
|
544
|
+
const asJson = hasFlag('--json');
|
|
545
|
+
if (asJson) {
|
|
546
|
+
console.log(JSON.stringify(r, null, 2));
|
|
547
|
+
} else if (out) {
|
|
548
|
+
writeFileSync(resolve(out), r.html, 'utf-8');
|
|
549
|
+
console.log(C.green(`Wrote ${resolve(out)} (intent: ${r.intent}, ${r.confidence})`));
|
|
550
|
+
if (r.responsiveHints?.length) {
|
|
551
|
+
console.log(C.yellow(` ${r.responsiveHints.length} layout hint(s) — run: velinstyle layout suggest ${out}`));
|
|
552
|
+
}
|
|
553
|
+
} else {
|
|
554
|
+
console.log(r.html);
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
async function layoutCmd() {
|
|
559
|
+
const sub = args[1] || 'audit';
|
|
560
|
+
const rawTarget = args[2] && !args[2].startsWith('-') ? args[2] : '.';
|
|
561
|
+
const targetPath = resolve(rawTarget);
|
|
562
|
+
const asJson = hasFlag('--json');
|
|
563
|
+
const write = hasFlag('--write');
|
|
564
|
+
const dryRun = hasFlag('--dry-run') || !write;
|
|
565
|
+
|
|
566
|
+
const { auditPath, suggestFromIssues, formatTextReport, fixPath } = await import('./layout-audit.js');
|
|
567
|
+
|
|
568
|
+
if (sub === 'fix') {
|
|
569
|
+
const result = fixPath(targetPath, { write, dryRun });
|
|
570
|
+
if (!result.ok) {
|
|
571
|
+
console.log(C.red(result.error || 'Fix failed'));
|
|
572
|
+
process.exit(1);
|
|
573
|
+
}
|
|
574
|
+
if (asJson) {
|
|
575
|
+
console.log(JSON.stringify(result, null, 2));
|
|
576
|
+
return;
|
|
577
|
+
}
|
|
578
|
+
if (result.changes.length === 0) {
|
|
579
|
+
console.log(C.green('No safe fixes to apply.'));
|
|
580
|
+
return;
|
|
581
|
+
}
|
|
582
|
+
for (const c of result.changes) {
|
|
583
|
+
console.log(`${dryRun ? '[dry-run] ' : ''}${c.file}`);
|
|
584
|
+
c.changes.forEach((ch) => console.log(C.dim(` - ${ch}`)));
|
|
585
|
+
}
|
|
586
|
+
return;
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
const { issues, files } = auditPath(targetPath);
|
|
590
|
+
const outIssues = sub === 'suggest' ? suggestFromIssues(issues) : issues;
|
|
591
|
+
|
|
592
|
+
if (asJson) {
|
|
593
|
+
console.log(JSON.stringify({ files, issues: outIssues }, null, 2));
|
|
594
|
+
return;
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
console.log(formatTextReport(outIssues, files));
|
|
598
|
+
if (sub === 'suggest' && issues.length) {
|
|
599
|
+
console.log(C.bold('Suggested fixes:'));
|
|
600
|
+
for (const i of outIssues) {
|
|
601
|
+
console.log(` [${i.id}] ${i.fix}`);
|
|
602
|
+
if (i.responsive?.mobile) {
|
|
603
|
+
console.log(C.dim(` mobile: ${i.responsive.mobile}`));
|
|
604
|
+
}
|
|
605
|
+
}
|
|
606
|
+
console.log('');
|
|
607
|
+
}
|
|
608
|
+
process.exit(issues.some((x) => x.severity === 'error') ? 1 : 0);
|
|
609
|
+
}
|
|
610
|
+
|
|
500
611
|
async function scanCmd() {
|
|
501
612
|
const targetPath = args[1] && !args[1].startsWith('-') ? resolve(args[1]) : resolve('.');
|
|
502
613
|
const format = getArg('--format') || 'text';
|
|
@@ -508,6 +619,7 @@ async function scanCmd() {
|
|
|
508
619
|
fixLang = 'de';
|
|
509
620
|
}
|
|
510
621
|
const severity = getArg('--severity') || 'warning';
|
|
622
|
+
const only = getArg('--only');
|
|
511
623
|
|
|
512
624
|
const { scan } = await import('./scanner.js');
|
|
513
625
|
const exitCode = scan(targetPath, {
|
|
@@ -516,6 +628,7 @@ async function scanCmd() {
|
|
|
516
628
|
fixDryRun,
|
|
517
629
|
fixLang: fixLang || undefined,
|
|
518
630
|
format,
|
|
631
|
+
only,
|
|
519
632
|
});
|
|
520
633
|
process.exit(exitCode);
|
|
521
634
|
}
|
|
@@ -532,6 +645,8 @@ switch (command) {
|
|
|
532
645
|
case 'tokens': await tokensCmd(); break;
|
|
533
646
|
case 'scan': scanCmd(); break;
|
|
534
647
|
case 'prefix': await prefixCmd(); break;
|
|
648
|
+
case 'scaffold': await scaffoldCmd(); break;
|
|
649
|
+
case 'layout': await layoutCmd(); break;
|
|
535
650
|
case '--help': case '-h': help(); break;
|
|
536
651
|
default: help(); break;
|
|
537
652
|
}
|