@reinvented/design 1.0.0 → 1.1.0

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.
Files changed (93) hide show
  1. package/README.md +1 -1
  2. package/SKILL.md +214 -0
  3. package/package.json +4 -3
  4. package/skills/apps/analytics.md +103 -0
  5. package/skills/apps/booking-scheduling.md +97 -0
  6. package/skills/apps/content-management.md +52 -0
  7. package/skills/apps/crm.md +80 -0
  8. package/skills/apps/e-commerce.md +109 -0
  9. package/skills/apps/education.md +79 -0
  10. package/skills/apps/finance.md +68 -0
  11. package/skills/apps/health-fitness.md +72 -0
  12. package/skills/apps/marketplace.md +99 -0
  13. package/skills/apps/messaging.md +84 -0
  14. package/skills/apps/portfolio-personal.md +90 -0
  15. package/skills/apps/project-management.md +95 -0
  16. package/skills/apps/saas-dashboard.md +104 -0
  17. package/skills/apps/social-platform.md +50 -0
  18. package/skills/blocks/auth.md +106 -0
  19. package/skills/blocks/communication.md +98 -0
  20. package/skills/blocks/content.md +107 -0
  21. package/skills/blocks/data-management.md +109 -0
  22. package/skills/blocks/data-viz.md +92 -0
  23. package/skills/blocks/ecommerce.md +126 -0
  24. package/skills/blocks/feedback.md +97 -0
  25. package/skills/blocks/filtering.md +127 -0
  26. package/skills/blocks/marketing.md +136 -0
  27. package/skills/blocks/media.md +102 -0
  28. package/skills/blocks/navigation.md +136 -0
  29. package/skills/blocks/onboarding.md +75 -0
  30. package/skills/blocks/profiles.md +131 -0
  31. package/skills/blocks/scheduling.md +117 -0
  32. package/skills/blocks/settings.md +102 -0
  33. package/skills/components/advanced-components.md +142 -0
  34. package/skills/components/avatar.md +92 -0
  35. package/skills/components/badge.md +105 -0
  36. package/skills/components/button.md +87 -0
  37. package/skills/components/card.md +144 -0
  38. package/skills/components/chart.md +88 -0
  39. package/skills/components/dialog.md +109 -0
  40. package/skills/components/dropdown-menu.md +117 -0
  41. package/skills/components/extended-components.md +187 -0
  42. package/skills/components/feedback.md +165 -0
  43. package/skills/components/form.md +112 -0
  44. package/skills/components/input.md +107 -0
  45. package/skills/components/map.md +53 -0
  46. package/skills/components/navigation.md +73 -0
  47. package/skills/components/overlay.md +77 -0
  48. package/skills/components/page-header.md +51 -0
  49. package/skills/components/select.md +175 -0
  50. package/skills/components/table.md +102 -0
  51. package/skills/components/tabs.md +105 -0
  52. package/skills/components/utilities.md +138 -0
  53. package/skills/devices/desktop.md +43 -0
  54. package/skills/devices/mobile.md +77 -0
  55. package/skills/foundation/design-principles.md +77 -0
  56. package/skills/foundation/design-tokens.md +121 -0
  57. package/skills/foundation/mockup-generation.md +118 -0
  58. package/skills/foundation/rules.md +54 -0
  59. package/skills/foundation/tailwind-usage.md +204 -0
  60. package/skills/layouts/dashboard.md +71 -0
  61. package/skills/layouts/full-page-form.md +75 -0
  62. package/skills/layouts/list-detail.md +70 -0
  63. package/skills/layouts/marketing.md +70 -0
  64. package/skills/layouts/responsive.md +67 -0
  65. package/skills/layouts/settings-page.md +106 -0
  66. package/skills/layouts/sidebar.md +73 -0
  67. package/skills/layouts/topbar.md +68 -0
  68. package/skills/patterns/auth.md +131 -0
  69. package/skills/patterns/content-display.md +164 -0
  70. package/skills/patterns/dashboards.md +104 -0
  71. package/skills/patterns/data-tables.md +113 -0
  72. package/skills/patterns/empty-states.md +71 -0
  73. package/skills/patterns/error-states.md +73 -0
  74. package/skills/patterns/forms.md +136 -0
  75. package/skills/patterns/loading-states.md +92 -0
  76. package/skills/patterns/navigation.md +113 -0
  77. package/skills/patterns/notifications.md +91 -0
  78. package/skills/patterns/onboarding.md +42 -0
  79. package/skills/patterns/search.md +55 -0
  80. package/skills/patterns/settings.md +132 -0
  81. package/skills/patterns/user-profiles.md +67 -0
  82. package/skills/personas/business-operator.md +114 -0
  83. package/skills/personas/consumer-casual.md +60 -0
  84. package/skills/personas/consumer-power-user.md +109 -0
  85. package/skills/personas/creative-professional.md +109 -0
  86. package/skills/personas/enterprise-admin.md +134 -0
  87. package/skills/visual/color-usage.md +62 -0
  88. package/skills/visual/dark-mode.md +50 -0
  89. package/skills/visual/polish-techniques.md +101 -0
  90. package/skills/visual/spacing-composition.md +69 -0
  91. package/skills/visual/transitions-animations.md +66 -0
  92. package/skills/visual/typography-hierarchy.md +66 -0
  93. package/DESIGN_GUIDE.md +0 -148
@@ -0,0 +1,113 @@
1
+ # Pattern: Data Tables
2
+
3
+ Complete table layouts with toolbar, search, filters, sorting indicators, pagination, and row actions.
4
+
5
+ ## Standard Data Table
6
+
7
+ ```tsx
8
+ <Card>
9
+ <!-- Toolbar -->
10
+ <CardHeader className="pb-4">
11
+ <div className="flex items-center justify-between">
12
+ <CardTitle>Team Members</CardTitle>
13
+ <Button size="sm"><Plus className="w-4 h-4" /> Add Member</Button>
14
+ </div>
15
+ <div className="flex items-center gap-3 mt-3">
16
+ <div className="relative flex-1 max-w-sm">
17
+ <Search className="absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground" />
18
+ <Input className="pl-9" placeholder="Search members..." defaultValue="search" />
19
+ </div>
20
+ <Select defaultValue="roleFilter">
21
+ <SelectTrigger className="w-36">
22
+ <SelectValue placeholder="All Roles" />
23
+ </SelectTrigger>
24
+ <SelectContent>
25
+ <SelectItem value="all">All Roles</SelectItem>
26
+ <SelectItem value="admin">Admin</SelectItem>
27
+ <SelectItem value="member">Member</SelectItem>
28
+ </SelectContent>
29
+ </Select>
30
+ </div>
31
+ </CardHeader>
32
+ <!-- Table -->
33
+ <CardContent className="p-0">
34
+ <Table>
35
+ <TableHeader>
36
+ <TableRow>
37
+ <TableHead className="pl-6">Member</TableHead>
38
+ <TableHead>Role</TableHead>
39
+ <TableHead>Status</TableHead>
40
+ <TableHead className="text-right">Last Active</TableHead>
41
+ <TableHead className="w-10 pr-6"></TableHead>
42
+ </TableRow>
43
+ </TableHeader>
44
+ <TableBody>
45
+ <TableRow v-for="member in members" :key="member.id">
46
+ <!-- Avatar + name + email in first column -->
47
+ <TableCell className="pl-6">
48
+ <div className="flex items-center gap-3">
49
+ <div className="w-8 h-8 rounded-full shrink-0 flex items-center justify-center text-xs font-medium bg-muted text-muted-foreground">
50
+ {{ member.name.split(' ').map(n => n[0]).join('') }}
51
+ </div>
52
+ <div className="min-w-0">
53
+ <p className="text-sm font-medium truncate">{{ member.name }}</p>
54
+ <p className="text-xs text-muted-foreground">{{ member.email }}</p>
55
+ </div>
56
+ </div>
57
+ </TableCell>
58
+ <TableCell className="text-sm">{{ member.role }}</TableCell>
59
+ <TableCell>
60
+ <Badge :variant="member.status === 'active' ? 'default' : 'secondary'">{{ member.status }}</Badge>
61
+ </TableCell>
62
+ <TableCell className="text-right text-sm text-muted-foreground">{{ member.lastActive }}</TableCell>
63
+ <TableCell className="pr-6">
64
+ <DropdownMenu>
65
+ <DropdownMenuTrigger as-child>
66
+ <Button variant="ghost" size="icon" className="h-8 w-8">
67
+ <MoreHorizontal className="w-4 h-4" />
68
+ </Button>
69
+ </DropdownMenuTrigger>
70
+ <DropdownMenuContent align="end">
71
+ <DropdownMenuItem><Pencil className="w-4 h-4" /> Edit</DropdownMenuItem>
72
+ <DropdownMenuSeparator />
73
+ <DropdownMenuItem className="text-destructive"><Trash2 className="w-4 h-4" /> Remove</DropdownMenuItem>
74
+ </DropdownMenuContent>
75
+ </DropdownMenu>
76
+ </TableCell>
77
+ </TableRow>
78
+ </TableBody>
79
+ </Table>
80
+ </CardContent>
81
+ <!-- Pagination -->
82
+ <CardFooter className="justify-between border-t py-3">
83
+ <p className="text-sm text-muted-foreground">Showing 1–10 of 47 members</p>
84
+ <div className="flex items-center gap-2">
85
+ <Button variant="outline" size="sm" disabled><ChevronLeft className="w-4 h-4" /></Button>
86
+ <Button variant="outline" size="sm"><ChevronRight className="w-4 h-4" /></Button>
87
+ </div>
88
+ </CardFooter>
89
+ </Card>
90
+ ```
91
+
92
+ ## Key Structural Rules
93
+
94
+ 1. **Wrap table in Card** — `CardContent` gets `className="p-0"` to let the table bleed edge-to-edge.
95
+ 2. **Cell Alignment** — Because the `CardHeader` has 24px padding (`p-6`) and `Table` cells default to 16px (`p-4`), you must add `className="pl-6"` to the first `TableHead`/`TableCell` and `className="pr-6"` to the last `TableHead`/`TableCell` so the table visually aligns with the header above it.
96
+ 3. **Toolbar in CardHeader** — search + filters above the table, primary action button top-right.
97
+ 4. **Pagination in CardFooter** — results count left, page controls right, separated by `border-t`.
98
+ 5. **First column is the identifier** — always name/title with `font-medium`, often with avatar.
99
+ 6. **Last column is actions** — `w-10` header, three-dot DropdownMenu.
100
+ 7. **5–8 rows for mockups** — enough to feel real, not so many it's overwhelming.
101
+
102
+ ## Bulk Actions
103
+
104
+ When the table supports multi-select, show a floating action bar:
105
+
106
+ ```tsx
107
+ <div v-if="selectedCount > 0" className="flex items-center gap-3 px-4 py-2 bg-muted rounded-md">
108
+ <p className="text-sm font-medium">{{ selectedCount }} selected</p>
109
+ <Separator orientation="vertical" className="h-4" />
110
+ <Button variant="ghost" size="sm">Archive</Button>
111
+ <Button variant="ghost" size="sm" className="text-destructive">Delete</Button>
112
+ </div>
113
+ ```
@@ -0,0 +1,71 @@
1
+ # Pattern: Empty States
2
+
3
+ Every empty view must have a well-designed empty state. Never show a blank page.
4
+
5
+ ## Standard Empty State
6
+
7
+ ```tsx
8
+ <div className="flex flex-col items-center justify-center py-16 text-center">
9
+ <div className="w-12 h-12 rounded-xl bg-muted flex items-center justify-center mb-4">
10
+ <Inbox className="w-6 h-6 text-muted-foreground" />
11
+ </div>
12
+ <h3 className="text-lg font-semibold mb-1">No messages yet</h3>
13
+ <p className="text-sm text-muted-foreground max-w-sm mb-4">
14
+ When you receive messages, they'll appear here. Start a conversation to get going.
15
+ </p>
16
+ <Button>
17
+ <Plus className="w-4 h-4" /> New Message
18
+ </Button>
19
+ </div>
20
+ ```
21
+
22
+ ## Required Elements
23
+
24
+ Every empty state needs all four:
25
+
26
+ 1. **Icon** — A relevant Lucide icon in a muted background container (`w-12 h-12 rounded-xl bg-muted`)
27
+ 2. **Title** — Clear, specific headline (`text-lg font-semibold`)
28
+ 3. **Description** — Explains what goes here and how to get started (`text-sm text-muted-foreground max-w-sm`)
29
+ 4. **CTA Button** — Primary action to create the first item
30
+
31
+ ## Context-Specific Examples
32
+
33
+ ### Empty Table
34
+ ```tsx
35
+ <TableRow>
36
+ <TableCell :colspan="columnCount" className="h-48">
37
+ <div className="flex flex-col items-center justify-center text-center">
38
+ <div className="w-12 h-12 rounded-xl bg-muted flex items-center justify-center mb-4">
39
+ <FileX className="w-6 h-6 text-muted-foreground" />
40
+ </div>
41
+ <p className="text-sm font-medium mb-1">No results found</p>
42
+ <p className="text-xs text-muted-foreground">Try adjusting your search or filters.</p>
43
+ </div>
44
+ </TableCell>
45
+ </TableRow>
46
+ ```
47
+
48
+ ### Empty Search Results
49
+ No CTA button — instead, suggest adjusting the search:
50
+ ```tsx
51
+ <div className="flex flex-col items-center justify-center py-12 text-center">
52
+ <Search className="w-10 h-10 text-muted-foreground mb-4" />
53
+ <h3 className="text-lg font-semibold mb-1">No results for "{{ query }}"</h3>
54
+ <p className="text-sm text-muted-foreground">Check your spelling or try different keywords.</p>
55
+ </div>
56
+ ```
57
+
58
+ ## Icon Suggestions
59
+
60
+ | Context | Icon |
61
+ |---------|------|
62
+ | Messages/inbox | `Inbox` or `MessageSquare` |
63
+ | Files/documents | `FileText` or `FolderOpen` |
64
+ | Users/team | `Users` or `UserPlus` |
65
+ | Tasks/projects | `CheckSquare` or `Clipboard` |
66
+ | Search results | `Search` |
67
+ | Products/items | `Package` or `ShoppingBag` |
68
+ | Events/calendar | `Calendar` |
69
+ | Analytics/data | `BarChart3` or `LineChart` |
70
+ | Notifications | `Bell` |
71
+ | Errors | `AlertCircle` or `FileX` |
@@ -0,0 +1,73 @@
1
+ # Pattern: Error States
2
+
3
+ Error handling UI for queries, mutations, forms, and network issues.
4
+
5
+ ## Page-Level Error
6
+
7
+ When a data fetch fails and the entire page can't render:
8
+
9
+ ```tsx
10
+ <div className="flex flex-col items-center justify-center py-16 text-center">
11
+ <div className="w-12 h-12 rounded-xl bg-destructive/10 flex items-center justify-center mb-4">
12
+ <AlertCircle className="w-6 h-6 text-destructive" />
13
+ </div>
14
+ <h3 className="text-lg font-semibold mb-1">Something went wrong</h3>
15
+ <p className="text-sm text-muted-foreground max-w-sm mb-4">
16
+ We couldn't load this page. Please try again.
17
+ </p>
18
+ <Button variant="outline" onClick="retry">
19
+ <RefreshCw className="w-4 h-4" /> Try Again
20
+ </Button>
21
+ </div>
22
+ ```
23
+
24
+ ## Inline Error (Alert Banner)
25
+
26
+ For errors within a page that still has other functional content:
27
+
28
+ ```tsx
29
+ <Alert variant="destructive">
30
+ <AlertCircle className="h-4 w-4" />
31
+ <AlertTitle>Failed to load recent activity</AlertTitle>
32
+ <AlertDescription className="flex items-center justify-between">
33
+ <span>Please check your connection and try again.</span>
34
+ <Button variant="outline" size="sm" onClick="retry">Retry</Button>
35
+ </AlertDescription>
36
+ </Alert>
37
+ ```
38
+
39
+ ## Mutation Error (Toast)
40
+
41
+ For save/create/update/delete failures:
42
+
43
+ ```ts
44
+ try {
45
+ await saveData()
46
+ toast.success('Changes saved successfully')
47
+ } catch (error) {
48
+ toast.error('Failed to save changes', {
49
+ action: { label: 'Retry', onClick: () => saveData() }
50
+ })
51
+ }
52
+ ```
53
+
54
+ ## Form Validation Errors
55
+
56
+ ```tsx
57
+ <div className="space-y-2">
58
+ <Label for="email" className="text-destructive">Email</Label>
59
+ <Input id="email" className="border-destructive focus-visible:ring-destructive" defaultValue="email" />
60
+ <p className="text-xs text-destructive">Please enter a valid email address.</p>
61
+ </div>
62
+ ```
63
+
64
+ ## Decision Tree
65
+
66
+ ```
67
+ What failed?
68
+ ├─ Page data fetch → Full-page error state
69
+ ├─ Section data fetch → Inline Alert with retry
70
+ ├─ Save/update/delete → Toast with retry action
71
+ ├─ Form validation → Inline field errors (red border + message)
72
+ ├─ Network offline → Banner at top of page
73
+ ```
@@ -0,0 +1,136 @@
1
+ # Pattern: Forms
2
+
3
+ Create/edit forms, multi-step wizards, inline editing, and validation patterns.
4
+
5
+ ## Standard Create Form (in Dialog)
6
+
7
+ For simple entities with ≤5 fields:
8
+
9
+ ```tsx
10
+ <Dialog v-model:open="showCreate">
11
+ <DialogTrigger as-child>
12
+ <Button><Plus className="w-4 h-4" /> New Project</Button>
13
+ </DialogTrigger>
14
+ <DialogContent className="sm:max-w-md">
15
+ <DialogHeader>
16
+ <DialogTitle>Create Project</DialogTitle>
17
+ <DialogDescription>Add a new project to your workspace.</DialogDescription>
18
+ </DialogHeader>
19
+ <form @submit.prevent="handleCreate" className="space-y-4 py-4">
20
+ <div className="space-y-2">
21
+ <Label for="name">Name</Label>
22
+ <Input id="name" defaultValue="form.name" placeholder="My Project" />
23
+ </div>
24
+ <div className="space-y-2">
25
+ <Label for="desc">Description</Label>
26
+ <Textarea id="desc" defaultValue="form.description" placeholder="What is this project about?" rows="3" />
27
+ </div>
28
+ <div className="space-y-2">
29
+ <Label>Priority</Label>
30
+ <Select defaultValue="form.priority">
31
+ <SelectTrigger><SelectValue placeholder="Select priority" /></SelectTrigger>
32
+ <SelectContent>
33
+ <SelectItem value="low">Low</SelectItem>
34
+ <SelectItem value="medium">Medium</SelectItem>
35
+ <SelectItem value="high">High</SelectItem>
36
+ </SelectContent>
37
+ </Select>
38
+ </div>
39
+ </form>
40
+ <DialogFooter>
41
+ <DialogClose as-child>
42
+ <Button variant="outline">Cancel</Button>
43
+ </DialogClose>
44
+ <Button onClick="handleCreate" :disabled="creating">
45
+ <Loader2 v-if="creating" className="w-4 h-4 animate-spin" />
46
+ {{ creating ? 'Creating...' : 'Create Project' }}
47
+ </Button>
48
+ </DialogFooter>
49
+ </DialogContent>
50
+ </Dialog>
51
+ ```
52
+
53
+ ## Full-Page Form (Complex)
54
+
55
+ For forms with 6+ fields or grouped sections:
56
+
57
+ ```tsx
58
+ <div className="max-w-2xl mx-auto px-6 py-8 space-y-8">
59
+ <div>
60
+ <Button variant="ghost" size="sm" className="gap-1 mb-4">
61
+ <ArrowLeft className="w-4 h-4" /> Back
62
+ </Button>
63
+ <h1 className="text-2xl font-bold">Create Organization</h1>
64
+ <p className="text-muted-foreground">Set up your organization details.</p>
65
+ </div>
66
+
67
+ <form @submit.prevent="handleSubmit" className="space-y-8">
68
+ <!-- Section 1 -->
69
+ <div className="space-y-4">
70
+ <h2 className="text-lg font-semibold">Basic Information</h2>
71
+ <div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
72
+ <div className="space-y-2">
73
+ <Label>Organization Name</Label>
74
+ <Input defaultValue="form.name" />
75
+ </div>
76
+ <div className="space-y-2">
77
+ <Label>Website (optional)</Label>
78
+ <Input defaultValue="form.website" placeholder="https://" />
79
+ </div>
80
+ </div>
81
+ <div className="space-y-2">
82
+ <Label>Description</Label>
83
+ <Textarea defaultValue="form.description" rows="3" />
84
+ </div>
85
+ </div>
86
+
87
+ <Separator />
88
+
89
+ <!-- Section 2 -->
90
+ <div className="space-y-4">
91
+ <h2 className="text-lg font-semibold">Settings</h2>
92
+ <!-- More fields -->
93
+ </div>
94
+
95
+ <!-- Actions (sticky or at bottom) -->
96
+ <div className="flex items-center justify-end gap-2 pt-4 border-t">
97
+ <Button variant="outline" type="button">Cancel</Button>
98
+ <Button type="submit" :disabled="saving">
99
+ <Loader2 v-if="saving" className="w-4 h-4 animate-spin" />
100
+ {{ saving ? 'Creating...' : 'Create Organization' }}
101
+ </Button>
102
+ </div>
103
+ </form>
104
+ </div>
105
+ ```
106
+
107
+ ## Edit Form
108
+
109
+ Same structure as create, but pre-filled with existing data and using "Save Changes" as the submit label.
110
+
111
+ ## Inline Edit
112
+
113
+ For single-field updates:
114
+
115
+ ```tsx
116
+ <div className="flex items-center gap-2 group">
117
+ <p v-if="!editing" className="text-sm" onClick="editing = true">
118
+ {{ value }}
119
+ </p>
120
+ <Input v-else defaultValue="value" @blur="save" @keyup.enter="save" className="h-7 text-sm" autofocus />
121
+ <Button v-if="!editing" variant="ghost" size="icon" className="h-6 w-6 opacity-0 group-hover:opacity-100"
122
+ onClick="editing = true">
123
+ <Pencil className="w-3 h-3" />
124
+ </Button>
125
+ </div>
126
+ ```
127
+
128
+ ## Decision Tree
129
+
130
+ ```
131
+ How many fields?
132
+ ├─ 1 field → Inline edit (click-to-edit)
133
+ ├─ 2–5 fields → Dialog
134
+ ├─ 6–8 fields → Full-page form with sections
135
+ ├─ 9+ fields or rich content → Full-page form with section nav
136
+ ```
@@ -0,0 +1,92 @@
1
+ # Pattern: Loading States
2
+
3
+ Skeleton placeholders, spinners, and progressive loading patterns.
4
+
5
+ ## Skeleton Loading (Preferred)
6
+
7
+ Skeletons replace content with gray shapes that match the content's layout. They signal that content is loading without a jarring spinner.
8
+
9
+ ### Page with Stat Cards + Table
10
+ ```tsx
11
+ <!-- Stat card skeletons -->
12
+ <div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4">
13
+ <Card v-for="i in 4" :key="i">
14
+ <CardHeader className="pb-2">
15
+ <Skeleton className="h-4 w-24" />
16
+ </CardHeader>
17
+ <CardContent>
18
+ <Skeleton className="h-7 w-20 mb-1" />
19
+ <Skeleton className="h-3 w-32" />
20
+ </CardContent>
21
+ </Card>
22
+ </div>
23
+
24
+ <!-- Table skeleton -->
25
+ <Card>
26
+ <CardHeader>
27
+ <Skeleton className="h-5 w-32" />
28
+ </CardHeader>
29
+ <CardContent className="space-y-3">
30
+ <div v-for="i in 5" :key="i" className="flex items-center gap-4">
31
+ <Skeleton className="w-8 h-8 rounded-full" />
32
+ <div className="flex-1 space-y-2">
33
+ <Skeleton className="h-4 w-1/3" />
34
+ <Skeleton className="h-3 w-1/4" />
35
+ </div>
36
+ <Skeleton className="h-5 w-16 rounded-full" />
37
+ <Skeleton className="h-4 w-20" />
38
+ </div>
39
+ </CardContent>
40
+ </Card>
41
+ ```
42
+
43
+ ### Rules for Skeletons
44
+ - **Match the shape**: Round for avatars (`rounded-full`), pill for badges (`rounded-full`), rectangle for text
45
+ - **Vary widths**: Don't make all skeletons the same width — use `w-1/3`, `w-1/2`, `w-3/4` to look natural
46
+ - **Show 3–5 rows**: Don't show 1 skeleton or 20 — 3-5 feels right
47
+ - **No text**: Skeletons are gray blocks, never "Loading..." text
48
+
49
+ ## Button Loading State
50
+
51
+ ```tsx
52
+ <Button :disabled="saving" onClick="handleSave">
53
+ <Loader2 v-if="saving" className="w-4 h-4 animate-spin" />
54
+ {{ saving ? 'Saving...' : 'Save Changes' }}
55
+ </Button>
56
+ ```
57
+
58
+ The button shows a spinner icon AND is disabled during the operation.
59
+
60
+ ## Full-Page Loading
61
+
62
+ For initial page load where no skeleton shape is known:
63
+
64
+ ```tsx
65
+ <div className="flex items-center justify-center h-64">
66
+ <Loader2 className="w-6 h-6 animate-spin text-muted-foreground" />
67
+ </div>
68
+ ```
69
+
70
+ Use sparingly — skeletons are almost always better.
71
+
72
+ ## Progressive Loading
73
+
74
+ Load and show content as it becomes available:
75
+ ```tsx
76
+ <div v-if="stats" className="grid grid-cols-4 gap-4">
77
+ <!-- Stats render immediately -->
78
+ </div>
79
+ <div v-else className="grid grid-cols-4 gap-4">
80
+ <!-- Stat skeletons -->
81
+ </div>
82
+
83
+ <!-- Table loads independently -->
84
+ <Card>
85
+ <CardContent v-if="tableData" className="p-0">
86
+ <Table><!-- ... --></Table>
87
+ </CardContent>
88
+ <CardContent v-else>
89
+ <!-- Table skeleton -->
90
+ </CardContent>
91
+ </Card>
92
+ ```
@@ -0,0 +1,113 @@
1
+ # Pattern: Navigation
2
+
3
+ Navigation structures for apps: sidebars, top bars, mobile nav, and nav composition.
4
+
5
+ ## Sidebar Navigation
6
+
7
+ The most common desktop navigation pattern. Vertical nav links on the left, content on the right.
8
+
9
+ ```tsx
10
+ <div className="flex h-screen">
11
+ <!-- Sidebar -->
12
+ <aside className="w-64 border-r bg-card flex flex-col shrink-0">
13
+ <!-- Logo -->
14
+ <div className="h-14 flex items-center px-4 border-b">
15
+ <div className="flex items-center gap-2">
16
+ <div className="w-7 h-7 rounded-md bg-primary flex items-center justify-center">
17
+ <Zap className="w-4 h-4 text-primary-foreground" />
18
+ </div>
19
+ <span className="text-sm font-semibold">Acme Inc</span>
20
+ </div>
21
+ </div>
22
+ <!-- Nav Links -->
23
+ <nav className="flex-1 p-3 space-y-1">
24
+ <button v-for="item in navItems" :key="item.label"
25
+ className={cn(
26
+ 'w-full flex items-center gap-3 px-3 py-2 text-sm rounded-md transition-colors',
27
+ item.active ? 'bg-accent font-medium' : 'text-muted-foreground hover:bg-accent/50 hover:text-foreground'
28
+ )}>
29
+ <component :is="item.icon" className="w-4 h-4" />
30
+ {{ item.label }}
31
+ </button>
32
+ </nav>
33
+ <!-- User menu at bottom -->
34
+ <div className="border-t p-3">
35
+ <div className="flex items-center gap-3 px-3 py-2">
36
+ <div className="w-8 h-8 rounded-full bg-gradient-to-br from-primary/60 to-primary shrink-0" />
37
+ <div className="flex-1 min-w-0">
38
+ <p className="text-sm font-medium truncate">Sarah Chen</p>
39
+ <p className="text-xs text-muted-foreground truncate">sarah@acme.co</p>
40
+ </div>
41
+ </div>
42
+ </div>
43
+ </aside>
44
+ <!-- Main Content -->
45
+ <main className="flex-1 overflow-y-auto">
46
+ <div className="max-w-7xl mx-auto px-6 py-8">
47
+ <!-- Page content -->
48
+ </div>
49
+ </main>
50
+ </div>
51
+ ```
52
+
53
+ ### Sidebar Nav Item States
54
+ | State | Classes |
55
+ |-------|---------|
56
+ | Default | `text-muted-foreground hover:bg-accent/50 hover:text-foreground` |
57
+ | Active | `bg-accent font-medium` (text color inherits foreground) |
58
+ | Disabled | `opacity-50 pointer-events-none` |
59
+
60
+ ### Sidebar with Sections
61
+ ```tsx
62
+ <nav className="flex-1 p-3 space-y-6">
63
+ <div className="space-y-1">
64
+ <p className="px-3 text-xs font-medium text-muted-foreground uppercase tracking-wider mb-2">Main</p>
65
+ <!-- Main nav items -->
66
+ </div>
67
+ <div className="space-y-1">
68
+ <p className="px-3 text-xs font-medium text-muted-foreground uppercase tracking-wider mb-2">Settings</p>
69
+ <!-- Settings nav items -->
70
+ </div>
71
+ </nav>
72
+ ```
73
+
74
+ ## Top Navigation Bar
75
+
76
+ For simpler apps or when sidebar isn't appropriate.
77
+
78
+ ```tsx
79
+ <header className="h-14 border-b bg-card flex items-center px-6">
80
+ <div className="flex items-center gap-6 w-full max-w-7xl mx-auto">
81
+ <!-- Logo -->
82
+ <div className="flex items-center gap-2 shrink-0">
83
+ <div className="w-7 h-7 rounded-md bg-primary flex items-center justify-center">
84
+ <Zap className="w-4 h-4 text-primary-foreground" />
85
+ </div>
86
+ <span className="text-sm font-semibold">Acme</span>
87
+ </div>
88
+ <!-- Nav links -->
89
+ <nav className="flex items-center gap-1">
90
+ <Button v-for="item in navItems" :key="item.label"
91
+ :variant="item.active ? 'secondary' : 'ghost'" size="sm">
92
+ {{ item.label }}
93
+ </Button>
94
+ </nav>
95
+ <!-- Right side -->
96
+ <div className="ml-auto flex items-center gap-2">
97
+ <Button variant="ghost" size="icon"><Bell className="w-4 h-4" /></Button>
98
+ <Button variant="ghost" size="icon" className="rounded-full">
99
+ <div className="w-7 h-7 rounded-full bg-gradient-to-br from-primary/60 to-primary" />
100
+ </Button>
101
+ </div>
102
+ </div>
103
+ </header>
104
+ ```
105
+
106
+ ## When to Use Which
107
+
108
+ | Navigation Type | Best For |
109
+ |----------------|----------|
110
+ | Sidebar | SaaS dashboards, admin panels, complex apps with many sections |
111
+ | Top bar | Marketing sites, simple apps, consumer products |
112
+ | Top bar + sidebar | Very complex apps (e.g., settings under an app that uses top bar) |
113
+ | Bottom tabs | Mobile apps (max 5 items) |