Initial commit

This commit is contained in:
Zhongwei Li
2025-11-30 09:01:28 +08:00
commit acd2b21597
6 changed files with 1729 additions and 0 deletions

490
skills/skill/SKILL.md Normal file
View File

@@ -0,0 +1,490 @@
---
name: styling-with-tailwind
description: Creates UIs using Tailwind CSS utility classes and shadcn/ui patterns. Covers CSS variables with OKLCH colors, component variants with CVA, responsive design, dark mode, and Tailwind v4 features. Use when building interfaces with Tailwind, styling shadcn/ui components, implementing themes, or working with utility-first CSS.
---
# Styling with Tailwind CSS
Build accessible UIs using Tailwind utility classes and shadcn/ui component patterns.
## Core Patterns
### CSS Variables for Theming
shadcn/ui uses semantic CSS variables mapped to Tailwind utilities:
```css
/* globals.css - Light mode */
:root {
--background: oklch(1 0 0);
--foreground: oklch(0.145 0 0);
--primary: oklch(0.205 0 0);
--primary-foreground: oklch(0.985 0 0);
--muted: oklch(0.97 0 0);
--muted-foreground: oklch(0.556 0 0);
--border: oklch(0.922 0 0);
--radius: 0.5rem;
}
/* Dark mode */
.dark {
--background: oklch(0.145 0 0);
--foreground: oklch(0.985 0 0);
--primary: oklch(0.922 0 0);
--primary-foreground: oklch(0.205 0 0);
}
/* Tailwind v4: Map variables */
@theme inline {
--color-background: var(--background);
--color-foreground: var(--foreground);
--color-primary: var(--primary);
}
```
**Usage in components:**
```tsx
// Background colors omit the "-background" suffix
<div className="bg-primary text-primary-foreground">
<div className="bg-muted text-muted-foreground">
<div className="bg-destructive text-destructive-foreground">
```
### Component Variants with CVA
Use `class-variance-authority` for component variants:
```tsx
import { cva } from "class-variance-authority"
const buttonVariants = cva(
"inline-flex items-center justify-center gap-2 rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 disabled:pointer-events-none disabled:opacity-50",
{
variants: {
variant: {
default: "bg-primary text-primary-foreground shadow hover:bg-primary/90",
destructive: "bg-destructive text-destructive-foreground hover:bg-destructive/90",
outline: "border border-input bg-background hover:bg-accent",
ghost: "hover:bg-accent hover:text-accent-foreground",
link: "text-primary underline-offset-4 hover:underline",
},
size: {
default: "h-9 px-4 py-2",
sm: "h-8 px-3 text-xs",
lg: "h-10 px-8",
icon: "size-9",
},
},
defaultVariants: {
variant: "default",
size: "default",
},
}
)
// Usage
<Button variant="outline" size="sm">Click me</Button>
```
### Responsive Design
Mobile-first breakpoints:
```tsx
// Stack on mobile, grid on tablet+
<div className="grid gap-4 md:grid-cols-2 lg:grid-cols-4">
// Hide on mobile
<div className="hidden md:block">
// Different layouts per breakpoint
<div className="flex flex-col md:flex-row lg:gap-8">
<aside className="w-full md:w-64">
<main className="flex-1">
</div>
// Responsive text sizes
<h1 className="text-3xl md:text-4xl lg:text-5xl">
```
### Dark Mode
```tsx
// Use dark: prefix for dark mode styles
<div className="bg-white dark:bg-black text-black dark:text-white">
// Theme toggle component
"use client"
import { Moon, Sun } from "lucide-react"
import { useTheme } from "next-themes"
export function ThemeToggle() {
const { theme, setTheme } = useTheme()
return (
<button onClick={() => setTheme(theme === "dark" ? "light" : "dark")}>
<Sun className="rotate-0 scale-100 dark:-rotate-90 dark:scale-0" />
<Moon className="absolute rotate-90 scale-0 dark:rotate-0 dark:scale-100" />
</button>
)
}
```
## Common Component Patterns
### Card
```tsx
<div className="rounded-xl border bg-card text-card-foreground shadow">
<div className="flex flex-col space-y-1.5 p-6">
<h3 className="font-semibold leading-none tracking-tight">Title</h3>
<p className="text-sm text-muted-foreground">Description</p>
</div>
<div className="p-6 pt-0">Content</div>
<div className="flex items-center p-6 pt-0">Footer</div>
</div>
```
### Form Field
```tsx
<div className="space-y-2">
<label className="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70">
Email
</label>
<input
type="email"
className="flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm transition-colors placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50"
/>
<p className="text-sm text-muted-foreground">Helper text</p>
</div>
```
### Badge
```tsx
const badgeVariants = cva(
"inline-flex items-center rounded-md border px-2.5 py-0.5 text-xs font-semibold transition-colors",
{
variants: {
variant: {
default: "border-transparent bg-primary text-primary-foreground shadow",
secondary: "border-transparent bg-secondary text-secondary-foreground",
destructive: "border-transparent bg-destructive text-destructive-foreground",
outline: "text-foreground",
},
},
}
)
```
### Alert
```tsx
<div className="relative w-full rounded-lg border px-4 py-3 text-sm [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 [&>svg+div]:translate-y-[-3px] [&:has(svg)]:pl-11">
<AlertCircle className="size-4" />
<div className="font-medium">Alert Title</div>
<div className="text-sm text-muted-foreground">Description</div>
</div>
```
### Loading Skeleton
```tsx
<div className="space-y-2">
<div className="h-4 w-[250px] animate-pulse rounded bg-muted" />
<div className="h-4 w-[200px] animate-pulse rounded bg-muted" />
</div>
```
## Layout Patterns
### Centered Layout
```tsx
<div className="flex min-h-screen items-center justify-center">
<div className="w-full max-w-md space-y-8 p-8">
{/* Content */}
</div>
</div>
```
### Sidebar Layout
```tsx
<div className="flex h-screen">
<aside className="w-64 border-r bg-muted/40">Sidebar</aside>
<main className="flex-1 overflow-auto">Content</main>
</div>
```
### Dashboard Grid
```tsx
<div className="grid gap-4 md:grid-cols-2 lg:grid-cols-4">
<Card className="col-span-2">Wide card</Card>
<Card>Regular</Card>
<Card>Regular</Card>
<Card className="col-span-4">Full width</Card>
</div>
```
### Container with Max Width
```tsx
<div className="container mx-auto px-4 md:px-6 lg:px-8">
<div className="max-w-2xl mx-auto">
{/* Centered content */}
</div>
</div>
```
## Accessibility Patterns
### Focus Visible
```tsx
<button className="focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2">
```
### Screen Reader Only
```tsx
<span className="sr-only">Close dialog</span>
```
### Disabled States
```tsx
<button className="disabled:cursor-not-allowed disabled:opacity-50" disabled>
```
### ARIA-friendly Alert
```tsx
<div role="alert" className="rounded-lg border p-4">
<div className="flex items-start gap-3">
<AlertCircle className="size-5 text-destructive" />
<div className="flex-1 space-y-1">
<h5 className="font-medium">Error</h5>
<p className="text-sm text-muted-foreground">Message</p>
</div>
</div>
</div>
```
## Tailwind v4 Features
### Size Utility
```tsx
// New syntax (replaces w-* h-*)
<div className="size-4">
<div className="size-8">
<div className="size-full">
```
### @theme Directive
```css
/* Tailwind v4 syntax */
@theme {
--color-primary: oklch(0.205 0 0);
--font-sans: "Inter", system-ui;
}
/* With CSS variables */
@theme inline {
--color-primary: var(--primary);
}
```
### Animation
```css
/* globals.css */
@import "tw-animate-css";
```
```tsx
<div className="animate-fade-in">
<div className="animate-slide-in-from-top">
<div className="animate-spin">
```
### Tailwind v4.1 Features (April 2025)
**Text Shadow:**
```tsx
// Subtle text shadows for depth
<h1 className="text-shadow-sm text-4xl font-bold">
<h2 className="text-shadow-md text-2xl">
<div className="text-shadow-lg text-xl">
// Custom text shadows
<div className="text-shadow-[0_2px_4px_rgb(0_0_0_/_0.1)]">
```
**Mask Utilities:**
```tsx
// Gradient masks for fade effects
<div className="mask-linear-to-b from-black to-transparent">
Fades to transparent at bottom
</div>
// Image masks
<div className="mask-[url('/mask.svg')]">
Masked content
</div>
// Common patterns
<div className="mask-radial-gradient">Spotlight effect</div>
```
**Colored Drop Shadow:**
```tsx
// Brand-colored shadows
<div className="drop-shadow-[0_4px_12px_oklch(0.488_0.243_264.376)]">
// Use with semantic colors
<Button className="drop-shadow-lg drop-shadow-primary/50">
Glowing button
</Button>
```
**Overflow Wrap:**
```tsx
// Break long words
<p className="overflow-wrap-anywhere">
verylongwordthatneedstowrap
</p>
<p className="overflow-wrap-break-word">
URLs and long strings
</p>
```
## OKLCH Colors
Use OKLCH for better color perception:
```css
/* Format: oklch(lightness chroma hue) */
--primary: oklch(0.205 0 0);
--destructive: oklch(0.577 0.245 27.325);
/* Benefits: perceptually uniform, consistent lightness across hues */
```
## Base Color Palettes
shadcn/ui provides multiple base colors:
```css
/* Neutral (default) - pure grayscale */
--primary: oklch(0.205 0 0);
/* Zinc - cooler, blue-gray */
--primary: oklch(0.21 0.006 285.885);
/* Slate - balanced blue-gray */
--primary: oklch(0.208 0.042 265.755);
/* Stone - warmer, brown-gray */
--primary: oklch(0.216 0.006 56.043);
```
## Best Practices
### Prefer Semantic Colors
```tsx
// Good - uses theme
<div className="bg-background text-foreground">
// Avoid - hardcoded
<div className="bg-white text-black dark:bg-zinc-950">
```
### Group Related Utilities
```tsx
<div className="
flex items-center justify-between
rounded-lg border
bg-card text-card-foreground
p-4 shadow-sm
hover:bg-accent
">
```
### Avoid Arbitrary Values
```tsx
// Prefer design tokens
<div className="p-4 text-sm">
// Avoid when unnecessary
<div className="p-[17px] text-[13px]">
```
## Installation
```bash
# Initialize shadcn/ui
pnpm dlx shadcn@latest init
# Add components
pnpm dlx shadcn@latest add button card form
# Add all components
pnpm dlx shadcn@latest add --all
```
## Troubleshooting
**Colors not updating:**
1. Check CSS variable in globals.css
2. Verify @theme inline includes variable
3. Clear build cache
**Dark mode not working:**
1. Verify ThemeProvider wraps app
2. Check suppressHydrationWarning on html tag
3. Ensure dark: variants defined
**Tailwind v4 migration:**
1. Run `@tailwindcss/upgrade@next` codemod
2. Update CSS variables with hsl() wrappers
3. Change @theme to @theme inline
4. Install tw-animate-css
## Component Patterns
For detailed component patterns see [components.md](components.md):
- **Composition**: asChild pattern for wrapping elements
- **Typography**: Heading scales, prose styles, inline code
- **Forms**: React Hook Form with Zod validation
- **Icons**: Lucide icons integration and sizing
- **Inputs**: OTP, file, grouped inputs
- **Dialogs**: Modal patterns and composition
- **Data Tables**: TanStack table integration
- **Toasts**: Sonner notifications
- **CLI**: Complete command reference
## Resources
See [theming.md](theming.md) for complete color system reference and examples.
## Summary
Key concepts:
- Use semantic CSS variables for theming
- Apply CVA for component variants
- Follow mobile-first responsive patterns
- Implement dark mode with next-themes
- Use OKLCH for modern color handling
- Prefer Tailwind v4 features (size-*, @theme)
- Always ensure accessibility with focus-visible, sr-only
This skill focuses on shadcn/ui patterns with Tailwind CSS. For component-specific examples, refer to the official shadcn/ui documentation.