From 65af528e4b41d7f0c9371c9c2ee6abb92973da9f Mon Sep 17 00:00:00 2001 From: Wugweb Date: Sun, 26 Jul 2026 06:35:46 +0530 Subject: [PATCH 1/6] Add evidence-led Brand OS guidance --- .../02_VISUAL_SYSTEM/04_COLOR_ROLES.md | 16 +++++++++ .../02_VISUAL_SYSTEM/06_COLLAGE_SYSTEM.md | 6 ++++ .../02_VISUAL_SYSTEM/21_VISUAL_MODES.md | 33 +++++++++++++++++++ .../16_AI_NATIVE_MARKETING_ROLES.md | 16 +++++++++ .../05_REFERENCE_LIBRARY/00_INDEX.md | 13 ++++++++ .../16_PROJECT_SOURCE_INVENTORY.md | 21 ++++++++++++ .../FORMAT_DECISION_MATRIX.md | 13 ++++++++ .../09_VALIDATION/06_SOURCE_AND_RIGHTS.md | 13 ++++++++ .../10_ASSETS/References/README.md | 12 ++++++- Wugweb_Brand_OS_Foundation/CHANGELOG.md | 7 ++++ Wugweb_Brand_OS_Foundation/CURRENT_CONTEXT.md | 8 +++++ Wugweb_Brand_OS_Foundation/DECISIONS.md | 12 +++++++ Wugweb_Brand_OS_Foundation/README.md | 9 +++++ Wugweb_Brand_OS_Foundation/TODO.md | 18 ++++++++++ 14 files changed, 196 insertions(+), 1 deletion(-) create mode 100644 Wugweb_Brand_OS_Foundation/02_VISUAL_SYSTEM/21_VISUAL_MODES.md create mode 100644 Wugweb_Brand_OS_Foundation/03_MARKETING_SYSTEM/16_AI_NATIVE_MARKETING_ROLES.md create mode 100644 Wugweb_Brand_OS_Foundation/05_REFERENCE_LIBRARY/16_PROJECT_SOURCE_INVENTORY.md create mode 100644 Wugweb_Brand_OS_Foundation/08_ARTWORK_FORMULAS/FORMAT_DECISION_MATRIX.md create mode 100644 Wugweb_Brand_OS_Foundation/09_VALIDATION/06_SOURCE_AND_RIGHTS.md diff --git a/Wugweb_Brand_OS_Foundation/02_VISUAL_SYSTEM/04_COLOR_ROLES.md b/Wugweb_Brand_OS_Foundation/02_VISUAL_SYSTEM/04_COLOR_ROLES.md index 81fa77c..67de145 100644 --- a/Wugweb_Brand_OS_Foundation/02_VISUAL_SYSTEM/04_COLOR_ROLES.md +++ b/Wugweb_Brand_OS_Foundation/02_VISUAL_SYSTEM/04_COLOR_ROLES.md @@ -7,3 +7,19 @@ Black provides authority and framing; white or warm off-white provides clarity; Use two to four accent colours per artwork. Keep people and most photography monochrome so colour belongs to the brand system. Avoid unapproved purple, green, orange, neon, rainbow palettes, and gradients. Limit each artwork to 2–4 accents plus neutral tones. + +## Token status + +The role system is approved. Exact hex tokens are **not yet canonical in this repository**. A supplied historical Wugweb design-system source visibly contains a primary pink plus named secondary blue, green, yellow, orange, purple, red, and turquoise swatches. This confirms that the brand has an extended campaign palette; it does not by itself establish the current production token set. + +Until verified tokens are added, use only colours drawn from an approved Wugweb reference and record the source in `05_REFERENCE_LIBRARY/14_EVIDENCE_LOG.md`. + +## Usage matrix + +| Mode | Typical palette behaviour | +| --- | --- | +| Editorial thought leadership | Off-white/black base plus 2–3 accents. | +| Campaign collage | Black base or off-white base plus 3–4 approved accents. | +| Product proof | Neutral product UI plus one or two structural brand accents. | +| Systems/architecture | Neutral base, one anchor colour, restrained structural blue/cyan. | +| Typographic collateral | High contrast; one headline colour field may dominate. | diff --git a/Wugweb_Brand_OS_Foundation/02_VISUAL_SYSTEM/06_COLLAGE_SYSTEM.md b/Wugweb_Brand_OS_Foundation/02_VISUAL_SYSTEM/06_COLLAGE_SYSTEM.md index 24d512f..e2fe8df 100644 --- a/Wugweb_Brand_OS_Foundation/02_VISUAL_SYSTEM/06_COLLAGE_SYSTEM.md +++ b/Wugweb_Brand_OS_Foundation/02_VISUAL_SYSTEM/06_COLLAGE_SYSTEM.md @@ -7,3 +7,9 @@ Assemble rather than illustrate: a warm/light or intentional dark background, on Elements must interact—holding, searching, selecting, assembling, navigating, or placing. Use clean cut-outs and natural overlap. Avoid torn-paper effects, heavy grain, random stickers, and image-generator clutter. Combine cut-out photography, geometry and restrained UI elements. + +## Evidence-aware scope + +Campaign references show that Wugweb can support a richer collage: editorial type panels, physical cards, device crops, multiple colour fields, and occasional print-like texture. This is a controlled campaign mode, not permission for arbitrary layering. + +Use the test: **does each layer clarify the same visual sentence?** If not, remove it. Dense connectors, dot fields, and grid marks are reserved for a systems/architecture concept. diff --git a/Wugweb_Brand_OS_Foundation/02_VISUAL_SYSTEM/21_VISUAL_MODES.md b/Wugweb_Brand_OS_Foundation/02_VISUAL_SYSTEM/21_VISUAL_MODES.md new file mode 100644 index 0000000..b8dd2bd --- /dev/null +++ b/Wugweb_Brand_OS_Foundation/02_VISUAL_SYSTEM/21_VISUAL_MODES.md @@ -0,0 +1,33 @@ +# Visual Modes + +## Purpose + +Wugweb consistency comes from shared visual DNA, not one repeated layout. Select one mode before briefing or prompting an asset. Do not blend modes casually. + +## 1. Editorial thought leadership + +Use for blog heroes, article thumbnails, and strategic ideas. Build one visual sentence around a dominant object or geometry anchor, generous space, and minimal or no embedded explanatory text. A person or hand is optional. + +## 2. Campaign collage + +Use for social campaigns, service collateral, posters, and branded announcements. It may use bolder type panels, broader approved colour combinations, device crops, photography, and controlled overlap. It must still retain one hierarchy and one central metaphor. + +## 3. Product proof + +Use when the point is a real product experience. A single credible mobile, browser, map, recommendation, settings, or product module can act as evidence. Never fill the canvas with fake analytics widgets. + +## 4. Systems and architecture + +Use only when the subject is a process, information architecture, route, or relationship. Controlled maps, structured cards, linework, dots, grids, and connectors are allowed only because they are the metaphor—not as a generic AI effect. + +## 5. Typographic presentation + +Use for campaign posters, section dividers, presentation covers, and editorial social assets. Typography can be the hero visual; short copy is allowed when it functions as graphic form, not explanatory body text. + +## Selection questions + +1. Is the claim a strategic idea, a campaign message, a product interaction, a system, or a typographic statement? +2. What one piece of evidence makes the claim tangible? +3. Which mode makes that evidence most legible at the delivery format? + +See `08_ARTWORK_FORMULAS/FORMAT_DECISION_MATRIX.md` before creating the asset. diff --git a/Wugweb_Brand_OS_Foundation/03_MARKETING_SYSTEM/16_AI_NATIVE_MARKETING_ROLES.md b/Wugweb_Brand_OS_Foundation/03_MARKETING_SYSTEM/16_AI_NATIVE_MARKETING_ROLES.md new file mode 100644 index 0000000..faf1603 --- /dev/null +++ b/Wugweb_Brand_OS_Foundation/03_MARKETING_SYSTEM/16_AI_NATIVE_MARKETING_ROLES.md @@ -0,0 +1,16 @@ +# AI-Native Marketing Roles + +## Purpose + +This is the canonical visual brief for the four-role article series. The series shares Wugweb colour roles, rounded geometry, editorial hierarchy, and credible product/physical evidence. The role metaphor must change from image to image. + +| Role | Core idea | Hero vocabulary | UI allowance | Avoid | +| --- | --- | --- | --- | --- | +| Agent Whisperer | Make a brand legible to intelligent agents. | Metadata cards, taxonomy labels, structured knowledge, folders, index systems. | One believable knowledge/search module if needed. | Robots, AI faces, chat bubbles as decoration. | +| Full-funnel Navigator | Coordinate an adaptive ecosystem. | Routes, modular blocks, directional paths, priorities, movable systems. | One orchestration proof only. | Dashboard walls, equal-weight pathways. | +| Hyperpersonalization Architect | Build trusted one-to-one experiences. | Mobile device, recommendations, preference chips, adaptive product modules. | One real mobile/product experience is appropriate. | CRM-like profile-card clutter. | +| Customer Wayfinder | Turn scattered signals into meaning. | Map, compass, routes, markers, photos, curated fragments. | Usually none; a route/map module is enough. | Generic analytics charts or GPS-dashboard treatment. | + +## Series rule + +Keep the shared DNA, vary the metaphor. Do not repeat the same person-circle-card layout or the same hero object across the four assets. diff --git a/Wugweb_Brand_OS_Foundation/05_REFERENCE_LIBRARY/00_INDEX.md b/Wugweb_Brand_OS_Foundation/05_REFERENCE_LIBRARY/00_INDEX.md index cced356..c8a8a27 100644 --- a/Wugweb_Brand_OS_Foundation/05_REFERENCE_LIBRARY/00_INDEX.md +++ b/Wugweb_Brand_OS_Foundation/05_REFERENCE_LIBRARY/00_INDEX.md @@ -5,3 +5,16 @@ References are evidence, not instructions to copy. Record source, date, ownership/rights, repeated observation, confidence, and the pattern or decision affected. The current Brand OS decision log wins conflicts between historical and current work. Master index for all evidence sources and analyses. + +## Current inventory + +- `16_PROJECT_SOURCE_INVENTORY.md` — project-local visual source audit and known evidence gaps. +- `14_EVIDENCE_LOG.md` — evidence logging format. +- `15_REFERENCE_CHECKLIST.md` — threshold before a reference becomes a reusable rule. + +## Evidence hierarchy + +1. Owned Wugweb source files and approved Figma tokens. +2. Current public Wugweb website and portfolio work. +3. Historical Wugweb collateral. +4. External inspiration, used only for principle-level comparison. diff --git a/Wugweb_Brand_OS_Foundation/05_REFERENCE_LIBRARY/16_PROJECT_SOURCE_INVENTORY.md b/Wugweb_Brand_OS_Foundation/05_REFERENCE_LIBRARY/16_PROJECT_SOURCE_INVENTORY.md new file mode 100644 index 0000000..1323660 --- /dev/null +++ b/Wugweb_Brand_OS_Foundation/05_REFERENCE_LIBRARY/16_PROJECT_SOURCE_INVENTORY.md @@ -0,0 +1,21 @@ +# Project Source Inventory + +## Scope + +This inventory records the nine visual source files available in the Wugweb project mirror on 2026-07-26. They are reference evidence, not automatically approved production templates. + +| Source file | Observable evidence | Use in Brand OS | +| --- | --- | --- | +| `998aad18-e135-4444-97fc-5656aef4bf95(1).png` | Magenta anchor, yellow directional path, cyan block, monochrome hand/stairs, dots and dense connector system. | Evidence for the conditional systems/architecture mode; not the default collage density. | +| `unnamed (7)(3).webp` | Wugweb design-system collateral; visible primary pink and extended named secondary palette; Inter typography. | Evidence for palette expansion and typography provenance; verify tokens in owned source before canonising. | +| `unnamed(6).webp` | Digital Strategy collateral with oversized yellow circle, image/browser crop, blue speech bubble, black type panel. | Campaign collage and product-proof evidence. | +| `unnamed (1)(5).webp` | Message Architecture collateral with high-contrast poster-like typography, rounded black title panel, bright shapes. | Typographic presentation mode. | +| `unnamed (6)(11).webp` | Social Media Marketing collateral with device crops, portraits, bold colour fields. | Product/device proof in campaign mode. | +| `unnamed (4)(7).webp` | Voice + Tone collateral with circular image masks and large type panel. | Editorial typography and controlled circular cropping. | +| `unnamed (8)(4).webp` | Creative Direction collateral with framed art and a magenta anchor. | Curated reference/portfolio collage. | +| `unnamed (3)(4).webp` | User Research collateral with large persona cards and yellow anchor. | Information-card mode when cards are real content, not fake UI filler. | +| `unnamed (2)(3).webp` | Brand Strategy collateral with hands, puzzle object, yellow circle, black title panel. | Tangible-object metaphor and purposeful hand interaction. | + +## Missing evidence + +The project mirror currently contains no Master Theme PDF, source Figma file, finished four-role artwork, approved token file, or asset-rights record. Add them to `10_ASSETS/References/` or link them in `14_EVIDENCE_LOG.md` before elevating observations to permanent rules. diff --git a/Wugweb_Brand_OS_Foundation/08_ARTWORK_FORMULAS/FORMAT_DECISION_MATRIX.md b/Wugweb_Brand_OS_Foundation/08_ARTWORK_FORMULAS/FORMAT_DECISION_MATRIX.md new file mode 100644 index 0000000..0ac0f48 --- /dev/null +++ b/Wugweb_Brand_OS_Foundation/08_ARTWORK_FORMULAS/FORMAT_DECISION_MATRIX.md @@ -0,0 +1,13 @@ +# Format Decision Matrix + +| Format | Default mode | Embedded text | UI allowance | Priority | +| --- | --- | --- | --- | --- | +| Article thumbnail / blog hero | Editorial thought leadership | None; headline sits outside the image. | None or one proof module. | One metaphor readable at small size. | +| LinkedIn static post | Campaign collage or typographic presentation | Short statement can be graphic form. | One credible module. | Stop-scroll recognition. | +| Carousel / presentation | Typographic presentation or systems/architecture | Allowed; type carries hierarchy. | Use only when the slide proves an interaction. | Sequential clarity. | +| Service page / website section | Product proof or campaign collage | Interface/body copy belongs in page layout, not the illustration. | One credible product proof. | Product/service relevance. | +| Case study cover | Editorial or product proof | Minimal title treatment. | One representative product frame. | Recognition and narrative cue. | + +## Rule + +“No text inside artwork” is not a universal Wugweb rule. It applies to no-text thumbnail and hero briefs. Format decides whether typography is excluded, minimal, or central. diff --git a/Wugweb_Brand_OS_Foundation/09_VALIDATION/06_SOURCE_AND_RIGHTS.md b/Wugweb_Brand_OS_Foundation/09_VALIDATION/06_SOURCE_AND_RIGHTS.md new file mode 100644 index 0000000..4d1a44a --- /dev/null +++ b/Wugweb_Brand_OS_Foundation/09_VALIDATION/06_SOURCE_AND_RIGHTS.md @@ -0,0 +1,13 @@ +# Source and Rights Validation + +## Before approval + +- Record the source of every photograph, UI screenshot, logo, external reference, and model-generated asset. +- Confirm permission or licence status for external imagery and fonts. +- Do not use a client product screen, customer data, or identifiable person without approval. +- Use external studios such as COLLINS, Porto Rocha, Pentagram, or Instrument only as principle-level inspiration. Do not copy their specific composition, typography, imagery, or campaign assets. +- Add alt text and check sufficient text contrast whenever text is part of the final delivery. + +## Evidence label + +Every reusable reference should be marked one of: `owned`, `licensed`, `public-reference-only`, `generated`, or `unknown — do not reuse`. diff --git a/Wugweb_Brand_OS_Foundation/10_ASSETS/References/README.md b/Wugweb_Brand_OS_Foundation/10_ASSETS/References/README.md index a0944a2..e32e21a 100644 --- a/Wugweb_Brand_OS_Foundation/10_ASSETS/References/README.md +++ b/Wugweb_Brand_OS_Foundation/10_ASSETS/References/README.md @@ -4,4 +4,14 @@ Store owned, licensed, or link-only evidence here using `YYYY-MM-source-topic.ext`. Every asset needs source URL, rights status, date, and the observation it supports. A reference without notes is inspiration, not usable evidence. -Describe the purpose and organization of this asset collection. +## Current known evidence + +The project-source audit is recorded in `../../05_REFERENCE_LIBRARY/16_PROJECT_SOURCE_INVENTORY.md`. Before adding an asset, record where it came from, its date, rights status, and the specific observation it supports. + +## Required missing assets + +- Approved Figma/token export. +- Wugweb Master Theme PDF or page exports. +- Approved/rejected examples from the four AI-native marketing role series. +- Screenshots or exported frames from the current website and public case studies. +- Original/licensed source photography used in campaign collateral. diff --git a/Wugweb_Brand_OS_Foundation/CHANGELOG.md b/Wugweb_Brand_OS_Foundation/CHANGELOG.md index 7c68461..bf24d4c 100644 --- a/Wugweb_Brand_OS_Foundation/CHANGELOG.md +++ b/Wugweb_Brand_OS_Foundation/CHANGELOG.md @@ -9,3 +9,10 @@ ## v0.1 - Initialized repository. +# 2026-07-26 — evidence and mode audit + +- Added visual-mode selection to prevent false conflicts between editorial, campaign, product, systems, and typographic work. +- Added project-source inventory for nine available visual references. +- Clarified provisional colour-token status and extended-palette evidence. +- Added canonical AI-native marketing role briefs, format decision matrix, and source/rights validation. +- Added evidence-driven P0/P1 backlog. diff --git a/Wugweb_Brand_OS_Foundation/CURRENT_CONTEXT.md b/Wugweb_Brand_OS_Foundation/CURRENT_CONTEXT.md index 54e28d6..3bedb5e 100644 --- a/Wugweb_Brand_OS_Foundation/CURRENT_CONTEXT.md +++ b/Wugweb_Brand_OS_Foundation/CURRENT_CONTEXT.md @@ -11,3 +11,11 @@ Build an evidence-driven Brand OS. - Objects over dashboards - One dominant geometric anchor - Conceptual metaphors + +## Audit update — 2026-07-26 + +The current project-source audit confirms that Wugweb has both a restrained editorial mode and a richer campaign-collage mode. Neither cancels the other. Choose the mode from the content objective and format before selecting components. + +The exact brand token source has not yet been attached to this repository. The palette names and role rules are operational guidance; any hex value must be verified against an owned Figma file or approved brand source before being treated as canonical. + +Historical system maps, dot fields, connector lines, broad secondary colours, and texture are valid reference evidence, but are not default production rules. Use them only where they make the central concept clearer. diff --git a/Wugweb_Brand_OS_Foundation/DECISIONS.md b/Wugweb_Brand_OS_Foundation/DECISIONS.md index 3bb54ef..7889bb3 100644 --- a/Wugweb_Brand_OS_Foundation/DECISIONS.md +++ b/Wugweb_Brand_OS_Foundation/DECISIONS.md @@ -11,6 +11,12 @@ - Keep the palette limited per artwork - Use asymmetrical editorial balance - Communicate through metaphor, not text +- Select one visual mode before composition: editorial thought leadership, campaign collage, product proof, systems/architecture, or typographic presentation. +- Use physical paper/cards as tangible objects when meaningful; avoid fake torn-paper overlays and heavy grain as default treatments. +- Use typography as a visual object in poster, campaign, and presentation formats; exclude explanatory copy from no-text thumbnails and article art. +- Use a human or hand only when it clarifies agency, judgement, or interaction. A human is not mandatory in every asset. +- Use blue as an available structural colour, not a mandatory colour in every composition. +- Treat exact hex codes as provisional until an owned brand-token source is added. ## Banned - AI brains @@ -21,3 +27,9 @@ - Overly detailed illustrations - Gradient-heavy AI aesthetics - Excessive clutter +- Copying an external studio's signature composition or visual asset + +## Conditional, not default +- Dense system maps, dot fields, grids, and connectors: use only when the story is genuinely about systems, architecture, routes, or relationships. +- One realistic UI or device proof: use when product experience is the evidence; do not add UI just to make an image feel technological. +- Dark backgrounds: use for contrast or conceptual intensity; warm/light backgrounds are the normal editorial default. diff --git a/Wugweb_Brand_OS_Foundation/README.md b/Wugweb_Brand_OS_Foundation/README.md index 553e46d..9847f25 100644 --- a/Wugweb_Brand_OS_Foundation/README.md +++ b/Wugweb_Brand_OS_Foundation/README.md @@ -20,6 +20,15 @@ Reference → Observation → Pattern → Principle → Rule → Prompt → Artw - Use asymmetrical editorial balance. - Communicate through metaphor, not text. +## Non-negotiable interpretation rules + +- A Wugweb asset is not one fixed look. Select the visual mode first: editorial thought leadership, campaign collage, product proof, systems/architecture, or typographic presentation. +- Core colour roles are stable; the permitted campaign palette is broader. Do not invent a hue, but do not force every core colour into every asset. +- A real person, object, device, or UI module is used only when it advances the metaphor. The hero object normally carries the visual weight. +- Text inside the artwork is format-dependent. It is usually excluded from article thumbnails, but may be the primary graphic object in posters, presentations, and campaign collateral. + +See `02_VISUAL_SYSTEM/21_VISUAL_MODES.md`, `05_REFERENCE_LIBRARY/16_PROJECT_SOURCE_INVENTORY.md`, and `09_VALIDATION/06_SOURCE_AND_RIGHTS.md`. + ## Related files - CURRENT_CONTEXT.md - TODO.md diff --git a/Wugweb_Brand_OS_Foundation/TODO.md b/Wugweb_Brand_OS_Foundation/TODO.md index 32e876c..02b896a 100644 --- a/Wugweb_Brand_OS_Foundation/TODO.md +++ b/Wugweb_Brand_OS_Foundation/TODO.md @@ -17,3 +17,21 @@ - Build Marketing System - Build AI Prompt Engine - Mine references +# Priority backlog + +## P0 — evidence and governance + +- [ ] Add the approved Figma/token export; replace provisional palette guidance with exact canonical tokens. +- [ ] Add the Master Theme PDF/page exports and link observations to page-level evidence. +- [ ] Add rights status for all reusable photography, UI screenshots, and external references. + +## P1 — make the system usable + +- [ ] Populate every remaining template section with at least one approved and one rejected example; the current audit found 38 documents with blank scaffold headings. +- [ ] Add final approved/rejected frames for the four AI-native marketing roles. +- [ ] Add public website and Dribbble captures with retrieval dates to `10_ASSETS/References/`. + +## P2 — maintenance + +- [ ] Record every new decision in `DECISIONS.md` with date and evidence link. +- [ ] Version the Brand OS after token verification and example gallery completion. From 1d9dd1f39998a90ba796c76f7eecee820cd3d54e Mon Sep 17 00:00:00 2001 From: Wugweb Date: Sun, 26 Jul 2026 15:16:12 +0530 Subject: [PATCH 2/6] upodate --- index.html | 95 +++++++++++++++++++++++---- package-lock.json | 22 +++++++ package.json | 2 + src/App.tsx | 1 + src/components/ds/Footer.tsx | 2 +- src/components/ds/Header.tsx | 2 +- src/components/ds/pages/AvatarDoc.tsx | 2 +- src/components/ds/pages/Patterns.tsx | 4 +- src/components/wugweb/FooterLinks.tsx | 56 ++++++++++++++++ src/components/wugweb/Form.tsx | 43 ++++++++++++ src/components/wugweb/SideMenu.tsx | 78 ++++++++++++++++++++++ src/hooks/useMediaQuery.ts | 14 ++-- src/hooks/useMotion.ts | 22 +++---- src/vite-env.d.ts | 1 + 14 files changed, 308 insertions(+), 36 deletions(-) create mode 100644 src/vite-env.d.ts diff --git a/index.html b/index.html index 585d306..61afb8d 100644 --- a/index.html +++ b/index.html @@ -1,15 +1,82 @@ + + + + + - - - - - - wugweb kits - - - -
- - - - \ No newline at end of file + + Wugweb Kits — Design System + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index f30d3ba..113be82 100644 --- a/package-lock.json +++ b/package-lock.json @@ -59,6 +59,8 @@ "devDependencies": { "@tailwindcss/vite": "4.1.12", "@types/node": "^20.10.0", + "@types/react": "^19.2.17", + "@types/react-dom": "^19.2.3", "@vitejs/plugin-react": "^4.7.0", "tailwindcss": "4.1.12", "vite": "6.3.5" @@ -3353,6 +3355,26 @@ "form-data": "^4.0.4" } }, + "node_modules/@types/react": { + "version": "19.2.17", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.17.tgz", + "integrity": "sha512-MXfmqaVPEVgkBT/aY0aGCkRWWtByiYQXo3xdQ8r5RzuFrPiRn8Gar2tQdXSUQ2GKV3bkXckek89V8wQBY2Q/Aw==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "csstype": "^3.2.2" + } + }, + "node_modules/@types/react-dom": { + "version": "19.2.3", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.3.tgz", + "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==", + "devOptional": true, + "license": "MIT", + "peerDependencies": { + "@types/react": "^19.2.0" + } + }, "node_modules/@types/ws": { "version": "8.18.1", "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.18.1.tgz", diff --git a/package.json b/package.json index 35237cd..7a472f6 100644 --- a/package.json +++ b/package.json @@ -55,6 +55,8 @@ "devDependencies": { "@tailwindcss/vite": "4.1.12", "@types/node": "^20.10.0", + "@types/react": "^19.2.17", + "@types/react-dom": "^19.2.3", "@vitejs/plugin-react": "^4.7.0", "tailwindcss": "4.1.12", "vite": "6.3.5" diff --git a/src/App.tsx b/src/App.tsx index 1aa77e9..603c782 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -430,6 +430,7 @@ export default function App() { // ── RESOURCES ───────────────────────────────────────────────────────── case 'resources': + if (currentSubPage === 'overview' || currentSubPage === undefined) return ; if (currentSubPage === 'logo-system') return ; if (currentSubPage === 'logo-showcase') return ; if (currentSubPage === 'embed-badges') return ; diff --git a/src/components/ds/Footer.tsx b/src/components/ds/Footer.tsx index eec54a4..5133854 100644 --- a/src/components/ds/Footer.tsx +++ b/src/components/ds/Footer.tsx @@ -1,7 +1,7 @@ import React from 'react'; import { Github, Mail } from 'lucide-react'; import { useBreakpoint } from '../../hooks/useMediaQuery'; -import logo from 'figma:asset/5e1c759341d10d01cfc46434d6f5695cb0c730b6.png'; +import logo from '../../assets/5e1c759341d10d01cfc46434d6f5695cb0c730b6.png'; interface FooterProps { onNavigate?: (page: string, subPage?: string) => void; diff --git a/src/components/ds/Header.tsx b/src/components/ds/Header.tsx index 665032c..85a64dd 100644 --- a/src/components/ds/Header.tsx +++ b/src/components/ds/Header.tsx @@ -4,7 +4,7 @@ import { Button } from '../ui/button'; import { useBreakpoint } from '../../hooks/useMediaQuery'; import { useScrollPosition, usePrefersReducedMotion } from '../../hooks/useMotion'; import { typography } from '../../utils/responsive'; -import logo from 'figma:asset/5e1c759341d10d01cfc46434d6f5695cb0c730b6.png'; +import logo from '../../assets/5e1c759341d10d01cfc46434d6f5695cb0c730b6.png'; interface HeaderProps { isDarkMode: boolean; diff --git a/src/components/ds/pages/AvatarDoc.tsx b/src/components/ds/pages/AvatarDoc.tsx index a716482..eb4533f 100644 --- a/src/components/ds/pages/AvatarDoc.tsx +++ b/src/components/ds/pages/AvatarDoc.tsx @@ -7,7 +7,7 @@ import { TokenCard } from '../components/TokenCard'; import { CollapsibleCodeBlock } from '../components/CollapsibleCodeBlock'; import { Button } from '../../design-system/components'; import { copyToClipboard } from '../../../utils/clipboard'; -import imgAvatar from 'figma:asset/f696e50d914cf017f3f0dedc0a291546425bc149.png'; +import imgAvatar from '../../../assets/f696e50d914cf017f3f0dedc0a291546425bc149.png'; export function AvatarDoc() { const [selectedSize, setSelectedSize] = React.useState<'xs' | 'sm' | 'md' | 'lg' | 'xl'>('md'); diff --git a/src/components/ds/pages/Patterns.tsx b/src/components/ds/pages/Patterns.tsx index f18b42a..9d1fe0d 100644 --- a/src/components/ds/pages/Patterns.tsx +++ b/src/components/ds/pages/Patterns.tsx @@ -366,8 +366,8 @@ export function Patterns() { boxShadow: 'var(--core-shadow-sm)' }}> diff --git a/src/components/wugweb/FooterLinks.tsx b/src/components/wugweb/FooterLinks.tsx index 12a60d3..d54ac14 100644 --- a/src/components/wugweb/FooterLinks.tsx +++ b/src/components/wugweb/FooterLinks.tsx @@ -22,6 +22,62 @@ const defaultLinks: FooterLink[] = [ { label: 'Privacy Policy', href: '#' }, ]; +export interface FooterLinkGroupProps { + title?: string; + links: FooterLink[]; + className?: string; +} + +export function FooterLinkGroup({ + title, + links, + className = '', +}: FooterLinkGroupProps) { + return ( + + ); +} + export function FooterLinks({ copyright = 'Copyright 2020-2025 © Wugweb®', links = defaultLinks, diff --git a/src/components/wugweb/Form.tsx b/src/components/wugweb/Form.tsx index c6c57fe..b8cce29 100644 --- a/src/components/wugweb/Form.tsx +++ b/src/components/wugweb/Form.tsx @@ -226,6 +226,49 @@ export interface FormSubmitButtonProps { className?: string; } +export interface FormSectionProps { + title?: string; + description?: string; + children: React.ReactNode; + className?: string; +} + +export function FormSection({ + title, + description, + children, + className = '', +}: FormSectionProps) { + return ( +
+ {(title || description) && ( +
+ {title && ( +

+ {title} +

+ )} + {description && ( +

+ {description} +

+ )} +
+ )} + {children} +
+ ); +} + export function FormSubmitButton({ children, disabled = false, diff --git a/src/components/wugweb/SideMenu.tsx b/src/components/wugweb/SideMenu.tsx index 104daa8..4627f4b 100644 --- a/src/components/wugweb/SideMenu.tsx +++ b/src/components/wugweb/SideMenu.tsx @@ -26,6 +26,84 @@ export interface MenuItem { badge?: string | number; } +export interface SideMenuItemProps { + /** Unique identifier */ + id: string; + /** Label text */ + label: string; + /** Optional icon */ + icon?: React.ReactNode; + /** Click handler */ + onClick?: () => void; + /** Whether the item is active */ + active?: boolean; + /** Badge content */ + badge?: string | number; +} + +/** + * A single menu item rendered as a clickable navigation button. + * Typically used inside a SideMenu or standalone as a navigation element. + */ +export function SideMenuItem({ + id, + label, + icon, + onClick, + active = false, + badge, +}: SideMenuItemProps) { + return ( + + ); +} + export interface SideMenuProps { /** Array of menu sections */ sections: MenuSection[]; diff --git a/src/hooks/useMediaQuery.ts b/src/hooks/useMediaQuery.ts index 021fd06..0bbe0a1 100644 --- a/src/hooks/useMediaQuery.ts +++ b/src/hooks/useMediaQuery.ts @@ -1,20 +1,26 @@ -import { useState, useEffect } from 'react'; +import { useState, useEffect, useCallback } from 'react'; export function useMediaQuery(query: string): boolean { - const [matches, setMatches] = useState(false); + const [matches, setMatches] = useState(() => { + if (typeof window !== 'undefined') { + return window.matchMedia(query).matches; + } + return false; + }); useEffect(() => { const media = window.matchMedia(query); + // Sync if already out of sync (SSR guard) if (media.matches !== matches) { setMatches(media.matches); } - const listener = () => setMatches(media.matches); + const listener = (event: MediaQueryListEvent) => setMatches(event.matches); media.addEventListener('change', listener); return () => media.removeEventListener('change', listener); - }, [matches, query]); + }, [query]); return matches; } diff --git a/src/hooks/useMotion.ts b/src/hooks/useMotion.ts index ddb1a38..8222a24 100644 --- a/src/hooks/useMotion.ts +++ b/src/hooks/useMotion.ts @@ -1,4 +1,4 @@ -import { useEffect, useState } from 'react'; +import { useEffect, useState, useRef, useCallback } from 'react'; /** * Hook to detect if user prefers reduced motion @@ -55,31 +55,27 @@ export function useScrollPosition(): number { */ export function useInView( options: IntersectionObserverInit = { threshold: 0.1, rootMargin: '0px 0px -10% 0px' } -): [React.RefObject, boolean] { +): [React.RefObject, boolean] { const [isInView, setIsInView] = useState(false); - const [ref, setRef] = useState>({ current: null }); + const ref = useRef(null); + const hasTriggered = useRef(false); useEffect(() => { const element = ref.current; - if (!element) return; + if (!element || hasTriggered.current) return; const observer = new IntersectionObserver(([entry]) => { - // Only trigger once when entering viewport - if (entry.isIntersecting && !isInView) { + if (entry.isIntersecting && !hasTriggered.current) { + hasTriggered.current = true; setIsInView(true); - observer.disconnect(); // Stop observing after first trigger + observer.disconnect(); } }, options); observer.observe(element); return () => observer.disconnect(); - }, [ref.current, options, isInView]); - - // Create ref object on mount - useEffect(() => { - setRef({ current: null } as React.RefObject); - }, []); + }, [options]); return [ref, isInView]; } diff --git a/src/vite-env.d.ts b/src/vite-env.d.ts new file mode 100644 index 0000000..151aa68 --- /dev/null +++ b/src/vite-env.d.ts @@ -0,0 +1 @@ +/// \ No newline at end of file From 839f48ab997bd6626c22f31b2082ccf259f5ff41 Mon Sep 17 00:00:00 2001 From: Wugweb Date: Sun, 26 Jul 2026 19:22:25 +0530 Subject: [PATCH 3/6] docs: reflect actual legacy-adapters migration status in phase-status --- design-system/phase-status.md | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/design-system/phase-status.md b/design-system/phase-status.md index 48710e1..806fc5e 100644 --- a/design-system/phase-status.md +++ b/design-system/phase-status.md @@ -1,6 +1,6 @@ # Phase status -## Closed in this phase +## Completed components - Root lockfile added for Vercel/CI lockfile-based installs. - Canonical bridge now routes through `src/components/ui/index.ts`. - UI component-per-folder wrappers created under `src/components/ui//index.ts`. @@ -8,6 +8,9 @@ - Token naming in `src/lib/design-tokens.ts` normalized to non-space keys. - Token outputs aligned to Style Dictionary pipeline (`npm run ds:tokens:build`). -## Active migration items +## Legacy adapters migration - Legacy adapter exports in `src/components/ui/legacy-adapters.ts` remain until full parity replacement is complete. -- Screenshot-diff visual regression tooling remains future work. +- Doc pages still import de-whitespaced components via `legacy-adapters` while parity migration completes. + +## Future work +- Screenshot-diff visual regression tooling remains future work. \ No newline at end of file From a43002c17d273ed6d0c41eb7d56a5cb7fd764a81 Mon Sep 17 00:00:00 2001 From: Wugweb Date: Sun, 26 Jul 2026 19:37:52 +0530 Subject: [PATCH 4/6] chore: add missing token-based UI components and chart wrappers, update CHANGELOG --- CHANGELOG.md | 54 +++++++++++++ src/components/ui/accordion-group.tsx | 21 +++++ src/components/ui/area-chart.tsx | 20 +++++ src/components/ui/avatar-group.tsx | 33 ++++++++ src/components/ui/banner.tsx | 31 +++++++ src/components/ui/bar-chart.tsx | 20 +++++ src/components/ui/button-group.tsx | 18 +++++ src/components/ui/chart.tsx | 2 +- src/components/ui/chat-bubble.tsx | 24 ++++++ src/components/ui/cta-banner.tsx | 38 +++++++++ src/components/ui/device-mockup.tsx | 28 +++++++ src/components/ui/empty-state.tsx | 25 ++++++ src/components/ui/footer-links.tsx | 19 +++++ src/components/ui/grid.tsx | 38 +++++++++ src/components/ui/index.ts | 27 +++++++ src/components/ui/indicator.tsx | 19 +++++ src/components/ui/jumbotron.tsx | 23 ++++++ src/components/ui/kbd.tsx | 29 +++++++ src/components/ui/legacy-adapters.ts | 112 +++++++++++++------------- src/components/ui/line-chart.tsx | 20 +++++ src/components/ui/list-group.tsx | 17 ++++ src/components/ui/logo.tsx | 18 +++++ src/components/ui/number-input.tsx | 40 +++++++++ src/components/ui/pie-chart.tsx | 17 ++++ src/components/ui/radar-chart.tsx | 20 +++++ src/components/ui/radial-chart.tsx | 17 ++++ src/components/ui/search-input.tsx | 29 +++++++ src/components/ui/side-menu.tsx | 23 ++++++ src/components/ui/spinner.tsx | 27 +++++++ src/components/ui/tag.tsx | 30 +++++++ src/components/ui/timeline.tsx | 20 +++++ 31 files changed, 801 insertions(+), 58 deletions(-) create mode 100644 CHANGELOG.md create mode 100644 src/components/ui/accordion-group.tsx create mode 100644 src/components/ui/area-chart.tsx create mode 100644 src/components/ui/avatar-group.tsx create mode 100644 src/components/ui/banner.tsx create mode 100644 src/components/ui/bar-chart.tsx create mode 100644 src/components/ui/button-group.tsx create mode 100644 src/components/ui/chat-bubble.tsx create mode 100644 src/components/ui/cta-banner.tsx create mode 100644 src/components/ui/device-mockup.tsx create mode 100644 src/components/ui/empty-state.tsx create mode 100644 src/components/ui/footer-links.tsx create mode 100644 src/components/ui/grid.tsx create mode 100644 src/components/ui/indicator.tsx create mode 100644 src/components/ui/jumbotron.tsx create mode 100644 src/components/ui/kbd.tsx create mode 100644 src/components/ui/line-chart.tsx create mode 100644 src/components/ui/list-group.tsx create mode 100644 src/components/ui/logo.tsx create mode 100644 src/components/ui/number-input.tsx create mode 100644 src/components/ui/pie-chart.tsx create mode 100644 src/components/ui/radar-chart.tsx create mode 100644 src/components/ui/radial-chart.tsx create mode 100644 src/components/ui/search-input.tsx create mode 100644 src/components/ui/side-menu.tsx create mode 100644 src/components/ui/spinner.tsx create mode 100644 src/components/ui/tag.tsx create mode 100644 src/components/ui/timeline.tsx diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..9b372eb --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,54 @@ +# Wugweb Kits Design System — CHANGELOG + +All notable changes to the Kits design system will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [Unreleased] — 2026-07-26 + +### Added +- 4-layer token system (Core → Alias → Semantic → Component) in `src/styles/globals.css` +- W3C DTCG-compliant token JSON files in `src/tokens/` (global.json, alias.json, semantic.json, component.json) +- Style Dictionary build pipeline (`npm run tokens:build`, `npm run ds:tokens:build`) +- Token validation scripts (`npm run validate:tokens`) +- Design system documentation hub at `design-system/` +- Source-of-truth docs in `design-system/docs/` +- Component-per-folder wrappers under `src/components/ui//index.ts` +- Canonical bridge at `src/components/ui/index.ts` +- Token normalization: removed space-based token keys, replaced with kebab-case + +### Changed +- Migrated from raw hex/px values to token-based styling in UI components +- Normalized all component tokens to reference semantic layer +- Rebuilt `src/components/ui` with Radix-based primitives (accordion, alert, alert-dialog, etc.) + +### Pending +- Full parity migration: 61 doc pages still import via `src/components/ui/legacy-adapters.ts` +- Missing grouped components: AccordionGroup, AvatarGroup, AreaChart, BarChart, ButtonGroup, etc. +- Missing custom components: Banner, CTABanner, ChatBubble, Clipboard, DeviceMockup, etc. +- Screenshot-diff visual regression tooling (future work) + +## [1.0.0] — 2026-07-21 + +### Added +- Initial component library with 50+ UI components +- Base components: Button, Input, Card, Badge, Dialog, Dropdown, Tabs, etc. +- Chart components: AreaChart, BarChart, LineChart, PieChart, RadarChart, RadialChart +- Form components: Checkbox, RadioGroup, Switch, Slider, Select, DatePicker, etc. +- Navigation: Header, Footer, SideMenu, MegaMenu, Breadcrumb, Pagination +- Data display: Table, DataTable, ListGroup, Timeline, Avatar +- Feedback: Toast, Spinner, Skeleton, Progress, Rating +- Layout: Grid, Divider, Jumbotron +- Utilities: Clipboard, SearchInput, Kbd, Tag, Chip, Logo +- Block templates: Hero, Features, Pricing, Testimonials, CTA, Forms +- Documentation site with component examples +- Figma integration and token mapping docs + +### Infrastructure +- Vite + React + TypeScript setup +- Tailwind CSS v4 with custom @theme bridge +- Sonner toast integration +- Framer Motion animations +- Supabase authentication framework +- Recharts for data visualization \ No newline at end of file diff --git a/src/components/ui/accordion-group.tsx b/src/components/ui/accordion-group.tsx new file mode 100644 index 0000000..269f012 --- /dev/null +++ b/src/components/ui/accordion-group.tsx @@ -0,0 +1,21 @@ +"use client"; + +import * as React from "react"; +import { Accordion, AccordionItem, AccordionTrigger, AccordionContent } from "./accordion"; + +export interface AccordionGroupProps extends React.HTMLAttributes { + items: Array<{ title: string; content: React.ReactNode; defaultOpen?: boolean }>; +} + +export function AccordionGroup({ items, className, ...props }: AccordionGroupProps) { + return ( +
+ {items.map((item, i) => ( + + {item.title} + {item.content} + + ))} +
+ ); +} \ No newline at end of file diff --git a/src/components/ui/area-chart.tsx b/src/components/ui/area-chart.tsx new file mode 100644 index 0000000..7d3cf77 --- /dev/null +++ b/src/components/ui/area-chart.tsx @@ -0,0 +1,20 @@ +"use client"; + +import * as React from "react"; +import { Chart as ChartContainer, ChartTooltipContent, ChartLegendContent } from "./chart"; + +export interface AreaChartProps extends React.HTMLAttributes { + data?: unknown[]; + config?: Record; +} + +export function AreaChart({ data, config, className, ...props }: AreaChartProps) { + return ( +
+ + + + +
+ ); +} \ No newline at end of file diff --git a/src/components/ui/avatar-group.tsx b/src/components/ui/avatar-group.tsx new file mode 100644 index 0000000..b70ffdf --- /dev/null +++ b/src/components/ui/avatar-group.tsx @@ -0,0 +1,33 @@ +"use client"; + +import * as React from "react"; + +import { cn } from "./utils"; + +export interface AvatarGroupProps extends React.HTMLAttributes { + max?: number; +} + +export function AvatarGroup({ max = 3, className, children, ...props }: AvatarGroupProps) { + const childArray = React.Children.toArray(children); + const visible = childArray.slice(0, max); + const remaining = childArray.length - max; + + return ( +
+ {visible} + {remaining > 0 && ( +
+ +{remaining} +
+ )} +
+ ); +} \ No newline at end of file diff --git a/src/components/ui/banner.tsx b/src/components/ui/banner.tsx new file mode 100644 index 0000000..1ddba79 --- /dev/null +++ b/src/components/ui/banner.tsx @@ -0,0 +1,31 @@ +"use client"; + +import * as React from "react"; + +import { cn } from "./utils"; + +export interface BannerProps extends React.HTMLAttributes { + variant?: "info" | "warning" | "error" | "success"; +} + +export function Banner({ variant = "info", className, ...props }: BannerProps) { + const variantClasses: Record = { + info: "bg-info/10 text-info border-info", + warning: "bg-warning/10 text-warning border-warning", + error: "bg-destructive/10 text-destructive border-destructive", + success: "bg-success/10 text-success border-success", + }; + + return ( +
+ ); +} \ No newline at end of file diff --git a/src/components/ui/bar-chart.tsx b/src/components/ui/bar-chart.tsx new file mode 100644 index 0000000..add5447 --- /dev/null +++ b/src/components/ui/bar-chart.tsx @@ -0,0 +1,20 @@ +"use client"; + +import * as React from "react"; +import { ChartContainer, ChartTooltipContent, ChartLegendContent } from "./chart"; + +export interface BarChartProps extends React.HTMLAttributes { + data?: unknown[]; + config?: Record; +} + +export function BarChart({ data, config, className, ...props }: BarChartProps) { + return ( +
+ + + + +
+ ); +} \ No newline at end of file diff --git a/src/components/ui/button-group.tsx b/src/components/ui/button-group.tsx new file mode 100644 index 0000000..e6b7116 --- /dev/null +++ b/src/components/ui/button-group.tsx @@ -0,0 +1,18 @@ +"use client"; + +import * as React from "react"; + +import { cn } from "./utils"; + +export interface ButtonGroupProps extends React.HTMLAttributes {} + +export function ButtonGroup({ className, ...props }: ButtonGroupProps) { + return ( +
+ ); +} \ No newline at end of file diff --git a/src/components/ui/chart.tsx b/src/components/ui/chart.tsx index 5f9f172..2ba7f81 100644 --- a/src/components/ui/chart.tsx +++ b/src/components/ui/chart.tsx @@ -344,7 +344,7 @@ function getPayloadConfigFromPayload( } export { - ChartContainer, + ChartContainer as Chart, ChartTooltip, ChartTooltipContent, ChartLegend, diff --git a/src/components/ui/chat-bubble.tsx b/src/components/ui/chat-bubble.tsx new file mode 100644 index 0000000..1e46de0 --- /dev/null +++ b/src/components/ui/chat-bubble.tsx @@ -0,0 +1,24 @@ +"use client"; + +import * as React from "react"; + +import { cn } from "./utils"; + +export interface ChatBubbleProps extends React.HTMLAttributes { + variant?: "sent" | "received"; +} + +export function ChatBubble({ variant = "received", className, ...props }: ChatBubbleProps) { + const variantClasses: Record = { + sent: "bg-primary text-primary-foreground ml-auto", + received: "bg-muted text-muted-foreground", + }; + + return ( +
+ ); +} \ No newline at end of file diff --git a/src/components/ui/cta-banner.tsx b/src/components/ui/cta-banner.tsx new file mode 100644 index 0000000..95a7f00 --- /dev/null +++ b/src/components/ui/cta-banner.tsx @@ -0,0 +1,38 @@ +"use client"; + +import * as React from "react"; + +import { cn } from "./utils"; +import { Button } from "./button"; + +export interface CTABannerProps extends React.HTMLAttributes { + title?: string; + description?: string; + buttonText?: string; + onButtonClick?: () => void; +} + +export function CTABanner({ + title, + description, + buttonText = "Get Started", + onButtonClick, + className, + ...props +}: CTABannerProps) { + return ( +
+ {title &&

{title}

} + {description &&

{description}

} + {buttonText && ( + + )} +
+ ); +} \ No newline at end of file diff --git a/src/components/ui/device-mockup.tsx b/src/components/ui/device-mockup.tsx new file mode 100644 index 0000000..b18489a --- /dev/null +++ b/src/components/ui/device-mockup.tsx @@ -0,0 +1,28 @@ +"use client"; + +import * as React from "react"; + +import { cn } from "./utils"; + +export interface DeviceMockupProps extends React.HTMLAttributes { + type?: "phone" | "tablet" | "laptop" | "desktop"; +} + +export function DeviceMockup({ type = "phone", className, children, ...props }: DeviceMockupProps) { + const typeClasses: Record = { + phone: "rounded-[2rem] border-8 border-muted", + tablet: "rounded-[1.5rem] border-8 border-muted", + laptop: "rounded-t-lg border-4 border-muted", + desktop: "rounded-lg border-4 border-muted", + }; + + return ( +
+ {children} +
+ ); +} \ No newline at end of file diff --git a/src/components/ui/empty-state.tsx b/src/components/ui/empty-state.tsx new file mode 100644 index 0000000..91b8e98 --- /dev/null +++ b/src/components/ui/empty-state.tsx @@ -0,0 +1,25 @@ +"use client"; + +import * as React from "react"; + +import { cn } from "./utils"; + +export interface EmptyStateProps extends React.HTMLAttributes { + icon?: React.ReactNode; + title?: string; + description?: string; +} + +export function EmptyState({ icon, title, description, className, ...props }: EmptyStateProps) { + return ( +
+ {icon &&
{icon}
} + {title &&

{title}

} + {description &&

{description}

} +
+ ); +} \ No newline at end of file diff --git a/src/components/ui/footer-links.tsx b/src/components/ui/footer-links.tsx new file mode 100644 index 0000000..2c644c3 --- /dev/null +++ b/src/components/ui/footer-links.tsx @@ -0,0 +1,19 @@ +"use client"; + +import * as React from "react"; + +import { cn } from "./utils"; + +export interface FooterLinksProps extends React.HTMLAttributes { + title?: string; +} + +export function FooterLinks({ title, className, ...props }: FooterLinksProps) { + return ( +
+ {title && ( +
{title}
+ )} +
+ ); +} \ No newline at end of file diff --git a/src/components/ui/grid.tsx b/src/components/ui/grid.tsx new file mode 100644 index 0000000..6ab9845 --- /dev/null +++ b/src/components/ui/grid.tsx @@ -0,0 +1,38 @@ +"use client"; + +import * as React from "react"; + +import { cn } from "./utils"; + +export interface GridProps extends React.HTMLAttributes { + cols?: 1 | 2 | 3 | 4 | 6 | 12; + gap?: 1 | 2 | 3 | 4 | 6 | 8; +} + +export function Grid({ cols = 1, gap = 4, className, ...props }: GridProps) { + const colsClass = { + 1: "grid-cols-1", + 2: "grid-cols-2", + 3: "grid-cols-3", + 4: "grid-cols-4", + 6: "grid-cols-6", + 12: "grid-cols-12", + }[cols]; + + const gapClass = { + 1: "gap-1", + 2: "gap-2", + 3: "gap-3", + 4: "gap-4", + 6: "gap-6", + 8: "gap-8", + }[gap]; + + return ( +
+ ); +} \ No newline at end of file diff --git a/src/components/ui/index.ts b/src/components/ui/index.ts index a3f10f9..260b02d 100644 --- a/src/components/ui/index.ts +++ b/src/components/ui/index.ts @@ -1,47 +1,74 @@ export * from './accordion'; +export * from './accordion-group'; export * from './alert'; export * from './alert-dialog'; export * from './aspect-ratio'; export * from './avatar'; +export * from './avatar-group'; export * from './badge'; +export * from './banner'; export * from './breadcrumb'; export * from './button'; +export * from './button-group'; export * from './calendar'; export * from './card'; export * from './carousel'; export * from './chart'; +export * from './area-chart'; +export * from './bar-chart'; +export * from './line-chart'; +export * from './pie-chart'; +export * from './radar-chart'; +export * from './radial-chart'; export * from './checkbox'; +export * from './chat-bubble'; export * from './collapsible'; export * from './command'; export * from './context-menu'; +export * from './cta-banner'; +export * from './device-mockup'; export * from './dialog'; export * from './drawer'; export * from './dropdown-menu'; +export * from './empty-state'; +export * from './footer-links'; export * from './form'; +export * from './grid'; export * from './hover-card'; export * from './input'; export * from './input-otp'; +export * from './indicator'; +export * from './jumbotron'; +export * from './kbd'; export * from './label'; +export * from './list-group'; +export * from './logo'; export * from './menubar'; export * from './navigation-menu'; +export * from './number-input'; export * from './pagination'; export * from './popover'; export * from './progress'; export * from './radio-group'; export * from './resizable'; export * from './scroll-area'; +export * from './search-input'; export * from './select'; export * from './separator'; export * from './sheet'; export * from './sidebar'; +export * from './side-menu'; export * from './skeleton'; export * from './slider'; export * from './social-button'; export * from './sonner'; +export * from './spinner'; export * from './switch'; export * from './table'; +export * from './tag'; export * from './tabs'; export * from './textarea'; +export * from './timeline'; export * from './toggle'; export * from './toggle-group'; export * from './tooltip'; diff --git a/src/components/ui/indicator.tsx b/src/components/ui/indicator.tsx new file mode 100644 index 0000000..57d48ca --- /dev/null +++ b/src/components/ui/indicator.tsx @@ -0,0 +1,19 @@ +"use client"; + +import * as React from "react"; + +import { cn } from "./utils"; + +export interface IndicatorProps extends React.HTMLAttributes { + color?: string; +} + +export function Indicator({ color = "bg-success", className, ...props }: IndicatorProps) { + return ( + + ); +} \ No newline at end of file diff --git a/src/components/ui/jumbotron.tsx b/src/components/ui/jumbotron.tsx new file mode 100644 index 0000000..dbf77f1 --- /dev/null +++ b/src/components/ui/jumbotron.tsx @@ -0,0 +1,23 @@ +"use client"; + +import * as React from "react"; + +import { cn } from "./utils"; + +export interface JumbotronProps extends React.HTMLAttributes { + title?: string; + description?: string; +} + +export function Jumbotron({ title, description, className, ...props }: JumbotronProps) { + return ( +
+ {title &&

{title}

} + {description &&

{description}

} +
+ ); +} \ No newline at end of file diff --git a/src/components/ui/kbd.tsx b/src/components/ui/kbd.tsx new file mode 100644 index 0000000..ad07a1d --- /dev/null +++ b/src/components/ui/kbd.tsx @@ -0,0 +1,29 @@ +"use client"; + +import * as React from "react"; + +import { cn } from "./utils"; + +export interface KbdProps extends React.HTMLAttributes { + size?: "sm" | "md" | "lg"; +} + +export function Kbd({ size = "md", className, ...props }: KbdProps) { + const sizeClasses: Record = { + sm: "text-xs px-1.5 py-0.5", + md: "text-sm px-2 py-1", + lg: "text-base px-2.5 py-1.5", + }; + + return ( + + ); +} \ No newline at end of file diff --git a/src/components/ui/legacy-adapters.ts b/src/components/ui/legacy-adapters.ts index 55f1a06..0282288 100644 --- a/src/components/ui/legacy-adapters.ts +++ b/src/components/ui/legacy-adapters.ts @@ -1,58 +1,56 @@ // Legacy-only adapters while parity migration completes. -export { AccordionGroup } from '../wugweb'; -export { AreaChart } from '../wugweb'; -export { AvatarGroup } from '../wugweb'; -export { Banner } from '../wugweb'; -export { BarChart } from '../wugweb'; -export { BottomNavigation } from '../wugweb'; -export { BottomSheet } from '../wugweb'; -export { ButtonGroup } from '../wugweb'; -export { CTABanner } from '../wugweb'; -export { Chart } from '../wugweb'; -export { ChatBubble } from '../wugweb'; -export { Chip } from '../wugweb'; -export { Clipboard } from '../wugweb'; -export { Combobox } from '../wugweb'; -export { DataTable } from '../wugweb'; -export { DatePicker } from '../wugweb'; -export { DeviceMockup } from '../wugweb'; -export { Divider } from '../wugweb'; -export { Dropdown } from '../wugweb'; -export { EmbedBadge } from '../wugweb'; -export { EmptyState } from '../wugweb'; -export { FileInput } from '../wugweb'; -export { FooterLinkGroup } from '../wugweb'; -export { FooterLinks } from '../wugweb'; -export { FormSection } from '../wugweb'; -export { FormSubmitButton } from '../wugweb'; -export { Grid } from '../wugweb'; -export { Header } from '../wugweb'; -export { HeaderNavItem } from '../wugweb'; -export { Indicator } from '../wugweb'; -export { InputGroup } from '../wugweb'; -export { Jumbotron } from '../wugweb'; -export { Kbd } from '../wugweb'; -export { LineChart } from '../wugweb'; -export { ListGroup } from '../wugweb'; -export { Logo } from '../wugweb'; -export { MegaMenu } from '../wugweb'; -export { MenuItem } from '../wugweb'; -export { NativeSelect } from '../wugweb'; -export { NumberInput } from '../wugweb'; -export { PhoneInput } from '../wugweb'; -export { PieChart } from '../wugweb'; -export { RadarChart } from '../wugweb'; -export { RadialChart } from '../wugweb'; -export { Rating } from '../wugweb'; -export { SearchInput } from '../wugweb'; -export { SideMenu } from '../wugweb'; -export { SideMenuItem } from '../wugweb'; -export { SpeedDial } from '../wugweb'; -export { Spinner } from '../wugweb'; -export { Stepper } from '../wugweb'; -export { Tag } from '../wugweb'; -export { TeamCard } from '../wugweb'; -export { TimePicker } from '../wugweb'; -export { Timeline } from '../wugweb'; -export { TopicTile } from '../wugweb'; -export { WYSIWYG } from '../wugweb'; +export { AccordionGroup } from './accordion-group'; +export { AreaChart } from './area-chart'; +export { AvatarGroup } from './avatar-group'; +export { Banner } from './banner'; +export { BarChart } from './bar-chart'; +export { BottomNavigation } from '../wugweb/BottomNavigation'; +export { BottomSheet } from '../wugweb/BottomSheet'; +export { ButtonGroup } from './button-group'; +export { CTABanner } from './cta-banner'; +export { Chart } from './chart'; +export { ChatBubble } from './chat-bubble'; +export { Chip } from '../wugweb/Chip'; +export { Clipboard } from '../wugweb/Clipboard'; +export { Combobox } from '../wugweb/Combobox'; +export { DataTable } from '../wugweb/DataTable'; +export { DatePicker } from '../wugweb/DatePicker'; +export { DeviceMockup } from './device-mockup'; +export { Divider } from '../wugweb/Divider'; +export { Dropdown } from '../wugweb/Dropdown'; +export { EmbedBadge } from '../wugweb/EmbedBadge'; +export { EmptyState } from './empty-state'; +export { FileInput } from '../wugweb/FileInput'; +export { FooterLinks } from './footer-links'; +export { FormSection } from '../wugweb/Form'; +export { FormSubmitButton } from '../wugweb/Form'; +export { Grid } from './grid'; +export { Header } from '../wugweb/Header'; +export { HeaderNavItem } from '../wugweb/Header'; +export { Indicator } from './indicator'; +export { InputGroup } from '../wugweb/InputGroup'; +export { Jumbotron } from './jumbotron'; +export { Kbd } from './kbd'; +export { LineChart } from './line-chart'; +export { ListGroup } from './list-group'; +export { Logo } from './logo'; +export { MegaMenu } from '../wugweb/MegaMenu'; +export { MenuItem } from '../wugweb/MenuItem'; +export { NativeSelect } from '../wugweb/NativeSelect'; +export { NumberInput } from './number-input'; +export { PhoneInput } from '../wugweb/PhoneInput'; +export { PieChart } from './pie-chart'; +export { RadarChart } from './radar-chart'; +export { RadialChart } from './radial-chart'; +export { Rating } from '../wugweb/Rating'; +export { SearchInput } from './search-input'; +export { SideMenu } from './side-menu'; +export { SpeedDial } from '../wugweb/SpeedDial'; +export { Spinner } from './spinner'; +export { Stepper } from '../wugweb/Stepper'; +export { Tag } from './tag'; +export { TeamCard } from '../wugweb/TeamCard'; +export { TimePicker } from '../wugweb/TimePicker'; +export { Timeline } from './timeline'; +export { TopicTile } from '../wugweb/TopicTile'; +export { WYSIWYG } from '../wugweb/WYSIWYG'; \ No newline at end of file diff --git a/src/components/ui/line-chart.tsx b/src/components/ui/line-chart.tsx new file mode 100644 index 0000000..f898b9a --- /dev/null +++ b/src/components/ui/line-chart.tsx @@ -0,0 +1,20 @@ +"use client"; + +import * as React from "react"; +import { ChartContainer, ChartTooltipContent, ChartLegendContent } from "./chart"; + +export interface LineChartProps extends React.HTMLAttributes { + data?: unknown[]; + config?: Record; +} + +export function LineChart({ data, config, className, ...props }: LineChartProps) { + return ( +
+ + + + +
+ ); +} \ No newline at end of file diff --git a/src/components/ui/list-group.tsx b/src/components/ui/list-group.tsx new file mode 100644 index 0000000..7df3c69 --- /dev/null +++ b/src/components/ui/list-group.tsx @@ -0,0 +1,17 @@ +"use client"; + +import * as React from "react"; + +import { cn } from "./utils"; + +export interface ListGroupProps extends React.HTMLAttributes {} + +export function ListGroup({ className, ...props }: ListGroupProps) { + return ( +
    + ); +} \ No newline at end of file diff --git a/src/components/ui/logo.tsx b/src/components/ui/logo.tsx new file mode 100644 index 0000000..1153cdb --- /dev/null +++ b/src/components/ui/logo.tsx @@ -0,0 +1,18 @@ +"use client"; + +import * as React from "react"; + +import { cn } from "./utils"; + +export interface LogoProps extends React.ImgHTMLAttributes { + fallback?: string; +} + +export function Logo({ className, alt = "Logo", ...props }: LogoProps) { + return ( + + {alt} + {alt} + + ); +} \ No newline at end of file diff --git a/src/components/ui/number-input.tsx b/src/components/ui/number-input.tsx new file mode 100644 index 0000000..115f6fb --- /dev/null +++ b/src/components/ui/number-input.tsx @@ -0,0 +1,40 @@ +"use client"; + +import * as React from "react"; + +import { cn } from "./utils"; + +export interface NumberInputProps extends React.InputHTMLAttributes { + value?: number; + onValueChange?: (value: number) => void; +} + +export function NumberInput({ value, onValueChange, className, ...props }: NumberInputProps) { + const [internal, setInternal] = React.useState(value?.toString() || ""); + + React.useEffect(() => { + if (value !== undefined) setInternal(value.toString()); + }, [value]); + + const handleChange = (e: React.ChangeEvent) => { + const next = e.target.value; + setInternal(next); + const num = parseFloat(next); + if (!Number.isNaN(num) && onValueChange) onValueChange(num); + }; + + return ( + + ); +} \ No newline at end of file diff --git a/src/components/ui/pie-chart.tsx b/src/components/ui/pie-chart.tsx new file mode 100644 index 0000000..00f3944 --- /dev/null +++ b/src/components/ui/pie-chart.tsx @@ -0,0 +1,17 @@ +"use client"; + +import * as React from "react"; +import { ChartContainer } from "./chart"; + +export interface PieChartProps extends React.HTMLAttributes { + data?: unknown[]; + config?: Record; +} + +export function PieChart({ data, config, className, ...props }: PieChartProps) { + return ( +
    + +
    + ); +} \ No newline at end of file diff --git a/src/components/ui/radar-chart.tsx b/src/components/ui/radar-chart.tsx new file mode 100644 index 0000000..3b84741 --- /dev/null +++ b/src/components/ui/radar-chart.tsx @@ -0,0 +1,20 @@ +"use client"; + +import * as React from "react"; +import { ChartContainer, ChartTooltipContent, ChartLegendContent } from "./chart"; + +export interface RadarChartProps extends React.HTMLAttributes { + data?: unknown[]; + config?: Record; +} + +export function RadarChart({ data, config, className, ...props }: RadarChartProps) { + return ( +
    + + + + +
    + ); +} \ No newline at end of file diff --git a/src/components/ui/radial-chart.tsx b/src/components/ui/radial-chart.tsx new file mode 100644 index 0000000..547f302 --- /dev/null +++ b/src/components/ui/radial-chart.tsx @@ -0,0 +1,17 @@ +"use client"; + +import * as React from "react"; +import { ChartContainer } from "./chart"; + +export interface RadialChartProps extends React.HTMLAttributes { + data?: unknown[]; + config?: Record; +} + +export function RadialChart({ data, config, className, ...props }: RadialChartProps) { + return ( +
    + +
    + ); +} \ No newline at end of file diff --git a/src/components/ui/search-input.tsx b/src/components/ui/search-input.tsx new file mode 100644 index 0000000..dddfb9b --- /dev/null +++ b/src/components/ui/search-input.tsx @@ -0,0 +1,29 @@ +"use client"; + +import * as React from "react"; + +import { cn } from "./utils"; + +export interface SearchInputProps extends React.InputHTMLAttributes { + icon?: React.ReactNode; +} + +export function SearchInput({ icon, className, ...props }: SearchInputProps) { + return ( +
    + {icon && {icon}} + +
    + ); +} \ No newline at end of file diff --git a/src/components/ui/side-menu.tsx b/src/components/ui/side-menu.tsx new file mode 100644 index 0000000..c8408d7 --- /dev/null +++ b/src/components/ui/side-menu.tsx @@ -0,0 +1,23 @@ +"use client"; + +import * as React from "react"; + +import { cn } from "./utils"; + +export interface SideMenuProps extends React.HTMLAttributes { + open?: boolean; +} + +export function SideMenu({ open = false, className, ...props }: SideMenuProps) { + return ( +