@deriv-com/trading-game-design-system 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +150 -0
- package/app/globals.css +211 -0
- package/components/ui/accordion.tsx +66 -0
- package/components/ui/alert-dialog.tsx +196 -0
- package/components/ui/alert.tsx +66 -0
- package/components/ui/aspect-ratio.tsx +11 -0
- package/components/ui/avatar.tsx +109 -0
- package/components/ui/badge.tsx +48 -0
- package/components/ui/breadcrumb.tsx +109 -0
- package/components/ui/button-group.tsx +83 -0
- package/components/ui/button.tsx +73 -0
- package/components/ui/calendar.tsx +220 -0
- package/components/ui/card.tsx +92 -0
- package/components/ui/carousel.tsx +241 -0
- package/components/ui/chart.tsx +357 -0
- package/components/ui/checkbox.tsx +32 -0
- package/components/ui/collapsible.tsx +33 -0
- package/components/ui/combobox.tsx +310 -0
- package/components/ui/command.tsx +184 -0
- package/components/ui/context-menu.tsx +252 -0
- package/components/ui/dialog.tsx +158 -0
- package/components/ui/direction.tsx +22 -0
- package/components/ui/drawer.tsx +135 -0
- package/components/ui/dropdown-menu.tsx +257 -0
- package/components/ui/empty.tsx +104 -0
- package/components/ui/field.tsx +248 -0
- package/components/ui/form.tsx +167 -0
- package/components/ui/hover-card.tsx +44 -0
- package/components/ui/input-group.tsx +170 -0
- package/components/ui/input-otp.tsx +77 -0
- package/components/ui/input.tsx +21 -0
- package/components/ui/item.tsx +193 -0
- package/components/ui/kbd.tsx +28 -0
- package/components/ui/label.tsx +24 -0
- package/components/ui/menubar.tsx +276 -0
- package/components/ui/native-select.tsx +53 -0
- package/components/ui/navigation-menu.tsx +168 -0
- package/components/ui/pagination.tsx +127 -0
- package/components/ui/popover.tsx +89 -0
- package/components/ui/progress.tsx +31 -0
- package/components/ui/radio-group.tsx +45 -0
- package/components/ui/resizable.tsx +53 -0
- package/components/ui/scroll-area.tsx +58 -0
- package/components/ui/select.tsx +190 -0
- package/components/ui/separator.tsx +28 -0
- package/components/ui/sheet.tsx +143 -0
- package/components/ui/sidebar.tsx +726 -0
- package/components/ui/skeleton.tsx +13 -0
- package/components/ui/slider.tsx +63 -0
- package/components/ui/sonner.tsx +40 -0
- package/components/ui/spinner.tsx +16 -0
- package/components/ui/switch.tsx +35 -0
- package/components/ui/table.tsx +116 -0
- package/components/ui/tabs.tsx +91 -0
- package/components/ui/textarea.tsx +18 -0
- package/components/ui/toggle-group.tsx +83 -0
- package/components/ui/toggle.tsx +47 -0
- package/components/ui/tooltip.tsx +57 -0
- package/lib/utils.ts +6 -0
- package/package.json +60 -0
package/README.md
ADDED
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
# Trading Game Design System
|
|
2
|
+
|
|
3
|
+
A component library and design token system for the Deriv trading game product. Built on [shadcn/ui](https://ui.shadcn.com/) with a custom Figma-driven token architecture, Tailwind CSS v4, and React 19.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## What's inside
|
|
8
|
+
|
|
9
|
+
- **50+ UI components** — buttons, forms, dialogs, charts, sidebars, and more
|
|
10
|
+
- **Design tokens** — CSS custom properties for color, radius, and typography synced from Figma
|
|
11
|
+
- **Dark mode** — built-in light/dark theming via CSS variables
|
|
12
|
+
- **TypeScript** — full type definitions included
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## Available components
|
|
17
|
+
|
|
18
|
+
| Component | Import |
|
|
19
|
+
|---|---|
|
|
20
|
+
| Accordion | `Accordion, AccordionItem, AccordionTrigger, AccordionContent` |
|
|
21
|
+
| Alert | `Alert, AlertTitle, AlertDescription` |
|
|
22
|
+
| Alert Dialog | `AlertDialog, AlertDialogTrigger, AlertDialogContent, ...` |
|
|
23
|
+
| Avatar | `Avatar, AvatarImage, AvatarFallback, AvatarBadge, AvatarGroup` |
|
|
24
|
+
| Badge | `Badge, badgeVariants` |
|
|
25
|
+
| Breadcrumb | `Breadcrumb, BreadcrumbList, BreadcrumbItem, ...` |
|
|
26
|
+
| Button | `Button, buttonVariants` |
|
|
27
|
+
| Button Group | `ButtonGroup, ButtonGroupSeparator, ButtonGroupText` |
|
|
28
|
+
| Calendar | `Calendar, CalendarDayButton` |
|
|
29
|
+
| Card | `Card, CardHeader, CardTitle, CardDescription, CardContent, CardFooter` |
|
|
30
|
+
| Carousel | `Carousel, CarouselContent, CarouselItem, CarouselPrevious, CarouselNext` |
|
|
31
|
+
| Chart | `ChartContainer, ChartTooltip, ChartLegend, ChartStyle` |
|
|
32
|
+
| Checkbox | `Checkbox` |
|
|
33
|
+
| Collapsible | `Collapsible, CollapsibleTrigger, CollapsibleContent` |
|
|
34
|
+
| Combobox | `Combobox, ComboboxInput, ComboboxContent, ComboboxItem, ...` |
|
|
35
|
+
| Command | `Command, CommandDialog, CommandInput, CommandList, ...` |
|
|
36
|
+
| Context Menu | `ContextMenu, ContextMenuTrigger, ContextMenuContent, ...` |
|
|
37
|
+
| Dialog | `Dialog, DialogTrigger, DialogContent, DialogHeader, ...` |
|
|
38
|
+
| Drawer | `Drawer, DrawerTrigger, DrawerContent, DrawerHeader, ...` |
|
|
39
|
+
| Dropdown Menu | `DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, ...` |
|
|
40
|
+
| Empty State | `Empty, EmptyHeader, EmptyTitle, EmptyDescription, EmptyContent` |
|
|
41
|
+
| Field | `Field, FieldLabel, FieldDescription, FieldError, FieldGroup` |
|
|
42
|
+
| Form | `Form, FormItem, FormLabel, FormControl, FormField, FormMessage` |
|
|
43
|
+
| Hover Card | `HoverCard, HoverCardTrigger, HoverCardContent` |
|
|
44
|
+
| Input | `Input` |
|
|
45
|
+
| Input Group | `InputGroup, InputGroupAddon, InputGroupButton, InputGroupText` |
|
|
46
|
+
| Input OTP | `InputOTP, InputOTPGroup, InputOTPSlot, InputOTPSeparator` |
|
|
47
|
+
| Item | `Item, ItemMedia, ItemContent, ItemTitle, ItemDescription` |
|
|
48
|
+
| Kbd | `Kbd, KbdGroup` |
|
|
49
|
+
| Label | `Label` |
|
|
50
|
+
| Menubar | `Menubar, MenubarMenu, MenubarTrigger, MenubarContent, ...` |
|
|
51
|
+
| Native Select | `NativeSelect, NativeSelectOptGroup, NativeSelectOption` |
|
|
52
|
+
| Navigation Menu | `NavigationMenu, NavigationMenuList, NavigationMenuTrigger, ...` |
|
|
53
|
+
| Pagination | `Pagination, PaginationContent, PaginationLink, ...` |
|
|
54
|
+
| Popover | `Popover, PopoverTrigger, PopoverContent, PopoverAnchor` |
|
|
55
|
+
| Progress | `Progress` |
|
|
56
|
+
| Radio Group | `RadioGroup, RadioGroupItem` |
|
|
57
|
+
| Resizable | `ResizableHandle, ResizablePanel, ResizablePanelGroup` |
|
|
58
|
+
| Scroll Area | `ScrollArea, ScrollBar` |
|
|
59
|
+
| Select | `Select, SelectTrigger, SelectContent, SelectItem, ...` |
|
|
60
|
+
| Separator | `Separator` |
|
|
61
|
+
| Sheet | `Sheet, SheetTrigger, SheetContent, SheetHeader, ...` |
|
|
62
|
+
| Sidebar | `Sidebar, SidebarProvider, SidebarMenu, SidebarMenuItem, ...` |
|
|
63
|
+
| Skeleton | `Skeleton` |
|
|
64
|
+
| Slider | `Slider` |
|
|
65
|
+
| Spinner | `Spinner` |
|
|
66
|
+
| Switch | `Switch` |
|
|
67
|
+
| Table | `Table, TableHeader, TableBody, TableRow, TableHead, TableCell` |
|
|
68
|
+
| Tabs | `Tabs, TabsList, TabsTrigger, TabsContent` |
|
|
69
|
+
| Textarea | `Textarea` |
|
|
70
|
+
| Toast | `Toaster` |
|
|
71
|
+
| Toggle | `Toggle, toggleVariants` |
|
|
72
|
+
| Toggle Group | `ToggleGroup, ToggleGroupItem` |
|
|
73
|
+
| Tooltip | `Tooltip, TooltipTrigger, TooltipContent, TooltipProvider` |
|
|
74
|
+
|
|
75
|
+
---
|
|
76
|
+
|
|
77
|
+
## Button variants and sizes
|
|
78
|
+
|
|
79
|
+
```tsx
|
|
80
|
+
// Variants
|
|
81
|
+
<Button variant="primary" /> // teal — main CTA
|
|
82
|
+
<Button variant="secondary" /> // amber — secondary action
|
|
83
|
+
<Button variant="outline" /> // teal outline
|
|
84
|
+
<Button variant="link" /> // text only
|
|
85
|
+
|
|
86
|
+
// Sizes
|
|
87
|
+
<Button size="lg" /> // 48px height (default)
|
|
88
|
+
<Button size="md" /> // 40px height
|
|
89
|
+
<Button size="sm" /> // 32px height
|
|
90
|
+
<Button size="xs" /> // 24px height
|
|
91
|
+
<Button size="icon" /> // 48px square
|
|
92
|
+
<Button size="icon-lg" /> // 40px square
|
|
93
|
+
<Button size="icon-sm" /> // 28px square
|
|
94
|
+
<Button size="icon-xs" /> // 24px square
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
---
|
|
98
|
+
|
|
99
|
+
## Design tokens
|
|
100
|
+
|
|
101
|
+
All tokens are CSS custom properties defined in `app/globals.css`.
|
|
102
|
+
|
|
103
|
+
| Token | Usage |
|
|
104
|
+
|---|---|
|
|
105
|
+
| `--primary` | Teal `#00FFFF` — brand primary |
|
|
106
|
+
| `--primary-hover` | Teal hover `#00D4D4` |
|
|
107
|
+
| `--secondary` | Amber at 10% opacity |
|
|
108
|
+
| `--secondary-hover` | Amber 500 — full opacity |
|
|
109
|
+
| `--semantic-win` | Green — positive outcome |
|
|
110
|
+
| `--semantic-loss` | Red — negative outcome |
|
|
111
|
+
| `--semantic-warning` | Amber — warning state |
|
|
112
|
+
| `--brand-usdt` | USDT green |
|
|
113
|
+
| `--background` | Page background |
|
|
114
|
+
| `--foreground` | Primary text |
|
|
115
|
+
| `--muted-foreground` | Secondary text |
|
|
116
|
+
| `--border` | Border color |
|
|
117
|
+
| `--radius` | Base border radius (`0.625rem`) |
|
|
118
|
+
|
|
119
|
+
---
|
|
120
|
+
|
|
121
|
+
## Development
|
|
122
|
+
|
|
123
|
+
```bash
|
|
124
|
+
# Clone
|
|
125
|
+
git clone https://github.com/deriv-com/product-design-trading-game-ds.git
|
|
126
|
+
cd product-design-trading-game-ds
|
|
127
|
+
|
|
128
|
+
# Install dependencies
|
|
129
|
+
npm install
|
|
130
|
+
|
|
131
|
+
# Start dev server (Next.js component playground)
|
|
132
|
+
npm run dev
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
### Updating design tokens
|
|
136
|
+
|
|
137
|
+
Design tokens are managed in Figma and exported as JSON variables. To update:
|
|
138
|
+
|
|
139
|
+
1. Export updated variables from Figma (TailwindCSS.json, Theme.json, Mode.json)
|
|
140
|
+
2. Update the CSS custom properties in `app/globals.css`
|
|
141
|
+
|
|
142
|
+
---
|
|
143
|
+
|
|
144
|
+
## Tech stack
|
|
145
|
+
|
|
146
|
+
- **React 19** + **TypeScript**
|
|
147
|
+
- **Tailwind CSS v4** — CSS-first configuration
|
|
148
|
+
- **shadcn/ui** (New York style) — base component primitives
|
|
149
|
+
- **Radix UI** — accessible headless primitives
|
|
150
|
+
- **Figma** — source of truth for design tokens
|
package/app/globals.css
ADDED
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
@import "tailwindcss";
|
|
2
|
+
@import "tw-animate-css";
|
|
3
|
+
@import "shadcn/tailwind.css";
|
|
4
|
+
|
|
5
|
+
@custom-variant dark (&:is(.dark *));
|
|
6
|
+
|
|
7
|
+
@theme inline {
|
|
8
|
+
--color-background: var(--background);
|
|
9
|
+
--color-foreground: var(--foreground);
|
|
10
|
+
--font-sans: var(--font-barlow);
|
|
11
|
+
--font-mono: var(--font-orbitron);
|
|
12
|
+
--color-sidebar-ring: var(--sidebar-ring);
|
|
13
|
+
--color-sidebar-border: var(--sidebar-border);
|
|
14
|
+
--color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
|
|
15
|
+
--color-sidebar-accent: var(--sidebar-accent);
|
|
16
|
+
--color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
|
|
17
|
+
--color-sidebar-primary: var(--sidebar-primary);
|
|
18
|
+
--color-sidebar-foreground: var(--sidebar-foreground);
|
|
19
|
+
--color-sidebar: var(--sidebar);
|
|
20
|
+
--color-chart-5: var(--chart-5);
|
|
21
|
+
--color-chart-4: var(--chart-4);
|
|
22
|
+
--color-chart-3: var(--chart-3);
|
|
23
|
+
--color-chart-2: var(--chart-2);
|
|
24
|
+
--color-chart-1: var(--chart-1);
|
|
25
|
+
--color-ring: var(--ring);
|
|
26
|
+
--color-input: var(--input);
|
|
27
|
+
--color-border: var(--border);
|
|
28
|
+
--color-destructive: var(--destructive);
|
|
29
|
+
--color-accent-foreground: var(--accent-foreground);
|
|
30
|
+
--color-accent: var(--accent);
|
|
31
|
+
--color-accent-hover: var(--accent-hover);
|
|
32
|
+
--color-muted-foreground: var(--muted-foreground);
|
|
33
|
+
--color-muted: var(--muted);
|
|
34
|
+
--color-secondary-foreground: var(--secondary-foreground);
|
|
35
|
+
--color-secondary: var(--secondary);
|
|
36
|
+
--color-primary-foreground: var(--primary-foreground);
|
|
37
|
+
--color-primary: var(--primary);
|
|
38
|
+
--color-primary-hover: var(--primary-hover);
|
|
39
|
+
--color-secondary-hover: var(--secondary-hover);
|
|
40
|
+
--color-popover-foreground: var(--popover-foreground);
|
|
41
|
+
--color-popover: var(--popover);
|
|
42
|
+
--color-card-foreground: var(--card-foreground);
|
|
43
|
+
--color-card: var(--card);
|
|
44
|
+
--color-semantic-win: var(--semantic-win);
|
|
45
|
+
--color-semantic-loss: var(--semantic-loss);
|
|
46
|
+
--color-semantic-warning: var(--semantic-warning);
|
|
47
|
+
--color-text-secondary: var(--text-secondary);
|
|
48
|
+
--color-text-tertiary: var(--text-tertiary);
|
|
49
|
+
--color-text-decorative: var(--text-decorative);
|
|
50
|
+
--radius-sm: calc(var(--radius) - 4px);
|
|
51
|
+
--radius-md: calc(var(--radius) - 2px);
|
|
52
|
+
--radius-lg: var(--radius);
|
|
53
|
+
--radius-xl: calc(var(--radius) + 4px);
|
|
54
|
+
--radius-2xl: calc(var(--radius) + 8px);
|
|
55
|
+
--radius-3xl: calc(var(--radius) + 12px);
|
|
56
|
+
--radius-4xl: calc(var(--radius) + 16px);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
:root {
|
|
60
|
+
--radius: 0.625rem;
|
|
61
|
+
/* Light mode */
|
|
62
|
+
/* base/white */
|
|
63
|
+
--background: oklch(1 0 0);
|
|
64
|
+
/* neutral/950 */
|
|
65
|
+
--foreground: oklch(0.07 0.012 165);
|
|
66
|
+
/* base/white */
|
|
67
|
+
--card: oklch(1 0 0);
|
|
68
|
+
--card-foreground: oklch(0.07 0.012 165);
|
|
69
|
+
/* base/white */
|
|
70
|
+
--popover: oklch(1 0 0);
|
|
71
|
+
--popover-foreground: oklch(0.07 0.012 165);
|
|
72
|
+
/* teal-N/default = #00FFFF */
|
|
73
|
+
--primary: oklch(0.905 0.158 194);
|
|
74
|
+
/* neutral/950 on primary */
|
|
75
|
+
--primary-foreground: oklch(0.07 0.012 165);
|
|
76
|
+
/* teal-N/hover/press = #00D4D4 */
|
|
77
|
+
--primary-hover: oklch(0.80 0.130 194);
|
|
78
|
+
/* amber/500 at 4% opacity */
|
|
79
|
+
--secondary: oklch(0.764 0.188 76 / 4%);
|
|
80
|
+
/* amber/500 */
|
|
81
|
+
--secondary-hover: oklch(0.764 0.188 76);
|
|
82
|
+
/* neutral/900 */
|
|
83
|
+
--secondary-foreground: oklch(0.12 0.015 160);
|
|
84
|
+
/* neutral/100 */
|
|
85
|
+
--muted: oklch(0.96 0 0);
|
|
86
|
+
/* neutral/500 */
|
|
87
|
+
--muted-foreground: oklch(0.52 0 0);
|
|
88
|
+
/* neutral/100 */
|
|
89
|
+
--accent: oklch(0.96 0 0);
|
|
90
|
+
/* neutral/900 */
|
|
91
|
+
--accent-foreground: oklch(0.12 0.015 160);
|
|
92
|
+
/* neutral/200 */
|
|
93
|
+
--accent-hover: oklch(0.92 0 0);
|
|
94
|
+
/* red/600 = #DC2626 */
|
|
95
|
+
--destructive: oklch(0.53 0.220 27);
|
|
96
|
+
/* neutral/200 */
|
|
97
|
+
--border: oklch(0.92 0 0);
|
|
98
|
+
--input: oklch(0.92 0 0);
|
|
99
|
+
/* neutral/400 */
|
|
100
|
+
--ring: oklch(0.70 0 0);
|
|
101
|
+
/* chart: orange/600, teal/600, cyan/900, amber/400, amber/500 */
|
|
102
|
+
--chart-1: oklch(0.62 0.200 41);
|
|
103
|
+
--chart-2: oklch(0.83 0.130 196);
|
|
104
|
+
--chart-3: oklch(0.37 0.075 215);
|
|
105
|
+
--chart-4: oklch(0.84 0.170 85);
|
|
106
|
+
--chart-5: oklch(0.764 0.188 76);
|
|
107
|
+
/* semantic colors */
|
|
108
|
+
--semantic-win: oklch(0.87 0.200 155);
|
|
109
|
+
--semantic-loss: oklch(0.60 0.240 15);
|
|
110
|
+
--semantic-warning: oklch(0.68 0.210 48);
|
|
111
|
+
--text-secondary: oklch(0.52 0 0);
|
|
112
|
+
--text-tertiary: oklch(0.38 0 0);
|
|
113
|
+
--text-decorative: oklch(0.12 0.015 160);
|
|
114
|
+
/* sidebar light */
|
|
115
|
+
--sidebar: oklch(1 0 0);
|
|
116
|
+
--sidebar-foreground: oklch(0.07 0.012 165);
|
|
117
|
+
/* neutral/900 */
|
|
118
|
+
--sidebar-primary: oklch(0.12 0.015 160);
|
|
119
|
+
/* neutral/50 = white */
|
|
120
|
+
--sidebar-primary-foreground: oklch(1 0 0);
|
|
121
|
+
/* neutral/100 */
|
|
122
|
+
--sidebar-accent: oklch(0.96 0 0);
|
|
123
|
+
/* neutral/900 */
|
|
124
|
+
--sidebar-accent-foreground: oklch(0.12 0.015 160);
|
|
125
|
+
/* neutral/200 */
|
|
126
|
+
--sidebar-border: oklch(0.92 0 0);
|
|
127
|
+
/* neutral/400 */
|
|
128
|
+
--sidebar-ring: oklch(0.70 0 0);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
.dark {
|
|
132
|
+
/* Dark mode */
|
|
133
|
+
/* neutral/950 = #020B0A */
|
|
134
|
+
--background: oklch(0.07 0.012 165);
|
|
135
|
+
/* neutral/50 = white */
|
|
136
|
+
--foreground: oklch(1 0 0);
|
|
137
|
+
/* neutral/900 = #0D1410 */
|
|
138
|
+
--card: oklch(0.12 0.015 160);
|
|
139
|
+
--card-foreground: oklch(1 0 0);
|
|
140
|
+
/* neutral/800 = #1C221C */
|
|
141
|
+
--popover: oklch(0.20 0.013 155);
|
|
142
|
+
--popover-foreground: oklch(1 0 0);
|
|
143
|
+
/* teal-N/default = #00FFFF */
|
|
144
|
+
--primary: oklch(0.905 0.158 194);
|
|
145
|
+
/* neutral/950 on primary */
|
|
146
|
+
--primary-foreground: oklch(0.07 0.012 165);
|
|
147
|
+
/* teal-N/hover/press = #00D4D4 */
|
|
148
|
+
--primary-hover: oklch(0.80 0.130 194);
|
|
149
|
+
/* amber/500 at 4% opacity */
|
|
150
|
+
--secondary: oklch(0.764 0.188 76 / 4%);
|
|
151
|
+
/* amber/500 */
|
|
152
|
+
--secondary-hover: oklch(0.764 0.188 76);
|
|
153
|
+
/* neutral/50 = white */
|
|
154
|
+
--secondary-foreground: oklch(1 0 0);
|
|
155
|
+
/* neutral/800 */
|
|
156
|
+
--muted: oklch(0.20 0.013 155);
|
|
157
|
+
/* neutral/400 */
|
|
158
|
+
--muted-foreground: oklch(0.70 0 0);
|
|
159
|
+
/* neutral/700 = #303530 */
|
|
160
|
+
--accent: oklch(0.28 0.010 155);
|
|
161
|
+
/* neutral/50 = white */
|
|
162
|
+
--accent-foreground: oklch(1 0 0);
|
|
163
|
+
/* neutral/600 */
|
|
164
|
+
--accent-hover: oklch(0.37 0.006 155);
|
|
165
|
+
/* red/400 = #F87171 */
|
|
166
|
+
--destructive: oklch(0.64 0.185 22);
|
|
167
|
+
/* white/10% */
|
|
168
|
+
--border: oklch(1 0 0 / 10%);
|
|
169
|
+
/* white/15% */
|
|
170
|
+
--input: oklch(1 0 0 / 15%);
|
|
171
|
+
/* neutral/500 */
|
|
172
|
+
--ring: oklch(0.52 0 0);
|
|
173
|
+
/* chart: blue/700, emerald/500, amber/500, purple/500, rose/500 */
|
|
174
|
+
--chart-1: oklch(0.44 0.240 265);
|
|
175
|
+
--chart-2: oklch(0.70 0.175 160);
|
|
176
|
+
--chart-3: oklch(0.764 0.188 76);
|
|
177
|
+
--chart-4: oklch(0.59 0.270 308);
|
|
178
|
+
--chart-5: oklch(0.64 0.235 12);
|
|
179
|
+
/* semantic colors */
|
|
180
|
+
--semantic-win: oklch(0.87 0.200 155);
|
|
181
|
+
--semantic-loss: oklch(0.60 0.240 15);
|
|
182
|
+
--semantic-warning: oklch(0.68 0.210 48);
|
|
183
|
+
--text-secondary: oklch(0.70 0 0);
|
|
184
|
+
--text-tertiary: oklch(0.40 0 0);
|
|
185
|
+
--text-decorative: oklch(0.20 0.013 155);
|
|
186
|
+
/* sidebar dark */
|
|
187
|
+
/* neutral/900 */
|
|
188
|
+
--sidebar: oklch(0.12 0.015 160);
|
|
189
|
+
--sidebar-foreground: oklch(1 0 0);
|
|
190
|
+
/* blue/700 */
|
|
191
|
+
--sidebar-primary: oklch(0.44 0.240 265);
|
|
192
|
+
/* neutral/50 = white */
|
|
193
|
+
--sidebar-primary-foreground: oklch(1 0 0);
|
|
194
|
+
/* neutral/800 */
|
|
195
|
+
--sidebar-accent: oklch(0.20 0.013 155);
|
|
196
|
+
/* neutral/50 = white */
|
|
197
|
+
--sidebar-accent-foreground: oklch(1 0 0);
|
|
198
|
+
/* white/10% */
|
|
199
|
+
--sidebar-border: oklch(1 0 0 / 10%);
|
|
200
|
+
/* neutral/600 */
|
|
201
|
+
--sidebar-ring: oklch(0.37 0 0);
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
@layer base {
|
|
205
|
+
* {
|
|
206
|
+
@apply border-border outline-ring/50;
|
|
207
|
+
}
|
|
208
|
+
body {
|
|
209
|
+
@apply bg-background text-foreground;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
"use client"
|
|
2
|
+
|
|
3
|
+
import * as React from "react"
|
|
4
|
+
import { ChevronDownIcon } from "lucide-react"
|
|
5
|
+
import { Accordion as AccordionPrimitive } from "radix-ui"
|
|
6
|
+
|
|
7
|
+
import { cn } from "@/lib/utils"
|
|
8
|
+
|
|
9
|
+
function Accordion({
|
|
10
|
+
...props
|
|
11
|
+
}: React.ComponentProps<typeof AccordionPrimitive.Root>) {
|
|
12
|
+
return <AccordionPrimitive.Root data-slot="accordion" {...props} />
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function AccordionItem({
|
|
16
|
+
className,
|
|
17
|
+
...props
|
|
18
|
+
}: React.ComponentProps<typeof AccordionPrimitive.Item>) {
|
|
19
|
+
return (
|
|
20
|
+
<AccordionPrimitive.Item
|
|
21
|
+
data-slot="accordion-item"
|
|
22
|
+
className={cn("border-b last:border-b-0", className)}
|
|
23
|
+
{...props}
|
|
24
|
+
/>
|
|
25
|
+
)
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function AccordionTrigger({
|
|
29
|
+
className,
|
|
30
|
+
children,
|
|
31
|
+
...props
|
|
32
|
+
}: React.ComponentProps<typeof AccordionPrimitive.Trigger>) {
|
|
33
|
+
return (
|
|
34
|
+
<AccordionPrimitive.Header className="flex">
|
|
35
|
+
<AccordionPrimitive.Trigger
|
|
36
|
+
data-slot="accordion-trigger"
|
|
37
|
+
className={cn(
|
|
38
|
+
"flex flex-1 items-start justify-between gap-4 rounded-md py-4 text-left text-sm font-medium transition-all outline-none hover:underline focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:pointer-events-none disabled:opacity-50 [&[data-state=open]>svg]:rotate-180",
|
|
39
|
+
className
|
|
40
|
+
)}
|
|
41
|
+
{...props}
|
|
42
|
+
>
|
|
43
|
+
{children}
|
|
44
|
+
<ChevronDownIcon className="pointer-events-none size-4 shrink-0 translate-y-0.5 text-muted-foreground transition-transform duration-200" />
|
|
45
|
+
</AccordionPrimitive.Trigger>
|
|
46
|
+
</AccordionPrimitive.Header>
|
|
47
|
+
)
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function AccordionContent({
|
|
51
|
+
className,
|
|
52
|
+
children,
|
|
53
|
+
...props
|
|
54
|
+
}: React.ComponentProps<typeof AccordionPrimitive.Content>) {
|
|
55
|
+
return (
|
|
56
|
+
<AccordionPrimitive.Content
|
|
57
|
+
data-slot="accordion-content"
|
|
58
|
+
className="overflow-hidden text-sm data-[state=closed]:animate-accordion-up data-[state=open]:animate-accordion-down"
|
|
59
|
+
{...props}
|
|
60
|
+
>
|
|
61
|
+
<div className={cn("pt-0 pb-4", className)}>{children}</div>
|
|
62
|
+
</AccordionPrimitive.Content>
|
|
63
|
+
)
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export { Accordion, AccordionItem, AccordionTrigger, AccordionContent }
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
"use client"
|
|
2
|
+
|
|
3
|
+
import * as React from "react"
|
|
4
|
+
import { AlertDialog as AlertDialogPrimitive } from "radix-ui"
|
|
5
|
+
|
|
6
|
+
import { cn } from "@/lib/utils"
|
|
7
|
+
import { Button } from "@/components/ui/button"
|
|
8
|
+
|
|
9
|
+
function AlertDialog({
|
|
10
|
+
...props
|
|
11
|
+
}: React.ComponentProps<typeof AlertDialogPrimitive.Root>) {
|
|
12
|
+
return <AlertDialogPrimitive.Root data-slot="alert-dialog" {...props} />
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function AlertDialogTrigger({
|
|
16
|
+
...props
|
|
17
|
+
}: React.ComponentProps<typeof AlertDialogPrimitive.Trigger>) {
|
|
18
|
+
return (
|
|
19
|
+
<AlertDialogPrimitive.Trigger data-slot="alert-dialog-trigger" {...props} />
|
|
20
|
+
)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function AlertDialogPortal({
|
|
24
|
+
...props
|
|
25
|
+
}: React.ComponentProps<typeof AlertDialogPrimitive.Portal>) {
|
|
26
|
+
return (
|
|
27
|
+
<AlertDialogPrimitive.Portal data-slot="alert-dialog-portal" {...props} />
|
|
28
|
+
)
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function AlertDialogOverlay({
|
|
32
|
+
className,
|
|
33
|
+
...props
|
|
34
|
+
}: React.ComponentProps<typeof AlertDialogPrimitive.Overlay>) {
|
|
35
|
+
return (
|
|
36
|
+
<AlertDialogPrimitive.Overlay
|
|
37
|
+
data-slot="alert-dialog-overlay"
|
|
38
|
+
className={cn(
|
|
39
|
+
"fixed inset-0 z-50 bg-black/50 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:animate-in data-[state=open]:fade-in-0",
|
|
40
|
+
className
|
|
41
|
+
)}
|
|
42
|
+
{...props}
|
|
43
|
+
/>
|
|
44
|
+
)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function AlertDialogContent({
|
|
48
|
+
className,
|
|
49
|
+
size = "default",
|
|
50
|
+
...props
|
|
51
|
+
}: React.ComponentProps<typeof AlertDialogPrimitive.Content> & {
|
|
52
|
+
size?: "default" | "sm"
|
|
53
|
+
}) {
|
|
54
|
+
return (
|
|
55
|
+
<AlertDialogPortal>
|
|
56
|
+
<AlertDialogOverlay />
|
|
57
|
+
<AlertDialogPrimitive.Content
|
|
58
|
+
data-slot="alert-dialog-content"
|
|
59
|
+
data-size={size}
|
|
60
|
+
className={cn(
|
|
61
|
+
"group/alert-dialog-content fixed top-[50%] left-[50%] z-50 grid w-full max-w-[calc(100%-2rem)] translate-x-[-50%] translate-y-[-50%] gap-4 rounded-lg border bg-background p-6 shadow-lg duration-200 data-[size=sm]:max-w-xs data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95 data-[size=default]:sm:max-w-lg",
|
|
62
|
+
className
|
|
63
|
+
)}
|
|
64
|
+
{...props}
|
|
65
|
+
/>
|
|
66
|
+
</AlertDialogPortal>
|
|
67
|
+
)
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function AlertDialogHeader({
|
|
71
|
+
className,
|
|
72
|
+
...props
|
|
73
|
+
}: React.ComponentProps<"div">) {
|
|
74
|
+
return (
|
|
75
|
+
<div
|
|
76
|
+
data-slot="alert-dialog-header"
|
|
77
|
+
className={cn(
|
|
78
|
+
"grid grid-rows-[auto_1fr] place-items-center gap-1.5 text-center has-data-[slot=alert-dialog-media]:grid-rows-[auto_auto_1fr] has-data-[slot=alert-dialog-media]:gap-x-6 sm:group-data-[size=default]/alert-dialog-content:place-items-start sm:group-data-[size=default]/alert-dialog-content:text-left sm:group-data-[size=default]/alert-dialog-content:has-data-[slot=alert-dialog-media]:grid-rows-[auto_1fr]",
|
|
79
|
+
className
|
|
80
|
+
)}
|
|
81
|
+
{...props}
|
|
82
|
+
/>
|
|
83
|
+
)
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function AlertDialogFooter({
|
|
87
|
+
className,
|
|
88
|
+
...props
|
|
89
|
+
}: React.ComponentProps<"div">) {
|
|
90
|
+
return (
|
|
91
|
+
<div
|
|
92
|
+
data-slot="alert-dialog-footer"
|
|
93
|
+
className={cn(
|
|
94
|
+
"flex flex-col-reverse gap-2 group-data-[size=sm]/alert-dialog-content:grid group-data-[size=sm]/alert-dialog-content:grid-cols-2 sm:flex-row sm:justify-end",
|
|
95
|
+
className
|
|
96
|
+
)}
|
|
97
|
+
{...props}
|
|
98
|
+
/>
|
|
99
|
+
)
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function AlertDialogTitle({
|
|
103
|
+
className,
|
|
104
|
+
...props
|
|
105
|
+
}: React.ComponentProps<typeof AlertDialogPrimitive.Title>) {
|
|
106
|
+
return (
|
|
107
|
+
<AlertDialogPrimitive.Title
|
|
108
|
+
data-slot="alert-dialog-title"
|
|
109
|
+
className={cn(
|
|
110
|
+
"text-lg font-semibold sm:group-data-[size=default]/alert-dialog-content:group-has-data-[slot=alert-dialog-media]/alert-dialog-content:col-start-2",
|
|
111
|
+
className
|
|
112
|
+
)}
|
|
113
|
+
{...props}
|
|
114
|
+
/>
|
|
115
|
+
)
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function AlertDialogDescription({
|
|
119
|
+
className,
|
|
120
|
+
...props
|
|
121
|
+
}: React.ComponentProps<typeof AlertDialogPrimitive.Description>) {
|
|
122
|
+
return (
|
|
123
|
+
<AlertDialogPrimitive.Description
|
|
124
|
+
data-slot="alert-dialog-description"
|
|
125
|
+
className={cn("text-sm text-muted-foreground", className)}
|
|
126
|
+
{...props}
|
|
127
|
+
/>
|
|
128
|
+
)
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function AlertDialogMedia({
|
|
132
|
+
className,
|
|
133
|
+
...props
|
|
134
|
+
}: React.ComponentProps<"div">) {
|
|
135
|
+
return (
|
|
136
|
+
<div
|
|
137
|
+
data-slot="alert-dialog-media"
|
|
138
|
+
className={cn(
|
|
139
|
+
"mb-2 inline-flex size-16 items-center justify-center rounded-md bg-muted sm:group-data-[size=default]/alert-dialog-content:row-span-2 *:[svg:not([class*='size-'])]:size-8",
|
|
140
|
+
className
|
|
141
|
+
)}
|
|
142
|
+
{...props}
|
|
143
|
+
/>
|
|
144
|
+
)
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
function AlertDialogAction({
|
|
148
|
+
className,
|
|
149
|
+
variant = "primary",
|
|
150
|
+
size = "lg",
|
|
151
|
+
...props
|
|
152
|
+
}: React.ComponentProps<typeof AlertDialogPrimitive.Action> &
|
|
153
|
+
Pick<React.ComponentProps<typeof Button>, "variant" | "size">) {
|
|
154
|
+
return (
|
|
155
|
+
<Button variant={variant} size={size} asChild>
|
|
156
|
+
<AlertDialogPrimitive.Action
|
|
157
|
+
data-slot="alert-dialog-action"
|
|
158
|
+
className={cn(className)}
|
|
159
|
+
{...props}
|
|
160
|
+
/>
|
|
161
|
+
</Button>
|
|
162
|
+
)
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
function AlertDialogCancel({
|
|
166
|
+
className,
|
|
167
|
+
variant = "outline",
|
|
168
|
+
size = "lg",
|
|
169
|
+
...props
|
|
170
|
+
}: React.ComponentProps<typeof AlertDialogPrimitive.Cancel> &
|
|
171
|
+
Pick<React.ComponentProps<typeof Button>, "variant" | "size">) {
|
|
172
|
+
return (
|
|
173
|
+
<Button variant={variant} size={size} asChild>
|
|
174
|
+
<AlertDialogPrimitive.Cancel
|
|
175
|
+
data-slot="alert-dialog-cancel"
|
|
176
|
+
className={cn(className)}
|
|
177
|
+
{...props}
|
|
178
|
+
/>
|
|
179
|
+
</Button>
|
|
180
|
+
)
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
export {
|
|
184
|
+
AlertDialog,
|
|
185
|
+
AlertDialogAction,
|
|
186
|
+
AlertDialogCancel,
|
|
187
|
+
AlertDialogContent,
|
|
188
|
+
AlertDialogDescription,
|
|
189
|
+
AlertDialogFooter,
|
|
190
|
+
AlertDialogHeader,
|
|
191
|
+
AlertDialogMedia,
|
|
192
|
+
AlertDialogOverlay,
|
|
193
|
+
AlertDialogPortal,
|
|
194
|
+
AlertDialogTitle,
|
|
195
|
+
AlertDialogTrigger,
|
|
196
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import * as React from "react"
|
|
2
|
+
import { cva, type VariantProps } from "class-variance-authority"
|
|
3
|
+
|
|
4
|
+
import { cn } from "@/lib/utils"
|
|
5
|
+
|
|
6
|
+
const alertVariants = cva(
|
|
7
|
+
"relative grid w-full grid-cols-[0_1fr] items-start gap-y-0.5 rounded-lg border px-4 py-3 text-sm has-[>svg]:grid-cols-[calc(var(--spacing)*4)_1fr] has-[>svg]:gap-x-3 [&>svg]:size-4 [&>svg]:translate-y-0.5 [&>svg]:text-current",
|
|
8
|
+
{
|
|
9
|
+
variants: {
|
|
10
|
+
variant: {
|
|
11
|
+
default: "bg-card text-card-foreground",
|
|
12
|
+
destructive:
|
|
13
|
+
"bg-card text-destructive *:data-[slot=alert-description]:text-destructive/90 [&>svg]:text-current",
|
|
14
|
+
},
|
|
15
|
+
},
|
|
16
|
+
defaultVariants: {
|
|
17
|
+
variant: "default",
|
|
18
|
+
},
|
|
19
|
+
}
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
function Alert({
|
|
23
|
+
className,
|
|
24
|
+
variant,
|
|
25
|
+
...props
|
|
26
|
+
}: React.ComponentProps<"div"> & VariantProps<typeof alertVariants>) {
|
|
27
|
+
return (
|
|
28
|
+
<div
|
|
29
|
+
data-slot="alert"
|
|
30
|
+
role="alert"
|
|
31
|
+
className={cn(alertVariants({ variant }), className)}
|
|
32
|
+
{...props}
|
|
33
|
+
/>
|
|
34
|
+
)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function AlertTitle({ className, ...props }: React.ComponentProps<"div">) {
|
|
38
|
+
return (
|
|
39
|
+
<div
|
|
40
|
+
data-slot="alert-title"
|
|
41
|
+
className={cn(
|
|
42
|
+
"col-start-2 line-clamp-1 min-h-4 font-medium tracking-tight",
|
|
43
|
+
className
|
|
44
|
+
)}
|
|
45
|
+
{...props}
|
|
46
|
+
/>
|
|
47
|
+
)
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function AlertDescription({
|
|
51
|
+
className,
|
|
52
|
+
...props
|
|
53
|
+
}: React.ComponentProps<"div">) {
|
|
54
|
+
return (
|
|
55
|
+
<div
|
|
56
|
+
data-slot="alert-description"
|
|
57
|
+
className={cn(
|
|
58
|
+
"col-start-2 grid justify-items-start gap-1 text-sm text-muted-foreground [&_p]:leading-relaxed",
|
|
59
|
+
className
|
|
60
|
+
)}
|
|
61
|
+
{...props}
|
|
62
|
+
/>
|
|
63
|
+
)
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export { Alert, AlertTitle, AlertDescription }
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use client"
|
|
2
|
+
|
|
3
|
+
import { AspectRatio as AspectRatioPrimitive } from "radix-ui"
|
|
4
|
+
|
|
5
|
+
function AspectRatio({
|
|
6
|
+
...props
|
|
7
|
+
}: React.ComponentProps<typeof AspectRatioPrimitive.Root>) {
|
|
8
|
+
return <AspectRatioPrimitive.Root data-slot="aspect-ratio" {...props} />
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export { AspectRatio }
|