vibe-design-system 2.2.1 → 2.3.1

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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vibe-design-system",
3
- "version": "2.2.1",
3
+ "version": "2.3.1",
4
4
  "description": "Auto-generate design systems for vibe coding projects",
5
5
  "type": "module",
6
6
  "bin": {
@@ -750,8 +750,6 @@ function extractFoundations() {
750
750
  const radius = {};
751
751
  if (cssRadiusVars.radius) radius.base = cssRadiusVars.radius;
752
752
  if (Object.keys(borderRadiusScale).length > 0) radius.borderRadius = borderRadiusScale;
753
- const foundationsColors = { ...colors };
754
- if (Object.keys(colorsDark).length > 0) foundationsColors._dark = colorsDark;
755
753
 
756
754
  // Fallback: if no typography tokens from config, extract from Google Fonts @import
757
755
  if (Object.keys(typography).length === 0 || (!typography.body && !typography.bodyFontFamily)) {
@@ -776,6 +774,91 @@ function extractFoundations() {
776
774
  }
777
775
  }
778
776
 
777
+ // ── FALLBACK 1: Arbitrary Tailwind values ──────────────────
778
+ let allTsxFiles = [];
779
+ try {
780
+ const { globSync } = projectRequire("glob");
781
+ allTsxFiles = globSync("src/**/*.{tsx,jsx,ts,js}", {
782
+ cwd: PROJECT_ROOT,
783
+ absolute: true,
784
+ ignore: ["**/node_modules/**", "**/*.stories.*", "**/dist/**", "**/vds-output*"],
785
+ });
786
+ } catch (_) {
787
+ function walkDir(dir, list) {
788
+ if (!fs.existsSync(dir)) return;
789
+ const entries = fs.readdirSync(dir, { withFileTypes: true });
790
+ for (const e of entries) {
791
+ const full = path.join(dir, e.name);
792
+ if (e.isDirectory()) {
793
+ if (e.name !== "node_modules" && e.name !== "dist") walkDir(full, list);
794
+ } else if (/\.(tsx|jsx|ts|js)$/i.test(e.name) && !e.name.includes(".stories.")) {
795
+ list.push(full);
796
+ }
797
+ }
798
+ }
799
+ walkDir(SRC_DIR, allTsxFiles);
800
+ }
801
+
802
+ const ARBITRARY_HEX = /(?:bg|text|border|ring|fill|stroke|from|to|via)-\[#([0-9a-fA-F]{3,8})\]/g;
803
+ const arbitraryColors = new Map();
804
+ for (const file of allTsxFiles) {
805
+ try {
806
+ const content = fs.readFileSync(file, "utf-8");
807
+ for (const match of content.matchAll(ARBITRARY_HEX)) {
808
+ const hex = "#" + match[1].toUpperCase();
809
+ arbitraryColors.set(hex, (arbitraryColors.get(hex) || 0) + 1);
810
+ }
811
+ } catch (_) {}
812
+ }
813
+ const getHex = (v) => {
814
+ const x = typeof v === "string" ? v : v?.hex ?? v?.value;
815
+ return x ? String(x).toUpperCase() : "";
816
+ };
817
+ const existingHexValues = new Set([
818
+ ...Object.values(colors).map((v) => getHex(v)).filter(Boolean),
819
+ ...Object.values(colorsDark).map((v) => getHex(v)).filter(Boolean),
820
+ ]);
821
+ for (const [hex, count] of arbitraryColors) {
822
+ const hexUpper = hex.toUpperCase();
823
+ if (existingHexValues.has(hexUpper)) continue;
824
+ if (count < 1) continue;
825
+ const name = "arbitrary-" + hex.slice(1).toLowerCase();
826
+ colors[name] = { value: hex, source: "arbitrary-tailwind", frequency: count };
827
+ }
828
+ // ── FALLBACK 2: Google Fonts URL ──────────────────────────
829
+ const GFONTS_PATTERN = /family=([A-Za-z+]+)(?::.*?)?(?:&|$)/g;
830
+ const fontFileCandidates = [
831
+ ...allTsxFiles.filter(
832
+ (f) =>
833
+ f.includes("layout.") ||
834
+ f.includes("_document.") ||
835
+ f.endsWith("index.css") ||
836
+ f.includes("globals.css")
837
+ ),
838
+ path.join(PROJECT_ROOT, "index.html"),
839
+ path.join(PROJECT_ROOT, "src", "index.css"),
840
+ path.join(PROJECT_ROOT, "src", "globals.css"),
841
+ path.join(PROJECT_ROOT, "src", "App.css"),
842
+ path.join(PROJECT_ROOT, "app", "globals.css"),
843
+ ].filter((p) => fs.existsSync(p));
844
+ for (const file of fontFileCandidates) {
845
+ try {
846
+ const content = fs.readFileSync(file, "utf-8");
847
+ if (!content.includes("fonts.googleapis.com")) continue;
848
+ for (const match of content.matchAll(GFONTS_PATTERN)) {
849
+ const family = match[1].replace(/\+/g, " ");
850
+ const alreadyHas = Object.values(typography).some((v) => String(v).includes(family));
851
+ if (!alreadyHas) {
852
+ const key = "--font-" + family.toLowerCase().replace(/\s+/g, "-");
853
+ typography[key] = { family, source: "google-fonts-url" };
854
+ }
855
+ }
856
+ } catch (_) {}
857
+ }
858
+
859
+ const foundationsColors = { ...colors };
860
+ if (Object.keys(colorsDark).length > 0) foundationsColors._dark = colorsDark;
861
+
779
862
  const twTheme = getTailwindTheme();
780
863
  const normalizeThemeObj = (obj) => {
781
864
  if (!obj || typeof obj !== "object") return {};
@@ -814,56 +814,29 @@ function writeComponentSuggestionsStory(componentSuggestions) {
814
814
  }
815
815
 
816
816
  function writeChangelogStory(changelog) {
817
- if (!Array.isArray(changelog) || changelog.length === 0) return;
818
817
  const foundationsDir = path.join(STORIES_DIR, "foundations");
819
818
  ensureDir(foundationsDir);
820
- const entries = changelog.map((e) => ({
821
- version: e.version,
822
- date: e.date,
823
- changes: e.changes || [],
824
- }));
819
+ const entries = Array.isArray(changelog) ? changelog.map((e) => ({ version: e.version, date: e.date, changes: e.changes || [] })) : [];
825
820
  const content =
826
821
  [
827
822
  "import type { Meta, StoryObj } from \"@storybook/react\";",
828
823
  "",
829
- "const meta = { title: \"Foundations/Changelog\" } satisfies Meta;",
824
+ "const meta = { title: \"Foundations/Changelog\", tags: [\"autodocs\"] } satisfies Meta;",
830
825
  "export default meta;",
831
826
  "type Story = StoryObj;",
832
827
  "",
833
828
  `const changelog = ${JSON.stringify(entries)};`,
834
829
  "",
835
- "function ChangeItem({ c }) {",
836
- " if (c.type === \"color_changed\")",
837
- " return (",
838
- " <div style={{ marginBottom: 8 }}>",
839
- " <strong>{c.name}</strong>: <span style={{ color: \"#888\" }}>{c.from}</span> → <span style={{ color: \"#0f0\" }}>{c.to}</span>",
840
- " <span style={{ display: \"inline-block\", width: 16, height: 16, backgroundColor: c.from, marginLeft: 8, border: \"1px solid #333\" }} />",
841
- " <span style={{ display: \"inline-block\", width: 16, height: 16, backgroundColor: c.to, marginLeft: 4, border: \"1px solid #333\" }} />",
842
- " </div>",
843
- " );",
844
- " if (c.type === \"color_added\") return <div style={{ marginBottom: 8 }}><strong>{c.name}</strong> added: <code>{c.to}</code> <span style={{ display: \"inline-block\", width: 16, height: 16, backgroundColor: c.to, marginLeft: 4, border: \"1px solid #333\" }} /></div>;",
845
- " if (c.type === \"color_removed\") return <div style={{ marginBottom: 8, color: \"#888\" }}><strong>{c.name}</strong> removed</div>;",
846
- " if (c.type === \"typography_changed\") return <div style={{ marginBottom: 8 }}><strong>{c.key}</strong>: {c.from} → {c.to}</div>;",
847
- " if (c.type === \"component_added\") return <div style={{ marginBottom: 8, color: \"#0f0\" }}>+ {c.name}</div>;",
848
- " if (c.type === \"component_removed\") return <div style={{ marginBottom: 8, color: \"#f88\" }}>− {c.name}</div>;",
849
- " return <div style={{ marginBottom: 8 }}>{c.type}: {JSON.stringify(c)}</div>;",
850
- "}",
851
- "",
852
830
  "export const Default: Story = {",
853
831
  " render: () => (",
854
- " <div style={{ padding: 24, fontFamily: \"system-ui, sans-serif\" }}>",
855
- " <h2 style={{ marginBottom: 16 }}>VDS Changelog</h2>",
856
- " <div style={{ display: \"flex\", flexDirection: \"column\", gap: 24 }}>",
857
- " {changelog.map((e, i) => (",
858
- " <div key={i} style={{ border: \"1px solid #333\", borderRadius: 8, padding: 16, background: \"#111\" }}>",
859
- " <div style={{ fontWeight: 600, marginBottom: 4 }}>v{e.version}</div>",
860
- " <div style={{ fontSize: 12, color: \"#888\", marginBottom: 12 }}>{e.date}</div>",
861
- " {e.changes.length === 0 ? <div style={{ color: \"#666\" }}>No changes</div> : (",
862
- " <div>{e.changes.map((c, j) => <ChangeItem key={j} c={c} />)}</div>",
863
- " )}",
864
- " </div>",
865
- " ))}",
866
- " </div>",
832
+ " <div style={{ fontFamily: \"monospace\", padding: 24 }}>",
833
+ " <h2>CHANGELOG</h2>",
834
+ " {changelog.length === 0 ? <p>No changes recorded yet. Run npm run vds again after making changes.</p> : changelog.map((entry) => (",
835
+ " <div key={entry.version}>",
836
+ " <h3>v{entry.version} {entry.date}</h3>",
837
+ " {entry.changes.map((c, i) => <div key={i}>{c.type}: {c.name ?? c.key ?? \"\"}</div>)}",
838
+ " </div>",
839
+ " ))}",
867
840
  " </div>",
868
841
  " ),",
869
842
  "};",
@@ -891,10 +864,7 @@ function main() {
891
864
  if (componentSuggestions?.length) {
892
865
  writeComponentSuggestionsStory(componentSuggestions);
893
866
  }
894
- const changelog = data.changelog;
895
- if (changelog?.length) {
896
- writeChangelogStory(changelog);
897
- }
867
+ writeChangelogStory(data.changelog);
898
868
  try {
899
869
  const fd = path.join(STORIES_DIR, "foundations");
900
870
  if (fs.existsSync(fd)) {