@modern-admin/ui 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/dist/components/accordion.d.ts +7 -0
- package/dist/components/accordion.d.ts.map +1 -0
- package/dist/components/accordion.jsx +19 -0
- package/dist/components/accordion.jsx.map +1 -0
- package/dist/components/alert-dialog.d.ts +22 -0
- package/dist/components/alert-dialog.d.ts.map +1 -0
- package/dist/components/alert-dialog.jsx +27 -0
- package/dist/components/alert-dialog.jsx.map +1 -0
- package/dist/components/audit-timeline.d.ts +24 -0
- package/dist/components/audit-timeline.d.ts.map +1 -0
- package/dist/components/audit-timeline.jsx +60 -0
- package/dist/components/audit-timeline.jsx.map +1 -0
- package/dist/components/avatar.d.ts +6 -0
- package/dist/components/avatar.d.ts.map +1 -0
- package/dist/components/avatar.jsx +10 -0
- package/dist/components/avatar.jsx.map +1 -0
- package/dist/components/badge.d.ts +10 -0
- package/dist/components/badge.d.ts.map +1 -0
- package/dist/components/badge.jsx +19 -0
- package/dist/components/badge.jsx.map +1 -0
- package/dist/components/breadcrumb.d.ts +17 -0
- package/dist/components/breadcrumb.d.ts.map +1 -0
- package/dist/components/breadcrumb.jsx +27 -0
- package/dist/components/breadcrumb.jsx.map +1 -0
- package/dist/components/button.d.ts +12 -0
- package/dist/components/button.d.ts.map +1 -0
- package/dist/components/button.jsx +37 -0
- package/dist/components/button.jsx.map +1 -0
- package/dist/components/calendar.d.ts +9 -0
- package/dist/components/calendar.d.ts.map +1 -0
- package/dist/components/calendar.jsx +102 -0
- package/dist/components/calendar.jsx.map +1 -0
- package/dist/components/card.d.ts +8 -0
- package/dist/components/card.d.ts.map +1 -0
- package/dist/components/card.jsx +18 -0
- package/dist/components/card.jsx.map +1 -0
- package/dist/components/chart.d.ts +97 -0
- package/dist/components/chart.d.ts.map +1 -0
- package/dist/components/chart.jsx +233 -0
- package/dist/components/chart.jsx.map +1 -0
- package/dist/components/checkbox.d.ts +4 -0
- package/dist/components/checkbox.d.ts.map +1 -0
- package/dist/components/checkbox.jsx +11 -0
- package/dist/components/checkbox.jsx.map +1 -0
- package/dist/components/combobox.d.ts +46 -0
- package/dist/components/combobox.d.ts.map +1 -0
- package/dist/components/combobox.jsx +145 -0
- package/dist/components/combobox.jsx.map +1 -0
- package/dist/components/command.d.ts +80 -0
- package/dist/components/command.d.ts.map +1 -0
- package/dist/components/command.jsx +32 -0
- package/dist/components/command.jsx.map +1 -0
- package/dist/components/date-picker.d.ts +24 -0
- package/dist/components/date-picker.d.ts.map +1 -0
- package/dist/components/date-picker.jsx +149 -0
- package/dist/components/date-picker.jsx.map +1 -0
- package/dist/components/date-range-input.d.ts +22 -0
- package/dist/components/date-range-input.d.ts.map +1 -0
- package/dist/components/date-range-input.jsx +202 -0
- package/dist/components/date-range-input.jsx.map +1 -0
- package/dist/components/dialog.d.ts +19 -0
- package/dist/components/dialog.d.ts.map +1 -0
- package/dist/components/dialog.jsx +30 -0
- package/dist/components/dialog.jsx.map +1 -0
- package/dist/components/diff-view.d.ts +24 -0
- package/dist/components/diff-view.d.ts.map +1 -0
- package/dist/components/diff-view.jsx +69 -0
- package/dist/components/diff-view.jsx.map +1 -0
- package/dist/components/dropdown-menu.d.ts +27 -0
- package/dist/components/dropdown-menu.d.ts.map +1 -0
- package/dist/components/dropdown-menu.jsx +48 -0
- package/dist/components/dropdown-menu.jsx.map +1 -0
- package/dist/components/empty.d.ts +15 -0
- package/dist/components/empty.d.ts.map +1 -0
- package/dist/components/empty.jsx +27 -0
- package/dist/components/empty.jsx.map +1 -0
- package/dist/components/field.d.ts +23 -0
- package/dist/components/field.d.ts.map +1 -0
- package/dist/components/field.jsx +60 -0
- package/dist/components/field.jsx.map +1 -0
- package/dist/components/file-input.d.ts +50 -0
- package/dist/components/file-input.d.ts.map +1 -0
- package/dist/components/file-input.jsx +104 -0
- package/dist/components/file-input.jsx.map +1 -0
- package/dist/components/form.d.ts +20 -0
- package/dist/components/form.d.ts.map +1 -0
- package/dist/components/form.jsx +66 -0
- package/dist/components/form.jsx.map +1 -0
- package/dist/components/info-tooltip.d.ts +11 -0
- package/dist/components/info-tooltip.d.ts.map +1 -0
- package/dist/components/info-tooltip.jsx +17 -0
- package/dist/components/info-tooltip.jsx.map +1 -0
- package/dist/components/input.d.ts +13 -0
- package/dist/components/input.d.ts.map +1 -0
- package/dist/components/input.jsx +19 -0
- package/dist/components/input.jsx.map +1 -0
- package/dist/components/json-editor.d.ts +23 -0
- package/dist/components/json-editor.d.ts.map +1 -0
- package/dist/components/json-editor.jsx +143 -0
- package/dist/components/json-editor.jsx.map +1 -0
- package/dist/components/kbd.d.ts +15 -0
- package/dist/components/kbd.d.ts.map +1 -0
- package/dist/components/kbd.jsx +23 -0
- package/dist/components/kbd.jsx.map +1 -0
- package/dist/components/key-value-editor.d.ts +92 -0
- package/dist/components/key-value-editor.d.ts.map +1 -0
- package/dist/components/key-value-editor.jsx +187 -0
- package/dist/components/key-value-editor.jsx.map +1 -0
- package/dist/components/keyboard-shortcuts-help.d.ts +17 -0
- package/dist/components/keyboard-shortcuts-help.d.ts.map +1 -0
- package/dist/components/keyboard-shortcuts-help.jsx +97 -0
- package/dist/components/keyboard-shortcuts-help.jsx.map +1 -0
- package/dist/components/label.d.ts +5 -0
- package/dist/components/label.d.ts.map +1 -0
- package/dist/components/label.jsx +8 -0
- package/dist/components/label.jsx.map +1 -0
- package/dist/components/media-preview.d.ts +30 -0
- package/dist/components/media-preview.d.ts.map +1 -0
- package/dist/components/media-preview.jsx +189 -0
- package/dist/components/media-preview.jsx.map +1 -0
- package/dist/components/multi-file-input.d.ts +76 -0
- package/dist/components/multi-file-input.d.ts.map +1 -0
- package/dist/components/multi-file-input.jsx +131 -0
- package/dist/components/multi-file-input.jsx.map +1 -0
- package/dist/components/password-input.d.ts +10 -0
- package/dist/components/password-input.d.ts.map +1 -0
- package/dist/components/password-input.jsx +18 -0
- package/dist/components/password-input.jsx.map +1 -0
- package/dist/components/popover.d.ts +7 -0
- package/dist/components/popover.d.ts.map +1 -0
- package/dist/components/popover.jsx +11 -0
- package/dist/components/popover.jsx.map +1 -0
- package/dist/components/revision-timeline.d.ts +30 -0
- package/dist/components/revision-timeline.d.ts.map +1 -0
- package/dist/components/revision-timeline.jsx +42 -0
- package/dist/components/revision-timeline.jsx.map +1 -0
- package/dist/components/richtext-editor.d.ts +43 -0
- package/dist/components/richtext-editor.d.ts.map +1 -0
- package/dist/components/richtext-editor.jsx +319 -0
- package/dist/components/richtext-editor.jsx.map +1 -0
- package/dist/components/richtext-mode.d.ts +23 -0
- package/dist/components/richtext-mode.d.ts.map +1 -0
- package/dist/components/richtext-mode.js +36 -0
- package/dist/components/richtext-mode.js.map +1 -0
- package/dist/components/richtext-render.d.ts +8 -0
- package/dist/components/richtext-render.d.ts.map +1 -0
- package/dist/components/richtext-render.jsx +33 -0
- package/dist/components/richtext-render.jsx.map +1 -0
- package/dist/components/richtext-sync.d.ts +37 -0
- package/dist/components/richtext-sync.d.ts.map +1 -0
- package/dist/components/richtext-sync.js +46 -0
- package/dist/components/richtext-sync.js.map +1 -0
- package/dist/components/scroll-area.d.ts +5 -0
- package/dist/components/scroll-area.d.ts.map +1 -0
- package/dist/components/scroll-area.jsx +16 -0
- package/dist/components/scroll-area.jsx.map +1 -0
- package/dist/components/select.d.ts +36 -0
- package/dist/components/select.d.ts.map +1 -0
- package/dist/components/select.jsx +87 -0
- package/dist/components/select.jsx.map +1 -0
- package/dist/components/separator.d.ts +4 -0
- package/dist/components/separator.d.ts.map +1 -0
- package/dist/components/separator.jsx +6 -0
- package/dist/components/separator.jsx.map +1 -0
- package/dist/components/sheet.d.ts +29 -0
- package/dist/components/sheet.d.ts.map +1 -0
- package/dist/components/sheet.jsx +44 -0
- package/dist/components/sheet.jsx.map +1 -0
- package/dist/components/sidebar.d.ts +70 -0
- package/dist/components/sidebar.d.ts.map +1 -0
- package/dist/components/sidebar.jsx +245 -0
- package/dist/components/sidebar.jsx.map +1 -0
- package/dist/components/skeleton.d.ts +3 -0
- package/dist/components/skeleton.d.ts.map +1 -0
- package/dist/components/skeleton.jsx +6 -0
- package/dist/components/skeleton.jsx.map +1 -0
- package/dist/components/sonner.d.ts +6 -0
- package/dist/components/sonner.d.ts.map +1 -0
- package/dist/components/sonner.jsx +29 -0
- package/dist/components/sonner.jsx.map +1 -0
- package/dist/components/switch.d.ts +4 -0
- package/dist/components/switch.d.ts.map +1 -0
- package/dist/components/switch.jsx +8 -0
- package/dist/components/switch.jsx.map +1 -0
- package/dist/components/table.d.ts +10 -0
- package/dist/components/table.d.ts.map +1 -0
- package/dist/components/table.jsx +21 -0
- package/dist/components/table.jsx.map +1 -0
- package/dist/components/tabs.d.ts +7 -0
- package/dist/components/tabs.d.ts.map +1 -0
- package/dist/components/tabs.jsx +14 -0
- package/dist/components/tabs.jsx.map +1 -0
- package/dist/components/textarea.d.ts +4 -0
- package/dist/components/textarea.d.ts.map +1 -0
- package/dist/components/textarea.jsx +5 -0
- package/dist/components/textarea.jsx.map +1 -0
- package/dist/components/tooltip.d.ts +7 -0
- package/dist/components/tooltip.d.ts.map +1 -0
- package/dist/components/tooltip.jsx +11 -0
- package/dist/components/tooltip.jsx.map +1 -0
- package/dist/index.d.ts +52 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +72 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/theme.d.ts +11 -0
- package/dist/lib/theme.d.ts.map +1 -0
- package/dist/lib/theme.js +44 -0
- package/dist/lib/theme.js.map +1 -0
- package/dist/lib/utils.d.ts +3 -0
- package/dist/lib/utils.d.ts.map +1 -0
- package/dist/lib/utils.js +6 -0
- package/dist/lib/utils.js.map +1 -0
- package/dist/styles.css +242 -0
- package/package.json +85 -0
- package/src/components/accordion.tsx +48 -0
- package/src/components/alert-dialog.tsx +113 -0
- package/src/components/audit-timeline.tsx +102 -0
- package/src/components/avatar.tsx +42 -0
- package/src/components/badge.tsx +34 -0
- package/src/components/breadcrumb.tsx +99 -0
- package/src/components/button.tsx +58 -0
- package/src/components/calendar.tsx +176 -0
- package/src/components/card.tsx +60 -0
- package/src/components/chart.tsx +558 -0
- package/src/components/checkbox.tsx +23 -0
- package/src/components/combobox.tsx +264 -0
- package/src/components/command.tsx +120 -0
- package/src/components/date-picker.tsx +221 -0
- package/src/components/date-range-input.tsx +295 -0
- package/src/components/dialog.tsx +94 -0
- package/src/components/diff-view.tsx +182 -0
- package/src/components/dropdown-menu.tsx +165 -0
- package/src/components/empty.tsx +100 -0
- package/src/components/field.tsx +168 -0
- package/src/components/file-input.tsx +233 -0
- package/src/components/form.tsx +152 -0
- package/src/components/info-tooltip.tsx +40 -0
- package/src/components/input.tsx +55 -0
- package/src/components/json-editor.tsx +210 -0
- package/src/components/kbd.tsx +35 -0
- package/src/components/key-value-editor.tsx +423 -0
- package/src/components/keyboard-shortcuts-help.tsx +136 -0
- package/src/components/label.tsx +16 -0
- package/src/components/media-preview.tsx +278 -0
- package/src/components/multi-file-input.tsx +315 -0
- package/src/components/password-input.tsx +50 -0
- package/src/components/popover.tsx +26 -0
- package/src/components/revision-timeline.tsx +93 -0
- package/src/components/richtext-editor.tsx +624 -0
- package/src/components/richtext-mode.ts +39 -0
- package/src/components/richtext-render.tsx +51 -0
- package/src/components/richtext-sync.ts +57 -0
- package/src/components/scroll-area.tsx +41 -0
- package/src/components/select.tsx +200 -0
- package/src/components/separator.tsx +21 -0
- package/src/components/sheet.tsx +109 -0
- package/src/components/sidebar.tsx +660 -0
- package/src/components/skeleton.tsx +9 -0
- package/src/components/sonner.tsx +45 -0
- package/src/components/switch.tsx +24 -0
- package/src/components/table.tsx +93 -0
- package/src/components/tabs.tsx +57 -0
- package/src/components/textarea.tsx +18 -0
- package/src/components/tooltip.tsx +25 -0
- package/src/index.ts +342 -0
- package/src/lib/theme.ts +45 -0
- package/src/lib/utils.ts +6 -0
- package/src/styles.css +242 -0
package/dist/styles.css
ADDED
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
/* Tailwind 4 CSS-first config. No tailwind.config.js — tokens live in @theme. */
|
|
2
|
+
@import "tailwindcss";
|
|
3
|
+
/* shadcn-style enter/exit/slide/zoom utilities (animate-in, fade-in-0,
|
|
4
|
+
slide-in-from-top-2, etc.) used by Radix primitives via data-state. */
|
|
5
|
+
@import "tw-animate-css";
|
|
6
|
+
/* `prose` long-form typography utilities for rendered HTML/Markdown
|
|
7
|
+
bodies (e.g. richtext fields). */
|
|
8
|
+
@plugin "@tailwindcss/typography";
|
|
9
|
+
|
|
10
|
+
/* Tailwind 4 only scans files inside the project that imports this CSS by
|
|
11
|
+
default. Our React components and shadcn primitives live in sibling
|
|
12
|
+
workspace packages, so we point the scanner at them explicitly. */
|
|
13
|
+
@source "../../react/src/**/*.{ts,tsx}";
|
|
14
|
+
@source "../src/**/*.{ts,tsx}";
|
|
15
|
+
|
|
16
|
+
@theme {
|
|
17
|
+
--animate-accordion-down: accordion-down 0.18s ease-out;
|
|
18
|
+
--animate-accordion-up: accordion-up 0.18s ease-out;
|
|
19
|
+
|
|
20
|
+
--color-brand-50: #f5f7ff;
|
|
21
|
+
--color-brand-100: #e6ebff;
|
|
22
|
+
--color-brand-500: #4f5af3;
|
|
23
|
+
--color-brand-600: #3b46d8;
|
|
24
|
+
--color-brand-700: #2c36b3;
|
|
25
|
+
--font-sans: ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
|
|
26
|
+
|
|
27
|
+
/* Semantic colors — bound to the `:root`/`.dark` HSL variables below.
|
|
28
|
+
Exposing them via @theme makes `bg-background`, `text-foreground`,
|
|
29
|
+
`border-border`, `bg-primary` work as utilities. */
|
|
30
|
+
--color-background: hsl(var(--background));
|
|
31
|
+
--color-foreground: hsl(var(--foreground));
|
|
32
|
+
--color-muted: hsl(var(--muted));
|
|
33
|
+
--color-muted-foreground: hsl(var(--muted-foreground));
|
|
34
|
+
--color-card: hsl(var(--card));
|
|
35
|
+
--color-card-foreground: hsl(var(--card-foreground));
|
|
36
|
+
--color-popover: hsl(var(--popover, var(--card)));
|
|
37
|
+
--color-popover-foreground: hsl(var(--popover-foreground, var(--card-foreground)));
|
|
38
|
+
--color-border: hsl(var(--border));
|
|
39
|
+
--color-input: hsl(var(--input));
|
|
40
|
+
--color-ring: hsl(var(--ring));
|
|
41
|
+
--color-primary: hsl(var(--primary));
|
|
42
|
+
--color-primary-foreground: hsl(var(--primary-foreground));
|
|
43
|
+
--color-secondary: hsl(var(--secondary));
|
|
44
|
+
--color-secondary-foreground: hsl(var(--secondary-foreground));
|
|
45
|
+
--color-accent: hsl(var(--accent, var(--secondary)));
|
|
46
|
+
--color-accent-foreground: hsl(var(--accent-foreground, var(--secondary-foreground)));
|
|
47
|
+
--color-destructive: hsl(var(--destructive));
|
|
48
|
+
--color-destructive-foreground: hsl(var(--destructive-foreground));
|
|
49
|
+
|
|
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
|
+
}
|
|
55
|
+
|
|
56
|
+
/* shadcn-flavoured semantic tokens. Light theme is the default; the
|
|
57
|
+
`.dark` class flips them. Apps can override any variable for custom
|
|
58
|
+
themes — see packages/ui/themes for ready-made sets. */
|
|
59
|
+
:root {
|
|
60
|
+
--background: 0 0% 100%;
|
|
61
|
+
--foreground: 222 47% 11%;
|
|
62
|
+
--muted: 210 40% 96%;
|
|
63
|
+
--muted-foreground: 215 16% 47%;
|
|
64
|
+
--card: 0 0% 100%;
|
|
65
|
+
--card-foreground: 222 47% 11%;
|
|
66
|
+
--popover: 0 0% 100%;
|
|
67
|
+
--popover-foreground: 222 47% 11%;
|
|
68
|
+
--border: 214 32% 91%;
|
|
69
|
+
--input: 214 32% 91%;
|
|
70
|
+
--ring: 215 20% 65%;
|
|
71
|
+
--primary: 222 47% 11%;
|
|
72
|
+
--primary-foreground: 210 40% 98%;
|
|
73
|
+
--secondary: 210 40% 96%;
|
|
74
|
+
--secondary-foreground: 222 47% 11%;
|
|
75
|
+
--accent: 210 40% 96%;
|
|
76
|
+
--accent-foreground: 222 47% 11%;
|
|
77
|
+
--destructive: 0 84% 60%;
|
|
78
|
+
--destructive-foreground: 210 40% 98%;
|
|
79
|
+
--radius: 0.5rem;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
.dark {
|
|
83
|
+
/* Near-black neutrals. Very low saturation on a slight zinc hue so the
|
|
84
|
+
palette reads as black/charcoal instead of navy. */
|
|
85
|
+
--background: 240 5% 5%;
|
|
86
|
+
--foreground: 0 0% 98%;
|
|
87
|
+
--muted: 240 4% 14%;
|
|
88
|
+
--muted-foreground: 240 5% 65%;
|
|
89
|
+
--card: 240 5% 7%;
|
|
90
|
+
--card-foreground: 0 0% 98%;
|
|
91
|
+
--popover: 240 5% 7%;
|
|
92
|
+
--popover-foreground: 0 0% 98%;
|
|
93
|
+
--border: 240 4% 18%;
|
|
94
|
+
--input: 240 4% 12%;
|
|
95
|
+
--ring: 240 5% 42%;
|
|
96
|
+
--primary: 0 0% 98%;
|
|
97
|
+
--primary-foreground: 240 6% 10%;
|
|
98
|
+
--secondary: 240 4% 14%;
|
|
99
|
+
--secondary-foreground: 0 0% 98%;
|
|
100
|
+
--accent: 240 4% 14%;
|
|
101
|
+
--accent-foreground: 0 0% 98%;
|
|
102
|
+
--destructive: 0 62% 40%;
|
|
103
|
+
--destructive-foreground: 0 0% 98%;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
@keyframes accordion-down {
|
|
107
|
+
from { height: 0; }
|
|
108
|
+
to { height: var(--radix-accordion-content-height); }
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
@keyframes accordion-up {
|
|
112
|
+
from { height: var(--radix-accordion-content-height); }
|
|
113
|
+
to { height: 0; }
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
html, body, #root {
|
|
117
|
+
height: 100%;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
body {
|
|
121
|
+
font-family: var(--font-sans);
|
|
122
|
+
color: hsl(var(--foreground));
|
|
123
|
+
background: hsl(var(--background));
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/* ── Custom scrollbars ─────────────────────────────────────────────────────
|
|
127
|
+
Themed via the same semantic tokens as the rest of the UI so they adapt
|
|
128
|
+
to light/dark/custom themes automatically. Firefox uses `scrollbar-*`
|
|
129
|
+
props; WebKit/Blink uses `::-webkit-scrollbar*`.
|
|
130
|
+
|
|
131
|
+
Scoped to actually-scrollable containers (root, body, common overflow
|
|
132
|
+
utility classes, opt-in `[data-scroll]`, textarea/pre). The previous
|
|
133
|
+
`*` selector forced WebKit to allocate scrollbar slots on every element,
|
|
134
|
+
which produced tiny "dot" artifacts at the corners of small controls
|
|
135
|
+
(buttons, selects) during hover/transition repaints. Firefox is happy
|
|
136
|
+
with declaring `scrollbar-width` only on `html` — it propagates the
|
|
137
|
+
styling to descendants automatically. */
|
|
138
|
+
:where(
|
|
139
|
+
html,
|
|
140
|
+
body,
|
|
141
|
+
[data-scroll],
|
|
142
|
+
.overflow-auto,
|
|
143
|
+
.overflow-y-auto,
|
|
144
|
+
.overflow-x-auto,
|
|
145
|
+
.overflow-scroll,
|
|
146
|
+
pre,
|
|
147
|
+
textarea
|
|
148
|
+
) {
|
|
149
|
+
scrollbar-width: thin;
|
|
150
|
+
scrollbar-color: hsl(var(--border)) transparent;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
:where(
|
|
154
|
+
html,
|
|
155
|
+
body,
|
|
156
|
+
[data-scroll],
|
|
157
|
+
.overflow-auto,
|
|
158
|
+
.overflow-y-auto,
|
|
159
|
+
.overflow-x-auto,
|
|
160
|
+
.overflow-scroll,
|
|
161
|
+
pre,
|
|
162
|
+
textarea
|
|
163
|
+
)::-webkit-scrollbar {
|
|
164
|
+
width: 10px;
|
|
165
|
+
height: 10px;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
:where(
|
|
169
|
+
html,
|
|
170
|
+
body,
|
|
171
|
+
[data-scroll],
|
|
172
|
+
.overflow-auto,
|
|
173
|
+
.overflow-y-auto,
|
|
174
|
+
.overflow-x-auto,
|
|
175
|
+
.overflow-scroll,
|
|
176
|
+
pre,
|
|
177
|
+
textarea
|
|
178
|
+
)::-webkit-scrollbar-track {
|
|
179
|
+
background: transparent;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
:where(
|
|
183
|
+
html,
|
|
184
|
+
body,
|
|
185
|
+
[data-scroll],
|
|
186
|
+
.overflow-auto,
|
|
187
|
+
.overflow-y-auto,
|
|
188
|
+
.overflow-x-auto,
|
|
189
|
+
.overflow-scroll,
|
|
190
|
+
pre,
|
|
191
|
+
textarea
|
|
192
|
+
)::-webkit-scrollbar-thumb {
|
|
193
|
+
background-color: hsl(var(--border));
|
|
194
|
+
border: 2px solid transparent;
|
|
195
|
+
border-radius: 9999px;
|
|
196
|
+
background-clip: padding-box;
|
|
197
|
+
transition: background-color 150ms ease;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
:where(
|
|
201
|
+
html,
|
|
202
|
+
body,
|
|
203
|
+
[data-scroll],
|
|
204
|
+
.overflow-auto,
|
|
205
|
+
.overflow-y-auto,
|
|
206
|
+
.overflow-x-auto,
|
|
207
|
+
.overflow-scroll,
|
|
208
|
+
pre,
|
|
209
|
+
textarea
|
|
210
|
+
)::-webkit-scrollbar-thumb:hover {
|
|
211
|
+
background-color: hsl(var(--muted-foreground) / 0.6);
|
|
212
|
+
background-clip: padding-box;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
:where(
|
|
216
|
+
html,
|
|
217
|
+
body,
|
|
218
|
+
[data-scroll],
|
|
219
|
+
.overflow-auto,
|
|
220
|
+
.overflow-y-auto,
|
|
221
|
+
.overflow-x-auto,
|
|
222
|
+
.overflow-scroll,
|
|
223
|
+
pre,
|
|
224
|
+
textarea
|
|
225
|
+
)::-webkit-scrollbar-thumb:active {
|
|
226
|
+
background-color: hsl(var(--muted-foreground) / 0.85);
|
|
227
|
+
background-clip: padding-box;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
:where(
|
|
231
|
+
html,
|
|
232
|
+
body,
|
|
233
|
+
[data-scroll],
|
|
234
|
+
.overflow-auto,
|
|
235
|
+
.overflow-y-auto,
|
|
236
|
+
.overflow-x-auto,
|
|
237
|
+
.overflow-scroll,
|
|
238
|
+
pre,
|
|
239
|
+
textarea
|
|
240
|
+
)::-webkit-scrollbar-corner {
|
|
241
|
+
background: transparent;
|
|
242
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@modern-admin/ui",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "i18n-unaware shadcn/ui-style React component library used by @modern-admin/react.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "https://github.com/modern-admin/modern-admin.git",
|
|
10
|
+
"directory": "packages/ui"
|
|
11
|
+
},
|
|
12
|
+
"main": "./dist/index.js",
|
|
13
|
+
"types": "./dist/index.d.ts",
|
|
14
|
+
"exports": {
|
|
15
|
+
".": {
|
|
16
|
+
"types": "./dist/index.d.ts",
|
|
17
|
+
"default": "./dist/index.js"
|
|
18
|
+
},
|
|
19
|
+
"./styles.css": "./dist/styles.css"
|
|
20
|
+
},
|
|
21
|
+
"files": [
|
|
22
|
+
"dist",
|
|
23
|
+
"src"
|
|
24
|
+
],
|
|
25
|
+
"publishConfig": {
|
|
26
|
+
"registry": "https://registry.npmjs.org",
|
|
27
|
+
"access": "public",
|
|
28
|
+
"main": "./dist/index.js",
|
|
29
|
+
"types": "./dist/index.d.ts",
|
|
30
|
+
"exports": {
|
|
31
|
+
".": {
|
|
32
|
+
"types": "./dist/index.d.ts",
|
|
33
|
+
"default": "./dist/index.js"
|
|
34
|
+
},
|
|
35
|
+
"./styles.css": "./dist/styles.css"
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
"dependencies": {
|
|
39
|
+
"@radix-ui/react-accordion": "^1.2.12",
|
|
40
|
+
"@radix-ui/react-alert-dialog": "^1.1.15",
|
|
41
|
+
"@radix-ui/react-avatar": "^1.1.11",
|
|
42
|
+
"@radix-ui/react-checkbox": "^1.3.3",
|
|
43
|
+
"@radix-ui/react-dialog": "^1.1.15",
|
|
44
|
+
"@radix-ui/react-dropdown-menu": "^2.1.16",
|
|
45
|
+
"@radix-ui/react-label": "^2.1.8",
|
|
46
|
+
"@radix-ui/react-popover": "^1.1.15",
|
|
47
|
+
"@radix-ui/react-scroll-area": "^1.2.10",
|
|
48
|
+
"@radix-ui/react-select": "^2.2.6",
|
|
49
|
+
"@radix-ui/react-separator": "^1.1.8",
|
|
50
|
+
"@radix-ui/react-slot": "^1.2.4",
|
|
51
|
+
"@radix-ui/react-switch": "^1.2.6",
|
|
52
|
+
"@radix-ui/react-tabs": "^1.1.13",
|
|
53
|
+
"@radix-ui/react-tooltip": "^1.2.8",
|
|
54
|
+
"@tailwindcss/typography": "^0.5.19",
|
|
55
|
+
"@tiptap/pm": "^3.22.5",
|
|
56
|
+
"@tiptap/react": "^3.22.5",
|
|
57
|
+
"@tiptap/starter-kit": "^3.22.5",
|
|
58
|
+
"class-variance-authority": "^0.7.1",
|
|
59
|
+
"clsx": "^2.1.1",
|
|
60
|
+
"cmdk": "^1.1.1",
|
|
61
|
+
"date-fns": "^4.1.0",
|
|
62
|
+
"dompurify": "^3.4.2",
|
|
63
|
+
"lucide-react": "^1.14.0",
|
|
64
|
+
"marked": "^18.0.3",
|
|
65
|
+
"react-day-picker": "^9.14.0",
|
|
66
|
+
"react-hook-form": "^7.75.0",
|
|
67
|
+
"recharts": "^3.8.1",
|
|
68
|
+
"sonner": "^2.0.7",
|
|
69
|
+
"tailwind-merge": "^3.5.0",
|
|
70
|
+
"tiptap-markdown": "^0.9.0",
|
|
71
|
+
"tw-animate-css": "^1.4.0"
|
|
72
|
+
},
|
|
73
|
+
"devDependencies": {
|
|
74
|
+
"@modern-admin/tsconfig": "0.1.0",
|
|
75
|
+
"@types/bun": "^1.3.13",
|
|
76
|
+
"@types/react": "^19.2.14",
|
|
77
|
+
"@types/react-dom": "^19.2.3",
|
|
78
|
+
"tailwindcss": "^4.2.4",
|
|
79
|
+
"typescript": "^6.0.3"
|
|
80
|
+
},
|
|
81
|
+
"peerDependencies": {
|
|
82
|
+
"react": "^19.2.6",
|
|
83
|
+
"react-dom": "^19.2.6"
|
|
84
|
+
}
|
|
85
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import * as AccordionPrimitive from '@radix-ui/react-accordion'
|
|
2
|
+
import { ChevronDown } from 'lucide-react'
|
|
3
|
+
import * as React from 'react'
|
|
4
|
+
import { cn } from '../lib/utils.js'
|
|
5
|
+
|
|
6
|
+
export const Accordion = AccordionPrimitive.Root
|
|
7
|
+
|
|
8
|
+
export const AccordionItem = React.forwardRef<
|
|
9
|
+
React.ElementRef<typeof AccordionPrimitive.Item>,
|
|
10
|
+
React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Item>
|
|
11
|
+
>(({ className, ...props }, ref) => (
|
|
12
|
+
<AccordionPrimitive.Item ref={ref} className={cn('border-b border-border', className)} {...props} />
|
|
13
|
+
))
|
|
14
|
+
AccordionItem.displayName = 'AccordionItem'
|
|
15
|
+
|
|
16
|
+
export const AccordionTrigger = React.forwardRef<
|
|
17
|
+
React.ElementRef<typeof AccordionPrimitive.Trigger>,
|
|
18
|
+
React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Trigger>
|
|
19
|
+
>(({ className, children, ...props }, ref) => (
|
|
20
|
+
<AccordionPrimitive.Header className="flex">
|
|
21
|
+
<AccordionPrimitive.Trigger
|
|
22
|
+
ref={ref}
|
|
23
|
+
className={cn(
|
|
24
|
+
'flex flex-1 cursor-pointer items-center justify-between py-1.5 text-xs font-semibold uppercase tracking-wide text-muted-foreground transition-all hover:text-foreground [&[data-state=open]>svg]:rotate-180',
|
|
25
|
+
className,
|
|
26
|
+
)}
|
|
27
|
+
{...props}
|
|
28
|
+
>
|
|
29
|
+
{children}
|
|
30
|
+
<ChevronDown className="size-3.5 shrink-0 transition-transform duration-200" />
|
|
31
|
+
</AccordionPrimitive.Trigger>
|
|
32
|
+
</AccordionPrimitive.Header>
|
|
33
|
+
))
|
|
34
|
+
AccordionTrigger.displayName = AccordionPrimitive.Trigger.displayName
|
|
35
|
+
|
|
36
|
+
export const AccordionContent = React.forwardRef<
|
|
37
|
+
React.ElementRef<typeof AccordionPrimitive.Content>,
|
|
38
|
+
React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Content>
|
|
39
|
+
>(({ className, children, ...props }, ref) => (
|
|
40
|
+
<AccordionPrimitive.Content
|
|
41
|
+
ref={ref}
|
|
42
|
+
className="overflow-hidden data-[state=closed]:animate-accordion-up data-[state=open]:animate-accordion-down"
|
|
43
|
+
{...props}
|
|
44
|
+
>
|
|
45
|
+
<div className={cn('pt-0.5 pb-1', className)}>{children}</div>
|
|
46
|
+
</AccordionPrimitive.Content>
|
|
47
|
+
))
|
|
48
|
+
AccordionContent.displayName = AccordionPrimitive.Content.displayName
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import * as React from 'react'
|
|
2
|
+
import * as AlertDialogPrimitive from '@radix-ui/react-alert-dialog'
|
|
3
|
+
import { buttonVariants } from './button.js'
|
|
4
|
+
import { cn } from '../lib/utils.js'
|
|
5
|
+
|
|
6
|
+
export const AlertDialog = AlertDialogPrimitive.Root
|
|
7
|
+
export const AlertDialogTrigger = AlertDialogPrimitive.Trigger
|
|
8
|
+
export const AlertDialogPortal = AlertDialogPrimitive.Portal
|
|
9
|
+
|
|
10
|
+
export const AlertDialogOverlay = React.forwardRef<
|
|
11
|
+
React.ElementRef<typeof AlertDialogPrimitive.Overlay>,
|
|
12
|
+
React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Overlay>
|
|
13
|
+
>(({ className, ...props }, ref) => (
|
|
14
|
+
<AlertDialogPrimitive.Overlay
|
|
15
|
+
ref={ref}
|
|
16
|
+
className={cn(
|
|
17
|
+
'fixed inset-0 z-50 bg-black/60 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0',
|
|
18
|
+
className,
|
|
19
|
+
)}
|
|
20
|
+
{...props}
|
|
21
|
+
/>
|
|
22
|
+
))
|
|
23
|
+
AlertDialogOverlay.displayName = AlertDialogPrimitive.Overlay.displayName
|
|
24
|
+
|
|
25
|
+
export const AlertDialogContent = React.forwardRef<
|
|
26
|
+
React.ElementRef<typeof AlertDialogPrimitive.Content>,
|
|
27
|
+
React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Content>
|
|
28
|
+
>(({ className, ...props }, ref) => (
|
|
29
|
+
<AlertDialogPortal>
|
|
30
|
+
<AlertDialogOverlay />
|
|
31
|
+
<AlertDialogPrimitive.Content
|
|
32
|
+
ref={ref}
|
|
33
|
+
className={cn(
|
|
34
|
+
'fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border border-border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 sm:rounded-lg',
|
|
35
|
+
className,
|
|
36
|
+
)}
|
|
37
|
+
{...props}
|
|
38
|
+
/>
|
|
39
|
+
</AlertDialogPortal>
|
|
40
|
+
))
|
|
41
|
+
AlertDialogContent.displayName = AlertDialogPrimitive.Content.displayName
|
|
42
|
+
|
|
43
|
+
export const AlertDialogHeader = ({
|
|
44
|
+
className,
|
|
45
|
+
...props
|
|
46
|
+
}: React.HTMLAttributes<HTMLDivElement>): React.ReactElement => (
|
|
47
|
+
<div
|
|
48
|
+
className={cn('flex flex-col gap-2 text-center sm:text-left', className)}
|
|
49
|
+
{...props}
|
|
50
|
+
/>
|
|
51
|
+
)
|
|
52
|
+
AlertDialogHeader.displayName = 'AlertDialogHeader'
|
|
53
|
+
|
|
54
|
+
export const AlertDialogFooter = ({
|
|
55
|
+
className,
|
|
56
|
+
...props
|
|
57
|
+
}: React.HTMLAttributes<HTMLDivElement>): React.ReactElement => (
|
|
58
|
+
<div
|
|
59
|
+
className={cn('flex flex-col-reverse sm:flex-row sm:justify-end sm:gap-2', className)}
|
|
60
|
+
{...props}
|
|
61
|
+
/>
|
|
62
|
+
)
|
|
63
|
+
AlertDialogFooter.displayName = 'AlertDialogFooter'
|
|
64
|
+
|
|
65
|
+
export const AlertDialogTitle = React.forwardRef<
|
|
66
|
+
React.ElementRef<typeof AlertDialogPrimitive.Title>,
|
|
67
|
+
React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Title>
|
|
68
|
+
>(({ className, ...props }, ref) => (
|
|
69
|
+
<AlertDialogPrimitive.Title
|
|
70
|
+
ref={ref}
|
|
71
|
+
className={cn('text-lg font-semibold', className)}
|
|
72
|
+
{...props}
|
|
73
|
+
/>
|
|
74
|
+
))
|
|
75
|
+
AlertDialogTitle.displayName = AlertDialogPrimitive.Title.displayName
|
|
76
|
+
|
|
77
|
+
export const AlertDialogDescription = React.forwardRef<
|
|
78
|
+
React.ElementRef<typeof AlertDialogPrimitive.Description>,
|
|
79
|
+
React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Description>
|
|
80
|
+
>(({ className, ...props }, ref) => (
|
|
81
|
+
<AlertDialogPrimitive.Description
|
|
82
|
+
ref={ref}
|
|
83
|
+
className={cn('text-sm text-muted-foreground', className)}
|
|
84
|
+
{...props}
|
|
85
|
+
/>
|
|
86
|
+
))
|
|
87
|
+
AlertDialogDescription.displayName = AlertDialogPrimitive.Description.displayName
|
|
88
|
+
|
|
89
|
+
export const AlertDialogAction = React.forwardRef<
|
|
90
|
+
React.ElementRef<typeof AlertDialogPrimitive.Action>,
|
|
91
|
+
React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Action> & {
|
|
92
|
+
variant?: 'default' | 'destructive'
|
|
93
|
+
}
|
|
94
|
+
>(({ className, variant = 'default', ...props }, ref) => (
|
|
95
|
+
<AlertDialogPrimitive.Action
|
|
96
|
+
ref={ref}
|
|
97
|
+
className={cn(buttonVariants({ variant }), className)}
|
|
98
|
+
{...props}
|
|
99
|
+
/>
|
|
100
|
+
))
|
|
101
|
+
AlertDialogAction.displayName = AlertDialogPrimitive.Action.displayName
|
|
102
|
+
|
|
103
|
+
export const AlertDialogCancel = React.forwardRef<
|
|
104
|
+
React.ElementRef<typeof AlertDialogPrimitive.Cancel>,
|
|
105
|
+
React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Cancel>
|
|
106
|
+
>(({ className, ...props }, ref) => (
|
|
107
|
+
<AlertDialogPrimitive.Cancel
|
|
108
|
+
ref={ref}
|
|
109
|
+
className={cn(buttonVariants({ variant: 'outline' }), 'mt-2 sm:mt-0', className)}
|
|
110
|
+
{...props}
|
|
111
|
+
/>
|
|
112
|
+
))
|
|
113
|
+
AlertDialogCancel.displayName = AlertDialogPrimitive.Cancel.displayName
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import * as React from 'react'
|
|
2
|
+
import { cn } from '../lib/utils.js'
|
|
3
|
+
|
|
4
|
+
export interface AuditTimelineItem {
|
|
5
|
+
/** Stable id for React reconciliation; falls back to `at + index`. */
|
|
6
|
+
id?: string
|
|
7
|
+
resourceId: string
|
|
8
|
+
action: string
|
|
9
|
+
recordId?: string
|
|
10
|
+
recordIds?: string[]
|
|
11
|
+
userId?: string
|
|
12
|
+
at: number
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export interface AuditTimelineLabels {
|
|
16
|
+
unknownUser?: string
|
|
17
|
+
noEvents?: string
|
|
18
|
+
records?: string
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export interface AuditTimelineProps {
|
|
22
|
+
items: ReadonlyArray<AuditTimelineItem>
|
|
23
|
+
labels?: AuditTimelineLabels
|
|
24
|
+
className?: string
|
|
25
|
+
formatDate?: (value: number) => string
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const DEFAULT_LABELS: Required<AuditTimelineLabels> = {
|
|
29
|
+
unknownUser: 'Unknown user',
|
|
30
|
+
noEvents: 'No events',
|
|
31
|
+
records: 'records',
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export function AuditTimeline({
|
|
35
|
+
items,
|
|
36
|
+
labels,
|
|
37
|
+
className,
|
|
38
|
+
formatDate = (v) => new Date(v).toISOString(),
|
|
39
|
+
}: AuditTimelineProps): React.ReactElement {
|
|
40
|
+
const l = { ...DEFAULT_LABELS, ...labels }
|
|
41
|
+
if (items.length === 0) {
|
|
42
|
+
return (
|
|
43
|
+
<div className={cn('rounded-md border border-dashed p-6 text-center text-sm text-muted-foreground', className)}>
|
|
44
|
+
{l.noEvents}
|
|
45
|
+
</div>
|
|
46
|
+
)
|
|
47
|
+
}
|
|
48
|
+
return (
|
|
49
|
+
<ol className={cn('relative space-y-3', className)}>
|
|
50
|
+
{items.map((item, index) => (
|
|
51
|
+
<li key={item.id ?? `${item.at}:${index}`} className="relative rounded-lg border bg-card p-4 shadow-sm">
|
|
52
|
+
<div className="flex flex-wrap items-start justify-between gap-3">
|
|
53
|
+
<div className="flex min-w-0 items-start gap-3">
|
|
54
|
+
<span className="flex size-9 shrink-0 items-center justify-center rounded-full bg-primary/10 text-xs font-semibold text-primary">
|
|
55
|
+
{initials(item.userId ?? l.unknownUser)}
|
|
56
|
+
</span>
|
|
57
|
+
<div className="min-w-0 space-y-1">
|
|
58
|
+
<p className="truncate text-sm font-medium">
|
|
59
|
+
{item.userId ?? l.unknownUser}
|
|
60
|
+
</p>
|
|
61
|
+
<p className="flex flex-wrap items-center gap-2 text-sm text-muted-foreground">
|
|
62
|
+
<ActionChip action={item.action} />
|
|
63
|
+
<span className="rounded-full border bg-muted px-2 py-0.5 text-xs">
|
|
64
|
+
{item.resourceId}
|
|
65
|
+
</span>
|
|
66
|
+
{item.recordId && (
|
|
67
|
+
<code className="rounded bg-muted px-1.5 py-0.5 text-xs">
|
|
68
|
+
#{item.recordId}
|
|
69
|
+
</code>
|
|
70
|
+
)}
|
|
71
|
+
{!item.recordId && item.recordIds?.length ? (
|
|
72
|
+
<span className="text-xs">
|
|
73
|
+
{item.recordIds.length} {l.records}
|
|
74
|
+
</span>
|
|
75
|
+
) : null}
|
|
76
|
+
</p>
|
|
77
|
+
</div>
|
|
78
|
+
</div>
|
|
79
|
+
<time className="shrink-0 text-xs text-muted-foreground">
|
|
80
|
+
{formatDate(item.at)}
|
|
81
|
+
</time>
|
|
82
|
+
</div>
|
|
83
|
+
</li>
|
|
84
|
+
))}
|
|
85
|
+
</ol>
|
|
86
|
+
)
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function ActionChip({ action }: { action: string }): React.ReactElement {
|
|
90
|
+
return (
|
|
91
|
+
<span className="rounded-full border border-primary/20 bg-primary/10 px-2 py-0.5 text-xs font-medium text-primary">
|
|
92
|
+
{action}
|
|
93
|
+
</span>
|
|
94
|
+
)
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function initials(value: string): string {
|
|
98
|
+
const parts = value.split(/\s+|[._@-]/).filter(Boolean)
|
|
99
|
+
if (parts.length === 0) return '?'
|
|
100
|
+
if (parts.length === 1) return parts[0]!.slice(0, 2).toUpperCase()
|
|
101
|
+
return (parts[0]![0]! + parts[1]![0]!).toUpperCase()
|
|
102
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import * as React from 'react'
|
|
2
|
+
import * as AvatarPrimitive from '@radix-ui/react-avatar'
|
|
3
|
+
import { cn } from '../lib/utils.js'
|
|
4
|
+
|
|
5
|
+
export const Avatar = React.forwardRef<
|
|
6
|
+
React.ElementRef<typeof AvatarPrimitive.Root>,
|
|
7
|
+
React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Root>
|
|
8
|
+
>(({ className, ...props }, ref) => (
|
|
9
|
+
<AvatarPrimitive.Root
|
|
10
|
+
ref={ref}
|
|
11
|
+
className={cn('relative flex h-9 w-9 shrink-0 overflow-hidden rounded-full', className)}
|
|
12
|
+
{...props}
|
|
13
|
+
/>
|
|
14
|
+
))
|
|
15
|
+
Avatar.displayName = AvatarPrimitive.Root.displayName
|
|
16
|
+
|
|
17
|
+
export const AvatarImage = React.forwardRef<
|
|
18
|
+
React.ElementRef<typeof AvatarPrimitive.Image>,
|
|
19
|
+
React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Image>
|
|
20
|
+
>(({ className, ...props }, ref) => (
|
|
21
|
+
<AvatarPrimitive.Image
|
|
22
|
+
ref={ref}
|
|
23
|
+
className={cn('aspect-square h-full w-full', className)}
|
|
24
|
+
{...props}
|
|
25
|
+
/>
|
|
26
|
+
))
|
|
27
|
+
AvatarImage.displayName = AvatarPrimitive.Image.displayName
|
|
28
|
+
|
|
29
|
+
export const AvatarFallback = React.forwardRef<
|
|
30
|
+
React.ElementRef<typeof AvatarPrimitive.Fallback>,
|
|
31
|
+
React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Fallback>
|
|
32
|
+
>(({ className, ...props }, ref) => (
|
|
33
|
+
<AvatarPrimitive.Fallback
|
|
34
|
+
ref={ref}
|
|
35
|
+
className={cn(
|
|
36
|
+
'flex h-full w-full items-center justify-center rounded-full bg-muted text-sm font-medium text-muted-foreground',
|
|
37
|
+
className,
|
|
38
|
+
)}
|
|
39
|
+
{...props}
|
|
40
|
+
/>
|
|
41
|
+
))
|
|
42
|
+
AvatarFallback.displayName = AvatarPrimitive.Fallback.displayName
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import * as React from 'react'
|
|
2
|
+
import { cva, type VariantProps } from 'class-variance-authority'
|
|
3
|
+
import { cn } from '../lib/utils.js'
|
|
4
|
+
|
|
5
|
+
const badgeVariants = cva(
|
|
6
|
+
'inline-flex items-center rounded-full border border-border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2',
|
|
7
|
+
{
|
|
8
|
+
variants: {
|
|
9
|
+
variant: {
|
|
10
|
+
default: 'border-transparent bg-primary text-primary-foreground hover:bg-primary/80',
|
|
11
|
+
secondary:
|
|
12
|
+
'border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80',
|
|
13
|
+
destructive:
|
|
14
|
+
'border-transparent bg-destructive text-destructive-foreground hover:bg-destructive/80',
|
|
15
|
+
outline: 'text-foreground',
|
|
16
|
+
success: 'border-transparent bg-emerald-100 text-emerald-700 dark:bg-emerald-900/40 dark:text-emerald-300',
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
defaultVariants: { variant: 'default' },
|
|
20
|
+
},
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
export interface BadgeProps
|
|
24
|
+
extends React.HTMLAttributes<HTMLSpanElement>,
|
|
25
|
+
VariantProps<typeof badgeVariants> {}
|
|
26
|
+
|
|
27
|
+
export const Badge = React.forwardRef<HTMLSpanElement, BadgeProps>(
|
|
28
|
+
({ className, variant, ...props }, ref) => (
|
|
29
|
+
<span ref={ref} className={cn(badgeVariants({ variant }), className)} {...props} />
|
|
30
|
+
),
|
|
31
|
+
)
|
|
32
|
+
Badge.displayName = 'Badge'
|
|
33
|
+
|
|
34
|
+
export { badgeVariants }
|