@reinvented/design 0.1.0 → 0.2.1

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 (219) hide show
  1. package/DESIGN_GUIDE.md +148 -0
  2. package/README.md +39 -162
  3. package/docs/components/alert-dialog.md +32 -0
  4. package/docs/components/avatar.md +14 -0
  5. package/docs/components/badge.md +24 -0
  6. package/docs/components/button.md +69 -0
  7. package/docs/components/card.md +49 -0
  8. package/docs/components/dialog.md +46 -0
  9. package/docs/components/dropdown-menu.md +32 -0
  10. package/docs/components/index.md +69 -0
  11. package/docs/components/input.md +34 -0
  12. package/docs/components/remaining-components.md +253 -0
  13. package/docs/components/scroll-area.md +17 -0
  14. package/docs/components/select.md +31 -0
  15. package/docs/components/separator.md +14 -0
  16. package/docs/components/sheet.md +32 -0
  17. package/docs/components/skeleton.md +20 -0
  18. package/docs/components/table.md +33 -0
  19. package/docs/components/tabs.md +23 -0
  20. package/docs/conventions.md +74 -0
  21. package/docs/layouts/dashboard.md +70 -0
  22. package/docs/layouts/detail-page.md +83 -0
  23. package/docs/layouts/index.md +45 -0
  24. package/docs/layouts/list-page.md +107 -0
  25. package/docs/layouts/settings-page.md +79 -0
  26. package/docs/layouts/step-wizard.md +73 -0
  27. package/docs/patterns/index.md +39 -0
  28. package/docs/rules.md +43 -0
  29. package/docs/visual-polish.md +141 -0
  30. package/package.json +40 -61
  31. package/src/components/ui/accordion/Accordion.vue +13 -0
  32. package/src/components/ui/accordion/AccordionContent.vue +20 -0
  33. package/src/components/ui/accordion/AccordionItem.vue +15 -0
  34. package/src/components/ui/accordion/AccordionTrigger.vue +25 -0
  35. package/src/components/ui/accordion/index.ts +4 -0
  36. package/src/components/ui/alert/Alert.vue +38 -0
  37. package/src/components/ui/alert/AlertDescription.vue +12 -0
  38. package/src/components/ui/alert/AlertTitle.vue +12 -0
  39. package/src/components/ui/alert/index.ts +3 -0
  40. package/src/components/ui/alert-dialog/AlertDialog.vue +13 -0
  41. package/src/components/ui/alert-dialog/AlertDialogAction.vue +21 -0
  42. package/src/components/ui/alert-dialog/AlertDialogCancel.vue +21 -0
  43. package/src/components/ui/alert-dialog/AlertDialogContent.vue +39 -0
  44. package/src/components/ui/alert-dialog/AlertDialogDescription.vue +15 -0
  45. package/src/components/ui/alert-dialog/AlertDialogFooter.vue +12 -0
  46. package/src/components/ui/alert-dialog/AlertDialogHeader.vue +12 -0
  47. package/src/components/ui/alert-dialog/AlertDialogTitle.vue +15 -0
  48. package/src/components/ui/alert-dialog/AlertDialogTrigger.vue +11 -0
  49. package/src/components/ui/alert-dialog/index.ts +9 -0
  50. package/src/components/ui/avatar/Avatar.vue +14 -0
  51. package/src/components/ui/avatar/index.ts +1 -0
  52. package/src/components/ui/badge/Badge.vue +27 -0
  53. package/src/components/ui/badge/index.ts +1 -0
  54. package/src/components/ui/breadcrumb/Breadcrumb.vue +6 -0
  55. package/src/components/ui/breadcrumb/BreadcrumbEllipsis.vue +12 -0
  56. package/src/components/ui/breadcrumb/BreadcrumbItem.vue +6 -0
  57. package/src/components/ui/breadcrumb/BreadcrumbLink.vue +20 -0
  58. package/src/components/ui/breadcrumb/BreadcrumbList.vue +6 -0
  59. package/src/components/ui/breadcrumb/BreadcrumbPage.vue +6 -0
  60. package/src/components/ui/breadcrumb/BreadcrumbSeparator.vue +11 -0
  61. package/src/components/ui/breadcrumb/index.ts +7 -0
  62. package/src/components/ui/button/Button.vue +65 -0
  63. package/src/components/ui/button/index.ts +1 -0
  64. package/src/components/ui/card/Card.vue +13 -0
  65. package/src/components/ui/card/CardContent.vue +7 -0
  66. package/src/components/ui/card/CardDescription.vue +7 -0
  67. package/src/components/ui/card/CardFooter.vue +7 -0
  68. package/src/components/ui/card/CardHeader.vue +9 -0
  69. package/src/components/ui/card/CardTitle.vue +7 -0
  70. package/src/components/ui/card/index.ts +6 -0
  71. package/src/components/ui/checkbox/Checkbox.vue +25 -0
  72. package/src/components/ui/checkbox/index.ts +1 -0
  73. package/src/components/ui/collapsible/Collapsible.vue +13 -0
  74. package/src/components/ui/collapsible/index.ts +2 -0
  75. package/src/components/ui/command/Command.vue +16 -0
  76. package/src/components/ui/command/CommandEmpty.vue +5 -0
  77. package/src/components/ui/command/CommandGroup.vue +22 -0
  78. package/src/components/ui/command/CommandInput.vue +21 -0
  79. package/src/components/ui/command/CommandItem.vue +22 -0
  80. package/src/components/ui/command/CommandList.vue +17 -0
  81. package/src/components/ui/command/CommandSeparator.vue +5 -0
  82. package/src/components/ui/command/index.ts +7 -0
  83. package/src/components/ui/context-menu/ContextMenuContent.vue +24 -0
  84. package/src/components/ui/context-menu/ContextMenuItem.vue +16 -0
  85. package/src/components/ui/context-menu/ContextMenuLabel.vue +9 -0
  86. package/src/components/ui/context-menu/ContextMenuSeparator.vue +9 -0
  87. package/src/components/ui/context-menu/ContextMenuSubContent.vue +14 -0
  88. package/src/components/ui/context-menu/index.ts +9 -0
  89. package/src/components/ui/dialog/Dialog.vue +14 -0
  90. package/src/components/ui/dialog/DialogClose.vue +12 -0
  91. package/src/components/ui/dialog/DialogContent.vue +48 -0
  92. package/src/components/ui/dialog/DialogDescription.vue +23 -0
  93. package/src/components/ui/dialog/DialogFooter.vue +12 -0
  94. package/src/components/ui/dialog/DialogHeader.vue +12 -0
  95. package/src/components/ui/dialog/DialogScrollContent.vue +47 -0
  96. package/src/components/ui/dialog/DialogTitle.vue +23 -0
  97. package/src/components/ui/dialog/DialogTrigger.vue +12 -0
  98. package/src/components/ui/dialog/index.ts +9 -0
  99. package/src/components/ui/dropdown-menu/DropdownMenu.vue +13 -0
  100. package/src/components/ui/dropdown-menu/DropdownMenuCheckboxItem.vue +28 -0
  101. package/src/components/ui/dropdown-menu/DropdownMenuContent.vue +33 -0
  102. package/src/components/ui/dropdown-menu/DropdownMenuGroup.vue +11 -0
  103. package/src/components/ui/dropdown-menu/DropdownMenuItem.vue +27 -0
  104. package/src/components/ui/dropdown-menu/DropdownMenuLabel.vue +23 -0
  105. package/src/components/ui/dropdown-menu/DropdownMenuRadioGroup.vue +13 -0
  106. package/src/components/ui/dropdown-menu/DropdownMenuRadioItem.vue +27 -0
  107. package/src/components/ui/dropdown-menu/DropdownMenuSeparator.vue +13 -0
  108. package/src/components/ui/dropdown-menu/DropdownMenuShortcut.vue +12 -0
  109. package/src/components/ui/dropdown-menu/DropdownMenuSub.vue +13 -0
  110. package/src/components/ui/dropdown-menu/DropdownMenuSubContent.vue +27 -0
  111. package/src/components/ui/dropdown-menu/DropdownMenuSubTrigger.vue +23 -0
  112. package/src/components/ui/dropdown-menu/DropdownMenuTrigger.vue +11 -0
  113. package/src/components/ui/dropdown-menu/index.ts +14 -0
  114. package/src/components/ui/form/FormControl.vue +3 -0
  115. package/src/components/ui/form/FormDescription.vue +6 -0
  116. package/src/components/ui/form/FormItem.vue +6 -0
  117. package/src/components/ui/form/FormLabel.vue +10 -0
  118. package/src/components/ui/form/FormMessage.vue +10 -0
  119. package/src/components/ui/form/index.ts +9 -0
  120. package/src/components/ui/hover-card/HoverCard.vue +13 -0
  121. package/src/components/ui/hover-card/HoverCardContent.vue +26 -0
  122. package/src/components/ui/hover-card/HoverCardTrigger.vue +11 -0
  123. package/src/components/ui/hover-card/index.ts +3 -0
  124. package/src/components/ui/input/Input.vue +23 -0
  125. package/src/components/ui/input/index.ts +1 -0
  126. package/src/components/ui/label/Label.vue +18 -0
  127. package/src/components/ui/label/index.ts +1 -0
  128. package/src/components/ui/lib/utils.ts +2 -0
  129. package/src/components/ui/menubar/MenubarContent.vue +15 -0
  130. package/src/components/ui/menubar/MenubarItem.vue +13 -0
  131. package/src/components/ui/menubar/MenubarTrigger.vue +13 -0
  132. package/src/components/ui/menubar/index.ts +5 -0
  133. package/src/components/ui/navigation-menu/NavigationMenuContent.vue +14 -0
  134. package/src/components/ui/navigation-menu/NavigationMenuTrigger.vue +15 -0
  135. package/src/components/ui/navigation-menu/index.ts +4 -0
  136. package/src/components/ui/pagination/PaginationContent.vue +13 -0
  137. package/src/components/ui/pagination/PaginationEllipsis.vue +12 -0
  138. package/src/components/ui/pagination/PaginationNext.vue +14 -0
  139. package/src/components/ui/pagination/PaginationPrev.vue +14 -0
  140. package/src/components/ui/pagination/index.ts +6 -0
  141. package/src/components/ui/popover/Popover.vue +13 -0
  142. package/src/components/ui/popover/PopoverContent.vue +27 -0
  143. package/src/components/ui/popover/PopoverTrigger.vue +11 -0
  144. package/src/components/ui/popover/index.ts +3 -0
  145. package/src/components/ui/progress/Progress.vue +21 -0
  146. package/src/components/ui/progress/index.ts +1 -0
  147. package/src/components/ui/radio-group/RadioGroup.vue +16 -0
  148. package/src/components/ui/radio-group/RadioGroupItem.vue +24 -0
  149. package/src/components/ui/radio-group/index.ts +2 -0
  150. package/src/components/ui/scroll-area/ScrollArea.vue +13 -0
  151. package/src/components/ui/scroll-area/index.ts +1 -0
  152. package/src/components/ui/select/Select.vue +13 -0
  153. package/src/components/ui/select/SelectContent.vue +40 -0
  154. package/src/components/ui/select/SelectGroup.vue +15 -0
  155. package/src/components/ui/select/SelectItem.vue +30 -0
  156. package/src/components/ui/select/SelectLabel.vue +15 -0
  157. package/src/components/ui/select/SelectSeparator.vue +13 -0
  158. package/src/components/ui/select/SelectTrigger.vue +23 -0
  159. package/src/components/ui/select/SelectValue.vue +11 -0
  160. package/src/components/ui/select/index.ts +8 -0
  161. package/src/components/ui/separator/Separator.vue +16 -0
  162. package/src/components/ui/separator/index.ts +1 -0
  163. package/src/components/ui/sheet/Sheet.vue +13 -0
  164. package/src/components/ui/sheet/SheetClose.vue +11 -0
  165. package/src/components/ui/sheet/SheetContent.vue +65 -0
  166. package/src/components/ui/sheet/SheetDescription.vue +15 -0
  167. package/src/components/ui/sheet/SheetFooter.vue +12 -0
  168. package/src/components/ui/sheet/SheetHeader.vue +12 -0
  169. package/src/components/ui/sheet/SheetTitle.vue +15 -0
  170. package/src/components/ui/sheet/SheetTrigger.vue +11 -0
  171. package/src/components/ui/sheet/index.ts +8 -0
  172. package/src/components/ui/skeleton/Skeleton.vue +9 -0
  173. package/src/components/ui/skeleton/index.ts +1 -0
  174. package/src/components/ui/slider/Slider.vue +26 -0
  175. package/src/components/ui/slider/index.ts +1 -0
  176. package/src/components/ui/switch/Switch.vue +24 -0
  177. package/src/components/ui/switch/index.ts +1 -0
  178. package/src/components/ui/table/Table.vue +13 -0
  179. package/src/components/ui/table/TableBody.vue +6 -0
  180. package/src/components/ui/table/TableCaption.vue +6 -0
  181. package/src/components/ui/table/TableCell.vue +6 -0
  182. package/src/components/ui/table/TableFooter.vue +6 -0
  183. package/src/components/ui/table/TableHead.vue +6 -0
  184. package/src/components/ui/table/TableHeader.vue +6 -0
  185. package/src/components/ui/table/TableRow.vue +6 -0
  186. package/src/components/ui/table/index.ts +8 -0
  187. package/src/components/ui/tabs/Tabs.vue +13 -0
  188. package/src/components/ui/tabs/TabsContent.vue +21 -0
  189. package/src/components/ui/tabs/TabsList.vue +21 -0
  190. package/src/components/ui/tabs/TabsTrigger.vue +21 -0
  191. package/src/components/ui/tabs/index.ts +4 -0
  192. package/src/components/ui/textarea/Textarea.vue +29 -0
  193. package/src/components/ui/textarea/index.ts +1 -0
  194. package/src/components/ui/toggle/Toggle.vue +40 -0
  195. package/src/components/ui/toggle/index.ts +1 -0
  196. package/src/components/ui/toggle-group/ToggleGroup.vue +16 -0
  197. package/src/components/ui/toggle-group/ToggleGroupItem.vue +21 -0
  198. package/src/components/ui/toggle-group/index.ts +2 -0
  199. package/src/components/ui/tooltip/Tooltip.vue +13 -0
  200. package/src/components/ui/tooltip/TooltipContent.vue +27 -0
  201. package/src/components/ui/tooltip/TooltipProvider.vue +12 -0
  202. package/src/components/ui/tooltip/TooltipTrigger.vue +11 -0
  203. package/src/components/ui/tooltip/index.ts +4 -0
  204. package/src/env.d.ts +7 -0
  205. package/src/index.ts +63 -0
  206. package/src/lib/utils.ts +7 -0
  207. package/src/patterns/DetailView.vue +46 -0
  208. package/src/patterns/EmptyState.vue +27 -0
  209. package/src/patterns/FormView.vue +34 -0
  210. package/src/patterns/ListView.vue +45 -0
  211. package/src/styles/index.css +4 -0
  212. package/src/styles/tokens.css +144 -0
  213. package/tailwind.config.js +108 -0
  214. package/tsconfig.json +21 -0
  215. package/dist/index.css +0 -1890
  216. package/dist/index.d.ts +0 -406
  217. package/dist/index.js +0 -1721
  218. package/dist/index.js.map +0 -1
  219. package/tailwind.config.ts +0 -174
@@ -0,0 +1,83 @@
1
+ # Detail Page Layout
2
+
3
+ ## When to Use
4
+ - Viewing a single item's complete information
5
+ - Item detail with related data sections
6
+ - Edit-in-place forms
7
+
8
+ ## Skeleton Code
9
+
10
+ ```vue
11
+ <script setup>
12
+ import {
13
+ Button, Badge, Separator, Tabs, TabsContent, TabsList, TabsTrigger,
14
+ Card, CardContent, CardHeader, CardTitle, Skeleton,
15
+ Breadcrumb, BreadcrumbItem, BreadcrumbLink, BreadcrumbList, BreadcrumbPage, BreadcrumbSeparator,
16
+ } from '@reinvented/design'
17
+ import { ArrowLeft, Pencil, Trash2 } from 'lucide-vue-next'
18
+
19
+ const item = ref(null)
20
+ const loading = ref(true)
21
+ </script>
22
+
23
+ <template>
24
+ <div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8 space-y-6">
25
+
26
+ <!-- Breadcrumb -->
27
+ <Breadcrumb>
28
+ <BreadcrumbList>
29
+ <BreadcrumbItem><BreadcrumbLink href="/items">Items</BreadcrumbLink></BreadcrumbItem>
30
+ <BreadcrumbSeparator />
31
+ <BreadcrumbItem><BreadcrumbPage>{{ item?.name }}</BreadcrumbPage></BreadcrumbItem>
32
+ </BreadcrumbList>
33
+ </Breadcrumb>
34
+
35
+ <!-- Page Header -->
36
+ <div class="flex items-center justify-between">
37
+ <div class="flex items-center gap-3">
38
+ <h1 class="text-2xl font-bold tracking-tight">{{ item?.name }}</h1>
39
+ <Badge>{{ item?.status }}</Badge>
40
+ </div>
41
+ <div class="flex items-center gap-2">
42
+ <Button variant="outline"><Pencil class="mr-2 h-4 w-4" /> Edit</Button>
43
+ <Button variant="destructive"><Trash2 class="mr-2 h-4 w-4" /> Delete</Button>
44
+ </div>
45
+ </div>
46
+
47
+ <Separator />
48
+
49
+ <!-- Tabbed Content -->
50
+ <Tabs default-value="overview">
51
+ <TabsList>
52
+ <TabsTrigger value="overview">Overview</TabsTrigger>
53
+ <TabsTrigger value="activity">Activity</TabsTrigger>
54
+ <TabsTrigger value="settings">Settings</TabsTrigger>
55
+ </TabsList>
56
+
57
+ <TabsContent value="overview" class="space-y-6">
58
+ <!-- Detail Cards -->
59
+ <div class="grid gap-6 md:grid-cols-2">
60
+ <Card>
61
+ <CardHeader><CardTitle>Details</CardTitle></CardHeader>
62
+ <CardContent>
63
+ <dl class="space-y-3">
64
+ <div>
65
+ <dt class="text-sm text-muted-foreground">Created</dt>
66
+ <dd class="text-sm font-medium">{{ item?.createdAt }}</dd>
67
+ </div>
68
+ </dl>
69
+ </CardContent>
70
+ </Card>
71
+ </div>
72
+ </TabsContent>
73
+ </Tabs>
74
+ </div>
75
+ </template>
76
+ ```
77
+
78
+ ## Key Patterns
79
+ - **Breadcrumb** at the top for back navigation
80
+ - **Header**: Title + badge + action buttons
81
+ - **Tabbed sections** for detailed content
82
+ - **Detail cards** in a 2-column grid for metadata
83
+ - **Separator** between header and tabbed content
@@ -0,0 +1,45 @@
1
+ # Layout Documentation
2
+
3
+ ## Decision Tree
4
+
5
+ Use this tree to choose the right layout for each view:
6
+
7
+ ```
8
+ Is this a list of items?
9
+ ├─ Yes → List Page (list-page.md)
10
+ ├─ No
11
+ │ ├─ Is this showing a single item's details?
12
+ │ │ ├─ Yes → Detail Page (detail-page.md)
13
+ │ │ ├─ No
14
+ │ │ │ ├─ Is this a dashboard/overview?
15
+ │ │ │ │ ├─ Yes → Dashboard (dashboard.md)
16
+ │ │ │ │ ├─ No
17
+ │ │ │ │ │ ├─ Is this a settings/configuration page?
18
+ │ │ │ │ │ │ ├─ Yes → Settings Page (settings-page.md)
19
+ │ │ │ │ │ │ ├─ No
20
+ │ │ │ │ │ │ │ ├─ Is this a multi-step process?
21
+ │ │ │ │ │ │ │ │ ├─ Yes → Step Wizard (step-wizard.md)
22
+ │ │ │ │ │ │ │ │ ├─ No
23
+ │ │ │ │ │ │ │ │ │ ├─ Is this a simple form?
24
+ │ │ │ │ │ │ │ │ │ │ ├─ ≤5 fields → Modal Form (use Dialog)
25
+ │ │ │ │ │ │ │ │ │ │ ├─ >5 fields → Full Page Form (detail-page.md variant)
26
+ ```
27
+
28
+ ## Available Layouts
29
+
30
+ | Layout | File | Use for |
31
+ |--------|------|---------|
32
+ | [List Page](list-page.md) | ✅ | Filterable, searchable lists of items |
33
+ | [Detail Page](detail-page.md) | ✅ | Single item view with actions |
34
+ | [Dashboard](dashboard.md) | ✅ | Overview grids with stats and summaries |
35
+ | [Settings Page](settings-page.md) | ✅ | Configuration with sidebar nav |
36
+ | [Step Wizard](step-wizard.md) | ✅ | Multi-step guided processes |
37
+ | Modal Form | — | Use Dialog component (≤5 fields) |
38
+
39
+ ## General Layout Rules
40
+
41
+ 1. **Max content width**: `max-w-7xl mx-auto` for main content
42
+ 2. **Page padding**: `px-4 sm:px-6 lg:px-8`
43
+ 3. **Section spacing**: `space-y-6` between major sections
44
+ 4. **Page header pattern**: Title + description + primary action
45
+ 5. **Responsive**: All layouts must work at mobile (320px+), tablet (768px+), desktop (1024px+)
@@ -0,0 +1,107 @@
1
+ # List Page Layout
2
+
3
+ ## When to Use
4
+ - Browse a collection of items (tasks, users, apps)
5
+ - Filterable, searchable, sortable data
6
+ - Paginated or infinite-scroll lists
7
+
8
+ ## Skeleton Code
9
+
10
+ ```vue
11
+ <script setup>
12
+ import { ref } from 'vue'
13
+ import {
14
+ Button, Input, Select, SelectContent, SelectItem, SelectTrigger, SelectValue,
15
+ Card, CardContent, Badge, Skeleton,
16
+ DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger,
17
+ } from '@reinvented/design'
18
+ import { Plus, Search, MoreHorizontal } from 'lucide-vue-next'
19
+
20
+ const search = ref('')
21
+ const filter = ref('all')
22
+ const items = ref([]) // from GraphQL query
23
+ const loading = ref(true)
24
+ </script>
25
+
26
+ <template>
27
+ <div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8 space-y-6">
28
+
29
+ <!-- Page Header -->
30
+ <div class="flex items-center justify-between">
31
+ <div>
32
+ <h1 class="text-2xl font-bold tracking-tight">Items</h1>
33
+ <p class="text-muted-foreground">Manage your items.</p>
34
+ </div>
35
+ <Button><Plus class="mr-2 h-4 w-4" /> New Item</Button>
36
+ </div>
37
+
38
+ <!-- Filters Bar -->
39
+ <div class="flex items-center gap-4">
40
+ <div class="relative flex-1 max-w-sm">
41
+ <Search class="absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground" />
42
+ <Input v-model="search" class="pl-9" placeholder="Search items..." />
43
+ </div>
44
+ <Select v-model="filter">
45
+ <SelectTrigger class="w-[150px]">
46
+ <SelectValue placeholder="Filter" />
47
+ </SelectTrigger>
48
+ <SelectContent>
49
+ <SelectItem value="all">All</SelectItem>
50
+ <SelectItem value="active">Active</SelectItem>
51
+ <SelectItem value="archived">Archived</SelectItem>
52
+ </SelectContent>
53
+ </Select>
54
+ </div>
55
+
56
+ <!-- Loading State -->
57
+ <div v-if="loading" class="space-y-3">
58
+ <Skeleton v-for="i in 5" :key="i" class="h-16 w-full rounded-lg" />
59
+ </div>
60
+
61
+ <!-- Empty State -->
62
+ <div v-else-if="items.length === 0" class="flex flex-col items-center justify-center py-12 text-center">
63
+ <div class="rounded-full bg-muted p-4 mb-4">
64
+ <Search class="h-8 w-8 text-muted-foreground" />
65
+ </div>
66
+ <h3 class="text-lg font-semibold">No items found</h3>
67
+ <p class="text-muted-foreground mt-1">Get started by creating your first item.</p>
68
+ <Button class="mt-4"><Plus class="mr-2 h-4 w-4" /> Create Item</Button>
69
+ </div>
70
+
71
+ <!-- Data State -->
72
+ <div v-else class="space-y-3">
73
+ <Card v-for="item in items" :key="item.id" class="hover:shadow-sm transition-shadow">
74
+ <CardContent class="flex items-center justify-between p-4">
75
+ <div class="flex items-center gap-3">
76
+ <div>
77
+ <p class="font-medium">{{ item.name }}</p>
78
+ <p class="text-sm text-muted-foreground">{{ item.description }}</p>
79
+ </div>
80
+ </div>
81
+ <div class="flex items-center gap-2">
82
+ <Badge>{{ item.status }}</Badge>
83
+ <DropdownMenu>
84
+ <DropdownMenuTrigger as-child>
85
+ <Button variant="ghost" size="icon">
86
+ <MoreHorizontal class="h-4 w-4" />
87
+ </Button>
88
+ </DropdownMenuTrigger>
89
+ <DropdownMenuContent align="end">
90
+ <DropdownMenuItem>Edit</DropdownMenuItem>
91
+ <DropdownMenuItem class="text-destructive">Delete</DropdownMenuItem>
92
+ </DropdownMenuContent>
93
+ </DropdownMenu>
94
+ </div>
95
+ </CardContent>
96
+ </Card>
97
+ </div>
98
+ </div>
99
+ </template>
100
+ ```
101
+
102
+ ## Key Patterns
103
+ - **Header**: Title + description + primary CTA
104
+ - **Filters**: Search + dropdown filters in a row
105
+ - **Three states**: Loading (skeletons), empty, data
106
+ - **Item cards**: Name + description + badge + action menu
107
+ - **Empty state**: Icon + message + CTA
@@ -0,0 +1,79 @@
1
+ # Settings Page Layout
2
+
3
+ ## When to Use
4
+ - User preferences
5
+ - App configuration
6
+ - Account management
7
+
8
+ ## Skeleton Code
9
+
10
+ ```vue
11
+ <script setup>
12
+ import {
13
+ Button, Input, Label, Separator, Switch, Textarea,
14
+ Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle,
15
+ } from '@reinvented/design'
16
+ </script>
17
+
18
+ <template>
19
+ <div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
20
+ <div class="flex flex-col md:flex-row gap-8">
21
+
22
+ <!-- Sidebar Nav -->
23
+ <nav class="w-full md:w-48 space-y-1">
24
+ <a v-for="section in sections" :key="section.id"
25
+ :href="`#${section.id}`"
26
+ class="block rounded-md px-3 py-2 text-sm font-medium text-muted-foreground hover:bg-muted hover:text-foreground"
27
+ :class="{ 'bg-muted text-foreground': activeSection === section.id }">
28
+ {{ section.label }}
29
+ </a>
30
+ </nav>
31
+
32
+ <!-- Settings Content -->
33
+ <div class="flex-1 space-y-6 max-w-2xl">
34
+ <Card id="profile">
35
+ <CardHeader>
36
+ <CardTitle>Profile</CardTitle>
37
+ <CardDescription>Update your personal information.</CardDescription>
38
+ </CardHeader>
39
+ <CardContent class="space-y-4">
40
+ <div class="space-y-2">
41
+ <Label for="name">Name</Label>
42
+ <Input id="name" placeholder="Your name" />
43
+ </div>
44
+ <div class="space-y-2">
45
+ <Label for="bio">Bio</Label>
46
+ <Textarea id="bio" placeholder="About you" />
47
+ </div>
48
+ </CardContent>
49
+ <CardFooter>
50
+ <Button>Save Changes</Button>
51
+ </CardFooter>
52
+ </Card>
53
+
54
+ <Card id="notifications">
55
+ <CardHeader>
56
+ <CardTitle>Notifications</CardTitle>
57
+ <CardDescription>Choose what notifications you receive.</CardDescription>
58
+ </CardHeader>
59
+ <CardContent class="space-y-4">
60
+ <div class="flex items-center justify-between">
61
+ <div>
62
+ <p class="text-sm font-medium">Email notifications</p>
63
+ <p class="text-sm text-muted-foreground">Receive updates via email.</p>
64
+ </div>
65
+ <Switch />
66
+ </div>
67
+ </CardContent>
68
+ </Card>
69
+ </div>
70
+ </div>
71
+ </div>
72
+ </template>
73
+ ```
74
+
75
+ ## Key Patterns
76
+ - **Sidebar nav** on left, content on right
77
+ - **Each section** is a Card with header + form fields + save button
78
+ - **Switch rows**: Label + description on left, Switch on right
79
+ - **Mobile**: sidebar stacks above content
@@ -0,0 +1,73 @@
1
+ # Step Wizard Layout
2
+
3
+ ## When to Use
4
+ - Multi-step processes (onboarding, app creation, checkout)
5
+ - 3–7 steps where each depends on the previous
6
+
7
+ ## Skeleton Code
8
+
9
+ ```vue
10
+ <script setup>
11
+ import { ref, computed } from 'vue'
12
+ import { Button, Card, CardContent, CardFooter, CardHeader, CardTitle, Progress } from '@reinvented/design'
13
+ import { Check } from 'lucide-vue-next'
14
+
15
+ const currentStep = ref(0)
16
+ const steps = [
17
+ { title: 'Details', component: 'StepDetails' },
18
+ { title: 'Configuration', component: 'StepConfig' },
19
+ { title: 'Review', component: 'StepReview' },
20
+ ]
21
+ const progress = computed(() => ((currentStep.value + 1) / steps.length) * 100)
22
+ </script>
23
+
24
+ <template>
25
+ <div class="max-w-2xl mx-auto px-4 py-8 space-y-8">
26
+
27
+ <!-- Step Indicator -->
28
+ <div class="space-y-4">
29
+ <Progress :model-value="progress" />
30
+ <div class="flex justify-between">
31
+ <div v-for="(step, i) in steps" :key="i" class="flex items-center gap-2 text-sm">
32
+ <div
33
+ class="flex h-6 w-6 items-center justify-center rounded-full text-xs font-medium"
34
+ :class="i <= currentStep ? 'bg-primary text-primary-foreground' : 'bg-muted text-muted-foreground'"
35
+ >
36
+ <Check v-if="i < currentStep" class="h-3 w-3" />
37
+ <span v-else>{{ i + 1 }}</span>
38
+ </div>
39
+ <span :class="i <= currentStep ? 'text-foreground' : 'text-muted-foreground'">{{ step.title }}</span>
40
+ </div>
41
+ </div>
42
+ </div>
43
+
44
+ <!-- Step Content -->
45
+ <Card>
46
+ <CardHeader>
47
+ <CardTitle>{{ steps[currentStep].title }}</CardTitle>
48
+ </CardHeader>
49
+ <CardContent>
50
+ <component :is="steps[currentStep].component" />
51
+ </CardContent>
52
+ <CardFooter class="flex justify-between">
53
+ <Button variant="outline" :disabled="currentStep === 0" @click="currentStep--">
54
+ Previous
55
+ </Button>
56
+ <Button v-if="currentStep < steps.length - 1" @click="currentStep++">
57
+ Next
58
+ </Button>
59
+ <Button v-else @click="submit">
60
+ Complete
61
+ </Button>
62
+ </CardFooter>
63
+ </Card>
64
+ </div>
65
+ </template>
66
+ ```
67
+
68
+ ## Key Patterns
69
+ - **Progress bar** + step circles at top
70
+ - **Single card** with dynamic content
71
+ - **Previous/Next** buttons in card footer
72
+ - **Narrower max-width** than other layouts (`max-w-2xl`)
73
+ - Completed steps show ✓, current step highlighted
@@ -0,0 +1,39 @@
1
+ # Patterns Index
2
+
3
+ Reusable UI patterns — compositions of DS components for common use cases. Each pattern has a dedicated file with skeleton code.
4
+
5
+ This directory grows via harmonization: when agents discover patterns used across multiple apps, they're promoted here.
6
+
7
+ ## Available Patterns
8
+
9
+ *No patterns promoted yet. Agents should propose new patterns via PRs to this repo.*
10
+
11
+ ## How Patterns Get Added
12
+
13
+ 1. Agent builds an app and identifies a reusable UI pattern
14
+ 2. Agent opens a PR to this repo with a new `patterns/<name>.md` file
15
+ 3. Human or harmonization agent reviews
16
+ 4. On merge, all future agent runs benefit from the pattern
17
+
18
+ ## Pattern File Format
19
+
20
+ Each pattern file should include:
21
+
22
+ ```markdown
23
+ # Pattern: [Name]
24
+
25
+ ## When to Use
26
+ [Describe the use case]
27
+
28
+ ## Skeleton Code
29
+ [Working Vue code with TODO comments for app-specific parts]
30
+
31
+ ## Props / Configuration
32
+ [What's customizable]
33
+
34
+ ## Related Components
35
+ [Which DS components this pattern uses]
36
+
37
+ ## Apps Using This
38
+ [List of apps where this pattern was first used or is in use]
39
+ ```
package/docs/rules.md ADDED
@@ -0,0 +1,43 @@
1
+ # Design Rules
2
+
3
+ Non-negotiable rules for all Reinvented apps. These are enforced by linting where possible.
4
+
5
+ ## Components
6
+
7
+ 1. **No raw `<button>`** — use `<Button>` from `@reinvented/design`
8
+ 2. **No raw `<input>`** — use `<Input>` from `@reinvented/design`
9
+ 3. **No raw `<select>`** — use `<Select>` from `@reinvented/design`
10
+ 4. **No raw `<textarea>`** — use `<Textarea>` from `@reinvented/design`
11
+ 5. **No `alert()`, `confirm()`, `prompt()`** — use `<Dialog>` / `<AlertDialog>` / `<Toast>`
12
+
13
+ ## Styling
14
+
15
+ 6. **No hardcoded colors** — use CSS variables (`bg-background`, `text-foreground`, `bg-primary`, etc.)
16
+ 7. **No arbitrary Tailwind values** — no `text-[#333]` or `p-[13px]`. Use only token-based utilities
17
+ 8. **No inline styles** — all styling through Tailwind utilities and DS component props
18
+ 9. **No `@apply` blocks** — prefer utility classes in templates
19
+
20
+ ## Icons & Media
21
+
22
+ 10. **No emojis** — use Lucide icons exclusively via `lucide-vue-next`
23
+ 11. **Default icon size**: `w-4 h-4` in buttons/nav, `w-12 h-12` in empty states
24
+
25
+ ## Layout
26
+
27
+ 12. **Modals for create/edit by default** — full pages only for forms with 8+ fields or rich content editing
28
+ 13. **Single-column responsive** — no split-screen layouts
29
+ 14. **Mobile-first** — no horizontal scrolling, minimum 44px touch targets
30
+ 15. **No custom scrollbars** — use `<ScrollArea>` from DS
31
+
32
+ ## States
33
+
34
+ 16. **Every view must have**: loading state, empty state, error state, data state
35
+ 17. **Every mutation button**: shows spinner during request, disabled while loading
36
+ 18. **Every list**: has empty state with descriptive text and CTA
37
+
38
+ ## Data
39
+
40
+ 19. **No `SELECT *`** — explicitly list columns
41
+ 20. **Parameterized queries only** — no string interpolation for user input
42
+ 21. **UUID primary keys** everywhere
43
+ 22. **RLS on every table** — no exceptions
@@ -0,0 +1,141 @@
1
+ # Visual Polish Guide
2
+
3
+ Standards for animations, transitions, loading patterns, and interaction polish.
4
+
5
+ ## Transition Durations
6
+
7
+ | Duration | Use |
8
+ |----------|-----|
9
+ | `duration-150` (150ms) | Hover states, color changes, opacity |
10
+ | `duration-200` (200ms) | Modals open/close, tooltips, popovers |
11
+ | `duration-300` (300ms) | Page transitions, slide-ins, expanded sections |
12
+
13
+ **Easing**: Use `ease-out` for entrances, `ease-in` for exits, `ease-in-out` for state changes.
14
+
15
+ ## Modal Animations
16
+
17
+ ```vue
18
+ <!-- Dialog with fade + scale -->
19
+ <DialogContent class="
20
+ data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95
21
+ data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95
22
+ duration-200
23
+ ">
24
+ ```
25
+
26
+ ## List Item Animations
27
+
28
+ ```vue
29
+ <TransitionGroup name="list" tag="div">
30
+ <Card v-for="item in items" :key="item.id">
31
+ <!-- content -->
32
+ </Card>
33
+ </TransitionGroup>
34
+
35
+ <style>
36
+ .list-enter-active { transition: all 0.3s ease-out; }
37
+ .list-leave-active { transition: all 0.2s ease-in; }
38
+ .list-enter-from { opacity: 0; transform: translateY(8px); }
39
+ .list-leave-to { opacity: 0; transform: translateX(-16px); }
40
+ .list-move { transition: transform 0.3s ease; }
41
+ </style>
42
+ ```
43
+
44
+ ## Button Loading State
45
+
46
+ ```vue
47
+ <script setup>
48
+ import { ref } from 'vue'
49
+ import { Button } from '@reinvented/design'
50
+ import { Loader2 } from 'lucide-vue-next'
51
+
52
+ const saving = ref(false)
53
+ async function handleSave() {
54
+ saving.value = true
55
+ try {
56
+ await saveMutation()
57
+ } finally {
58
+ saving.value = false
59
+ }
60
+ }
61
+ </script>
62
+
63
+ <template>
64
+ <Button :disabled="saving" @click="handleSave">
65
+ <Loader2 v-if="saving" class="w-4 h-4 mr-2 animate-spin" />
66
+ {{ saving ? 'Saving...' : 'Save' }}
67
+ </Button>
68
+ </template>
69
+ ```
70
+
71
+ ## Skeleton Loading
72
+
73
+ Skeletons must match the shape of the actual content:
74
+
75
+ ```vue
76
+ <!-- Skeleton for a card list -->
77
+ <div class="space-y-4">
78
+ <div v-for="i in 3" :key="i" class="p-4 border rounded-lg">
79
+ <div class="flex items-center gap-3">
80
+ <Skeleton class="w-10 h-10 rounded-full" />
81
+ <div class="flex-1 space-y-2">
82
+ <Skeleton class="h-4 w-3/4" />
83
+ <Skeleton class="h-3 w-1/2" />
84
+ </div>
85
+ </div>
86
+ </div>
87
+ </div>
88
+ ```
89
+
90
+ ## Toast Notifications
91
+
92
+ ```vue
93
+ <script setup>
94
+ import { toast } from '@reinvented/design'
95
+
96
+ // Success
97
+ toast.success('Task created')
98
+
99
+ // Error with action
100
+ toast.error('Failed to save', {
101
+ action: { label: 'Retry', onClick: () => handleSave() }
102
+ })
103
+
104
+ // Promise-based (auto shows loading → success/error)
105
+ toast.promise(saveMutation(), {
106
+ loading: 'Saving...',
107
+ success: 'Saved!',
108
+ error: 'Failed to save'
109
+ })
110
+ </script>
111
+ ```
112
+
113
+ ## Focus Management
114
+
115
+ - **Modal open**: Focus first interactive element inside the modal
116
+ - **Modal close**: Return focus to the trigger element
117
+ - **After delete**: Focus the next item in the list (or empty state)
118
+ - **After create**: Focus the newly created item (or close modal and show toast)
119
+ - **Tab order**: Logical reading order, top-to-bottom, left-to-right
120
+
121
+ ## Hover Effects
122
+
123
+ ```vue
124
+ <!-- Card with hover lift -->
125
+ <Card class="transition-shadow duration-150 hover:shadow-md cursor-pointer">
126
+
127
+ <!-- Button with subtle scale on press -->
128
+ <Button class="active:scale-[0.98] transition-transform duration-150">
129
+ ```
130
+
131
+ ## Optimistic Updates
132
+
133
+ Use for:
134
+ - Toggles (like/unlike, pin/unpin)
135
+ - Status changes (mark complete)
136
+ - Reordering (drag and drop)
137
+
138
+ Do NOT use for:
139
+ - Creation (need server-generated ID)
140
+ - Deletion (hard to undo if server rejects)
141
+ - Complex mutations (multiple side effects)