@7onic-ui/react 0.3.9 → 0.3.10
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 +2 -2
- package/dist/chart.mjs +3 -9
- package/dist/chart.mjs.map +1 -1
- package/dist/chunk-234NAXGV.mjs +252 -0
- package/dist/chunk-234NAXGV.mjs.map +1 -0
- package/dist/chunk-53MIUPSY.mjs +13 -0
- package/dist/chunk-53MIUPSY.mjs.map +1 -0
- package/dist/chunk-BN5BEA3V.mjs +195 -0
- package/dist/chunk-BN5BEA3V.mjs.map +1 -0
- package/dist/chunk-COW3B62M.mjs +214 -0
- package/dist/chunk-COW3B62M.mjs.map +1 -0
- package/dist/chunk-CTH6SN5Y.mjs +114 -0
- package/dist/chunk-CTH6SN5Y.mjs.map +1 -0
- package/dist/chunk-D3NTQNDW.mjs +440 -0
- package/dist/chunk-D3NTQNDW.mjs.map +1 -0
- package/dist/chunk-DDRYEJBJ.mjs +164 -0
- package/dist/chunk-DDRYEJBJ.mjs.map +1 -0
- package/dist/chunk-DJAEXCRU.mjs +190 -0
- package/dist/chunk-DJAEXCRU.mjs.map +1 -0
- package/dist/chunk-DRVHHEAY.mjs +145 -0
- package/dist/chunk-DRVHHEAY.mjs.map +1 -0
- package/dist/chunk-DTLNWOTR.mjs +482 -0
- package/dist/chunk-DTLNWOTR.mjs.map +1 -0
- package/dist/chunk-DYYQOHQR.mjs +214 -0
- package/dist/chunk-DYYQOHQR.mjs.map +1 -0
- package/dist/chunk-FHUAH6AJ.mjs +93 -0
- package/dist/chunk-FHUAH6AJ.mjs.map +1 -0
- package/dist/chunk-GD4YE5AE.mjs +209 -0
- package/dist/chunk-GD4YE5AE.mjs.map +1 -0
- package/dist/chunk-GRCJ35DX.mjs +144 -0
- package/dist/chunk-GRCJ35DX.mjs.map +1 -0
- package/dist/chunk-HHX4GABH.mjs +129 -0
- package/dist/chunk-HHX4GABH.mjs.map +1 -0
- package/dist/chunk-IPCIC2BI.mjs +148 -0
- package/dist/chunk-IPCIC2BI.mjs.map +1 -0
- package/dist/chunk-IY3R2VGB.mjs +272 -0
- package/dist/chunk-IY3R2VGB.mjs.map +1 -0
- package/dist/chunk-JCJEVXER.mjs +170 -0
- package/dist/chunk-JCJEVXER.mjs.map +1 -0
- package/dist/chunk-KBPYAMGS.mjs +157 -0
- package/dist/chunk-KBPYAMGS.mjs.map +1 -0
- package/dist/chunk-LJJ6K4IU.mjs +318 -0
- package/dist/chunk-LJJ6K4IU.mjs.map +1 -0
- package/dist/chunk-MRUVGHGP.mjs +375 -0
- package/dist/chunk-MRUVGHGP.mjs.map +1 -0
- package/dist/chunk-N4K2BDGM.mjs +153 -0
- package/dist/chunk-N4K2BDGM.mjs.map +1 -0
- package/dist/chunk-NWFMJWGX.mjs +165 -0
- package/dist/chunk-NWFMJWGX.mjs.map +1 -0
- package/dist/chunk-PTAPPOKU.mjs +117 -0
- package/dist/chunk-PTAPPOKU.mjs.map +1 -0
- package/dist/chunk-PVTBM7V7.mjs +316 -0
- package/dist/chunk-PVTBM7V7.mjs.map +1 -0
- package/dist/chunk-Q5WVLK2L.mjs +77 -0
- package/dist/chunk-Q5WVLK2L.mjs.map +1 -0
- package/dist/chunk-RKSB2N5L.mjs +206 -0
- package/dist/chunk-RKSB2N5L.mjs.map +1 -0
- package/dist/chunk-S4DGVKBK.mjs +151 -0
- package/dist/chunk-S4DGVKBK.mjs.map +1 -0
- package/dist/chunk-S4T4PU7F.mjs +114 -0
- package/dist/chunk-S4T4PU7F.mjs.map +1 -0
- package/dist/chunk-SZPZOGPC.mjs +394 -0
- package/dist/chunk-SZPZOGPC.mjs.map +1 -0
- package/dist/chunk-T546XBQG.mjs +443 -0
- package/dist/chunk-T546XBQG.mjs.map +1 -0
- package/dist/chunk-UWTT5AE6.mjs +145 -0
- package/dist/chunk-UWTT5AE6.mjs.map +1 -0
- package/dist/chunk-V5UFWYFI.mjs +255 -0
- package/dist/chunk-V5UFWYFI.mjs.map +1 -0
- package/dist/chunk-VUPGBB5X.mjs +150 -0
- package/dist/chunk-VUPGBB5X.mjs.map +1 -0
- package/dist/chunk-W6YNEU53.mjs +175 -0
- package/dist/chunk-W6YNEU53.mjs.map +1 -0
- package/dist/chunk-WWSN5YME.mjs +222 -0
- package/dist/chunk-WWSN5YME.mjs.map +1 -0
- package/dist/chunk-XK52LYR4.mjs +182 -0
- package/dist/chunk-XK52LYR4.mjs.map +1 -0
- package/dist/chunk-YIAH6KHV.mjs +164 -0
- package/dist/chunk-YIAH6KHV.mjs.map +1 -0
- package/dist/chunk-Z6JWWCNL.mjs +108 -0
- package/dist/chunk-Z6JWWCNL.mjs.map +1 -0
- package/dist/chunk-ZDRUTJ4T.mjs +119 -0
- package/dist/chunk-ZDRUTJ4T.mjs.map +1 -0
- package/dist/components/accordion.mjs +19 -0
- package/dist/components/accordion.mjs.map +1 -0
- package/dist/components/alert.mjs +15 -0
- package/dist/components/alert.mjs.map +1 -0
- package/dist/components/avatar.mjs +23 -0
- package/dist/components/avatar.mjs.map +1 -0
- package/dist/components/badge.mjs +11 -0
- package/dist/components/badge.mjs.map +1 -0
- package/dist/components/breadcrumb.mjs +23 -0
- package/dist/components/breadcrumb.mjs.map +1 -0
- package/dist/components/button-group.mjs +11 -0
- package/dist/components/button-group.mjs.map +1 -0
- package/dist/components/button.mjs +12 -0
- package/dist/components/button.mjs.map +1 -0
- package/dist/components/card.mjs +25 -0
- package/dist/components/card.mjs.map +1 -0
- package/dist/components/chat-input.mjs +15 -0
- package/dist/components/chat-input.mjs.map +1 -0
- package/dist/components/chat-message.mjs +17 -0
- package/dist/components/chat-message.mjs.map +1 -0
- package/dist/components/checkbox.mjs +12 -0
- package/dist/components/checkbox.mjs.map +1 -0
- package/dist/components/divider.mjs +11 -0
- package/dist/components/divider.mjs.map +1 -0
- package/dist/components/drawer.mjs +33 -0
- package/dist/components/drawer.mjs.map +1 -0
- package/dist/components/dropdown.mjs +35 -0
- package/dist/components/dropdown.mjs.map +1 -0
- package/dist/components/field.mjs +17 -0
- package/dist/components/field.mjs.map +1 -0
- package/dist/components/icon-button.mjs +12 -0
- package/dist/components/icon-button.mjs.map +1 -0
- package/dist/components/input.mjs +12 -0
- package/dist/components/input.mjs.map +1 -0
- package/dist/components/metric-card.mjs +23 -0
- package/dist/components/metric-card.mjs.map +1 -0
- package/dist/components/modal.mjs +57 -0
- package/dist/components/modal.mjs.map +1 -0
- package/dist/components/navigation-menu.mjs +27 -0
- package/dist/components/navigation-menu.mjs.map +1 -0
- package/dist/components/pagination.mjs +33 -0
- package/dist/components/pagination.mjs.map +1 -0
- package/dist/components/popover.mjs +23 -0
- package/dist/components/popover.mjs.map +1 -0
- package/dist/components/progress.mjs +11 -0
- package/dist/components/progress.mjs.map +1 -0
- package/dist/components/quick-reply.mjs +15 -0
- package/dist/components/quick-reply.mjs.map +1 -0
- package/dist/components/radio-group.mjs +16 -0
- package/dist/components/radio-group.mjs.map +1 -0
- package/dist/components/segmented.mjs +15 -0
- package/dist/components/segmented.mjs.map +1 -0
- package/dist/components/select.mjs +23 -0
- package/dist/components/select.mjs.map +1 -0
- package/dist/components/skeleton.mjs +11 -0
- package/dist/components/skeleton.mjs.map +1 -0
- package/dist/components/slider.mjs +11 -0
- package/dist/components/slider.mjs.map +1 -0
- package/dist/components/spinner.mjs +11 -0
- package/dist/components/spinner.mjs.map +1 -0
- package/dist/components/switch.mjs +12 -0
- package/dist/components/switch.mjs.map +1 -0
- package/dist/components/table.mjs +23 -0
- package/dist/components/table.mjs.map +1 -0
- package/dist/components/tabs.mjs +19 -0
- package/dist/components/tabs.mjs.map +1 -0
- package/dist/components/textarea.mjs +12 -0
- package/dist/components/textarea.mjs.map +1 -0
- package/dist/components/toast.mjs +13 -0
- package/dist/components/toast.mjs.map +1 -0
- package/dist/components/toggle-group.mjs +15 -0
- package/dist/components/toggle-group.mjs.map +1 -0
- package/dist/components/toggle.mjs +11 -0
- package/dist/components/toggle.mjs.map +1 -0
- package/dist/components/tooltip.mjs +21 -0
- package/dist/components/tooltip.mjs.map +1 -0
- package/dist/components/typing-indicator.mjs +11 -0
- package/dist/components/typing-indicator.mjs.map +1 -0
- package/dist/index.mjs +296 -7536
- package/dist/index.mjs.map +1 -1
- package/llms.txt +23 -23
- package/package.json +4 -3
- package/dist/chart.d.mts +0 -147
- package/dist/index.d.mts +0 -1535
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import {
|
|
3
|
+
cn
|
|
4
|
+
} from "./chunk-53MIUPSY.mjs";
|
|
5
|
+
|
|
6
|
+
// src/components/ui/metric-card.tsx
|
|
7
|
+
import * as React from "react";
|
|
8
|
+
import { cva } from "class-variance-authority";
|
|
9
|
+
var metricCardVariants = cva(
|
|
10
|
+
"transition-colors",
|
|
11
|
+
{
|
|
12
|
+
variants: {
|
|
13
|
+
variant: {
|
|
14
|
+
default: "bg-background-paper border border-border",
|
|
15
|
+
elevated: "bg-background-paper shadow-md",
|
|
16
|
+
ghost: "bg-transparent"
|
|
17
|
+
},
|
|
18
|
+
size: {
|
|
19
|
+
sm: "p-4",
|
|
20
|
+
default: "p-4 sm:p-5",
|
|
21
|
+
lg: "p-4 sm:p-6"
|
|
22
|
+
},
|
|
23
|
+
radius: {
|
|
24
|
+
none: "rounded-none",
|
|
25
|
+
// 0px
|
|
26
|
+
sm: "rounded-sm",
|
|
27
|
+
// 2px
|
|
28
|
+
base: "rounded",
|
|
29
|
+
// 4px
|
|
30
|
+
default: "rounded-xl",
|
|
31
|
+
// 12px - card default
|
|
32
|
+
lg: "rounded-lg",
|
|
33
|
+
// 8px
|
|
34
|
+
xl: "rounded-xl",
|
|
35
|
+
// 12px
|
|
36
|
+
"2xl": "rounded-2xl",
|
|
37
|
+
// 16px
|
|
38
|
+
"3xl": "rounded-3xl",
|
|
39
|
+
// 24px
|
|
40
|
+
full: "rounded-full"
|
|
41
|
+
// 9999px
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
defaultVariants: { variant: "default", size: "default", radius: "default" }
|
|
45
|
+
}
|
|
46
|
+
);
|
|
47
|
+
var valueSizes = {
|
|
48
|
+
sm: "text-xl",
|
|
49
|
+
default: "text-2xl",
|
|
50
|
+
lg: "text-3xl"
|
|
51
|
+
};
|
|
52
|
+
var titleSizes = {
|
|
53
|
+
sm: "text-xs",
|
|
54
|
+
default: "text-sm",
|
|
55
|
+
lg: "text-sm"
|
|
56
|
+
};
|
|
57
|
+
var iconWrapperSizes = {
|
|
58
|
+
sm: "[&>svg]:icon-sm",
|
|
59
|
+
default: "[&>svg]:icon-md",
|
|
60
|
+
lg: "[&>svg]:icon-lg"
|
|
61
|
+
};
|
|
62
|
+
var trendConfig = {
|
|
63
|
+
up: { color: "text-text-success", srLabel: "Increased" },
|
|
64
|
+
down: { color: "text-text-error", srLabel: "Decreased" },
|
|
65
|
+
neutral: { color: "text-text-muted", srLabel: "No change" }
|
|
66
|
+
};
|
|
67
|
+
var MetricCardContext = React.createContext({ size: "default", animated: false });
|
|
68
|
+
var MetricCard = React.forwardRef(
|
|
69
|
+
({ className, variant, size, radius, animated = false, children, ...props }, ref) => {
|
|
70
|
+
const resolvedSize = size || "default";
|
|
71
|
+
return /* @__PURE__ */ React.createElement(MetricCardContext.Provider, { value: { size: resolvedSize, animated } }, /* @__PURE__ */ React.createElement(
|
|
72
|
+
"div",
|
|
73
|
+
{
|
|
74
|
+
ref,
|
|
75
|
+
className: cn(metricCardVariants({ variant, size, radius }), className),
|
|
76
|
+
...props
|
|
77
|
+
},
|
|
78
|
+
children
|
|
79
|
+
));
|
|
80
|
+
}
|
|
81
|
+
);
|
|
82
|
+
MetricCard.displayName = "MetricCard";
|
|
83
|
+
var MetricCardHeader = React.forwardRef(
|
|
84
|
+
({ className, ...props }, ref) => /* @__PURE__ */ React.createElement(
|
|
85
|
+
"div",
|
|
86
|
+
{
|
|
87
|
+
ref,
|
|
88
|
+
className: cn("flex items-center justify-between gap-2", className),
|
|
89
|
+
...props
|
|
90
|
+
}
|
|
91
|
+
)
|
|
92
|
+
);
|
|
93
|
+
MetricCardHeader.displayName = "MetricCardHeader";
|
|
94
|
+
var MetricCardTitle = React.forwardRef(
|
|
95
|
+
({ className, ...props }, ref) => {
|
|
96
|
+
const { size } = React.useContext(MetricCardContext);
|
|
97
|
+
return /* @__PURE__ */ React.createElement(
|
|
98
|
+
"p",
|
|
99
|
+
{
|
|
100
|
+
ref,
|
|
101
|
+
className: cn(titleSizes[size], "font-semibold text-text-muted", className),
|
|
102
|
+
...props
|
|
103
|
+
}
|
|
104
|
+
);
|
|
105
|
+
}
|
|
106
|
+
);
|
|
107
|
+
MetricCardTitle.displayName = "MetricCardTitle";
|
|
108
|
+
var MetricCardValue = React.forwardRef(
|
|
109
|
+
({ className, children, ...props }, ref) => {
|
|
110
|
+
const { size, animated } = React.useContext(MetricCardContext);
|
|
111
|
+
const [display, setDisplay] = React.useState(children);
|
|
112
|
+
React.useEffect(() => {
|
|
113
|
+
if (!animated || typeof children !== "string") {
|
|
114
|
+
setDisplay(children);
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
const numMatch = children.match(/[\d,.]+/);
|
|
118
|
+
if (!numMatch) {
|
|
119
|
+
setDisplay(children);
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
const numStr = numMatch[0].replace(/,/g, "");
|
|
123
|
+
const target = parseFloat(numStr);
|
|
124
|
+
if (isNaN(target)) {
|
|
125
|
+
setDisplay(children);
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
const prefix = children.slice(0, children.indexOf(numMatch[0]));
|
|
129
|
+
const suffix = children.slice(children.indexOf(numMatch[0]) + numMatch[0].length);
|
|
130
|
+
const steps = 24;
|
|
131
|
+
const duration = 700;
|
|
132
|
+
let step = 0;
|
|
133
|
+
setDisplay(prefix + "0" + suffix);
|
|
134
|
+
const timer = setInterval(() => {
|
|
135
|
+
step++;
|
|
136
|
+
const eased = 1 - Math.pow(1 - step / steps, 3);
|
|
137
|
+
const current = target * eased;
|
|
138
|
+
const formatted = target >= 1e3 ? Math.floor(current).toLocaleString() : current.toFixed(numStr.includes(".") ? 2 : 0);
|
|
139
|
+
setDisplay(prefix + formatted + suffix);
|
|
140
|
+
if (step >= steps) {
|
|
141
|
+
setDisplay(children);
|
|
142
|
+
clearInterval(timer);
|
|
143
|
+
}
|
|
144
|
+
}, duration / steps);
|
|
145
|
+
return () => clearInterval(timer);
|
|
146
|
+
}, [children, animated]);
|
|
147
|
+
return /* @__PURE__ */ React.createElement(
|
|
148
|
+
"p",
|
|
149
|
+
{
|
|
150
|
+
ref,
|
|
151
|
+
className: cn(valueSizes[size], "font-bold text-foreground mt-1", className),
|
|
152
|
+
...props
|
|
153
|
+
},
|
|
154
|
+
display
|
|
155
|
+
);
|
|
156
|
+
}
|
|
157
|
+
);
|
|
158
|
+
MetricCardValue.displayName = "MetricCardValue";
|
|
159
|
+
var MetricCardTrend = React.forwardRef(
|
|
160
|
+
({ className, direction, children, ...props }, ref) => {
|
|
161
|
+
const config = trendConfig[direction];
|
|
162
|
+
return /* @__PURE__ */ React.createElement(
|
|
163
|
+
"p",
|
|
164
|
+
{
|
|
165
|
+
ref,
|
|
166
|
+
className: cn("flex items-center gap-1 text-sm mt-2", config.color, className),
|
|
167
|
+
...props
|
|
168
|
+
},
|
|
169
|
+
direction === "up" && /* @__PURE__ */ React.createElement("svg", { className: "icon-xs", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 2.5, "aria-hidden": "true" }, /* @__PURE__ */ React.createElement("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M4.5 15.75l7.5-7.5 7.5 7.5" })),
|
|
170
|
+
direction === "down" && /* @__PURE__ */ React.createElement("svg", { className: "icon-xs", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 2.5, "aria-hidden": "true" }, /* @__PURE__ */ React.createElement("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M19.5 8.25l-7.5 7.5-7.5-7.5" })),
|
|
171
|
+
direction === "neutral" && /* @__PURE__ */ React.createElement("svg", { className: "icon-xs", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 2.5, "aria-hidden": "true" }, /* @__PURE__ */ React.createElement("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M5 12h14" })),
|
|
172
|
+
/* @__PURE__ */ React.createElement("span", { className: "sr-only" }, config.srLabel),
|
|
173
|
+
children
|
|
174
|
+
);
|
|
175
|
+
}
|
|
176
|
+
);
|
|
177
|
+
MetricCardTrend.displayName = "MetricCardTrend";
|
|
178
|
+
var MetricCardDescription = React.forwardRef(
|
|
179
|
+
({ className, ...props }, ref) => /* @__PURE__ */ React.createElement(
|
|
180
|
+
"p",
|
|
181
|
+
{
|
|
182
|
+
ref,
|
|
183
|
+
className: cn("text-xs text-text-muted mt-1", className),
|
|
184
|
+
...props
|
|
185
|
+
}
|
|
186
|
+
)
|
|
187
|
+
);
|
|
188
|
+
MetricCardDescription.displayName = "MetricCardDescription";
|
|
189
|
+
var MetricCardSymbol = React.forwardRef(
|
|
190
|
+
({ className, ...props }, ref) => {
|
|
191
|
+
const { size } = React.useContext(MetricCardContext);
|
|
192
|
+
return /* @__PURE__ */ React.createElement(
|
|
193
|
+
"div",
|
|
194
|
+
{
|
|
195
|
+
ref,
|
|
196
|
+
className: cn("text-text-muted", iconWrapperSizes[size], className),
|
|
197
|
+
...props
|
|
198
|
+
}
|
|
199
|
+
);
|
|
200
|
+
}
|
|
201
|
+
);
|
|
202
|
+
MetricCardSymbol.displayName = "MetricCardSymbol";
|
|
203
|
+
|
|
204
|
+
export {
|
|
205
|
+
metricCardVariants,
|
|
206
|
+
MetricCard,
|
|
207
|
+
MetricCardHeader,
|
|
208
|
+
MetricCardTitle,
|
|
209
|
+
MetricCardValue,
|
|
210
|
+
MetricCardTrend,
|
|
211
|
+
MetricCardDescription,
|
|
212
|
+
MetricCardSymbol
|
|
213
|
+
};
|
|
214
|
+
//# sourceMappingURL=chunk-DYYQOHQR.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/ui/metric-card.tsx"],"sourcesContent":["'use client'\n\nimport * as React from 'react'\nimport { cva, type VariantProps } from 'class-variance-authority'\nimport { cn } from '@/lib/utils'\n\n// ── CVA Variants ──\n\nconst metricCardVariants = cva(\n 'transition-colors',\n {\n variants: {\n variant: {\n default: 'bg-background-paper border border-border',\n elevated: 'bg-background-paper shadow-md',\n ghost: 'bg-transparent',\n },\n size: {\n sm: 'p-4',\n default: 'p-4 sm:p-5',\n lg: 'p-4 sm:p-6',\n },\n radius: {\n none: 'rounded-none', // 0px\n sm: 'rounded-sm', // 2px\n base: 'rounded', // 4px\n default: 'rounded-xl', // 12px - card default\n lg: 'rounded-lg', // 8px\n xl: 'rounded-xl', // 12px\n '2xl': 'rounded-2xl', // 16px\n '3xl': 'rounded-3xl', // 24px\n full: 'rounded-full', // 9999px\n },\n },\n defaultVariants: { variant: 'default', size: 'default', radius: 'default' },\n }\n)\n\n// ── Size maps ──\n\nconst valueSizes = {\n sm: 'text-xl',\n default: 'text-2xl',\n lg: 'text-3xl',\n} as const\n\nconst titleSizes = {\n sm: 'text-xs',\n default: 'text-sm',\n lg: 'text-sm',\n} as const\n\nconst iconWrapperSizes = {\n sm: '[&>svg]:icon-sm',\n default: '[&>svg]:icon-md',\n lg: '[&>svg]:icon-lg',\n} as const\n\n// ── Trend config ──\n\nconst trendConfig = {\n up: { color: 'text-text-success', srLabel: 'Increased' },\n down: { color: 'text-text-error', srLabel: 'Decreased' },\n neutral: { color: 'text-text-muted', srLabel: 'No change' },\n} as const\n\n// ── Context ──\n\ntype MetricCardContextValue = { size: 'sm' | 'default' | 'lg'; animated: boolean }\nconst MetricCardContext = React.createContext<MetricCardContextValue>({ size: 'default', animated: false })\n\n// ── Types ──\n\nexport type MetricCardVariant = 'default' | 'elevated' | 'ghost'\nexport type MetricCardSize = 'sm' | 'default' | 'lg'\nexport type MetricCardRadius = 'none' | 'sm' | 'base' | 'default' | 'lg' | 'xl' | '2xl' | '3xl' | 'full'\nexport type MetricCardTrendDirection = 'up' | 'down' | 'neutral'\n\n// ── MetricCard (root) ──\n\nexport interface MetricCardProps\n extends React.HTMLAttributes<HTMLDivElement>,\n VariantProps<typeof metricCardVariants> {\n animated?: boolean\n}\n\nconst MetricCard = React.forwardRef<HTMLDivElement, MetricCardProps>(\n ({ className, variant, size, radius, animated = false, children, ...props }, ref) => {\n const resolvedSize = (size || 'default') as MetricCardSize\n return (\n <MetricCardContext.Provider value={{ size: resolvedSize, animated }}>\n <div\n ref={ref}\n className={cn(metricCardVariants({ variant, size, radius }), className)}\n {...props}\n >\n {children}\n </div>\n </MetricCardContext.Provider>\n )\n }\n)\nMetricCard.displayName = 'MetricCard'\n\n// ── MetricCardHeader ──\n\nexport interface MetricCardHeaderProps extends React.HTMLAttributes<HTMLDivElement> {}\n\nconst MetricCardHeader = React.forwardRef<HTMLDivElement, MetricCardHeaderProps>(\n ({ className, ...props }, ref) => (\n <div\n ref={ref}\n className={cn('flex items-center justify-between gap-2', className)}\n {...props}\n />\n )\n)\nMetricCardHeader.displayName = 'MetricCardHeader'\n\n// ── MetricCardTitle ──\n\nexport interface MetricCardTitleProps extends React.HTMLAttributes<HTMLParagraphElement> {}\n\nconst MetricCardTitle = React.forwardRef<HTMLParagraphElement, MetricCardTitleProps>(\n ({ className, ...props }, ref) => {\n const { size } = React.useContext(MetricCardContext)\n return (\n <p\n ref={ref}\n className={cn(titleSizes[size], 'font-semibold text-text-muted', className)}\n {...props}\n />\n )\n }\n)\nMetricCardTitle.displayName = 'MetricCardTitle'\n\n// ── MetricCardValue ──\n\nexport interface MetricCardValueProps extends React.HTMLAttributes<HTMLParagraphElement> {}\n\nconst MetricCardValue = React.forwardRef<HTMLParagraphElement, MetricCardValueProps>(\n ({ className, children, ...props }, ref) => {\n const { size, animated } = React.useContext(MetricCardContext)\n const [display, setDisplay] = React.useState<React.ReactNode>(children)\n\n React.useEffect(() => {\n if (!animated || typeof children !== 'string') { setDisplay(children); return }\n const numMatch = children.match(/[\\d,.]+/)\n if (!numMatch) { setDisplay(children); return }\n const numStr = numMatch[0].replace(/,/g, '')\n const target = parseFloat(numStr)\n if (isNaN(target)) { setDisplay(children); return }\n const prefix = children.slice(0, children.indexOf(numMatch[0]))\n const suffix = children.slice(children.indexOf(numMatch[0]) + numMatch[0].length)\n const steps = 24\n const duration = 700\n let step = 0\n setDisplay(prefix + '0' + suffix)\n const timer = setInterval(() => {\n step++\n const eased = 1 - Math.pow(1 - step / steps, 3)\n const current = target * eased\n const formatted = target >= 1000\n ? Math.floor(current).toLocaleString()\n : current.toFixed(numStr.includes('.') ? 2 : 0)\n setDisplay(prefix + formatted + suffix)\n if (step >= steps) { setDisplay(children); clearInterval(timer) }\n }, duration / steps)\n return () => clearInterval(timer)\n }, [children, animated])\n\n return (\n <p\n ref={ref}\n className={cn(valueSizes[size], 'font-bold text-foreground mt-1', className)}\n {...props}\n >\n {display}\n </p>\n )\n }\n)\nMetricCardValue.displayName = 'MetricCardValue'\n\n// ── MetricCardTrend ──\n\nexport interface MetricCardTrendProps extends React.HTMLAttributes<HTMLParagraphElement> {\n direction: MetricCardTrendDirection\n}\n\nconst MetricCardTrend = React.forwardRef<HTMLParagraphElement, MetricCardTrendProps>(\n ({ className, direction, children, ...props }, ref) => {\n const config = trendConfig[direction]\n return (\n <p\n ref={ref}\n className={cn('flex items-center gap-1 text-sm mt-2', config.color, className)}\n {...props}\n >\n {direction === 'up' && (\n <svg className=\"icon-xs\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" strokeWidth={2.5} aria-hidden=\"true\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M4.5 15.75l7.5-7.5 7.5 7.5\" />\n </svg>\n )}\n {direction === 'down' && (\n <svg className=\"icon-xs\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" strokeWidth={2.5} aria-hidden=\"true\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M19.5 8.25l-7.5 7.5-7.5-7.5\" />\n </svg>\n )}\n {direction === 'neutral' && (\n <svg className=\"icon-xs\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" strokeWidth={2.5} aria-hidden=\"true\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M5 12h14\" />\n </svg>\n )}\n <span className=\"sr-only\">{config.srLabel}</span>\n {children}\n </p>\n )\n }\n)\nMetricCardTrend.displayName = 'MetricCardTrend'\n\n// ── MetricCardDescription ──\n\nexport interface MetricCardDescriptionProps extends React.HTMLAttributes<HTMLParagraphElement> {}\n\nconst MetricCardDescription = React.forwardRef<HTMLParagraphElement, MetricCardDescriptionProps>(\n ({ className, ...props }, ref) => (\n <p\n ref={ref}\n className={cn('text-xs text-text-muted mt-1', className)}\n {...props}\n />\n )\n)\nMetricCardDescription.displayName = 'MetricCardDescription'\n\n// ── MetricCardSymbol ──\n\nexport interface MetricCardSymbolProps extends React.HTMLAttributes<HTMLDivElement> {}\n\nconst MetricCardSymbol = React.forwardRef<HTMLDivElement, MetricCardSymbolProps>(\n ({ className, ...props }, ref) => {\n const { size } = React.useContext(MetricCardContext)\n return (\n <div\n ref={ref}\n className={cn('text-text-muted', iconWrapperSizes[size], className)}\n {...props}\n />\n )\n }\n)\nMetricCardSymbol.displayName = 'MetricCardSymbol'\n\n// ── Exports ──\nexport {\n MetricCard,\n MetricCardHeader,\n MetricCardTitle,\n MetricCardValue,\n MetricCardTrend,\n MetricCardDescription,\n MetricCardSymbol,\n metricCardVariants,\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import {
|
|
3
|
+
cn
|
|
4
|
+
} from "./chunk-53MIUPSY.mjs";
|
|
5
|
+
|
|
6
|
+
// src/components/ui/tooltip.tsx
|
|
7
|
+
import * as React from "react";
|
|
8
|
+
import * as TooltipPrimitive from "@radix-ui/react-tooltip";
|
|
9
|
+
import { cva } from "class-variance-authority";
|
|
10
|
+
var ANIMATION_CLASSES = {
|
|
11
|
+
top: "data-[state=delayed-open]:animate-tooltip-top-enter data-[state=instant-open]:animate-tooltip-top-enter data-[state=closed]:animate-tooltip-top-exit",
|
|
12
|
+
bottom: "data-[state=delayed-open]:animate-tooltip-bottom-enter data-[state=instant-open]:animate-tooltip-bottom-enter data-[state=closed]:animate-tooltip-bottom-exit",
|
|
13
|
+
left: "data-[state=delayed-open]:animate-tooltip-left-enter data-[state=instant-open]:animate-tooltip-left-enter data-[state=closed]:animate-tooltip-left-exit",
|
|
14
|
+
right: "data-[state=delayed-open]:animate-tooltip-right-enter data-[state=instant-open]:animate-tooltip-right-enter data-[state=closed]:animate-tooltip-right-exit"
|
|
15
|
+
};
|
|
16
|
+
var tooltipContentVariants = cva(
|
|
17
|
+
"z-tooltip rounded-lg font-normal select-none max-w-72",
|
|
18
|
+
{
|
|
19
|
+
variants: {
|
|
20
|
+
variant: {
|
|
21
|
+
default: "bg-foreground text-background shadow-lg",
|
|
22
|
+
inverted: "bg-background-paper/95 text-foreground border border-border-subtle shadow-lg backdrop-blur-sm"
|
|
23
|
+
},
|
|
24
|
+
size: {
|
|
25
|
+
sm: "text-xs px-2.5 py-1",
|
|
26
|
+
default: "text-sm px-3 py-1.5"
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
defaultVariants: {
|
|
30
|
+
variant: "default",
|
|
31
|
+
size: "default"
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
);
|
|
35
|
+
var ARROW_FILL = {
|
|
36
|
+
default: "fill-foreground drop-shadow-sm",
|
|
37
|
+
inverted: "fill-background-paper drop-shadow-sm"
|
|
38
|
+
};
|
|
39
|
+
var TooltipProvider = TooltipPrimitive.Provider;
|
|
40
|
+
function Tooltip({ delayDuration = 200, ...props }) {
|
|
41
|
+
return /* @__PURE__ */ React.createElement(TooltipPrimitive.Root, { delayDuration, ...props });
|
|
42
|
+
}
|
|
43
|
+
var TooltipTrigger = TooltipPrimitive.Trigger;
|
|
44
|
+
var TooltipPortal = TooltipPrimitive.Portal;
|
|
45
|
+
var TooltipContent = React.forwardRef(({ className, variant = "default", size, side = "top", sideOffset = 6, showArrow = true, children, ...props }, ref) => {
|
|
46
|
+
const resolvedSide = side;
|
|
47
|
+
return /* @__PURE__ */ React.createElement(TooltipPrimitive.Portal, null, /* @__PURE__ */ React.createElement(
|
|
48
|
+
TooltipPrimitive.Content,
|
|
49
|
+
{
|
|
50
|
+
ref,
|
|
51
|
+
side,
|
|
52
|
+
sideOffset,
|
|
53
|
+
className: cn(
|
|
54
|
+
tooltipContentVariants({ variant, size }),
|
|
55
|
+
ANIMATION_CLASSES[resolvedSide],
|
|
56
|
+
className
|
|
57
|
+
),
|
|
58
|
+
...props
|
|
59
|
+
},
|
|
60
|
+
children,
|
|
61
|
+
showArrow && /* @__PURE__ */ React.createElement(
|
|
62
|
+
TooltipPrimitive.Arrow,
|
|
63
|
+
{
|
|
64
|
+
className: ARROW_FILL[variant || "default"],
|
|
65
|
+
width: 10,
|
|
66
|
+
height: 5
|
|
67
|
+
}
|
|
68
|
+
)
|
|
69
|
+
));
|
|
70
|
+
});
|
|
71
|
+
TooltipContent.displayName = "TooltipContent";
|
|
72
|
+
var TooltipArrow = React.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ React.createElement(
|
|
73
|
+
TooltipPrimitive.Arrow,
|
|
74
|
+
{
|
|
75
|
+
ref,
|
|
76
|
+
className: cn("fill-foreground", className),
|
|
77
|
+
width: 8,
|
|
78
|
+
height: 4,
|
|
79
|
+
...props
|
|
80
|
+
}
|
|
81
|
+
));
|
|
82
|
+
TooltipArrow.displayName = "TooltipArrow";
|
|
83
|
+
|
|
84
|
+
export {
|
|
85
|
+
tooltipContentVariants,
|
|
86
|
+
TooltipProvider,
|
|
87
|
+
Tooltip,
|
|
88
|
+
TooltipTrigger,
|
|
89
|
+
TooltipPortal,
|
|
90
|
+
TooltipContent,
|
|
91
|
+
TooltipArrow
|
|
92
|
+
};
|
|
93
|
+
//# sourceMappingURL=chunk-FHUAH6AJ.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/ui/tooltip.tsx"],"sourcesContent":["'use client'\n\nimport * as React from 'react'\nimport * as TooltipPrimitive from '@radix-ui/react-tooltip'\nimport { cva, type VariantProps } from 'class-variance-authority'\nimport { cn } from '@/lib/utils'\n\n// ─── Types ──────────────────────────────────────────────────\nexport type TooltipSide = 'top' | 'right' | 'bottom' | 'left'\n\n// ─── Animation class mapping (static strings for Tailwind scanner) ──\nconst ANIMATION_CLASSES: Record<TooltipSide, string> = {\n top: 'data-[state=delayed-open]:animate-tooltip-top-enter data-[state=instant-open]:animate-tooltip-top-enter data-[state=closed]:animate-tooltip-top-exit',\n bottom: 'data-[state=delayed-open]:animate-tooltip-bottom-enter data-[state=instant-open]:animate-tooltip-bottom-enter data-[state=closed]:animate-tooltip-bottom-exit',\n left: 'data-[state=delayed-open]:animate-tooltip-left-enter data-[state=instant-open]:animate-tooltip-left-enter data-[state=closed]:animate-tooltip-left-exit',\n right: 'data-[state=delayed-open]:animate-tooltip-right-enter data-[state=instant-open]:animate-tooltip-right-enter data-[state=closed]:animate-tooltip-right-exit',\n}\n\n// ─── Content variants ────────────────────────────────────────\nconst tooltipContentVariants = cva(\n 'z-tooltip rounded-lg font-normal select-none max-w-72',\n {\n variants: {\n variant: {\n default: 'bg-foreground text-background shadow-lg',\n inverted: 'bg-background-paper/95 text-foreground border border-border-subtle shadow-lg backdrop-blur-sm',\n },\n size: {\n sm: 'text-xs px-2.5 py-1',\n default: 'text-sm px-3 py-1.5',\n },\n },\n defaultVariants: {\n variant: 'default',\n size: 'default',\n },\n }\n)\n\n// ─── Arrow fill mapping (matches content variant background) ──\nconst ARROW_FILL: Record<string, string> = {\n default: 'fill-foreground drop-shadow-sm',\n inverted: 'fill-background-paper drop-shadow-sm',\n}\n\n// ═══════════════════════════════════════════════════════════════\n// Tooltip\n// ═══════════════════════════════════════════════════════════════\n\n// ─── TooltipProvider ─────────────────────────────────────────\nconst TooltipProvider = TooltipPrimitive.Provider\n\n// ─── Tooltip (Root) — Props type ──\nexport interface TooltipRootProps extends React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Root> {\n /** Delay in ms before tooltip appears */\n delayDuration?: number\n}\n\n// ─── Tooltip (Root) — thin wrapper to expose as named export with default delayDuration ──\nfunction Tooltip({ delayDuration = 200, ...props }: TooltipRootProps) {\n return <TooltipPrimitive.Root delayDuration={delayDuration} {...props} />\n}\n\n// ─── TooltipTrigger ──────────────────────────────────────────\nconst TooltipTrigger = TooltipPrimitive.Trigger\n\n// ─── TooltipPortal ───────────────────────────────────────────\nconst TooltipPortal = TooltipPrimitive.Portal\n\n// ─── TooltipContent ──────────────────────────────────────────\nexport interface TooltipContentProps\n extends React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Content>,\n VariantProps<typeof tooltipContentVariants> {\n /** Show arrow pointing to trigger */\n showArrow?: boolean\n}\n\nconst TooltipContent = React.forwardRef<\n React.ElementRef<typeof TooltipPrimitive.Content>,\n TooltipContentProps\n>(({ className, variant = 'default', size, side = 'top', sideOffset = 6, showArrow = true, children, ...props }, ref) => {\n const resolvedSide = side as TooltipSide\n\n return (\n <TooltipPrimitive.Portal>\n <TooltipPrimitive.Content\n ref={ref}\n side={side}\n sideOffset={sideOffset}\n className={cn(\n tooltipContentVariants({ variant, size }),\n ANIMATION_CLASSES[resolvedSide],\n className,\n )}\n {...props}\n >\n {children}\n {showArrow && (\n <TooltipPrimitive.Arrow\n className={ARROW_FILL[variant || 'default']}\n width={10}\n height={5}\n />\n )}\n </TooltipPrimitive.Content>\n </TooltipPrimitive.Portal>\n )\n})\nTooltipContent.displayName = 'TooltipContent'\n\n// ─── TooltipArrow (standalone, for manual placement outside Content) ──\nconst TooltipArrow = React.forwardRef<\n React.ElementRef<typeof TooltipPrimitive.Arrow>,\n React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Arrow>\n>(({ className, ...props }, ref) => (\n <TooltipPrimitive.Arrow\n ref={ref}\n className={cn('fill-foreground', className)}\n width={8}\n height={4}\n {...props}\n />\n))\nTooltipArrow.displayName = 'TooltipArrow'\n\n// ─── Exports ────────────────────────────────────────────────\nexport {\n Tooltip,\n TooltipTrigger,\n TooltipContent,\n TooltipArrow,\n TooltipPortal,\n TooltipProvider,\n tooltipContentVariants,\n}\n"],"mappings":";;;;;;AAEA,YAAY,WAAW;AACvB,YAAY,sBAAsB;AAClC,SAAS,WAA8B;AAOvC,IAAM,oBAAiD;AAAA,EACrD,KAAQ;AAAA,EACR,QAAQ;AAAA,EACR,MAAQ;AAAA,EACR,OAAQ;AACV;AAGA,IAAM,yBAAyB;AAAA,EAC7B;AAAA,EACA;AAAA,IACE,UAAU;AAAA,MACR,SAAS;AAAA,QACP,SAAS;AAAA,QACT,UAAU;AAAA,MACZ;AAAA,MACA,MAAM;AAAA,QACJ,IAAI;AAAA,QACJ,SAAS;AAAA,MACX;AAAA,IACF;AAAA,IACA,iBAAiB;AAAA,MACf,SAAS;AAAA,MACT,MAAM;AAAA,IACR;AAAA,EACF;AACF;AAGA,IAAM,aAAqC;AAAA,EACzC,SAAS;AAAA,EACT,UAAU;AACZ;AAOA,IAAM,kBAAmC;AASzC,SAAS,QAAQ,EAAE,gBAAgB,KAAK,GAAG,MAAM,GAAqB;AACpE,SAAO,oCAAkB,uBAAjB,EAAsB,eAA+B,GAAG,OAAO;AACzE;AAGA,IAAM,iBAAkC;AAGxC,IAAM,gBAAiC;AAUvC,IAAM,iBAAuB,iBAG3B,CAAC,EAAE,WAAW,UAAU,WAAW,MAAM,OAAO,OAAO,aAAa,GAAG,YAAY,MAAM,UAAU,GAAG,MAAM,GAAG,QAAQ;AACvH,QAAM,eAAe;AAErB,SACE,oCAAkB,yBAAjB,MACC;AAAA,IAAkB;AAAA,IAAjB;AAAA,MACC;AAAA,MACA;AAAA,MACA;AAAA,MACA,WAAW;AAAA,QACT,uBAAuB,EAAE,SAAS,KAAK,CAAC;AAAA,QACxC,kBAAkB,YAAY;AAAA,QAC9B;AAAA,MACF;AAAA,MACC,GAAG;AAAA;AAAA,IAEH;AAAA,IACA,aACC;AAAA,MAAkB;AAAA,MAAjB;AAAA,QACC,WAAW,WAAW,WAAW,SAAS;AAAA,QAC1C,OAAO;AAAA,QACP,QAAQ;AAAA;AAAA,IACV;AAAA,EAEJ,CACF;AAEJ,CAAC;AACD,eAAe,cAAc;AAG7B,IAAM,eAAqB,iBAGzB,CAAC,EAAE,WAAW,GAAG,MAAM,GAAG,QAC1B;AAAA,EAAkB;AAAA,EAAjB;AAAA,IACC;AAAA,IACA,WAAW,GAAG,mBAAmB,SAAS;AAAA,IAC1C,OAAO;AAAA,IACP,QAAQ;AAAA,IACP,GAAG;AAAA;AACN,CACD;AACD,aAAa,cAAc;","names":[]}
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import {
|
|
3
|
+
cn
|
|
4
|
+
} from "./chunk-53MIUPSY.mjs";
|
|
5
|
+
|
|
6
|
+
// src/components/ui/avatar.tsx
|
|
7
|
+
import * as React from "react";
|
|
8
|
+
import * as AvatarPrimitive from "@radix-ui/react-avatar";
|
|
9
|
+
import { cva } from "class-variance-authority";
|
|
10
|
+
var avatarVariants = cva(
|
|
11
|
+
"relative inline-flex items-center justify-center overflow-hidden bg-background-muted select-none",
|
|
12
|
+
{
|
|
13
|
+
variants: {
|
|
14
|
+
size: {
|
|
15
|
+
xs: "w-6 h-6",
|
|
16
|
+
// 24px
|
|
17
|
+
sm: "w-8 h-8",
|
|
18
|
+
// 32px
|
|
19
|
+
default: "w-10 h-10",
|
|
20
|
+
// 40px
|
|
21
|
+
lg: "w-12 h-12",
|
|
22
|
+
// 48px
|
|
23
|
+
xl: "w-16 h-16",
|
|
24
|
+
// 64px
|
|
25
|
+
"2xl": "w-20 h-20"
|
|
26
|
+
// 80px
|
|
27
|
+
},
|
|
28
|
+
shape: {
|
|
29
|
+
circle: "rounded-full",
|
|
30
|
+
square: "rounded-xl"
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
defaultVariants: { size: "default", shape: "circle" }
|
|
34
|
+
}
|
|
35
|
+
);
|
|
36
|
+
var statusDotSizes = {
|
|
37
|
+
xs: "w-1.5 h-1.5",
|
|
38
|
+
sm: "w-2 h-2",
|
|
39
|
+
default: "w-2.5 h-2.5",
|
|
40
|
+
lg: "w-3 h-3",
|
|
41
|
+
xl: "w-3.5 h-3.5",
|
|
42
|
+
"2xl": "w-4 h-4"
|
|
43
|
+
};
|
|
44
|
+
var statusColors = {
|
|
45
|
+
online: "bg-success",
|
|
46
|
+
offline: "bg-text-muted",
|
|
47
|
+
busy: "bg-error",
|
|
48
|
+
away: "bg-warning"
|
|
49
|
+
};
|
|
50
|
+
var fallbackFontSizes = {
|
|
51
|
+
xs: "text-2xs",
|
|
52
|
+
sm: "text-xs",
|
|
53
|
+
default: "text-sm",
|
|
54
|
+
lg: "text-base",
|
|
55
|
+
xl: "text-xl",
|
|
56
|
+
"2xl": "text-2xl"
|
|
57
|
+
};
|
|
58
|
+
var groupNegativeMargins = {
|
|
59
|
+
xs: "-space-x-1.5",
|
|
60
|
+
sm: "-space-x-2",
|
|
61
|
+
default: "-space-x-2.5",
|
|
62
|
+
lg: "-space-x-3",
|
|
63
|
+
xl: "-space-x-4",
|
|
64
|
+
"2xl": "-space-x-5"
|
|
65
|
+
};
|
|
66
|
+
var avatarColors = [
|
|
67
|
+
{ vivid: { bg: "bg-[#DC2626]", text: "text-white" }, soft: { bg: "bg-[#FEE2E2]", text: "text-[#DC2626]" } },
|
|
68
|
+
// red
|
|
69
|
+
{ vivid: { bg: "bg-[#EA580C]", text: "text-white" }, soft: { bg: "bg-[#FFEDD5]", text: "text-[#EA580C]" } },
|
|
70
|
+
// orange
|
|
71
|
+
{ vivid: { bg: "bg-[#D97706]", text: "text-white" }, soft: { bg: "bg-[#FEF3C7]", text: "text-[#B45309]" } },
|
|
72
|
+
// amber
|
|
73
|
+
{ vivid: { bg: "bg-[#CA8A04]", text: "text-white" }, soft: { bg: "bg-[#FEF9C3]", text: "text-[#A16207]" } },
|
|
74
|
+
// yellow
|
|
75
|
+
{ vivid: { bg: "bg-[#059669]", text: "text-white" }, soft: { bg: "bg-[#D1FAE5]", text: "text-[#047857]" } },
|
|
76
|
+
// emerald
|
|
77
|
+
{ vivid: { bg: "bg-[#0D9488]", text: "text-white" }, soft: { bg: "bg-[#CCFBF1]", text: "text-[#0F766E]" } },
|
|
78
|
+
// teal
|
|
79
|
+
{ vivid: { bg: "bg-[#0891B2]", text: "text-white" }, soft: { bg: "bg-[#CFFAFE]", text: "text-[#0E7490]" } },
|
|
80
|
+
// cyan
|
|
81
|
+
{ vivid: { bg: "bg-[#2563EB]", text: "text-white" }, soft: { bg: "bg-[#DBEAFE]", text: "text-[#1D4ED8]" } },
|
|
82
|
+
// blue
|
|
83
|
+
{ vivid: { bg: "bg-[#4F46E5]", text: "text-white" }, soft: { bg: "bg-[#E0E7FF]", text: "text-[#4338CA]" } },
|
|
84
|
+
// indigo
|
|
85
|
+
{ vivid: { bg: "bg-[#7C3AED]", text: "text-white" }, soft: { bg: "bg-[#EDE9FE]", text: "text-[#6D28D9]" } },
|
|
86
|
+
// violet
|
|
87
|
+
{ vivid: { bg: "bg-[#9333EA]", text: "text-white" }, soft: { bg: "bg-[#F3E8FF]", text: "text-[#7E22CE]" } },
|
|
88
|
+
// purple
|
|
89
|
+
{ vivid: { bg: "bg-[#DB2777]", text: "text-white" }, soft: { bg: "bg-[#FCE7F3]", text: "text-[#BE185D]" } }
|
|
90
|
+
// pink
|
|
91
|
+
];
|
|
92
|
+
function getAvatarInitials(name, maxChars = 2) {
|
|
93
|
+
const trimmed = name.trim();
|
|
94
|
+
if (!trimmed) return "";
|
|
95
|
+
const cjkRegex = /[\u3000-\u9fff\uac00-\ud7af\uff00-\uffef]/;
|
|
96
|
+
if (cjkRegex.test(trimmed.charAt(0))) {
|
|
97
|
+
return trimmed.slice(0, maxChars);
|
|
98
|
+
}
|
|
99
|
+
const parts = trimmed.split(/[\s\-_.]+/).filter(Boolean);
|
|
100
|
+
if (parts.length === 1) {
|
|
101
|
+
return parts[0].charAt(0).toUpperCase();
|
|
102
|
+
}
|
|
103
|
+
return (parts[0].charAt(0) + parts[parts.length - 1].charAt(0)).toUpperCase().slice(0, maxChars);
|
|
104
|
+
}
|
|
105
|
+
function getAvatarColor(name, variant = "vivid") {
|
|
106
|
+
let hash = 5381;
|
|
107
|
+
for (let i = 0; i < name.length; i++) {
|
|
108
|
+
hash = (hash << 5) + hash ^ name.charCodeAt(i);
|
|
109
|
+
}
|
|
110
|
+
return avatarColors[(hash >>> 0) % avatarColors.length][variant];
|
|
111
|
+
}
|
|
112
|
+
var Avatar = React.forwardRef(({ className, size, shape, status, children, ...props }, ref) => {
|
|
113
|
+
const resolvedSize = size || "default";
|
|
114
|
+
if (!status) {
|
|
115
|
+
return /* @__PURE__ */ React.createElement(
|
|
116
|
+
AvatarPrimitive.Root,
|
|
117
|
+
{
|
|
118
|
+
ref,
|
|
119
|
+
className: cn(avatarVariants({ size, shape }), className),
|
|
120
|
+
...props
|
|
121
|
+
},
|
|
122
|
+
children
|
|
123
|
+
);
|
|
124
|
+
}
|
|
125
|
+
return /* @__PURE__ */ React.createElement("span", { className: "relative inline-flex" }, /* @__PURE__ */ React.createElement(
|
|
126
|
+
AvatarPrimitive.Root,
|
|
127
|
+
{
|
|
128
|
+
ref,
|
|
129
|
+
className: cn(avatarVariants({ size, shape }), className),
|
|
130
|
+
...props
|
|
131
|
+
},
|
|
132
|
+
children
|
|
133
|
+
), /* @__PURE__ */ React.createElement(
|
|
134
|
+
"span",
|
|
135
|
+
{
|
|
136
|
+
className: cn(
|
|
137
|
+
"absolute bottom-0 right-0 rounded-full ring-2 ring-background",
|
|
138
|
+
statusDotSizes[resolvedSize],
|
|
139
|
+
statusColors[status]
|
|
140
|
+
)
|
|
141
|
+
}
|
|
142
|
+
));
|
|
143
|
+
});
|
|
144
|
+
Avatar.displayName = "Avatar";
|
|
145
|
+
var AvatarImage = React.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ React.createElement(
|
|
146
|
+
AvatarPrimitive.Image,
|
|
147
|
+
{
|
|
148
|
+
ref,
|
|
149
|
+
className: cn("object-cover w-full h-full", className),
|
|
150
|
+
...props
|
|
151
|
+
}
|
|
152
|
+
));
|
|
153
|
+
AvatarImage.displayName = "AvatarImage";
|
|
154
|
+
var AvatarFallback = React.forwardRef(({ className, size, name, colorized, colorVariant = "vivid", children, ...props }, ref) => {
|
|
155
|
+
const resolvedSize = size || "default";
|
|
156
|
+
const colorKey = name || colorized;
|
|
157
|
+
const color = colorKey ? getAvatarColor(colorKey, colorVariant) : null;
|
|
158
|
+
const resolvedChildren = children ?? (name ? getAvatarInitials(name) : void 0);
|
|
159
|
+
return /* @__PURE__ */ React.createElement(
|
|
160
|
+
AvatarPrimitive.Fallback,
|
|
161
|
+
{
|
|
162
|
+
ref,
|
|
163
|
+
className: cn(
|
|
164
|
+
"flex items-center justify-center w-full h-full font-semibold",
|
|
165
|
+
color ? [color.bg, color.text] : "bg-background-muted text-text-muted",
|
|
166
|
+
fallbackFontSizes[resolvedSize],
|
|
167
|
+
className
|
|
168
|
+
),
|
|
169
|
+
...props
|
|
170
|
+
},
|
|
171
|
+
resolvedChildren
|
|
172
|
+
);
|
|
173
|
+
});
|
|
174
|
+
AvatarFallback.displayName = "AvatarFallback";
|
|
175
|
+
var AvatarGroup = React.forwardRef(
|
|
176
|
+
({ className, max, size = "default", shape = "circle", children, ...props }, ref) => {
|
|
177
|
+
const childArray = React.Children.toArray(children);
|
|
178
|
+
const visibleChildren = max ? childArray.slice(0, max) : childArray;
|
|
179
|
+
const overflowCount = max ? childArray.length - max : 0;
|
|
180
|
+
return /* @__PURE__ */ React.createElement(
|
|
181
|
+
"div",
|
|
182
|
+
{
|
|
183
|
+
ref,
|
|
184
|
+
className: cn(
|
|
185
|
+
"flex items-center",
|
|
186
|
+
groupNegativeMargins[size],
|
|
187
|
+
"[&>*]:ring-2 [&>*]:ring-background",
|
|
188
|
+
className
|
|
189
|
+
),
|
|
190
|
+
...props
|
|
191
|
+
},
|
|
192
|
+
visibleChildren,
|
|
193
|
+
overflowCount > 0 && /* @__PURE__ */ React.createElement(Avatar, { size, shape }, /* @__PURE__ */ React.createElement(AvatarFallback, { size }, "+", overflowCount))
|
|
194
|
+
);
|
|
195
|
+
}
|
|
196
|
+
);
|
|
197
|
+
AvatarGroup.displayName = "AvatarGroup";
|
|
198
|
+
|
|
199
|
+
export {
|
|
200
|
+
avatarVariants,
|
|
201
|
+
avatarColors,
|
|
202
|
+
getAvatarInitials,
|
|
203
|
+
getAvatarColor,
|
|
204
|
+
Avatar,
|
|
205
|
+
AvatarImage,
|
|
206
|
+
AvatarFallback,
|
|
207
|
+
AvatarGroup
|
|
208
|
+
};
|
|
209
|
+
//# sourceMappingURL=chunk-GD4YE5AE.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/ui/avatar.tsx"],"sourcesContent":["'use client'\n\nimport * as React from 'react'\nimport * as AvatarPrimitive from '@radix-ui/react-avatar'\nimport { cva, type VariantProps } from 'class-variance-authority'\nimport { cn } from '@/lib/utils'\n\n// Avatar root variants\nconst avatarVariants = cva(\n 'relative inline-flex items-center justify-center overflow-hidden bg-background-muted select-none',\n {\n variants: {\n size: {\n xs: 'w-6 h-6', // 24px\n sm: 'w-8 h-8', // 32px\n default: 'w-10 h-10', // 40px\n lg: 'w-12 h-12', // 48px\n xl: 'w-16 h-16', // 64px\n '2xl': 'w-20 h-20', // 80px\n },\n shape: {\n circle: 'rounded-full',\n square: 'rounded-xl',\n },\n },\n defaultVariants: { size: 'default', shape: 'circle' },\n }\n)\n\n// Status dot sizes per avatar size\nconst statusDotSizes = {\n xs: 'w-1.5 h-1.5',\n sm: 'w-2 h-2',\n default: 'w-2.5 h-2.5',\n lg: 'w-3 h-3',\n xl: 'w-3.5 h-3.5',\n '2xl': 'w-4 h-4',\n}\n\n// Status dot colors\nconst statusColors = {\n online: 'bg-success',\n offline: 'bg-text-muted',\n busy: 'bg-error',\n away: 'bg-warning',\n}\n\n// Fallback font sizes per avatar size\nconst fallbackFontSizes = {\n xs: 'text-2xs',\n sm: 'text-xs',\n default: 'text-sm',\n lg: 'text-base',\n xl: 'text-xl',\n '2xl': 'text-2xl',\n}\n\n// Negative margin per size for AvatarGroup overlap\nconst groupNegativeMargins = {\n xs: '-space-x-1.5',\n sm: '-space-x-2',\n default: '-space-x-2.5',\n lg: '-space-x-3',\n xl: '-space-x-4',\n '2xl': '-space-x-5',\n}\n\n// Colorized fallback palette (12 colors × 2 variants) — exception 13 in TOKEN-EXCEPTIONS.md\nconst avatarColors = [\n { vivid: { bg: 'bg-[#DC2626]', text: 'text-white' }, soft: { bg: 'bg-[#FEE2E2]', text: 'text-[#DC2626]' } }, // red\n { vivid: { bg: 'bg-[#EA580C]', text: 'text-white' }, soft: { bg: 'bg-[#FFEDD5]', text: 'text-[#EA580C]' } }, // orange\n { vivid: { bg: 'bg-[#D97706]', text: 'text-white' }, soft: { bg: 'bg-[#FEF3C7]', text: 'text-[#B45309]' } }, // amber\n { vivid: { bg: 'bg-[#CA8A04]', text: 'text-white' }, soft: { bg: 'bg-[#FEF9C3]', text: 'text-[#A16207]' } }, // yellow\n { vivid: { bg: 'bg-[#059669]', text: 'text-white' }, soft: { bg: 'bg-[#D1FAE5]', text: 'text-[#047857]' } }, // emerald\n { vivid: { bg: 'bg-[#0D9488]', text: 'text-white' }, soft: { bg: 'bg-[#CCFBF1]', text: 'text-[#0F766E]' } }, // teal\n { vivid: { bg: 'bg-[#0891B2]', text: 'text-white' }, soft: { bg: 'bg-[#CFFAFE]', text: 'text-[#0E7490]' } }, // cyan\n { vivid: { bg: 'bg-[#2563EB]', text: 'text-white' }, soft: { bg: 'bg-[#DBEAFE]', text: 'text-[#1D4ED8]' } }, // blue\n { vivid: { bg: 'bg-[#4F46E5]', text: 'text-white' }, soft: { bg: 'bg-[#E0E7FF]', text: 'text-[#4338CA]' } }, // indigo\n { vivid: { bg: 'bg-[#7C3AED]', text: 'text-white' }, soft: { bg: 'bg-[#EDE9FE]', text: 'text-[#6D28D9]' } }, // violet\n { vivid: { bg: 'bg-[#9333EA]', text: 'text-white' }, soft: { bg: 'bg-[#F3E8FF]', text: 'text-[#7E22CE]' } }, // purple\n { vivid: { bg: 'bg-[#DB2777]', text: 'text-white' }, soft: { bg: 'bg-[#FCE7F3]', text: 'text-[#BE185D]' } }, // pink\n] as const\n\nexport type AvatarColorVariant = 'vivid' | 'soft'\n\n/** Extract initials from a name string (e.g. \"John Doe\" → \"JD\", \"김민수\" → \"김민\") */\nfunction getAvatarInitials(name: string, maxChars = 2): string {\n const trimmed = name.trim()\n if (!trimmed) return ''\n\n // CJK: use first character(s) directly\n const cjkRegex = /[\\u3000-\\u9fff\\uac00-\\ud7af\\uff00-\\uffef]/\n if (cjkRegex.test(trimmed.charAt(0))) {\n return trimmed.slice(0, maxChars)\n }\n\n // Split on spaces, hyphens, underscores, dots\n const parts = trimmed.split(/[\\s\\-_.]+/).filter(Boolean)\n if (parts.length === 1) {\n return parts[0].charAt(0).toUpperCase()\n }\n\n // First + last part initials\n return (parts[0].charAt(0) + parts[parts.length - 1].charAt(0))\n .toUpperCase()\n .slice(0, maxChars)\n}\n\n/** Hash a name string to a deterministic avatar color pair (djb2 xor variant) */\nfunction getAvatarColor(name: string, variant: AvatarColorVariant = 'vivid') {\n let hash = 5381\n for (let i = 0; i < name.length; i++) {\n hash = ((hash << 5) + hash) ^ name.charCodeAt(i)\n }\n return avatarColors[(hash >>> 0) % avatarColors.length][variant]\n}\n\nexport type AvatarSize = 'xs' | 'sm' | 'default' | 'lg' | 'xl' | '2xl'\nexport type AvatarShape = 'circle' | 'square'\nexport type AvatarStatus = 'online' | 'offline' | 'busy' | 'away'\n\nexport interface AvatarProps\n extends React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Root>,\n VariantProps<typeof avatarVariants> {\n status?: AvatarStatus\n}\n\nconst Avatar = React.forwardRef<\n React.ElementRef<typeof AvatarPrimitive.Root>,\n AvatarProps\n>(({ className, size, shape, status, children, ...props }, ref) => {\n const resolvedSize = size || 'default'\n\n if (!status) {\n return (\n <AvatarPrimitive.Root\n ref={ref}\n className={cn(avatarVariants({ size, shape }), className)}\n {...props}\n >\n {children}\n </AvatarPrimitive.Root>\n )\n }\n\n // Wrap with an outer span so the status dot is not clipped by overflow-hidden\n return (\n <span className=\"relative inline-flex\">\n <AvatarPrimitive.Root\n ref={ref}\n className={cn(avatarVariants({ size, shape }), className)}\n {...props}\n >\n {children}\n </AvatarPrimitive.Root>\n <span\n className={cn(\n 'absolute bottom-0 right-0 rounded-full ring-2 ring-background',\n statusDotSizes[resolvedSize],\n statusColors[status]\n )}\n />\n </span>\n )\n})\nAvatar.displayName = 'Avatar'\n\nexport interface AvatarImageProps\n extends React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Image> {}\n\nconst AvatarImage = React.forwardRef<\n React.ElementRef<typeof AvatarPrimitive.Image>,\n AvatarImageProps\n>(({ className, ...props }, ref) => (\n <AvatarPrimitive.Image\n ref={ref}\n className={cn('object-cover w-full h-full', className)}\n {...props}\n />\n))\nAvatarImage.displayName = 'AvatarImage'\n\nexport interface AvatarFallbackProps\n extends React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Fallback> {\n size?: AvatarSize\n /** Shorthand: auto-generates initials + color from a name. Children override auto-initials. */\n name?: string\n /** Pass a name/key to enable colorized mode. The string is hashed to pick a deterministic color. */\n colorized?: string\n /** Color style: \"vivid\" (strong bg + white text) or \"soft\" (pastel bg + dark text). Default: \"vivid\" */\n colorVariant?: AvatarColorVariant\n}\n\nconst AvatarFallback = React.forwardRef<\n React.ElementRef<typeof AvatarPrimitive.Fallback>,\n AvatarFallbackProps\n>(({ className, size, name, colorized, colorVariant = 'vivid', children, ...props }, ref) => {\n const resolvedSize = size || 'default'\n const colorKey = name || colorized\n const color = colorKey ? getAvatarColor(colorKey, colorVariant) : null\n const resolvedChildren = children ?? (name ? getAvatarInitials(name) : undefined)\n return (\n <AvatarPrimitive.Fallback\n ref={ref}\n className={cn(\n 'flex items-center justify-center w-full h-full font-semibold',\n color ? [color.bg, color.text] : 'bg-background-muted text-text-muted',\n fallbackFontSizes[resolvedSize],\n className\n )}\n {...props}\n >\n {resolvedChildren}\n </AvatarPrimitive.Fallback>\n )\n})\nAvatarFallback.displayName = 'AvatarFallback'\n\nexport interface AvatarGroupProps extends React.HTMLAttributes<HTMLDivElement> {\n max?: number\n size?: AvatarSize\n shape?: AvatarShape\n}\n\nconst AvatarGroup = React.forwardRef<HTMLDivElement, AvatarGroupProps>(\n ({ className, max, size = 'default', shape = 'circle', children, ...props }, ref) => {\n const childArray = React.Children.toArray(children)\n const visibleChildren = max ? childArray.slice(0, max) : childArray\n const overflowCount = max ? childArray.length - max : 0\n\n return (\n <div\n ref={ref}\n className={cn(\n 'flex items-center',\n groupNegativeMargins[size],\n '[&>*]:ring-2 [&>*]:ring-background',\n className\n )}\n {...props}\n >\n {visibleChildren}\n {overflowCount > 0 && (\n <Avatar size={size} shape={shape}>\n <AvatarFallback size={size}>+{overflowCount}</AvatarFallback>\n </Avatar>\n )}\n </div>\n )\n }\n)\nAvatarGroup.displayName = 'AvatarGroup'\n\nexport { Avatar, AvatarImage, AvatarFallback, AvatarGroup, avatarVariants, avatarColors, getAvatarColor, getAvatarInitials }\n"],"mappings":"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","names":[]}
|