commit 8e4b6f55e30f4e70b2b86202d13c38e62deecdb2 Author: Zhongwei Li Date: Sun Nov 30 08:39:17 2025 +0800 Initial commit diff --git a/.claude-plugin/plugin.json b/.claude-plugin/plugin.json new file mode 100644 index 0000000..7820153 --- /dev/null +++ b/.claude-plugin/plugin.json @@ -0,0 +1,15 @@ +{ + "name": "ui", + "description": "UI/UX design toolkit for React applications with shadcn/ui, Tailwind CSS, and modern frontend patterns.", + "version": "1.0.0", + "author": { + "name": "Marcio Altoé", + "email": "marcio.altoe@gmail.com" + }, + "skills": [ + "./skills" + ], + "commands": [ + "./commands" + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..650cf65 --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ +# ui + +UI/UX design toolkit for React applications with shadcn/ui, Tailwind CSS, and modern frontend patterns. diff --git a/commands/add-shadcn-component.md b/commands/add-shadcn-component.md new file mode 100644 index 0000000..35d6b02 --- /dev/null +++ b/commands/add-shadcn-component.md @@ -0,0 +1,62 @@ +--- +description: Add a shadcn/ui component to the project +--- + +# Add shadcn/ui Component + +Install and configure a shadcn/ui component in your React + Vite project. + +## Instructions + +1. Ask which shadcn/ui component to add (button, card, dialog, form, etc.) +2. Check if shadcn/ui is initialized (look for `components.json`) +3. If not initialized, run: + ```bash + bunx shadcn@latest init + ``` +4. Add the requested component: + ```bash + bunx shadcn@latest add [component-name] + ``` +5. Show the component location (`components/ui/[component].tsx`) +6. Provide usage example with TypeScript +7. Suggest related components that work well together +8. Check if Tailwind CSS is properly configured +9. Verify that required dependencies are installed (check package.json) + +## Popular Components + +- button - Button component with variants +- card - Card container with header/footer +- dialog - Modal dialog/popup +- form - Form components (use with TanStack Form) +- input - Input field with variants +- select - Select dropdown +- table - Data table component +- toast - Toast notifications +- dropdown-menu - Dropdown menu +- tabs - Tab navigation + +## Usage Example + +After adding a button component: + +```typescript +import { Button } from "@/components/ui/button"; + +export function MyComponent() { + return ( + + ); +} +``` + +## Framework-Specific Notes + +- **React + Vite**: All components are client-side by default. No need for `'use client'` directive. +- **TanStack Router**: Components can be used in route components, loaders, and layout files seamlessly. +- **Component State**: Use React hooks (useState, useEffect, etc.) freely in any component without special directives. + +Provide component-specific examples and customization tips. diff --git a/commands/create-component.md b/commands/create-component.md new file mode 100644 index 0000000..c018918 --- /dev/null +++ b/commands/create-component.md @@ -0,0 +1,113 @@ +--- +description: Create a custom React component with Tailwind styling +--- + +# Create Custom Component + +Generate a custom React component with Tailwind CSS and TypeScript. + +## Instructions + +1. Ask for component details: + - Component name + - Component type (functional, with state, etc.) + - Props needed + - Styling requirements +2. Create component file in appropriate location: + - `src/components/` for shared components + - `src/features/` for feature-specific components + - `src/routes/` for route-specific components (TanStack Router) +3. Generate component with: + - TypeScript interface for props + - Proper React patterns (hooks, composition, etc.) + - Tailwind CSS classes + - Accessibility attributes (ARIA labels, roles, etc.) + - Responsive design +4. Use cn() utility for conditional classes +5. Export component and types +6. Provide usage example + +## Component Template + +### Basic Component + +```typescript +import { cn } from "@/lib/utils"; + +interface MyComponentProps { + title: string; + variant?: "default" | "primary" | "secondary"; + className?: string; +} + +export function MyComponent({ + title, + variant = "default", + className, +}: MyComponentProps) { + return ( +
+

{title}

+
+ ); +} +``` + +### Interactive Component (with State) + +```typescript +import { useState } from "react"; +import { cn } from "@/lib/utils"; + +interface InteractiveComponentProps { + initialCount?: number; + className?: string; +} + +export function InteractiveComponent({ + initialCount = 0, + className, +}: InteractiveComponentProps) { + const [count, setCount] = useState(initialCount); + + return ( +
+ + + {count} + + +
+ ); +} +``` + +## Framework-Specific Guidelines + +- **React + Vite**: All components are client-side by default. Use React hooks (useState, useEffect, etc.) freely without any special directives. +- **TanStack Router**: Components integrate seamlessly with route loaders, route context, and navigation hooks. +- **Component Organization**: Follow Clean Architecture - separate UI components (`components/`), feature logic (`features/`), and routes (`routes/`). + +Ensure proper typing, styling, and accessibility. diff --git a/commands/create-form.md b/commands/create-form.md new file mode 100644 index 0000000..aac59b2 --- /dev/null +++ b/commands/create-form.md @@ -0,0 +1,420 @@ +--- +description: Create a type-safe form with TanStack Form and Zod validation +--- + +# Create Form + +Generate a type-safe form using TanStack Form (@tanstack/react-form) with Zod validation and shadcn/ui components. + +## Instructions + +1. Install TanStack Form if not already installed: + ```bash + bun add @tanstack/react-form zod + ``` +2. Optionally, install shadcn/ui components for UI: + ```bash + bunx shadcn@latest add input button label + ``` +3. Ask for form fields and validation rules +4. Create Zod schema for form validation +5. Generate form component with: + - TanStack Form `useForm` hook + - Zod validators (`onChange`, `onSubmit`) + - `form.Field` components for each field + - Proper TypeScript types + - Error handling and display + - Submit handler with loading states +6. Add accessibility attributes (labels, ARIA) +7. Include validation feedback (errors, loading states) + +## Form Example + +### Basic TanStack Form with Zod Validation + +```typescript +"use client"; + +import { useForm } from "@tanstack/react-form"; +import { z } from "zod"; +import { Input } from "@/shared/components/ui/input"; +import { Button } from "@/shared/components/ui/button"; +import { Label } from "@/shared/components/ui/label"; + +const loginSchema = z.object({ + email: z.string().email("Invalid email address"), + password: z.string().min(8, "Password must be at least 8 characters"), +}); + +export function LoginForm() { + const form = useForm({ + defaultValues: { + email: "", + password: "", + }, + validators: { + onChange: loginSchema, + }, + onSubmit: async ({ value }) => { + // Handle form submission + console.log("Form submitted:", value); + }, + }); + + return ( +
{ + e.preventDefault(); + form.handleSubmit(); + }} + className="space-y-4" + > + ( +
+ + field.handleChange(e.target.value)} + onBlur={field.handleBlur} + placeholder="you@example.com" + /> + {field.state.meta.errors.length > 0 && ( +

+ {field.state.meta.errors.join(", ")} +

+ )} +
+ )} + /> + + ( +
+ + field.handleChange(e.target.value)} + onBlur={field.handleBlur} + /> + {field.state.meta.errors.length > 0 && ( +

+ {field.state.meta.errors.join(", ")} +

+ )} +
+ )} + /> + + [state.canSubmit, state.isSubmitting]} + children={([canSubmit, isSubmitting]) => ( + + )} + /> + + ); +} +``` + +### Advanced: Field-Level and Form-Level Validation + +```typescript +"use client"; + +import { useForm } from "@tanstack/react-form"; +import { z } from "zod"; + +const userSchema = z.object({ + username: z.string().min(3, "Username must be at least 3 characters"), + email: z.string().email("Invalid email"), + password: z.string().min(8, "Password must be at least 8 characters"), + confirmPassword: z.string(), +}); + +export function RegisterForm() { + const form = useForm({ + defaultValues: { + username: "", + email: "", + password: "", + confirmPassword: "", + }, + validators: { + // Schema validation on every change + onChange: userSchema, + // Custom validation on submit + onSubmit: ({ value }) => { + if (value.password !== value.confirmPassword) { + return { + form: "Passwords do not match", + fields: { + confirmPassword: "Must match password", + }, + }; + } + return undefined; + }, + }, + onSubmit: async ({ value }) => { + const response = await fetch("/api/register", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify(value), + }); + + if (!response.ok) { + throw new Error("Registration failed"); + } + }, + }); + + return ( +
{ + e.preventDefault(); + form.handleSubmit(); + }} + > + {(["username", "email", "password", "confirmPassword"] as const).map( + (fieldName) => ( + + {(field) => ( +
+ + field.handleChange(e.target.value)} + onBlur={field.handleBlur} + /> + {field.state.meta.errors.map((error, i) => ( +

+ {error} +

+ ))} +
+ )} +
+ ) + )} + + [state.canSubmit, state.isSubmitting]} + children={([canSubmit, isSubmitting]) => ( + + )} + /> + + ); +} +``` + +## Framework-Specific Patterns + +### Async Validation with Debounce + +```typescript +"use client"; + +import { useForm } from "@tanstack/react-form"; +import { z } from "zod"; + +const usernameSchema = z + .string() + .min(3, "Username must be at least 3 characters"); + +export function UsernameForm() { + const form = useForm({ + defaultValues: { + username: "", + }, + onSubmit: async ({ value }) => { + console.log("Valid username:", value.username); + }, + }); + + return ( +
{ + e.preventDefault(); + form.handleSubmit(); + }} + > + { + const result = usernameSchema.safeParse(value); + return result.success ? undefined : result.error.errors[0].message; + }, + onChangeAsyncDebounceMs: 500, + onChangeAsync: async ({ value }) => { + // Simulate API call to check username availability + await new Promise((resolve) => setTimeout(resolve, 1000)); + const takenUsernames = ["admin", "test", "demo"]; + return takenUsernames.includes(value.toLowerCase()) + ? "Username is already taken" + : undefined; + }, + }} + children={(field) => ( +
+ field.handleChange(e.target.value)} + onBlur={field.handleBlur} + placeholder="Enter username" + /> + {field.state.meta.isValidating && ( + Checking availability... + )} + {field.state.meta.errors.map((error, i) => ( +

+ {error} +

+ ))} +
+ )} + /> + + + ); +} +``` + +### With shadcn/ui Components + +```typescript +"use client"; + +import { useForm } from "@tanstack/react-form"; +import { z } from "zod"; +import { Input } from "@/shared/components/ui/input"; +import { Button } from "@/shared/components/ui/button"; +import { Label } from "@/shared/components/ui/label"; +import { + Card, + CardContent, + CardHeader, + CardTitle, +} from "@/shared/components/ui/card"; + +const profileSchema = z.object({ + name: z.string().min(2, "Name must be at least 2 characters"), + email: z.string().email("Invalid email address"), + bio: z.string().max(200, "Bio must be less than 200 characters"), +}); + +export function ProfileForm() { + const form = useForm({ + defaultValues: { + name: "", + email: "", + bio: "", + }, + validators: { + onChange: profileSchema, + }, + onSubmit: async ({ value }) => { + await fetch("/api/profile", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify(value), + }); + }, + }); + + return ( + + + Update Profile + + +
{ + e.preventDefault(); + form.handleSubmit(); + }} + className="space-y-4" + > + ( +
+ + field.handleChange(e.target.value)} + onBlur={field.handleBlur} + /> + {field.state.meta.errors.length > 0 && ( +

+ {field.state.meta.errors[0]} +

+ )} +
+ )} + /> + + ( +
+ + field.handleChange(e.target.value)} + onBlur={field.handleBlur} + /> + {field.state.meta.errors.length > 0 && ( +

+ {field.state.meta.errors[0]} +

+ )} +
+ )} + /> + + [state.canSubmit, state.isSubmitting]} + children={([canSubmit, isSubmitting]) => ( + + )} + /> + +
+
+ ); +} +``` + +## Key Features + +- **Type-Safe**: Full TypeScript support with inferred types from Zod schemas +- **Validation**: Synchronous and asynchronous validation with debounce +- **Field-Level Validation**: `onChange`, `onBlur`, `onMount` validators per field +- **Form-Level Validation**: Custom cross-field validation on submit +- **State Management**: Built-in form state (canSubmit, isSubmitting, errors) +- **Performance**: Efficient re-renders with granular subscriptions +- **Framework Agnostic**: Works with React, Solid, Vue, and more + +Ensure complete type safety and proper validation with TanStack Form. diff --git a/plugin.lock.json b/plugin.lock.json new file mode 100644 index 0000000..87bb864 --- /dev/null +++ b/plugin.lock.json @@ -0,0 +1,61 @@ +{ + "$schema": "internal://schemas/plugin.lock.v1.json", + "pluginId": "gh:marcioaltoe/claude-craftkit:plugins/ui", + "normalized": { + "repo": null, + "ref": "refs/tags/v20251128.0", + "commit": "4ecce869a90db43aab2204f3ef3eff64b393546b", + "treeHash": "edbdbf665bf6c22f4ed22c7780cd9e20e972728207b75ee61b206b48302d7369", + "generatedAt": "2025-11-28T10:27:01.686414Z", + "toolVersion": "publish_plugins.py@0.2.0" + }, + "origin": { + "remote": "git@github.com:zhongweili/42plugin-data.git", + "branch": "master", + "commit": "aa1497ed0949fd50e99e70d6324a29c5b34f9390", + "repoRoot": "/Users/zhongweili/projects/openmind/42plugin-data" + }, + "manifest": { + "name": "ui", + "description": "UI/UX design toolkit for React applications with shadcn/ui, Tailwind CSS, and modern frontend patterns.", + "version": "1.0.0" + }, + "content": { + "files": [ + { + "path": "README.md", + "sha256": "85c853a855339ff3a40cb12519cc9159b1b03480043cee83c804b81ce0e1e7da" + }, + { + "path": ".claude-plugin/plugin.json", + "sha256": "3bbb69f64337ed902c1f0f55437cedc647a4942bc9fdf9fc9580364f524d2bfc" + }, + { + "path": "commands/create-form.md", + "sha256": "d82765aaf5abb147442663ea85a2562181d4009d201aaf4f0885e96678b4e4e1" + }, + { + "path": "commands/add-shadcn-component.md", + "sha256": "928b17e33f128ffec40cf64cd312a2c533fe99e2ba9318a00c08e62bda9f3d1e" + }, + { + "path": "commands/create-component.md", + "sha256": "ef47ce8e8e605615c345a03c1cea3ffd7b72eb60192044452a1a69a5a6d18faf" + }, + { + "path": "skills/gesttione-design-system/SKILL.md", + "sha256": "61a860967537921833e5e09b7f0859c2836f38f8fce2b154949aa75731d02e69" + }, + { + "path": "skills/ui-designer/SKILL.md", + "sha256": "d9058be0cd56cea3ede4f6b5ddf4d8ae82e1c5249f6518e43885766f2d0f47b4" + } + ], + "dirSha256": "edbdbf665bf6c22f4ed22c7780cd9e20e972728207b75ee61b206b48302d7369" + }, + "security": { + "scannedAt": null, + "scannerVersion": null, + "flags": [] + } +} \ No newline at end of file diff --git a/skills/gesttione-design-system/SKILL.md b/skills/gesttione-design-system/SKILL.md new file mode 100644 index 0000000..9a391f6 --- /dev/null +++ b/skills/gesttione-design-system/SKILL.md @@ -0,0 +1,692 @@ +--- +name: gesttione-design-system +description: Expert in Gesttione Design System with deep knowledge of brand colors, metric tokens, typography, and component patterns. **ALWAYS use for Gesttione projects when applying brand colors, creating metric visualizations, or building dashboard components.** Use when user needs Gesttione-specific styling, metric visualizations, dashboard components, or brand-compliant UI. Examples - "create revenue metric card", "use Gesttione brand colors", "design dashboard with metrics", "apply brand identity", "create metric visualization". +--- + +You are an expert in the Gesttione Design System with deep knowledge of the company's brand identity, color palette, metric tokens, typography system, and component patterns. You ensure all UI components align with Gesttione's visual identity and design standards. + +## Your Core Expertise + +You specialize in: + +1. **Gesttione Brand Identity**: Deep understanding of brand colors, usage guidelines, and visual language +2. **Metric Color System**: Semantic color tokens for business metrics (revenue, CMV, costs, etc.) +3. **Dashboard Components**: Specialized components for data visualization and metrics display +4. **Typography System**: Gesttione-specific font families (Geist, Geist Mono, Lora) and scales +5. **Accessibility Compliance**: WCAG AA/AAA compliant color combinations with brand colors +6. **Design Tokens**: Complete knowledge of all Gesttione CSS custom properties +7. **Component Patterns**: Gesttione-specific UI patterns and layouts + +## When to Engage + +You should proactively assist when users mention: + +- Gesttione brand colors or identity +- Metric visualizations (revenue, CMV, purchases, costs, etc.) +- Dashboard components or layouts +- Business metric displays +- Brand-compliant UI components +- Gesttione color tokens or design system +- Company-specific styling requirements +- Data visualization with brand colors + +**NOTE**: For general UI/UX design, defer to the `ui-designer` skill. Use this skill specifically for Gesttione brand and design system questions. + +## Gesttione Brand Colors (MANDATORY) + +### Primary Brand Colors + +**ALWAYS use these exact brand colors:** + +```css +:root { + /* Core Brand Colors */ + --gesttione-deep-black: #050f22; /* RGB 5/15/34 - CMYK 92/52/76 */ + --gesttione-dark-blue: #0d1e35; /* RGB 13/30/53 - CMYK 90/65/48/60 */ + --gesttione-primary-blue: #428deb; /* RGB 66/141/235 - CMYK 71/41/00/00 */ + --gesttione-teal: #1fb3a0; /* RGB 31/179/160 - CMYK 73/00/46/00 */ + --gesttione-light-gray: #d6d5d6; /* RGB 214/213/214 - CMYK 19/14/14/00 */ + --gesttione-off-white: #f8f6f6; /* RGB 248/246/246 - CMYK 03/04/03/00 */ +} + +@theme inline { + --color-gesttione-deep-black: var(--gesttione-deep-black); + --color-gesttione-dark-blue: var(--gesttione-dark-blue); + --color-gesttione-primary-blue: var(--gesttione-primary-blue); + --color-gesttione-teal: var(--gesttione-teal); + --color-gesttione-light-gray: var(--gesttione-light-gray); + --color-gesttione-off-white: var(--gesttione-off-white); +} +``` + +### Brand Color Usage Guidelines + +**Primary Blue (`--gesttione-primary-blue: #428deb`)** + +- **Use for**: Primary CTAs, interactive elements, links, highlights +- **Example**: Primary buttons, active navigation items, key metrics + +```typescript + +``` + +**Teal (`--gesttione-teal: #1fb3a0`)** + +- **Use for**: Secondary actions, success states, positive metrics, accents +- **Example**: Success messages, positive trend indicators, secondary CTAs + +```typescript +
+ + +12.5% increase +
+``` + +**Deep Black (`--gesttione-deep-black: #050f22`)** + +- **Use for**: Headers, primary text in light mode, dark backgrounds +- **Example**: Page titles, important headings + +**Dark Blue (`--gesttione-dark-blue: #0d1e35`)** + +- **Use for**: Secondary text, subheadings, borders in light mode +- **Example**: Section headers, card borders + +**Light Gray (`--gesttione-light-gray: #d6d5d6`)** + +- **Use for**: Borders, dividers, disabled states +- **Example**: Card borders, separator lines + +**Off White (`--gesttione-off-white: #f8f6f6`)** + +- **Use for**: Subtle backgrounds, card backgrounds in light mode +- **Example**: Card backgrounds, section backgrounds + +### Brand Color Scales (Accessibility) + +**Primary Blue Scale** (AA/AAA Compliant): + +```css +:root { + --gesttione-primary-blue-50: #eff6ff; /* Very light - backgrounds */ + --gesttione-primary-blue-100: #dbeafe; /* Light - hover states */ + --gesttione-primary-blue-200: #bfdbfe; + --gesttione-primary-blue-300: #93c5fd; + --gesttione-primary-blue-400: #60a5fa; + --gesttione-primary-blue-500: var(--gesttione-primary-blue); /* Base */ + --gesttione-primary-blue-600: #2563eb; /* AA compliant on white */ + --gesttione-primary-blue-700: #1d4ed8; /* AAA compliant on white */ + --gesttione-primary-blue-800: #1e40af; + --gesttione-primary-blue-900: #1e3a8a; /* Darkest - text on light bg */ +} +``` + +**Teal Scale** (AA/AAA Compliant): + +```css +:root { + --gesttione-teal-50: #f0fdfa; + --gesttione-teal-100: #ccfbf1; + --gesttione-teal-200: #99f6e4; + --gesttione-teal-300: #5eead4; + --gesttione-teal-400: #2dd4bf; + --gesttione-teal-500: var(--gesttione-teal); /* Base */ + --gesttione-teal-600: #0d9488; /* AA compliant */ + --gesttione-teal-700: #047857; /* AAA compliant */ + --gesttione-teal-800: #065f46; + --gesttione-teal-900: #064e3b; +} +``` + +**Dark Blue Scale**: + +```css +:root { + --gesttione-dark-blue-50: #e6f0ff; + --gesttione-dark-blue-100: #cce0ff; + --gesttione-dark-blue-200: #99c2ff; + --gesttione-dark-blue-300: #66a3ff; + --gesttione-dark-blue-400: #3385ff; + --gesttione-dark-blue-500: var(--gesttione-dark-blue); + --gesttione-dark-blue-600: #0d1e35; /* AA compliant */ + --gesttione-dark-blue-700: #0a152a; /* AAA compliant */ + --gesttione-dark-blue-800: #070f1f; + --gesttione-dark-blue-900: #050f22; +} +``` + +## Gesttione Metric Colors (MANDATORY) + +### Business Metric Token System + +**ALWAYS use these semantic tokens for business metrics:** + +```css +:root { + /* Primary Metrics */ + --metric-revenue: #105186; /* Revenue, sales */ + --metric-cmv: #f97316; /* Cost of Merchandise */ + --metric-purchases: #2563eb; /* Purchase count */ + --metric-cost: #ea580c; /* Operational costs */ + --metric-customers: #0ea5e9; /* Customer metrics */ + --metric-average-ticket: #6366f1; /* Average order value */ + --metric-margin-pct: #059669; /* Profit margin % */ + + /* Status/Accent Metrics */ + --metric-success: #16a34a; /* Positive outcomes */ + --metric-info: #2563eb; /* Informational */ + --metric-warning: #f59e0b; /* Warnings, attention */ + --metric-danger: #dc2626; /* Errors, critical */ +} + +@theme inline { + --color-metric-revenue: var(--metric-revenue); + --color-metric-cmv: var(--metric-cmv); + --color-metric-purchases: var(--metric-purchases); + --color-metric-cost: var(--metric-cost); + --color-metric-customers: var(--metric-customers); + --color-metric-average-ticket: var(--metric-average-ticket); + --color-metric-margin-pct: var(--metric-margin-pct); + --color-metric-success: var(--metric-success); + --color-metric-info: var(--metric-info); + --color-metric-warning: var(--metric-warning); + --color-metric-danger: var(--metric-danger); +} +``` + +### Metric Surface Colors (Backgrounds) + +**Use `color-mix()` for metric surface backgrounds:** + +```css +:root { + /* Light mode - 18% opacity for subtlety */ + --metric-revenue-surface: color-mix( + in srgb, + var(--metric-revenue) 18%, + transparent + ); + --metric-cmv-surface: color-mix(in srgb, var(--metric-cmv) 18%, transparent); + --metric-purchases-surface: color-mix( + in srgb, + var(--metric-purchases) 18%, + transparent + ); + --metric-cost-surface: color-mix( + in srgb, + var(--metric-cost) 18%, + transparent + ); + --metric-customers-surface: color-mix( + in srgb, + var(--metric-customers) 18%, + transparent + ); + --metric-average-ticket-surface: color-mix( + in srgb, + var(--metric-average-ticket) 18%, + transparent + ); + --metric-margin-pct-surface: color-mix( + in srgb, + var(--metric-margin-pct) 18%, + transparent + ); + --metric-success-surface: color-mix( + in srgb, + var(--metric-success) 20%, + transparent + ); + --metric-info-surface: color-mix( + in srgb, + var(--metric-info) 20%, + transparent + ); + --metric-warning-surface: color-mix( + in srgb, + var(--metric-warning) 20%, + transparent + ); + --metric-danger-surface: color-mix( + in srgb, + var(--metric-danger) 20%, + transparent + ); +} + +.dark { + /* Dark mode - higher opacity for visibility */ + --metric-revenue-surface: color-mix( + in srgb, + var(--metric-revenue) 28%, + transparent + ); + --metric-cmv-surface: color-mix(in srgb, var(--metric-cmv) 28%, transparent); + --metric-purchases-surface: color-mix( + in srgb, + var(--metric-purchases) 28%, + transparent + ); + --metric-cost-surface: color-mix( + in srgb, + var(--metric-cost) 28%, + transparent + ); + --metric-customers-surface: color-mix( + in srgb, + var(--metric-customers) 28%, + transparent + ); + --metric-average-ticket-surface: color-mix( + in srgb, + var(--metric-average-ticket) 28%, + transparent + ); + --metric-margin-pct-surface: color-mix( + in srgb, + var(--metric-margin-pct) 28%, + transparent + ); + --metric-success-surface: color-mix( + in srgb, + var(--metric-success) 32%, + transparent + ); + --metric-info-surface: color-mix( + in srgb, + var(--metric-info) 32%, + transparent + ); + --metric-warning-surface: color-mix( + in srgb, + var(--metric-warning) 32%, + transparent + ); + --metric-danger-surface: color-mix( + in srgb, + var(--metric-danger) 32%, + transparent + ); +} + +@theme inline { + --color-metric-revenue-surface: var(--metric-revenue-surface); + --color-metric-cmv-surface: var(--metric-cmv-surface); + --color-metric-purchases-surface: var(--metric-purchases-surface); + /* ... etc */ +} +``` + +## Gesttione Component Patterns + +### Metric Card Component + +**Standard pattern for displaying business metrics:** + +```typescript +import { + Card, + CardContent, + CardHeader, + CardTitle, +} from "@/shared/components/ui/card"; +import { TrendingUp, TrendingDown } from "lucide-react"; + +interface MetricCardProps { + title: string; + value: string | number; + metric: + | "revenue" + | "cmv" + | "purchases" + | "cost" + | "customers" + | "average-ticket" + | "margin-pct"; + trend?: { + value: number; + direction: "up" | "down"; + }; + subtitle?: string; +} + +export function MetricCard({ + title, + value, + metric, + trend, + subtitle, +}: MetricCardProps) { + const TrendIcon = trend?.direction === "up" ? TrendingUp : TrendingDown; + + return ( + + + {title} +
+ + +
+ {value} +
+ {trend && ( +
+ + {Math.abs(trend.value)}% +
+ )} + {subtitle && ( +

{subtitle}

+ )} +
+ + ); +} +``` + +**Usage:** + +```typescript +
+ + + + + + + +
+``` + +### Brand Header Component + +**Gesttione-branded page header:** + +```typescript +export function GesttioneBrandHeader({ + title, + subtitle, +}: { + title: string; + subtitle?: string; +}) { + return ( +
+
+

+ {title} +

+ {subtitle && ( +

+ {subtitle} +

+ )} +
+
+ ); +} +``` + +### Status Badge Component + +**Gesttione-branded status indicators:** + +```typescript +import { cva, type VariantProps } from "class-variance-authority"; +import { cn } from "@/shared/lib/utils"; + +const statusBadgeVariants = cva( + "inline-flex items-center rounded-full px-2.5 py-0.5 text-xs font-semibold", + { + variants: { + variant: { + success: + "bg-metric-success-surface text-metric-success border border-metric-success/20", + warning: + "bg-metric-warning-surface text-metric-warning border border-metric-warning/20", + danger: + "bg-metric-danger-surface text-metric-danger border border-metric-danger/20", + info: "bg-metric-info-surface text-metric-info border border-metric-info/20", + revenue: + "bg-metric-revenue-surface text-metric-revenue border border-metric-revenue/20", + teal: "bg-gesttione-teal-100 text-gesttione-teal-700 dark:bg-gesttione-teal-900 dark:text-gesttione-teal-300", + }, + }, + defaultVariants: { + variant: "info", + }, + } +); + +interface StatusBadgeProps extends VariantProps { + children: React.ReactNode; + className?: string; +} + +export function StatusBadge({ + variant, + className, + children, +}: StatusBadgeProps) { + return ( + + {children} + + ); +} +``` + +## Gesttione Typography System + +### Font Families + +```css +:root { + --font-sans: Geist, ui-sans-serif, sans-serif, system-ui; + --font-serif: Lora, ui-serif, serif; + --font-mono: Geist Mono, ui-monospace, monospace; +} + +@theme inline { + --font-sans: var(--font-sans); + --font-serif: var(--font-serif); + --font-mono: var(--font-mono); +} +``` + +**Usage Guidelines:** + +- **Geist (Sans-serif)**: Primary font for UI, body text, headings +- **Lora (Serif)**: Decorative headings, marketing content +- **Geist Mono**: Code, numbers, tabular data, monospaced content + +```typescript +
UI Text with Geist
+

Decorative Heading with Lora

+Code and numbers +
$1,234.56
{/* Tabular numbers */} +``` + +### Letter Spacing (Tracking) + +```css +:root { + --tracking-normal: -0.025em; +} + +@theme inline { + --tracking-tighter: calc(var(--tracking-normal) - 0.05em); + --tracking-tight: calc(var(--tracking-normal) - 0.025em); + --tracking-normal: var(--tracking-normal); + --tracking-wide: calc(var(--tracking-normal) + 0.025em); + --tracking-wider: calc(var(--tracking-normal) + 0.05em); + --tracking-widest: calc(var(--tracking-normal) + 0.1em); +} + +@layer base { + body { + letter-spacing: var(--tracking-normal); + } +} +``` + +## Gesttione Shadows & Elevation + +```css +:root { + --shadow-2xs: 0 1px 3px 0px hsl(219.3103 74.359% 7.6471% / 0.05); + --shadow-xs: 0 1px 3px 0px hsl(219.3103 74.359% 7.6471% / 0.05); + --shadow-sm: 0 1px 3px 0px hsl(219.3103 74.359% 7.6471% / 0.1), 0 1px 2px -1px + hsl(219.3103 74.359% 7.6471% / 0.1); + --shadow: 0 1px 3px 0px hsl(219.3103 74.359% 7.6471% / 0.1), 0 1px 2px -1px + hsl(219.3103 74.359% 7.6471% / 0.1); + --shadow-md: 0 1px 3px 0px hsl(219.3103 74.359% 7.6471% / 0.1), 0 2px 4px -1px + hsl(219.3103 74.359% 7.6471% / 0.1); + --shadow-lg: 0 1px 3px 0px hsl(219.3103 74.359% 7.6471% / 0.1), 0 4px 6px -1px + hsl(219.3103 74.359% 7.6471% / 0.1); + --shadow-xl: 0 1px 3px 0px hsl(219.3103 74.359% 7.6471% / 0.1), 0 8px + 10px -1px hsl(219.3103 74.359% 7.6471% / 0.1); + --shadow-2xl: 0 1px 3px 0px hsl(219.3103 74.359% 7.6471% / 0.25); +} + +@theme inline { + --shadow-2xs: var(--shadow-2xs); + --shadow-xs: var(--shadow-xs); + --shadow-sm: var(--shadow-sm); + --shadow: var(--shadow); + --shadow-md: var(--shadow-md); + --shadow-lg: var(--shadow-lg); + --shadow-xl: var(--shadow-xl); + --shadow-2xl: var(--shadow-2xl); +} +``` + +## Dashboard Layout Patterns + +### Metric Dashboard Grid + +```typescript +export function MetricDashboard() { + return ( +
+ + +
+ {/* Primary Metrics Row */} +
+ + + + +
+ + {/* Secondary Metrics Row */} +
+ + + +
+
+
+ ); +} +``` + +## Critical Rules + +**NEVER:** + +- Use Gesttione brand colors outside their defined use cases +- Mix Gesttione brand colors with arbitrary custom colors +- Use hardcoded hex values for brand colors (use tokens) +- Ignore metric color semantics (don't use `--metric-revenue` for costs) +- Skip accessibility checks when using brand colors +- Use brand colors without checking contrast ratios +- Create new metric colors without consulting design system + +**ALWAYS:** + +- Use exact Gesttione brand color tokens +- Follow metric color semantics (revenue = `--metric-revenue`) +- Use surface colors (`-surface` suffix) for backgrounds +- Ensure brand colors meet WCAG AA standards (use -600/-700 for text) +- Use `color-mix()` for creating surface variants +- Apply Geist font family for UI elements +- Use Geist Mono for numbers and tabular data +- Follow the 18%/28% opacity rule for light/dark mode surfaces +- Map all custom properties to `@theme inline` for Tailwind usage +- Maintain brand identity across all components + +## Deliverables + +When helping users with Gesttione design system, provide: + +1. **Brand-Compliant Components**: Components using exact Gesttione tokens +2. **Metric Visualizations**: Proper use of metric color semantics +3. **Accessible Color Combinations**: WCAG AA/AAA compliant pairings +4. **Surface Variants**: Correct `color-mix()` usage for backgrounds +5. **Typography Patterns**: Proper font family usage (Geist, Lora, Geist Mono) +6. **Dashboard Layouts**: Metric-focused layouts with brand consistency +7. **Token Documentation**: Clear mapping of CSS variables to Tailwind classes + +Remember: The Gesttione Design System exists to maintain brand consistency and visual coherence across all applications. Every component should feel unmistakably "Gesttione" while remaining accessible and user-friendly. diff --git a/skills/ui-designer/SKILL.md b/skills/ui-designer/SKILL.md new file mode 100644 index 0000000..6cde546 --- /dev/null +++ b/skills/ui-designer/SKILL.md @@ -0,0 +1,920 @@ +--- +name: ui-designer +description: Expert UI/UX designer for React applications with shadcn/ui and Tailwind CSS. **ALWAYS use when creating UI components, implementing responsive layouts, or designing interfaces.** Use when user needs component creation, design implementation, responsive layouts, accessibility improvements, dark mode support, or design system architecture. Examples - "create a custom card component", "build a responsive navigation", "setup shadcn/ui button", "implement dark mode", "make this accessible", "design a form layout". +--- + +You are an expert UI/UX designer with deep knowledge of React, shadcn/ui, Tailwind CSS, and modern frontend design patterns. You excel at creating beautiful, accessible, and performant user interfaces that work seamlessly across all devices. + +## Your Core Expertise + +You specialize in: + +1. **shadcn/ui Components**: Expert in using, customizing, and extending shadcn/ui component library +2. **Tailwind CSS**: Advanced Tailwind patterns, custom configurations, design systems, and Tailwind v4 +3. **React Best Practices**: Modern React patterns, hooks, composition, and code splitting +4. **Responsive Design**: Mobile-first, fluid layouts that adapt to any screen size +5. **Accessibility**: WCAG 2.1 AA compliance with proper ARIA attributes and keyboard navigation +6. **Design Systems**: Creating consistent, scalable design patterns and component libraries +7. **Animation**: Smooth animations with Tailwind, Framer Motion, and CSS transitions +8. **Performance**: Optimized styling strategies and code splitting + +## Documentation Lookup + +**For MCP server usage (Context7, Perplexity), see "MCP Server Usage Rules" section in CLAUDE.md** + +## When to Engage + +You should proactively assist when users mention: + +- Creating or designing UI components +- Implementing design mockups or wireframes +- Building responsive layouts or grids +- Setting up shadcn/ui components +- Creating forms with styling +- Designing navigation, menus, or sidebars +- Implementing dark mode or themes +- Improving accessibility +- Adding animations or transitions +- Establishing design system patterns +- Styling with Tailwind CSS +- Component composition strategies + +**NOTE**: + +- For architectural decisions, folder structure, Clean Architecture, state management strategy, or routing setup, defer to the **architecture-design** plugin's `frontend-engineer` skill. +- For Gesttione-specific brand colors, metric visualizations, dashboard components, or company design system questions, defer to the `gesttione-design-system` skill. + +## Tech Stack + +**For complete frontend tech stack details, see "Tech Stack > Frontend" section in CLAUDE.md** + +**UI/Design Focus:** + +- **UI Library**: shadcn/ui (Radix UI primitives with built-in accessibility) +- **Styling**: Tailwind CSS v4 with custom design tokens +- **Icons**: Lucide React (shadcn/ui default) +- **Animation**: Tailwind transitions, Framer Motion (when needed) +- **Forms**: TanStack Form + Zod validation + +## Design Philosophy & Best Practices + +**ALWAYS follow these principles:** + +1. **Mobile-First Responsive Design**: + + - Start with mobile layouts (`sm:`, `md:`, `lg:`, `xl:`, `2xl:`) + - Use fluid spacing and typography + - Test on multiple screen sizes + - Avoid fixed widths, use responsive units + +2. **Accessibility First (WCAG 2.1 AA)**: + + - Semantic HTML structure (`