@reinvented/design 0.2.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.
- package/docs/components/alert-dialog.md +32 -0
- package/docs/components/avatar.md +14 -0
- package/docs/components/badge.md +24 -0
- package/docs/components/button.md +69 -0
- package/docs/components/card.md +49 -0
- package/docs/components/dialog.md +46 -0
- package/docs/components/dropdown-menu.md +32 -0
- package/docs/components/index.md +69 -50
- package/docs/components/input.md +34 -0
- package/docs/components/remaining-components.md +253 -0
- package/docs/components/scroll-area.md +17 -0
- package/docs/components/select.md +31 -0
- package/docs/components/separator.md +14 -0
- package/docs/components/sheet.md +32 -0
- package/docs/components/skeleton.md +20 -0
- package/docs/components/table.md +33 -0
- package/docs/components/tabs.md +23 -0
- package/docs/layouts/dashboard.md +70 -0
- package/docs/layouts/detail-page.md +83 -0
- package/docs/layouts/index.md +37 -24
- package/docs/layouts/list-page.md +107 -0
- package/docs/layouts/settings-page.md +79 -0
- package/docs/layouts/step-wizard.md +73 -0
- package/package.json +1 -1
- package/src/components/ui/accordion/Accordion.vue +13 -0
- package/src/components/ui/accordion/AccordionContent.vue +20 -0
- package/src/components/ui/accordion/AccordionItem.vue +15 -0
- package/src/components/ui/accordion/AccordionTrigger.vue +25 -0
- package/src/components/ui/accordion/index.ts +4 -0
- package/src/components/ui/alert/Alert.vue +38 -0
- package/src/components/ui/alert/AlertDescription.vue +12 -0
- package/src/components/ui/alert/AlertTitle.vue +12 -0
- package/src/components/ui/alert/index.ts +3 -0
- package/src/components/ui/alert-dialog/AlertDialog.vue +13 -0
- package/src/components/ui/alert-dialog/AlertDialogAction.vue +21 -0
- package/src/components/ui/alert-dialog/AlertDialogCancel.vue +21 -0
- package/src/components/ui/alert-dialog/AlertDialogContent.vue +39 -0
- package/src/components/ui/alert-dialog/AlertDialogDescription.vue +15 -0
- package/src/components/ui/alert-dialog/AlertDialogFooter.vue +12 -0
- package/src/components/ui/alert-dialog/AlertDialogHeader.vue +12 -0
- package/src/components/ui/alert-dialog/AlertDialogTitle.vue +15 -0
- package/src/components/ui/alert-dialog/AlertDialogTrigger.vue +11 -0
- package/src/components/ui/alert-dialog/index.ts +9 -0
- package/src/components/ui/breadcrumb/Breadcrumb.vue +6 -0
- package/src/components/ui/breadcrumb/BreadcrumbEllipsis.vue +12 -0
- package/src/components/ui/breadcrumb/BreadcrumbItem.vue +6 -0
- package/src/components/ui/breadcrumb/BreadcrumbLink.vue +20 -0
- package/src/components/ui/breadcrumb/BreadcrumbList.vue +6 -0
- package/src/components/ui/breadcrumb/BreadcrumbPage.vue +6 -0
- package/src/components/ui/breadcrumb/BreadcrumbSeparator.vue +11 -0
- package/src/components/ui/breadcrumb/index.ts +7 -0
- package/src/components/ui/button/Button.vue +0 -1
- package/src/components/ui/checkbox/Checkbox.vue +25 -0
- package/src/components/ui/checkbox/index.ts +1 -0
- package/src/components/ui/collapsible/Collapsible.vue +13 -0
- package/src/components/ui/collapsible/index.ts +2 -0
- package/src/components/ui/command/Command.vue +16 -0
- package/src/components/ui/command/CommandEmpty.vue +5 -0
- package/src/components/ui/command/CommandGroup.vue +22 -0
- package/src/components/ui/command/CommandInput.vue +21 -0
- package/src/components/ui/command/CommandItem.vue +22 -0
- package/src/components/ui/command/CommandList.vue +17 -0
- package/src/components/ui/command/CommandSeparator.vue +5 -0
- package/src/components/ui/command/index.ts +7 -0
- package/src/components/ui/context-menu/ContextMenuContent.vue +24 -0
- package/src/components/ui/context-menu/ContextMenuItem.vue +16 -0
- package/src/components/ui/context-menu/ContextMenuLabel.vue +9 -0
- package/src/components/ui/context-menu/ContextMenuSeparator.vue +9 -0
- package/src/components/ui/context-menu/ContextMenuSubContent.vue +14 -0
- package/src/components/ui/context-menu/index.ts +9 -0
- package/src/components/ui/dialog/Dialog.vue +14 -0
- package/src/components/ui/dialog/DialogClose.vue +12 -0
- package/src/components/ui/dialog/DialogContent.vue +48 -0
- package/src/components/ui/dialog/DialogDescription.vue +23 -0
- package/src/components/ui/dialog/DialogFooter.vue +12 -0
- package/src/components/ui/dialog/DialogHeader.vue +12 -0
- package/src/components/ui/dialog/DialogScrollContent.vue +47 -0
- package/src/components/ui/dialog/DialogTitle.vue +23 -0
- package/src/components/ui/dialog/DialogTrigger.vue +12 -0
- package/src/components/ui/dialog/index.ts +9 -0
- package/src/components/ui/dropdown-menu/DropdownMenu.vue +13 -0
- package/src/components/ui/dropdown-menu/DropdownMenuCheckboxItem.vue +28 -0
- package/src/components/ui/dropdown-menu/DropdownMenuContent.vue +33 -0
- package/src/components/ui/dropdown-menu/DropdownMenuGroup.vue +11 -0
- package/src/components/ui/dropdown-menu/DropdownMenuItem.vue +27 -0
- package/src/components/ui/dropdown-menu/DropdownMenuLabel.vue +23 -0
- package/src/components/ui/dropdown-menu/DropdownMenuRadioGroup.vue +13 -0
- package/src/components/ui/dropdown-menu/DropdownMenuRadioItem.vue +27 -0
- package/src/components/ui/dropdown-menu/DropdownMenuSeparator.vue +13 -0
- package/src/components/ui/dropdown-menu/DropdownMenuShortcut.vue +12 -0
- package/src/components/ui/dropdown-menu/DropdownMenuSub.vue +13 -0
- package/src/components/ui/dropdown-menu/DropdownMenuSubContent.vue +27 -0
- package/src/components/ui/dropdown-menu/DropdownMenuSubTrigger.vue +23 -0
- package/src/components/ui/dropdown-menu/DropdownMenuTrigger.vue +11 -0
- package/src/components/ui/dropdown-menu/index.ts +14 -0
- package/src/components/ui/form/FormControl.vue +3 -0
- package/src/components/ui/form/FormDescription.vue +6 -0
- package/src/components/ui/form/FormItem.vue +6 -0
- package/src/components/ui/form/FormLabel.vue +10 -0
- package/src/components/ui/form/FormMessage.vue +10 -0
- package/src/components/ui/form/index.ts +9 -0
- package/src/components/ui/hover-card/HoverCard.vue +13 -0
- package/src/components/ui/hover-card/HoverCardContent.vue +26 -0
- package/src/components/ui/hover-card/HoverCardTrigger.vue +11 -0
- package/src/components/ui/hover-card/index.ts +3 -0
- package/src/components/ui/label/Label.vue +18 -0
- package/src/components/ui/label/index.ts +1 -0
- package/src/components/ui/menubar/MenubarContent.vue +15 -0
- package/src/components/ui/menubar/MenubarItem.vue +13 -0
- package/src/components/ui/menubar/MenubarTrigger.vue +13 -0
- package/src/components/ui/menubar/index.ts +5 -0
- package/src/components/ui/navigation-menu/NavigationMenuContent.vue +14 -0
- package/src/components/ui/navigation-menu/NavigationMenuTrigger.vue +15 -0
- package/src/components/ui/navigation-menu/index.ts +4 -0
- package/src/components/ui/pagination/PaginationContent.vue +13 -0
- package/src/components/ui/pagination/PaginationEllipsis.vue +12 -0
- package/src/components/ui/pagination/PaginationNext.vue +14 -0
- package/src/components/ui/pagination/PaginationPrev.vue +14 -0
- package/src/components/ui/pagination/index.ts +6 -0
- package/src/components/ui/popover/Popover.vue +13 -0
- package/src/components/ui/popover/PopoverContent.vue +27 -0
- package/src/components/ui/popover/PopoverTrigger.vue +11 -0
- package/src/components/ui/popover/index.ts +3 -0
- package/src/components/ui/progress/Progress.vue +21 -0
- package/src/components/ui/progress/index.ts +1 -0
- package/src/components/ui/radio-group/RadioGroup.vue +16 -0
- package/src/components/ui/radio-group/RadioGroupItem.vue +24 -0
- package/src/components/ui/radio-group/index.ts +2 -0
- package/src/components/ui/select/Select.vue +13 -0
- package/src/components/ui/select/SelectContent.vue +40 -0
- package/src/components/ui/select/SelectGroup.vue +15 -0
- package/src/components/ui/select/SelectItem.vue +30 -0
- package/src/components/ui/select/SelectLabel.vue +15 -0
- package/src/components/ui/select/SelectSeparator.vue +13 -0
- package/src/components/ui/select/SelectTrigger.vue +23 -0
- package/src/components/ui/select/SelectValue.vue +11 -0
- package/src/components/ui/select/index.ts +8 -0
- package/src/components/ui/sheet/Sheet.vue +13 -0
- package/src/components/ui/sheet/SheetClose.vue +11 -0
- package/src/components/ui/sheet/SheetContent.vue +65 -0
- package/src/components/ui/sheet/SheetDescription.vue +15 -0
- package/src/components/ui/sheet/SheetFooter.vue +12 -0
- package/src/components/ui/sheet/SheetHeader.vue +12 -0
- package/src/components/ui/sheet/SheetTitle.vue +15 -0
- package/src/components/ui/sheet/SheetTrigger.vue +11 -0
- package/src/components/ui/sheet/index.ts +8 -0
- package/src/components/ui/slider/Slider.vue +26 -0
- package/src/components/ui/slider/index.ts +1 -0
- package/src/components/ui/switch/Switch.vue +24 -0
- package/src/components/ui/switch/index.ts +1 -0
- package/src/components/ui/table/Table.vue +13 -0
- package/src/components/ui/table/TableBody.vue +6 -0
- package/src/components/ui/table/TableCaption.vue +6 -0
- package/src/components/ui/table/TableCell.vue +6 -0
- package/src/components/ui/table/TableFooter.vue +6 -0
- package/src/components/ui/table/TableHead.vue +6 -0
- package/src/components/ui/table/TableHeader.vue +6 -0
- package/src/components/ui/table/TableRow.vue +6 -0
- package/src/components/ui/table/index.ts +8 -0
- package/src/components/ui/tabs/Tabs.vue +13 -0
- package/src/components/ui/tabs/TabsContent.vue +21 -0
- package/src/components/ui/tabs/TabsList.vue +21 -0
- package/src/components/ui/tabs/TabsTrigger.vue +21 -0
- package/src/components/ui/tabs/index.ts +4 -0
- package/src/components/ui/textarea/Textarea.vue +29 -0
- package/src/components/ui/textarea/index.ts +1 -0
- package/src/components/ui/toggle/Toggle.vue +40 -0
- package/src/components/ui/toggle/index.ts +1 -0
- package/src/components/ui/toggle-group/ToggleGroup.vue +16 -0
- package/src/components/ui/toggle-group/ToggleGroupItem.vue +21 -0
- package/src/components/ui/toggle-group/index.ts +2 -0
- package/src/components/ui/tooltip/Tooltip.vue +13 -0
- package/src/components/ui/tooltip/TooltipContent.vue +27 -0
- package/src/components/ui/tooltip/TooltipProvider.vue +12 -0
- package/src/components/ui/tooltip/TooltipTrigger.vue +11 -0
- package/src/components/ui/tooltip/index.ts +4 -0
- package/src/index.ts +46 -192
- package/src/patterns/DetailView.vue +2 -2
- package/src/patterns/EmptyState.vue +2 -2
- package/src/patterns/FormView.vue +2 -2
- package/src/patterns/ListView.vue +2 -2
- package/tsconfig.json +17 -3
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# ScrollArea
|
|
2
|
+
## Skeleton Code
|
|
3
|
+
```vue
|
|
4
|
+
<script setup>
|
|
5
|
+
import { ScrollArea } from '@reinvented/design'
|
|
6
|
+
</script>
|
|
7
|
+
<template>
|
|
8
|
+
<ScrollArea class="h-72 w-48 rounded-md border">
|
|
9
|
+
<div class="p-4">
|
|
10
|
+
<!-- Scrollable content -->
|
|
11
|
+
</div>
|
|
12
|
+
</ScrollArea>
|
|
13
|
+
</template>
|
|
14
|
+
```
|
|
15
|
+
## Gotchas
|
|
16
|
+
- Must have explicit height set via class
|
|
17
|
+
- Use instead of native scrollbars per DS rules
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# Select
|
|
2
|
+
## When to Use
|
|
3
|
+
- Single-value selection from a list of options
|
|
4
|
+
- When NOT to use: multi-select (use Checkbox group), binary toggle (use Switch)
|
|
5
|
+
|
|
6
|
+
## Skeleton Code
|
|
7
|
+
```vue
|
|
8
|
+
<script setup>
|
|
9
|
+
import { Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectTrigger, SelectValue } from '@reinvented/design'
|
|
10
|
+
</script>
|
|
11
|
+
|
|
12
|
+
<template>
|
|
13
|
+
<Select>
|
|
14
|
+
<SelectTrigger class="w-[180px]">
|
|
15
|
+
<SelectValue placeholder="Select a fruit" />
|
|
16
|
+
</SelectTrigger>
|
|
17
|
+
<SelectContent>
|
|
18
|
+
<SelectGroup>
|
|
19
|
+
<SelectLabel>Fruits</SelectLabel>
|
|
20
|
+
<SelectItem value="apple">Apple</SelectItem>
|
|
21
|
+
<SelectItem value="banana">Banana</SelectItem>
|
|
22
|
+
<SelectItem value="orange">Orange</SelectItem>
|
|
23
|
+
</SelectGroup>
|
|
24
|
+
</SelectContent>
|
|
25
|
+
</Select>
|
|
26
|
+
</template>
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Gotchas
|
|
30
|
+
- Use `placeholder` on `SelectValue` for the empty state text
|
|
31
|
+
- Supports `v-model` via `modelValue` prop on `Select`
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# Separator
|
|
2
|
+
## Skeleton Code
|
|
3
|
+
```vue
|
|
4
|
+
<script setup>
|
|
5
|
+
import { Separator } from '@reinvented/design'
|
|
6
|
+
</script>
|
|
7
|
+
<template>
|
|
8
|
+
<Separator /> <!-- Horizontal -->
|
|
9
|
+
<Separator orientation="vertical" /> <!-- Vertical -->
|
|
10
|
+
</template>
|
|
11
|
+
```
|
|
12
|
+
## Gotchas
|
|
13
|
+
- Use between logical sections, not decoratively
|
|
14
|
+
- Vertical separators need a container with `flex` and explicit height
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# Sheet
|
|
2
|
+
## When to Use
|
|
3
|
+
- Side panels for details or filters
|
|
4
|
+
- Mobile navigation drawers
|
|
5
|
+
- Quick edit forms that need more space than a dialog
|
|
6
|
+
|
|
7
|
+
## Skeleton Code
|
|
8
|
+
```vue
|
|
9
|
+
<script setup>
|
|
10
|
+
import { Sheet, SheetContent, SheetDescription, SheetHeader, SheetTitle, SheetTrigger, Button } from '@reinvented/design'
|
|
11
|
+
</script>
|
|
12
|
+
<template>
|
|
13
|
+
<Sheet>
|
|
14
|
+
<SheetTrigger as-child>
|
|
15
|
+
<Button variant="outline">Open</Button>
|
|
16
|
+
</SheetTrigger>
|
|
17
|
+
<SheetContent>
|
|
18
|
+
<SheetHeader>
|
|
19
|
+
<SheetTitle>Edit Profile</SheetTitle>
|
|
20
|
+
<SheetDescription>Make changes to your profile here.</SheetDescription>
|
|
21
|
+
</SheetHeader>
|
|
22
|
+
<!-- Content here -->
|
|
23
|
+
</SheetContent>
|
|
24
|
+
</Sheet>
|
|
25
|
+
</template>
|
|
26
|
+
```
|
|
27
|
+
## Side Variants
|
|
28
|
+
Use `side` prop on `SheetContent`: `"top"`, `"bottom"`, `"left"`, `"right"` (default: `"right"`).
|
|
29
|
+
|
|
30
|
+
## Gotchas
|
|
31
|
+
- Default width is `sm:max-w-sm` — override with class if wider content needed
|
|
32
|
+
- Mobile: use `side="bottom"` for bottom sheets
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# Skeleton
|
|
2
|
+
## Skeleton Code
|
|
3
|
+
```vue
|
|
4
|
+
<script setup>
|
|
5
|
+
import { Skeleton } from '@reinvented/design'
|
|
6
|
+
</script>
|
|
7
|
+
<template>
|
|
8
|
+
<!-- Match shape of real content -->
|
|
9
|
+
<div class="flex items-center gap-3">
|
|
10
|
+
<Skeleton class="w-10 h-10 rounded-full" />
|
|
11
|
+
<div class="flex-1 space-y-2">
|
|
12
|
+
<Skeleton class="h-4 w-3/4" />
|
|
13
|
+
<Skeleton class="h-3 w-1/2" />
|
|
14
|
+
</div>
|
|
15
|
+
</div>
|
|
16
|
+
</template>
|
|
17
|
+
```
|
|
18
|
+
## Gotchas
|
|
19
|
+
- Must match the shape of actual content layout
|
|
20
|
+
- Never show bare spinner — always show skeletons matching the data shape
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# Table
|
|
2
|
+
## Sub-components
|
|
3
|
+
`Table`, `TableHeader`, `TableBody`, `TableFooter`, `TableRow`, `TableHead`, `TableCell`, `TableCaption`
|
|
4
|
+
|
|
5
|
+
## Skeleton Code
|
|
6
|
+
```vue
|
|
7
|
+
<script setup>
|
|
8
|
+
import { Table, TableBody, TableCaption, TableCell, TableHead, TableHeader, TableRow } from '@reinvented/design'
|
|
9
|
+
</script>
|
|
10
|
+
<template>
|
|
11
|
+
<Table>
|
|
12
|
+
<TableCaption>A list of your recent invoices.</TableCaption>
|
|
13
|
+
<TableHeader>
|
|
14
|
+
<TableRow>
|
|
15
|
+
<TableHead>Invoice</TableHead>
|
|
16
|
+
<TableHead>Status</TableHead>
|
|
17
|
+
<TableHead class="text-right">Amount</TableHead>
|
|
18
|
+
</TableRow>
|
|
19
|
+
</TableHeader>
|
|
20
|
+
<TableBody>
|
|
21
|
+
<TableRow v-for="item in items" :key="item.id">
|
|
22
|
+
<TableCell class="font-medium">{{ item.invoice }}</TableCell>
|
|
23
|
+
<TableCell>{{ item.status }}</TableCell>
|
|
24
|
+
<TableCell class="text-right">{{ item.amount }}</TableCell>
|
|
25
|
+
</TableRow>
|
|
26
|
+
</TableBody>
|
|
27
|
+
</Table>
|
|
28
|
+
</template>
|
|
29
|
+
```
|
|
30
|
+
## Gotchas
|
|
31
|
+
- Use `text-right` for numeric columns
|
|
32
|
+
- Use `font-medium` for the primary identifier column
|
|
33
|
+
- For empty state, show a full-width row with empty state message
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# Tabs
|
|
2
|
+
## Skeleton Code
|
|
3
|
+
```vue
|
|
4
|
+
<script setup>
|
|
5
|
+
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@reinvented/design'
|
|
6
|
+
</script>
|
|
7
|
+
<template>
|
|
8
|
+
<Tabs default-value="overview">
|
|
9
|
+
<TabsList>
|
|
10
|
+
<TabsTrigger value="overview">Overview</TabsTrigger>
|
|
11
|
+
<TabsTrigger value="analytics">Analytics</TabsTrigger>
|
|
12
|
+
<TabsTrigger value="settings">Settings</TabsTrigger>
|
|
13
|
+
</TabsList>
|
|
14
|
+
<TabsContent value="overview">Overview content</TabsContent>
|
|
15
|
+
<TabsContent value="analytics">Analytics content</TabsContent>
|
|
16
|
+
<TabsContent value="settings">Settings content</TabsContent>
|
|
17
|
+
</Tabs>
|
|
18
|
+
</template>
|
|
19
|
+
```
|
|
20
|
+
## Gotchas
|
|
21
|
+
- Use `default-value` for uncontrolled, `v-model` for controlled
|
|
22
|
+
- Tab values must be unique strings
|
|
23
|
+
- Keep tab labels short (1-2 words)
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# Dashboard Layout
|
|
2
|
+
|
|
3
|
+
## When to Use
|
|
4
|
+
- App home/overview pages
|
|
5
|
+
- Stats summaries with key metrics
|
|
6
|
+
- Quick-access to recent items
|
|
7
|
+
|
|
8
|
+
## Skeleton Code
|
|
9
|
+
|
|
10
|
+
```vue
|
|
11
|
+
<script setup>
|
|
12
|
+
import {
|
|
13
|
+
Card, CardContent, CardDescription, CardHeader, CardTitle, Skeleton,
|
|
14
|
+
} from '@reinvented/design'
|
|
15
|
+
import { Activity, Users, CreditCard, DollarSign } from 'lucide-vue-next'
|
|
16
|
+
</script>
|
|
17
|
+
|
|
18
|
+
<template>
|
|
19
|
+
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8 space-y-6">
|
|
20
|
+
|
|
21
|
+
<!-- Page Header -->
|
|
22
|
+
<div>
|
|
23
|
+
<h1 class="text-2xl font-bold tracking-tight">Dashboard</h1>
|
|
24
|
+
<p class="text-muted-foreground">Overview of your workspace.</p>
|
|
25
|
+
</div>
|
|
26
|
+
|
|
27
|
+
<!-- Stats Grid -->
|
|
28
|
+
<div class="grid gap-4 sm:grid-cols-2 lg:grid-cols-4">
|
|
29
|
+
<Card>
|
|
30
|
+
<CardHeader class="flex flex-row items-center justify-between pb-2">
|
|
31
|
+
<CardTitle class="text-sm font-medium">Total Revenue</CardTitle>
|
|
32
|
+
<DollarSign class="h-4 w-4 text-muted-foreground" />
|
|
33
|
+
</CardHeader>
|
|
34
|
+
<CardContent>
|
|
35
|
+
<p class="text-2xl font-bold">$45,231</p>
|
|
36
|
+
<p class="text-xs text-muted-foreground">+20.1% from last month</p>
|
|
37
|
+
</CardContent>
|
|
38
|
+
</Card>
|
|
39
|
+
<!-- Repeat for other stats -->
|
|
40
|
+
</div>
|
|
41
|
+
|
|
42
|
+
<!-- Content Grid -->
|
|
43
|
+
<div class="grid gap-6 md:grid-cols-2 lg:grid-cols-7">
|
|
44
|
+
<Card class="col-span-4">
|
|
45
|
+
<CardHeader>
|
|
46
|
+
<CardTitle>Overview</CardTitle>
|
|
47
|
+
</CardHeader>
|
|
48
|
+
<CardContent>
|
|
49
|
+
<!-- Chart or main content -->
|
|
50
|
+
</CardContent>
|
|
51
|
+
</Card>
|
|
52
|
+
<Card class="col-span-3">
|
|
53
|
+
<CardHeader>
|
|
54
|
+
<CardTitle>Recent Activity</CardTitle>
|
|
55
|
+
<CardDescription>Latest actions in your workspace.</CardDescription>
|
|
56
|
+
</CardHeader>
|
|
57
|
+
<CardContent>
|
|
58
|
+
<!-- Activity list -->
|
|
59
|
+
</CardContent>
|
|
60
|
+
</Card>
|
|
61
|
+
</div>
|
|
62
|
+
</div>
|
|
63
|
+
</template>
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Key Patterns
|
|
67
|
+
- **Stats row**: 4-column grid of metric cards
|
|
68
|
+
- **Content grid**: Asymmetric grid (4/7 + 3/7) for main content + sidebar
|
|
69
|
+
- **Card headers**: Icon + title aligned horizontally
|
|
70
|
+
- **Responsive**: Stack to 2-col then 1-col on smaller screens
|
|
@@ -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
|
package/docs/layouts/index.md
CHANGED
|
@@ -1,32 +1,45 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Layout Documentation
|
|
2
2
|
|
|
3
|
-
|
|
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
|
+
```
|
|
4
27
|
|
|
5
28
|
## Available Layouts
|
|
6
29
|
|
|
7
30
|
| Layout | File | Use for |
|
|
8
31
|
|--------|------|---------|
|
|
9
|
-
| [List Page](list-page.md) |
|
|
10
|
-
| [Detail Page](detail-page.md) |
|
|
11
|
-
| [Dashboard](dashboard.md) |
|
|
12
|
-
| [
|
|
13
|
-
| [
|
|
14
|
-
|
|
15
|
-
## Choosing a Layout
|
|
16
|
-
|
|
17
|
-
```
|
|
18
|
-
What is the user doing?
|
|
19
|
-
├── Browsing a list of things → List Page
|
|
20
|
-
├── Looking at one specific thing → Detail Page
|
|
21
|
-
├── Getting an overview / summary → Dashboard
|
|
22
|
-
├── Creating or editing something → Modal Form (default) or Settings Page (complex)
|
|
23
|
-
└── Configuring settings → Settings Page
|
|
24
|
-
```
|
|
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) |
|
|
25
38
|
|
|
26
|
-
## Layout
|
|
39
|
+
## General Layout Rules
|
|
27
40
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
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
|