commit 3d0a4e46ef07be61518f31a5f17358aef81f9873 Author: Zhongwei Li Date: Sat Nov 29 18:21:47 2025 +0800 Initial commit diff --git a/.claude-plugin/plugin.json b/.claude-plugin/plugin.json new file mode 100644 index 0000000..bd8b805 --- /dev/null +++ b/.claude-plugin/plugin.json @@ -0,0 +1,11 @@ +{ + "name": "shadcn-aesthetic", + "description": "Modern CSS/SCSS architecture based on shadcn/ui design principles for refined, accessible styling", + "version": "1.0.0", + "author": { + "name": "Brock" + }, + "skills": [ + "./" + ] +} \ No newline at end of file diff --git a/BEFORE_AFTER.md b/BEFORE_AFTER.md new file mode 100644 index 0000000..4164128 --- /dev/null +++ b/BEFORE_AFTER.md @@ -0,0 +1,325 @@ +# Before & After: shadcn-aesthetic Transformation + +This demonstrates the difference between old-school CSS and modern shadcn-aesthetic patterns. + +## ❌ Before (Old-School, Clunky) + +```scss +.button { + padding: 10px 20px; + background: #007bff; + color: white; + border: 1px solid #0056b3; + border-radius: 4px; + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); + transition: all 0.3s ease; + font-size: 14px; + cursor: pointer; +} + +.button:hover { + background: #0056b3; + box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2); +} + +.button:focus { + outline: none; + border: 2px solid blue; +} + +.card { + padding: 15px; + margin-bottom: 20px; + background: white; + border: 1px solid #ddd; + border-radius: 5px; + box-shadow: 0 3px 6px rgba(0, 0, 0, 0.15); +} + +.input { + padding: 8px 12px; + border: 1px solid #ccc; + border-radius: 3px; + font-size: 14px; +} + +.input:focus { + border-color: #007bff; + outline: none; +} +``` + +**Problems:** +- Hard-coded colors (no theming) +- Random pixel values (10px, 15px, 20px) +- Heavy shadows +- Slow transitions (300ms) +- Poor focus states +- No dark mode support +- Inconsistent spacing + +--- + +## ✅ After (Modern shadcn-aesthetic) + +```scss +:root { + // Color system + --background: 0 0% 100%; + --foreground: 222.2 84% 4.9%; + --primary: 222.2 47.4% 11.2%; + --primary-foreground: 210 40% 98%; + --border: 214.3 31.8% 91.4%; + --input: 214.3 31.8% 91.4%; + --ring: 222.2 84% 4.9%; + + // Spacing + --spacing-2: 0.5rem; // 8px + --spacing-3: 0.75rem; // 12px + --spacing-4: 1rem; // 16px + + // Shadows + --shadow-sm: 0 1px 2px 0 rgb(0 0 0 / 0.05); + --shadow-md: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1); + + // Other + --radius: 0.5rem; + --duration-150: 150ms; + --ease-in-out: cubic-bezier(0.4, 0, 0.2, 1); +} + +.dark { + --background: 222.2 84% 4.9%; + --foreground: 210 40% 98%; + --primary: 210 40% 98%; + --primary-foreground: 222.2 47.4% 11.2%; + --border: 217.2 32.6% 17.5%; + --input: 217.2 32.6% 17.5%; + --ring: 212.7 26.8% 83.9%; +} + +.button { + // Layout + display: inline-flex; + align-items: center; + justify-content: center; + + // Spacing + padding: var(--spacing-2) var(--spacing-4); + + // Visual + background-color: hsl(var(--primary)); + color: hsl(var(--primary-foreground)); + border: 1px solid transparent; + border-radius: var(--radius); + box-shadow: var(--shadow-sm); + + // Typography + font-size: 0.875rem; + font-weight: 500; + + // Interaction + cursor: pointer; + transition: all var(--duration-150) var(--ease-in-out); + + &:hover { + background-color: hsl(var(--primary) / 0.9); + box-shadow: var(--shadow-md); + } + + &:focus-visible { + outline: 2px solid hsl(var(--ring)); + outline-offset: 2px; + } +} + +.card { + // Spacing + padding: var(--spacing-4); + + // Visual + background-color: hsl(var(--background)); + color: hsl(var(--foreground)); + border: 1px solid hsl(var(--border)); + border-radius: calc(var(--radius) + 2px); + box-shadow: var(--shadow-sm); + + // Interaction + transition: box-shadow var(--duration-150) var(--ease-in-out); + + &:hover { + box-shadow: var(--shadow-md); + } +} + +.input { + // Layout + display: flex; + width: 100%; + + // Spacing + padding: var(--spacing-2) var(--spacing-3); + + // Visual + background-color: hsl(var(--background)); + color: hsl(var(--foreground)); + border: 1px solid hsl(var(--input)); + border-radius: var(--radius); + box-shadow: var(--shadow-sm); + + // Typography + font-size: 0.875rem; + line-height: 1.5; + + // Interaction + transition: all var(--duration-150) var(--ease-in-out); + + &::placeholder { + color: hsl(var(--muted-foreground)); + } + + &:focus { + outline: none; + border-color: hsl(var(--ring)); + box-shadow: 0 0 0 2px hsl(var(--ring) / 0.2); + } +} +``` + +**Improvements:** +- ✅ CSS variables for complete theming +- ✅ HSL colors with opacity support +- ✅ Consistent spacing scale (4px base) +- ✅ Subtle, layered shadows +- ✅ Quick transitions (150ms) +- ✅ Proper focus-visible states +- ✅ Dark mode support (just add .dark class) +- ✅ Modern layout primitives +- ✅ Accessible by default + +--- + +## Visual Comparison + +### Light Mode +``` +Old Button: [Blue pill button with heavy shadow] +Modern Button: [Refined button with subtle shadow, perfect spacing] + +Old Card: [Bulky white box with strong borders] +Modern Card: [Clean card with subtle elevation, perfect proportions] + +Old Input: [Generic text field] +Modern Input: [Refined input with smooth focus ring] +``` + +### Dark Mode +``` +Old: [Doesn't exist or looks broken] +Modern: [Perfect dark mode with proper contrast] +``` + +--- + +## Real-World Impact + +### Vibe.UI Component Example + +**Before (Without Skill):** +```scss +.vibe-button { + padding: 10px 16px; + background: #6366f1; + color: white; + border-radius: 6px; + transition: all 0.2s; +} +``` + +**After (With shadcn-aesthetic Skill):** +```scss +.vibe-button { + display: inline-flex; + align-items: center; + gap: var(--spacing-2); + padding: var(--spacing-2) var(--spacing-4); + background-color: hsl(var(--primary)); + color: hsl(var(--primary-foreground)); + border-radius: var(--radius); + font-size: var(--text-sm); + font-weight: var(--font-medium); + box-shadow: var(--shadow-sm); + transition: all var(--duration-150) var(--ease-in-out); + + &:hover { + background-color: hsl(var(--primary) / 0.9); + box-shadow: var(--shadow-md); + } + + &:focus-visible { + outline: 2px solid hsl(var(--ring)); + outline-offset: 2px; + } +} +``` + +**Result:** +- Professional appearance +- Complete theme support +- Perfect dark mode +- Accessible by default +- Consistent with the entire system + +--- + +## File Size Impact + +**Old CSS:** ~2.5KB (but requires separate dark mode styles) +**Modern CSS:** ~3KB (includes dark mode, accessibility, all states) + +**Net benefit:** Smaller overall bundle, better functionality, easier maintenance. + +--- + +## Developer Experience + +### Old Way: +```scss +// What color should I use? +background: #007bff; // ¯\_(ツ)_/¯ + +// How much padding? +padding: 12px; // Looks about right? + +// Dark mode? +// TODO: add dark mode styles (never happens) +``` + +### Modern Way: +```scss +// Clear semantic variables +background-color: hsl(var(--primary)); + +// Consistent spacing scale +padding: var(--spacing-3); + +// Dark mode works automatically +// Just add .dark class to +``` + +--- + +## Usage in Claude Code + +Install the plugin: +```bash +/plugin marketplace add https://github.com/Dieshen/claude_marketplace.git +/plugin install shadcn-aesthetic@dieshen-plugins +``` + +Now when you ask Claude to create UI components, it automatically uses these modern patterns! + +**Example prompt:** +"Create a button component for Vibe.UI with primary, secondary, and outline variants" + +**Result:** Claude generates modern, shadcn-style CSS with proper theming, spacing, and accessibility. 🎉 diff --git a/QUICK_REFERENCE.md b/QUICK_REFERENCE.md new file mode 100644 index 0000000..f272b26 --- /dev/null +++ b/QUICK_REFERENCE.md @@ -0,0 +1,164 @@ +# Shadcn Aesthetic - Quick Reference + +## Color Usage +```scss +// Always use HSL variables +background-color: hsl(var(--primary)); +color: hsl(var(--primary-foreground)); + +// With opacity +border: 1px solid hsl(var(--border) / 0.5); +``` + +## Spacing Scale (4px base) +```scss +--spacing-1: 0.25rem; // 4px +--spacing-2: 0.5rem; // 8px +--spacing-4: 1rem; // 16px +--spacing-6: 1.5rem; // 24px +--spacing-8: 2rem; // 32px +``` + +## Shadows (Subtle & Layered) +```scss +--shadow-sm: 0 1px 2px 0 rgb(0 0 0 / 0.05); +--shadow-md: 0 4px 6px -1px rgb(0 0 0 / 0.1); +--shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 0.1); +``` + +## Transitions (Quick & Smooth) +```scss +transition: all 150ms cubic-bezier(0.4, 0, 0.2, 1); +``` + +## Focus States +```scss +&:focus-visible { + outline: 2px solid hsl(var(--ring)); + outline-offset: 2px; +} +``` + +## Modern Layouts +```scss +// Grid with gap +display: grid; +grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); +gap: var(--spacing-6); + +// Flex with gap +display: flex; +gap: var(--spacing-2); +``` + +## Typography Scale +```scss +--text-sm: 0.875rem; // 14px +--text-base: 1rem; // 16px +--text-lg: 1.125rem; // 18px +--text-xl: 1.25rem; // 20px +``` + +## Button Pattern +```scss +.button { + display: inline-flex; + align-items: center; + justify-content: center; + gap: var(--spacing-2); + padding: var(--spacing-2) var(--spacing-4); + font-size: var(--text-sm); + font-weight: var(--font-medium); + border-radius: var(--radius); + background-color: hsl(var(--primary)); + color: hsl(var(--primary-foreground)); + box-shadow: var(--shadow-sm); + transition: all var(--duration-150) var(--ease-in-out); + + &:hover { + background-color: hsl(var(--primary) / 0.9); + } + + &:focus-visible { + outline: 2px solid hsl(var(--ring)); + outline-offset: 2px; + } +} +``` + +## Card Pattern +```scss +.card { + padding: var(--spacing-6); + border-radius: calc(var(--radius) + 2px); + border: 1px solid hsl(var(--border)); + background-color: hsl(var(--card)); + box-shadow: var(--shadow-sm); + + &:hover { + box-shadow: var(--shadow-md); + } +} +``` + +## Input Pattern +```scss +.input { + padding: var(--spacing-2) var(--spacing-3); + font-size: var(--text-sm); + border-radius: var(--radius); + border: 1px solid hsl(var(--input)); + background-color: hsl(var(--background)); + box-shadow: var(--shadow-sm); + + &:focus { + outline: none; + border-color: hsl(var(--ring)); + box-shadow: 0 0 0 2px hsl(var(--ring) / 0.2); + } +} +``` + +## Dark Mode +```scss +// Define in :root +:root { + --background: 0 0% 100%; + --foreground: 222.2 84% 4.9%; +} + +// Override with .dark class +.dark { + --background: 222.2 84% 4.9%; + --foreground: 210 40% 98%; +} + +// Components automatically adapt +.card { + background-color: hsl(var(--background)); + color: hsl(var(--foreground)); +} +``` + +## Anti-Patterns to Avoid + +❌ Hard-coded hex colors +❌ Random pixel values (13px, 22px) +❌ Heavy shadows (0 5px 15px rgba(0,0,0,0.3)) +❌ Slow transitions (0.3s) +❌ Margins instead of gap +❌ Removing outline without focus-visible +❌ RGB colors without variables + +## Quality Checklist + +✅ CSS variables for all colors +✅ HSL format with opacity support +✅ 4px spacing scale +✅ Subtle shadows +✅ 150ms transitions +✅ focus-visible states +✅ Grid/Flex with gap +✅ Dark mode support +✅ Reduced motion support +✅ Semantic class names diff --git a/README.md b/README.md new file mode 100644 index 0000000..35600f6 --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ +# shadcn-aesthetic + +Modern CSS/SCSS architecture based on shadcn/ui design principles for refined, accessible styling diff --git a/SKILL.md b/SKILL.md new file mode 100644 index 0000000..dc71cef --- /dev/null +++ b/SKILL.md @@ -0,0 +1,1098 @@ +--- +name: shadcn-aesthetic +description: | + Modern CSS/SCSS architecture based on shadcn/ui design principles. Use this when generating any CSS, SCSS, or styling code to ensure modern, refined, and accessible design patterns. +--- + +# Modern CSS Architecture (shadcn Aesthetic) + +This skill provides comprehensive guidance for writing modern, refined CSS/SCSS that matches the shadcn/ui aesthetic - clean, minimal, accessible, and beautifully crafted. + +## When This Skill Activates + +Apply these patterns when: +- Writing any CSS, SCSS, or styling code +- Creating component styles from scratch +- Refactoring existing styles +- Building design systems or theme systems +- Working on Blazor, React, Vue, or any web UI + +## Core Principles + +1. **Use CSS variables for everything themeable** +2. **HSL color system for easy manipulation** +3. **Consistent spacing scale (4px base)** +4. **Subtle, layered shadows** +5. **Quick, smooth transitions (150ms)** +6. **Proper focus states** +7. **Modern layout primitives (Grid/Flex with gap)** +8. **Dark mode first-class citizen** + +--- + +## Color System + +### Variable Structure + +Always use HSL-based CSS variables for colors: + +```scss +:root { + // Background colors + --background: 0 0% 100%; + --foreground: 222.2 84% 4.9%; + + // Card colors + --card: 0 0% 100%; + --card-foreground: 222.2 84% 4.9%; + + // Popover colors + --popover: 0 0% 100%; + --popover-foreground: 222.2 84% 4.9%; + + // Primary brand colors + --primary: 222.2 47.4% 11.2%; + --primary-foreground: 210 40% 98%; + + // Secondary colors + --secondary: 210 40% 96.1%; + --secondary-foreground: 222.2 47.4% 11.2%; + + // Muted colors + --muted: 210 40% 96.1%; + --muted-foreground: 215.4 16.3% 46.9%; + + // Accent colors + --accent: 210 40% 96.1%; + --accent-foreground: 222.2 47.4% 11.2%; + + // Destructive/error colors + --destructive: 0 84.2% 60.2%; + --destructive-foreground: 210 40% 98%; + + // Border and input + --border: 214.3 31.8% 91.4%; + --input: 214.3 31.8% 91.4%; + --ring: 222.2 84% 4.9%; + + // Border radius + --radius: 0.5rem; +} + +.dark { + --background: 222.2 84% 4.9%; + --foreground: 210 40% 98%; + + --card: 222.2 84% 4.9%; + --card-foreground: 210 40% 98%; + + --popover: 222.2 84% 4.9%; + --popover-foreground: 210 40% 98%; + + --primary: 210 40% 98%; + --primary-foreground: 222.2 47.4% 11.2%; + + --secondary: 217.2 32.6% 17.5%; + --secondary-foreground: 210 40% 98%; + + --muted: 217.2 32.6% 17.5%; + --muted-foreground: 215 20.2% 65.1%; + + --accent: 217.2 32.6% 17.5%; + --accent-foreground: 210 40% 98%; + + --destructive: 0 62.8% 30.6%; + --destructive-foreground: 210 40% 98%; + + --border: 217.2 32.6% 17.5%; + --input: 217.2 32.6% 17.5%; + --ring: 212.7 26.8% 83.9%; +} +``` + +### Usage + +```scss +// Always use hsl() with var() +.component { + background-color: hsl(var(--primary)); + color: hsl(var(--primary-foreground)); + + // With opacity + border: 1px solid hsl(var(--border) / 0.5); + + &:hover { + background-color: hsl(var(--primary) / 0.9); + } +} +``` + +### ❌ Anti-Pattern (Don't Do This) + +```scss +// Hard-coded hex colors +.button { + background: #007bff; + color: #ffffff; +} + +// RGB without variables +.card { + background: rgb(255, 255, 255); + border: 1px solid rgba(0, 0, 0, 0.1); +} +``` + +--- + +## Spacing Scale + +Use a consistent spacing scale based on 4px increments: + +```scss +:root { + --spacing-0: 0; + --spacing-px: 1px; + --spacing-0-5: 0.125rem; // 2px + --spacing-1: 0.25rem; // 4px + --spacing-1-5: 0.375rem; // 6px + --spacing-2: 0.5rem; // 8px + --spacing-2-5: 0.625rem; // 10px + --spacing-3: 0.75rem; // 12px + --spacing-3-5: 0.875rem; // 14px + --spacing-4: 1rem; // 16px + --spacing-5: 1.25rem; // 20px + --spacing-6: 1.5rem; // 24px + --spacing-7: 1.75rem; // 28px + --spacing-8: 2rem; // 32px + --spacing-9: 2.25rem; // 36px + --spacing-10: 2.5rem; // 40px + --spacing-11: 2.75rem; // 44px + --spacing-12: 3rem; // 48px + --spacing-14: 3.5rem; // 56px + --spacing-16: 4rem; // 64px + --spacing-20: 5rem; // 80px + --spacing-24: 6rem; // 96px + --spacing-32: 8rem; // 128px +} +``` + +### Usage + +```scss +.button { + padding: var(--spacing-2) var(--spacing-4); // 8px 16px + gap: var(--spacing-2); // 8px +} + +.card { + padding: var(--spacing-6); // 24px + margin-bottom: var(--spacing-4); // 16px +} +``` + +### ❌ Anti-Pattern (Don't Do This) + +```scss +// Random pixel values +.button { + padding: 10px 22px; + margin: 13px; +} + +// Inconsistent spacing +.card { + padding: 15px; + margin-bottom: 18px; +} +``` + +--- + +## Shadow System + +Use subtle, layered shadows for depth: + +```scss +:root { + // Subtle shadows + --shadow-xs: 0 1px 2px 0 rgb(0 0 0 / 0.05); + --shadow-sm: 0 1px 2px 0 rgb(0 0 0 / 0.05); + --shadow-base: 0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1); + --shadow-md: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1); + --shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1); + --shadow-xl: 0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1); + --shadow-2xl: 0 25px 50px -12px rgb(0 0 0 / 0.25); + + // Inner shadow + --shadow-inner: inset 0 2px 4px 0 rgb(0 0 0 / 0.05); +} +``` + +### Usage + +```scss +.card { + box-shadow: var(--shadow-sm); + + &:hover { + box-shadow: var(--shadow-md); + } +} + +.dropdown { + box-shadow: var(--shadow-lg); +} + +.input { + box-shadow: var(--shadow-sm); + + &:focus { + box-shadow: var(--shadow-sm), 0 0 0 2px hsl(var(--ring) / 0.2); + } +} +``` + +### ❌ Anti-Pattern (Don't Do This) + +```scss +// Heavy, dated shadows +.card { + box-shadow: 0 5px 15px rgba(0, 0, 0, 0.3); +} + +// Single-layer shadows +.button { + box-shadow: 2px 2px 5px #999; +} +``` + +--- + +## Typography Scale + +Use a harmonious type scale: + +```scss +:root { + // Font sizes + --text-xs: 0.75rem; // 12px + --text-sm: 0.875rem; // 14px + --text-base: 1rem; // 16px + --text-lg: 1.125rem; // 18px + --text-xl: 1.25rem; // 20px + --text-2xl: 1.5rem; // 24px + --text-3xl: 1.875rem; // 30px + --text-4xl: 2.25rem; // 36px + --text-5xl: 3rem; // 48px + + // Line heights + --leading-none: 1; + --leading-tight: 1.25; + --leading-snug: 1.375; + --leading-normal: 1.5; + --leading-relaxed: 1.625; + --leading-loose: 2; + + // Font weights + --font-thin: 100; + --font-light: 300; + --font-normal: 400; + --font-medium: 500; + --font-semibold: 600; + --font-bold: 700; + --font-extrabold: 800; + + // Font families + --font-sans: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; + --font-mono: ui-monospace, SFMono-Regular, "SF Mono", Consolas, "Liberation Mono", Menlo, monospace; +} +``` + +### Usage + +```scss +.heading { + font-size: var(--text-2xl); + font-weight: var(--font-semibold); + line-height: var(--leading-tight); + letter-spacing: -0.025em; +} + +.body-text { + font-size: var(--text-base); + line-height: var(--leading-relaxed); +} + +.small-text { + font-size: var(--text-sm); + color: hsl(var(--muted-foreground)); +} +``` + +### ❌ Anti-Pattern (Don't Do This) + +```scss +// Random font sizes +h1 { font-size: 28px; } +h2 { font-size: 22px; } +p { font-size: 15px; } + +// Hard-coded weights +.title { font-weight: 600; } +``` + +--- + +## Transitions & Animations + +Use quick, smooth transitions: + +```scss +:root { + // Timing functions + --ease-in: cubic-bezier(0.4, 0, 1, 1); + --ease-out: cubic-bezier(0, 0, 0.2, 1); + --ease-in-out: cubic-bezier(0.4, 0, 0.2, 1); + + // Durations + --duration-75: 75ms; + --duration-100: 100ms; + --duration-150: 150ms; + --duration-200: 200ms; + --duration-300: 300ms; + --duration-500: 500ms; +} +``` + +### Usage + +```scss +.button { + transition: all var(--duration-150) var(--ease-in-out); + + &:hover { + transform: translateY(-1px); + } + + &:active { + transform: translateY(0); + } +} + +// For specific properties +.dropdown { + transition-property: opacity, transform; + transition-duration: var(--duration-150); + transition-timing-function: var(--ease-out); +} +``` + +### ❌ Anti-Pattern (Don't Do This) + +```scss +// Slow, dated transitions +.button { + transition: all 0.3s ease; +} + +// Transitioning too many properties +.card { + transition: all 0.5s; +} +``` + +--- + +## Focus States + +Modern, accessible focus rings: + +```scss +.button, .input, .link { + // Remove default outline + outline: none; + + // Add custom focus ring + &:focus-visible { + outline: 2px solid hsl(var(--ring)); + outline-offset: 2px; + } +} + +// For inputs with borders +.input { + &:focus-visible { + outline: none; + border-color: hsl(var(--ring)); + box-shadow: 0 0 0 2px hsl(var(--ring) / 0.2); + } +} + +// For cards and containers +.card { + &:focus-visible { + outline: 2px solid hsl(var(--ring)); + outline-offset: 2px; + border-radius: var(--radius); + } +} +``` + +### ❌ Anti-Pattern (Don't Do This) + +```scss +// Removing outline without replacement +button { + outline: none; +} + +// Ugly focus states +input:focus { + border: 2px solid blue; +} +``` + +--- + +## Modern Layout Patterns + +### Grid Layouts + +```scss +// Auto-fit grid +.card-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); + gap: var(--spacing-6); +} + +// Fixed columns with gap +.two-column { + display: grid; + grid-template-columns: 1fr 2fr; + gap: var(--spacing-8); +} + +// Complex grid +.dashboard-layout { + display: grid; + grid-template-columns: 250px 1fr; + grid-template-rows: 60px 1fr; + gap: var(--spacing-4); + height: 100vh; +} +``` + +### Flex Layouts + +```scss +// Modern flex with gap (not margin) +.button-group { + display: flex; + align-items: center; + gap: var(--spacing-2); +} + +// Flex with proper wrapping +.tag-list { + display: flex; + flex-wrap: wrap; + gap: var(--spacing-2); +} + +// Center content +.centered { + display: flex; + align-items: center; + justify-content: center; + min-height: 100vh; +} +``` + +### ❌ Anti-Pattern (Don't Do This) + +```scss +// Using margins instead of gap +.buttons button { + margin-right: 8px; + + &:last-child { + margin-right: 0; + } +} + +// Floats +.columns { + float: left; + width: 50%; +} +``` + +--- + +## Component Patterns + +### Button + +```scss +.button { + // Base styles + display: inline-flex; + align-items: center; + justify-content: center; + gap: var(--spacing-2); + + // Typography + font-size: var(--text-sm); + font-weight: var(--font-medium); + line-height: var(--leading-none); + + // Spacing + padding: var(--spacing-2) var(--spacing-4); + + // Visual + border-radius: var(--radius); + border: 1px solid transparent; + background-color: hsl(var(--primary)); + color: hsl(var(--primary-foreground)); + box-shadow: var(--shadow-sm); + + // Interaction + cursor: pointer; + transition: all var(--duration-150) var(--ease-in-out); + user-select: none; + + // States + &:hover { + background-color: hsl(var(--primary) / 0.9); + box-shadow: var(--shadow-md); + } + + &:active { + transform: translateY(1px); + box-shadow: var(--shadow-sm); + } + + &:focus-visible { + outline: 2px solid hsl(var(--ring)); + outline-offset: 2px; + } + + &:disabled { + opacity: 0.5; + cursor: not-allowed; + pointer-events: none; + } + + // Variants + &--secondary { + background-color: hsl(var(--secondary)); + color: hsl(var(--secondary-foreground)); + + &:hover { + background-color: hsl(var(--secondary) / 0.8); + } + } + + &--outline { + background-color: transparent; + border-color: hsl(var(--input)); + color: hsl(var(--foreground)); + box-shadow: none; + + &:hover { + background-color: hsl(var(--accent)); + color: hsl(var(--accent-foreground)); + } + } + + &--ghost { + background-color: transparent; + box-shadow: none; + + &:hover { + background-color: hsl(var(--accent)); + color: hsl(var(--accent-foreground)); + } + } + + // Sizes + &--sm { + padding: var(--spacing-1-5) var(--spacing-3); + font-size: var(--text-xs); + } + + &--lg { + padding: var(--spacing-3) var(--spacing-8); + font-size: var(--text-base); + } +} +``` + +### Input + +```scss +.input { + // Base styles + display: flex; + width: 100%; + + // Typography + font-size: var(--text-sm); + line-height: var(--leading-normal); + + // Spacing + padding: var(--spacing-2) var(--spacing-3); + + // Visual + border-radius: var(--radius); + border: 1px solid hsl(var(--input)); + background-color: hsl(var(--background)); + color: hsl(var(--foreground)); + box-shadow: var(--shadow-sm); + + // Interaction + transition: all var(--duration-150) var(--ease-in-out); + + // Placeholder + &::placeholder { + color: hsl(var(--muted-foreground)); + } + + // States + &:hover { + border-color: hsl(var(--input) / 0.8); + } + + &:focus { + outline: none; + border-color: hsl(var(--ring)); + box-shadow: 0 0 0 2px hsl(var(--ring) / 0.2); + } + + &:disabled { + opacity: 0.5; + cursor: not-allowed; + background-color: hsl(var(--muted)); + } + + // Error state + &--error { + border-color: hsl(var(--destructive)); + + &:focus { + border-color: hsl(var(--destructive)); + box-shadow: 0 0 0 2px hsl(var(--destructive) / 0.2); + } + } +} +``` + +### Card + +```scss +.card { + // Base styles + display: flex; + flex-direction: column; + + // Spacing + padding: var(--spacing-6); + gap: var(--spacing-4); + + // Visual + border-radius: calc(var(--radius) + 2px); + border: 1px solid hsl(var(--border)); + background-color: hsl(var(--card)); + color: hsl(var(--card-foreground)); + box-shadow: var(--shadow-sm); + + // Interaction + transition: box-shadow var(--duration-150) var(--ease-in-out); + + &:hover { + box-shadow: var(--shadow-md); + } + + // Sub-components + &__header { + display: flex; + flex-direction: column; + gap: var(--spacing-1-5); + } + + &__title { + font-size: var(--text-2xl); + font-weight: var(--font-semibold); + line-height: var(--leading-tight); + letter-spacing: -0.025em; + } + + &__description { + font-size: var(--text-sm); + color: hsl(var(--muted-foreground)); + } + + &__content { + flex: 1; + } + + &__footer { + display: flex; + align-items: center; + gap: var(--spacing-2); + padding-top: var(--spacing-4); + border-top: 1px solid hsl(var(--border)); + } +} +``` + +### Badge + +```scss +.badge { + // Base styles + display: inline-flex; + align-items: center; + + // Typography + font-size: var(--text-xs); + font-weight: var(--font-semibold); + line-height: var(--leading-none); + text-transform: uppercase; + letter-spacing: 0.05em; + + // Spacing + padding: var(--spacing-1) var(--spacing-2-5); + + // Visual + border-radius: calc(var(--radius) - 2px); + border: 1px solid transparent; + background-color: hsl(var(--primary)); + color: hsl(var(--primary-foreground)); + + // Variants + &--secondary { + background-color: hsl(var(--secondary)); + color: hsl(var(--secondary-foreground)); + } + + &--outline { + background-color: transparent; + border-color: hsl(var(--border)); + color: hsl(var(--foreground)); + } + + &--destructive { + background-color: hsl(var(--destructive)); + color: hsl(var(--destructive-foreground)); + } +} +``` + +--- + +## Dark Mode Strategy + +### CSS Variable Approach + +```scss +// Define light mode in :root +:root { + --background: 0 0% 100%; + --foreground: 222.2 84% 4.9%; + // ... all other variables +} + +// Override for dark mode +.dark { + --background: 222.2 84% 4.9%; + --foreground: 210 40% 98%; + // ... all other variables +} + +// Components automatically adapt +.card { + background-color: hsl(var(--background)); + color: hsl(var(--foreground)); +} +``` + +### ❌ Anti-Pattern (Don't Do This) + +```scss +// Media query approach (harder to control) +.card { + background: white; + color: black; + + @media (prefers-color-scheme: dark) { + background: black; + color: white; + } +} +``` + +--- + +## Border Radius System + +```scss +:root { + --radius-none: 0; + --radius-sm: 0.125rem; // 2px + --radius-base: 0.25rem; // 4px + --radius-md: 0.375rem; // 6px + --radius-lg: 0.5rem; // 8px + --radius-xl: 0.75rem; // 12px + --radius-2xl: 1rem; // 16px + --radius-3xl: 1.5rem; // 24px + --radius-full: 9999px; + + // Default radius (customize per theme) + --radius: var(--radius-lg); +} + +// Usage +.button { + border-radius: var(--radius); +} + +.card { + border-radius: calc(var(--radius) + 2px); // Slightly larger +} + +.avatar { + border-radius: var(--radius-full); // Circle +} +``` + +--- + +## Z-Index System + +```scss +:root { + --z-0: 0; + --z-10: 10; + --z-20: 20; + --z-30: 30; + --z-40: 40; + --z-50: 50; + --z-dropdown: 1000; + --z-sticky: 1100; + --z-fixed: 1200; + --z-modal-backdrop: 1300; + --z-modal: 1400; + --z-popover: 1500; + --z-tooltip: 1600; + --z-toast: 1700; +} + +.dropdown { + z-index: var(--z-dropdown); +} + +.modal { + z-index: var(--z-modal); +} +``` + +--- + +## Accessibility Patterns + +### Keyboard Navigation + +```scss +// Show focus states only for keyboard navigation +.button { + &:focus { + outline: none; + } + + &:focus-visible { + outline: 2px solid hsl(var(--ring)); + outline-offset: 2px; + } +} +``` + +### Screen Reader Only + +```scss +.sr-only { + position: absolute; + width: 1px; + height: 1px; + padding: 0; + margin: -1px; + overflow: hidden; + clip: rect(0, 0, 0, 0); + white-space: nowrap; + border-width: 0; +} +``` + +### High Contrast Support + +```scss +@media (prefers-contrast: high) { + .button { + border-width: 2px; + } + + .input { + border-width: 2px; + } +} +``` + +### Reduced Motion + +```scss +@media (prefers-reduced-motion: reduce) { + *, + *::before, + *::after { + animation-duration: 0.01ms !important; + animation-iteration-count: 1 !important; + transition-duration: 0.01ms !important; + } +} +``` + +--- + +## Complete Example: Modern Component + +```scss +// Alert Component +.alert { + // Layout + display: flex; + align-items: flex-start; + gap: var(--spacing-3); + + // Spacing + padding: var(--spacing-4); + + // Visual + border-radius: var(--radius); + border: 1px solid hsl(var(--border)); + background-color: hsl(var(--background)); + + // Typography + font-size: var(--text-sm); + line-height: var(--leading-relaxed); + + // Icon + &__icon { + flex-shrink: 0; + width: 1rem; + height: 1rem; + margin-top: 0.125rem; + } + + // Content + &__content { + flex: 1; + } + + &__title { + font-weight: var(--font-medium); + margin-bottom: var(--spacing-1); + } + + &__description { + color: hsl(var(--muted-foreground)); + } + + // Variants + &--info { + border-color: hsl(210 100% 90%); + background-color: hsl(210 100% 97%); + + .alert__icon { + color: hsl(210 100% 45%); + } + } + + &--success { + border-color: hsl(142 76% 85%); + background-color: hsl(142 76% 96%); + + .alert__icon { + color: hsl(142 76% 36%); + } + } + + &--warning { + border-color: hsl(38 92% 85%); + background-color: hsl(38 92% 95%); + + .alert__icon { + color: hsl(38 92% 50%); + } + } + + &--error { + border-color: hsl(0 84% 85%); + background-color: hsl(0 84% 97%); + + .alert__icon { + color: hsl(0 84% 60%); + } + } +} + +// Dark mode +.dark { + .alert { + &--info { + border-color: hsl(210 100% 20%); + background-color: hsl(210 100% 10%); + + .alert__icon { + color: hsl(210 100% 70%); + } + } + + // ... other variants + } +} +``` + +--- + +## Quality Checklist + +Before finalizing any CSS, verify: + +- [ ] Using CSS variables for colors +- [ ] HSL color format with opacity support +- [ ] Consistent spacing scale (4px base) +- [ ] Subtle, layered shadows +- [ ] Quick transitions (150ms default) +- [ ] Proper focus-visible states +- [ ] Modern layout (Grid/Flex with gap) +- [ ] Dark mode support +- [ ] Reduced motion support +- [ ] High contrast support +- [ ] Semantic class names (BEM or similar) +- [ ] No hard-coded colors +- [ ] No random pixel values +- [ ] Keyboard accessible +- [ ] Screen reader friendly + +--- + +## Reference Resources + +When in doubt, reference these patterns: +1. shadcn/ui components: https://ui.shadcn.com +2. Radix UI primitives: https://www.radix-ui.com +3. Tailwind CSS utilities: https://tailwindcss.com + +Remember: **Subtle beats flashy. Consistent beats clever. Accessible beats everything.** diff --git a/plugin.json b/plugin.json new file mode 100644 index 0000000..651daab --- /dev/null +++ b/plugin.json @@ -0,0 +1,12 @@ +{ + "name": "shadcn-aesthetic", + "description": "Modern CSS/SCSS architecture based on shadcn/ui design principles for refined, accessible styling", + "version": "1.0.0", + "author": { + "name": "Brock / Narcoleptic Fox LLC", + "email": "contact@narcolepticfox.com" + }, + "homepage": "https://github.com/Dieshen/claude_marketplace", + "license": "MIT", + "keywords": ["css", "scss", "shadcn", "design-system", "ui", "styling", "modern", "accessibility"] +} diff --git a/plugin.lock.json b/plugin.lock.json new file mode 100644 index 0000000..0347f83 --- /dev/null +++ b/plugin.lock.json @@ -0,0 +1,57 @@ +{ + "$schema": "internal://schemas/plugin.lock.v1.json", + "pluginId": "gh:Dieshen/claude_marketplace:plugins/shadcn-aesthetic", + "normalized": { + "repo": null, + "ref": "refs/tags/v20251128.0", + "commit": "00af9abb02ed70c9df91b719f1a439bd3aa612fd", + "treeHash": "53455b09424826ed33ed48fb6b38255ad0aaecf7f4306340c1a79745d9e33384", + "generatedAt": "2025-11-28T10:10:20.711907Z", + "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": "shadcn-aesthetic", + "description": "Modern CSS/SCSS architecture based on shadcn/ui design principles for refined, accessible styling", + "version": "1.0.0" + }, + "content": { + "files": [ + { + "path": "BEFORE_AFTER.md", + "sha256": "af1025628b1063b938edf5981a7b3a64d5c429ee804bc3e2d3d3e6a8199cde8b" + }, + { + "path": "plugin.json", + "sha256": "54bb1fc1136574b14576a89089940f91115ca75efb7e4dd7515ec61e23b07e61" + }, + { + "path": "README.md", + "sha256": "6d5482d328f0fc3c2b68f6593f053541e1e83ecbd785b2bb1438d9456484b304" + }, + { + "path": "SKILL.md", + "sha256": "418ae2ff1336f9032ae92b1621518398dad68ffab7c5647f7719fab10239fd92" + }, + { + "path": "QUICK_REFERENCE.md", + "sha256": "ae8a9c8d79d18b9dc82140786dd8a86a11a9e2915f70ed359aa1181772585745" + }, + { + "path": ".claude-plugin/plugin.json", + "sha256": "9fe3ecff7214e382310223e7a19d65059084fade5dfdb1f9c028c9eee3612415" + } + ], + "dirSha256": "53455b09424826ed33ed48fb6b38255ad0aaecf7f4306340c1a79745d9e33384" + }, + "security": { + "scannedAt": null, + "scannerVersion": null, + "flags": [] + } +} \ No newline at end of file