vibe-design-system 2.8.66 → 2.8.68
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/package.json
CHANGED
|
@@ -2505,6 +2505,7 @@ function writeFoundationsStories(foundations) {
|
|
|
2505
2505
|
.slice(0, 60); // cap to avoid extremely long stories
|
|
2506
2506
|
|
|
2507
2507
|
const colorsContent = [
|
|
2508
|
+
"import React from \"react\";",
|
|
2508
2509
|
"import type { Meta, StoryObj } from \"@storybook/react\";",
|
|
2509
2510
|
"",
|
|
2510
2511
|
"const meta = { title: \"Foundations/Colors\", parameters: { layout: \"fullscreen\" } } satisfies Meta;",
|
|
@@ -2630,6 +2631,7 @@ function writeFoundationsStories(foundations) {
|
|
|
2630
2631
|
const sansFamily = typo.fontSans || typo.tailwindSans || typo.body || "system-ui, sans-serif";
|
|
2631
2632
|
|
|
2632
2633
|
const typoContent = [
|
|
2634
|
+
"import React from \"react\";",
|
|
2633
2635
|
"import type { Meta, StoryObj } from \"@storybook/react\";",
|
|
2634
2636
|
"",
|
|
2635
2637
|
"const meta = { title: \"Foundations/Typography\", parameters: { layout: \"fullscreen\" } } satisfies Meta;",
|
|
@@ -2790,6 +2792,7 @@ function writeFoundationsStories(foundations) {
|
|
|
2790
2792
|
|
|
2791
2793
|
const brandContent =
|
|
2792
2794
|
[
|
|
2795
|
+
"import React from \"react\";",
|
|
2793
2796
|
"import type { Meta, StoryObj } from \"@storybook/react\";",
|
|
2794
2797
|
"",
|
|
2795
2798
|
"const meta = { title: \"Foundations/Brand\", parameters: { layout: \"fullscreen\" } } satisfies Meta;",
|
|
@@ -2823,6 +2826,7 @@ function writeFoundationsStories(foundations) {
|
|
|
2823
2826
|
|
|
2824
2827
|
const iconsContent = [
|
|
2825
2828
|
"import { useState } from \"react\";",
|
|
2829
|
+
"import React from \"react\";",
|
|
2826
2830
|
"import type { Meta, StoryObj } from \"@storybook/react\";",
|
|
2827
2831
|
"import * as Lucide from \"lucide-react\";",
|
|
2828
2832
|
"",
|
|
@@ -2997,6 +3001,7 @@ function writeFoundationsStories(foundations) {
|
|
|
2997
3001
|
const containerCount = gridSystem.containerCount || 0;
|
|
2998
3002
|
|
|
2999
3003
|
const gridContent = [
|
|
3004
|
+
"import React from \"react\";",
|
|
3000
3005
|
"import type { Meta, StoryObj } from \"@storybook/react\";",
|
|
3001
3006
|
"",
|
|
3002
3007
|
"const meta = { title: \"Foundations/Grid\", parameters: { layout: \"fullscreen\" } } satisfies Meta;",
|
|
@@ -3186,6 +3191,7 @@ function writeFoundationsStories(foundations) {
|
|
|
3186
3191
|
}));
|
|
3187
3192
|
const buttonsContent =
|
|
3188
3193
|
[
|
|
3194
|
+
"import React from \"react\";",
|
|
3189
3195
|
"import type { Meta, StoryObj } from \"@storybook/react\";",
|
|
3190
3196
|
"",
|
|
3191
3197
|
"const meta = { title: \"Foundations/Button Usage\", parameters: { layout: \"fullscreen\" } } satisfies Meta;",
|
|
@@ -3261,6 +3267,7 @@ function writeFoundationsStories(foundations) {
|
|
|
3261
3267
|
|
|
3262
3268
|
const usedSpacing = (foundations?.tokenUsage?.spacing || []).slice(0, 16);
|
|
3263
3269
|
const spacingContent = [
|
|
3270
|
+
"import React from \"react\";",
|
|
3264
3271
|
"import type { Meta, StoryObj } from \"@storybook/react\";",
|
|
3265
3272
|
"",
|
|
3266
3273
|
"const meta = { title: \"Foundations/Spacing & Layout\", parameters: { layout: \"fullscreen\" } } satisfies Meta;",
|
|
@@ -3368,6 +3375,7 @@ function writeFoundationsStories(foundations) {
|
|
|
3368
3375
|
const zIndexSemantics = { "z-0": "Base", "z-10": "Low / hover", "z-20": "Dropdown", "z-30": "Sticky", "z-40": "Fixed", "z-50": "Modal / overlay" };
|
|
3369
3376
|
|
|
3370
3377
|
const elevationContent = [
|
|
3378
|
+
"import React from \"react\";",
|
|
3371
3379
|
"import type { Meta, StoryObj } from \"@storybook/react\";",
|
|
3372
3380
|
"",
|
|
3373
3381
|
"const meta = { title: \"Foundations/Elevation & Shadows\", parameters: { layout: \"fullscreen\" } } satisfies Meta;",
|
|
@@ -3490,6 +3498,7 @@ function writeFoundationsStories(foundations) {
|
|
|
3490
3498
|
const usedRadius = (foundations?.tokenUsage?.radius || []).slice(0, 12);
|
|
3491
3499
|
|
|
3492
3500
|
const borderContent = [
|
|
3501
|
+
"import React from \"react\";",
|
|
3493
3502
|
"import type { Meta, StoryObj } from \"@storybook/react\";",
|
|
3494
3503
|
"",
|
|
3495
3504
|
"const meta = { title: \"Foundations/Border & Radius\", parameters: { layout: \"fullscreen\" } } satisfies Meta;",
|
|
@@ -3593,6 +3602,7 @@ function writeFoundationsStories(foundations) {
|
|
|
3593
3602
|
const motionChips = (foundations?.tokenUsage?.animations || []).slice(0, 24);
|
|
3594
3603
|
|
|
3595
3604
|
const motionContent = [
|
|
3605
|
+
"import React from \"react\";",
|
|
3596
3606
|
"import type { Meta, StoryObj } from \"@storybook/react\";",
|
|
3597
3607
|
"import { useState, useEffect } from \"react\";",
|
|
3598
3608
|
"",
|
|
@@ -3743,6 +3753,7 @@ function writeComponentSuggestionsStory(componentSuggestions) {
|
|
|
3743
3753
|
}));
|
|
3744
3754
|
const content =
|
|
3745
3755
|
[
|
|
3756
|
+
"import React from \"react\";",
|
|
3746
3757
|
"import type { Meta, StoryObj } from \"@storybook/react\";",
|
|
3747
3758
|
"import { useState } from \"react\";",
|
|
3748
3759
|
"",
|
|
@@ -4007,132 +4018,236 @@ function writeComponentInventoryStory(components, foundations) {
|
|
|
4007
4018
|
const foundationsDir = path.join(STORIES_DIR, "foundations");
|
|
4008
4019
|
ensureDir(foundationsDir);
|
|
4009
4020
|
|
|
4010
|
-
// Build per-component data
|
|
4011
4021
|
const CATEGORY_ORDER = [
|
|
4012
4022
|
"Forms and Input", "Status Indicators", "Navigation", "Overlays and Layering",
|
|
4013
4023
|
"Loading", "Messaging", "Images and Icons", "Layout and Structure", "Text and Data Display",
|
|
4014
4024
|
];
|
|
4015
|
-
const categorized = {};
|
|
4025
|
+
const categorized = {};
|
|
4016
4026
|
const foundColors = (foundations && foundations.colors) ? foundations.colors : {};
|
|
4017
4027
|
|
|
4018
|
-
// Determine which components are actually used as JSX in the project source
|
|
4019
4028
|
const componentNames = components.map(c => c.name);
|
|
4020
4029
|
const usedSet = buildComponentUsageSet(componentNames, PROJECT_ROOT);
|
|
4021
4030
|
|
|
4031
|
+
// ── Build import info for every component ──────────────────────────────────
|
|
4032
|
+
const atRoot = path.dirname(COMPONENTS_REL_DIR); // "client/src" or "src"
|
|
4033
|
+
const compBase = path.basename(COMPONENTS_REL_DIR); // "components"
|
|
4034
|
+
|
|
4035
|
+
function toPascalLocal(name) {
|
|
4036
|
+
return name.replace(/[-\s]+(.)/g, (_, c) => c.toUpperCase()).replace(/^(.)/, c => c.toUpperCase());
|
|
4037
|
+
}
|
|
4038
|
+
|
|
4039
|
+
const importInfoMap = {}; // comp.name → { identifier, importAlias, isDefault }
|
|
4040
|
+
const seenAliases = new Set();
|
|
4041
|
+
const orderedImports = []; // deduplicated
|
|
4042
|
+
|
|
4022
4043
|
for (const comp of components) {
|
|
4023
|
-
|
|
4024
|
-
const
|
|
4044
|
+
if (!comp.file) continue;
|
|
4045
|
+
const identifier = toPascalLocal(comp.name);
|
|
4046
|
+
const fileNoExt = comp.file.replace(/\.(tsx|ts|jsx|js)$/, '');
|
|
4047
|
+
const posixNoExt = fileNoExt.replace(/\\/g, '/');
|
|
4048
|
+
|
|
4049
|
+
// Derive @/ alias
|
|
4050
|
+
const absFromRoot = path.join(PROJECT_ROOT, comp.file);
|
|
4051
|
+
const isProjectRelative = fs.existsSync(absFromRoot);
|
|
4052
|
+
let importAlias;
|
|
4053
|
+
if (isProjectRelative) {
|
|
4054
|
+
const rel = path.posix.relative(atRoot, posixNoExt);
|
|
4055
|
+
importAlias = rel.startsWith('..') ? `@/${compBase}/${posixNoExt}` : `@/${rel}`;
|
|
4056
|
+
} else {
|
|
4057
|
+
importAlias = `@/${compBase}/${posixNoExt}`;
|
|
4058
|
+
}
|
|
4059
|
+
|
|
4060
|
+
// Detect default vs named export
|
|
4061
|
+
let isDefault = false;
|
|
4062
|
+
try {
|
|
4063
|
+
const srcPath = isProjectRelative
|
|
4064
|
+
? absFromRoot
|
|
4065
|
+
: path.join(PROJECT_ROOT, COMPONENTS_REL_DIR, comp.file);
|
|
4066
|
+
isDefault = /export\s+default\b/.test(fs.readFileSync(srcPath, 'utf-8'));
|
|
4067
|
+
} catch { /* keep false */ }
|
|
4068
|
+
|
|
4069
|
+
importInfoMap[comp.name] = { identifier, importAlias, isDefault };
|
|
4070
|
+
|
|
4071
|
+
if (!seenAliases.has(importAlias)) {
|
|
4072
|
+
seenAliases.add(importAlias);
|
|
4073
|
+
orderedImports.push({ identifier, importAlias, isDefault });
|
|
4074
|
+
}
|
|
4075
|
+
}
|
|
4076
|
+
|
|
4077
|
+
// Does the project use @tanstack/react-query?
|
|
4078
|
+
let needsQC = false;
|
|
4079
|
+
try {
|
|
4080
|
+
const pkg = JSON.parse(fs.readFileSync(path.join(PROJECT_ROOT, 'package.json'), 'utf-8'));
|
|
4081
|
+
const deps = { ...(pkg.dependencies || {}), ...(pkg.devDependencies || {}) };
|
|
4082
|
+
needsQC = '@tanstack/react-query' in deps;
|
|
4083
|
+
} catch { /* ignore */ }
|
|
4084
|
+
|
|
4085
|
+
// Preview scale per category
|
|
4086
|
+
const COMPACT_CATS = new Set(["Status Indicators"]);
|
|
4087
|
+
const MEDIUM_CATS = new Set(["Forms and Input", "Images and Icons", "Loading"]);
|
|
4088
|
+
|
|
4089
|
+
// ── Per-component metadata ─────────────────────────────────────────────────
|
|
4090
|
+
for (const comp of components) {
|
|
4091
|
+
const g = comp.group || "Components";
|
|
4025
4092
|
const tokens = Array.isArray(comp.tokens) ? comp.tokens : [];
|
|
4026
4093
|
const props = Array.isArray(comp.props) ? comp.props : [];
|
|
4027
4094
|
const semantic = classifyComponent(comp.name, tokens, props);
|
|
4028
4095
|
const category = semantic || g;
|
|
4029
4096
|
|
|
4030
|
-
// Resolve color tokens to hex swatches from foundations.colors (max 6)
|
|
4031
4097
|
const colorSwatches = tokens
|
|
4032
4098
|
.filter(t => !/:/.test(t) &&
|
|
4033
4099
|
/^(bg|text|border|ring|from|to|fill|stroke)-/.test(t) &&
|
|
4034
|
-
// Exclude border-side shorthands (b, t, l, r, x, y) and alignment/size text-* tokens
|
|
4035
4100
|
!/^border-[btlrxy]$/.test(t) &&
|
|
4036
4101
|
!/^text-(xs|sm|base|lg|xl|2xl|3xl|4xl|5xl|6xl|7xl|8xl|9xl|\d|left|right|center|justify|start|end|wrap|nowrap|balance|pretty|clip|ellipsis)/.test(t))
|
|
4037
4102
|
.slice(0, 6)
|
|
4038
4103
|
.map(token => {
|
|
4039
4104
|
const m = token.match(/^(?:bg|text|border|ring|from|to|fill|stroke)-(.+)$/);
|
|
4040
4105
|
let key = m ? m[1] : null;
|
|
4041
|
-
// Strip opacity modifier: "muted/20" → "muted", "primary/5" → "primary"
|
|
4042
4106
|
if (key) key = key.replace(/\/\d+$/, "");
|
|
4043
4107
|
const entry = key ? foundColors[key] : null;
|
|
4044
4108
|
const hex = entry?.hex && /^#[0-9a-fA-F]{3,8}$/.test(entry.hex) ? entry.hex : null;
|
|
4045
4109
|
return { token, hex };
|
|
4046
4110
|
})
|
|
4047
|
-
.filter(s => s.hex);
|
|
4111
|
+
.filter(s => s.hex);
|
|
4048
4112
|
|
|
4049
|
-
|
|
4050
|
-
const
|
|
4051
|
-
|
|
4052
|
-
// Whether this component is actually used as a JSX tag anywhere in the project source
|
|
4053
|
-
const active = usedSet.has(comp.name);
|
|
4113
|
+
const previewHtml = buildInventoryPreviewHtml(comp.name, category, colorSwatches, tokens.filter(t => !/:/.test(t)));
|
|
4114
|
+
const active = usedSet.has(comp.name);
|
|
4115
|
+
const previewScale = COMPACT_CATS.has(category) ? 1.0 : MEDIUM_CATS.has(category) ? 0.65 : 0.3;
|
|
4054
4116
|
|
|
4055
4117
|
if (!categorized[category]) categorized[category] = [];
|
|
4056
4118
|
categorized[category].push({
|
|
4057
|
-
name:
|
|
4058
|
-
|
|
4059
|
-
|
|
4060
|
-
|
|
4061
|
-
colorSwatches,
|
|
4062
|
-
previewHtml,
|
|
4063
|
-
active,
|
|
4119
|
+
name: comp.name, group: g,
|
|
4120
|
+
tokenCount: tokens.filter(t => !/:/.test(t)).length,
|
|
4121
|
+
propCount: props.length,
|
|
4122
|
+
colorSwatches, previewHtml, previewScale, active,
|
|
4064
4123
|
});
|
|
4065
4124
|
}
|
|
4066
4125
|
|
|
4067
4126
|
const sortedCategories = Object.keys(categorized).sort((a, b) => {
|
|
4068
|
-
const ai = CATEGORY_ORDER.indexOf(a);
|
|
4069
|
-
const bi = CATEGORY_ORDER.indexOf(b);
|
|
4127
|
+
const ai = CATEGORY_ORDER.indexOf(a), bi = CATEGORY_ORDER.indexOf(b);
|
|
4070
4128
|
if (ai >= 0 && bi >= 0) return ai - bi;
|
|
4071
|
-
|
|
4072
|
-
if (bi >= 0) return 1;
|
|
4073
|
-
return a.localeCompare(b);
|
|
4129
|
+
return (ai >= 0) ? -1 : (bi >= 0) ? 1 : a.localeCompare(b);
|
|
4074
4130
|
});
|
|
4075
4131
|
|
|
4076
4132
|
const inventoryData = sortedCategories.map(cat => ({
|
|
4077
4133
|
category: cat,
|
|
4078
|
-
// Sort: active first, then alphabetical within each group
|
|
4079
4134
|
components: categorized[cat].sort((a, b) => {
|
|
4080
4135
|
if (a.active !== b.active) return a.active ? -1 : 1;
|
|
4081
4136
|
return a.name.localeCompare(b.name);
|
|
4082
4137
|
}),
|
|
4083
4138
|
}));
|
|
4084
4139
|
|
|
4085
|
-
const totalComponents
|
|
4140
|
+
const totalComponents = components.length;
|
|
4086
4141
|
const activeComponents = [...usedSet].length;
|
|
4087
|
-
const uniqueTokens
|
|
4142
|
+
const uniqueTokens = [...new Set(
|
|
4088
4143
|
components.flatMap(c => Array.isArray(c.tokens) ? c.tokens.filter(t => !/:/.test(t)) : [])
|
|
4089
4144
|
)].length;
|
|
4090
4145
|
|
|
4146
|
+
// ── Build import lines ─────────────────────────────────────────────────────
|
|
4147
|
+
const importLines = orderedImports.map(imp =>
|
|
4148
|
+
imp.isDefault
|
|
4149
|
+
? `import ${imp.identifier} from "${imp.importAlias}";`
|
|
4150
|
+
: `import { ${imp.identifier} } from "${imp.importAlias}";`
|
|
4151
|
+
);
|
|
4152
|
+
|
|
4153
|
+
// ── PREVIEWS map entries ───────────────────────────────────────────────────
|
|
4154
|
+
const TEXT_CHILD_NAMES = new Set(['button','badge','toggle','label','link','chip','tag','pill']);
|
|
4155
|
+
const previewEntries = components
|
|
4156
|
+
.filter(comp => importInfoMap[comp.name])
|
|
4157
|
+
.map(comp => {
|
|
4158
|
+
const { identifier } = importInfoMap[comp.name];
|
|
4159
|
+
const hasText = TEXT_CHILD_NAMES.has(identifier.toLowerCase());
|
|
4160
|
+
const call = hasText
|
|
4161
|
+
? `() => React.createElement(${identifier} as any, null, "${comp.name}")`
|
|
4162
|
+
: `() => React.createElement(${identifier} as any)`;
|
|
4163
|
+
return ` ${JSON.stringify(comp.name)}: ${call}`;
|
|
4164
|
+
});
|
|
4165
|
+
|
|
4166
|
+
// ── Generate story file ────────────────────────────────────────────────────
|
|
4091
4167
|
const content = [
|
|
4168
|
+
`import React from "react";`,
|
|
4092
4169
|
`import type { Meta, StoryObj } from "@storybook/react";`,
|
|
4170
|
+
...(needsQC ? [`import { QueryClient, QueryClientProvider } from "@tanstack/react-query";`] : []),
|
|
4171
|
+
...importLines,
|
|
4093
4172
|
``,
|
|
4094
4173
|
`const meta = { title: "Foundations/Component Inventory", parameters: { layout: "fullscreen" } } satisfies Meta;`,
|
|
4095
4174
|
`export default meta;`,
|
|
4096
4175
|
`type Story = StoryObj;`,
|
|
4097
4176
|
``,
|
|
4098
|
-
|
|
4177
|
+
// ErrorBoundary — catches broken component renders and falls back to shape HTML
|
|
4178
|
+
`class _EB extends React.Component<{ children: React.ReactNode; fallback: React.ReactNode }, { err: boolean }> {`,
|
|
4179
|
+
` state = { err: false };`,
|
|
4180
|
+
` static getDerivedStateFromError() { return { err: true }; }`,
|
|
4181
|
+
` componentDidCatch() {}`,
|
|
4182
|
+
` render() { return (this.state.err ? this.props.fallback : this.props.children) as React.ReactElement; }`,
|
|
4183
|
+
`}`,
|
|
4184
|
+
// Provider wrapper — QueryClientProvider if project uses react-query, otherwise fragment
|
|
4185
|
+
...(needsQC ? [
|
|
4186
|
+
`const _qc = new QueryClient({ defaultOptions: { queries: { retry: false, staleTime: Infinity } } });`,
|
|
4187
|
+
`const _PW = ({ children }: { children: React.ReactNode }) => React.createElement(QueryClientProvider, { client: _qc }, children) as React.ReactElement;`,
|
|
4188
|
+
] : [
|
|
4189
|
+
`const _PW = ({ children }: { children: React.ReactNode }) => React.createElement(React.Fragment, null, children) as React.ReactElement;`,
|
|
4190
|
+
]),
|
|
4191
|
+
// PREVIEWS: each component renders via its real import; ErrorBoundary catches failures
|
|
4192
|
+
`const PREVIEWS: Record<string, () => React.ReactElement> = {`,
|
|
4193
|
+
...previewEntries.map(e => e + ','),
|
|
4194
|
+
`};`,
|
|
4195
|
+
``,
|
|
4196
|
+
// Inventory data (metadata only — visual rendering is done at runtime via PREVIEWS)
|
|
4197
|
+
`const inventoryData: { category: string; components: { name: string; group: string; tokenCount: number; propCount: number; colorSwatches: { token: string; hex: string }[]; previewHtml: string; previewScale: number; active: boolean }[] }[] = ${JSON.stringify(inventoryData)};`,
|
|
4099
4198
|
`const totalComponents = ${totalComponents};`,
|
|
4100
4199
|
`const activeComponents = ${activeComponents};`,
|
|
4101
4200
|
`const uniqueTokens = ${uniqueTokens};`,
|
|
4102
4201
|
``,
|
|
4202
|
+
// CardPreview: renders the actual component at the right scale, falls back to shape HTML
|
|
4203
|
+
`const CardPreview = ({ comp }: { comp: any }) => {`,
|
|
4204
|
+
` const s: number = comp.previewScale || 0.4;`,
|
|
4205
|
+
` const centered = s >= 0.9;`,
|
|
4206
|
+
` const fn = PREVIEWS[comp.name];`,
|
|
4207
|
+
` const shapeHtml = (`,
|
|
4208
|
+
` <div style={{ width: "100%", height: "100%", display: "flex", alignItems: "center", justifyContent: "center" }}`,
|
|
4209
|
+
` dangerouslySetInnerHTML={{ __html: comp.previewHtml }} />`,
|
|
4210
|
+
` );`,
|
|
4211
|
+
` const wPct = (+(100 / s).toFixed(1)) + "%";`,
|
|
4212
|
+
` const innerStyle: React.CSSProperties = centered`,
|
|
4213
|
+
` ? { position: "absolute", top: "50%", left: "50%",`,
|
|
4214
|
+
` transform: "translate(-50%, -50%) scale(" + s + ")",`,
|
|
4215
|
+
` transformOrigin: "center center", pointerEvents: "none" }`,
|
|
4216
|
+
` : { position: "absolute", top: 0, left: 0, width: wPct,`,
|
|
4217
|
+
` transform: "scale(" + s + ")",`,
|
|
4218
|
+
` transformOrigin: "top left", pointerEvents: "none" };`,
|
|
4219
|
+
` return (`,
|
|
4220
|
+
` <div style={{ height: 96, overflow: "hidden", position: "relative", background: "#fff" }}>`,
|
|
4221
|
+
` <_EB fallback={shapeHtml}>`,
|
|
4222
|
+
` {fn ? <_PW><div style={innerStyle}>{fn()}</div></_PW> : shapeHtml}`,
|
|
4223
|
+
` </_EB>`,
|
|
4224
|
+
` </div>`,
|
|
4225
|
+
` );`,
|
|
4226
|
+
`};`,
|
|
4227
|
+
`const Card = ({ comp }: { comp: any }) => (`,
|
|
4228
|
+
` <div style={{ border: "1px solid " + (comp.active ? "#e5e7eb" : "#f0f0f0"), borderRadius: 10, overflow: "hidden", background: comp.active ? "#fff" : "#fafafa", display: "flex", flexDirection: "column" as any, boxShadow: comp.active ? "0 1px 3px rgba(0,0,0,0.05)" : "none", opacity: comp.active ? 1 : 0.55 }}>`,
|
|
4229
|
+
` <div style={{ background: comp.active ? "#f8f9fa" : "#f5f5f5", borderBottom: "1px solid #f0f0f0" }}>`,
|
|
4230
|
+
` <CardPreview comp={comp} />`,
|
|
4231
|
+
` </div>`,
|
|
4232
|
+
` <div style={{ padding: "10px 12px" }}>`,
|
|
4233
|
+
` <div style={{ display: "flex", alignItems: "center", gap: 5, marginBottom: 5 }}>`,
|
|
4234
|
+
` <span style={{ fontWeight: 700, fontSize: 13, color: comp.active ? "#111" : "#9ca3af" }}>{comp.name}</span>`,
|
|
4235
|
+
` {comp.active && <span style={{ fontSize: 9, background: "#dcfce7", color: "#15803d", padding: "1px 5px", borderRadius: 4, fontWeight: 700, letterSpacing: "0.05em" }}>USED</span>}`,
|
|
4236
|
+
` </div>`,
|
|
4237
|
+
` <div style={{ display: "flex", gap: 4, flexWrap: "wrap" as any }}>`,
|
|
4238
|
+
` {comp.tokenCount > 0 && <span style={{ fontSize: 10, background: "#eff6ff", color: "#1d4ed8", padding: "2px 7px", borderRadius: 10, border: "1px solid #dbeafe" }}>{comp.tokenCount} tokens</span>}`,
|
|
4239
|
+
` {comp.colorSwatches.length > 0 && <span style={{ fontSize: 10, background: "#fef9c3", color: "#713f12", padding: "2px 7px", borderRadius: 10, border: "1px solid #fde68a" }}>{comp.colorSwatches.length} colors</span>}`,
|
|
4240
|
+
` {!comp.active && <span style={{ fontSize: 10, background: "#f3f4f6", color: "#9ca3af", padding: "2px 7px", borderRadius: 10, border: "1px solid #e5e7eb" }}>installed</span>}`,
|
|
4241
|
+
` </div>`,
|
|
4242
|
+
` </div>`,
|
|
4243
|
+
` </div>`,
|
|
4244
|
+
`);`,
|
|
4245
|
+
``,
|
|
4103
4246
|
`export const Default: Story = {`,
|
|
4104
4247
|
` render: () => {`,
|
|
4105
|
-
` const [showUnused, setShowUnused] = (window as any).__vdsShowUnused !== undefined`,
|
|
4106
|
-
` ? [(window as any).__vdsShowUnused, (v: boolean) => { (window as any).__vdsShowUnused = v; }]`,
|
|
4107
|
-
` : [false, () => {}];`,
|
|
4108
4248
|
` const [expanded, setExpanded] = React.useState(false);`,
|
|
4109
|
-
` const Card = ({ comp }: { comp: any }) => (`,
|
|
4110
|
-
` <div style={{ border: \`1px solid \${comp.active ? "#e5e7eb" : "#f0f0f0"}\`, borderRadius: 10, overflow: "hidden", background: comp.active ? "#fff" : "#fafafa", display: "flex", flexDirection: "column" as any, boxShadow: comp.active ? "0 1px 3px rgba(0,0,0,0.05)" : "none", opacity: comp.active ? 1 : 0.55 }}>`,
|
|
4111
|
-
` <div style={{ background: comp.active ? "#f8f9fa" : "#f5f5f5", borderBottom: "1px solid #f0f0f0", minHeight: 64, display: "flex", alignItems: "center", justifyContent: "center" }}`,
|
|
4112
|
-
` dangerouslySetInnerHTML={{ __html: comp.previewHtml }}`,
|
|
4113
|
-
` />`,
|
|
4114
|
-
` <div style={{ padding: "10px 12px" }}>`,
|
|
4115
|
-
` <div style={{ display: "flex", alignItems: "center", gap: 5, marginBottom: 5 }}>`,
|
|
4116
|
-
` <span style={{ fontWeight: 700, fontSize: 13, color: comp.active ? "#111" : "#9ca3af" }}>{comp.name}</span>`,
|
|
4117
|
-
` {comp.active && <span style={{ fontSize: 9, background: "#dcfce7", color: "#15803d", padding: "1px 5px", borderRadius: 4, fontWeight: 700, letterSpacing: "0.05em" }}>USED</span>}`,
|
|
4118
|
-
` </div>`,
|
|
4119
|
-
` <div style={{ display: "flex", gap: 4, flexWrap: "wrap" as any }}>`,
|
|
4120
|
-
` {comp.tokenCount > 0 && (`,
|
|
4121
|
-
` <span style={{ fontSize: 10, background: "#eff6ff", color: "#1d4ed8", padding: "2px 7px", borderRadius: 10, border: "1px solid #dbeafe" }}>{comp.tokenCount} tokens</span>`,
|
|
4122
|
-
` )}`,
|
|
4123
|
-
` {comp.colorSwatches.length > 0 && (`,
|
|
4124
|
-
` <span style={{ fontSize: 10, background: "#fef9c3", color: "#713f12", padding: "2px 7px", borderRadius: 10, border: "1px solid #fde68a" }}>{comp.colorSwatches.length} colors</span>`,
|
|
4125
|
-
` )}`,
|
|
4126
|
-
` {!comp.active && (`,
|
|
4127
|
-
` <span style={{ fontSize: 10, background: "#f3f4f6", color: "#9ca3af", padding: "2px 7px", borderRadius: 10, border: "1px solid #e5e7eb" }}>installed</span>`,
|
|
4128
|
-
` )}`,
|
|
4129
|
-
` </div>`,
|
|
4130
|
-
` </div>`,
|
|
4131
|
-
` </div>`,
|
|
4132
|
-
` );`,
|
|
4133
4249
|
` return (`,
|
|
4134
4250
|
` <div style={{ padding: 32, background: "#f8f9fa", fontFamily: "system-ui,sans-serif", color: "#111", minHeight: "100vh", width: "100%" }}>`,
|
|
4135
|
-
` {/* Header */}`,
|
|
4136
4251
|
` <div style={{ marginBottom: 40 }}>`,
|
|
4137
4252
|
` <h2 style={{ fontSize: 28, fontWeight: 700, margin: "0 0 8px" }}>Component Inventory</h2>`,
|
|
4138
4253
|
` <p style={{ fontSize: 14, color: "#6b7280", margin: "0 0 20px" }}>Components actually used in this project. <strong style={{ color: "#111" }}>USED</strong> = appears as a JSX tag in source files.</p>`,
|
|
@@ -4142,7 +4257,7 @@ function writeComponentInventoryStory(components, foundations) {
|
|
|
4142
4257
|
` { value: (totalComponents - activeComponents).toString(), label: "Installed Only", bg: "#f9fafb", fg: "#6b7280", border: "#e5e7eb" },`,
|
|
4143
4258
|
` { value: uniqueTokens.toString(), label: "Unique Tokens", bg: "#eff6ff", fg: "#1d4ed8", border: "#dbeafe" },`,
|
|
4144
4259
|
` ].map(stat => (`,
|
|
4145
|
-
` <div key={stat.label} style={{ padding: "12px 20px", background: stat.bg, borderRadius: 10, textAlign: "center" as any, minWidth: 110, border:
|
|
4260
|
+
` <div key={stat.label} style={{ padding: "12px 20px", background: stat.bg, borderRadius: 10, textAlign: "center" as any, minWidth: 110, border: "1px solid " + stat.border }}>`,
|
|
4146
4261
|
` <div style={{ fontSize: 26, fontWeight: 800, color: stat.fg, lineHeight: 1 }}>{stat.value}</div>`,
|
|
4147
4262
|
` <div style={{ fontSize: 12, color: stat.fg, marginTop: 4, opacity: 0.8 }}>{stat.label}</div>`,
|
|
4148
4263
|
` </div>`,
|
|
@@ -4152,23 +4267,22 @@ function writeComponentInventoryStory(components, foundations) {
|
|
|
4152
4267
|
` {expanded ? "Hide" : "Show"} installed-only components`,
|
|
4153
4268
|
` </button>`,
|
|
4154
4269
|
` </div>`,
|
|
4155
|
-
` {/* Category groups — active components first */}`,
|
|
4156
4270
|
` {inventoryData.map(group => {`,
|
|
4157
4271
|
` const active = group.components.filter((c: any) => c.active);`,
|
|
4158
4272
|
` const inactive = group.components.filter((c: any) => !c.active);`,
|
|
4159
4273
|
` if (active.length === 0 && !expanded) return null;`,
|
|
4160
4274
|
` return (`,
|
|
4161
|
-
`
|
|
4162
|
-
`
|
|
4163
|
-
`
|
|
4164
|
-
`
|
|
4165
|
-
`
|
|
4166
|
-
`
|
|
4167
|
-
`
|
|
4168
|
-
`
|
|
4169
|
-
`
|
|
4275
|
+
` <div key={group.category} style={{ marginBottom: 44 }}>`,
|
|
4276
|
+
` <div style={{ display: "flex", alignItems: "center", gap: 10, marginBottom: 16, paddingBottom: 10, borderBottom: "2px solid #e5e7eb" }}>`,
|
|
4277
|
+
` <h3 style={{ margin: 0, fontSize: 15, fontWeight: 700, color: "#111" }}>{group.category}</h3>`,
|
|
4278
|
+
` <span style={{ fontSize: 12, background: "#dcfce7", color: "#15803d", padding: "2px 9px", borderRadius: 12, fontWeight: 600 }}>{active.length} used</span>`,
|
|
4279
|
+
` {inactive.length > 0 && <span style={{ fontSize: 12, background: "#f3f4f6", color: "#9ca3af", padding: "2px 9px", borderRadius: 12 }}>{inactive.length} installed</span>}`,
|
|
4280
|
+
` </div>`,
|
|
4281
|
+
` <div style={{ display: "grid", gridTemplateColumns: "repeat(auto-fill, minmax(200px, 1fr))", gap: 12 }}>`,
|
|
4282
|
+
` {active.map((comp: any) => <Card key={comp.name} comp={comp} />)}`,
|
|
4283
|
+
` {expanded && inactive.map((comp: any) => <Card key={comp.name} comp={comp} />)}`,
|
|
4284
|
+
` </div>`,
|
|
4170
4285
|
` </div>`,
|
|
4171
|
-
` </div>`,
|
|
4172
4286
|
` );`,
|
|
4173
4287
|
` })}`,
|
|
4174
4288
|
` </div>`,
|
|
@@ -4227,6 +4341,7 @@ function writeChangelogStory(changelog) {
|
|
|
4227
4341
|
const entries = Array.isArray(changelog) ? changelog.map((e) => ({ version: e.version, date: e.date, changes: e.changes || [] })) : [];
|
|
4228
4342
|
const content =
|
|
4229
4343
|
[
|
|
4344
|
+
"import React from \"react\";",
|
|
4230
4345
|
"import type { Meta, StoryObj } from \"@storybook/react\";",
|
|
4231
4346
|
"",
|
|
4232
4347
|
"const meta = { title: \"Foundations/Changelog\", tags: [\"autodocs\"], parameters: { layout: \"fullscreen\" } } satisfies Meta;",
|