@reinvented/design 0.1.0 → 0.2.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.
- package/DESIGN_GUIDE.md +148 -0
- package/README.md +39 -162
- package/docs/components/index.md +50 -0
- package/docs/conventions.md +74 -0
- package/docs/layouts/index.md +32 -0
- package/docs/patterns/index.md +39 -0
- package/docs/rules.md +43 -0
- package/docs/visual-polish.md +141 -0
- package/package.json +40 -61
- package/src/components/ui/avatar/Avatar.vue +14 -0
- package/src/components/ui/avatar/index.ts +1 -0
- package/src/components/ui/badge/Badge.vue +27 -0
- package/src/components/ui/badge/index.ts +1 -0
- package/src/components/ui/button/Button.vue +66 -0
- package/src/components/ui/button/index.ts +1 -0
- package/src/components/ui/card/Card.vue +13 -0
- package/src/components/ui/card/CardContent.vue +7 -0
- package/src/components/ui/card/CardDescription.vue +7 -0
- package/src/components/ui/card/CardFooter.vue +7 -0
- package/src/components/ui/card/CardHeader.vue +9 -0
- package/src/components/ui/card/CardTitle.vue +7 -0
- package/src/components/ui/card/index.ts +6 -0
- package/src/components/ui/input/Input.vue +23 -0
- package/src/components/ui/input/index.ts +1 -0
- package/src/components/ui/lib/utils.ts +2 -0
- package/src/components/ui/scroll-area/ScrollArea.vue +13 -0
- package/src/components/ui/scroll-area/index.ts +1 -0
- package/src/components/ui/separator/Separator.vue +16 -0
- package/src/components/ui/separator/index.ts +1 -0
- package/src/components/ui/skeleton/Skeleton.vue +9 -0
- package/src/components/ui/skeleton/index.ts +1 -0
- package/src/env.d.ts +7 -0
- package/src/index.ts +209 -0
- package/src/lib/utils.ts +7 -0
- package/src/patterns/DetailView.vue +46 -0
- package/src/patterns/EmptyState.vue +27 -0
- package/src/patterns/FormView.vue +34 -0
- package/src/patterns/ListView.vue +45 -0
- package/src/styles/index.css +4 -0
- package/src/styles/tokens.css +144 -0
- package/tailwind.config.js +108 -0
- package/tsconfig.json +7 -0
- package/dist/index.css +0 -1890
- package/dist/index.d.ts +0 -406
- package/dist/index.js +0 -1721
- package/dist/index.js.map +0 -1
- package/tailwind.config.ts +0 -174
package/DESIGN_GUIDE.md
ADDED
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
# Reinvented Design Guide
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
The Reinvented design system uses **Shadcn-vue** components with custom **Radix-vue** primitives,
|
|
5
|
+
**Tailwind CSS** for styling, and **Lucide** icons. All UI surfaces share this consistent foundation.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Typography
|
|
10
|
+
|
|
11
|
+
| Token | Size | Weight | Use |
|
|
12
|
+
|---------------|--------|----------|------------------------|
|
|
13
|
+
| `text-xs` | 12px | 400 | Timestamps, captions |
|
|
14
|
+
| `text-sm` | 14px | 400–500 | Body text, labels |
|
|
15
|
+
| `text-base` | 16px | 400 | Default body |
|
|
16
|
+
| `text-lg` | 18px | 600 | Section headings |
|
|
17
|
+
| `text-xl` | 20px | 600 | Page subtitles |
|
|
18
|
+
| `text-2xl` | 24px | 700 | Page titles |
|
|
19
|
+
| `text-3xl` | 30px | 700 | Hero text |
|
|
20
|
+
|
|
21
|
+
**Font:** Inter (loaded via Google Fonts).
|
|
22
|
+
**Line height:** Use `leading-tight` (1.25) for headings, `leading-normal` (1.5) for body.
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## Colors
|
|
27
|
+
|
|
28
|
+
Our brand color is **purple** (`hsl(252 100% 63%)`).
|
|
29
|
+
|
|
30
|
+
| Token | Light | Dark | Use |
|
|
31
|
+
|-----------------|-------------------|-------------------|------------------------|
|
|
32
|
+
| `primary` | Purple 63% | Purple 69% | Buttons, links, focus |
|
|
33
|
+
| `secondary` | Zinc 96% | Zinc 16% | Secondary actions |
|
|
34
|
+
| `muted` | Zinc 96% | Zinc 16% | Backgrounds, disabled |
|
|
35
|
+
| `destructive` | Red 60% | Red 31% | Delete, errors |
|
|
36
|
+
| `success` | Green 36% | Green 45% | Confirmations |
|
|
37
|
+
| `warning` | Amber 50% | Amber 55% | Alerts |
|
|
38
|
+
| `info` | Blue 60% | Blue 65% | Information |
|
|
39
|
+
|
|
40
|
+
**Usage rules:**
|
|
41
|
+
- Never hardcode colors — always use `hsl(var(--token))`
|
|
42
|
+
- Use `text-muted-foreground` for secondary text (not arbitrary gray)
|
|
43
|
+
- Apply `bg-card` for card surfaces, `bg-background` for page backgrounds
|
|
44
|
+
|
|
45
|
+
---
|
|
46
|
+
|
|
47
|
+
## Spacing
|
|
48
|
+
|
|
49
|
+
Based on **4px increments**. Use Tailwind utilities:
|
|
50
|
+
|
|
51
|
+
| Class | Value | Use |
|
|
52
|
+
|----------|-------|----------------------------|
|
|
53
|
+
| `gap-1` | 4px | Icon-to-text gap |
|
|
54
|
+
| `gap-2` | 8px | Between small elements |
|
|
55
|
+
| `gap-3` | 12px | Between form fields |
|
|
56
|
+
| `gap-4` | 16px | Section spacing |
|
|
57
|
+
| `gap-6` | 24px | Between major sections |
|
|
58
|
+
| `p-4` | 16px | Standard padding |
|
|
59
|
+
| `p-6` | 24px | Card padding |
|
|
60
|
+
| `px-4` | 16px | Page horizontal padding |
|
|
61
|
+
|
|
62
|
+
**Rules:**
|
|
63
|
+
- Always use spacing tokens, never arbitrary values
|
|
64
|
+
- Vertical rhythm: Use `gap-4` or `gap-6` for stacking sections
|
|
65
|
+
- Horizontal rhythm: Use `gap-2` or `gap-3` for inline elements
|
|
66
|
+
|
|
67
|
+
---
|
|
68
|
+
|
|
69
|
+
## Icons
|
|
70
|
+
|
|
71
|
+
- **Library:** Lucide Vue Next (`lucide-vue-next`)
|
|
72
|
+
- **NO emojis** anywhere in the UI
|
|
73
|
+
- Default icon size: `16px` (`w-4 h-4`)
|
|
74
|
+
- In buttons/nav: `w-4 h-4`
|
|
75
|
+
- In empty states: `w-12 h-12` with `text-muted-foreground`
|
|
76
|
+
- Always use `stroke-width="2"` (Lucide default)
|
|
77
|
+
|
|
78
|
+
---
|
|
79
|
+
|
|
80
|
+
## Shadows & Borders
|
|
81
|
+
|
|
82
|
+
| Token | CSS | Use |
|
|
83
|
+
|-------------|-------------------------------|----------------------------|
|
|
84
|
+
| `shadow-sm` | Subtle 1px shadow | Cards, buttons |
|
|
85
|
+
| `shadow-md` | Medium depth | Dropdowns, popovers |
|
|
86
|
+
| `shadow-lg` | Strong depth | Modals, dialogs |
|
|
87
|
+
| `rounded-md`| `calc(var(--radius) - 2px)` | Inputs, small elements |
|
|
88
|
+
| `rounded-lg`| `var(--radius)` (10px) | Cards, containers |
|
|
89
|
+
|
|
90
|
+
---
|
|
91
|
+
|
|
92
|
+
## Component Guidelines
|
|
93
|
+
|
|
94
|
+
### When to use existing components
|
|
95
|
+
Always check `@reinvented/design` first:
|
|
96
|
+
```ts
|
|
97
|
+
import { Button, Card, Input, Avatar, Badge } from '@reinvented/design'
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### Using Radix primitives
|
|
101
|
+
For Dialog, DropdownMenu, Tabs, Tooltip, PopoverSelect, etc.:
|
|
102
|
+
```ts
|
|
103
|
+
import { Dialog, DialogTrigger, DialogContent, DialogTitle } from '@reinvented/design'
|
|
104
|
+
```
|
|
105
|
+
Style them using `cn()` and Tailwind:
|
|
106
|
+
```vue
|
|
107
|
+
<DialogContent :class="cn('fixed inset-0 z-50 flex items-center justify-center')">
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
### Building new components
|
|
111
|
+
1. Create in `packages/ds/src/components/ui/<name>/`
|
|
112
|
+
2. Use `cn()` for class merging
|
|
113
|
+
3. Accept `class` prop for customization
|
|
114
|
+
4. Use design tokens (never hardcode colors)
|
|
115
|
+
5. Export from barrel (`src/index.ts`)
|
|
116
|
+
|
|
117
|
+
---
|
|
118
|
+
|
|
119
|
+
## Page Patterns
|
|
120
|
+
|
|
121
|
+
Import from `@reinvented/design/patterns/*`:
|
|
122
|
+
|
|
123
|
+
| Pattern | Use |
|
|
124
|
+
|--------------|----------------------------------------------|
|
|
125
|
+
| `ListView` | Lists with search, filters, items |
|
|
126
|
+
| `DetailView` | Detail pages with hero, tabs, content |
|
|
127
|
+
| `FormView` | Forms with validation and submit |
|
|
128
|
+
| `EmptyState` | Centered empty state with icon and CTA |
|
|
129
|
+
|
|
130
|
+
---
|
|
131
|
+
|
|
132
|
+
## Dark Mode
|
|
133
|
+
|
|
134
|
+
- Controlled via `.dark` class on `<html>` or `<body>`
|
|
135
|
+
- All tokens automatically switch in dark mode
|
|
136
|
+
- Test both modes when building surfaces
|
|
137
|
+
- Use `dark:` prefix sparingly — prefer CSS variable-driven theming
|
|
138
|
+
|
|
139
|
+
---
|
|
140
|
+
|
|
141
|
+
## Do NOT
|
|
142
|
+
|
|
143
|
+
- Use `alert()`, `confirm()`, or `prompt()` — use Dialog/AlertDialog
|
|
144
|
+
- Use emojis — use Lucide icons
|
|
145
|
+
- Hardcode colors — use CSS variables
|
|
146
|
+
- Use arbitrary Tailwind values (e.g., `text-[#333]`) — use tokens
|
|
147
|
+
- Create split-screen layouts — use single-column responsive design
|
|
148
|
+
- Use `@apply` excessively — prefer utility classes in templates
|
package/README.md
CHANGED
|
@@ -1,179 +1,56 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Reinvented Design System
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
The opinionated visual foundation for all Reinvented apps. Components, patterns, layouts, conventions, rules, and documentation.
|
|
4
4
|
|
|
5
|
-
##
|
|
6
|
-
|
|
7
|
-
- **Dark-first** — Nearly-black backgrounds (`#0a0a0b`) with subtle surface elevation, not obvious cards
|
|
8
|
-
- **Restrained palette** — Mostly grays with one accent color (violet-blue `#5b6af0`), used sparingly on interactive elements
|
|
9
|
-
- **Muted borders** — No heavy shadows in dark mode; borders at 4–16% white opacity
|
|
10
|
-
- **Tight typography** — Inter font, compact scale (11px–36px), 4 main text styles
|
|
11
|
-
- **Smooth animations** — Subtle fade-in, slide-up, scale-in transitions (200ms default)
|
|
12
|
-
- **Consistency-first** — Composition components with locked styling prevent visual drift
|
|
13
|
-
|
|
14
|
-
## Installation
|
|
5
|
+
## Quick Start
|
|
15
6
|
|
|
16
7
|
```bash
|
|
17
|
-
|
|
8
|
+
npm install @reinvented/design
|
|
18
9
|
```
|
|
19
10
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
11
|
+
```vue
|
|
12
|
+
<script setup>
|
|
13
|
+
import { Button, Card, Input, Badge, Dialog } from '@reinvented/design'
|
|
14
|
+
</script>
|
|
24
15
|
```
|
|
25
16
|
|
|
26
|
-
##
|
|
17
|
+
## Stack
|
|
27
18
|
|
|
28
|
-
|
|
19
|
+
- **Components**: [Shadcn-vue](https://www.shadcn-vue.com/) (all components, styled with our tokens)
|
|
20
|
+
- **Primitives**: [Radix Vue](https://www.radix-vue.com/) (accessible headless components)
|
|
21
|
+
- **Styling**: [Tailwind CSS](https://tailwindcss.com/) with design tokens
|
|
22
|
+
- **Icons**: [Lucide Vue Next](https://lucide.dev/) (no emojis, ever)
|
|
23
|
+
- **Typography**: Inter (via Google Fonts)
|
|
29
24
|
|
|
30
|
-
|
|
31
|
-
import { Button, Input, Card, Badge, Dialog } from "@reinvented/design";
|
|
25
|
+
## Structure
|
|
32
26
|
|
|
33
|
-
<Button variant="primary" size="md">Save</Button>
|
|
34
|
-
<Button variant="ghost" size="sm">Cancel</Button>
|
|
35
|
-
<Input label="Email" placeholder="you@example.com" error="Required" />
|
|
36
|
-
<Badge variant="success">Active</Badge>
|
|
37
27
|
```
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
<ListItem
|
|
53
|
-
leading={<UserIcon size={16} />}
|
|
54
|
-
title="John Doe"
|
|
55
|
-
description="john@example.com"
|
|
56
|
-
trailing={<Badge>Admin</Badge>}
|
|
57
|
-
onClick={() => navigate("/users/1")}
|
|
58
|
-
/>
|
|
59
|
-
|
|
60
|
-
<EmptyState
|
|
61
|
-
icon={<InboxIcon size={32} />}
|
|
62
|
-
title="No items yet"
|
|
63
|
-
description="Create your first item to get started"
|
|
64
|
-
action={<Button>Create</Button>}
|
|
65
|
-
/>
|
|
28
|
+
src/
|
|
29
|
+
components/ui/ All styled components
|
|
30
|
+
patterns/ Reusable compositions (ListView, DetailView, etc.)
|
|
31
|
+
layouts/ Page-level layout components with slots
|
|
32
|
+
lib/ Utilities (cn, etc.)
|
|
33
|
+
styles/ Tokens, CSS variables
|
|
34
|
+
docs/
|
|
35
|
+
rules.md Hard design rules
|
|
36
|
+
conventions.md Opinionated UX decisions
|
|
37
|
+
visual-polish.md Animations, transitions, polish guidelines
|
|
38
|
+
components/ Per-component usage guides
|
|
39
|
+
patterns/ Per-pattern docs with skeleton code
|
|
40
|
+
layouts/ Per-layout docs with skeleton code
|
|
41
|
+
examples/ Full skeleton examples
|
|
66
42
|
```
|
|
67
43
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
```tsx
|
|
71
|
-
import { AppShell, TopBar, SideRail, SideRailItem, PageContainer } from "@reinvented/design";
|
|
44
|
+
## Documentation
|
|
72
45
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
}
|
|
81
|
-
>
|
|
82
|
-
<PageContainer>
|
|
83
|
-
{/* Page content */}
|
|
84
|
-
</PageContainer>
|
|
85
|
-
</AppShell>
|
|
86
|
-
```
|
|
87
|
-
|
|
88
|
-
### Icons
|
|
89
|
-
|
|
90
|
-
```tsx
|
|
91
|
-
import { DynamicIcon, Settings, ChevronRight } from "@reinvented/design";
|
|
92
|
-
|
|
93
|
-
// Static icon
|
|
94
|
-
<Settings size={16} />
|
|
95
|
-
|
|
96
|
-
// Dynamic icon by name string (for app manager)
|
|
97
|
-
<DynamicIcon name="Settings" size={16} />
|
|
98
|
-
```
|
|
99
|
-
|
|
100
|
-
### Hooks
|
|
101
|
-
|
|
102
|
-
```tsx
|
|
103
|
-
import { useTheme, useMediaQuery } from "@reinvented/design";
|
|
104
|
-
|
|
105
|
-
const { theme, toggleTheme, isDark } = useTheme();
|
|
106
|
-
const isMobile = useMediaQuery("(max-width: 768px)");
|
|
107
|
-
```
|
|
108
|
-
|
|
109
|
-
### Utilities
|
|
110
|
-
|
|
111
|
-
```tsx
|
|
112
|
-
import { cn } from "@reinvented/design";
|
|
113
|
-
|
|
114
|
-
<div className={cn("text-fg-primary", isActive && "text-accent")} />
|
|
115
|
-
```
|
|
116
|
-
|
|
117
|
-
### Command Palette
|
|
118
|
-
|
|
119
|
-
```tsx
|
|
120
|
-
import { CommandPalette, CommandGroup, CommandItem, CommandEmpty } from "@reinvented/design";
|
|
121
|
-
|
|
122
|
-
<CommandPalette placeholder="Search or jump to…">
|
|
123
|
-
<CommandEmpty>No results found.</CommandEmpty>
|
|
124
|
-
<CommandGroup heading="Actions">
|
|
125
|
-
<CommandItem onSelect={() => navigate("/settings")}>Settings</CommandItem>
|
|
126
|
-
</CommandGroup>
|
|
127
|
-
</CommandPalette>
|
|
128
|
-
// Opens with Cmd+K / Ctrl+K
|
|
129
|
-
```
|
|
130
|
-
|
|
131
|
-
## Token Reference
|
|
132
|
-
|
|
133
|
-
| Token | Dark Value | Purpose |
|
|
134
|
-
|-------|-----------|---------|
|
|
135
|
-
| `--bg-base` | `#0a0a0b` | App background |
|
|
136
|
-
| `--bg-surface` | `#111113` | Cards, panels |
|
|
137
|
-
| `--bg-elevated` | `#191a1f` | Dropdowns, popovers |
|
|
138
|
-
| `--fg-primary` | `#ededef` | Primary text |
|
|
139
|
-
| `--fg-secondary` | `#a1a1a6` | Secondary text |
|
|
140
|
-
| `--fg-muted` | `#6e6e76` | Placeholder, hints |
|
|
141
|
-
| `--accent` | `#5b6af0` | Interactive elements |
|
|
142
|
-
| `--border-default` | `rgba(255,255,255,0.08)` | Standard borders |
|
|
143
|
-
|
|
144
|
-
## Component Catalog
|
|
145
|
-
|
|
146
|
-
### Primitives
|
|
147
|
-
Button, Input, Badge, Avatar, Card, Label, Dialog, DropdownMenu, Toast, Separator, ScrollArea, Select, Switch, Checkbox, Tabs, Tooltip, Skeleton, Sheet
|
|
148
|
-
|
|
149
|
-
### Composition (locked)
|
|
150
|
-
ContentCard, PageHeader, ListItem, FormSection, ActionBar, EmptyState
|
|
151
|
-
|
|
152
|
-
### Layout
|
|
153
|
-
AppShell, TopBar, SideRail, BottomBar, PageContainer
|
|
154
|
-
|
|
155
|
-
### Feedback & Overlays
|
|
156
|
-
Spinner, ErrorBoundary, CommandPalette
|
|
157
|
-
|
|
158
|
-
## Tailwind Config
|
|
159
|
-
|
|
160
|
-
Consuming apps should extend the design system's Tailwind config:
|
|
161
|
-
|
|
162
|
-
```ts
|
|
163
|
-
// tailwind.config.ts in your app
|
|
164
|
-
import designConfig from "@reinvented/design/tailwind";
|
|
165
|
-
|
|
166
|
-
export default {
|
|
167
|
-
presets: [designConfig],
|
|
168
|
-
content: [
|
|
169
|
-
"./src/**/*.{ts,tsx}",
|
|
170
|
-
"../../packages/design/src/**/*.{ts,tsx}",
|
|
171
|
-
],
|
|
172
|
-
};
|
|
173
|
-
```
|
|
46
|
+
- **[Rules](docs/rules.md)** — Non-negotiable design constraints
|
|
47
|
+
- **[Conventions](docs/conventions.md)** — Opinionated UX decisions
|
|
48
|
+
- **[Visual Polish](docs/visual-polish.md)** — Animation and polish guide
|
|
49
|
+
- **[Components](docs/components/index.md)** — Component usage guides
|
|
50
|
+
- **[Patterns](docs/patterns/index.md)** — Reusable UI patterns
|
|
51
|
+
- **[Layouts](docs/layouts/index.md)** — Page layout recipes
|
|
52
|
+
- **[Design Guide](DESIGN_GUIDE.md)** — Tokens, typography, colors, spacing
|
|
174
53
|
|
|
175
|
-
##
|
|
54
|
+
## Contributing
|
|
176
55
|
|
|
177
|
-
|
|
178
|
-
2. Export it from `src/index.ts`
|
|
179
|
-
3. Run `pnpm build` to verify
|
|
56
|
+
Agents and humans can propose changes via PRs. See [conventions](docs/conventions.md) for design principles.
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# Components Index
|
|
2
|
+
|
|
3
|
+
Usage guides for `@reinvented/design` components. Read individual files for detailed usage, gotchas, and skeleton code.
|
|
4
|
+
|
|
5
|
+
## Styled Components
|
|
6
|
+
|
|
7
|
+
| Component | File | Use for |
|
|
8
|
+
|-----------|------|---------|
|
|
9
|
+
| [Button](button.md) | `button.md` | All clickable actions |
|
|
10
|
+
| [Card](card.md) | `card.md` | Content containers, list items |
|
|
11
|
+
| [Input](input.md) | `input.md` | Text input fields |
|
|
12
|
+
| [Badge](badge.md) | `badge.md` | Status indicators, counts, tags |
|
|
13
|
+
| [Avatar](avatar.md) | `avatar.md` | User/entity profile images |
|
|
14
|
+
| [Separator](separator.md) | `separator.md` | Visual dividers |
|
|
15
|
+
| [Skeleton](skeleton.md) | `skeleton.md` | Loading placeholders |
|
|
16
|
+
| [ScrollArea](scroll-area.md) | `scroll-area.md` | Custom scrollable regions |
|
|
17
|
+
|
|
18
|
+
## Radix Primitives (styled via Tailwind + tokens)
|
|
19
|
+
|
|
20
|
+
These are re-exported from radix-vue. Use with `cn()` and design tokens.
|
|
21
|
+
|
|
22
|
+
| Component | Use for |
|
|
23
|
+
|-----------|---------|
|
|
24
|
+
| Dialog | Modal dialogs (create, edit, confirm) |
|
|
25
|
+
| AlertDialog | Destructive action confirmation |
|
|
26
|
+
| DropdownMenu | Context menus, action menus |
|
|
27
|
+
| Select | Single-value selection |
|
|
28
|
+
| Tabs | Section navigation within a view |
|
|
29
|
+
| Tooltip | Hover hints |
|
|
30
|
+
| Popover | Rich hover/click content |
|
|
31
|
+
| Accordion | Collapsible sections |
|
|
32
|
+
| Switch | On/off toggles |
|
|
33
|
+
| Checkbox | Multi-select options |
|
|
34
|
+
| RadioGroup | Single-select from options |
|
|
35
|
+
| Progress | Progress indicators |
|
|
36
|
+
| Slider | Range input |
|
|
37
|
+
| Collapsible | Show/hide content blocks |
|
|
38
|
+
| ContextMenu | Right-click menus |
|
|
39
|
+
| NavigationMenu | Top-level navigation |
|
|
40
|
+
| HoverCard | Rich hover preview |
|
|
41
|
+
| ToggleGroup | Grouped toggles |
|
|
42
|
+
| Pagination | Page navigation |
|
|
43
|
+
|
|
44
|
+
## External Re-exports
|
|
45
|
+
|
|
46
|
+
| Component | From | Use for |
|
|
47
|
+
|-----------|------|---------|
|
|
48
|
+
| Toaster / toast | vue-sonner | Toast notifications |
|
|
49
|
+
|
|
50
|
+
> **Note**: Many primitives above need proper styled wrappers (like Button, Card, etc. have). See [rules.md](../rules.md) — agents should always use DS components, never raw HTML elements.
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# UX Conventions
|
|
2
|
+
|
|
3
|
+
Opinionated design decisions that ensure consistency across all Reinvented apps.
|
|
4
|
+
|
|
5
|
+
## Create/Edit Flows
|
|
6
|
+
|
|
7
|
+
| Scenario | Pattern | Why |
|
|
8
|
+
|----------|---------|-----|
|
|
9
|
+
| Simple form (≤ 5 fields) | Modal dialog | Fast, keeps context |
|
|
10
|
+
| Medium form (6–8 fields) | Modal dialog with sections | Still fits in a modal |
|
|
11
|
+
| Complex form (8+ fields) | Full page | Too much for a modal |
|
|
12
|
+
| Rich content editing (markdown, images) | Full page | Needs space and toolbars |
|
|
13
|
+
| Single-field update (e.g., rename) | Inline editing (click-to-edit) | Minimal friction |
|
|
14
|
+
| Toggle/switch (enable/disable) | Inline toggle | Immediate feedback |
|
|
15
|
+
| Status change | Inline dropdown or button group | Immediate feedback |
|
|
16
|
+
|
|
17
|
+
**Default: modal.** Only escalate to full page when the modal becomes cramped.
|
|
18
|
+
|
|
19
|
+
## Delete/Destructive Actions
|
|
20
|
+
|
|
21
|
+
1. Always use `<AlertDialog>` with explicit confirmation
|
|
22
|
+
2. Confirm button must say what it does: "Delete Task" not "OK"
|
|
23
|
+
3. Cancel button is always the default focus
|
|
24
|
+
4. Consider "undo via toast" for low-risk deletions instead of pre-confirmation
|
|
25
|
+
|
|
26
|
+
## Navigation
|
|
27
|
+
|
|
28
|
+
- **Back button**: Always present on detail views. Uses router history, not hardcoded routes
|
|
29
|
+
- **Breadcrumbs**: Use on 3+ level deep hierarchies
|
|
30
|
+
- **Tabs**: Use for related content within a single view (e.g., "Overview / Activity / Settings")
|
|
31
|
+
- **Bottom navigation**: Mobile only, max 5 items
|
|
32
|
+
|
|
33
|
+
## Information Hierarchy
|
|
34
|
+
|
|
35
|
+
- **Page title**: `text-2xl font-bold` — one per page, describes the primary content
|
|
36
|
+
- **Section headings**: `text-lg font-semibold` — group related content
|
|
37
|
+
- **Cards**: Use to visually separate distinct content blocks
|
|
38
|
+
- **Secondary text**: Always `text-muted-foreground`, never arbitrary gray
|
|
39
|
+
|
|
40
|
+
## Empty States
|
|
41
|
+
|
|
42
|
+
Every empty state must have:
|
|
43
|
+
1. A relevant Lucide icon (`w-12 h-12 text-muted-foreground`)
|
|
44
|
+
2. A title explaining what goes here
|
|
45
|
+
3. A description explaining how to get started
|
|
46
|
+
4. A primary CTA button
|
|
47
|
+
|
|
48
|
+
## Loading States
|
|
49
|
+
|
|
50
|
+
- **Page/section load**: Skeleton shapes matching the real content layout
|
|
51
|
+
- **Button during mutation**: Spinner icon + disabled state
|
|
52
|
+
- **Optimistic updates**: Use for toggles, status changes, likes — anything easily reversible
|
|
53
|
+
- **Never**: bare spinner with no context. Always indicate WHAT is loading
|
|
54
|
+
|
|
55
|
+
## Error States
|
|
56
|
+
|
|
57
|
+
- **Query failures**: `<Alert variant="destructive">` with error message + retry button
|
|
58
|
+
- **Mutation failures**: Toast notification with error message + retry action
|
|
59
|
+
- **Form validation**: Inline field errors below the input, shown on blur or submit
|
|
60
|
+
- **Network offline**: Banner at top of page
|
|
61
|
+
|
|
62
|
+
## Responsive Behavior
|
|
63
|
+
|
|
64
|
+
| Breakpoint | Width | Behavior |
|
|
65
|
+
|------------|-------|----------|
|
|
66
|
+
| Mobile | < 640px | Single column, bottom sheets, stacked cards |
|
|
67
|
+
| Tablet | 640-1024px | Two columns possible, side panels collapse |
|
|
68
|
+
| Desktop | > 1024px | Full layout, side panels open |
|
|
69
|
+
|
|
70
|
+
## Consistency
|
|
71
|
+
|
|
72
|
+
- Same object type → same card component everywhere
|
|
73
|
+
- Same action → same pattern everywhere (e.g., all "delete" flows use AlertDialog)
|
|
74
|
+
- Same icon → same meaning everywhere (e.g., Trash2 always means delete)
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# Layouts Index
|
|
2
|
+
|
|
3
|
+
Page-level layout components with slots. Each layout is a Vue component in `src/layouts/` AND documented here with skeleton code and usage guidance.
|
|
4
|
+
|
|
5
|
+
## Available Layouts
|
|
6
|
+
|
|
7
|
+
| Layout | File | Use for |
|
|
8
|
+
|--------|------|---------|
|
|
9
|
+
| [List Page](list-page.md) | `list-page.md` | Browsing collections (tasks, members, notifications) |
|
|
10
|
+
| [Detail Page](detail-page.md) | `detail-page.md` | Viewing a single item with full context |
|
|
11
|
+
| [Dashboard](dashboard.md) | `dashboard.md` | Overview with stats, charts, recent activity |
|
|
12
|
+
| [Modal Form](modal-form.md) | `modal-form.md` | Create/edit dialogs with form fields |
|
|
13
|
+
| [Settings Page](settings-page.md) | `settings-page.md` | Configuration with sectioned form |
|
|
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
|
+
```
|
|
25
|
+
|
|
26
|
+
## Layout Component Structure
|
|
27
|
+
|
|
28
|
+
All layout components follow the same convention:
|
|
29
|
+
- Accept a `class` prop for customization
|
|
30
|
+
- Use named slots for content areas (header, content, footer, etc.)
|
|
31
|
+
- Handle responsive breakpoints internally
|
|
32
|
+
- Use DS tokens for spacing and typography
|
|
@@ -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
|