@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/src/index.ts
ADDED
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
// ── @reinvented/design — Design System Barrel Export ──────────────
|
|
2
|
+
// Re-exports all UI components, utils, and types
|
|
3
|
+
|
|
4
|
+
// Utilities
|
|
5
|
+
export { cn } from './lib/utils'
|
|
6
|
+
|
|
7
|
+
// UI Components
|
|
8
|
+
export { Button } from './components/ui/button'
|
|
9
|
+
export { Card, CardHeader, CardTitle, CardDescription, CardContent, CardFooter } from './components/ui/card'
|
|
10
|
+
export { Input } from './components/ui/input'
|
|
11
|
+
export { Badge } from './components/ui/badge'
|
|
12
|
+
export { Avatar } from './components/ui/avatar'
|
|
13
|
+
export { Separator } from './components/ui/separator'
|
|
14
|
+
export { Skeleton } from './components/ui/skeleton'
|
|
15
|
+
export { ScrollArea } from './components/ui/scroll-area'
|
|
16
|
+
|
|
17
|
+
// Re-export radix-vue primitives for advanced use
|
|
18
|
+
// Consumers can build Dialog, DropdownMenu, Tabs, etc. using radix-vue directly
|
|
19
|
+
// with our design tokens and cn() utility
|
|
20
|
+
export {
|
|
21
|
+
DialogRoot as Dialog,
|
|
22
|
+
DialogTrigger,
|
|
23
|
+
DialogContent,
|
|
24
|
+
DialogTitle,
|
|
25
|
+
DialogDescription,
|
|
26
|
+
DialogClose,
|
|
27
|
+
DialogOverlay,
|
|
28
|
+
DialogPortal,
|
|
29
|
+
} from 'radix-vue'
|
|
30
|
+
|
|
31
|
+
export {
|
|
32
|
+
DropdownMenuRoot as DropdownMenu,
|
|
33
|
+
DropdownMenuTrigger,
|
|
34
|
+
DropdownMenuContent,
|
|
35
|
+
DropdownMenuItem,
|
|
36
|
+
DropdownMenuSeparator,
|
|
37
|
+
DropdownMenuLabel,
|
|
38
|
+
DropdownMenuGroup,
|
|
39
|
+
DropdownMenuSub,
|
|
40
|
+
DropdownMenuSubTrigger,
|
|
41
|
+
DropdownMenuSubContent,
|
|
42
|
+
DropdownMenuCheckboxItem,
|
|
43
|
+
DropdownMenuRadioGroup,
|
|
44
|
+
DropdownMenuRadioItem,
|
|
45
|
+
DropdownMenuPortal,
|
|
46
|
+
} from 'radix-vue'
|
|
47
|
+
|
|
48
|
+
export {
|
|
49
|
+
TabsRoot as Tabs,
|
|
50
|
+
TabsList,
|
|
51
|
+
TabsTrigger,
|
|
52
|
+
TabsContent,
|
|
53
|
+
} from 'radix-vue'
|
|
54
|
+
|
|
55
|
+
export {
|
|
56
|
+
TooltipRoot as Tooltip,
|
|
57
|
+
TooltipTrigger,
|
|
58
|
+
TooltipContent,
|
|
59
|
+
TooltipProvider,
|
|
60
|
+
TooltipPortal,
|
|
61
|
+
} from 'radix-vue'
|
|
62
|
+
|
|
63
|
+
export {
|
|
64
|
+
PopoverRoot as Popover,
|
|
65
|
+
PopoverTrigger,
|
|
66
|
+
PopoverContent,
|
|
67
|
+
PopoverPortal,
|
|
68
|
+
} from 'radix-vue'
|
|
69
|
+
|
|
70
|
+
export {
|
|
71
|
+
SelectRoot as Select,
|
|
72
|
+
SelectTrigger,
|
|
73
|
+
SelectContent,
|
|
74
|
+
SelectItem,
|
|
75
|
+
SelectValue,
|
|
76
|
+
SelectGroup,
|
|
77
|
+
SelectLabel,
|
|
78
|
+
SelectSeparator,
|
|
79
|
+
SelectPortal,
|
|
80
|
+
SelectViewport,
|
|
81
|
+
SelectItemText,
|
|
82
|
+
SelectItemIndicator,
|
|
83
|
+
} from 'radix-vue'
|
|
84
|
+
|
|
85
|
+
export {
|
|
86
|
+
AccordionRoot as Accordion,
|
|
87
|
+
AccordionItem,
|
|
88
|
+
AccordionTrigger,
|
|
89
|
+
AccordionContent,
|
|
90
|
+
AccordionHeader,
|
|
91
|
+
} from 'radix-vue'
|
|
92
|
+
|
|
93
|
+
export {
|
|
94
|
+
SwitchRoot as Switch,
|
|
95
|
+
SwitchThumb,
|
|
96
|
+
} from 'radix-vue'
|
|
97
|
+
|
|
98
|
+
export {
|
|
99
|
+
CheckboxRoot as Checkbox,
|
|
100
|
+
CheckboxIndicator,
|
|
101
|
+
} from 'radix-vue'
|
|
102
|
+
|
|
103
|
+
export {
|
|
104
|
+
RadioGroupRoot as RadioGroup,
|
|
105
|
+
RadioGroupItem,
|
|
106
|
+
RadioGroupIndicator,
|
|
107
|
+
} from 'radix-vue'
|
|
108
|
+
|
|
109
|
+
export {
|
|
110
|
+
AlertDialogRoot as AlertDialog,
|
|
111
|
+
AlertDialogTrigger,
|
|
112
|
+
AlertDialogContent,
|
|
113
|
+
AlertDialogTitle,
|
|
114
|
+
AlertDialogDescription,
|
|
115
|
+
AlertDialogAction,
|
|
116
|
+
AlertDialogCancel,
|
|
117
|
+
AlertDialogOverlay,
|
|
118
|
+
AlertDialogPortal,
|
|
119
|
+
} from 'radix-vue'
|
|
120
|
+
|
|
121
|
+
export {
|
|
122
|
+
ProgressRoot as Progress,
|
|
123
|
+
ProgressIndicator,
|
|
124
|
+
} from 'radix-vue'
|
|
125
|
+
|
|
126
|
+
export {
|
|
127
|
+
SliderRoot as Slider,
|
|
128
|
+
SliderTrack,
|
|
129
|
+
SliderRange,
|
|
130
|
+
SliderThumb,
|
|
131
|
+
} from 'radix-vue'
|
|
132
|
+
|
|
133
|
+
export {
|
|
134
|
+
CollapsibleRoot as Collapsible,
|
|
135
|
+
CollapsibleTrigger,
|
|
136
|
+
CollapsibleContent,
|
|
137
|
+
} from 'radix-vue'
|
|
138
|
+
|
|
139
|
+
export {
|
|
140
|
+
ContextMenuRoot as ContextMenu,
|
|
141
|
+
ContextMenuTrigger,
|
|
142
|
+
ContextMenuContent,
|
|
143
|
+
ContextMenuItem,
|
|
144
|
+
ContextMenuSeparator,
|
|
145
|
+
ContextMenuLabel,
|
|
146
|
+
ContextMenuGroup,
|
|
147
|
+
ContextMenuSub,
|
|
148
|
+
ContextMenuSubTrigger,
|
|
149
|
+
ContextMenuSubContent,
|
|
150
|
+
ContextMenuCheckboxItem,
|
|
151
|
+
ContextMenuRadioGroup,
|
|
152
|
+
ContextMenuRadioItem,
|
|
153
|
+
ContextMenuPortal,
|
|
154
|
+
} from 'radix-vue'
|
|
155
|
+
|
|
156
|
+
export {
|
|
157
|
+
MenubarRoot as Menubar,
|
|
158
|
+
MenubarMenu,
|
|
159
|
+
MenubarTrigger,
|
|
160
|
+
MenubarContent,
|
|
161
|
+
MenubarItem,
|
|
162
|
+
MenubarSeparator,
|
|
163
|
+
MenubarPortal,
|
|
164
|
+
} from 'radix-vue'
|
|
165
|
+
|
|
166
|
+
export {
|
|
167
|
+
ScrollAreaRoot,
|
|
168
|
+
ScrollAreaViewport,
|
|
169
|
+
ScrollAreaScrollbar,
|
|
170
|
+
ScrollAreaThumb,
|
|
171
|
+
ScrollAreaCorner,
|
|
172
|
+
} from 'radix-vue'
|
|
173
|
+
|
|
174
|
+
export {
|
|
175
|
+
NavigationMenuRoot as NavigationMenu,
|
|
176
|
+
NavigationMenuList,
|
|
177
|
+
NavigationMenuItem,
|
|
178
|
+
NavigationMenuTrigger,
|
|
179
|
+
NavigationMenuContent,
|
|
180
|
+
NavigationMenuLink,
|
|
181
|
+
NavigationMenuViewport,
|
|
182
|
+
NavigationMenuIndicator,
|
|
183
|
+
} from 'radix-vue'
|
|
184
|
+
|
|
185
|
+
export {
|
|
186
|
+
HoverCardRoot as HoverCard,
|
|
187
|
+
HoverCardTrigger,
|
|
188
|
+
HoverCardContent,
|
|
189
|
+
HoverCardPortal,
|
|
190
|
+
} from 'radix-vue'
|
|
191
|
+
|
|
192
|
+
export {
|
|
193
|
+
ToggleGroupRoot as ToggleGroup,
|
|
194
|
+
ToggleGroupItem,
|
|
195
|
+
} from 'radix-vue'
|
|
196
|
+
|
|
197
|
+
export {
|
|
198
|
+
PaginationRoot as Pagination,
|
|
199
|
+
PaginationList,
|
|
200
|
+
PaginationListItem,
|
|
201
|
+
PaginationFirst,
|
|
202
|
+
PaginationPrev,
|
|
203
|
+
PaginationNext,
|
|
204
|
+
PaginationLast,
|
|
205
|
+
PaginationEllipsis,
|
|
206
|
+
} from 'radix-vue'
|
|
207
|
+
|
|
208
|
+
// External library re-exports
|
|
209
|
+
export { Toaster, toast } from 'vue-sonner'
|
package/src/lib/utils.ts
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
/**
|
|
3
|
+
* DetailView Pattern
|
|
4
|
+
* A detail page with hero/header + content sections.
|
|
5
|
+
* Use for: Circle detail, Event detail, Profile, App detail.
|
|
6
|
+
*/
|
|
7
|
+
import { type HTMLAttributes } from 'vue'
|
|
8
|
+
import { cn } from '../../lib/utils'
|
|
9
|
+
|
|
10
|
+
interface Props {
|
|
11
|
+
title?: string
|
|
12
|
+
subtitle?: string
|
|
13
|
+
class?: HTMLAttributes['class']
|
|
14
|
+
}
|
|
15
|
+
defineProps<Props>()
|
|
16
|
+
</script>
|
|
17
|
+
|
|
18
|
+
<template>
|
|
19
|
+
<div :class="cn('flex flex-col h-full', props.class)">
|
|
20
|
+
<!-- Back navigation -->
|
|
21
|
+
<div class="flex items-center gap-2 px-4 py-2 border-b">
|
|
22
|
+
<slot name="back-button" />
|
|
23
|
+
<slot name="breadcrumb" />
|
|
24
|
+
<div class="flex-1" />
|
|
25
|
+
<slot name="header-actions" />
|
|
26
|
+
</div>
|
|
27
|
+
|
|
28
|
+
<!-- Hero / Header section -->
|
|
29
|
+
<div class="px-4 py-6 border-b">
|
|
30
|
+
<slot name="hero">
|
|
31
|
+
<h1 v-if="title" class="text-2xl font-bold">{{ title }}</h1>
|
|
32
|
+
<p v-if="subtitle" class="text-muted-foreground mt-1">{{ subtitle }}</p>
|
|
33
|
+
</slot>
|
|
34
|
+
</div>
|
|
35
|
+
|
|
36
|
+
<!-- Tabs / navigation -->
|
|
37
|
+
<div v-if="$slots['tabs']" class="px-4 border-b">
|
|
38
|
+
<slot name="tabs" />
|
|
39
|
+
</div>
|
|
40
|
+
|
|
41
|
+
<!-- Main content -->
|
|
42
|
+
<div class="flex-1 overflow-auto px-4 py-4">
|
|
43
|
+
<slot />
|
|
44
|
+
</div>
|
|
45
|
+
</div>
|
|
46
|
+
</template>
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
/**
|
|
3
|
+
* EmptyState Pattern
|
|
4
|
+
* A centered, friendly empty state with icon, title, description, and CTA.
|
|
5
|
+
* Use when a list/section has no data.
|
|
6
|
+
*/
|
|
7
|
+
import { type HTMLAttributes } from 'vue'
|
|
8
|
+
import { cn } from '../../lib/utils'
|
|
9
|
+
|
|
10
|
+
interface Props {
|
|
11
|
+
title: string
|
|
12
|
+
description?: string
|
|
13
|
+
class?: HTMLAttributes['class']
|
|
14
|
+
}
|
|
15
|
+
defineProps<Props>()
|
|
16
|
+
</script>
|
|
17
|
+
|
|
18
|
+
<template>
|
|
19
|
+
<div :class="cn('flex flex-col items-center justify-center text-center py-12 px-4', props.class)">
|
|
20
|
+
<div v-if="$slots['icon']" class="mb-4 text-muted-foreground">
|
|
21
|
+
<slot name="icon" />
|
|
22
|
+
</div>
|
|
23
|
+
<h3 class="text-lg font-semibold mb-1">{{ title }}</h3>
|
|
24
|
+
<p v-if="description" class="text-sm text-muted-foreground max-w-sm mb-4">{{ description }}</p>
|
|
25
|
+
<slot name="action" />
|
|
26
|
+
</div>
|
|
27
|
+
</template>
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
/**
|
|
3
|
+
* FormView Pattern
|
|
4
|
+
* A form page/dialog with sections, validation, and submit.
|
|
5
|
+
* Use for: Settings, Profile edit, Create event, etc.
|
|
6
|
+
*/
|
|
7
|
+
import { type HTMLAttributes } from 'vue'
|
|
8
|
+
import { cn } from '../../lib/utils'
|
|
9
|
+
|
|
10
|
+
interface Props {
|
|
11
|
+
title?: string
|
|
12
|
+
description?: string
|
|
13
|
+
class?: HTMLAttributes['class']
|
|
14
|
+
}
|
|
15
|
+
defineProps<Props>()
|
|
16
|
+
const emit = defineEmits<{ submit: [] }>()
|
|
17
|
+
</script>
|
|
18
|
+
|
|
19
|
+
<template>
|
|
20
|
+
<form :class="cn('flex flex-col gap-6', props.class)" @submit.prevent="emit('submit')">
|
|
21
|
+
<div v-if="title" class="space-y-1">
|
|
22
|
+
<h2 class="text-xl font-semibold">{{ title }}</h2>
|
|
23
|
+
<p v-if="description" class="text-sm text-muted-foreground">{{ description }}</p>
|
|
24
|
+
</div>
|
|
25
|
+
|
|
26
|
+
<!-- Form sections -->
|
|
27
|
+
<slot />
|
|
28
|
+
|
|
29
|
+
<!-- Actions -->
|
|
30
|
+
<div v-if="$slots['actions']" class="flex items-center justify-end gap-2 pt-4 border-t">
|
|
31
|
+
<slot name="actions" />
|
|
32
|
+
</div>
|
|
33
|
+
</form>
|
|
34
|
+
</template>
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
/**
|
|
3
|
+
* ListView Pattern
|
|
4
|
+
* A standard list page with search, filters, and items.
|
|
5
|
+
* Use for: Circles list, Friends list, Notifications, App Store browse.
|
|
6
|
+
*/
|
|
7
|
+
import { type HTMLAttributes } from 'vue'
|
|
8
|
+
import { cn } from '../../lib/utils'
|
|
9
|
+
|
|
10
|
+
interface Props {
|
|
11
|
+
title?: string
|
|
12
|
+
class?: HTMLAttributes['class']
|
|
13
|
+
}
|
|
14
|
+
defineProps<Props>()
|
|
15
|
+
</script>
|
|
16
|
+
|
|
17
|
+
<template>
|
|
18
|
+
<div :class="cn('flex flex-col h-full', props.class)">
|
|
19
|
+
<!-- Header with title and actions -->
|
|
20
|
+
<div class="flex items-center justify-between px-4 py-3 border-b">
|
|
21
|
+
<h1 v-if="title" class="text-xl font-semibold">{{ title }}</h1>
|
|
22
|
+
<slot name="header-actions" />
|
|
23
|
+
</div>
|
|
24
|
+
|
|
25
|
+
<!-- Search / Filter Bar -->
|
|
26
|
+
<div v-if="$slots['search']" class="px-4 py-2 border-b bg-muted/30">
|
|
27
|
+
<slot name="search" />
|
|
28
|
+
</div>
|
|
29
|
+
|
|
30
|
+
<!-- Filter Tabs -->
|
|
31
|
+
<div v-if="$slots['filters']" class="px-4 py-2 border-b">
|
|
32
|
+
<slot name="filters" />
|
|
33
|
+
</div>
|
|
34
|
+
|
|
35
|
+
<!-- List content -->
|
|
36
|
+
<div class="flex-1 overflow-auto">
|
|
37
|
+
<slot />
|
|
38
|
+
</div>
|
|
39
|
+
|
|
40
|
+
<!-- Empty state -->
|
|
41
|
+
<div v-if="$slots['empty']" class="flex-1 flex items-center justify-center p-8">
|
|
42
|
+
<slot name="empty" />
|
|
43
|
+
</div>
|
|
44
|
+
</div>
|
|
45
|
+
</template>
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
/* ============================================================
|
|
2
|
+
Reinvented Design Tokens
|
|
3
|
+
============================================================
|
|
4
|
+
Brand-first design system using CSS custom properties.
|
|
5
|
+
Import this file in your app's root CSS.
|
|
6
|
+
============================================================ */
|
|
7
|
+
|
|
8
|
+
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800&display=swap');
|
|
9
|
+
|
|
10
|
+
:root {
|
|
11
|
+
/* ── Brand Colors ──────────────────────────────────────────── */
|
|
12
|
+
--background: 0 0% 100%;
|
|
13
|
+
--foreground: 240 10% 3.9%;
|
|
14
|
+
--card: 0 0% 100%;
|
|
15
|
+
--card-foreground: 240 10% 3.9%;
|
|
16
|
+
--popover: 0 0% 100%;
|
|
17
|
+
--popover-foreground: 240 10% 3.9%;
|
|
18
|
+
--primary: 252 100% 63%; /* Vibrant purple — Reinvented brand */
|
|
19
|
+
--primary-foreground: 0 0% 100%;
|
|
20
|
+
--secondary: 240 4.8% 95.9%;
|
|
21
|
+
--secondary-foreground: 240 5.9% 10%;
|
|
22
|
+
--muted: 240 4.8% 95.9%;
|
|
23
|
+
--muted-foreground: 240 3.8% 46.1%;
|
|
24
|
+
--accent: 240 4.8% 95.9%;
|
|
25
|
+
--accent-foreground: 240 5.9% 10%;
|
|
26
|
+
--destructive: 0 84.2% 60.2%;
|
|
27
|
+
--destructive-foreground: 0 0% 98%;
|
|
28
|
+
--border: 240 5.9% 90%;
|
|
29
|
+
--input: 240 5.9% 90%;
|
|
30
|
+
--ring: 252 100% 63%;
|
|
31
|
+
--radius: 0.625rem;
|
|
32
|
+
|
|
33
|
+
/* ── Success / Warning / Info ──────────────────────────────── */
|
|
34
|
+
--success: 142 76% 36%;
|
|
35
|
+
--success-foreground: 0 0% 100%;
|
|
36
|
+
--warning: 38 92% 50%;
|
|
37
|
+
--warning-foreground: 0 0% 100%;
|
|
38
|
+
--info: 217 91% 60%;
|
|
39
|
+
--info-foreground: 0 0% 100%;
|
|
40
|
+
|
|
41
|
+
/* ── Typography ────────────────────────────────────────────── */
|
|
42
|
+
--font-sans: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
43
|
+
--font-mono: 'JetBrains Mono', 'Fira Code', monospace;
|
|
44
|
+
|
|
45
|
+
/* ── Spacing Scale (4px base) ──────────────────────────────── */
|
|
46
|
+
--space-0: 0;
|
|
47
|
+
--space-1: 0.25rem; /* 4px */
|
|
48
|
+
--space-2: 0.5rem; /* 8px */
|
|
49
|
+
--space-3: 0.75rem; /* 12px */
|
|
50
|
+
--space-4: 1rem; /* 16px */
|
|
51
|
+
--space-5: 1.25rem; /* 20px */
|
|
52
|
+
--space-6: 1.5rem; /* 24px */
|
|
53
|
+
--space-8: 2rem; /* 32px */
|
|
54
|
+
--space-10: 2.5rem; /* 40px */
|
|
55
|
+
--space-12: 3rem; /* 48px */
|
|
56
|
+
--space-16: 4rem; /* 64px */
|
|
57
|
+
|
|
58
|
+
/* ── Typography Scale ──────────────────────────────────────── */
|
|
59
|
+
--text-xs: 0.75rem; /* 12px */
|
|
60
|
+
--text-sm: 0.875rem; /* 14px */
|
|
61
|
+
--text-base: 1rem; /* 16px */
|
|
62
|
+
--text-lg: 1.125rem; /* 18px */
|
|
63
|
+
--text-xl: 1.25rem; /* 20px */
|
|
64
|
+
--text-2xl: 1.5rem; /* 24px */
|
|
65
|
+
--text-3xl: 1.875rem; /* 30px */
|
|
66
|
+
--text-4xl: 2.25rem; /* 36px */
|
|
67
|
+
|
|
68
|
+
--leading-tight: 1.25;
|
|
69
|
+
--leading-normal: 1.5;
|
|
70
|
+
--leading-relaxed: 1.625;
|
|
71
|
+
|
|
72
|
+
/* ── Shadows ───────────────────────────────────────────────── */
|
|
73
|
+
--shadow-sm: 0 1px 2px 0 rgb(0 0 0 / 0.05);
|
|
74
|
+
--shadow-md: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1);
|
|
75
|
+
--shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);
|
|
76
|
+
--shadow-xl: 0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1);
|
|
77
|
+
|
|
78
|
+
/* ── Transitions ───────────────────────────────────────────── */
|
|
79
|
+
--duration-fast: 100ms;
|
|
80
|
+
--duration-normal: 200ms;
|
|
81
|
+
--duration-slow: 300ms;
|
|
82
|
+
--ease-default: cubic-bezier(0.4, 0, 0.2, 1);
|
|
83
|
+
--ease-in: cubic-bezier(0.4, 0, 1, 1);
|
|
84
|
+
--ease-out: cubic-bezier(0, 0, 0.2, 1);
|
|
85
|
+
|
|
86
|
+
/* ── Sidebar (for ShadCN sidebar component) ────────────────── */
|
|
87
|
+
--sidebar-background: 0 0% 98%;
|
|
88
|
+
--sidebar-foreground: 240 5.3% 26.1%;
|
|
89
|
+
--sidebar-primary: 252 100% 63%;
|
|
90
|
+
--sidebar-primary-foreground: 0 0% 100%;
|
|
91
|
+
--sidebar-accent: 240 4.8% 95.9%;
|
|
92
|
+
--sidebar-accent-foreground: 240 5.9% 10%;
|
|
93
|
+
--sidebar-border: 220 13% 91%;
|
|
94
|
+
--sidebar-ring: 252 100% 63%;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/* ── Dark Mode ───────────────────────────────────────────────── */
|
|
98
|
+
.dark {
|
|
99
|
+
--background: 240 10% 3.9%;
|
|
100
|
+
--foreground: 0 0% 98%;
|
|
101
|
+
--card: 240 10% 3.9%;
|
|
102
|
+
--card-foreground: 0 0% 98%;
|
|
103
|
+
--popover: 240 10% 3.9%;
|
|
104
|
+
--popover-foreground: 0 0% 98%;
|
|
105
|
+
--primary: 252 100% 69%;
|
|
106
|
+
--primary-foreground: 0 0% 100%;
|
|
107
|
+
--secondary: 240 3.7% 15.9%;
|
|
108
|
+
--secondary-foreground: 0 0% 98%;
|
|
109
|
+
--muted: 240 3.7% 15.9%;
|
|
110
|
+
--muted-foreground: 240 5% 64.9%;
|
|
111
|
+
--accent: 240 3.7% 15.9%;
|
|
112
|
+
--accent-foreground: 0 0% 98%;
|
|
113
|
+
--destructive: 0 62.8% 30.6%;
|
|
114
|
+
--destructive-foreground: 0 0% 98%;
|
|
115
|
+
--border: 240 3.7% 15.9%;
|
|
116
|
+
--input: 240 3.7% 15.9%;
|
|
117
|
+
--ring: 252 100% 69%;
|
|
118
|
+
|
|
119
|
+
--success: 142 76% 45%;
|
|
120
|
+
--warning: 38 92% 55%;
|
|
121
|
+
--info: 217 91% 65%;
|
|
122
|
+
|
|
123
|
+
--sidebar-background: 240 5.9% 10%;
|
|
124
|
+
--sidebar-foreground: 240 4.8% 95.9%;
|
|
125
|
+
--sidebar-primary: 252 100% 69%;
|
|
126
|
+
--sidebar-primary-foreground: 0 0% 100%;
|
|
127
|
+
--sidebar-accent: 240 3.7% 15.9%;
|
|
128
|
+
--sidebar-accent-foreground: 240 4.8% 95.9%;
|
|
129
|
+
--sidebar-border: 240 3.7% 15.9%;
|
|
130
|
+
--sidebar-ring: 252 100% 69%;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/* ── Base Styles ─────────────────────────────────────────────── */
|
|
134
|
+
* {
|
|
135
|
+
border-color: hsl(var(--border));
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
body {
|
|
139
|
+
font-family: var(--font-sans);
|
|
140
|
+
background-color: hsl(var(--background));
|
|
141
|
+
color: hsl(var(--foreground));
|
|
142
|
+
-webkit-font-smoothing: antialiased;
|
|
143
|
+
-moz-osx-font-smoothing: grayscale;
|
|
144
|
+
}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/** @type {import('tailwindcss').Config} */
|
|
2
|
+
export default {
|
|
3
|
+
darkMode: 'class',
|
|
4
|
+
content: [
|
|
5
|
+
'./src/**/*.{vue,ts,tsx}',
|
|
6
|
+
// Consumer apps should add their own content paths
|
|
7
|
+
],
|
|
8
|
+
theme: {
|
|
9
|
+
container: {
|
|
10
|
+
center: true,
|
|
11
|
+
padding: '2rem',
|
|
12
|
+
screens: { '2xl': '1400px' },
|
|
13
|
+
},
|
|
14
|
+
extend: {
|
|
15
|
+
colors: {
|
|
16
|
+
border: 'hsl(var(--border))',
|
|
17
|
+
input: 'hsl(var(--input))',
|
|
18
|
+
ring: 'hsl(var(--ring))',
|
|
19
|
+
background: 'hsl(var(--background))',
|
|
20
|
+
foreground: 'hsl(var(--foreground))',
|
|
21
|
+
primary: {
|
|
22
|
+
DEFAULT: 'hsl(var(--primary))',
|
|
23
|
+
foreground: 'hsl(var(--primary-foreground))',
|
|
24
|
+
},
|
|
25
|
+
secondary: {
|
|
26
|
+
DEFAULT: 'hsl(var(--secondary))',
|
|
27
|
+
foreground: 'hsl(var(--secondary-foreground))',
|
|
28
|
+
},
|
|
29
|
+
destructive: {
|
|
30
|
+
DEFAULT: 'hsl(var(--destructive))',
|
|
31
|
+
foreground: 'hsl(var(--destructive-foreground))',
|
|
32
|
+
},
|
|
33
|
+
muted: {
|
|
34
|
+
DEFAULT: 'hsl(var(--muted))',
|
|
35
|
+
foreground: 'hsl(var(--muted-foreground))',
|
|
36
|
+
},
|
|
37
|
+
accent: {
|
|
38
|
+
DEFAULT: 'hsl(var(--accent))',
|
|
39
|
+
foreground: 'hsl(var(--accent-foreground))',
|
|
40
|
+
},
|
|
41
|
+
popover: {
|
|
42
|
+
DEFAULT: 'hsl(var(--popover))',
|
|
43
|
+
foreground: 'hsl(var(--popover-foreground))',
|
|
44
|
+
},
|
|
45
|
+
card: {
|
|
46
|
+
DEFAULT: 'hsl(var(--card))',
|
|
47
|
+
foreground: 'hsl(var(--card-foreground))',
|
|
48
|
+
},
|
|
49
|
+
success: {
|
|
50
|
+
DEFAULT: 'hsl(var(--success))',
|
|
51
|
+
foreground: 'hsl(var(--success-foreground))',
|
|
52
|
+
},
|
|
53
|
+
warning: {
|
|
54
|
+
DEFAULT: 'hsl(var(--warning))',
|
|
55
|
+
foreground: 'hsl(var(--warning-foreground))',
|
|
56
|
+
},
|
|
57
|
+
info: {
|
|
58
|
+
DEFAULT: 'hsl(var(--info))',
|
|
59
|
+
foreground: 'hsl(var(--info-foreground))',
|
|
60
|
+
},
|
|
61
|
+
sidebar: {
|
|
62
|
+
DEFAULT: 'hsl(var(--sidebar-background))',
|
|
63
|
+
foreground: 'hsl(var(--sidebar-foreground))',
|
|
64
|
+
primary: 'hsl(var(--sidebar-primary))',
|
|
65
|
+
'primary-foreground': 'hsl(var(--sidebar-primary-foreground))',
|
|
66
|
+
accent: 'hsl(var(--sidebar-accent))',
|
|
67
|
+
'accent-foreground': 'hsl(var(--sidebar-accent-foreground))',
|
|
68
|
+
border: 'hsl(var(--sidebar-border))',
|
|
69
|
+
ring: 'hsl(var(--sidebar-ring))',
|
|
70
|
+
},
|
|
71
|
+
},
|
|
72
|
+
borderRadius: {
|
|
73
|
+
lg: 'var(--radius)',
|
|
74
|
+
md: 'calc(var(--radius) - 2px)',
|
|
75
|
+
sm: 'calc(var(--radius) - 4px)',
|
|
76
|
+
},
|
|
77
|
+
fontFamily: {
|
|
78
|
+
sans: ['var(--font-sans)'],
|
|
79
|
+
mono: ['var(--font-mono)'],
|
|
80
|
+
},
|
|
81
|
+
keyframes: {
|
|
82
|
+
'accordion-down': {
|
|
83
|
+
from: { height: '0' },
|
|
84
|
+
to: { height: 'var(--radix-accordion-content-height)' },
|
|
85
|
+
},
|
|
86
|
+
'accordion-up': {
|
|
87
|
+
from: { height: 'var(--radix-accordion-content-height)' },
|
|
88
|
+
to: { height: '0' },
|
|
89
|
+
},
|
|
90
|
+
'collapsible-down': {
|
|
91
|
+
from: { height: '0' },
|
|
92
|
+
to: { height: 'var(--radix-collapsible-content-height)' },
|
|
93
|
+
},
|
|
94
|
+
'collapsible-up': {
|
|
95
|
+
from: { height: 'var(--radix-collapsible-content-height)' },
|
|
96
|
+
to: { height: '0' },
|
|
97
|
+
},
|
|
98
|
+
},
|
|
99
|
+
animation: {
|
|
100
|
+
'accordion-down': 'accordion-down 0.2s ease-out',
|
|
101
|
+
'accordion-up': 'accordion-up 0.2s ease-out',
|
|
102
|
+
'collapsible-down': 'collapsible-down 0.2s ease-out',
|
|
103
|
+
'collapsible-up': 'collapsible-up 0.2s ease-out',
|
|
104
|
+
},
|
|
105
|
+
},
|
|
106
|
+
},
|
|
107
|
+
plugins: [require('tailwindcss-animate')],
|
|
108
|
+
}
|