@birdapi/velinstyle 1.2.0 → 1.2.2

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 (89) hide show
  1. package/README.de.md +150 -24
  2. package/README.md +155 -33
  3. package/cli/__fixtures__/atelier-library/showcases/01-login/app.css +1 -0
  4. package/cli/__fixtures__/atelier-library/showcases/01-login/app.js +2 -0
  5. package/cli/__fixtures__/atelier-library/showcases/01-login/index.html +5 -0
  6. package/cli/__fixtures__/atelier-library/showcases/04-pricing/app.css +1 -0
  7. package/cli/__fixtures__/atelier-library/showcases/04-pricing/app.js +2 -0
  8. package/cli/__fixtures__/atelier-library/showcases/04-pricing/index.html +5 -0
  9. package/cli/__fixtures__/atelier-library/showcases/36-calendar/app.css +1 -0
  10. package/cli/__fixtures__/atelier-library/showcases/36-calendar/app.js +2 -0
  11. package/cli/__fixtures__/atelier-library/showcases/36-calendar/index.html +5 -0
  12. package/cli/atelier-catalog.json +1267 -0
  13. package/cli/atelier-formats.js +159 -0
  14. package/cli/atelier.js +382 -0
  15. package/cli/blueprints/empty-state.html +3 -5
  16. package/cli/cli-manifest.json +23 -10
  17. package/cli/docgen/extract-attributes.js +2 -0
  18. package/cli/docgen/extract-cli.js +1 -1
  19. package/cli/index.js +181 -6
  20. package/cli/production/component-graph.json +166 -0
  21. package/cli/production/explain.js +52 -0
  22. package/cli/production/extract.js +238 -0
  23. package/cli/production/graph.js +102 -0
  24. package/cli/production/report.js +78 -0
  25. package/cli/production/run.js +312 -0
  26. package/cli/production/trim-css.js +177 -0
  27. package/cli/production/trim-fonts.js +23 -0
  28. package/cli/production/trim-icons.js +38 -0
  29. package/cli/production/trim-js.js +48 -0
  30. package/cli/production/trim-motion.js +22 -0
  31. package/cli/production/trim-themes.js +50 -0
  32. package/cli/production/watch.js +38 -0
  33. package/cli/review.js +48 -1
  34. package/cli/scripts/write-atelier-fixtures.mjs +33 -0
  35. package/cli/transparency.js +221 -0
  36. package/components/index.js +3 -0
  37. package/components/runtime/component-loaders.js +3 -0
  38. package/components/velin-drawer.js +43 -4
  39. package/components/velin-empty-state.js +83 -0
  40. package/components/velin-modal.js +76 -15
  41. package/components/velin-otp-input.js +220 -0
  42. package/components/velin-password-strength.js +147 -0
  43. package/components/velin-sheet.js +49 -4
  44. package/core/a11y/component-contracts.json +23 -4
  45. package/core/attributes/registry.js +14 -0
  46. package/core/meta/knowledge/components.json +75 -3
  47. package/core/meta/schema.js +10 -0
  48. package/core/transparency/attach.js +74 -0
  49. package/core/transparency/claims.js +97 -0
  50. package/core/transparency/doctor.js +142 -0
  51. package/core/transparency/engine.js +75 -0
  52. package/core/transparency/export.js +98 -0
  53. package/core/transparency/index.js +30 -0
  54. package/core/transparency/migrate.js +130 -0
  55. package/core/transparency/normalize.js +125 -0
  56. package/core/transparency/policy.js +105 -0
  57. package/core/transparency/providers.js +235 -0
  58. package/core/transparency/registry.js +104 -0
  59. package/core/transparency/renderer.js +111 -0
  60. package/core/transparency/reporter.js +113 -0
  61. package/core/transparency/validator.js +112 -0
  62. package/dist/chunks/attach-H2ZSEAE6.js +365 -0
  63. package/dist/chunks/attributes-2ORR27KA.js +404 -0
  64. package/dist/chunks/attributes-DZCXX2RZ.js +404 -0
  65. package/dist/chunks/chunk-CQMTCEI6.js +113 -0
  66. package/dist/chunks/chunk-Y6HN7HWX.js +116 -0
  67. package/dist/chunks/runtime-entry.js +1 -1
  68. package/dist/chunks/velin-drawer-A7Q7EBOS.js +162 -0
  69. package/dist/chunks/velin-empty-state-3NTUH2RF.js +81 -0
  70. package/dist/chunks/velin-modal-3MV4FYBK.js +231 -0
  71. package/dist/chunks/velin-otp-input-PSK42MM6.js +207 -0
  72. package/dist/chunks/velin-password-strength-TAXMLSED.js +136 -0
  73. package/dist/chunks/velin-sheet-N2VVYXFP.js +157 -0
  74. package/dist/llms.txt +5 -4
  75. package/dist/search-index.json +94 -5
  76. package/dist/velin-agent.json +290 -23
  77. package/dist/velinstyle-components.iife.js +3189 -2202
  78. package/dist/velinstyle-components.js +3187 -2196
  79. package/dist/velinstyle-components.min.js +261 -119
  80. package/dist/velinstyle.css +214 -6
  81. package/dist/velinstyle.d.ts +3 -0
  82. package/dist/velinstyle.min.css +1 -1
  83. package/package.json +143 -142
  84. package/packages/velinstyle-skills/catalog.json +1 -1
  85. package/src/components/data-table.css +19 -0
  86. package/src/components/empty-auth.css +33 -0
  87. package/src/components/table.css +16 -6
  88. package/src/components/transparency.css +138 -0
  89. package/src/velinstyle.css +2 -0
package/cli/index.js CHANGED
@@ -45,6 +45,7 @@ const LAYER_FILES = {
45
45
  'components/timeline.css', 'components/stepper.css', 'components/stat.css',
46
46
  'components/drawer.css', 'components/input-group.css', 'components/form-validation.css', 'components/collapse.css',
47
47
  'components/calendar-dropzone.css',
48
+ 'components/transparency.css',
48
49
  ],
49
50
  utilities: [
50
51
  'utilities/color.css', 'utilities/spacing.css', 'utilities/display.css',
@@ -91,6 +92,8 @@ function help() {
91
92
  ${C.bold('Usage:')}
92
93
  velinstyle init Create velinstyle.config.js
93
94
  velinstyle build Build custom CSS with selected layers
95
+ velinstyle build --production Content-aware production output (CSS/JS/themes/icons)
96
+ velinstyle production [path] Alias for build --production
94
97
  velinstyle themes List available themes
95
98
  velinstyle add <name> Add a single component CSS
96
99
  velinstyle icons <subcommand> Manage icon providers
@@ -101,9 +104,14 @@ function help() {
101
104
  velinstyle create <kind> [dir] Scaffold: landing|dashboard|docs|auth
102
105
  velinstyle serve [dir] Static preview server (default port 4173)
103
106
  velinstyle doctor Check dist, icons, config, Windows ESM paths
104
- velinstyle check [path] doctor + blueprint --strict + scan + review
107
+ velinstyle transparency <sub> Transparency Framework: doctor|validate|report|export|migrate
108
+ velinstyle check [path] doctor + blueprint --strict + scan + review + transparency
105
109
  velinstyle scaffold "<prompt>" Plan-first page HTML or recipe fragment
110
+ velinstyle scaffold --atelier 04,07 Compose Atelier Library ids (beta)
106
111
  velinstyle plan "<prompt>" Emit page plan JSON (no HTML)
112
+ velinstyle plan --atelier 04,07 Emit plan JSON for Atelier ids (beta)
113
+ velinstyle atelier <num|id> Pull curated Atelier Library showcase
114
+ velinstyle atelier list List curated Library numbers/ids
107
115
  velinstyle review [file|html] Design / a11y / SEO / conversion review gate
108
116
  velinstyle wc api <tag> Human-readable Web Component API from source
109
117
  velinstyle layout <sub> Responsive layout audit and fixes
@@ -145,11 +153,27 @@ function help() {
145
153
  velinstyle scaffold "<prompt>" Plan → render → review for pages; recipes for fragments
146
154
  velinstyle scaffold list-intents Show recipe intent keywords
147
155
  velinstyle scaffold "<prompt>" -o out.html [--json]
156
+ velinstyle scaffold --atelier 04,07 [-o page.html] [--from <library>] Compose Library showcases (beta)
148
157
 
149
- ${C.bold('Plan / Review (1.2.0):')}
158
+ ${C.bold('Atelier Library pull (1.2.x):')}
159
+ velinstyle atelier list
160
+ velinstyle atelier 36 [-o dir] [--format html|blade|vue|react] [--from <library>] [--base-url <url>]
161
+ Limitation: blade/vue/react = integration wrappers around vanilla assets (not native rewrites).
162
+ Native framework blocks / Velin Studio Builder = planned. Atelier ≠ Studio.
163
+
164
+ ${C.bold('Plan / Review (1.2.x):')}
150
165
  velinstyle plan "<prompt>" [--json] [-o plan.json]
166
+ velinstyle plan --atelier 04,07 [-o plan.json] Atelier compose plan (beta)
151
167
  velinstyle review <file.html> [--json] [--prompt "..."]
152
168
 
169
+ ${C.bold('Transparency (1.2.1):')}
170
+ velinstyle transparency doctor [path|file] [--policy file] [--json]
171
+ velinstyle transparency validate [path|file] [--policy file] [--json]
172
+ velinstyle transparency report [path|file] [--out dir] [--policy file]
173
+ velinstyle transparency export [path|file] [--format json|json-ld|csv|html] [-o file]
174
+ velinstyle transparency migrate [path|file] [--apply] [--write] [--policy file]
175
+ Alias: transparency scan → doctor
176
+
153
177
  ${C.bold('Layout (0.8.0):')}
154
178
  velinstyle layout audit [path] Report flex/grid/responsive issues
155
179
  velinstyle layout suggest [path] Audit with fix suggestions
@@ -160,6 +184,16 @@ function help() {
160
184
  velinstyle perf suggest [path|file] Same as audit with fix hints
161
185
  velinstyle perf fix [path|file] Apply safe fixes (--write)
162
186
 
187
+ ${C.bold('Production Builder (1.2.2):')}
188
+ velinstyle build --production [path]
189
+ velinstyle production [path]
190
+ --out, -o <dir> Default: ./dist/velin-production
191
+ --explain Show removed CSS/themes/icons + reasons
192
+ --watch Rebuild on content change
193
+ --report <file> Write JSON/Markdown report
194
+ --safelist <list|file> Extra classes / themes / icons / CSS files
195
+ --no-js --no-icons --no-themes --no-motion --no-minify
196
+
163
197
  ${C.bold('Tokens:')}
164
198
  velinstyle tokens build [--input <path>] [--output, -o <file>]
165
199
  velinstyle tokens validate [--input <path>]
@@ -300,6 +334,13 @@ export default {
300
334
  // ── Build ────────────────────────────────────────────────────────────────────
301
335
 
302
336
  async function build() {
337
+ if (hasFlag('--production')) {
338
+ const { runProduction } = await import('./production/run.js');
339
+ const rest = args.slice(1).filter((a) => a !== '--production');
340
+ await runProduction({ args: rest, helpers: { getArg, hasFlag, C } });
341
+ return;
342
+ }
343
+
303
344
  const configPath = resolve('velinstyle.config.js');
304
345
  let config;
305
346
 
@@ -777,6 +818,60 @@ async function prefixCmd() {
777
818
  }
778
819
  }
779
820
 
821
+ async function atelierCmd() {
822
+ const sub = args[1];
823
+ const {
824
+ listAtelierEntries,
825
+ pullAtelier,
826
+ } = await import('./atelier.js');
827
+
828
+ if (!sub || sub === '--help' || sub === '-h') {
829
+ console.log(`Usage: velinstyle atelier list
830
+ velinstyle atelier <num|id> [-o dir] [--format html|blade|vue|react]
831
+ [--from <library-root>] [--base-url <url>] [--rewrite-vendor <path>]
832
+
833
+ Pull a curated Atelier Library showcase (e.g. 36 → 36-calendar).
834
+ Limitation: --format blade|vue|react writes integration shells only (not native rewrites).
835
+ Velin Studio Builder and native framework blocks are planned — not shipped.`);
836
+ return;
837
+ }
838
+
839
+ if (sub === 'list') {
840
+ const r = listAtelierEntries();
841
+ if (!r.ok) {
842
+ console.log(C.red(r.error));
843
+ process.exit(1);
844
+ }
845
+ console.log(`\n ${C.bold('Atelier Library (curated)')} · ${r.items.length} templates\n`);
846
+ for (const it of r.items) {
847
+ console.log(` ${C.cyan(it.num.padStart(3))} ${it.id} ${C.dim(it.title || '')}`);
848
+ }
849
+ console.log(`\n ${C.dim('Example: velinstyle atelier 36 -o ./velin-atelier/36-calendar')}\n`);
850
+ return;
851
+ }
852
+
853
+ const out = getArg('--output', '-o');
854
+ const format = getArg('--format') || 'html';
855
+ const from = getArg('--from') || process.env.VELINSTYLE_ATELIER_ROOT || null;
856
+ const baseUrl = getArg('--base-url');
857
+ const rewriteVendor = getArg('--rewrite-vendor');
858
+
859
+ const r = await pullAtelier(sub, {
860
+ output: out || undefined,
861
+ format,
862
+ from: from || undefined,
863
+ baseUrl: baseUrl || undefined,
864
+ rewriteVendor: rewriteVendor || undefined,
865
+ });
866
+ if (!r.ok) {
867
+ console.log(C.red(r.error));
868
+ process.exit(1);
869
+ }
870
+ console.log(C.green(`Pulled ${r.entry.id} → ${r.path} (format: ${r.format})`));
871
+ console.log(C.dim(` source: ${r.source}`));
872
+ console.log(C.dim(' Limitation: blade/vue/react = wrappers; Studio/native rewrites planned.'));
873
+ }
874
+
780
875
  async function scaffoldCmd() {
781
876
  const sub = args[1];
782
877
  const { scaffoldFromPrompt, listIntents } = await import('./scaffold.js');
@@ -789,6 +884,38 @@ async function scaffoldCmd() {
789
884
  console.log('');
790
885
  return;
791
886
  }
887
+
888
+ const atelierList = getArg('--atelier');
889
+ if (atelierList) {
890
+ const { composeAtelierPage } = await import('./atelier.js');
891
+ const out = getArg('--output', '-o') || resolve('velin-atelier/compose.html');
892
+ const from = getArg('--from') || process.env.VELINSTYLE_ATELIER_ROOT || null;
893
+ const baseUrl = getArg('--base-url');
894
+ const r = await composeAtelierPage(atelierList, {
895
+ output: out,
896
+ from: from || undefined,
897
+ baseUrl: baseUrl || undefined,
898
+ });
899
+ if (!r.ok) {
900
+ console.log(C.red(r.error));
901
+ process.exit(1);
902
+ }
903
+ if (hasFlag('--json')) {
904
+ console.log(JSON.stringify({
905
+ ok: true,
906
+ mode: r.mode,
907
+ path: r.path,
908
+ entries: r.entries,
909
+ planSections: r.planSections,
910
+ }, null, 2));
911
+ } else {
912
+ console.log(C.green(`Wrote Atelier compose (beta) → ${r.path}`));
913
+ console.log(C.dim(` ids: ${r.entries.map((e) => e.id).join(', ')}`));
914
+ console.log(C.dim(' Beta: Library compose — not Velin Studio. Wrappers ≠ native rewrites.'));
915
+ }
916
+ return;
917
+ }
918
+
792
919
  const promptParts = [];
793
920
  let i = 1;
794
921
  while (i < args.length) {
@@ -800,6 +927,7 @@ async function scaffoldCmd() {
800
927
  const prompt = promptParts.join(' ').trim() || sub;
801
928
  if (!prompt || prompt === 'list-intents') {
802
929
  console.log('Usage: velinstyle scaffold "<description>" [-o file.html] [--json]');
930
+ console.log(' velinstyle scaffold --atelier 04,07 [-o page.html] [--from <library>]');
803
931
  return;
804
932
  }
805
933
  const r = scaffoldFromPrompt(prompt);
@@ -826,6 +954,24 @@ async function scaffoldCmd() {
826
954
  }
827
955
 
828
956
  async function planCmd() {
957
+ const atelierList = getArg('--atelier');
958
+ if (atelierList) {
959
+ const { planFromAtelierList } = await import('./atelier.js');
960
+ const payload = planFromAtelierList(atelierList, { prompt: args.slice(1).filter((a) => !a.startsWith('-')).join(' ') });
961
+ if (!payload.ok) {
962
+ console.log(C.red(payload.error));
963
+ process.exit(1);
964
+ }
965
+ const out = getArg('--output', '-o');
966
+ if (out) {
967
+ writeFileSync(resolve(out), JSON.stringify(payload, null, 2), 'utf-8');
968
+ console.log(C.green(`Wrote Atelier plan (beta) ${resolve(out)} (${payload.plan.sections.length} sections)`));
969
+ return;
970
+ }
971
+ console.log(JSON.stringify(payload, null, 2));
972
+ return;
973
+ }
974
+
829
975
  const promptParts = [];
830
976
  let i = 1;
831
977
  while (i < args.length) {
@@ -837,6 +983,7 @@ async function planCmd() {
837
983
  const prompt = promptParts.join(' ').trim();
838
984
  if (!prompt) {
839
985
  console.log('Usage: velinstyle plan "<description>" [--json] [-o plan.json]');
986
+ console.log(' velinstyle plan --atelier 04,07 [-o plan.json]');
840
987
  return;
841
988
  }
842
989
  const { analyzePrompt, buildPlan } = await import('./prompt-engine.js');
@@ -877,7 +1024,10 @@ async function reviewCmd() {
877
1024
  console.log(JSON.stringify(report, null, 2));
878
1025
  } else {
879
1026
  console.log(`\n ${C.bold('Review gate:')} ${report.gate} ${C.dim(`profile ${report.profile} · promptScore ${report.promptScore}`)}`);
880
- console.log(C.dim(` design ${report.scores.design} · a11y ${report.scores.accessibility} · seo ${report.scores.seo} · perf ${report.scores.performance} · conversion ${report.scores.conversion}`));
1027
+ console.log(C.dim(` design ${report.scores.design} · a11y ${report.scores.accessibility} · seo ${report.scores.seo} · perf ${report.scores.performance} · conversion ${report.scores.conversion} · opt ${report.scores.optimization ?? '—'}`));
1028
+ if (report.optimization) {
1029
+ console.log(C.dim(` optimization · unused themes ${report.optimization.unusedThemes} · WC tags ${report.optimization.componentTags} · class tokens ${report.optimization.classTokens}`));
1030
+ }
881
1031
  if (report.issues.length) {
882
1032
  console.log(`\n ${C.bold('Issues:')}`);
883
1033
  for (const issue of report.issues) {
@@ -1123,6 +1273,20 @@ async function checkCmd() {
1123
1273
  steps.push({ step: 'review', ok: true, skipped: true });
1124
1274
  }
1125
1275
 
1276
+ if (!quiet) console.log(C.bold('\n── transparency ──'));
1277
+ try {
1278
+ const { transparencyCheckStep } = await import('./transparency.js');
1279
+ const tx = await transparencyCheckStep(htmlFile || target, { quiet, C });
1280
+ if (!tx.ok && !tx.skipped) failed += 1;
1281
+ if (!quiet && tx.scores) {
1282
+ console.log(`Transparency ${tx.scores.transparency}% · AI ${tx.scores.ai}% · Trust ${tx.scores.trust}% · Provenance ${tx.scores.provenance}%`);
1283
+ }
1284
+ steps.push({ step: 'transparency', ok: tx.ok || !!tx.skipped, scores: tx.scores, skipped: tx.skipped });
1285
+ } catch (err) {
1286
+ if (!quiet) console.log(C.yellow(`transparency skipped: ${err.message}`));
1287
+ steps.push({ step: 'transparency', ok: true, skipped: true, error: String(err.message || err) });
1288
+ }
1289
+
1126
1290
  const payload = {
1127
1291
  ok: failed === 0,
1128
1292
  failedSteps: failed,
@@ -1181,8 +1345,8 @@ async function checkCmd() {
1181
1345
  function suggestCommand(unknown) {
1182
1346
  const names = [
1183
1347
  'init', 'build', 'themes', 'add', 'icons', 'blueprint', 'create', 'serve', 'doctor', 'check',
1184
- 'validate', 'tokens', 'scan', 'prefix', 'scaffold', 'plan', 'review', 'layout', 'perf',
1185
- 'docs', 'documentation', 'meta', 'search', 'skills', 'workflow', 'wc',
1348
+ 'validate', 'tokens', 'scan', 'prefix', 'scaffold', 'plan', 'review', 'transparency', 'layout', 'perf',
1349
+ 'docs', 'documentation', 'meta', 'search', 'skills', 'workflow', 'wc', 'production', 'atelier',
1186
1350
  ];
1187
1351
  const q = String(unknown || '').toLowerCase();
1188
1352
  function editDistance(a, b) {
@@ -1229,7 +1393,12 @@ const resolvedCommand = ALIASES[command] || command;
1229
1393
 
1230
1394
  switch (resolvedCommand) {
1231
1395
  case 'init': init(); break;
1232
- case 'build': build(); break;
1396
+ case 'build': await build(); break;
1397
+ case 'production': {
1398
+ const { runProduction } = await import('./production/run.js');
1399
+ await runProduction({ args: args.slice(1), helpers: { getArg, hasFlag, C } });
1400
+ break;
1401
+ }
1233
1402
  case 'themes': themes(); break;
1234
1403
  case 'add': add(); break;
1235
1404
  case 'icons': icons(); break;
@@ -1243,7 +1412,13 @@ switch (resolvedCommand) {
1243
1412
  case 'prefix': await prefixCmd(); break;
1244
1413
  case 'scaffold': await scaffoldCmd(); break;
1245
1414
  case 'plan': await planCmd(); break;
1415
+ case 'atelier': await atelierCmd(); break;
1246
1416
  case 'review': await reviewCmd(); break;
1417
+ case 'transparency': {
1418
+ const { transparencyCmd } = await import('./transparency.js');
1419
+ await transparencyCmd(args.slice(1), { C, getArg, hasFlag });
1420
+ break;
1421
+ }
1247
1422
  case 'layout': await layoutCmd(); break;
1248
1423
  case 'perf': await perfCmd(); break;
1249
1424
  case 'docs': await docsCmd(); break;
@@ -0,0 +1,166 @@
1
+ {
2
+ "version": 1,
3
+ "alwaysCss": [
4
+ "tokens/fonts.css",
5
+ "tokens/color.css",
6
+ "tokens/spacing.css",
7
+ "tokens/typography.css",
8
+ "tokens/radius.css",
9
+ "tokens/shadow.css",
10
+ "tokens/motion.css",
11
+ "tokens/z-index.css",
12
+ "tokens/aspect-ratio.css",
13
+ "base/root.css",
14
+ "base/reset.css",
15
+ "base/focus.css",
16
+ "base/content.css",
17
+ "a11y/sr-only.css",
18
+ "a11y/skip-link.css",
19
+ "a11y/reduced-motion.css",
20
+ "a11y/forced-colors.css",
21
+ "a11y/focus-appearance.css",
22
+ "a11y/target-size.css",
23
+ "layout/breakpoints.css",
24
+ "layout/container.css"
25
+ ],
26
+ "classPrefixes": {
27
+ "velin-btn": { "css": ["components/button.css"] },
28
+ "velin-card": { "css": ["components/card.css"] },
29
+ "velin-input": { "css": ["components/input.css", "components/form-validation.css"] },
30
+ "velin-textarea": { "css": ["components/input.css", "components/form-validation.css"] },
31
+ "velin-select": { "css": ["components/input.css", "components/form-validation.css"] },
32
+ "velin-label": { "css": ["components/input.css"] },
33
+ "velin-field": { "css": ["components/input.css", "components/form-validation.css"] },
34
+ "velin-nav": { "css": ["components/nav.css"] },
35
+ "velin-navbar": { "css": ["components/nav.css"] },
36
+ "velin-alert": { "css": ["components/alert.css"] },
37
+ "velin-badge": { "css": ["components/badge.css"] },
38
+ "velin-table": { "css": ["components/table.css"] },
39
+ "velin-data-table": { "css": ["components/data-table.css", "components/table.css"] },
40
+ "velin-tooltip": { "css": ["components/tooltip.css"] },
41
+ "velin-modal": { "css": ["components/modal.css", "components/button.css"] },
42
+ "velin-dialog": { "css": ["components/modal.css", "components/button.css"] },
43
+ "velin-breadcrumb": { "css": ["components/breadcrumb.css"] },
44
+ "velin-pagination": { "css": ["components/pagination.css"] },
45
+ "velin-progress": { "css": ["components/progress.css"] },
46
+ "velin-spinner": { "css": ["components/spinner.css"] },
47
+ "velin-list": { "css": ["components/list-group.css"] },
48
+ "velin-avatar": { "css": ["components/avatar.css"] },
49
+ "velin-switch": { "css": ["components/switch.css"] },
50
+ "velin-divider": { "css": ["components/divider.css"] },
51
+ "velin-chip": { "css": ["components/chip.css"] },
52
+ "velin-timeline": { "css": ["components/timeline.css"] },
53
+ "velin-stepper": { "css": ["components/stepper.css"] },
54
+ "velin-stat": { "css": ["components/stat.css"] },
55
+ "velin-drawer": { "css": ["components/drawer.css", "components/button.css"] },
56
+ "velin-sheet": { "css": ["components/drawer.css", "components/button.css"] },
57
+ "velin-input-group": { "css": ["components/input-group.css", "components/input.css"] },
58
+ "velin-collapse": { "css": ["components/collapse.css"] },
59
+ "velin-accordion": { "css": ["components/collapse.css"] },
60
+ "velin-calendar": { "css": ["components/calendar-dropzone.css"] },
61
+ "velin-dropzone": { "css": ["components/calendar-dropzone.css"] },
62
+ "velin-grid": { "css": ["layout/grid.css"] },
63
+ "velin-flex": { "css": ["layout/flex.css"] },
64
+ "velin-container": { "css": ["layout/container.css"] },
65
+ "velin-stack": { "css": ["layout/patterns.css"] },
66
+ "velin-cluster": { "css": ["layout/patterns.css"] },
67
+ "velin-sidebar": { "css": ["layout/patterns.css", "layout/app-shell.css"] },
68
+ "velin-app": { "css": ["layout/app-shell.css"] },
69
+ "velin-shell": { "css": ["layout/app-shell.css"] },
70
+ "velin-skeleton": { "css": ["a11y/skeleton.css"] },
71
+ "velin-sr-only": { "css": ["a11y/sr-only.css"] },
72
+ "velin-skip": { "css": ["a11y/skip-link.css"] },
73
+ "velin-transparency": { "css": ["components/transparency.css"] },
74
+ "velin-disclosure": { "css": ["components/transparency.css"] },
75
+ "velin-otp-input": { "css": ["components/empty-auth.css", "components/input.css"] },
76
+ "velin-password-strength": { "css": ["components/empty-auth.css", "components/progress.css"] },
77
+ "velin-empty-state": { "css": ["components/empty-auth.css", "components/button.css"] }
78
+ },
79
+ "wc": {
80
+ "velin-modal": { "css": ["components/modal.css", "components/button.css"], "peers": ["velin-icon"] },
81
+ "velin-dialog": { "css": ["components/modal.css", "components/button.css"], "peers": ["velin-icon"] },
82
+ "velin-drawer": { "css": ["components/drawer.css", "components/button.css"], "peers": [] },
83
+ "velin-sheet": { "css": ["components/drawer.css", "components/button.css"], "peers": [] },
84
+ "velin-toast": { "css": ["components/alert.css"], "peers": ["velin-icon"] },
85
+ "velin-tooltip": { "css": ["components/tooltip.css"], "peers": [] },
86
+ "velin-tooltip-wc": { "css": ["components/tooltip.css"], "peers": [] },
87
+ "velin-tabs": { "css": ["components/nav.css"], "peers": [] },
88
+ "velin-icon": { "css": [], "peers": [] },
89
+ "velin-accordion": { "css": ["components/collapse.css"], "peers": [] },
90
+ "velin-collapse": { "css": ["components/collapse.css"], "peers": [] },
91
+ "velin-dropdown": { "css": ["components/nav.css", "components/button.css"], "peers": [] },
92
+ "velin-popover": { "css": ["components/tooltip.css"], "peers": [] },
93
+ "velin-carousel": { "css": [], "peers": ["velin-icon"] },
94
+ "velin-lightbox": { "css": ["components/modal.css"], "peers": ["velin-icon"] },
95
+ "velin-data-table": { "css": ["components/data-table.css", "components/table.css"], "peers": [] },
96
+ "velin-stepper": { "css": ["components/stepper.css"], "peers": [] },
97
+ "velin-stepper-wc": { "css": ["components/stepper.css"], "peers": [] },
98
+ "velin-theme-toggle": { "css": ["components/button.css"], "peers": ["velin-icon"] },
99
+ "velin-search": { "css": ["components/input.css", "components/input-group.css"], "peers": ["velin-icon"] },
100
+ "velin-combobox": { "css": ["components/input.css"], "peers": [] },
101
+ "velin-command": { "css": ["components/modal.css", "components/input.css"], "peers": [] },
102
+ "velin-bottom-nav": { "css": ["components/nav.css"], "peers": ["velin-icon"] },
103
+ "velin-menubar": { "css": ["components/nav.css"], "peers": [] },
104
+ "velin-calendar": { "css": ["components/calendar-dropzone.css"], "peers": [] },
105
+ "velin-file-dropzone": { "css": ["components/calendar-dropzone.css"], "peers": [] },
106
+ "velin-progress-ring": { "css": ["components/progress.css"], "peers": [] },
107
+ "velin-rating": { "css": ["components/chip.css"], "peers": ["velin-icon"] },
108
+ "velin-scroll-top": { "css": ["components/button.css"], "peers": ["velin-icon"] },
109
+ "velin-scrollspy": { "css": [], "peers": [] },
110
+ "velin-sparkline": { "css": [], "peers": [] },
111
+ "velin-countdown": { "css": ["components/stat.css"], "peers": [] },
112
+ "velin-counter": { "css": ["components/stat.css"], "peers": [] },
113
+ "velin-live-dot": { "css": ["components/badge.css"], "peers": [] },
114
+ "velin-announcer": { "css": ["a11y/sr-only.css"], "peers": [] },
115
+ "velin-copy": { "css": ["components/button.css"], "peers": ["velin-icon"] },
116
+ "velin-email": { "css": ["components/input.css"], "peers": [] },
117
+ "velin-secure-field": { "css": ["components/input.css", "a11y/security.css"], "peers": [] },
118
+ "velin-form-summary": { "css": ["components/form-validation.css", "components/alert.css"], "peers": [] },
119
+ "velin-persist": { "css": [], "peers": [] },
120
+ "velin-code-block": { "css": [], "peers": [] },
121
+ "velin-segmented-control": { "css": ["components/chip.css", "components/button.css"], "peers": [] },
122
+ "velin-otp-input": { "css": ["components/empty-auth.css", "components/input.css"], "peers": [] },
123
+ "velin-password-strength": { "css": ["components/empty-auth.css", "components/progress.css"], "peers": [] },
124
+ "velin-empty-state": { "css": ["components/empty-auth.css", "components/button.css"], "peers": [] }
125
+ },
126
+ "utilityFiles": [
127
+ "utilities/color.css",
128
+ "utilities/spacing.css",
129
+ "utilities/display.css",
130
+ "utilities/text.css",
131
+ "utilities/sizing.css",
132
+ "utilities/border.css",
133
+ "utilities/position.css",
134
+ "utilities/animation.css",
135
+ "utilities/gradient.css",
136
+ "utilities/print.css",
137
+ "utilities/responsive.css",
138
+ "utilities/divide.css",
139
+ "utilities/scroll.css",
140
+ "utilities/color-mix.css",
141
+ "utilities/scroll-animation.css",
142
+ "utilities/view-transition.css",
143
+ "utilities/scope.css",
144
+ "utilities/anchor.css",
145
+ "utilities/filter.css",
146
+ "utilities/filter-effects.css",
147
+ "utilities/chart-animation.css",
148
+ "utilities/container-style.css",
149
+ "utilities/state.css",
150
+ "utilities/safe-area.css"
151
+ ],
152
+ "motionFiles": [
153
+ "utilities/animation.css",
154
+ "utilities/scroll-animation.css",
155
+ "utilities/chart-animation.css",
156
+ "utilities/view-transition.css",
157
+ "tokens/motion.css",
158
+ "a11y/reduced-motion.css"
159
+ ],
160
+ "fontClassPrefixes": [
161
+ "velin-font-",
162
+ "velin-text-",
163
+ "velin-leading-",
164
+ "velin-tracking-"
165
+ ]
166
+ }
@@ -0,0 +1,52 @@
1
+ /**
2
+ * --explain: human-readable removals with reasons.
3
+ */
4
+ export function buildExplain({
5
+ skippedCss = [],
6
+ skippedThemes = [],
7
+ skippedIcons = [],
8
+ skippedMotion = false,
9
+ graphExplain = [],
10
+ } = {}) {
11
+ const removed = [];
12
+
13
+ for (const item of skippedCss) {
14
+ removed.push({
15
+ id: item.file || item,
16
+ reason: item.reason || 'Nicht benutzt',
17
+ });
18
+ }
19
+ for (const theme of skippedThemes) {
20
+ removed.push({ id: `${theme}.theme.css`, reason: 'Nicht benutzt' });
21
+ }
22
+ for (const icon of skippedIcons.slice(0, 40)) {
23
+ removed.push({ id: `icon:${icon}`, reason: 'Nicht benutzt' });
24
+ }
25
+ if (skippedIcons.length > 40) {
26
+ removed.push({ id: `icon:…(+${skippedIcons.length - 40})`, reason: 'Nicht benutzt' });
27
+ }
28
+ if (skippedMotion) {
29
+ removed.push({ id: 'motion utilities', reason: 'Keine Animate-/Motion-Klassen gefunden' });
30
+ }
31
+
32
+ const kept = [];
33
+ const seen = new Set();
34
+ for (const e of graphExplain) {
35
+ if (!e.keep || seen.has(e.keep)) continue;
36
+ seen.add(e.keep);
37
+ kept.push({ id: e.keep, reason: e.reason });
38
+ }
39
+
40
+ const lines = ['Entfernt'];
41
+ if (!removed.length) lines.push('(nichts entfernt — oder Scan fand fast alles)');
42
+ for (const r of removed) {
43
+ lines.push(`${r.id.padEnd(28)} ${r.reason}`);
44
+ }
45
+ lines.push('');
46
+ lines.push('Behalten (Auszug)');
47
+ for (const k of kept.slice(0, 30)) {
48
+ lines.push(`${k.id.padEnd(28)} ${k.reason}`);
49
+ }
50
+
51
+ return { removed, kept, text: lines.join('\n') };
52
+ }