@exitvibing/hqui 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 +45 -0
- package/dist/index.css +1 -0
- package/dist/index.d.mts +180 -0
- package/dist/index.d.ts +180 -0
- package/dist/index.js +1049 -0
- package/dist/index.mjs +988 -0
- package/docs/components.md +304 -0
- package/docs/design-system.md +85 -0
- package/docs/extended-components.md +201 -0
- package/docs/setup.md +146 -0
- package/package.json +33 -0
- package/src/components/Badge.tsx +40 -0
- package/src/components/Button.tsx +50 -0
- package/src/components/Card.tsx +72 -0
- package/src/components/Checkbox.tsx +47 -0
- package/src/components/HighlightText.tsx +24 -0
- package/src/components/Input.tsx +21 -0
- package/src/components/ProgressBar.tsx +64 -0
- package/src/components/Separator.tsx +25 -0
- package/src/components/Switch.tsx +43 -0
- package/src/components/Table.tsx +87 -0
- package/src/components/Tabs.tsx +122 -0
- package/src/components/ThemeToggle.tsx +40 -0
- package/src/components/Tooltip.tsx +120 -0
- package/src/components/extended/ArrowButton.tsx +28 -0
- package/src/components/extended/ChooseList.tsx +38 -0
- package/src/components/extended/Counter.tsx +74 -0
- package/src/components/extended/Popup.tsx +78 -0
- package/src/components/extended/StatusBar.tsx +45 -0
- package/src/components/extended/WeekViewCalendar.tsx +126 -0
- package/src/index.css +119 -0
- package/src/index.ts +25 -0
- package/src/lib/cn.ts +6 -0
- package/tailwind.config.ts +64 -0
- package/tsconfig.json +22 -0
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,988 @@
|
|
|
1
|
+
// src/lib/cn.ts
|
|
2
|
+
import { clsx } from "clsx";
|
|
3
|
+
import { twMerge } from "tailwind-merge";
|
|
4
|
+
function cn(...inputs) {
|
|
5
|
+
return twMerge(clsx(inputs));
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
// src/components/Button.tsx
|
|
9
|
+
import { forwardRef } from "react";
|
|
10
|
+
import { jsx } from "react/jsx-runtime";
|
|
11
|
+
var variants = {
|
|
12
|
+
primary: "bg-primary text-primary-foreground shadow hover:bg-primary/90",
|
|
13
|
+
secondary: "bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80",
|
|
14
|
+
destructive: "bg-[hsl(var(--red))] text-white shadow-sm hover:bg-[hsl(var(--red))]/90",
|
|
15
|
+
outline: "border border-border bg-transparent shadow-sm hover:bg-accent hover:text-accent-foreground",
|
|
16
|
+
ghost: "hover:bg-accent hover:text-accent-foreground",
|
|
17
|
+
purple: "bg-[hsl(var(--purple))] text-white shadow-sm hover:bg-[hsl(var(--purple))]/90",
|
|
18
|
+
orange: "bg-[hsl(var(--orange))] text-white shadow-sm hover:bg-[hsl(var(--orange))]/90",
|
|
19
|
+
blue: "bg-[hsl(var(--blue))] text-white shadow-sm hover:bg-[hsl(var(--blue))]/90",
|
|
20
|
+
green: "bg-[hsl(var(--green))] text-white shadow-sm hover:bg-[hsl(var(--green))]/90"
|
|
21
|
+
};
|
|
22
|
+
var sizes = {
|
|
23
|
+
sm: "h-8 rounded-md px-3 text-xs gap-1.5",
|
|
24
|
+
default: "h-9 px-4 py-2 text-sm gap-2",
|
|
25
|
+
lg: "h-10 rounded-md px-6 text-base gap-2",
|
|
26
|
+
icon: "h-9 w-9 p-0"
|
|
27
|
+
};
|
|
28
|
+
var Button = forwardRef(
|
|
29
|
+
({ className, variant = "primary", size = "default", ...props }, ref) => {
|
|
30
|
+
return /* @__PURE__ */ jsx(
|
|
31
|
+
"button",
|
|
32
|
+
{
|
|
33
|
+
ref,
|
|
34
|
+
className: cn(
|
|
35
|
+
"inline-flex items-center justify-center whitespace-nowrap rounded-md font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50",
|
|
36
|
+
variants[variant],
|
|
37
|
+
sizes[size],
|
|
38
|
+
className
|
|
39
|
+
),
|
|
40
|
+
...props
|
|
41
|
+
}
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
);
|
|
45
|
+
Button.displayName = "Button";
|
|
46
|
+
|
|
47
|
+
// src/components/Card.tsx
|
|
48
|
+
import { forwardRef as forwardRef2 } from "react";
|
|
49
|
+
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
50
|
+
var Card = forwardRef2(
|
|
51
|
+
({ className, ...props }, ref) => /* @__PURE__ */ jsx2(
|
|
52
|
+
"div",
|
|
53
|
+
{
|
|
54
|
+
ref,
|
|
55
|
+
className: cn(
|
|
56
|
+
"rounded-xl border border-border bg-card text-card-foreground shadow-sm transition-shadow hover:shadow-md",
|
|
57
|
+
className
|
|
58
|
+
),
|
|
59
|
+
...props
|
|
60
|
+
}
|
|
61
|
+
)
|
|
62
|
+
);
|
|
63
|
+
Card.displayName = "Card";
|
|
64
|
+
var CardHeader = forwardRef2(({ className, ...props }, ref) => /* @__PURE__ */ jsx2(
|
|
65
|
+
"div",
|
|
66
|
+
{
|
|
67
|
+
ref,
|
|
68
|
+
className: cn("flex flex-col space-y-1.5 p-6 pb-4", className),
|
|
69
|
+
...props
|
|
70
|
+
}
|
|
71
|
+
));
|
|
72
|
+
CardHeader.displayName = "CardHeader";
|
|
73
|
+
var CardTitle = forwardRef2(({ className, ...props }, ref) => /* @__PURE__ */ jsx2(
|
|
74
|
+
"h3",
|
|
75
|
+
{
|
|
76
|
+
ref,
|
|
77
|
+
className: cn("font-semibold leading-none tracking-tight", className),
|
|
78
|
+
...props
|
|
79
|
+
}
|
|
80
|
+
));
|
|
81
|
+
CardTitle.displayName = "CardTitle";
|
|
82
|
+
var CardDescription = forwardRef2(({ className, ...props }, ref) => /* @__PURE__ */ jsx2(
|
|
83
|
+
"p",
|
|
84
|
+
{
|
|
85
|
+
ref,
|
|
86
|
+
className: cn("text-sm text-muted-foreground", className),
|
|
87
|
+
...props
|
|
88
|
+
}
|
|
89
|
+
));
|
|
90
|
+
CardDescription.displayName = "CardDescription";
|
|
91
|
+
var CardContent = forwardRef2(({ className, ...props }, ref) => /* @__PURE__ */ jsx2("div", { ref, className: cn("p-6 pt-0", className), ...props }));
|
|
92
|
+
CardContent.displayName = "CardContent";
|
|
93
|
+
var CardFooter = forwardRef2(({ className, ...props }, ref) => /* @__PURE__ */ jsx2(
|
|
94
|
+
"div",
|
|
95
|
+
{
|
|
96
|
+
ref,
|
|
97
|
+
className: cn("flex items-center p-6 pt-0", className),
|
|
98
|
+
...props
|
|
99
|
+
}
|
|
100
|
+
));
|
|
101
|
+
CardFooter.displayName = "CardFooter";
|
|
102
|
+
|
|
103
|
+
// src/components/Input.tsx
|
|
104
|
+
import { forwardRef as forwardRef3 } from "react";
|
|
105
|
+
import { jsx as jsx3 } from "react/jsx-runtime";
|
|
106
|
+
var Input = forwardRef3(
|
|
107
|
+
({ className, type = "text", ...props }, ref) => {
|
|
108
|
+
return /* @__PURE__ */ jsx3(
|
|
109
|
+
"input",
|
|
110
|
+
{
|
|
111
|
+
type,
|
|
112
|
+
className: cn(
|
|
113
|
+
"flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50",
|
|
114
|
+
className
|
|
115
|
+
),
|
|
116
|
+
ref,
|
|
117
|
+
...props
|
|
118
|
+
}
|
|
119
|
+
);
|
|
120
|
+
}
|
|
121
|
+
);
|
|
122
|
+
Input.displayName = "Input";
|
|
123
|
+
|
|
124
|
+
// src/components/Checkbox.tsx
|
|
125
|
+
import React4, { forwardRef as forwardRef4 } from "react";
|
|
126
|
+
import { Check } from "lucide-react";
|
|
127
|
+
import { jsx as jsx4, jsxs } from "react/jsx-runtime";
|
|
128
|
+
var Checkbox = forwardRef4(
|
|
129
|
+
({ className, label, id, ...props }, ref) => {
|
|
130
|
+
const defaultId = React4.useId();
|
|
131
|
+
const inputId = id || defaultId;
|
|
132
|
+
return /* @__PURE__ */ jsxs(
|
|
133
|
+
"label",
|
|
134
|
+
{
|
|
135
|
+
htmlFor: inputId,
|
|
136
|
+
className: cn(
|
|
137
|
+
"flex items-center gap-2 cursor-pointer select-none",
|
|
138
|
+
className
|
|
139
|
+
),
|
|
140
|
+
children: [
|
|
141
|
+
/* @__PURE__ */ jsxs("div", { className: "relative flex items-center justify-center", children: [
|
|
142
|
+
/* @__PURE__ */ jsx4(
|
|
143
|
+
"input",
|
|
144
|
+
{
|
|
145
|
+
id: inputId,
|
|
146
|
+
type: "checkbox",
|
|
147
|
+
className: "peer h-4 w-4 shrink-0 rounded-sm border border-foreground/30 shadow appearance-none focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 checked:bg-foreground checked:border-foreground",
|
|
148
|
+
ref,
|
|
149
|
+
...props
|
|
150
|
+
}
|
|
151
|
+
),
|
|
152
|
+
/* @__PURE__ */ jsx4(
|
|
153
|
+
Check,
|
|
154
|
+
{
|
|
155
|
+
className: "absolute h-3 w-3 text-background pointer-events-none opacity-0 peer-checked:opacity-100 transition-opacity",
|
|
156
|
+
strokeWidth: 3
|
|
157
|
+
}
|
|
158
|
+
)
|
|
159
|
+
] }),
|
|
160
|
+
label && /* @__PURE__ */ jsx4("span", { className: "text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70", children: label })
|
|
161
|
+
]
|
|
162
|
+
}
|
|
163
|
+
);
|
|
164
|
+
}
|
|
165
|
+
);
|
|
166
|
+
Checkbox.displayName = "Checkbox";
|
|
167
|
+
|
|
168
|
+
// src/components/ProgressBar.tsx
|
|
169
|
+
import { forwardRef as forwardRef5 } from "react";
|
|
170
|
+
import { jsx as jsx5, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
171
|
+
var colorClasses = {
|
|
172
|
+
white: "bg-foreground",
|
|
173
|
+
purple: "bg-[hsl(var(--purple))]",
|
|
174
|
+
orange: "bg-[hsl(var(--orange))]",
|
|
175
|
+
blue: "bg-[hsl(var(--blue))]",
|
|
176
|
+
green: "bg-[hsl(var(--green))]"
|
|
177
|
+
};
|
|
178
|
+
var ProgressBar = forwardRef5(
|
|
179
|
+
({
|
|
180
|
+
className,
|
|
181
|
+
value = 0,
|
|
182
|
+
max = 100,
|
|
183
|
+
showLabel = false,
|
|
184
|
+
color = "white",
|
|
185
|
+
...props
|
|
186
|
+
}, ref) => {
|
|
187
|
+
const percentage = Math.min(Math.max(0, value / max * 100), 100);
|
|
188
|
+
return /* @__PURE__ */ jsxs2("div", { className: cn("flex items-center gap-3", showLabel && "w-full"), children: [
|
|
189
|
+
/* @__PURE__ */ jsx5(
|
|
190
|
+
"div",
|
|
191
|
+
{
|
|
192
|
+
ref,
|
|
193
|
+
role: "progressbar",
|
|
194
|
+
"aria-valuemin": 0,
|
|
195
|
+
"aria-valuemax": max,
|
|
196
|
+
"aria-valuenow": value,
|
|
197
|
+
className: cn(
|
|
198
|
+
"relative h-2 w-full overflow-hidden rounded-full bg-secondary",
|
|
199
|
+
className
|
|
200
|
+
),
|
|
201
|
+
...props,
|
|
202
|
+
children: /* @__PURE__ */ jsx5(
|
|
203
|
+
"div",
|
|
204
|
+
{
|
|
205
|
+
className: cn(
|
|
206
|
+
"h-full rounded-full transition-all duration-500 ease-out",
|
|
207
|
+
colorClasses[color]
|
|
208
|
+
),
|
|
209
|
+
style: { width: `${percentage}%` }
|
|
210
|
+
}
|
|
211
|
+
)
|
|
212
|
+
}
|
|
213
|
+
),
|
|
214
|
+
showLabel && /* @__PURE__ */ jsxs2("span", { className: "text-xs font-medium text-muted-foreground tabular-nums w-10 text-right", children: [
|
|
215
|
+
Math.round(percentage),
|
|
216
|
+
"%"
|
|
217
|
+
] })
|
|
218
|
+
] });
|
|
219
|
+
}
|
|
220
|
+
);
|
|
221
|
+
ProgressBar.displayName = "ProgressBar";
|
|
222
|
+
|
|
223
|
+
// src/components/Table.tsx
|
|
224
|
+
import {
|
|
225
|
+
forwardRef as forwardRef6
|
|
226
|
+
} from "react";
|
|
227
|
+
import { jsx as jsx6 } from "react/jsx-runtime";
|
|
228
|
+
var Table = forwardRef6(({ className, ...props }, ref) => /* @__PURE__ */ jsx6("div", { className: "relative w-full overflow-auto rounded-lg border border-border", children: /* @__PURE__ */ jsx6(
|
|
229
|
+
"table",
|
|
230
|
+
{
|
|
231
|
+
ref,
|
|
232
|
+
className: cn("w-full caption-bottom text-sm", className),
|
|
233
|
+
...props
|
|
234
|
+
}
|
|
235
|
+
) }));
|
|
236
|
+
Table.displayName = "Table";
|
|
237
|
+
var TableHeader = forwardRef6(({ className, ...props }, ref) => /* @__PURE__ */ jsx6(
|
|
238
|
+
"thead",
|
|
239
|
+
{
|
|
240
|
+
ref,
|
|
241
|
+
className: cn("bg-muted/50 [&_tr]:border-b", className),
|
|
242
|
+
...props
|
|
243
|
+
}
|
|
244
|
+
));
|
|
245
|
+
TableHeader.displayName = "TableHeader";
|
|
246
|
+
var TableBody = forwardRef6(({ className, ...props }, ref) => /* @__PURE__ */ jsx6(
|
|
247
|
+
"tbody",
|
|
248
|
+
{
|
|
249
|
+
ref,
|
|
250
|
+
className: cn("[&_tr:last-child]:border-0", className),
|
|
251
|
+
...props
|
|
252
|
+
}
|
|
253
|
+
));
|
|
254
|
+
TableBody.displayName = "TableBody";
|
|
255
|
+
var TableRow = forwardRef6(({ className, ...props }, ref) => /* @__PURE__ */ jsx6(
|
|
256
|
+
"tr",
|
|
257
|
+
{
|
|
258
|
+
ref,
|
|
259
|
+
className: cn(
|
|
260
|
+
"border-b border-border transition-colors hover:bg-muted/50 data-[state=selected]:bg-muted",
|
|
261
|
+
className
|
|
262
|
+
),
|
|
263
|
+
...props
|
|
264
|
+
}
|
|
265
|
+
));
|
|
266
|
+
TableRow.displayName = "TableRow";
|
|
267
|
+
var TableHead = forwardRef6(({ className, ...props }, ref) => /* @__PURE__ */ jsx6(
|
|
268
|
+
"th",
|
|
269
|
+
{
|
|
270
|
+
ref,
|
|
271
|
+
className: cn(
|
|
272
|
+
"h-10 px-4 text-left align-middle font-medium text-muted-foreground [&:has([role=checkbox])]:pr-0",
|
|
273
|
+
className
|
|
274
|
+
),
|
|
275
|
+
...props
|
|
276
|
+
}
|
|
277
|
+
));
|
|
278
|
+
TableHead.displayName = "TableHead";
|
|
279
|
+
var TableCell = forwardRef6(({ className, ...props }, ref) => /* @__PURE__ */ jsx6(
|
|
280
|
+
"td",
|
|
281
|
+
{
|
|
282
|
+
ref,
|
|
283
|
+
className: cn("p-4 align-middle [&:has([role=checkbox])]:pr-0", className),
|
|
284
|
+
...props
|
|
285
|
+
}
|
|
286
|
+
));
|
|
287
|
+
TableCell.displayName = "TableCell";
|
|
288
|
+
|
|
289
|
+
// src/components/HighlightText.tsx
|
|
290
|
+
import { forwardRef as forwardRef7 } from "react";
|
|
291
|
+
import { jsx as jsx7 } from "react/jsx-runtime";
|
|
292
|
+
var HighlightText = forwardRef7(
|
|
293
|
+
({ className, children, ...props }, ref) => {
|
|
294
|
+
return /* @__PURE__ */ jsx7(
|
|
295
|
+
"span",
|
|
296
|
+
{
|
|
297
|
+
ref,
|
|
298
|
+
className: cn(
|
|
299
|
+
"bg-foreground text-background px-1.5 py-0.5 rounded font-medium",
|
|
300
|
+
className
|
|
301
|
+
),
|
|
302
|
+
...props,
|
|
303
|
+
children
|
|
304
|
+
}
|
|
305
|
+
);
|
|
306
|
+
}
|
|
307
|
+
);
|
|
308
|
+
HighlightText.displayName = "HighlightText";
|
|
309
|
+
|
|
310
|
+
// src/components/Badge.tsx
|
|
311
|
+
import { forwardRef as forwardRef8 } from "react";
|
|
312
|
+
import { jsx as jsx8 } from "react/jsx-runtime";
|
|
313
|
+
var colorVariants = {
|
|
314
|
+
default: "bg-primary text-primary-foreground shadow hover:bg-primary/80",
|
|
315
|
+
secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80",
|
|
316
|
+
outline: "border border-border text-foreground",
|
|
317
|
+
white: "bg-foreground/10 text-foreground border border-foreground/20",
|
|
318
|
+
destructive: "bg-[hsl(var(--red))] text-white shadow hover:bg-[hsl(var(--red))]/80",
|
|
319
|
+
purple: "bg-[hsl(var(--purple))]/15 text-[hsl(var(--purple))] border border-[hsl(var(--purple))]/20",
|
|
320
|
+
orange: "bg-[hsl(var(--orange))]/15 text-[hsl(var(--orange))] border border-[hsl(var(--orange))]/20",
|
|
321
|
+
blue: "bg-[hsl(var(--blue))]/15 text-[hsl(var(--blue))] border border-[hsl(var(--blue))]/20",
|
|
322
|
+
green: "bg-[hsl(var(--green))]/15 text-[hsl(var(--green))] border border-[hsl(var(--green))]/20",
|
|
323
|
+
red: "bg-[hsl(var(--red))]/15 text-[hsl(var(--red))] border border-[hsl(var(--red))]/20"
|
|
324
|
+
};
|
|
325
|
+
var Badge = forwardRef8(
|
|
326
|
+
({ className, variant = "default", ...props }, ref) => {
|
|
327
|
+
return /* @__PURE__ */ jsx8(
|
|
328
|
+
"span",
|
|
329
|
+
{
|
|
330
|
+
ref,
|
|
331
|
+
className: cn(
|
|
332
|
+
"inline-flex items-center rounded-md px-2 py-0.5 text-xs font-semibold transition-colors",
|
|
333
|
+
colorVariants[variant],
|
|
334
|
+
className
|
|
335
|
+
),
|
|
336
|
+
...props
|
|
337
|
+
}
|
|
338
|
+
);
|
|
339
|
+
}
|
|
340
|
+
);
|
|
341
|
+
Badge.displayName = "Badge";
|
|
342
|
+
|
|
343
|
+
// src/components/Separator.tsx
|
|
344
|
+
import { forwardRef as forwardRef9 } from "react";
|
|
345
|
+
import { jsx as jsx9 } from "react/jsx-runtime";
|
|
346
|
+
var Separator = forwardRef9(
|
|
347
|
+
({ className, orientation = "horizontal", ...props }, ref) => {
|
|
348
|
+
return /* @__PURE__ */ jsx9(
|
|
349
|
+
"div",
|
|
350
|
+
{
|
|
351
|
+
ref,
|
|
352
|
+
role: "separator",
|
|
353
|
+
"aria-orientation": orientation,
|
|
354
|
+
className: cn(
|
|
355
|
+
"shrink-0 bg-border",
|
|
356
|
+
orientation === "horizontal" ? "h-[1px] w-full" : "h-full w-[1px]",
|
|
357
|
+
className
|
|
358
|
+
),
|
|
359
|
+
...props
|
|
360
|
+
}
|
|
361
|
+
);
|
|
362
|
+
}
|
|
363
|
+
);
|
|
364
|
+
Separator.displayName = "Separator";
|
|
365
|
+
|
|
366
|
+
// src/components/Tabs.tsx
|
|
367
|
+
import { createContext, useContext, useState, forwardRef as forwardRef10 } from "react";
|
|
368
|
+
import { jsx as jsx10 } from "react/jsx-runtime";
|
|
369
|
+
var TabsContext = createContext({
|
|
370
|
+
value: "",
|
|
371
|
+
onValueChange: () => {
|
|
372
|
+
}
|
|
373
|
+
});
|
|
374
|
+
var Tabs = forwardRef10(
|
|
375
|
+
({
|
|
376
|
+
className,
|
|
377
|
+
defaultValue = "",
|
|
378
|
+
value: controlledValue,
|
|
379
|
+
onValueChange,
|
|
380
|
+
children,
|
|
381
|
+
...props
|
|
382
|
+
}, ref) => {
|
|
383
|
+
const [uncontrolledValue, setUncontrolledValue] = useState(defaultValue);
|
|
384
|
+
const isControlled = controlledValue !== void 0;
|
|
385
|
+
const currentValue = isControlled ? controlledValue : uncontrolledValue;
|
|
386
|
+
const handleChange = (newValue) => {
|
|
387
|
+
if (!isControlled) setUncontrolledValue(newValue);
|
|
388
|
+
onValueChange?.(newValue);
|
|
389
|
+
};
|
|
390
|
+
return /* @__PURE__ */ jsx10(
|
|
391
|
+
TabsContext.Provider,
|
|
392
|
+
{
|
|
393
|
+
value: { value: currentValue, onValueChange: handleChange },
|
|
394
|
+
children: /* @__PURE__ */ jsx10("div", { ref, className: cn("w-full", className), ...props, children })
|
|
395
|
+
}
|
|
396
|
+
);
|
|
397
|
+
}
|
|
398
|
+
);
|
|
399
|
+
Tabs.displayName = "Tabs";
|
|
400
|
+
var TabsList = forwardRef10(({ className, ...props }, ref) => /* @__PURE__ */ jsx10(
|
|
401
|
+
"div",
|
|
402
|
+
{
|
|
403
|
+
ref,
|
|
404
|
+
className: cn(
|
|
405
|
+
"inline-flex h-9 items-center justify-center rounded-lg bg-muted p-1 text-muted-foreground",
|
|
406
|
+
className
|
|
407
|
+
),
|
|
408
|
+
...props
|
|
409
|
+
}
|
|
410
|
+
));
|
|
411
|
+
TabsList.displayName = "TabsList";
|
|
412
|
+
var TabsTrigger = forwardRef10(
|
|
413
|
+
({ className, value, ...props }, ref) => {
|
|
414
|
+
const ctx = useContext(TabsContext);
|
|
415
|
+
const isActive = ctx.value === value;
|
|
416
|
+
return /* @__PURE__ */ jsx10(
|
|
417
|
+
"button",
|
|
418
|
+
{
|
|
419
|
+
ref,
|
|
420
|
+
type: "button",
|
|
421
|
+
role: "tab",
|
|
422
|
+
"aria-selected": isActive,
|
|
423
|
+
"data-state": isActive ? "active" : "inactive",
|
|
424
|
+
className: cn(
|
|
425
|
+
"inline-flex items-center justify-center whitespace-nowrap rounded-md px-3 py-1 text-sm font-medium ring-offset-background transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50",
|
|
426
|
+
isActive ? "bg-background text-foreground shadow" : "hover:bg-background/50 hover:text-foreground",
|
|
427
|
+
className
|
|
428
|
+
),
|
|
429
|
+
onClick: () => ctx.onValueChange(value),
|
|
430
|
+
...props
|
|
431
|
+
}
|
|
432
|
+
);
|
|
433
|
+
}
|
|
434
|
+
);
|
|
435
|
+
TabsTrigger.displayName = "TabsTrigger";
|
|
436
|
+
var TabsContent = forwardRef10(
|
|
437
|
+
({ className, value, ...props }, ref) => {
|
|
438
|
+
const ctx = useContext(TabsContext);
|
|
439
|
+
if (ctx.value !== value) return null;
|
|
440
|
+
return /* @__PURE__ */ jsx10(
|
|
441
|
+
"div",
|
|
442
|
+
{
|
|
443
|
+
ref,
|
|
444
|
+
role: "tabpanel",
|
|
445
|
+
className: cn(
|
|
446
|
+
"mt-2 ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 animate-fade-in",
|
|
447
|
+
className
|
|
448
|
+
),
|
|
449
|
+
...props
|
|
450
|
+
}
|
|
451
|
+
);
|
|
452
|
+
}
|
|
453
|
+
);
|
|
454
|
+
TabsContent.displayName = "TabsContent";
|
|
455
|
+
|
|
456
|
+
// src/components/Switch.tsx
|
|
457
|
+
import React11, { forwardRef as forwardRef11 } from "react";
|
|
458
|
+
import { jsx as jsx11, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
459
|
+
var Switch = forwardRef11(
|
|
460
|
+
({ className, label, id, ...props }, ref) => {
|
|
461
|
+
const defaultId = React11.useId();
|
|
462
|
+
const inputId = id || defaultId;
|
|
463
|
+
return /* @__PURE__ */ jsxs3(
|
|
464
|
+
"label",
|
|
465
|
+
{
|
|
466
|
+
htmlFor: inputId,
|
|
467
|
+
className: cn(
|
|
468
|
+
"inline-flex items-center gap-2 cursor-pointer select-none",
|
|
469
|
+
className
|
|
470
|
+
),
|
|
471
|
+
children: [
|
|
472
|
+
/* @__PURE__ */ jsxs3("div", { className: "relative", children: [
|
|
473
|
+
/* @__PURE__ */ jsx11(
|
|
474
|
+
"input",
|
|
475
|
+
{
|
|
476
|
+
id: inputId,
|
|
477
|
+
type: "checkbox",
|
|
478
|
+
role: "switch",
|
|
479
|
+
className: "peer sr-only",
|
|
480
|
+
ref,
|
|
481
|
+
...props
|
|
482
|
+
}
|
|
483
|
+
),
|
|
484
|
+
/* @__PURE__ */ jsx11("div", { className: "h-5 w-9 rounded-full border-2 border-transparent bg-input transition-colors peer-checked:bg-foreground peer-focus-visible:outline-none peer-focus-visible:ring-2 peer-focus-visible:ring-ring peer-focus-visible:ring-offset-2 peer-focus-visible:ring-offset-background peer-disabled:cursor-not-allowed peer-disabled:opacity-50" }),
|
|
485
|
+
/* @__PURE__ */ jsx11("div", { className: "absolute left-0.5 top-0.5 h-4 w-4 rounded-full bg-background shadow-lg transition-transform peer-checked:translate-x-4 peer-checked:bg-background" })
|
|
486
|
+
] }),
|
|
487
|
+
label && /* @__PURE__ */ jsx11("span", { className: "text-sm font-medium leading-none", children: label })
|
|
488
|
+
]
|
|
489
|
+
}
|
|
490
|
+
);
|
|
491
|
+
}
|
|
492
|
+
);
|
|
493
|
+
Switch.displayName = "Switch";
|
|
494
|
+
|
|
495
|
+
// src/components/Tooltip.tsx
|
|
496
|
+
import {
|
|
497
|
+
forwardRef as forwardRef12,
|
|
498
|
+
useState as useState2,
|
|
499
|
+
useRef,
|
|
500
|
+
useEffect,
|
|
501
|
+
useCallback
|
|
502
|
+
} from "react";
|
|
503
|
+
import { Fragment, jsx as jsx12, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
504
|
+
var Tooltip = forwardRef12(
|
|
505
|
+
({ className, content, side = "top", delayMs = 200, children, ...props }, ref) => {
|
|
506
|
+
const [visible, setVisible] = useState2(false);
|
|
507
|
+
const timeoutRef = useRef();
|
|
508
|
+
const wrapperRef = useRef(null);
|
|
509
|
+
const tooltipRef = useRef(null);
|
|
510
|
+
const [position, setPosition] = useState2({ top: 0, left: 0 });
|
|
511
|
+
const show = () => {
|
|
512
|
+
timeoutRef.current = setTimeout(() => setVisible(true), delayMs);
|
|
513
|
+
};
|
|
514
|
+
const hide = () => {
|
|
515
|
+
clearTimeout(timeoutRef.current);
|
|
516
|
+
setVisible(false);
|
|
517
|
+
};
|
|
518
|
+
const updatePosition = useCallback(() => {
|
|
519
|
+
if (!wrapperRef.current || !tooltipRef.current) return;
|
|
520
|
+
const trigger = wrapperRef.current.getBoundingClientRect();
|
|
521
|
+
const tip = tooltipRef.current.getBoundingClientRect();
|
|
522
|
+
const gap = 8;
|
|
523
|
+
let top = 0;
|
|
524
|
+
let left = 0;
|
|
525
|
+
switch (side) {
|
|
526
|
+
case "top":
|
|
527
|
+
top = trigger.top - tip.height - gap;
|
|
528
|
+
left = trigger.left + trigger.width / 2 - tip.width / 2;
|
|
529
|
+
break;
|
|
530
|
+
case "bottom":
|
|
531
|
+
top = trigger.bottom + gap;
|
|
532
|
+
left = trigger.left + trigger.width / 2 - tip.width / 2;
|
|
533
|
+
break;
|
|
534
|
+
case "left":
|
|
535
|
+
top = trigger.top + trigger.height / 2 - tip.height / 2;
|
|
536
|
+
left = trigger.left - tip.width - gap;
|
|
537
|
+
break;
|
|
538
|
+
case "right":
|
|
539
|
+
top = trigger.top + trigger.height / 2 - tip.height / 2;
|
|
540
|
+
left = trigger.right + gap;
|
|
541
|
+
break;
|
|
542
|
+
}
|
|
543
|
+
setPosition({ top, left });
|
|
544
|
+
}, [side]);
|
|
545
|
+
useEffect(() => {
|
|
546
|
+
if (visible) {
|
|
547
|
+
requestAnimationFrame(updatePosition);
|
|
548
|
+
}
|
|
549
|
+
}, [visible, updatePosition]);
|
|
550
|
+
useEffect(() => {
|
|
551
|
+
return () => clearTimeout(timeoutRef.current);
|
|
552
|
+
}, []);
|
|
553
|
+
return /* @__PURE__ */ jsxs4(Fragment, { children: [
|
|
554
|
+
/* @__PURE__ */ jsx12(
|
|
555
|
+
"div",
|
|
556
|
+
{
|
|
557
|
+
ref: (node) => {
|
|
558
|
+
wrapperRef.current = node;
|
|
559
|
+
if (typeof ref === "function") ref(node);
|
|
560
|
+
else if (ref)
|
|
561
|
+
ref.current = node;
|
|
562
|
+
},
|
|
563
|
+
className: cn("inline-flex", className),
|
|
564
|
+
onMouseEnter: show,
|
|
565
|
+
onMouseLeave: hide,
|
|
566
|
+
onFocus: show,
|
|
567
|
+
onBlur: hide,
|
|
568
|
+
...props,
|
|
569
|
+
children
|
|
570
|
+
}
|
|
571
|
+
),
|
|
572
|
+
visible && /* @__PURE__ */ jsx12(
|
|
573
|
+
"div",
|
|
574
|
+
{
|
|
575
|
+
ref: tooltipRef,
|
|
576
|
+
role: "tooltip",
|
|
577
|
+
className: "fixed z-[9999] rounded-md bg-foreground px-3 py-1.5 text-xs text-background shadow-md whitespace-nowrap pointer-events-none",
|
|
578
|
+
style: {
|
|
579
|
+
top: position.top,
|
|
580
|
+
left: position.left,
|
|
581
|
+
animation: "popup-fade-in 0.1s ease-out"
|
|
582
|
+
},
|
|
583
|
+
children: content
|
|
584
|
+
}
|
|
585
|
+
)
|
|
586
|
+
] });
|
|
587
|
+
}
|
|
588
|
+
);
|
|
589
|
+
Tooltip.displayName = "Tooltip";
|
|
590
|
+
|
|
591
|
+
// src/components/ThemeToggle.tsx
|
|
592
|
+
import { forwardRef as forwardRef13, useEffect as useEffect2, useState as useState3 } from "react";
|
|
593
|
+
import { Moon, Sun } from "lucide-react";
|
|
594
|
+
import { jsx as jsx13 } from "react/jsx-runtime";
|
|
595
|
+
var ThemeToggle = forwardRef13(
|
|
596
|
+
({ className, defaultTheme }, ref) => {
|
|
597
|
+
const [isDark, setIsDark] = useState3(() => {
|
|
598
|
+
if (typeof window === "undefined") return defaultTheme === "dark";
|
|
599
|
+
return document.documentElement.classList.contains("dark");
|
|
600
|
+
});
|
|
601
|
+
useEffect2(() => {
|
|
602
|
+
if (isDark) {
|
|
603
|
+
document.documentElement.classList.add("dark");
|
|
604
|
+
} else {
|
|
605
|
+
document.documentElement.classList.remove("dark");
|
|
606
|
+
}
|
|
607
|
+
}, [isDark]);
|
|
608
|
+
return /* @__PURE__ */ jsx13(
|
|
609
|
+
Button,
|
|
610
|
+
{
|
|
611
|
+
ref,
|
|
612
|
+
variant: "ghost",
|
|
613
|
+
size: "icon",
|
|
614
|
+
className: cn("rounded-full", className),
|
|
615
|
+
onClick: () => setIsDark((prev) => !prev),
|
|
616
|
+
"aria-label": isDark ? "Switch to light mode" : "Switch to dark mode",
|
|
617
|
+
children: isDark ? /* @__PURE__ */ jsx13(Sun, { className: "h-4 w-4" }) : /* @__PURE__ */ jsx13(Moon, { className: "h-4 w-4" })
|
|
618
|
+
}
|
|
619
|
+
);
|
|
620
|
+
}
|
|
621
|
+
);
|
|
622
|
+
ThemeToggle.displayName = "ThemeToggle";
|
|
623
|
+
|
|
624
|
+
// src/components/extended/Counter.tsx
|
|
625
|
+
import { useState as useState4, forwardRef as forwardRef14 } from "react";
|
|
626
|
+
import { Plus, Minus } from "lucide-react";
|
|
627
|
+
import { jsx as jsx14, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
628
|
+
var Counter = forwardRef14(
|
|
629
|
+
({
|
|
630
|
+
initialValue = 0,
|
|
631
|
+
min = Number.MIN_SAFE_INTEGER,
|
|
632
|
+
max = Number.MAX_SAFE_INTEGER,
|
|
633
|
+
step = 1,
|
|
634
|
+
onChange,
|
|
635
|
+
className
|
|
636
|
+
}, ref) => {
|
|
637
|
+
const [value, setValue] = useState4(initialValue);
|
|
638
|
+
const handleIncrement = () => {
|
|
639
|
+
const next = Math.min(max, value + step);
|
|
640
|
+
setValue(next);
|
|
641
|
+
onChange?.(next);
|
|
642
|
+
};
|
|
643
|
+
const handleDecrement = () => {
|
|
644
|
+
const next = Math.max(min, value - step);
|
|
645
|
+
setValue(next);
|
|
646
|
+
onChange?.(next);
|
|
647
|
+
};
|
|
648
|
+
return /* @__PURE__ */ jsxs5(
|
|
649
|
+
"div",
|
|
650
|
+
{
|
|
651
|
+
ref,
|
|
652
|
+
className: cn(
|
|
653
|
+
"inline-flex items-center rounded-lg border border-border bg-card",
|
|
654
|
+
className
|
|
655
|
+
),
|
|
656
|
+
children: [
|
|
657
|
+
/* @__PURE__ */ jsx14(
|
|
658
|
+
Button,
|
|
659
|
+
{
|
|
660
|
+
variant: "ghost",
|
|
661
|
+
size: "icon",
|
|
662
|
+
className: "h-8 w-8 rounded-r-none",
|
|
663
|
+
onClick: handleDecrement,
|
|
664
|
+
disabled: value <= min,
|
|
665
|
+
children: /* @__PURE__ */ jsx14(Minus, { className: "h-3.5 w-3.5" })
|
|
666
|
+
}
|
|
667
|
+
),
|
|
668
|
+
/* @__PURE__ */ jsx14("span", { className: "w-10 text-center text-sm font-medium tabular-nums border-x border-border", children: value }),
|
|
669
|
+
/* @__PURE__ */ jsx14(
|
|
670
|
+
Button,
|
|
671
|
+
{
|
|
672
|
+
variant: "ghost",
|
|
673
|
+
size: "icon",
|
|
674
|
+
className: "h-8 w-8 rounded-l-none",
|
|
675
|
+
onClick: handleIncrement,
|
|
676
|
+
disabled: value >= max,
|
|
677
|
+
children: /* @__PURE__ */ jsx14(Plus, { className: "h-3.5 w-3.5" })
|
|
678
|
+
}
|
|
679
|
+
)
|
|
680
|
+
]
|
|
681
|
+
}
|
|
682
|
+
);
|
|
683
|
+
}
|
|
684
|
+
);
|
|
685
|
+
Counter.displayName = "Counter";
|
|
686
|
+
|
|
687
|
+
// src/components/extended/ArrowButton.tsx
|
|
688
|
+
import { forwardRef as forwardRef15 } from "react";
|
|
689
|
+
import { ChevronLeft, ChevronRight } from "lucide-react";
|
|
690
|
+
import { jsx as jsx15, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
691
|
+
var ArrowButton = forwardRef15(
|
|
692
|
+
({ direction = "right", text, className, children, ...props }, ref) => {
|
|
693
|
+
const Icon = direction === "left" ? ChevronLeft : ChevronRight;
|
|
694
|
+
return /* @__PURE__ */ jsxs6(
|
|
695
|
+
Button,
|
|
696
|
+
{
|
|
697
|
+
ref,
|
|
698
|
+
className: cn("gap-1", !text && !children && "px-2", className),
|
|
699
|
+
...props,
|
|
700
|
+
children: [
|
|
701
|
+
direction === "left" && /* @__PURE__ */ jsx15(Icon, { className: "h-4 w-4" }),
|
|
702
|
+
(text || children) && /* @__PURE__ */ jsx15("span", { children: text || children }),
|
|
703
|
+
direction === "right" && /* @__PURE__ */ jsx15(Icon, { className: "h-4 w-4" })
|
|
704
|
+
]
|
|
705
|
+
}
|
|
706
|
+
);
|
|
707
|
+
}
|
|
708
|
+
);
|
|
709
|
+
ArrowButton.displayName = "ArrowButton";
|
|
710
|
+
|
|
711
|
+
// src/components/extended/ChooseList.tsx
|
|
712
|
+
import { forwardRef as forwardRef16 } from "react";
|
|
713
|
+
import { ChevronDown } from "lucide-react";
|
|
714
|
+
import { jsx as jsx16, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
715
|
+
var ChooseList = forwardRef16(
|
|
716
|
+
({ className, options, ...props }, ref) => {
|
|
717
|
+
return /* @__PURE__ */ jsxs7("div", { className: "relative inline-block w-full", children: [
|
|
718
|
+
/* @__PURE__ */ jsx16(
|
|
719
|
+
"select",
|
|
720
|
+
{
|
|
721
|
+
ref,
|
|
722
|
+
className: cn(
|
|
723
|
+
"flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring appearance-none cursor-pointer pr-10",
|
|
724
|
+
className
|
|
725
|
+
),
|
|
726
|
+
...props,
|
|
727
|
+
children: options.map((opt) => /* @__PURE__ */ jsx16(
|
|
728
|
+
"option",
|
|
729
|
+
{
|
|
730
|
+
value: opt.value,
|
|
731
|
+
className: "bg-card text-foreground",
|
|
732
|
+
children: opt.label
|
|
733
|
+
},
|
|
734
|
+
opt.value
|
|
735
|
+
))
|
|
736
|
+
}
|
|
737
|
+
),
|
|
738
|
+
/* @__PURE__ */ jsx16("div", { className: "pointer-events-none absolute inset-y-0 right-0 flex items-center px-3 text-muted-foreground", children: /* @__PURE__ */ jsx16(ChevronDown, { className: "h-4 w-4" }) })
|
|
739
|
+
] });
|
|
740
|
+
}
|
|
741
|
+
);
|
|
742
|
+
ChooseList.displayName = "ChooseList";
|
|
743
|
+
|
|
744
|
+
// src/components/extended/Popup.tsx
|
|
745
|
+
import { forwardRef as forwardRef17, useEffect as useEffect3 } from "react";
|
|
746
|
+
import { X } from "lucide-react";
|
|
747
|
+
import { jsx as jsx17, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
748
|
+
var Popup = forwardRef17(
|
|
749
|
+
({ className, open, onClose, title, children, ...props }, ref) => {
|
|
750
|
+
useEffect3(() => {
|
|
751
|
+
if (open) {
|
|
752
|
+
document.body.style.overflow = "hidden";
|
|
753
|
+
} else {
|
|
754
|
+
document.body.style.overflow = "";
|
|
755
|
+
}
|
|
756
|
+
return () => {
|
|
757
|
+
document.body.style.overflow = "";
|
|
758
|
+
};
|
|
759
|
+
}, [open]);
|
|
760
|
+
useEffect3(() => {
|
|
761
|
+
const handleEscape = (e) => {
|
|
762
|
+
if (e.key === "Escape") onClose();
|
|
763
|
+
};
|
|
764
|
+
if (open) document.addEventListener("keydown", handleEscape);
|
|
765
|
+
return () => document.removeEventListener("keydown", handleEscape);
|
|
766
|
+
}, [open, onClose]);
|
|
767
|
+
if (!open) return null;
|
|
768
|
+
return /* @__PURE__ */ jsxs8("div", { className: "fixed inset-0 z-50 flex items-center justify-center p-4", children: [
|
|
769
|
+
/* @__PURE__ */ jsx17(
|
|
770
|
+
"div",
|
|
771
|
+
{
|
|
772
|
+
className: "fixed inset-0 bg-background/80 backdrop-blur-sm",
|
|
773
|
+
style: { animation: "popup-fade-in 0.15s ease-out" },
|
|
774
|
+
onClick: onClose
|
|
775
|
+
}
|
|
776
|
+
),
|
|
777
|
+
/* @__PURE__ */ jsxs8(
|
|
778
|
+
"div",
|
|
779
|
+
{
|
|
780
|
+
ref,
|
|
781
|
+
role: "dialog",
|
|
782
|
+
"aria-modal": "true",
|
|
783
|
+
className: cn(
|
|
784
|
+
"relative z-50 w-full max-w-lg rounded-xl border border-border bg-card p-6 shadow-2xl",
|
|
785
|
+
className
|
|
786
|
+
),
|
|
787
|
+
style: { animation: "popup-scale-in 0.15s ease-out" },
|
|
788
|
+
...props,
|
|
789
|
+
children: [
|
|
790
|
+
/* @__PURE__ */ jsxs8("div", { className: "flex items-center justify-between mb-4", children: [
|
|
791
|
+
title && /* @__PURE__ */ jsx17("h2", { className: "text-lg font-semibold tracking-tight", children: title }),
|
|
792
|
+
/* @__PURE__ */ jsx17(
|
|
793
|
+
Button,
|
|
794
|
+
{
|
|
795
|
+
variant: "ghost",
|
|
796
|
+
size: "icon",
|
|
797
|
+
className: "h-7 w-7 rounded-full ml-auto",
|
|
798
|
+
onClick: onClose,
|
|
799
|
+
"aria-label": "Close popup",
|
|
800
|
+
children: /* @__PURE__ */ jsx17(X, { className: "h-4 w-4" })
|
|
801
|
+
}
|
|
802
|
+
)
|
|
803
|
+
] }),
|
|
804
|
+
/* @__PURE__ */ jsx17("div", { className: "text-sm text-muted-foreground", children })
|
|
805
|
+
]
|
|
806
|
+
}
|
|
807
|
+
)
|
|
808
|
+
] });
|
|
809
|
+
}
|
|
810
|
+
);
|
|
811
|
+
Popup.displayName = "Popup";
|
|
812
|
+
|
|
813
|
+
// src/components/extended/StatusBar.tsx
|
|
814
|
+
import { forwardRef as forwardRef18 } from "react";
|
|
815
|
+
import { jsx as jsx18, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
816
|
+
var statusStyles = {
|
|
817
|
+
idle: "bg-muted-foreground",
|
|
818
|
+
working: "bg-[hsl(var(--blue))] animate-pulse",
|
|
819
|
+
error: "bg-[hsl(var(--orange))]",
|
|
820
|
+
ready: "bg-[hsl(var(--purple))]",
|
|
821
|
+
live: "bg-[hsl(var(--purple))] animate-pulse"
|
|
822
|
+
};
|
|
823
|
+
var StatusBar = forwardRef18(
|
|
824
|
+
({ className, status = "idle", label, children, ...props }, ref) => {
|
|
825
|
+
return /* @__PURE__ */ jsxs9(
|
|
826
|
+
"div",
|
|
827
|
+
{
|
|
828
|
+
ref,
|
|
829
|
+
role: "status",
|
|
830
|
+
className: cn(
|
|
831
|
+
"inline-flex items-center gap-2 rounded-full border border-border bg-card px-3 py-1",
|
|
832
|
+
className
|
|
833
|
+
),
|
|
834
|
+
...props,
|
|
835
|
+
children: [
|
|
836
|
+
/* @__PURE__ */ jsx18(
|
|
837
|
+
"span",
|
|
838
|
+
{
|
|
839
|
+
className: cn("h-2 w-2 rounded-full", statusStyles[status]),
|
|
840
|
+
"aria-hidden": "true"
|
|
841
|
+
}
|
|
842
|
+
),
|
|
843
|
+
/* @__PURE__ */ jsx18("span", { className: "text-xs font-semibold uppercase tracking-wider", children: label || status }),
|
|
844
|
+
children && /* @__PURE__ */ jsx18("span", { className: "text-xs text-muted-foreground border-l border-border pl-2", children })
|
|
845
|
+
]
|
|
846
|
+
}
|
|
847
|
+
);
|
|
848
|
+
}
|
|
849
|
+
);
|
|
850
|
+
StatusBar.displayName = "StatusBar";
|
|
851
|
+
|
|
852
|
+
// src/components/extended/WeekViewCalendar.tsx
|
|
853
|
+
import { forwardRef as forwardRef19 } from "react";
|
|
854
|
+
import { jsx as jsx19, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
855
|
+
var WeekViewCalendar = forwardRef19(({ className, events = [], startHour = 8, endHour = 18, ...props }, ref) => {
|
|
856
|
+
const days = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
|
|
857
|
+
const hours = Array.from(
|
|
858
|
+
{ length: endHour - startHour },
|
|
859
|
+
(_, i) => i + startHour
|
|
860
|
+
);
|
|
861
|
+
return /* @__PURE__ */ jsxs10(
|
|
862
|
+
"div",
|
|
863
|
+
{
|
|
864
|
+
ref,
|
|
865
|
+
className: cn(
|
|
866
|
+
"flex flex-col rounded-lg border border-border overflow-hidden bg-card",
|
|
867
|
+
className
|
|
868
|
+
),
|
|
869
|
+
...props,
|
|
870
|
+
children: [
|
|
871
|
+
/* @__PURE__ */ jsxs10("div", { className: "grid grid-cols-8 border-b border-border bg-muted/30", children: [
|
|
872
|
+
/* @__PURE__ */ jsx19("div", { className: "flex items-center justify-center border-r border-border p-2 text-xs font-medium text-muted-foreground w-16", children: "Time" }),
|
|
873
|
+
days.map((day, i) => /* @__PURE__ */ jsx19(
|
|
874
|
+
"div",
|
|
875
|
+
{
|
|
876
|
+
className: cn(
|
|
877
|
+
"p-2 text-center text-sm font-semibold",
|
|
878
|
+
i < 6 && "border-r border-border"
|
|
879
|
+
),
|
|
880
|
+
children: day
|
|
881
|
+
},
|
|
882
|
+
day
|
|
883
|
+
))
|
|
884
|
+
] }),
|
|
885
|
+
/* @__PURE__ */ jsxs10("div", { className: "relative overflow-y-auto max-h-[500px] custom-scrollbar", children: [
|
|
886
|
+
hours.map((hour, hIndex) => /* @__PURE__ */ jsxs10(
|
|
887
|
+
"div",
|
|
888
|
+
{
|
|
889
|
+
className: cn(
|
|
890
|
+
"grid grid-cols-8",
|
|
891
|
+
hIndex < hours.length - 1 && "border-b border-border/50"
|
|
892
|
+
),
|
|
893
|
+
children: [
|
|
894
|
+
/* @__PURE__ */ jsx19("div", { className: "flex items-start justify-center border-r border-border p-2 text-xs text-muted-foreground w-16 sticky left-0 bg-card", children: `${hour === 0 ? 12 : hour > 12 ? hour - 12 : hour} ${hour >= 12 ? "PM" : "AM"}` }),
|
|
895
|
+
days.map((_, dIndex) => /* @__PURE__ */ jsx19(
|
|
896
|
+
"div",
|
|
897
|
+
{
|
|
898
|
+
className: cn(
|
|
899
|
+
"h-16 relative",
|
|
900
|
+
dIndex < 6 && "border-r border-border/50"
|
|
901
|
+
)
|
|
902
|
+
},
|
|
903
|
+
dIndex
|
|
904
|
+
))
|
|
905
|
+
]
|
|
906
|
+
},
|
|
907
|
+
hour
|
|
908
|
+
)),
|
|
909
|
+
/* @__PURE__ */ jsx19(
|
|
910
|
+
"div",
|
|
911
|
+
{
|
|
912
|
+
className: "absolute inset-0 z-10 pointer-events-none",
|
|
913
|
+
style: { paddingLeft: "4rem" },
|
|
914
|
+
children: /* @__PURE__ */ jsx19("div", { className: "relative w-full h-full", children: events.map((event) => {
|
|
915
|
+
if (event.startHour < startHour || event.startHour >= endHour)
|
|
916
|
+
return null;
|
|
917
|
+
const top = (event.startHour - startHour) / (endHour - startHour) * 100;
|
|
918
|
+
const height = event.durationHours / (endHour - startHour) * 100;
|
|
919
|
+
const left = event.dayIndex / 7 * 100;
|
|
920
|
+
const width = 100 / 7;
|
|
921
|
+
return /* @__PURE__ */ jsx19(
|
|
922
|
+
"div",
|
|
923
|
+
{
|
|
924
|
+
className: "absolute p-0.5 pointer-events-auto",
|
|
925
|
+
style: {
|
|
926
|
+
top: `${top}%`,
|
|
927
|
+
left: `${left}%`,
|
|
928
|
+
height: `${height}%`,
|
|
929
|
+
width: `${width}%`
|
|
930
|
+
},
|
|
931
|
+
children: /* @__PURE__ */ jsx19(
|
|
932
|
+
"div",
|
|
933
|
+
{
|
|
934
|
+
className: "h-full w-full rounded-md border border-white/10 p-1.5 text-xs font-semibold text-white overflow-hidden shadow-sm transition-transform hover:scale-[1.02] hover:shadow-md cursor-pointer",
|
|
935
|
+
style: {
|
|
936
|
+
backgroundColor: event.color || "hsl(var(--primary))"
|
|
937
|
+
},
|
|
938
|
+
title: event.title,
|
|
939
|
+
children: event.title
|
|
940
|
+
}
|
|
941
|
+
)
|
|
942
|
+
},
|
|
943
|
+
event.id
|
|
944
|
+
);
|
|
945
|
+
}) })
|
|
946
|
+
}
|
|
947
|
+
)
|
|
948
|
+
] })
|
|
949
|
+
]
|
|
950
|
+
}
|
|
951
|
+
);
|
|
952
|
+
});
|
|
953
|
+
WeekViewCalendar.displayName = "WeekViewCalendar";
|
|
954
|
+
export {
|
|
955
|
+
ArrowButton,
|
|
956
|
+
Badge,
|
|
957
|
+
Button,
|
|
958
|
+
Card,
|
|
959
|
+
CardContent,
|
|
960
|
+
CardDescription,
|
|
961
|
+
CardFooter,
|
|
962
|
+
CardHeader,
|
|
963
|
+
CardTitle,
|
|
964
|
+
Checkbox,
|
|
965
|
+
ChooseList,
|
|
966
|
+
Counter,
|
|
967
|
+
HighlightText,
|
|
968
|
+
Input,
|
|
969
|
+
Popup,
|
|
970
|
+
ProgressBar,
|
|
971
|
+
Separator,
|
|
972
|
+
StatusBar,
|
|
973
|
+
Switch,
|
|
974
|
+
Table,
|
|
975
|
+
TableBody,
|
|
976
|
+
TableCell,
|
|
977
|
+
TableHead,
|
|
978
|
+
TableHeader,
|
|
979
|
+
TableRow,
|
|
980
|
+
Tabs,
|
|
981
|
+
TabsContent,
|
|
982
|
+
TabsList,
|
|
983
|
+
TabsTrigger,
|
|
984
|
+
ThemeToggle,
|
|
985
|
+
Tooltip,
|
|
986
|
+
WeekViewCalendar,
|
|
987
|
+
cn
|
|
988
|
+
};
|