opencodekit 0.15.0 → 0.15.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +367 -31
- package/dist/template/.opencode/README.md +1 -1
- package/dist/template/.opencode/agent/vision.md +4 -4
- package/dist/template/.opencode/command/agent-browser.md +21 -0
- package/dist/template/.opencode/command/complete-next-task.md +77 -0
- package/dist/template/.opencode/command/create.md +38 -3
- package/dist/template/.opencode/command/design-audit.md +1 -1
- package/dist/template/.opencode/command/design.md +1 -1
- package/dist/template/.opencode/command/finish.md +8 -0
- package/dist/template/.opencode/command/frontend-design.md +21 -0
- package/dist/template/.opencode/command/index-knowledge.md +25 -0
- package/dist/template/.opencode/command/init.md +6 -0
- package/dist/template/.opencode/command/opensrc.md +58 -0
- package/dist/template/.opencode/command/skill-create.md +3 -3
- package/dist/template/.opencode/command/skill-optimize.md +2 -2
- package/dist/template/.opencode/command/start.md +15 -6
- package/dist/template/.opencode/command/ui-review.md +1 -1
- package/dist/template/.opencode/memory/_templates/prd.md +50 -14
- package/dist/template/.opencode/opencode.json +143 -159
- package/dist/template/.opencode/package.json +1 -1
- package/dist/template/.opencode/skill/accessibility-audit/SKILL.md +1 -1
- package/dist/template/.opencode/skill/agent-browser/SKILL.md +376 -0
- package/dist/template/.opencode/skill/design-system-audit/SKILL.md +1 -1
- package/dist/template/.opencode/skill/frontend-design/SKILL.md +155 -0
- package/dist/template/.opencode/skill/frontend-design/references/animation/motion-advanced.md +224 -0
- package/dist/template/.opencode/skill/frontend-design/references/animation/motion-core.md +171 -0
- package/dist/template/.opencode/skill/frontend-design/references/canvas/execution.md +90 -0
- package/dist/template/.opencode/skill/frontend-design/references/canvas/philosophy.md +94 -0
- package/dist/template/.opencode/skill/frontend-design/references/shadcn/accessibility.md +132 -0
- package/dist/template/.opencode/skill/frontend-design/references/shadcn/core-components.md +153 -0
- package/dist/template/.opencode/skill/frontend-design/references/shadcn/form-components.md +158 -0
- package/dist/template/.opencode/skill/frontend-design/references/shadcn/setup.md +69 -0
- package/dist/template/.opencode/skill/frontend-design/references/shadcn/theming.md +152 -0
- package/dist/template/.opencode/skill/frontend-design/references/tailwind/responsive.md +112 -0
- package/dist/template/.opencode/skill/frontend-design/references/tailwind/utilities-layout.md +134 -0
- package/dist/template/.opencode/skill/frontend-design/references/tailwind/utilities-styling.md +165 -0
- package/dist/template/.opencode/skill/frontend-design/references/tailwind/v4-config.md +147 -0
- package/dist/template/.opencode/skill/frontend-design/references/tailwind/v4-features.md +128 -0
- package/dist/template/.opencode/skill/index-knowledge/SKILL.md +358 -0
- package/dist/template/.opencode/skill/mockup-to-code/SKILL.md +1 -1
- package/dist/template/.opencode/skill/opensrc/SKILL.md +115 -0
- package/dist/template/.opencode/skill/opensrc/references/architecture.md +176 -0
- package/dist/template/.opencode/skill/opensrc/references/cli-usage.md +176 -0
- package/dist/template/.opencode/skill/opensrc/references/registry-support.md +137 -0
- package/dist/template/.opencode/skill/prd/SKILL.md +212 -0
- package/dist/template/.opencode/skill/prd-task/SKILL.md +128 -0
- package/dist/template/.opencode/skill/prd-task/references/prd-schema.json +28 -0
- package/dist/template/.opencode/skill/skill-creator/SKILL.md +155 -0
- package/dist/template/.opencode/skill/ui-ux-research/SKILL.md +1 -1
- package/dist/template/.opencode/skill/visual-analysis/SKILL.md +1 -1
- package/package.json +1 -1
- package/dist/template/.opencode/skill/frontend-aesthetics/SKILL.md +0 -117
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
# shadcn/ui Core Components
|
|
2
|
+
|
|
3
|
+
Button, Card, Dialog, Select, Tabs, Toast, Command, Sidebar, Table.
|
|
4
|
+
|
|
5
|
+
## Button
|
|
6
|
+
|
|
7
|
+
```tsx
|
|
8
|
+
import { Button } from "@/components/ui/button"
|
|
9
|
+
|
|
10
|
+
<Button variant="default">Default</Button>
|
|
11
|
+
<Button variant="destructive">Delete</Button>
|
|
12
|
+
<Button variant="outline">Outline</Button>
|
|
13
|
+
<Button variant="secondary">Secondary</Button>
|
|
14
|
+
<Button variant="ghost">Ghost</Button>
|
|
15
|
+
<Button variant="link">Link</Button>
|
|
16
|
+
|
|
17
|
+
<Button size="sm">Small</Button>
|
|
18
|
+
<Button size="lg">Large</Button>
|
|
19
|
+
<Button size="icon"><Icon /></Button>
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Card
|
|
23
|
+
|
|
24
|
+
```tsx
|
|
25
|
+
import { Card, CardHeader, CardTitle, CardDescription, CardContent, CardFooter } from "@/components/ui/card"
|
|
26
|
+
|
|
27
|
+
<Card>
|
|
28
|
+
<CardHeader>
|
|
29
|
+
<CardTitle>Title</CardTitle>
|
|
30
|
+
<CardDescription>Description</CardDescription>
|
|
31
|
+
</CardHeader>
|
|
32
|
+
<CardContent>Content</CardContent>
|
|
33
|
+
<CardFooter><Button>Action</Button></CardFooter>
|
|
34
|
+
</Card>
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Dialog
|
|
38
|
+
|
|
39
|
+
```tsx
|
|
40
|
+
import { Dialog, DialogTrigger, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogFooter } from "@/components/ui/dialog"
|
|
41
|
+
|
|
42
|
+
<Dialog>
|
|
43
|
+
<DialogTrigger asChild><Button>Open</Button></DialogTrigger>
|
|
44
|
+
<DialogContent>
|
|
45
|
+
<DialogHeader>
|
|
46
|
+
<DialogTitle>Are you sure?</DialogTitle>
|
|
47
|
+
<DialogDescription>Cannot be undone.</DialogDescription>
|
|
48
|
+
</DialogHeader>
|
|
49
|
+
<DialogFooter><Button>Confirm</Button></DialogFooter>
|
|
50
|
+
</DialogContent>
|
|
51
|
+
</Dialog>
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Select
|
|
55
|
+
|
|
56
|
+
```tsx
|
|
57
|
+
import { Select, SelectTrigger, SelectValue, SelectContent, SelectItem } from "@/components/ui/select"
|
|
58
|
+
|
|
59
|
+
<Select>
|
|
60
|
+
<SelectTrigger className="w-[180px]">
|
|
61
|
+
<SelectValue placeholder="Theme" />
|
|
62
|
+
</SelectTrigger>
|
|
63
|
+
<SelectContent>
|
|
64
|
+
<SelectItem value="light">Light</SelectItem>
|
|
65
|
+
<SelectItem value="dark">Dark</SelectItem>
|
|
66
|
+
</SelectContent>
|
|
67
|
+
</Select>
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## Tabs
|
|
71
|
+
|
|
72
|
+
```tsx
|
|
73
|
+
import { Tabs, TabsList, TabsTrigger, TabsContent } from "@/components/ui/tabs"
|
|
74
|
+
|
|
75
|
+
<Tabs defaultValue="account">
|
|
76
|
+
<TabsList>
|
|
77
|
+
<TabsTrigger value="account">Account</TabsTrigger>
|
|
78
|
+
<TabsTrigger value="password">Password</TabsTrigger>
|
|
79
|
+
</TabsList>
|
|
80
|
+
<TabsContent value="account">Account settings</TabsContent>
|
|
81
|
+
<TabsContent value="password">Password settings</TabsContent>
|
|
82
|
+
</Tabs>
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## Toast (Sonner)
|
|
86
|
+
|
|
87
|
+
```tsx
|
|
88
|
+
import { toast } from "sonner"
|
|
89
|
+
|
|
90
|
+
toast("Event created")
|
|
91
|
+
toast.success("Saved")
|
|
92
|
+
toast.error("Failed")
|
|
93
|
+
toast.promise(saveData(), { loading: "Saving...", success: "Done!", error: "Error" })
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
## Command
|
|
97
|
+
|
|
98
|
+
```tsx
|
|
99
|
+
import { Command, CommandInput, CommandList, CommandEmpty, CommandGroup, CommandItem } from "@/components/ui/command"
|
|
100
|
+
|
|
101
|
+
<Command>
|
|
102
|
+
<CommandInput placeholder="Search..." />
|
|
103
|
+
<CommandList>
|
|
104
|
+
<CommandEmpty>No results.</CommandEmpty>
|
|
105
|
+
<CommandGroup heading="Suggestions">
|
|
106
|
+
<CommandItem>Calendar</CommandItem>
|
|
107
|
+
<CommandItem>Search</CommandItem>
|
|
108
|
+
</CommandGroup>
|
|
109
|
+
</CommandList>
|
|
110
|
+
</Command>
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
## Sidebar
|
|
114
|
+
|
|
115
|
+
```tsx
|
|
116
|
+
import { Sidebar, SidebarContent, SidebarGroup, SidebarGroupLabel, SidebarMenu, SidebarMenuItem, SidebarMenuButton } from "@/components/ui/sidebar"
|
|
117
|
+
|
|
118
|
+
<Sidebar>
|
|
119
|
+
<SidebarContent>
|
|
120
|
+
<SidebarGroup>
|
|
121
|
+
<SidebarGroupLabel>App</SidebarGroupLabel>
|
|
122
|
+
<SidebarMenu>
|
|
123
|
+
<SidebarMenuItem>
|
|
124
|
+
<SidebarMenuButton asChild>
|
|
125
|
+
<a href="/dashboard"><HomeIcon />Dashboard</a>
|
|
126
|
+
</SidebarMenuButton>
|
|
127
|
+
</SidebarMenuItem>
|
|
128
|
+
</SidebarMenu>
|
|
129
|
+
</SidebarGroup>
|
|
130
|
+
</SidebarContent>
|
|
131
|
+
</Sidebar>
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
## Table
|
|
135
|
+
|
|
136
|
+
```tsx
|
|
137
|
+
import { Table, TableHeader, TableBody, TableRow, TableHead, TableCell } from "@/components/ui/table"
|
|
138
|
+
|
|
139
|
+
<Table>
|
|
140
|
+
<TableHeader>
|
|
141
|
+
<TableRow>
|
|
142
|
+
<TableHead>Name</TableHead>
|
|
143
|
+
<TableHead>Status</TableHead>
|
|
144
|
+
</TableRow>
|
|
145
|
+
</TableHeader>
|
|
146
|
+
<TableBody>
|
|
147
|
+
<TableRow>
|
|
148
|
+
<TableCell>John</TableCell>
|
|
149
|
+
<TableCell>Active</TableCell>
|
|
150
|
+
</TableRow>
|
|
151
|
+
</TableBody>
|
|
152
|
+
</Table>
|
|
153
|
+
```
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
# shadcn/ui Form Components
|
|
2
|
+
|
|
3
|
+
Form, Field, Input Group, and new 2026 components.
|
|
4
|
+
|
|
5
|
+
## Form (React Hook Form + Zod)
|
|
6
|
+
|
|
7
|
+
```tsx
|
|
8
|
+
import { useForm } from "react-hook-form"
|
|
9
|
+
import { zodResolver } from "@hookform/resolvers/zod"
|
|
10
|
+
import * as z from "zod"
|
|
11
|
+
import { Form, FormField, FormItem, FormLabel, FormControl, FormMessage } from "@/components/ui/form"
|
|
12
|
+
|
|
13
|
+
const schema = z.object({
|
|
14
|
+
email: z.string().email(),
|
|
15
|
+
password: z.string().min(8)
|
|
16
|
+
})
|
|
17
|
+
|
|
18
|
+
function LoginForm() {
|
|
19
|
+
const form = useForm({ resolver: zodResolver(schema), defaultValues: { email: "", password: "" } })
|
|
20
|
+
|
|
21
|
+
return (
|
|
22
|
+
<Form {...form}>
|
|
23
|
+
<form onSubmit={form.handleSubmit(console.log)} className="space-y-6">
|
|
24
|
+
<FormField control={form.control} name="email" render={({ field }) => (
|
|
25
|
+
<FormItem>
|
|
26
|
+
<FormLabel>Email</FormLabel>
|
|
27
|
+
<FormControl><Input type="email" {...field} /></FormControl>
|
|
28
|
+
<FormMessage />
|
|
29
|
+
</FormItem>
|
|
30
|
+
)} />
|
|
31
|
+
<Button type="submit">Sign In</Button>
|
|
32
|
+
</form>
|
|
33
|
+
</Form>
|
|
34
|
+
)
|
|
35
|
+
}
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Field (2026)
|
|
39
|
+
|
|
40
|
+
Simpler form abstraction:
|
|
41
|
+
|
|
42
|
+
```tsx
|
|
43
|
+
import { Field, FieldLabel, FieldDescription, FieldGroup, FieldSet } from "@/components/ui/field"
|
|
44
|
+
|
|
45
|
+
<FieldSet>
|
|
46
|
+
<FieldGroup>
|
|
47
|
+
<Field>
|
|
48
|
+
<FieldLabel htmlFor="email">Email</FieldLabel>
|
|
49
|
+
<Input id="email" type="email" />
|
|
50
|
+
<FieldDescription>Never shared.</FieldDescription>
|
|
51
|
+
</Field>
|
|
52
|
+
<Field orientation="horizontal">
|
|
53
|
+
<Checkbox id="terms" />
|
|
54
|
+
<FieldLabel htmlFor="terms">Accept terms</FieldLabel>
|
|
55
|
+
</Field>
|
|
56
|
+
</FieldGroup>
|
|
57
|
+
</FieldSet>
|
|
58
|
+
|
|
59
|
+
<!-- Responsive layout -->
|
|
60
|
+
<Field orientation="responsive">
|
|
61
|
+
<FieldContent>
|
|
62
|
+
<FieldLabel>Name</FieldLabel>
|
|
63
|
+
<FieldDescription>Display name</FieldDescription>
|
|
64
|
+
</FieldContent>
|
|
65
|
+
<Input placeholder="Evil Rabbit" />
|
|
66
|
+
</Field>
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## Input Group (2026)
|
|
70
|
+
|
|
71
|
+
```tsx
|
|
72
|
+
import { InputGroup, InputGroupAddon, InputGroupInput, InputGroupButton } from "@/components/ui/input-group"
|
|
73
|
+
|
|
74
|
+
<InputGroup>
|
|
75
|
+
<InputGroupAddon><SearchIcon /></InputGroupAddon>
|
|
76
|
+
<InputGroupInput placeholder="Search..." />
|
|
77
|
+
</InputGroup>
|
|
78
|
+
|
|
79
|
+
<InputGroup>
|
|
80
|
+
<InputGroupAddon>https://</InputGroupAddon>
|
|
81
|
+
<InputGroupInput placeholder="example.com" />
|
|
82
|
+
<InputGroupAddon align="inline-end">
|
|
83
|
+
<InputGroupButton>Go</InputGroupButton>
|
|
84
|
+
</InputGroupAddon>
|
|
85
|
+
</InputGroup>
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## Spinner (2026)
|
|
89
|
+
|
|
90
|
+
```tsx
|
|
91
|
+
import { Spinner } from "@/components/ui/spinner"
|
|
92
|
+
|
|
93
|
+
<Spinner />
|
|
94
|
+
|
|
95
|
+
<Button disabled>
|
|
96
|
+
<Spinner />Loading...
|
|
97
|
+
</Button>
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## Kbd (2026)
|
|
101
|
+
|
|
102
|
+
```tsx
|
|
103
|
+
import { Kbd, KbdGroup } from "@/components/ui/kbd"
|
|
104
|
+
|
|
105
|
+
<KbdGroup>
|
|
106
|
+
<Kbd>Cmd</Kbd>
|
|
107
|
+
<Kbd>K</Kbd>
|
|
108
|
+
</KbdGroup>
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
## Button Group (2026)
|
|
112
|
+
|
|
113
|
+
```tsx
|
|
114
|
+
import { ButtonGroup } from "@/components/ui/button-group"
|
|
115
|
+
|
|
116
|
+
<ButtonGroup>
|
|
117
|
+
<Button>Archive</Button>
|
|
118
|
+
<Button>Report</Button>
|
|
119
|
+
<DropdownMenu>
|
|
120
|
+
<DropdownMenuTrigger asChild>
|
|
121
|
+
<Button size="icon"><MoreIcon /></Button>
|
|
122
|
+
</DropdownMenuTrigger>
|
|
123
|
+
<DropdownMenuContent>...</DropdownMenuContent>
|
|
124
|
+
</DropdownMenu>
|
|
125
|
+
</ButtonGroup>
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
## Item (2026)
|
|
129
|
+
|
|
130
|
+
```tsx
|
|
131
|
+
import { Item, ItemContent, ItemMedia, ItemTitle, ItemDescription, ItemActions } from "@/components/ui/item"
|
|
132
|
+
|
|
133
|
+
<Item variant="outline">
|
|
134
|
+
<ItemMedia variant="icon"><UserIcon /></ItemMedia>
|
|
135
|
+
<ItemContent>
|
|
136
|
+
<ItemTitle>Profile</ItemTitle>
|
|
137
|
+
<ItemDescription>Manage account</ItemDescription>
|
|
138
|
+
</ItemContent>
|
|
139
|
+
<ItemActions><Button size="sm">Edit</Button></ItemActions>
|
|
140
|
+
</Item>
|
|
141
|
+
|
|
142
|
+
<Item asChild>
|
|
143
|
+
<a href="/dashboard"><ItemContent><ItemTitle>Dashboard</ItemTitle></ItemContent></a>
|
|
144
|
+
</Item>
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
## Empty (2026)
|
|
148
|
+
|
|
149
|
+
```tsx
|
|
150
|
+
import { Empty, EmptyIcon, EmptyTitle, EmptyDescription, EmptyActions } from "@/components/ui/empty"
|
|
151
|
+
|
|
152
|
+
<Empty>
|
|
153
|
+
<EmptyIcon><InboxIcon /></EmptyIcon>
|
|
154
|
+
<EmptyTitle>No messages</EmptyTitle>
|
|
155
|
+
<EmptyDescription>Send your first message.</EmptyDescription>
|
|
156
|
+
<EmptyActions><Button>New Message</Button></EmptyActions>
|
|
157
|
+
</Empty>
|
|
158
|
+
```
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# shadcn/ui Setup
|
|
2
|
+
|
|
3
|
+
CLI v3.6.x (current: v3.6.3) - Copy-paste components, Radix UI + Tailwind v4.
|
|
4
|
+
|
|
5
|
+
## New Project
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npx shadcn create
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Interactive setup:
|
|
12
|
+
- Visual style: Vega, Nova, Maia, Lyra, Mira
|
|
13
|
+
- Component library: Radix UI or Base UI
|
|
14
|
+
- Icon library (including Phosphor)
|
|
15
|
+
- Next.js 16 support
|
|
16
|
+
|
|
17
|
+
## Existing Project
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npx shadcn@latest init
|
|
21
|
+
npx shadcn@latest add button card dialog
|
|
22
|
+
npx shadcn@latest add --all
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Components install to `components/ui/`.
|
|
26
|
+
|
|
27
|
+
## Visual Styles
|
|
28
|
+
|
|
29
|
+
| Style | Description |
|
|
30
|
+
|-------|-------------|
|
|
31
|
+
| **Vega** | Classic shadcn look |
|
|
32
|
+
| **Nova** | Reduced padding, compact |
|
|
33
|
+
| **Maia** | Soft, rounded, generous |
|
|
34
|
+
| **Lyra** | Boxy, sharp, mono fonts |
|
|
35
|
+
| **Mira** | Compact, dense interfaces |
|
|
36
|
+
|
|
37
|
+
## Component Libraries
|
|
38
|
+
|
|
39
|
+
- **Radix UI** (default): Full accessibility, React-only
|
|
40
|
+
- **Base UI**: MUI unstyled components
|
|
41
|
+
|
|
42
|
+
Select during `npx shadcn create` or in `components.json`.
|
|
43
|
+
|
|
44
|
+
## MCP Server Support
|
|
45
|
+
|
|
46
|
+
- OpenCode MCP (v3.6.3)
|
|
47
|
+
- Codex MCP (v3.4.0)
|
|
48
|
+
|
|
49
|
+
## Registry System
|
|
50
|
+
|
|
51
|
+
- Registry Directory: https://ui.shadcn.com/docs/directory
|
|
52
|
+
- Custom registries via `components.json`
|
|
53
|
+
- Namespaced components
|
|
54
|
+
|
|
55
|
+
## Component List
|
|
56
|
+
|
|
57
|
+
**Layout**: Card, Sidebar, Separator, Resizable, Scroll Area
|
|
58
|
+
|
|
59
|
+
**Forms**: Button, Input, Textarea, Select, Checkbox, Radio Group, Switch, Slider, Form, Field, Input Group, Label
|
|
60
|
+
|
|
61
|
+
**Feedback**: Alert, Alert Dialog, Dialog, Drawer, Sheet, Toast (Sonner), Progress, Spinner, Skeleton
|
|
62
|
+
|
|
63
|
+
**Navigation**: Tabs, Accordion, Breadcrumb, Navigation Menu, Menubar, Pagination, Command
|
|
64
|
+
|
|
65
|
+
**Data Display**: Table, Avatar, Badge, Hover Card, Tooltip, Calendar, Carousel, Chart
|
|
66
|
+
|
|
67
|
+
**Overlay**: Dropdown Menu, Context Menu, Popover, Collapsible
|
|
68
|
+
|
|
69
|
+
**Other**: Toggle, Toggle Group, Kbd, Button Group, Item, Empty, Input OTP
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
# shadcn/ui Theming
|
|
2
|
+
|
|
3
|
+
CSS variables, OKLCH colors, dark mode for Tailwind v4.
|
|
4
|
+
|
|
5
|
+
## CSS Variables
|
|
6
|
+
|
|
7
|
+
```css
|
|
8
|
+
@import "tailwindcss";
|
|
9
|
+
|
|
10
|
+
@theme {
|
|
11
|
+
--color-background: oklch(1 0 0);
|
|
12
|
+
--color-foreground: oklch(0.15 0.02 264);
|
|
13
|
+
|
|
14
|
+
--color-primary: oklch(0.55 0.22 264);
|
|
15
|
+
--color-primary-foreground: oklch(0.98 0.01 264);
|
|
16
|
+
|
|
17
|
+
--color-secondary: oklch(0.96 0.01 264);
|
|
18
|
+
--color-secondary-foreground: oklch(0.15 0.02 264);
|
|
19
|
+
|
|
20
|
+
--color-muted: oklch(0.96 0.01 264);
|
|
21
|
+
--color-muted-foreground: oklch(0.55 0.02 264);
|
|
22
|
+
|
|
23
|
+
--color-destructive: oklch(0.55 0.22 25);
|
|
24
|
+
--color-border: oklch(0.90 0.01 264);
|
|
25
|
+
--color-ring: oklch(0.55 0.22 264);
|
|
26
|
+
|
|
27
|
+
--radius: 0.5rem;
|
|
28
|
+
}
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## OKLCH Format
|
|
32
|
+
|
|
33
|
+
```
|
|
34
|
+
oklch(L C H)
|
|
35
|
+
│ │ └─ Hue (0-360)
|
|
36
|
+
│ └─── Chroma (0-0.4)
|
|
37
|
+
└───── Lightness (0-1)
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Benefits: perceptually uniform, wider P3 gamut, better gradients.
|
|
41
|
+
|
|
42
|
+
```css
|
|
43
|
+
--color-brand-50: oklch(0.98 0.02 250);
|
|
44
|
+
--color-brand-500: oklch(0.65 0.22 250);
|
|
45
|
+
--color-brand-900: oklch(0.25 0.15 250);
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Dark Mode Setup
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
npm install next-themes
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
```tsx
|
|
55
|
+
// components/theme-provider.tsx
|
|
56
|
+
"use client"
|
|
57
|
+
import { ThemeProvider as NextThemesProvider } from "next-themes"
|
|
58
|
+
|
|
59
|
+
export function ThemeProvider({ children, ...props }) {
|
|
60
|
+
return <NextThemesProvider {...props}>{children}</NextThemesProvider>
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// app/layout.tsx
|
|
64
|
+
<ThemeProvider attribute="class" defaultTheme="system" enableSystem>
|
|
65
|
+
{children}
|
|
66
|
+
</ThemeProvider>
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## Theme Toggle
|
|
70
|
+
|
|
71
|
+
```tsx
|
|
72
|
+
import { useTheme } from "next-themes"
|
|
73
|
+
|
|
74
|
+
export function ThemeToggle() {
|
|
75
|
+
const { setTheme, theme } = useTheme()
|
|
76
|
+
return (
|
|
77
|
+
<Button variant="ghost" size="icon" onClick={() => setTheme(theme === "light" ? "dark" : "light")}>
|
|
78
|
+
<Sun className="h-5 w-5 dark:hidden" />
|
|
79
|
+
<Moon className="h-5 w-5 hidden dark:block" />
|
|
80
|
+
</Button>
|
|
81
|
+
)
|
|
82
|
+
}
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## Dark Mode Colors
|
|
86
|
+
|
|
87
|
+
```css
|
|
88
|
+
.dark {
|
|
89
|
+
--color-background: oklch(0.15 0.02 264);
|
|
90
|
+
--color-foreground: oklch(0.98 0.01 264);
|
|
91
|
+
--color-primary: oklch(0.75 0.18 264);
|
|
92
|
+
--color-muted: oklch(0.25 0.02 264);
|
|
93
|
+
--color-border: oklch(0.30 0.02 264);
|
|
94
|
+
}
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
## Multiple Themes
|
|
98
|
+
|
|
99
|
+
```css
|
|
100
|
+
[data-theme="violet"] { --color-primary: oklch(0.55 0.25 290); }
|
|
101
|
+
[data-theme="rose"] { --color-primary: oklch(0.60 0.22 350); }
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
```tsx
|
|
105
|
+
<div data-theme="violet"><Button>Violet</Button></div>
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
## Custom Button Variants
|
|
109
|
+
|
|
110
|
+
```tsx
|
|
111
|
+
const buttonVariants = cva("...", {
|
|
112
|
+
variants: {
|
|
113
|
+
variant: {
|
|
114
|
+
gradient: "bg-gradient-to-r from-violet-500 to-pink-500 text-white",
|
|
115
|
+
glass: "bg-white/10 backdrop-blur-md border border-white/20",
|
|
116
|
+
},
|
|
117
|
+
size: {
|
|
118
|
+
xl: "h-14 rounded-lg px-10 text-lg",
|
|
119
|
+
},
|
|
120
|
+
},
|
|
121
|
+
})
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
## Radius
|
|
125
|
+
|
|
126
|
+
```css
|
|
127
|
+
@theme {
|
|
128
|
+
--radius: 0.5rem; /* Default */
|
|
129
|
+
/* --radius: 0rem; /* Sharp */
|
|
130
|
+
/* --radius: 1rem; /* Rounded */
|
|
131
|
+
}
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
Components use: `rounded-lg` (--radius), `rounded-md` (--radius - 2px).
|
|
135
|
+
|
|
136
|
+
## Typography
|
|
137
|
+
|
|
138
|
+
```css
|
|
139
|
+
@theme {
|
|
140
|
+
--font-sans: "Inter", system-ui, sans-serif;
|
|
141
|
+
--font-display: "Playfair Display", serif;
|
|
142
|
+
--font-mono: "JetBrains Mono", monospace;
|
|
143
|
+
}
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
## Best Practices
|
|
147
|
+
|
|
148
|
+
1. Use CSS variables for runtime switching
|
|
149
|
+
2. OKLCH for gradients and accessibility
|
|
150
|
+
3. Semantic naming (primary, not blue)
|
|
151
|
+
4. Test both themes
|
|
152
|
+
5. Maintain WCAG AA contrast (4.5:1)
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
# Tailwind Responsive Design
|
|
2
|
+
|
|
3
|
+
Mobile-first breakpoints, container queries.
|
|
4
|
+
|
|
5
|
+
## Mobile-First
|
|
6
|
+
|
|
7
|
+
Base styles apply to all. Breakpoint prefixes override at larger sizes.
|
|
8
|
+
```html
|
|
9
|
+
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4">
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
## Breakpoints
|
|
13
|
+
|
|
14
|
+
| Prefix | Min Width |
|
|
15
|
+
|--------|-----------|
|
|
16
|
+
| `sm:` | 640px |
|
|
17
|
+
| `md:` | 768px |
|
|
18
|
+
| `lg:` | 1024px |
|
|
19
|
+
| `xl:` | 1280px |
|
|
20
|
+
| `2xl:` | 1536px |
|
|
21
|
+
|
|
22
|
+
Custom (v4):
|
|
23
|
+
```css
|
|
24
|
+
@theme {
|
|
25
|
+
--breakpoint-3xl: 1920px;
|
|
26
|
+
}
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Common Patterns
|
|
30
|
+
|
|
31
|
+
```html
|
|
32
|
+
<!-- Stack to row -->
|
|
33
|
+
<div class="flex flex-col lg:flex-row gap-4">
|
|
34
|
+
|
|
35
|
+
<!-- Grid columns -->
|
|
36
|
+
<div class="grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3">
|
|
37
|
+
|
|
38
|
+
<!-- Visibility -->
|
|
39
|
+
<div class="hidden lg:block">Desktop only</div>
|
|
40
|
+
<div class="block lg:hidden">Mobile only</div>
|
|
41
|
+
|
|
42
|
+
<!-- Typography -->
|
|
43
|
+
<h1 class="text-2xl md:text-4xl lg:text-6xl">
|
|
44
|
+
|
|
45
|
+
<!-- Spacing -->
|
|
46
|
+
<div class="p-4 md:p-6 lg:p-8">
|
|
47
|
+
|
|
48
|
+
<!-- Width -->
|
|
49
|
+
<div class="w-full lg:w-1/2 xl:w-1/3">
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## Layout Examples
|
|
53
|
+
|
|
54
|
+
### Sidebar
|
|
55
|
+
```html
|
|
56
|
+
<div class="flex flex-col lg:flex-row min-h-screen">
|
|
57
|
+
<aside class="w-full lg:w-64 bg-gray-100 p-4">Sidebar</aside>
|
|
58
|
+
<main class="flex-1 p-4 md:p-8">Main</main>
|
|
59
|
+
</div>
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### Card Grid
|
|
63
|
+
```html
|
|
64
|
+
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-4 md:gap-6">
|
|
65
|
+
<div class="bg-white rounded-lg shadow p-6">Card</div>
|
|
66
|
+
</div>
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### Navigation
|
|
70
|
+
```html
|
|
71
|
+
<nav class="flex items-center justify-between h-16">
|
|
72
|
+
<div class="text-xl font-bold">Logo</div>
|
|
73
|
+
<div class="hidden md:flex gap-6">Links</div>
|
|
74
|
+
<button class="md:hidden">Menu</button>
|
|
75
|
+
</nav>
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## Max-Width Queries
|
|
79
|
+
|
|
80
|
+
```html
|
|
81
|
+
<div class="max-lg:text-center">Below lg</div>
|
|
82
|
+
<div class="max-sm:hidden">Below sm</div>
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## Container Queries (v4)
|
|
86
|
+
|
|
87
|
+
Style based on container, not viewport:
|
|
88
|
+
```html
|
|
89
|
+
<div class="@container">
|
|
90
|
+
<div class="grid grid-cols-1 @sm:grid-cols-2 @lg:grid-cols-4">
|
|
91
|
+
</div>
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
Breakpoints: `@sm:`, `@md:`, `@lg:`, `@xl:`, `@2xl:`
|
|
95
|
+
|
|
96
|
+
Max-width: `@max-md:grid-cols-1`
|
|
97
|
+
Range: `@min-md:@max-xl:hidden`
|
|
98
|
+
|
|
99
|
+
## Responsive + State
|
|
100
|
+
|
|
101
|
+
```html
|
|
102
|
+
<button class="lg:hover:scale-105">
|
|
103
|
+
<a class="hover:text-blue-600 lg:hover:text-purple-600">
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
## Best Practices
|
|
107
|
+
|
|
108
|
+
1. Mobile-first: start mobile, add complexity larger
|
|
109
|
+
2. Consistent breakpoints across related elements
|
|
110
|
+
3. Test at exact breakpoint widths
|
|
111
|
+
4. 2-3 breakpoints per element max
|
|
112
|
+
5. Verify touch targets min 44x44px
|