@marcoschwartz/lite-ui 0.1.1 → 0.3.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 +238 -134
- package/dist/index.d.mts +569 -2
- package/dist/index.d.ts +569 -2
- package/dist/index.js +4289 -52
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +4179 -53
- package/dist/index.mjs.map +1 -1
- package/dist/styles.css +1 -1
- package/package.json +9 -2
package/dist/index.mjs
CHANGED
|
@@ -8,7 +8,7 @@ var themes = {
|
|
|
8
8
|
default: {
|
|
9
9
|
name: "default",
|
|
10
10
|
button: {
|
|
11
|
-
base: "font-semibold rounded-lg transition-all duration-150 focus:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 active:scale-95",
|
|
11
|
+
base: "font-semibold rounded-lg transition-all duration-150 focus:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 active:scale-95 gap-2",
|
|
12
12
|
variants: {
|
|
13
13
|
primary: "bg-blue-600 hover:bg-blue-700 active:bg-blue-800 text-white shadow-sm hover:shadow-md dark:bg-blue-500 dark:hover:bg-blue-600 dark:active:bg-blue-700",
|
|
14
14
|
secondary: "bg-gray-600 hover:bg-gray-700 active:bg-gray-800 text-white shadow-sm hover:shadow-md dark:bg-gray-500 dark:hover:bg-gray-600 dark:active:bg-gray-700",
|
|
@@ -18,15 +18,15 @@ var themes = {
|
|
|
18
18
|
info: "bg-cyan-600 hover:bg-cyan-700 active:bg-cyan-800 text-white shadow-sm hover:shadow-md dark:bg-cyan-500 dark:hover:bg-cyan-600 dark:active:bg-cyan-700"
|
|
19
19
|
},
|
|
20
20
|
sizes: {
|
|
21
|
-
sm: "px-3 py-1.5 text-sm",
|
|
22
|
-
md: "px-4 py-2 text-base",
|
|
23
|
-
lg: "px-6 py-3 text-lg",
|
|
24
|
-
xl: "px-8 py-4 text-xl"
|
|
21
|
+
sm: "px-3 py-1.5 text-sm min-h-[30px]",
|
|
22
|
+
md: "px-4 py-2 text-base min-h-[38px]",
|
|
23
|
+
lg: "px-6 py-3 text-lg min-h-[48px]",
|
|
24
|
+
xl: "px-8 py-4 text-xl min-h-[60px]"
|
|
25
25
|
},
|
|
26
26
|
disabled: "opacity-50 cursor-not-allowed hover:shadow-sm active:scale-100"
|
|
27
27
|
},
|
|
28
28
|
select: {
|
|
29
|
-
base: "w-full appearance-none rounded-lg border border-gray-300 bg-white text-gray-900 transition-all duration-150 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent shadow-sm hover:border-gray-400 pr-10 cursor-pointer dark:bg-gray-800 dark:border-gray-600 dark:text-gray-100 dark:hover:border-gray-500",
|
|
29
|
+
base: "w-full appearance-none rounded-lg border border-gray-300 bg-white text-gray-900 text-left transition-all duration-150 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent shadow-sm hover:border-gray-400 pr-10 cursor-pointer dark:bg-gray-800 dark:border-gray-600 dark:text-gray-100 dark:hover:border-gray-500",
|
|
30
30
|
sizes: {
|
|
31
31
|
sm: "px-3 py-1.5 text-sm",
|
|
32
32
|
md: "px-4 py-2.5 text-base",
|
|
@@ -39,7 +39,7 @@ var themes = {
|
|
|
39
39
|
minimalistic: {
|
|
40
40
|
name: "minimalistic",
|
|
41
41
|
button: {
|
|
42
|
-
base: "font-normal rounded-none transition-colors duration-200 focus:outline-none border-2",
|
|
42
|
+
base: "font-normal rounded-none transition-colors duration-200 focus:outline-none border-2 gap-2",
|
|
43
43
|
variants: {
|
|
44
44
|
primary: "bg-transparent border-white text-white hover:bg-white hover:text-black",
|
|
45
45
|
secondary: "bg-transparent border-gray-400 text-gray-400 hover:bg-gray-400 hover:text-black",
|
|
@@ -49,15 +49,15 @@ var themes = {
|
|
|
49
49
|
info: "bg-transparent border-blue-400 text-blue-400 hover:bg-blue-400 hover:text-black"
|
|
50
50
|
},
|
|
51
51
|
sizes: {
|
|
52
|
-
sm: "px-4 py-2 text-sm uppercase tracking-wide",
|
|
53
|
-
md: "px-6 py-3 text-base uppercase tracking-wide",
|
|
54
|
-
lg: "px-8 py-4 text-lg uppercase tracking-wider",
|
|
55
|
-
xl: "px-10 py-5 text-xl uppercase tracking-wider"
|
|
52
|
+
sm: "px-4 py-2 text-sm uppercase tracking-wide min-h-[36px]",
|
|
53
|
+
md: "px-6 py-3 text-base uppercase tracking-wide min-h-[48px]",
|
|
54
|
+
lg: "px-8 py-4 text-lg uppercase tracking-wider min-h-[60px]",
|
|
55
|
+
xl: "px-10 py-5 text-xl uppercase tracking-wider min-h-[72px]"
|
|
56
56
|
},
|
|
57
57
|
disabled: "opacity-30 cursor-not-allowed hover:bg-transparent"
|
|
58
58
|
},
|
|
59
59
|
select: {
|
|
60
|
-
base: "w-full appearance-none rounded-none border-2 border-white bg-transparent text-white transition-colors duration-200 focus:outline-none pr-10 cursor-pointer placeholder:text-gray-500",
|
|
60
|
+
base: "w-full appearance-none rounded-none border-2 border-white bg-transparent text-white text-left transition-colors duration-200 focus:outline-none pr-10 cursor-pointer placeholder:text-gray-500",
|
|
61
61
|
sizes: {
|
|
62
62
|
sm: "px-4 py-2 text-sm uppercase tracking-wide",
|
|
63
63
|
md: "px-4 py-3 text-base uppercase tracking-wide",
|
|
@@ -75,7 +75,20 @@ var ThemeContext = createContext(void 0);
|
|
|
75
75
|
function useTheme() {
|
|
76
76
|
const context = useContext(ThemeContext);
|
|
77
77
|
if (!context) {
|
|
78
|
-
|
|
78
|
+
const warnOnce = () => {
|
|
79
|
+
if (process.env.NODE_ENV === "development") {
|
|
80
|
+
console.warn("useTheme: Component used outside ThemeProvider. Using default theme. Wrap your app with <ThemeProvider> for full functionality.");
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
return {
|
|
84
|
+
theme: themes.default,
|
|
85
|
+
themeName: "default",
|
|
86
|
+
setTheme: () => warnOnce(),
|
|
87
|
+
colorMode: "light",
|
|
88
|
+
setColorMode: () => warnOnce(),
|
|
89
|
+
toggleColorMode: () => warnOnce(),
|
|
90
|
+
resolvedColorMode: "light"
|
|
91
|
+
};
|
|
79
92
|
}
|
|
80
93
|
return context;
|
|
81
94
|
}
|
|
@@ -123,6 +136,13 @@ function ThemeProvider({
|
|
|
123
136
|
document.documentElement.classList.remove("dark");
|
|
124
137
|
}
|
|
125
138
|
};
|
|
139
|
+
const toggleColorMode = () => {
|
|
140
|
+
if (colorMode === "system") {
|
|
141
|
+
setColorMode(resolvedColorMode === "dark" ? "light" : "dark");
|
|
142
|
+
} else {
|
|
143
|
+
setColorMode(colorMode === "dark" ? "light" : "dark");
|
|
144
|
+
}
|
|
145
|
+
};
|
|
126
146
|
useEffect(() => {
|
|
127
147
|
if (!mounted) return;
|
|
128
148
|
const mediaQuery = window.matchMedia("(prefers-color-scheme: dark)");
|
|
@@ -147,40 +167,49 @@ function ThemeProvider({
|
|
|
147
167
|
setTheme,
|
|
148
168
|
colorMode,
|
|
149
169
|
setColorMode,
|
|
170
|
+
toggleColorMode,
|
|
150
171
|
resolvedColorMode
|
|
151
172
|
}, children });
|
|
152
173
|
}
|
|
153
174
|
|
|
154
175
|
// src/components/Button.tsx
|
|
155
|
-
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
176
|
+
import { Fragment, jsx as jsx2, jsxs } from "react/jsx-runtime";
|
|
156
177
|
var Button = ({
|
|
157
178
|
variant = "primary",
|
|
158
179
|
size = "md",
|
|
159
180
|
className = "",
|
|
160
181
|
children,
|
|
161
182
|
disabled,
|
|
183
|
+
leftIcon,
|
|
184
|
+
rightIcon,
|
|
185
|
+
iconOnly = false,
|
|
162
186
|
...props
|
|
163
187
|
}) => {
|
|
164
188
|
const { theme } = useTheme();
|
|
165
189
|
const baseStyles = theme.button.base;
|
|
166
|
-
const
|
|
167
|
-
const
|
|
190
|
+
const variantStyles3 = theme.button.variants[variant];
|
|
191
|
+
const sizeStyles2 = theme.button.sizes[size];
|
|
168
192
|
const disabledStyles = disabled ? theme.button.disabled : "";
|
|
169
|
-
const
|
|
193
|
+
const iconOnlyStyles = iconOnly ? "!p-0 aspect-square" : "";
|
|
194
|
+
const classes = `inline-flex items-center justify-center ${baseStyles} ${variantStyles3} ${sizeStyles2} ${disabledStyles} ${iconOnlyStyles} ${className}`.trim();
|
|
170
195
|
return /* @__PURE__ */ jsx2(
|
|
171
196
|
"button",
|
|
172
197
|
{
|
|
173
198
|
className: classes,
|
|
174
199
|
disabled,
|
|
175
200
|
...props,
|
|
176
|
-
children
|
|
201
|
+
children: iconOnly ? children : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
202
|
+
leftIcon && /* @__PURE__ */ jsx2("span", { className: "inline-flex shrink-0", children: leftIcon }),
|
|
203
|
+
children && /* @__PURE__ */ jsx2("span", { className: "inline-flex items-center", children }),
|
|
204
|
+
rightIcon && /* @__PURE__ */ jsx2("span", { className: "inline-flex shrink-0", children: rightIcon })
|
|
205
|
+
] })
|
|
177
206
|
}
|
|
178
207
|
);
|
|
179
208
|
};
|
|
180
209
|
|
|
181
210
|
// src/components/Select.tsx
|
|
182
211
|
import { useState as useState2, useRef, useEffect as useEffect2 } from "react";
|
|
183
|
-
import { jsx as jsx3, jsxs } from "react/jsx-runtime";
|
|
212
|
+
import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
184
213
|
var Select = ({
|
|
185
214
|
options,
|
|
186
215
|
size = "md",
|
|
@@ -190,19 +219,30 @@ var Select = ({
|
|
|
190
219
|
value: controlledValue,
|
|
191
220
|
defaultValue,
|
|
192
221
|
onChange,
|
|
222
|
+
label,
|
|
223
|
+
error,
|
|
224
|
+
helperText,
|
|
225
|
+
searchable = false,
|
|
226
|
+
searchPlaceholder = "Search...",
|
|
193
227
|
...props
|
|
194
228
|
}) => {
|
|
195
229
|
const { theme, themeName } = useTheme();
|
|
196
230
|
const [isOpen, setIsOpen] = useState2(false);
|
|
197
231
|
const [internalValue, setInternalValue] = useState2(defaultValue || "");
|
|
232
|
+
const [searchQuery, setSearchQuery] = useState2("");
|
|
198
233
|
const dropdownRef = useRef(null);
|
|
234
|
+
const searchInputRef = useRef(null);
|
|
199
235
|
const value = controlledValue !== void 0 ? controlledValue : internalValue;
|
|
200
236
|
const selectedOption = options.find((opt) => opt.value === value);
|
|
201
237
|
const displayText = selectedOption ? selectedOption.label : placeholder || "Select...";
|
|
238
|
+
const filteredOptions = searchable && searchQuery ? options.filter(
|
|
239
|
+
(option) => option.label.toLowerCase().includes(searchQuery.toLowerCase())
|
|
240
|
+
) : options;
|
|
202
241
|
useEffect2(() => {
|
|
203
242
|
const handleClickOutside = (event) => {
|
|
204
243
|
if (dropdownRef.current && !dropdownRef.current.contains(event.target)) {
|
|
205
244
|
setIsOpen(false);
|
|
245
|
+
setSearchQuery("");
|
|
206
246
|
}
|
|
207
247
|
};
|
|
208
248
|
if (isOpen) {
|
|
@@ -210,11 +250,17 @@ var Select = ({
|
|
|
210
250
|
return () => document.removeEventListener("mousedown", handleClickOutside);
|
|
211
251
|
}
|
|
212
252
|
}, [isOpen]);
|
|
253
|
+
useEffect2(() => {
|
|
254
|
+
if (isOpen && searchable && searchInputRef.current) {
|
|
255
|
+
searchInputRef.current.focus();
|
|
256
|
+
}
|
|
257
|
+
}, [isOpen, searchable]);
|
|
213
258
|
const handleSelect = (optionValue) => {
|
|
214
259
|
if (disabled) return;
|
|
215
260
|
setInternalValue(optionValue);
|
|
216
261
|
onChange?.(optionValue);
|
|
217
262
|
setIsOpen(false);
|
|
263
|
+
setSearchQuery("");
|
|
218
264
|
};
|
|
219
265
|
const handleToggle = () => {
|
|
220
266
|
if (!disabled) {
|
|
@@ -222,9 +268,10 @@ var Select = ({
|
|
|
222
268
|
}
|
|
223
269
|
};
|
|
224
270
|
const baseStyles = theme.select.base;
|
|
225
|
-
const
|
|
271
|
+
const sizeStyles2 = theme.select.sizes[size];
|
|
226
272
|
const disabledStyles = disabled ? theme.select.disabled : "";
|
|
227
|
-
const
|
|
273
|
+
const errorStyles = error ? "border-red-500 focus:ring-red-500 dark:border-red-500" : "";
|
|
274
|
+
const buttonClasses = `${baseStyles} ${sizeStyles2} ${disabledStyles} ${errorStyles}`.trim();
|
|
228
275
|
const iconColor = themeName === "minimalistic" ? disabled ? "text-gray-600" : "text-white" : disabled ? "text-gray-400" : "text-gray-500";
|
|
229
276
|
const dropdownBaseStyles = themeName === "minimalistic" ? "bg-black border-2 border-white" : "bg-white border border-gray-300 shadow-lg dark:bg-gray-800 dark:border-gray-600";
|
|
230
277
|
const optionBaseStyles = themeName === "minimalistic" ? "text-white hover:bg-white hover:text-black transition-colors duration-200" : "text-gray-900 hover:bg-blue-50 transition-colors duration-150 dark:text-gray-100 dark:hover:bg-gray-700";
|
|
@@ -234,51 +281,4029 @@ var Select = ({
|
|
|
234
281
|
lg: "px-4 py-3 text-lg",
|
|
235
282
|
xl: "px-5 py-4 text-xl"
|
|
236
283
|
}[size];
|
|
237
|
-
return /* @__PURE__ */
|
|
238
|
-
/* @__PURE__ */ jsx3(
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
284
|
+
return /* @__PURE__ */ jsxs2("div", { className: `w-full ${className}`, children: [
|
|
285
|
+
label && /* @__PURE__ */ jsx3("label", { className: "block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1", children: label }),
|
|
286
|
+
/* @__PURE__ */ jsxs2("div", { className: "relative inline-block w-full", ref: dropdownRef, ...props, children: [
|
|
287
|
+
/* @__PURE__ */ jsx3(
|
|
288
|
+
"button",
|
|
289
|
+
{
|
|
290
|
+
type: "button",
|
|
291
|
+
className: buttonClasses,
|
|
292
|
+
onClick: handleToggle,
|
|
293
|
+
disabled,
|
|
294
|
+
children: /* @__PURE__ */ jsx3("span", { className: !selectedOption && placeholder ? "opacity-50" : "", children: displayText })
|
|
295
|
+
}
|
|
296
|
+
),
|
|
297
|
+
/* @__PURE__ */ jsx3("div", { className: "pointer-events-none absolute inset-y-0 right-0 flex items-center pr-4", children: /* @__PURE__ */ jsx3(
|
|
298
|
+
"svg",
|
|
299
|
+
{
|
|
300
|
+
className: `h-5 w-5 transition-transform duration-200 ${iconColor} ${isOpen ? "rotate-180" : ""}`,
|
|
301
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
302
|
+
viewBox: "0 0 20 20",
|
|
303
|
+
fill: "currentColor",
|
|
304
|
+
"aria-hidden": "true",
|
|
305
|
+
children: /* @__PURE__ */ jsx3(
|
|
306
|
+
"path",
|
|
307
|
+
{
|
|
308
|
+
fillRule: "evenodd",
|
|
309
|
+
d: "M5.23 7.21a.75.75 0 011.06.02L10 11.168l3.71-3.938a.75.75 0 111.08 1.04l-4.25 4.5a.75.75 0 01-1.08 0l-4.25-4.5a.75.75 0 01.02-1.06z",
|
|
310
|
+
clipRule: "evenodd"
|
|
311
|
+
}
|
|
312
|
+
)
|
|
313
|
+
}
|
|
314
|
+
) }),
|
|
315
|
+
isOpen && !disabled && /* @__PURE__ */ jsxs2(
|
|
316
|
+
"div",
|
|
317
|
+
{
|
|
318
|
+
className: `absolute z-50 w-full mt-1 ${dropdownBaseStyles} rounded-lg overflow-hidden`,
|
|
319
|
+
children: [
|
|
320
|
+
searchable && /* @__PURE__ */ jsx3("div", { className: `sticky top-0 ${themeName === "minimalistic" ? "bg-black border-b-2 border-white" : "bg-white dark:bg-gray-800 border-b border-gray-200 dark:border-gray-700"}`, children: /* @__PURE__ */ jsx3(
|
|
321
|
+
"input",
|
|
322
|
+
{
|
|
323
|
+
ref: searchInputRef,
|
|
324
|
+
type: "text",
|
|
325
|
+
className: `w-full ${optionSizeStyles} ${themeName === "minimalistic" ? "bg-black text-white placeholder-gray-600 focus:outline-none" : "bg-transparent text-gray-900 dark:text-gray-100 placeholder-gray-400 focus:outline-none"}`,
|
|
326
|
+
placeholder: searchPlaceholder,
|
|
327
|
+
value: searchQuery,
|
|
328
|
+
onChange: (e) => setSearchQuery(e.target.value),
|
|
329
|
+
onClick: (e) => e.stopPropagation()
|
|
330
|
+
}
|
|
331
|
+
) }),
|
|
332
|
+
/* @__PURE__ */ jsx3("style", { children: `
|
|
333
|
+
.select-dropdown-scroll {
|
|
334
|
+
scrollbar-width: thin;
|
|
335
|
+
scrollbar-color: rgba(156, 163, 175, 0.5) transparent;
|
|
336
|
+
}
|
|
337
|
+
.select-dropdown-scroll::-webkit-scrollbar {
|
|
338
|
+
width: 8px;
|
|
339
|
+
}
|
|
340
|
+
.select-dropdown-scroll::-webkit-scrollbar-track {
|
|
341
|
+
background: transparent;
|
|
342
|
+
}
|
|
343
|
+
.select-dropdown-scroll::-webkit-scrollbar-thumb {
|
|
344
|
+
background-color: rgba(156, 163, 175, 0.5);
|
|
345
|
+
border-radius: 4px;
|
|
346
|
+
border: 2px solid transparent;
|
|
347
|
+
background-clip: padding-box;
|
|
348
|
+
}
|
|
349
|
+
.select-dropdown-scroll::-webkit-scrollbar-thumb:hover {
|
|
350
|
+
background-color: rgba(156, 163, 175, 0.7);
|
|
351
|
+
}
|
|
352
|
+
.dark .select-dropdown-scroll {
|
|
353
|
+
scrollbar-color: rgba(75, 85, 99, 0.6) transparent;
|
|
354
|
+
}
|
|
355
|
+
.dark .select-dropdown-scroll::-webkit-scrollbar-thumb {
|
|
356
|
+
background-color: rgba(75, 85, 99, 0.6);
|
|
357
|
+
}
|
|
358
|
+
.dark .select-dropdown-scroll::-webkit-scrollbar-thumb:hover {
|
|
359
|
+
background-color: rgba(75, 85, 99, 0.8);
|
|
360
|
+
}
|
|
361
|
+
` }),
|
|
362
|
+
/* @__PURE__ */ jsx3(
|
|
363
|
+
"div",
|
|
364
|
+
{
|
|
365
|
+
className: "select-dropdown-scroll",
|
|
366
|
+
style: { maxHeight: "300px", overflowY: "auto" },
|
|
367
|
+
children: filteredOptions.length > 0 ? filteredOptions.map((option) => /* @__PURE__ */ jsx3(
|
|
368
|
+
"div",
|
|
369
|
+
{
|
|
370
|
+
className: `${optionBaseStyles} ${optionSizeStyles} cursor-pointer ${value === option.value ? themeName === "minimalistic" ? "bg-white text-black" : "bg-blue-50 dark:bg-gray-700" : ""}`,
|
|
371
|
+
onClick: () => handleSelect(option.value),
|
|
372
|
+
children: option.label
|
|
373
|
+
},
|
|
374
|
+
option.value
|
|
375
|
+
)) : /* @__PURE__ */ jsx3("div", { className: `${optionSizeStyles} ${themeName === "minimalistic" ? "text-gray-500" : "text-gray-500 dark:text-gray-400"} text-center`, children: "No results found" })
|
|
376
|
+
}
|
|
377
|
+
)
|
|
378
|
+
]
|
|
379
|
+
}
|
|
380
|
+
)
|
|
381
|
+
] }),
|
|
382
|
+
error && /* @__PURE__ */ jsx3("p", { className: "mt-1 text-sm text-red-600 dark:text-red-400", children: error }),
|
|
383
|
+
helperText && !error && /* @__PURE__ */ jsx3("p", { className: "mt-1 text-sm text-gray-500 dark:text-gray-400", children: helperText })
|
|
384
|
+
] });
|
|
385
|
+
};
|
|
386
|
+
|
|
387
|
+
// src/components/Modal.tsx
|
|
388
|
+
import { useEffect as useEffect3 } from "react";
|
|
389
|
+
import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
390
|
+
var sizeClasses = {
|
|
391
|
+
sm: "max-w-md",
|
|
392
|
+
md: "max-w-lg",
|
|
393
|
+
lg: "max-w-2xl",
|
|
394
|
+
xl: "max-w-4xl"
|
|
395
|
+
};
|
|
396
|
+
var Modal = ({
|
|
397
|
+
isOpen,
|
|
398
|
+
onClose,
|
|
399
|
+
title,
|
|
400
|
+
children,
|
|
401
|
+
size = "md",
|
|
402
|
+
showCloseButton = true
|
|
403
|
+
}) => {
|
|
404
|
+
const { theme } = useTheme();
|
|
405
|
+
useEffect3(() => {
|
|
406
|
+
const handleEscape = (e) => {
|
|
407
|
+
if (e.key === "Escape" && isOpen) {
|
|
408
|
+
onClose();
|
|
246
409
|
}
|
|
247
|
-
|
|
248
|
-
|
|
410
|
+
};
|
|
411
|
+
if (isOpen) {
|
|
412
|
+
document.addEventListener("keydown", handleEscape);
|
|
413
|
+
document.body.style.overflow = "hidden";
|
|
414
|
+
}
|
|
415
|
+
return () => {
|
|
416
|
+
document.removeEventListener("keydown", handleEscape);
|
|
417
|
+
document.body.style.overflow = "unset";
|
|
418
|
+
};
|
|
419
|
+
}, [isOpen, onClose]);
|
|
420
|
+
if (!isOpen) return null;
|
|
421
|
+
const sizeClass = sizeClasses[size];
|
|
422
|
+
return /* @__PURE__ */ jsx4(
|
|
423
|
+
"div",
|
|
424
|
+
{
|
|
425
|
+
className: "fixed inset-0 z-50 flex items-center justify-center p-4 bg-black/60 backdrop-blur-sm transition-all duration-200",
|
|
426
|
+
onClick: onClose,
|
|
427
|
+
role: "dialog",
|
|
428
|
+
"aria-modal": "true",
|
|
429
|
+
"aria-labelledby": title ? "modal-title" : void 0,
|
|
430
|
+
children: /* @__PURE__ */ jsxs3(
|
|
431
|
+
"div",
|
|
432
|
+
{
|
|
433
|
+
className: `relative w-full ${sizeClass} bg-white dark:bg-gray-800 rounded-lg shadow-2xl transform transition-all duration-200 scale-100 animate-in`,
|
|
434
|
+
onClick: (e) => e.stopPropagation(),
|
|
435
|
+
children: [
|
|
436
|
+
(title || showCloseButton) && /* @__PURE__ */ jsxs3("div", { className: "flex items-center justify-between p-6 border-b border-gray-200 dark:border-gray-700", children: [
|
|
437
|
+
title && /* @__PURE__ */ jsx4("h3", { id: "modal-title", className: "text-xl font-semibold text-gray-900 dark:text-gray-100", children: title }),
|
|
438
|
+
showCloseButton && /* @__PURE__ */ jsx4(
|
|
439
|
+
"button",
|
|
440
|
+
{
|
|
441
|
+
onClick: onClose,
|
|
442
|
+
className: "ml-auto text-gray-400 hover:text-gray-600 dark:hover:text-gray-300 transition-colors",
|
|
443
|
+
"aria-label": "Close modal",
|
|
444
|
+
children: /* @__PURE__ */ jsx4("svg", { className: "w-6 h-6", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ jsx4("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M6 18L18 6M6 6l12 12" }) })
|
|
445
|
+
}
|
|
446
|
+
)
|
|
447
|
+
] }),
|
|
448
|
+
/* @__PURE__ */ jsx4("div", { className: "p-6", children })
|
|
449
|
+
]
|
|
450
|
+
}
|
|
451
|
+
)
|
|
452
|
+
}
|
|
453
|
+
);
|
|
454
|
+
};
|
|
455
|
+
|
|
456
|
+
// src/components/Navbar.tsx
|
|
457
|
+
import { jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
458
|
+
var Navbar = ({
|
|
459
|
+
logo,
|
|
460
|
+
children,
|
|
461
|
+
className = "",
|
|
462
|
+
sticky = false
|
|
463
|
+
}) => {
|
|
464
|
+
const { theme } = useTheme();
|
|
465
|
+
const baseClasses = sticky ? "sticky top-0 z-40" : "";
|
|
466
|
+
return /* @__PURE__ */ jsx5("nav", { className: `bg-white dark:bg-gray-800 border-b border-gray-200 dark:border-gray-700 ${baseClasses} ${className}`, children: /* @__PURE__ */ jsx5("div", { className: "max-w-7xl mx-auto px-4 sm:px-6 lg:px-8", children: /* @__PURE__ */ jsxs4("div", { className: "flex justify-between items-center h-16", children: [
|
|
467
|
+
logo && /* @__PURE__ */ jsx5("div", { className: "flex items-center", children: logo }),
|
|
468
|
+
children && /* @__PURE__ */ jsx5("div", { className: "flex items-center gap-6", children })
|
|
469
|
+
] }) }) });
|
|
470
|
+
};
|
|
471
|
+
|
|
472
|
+
// src/components/Sidebar.tsx
|
|
473
|
+
import { jsx as jsx6 } from "react/jsx-runtime";
|
|
474
|
+
var widthClasses = {
|
|
475
|
+
sm: "w-48",
|
|
476
|
+
md: "w-64",
|
|
477
|
+
lg: "w-80"
|
|
478
|
+
};
|
|
479
|
+
var Sidebar = ({
|
|
480
|
+
children,
|
|
481
|
+
className = "",
|
|
482
|
+
width = "md",
|
|
483
|
+
position = "left"
|
|
484
|
+
}) => {
|
|
485
|
+
const { theme } = useTheme();
|
|
486
|
+
const widthClass = widthClasses[width];
|
|
487
|
+
const borderClass = position === "left" ? "border-r" : "border-l";
|
|
488
|
+
return /* @__PURE__ */ jsx6(
|
|
489
|
+
"aside",
|
|
490
|
+
{
|
|
491
|
+
className: `${widthClass} bg-white dark:bg-gray-800 ${borderClass} border-gray-200 dark:border-gray-700 h-full overflow-y-auto ${className}`,
|
|
492
|
+
children
|
|
493
|
+
}
|
|
494
|
+
);
|
|
495
|
+
};
|
|
496
|
+
|
|
497
|
+
// src/components/SidebarProvider.tsx
|
|
498
|
+
import { createContext as createContext2, useContext as useContext2, useState as useState3 } from "react";
|
|
499
|
+
import { jsx as jsx7 } from "react/jsx-runtime";
|
|
500
|
+
var SidebarContext = createContext2(void 0);
|
|
501
|
+
var SidebarProvider = ({
|
|
502
|
+
children,
|
|
503
|
+
defaultOpen = false
|
|
504
|
+
}) => {
|
|
505
|
+
const [isOpen, setIsOpen] = useState3(defaultOpen);
|
|
506
|
+
const [isMobile, setIsMobile] = useState3(false);
|
|
507
|
+
const open = () => setIsOpen(true);
|
|
508
|
+
const close = () => setIsOpen(false);
|
|
509
|
+
const toggle = () => setIsOpen((prev) => !prev);
|
|
510
|
+
const value = {
|
|
511
|
+
isOpen,
|
|
512
|
+
isMobile,
|
|
513
|
+
open,
|
|
514
|
+
close,
|
|
515
|
+
toggle,
|
|
516
|
+
setIsMobile
|
|
517
|
+
};
|
|
518
|
+
return /* @__PURE__ */ jsx7(SidebarContext.Provider, { value, children });
|
|
519
|
+
};
|
|
520
|
+
var useSidebar = () => {
|
|
521
|
+
const context = useContext2(SidebarContext);
|
|
522
|
+
if (!context) {
|
|
523
|
+
throw new Error("useSidebar must be used within a SidebarProvider");
|
|
524
|
+
}
|
|
525
|
+
return context;
|
|
526
|
+
};
|
|
527
|
+
|
|
528
|
+
// src/components/AppShell.tsx
|
|
529
|
+
import { useState as useState4 } from "react";
|
|
530
|
+
|
|
531
|
+
// src/icons/icon-utils.tsx
|
|
532
|
+
import { jsx as jsx8 } from "react/jsx-runtime";
|
|
533
|
+
var sizeClasses2 = {
|
|
534
|
+
xs: "w-3 h-3",
|
|
535
|
+
sm: "w-4 h-4",
|
|
536
|
+
md: "w-5 h-5",
|
|
537
|
+
lg: "w-6 h-6",
|
|
538
|
+
xl: "w-8 h-8"
|
|
539
|
+
};
|
|
540
|
+
var createIcon = (displayName, path, filled = false) => {
|
|
541
|
+
const Icon = ({ size = "md", className = "", color = "currentColor" }) => {
|
|
542
|
+
const sizeClass = sizeClasses2[size];
|
|
543
|
+
return /* @__PURE__ */ jsx8(
|
|
249
544
|
"svg",
|
|
250
545
|
{
|
|
251
|
-
className:
|
|
252
|
-
|
|
253
|
-
viewBox: "0 0
|
|
254
|
-
|
|
546
|
+
className: `${sizeClass} ${className}`,
|
|
547
|
+
fill: filled ? color : "none",
|
|
548
|
+
viewBox: "0 0 24 24",
|
|
549
|
+
stroke: filled ? "none" : color,
|
|
255
550
|
"aria-hidden": "true",
|
|
256
|
-
children:
|
|
257
|
-
|
|
551
|
+
children: path
|
|
552
|
+
}
|
|
553
|
+
);
|
|
554
|
+
};
|
|
555
|
+
Icon.displayName = displayName;
|
|
556
|
+
return Icon;
|
|
557
|
+
};
|
|
558
|
+
|
|
559
|
+
// src/icons/HomeIcon.tsx
|
|
560
|
+
import { jsx as jsx9 } from "react/jsx-runtime";
|
|
561
|
+
var HomeIcon = createIcon(
|
|
562
|
+
"HomeIcon",
|
|
563
|
+
/* @__PURE__ */ jsx9("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-6 0a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1m-6 0h6" })
|
|
564
|
+
);
|
|
565
|
+
|
|
566
|
+
// src/icons/UserIcon.tsx
|
|
567
|
+
import { jsx as jsx10 } from "react/jsx-runtime";
|
|
568
|
+
var UserIcon = createIcon(
|
|
569
|
+
"UserIcon",
|
|
570
|
+
/* @__PURE__ */ jsx10("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z" })
|
|
571
|
+
);
|
|
572
|
+
|
|
573
|
+
// src/icons/SearchIcon.tsx
|
|
574
|
+
import { jsx as jsx11 } from "react/jsx-runtime";
|
|
575
|
+
var SearchIcon = createIcon(
|
|
576
|
+
"SearchIcon",
|
|
577
|
+
/* @__PURE__ */ jsx11("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" })
|
|
578
|
+
);
|
|
579
|
+
|
|
580
|
+
// src/icons/BellIcon.tsx
|
|
581
|
+
import { jsx as jsx12 } from "react/jsx-runtime";
|
|
582
|
+
var BellIcon = createIcon(
|
|
583
|
+
"BellIcon",
|
|
584
|
+
/* @__PURE__ */ jsx12("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M15 17h5l-1.405-1.405A2.032 2.032 0 0118 14.158V11a6.002 6.002 0 00-4-5.659V5a2 2 0 10-4 0v.341C7.67 6.165 6 8.388 6 11v3.159c0 .538-.214 1.055-.595 1.436L4 17h5m6 0v1a3 3 0 11-6 0v-1m6 0H9" })
|
|
585
|
+
);
|
|
586
|
+
|
|
587
|
+
// src/icons/SettingsIcon.tsx
|
|
588
|
+
import { Fragment as Fragment2, jsx as jsx13, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
589
|
+
var SettingsIcon = createIcon(
|
|
590
|
+
"SettingsIcon",
|
|
591
|
+
/* @__PURE__ */ jsxs5(Fragment2, { children: [
|
|
592
|
+
/* @__PURE__ */ jsx13("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z" }),
|
|
593
|
+
/* @__PURE__ */ jsx13("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M15 12a3 3 0 11-6 0 3 3 0 016 0z" })
|
|
594
|
+
] })
|
|
595
|
+
);
|
|
596
|
+
|
|
597
|
+
// src/icons/MenuIcon.tsx
|
|
598
|
+
import { jsx as jsx14 } from "react/jsx-runtime";
|
|
599
|
+
var MenuIcon = createIcon(
|
|
600
|
+
"MenuIcon",
|
|
601
|
+
/* @__PURE__ */ jsx14("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M4 6h16M4 12h16M4 18h16" })
|
|
602
|
+
);
|
|
603
|
+
|
|
604
|
+
// src/icons/CloseIcon.tsx
|
|
605
|
+
import { jsx as jsx15 } from "react/jsx-runtime";
|
|
606
|
+
var CloseIcon = createIcon(
|
|
607
|
+
"CloseIcon",
|
|
608
|
+
/* @__PURE__ */ jsx15("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M6 18L18 6M6 6l12 12" })
|
|
609
|
+
);
|
|
610
|
+
|
|
611
|
+
// src/icons/PlusIcon.tsx
|
|
612
|
+
import { jsx as jsx16 } from "react/jsx-runtime";
|
|
613
|
+
var PlusIcon = createIcon(
|
|
614
|
+
"PlusIcon",
|
|
615
|
+
/* @__PURE__ */ jsx16("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 4v16m8-8H4" })
|
|
616
|
+
);
|
|
617
|
+
|
|
618
|
+
// src/icons/ArrowLeftIcon.tsx
|
|
619
|
+
import { jsx as jsx17 } from "react/jsx-runtime";
|
|
620
|
+
var ArrowLeftIcon = createIcon(
|
|
621
|
+
"ArrowLeftIcon",
|
|
622
|
+
/* @__PURE__ */ jsx17("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M10 19l-7-7m0 0l7-7m-7 7h18" })
|
|
623
|
+
);
|
|
624
|
+
|
|
625
|
+
// src/icons/ArrowRightIcon.tsx
|
|
626
|
+
import { jsx as jsx18 } from "react/jsx-runtime";
|
|
627
|
+
var ArrowRightIcon = createIcon(
|
|
628
|
+
"ArrowRightIcon",
|
|
629
|
+
/* @__PURE__ */ jsx18("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M14 5l7 7m0 0l-7 7m7-7H3" })
|
|
630
|
+
);
|
|
631
|
+
|
|
632
|
+
// src/icons/ChevronDownIcon.tsx
|
|
633
|
+
import { jsx as jsx19 } from "react/jsx-runtime";
|
|
634
|
+
var ChevronDownIcon = createIcon(
|
|
635
|
+
"ChevronDownIcon",
|
|
636
|
+
/* @__PURE__ */ jsx19("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M19 9l-7 7-7-7" })
|
|
637
|
+
);
|
|
638
|
+
|
|
639
|
+
// src/icons/ChevronUpIcon.tsx
|
|
640
|
+
import { jsx as jsx20 } from "react/jsx-runtime";
|
|
641
|
+
var ChevronUpIcon = createIcon(
|
|
642
|
+
"ChevronUpIcon",
|
|
643
|
+
/* @__PURE__ */ jsx20("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M5 15l7-7 7 7" })
|
|
644
|
+
);
|
|
645
|
+
|
|
646
|
+
// src/icons/ChevronLeftIcon.tsx
|
|
647
|
+
import { jsx as jsx21 } from "react/jsx-runtime";
|
|
648
|
+
var ChevronLeftIcon = createIcon(
|
|
649
|
+
"ChevronLeftIcon",
|
|
650
|
+
/* @__PURE__ */ jsx21("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M15 19l-7-7 7-7" })
|
|
651
|
+
);
|
|
652
|
+
|
|
653
|
+
// src/icons/ChevronRightIcon.tsx
|
|
654
|
+
import { jsx as jsx22 } from "react/jsx-runtime";
|
|
655
|
+
var ChevronRightIcon = createIcon(
|
|
656
|
+
"ChevronRightIcon",
|
|
657
|
+
/* @__PURE__ */ jsx22("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M9 5l7 7-7 7" })
|
|
658
|
+
);
|
|
659
|
+
|
|
660
|
+
// src/icons/ExternalLinkIcon.tsx
|
|
661
|
+
import { jsx as jsx23 } from "react/jsx-runtime";
|
|
662
|
+
var ExternalLinkIcon = createIcon(
|
|
663
|
+
"ExternalLinkIcon",
|
|
664
|
+
/* @__PURE__ */ jsx23("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14" })
|
|
665
|
+
);
|
|
666
|
+
|
|
667
|
+
// src/icons/CheckIcon.tsx
|
|
668
|
+
import { jsx as jsx24 } from "react/jsx-runtime";
|
|
669
|
+
var CheckIcon = createIcon(
|
|
670
|
+
"CheckIcon",
|
|
671
|
+
/* @__PURE__ */ jsx24("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M5 13l4 4L19 7" })
|
|
672
|
+
);
|
|
673
|
+
|
|
674
|
+
// src/icons/CheckCircleIcon.tsx
|
|
675
|
+
import { jsx as jsx25 } from "react/jsx-runtime";
|
|
676
|
+
var CheckCircleIcon = createIcon(
|
|
677
|
+
"CheckCircleIcon",
|
|
678
|
+
/* @__PURE__ */ jsx25("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" })
|
|
679
|
+
);
|
|
680
|
+
|
|
681
|
+
// src/icons/AlertCircleIcon.tsx
|
|
682
|
+
import { jsx as jsx26 } from "react/jsx-runtime";
|
|
683
|
+
var AlertCircleIcon = createIcon(
|
|
684
|
+
"AlertCircleIcon",
|
|
685
|
+
/* @__PURE__ */ jsx26("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" })
|
|
686
|
+
);
|
|
687
|
+
|
|
688
|
+
// src/icons/InfoCircleIcon.tsx
|
|
689
|
+
import { jsx as jsx27 } from "react/jsx-runtime";
|
|
690
|
+
var InfoCircleIcon = createIcon(
|
|
691
|
+
"InfoCircleIcon",
|
|
692
|
+
/* @__PURE__ */ jsx27("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" })
|
|
693
|
+
);
|
|
694
|
+
|
|
695
|
+
// src/icons/TrashIcon.tsx
|
|
696
|
+
import { jsx as jsx28 } from "react/jsx-runtime";
|
|
697
|
+
var TrashIcon = createIcon(
|
|
698
|
+
"TrashIcon",
|
|
699
|
+
/* @__PURE__ */ jsx28("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16" })
|
|
700
|
+
);
|
|
701
|
+
|
|
702
|
+
// src/icons/EditIcon.tsx
|
|
703
|
+
import { jsx as jsx29 } from "react/jsx-runtime";
|
|
704
|
+
var EditIcon = createIcon(
|
|
705
|
+
"EditIcon",
|
|
706
|
+
/* @__PURE__ */ jsx29("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z" })
|
|
707
|
+
);
|
|
708
|
+
|
|
709
|
+
// src/icons/CopyIcon.tsx
|
|
710
|
+
import { jsx as jsx30 } from "react/jsx-runtime";
|
|
711
|
+
var CopyIcon = createIcon(
|
|
712
|
+
"CopyIcon",
|
|
713
|
+
/* @__PURE__ */ jsx30("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z" })
|
|
714
|
+
);
|
|
715
|
+
|
|
716
|
+
// src/icons/SaveIcon.tsx
|
|
717
|
+
import { jsx as jsx31 } from "react/jsx-runtime";
|
|
718
|
+
var SaveIcon = createIcon(
|
|
719
|
+
"SaveIcon",
|
|
720
|
+
/* @__PURE__ */ jsx31("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M8 7H5a2 2 0 00-2 2v10a2 2 0 002 2h14a2 2 0 002-2V9a2 2 0 00-2-2h-3m-1 4l-3 3m0 0l-3-3m3 3V4" })
|
|
721
|
+
);
|
|
722
|
+
|
|
723
|
+
// src/icons/DownloadIcon.tsx
|
|
724
|
+
import { jsx as jsx32 } from "react/jsx-runtime";
|
|
725
|
+
var DownloadIcon = createIcon(
|
|
726
|
+
"DownloadIcon",
|
|
727
|
+
/* @__PURE__ */ jsx32("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4" })
|
|
728
|
+
);
|
|
729
|
+
|
|
730
|
+
// src/icons/UploadIcon.tsx
|
|
731
|
+
import { jsx as jsx33 } from "react/jsx-runtime";
|
|
732
|
+
var UploadIcon = createIcon(
|
|
733
|
+
"UploadIcon",
|
|
734
|
+
/* @__PURE__ */ jsx33("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-8l-4-4m0 0L8 8m4-4v12" })
|
|
735
|
+
);
|
|
736
|
+
|
|
737
|
+
// src/icons/RefreshIcon.tsx
|
|
738
|
+
import { jsx as jsx34 } from "react/jsx-runtime";
|
|
739
|
+
var RefreshIcon = createIcon(
|
|
740
|
+
"RefreshIcon",
|
|
741
|
+
/* @__PURE__ */ jsx34("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15" })
|
|
742
|
+
);
|
|
743
|
+
|
|
744
|
+
// src/icons/EyeIcon.tsx
|
|
745
|
+
import { jsx as jsx35 } from "react/jsx-runtime";
|
|
746
|
+
var EyeIcon = createIcon(
|
|
747
|
+
"EyeIcon",
|
|
748
|
+
/* @__PURE__ */ jsx35("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M15 12a3 3 0 11-6 0 3 3 0 016 0z M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z" })
|
|
749
|
+
);
|
|
750
|
+
|
|
751
|
+
// src/icons/EyeOffIcon.tsx
|
|
752
|
+
import { jsx as jsx36 } from "react/jsx-runtime";
|
|
753
|
+
var EyeOffIcon = createIcon(
|
|
754
|
+
"EyeOffIcon",
|
|
755
|
+
/* @__PURE__ */ jsx36("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M13.875 18.825A10.05 10.05 0 0112 19c-4.478 0-8.268-2.943-9.543-7a9.97 9.97 0 011.563-3.029m5.858.908a3 3 0 114.243 4.243M9.878 9.878l4.242 4.242M9.88 9.88l-3.29-3.29m7.532 7.532l3.29 3.29M3 3l3.59 3.59m0 0A9.953 9.953 0 0112 5c4.478 0 8.268 2.943 9.543 7a10.025 10.025 0 01-4.132 5.411m0 0L21 21" })
|
|
756
|
+
);
|
|
757
|
+
|
|
758
|
+
// src/icons/PlayIcon.tsx
|
|
759
|
+
import { jsx as jsx37 } from "react/jsx-runtime";
|
|
760
|
+
var PlayIcon = createIcon(
|
|
761
|
+
"PlayIcon",
|
|
762
|
+
/* @__PURE__ */ jsx37("path", { d: "M8 5v14l11-7z" }),
|
|
763
|
+
true
|
|
764
|
+
);
|
|
765
|
+
|
|
766
|
+
// src/icons/PauseIcon.tsx
|
|
767
|
+
import { Fragment as Fragment3, jsx as jsx38, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
768
|
+
var PauseIcon = createIcon(
|
|
769
|
+
"PauseIcon",
|
|
770
|
+
/* @__PURE__ */ jsxs6(Fragment3, { children: [
|
|
771
|
+
/* @__PURE__ */ jsx38("rect", { x: "6", y: "4", width: "4", height: "16", rx: "1" }),
|
|
772
|
+
/* @__PURE__ */ jsx38("rect", { x: "14", y: "4", width: "4", height: "16", rx: "1" })
|
|
773
|
+
] }),
|
|
774
|
+
true
|
|
775
|
+
);
|
|
776
|
+
|
|
777
|
+
// src/icons/StopIcon.tsx
|
|
778
|
+
import { jsx as jsx39 } from "react/jsx-runtime";
|
|
779
|
+
var StopIcon = createIcon(
|
|
780
|
+
"StopIcon",
|
|
781
|
+
/* @__PURE__ */ jsx39("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M21 12a9 9 0 11-18 0 9 9 0 0118 0z" })
|
|
782
|
+
);
|
|
783
|
+
|
|
784
|
+
// src/icons/SkipBackIcon.tsx
|
|
785
|
+
import { Fragment as Fragment4, jsx as jsx40 } from "react/jsx-runtime";
|
|
786
|
+
var SkipBackIcon = createIcon(
|
|
787
|
+
"SkipBackIcon",
|
|
788
|
+
/* @__PURE__ */ jsx40(Fragment4, { children: /* @__PURE__ */ jsx40("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12.066 11.2a1 1 0 000 1.6l5.334 4A1 1 0 0019 16V8a1 1 0 00-1.6-.8l-5.333 4zM4.066 11.2a1 1 0 000 1.6l5.334 4A1 1 0 0011 16V8a1 1 0 00-1.6-.8l-5.334 4z" }) }),
|
|
789
|
+
false
|
|
790
|
+
);
|
|
791
|
+
|
|
792
|
+
// src/icons/SkipForwardIcon.tsx
|
|
793
|
+
import { Fragment as Fragment5, jsx as jsx41 } from "react/jsx-runtime";
|
|
794
|
+
var SkipForwardIcon = createIcon(
|
|
795
|
+
"SkipForwardIcon",
|
|
796
|
+
/* @__PURE__ */ jsx41(Fragment5, { children: /* @__PURE__ */ jsx41("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M11.933 12.8a1 1 0 000-1.6L6.6 7.2A1 1 0 005 8v8a1 1 0 001.6.8l5.333-4zM19.933 12.8a1 1 0 000-1.6l-5.333-4A1 1 0 0013 8v8a1 1 0 001.6.8l5.333-4z" }) }),
|
|
797
|
+
false
|
|
798
|
+
);
|
|
799
|
+
|
|
800
|
+
// src/icons/VolumeUpIcon.tsx
|
|
801
|
+
import { Fragment as Fragment6, jsx as jsx42 } from "react/jsx-runtime";
|
|
802
|
+
var VolumeUpIcon = createIcon(
|
|
803
|
+
"VolumeUpIcon",
|
|
804
|
+
/* @__PURE__ */ jsx42(Fragment6, { children: /* @__PURE__ */ jsx42("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M15.536 8.464a5 5 0 010 7.072m2.828-9.9a9 9 0 010 12.728M5.586 15H4a1 1 0 01-1-1v-4a1 1 0 011-1h1.586l4.707-4.707C10.923 3.663 12 4.109 12 5v14c0 .891-1.077 1.337-1.707.707L5.586 15z" }) }),
|
|
805
|
+
false
|
|
806
|
+
);
|
|
807
|
+
|
|
808
|
+
// src/icons/VolumeOffIcon.tsx
|
|
809
|
+
import { Fragment as Fragment7, jsx as jsx43, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
810
|
+
var VolumeOffIcon = createIcon(
|
|
811
|
+
"VolumeOffIcon",
|
|
812
|
+
/* @__PURE__ */ jsxs7(Fragment7, { children: [
|
|
813
|
+
/* @__PURE__ */ jsx43("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M5.586 15H4a1 1 0 01-1-1v-4a1 1 0 011-1h1.586l4.707-4.707C10.923 3.663 12 4.109 12 5v14c0 .891-1.077 1.337-1.707.707L5.586 15z", clipRule: "evenodd" }),
|
|
814
|
+
/* @__PURE__ */ jsx43("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M17 14l2-2m0 0l2-2m-2 2l-2-2m2 2l2 2" })
|
|
815
|
+
] }),
|
|
816
|
+
false
|
|
817
|
+
);
|
|
818
|
+
|
|
819
|
+
// src/icons/MailIcon.tsx
|
|
820
|
+
import { jsx as jsx44 } from "react/jsx-runtime";
|
|
821
|
+
var MailIcon = createIcon(
|
|
822
|
+
"MailIcon",
|
|
823
|
+
/* @__PURE__ */ jsx44("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M3 8l7.89 5.26a2 2 0 002.22 0L21 8M5 19h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z" })
|
|
824
|
+
);
|
|
825
|
+
|
|
826
|
+
// src/icons/ChatIcon.tsx
|
|
827
|
+
import { jsx as jsx45 } from "react/jsx-runtime";
|
|
828
|
+
var ChatIcon = createIcon(
|
|
829
|
+
"ChatIcon",
|
|
830
|
+
/* @__PURE__ */ jsx45("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M8 12h.01M12 12h.01M16 12h.01M21 12c0 4.418-4.03 8-9 8a9.863 9.863 0 01-4.255-.949L3 20l1.395-3.72C3.512 15.042 3 13.574 3 12c0-4.418 4.03-8 9-8s9 3.582 9 8z" })
|
|
831
|
+
);
|
|
832
|
+
|
|
833
|
+
// src/icons/StarIcon.tsx
|
|
834
|
+
import { jsx as jsx46 } from "react/jsx-runtime";
|
|
835
|
+
var StarIcon = createIcon(
|
|
836
|
+
"StarIcon",
|
|
837
|
+
/* @__PURE__ */ jsx46("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M11.049 2.927c.3-.921 1.603-.921 1.902 0l1.519 4.674a1 1 0 00.95.69h4.915c.969 0 1.371 1.24.588 1.81l-3.976 2.888a1 1 0 00-.363 1.118l1.518 4.674c.3.922-.755 1.688-1.538 1.118l-3.976-2.888a1 1 0 00-1.176 0l-3.976 2.888c-.783.57-1.838-.197-1.538-1.118l1.518-4.674a1 1 0 00-.363-1.118l-3.976-2.888c-.784-.57-.38-1.81.588-1.81h4.914a1 1 0 00.951-.69l1.519-4.674z" })
|
|
838
|
+
);
|
|
839
|
+
|
|
840
|
+
// src/icons/HeartIcon.tsx
|
|
841
|
+
import { jsx as jsx47 } from "react/jsx-runtime";
|
|
842
|
+
var HeartIcon = createIcon(
|
|
843
|
+
"HeartIcon",
|
|
844
|
+
/* @__PURE__ */ jsx47("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M4.318 6.318a4.5 4.5 0 000 6.364L12 20.364l7.682-7.682a4.5 4.5 0 00-6.364-6.364L12 7.636l-1.318-1.318a4.5 4.5 0 00-6.364 0z" })
|
|
845
|
+
);
|
|
846
|
+
|
|
847
|
+
// src/icons/CameraIcon.tsx
|
|
848
|
+
import { Fragment as Fragment8, jsx as jsx48, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
849
|
+
var CameraIcon = createIcon(
|
|
850
|
+
"CameraIcon",
|
|
851
|
+
/* @__PURE__ */ jsxs8(Fragment8, { children: [
|
|
852
|
+
/* @__PURE__ */ jsx48("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M3 9a2 2 0 012-2h.93a2 2 0 001.664-.89l.812-1.22A2 2 0 0110.07 4h3.86a2 2 0 011.664.89l.812 1.22A2 2 0 0018.07 7H19a2 2 0 012 2v9a2 2 0 01-2 2H5a2 2 0 01-2-2V9z" }),
|
|
853
|
+
/* @__PURE__ */ jsx48("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M15 13a3 3 0 11-6 0 3 3 0 016 0z" })
|
|
854
|
+
] })
|
|
855
|
+
);
|
|
856
|
+
|
|
857
|
+
// src/icons/CalendarIcon.tsx
|
|
858
|
+
import { jsx as jsx49 } from "react/jsx-runtime";
|
|
859
|
+
var CalendarIcon = createIcon(
|
|
860
|
+
"CalendarIcon",
|
|
861
|
+
/* @__PURE__ */ jsx49("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z" })
|
|
862
|
+
);
|
|
863
|
+
|
|
864
|
+
// src/icons/BookIcon.tsx
|
|
865
|
+
import { jsx as jsx50 } from "react/jsx-runtime";
|
|
866
|
+
var BookIcon = createIcon(
|
|
867
|
+
"BookIcon",
|
|
868
|
+
/* @__PURE__ */ jsx50("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 6.253v13m0-13C10.832 5.477 9.246 5 7.5 5S4.168 5.477 3 6.253v13C4.168 18.477 5.754 18 7.5 18s3.332.477 4.5 1.253m0-13C13.168 5.477 14.754 5 16.5 5c1.747 0 3.332.477 4.5 1.253v13C19.832 18.477 18.247 18 16.5 18c-1.746 0-3.332.477-4.5 1.253" })
|
|
869
|
+
);
|
|
870
|
+
|
|
871
|
+
// src/icons/FileIcon.tsx
|
|
872
|
+
import { jsx as jsx51 } from "react/jsx-runtime";
|
|
873
|
+
var FileIcon = createIcon(
|
|
874
|
+
"FileIcon",
|
|
875
|
+
/* @__PURE__ */ jsx51("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M7 21h10a2 2 0 002-2V9.414a1 1 0 00-.293-.707l-5.414-5.414A1 1 0 0012.586 3H7a2 2 0 00-2 2v14a2 2 0 002 2z" })
|
|
876
|
+
);
|
|
877
|
+
|
|
878
|
+
// src/icons/FolderIcon.tsx
|
|
879
|
+
import { jsx as jsx52 } from "react/jsx-runtime";
|
|
880
|
+
var FolderIcon = createIcon(
|
|
881
|
+
"FolderIcon",
|
|
882
|
+
/* @__PURE__ */ jsx52("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M3 7v10a2 2 0 002 2h14a2 2 0 002-2V9a2 2 0 00-2-2h-6l-2-2H5a2 2 0 00-2 2z" })
|
|
883
|
+
);
|
|
884
|
+
|
|
885
|
+
// src/icons/ImageIcon.tsx
|
|
886
|
+
import { jsx as jsx53 } from "react/jsx-runtime";
|
|
887
|
+
var ImageIcon = createIcon(
|
|
888
|
+
"ImageIcon",
|
|
889
|
+
/* @__PURE__ */ jsx53("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z" })
|
|
890
|
+
);
|
|
891
|
+
|
|
892
|
+
// src/icons/CodeIcon.tsx
|
|
893
|
+
import { jsx as jsx54 } from "react/jsx-runtime";
|
|
894
|
+
var CodeIcon = createIcon(
|
|
895
|
+
"CodeIcon",
|
|
896
|
+
/* @__PURE__ */ jsx54("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M10 20l4-16m4 4l4 4-4 4M6 16l-4-4 4-4" })
|
|
897
|
+
);
|
|
898
|
+
|
|
899
|
+
// src/icons/TerminalIcon.tsx
|
|
900
|
+
import { jsx as jsx55 } from "react/jsx-runtime";
|
|
901
|
+
var TerminalIcon = createIcon(
|
|
902
|
+
"TerminalIcon",
|
|
903
|
+
/* @__PURE__ */ jsx55("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M8 9l3 3-3 3m5 0h3M5 20h14a2 2 0 002-2V6a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z" })
|
|
904
|
+
);
|
|
905
|
+
|
|
906
|
+
// src/icons/DatabaseIcon.tsx
|
|
907
|
+
import { jsx as jsx56 } from "react/jsx-runtime";
|
|
908
|
+
var DatabaseIcon = createIcon(
|
|
909
|
+
"DatabaseIcon",
|
|
910
|
+
/* @__PURE__ */ jsx56("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M4 7v10c0 2.21 3.582 4 8 4s8-1.79 8-4V7M4 7c0 2.21 3.582 4 8 4s8-1.79 8-4M4 7c0-2.21 3.582-4 8-4s8 1.79 8 4m0 5c0 2.21-3.582 4-8 4s-8-1.79-8-4" })
|
|
911
|
+
);
|
|
912
|
+
|
|
913
|
+
// src/icons/CloudIcon.tsx
|
|
914
|
+
import { jsx as jsx57 } from "react/jsx-runtime";
|
|
915
|
+
var CloudIcon = createIcon(
|
|
916
|
+
"CloudIcon",
|
|
917
|
+
/* @__PURE__ */ jsx57("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M3 15a4 4 0 004 4h9a5 5 0 10-.1-9.999 5.002 5.002 0 10-9.78 2.096A4.001 4.001 0 003 15z" })
|
|
918
|
+
);
|
|
919
|
+
|
|
920
|
+
// src/icons/PlugIcon.tsx
|
|
921
|
+
import { jsx as jsx58 } from "react/jsx-runtime";
|
|
922
|
+
var PlugIcon = createIcon(
|
|
923
|
+
"PlugIcon",
|
|
924
|
+
/* @__PURE__ */ jsx58("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M13 10V3L4 14h7v7l9-11h-7z" })
|
|
925
|
+
);
|
|
926
|
+
|
|
927
|
+
// src/icons/KeyIcon.tsx
|
|
928
|
+
import { jsx as jsx59 } from "react/jsx-runtime";
|
|
929
|
+
var KeyIcon = createIcon(
|
|
930
|
+
"KeyIcon",
|
|
931
|
+
/* @__PURE__ */ jsx59("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M15 7a2 2 0 012 2m4 0a6 6 0 01-7.743 5.743L11 17H9v2H7v2H4a1 1 0 01-1-1v-2.586a1 1 0 01.293-.707l5.964-5.964A6 6 0 1121 9z" })
|
|
932
|
+
);
|
|
933
|
+
|
|
934
|
+
// src/icons/LockIcon.tsx
|
|
935
|
+
import { jsx as jsx60 } from "react/jsx-runtime";
|
|
936
|
+
var LockIcon = createIcon(
|
|
937
|
+
"LockIcon",
|
|
938
|
+
/* @__PURE__ */ jsx60("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 15v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 002 2zm10-10V7a4 4 0 00-8 0v4h8z" })
|
|
939
|
+
);
|
|
940
|
+
|
|
941
|
+
// src/icons/ShieldIcon.tsx
|
|
942
|
+
import { jsx as jsx61 } from "react/jsx-runtime";
|
|
943
|
+
var ShieldIcon = createIcon(
|
|
944
|
+
"ShieldIcon",
|
|
945
|
+
/* @__PURE__ */ jsx61("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M9 12l2 2 4-4m5.618-4.016A11.955 11.955 0 0112 2.944a11.955 11.955 0 01-8.618 3.04A12.02 12.02 0 003 9c0 5.591 3.824 10.29 9 11.622 5.176-1.332 9-6.03 9-11.622 0-1.042-.133-2.052-.382-3.016z" })
|
|
946
|
+
);
|
|
947
|
+
|
|
948
|
+
// src/icons/SparklesIcon.tsx
|
|
949
|
+
import { jsx as jsx62 } from "react/jsx-runtime";
|
|
950
|
+
var SparklesIcon = createIcon(
|
|
951
|
+
"SparklesIcon",
|
|
952
|
+
/* @__PURE__ */ jsx62("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M5 3v4M3 5h4M6 17v4m-2-2h4m5-16l2.286 6.857L21 12l-5.714 2.143L13 21l-2.286-6.857L5 12l5.714-2.143L13 3z" })
|
|
953
|
+
);
|
|
954
|
+
|
|
955
|
+
// src/icons/BrainIcon.tsx
|
|
956
|
+
import { jsx as jsx63 } from "react/jsx-runtime";
|
|
957
|
+
var BrainIcon = createIcon(
|
|
958
|
+
"BrainIcon",
|
|
959
|
+
/* @__PURE__ */ jsx63("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M9.663 17h4.673M12 3v1m6.364 1.636l-.707.707M21 12h-1M4 12H3m3.343-5.657l-.707-.707m2.828 9.9a5 5 0 117.072 0l-.548.547A3.374 3.374 0 0014 18.469V19a2 2 0 11-4 0v-.531c0-.895-.356-1.754-.988-2.386l-.548-.547z" })
|
|
960
|
+
);
|
|
961
|
+
|
|
962
|
+
// src/icons/GlobeIcon.tsx
|
|
963
|
+
import { jsx as jsx64 } from "react/jsx-runtime";
|
|
964
|
+
var GlobeIcon = createIcon(
|
|
965
|
+
"GlobeIcon",
|
|
966
|
+
/* @__PURE__ */ jsx64("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M3.055 11H5a2 2 0 012 2v1a2 2 0 002 2 2 2 0 012 2v2.945M8 3.935V5.5A2.5 2.5 0 0010.5 8h.5a2 2 0 012 2 2 2 0 104 0 2 2 0 012-2h1.064M15 20.488V18a2 2 0 012-2h3.064M21 12a9 9 0 11-18 0 9 9 0 0118 0z" })
|
|
967
|
+
);
|
|
968
|
+
|
|
969
|
+
// src/icons/BeakerIcon.tsx
|
|
970
|
+
import { jsx as jsx65 } from "react/jsx-runtime";
|
|
971
|
+
var BeakerIcon = createIcon(
|
|
972
|
+
"BeakerIcon",
|
|
973
|
+
/* @__PURE__ */ jsx65("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M19.428 15.428a2 2 0 00-1.022-.547l-2.387-.477a6 6 0 00-3.86.517l-.318.158a6 6 0 01-3.86.517L6.05 15.21a2 2 0 00-1.806.547M8 4h8l-1 1v5.172a2 2 0 00.586 1.414l5 5c1.26 1.26.367 3.414-1.415 3.414H4.828c-1.782 0-2.674-2.154-1.414-3.414l5-5A2 2 0 009 10.172V5L8 4z" })
|
|
974
|
+
);
|
|
975
|
+
|
|
976
|
+
// src/icons/GoogleIcon.tsx
|
|
977
|
+
import { jsx as jsx66 } from "react/jsx-runtime";
|
|
978
|
+
var GoogleIcon = createIcon(
|
|
979
|
+
"GoogleIcon",
|
|
980
|
+
/* @__PURE__ */ jsx66("path", { d: "M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92c-.26 1.37-1.04 2.53-2.21 3.31v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.09z M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z" }),
|
|
981
|
+
true
|
|
982
|
+
);
|
|
983
|
+
|
|
984
|
+
// src/icons/GitHubIcon.tsx
|
|
985
|
+
import { jsx as jsx67 } from "react/jsx-runtime";
|
|
986
|
+
var GitHubIcon = createIcon(
|
|
987
|
+
"GitHubIcon",
|
|
988
|
+
/* @__PURE__ */ jsx67("path", { d: "M12 2C6.477 2 2 6.484 2 12.017c0 4.425 2.865 8.18 6.839 9.504.5.092.682-.217.682-.483 0-.237-.008-.868-.013-1.703-2.782.605-3.369-1.343-3.369-1.343-.454-1.158-1.11-1.466-1.11-1.466-.908-.62.069-.608.069-.608 1.003.07 1.531 1.032 1.531 1.032.892 1.53 2.341 1.088 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.113-4.555-4.951 0-1.093.39-1.988 1.029-2.688-.103-.253-.446-1.272.098-2.65 0 0 .84-.27 2.75 1.026A9.564 9.564 0 0112 6.844c.85.004 1.705.115 2.504.337 1.909-1.296 2.747-1.027 2.747-1.027.546 1.379.202 2.398.1 2.651.64.7 1.028 1.595 1.028 2.688 0 3.848-2.339 4.695-4.566 4.943.359.309.678.92.678 1.855 0 1.338-.012 2.419-.012 2.747 0 .268.18.58.688.482A10.019 10.019 0 0022 12.017C22 6.484 17.522 2 12 2z" }),
|
|
989
|
+
true
|
|
990
|
+
);
|
|
991
|
+
|
|
992
|
+
// src/icons/TwitterIcon.tsx
|
|
993
|
+
import { jsx as jsx68 } from "react/jsx-runtime";
|
|
994
|
+
var TwitterIcon = createIcon(
|
|
995
|
+
"TwitterIcon",
|
|
996
|
+
/* @__PURE__ */ jsx68("path", { d: "M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z" }),
|
|
997
|
+
true
|
|
998
|
+
);
|
|
999
|
+
|
|
1000
|
+
// src/icons/FacebookIcon.tsx
|
|
1001
|
+
import { jsx as jsx69 } from "react/jsx-runtime";
|
|
1002
|
+
var FacebookIcon = createIcon(
|
|
1003
|
+
"FacebookIcon",
|
|
1004
|
+
/* @__PURE__ */ jsx69("path", { d: "M9.101 23.691v-7.98H6.627v-3.667h2.474v-1.58c0-4.085 1.848-5.978 5.858-5.978.401 0 .955.042 1.468.103a8.68 8.68 0 0 1 1.141.195v3.325a8.623 8.623 0 0 0-.653-.036 26.805 26.805 0 0 0-.733-.009c-.707 0-1.259.096-1.675.309a1.686 1.686 0 0 0-.679.622c-.258.42-.374.995-.374 1.752v1.297h3.919l-.386 2.103-.287 1.564h-3.246v8.245C19.396 23.238 24 18.179 24 12.044c0-6.627-5.373-12-12-12s-12 5.373-12 12c0 5.628 3.874 10.35 9.101 11.647Z" }),
|
|
1005
|
+
true
|
|
1006
|
+
);
|
|
1007
|
+
|
|
1008
|
+
// src/icons/AppleIcon.tsx
|
|
1009
|
+
import { jsx as jsx70 } from "react/jsx-runtime";
|
|
1010
|
+
var AppleIcon = createIcon(
|
|
1011
|
+
"AppleIcon",
|
|
1012
|
+
/* @__PURE__ */ jsx70("path", { d: "M17.05 20.28c-.98.95-2.05.88-3.08.4-1.09-.5-2.08-.48-3.24 0-1.44.62-2.2.44-3.06-.4C2.79 15.25 3.51 7.59 9.05 7.31c1.35.07 2.29.74 3.08.8 1.18-.24 2.31-.93 3.57-.84 1.51.12 2.65.72 3.4 1.8-3.12 1.87-2.38 5.98.48 7.13-.57 1.5-1.31 2.99-2.54 4.09l.01-.01zM12.03 7.25c-.15-2.23 1.66-4.07 3.74-4.25.29 2.58-2.34 4.5-3.74 4.25z" }),
|
|
1013
|
+
true
|
|
1014
|
+
);
|
|
1015
|
+
|
|
1016
|
+
// src/icons/LinkedInIcon.tsx
|
|
1017
|
+
import { jsx as jsx71 } from "react/jsx-runtime";
|
|
1018
|
+
var LinkedInIcon = createIcon(
|
|
1019
|
+
"LinkedInIcon",
|
|
1020
|
+
/* @__PURE__ */ jsx71("path", { d: "M20.447 20.452h-3.554v-5.569c0-1.328-.027-3.037-1.852-3.037-1.853 0-2.136 1.445-2.136 2.939v5.667H9.351V9h3.414v1.561h.046c.477-.9 1.637-1.85 3.37-1.85 3.601 0 4.267 2.37 4.267 5.455v6.286zM5.337 7.433c-1.144 0-2.063-.926-2.063-2.065 0-1.138.92-2.063 2.063-2.063 1.14 0 2.064.925 2.064 2.063 0 1.139-.925 2.065-2.064 2.065zm1.782 13.019H3.555V9h3.564v11.452zM22.225 0H1.771C.792 0 0 .774 0 1.729v20.542C0 23.227.792 24 1.771 24h20.451C23.2 24 24 23.227 24 22.271V1.729C24 .774 23.2 0 22.222 0h.003z" }),
|
|
1021
|
+
true
|
|
1022
|
+
);
|
|
1023
|
+
|
|
1024
|
+
// src/icons/YouTubeIcon.tsx
|
|
1025
|
+
import { jsx as jsx72 } from "react/jsx-runtime";
|
|
1026
|
+
var YouTubeIcon = createIcon(
|
|
1027
|
+
"YouTubeIcon",
|
|
1028
|
+
/* @__PURE__ */ jsx72("path", { d: "M23.498 6.186a3.016 3.016 0 0 0-2.122-2.136C19.505 3.545 12 3.545 12 3.545s-7.505 0-9.377.505A3.017 3.017 0 0 0 .502 6.186C0 8.07 0 12 0 12s0 3.93.502 5.814a3.016 3.016 0 0 0 2.122 2.136c1.871.505 9.376.505 9.376.505s7.505 0 9.377-.505a3.015 3.015 0 0 0 2.122-2.136C24 15.93 24 12 24 12s0-3.93-.502-5.814zM9.545 15.568V8.432L15.818 12l-6.273 3.568z" }),
|
|
1029
|
+
true
|
|
1030
|
+
);
|
|
1031
|
+
|
|
1032
|
+
// src/icons/SlackIcon.tsx
|
|
1033
|
+
import { jsx as jsx73 } from "react/jsx-runtime";
|
|
1034
|
+
var SlackIcon = createIcon(
|
|
1035
|
+
"SlackIcon",
|
|
1036
|
+
/* @__PURE__ */ jsx73("path", { d: "M5.042 15.165a2.528 2.528 0 0 1-2.52 2.523A2.528 2.528 0 0 1 0 15.165a2.527 2.527 0 0 1 2.522-2.52h2.52v2.52zm1.271 0a2.527 2.527 0 0 1 2.521-2.52 2.527 2.527 0 0 1 2.521 2.52v6.313A2.528 2.528 0 0 1 8.834 24a2.528 2.528 0 0 1-2.521-2.522v-6.313zM8.834 5.042a2.528 2.528 0 0 1-2.521-2.52A2.528 2.528 0 0 1 8.834 0a2.528 2.528 0 0 1 2.521 2.522v2.52H8.834zm0 1.271a2.528 2.528 0 0 1 2.521 2.521 2.528 2.528 0 0 1-2.521 2.521H2.522A2.528 2.528 0 0 1 0 8.834a2.528 2.528 0 0 1 2.522-2.521h6.312zm10.122 2.521a2.528 2.528 0 0 1 2.522-2.521A2.528 2.528 0 0 1 24 8.834a2.528 2.528 0 0 1-2.522 2.521h-2.522V8.834zm-1.268 0a2.528 2.528 0 0 1-2.523 2.521 2.527 2.527 0 0 1-2.52-2.521V2.522A2.527 2.527 0 0 1 15.165 0a2.528 2.528 0 0 1 2.523 2.522v6.312zm-2.523 10.122a2.528 2.528 0 0 1 2.523 2.522A2.528 2.528 0 0 1 15.165 24a2.527 2.527 0 0 1-2.52-2.522v-2.522h2.52zm0-1.268a2.527 2.527 0 0 1-2.52-2.523 2.526 2.526 0 0 1 2.52-2.52h6.313A2.527 2.527 0 0 1 24 15.165a2.528 2.528 0 0 1-2.522 2.523h-6.313z" }),
|
|
1037
|
+
true
|
|
1038
|
+
);
|
|
1039
|
+
|
|
1040
|
+
// src/components/AppShell.tsx
|
|
1041
|
+
import { Fragment as Fragment9, jsx as jsx74, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
1042
|
+
var widthClasses2 = {
|
|
1043
|
+
sm: "w-48",
|
|
1044
|
+
md: "w-64",
|
|
1045
|
+
lg: "w-80"
|
|
1046
|
+
};
|
|
1047
|
+
var breakpointClasses = {
|
|
1048
|
+
sm: "sm",
|
|
1049
|
+
md: "md",
|
|
1050
|
+
lg: "lg",
|
|
1051
|
+
xl: "xl"
|
|
1052
|
+
};
|
|
1053
|
+
var AppShell = ({
|
|
1054
|
+
children,
|
|
1055
|
+
navbar,
|
|
1056
|
+
header,
|
|
1057
|
+
navbarTitle,
|
|
1058
|
+
navbarLogo,
|
|
1059
|
+
defaultNavbarOpen = false,
|
|
1060
|
+
responsive = true,
|
|
1061
|
+
className = ""
|
|
1062
|
+
}) => {
|
|
1063
|
+
const { theme } = useTheme();
|
|
1064
|
+
const [isMobileNavbarOpen, setIsMobileNavbarOpen] = useState4(defaultNavbarOpen);
|
|
1065
|
+
const navbarWidth = navbar?.width || "md";
|
|
1066
|
+
const navbarBreakpoint = navbar?.breakpoint || "md";
|
|
1067
|
+
const navbarPosition = navbar?.position || "side";
|
|
1068
|
+
const widthClass = widthClasses2[navbarWidth];
|
|
1069
|
+
const breakpoint = breakpointClasses[navbarBreakpoint];
|
|
1070
|
+
if (!responsive && navbar) {
|
|
1071
|
+
return /* @__PURE__ */ jsxs9("div", { className: `min-h-screen flex flex-col ${className}`, children: [
|
|
1072
|
+
header && /* @__PURE__ */ jsx74("div", { className: "w-full", children: header }),
|
|
1073
|
+
/* @__PURE__ */ jsxs9("div", { className: "flex flex-1", children: [
|
|
1074
|
+
/* @__PURE__ */ jsx74("aside", { className: `${widthClass} bg-white dark:bg-gray-800 border-r border-gray-200 dark:border-gray-700 h-full overflow-y-auto`, children: navbar.content }),
|
|
1075
|
+
/* @__PURE__ */ jsx74("main", { className: "flex-1 overflow-y-auto", children })
|
|
1076
|
+
] })
|
|
1077
|
+
] });
|
|
1078
|
+
}
|
|
1079
|
+
if (!responsive) {
|
|
1080
|
+
return /* @__PURE__ */ jsxs9("div", { className: `min-h-screen flex flex-col ${className}`, children: [
|
|
1081
|
+
header && /* @__PURE__ */ jsx74("div", { className: "w-full", children: header }),
|
|
1082
|
+
/* @__PURE__ */ jsx74("main", { className: "flex-1 overflow-y-auto", children })
|
|
1083
|
+
] });
|
|
1084
|
+
}
|
|
1085
|
+
if (navbar && navbarPosition === "top") {
|
|
1086
|
+
const mobileMenuClass = navbarBreakpoint === "sm" ? "sm:hidden" : navbarBreakpoint === "md" ? "md:hidden" : navbarBreakpoint === "lg" ? "lg:hidden" : "xl:hidden";
|
|
1087
|
+
const desktopNavClass = navbarBreakpoint === "sm" ? "sm:flex" : navbarBreakpoint === "md" ? "md:flex" : navbarBreakpoint === "lg" ? "lg:flex" : "xl:flex";
|
|
1088
|
+
return /* @__PURE__ */ jsxs9("div", { className: `min-h-screen flex flex-col bg-gray-50 dark:bg-gray-900 ${className}`, children: [
|
|
1089
|
+
/* @__PURE__ */ jsx74("nav", { className: "sticky top-0 z-30 bg-white dark:bg-gray-800 border-b border-gray-200 dark:border-gray-700", children: /* @__PURE__ */ jsx74("div", { className: "max-w-7xl mx-auto px-4 sm:px-6 lg:px-8", children: /* @__PURE__ */ jsxs9("div", { className: "flex justify-between items-center h-16", children: [
|
|
1090
|
+
/* @__PURE__ */ jsx74("div", { className: "flex items-center", children: navbarLogo ? /* @__PURE__ */ jsx74("div", { children: navbarLogo }) : navbarTitle ? /* @__PURE__ */ jsx74("span", { className: "text-xl font-bold text-gray-900 dark:text-gray-100", children: navbarTitle }) : null }),
|
|
1091
|
+
/* @__PURE__ */ jsx74("div", { className: `hidden ${desktopNavClass} items-center gap-6`, children: navbar.content }),
|
|
1092
|
+
/* @__PURE__ */ jsx74(
|
|
1093
|
+
"button",
|
|
1094
|
+
{
|
|
1095
|
+
className: `${mobileMenuClass} p-2 rounded-lg hover:bg-gray-100 dark:hover:bg-gray-700 transition-colors`,
|
|
1096
|
+
onClick: () => setIsMobileNavbarOpen(!isMobileNavbarOpen),
|
|
1097
|
+
"aria-label": "Toggle menu",
|
|
1098
|
+
children: /* @__PURE__ */ jsx74(MenuIcon, { size: "md" })
|
|
1099
|
+
}
|
|
1100
|
+
)
|
|
1101
|
+
] }) }) }),
|
|
1102
|
+
header && /* @__PURE__ */ jsx74("div", { className: "w-full", children: header }),
|
|
1103
|
+
isMobileNavbarOpen && /* @__PURE__ */ jsxs9(Fragment9, { children: [
|
|
1104
|
+
/* @__PURE__ */ jsx74(
|
|
1105
|
+
"div",
|
|
258
1106
|
{
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
1107
|
+
className: `${mobileMenuClass} fixed inset-0 z-40 bg-black/60 backdrop-blur-sm animate-in fade-in duration-200`,
|
|
1108
|
+
onClick: () => setIsMobileNavbarOpen(false)
|
|
1109
|
+
}
|
|
1110
|
+
),
|
|
1111
|
+
/* @__PURE__ */ jsxs9("div", { className: `${mobileMenuClass} fixed left-0 top-0 bottom-0 z-50 w-64 bg-white dark:bg-gray-800 shadow-2xl animate-in slide-in-from-left duration-300`, children: [
|
|
1112
|
+
/* @__PURE__ */ jsxs9("div", { className: "p-4 border-b border-gray-200 dark:border-gray-700 flex items-center justify-between", children: [
|
|
1113
|
+
navbarLogo ? /* @__PURE__ */ jsx74("div", { children: navbarLogo }) : navbarTitle ? /* @__PURE__ */ jsx74("span", { className: "text-xl font-bold text-gray-900 dark:text-gray-100", children: navbarTitle }) : null,
|
|
1114
|
+
/* @__PURE__ */ jsx74(
|
|
1115
|
+
"button",
|
|
1116
|
+
{
|
|
1117
|
+
className: "p-1 rounded hover:bg-gray-100 dark:hover:bg-gray-700 transition-colors",
|
|
1118
|
+
onClick: () => setIsMobileNavbarOpen(false),
|
|
1119
|
+
"aria-label": "Close menu",
|
|
1120
|
+
children: /* @__PURE__ */ jsx74("svg", { className: "w-6 h-6", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx74("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M6 18L18 6M6 6l12 12" }) })
|
|
1121
|
+
}
|
|
1122
|
+
)
|
|
1123
|
+
] }),
|
|
1124
|
+
/* @__PURE__ */ jsx74(
|
|
1125
|
+
"div",
|
|
1126
|
+
{
|
|
1127
|
+
className: "p-4 flex flex-col gap-4",
|
|
1128
|
+
onClick: () => setIsMobileNavbarOpen(false),
|
|
1129
|
+
children: navbar.content
|
|
1130
|
+
}
|
|
1131
|
+
)
|
|
1132
|
+
] })
|
|
1133
|
+
] }),
|
|
1134
|
+
/* @__PURE__ */ jsx74("main", { className: "flex-1 overflow-y-auto", children })
|
|
1135
|
+
] });
|
|
1136
|
+
}
|
|
1137
|
+
if (navbar) {
|
|
1138
|
+
const mobileHeaderClass = navbarBreakpoint === "sm" ? "sm:hidden" : navbarBreakpoint === "md" ? "md:hidden" : navbarBreakpoint === "lg" ? "lg:hidden" : "xl:hidden";
|
|
1139
|
+
const desktopNavbarClass = navbarBreakpoint === "sm" ? "sm:block" : navbarBreakpoint === "md" ? "md:block" : navbarBreakpoint === "lg" ? "lg:block" : "xl:block";
|
|
1140
|
+
const mobileDrawerClass = navbarBreakpoint === "sm" ? "sm:hidden" : navbarBreakpoint === "md" ? "md:hidden" : navbarBreakpoint === "lg" ? "lg:hidden" : "xl:hidden";
|
|
1141
|
+
const sidebarWidthClass = navbarWidth === "sm" ? "w-48" : navbarWidth === "lg" ? "w-80" : "w-64";
|
|
1142
|
+
return /* @__PURE__ */ jsxs9("div", { className: `min-h-screen flex flex-col bg-gray-50 dark:bg-gray-900 ${className}`, children: [
|
|
1143
|
+
/* @__PURE__ */ jsxs9("div", { className: `${mobileHeaderClass} sticky top-0 z-30 bg-white dark:bg-gray-800 border-b border-gray-200 dark:border-gray-700 px-4 py-3 flex items-center justify-between`, children: [
|
|
1144
|
+
navbarLogo ? /* @__PURE__ */ jsx74("div", { children: navbarLogo }) : navbarTitle ? /* @__PURE__ */ jsx74("span", { className: "text-xl font-bold text-gray-900 dark:text-gray-100", children: navbarTitle }) : null,
|
|
1145
|
+
/* @__PURE__ */ jsx74(
|
|
1146
|
+
"button",
|
|
1147
|
+
{
|
|
1148
|
+
className: "p-2 rounded-lg hover:bg-gray-100 dark:hover:bg-gray-700 transition-colors",
|
|
1149
|
+
onClick: () => setIsMobileNavbarOpen(!isMobileNavbarOpen),
|
|
1150
|
+
"aria-label": "Toggle menu",
|
|
1151
|
+
children: /* @__PURE__ */ jsx74(MenuIcon, { size: "md" })
|
|
262
1152
|
}
|
|
263
1153
|
)
|
|
1154
|
+
] }),
|
|
1155
|
+
header && /* @__PURE__ */ jsx74("div", { className: "w-full", children: header }),
|
|
1156
|
+
/* @__PURE__ */ jsxs9("div", { className: "flex flex-1 min-h-0", children: [
|
|
1157
|
+
/* @__PURE__ */ jsx74("aside", { className: `hidden ${desktopNavbarClass} ${sidebarWidthClass} bg-white dark:bg-gray-800 border-r border-gray-200 dark:border-gray-700 overflow-y-auto shrink-0`, children: navbar.content }),
|
|
1158
|
+
isMobileNavbarOpen && /* @__PURE__ */ jsxs9(Fragment9, { children: [
|
|
1159
|
+
/* @__PURE__ */ jsx74(
|
|
1160
|
+
"div",
|
|
1161
|
+
{
|
|
1162
|
+
className: `${mobileDrawerClass} fixed inset-0 z-40 bg-black/60 backdrop-blur-sm animate-in fade-in duration-200`,
|
|
1163
|
+
onClick: () => setIsMobileNavbarOpen(false)
|
|
1164
|
+
}
|
|
1165
|
+
),
|
|
1166
|
+
/* @__PURE__ */ jsxs9("div", { className: `${mobileDrawerClass} fixed left-0 top-0 bottom-0 z-50 w-64 bg-white dark:bg-gray-800 shadow-2xl animate-in slide-in-from-left duration-300`, children: [
|
|
1167
|
+
/* @__PURE__ */ jsxs9("div", { className: "p-4 border-b border-gray-200 dark:border-gray-700 flex items-center justify-between", children: [
|
|
1168
|
+
navbarLogo ? /* @__PURE__ */ jsx74("div", { children: navbarLogo }) : navbarTitle ? /* @__PURE__ */ jsx74("span", { className: "text-xl font-bold text-gray-900 dark:text-gray-100", children: navbarTitle }) : null,
|
|
1169
|
+
/* @__PURE__ */ jsx74(
|
|
1170
|
+
"button",
|
|
1171
|
+
{
|
|
1172
|
+
className: "p-1 rounded hover:bg-gray-100 dark:hover:bg-gray-700 transition-colors",
|
|
1173
|
+
onClick: () => setIsMobileNavbarOpen(false),
|
|
1174
|
+
"aria-label": "Close menu",
|
|
1175
|
+
children: /* @__PURE__ */ jsx74("svg", { className: "w-6 h-6", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx74("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M6 18L18 6M6 6l12 12" }) })
|
|
1176
|
+
}
|
|
1177
|
+
)
|
|
1178
|
+
] }),
|
|
1179
|
+
/* @__PURE__ */ jsx74(
|
|
1180
|
+
"div",
|
|
1181
|
+
{
|
|
1182
|
+
className: "overflow-y-auto h-[calc(100vh-73px)]",
|
|
1183
|
+
onClick: () => setIsMobileNavbarOpen(false),
|
|
1184
|
+
children: navbar.content
|
|
1185
|
+
}
|
|
1186
|
+
)
|
|
1187
|
+
] })
|
|
1188
|
+
] }),
|
|
1189
|
+
/* @__PURE__ */ jsx74("main", { className: "flex-1 overflow-y-auto min-h-screen", children })
|
|
1190
|
+
] })
|
|
1191
|
+
] });
|
|
1192
|
+
}
|
|
1193
|
+
return /* @__PURE__ */ jsxs9("div", { className: `min-h-screen flex flex-col ${className}`, children: [
|
|
1194
|
+
header && /* @__PURE__ */ jsx74("div", { className: "w-full", children: header }),
|
|
1195
|
+
/* @__PURE__ */ jsx74("main", { className: "flex-1 overflow-y-auto", children })
|
|
1196
|
+
] });
|
|
1197
|
+
};
|
|
1198
|
+
|
|
1199
|
+
// src/components/Drawer.tsx
|
|
1200
|
+
import { useEffect as useEffect4 } from "react";
|
|
1201
|
+
import { Fragment as Fragment10, jsx as jsx75, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
1202
|
+
var sizeClasses3 = {
|
|
1203
|
+
left: {
|
|
1204
|
+
sm: "w-64",
|
|
1205
|
+
md: "w-80",
|
|
1206
|
+
lg: "w-96"
|
|
1207
|
+
},
|
|
1208
|
+
right: {
|
|
1209
|
+
sm: "w-64",
|
|
1210
|
+
md: "w-80",
|
|
1211
|
+
lg: "w-96"
|
|
1212
|
+
},
|
|
1213
|
+
top: {
|
|
1214
|
+
sm: "h-48",
|
|
1215
|
+
md: "h-64",
|
|
1216
|
+
lg: "h-80"
|
|
1217
|
+
},
|
|
1218
|
+
bottom: {
|
|
1219
|
+
sm: "h-48",
|
|
1220
|
+
md: "h-64",
|
|
1221
|
+
lg: "h-80"
|
|
1222
|
+
}
|
|
1223
|
+
};
|
|
1224
|
+
var positionClasses = {
|
|
1225
|
+
left: "left-0 top-0 h-full",
|
|
1226
|
+
right: "right-0 top-0 h-full",
|
|
1227
|
+
top: "top-0 left-0 w-full",
|
|
1228
|
+
bottom: "bottom-0 left-0 w-full"
|
|
1229
|
+
};
|
|
1230
|
+
var slideClasses = {
|
|
1231
|
+
left: "transform transition-transform duration-300",
|
|
1232
|
+
right: "transform transition-transform duration-300",
|
|
1233
|
+
top: "transform transition-transform duration-300",
|
|
1234
|
+
bottom: "transform transition-transform duration-300"
|
|
1235
|
+
};
|
|
1236
|
+
var Drawer = ({
|
|
1237
|
+
isOpen,
|
|
1238
|
+
onClose,
|
|
1239
|
+
title,
|
|
1240
|
+
children,
|
|
1241
|
+
position = "right",
|
|
1242
|
+
size = "md",
|
|
1243
|
+
showCloseButton = true
|
|
1244
|
+
}) => {
|
|
1245
|
+
const { theme } = useTheme();
|
|
1246
|
+
useEffect4(() => {
|
|
1247
|
+
const handleEscape = (e) => {
|
|
1248
|
+
if (e.key === "Escape" && isOpen) {
|
|
1249
|
+
onClose();
|
|
264
1250
|
}
|
|
265
|
-
|
|
266
|
-
isOpen
|
|
1251
|
+
};
|
|
1252
|
+
if (isOpen) {
|
|
1253
|
+
document.addEventListener("keydown", handleEscape);
|
|
1254
|
+
document.body.style.overflow = "hidden";
|
|
1255
|
+
}
|
|
1256
|
+
return () => {
|
|
1257
|
+
document.removeEventListener("keydown", handleEscape);
|
|
1258
|
+
document.body.style.overflow = "unset";
|
|
1259
|
+
};
|
|
1260
|
+
}, [isOpen, onClose]);
|
|
1261
|
+
if (!isOpen) return null;
|
|
1262
|
+
const sizeClass = sizeClasses3[position][size];
|
|
1263
|
+
const positionClass = positionClasses[position];
|
|
1264
|
+
return /* @__PURE__ */ jsxs10(Fragment10, { children: [
|
|
1265
|
+
/* @__PURE__ */ jsx75(
|
|
267
1266
|
"div",
|
|
268
1267
|
{
|
|
269
|
-
className:
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
1268
|
+
className: "fixed inset-0 z-40 bg-black/60 backdrop-blur-sm transition-all duration-200",
|
|
1269
|
+
onClick: onClose
|
|
1270
|
+
}
|
|
1271
|
+
),
|
|
1272
|
+
/* @__PURE__ */ jsxs10(
|
|
1273
|
+
"div",
|
|
1274
|
+
{
|
|
1275
|
+
className: `fixed z-50 ${positionClass} ${sizeClass} bg-white dark:bg-gray-800 shadow-2xl overflow-hidden flex flex-col ${slideClasses[position]}`,
|
|
1276
|
+
children: [
|
|
1277
|
+
(title || showCloseButton) && /* @__PURE__ */ jsxs10("div", { className: "flex items-center justify-between p-6 border-b border-gray-200 dark:border-gray-700", children: [
|
|
1278
|
+
title && /* @__PURE__ */ jsx75("h3", { className: "text-xl font-semibold text-gray-900 dark:text-gray-100", children: title }),
|
|
1279
|
+
showCloseButton && /* @__PURE__ */ jsx75(
|
|
1280
|
+
"button",
|
|
1281
|
+
{
|
|
1282
|
+
onClick: onClose,
|
|
1283
|
+
className: "ml-auto text-gray-400 hover:text-gray-600 dark:hover:text-gray-300 transition-colors",
|
|
1284
|
+
"aria-label": "Close drawer",
|
|
1285
|
+
children: /* @__PURE__ */ jsx75("svg", { className: "w-6 h-6", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ jsx75("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M6 18L18 6M6 6l12 12" }) })
|
|
1286
|
+
}
|
|
1287
|
+
)
|
|
1288
|
+
] }),
|
|
1289
|
+
/* @__PURE__ */ jsx75("div", { className: "flex-1 p-6 overflow-y-auto", children })
|
|
1290
|
+
]
|
|
1291
|
+
}
|
|
1292
|
+
)
|
|
1293
|
+
] });
|
|
1294
|
+
};
|
|
1295
|
+
|
|
1296
|
+
// src/components/TextInput.tsx
|
|
1297
|
+
import { forwardRef } from "react";
|
|
1298
|
+
import { jsx as jsx76, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
1299
|
+
var sizeClasses4 = {
|
|
1300
|
+
sm: "px-3 py-1.5 text-sm",
|
|
1301
|
+
md: "px-4 py-2.5 text-base",
|
|
1302
|
+
lg: "px-4 py-3 text-lg"
|
|
1303
|
+
};
|
|
1304
|
+
var TextInput = forwardRef(
|
|
1305
|
+
({
|
|
1306
|
+
label,
|
|
1307
|
+
error,
|
|
1308
|
+
helperText,
|
|
1309
|
+
size = "md",
|
|
1310
|
+
fullWidth = false,
|
|
1311
|
+
leftIcon,
|
|
1312
|
+
rightIcon,
|
|
1313
|
+
className = "",
|
|
1314
|
+
disabled,
|
|
1315
|
+
...props
|
|
1316
|
+
}, ref) => {
|
|
1317
|
+
const { theme, themeName } = useTheme();
|
|
1318
|
+
const baseStyles = theme.select?.base || "w-full appearance-none rounded-lg border border-gray-300 bg-white text-gray-900 transition-all duration-150 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent shadow-sm hover:border-gray-400 dark:bg-gray-800 dark:border-gray-600 dark:text-gray-100 dark:hover:border-gray-500";
|
|
1319
|
+
const sizeStyle = sizeClasses4[size];
|
|
1320
|
+
const errorStyles = error ? "border-red-500 focus:ring-red-500 dark:border-red-500" : "";
|
|
1321
|
+
const disabledStyles = disabled ? "opacity-50 cursor-not-allowed bg-gray-50 dark:bg-gray-900" : "";
|
|
1322
|
+
const widthStyle = fullWidth ? "w-full" : "";
|
|
1323
|
+
const paddingWithIcon = leftIcon ? "pl-10" : rightIcon ? "pr-10" : "";
|
|
1324
|
+
return /* @__PURE__ */ jsxs11("div", { className: `${widthStyle} ${className}`, children: [
|
|
1325
|
+
label && /* @__PURE__ */ jsx76("label", { className: "block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1", children: label }),
|
|
1326
|
+
/* @__PURE__ */ jsxs11("div", { className: "relative", children: [
|
|
1327
|
+
leftIcon && /* @__PURE__ */ jsx76("div", { className: "absolute left-3 top-1/2 transform -translate-y-1/2 text-gray-400 dark:text-gray-500", children: leftIcon }),
|
|
1328
|
+
/* @__PURE__ */ jsx76(
|
|
1329
|
+
"input",
|
|
1330
|
+
{
|
|
1331
|
+
ref,
|
|
1332
|
+
className: `${baseStyles} ${sizeStyle} ${errorStyles} ${disabledStyles} ${paddingWithIcon}`.trim(),
|
|
1333
|
+
disabled,
|
|
1334
|
+
...props
|
|
1335
|
+
}
|
|
1336
|
+
),
|
|
1337
|
+
rightIcon && /* @__PURE__ */ jsx76("div", { className: "absolute right-3 top-1/2 transform -translate-y-1/2 text-gray-400 dark:text-gray-500", children: rightIcon })
|
|
1338
|
+
] }),
|
|
1339
|
+
error && /* @__PURE__ */ jsx76("p", { className: "mt-1 text-sm text-red-600 dark:text-red-400", children: error }),
|
|
1340
|
+
helperText && !error && /* @__PURE__ */ jsx76("p", { className: "mt-1 text-sm text-gray-500 dark:text-gray-400", children: helperText })
|
|
1341
|
+
] });
|
|
1342
|
+
}
|
|
1343
|
+
);
|
|
1344
|
+
TextInput.displayName = "TextInput";
|
|
1345
|
+
|
|
1346
|
+
// src/components/NumberInput.tsx
|
|
1347
|
+
import { useState as useState5, useRef as useRef2 } from "react";
|
|
1348
|
+
import { jsx as jsx77, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
1349
|
+
var sizeClasses5 = {
|
|
1350
|
+
sm: "px-3 py-1.5 text-sm",
|
|
1351
|
+
md: "px-4 py-2.5 text-base",
|
|
1352
|
+
lg: "px-4 py-3 text-lg"
|
|
1353
|
+
};
|
|
1354
|
+
var NumberInput = ({
|
|
1355
|
+
label,
|
|
1356
|
+
error,
|
|
1357
|
+
helperText,
|
|
1358
|
+
value,
|
|
1359
|
+
onChange,
|
|
1360
|
+
min,
|
|
1361
|
+
max,
|
|
1362
|
+
step = 1,
|
|
1363
|
+
precision,
|
|
1364
|
+
disabled = false,
|
|
1365
|
+
hideControls = false,
|
|
1366
|
+
size = "md",
|
|
1367
|
+
fullWidth = false,
|
|
1368
|
+
placeholder,
|
|
1369
|
+
className = ""
|
|
1370
|
+
}) => {
|
|
1371
|
+
const { theme } = useTheme();
|
|
1372
|
+
const inputRef = useRef2(null);
|
|
1373
|
+
const [isFocused, setIsFocused] = useState5(false);
|
|
1374
|
+
const clampValue = (val) => {
|
|
1375
|
+
let clamped = val;
|
|
1376
|
+
if (min !== void 0 && clamped < min) clamped = min;
|
|
1377
|
+
if (max !== void 0 && clamped > max) clamped = max;
|
|
1378
|
+
if (precision !== void 0) {
|
|
1379
|
+
clamped = parseFloat(clamped.toFixed(precision));
|
|
1380
|
+
}
|
|
1381
|
+
return clamped;
|
|
1382
|
+
};
|
|
1383
|
+
const handleIncrement = () => {
|
|
1384
|
+
if (disabled) return;
|
|
1385
|
+
const currentValue = value ?? 0;
|
|
1386
|
+
const newValue = clampValue(currentValue + step);
|
|
1387
|
+
onChange?.(newValue);
|
|
1388
|
+
};
|
|
1389
|
+
const handleDecrement = () => {
|
|
1390
|
+
if (disabled) return;
|
|
1391
|
+
const currentValue = value ?? 0;
|
|
1392
|
+
const newValue = clampValue(currentValue - step);
|
|
1393
|
+
onChange?.(newValue);
|
|
1394
|
+
};
|
|
1395
|
+
const handleInputChange = (e) => {
|
|
1396
|
+
const inputValue = e.target.value;
|
|
1397
|
+
if (inputValue === "" || inputValue === "-") {
|
|
1398
|
+
onChange?.(void 0);
|
|
1399
|
+
return;
|
|
1400
|
+
}
|
|
1401
|
+
const numValue = parseFloat(inputValue);
|
|
1402
|
+
if (!isNaN(numValue)) {
|
|
1403
|
+
const clamped = clampValue(numValue);
|
|
1404
|
+
onChange?.(clamped);
|
|
1405
|
+
}
|
|
1406
|
+
};
|
|
1407
|
+
const handleKeyDown = (e) => {
|
|
1408
|
+
if (e.key === "ArrowUp") {
|
|
1409
|
+
e.preventDefault();
|
|
1410
|
+
handleIncrement();
|
|
1411
|
+
} else if (e.key === "ArrowDown") {
|
|
1412
|
+
e.preventDefault();
|
|
1413
|
+
handleDecrement();
|
|
1414
|
+
}
|
|
1415
|
+
};
|
|
1416
|
+
const baseStyles = "w-full appearance-none rounded-lg border border-gray-300 bg-white text-gray-900 transition-all duration-150 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent shadow-sm hover:border-gray-400 dark:bg-gray-800 dark:border-gray-600 dark:text-gray-100 dark:hover:border-gray-500";
|
|
1417
|
+
const sizeStyle = sizeClasses5[size];
|
|
1418
|
+
const errorStyles = error ? "border-red-500 focus:ring-red-500 dark:border-red-500" : "";
|
|
1419
|
+
const disabledStyles = disabled ? "opacity-50 cursor-not-allowed bg-gray-50 dark:bg-gray-900" : "";
|
|
1420
|
+
const widthStyle = fullWidth ? "w-full" : "";
|
|
1421
|
+
const paddingWithControls = !hideControls ? "pr-8" : "";
|
|
1422
|
+
const displayValue = value !== void 0 ? value.toString() : "";
|
|
1423
|
+
return /* @__PURE__ */ jsxs12("div", { className: `${widthStyle} ${className}`, children: [
|
|
1424
|
+
label && /* @__PURE__ */ jsx77("label", { className: "block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1", children: label }),
|
|
1425
|
+
/* @__PURE__ */ jsxs12("div", { className: "relative", children: [
|
|
1426
|
+
/* @__PURE__ */ jsx77(
|
|
1427
|
+
"input",
|
|
1428
|
+
{
|
|
1429
|
+
ref: inputRef,
|
|
1430
|
+
type: "number",
|
|
1431
|
+
value: displayValue,
|
|
1432
|
+
onChange: handleInputChange,
|
|
1433
|
+
onKeyDown: handleKeyDown,
|
|
1434
|
+
onFocus: () => setIsFocused(true),
|
|
1435
|
+
onBlur: () => setIsFocused(false),
|
|
1436
|
+
disabled,
|
|
1437
|
+
placeholder,
|
|
1438
|
+
min,
|
|
1439
|
+
max,
|
|
1440
|
+
step,
|
|
1441
|
+
className: `${baseStyles} ${sizeStyle} ${errorStyles} ${disabledStyles} ${paddingWithControls} [appearance:textfield] [&::-webkit-outer-spin-button]:appearance-none [&::-webkit-inner-spin-button]:appearance-none`.trim()
|
|
1442
|
+
}
|
|
1443
|
+
),
|
|
1444
|
+
!hideControls && /* @__PURE__ */ jsxs12("div", { className: "absolute right-1 top-1/2 -translate-y-1/2 flex flex-col", children: [
|
|
1445
|
+
/* @__PURE__ */ jsx77(
|
|
1446
|
+
"button",
|
|
1447
|
+
{
|
|
1448
|
+
type: "button",
|
|
1449
|
+
onClick: handleIncrement,
|
|
1450
|
+
disabled: disabled || max !== void 0 && value !== void 0 && value >= max,
|
|
1451
|
+
className: "px-2 py-0.5 hover:bg-gray-100 dark:hover:bg-gray-700 rounded transition-colors disabled:opacity-30 disabled:cursor-not-allowed",
|
|
1452
|
+
tabIndex: -1,
|
|
1453
|
+
children: /* @__PURE__ */ jsx77("svg", { className: "w-3 h-3 text-gray-600 dark:text-gray-400", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx77("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 3, d: "M5 15l7-7 7 7" }) })
|
|
1454
|
+
}
|
|
1455
|
+
),
|
|
1456
|
+
/* @__PURE__ */ jsx77(
|
|
1457
|
+
"button",
|
|
1458
|
+
{
|
|
1459
|
+
type: "button",
|
|
1460
|
+
onClick: handleDecrement,
|
|
1461
|
+
disabled: disabled || min !== void 0 && value !== void 0 && value <= min,
|
|
1462
|
+
className: "px-2 py-0.5 hover:bg-gray-100 dark:hover:bg-gray-700 rounded transition-colors disabled:opacity-30 disabled:cursor-not-allowed",
|
|
1463
|
+
tabIndex: -1,
|
|
1464
|
+
children: /* @__PURE__ */ jsx77("svg", { className: "w-3 h-3 text-gray-600 dark:text-gray-400", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx77("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 3, d: "M19 9l-7 7-7-7" }) })
|
|
1465
|
+
}
|
|
1466
|
+
)
|
|
1467
|
+
] })
|
|
1468
|
+
] }),
|
|
1469
|
+
error && /* @__PURE__ */ jsx77("p", { className: "mt-1 text-sm text-red-600 dark:text-red-400", children: error }),
|
|
1470
|
+
helperText && !error && /* @__PURE__ */ jsx77("p", { className: "mt-1 text-sm text-gray-500 dark:text-gray-400", children: helperText })
|
|
1471
|
+
] });
|
|
1472
|
+
};
|
|
1473
|
+
NumberInput.displayName = "NumberInput";
|
|
1474
|
+
|
|
1475
|
+
// src/components/ActionMenu.tsx
|
|
1476
|
+
import { useState as useState6, useRef as useRef3, useEffect as useEffect5 } from "react";
|
|
1477
|
+
import { createPortal } from "react-dom";
|
|
1478
|
+
import { Fragment as Fragment11, jsx as jsx78, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
1479
|
+
var ActionMenu = ({
|
|
1480
|
+
items,
|
|
1481
|
+
trigger,
|
|
1482
|
+
position = "right",
|
|
1483
|
+
placement = "bottom"
|
|
1484
|
+
}) => {
|
|
1485
|
+
const { themeName } = useTheme();
|
|
1486
|
+
const [isOpen, setIsOpen] = useState6(false);
|
|
1487
|
+
const [menuPosition, setMenuPosition] = useState6(null);
|
|
1488
|
+
const [mounted, setMounted] = useState6(false);
|
|
1489
|
+
const menuRef = useRef3(null);
|
|
1490
|
+
const triggerRef = useRef3(null);
|
|
1491
|
+
useEffect5(() => {
|
|
1492
|
+
setMounted(true);
|
|
1493
|
+
}, []);
|
|
1494
|
+
useEffect5(() => {
|
|
1495
|
+
const handleClickOutside = (event) => {
|
|
1496
|
+
if (menuRef.current && !menuRef.current.contains(event.target) && triggerRef.current && !triggerRef.current.contains(event.target)) {
|
|
1497
|
+
setIsOpen(false);
|
|
1498
|
+
}
|
|
1499
|
+
};
|
|
1500
|
+
if (isOpen) {
|
|
1501
|
+
document.addEventListener("mousedown", handleClickOutside);
|
|
1502
|
+
return () => document.removeEventListener("mousedown", handleClickOutside);
|
|
1503
|
+
}
|
|
1504
|
+
}, [isOpen]);
|
|
1505
|
+
useEffect5(() => {
|
|
1506
|
+
if (isOpen && triggerRef.current) {
|
|
1507
|
+
const rect = triggerRef.current.getBoundingClientRect();
|
|
1508
|
+
const menuWidth = 224;
|
|
1509
|
+
const menuHeight = 300;
|
|
1510
|
+
const spacing = 8;
|
|
1511
|
+
let top = 0;
|
|
1512
|
+
let left = 0;
|
|
1513
|
+
switch (placement) {
|
|
1514
|
+
case "top":
|
|
1515
|
+
top = rect.top - menuHeight - spacing;
|
|
1516
|
+
left = position === "left" ? rect.left : rect.right - menuWidth;
|
|
1517
|
+
break;
|
|
1518
|
+
case "bottom":
|
|
1519
|
+
top = rect.bottom + spacing;
|
|
1520
|
+
left = position === "left" ? rect.left : rect.right - menuWidth;
|
|
1521
|
+
break;
|
|
1522
|
+
case "left":
|
|
1523
|
+
top = rect.top;
|
|
1524
|
+
left = rect.left - menuWidth - spacing;
|
|
1525
|
+
break;
|
|
1526
|
+
case "right":
|
|
1527
|
+
top = rect.top;
|
|
1528
|
+
left = rect.right + spacing;
|
|
1529
|
+
break;
|
|
1530
|
+
}
|
|
1531
|
+
setMenuPosition({ top, left });
|
|
1532
|
+
} else {
|
|
1533
|
+
setMenuPosition(null);
|
|
1534
|
+
}
|
|
1535
|
+
}, [isOpen, position, placement]);
|
|
1536
|
+
const handleItemClick = (item) => {
|
|
1537
|
+
if (item.type === "divider") return;
|
|
1538
|
+
if (!item.disabled) {
|
|
1539
|
+
item.onClick();
|
|
1540
|
+
setIsOpen(false);
|
|
1541
|
+
}
|
|
1542
|
+
};
|
|
1543
|
+
const defaultTrigger = /* @__PURE__ */ jsx78(
|
|
1544
|
+
"button",
|
|
1545
|
+
{
|
|
1546
|
+
className: "p-2 rounded-md hover:bg-gray-100 dark:hover:bg-gray-700 transition-colors",
|
|
1547
|
+
"aria-label": "Open menu",
|
|
1548
|
+
children: /* @__PURE__ */ jsx78("svg", { className: "w-5 h-5 text-gray-600 dark:text-gray-400", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ jsx78("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 5v.01M12 12v.01M12 19v.01M12 6a1 1 0 110-2 1 1 0 010 2zm0 7a1 1 0 110-2 1 1 0 010 2zm0 7a1 1 0 110-2 1 1 0 010 2z" }) })
|
|
1549
|
+
}
|
|
1550
|
+
);
|
|
1551
|
+
const menuBaseStyles = themeName === "minimalistic" ? "bg-black border-2 border-white" : "bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 shadow-lg";
|
|
1552
|
+
const itemBaseStyles = themeName === "minimalistic" ? "text-white hover:bg-white hover:text-black transition-colors duration-200" : "text-gray-700 dark:text-gray-200 hover:bg-gray-100 dark:hover:bg-gray-700 transition-colors";
|
|
1553
|
+
const menu = isOpen && mounted && menuPosition ? /* @__PURE__ */ jsx78(
|
|
1554
|
+
"div",
|
|
1555
|
+
{
|
|
1556
|
+
ref: menuRef,
|
|
1557
|
+
className: `fixed w-56 rounded-lg ${menuBaseStyles} z-[9999] max-h-[80vh] overflow-auto`,
|
|
1558
|
+
style: {
|
|
1559
|
+
minWidth: "14rem",
|
|
1560
|
+
top: `${menuPosition.top}px`,
|
|
1561
|
+
left: `${menuPosition.left}px`
|
|
1562
|
+
},
|
|
1563
|
+
children: items.map((item, index) => {
|
|
1564
|
+
if (item.type === "divider") {
|
|
1565
|
+
return /* @__PURE__ */ jsx78(
|
|
1566
|
+
"div",
|
|
1567
|
+
{
|
|
1568
|
+
className: "my-1 border-t border-gray-200 dark:border-gray-700"
|
|
1569
|
+
},
|
|
1570
|
+
index
|
|
1571
|
+
);
|
|
1572
|
+
}
|
|
1573
|
+
return /* @__PURE__ */ jsxs13(
|
|
1574
|
+
"button",
|
|
273
1575
|
{
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
1576
|
+
onClick: () => handleItemClick(item),
|
|
1577
|
+
disabled: item.disabled,
|
|
1578
|
+
className: `w-full text-left px-4 py-3 flex items-center gap-3 ${itemBaseStyles} ${item.disabled ? "opacity-50 cursor-not-allowed" : "cursor-pointer"} ${item.variant === "danger" ? "text-red-600 dark:text-red-400 hover:bg-red-50 dark:hover:bg-red-900/20" : ""}`,
|
|
1579
|
+
children: [
|
|
1580
|
+
item.icon && /* @__PURE__ */ jsx78("span", { className: "flex-shrink-0", children: item.icon }),
|
|
1581
|
+
/* @__PURE__ */ jsx78("span", { className: "flex-1", children: item.label })
|
|
1582
|
+
]
|
|
277
1583
|
},
|
|
278
|
-
|
|
279
|
-
)
|
|
1584
|
+
index
|
|
1585
|
+
);
|
|
1586
|
+
})
|
|
1587
|
+
}
|
|
1588
|
+
) : null;
|
|
1589
|
+
return /* @__PURE__ */ jsxs13(Fragment11, { children: [
|
|
1590
|
+
/* @__PURE__ */ jsx78("div", { className: "relative inline-block", ref: triggerRef, children: /* @__PURE__ */ jsx78("div", { onClick: () => setIsOpen(!isOpen), children: trigger || defaultTrigger }) }),
|
|
1591
|
+
mounted && createPortal(menu, document.body)
|
|
1592
|
+
] });
|
|
1593
|
+
};
|
|
1594
|
+
|
|
1595
|
+
// src/components/Card.tsx
|
|
1596
|
+
import { jsx as jsx79 } from "react/jsx-runtime";
|
|
1597
|
+
var paddingClasses = {
|
|
1598
|
+
none: "",
|
|
1599
|
+
sm: "p-4",
|
|
1600
|
+
md: "p-6",
|
|
1601
|
+
lg: "p-8"
|
|
1602
|
+
};
|
|
1603
|
+
var Card = ({
|
|
1604
|
+
children,
|
|
1605
|
+
className = "",
|
|
1606
|
+
padding = "md",
|
|
1607
|
+
hover = false,
|
|
1608
|
+
...props
|
|
1609
|
+
}) => {
|
|
1610
|
+
const { theme } = useTheme();
|
|
1611
|
+
const paddingClass = paddingClasses[padding];
|
|
1612
|
+
const hoverClass = hover ? "hover:shadow-xl hover:scale-[1.02] hover:border-blue-400 dark:hover:border-blue-500 cursor-pointer transition-all duration-200 ease-in-out" : "";
|
|
1613
|
+
return /* @__PURE__ */ jsx79(
|
|
1614
|
+
"div",
|
|
1615
|
+
{
|
|
1616
|
+
className: `bg-white dark:bg-gray-800 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700 ${paddingClass} ${hoverClass} ${className}`,
|
|
1617
|
+
...props,
|
|
1618
|
+
children
|
|
1619
|
+
}
|
|
1620
|
+
);
|
|
1621
|
+
};
|
|
1622
|
+
|
|
1623
|
+
// src/components/Alert.tsx
|
|
1624
|
+
import { jsx as jsx80, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
1625
|
+
var variantStyles = {
|
|
1626
|
+
info: "bg-blue-50 dark:bg-blue-900/20 border-blue-200 dark:border-blue-800 text-blue-900 dark:text-blue-100",
|
|
1627
|
+
success: "bg-green-50 dark:bg-green-900/20 border-green-200 dark:border-green-800 text-green-900 dark:text-green-100",
|
|
1628
|
+
warning: "bg-yellow-50 dark:bg-yellow-900/20 border-yellow-200 dark:border-yellow-800 text-yellow-900 dark:text-yellow-100",
|
|
1629
|
+
error: "bg-red-50 dark:bg-red-900/20 border-red-200 dark:border-red-800 text-red-900 dark:text-red-100"
|
|
1630
|
+
};
|
|
1631
|
+
var iconStyles = {
|
|
1632
|
+
info: "text-blue-600 dark:text-blue-400",
|
|
1633
|
+
success: "text-green-600 dark:text-green-400",
|
|
1634
|
+
warning: "text-yellow-600 dark:text-yellow-400",
|
|
1635
|
+
error: "text-red-600 dark:text-red-400"
|
|
1636
|
+
};
|
|
1637
|
+
var Alert = ({
|
|
1638
|
+
variant = "info",
|
|
1639
|
+
title,
|
|
1640
|
+
children,
|
|
1641
|
+
onClose,
|
|
1642
|
+
className = ""
|
|
1643
|
+
}) => {
|
|
1644
|
+
const { theme } = useTheme();
|
|
1645
|
+
const variantClass = variantStyles[variant];
|
|
1646
|
+
const iconClass = iconStyles[variant];
|
|
1647
|
+
return /* @__PURE__ */ jsx80("div", { className: `rounded-lg border p-4 ${variantClass} ${className}`, role: "alert", children: /* @__PURE__ */ jsxs14("div", { className: "flex items-start gap-3", children: [
|
|
1648
|
+
/* @__PURE__ */ jsxs14("div", { className: `flex-shrink-0 ${iconClass}`, children: [
|
|
1649
|
+
variant === "info" && /* @__PURE__ */ jsx80("svg", { className: "w-5 h-5", fill: "currentColor", viewBox: "0 0 20 20", children: /* @__PURE__ */ jsx80("path", { fillRule: "evenodd", d: "M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a1 1 0 000 2v3a1 1 0 001 1h1a1 1 0 100-2v-3a1 1 0 00-1-1H9z", clipRule: "evenodd" }) }),
|
|
1650
|
+
variant === "success" && /* @__PURE__ */ jsx80("svg", { className: "w-5 h-5", fill: "currentColor", viewBox: "0 0 20 20", children: /* @__PURE__ */ jsx80("path", { fillRule: "evenodd", d: "M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z", clipRule: "evenodd" }) }),
|
|
1651
|
+
variant === "warning" && /* @__PURE__ */ jsx80("svg", { className: "w-5 h-5", fill: "currentColor", viewBox: "0 0 20 20", children: /* @__PURE__ */ jsx80("path", { fillRule: "evenodd", d: "M8.257 3.099c.765-1.36 2.722-1.36 3.486 0l5.58 9.92c.75 1.334-.213 2.98-1.742 2.98H4.42c-1.53 0-2.493-1.646-1.743-2.98l5.58-9.92zM11 13a1 1 0 11-2 0 1 1 0 012 0zm-1-8a1 1 0 00-1 1v3a1 1 0 002 0V6a1 1 0 00-1-1z", clipRule: "evenodd" }) }),
|
|
1652
|
+
variant === "error" && /* @__PURE__ */ jsx80("svg", { className: "w-5 h-5", fill: "currentColor", viewBox: "0 0 20 20", children: /* @__PURE__ */ jsx80("path", { fillRule: "evenodd", d: "M10 18a8 8 0 100-16 8 8 0 000 16zM8.707 7.293a1 1 0 00-1.414 1.414L8.586 10l-1.293 1.293a1 1 0 101.414 1.414L10 11.414l1.293 1.293a1 1 0 001.414-1.414L11.414 10l1.293-1.293a1 1 0 00-1.414-1.414L10 8.586 8.707 7.293z", clipRule: "evenodd" }) })
|
|
1653
|
+
] }),
|
|
1654
|
+
/* @__PURE__ */ jsxs14("div", { className: "flex-1", children: [
|
|
1655
|
+
title && /* @__PURE__ */ jsx80("h3", { className: "font-semibold mb-1", children: title }),
|
|
1656
|
+
/* @__PURE__ */ jsx80("div", { className: "text-sm", children })
|
|
1657
|
+
] }),
|
|
1658
|
+
onClose && /* @__PURE__ */ jsx80(
|
|
1659
|
+
"button",
|
|
1660
|
+
{
|
|
1661
|
+
onClick: onClose,
|
|
1662
|
+
className: `flex-shrink-0 ${iconClass} hover:opacity-70 transition-opacity`,
|
|
1663
|
+
"aria-label": "Close alert",
|
|
1664
|
+
children: /* @__PURE__ */ jsx80("svg", { className: "w-5 h-5", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ jsx80("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M6 18L18 6M6 6l12 12" }) })
|
|
280
1665
|
}
|
|
281
1666
|
)
|
|
1667
|
+
] }) });
|
|
1668
|
+
};
|
|
1669
|
+
|
|
1670
|
+
// src/components/Checkbox.tsx
|
|
1671
|
+
import { forwardRef as forwardRef2 } from "react";
|
|
1672
|
+
import { jsx as jsx81, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
1673
|
+
var Checkbox = forwardRef2(
|
|
1674
|
+
({ label, error, className = "", disabled, checked, ...props }, ref) => {
|
|
1675
|
+
const { theme } = useTheme();
|
|
1676
|
+
return /* @__PURE__ */ jsxs15("div", { className, children: [
|
|
1677
|
+
/* @__PURE__ */ jsxs15("label", { className: "flex items-center gap-2 cursor-pointer group", children: [
|
|
1678
|
+
/* @__PURE__ */ jsxs15("div", { className: "relative inline-flex items-center", children: [
|
|
1679
|
+
/* @__PURE__ */ jsx81(
|
|
1680
|
+
"input",
|
|
1681
|
+
{
|
|
1682
|
+
ref,
|
|
1683
|
+
type: "checkbox",
|
|
1684
|
+
disabled,
|
|
1685
|
+
checked,
|
|
1686
|
+
className: "sr-only peer",
|
|
1687
|
+
...props
|
|
1688
|
+
}
|
|
1689
|
+
),
|
|
1690
|
+
/* @__PURE__ */ jsx81("div", { className: `w-4 h-4 border-2 rounded transition-all duration-200 flex items-center justify-center
|
|
1691
|
+
${error ? "border-red-500 dark:border-red-500" : "border-gray-300 dark:border-gray-600"}
|
|
1692
|
+
${disabled ? "opacity-50 cursor-not-allowed bg-gray-100 dark:bg-gray-800" : "peer-hover:border-gray-400 dark:peer-hover:border-gray-500"}
|
|
1693
|
+
peer-checked:bg-blue-600 peer-checked:border-blue-600
|
|
1694
|
+
peer-focus:ring-2 peer-focus:ring-blue-500 peer-focus:ring-offset-2
|
|
1695
|
+
`, children: /* @__PURE__ */ jsx81(
|
|
1696
|
+
"svg",
|
|
1697
|
+
{
|
|
1698
|
+
className: `w-3 h-3 text-white transition-opacity duration-200 ${checked ? "opacity-100" : "opacity-0"}`,
|
|
1699
|
+
viewBox: "0 0 12 12",
|
|
1700
|
+
fill: "none",
|
|
1701
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
1702
|
+
children: /* @__PURE__ */ jsx81(
|
|
1703
|
+
"path",
|
|
1704
|
+
{
|
|
1705
|
+
d: "M10 3L4.5 8.5L2 6",
|
|
1706
|
+
stroke: "currentColor",
|
|
1707
|
+
strokeWidth: "2",
|
|
1708
|
+
strokeLinecap: "round",
|
|
1709
|
+
strokeLinejoin: "round"
|
|
1710
|
+
}
|
|
1711
|
+
)
|
|
1712
|
+
}
|
|
1713
|
+
) })
|
|
1714
|
+
] }),
|
|
1715
|
+
label && /* @__PURE__ */ jsx81("span", { className: `text-sm text-gray-700 dark:text-gray-300 ${disabled ? "opacity-50 cursor-not-allowed" : "group-hover:text-gray-900 dark:group-hover:text-gray-100"}`, children: label })
|
|
1716
|
+
] }),
|
|
1717
|
+
error && /* @__PURE__ */ jsx81("p", { className: "mt-1 text-sm text-red-600 dark:text-red-400", children: error })
|
|
1718
|
+
] });
|
|
1719
|
+
}
|
|
1720
|
+
);
|
|
1721
|
+
Checkbox.displayName = "Checkbox";
|
|
1722
|
+
|
|
1723
|
+
// src/components/Toggle.tsx
|
|
1724
|
+
import { forwardRef as forwardRef3 } from "react";
|
|
1725
|
+
import { jsx as jsx82, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
1726
|
+
var Toggle = forwardRef3(
|
|
1727
|
+
({ label, size = "md", className = "", disabled, checked, ...props }, ref) => {
|
|
1728
|
+
const { theme } = useTheme();
|
|
1729
|
+
const toggleClasses = {
|
|
1730
|
+
sm: {
|
|
1731
|
+
switch: "w-9 h-5",
|
|
1732
|
+
thumb: "w-4 h-4 peer-checked:translate-x-4"
|
|
1733
|
+
},
|
|
1734
|
+
md: {
|
|
1735
|
+
switch: "w-11 h-6",
|
|
1736
|
+
thumb: "w-5 h-5 peer-checked:translate-x-5"
|
|
1737
|
+
},
|
|
1738
|
+
lg: {
|
|
1739
|
+
switch: "w-14 h-7",
|
|
1740
|
+
thumb: "w-6 h-6 peer-checked:translate-x-7"
|
|
1741
|
+
}
|
|
1742
|
+
};
|
|
1743
|
+
const currentSize = toggleClasses[size];
|
|
1744
|
+
return /* @__PURE__ */ jsxs16("label", { className: `inline-flex items-center gap-3 cursor-pointer ${disabled ? "opacity-50 cursor-not-allowed" : ""} ${className}`, children: [
|
|
1745
|
+
/* @__PURE__ */ jsxs16("div", { className: "relative", children: [
|
|
1746
|
+
/* @__PURE__ */ jsx82(
|
|
1747
|
+
"input",
|
|
1748
|
+
{
|
|
1749
|
+
ref,
|
|
1750
|
+
type: "checkbox",
|
|
1751
|
+
className: "sr-only peer",
|
|
1752
|
+
disabled,
|
|
1753
|
+
checked,
|
|
1754
|
+
...props
|
|
1755
|
+
}
|
|
1756
|
+
),
|
|
1757
|
+
/* @__PURE__ */ jsx82(
|
|
1758
|
+
"div",
|
|
1759
|
+
{
|
|
1760
|
+
className: `${currentSize.switch} bg-gray-300 dark:bg-gray-700 peer-focus:ring-2 peer-focus:ring-blue-500 rounded-full peer peer-checked:bg-blue-600 dark:peer-checked:bg-blue-500 transition-colors`
|
|
1761
|
+
}
|
|
1762
|
+
),
|
|
1763
|
+
/* @__PURE__ */ jsx82(
|
|
1764
|
+
"div",
|
|
1765
|
+
{
|
|
1766
|
+
className: `${currentSize.thumb} bg-white rounded-full shadow-md absolute top-0.5 left-0.5 transition-transform`
|
|
1767
|
+
}
|
|
1768
|
+
)
|
|
1769
|
+
] }),
|
|
1770
|
+
label && /* @__PURE__ */ jsx82("span", { className: "text-sm font-medium text-gray-700 dark:text-gray-300", children: label })
|
|
1771
|
+
] });
|
|
1772
|
+
}
|
|
1773
|
+
);
|
|
1774
|
+
Toggle.displayName = "Toggle";
|
|
1775
|
+
|
|
1776
|
+
// src/components/Badge.tsx
|
|
1777
|
+
import { jsx as jsx83 } from "react/jsx-runtime";
|
|
1778
|
+
var variantStyles2 = {
|
|
1779
|
+
default: "bg-gray-100 dark:bg-gray-700 text-gray-800 dark:text-gray-200",
|
|
1780
|
+
primary: "bg-blue-100 dark:bg-blue-900/30 text-blue-800 dark:text-blue-200",
|
|
1781
|
+
success: "bg-green-100 dark:bg-green-900/30 text-green-800 dark:text-green-200",
|
|
1782
|
+
warning: "bg-yellow-100 dark:bg-yellow-900/30 text-yellow-800 dark:text-yellow-200",
|
|
1783
|
+
error: "bg-red-100 dark:bg-red-900/30 text-red-800 dark:text-red-200",
|
|
1784
|
+
info: "bg-cyan-100 dark:bg-cyan-900/30 text-cyan-800 dark:text-cyan-200"
|
|
1785
|
+
};
|
|
1786
|
+
var sizeStyles = {
|
|
1787
|
+
sm: "px-2 py-0.5 text-xs",
|
|
1788
|
+
md: "px-2.5 py-1 text-sm",
|
|
1789
|
+
lg: "px-3 py-1.5 text-base"
|
|
1790
|
+
};
|
|
1791
|
+
var Badge = ({
|
|
1792
|
+
children,
|
|
1793
|
+
variant = "default",
|
|
1794
|
+
size = "md",
|
|
1795
|
+
className = ""
|
|
1796
|
+
}) => {
|
|
1797
|
+
const { theme } = useTheme();
|
|
1798
|
+
const variantClass = variantStyles2[variant];
|
|
1799
|
+
const sizeClass = sizeStyles[size];
|
|
1800
|
+
return /* @__PURE__ */ jsx83("span", { className: `inline-flex items-center font-medium rounded-full ${variantClass} ${sizeClass} ${className}`, children });
|
|
1801
|
+
};
|
|
1802
|
+
|
|
1803
|
+
// src/components/Spinner.tsx
|
|
1804
|
+
import { jsx as jsx84 } from "react/jsx-runtime";
|
|
1805
|
+
var sizeClasses6 = {
|
|
1806
|
+
sm: "w-4 h-4 border-2",
|
|
1807
|
+
md: "w-8 h-8 border-2",
|
|
1808
|
+
lg: "w-12 h-12 border-3",
|
|
1809
|
+
xl: "w-16 h-16 border-4"
|
|
1810
|
+
};
|
|
1811
|
+
var colorClasses = {
|
|
1812
|
+
primary: "border-blue-600 border-t-transparent",
|
|
1813
|
+
secondary: "border-gray-600 border-t-transparent",
|
|
1814
|
+
white: "border-white border-t-transparent"
|
|
1815
|
+
};
|
|
1816
|
+
var Spinner = ({
|
|
1817
|
+
size = "md",
|
|
1818
|
+
color = "primary",
|
|
1819
|
+
className = ""
|
|
1820
|
+
}) => {
|
|
1821
|
+
const { theme } = useTheme();
|
|
1822
|
+
const sizeClass = sizeClasses6[size];
|
|
1823
|
+
const colorClass = colorClasses[color];
|
|
1824
|
+
return /* @__PURE__ */ jsx84(
|
|
1825
|
+
"div",
|
|
1826
|
+
{
|
|
1827
|
+
className: `inline-block rounded-full animate-spin ${sizeClass} ${colorClass} ${className}`,
|
|
1828
|
+
role: "status",
|
|
1829
|
+
"aria-label": "Loading",
|
|
1830
|
+
children: /* @__PURE__ */ jsx84("span", { className: "sr-only", children: "Loading..." })
|
|
1831
|
+
}
|
|
1832
|
+
);
|
|
1833
|
+
};
|
|
1834
|
+
|
|
1835
|
+
// src/components/Tabs.tsx
|
|
1836
|
+
import { useState as useState7 } from "react";
|
|
1837
|
+
import { jsx as jsx85, jsxs as jsxs17 } from "react/jsx-runtime";
|
|
1838
|
+
var Tabs = ({
|
|
1839
|
+
tabs,
|
|
1840
|
+
defaultIndex = 0,
|
|
1841
|
+
onChange,
|
|
1842
|
+
className = ""
|
|
1843
|
+
}) => {
|
|
1844
|
+
const { theme } = useTheme();
|
|
1845
|
+
const [activeIndex, setActiveIndex] = useState7(defaultIndex);
|
|
1846
|
+
const handleTabClick = (index) => {
|
|
1847
|
+
if (tabs[index].disabled) return;
|
|
1848
|
+
setActiveIndex(index);
|
|
1849
|
+
onChange?.(index);
|
|
1850
|
+
};
|
|
1851
|
+
return /* @__PURE__ */ jsxs17("div", { className, children: [
|
|
1852
|
+
/* @__PURE__ */ jsx85("div", { className: "border-b border-gray-200 dark:border-gray-700", children: /* @__PURE__ */ jsx85("nav", { className: "flex gap-8 px-6", "aria-label": "Tabs", children: tabs.map((tab, index) => /* @__PURE__ */ jsx85(
|
|
1853
|
+
"button",
|
|
1854
|
+
{
|
|
1855
|
+
onClick: () => handleTabClick(index),
|
|
1856
|
+
disabled: tab.disabled,
|
|
1857
|
+
className: `py-4 px-1 border-b-2 font-medium text-sm transition-colors ${activeIndex === index ? "border-blue-600 text-blue-600 dark:text-blue-400" : "border-transparent text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-gray-200 hover:border-gray-300 dark:hover:border-gray-600"} ${tab.disabled ? "opacity-50 cursor-not-allowed" : "cursor-pointer"}`,
|
|
1858
|
+
"aria-current": activeIndex === index ? "page" : void 0,
|
|
1859
|
+
children: tab.label
|
|
1860
|
+
},
|
|
1861
|
+
index
|
|
1862
|
+
)) }) }),
|
|
1863
|
+
/* @__PURE__ */ jsx85("div", { children: tabs[activeIndex]?.content })
|
|
1864
|
+
] });
|
|
1865
|
+
};
|
|
1866
|
+
|
|
1867
|
+
// src/components/Table.tsx
|
|
1868
|
+
import { jsx as jsx86, jsxs as jsxs18 } from "react/jsx-runtime";
|
|
1869
|
+
function Table({
|
|
1870
|
+
columns,
|
|
1871
|
+
data,
|
|
1872
|
+
keyField = "id",
|
|
1873
|
+
striped = false,
|
|
1874
|
+
hoverable = true,
|
|
1875
|
+
className = ""
|
|
1876
|
+
}) {
|
|
1877
|
+
const { theme } = useTheme();
|
|
1878
|
+
return /* @__PURE__ */ jsxs18("div", { className: `overflow-x-auto ${className}`, children: [
|
|
1879
|
+
/* @__PURE__ */ jsxs18("table", { className: "w-full text-left", children: [
|
|
1880
|
+
/* @__PURE__ */ jsx86("thead", { className: "bg-gray-50 dark:bg-gray-800 border-b border-gray-200 dark:border-gray-700", children: /* @__PURE__ */ jsx86("tr", { children: columns.map((column, colIndex) => {
|
|
1881
|
+
const isLast = colIndex === columns.length - 1;
|
|
1882
|
+
return /* @__PURE__ */ jsx86(
|
|
1883
|
+
"th",
|
|
1884
|
+
{
|
|
1885
|
+
className: isLast ? "px-6 py-3 text-xs font-medium text-gray-700 dark:text-gray-300 uppercase tracking-wider relative" : "px-6 py-3 text-xs font-medium text-gray-700 dark:text-gray-300 uppercase tracking-wider",
|
|
1886
|
+
style: { width: column.width },
|
|
1887
|
+
children: column.title
|
|
1888
|
+
},
|
|
1889
|
+
column.key
|
|
1890
|
+
);
|
|
1891
|
+
}) }) }),
|
|
1892
|
+
/* @__PURE__ */ jsx86("tbody", { className: "bg-white dark:bg-gray-900 divide-y divide-gray-200 dark:divide-gray-700", children: data.map((row, rowIndex) => {
|
|
1893
|
+
const rowClasses = [
|
|
1894
|
+
striped && rowIndex % 2 === 1 ? "bg-gray-50 dark:bg-gray-800/50" : "",
|
|
1895
|
+
hoverable ? "hover:bg-gray-100 dark:hover:bg-gray-800 transition-colors" : ""
|
|
1896
|
+
].filter(Boolean).join(" ");
|
|
1897
|
+
return /* @__PURE__ */ jsx86(
|
|
1898
|
+
"tr",
|
|
1899
|
+
{
|
|
1900
|
+
className: rowClasses,
|
|
1901
|
+
children: columns.map((column, colIndex) => {
|
|
1902
|
+
const isLast = colIndex === columns.length - 1;
|
|
1903
|
+
return /* @__PURE__ */ jsx86(
|
|
1904
|
+
"td",
|
|
1905
|
+
{
|
|
1906
|
+
className: isLast ? "px-6 py-4 text-sm text-gray-900 dark:text-gray-100 overflow-visible" : "px-6 py-4 text-sm text-gray-900 dark:text-gray-100",
|
|
1907
|
+
children: column.render ? column.render(row[column.key], row, rowIndex) : row[column.key]
|
|
1908
|
+
},
|
|
1909
|
+
column.key
|
|
1910
|
+
);
|
|
1911
|
+
})
|
|
1912
|
+
},
|
|
1913
|
+
row[keyField] || rowIndex
|
|
1914
|
+
);
|
|
1915
|
+
}) })
|
|
1916
|
+
] }),
|
|
1917
|
+
data.length === 0 && /* @__PURE__ */ jsx86("div", { className: "text-center py-8 text-gray-500 dark:text-gray-400", children: "No data available" })
|
|
1918
|
+
] });
|
|
1919
|
+
}
|
|
1920
|
+
|
|
1921
|
+
// src/components/Pagination.tsx
|
|
1922
|
+
import { jsx as jsx87, jsxs as jsxs19 } from "react/jsx-runtime";
|
|
1923
|
+
var Pagination = ({
|
|
1924
|
+
currentPage,
|
|
1925
|
+
totalPages,
|
|
1926
|
+
onPageChange,
|
|
1927
|
+
siblingCount = 1,
|
|
1928
|
+
className = ""
|
|
1929
|
+
}) => {
|
|
1930
|
+
const { theme } = useTheme();
|
|
1931
|
+
const range = (start, end) => {
|
|
1932
|
+
const length = end - start + 1;
|
|
1933
|
+
return Array.from({ length }, (_, idx) => idx + start);
|
|
1934
|
+
};
|
|
1935
|
+
const paginationRange = () => {
|
|
1936
|
+
const totalPageNumbers = siblingCount + 5;
|
|
1937
|
+
if (totalPageNumbers >= totalPages) {
|
|
1938
|
+
return range(1, totalPages);
|
|
1939
|
+
}
|
|
1940
|
+
const leftSiblingIndex = Math.max(currentPage - siblingCount, 1);
|
|
1941
|
+
const rightSiblingIndex = Math.min(currentPage + siblingCount, totalPages);
|
|
1942
|
+
const shouldShowLeftDots = leftSiblingIndex > 2;
|
|
1943
|
+
const shouldShowRightDots = rightSiblingIndex < totalPages - 2;
|
|
1944
|
+
const firstPageIndex = 1;
|
|
1945
|
+
const lastPageIndex = totalPages;
|
|
1946
|
+
if (!shouldShowLeftDots && shouldShowRightDots) {
|
|
1947
|
+
const leftItemCount = 3 + 2 * siblingCount;
|
|
1948
|
+
const leftRange = range(1, leftItemCount);
|
|
1949
|
+
return [...leftRange, "...", totalPages];
|
|
1950
|
+
}
|
|
1951
|
+
if (shouldShowLeftDots && !shouldShowRightDots) {
|
|
1952
|
+
const rightItemCount = 3 + 2 * siblingCount;
|
|
1953
|
+
const rightRange = range(totalPages - rightItemCount + 1, totalPages);
|
|
1954
|
+
return [firstPageIndex, "...", ...rightRange];
|
|
1955
|
+
}
|
|
1956
|
+
if (shouldShowLeftDots && shouldShowRightDots) {
|
|
1957
|
+
const middleRange = range(leftSiblingIndex, rightSiblingIndex);
|
|
1958
|
+
return [firstPageIndex, "...", ...middleRange, "...", lastPageIndex];
|
|
1959
|
+
}
|
|
1960
|
+
return range(1, totalPages);
|
|
1961
|
+
};
|
|
1962
|
+
const pages = paginationRange();
|
|
1963
|
+
return /* @__PURE__ */ jsxs19("nav", { className: `flex items-center gap-1 ${className}`, "aria-label": "Pagination", children: [
|
|
1964
|
+
/* @__PURE__ */ jsx87(
|
|
1965
|
+
"button",
|
|
1966
|
+
{
|
|
1967
|
+
onClick: () => onPageChange(currentPage - 1),
|
|
1968
|
+
disabled: currentPage === 1,
|
|
1969
|
+
className: "px-3 py-2 rounded-md text-sm font-medium text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-800 disabled:opacity-50 disabled:cursor-not-allowed transition-colors",
|
|
1970
|
+
"aria-label": "Previous page",
|
|
1971
|
+
children: "Previous"
|
|
1972
|
+
}
|
|
1973
|
+
),
|
|
1974
|
+
pages.map((page, index) => {
|
|
1975
|
+
if (page === "...") {
|
|
1976
|
+
return /* @__PURE__ */ jsx87(
|
|
1977
|
+
"span",
|
|
1978
|
+
{
|
|
1979
|
+
className: "px-3 py-2 text-gray-700 dark:text-gray-300",
|
|
1980
|
+
children: "..."
|
|
1981
|
+
},
|
|
1982
|
+
`dots-${index}`
|
|
1983
|
+
);
|
|
1984
|
+
}
|
|
1985
|
+
return /* @__PURE__ */ jsx87(
|
|
1986
|
+
"button",
|
|
1987
|
+
{
|
|
1988
|
+
onClick: () => onPageChange(page),
|
|
1989
|
+
className: `px-3 py-2 rounded-md text-sm font-medium transition-colors ${currentPage === page ? "bg-blue-600 text-white" : "text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-800"}`,
|
|
1990
|
+
"aria-label": `Page ${page}`,
|
|
1991
|
+
"aria-current": currentPage === page ? "page" : void 0,
|
|
1992
|
+
children: page
|
|
1993
|
+
},
|
|
1994
|
+
page
|
|
1995
|
+
);
|
|
1996
|
+
}),
|
|
1997
|
+
/* @__PURE__ */ jsx87(
|
|
1998
|
+
"button",
|
|
1999
|
+
{
|
|
2000
|
+
onClick: () => onPageChange(currentPage + 1),
|
|
2001
|
+
disabled: currentPage === totalPages,
|
|
2002
|
+
className: "px-3 py-2 rounded-md text-sm font-medium text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-800 disabled:opacity-50 disabled:cursor-not-allowed transition-colors",
|
|
2003
|
+
"aria-label": "Next page",
|
|
2004
|
+
children: "Next"
|
|
2005
|
+
}
|
|
2006
|
+
)
|
|
2007
|
+
] });
|
|
2008
|
+
};
|
|
2009
|
+
|
|
2010
|
+
// src/components/DatePicker.tsx
|
|
2011
|
+
import { useState as useState8, useRef as useRef4, useEffect as useEffect6 } from "react";
|
|
2012
|
+
import { createPortal as createPortal2 } from "react-dom";
|
|
2013
|
+
import { jsx as jsx88, jsxs as jsxs20 } from "react/jsx-runtime";
|
|
2014
|
+
var DAYS = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
|
|
2015
|
+
var MONTHS = [
|
|
2016
|
+
"January",
|
|
2017
|
+
"February",
|
|
2018
|
+
"March",
|
|
2019
|
+
"April",
|
|
2020
|
+
"May",
|
|
2021
|
+
"June",
|
|
2022
|
+
"July",
|
|
2023
|
+
"August",
|
|
2024
|
+
"September",
|
|
2025
|
+
"October",
|
|
2026
|
+
"November",
|
|
2027
|
+
"December"
|
|
2028
|
+
];
|
|
2029
|
+
var DatePicker = ({
|
|
2030
|
+
label,
|
|
2031
|
+
error,
|
|
2032
|
+
helperText,
|
|
2033
|
+
value,
|
|
2034
|
+
onChange,
|
|
2035
|
+
minDate,
|
|
2036
|
+
maxDate,
|
|
2037
|
+
disabled,
|
|
2038
|
+
className = "",
|
|
2039
|
+
placeholder = "Select date..."
|
|
2040
|
+
}) => {
|
|
2041
|
+
const { theme } = useTheme();
|
|
2042
|
+
const [isOpen, setIsOpen] = useState8(false);
|
|
2043
|
+
const [viewDate, setViewDate] = useState8(value || /* @__PURE__ */ new Date());
|
|
2044
|
+
const [mounted, setMounted] = useState8(false);
|
|
2045
|
+
const [calendarPosition, setCalendarPosition] = useState8(null);
|
|
2046
|
+
const inputRef = useRef4(null);
|
|
2047
|
+
const calendarRef = useRef4(null);
|
|
2048
|
+
useEffect6(() => {
|
|
2049
|
+
setMounted(true);
|
|
2050
|
+
}, []);
|
|
2051
|
+
useEffect6(() => {
|
|
2052
|
+
const handleClickOutside = (event) => {
|
|
2053
|
+
if (calendarRef.current && !calendarRef.current.contains(event.target) && inputRef.current && !inputRef.current.contains(event.target)) {
|
|
2054
|
+
setIsOpen(false);
|
|
2055
|
+
}
|
|
2056
|
+
};
|
|
2057
|
+
if (isOpen) {
|
|
2058
|
+
document.addEventListener("mousedown", handleClickOutside);
|
|
2059
|
+
return () => document.removeEventListener("mousedown", handleClickOutside);
|
|
2060
|
+
}
|
|
2061
|
+
}, [isOpen]);
|
|
2062
|
+
useEffect6(() => {
|
|
2063
|
+
if (isOpen && inputRef.current) {
|
|
2064
|
+
const rect = inputRef.current.getBoundingClientRect();
|
|
2065
|
+
setCalendarPosition({
|
|
2066
|
+
top: rect.bottom + 8,
|
|
2067
|
+
left: rect.left
|
|
2068
|
+
});
|
|
2069
|
+
} else {
|
|
2070
|
+
setCalendarPosition(null);
|
|
2071
|
+
}
|
|
2072
|
+
}, [isOpen]);
|
|
2073
|
+
const year = viewDate.getFullYear();
|
|
2074
|
+
const month = viewDate.getMonth();
|
|
2075
|
+
const firstDayOfMonth = new Date(year, month, 1).getDay();
|
|
2076
|
+
const daysInMonth = new Date(year, month + 1, 0).getDate();
|
|
2077
|
+
const daysInPrevMonth = new Date(year, month, 0).getDate();
|
|
2078
|
+
const calendarDays = [];
|
|
2079
|
+
for (let i = firstDayOfMonth - 1; i >= 0; i--) {
|
|
2080
|
+
calendarDays.push(new Date(year, month - 1, daysInPrevMonth - i));
|
|
2081
|
+
}
|
|
2082
|
+
for (let i = 1; i <= daysInMonth; i++) {
|
|
2083
|
+
calendarDays.push(new Date(year, month, i));
|
|
2084
|
+
}
|
|
2085
|
+
const remainingDays = 42 - calendarDays.length;
|
|
2086
|
+
for (let i = 1; i <= remainingDays; i++) {
|
|
2087
|
+
calendarDays.push(new Date(year, month + 1, i));
|
|
2088
|
+
}
|
|
2089
|
+
const isSameDay = (date1, date2) => {
|
|
2090
|
+
return date1.getDate() === date2.getDate() && date1.getMonth() === date2.getMonth() && date1.getFullYear() === date2.getFullYear();
|
|
2091
|
+
};
|
|
2092
|
+
const isToday = (date) => {
|
|
2093
|
+
return isSameDay(date, /* @__PURE__ */ new Date());
|
|
2094
|
+
};
|
|
2095
|
+
const isSelected = (date) => {
|
|
2096
|
+
return value && isSameDay(date, value);
|
|
2097
|
+
};
|
|
2098
|
+
const isCurrentMonth = (date) => {
|
|
2099
|
+
return date.getMonth() === month;
|
|
2100
|
+
};
|
|
2101
|
+
const isDisabled = (date) => {
|
|
2102
|
+
if (minDate && date < minDate) return true;
|
|
2103
|
+
if (maxDate && date > maxDate) return true;
|
|
2104
|
+
return false;
|
|
2105
|
+
};
|
|
2106
|
+
const handleDateClick = (date) => {
|
|
2107
|
+
if (isDisabled(date)) return;
|
|
2108
|
+
onChange?.(date);
|
|
2109
|
+
setIsOpen(false);
|
|
2110
|
+
};
|
|
2111
|
+
const handlePrevMonth = () => {
|
|
2112
|
+
setViewDate(new Date(year, month - 1, 1));
|
|
2113
|
+
};
|
|
2114
|
+
const handleNextMonth = () => {
|
|
2115
|
+
setViewDate(new Date(year, month + 1, 1));
|
|
2116
|
+
};
|
|
2117
|
+
const handleToday = () => {
|
|
2118
|
+
const today = /* @__PURE__ */ new Date();
|
|
2119
|
+
setViewDate(today);
|
|
2120
|
+
onChange?.(today);
|
|
2121
|
+
setIsOpen(false);
|
|
2122
|
+
};
|
|
2123
|
+
const formatDate = (date) => {
|
|
2124
|
+
if (!date) return "";
|
|
2125
|
+
return date.toLocaleDateString("en-US", {
|
|
2126
|
+
month: "short",
|
|
2127
|
+
day: "numeric",
|
|
2128
|
+
year: "numeric"
|
|
2129
|
+
});
|
|
2130
|
+
};
|
|
2131
|
+
const baseStyles = "w-full appearance-none rounded-lg border border-gray-300 bg-white text-gray-900 px-4 py-2.5 text-base transition-all duration-150 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent shadow-sm hover:border-gray-400 dark:bg-gray-800 dark:border-gray-600 dark:text-gray-100 dark:hover:border-gray-500 cursor-pointer";
|
|
2132
|
+
const errorStyles = error ? "border-red-500 focus:ring-red-500 dark:border-red-500" : "";
|
|
2133
|
+
const disabledStyles = disabled ? "opacity-50 cursor-not-allowed bg-gray-50 dark:bg-gray-900" : "";
|
|
2134
|
+
const calendar = isOpen && mounted && calendarPosition ? /* @__PURE__ */ jsxs20(
|
|
2135
|
+
"div",
|
|
2136
|
+
{
|
|
2137
|
+
ref: calendarRef,
|
|
2138
|
+
className: "fixed z-[9999] bg-white dark:bg-gray-800 rounded-lg border border-gray-200 dark:border-gray-700 shadow-xl p-4",
|
|
2139
|
+
style: {
|
|
2140
|
+
top: `${calendarPosition.top}px`,
|
|
2141
|
+
left: `${calendarPosition.left}px`,
|
|
2142
|
+
minWidth: "320px"
|
|
2143
|
+
},
|
|
2144
|
+
children: [
|
|
2145
|
+
/* @__PURE__ */ jsxs20("div", { className: "flex items-center justify-between mb-4", children: [
|
|
2146
|
+
/* @__PURE__ */ jsx88(
|
|
2147
|
+
"button",
|
|
2148
|
+
{
|
|
2149
|
+
onClick: handlePrevMonth,
|
|
2150
|
+
className: "p-2 hover:bg-gray-100 dark:hover:bg-gray-700 rounded-lg transition-colors",
|
|
2151
|
+
"aria-label": "Previous month",
|
|
2152
|
+
children: /* @__PURE__ */ jsx88("svg", { className: "w-5 h-5 text-gray-600 dark:text-gray-400", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx88("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M15 19l-7-7 7-7" }) })
|
|
2153
|
+
}
|
|
2154
|
+
),
|
|
2155
|
+
/* @__PURE__ */ jsxs20("div", { className: "flex items-center gap-2", children: [
|
|
2156
|
+
/* @__PURE__ */ jsxs20("h2", { className: "text-base font-semibold text-gray-900 dark:text-gray-100", children: [
|
|
2157
|
+
MONTHS[month],
|
|
2158
|
+
" ",
|
|
2159
|
+
year
|
|
2160
|
+
] }),
|
|
2161
|
+
/* @__PURE__ */ jsx88(
|
|
2162
|
+
"button",
|
|
2163
|
+
{
|
|
2164
|
+
onClick: handleToday,
|
|
2165
|
+
className: "px-2 py-1 text-xs bg-blue-600 text-white rounded hover:bg-blue-700 transition-colors",
|
|
2166
|
+
children: "Today"
|
|
2167
|
+
}
|
|
2168
|
+
)
|
|
2169
|
+
] }),
|
|
2170
|
+
/* @__PURE__ */ jsx88(
|
|
2171
|
+
"button",
|
|
2172
|
+
{
|
|
2173
|
+
onClick: handleNextMonth,
|
|
2174
|
+
className: "p-2 hover:bg-gray-100 dark:hover:bg-gray-700 rounded-lg transition-colors",
|
|
2175
|
+
"aria-label": "Next month",
|
|
2176
|
+
children: /* @__PURE__ */ jsx88("svg", { className: "w-5 h-5 text-gray-600 dark:text-gray-400", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx88("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M9 5l7 7-7 7" }) })
|
|
2177
|
+
}
|
|
2178
|
+
)
|
|
2179
|
+
] }),
|
|
2180
|
+
/* @__PURE__ */ jsx88("div", { className: "grid grid-cols-7 gap-1 mb-2", children: DAYS.map((day) => /* @__PURE__ */ jsx88("div", { className: "text-center text-xs font-semibold text-gray-600 dark:text-gray-400 py-1", children: day }, day)) }),
|
|
2181
|
+
/* @__PURE__ */ jsx88("div", { className: "grid grid-cols-7 gap-1", children: calendarDays.map((date, index) => {
|
|
2182
|
+
const isCurrentMonthDay = isCurrentMonth(date);
|
|
2183
|
+
const isTodayDay = isToday(date);
|
|
2184
|
+
const isSelectedDay = isSelected(date);
|
|
2185
|
+
const isDisabledDay = isDisabled(date);
|
|
2186
|
+
return /* @__PURE__ */ jsx88(
|
|
2187
|
+
"button",
|
|
2188
|
+
{
|
|
2189
|
+
onClick: () => handleDateClick(date),
|
|
2190
|
+
disabled: isDisabledDay,
|
|
2191
|
+
className: `
|
|
2192
|
+
aspect-square p-1 rounded-lg text-sm font-medium transition-all
|
|
2193
|
+
${!isCurrentMonthDay ? "text-gray-400 dark:text-gray-600" : "text-gray-900 dark:text-gray-100"}
|
|
2194
|
+
${isTodayDay && !isSelectedDay ? "bg-blue-50 dark:bg-blue-900/20 text-blue-600 dark:text-blue-400 font-bold" : ""}
|
|
2195
|
+
${isSelectedDay ? "bg-blue-600 text-white hover:bg-blue-700" : ""}
|
|
2196
|
+
${!isSelectedDay && !isDisabledDay ? "hover:bg-gray-100 dark:hover:bg-gray-700" : ""}
|
|
2197
|
+
${isDisabledDay ? "opacity-30 cursor-not-allowed" : "cursor-pointer"}
|
|
2198
|
+
`,
|
|
2199
|
+
children: date.getDate()
|
|
2200
|
+
},
|
|
2201
|
+
index
|
|
2202
|
+
);
|
|
2203
|
+
}) })
|
|
2204
|
+
]
|
|
2205
|
+
}
|
|
2206
|
+
) : null;
|
|
2207
|
+
return /* @__PURE__ */ jsxs20("div", { className, children: [
|
|
2208
|
+
label && /* @__PURE__ */ jsx88("label", { className: "block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1", children: label }),
|
|
2209
|
+
/* @__PURE__ */ jsxs20(
|
|
2210
|
+
"div",
|
|
2211
|
+
{
|
|
2212
|
+
ref: inputRef,
|
|
2213
|
+
onClick: () => !disabled && setIsOpen(!isOpen),
|
|
2214
|
+
className: `${baseStyles} ${errorStyles} ${disabledStyles} flex items-center justify-between`.trim(),
|
|
2215
|
+
children: [
|
|
2216
|
+
/* @__PURE__ */ jsx88("span", { className: !value ? "text-gray-500 dark:text-gray-400" : "", children: value ? formatDate(value) : placeholder }),
|
|
2217
|
+
/* @__PURE__ */ jsx88("svg", { className: "w-5 h-5 text-gray-400", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx88("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z" }) })
|
|
2218
|
+
]
|
|
2219
|
+
}
|
|
2220
|
+
),
|
|
2221
|
+
error && /* @__PURE__ */ jsx88("p", { className: "mt-1 text-sm text-red-600 dark:text-red-400", children: error }),
|
|
2222
|
+
helperText && !error && /* @__PURE__ */ jsx88("p", { className: "mt-1 text-sm text-gray-500 dark:text-gray-400", children: helperText }),
|
|
2223
|
+
mounted && createPortal2(calendar, document.body)
|
|
2224
|
+
] });
|
|
2225
|
+
};
|
|
2226
|
+
DatePicker.displayName = "DatePicker";
|
|
2227
|
+
|
|
2228
|
+
// src/components/TimePicker.tsx
|
|
2229
|
+
import { forwardRef as forwardRef4 } from "react";
|
|
2230
|
+
import { jsx as jsx89, jsxs as jsxs21 } from "react/jsx-runtime";
|
|
2231
|
+
var TimePicker = forwardRef4(
|
|
2232
|
+
({ label, error, helperText, className = "", disabled, ...props }, ref) => {
|
|
2233
|
+
const { theme } = useTheme();
|
|
2234
|
+
const baseStyles = "w-full appearance-none rounded-lg border border-gray-300 bg-white text-gray-900 px-4 py-2.5 text-base transition-all duration-150 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent shadow-sm hover:border-gray-400 dark:bg-gray-800 dark:border-gray-600 dark:text-gray-100 dark:hover:border-gray-500";
|
|
2235
|
+
const errorStyles = error ? "border-red-500 focus:ring-red-500 dark:border-red-500" : "";
|
|
2236
|
+
const disabledStyles = disabled ? "opacity-50 cursor-not-allowed bg-gray-50 dark:bg-gray-900" : "";
|
|
2237
|
+
return /* @__PURE__ */ jsxs21("div", { className, children: [
|
|
2238
|
+
label && /* @__PURE__ */ jsx89("label", { className: "block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1", children: label }),
|
|
2239
|
+
/* @__PURE__ */ jsx89(
|
|
2240
|
+
"input",
|
|
2241
|
+
{
|
|
2242
|
+
ref,
|
|
2243
|
+
type: "time",
|
|
2244
|
+
disabled,
|
|
2245
|
+
className: `${baseStyles} ${errorStyles} ${disabledStyles}`.trim(),
|
|
2246
|
+
...props
|
|
2247
|
+
}
|
|
2248
|
+
),
|
|
2249
|
+
error && /* @__PURE__ */ jsx89("p", { className: "mt-1 text-sm text-red-600 dark:text-red-400", children: error }),
|
|
2250
|
+
helperText && !error && /* @__PURE__ */ jsx89("p", { className: "mt-1 text-sm text-gray-500 dark:text-gray-400", children: helperText })
|
|
2251
|
+
] });
|
|
2252
|
+
}
|
|
2253
|
+
);
|
|
2254
|
+
TimePicker.displayName = "TimePicker";
|
|
2255
|
+
|
|
2256
|
+
// src/components/DateTimePicker.tsx
|
|
2257
|
+
import { useState as useState9, useRef as useRef5, useEffect as useEffect7 } from "react";
|
|
2258
|
+
import { createPortal as createPortal3 } from "react-dom";
|
|
2259
|
+
import { jsx as jsx90, jsxs as jsxs22 } from "react/jsx-runtime";
|
|
2260
|
+
var DAYS2 = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
|
|
2261
|
+
var MONTHS2 = [
|
|
2262
|
+
"January",
|
|
2263
|
+
"February",
|
|
2264
|
+
"March",
|
|
2265
|
+
"April",
|
|
2266
|
+
"May",
|
|
2267
|
+
"June",
|
|
2268
|
+
"July",
|
|
2269
|
+
"August",
|
|
2270
|
+
"September",
|
|
2271
|
+
"October",
|
|
2272
|
+
"November",
|
|
2273
|
+
"December"
|
|
2274
|
+
];
|
|
2275
|
+
var DateTimePicker = ({
|
|
2276
|
+
label,
|
|
2277
|
+
error,
|
|
2278
|
+
helperText,
|
|
2279
|
+
value,
|
|
2280
|
+
onChange,
|
|
2281
|
+
minDate,
|
|
2282
|
+
maxDate,
|
|
2283
|
+
disabled,
|
|
2284
|
+
className = "",
|
|
2285
|
+
placeholder = "Select date and time..."
|
|
2286
|
+
}) => {
|
|
2287
|
+
const { theme } = useTheme();
|
|
2288
|
+
const [isOpen, setIsOpen] = useState9(false);
|
|
2289
|
+
const [viewDate, setViewDate] = useState9(value || /* @__PURE__ */ new Date());
|
|
2290
|
+
const [selectedTime, setSelectedTime] = useState9(
|
|
2291
|
+
value ? { hours: value.getHours(), minutes: value.getMinutes() } : { hours: 12, minutes: 0 }
|
|
2292
|
+
);
|
|
2293
|
+
const [mounted, setMounted] = useState9(false);
|
|
2294
|
+
const [pickerPosition, setPickerPosition] = useState9(null);
|
|
2295
|
+
const inputRef = useRef5(null);
|
|
2296
|
+
const pickerRef = useRef5(null);
|
|
2297
|
+
useEffect7(() => {
|
|
2298
|
+
setMounted(true);
|
|
2299
|
+
}, []);
|
|
2300
|
+
useEffect7(() => {
|
|
2301
|
+
const handleClickOutside = (event) => {
|
|
2302
|
+
if (pickerRef.current && !pickerRef.current.contains(event.target) && inputRef.current && !inputRef.current.contains(event.target)) {
|
|
2303
|
+
setIsOpen(false);
|
|
2304
|
+
}
|
|
2305
|
+
};
|
|
2306
|
+
if (isOpen) {
|
|
2307
|
+
document.addEventListener("mousedown", handleClickOutside);
|
|
2308
|
+
return () => document.removeEventListener("mousedown", handleClickOutside);
|
|
2309
|
+
}
|
|
2310
|
+
}, [isOpen]);
|
|
2311
|
+
useEffect7(() => {
|
|
2312
|
+
if (isOpen && inputRef.current) {
|
|
2313
|
+
const rect = inputRef.current.getBoundingClientRect();
|
|
2314
|
+
setPickerPosition({
|
|
2315
|
+
top: rect.bottom + 8,
|
|
2316
|
+
left: rect.left
|
|
2317
|
+
});
|
|
2318
|
+
} else {
|
|
2319
|
+
setPickerPosition(null);
|
|
2320
|
+
}
|
|
2321
|
+
}, [isOpen]);
|
|
2322
|
+
const year = viewDate.getFullYear();
|
|
2323
|
+
const month = viewDate.getMonth();
|
|
2324
|
+
const firstDayOfMonth = new Date(year, month, 1).getDay();
|
|
2325
|
+
const daysInMonth = new Date(year, month + 1, 0).getDate();
|
|
2326
|
+
const daysInPrevMonth = new Date(year, month, 0).getDate();
|
|
2327
|
+
const calendarDays = [];
|
|
2328
|
+
for (let i = firstDayOfMonth - 1; i >= 0; i--) {
|
|
2329
|
+
calendarDays.push(new Date(year, month - 1, daysInPrevMonth - i));
|
|
2330
|
+
}
|
|
2331
|
+
for (let i = 1; i <= daysInMonth; i++) {
|
|
2332
|
+
calendarDays.push(new Date(year, month, i));
|
|
2333
|
+
}
|
|
2334
|
+
const remainingDays = 42 - calendarDays.length;
|
|
2335
|
+
for (let i = 1; i <= remainingDays; i++) {
|
|
2336
|
+
calendarDays.push(new Date(year, month + 1, i));
|
|
2337
|
+
}
|
|
2338
|
+
const isSameDay = (date1, date2) => {
|
|
2339
|
+
return date1.getDate() === date2.getDate() && date1.getMonth() === date2.getMonth() && date1.getFullYear() === date2.getFullYear();
|
|
2340
|
+
};
|
|
2341
|
+
const isToday = (date) => {
|
|
2342
|
+
return isSameDay(date, /* @__PURE__ */ new Date());
|
|
2343
|
+
};
|
|
2344
|
+
const isSelected = (date) => {
|
|
2345
|
+
return value && isSameDay(date, value);
|
|
2346
|
+
};
|
|
2347
|
+
const isCurrentMonth = (date) => {
|
|
2348
|
+
return date.getMonth() === month;
|
|
2349
|
+
};
|
|
2350
|
+
const isDisabled = (date) => {
|
|
2351
|
+
if (minDate && date < minDate) return true;
|
|
2352
|
+
if (maxDate && date > maxDate) return true;
|
|
2353
|
+
return false;
|
|
2354
|
+
};
|
|
2355
|
+
const handleDateClick = (date) => {
|
|
2356
|
+
if (isDisabled(date)) return;
|
|
2357
|
+
const newDateTime = new Date(
|
|
2358
|
+
date.getFullYear(),
|
|
2359
|
+
date.getMonth(),
|
|
2360
|
+
date.getDate(),
|
|
2361
|
+
selectedTime.hours,
|
|
2362
|
+
selectedTime.minutes
|
|
2363
|
+
);
|
|
2364
|
+
onChange?.(newDateTime);
|
|
2365
|
+
};
|
|
2366
|
+
const handleTimeChange = (hours, minutes) => {
|
|
2367
|
+
setSelectedTime({ hours, minutes });
|
|
2368
|
+
if (value) {
|
|
2369
|
+
const newDateTime = new Date(
|
|
2370
|
+
value.getFullYear(),
|
|
2371
|
+
value.getMonth(),
|
|
2372
|
+
value.getDate(),
|
|
2373
|
+
hours,
|
|
2374
|
+
minutes
|
|
2375
|
+
);
|
|
2376
|
+
onChange?.(newDateTime);
|
|
2377
|
+
}
|
|
2378
|
+
};
|
|
2379
|
+
const handleDone = () => {
|
|
2380
|
+
if (value) {
|
|
2381
|
+
setIsOpen(false);
|
|
2382
|
+
}
|
|
2383
|
+
};
|
|
2384
|
+
const handlePrevMonth = () => {
|
|
2385
|
+
setViewDate(new Date(year, month - 1, 1));
|
|
2386
|
+
};
|
|
2387
|
+
const handleNextMonth = () => {
|
|
2388
|
+
setViewDate(new Date(year, month + 1, 1));
|
|
2389
|
+
};
|
|
2390
|
+
const handleToday = () => {
|
|
2391
|
+
const now = /* @__PURE__ */ new Date();
|
|
2392
|
+
setViewDate(now);
|
|
2393
|
+
setSelectedTime({ hours: now.getHours(), minutes: now.getMinutes() });
|
|
2394
|
+
onChange?.(now);
|
|
2395
|
+
};
|
|
2396
|
+
const formatDateTime = (date) => {
|
|
2397
|
+
if (!date) return "";
|
|
2398
|
+
return date.toLocaleString("en-US", {
|
|
2399
|
+
month: "short",
|
|
2400
|
+
day: "numeric",
|
|
2401
|
+
year: "numeric",
|
|
2402
|
+
hour: "numeric",
|
|
2403
|
+
minute: "2-digit",
|
|
2404
|
+
hour12: true
|
|
2405
|
+
});
|
|
2406
|
+
};
|
|
2407
|
+
const formatTime = (hours, minutes) => {
|
|
2408
|
+
const period = hours >= 12 ? "PM" : "AM";
|
|
2409
|
+
const displayHours = hours % 12 || 12;
|
|
2410
|
+
const displayMinutes = minutes.toString().padStart(2, "0");
|
|
2411
|
+
return `${displayHours}:${displayMinutes} ${period}`;
|
|
2412
|
+
};
|
|
2413
|
+
const baseStyles = "w-full appearance-none rounded-lg border border-gray-300 bg-white text-gray-900 px-4 py-2.5 text-base transition-all duration-150 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent shadow-sm hover:border-gray-400 dark:bg-gray-800 dark:border-gray-600 dark:text-gray-100 dark:hover:border-gray-500 cursor-pointer";
|
|
2414
|
+
const errorStyles = error ? "border-red-500 focus:ring-red-500 dark:border-red-500" : "";
|
|
2415
|
+
const disabledStyles = disabled ? "opacity-50 cursor-not-allowed bg-gray-50 dark:bg-gray-900" : "";
|
|
2416
|
+
const picker = isOpen && mounted && pickerPosition ? /* @__PURE__ */ jsxs22(
|
|
2417
|
+
"div",
|
|
2418
|
+
{
|
|
2419
|
+
ref: pickerRef,
|
|
2420
|
+
className: "fixed z-[9999] bg-white dark:bg-gray-800 rounded-lg border border-gray-200 dark:border-gray-700 shadow-xl p-4",
|
|
2421
|
+
style: {
|
|
2422
|
+
top: `${pickerPosition.top}px`,
|
|
2423
|
+
left: `${pickerPosition.left}px`,
|
|
2424
|
+
minWidth: "360px"
|
|
2425
|
+
},
|
|
2426
|
+
children: [
|
|
2427
|
+
/* @__PURE__ */ jsxs22("div", { className: "flex items-center justify-between mb-4", children: [
|
|
2428
|
+
/* @__PURE__ */ jsx90(
|
|
2429
|
+
"button",
|
|
2430
|
+
{
|
|
2431
|
+
onClick: handlePrevMonth,
|
|
2432
|
+
className: "p-2 hover:bg-gray-100 dark:hover:bg-gray-700 rounded-lg transition-colors",
|
|
2433
|
+
"aria-label": "Previous month",
|
|
2434
|
+
children: /* @__PURE__ */ jsx90("svg", { className: "w-5 h-5 text-gray-600 dark:text-gray-400", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx90("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M15 19l-7-7 7-7" }) })
|
|
2435
|
+
}
|
|
2436
|
+
),
|
|
2437
|
+
/* @__PURE__ */ jsxs22("div", { className: "flex items-center gap-2", children: [
|
|
2438
|
+
/* @__PURE__ */ jsxs22("h2", { className: "text-base font-semibold text-gray-900 dark:text-gray-100", children: [
|
|
2439
|
+
MONTHS2[month],
|
|
2440
|
+
" ",
|
|
2441
|
+
year
|
|
2442
|
+
] }),
|
|
2443
|
+
/* @__PURE__ */ jsx90(
|
|
2444
|
+
"button",
|
|
2445
|
+
{
|
|
2446
|
+
onClick: handleToday,
|
|
2447
|
+
className: "px-2 py-1 text-xs bg-blue-600 text-white rounded hover:bg-blue-700 transition-colors",
|
|
2448
|
+
children: "Now"
|
|
2449
|
+
}
|
|
2450
|
+
)
|
|
2451
|
+
] }),
|
|
2452
|
+
/* @__PURE__ */ jsx90(
|
|
2453
|
+
"button",
|
|
2454
|
+
{
|
|
2455
|
+
onClick: handleNextMonth,
|
|
2456
|
+
className: "p-2 hover:bg-gray-100 dark:hover:bg-gray-700 rounded-lg transition-colors",
|
|
2457
|
+
"aria-label": "Next month",
|
|
2458
|
+
children: /* @__PURE__ */ jsx90("svg", { className: "w-5 h-5 text-gray-600 dark:text-gray-400", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx90("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M9 5l7 7-7 7" }) })
|
|
2459
|
+
}
|
|
2460
|
+
)
|
|
2461
|
+
] }),
|
|
2462
|
+
/* @__PURE__ */ jsx90("div", { className: "grid grid-cols-7 gap-1 mb-2", children: DAYS2.map((day) => /* @__PURE__ */ jsx90("div", { className: "text-center text-xs font-semibold text-gray-600 dark:text-gray-400 py-1", children: day }, day)) }),
|
|
2463
|
+
/* @__PURE__ */ jsx90("div", { className: "grid grid-cols-7 gap-1 mb-4", children: calendarDays.map((date, index) => {
|
|
2464
|
+
const isCurrentMonthDay = isCurrentMonth(date);
|
|
2465
|
+
const isTodayDay = isToday(date);
|
|
2466
|
+
const isSelectedDay = isSelected(date);
|
|
2467
|
+
const isDisabledDay = isDisabled(date);
|
|
2468
|
+
return /* @__PURE__ */ jsx90(
|
|
2469
|
+
"button",
|
|
2470
|
+
{
|
|
2471
|
+
onClick: () => handleDateClick(date),
|
|
2472
|
+
disabled: isDisabledDay,
|
|
2473
|
+
className: `
|
|
2474
|
+
aspect-square p-1 rounded-lg text-sm font-medium transition-all
|
|
2475
|
+
${!isCurrentMonthDay ? "text-gray-400 dark:text-gray-600" : "text-gray-900 dark:text-gray-100"}
|
|
2476
|
+
${isTodayDay && !isSelectedDay ? "bg-blue-50 dark:bg-blue-900/20 text-blue-600 dark:text-blue-400 font-bold" : ""}
|
|
2477
|
+
${isSelectedDay ? "bg-blue-600 text-white hover:bg-blue-700" : ""}
|
|
2478
|
+
${!isSelectedDay && !isDisabledDay ? "hover:bg-gray-100 dark:hover:bg-gray-700" : ""}
|
|
2479
|
+
${isDisabledDay ? "opacity-30 cursor-not-allowed" : "cursor-pointer"}
|
|
2480
|
+
`,
|
|
2481
|
+
children: date.getDate()
|
|
2482
|
+
},
|
|
2483
|
+
index
|
|
2484
|
+
);
|
|
2485
|
+
}) }),
|
|
2486
|
+
/* @__PURE__ */ jsxs22("div", { className: "border-t border-gray-200 dark:border-gray-700 pt-4", children: [
|
|
2487
|
+
/* @__PURE__ */ jsxs22("div", { className: "flex items-center justify-center gap-4 mb-4", children: [
|
|
2488
|
+
/* @__PURE__ */ jsxs22("div", { className: "flex flex-col items-center", children: [
|
|
2489
|
+
/* @__PURE__ */ jsx90("label", { className: "text-xs font-semibold text-gray-600 dark:text-gray-400 mb-2", children: "Hour" }),
|
|
2490
|
+
/* @__PURE__ */ jsxs22("div", { className: "flex flex-col items-center gap-1", children: [
|
|
2491
|
+
/* @__PURE__ */ jsx90(
|
|
2492
|
+
"button",
|
|
2493
|
+
{
|
|
2494
|
+
type: "button",
|
|
2495
|
+
onClick: () => handleTimeChange((selectedTime.hours + 1) % 24, selectedTime.minutes),
|
|
2496
|
+
className: "p-1 hover:bg-gray-100 dark:hover:bg-gray-700 rounded transition-colors",
|
|
2497
|
+
children: /* @__PURE__ */ jsx90("svg", { className: "w-4 h-4 text-gray-600 dark:text-gray-400", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx90("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M5 15l7-7 7 7" }) })
|
|
2498
|
+
}
|
|
2499
|
+
),
|
|
2500
|
+
/* @__PURE__ */ jsx90(
|
|
2501
|
+
"input",
|
|
2502
|
+
{
|
|
2503
|
+
type: "number",
|
|
2504
|
+
min: "0",
|
|
2505
|
+
max: "23",
|
|
2506
|
+
value: selectedTime.hours,
|
|
2507
|
+
onChange: (e) => {
|
|
2508
|
+
const val = parseInt(e.target.value);
|
|
2509
|
+
if (!isNaN(val) && val >= 0 && val <= 23) {
|
|
2510
|
+
handleTimeChange(val, selectedTime.minutes);
|
|
2511
|
+
}
|
|
2512
|
+
},
|
|
2513
|
+
className: "w-16 px-2 py-2 text-center border border-gray-300 dark:border-gray-600 rounded-lg bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100 focus:outline-none focus:ring-2 focus:ring-blue-500 text-lg font-semibold [appearance:textfield] [&::-webkit-outer-spin-button]:appearance-none [&::-webkit-inner-spin-button]:appearance-none"
|
|
2514
|
+
}
|
|
2515
|
+
),
|
|
2516
|
+
/* @__PURE__ */ jsx90(
|
|
2517
|
+
"button",
|
|
2518
|
+
{
|
|
2519
|
+
type: "button",
|
|
2520
|
+
onClick: () => handleTimeChange((selectedTime.hours - 1 + 24) % 24, selectedTime.minutes),
|
|
2521
|
+
className: "p-1 hover:bg-gray-100 dark:hover:bg-gray-700 rounded transition-colors",
|
|
2522
|
+
children: /* @__PURE__ */ jsx90("svg", { className: "w-4 h-4 text-gray-600 dark:text-gray-400", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx90("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M19 9l-7 7-7-7" }) })
|
|
2523
|
+
}
|
|
2524
|
+
)
|
|
2525
|
+
] })
|
|
2526
|
+
] }),
|
|
2527
|
+
/* @__PURE__ */ jsx90("span", { className: "text-2xl font-bold text-gray-600 dark:text-gray-400 mt-8", children: ":" }),
|
|
2528
|
+
/* @__PURE__ */ jsxs22("div", { className: "flex flex-col items-center", children: [
|
|
2529
|
+
/* @__PURE__ */ jsx90("label", { className: "text-xs font-semibold text-gray-600 dark:text-gray-400 mb-2", children: "Minute" }),
|
|
2530
|
+
/* @__PURE__ */ jsxs22("div", { className: "flex flex-col items-center gap-1", children: [
|
|
2531
|
+
/* @__PURE__ */ jsx90(
|
|
2532
|
+
"button",
|
|
2533
|
+
{
|
|
2534
|
+
type: "button",
|
|
2535
|
+
onClick: () => handleTimeChange(selectedTime.hours, (selectedTime.minutes + 1) % 60),
|
|
2536
|
+
className: "p-1 hover:bg-gray-100 dark:hover:bg-gray-700 rounded transition-colors",
|
|
2537
|
+
children: /* @__PURE__ */ jsx90("svg", { className: "w-4 h-4 text-gray-600 dark:text-gray-400", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx90("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M5 15l7-7 7 7" }) })
|
|
2538
|
+
}
|
|
2539
|
+
),
|
|
2540
|
+
/* @__PURE__ */ jsx90(
|
|
2541
|
+
"input",
|
|
2542
|
+
{
|
|
2543
|
+
type: "number",
|
|
2544
|
+
min: "0",
|
|
2545
|
+
max: "59",
|
|
2546
|
+
value: selectedTime.minutes,
|
|
2547
|
+
onChange: (e) => {
|
|
2548
|
+
const val = parseInt(e.target.value);
|
|
2549
|
+
if (!isNaN(val) && val >= 0 && val <= 59) {
|
|
2550
|
+
handleTimeChange(selectedTime.hours, val);
|
|
2551
|
+
}
|
|
2552
|
+
},
|
|
2553
|
+
className: "w-16 px-2 py-2 text-center border border-gray-300 dark:border-gray-600 rounded-lg bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100 focus:outline-none focus:ring-2 focus:ring-blue-500 text-lg font-semibold [appearance:textfield] [&::-webkit-outer-spin-button]:appearance-none [&::-webkit-inner-spin-button]:appearance-none"
|
|
2554
|
+
}
|
|
2555
|
+
),
|
|
2556
|
+
/* @__PURE__ */ jsx90(
|
|
2557
|
+
"button",
|
|
2558
|
+
{
|
|
2559
|
+
type: "button",
|
|
2560
|
+
onClick: () => handleTimeChange(selectedTime.hours, (selectedTime.minutes - 1 + 60) % 60),
|
|
2561
|
+
className: "p-1 hover:bg-gray-100 dark:hover:bg-gray-700 rounded transition-colors",
|
|
2562
|
+
children: /* @__PURE__ */ jsx90("svg", { className: "w-4 h-4 text-gray-600 dark:text-gray-400", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx90("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M19 9l-7 7-7-7" }) })
|
|
2563
|
+
}
|
|
2564
|
+
)
|
|
2565
|
+
] })
|
|
2566
|
+
] })
|
|
2567
|
+
] }),
|
|
2568
|
+
/* @__PURE__ */ jsx90("div", { className: "text-center text-sm text-gray-600 dark:text-gray-400 mb-4", children: formatTime(selectedTime.hours, selectedTime.minutes) }),
|
|
2569
|
+
/* @__PURE__ */ jsx90(
|
|
2570
|
+
"button",
|
|
2571
|
+
{
|
|
2572
|
+
onClick: handleDone,
|
|
2573
|
+
className: "w-full px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors font-medium",
|
|
2574
|
+
children: "Done"
|
|
2575
|
+
}
|
|
2576
|
+
)
|
|
2577
|
+
] })
|
|
2578
|
+
]
|
|
2579
|
+
}
|
|
2580
|
+
) : null;
|
|
2581
|
+
return /* @__PURE__ */ jsxs22("div", { className, children: [
|
|
2582
|
+
label && /* @__PURE__ */ jsx90("label", { className: "block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1", children: label }),
|
|
2583
|
+
/* @__PURE__ */ jsxs22(
|
|
2584
|
+
"div",
|
|
2585
|
+
{
|
|
2586
|
+
ref: inputRef,
|
|
2587
|
+
onClick: () => !disabled && setIsOpen(!isOpen),
|
|
2588
|
+
className: `${baseStyles} ${errorStyles} ${disabledStyles} flex items-center justify-between`.trim(),
|
|
2589
|
+
children: [
|
|
2590
|
+
/* @__PURE__ */ jsx90("span", { className: !value ? "text-gray-500 dark:text-gray-400" : "", children: value ? formatDateTime(value) : placeholder }),
|
|
2591
|
+
/* @__PURE__ */ jsx90("svg", { className: "w-5 h-5 text-gray-400", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx90("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z" }) })
|
|
2592
|
+
]
|
|
2593
|
+
}
|
|
2594
|
+
),
|
|
2595
|
+
error && /* @__PURE__ */ jsx90("p", { className: "mt-1 text-sm text-red-600 dark:text-red-400", children: error }),
|
|
2596
|
+
helperText && !error && /* @__PURE__ */ jsx90("p", { className: "mt-1 text-sm text-gray-500 dark:text-gray-400", children: helperText }),
|
|
2597
|
+
mounted && createPortal3(picker, document.body)
|
|
2598
|
+
] });
|
|
2599
|
+
};
|
|
2600
|
+
DateTimePicker.displayName = "DateTimePicker";
|
|
2601
|
+
|
|
2602
|
+
// src/components/Calendar.tsx
|
|
2603
|
+
import { useState as useState10 } from "react";
|
|
2604
|
+
import { jsx as jsx91, jsxs as jsxs23 } from "react/jsx-runtime";
|
|
2605
|
+
var DAYS3 = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
|
|
2606
|
+
var MONTHS3 = [
|
|
2607
|
+
"January",
|
|
2608
|
+
"February",
|
|
2609
|
+
"March",
|
|
2610
|
+
"April",
|
|
2611
|
+
"May",
|
|
2612
|
+
"June",
|
|
2613
|
+
"July",
|
|
2614
|
+
"August",
|
|
2615
|
+
"September",
|
|
2616
|
+
"October",
|
|
2617
|
+
"November",
|
|
2618
|
+
"December"
|
|
2619
|
+
];
|
|
2620
|
+
var Calendar = ({
|
|
2621
|
+
value,
|
|
2622
|
+
onChange,
|
|
2623
|
+
minDate,
|
|
2624
|
+
maxDate,
|
|
2625
|
+
className = ""
|
|
2626
|
+
}) => {
|
|
2627
|
+
const { theme } = useTheme();
|
|
2628
|
+
const [currentDate, setCurrentDate] = useState10(value || /* @__PURE__ */ new Date());
|
|
2629
|
+
const [viewDate, setViewDate] = useState10(value || /* @__PURE__ */ new Date());
|
|
2630
|
+
const year = viewDate.getFullYear();
|
|
2631
|
+
const month = viewDate.getMonth();
|
|
2632
|
+
const firstDayOfMonth = new Date(year, month, 1).getDay();
|
|
2633
|
+
const daysInMonth = new Date(year, month + 1, 0).getDate();
|
|
2634
|
+
const daysInPrevMonth = new Date(year, month, 0).getDate();
|
|
2635
|
+
const calendarDays = [];
|
|
2636
|
+
for (let i = firstDayOfMonth - 1; i >= 0; i--) {
|
|
2637
|
+
calendarDays.push(new Date(year, month - 1, daysInPrevMonth - i));
|
|
2638
|
+
}
|
|
2639
|
+
for (let i = 1; i <= daysInMonth; i++) {
|
|
2640
|
+
calendarDays.push(new Date(year, month, i));
|
|
2641
|
+
}
|
|
2642
|
+
const remainingDays = 42 - calendarDays.length;
|
|
2643
|
+
for (let i = 1; i <= remainingDays; i++) {
|
|
2644
|
+
calendarDays.push(new Date(year, month + 1, i));
|
|
2645
|
+
}
|
|
2646
|
+
const isSameDay = (date1, date2) => {
|
|
2647
|
+
return date1.getDate() === date2.getDate() && date1.getMonth() === date2.getMonth() && date1.getFullYear() === date2.getFullYear();
|
|
2648
|
+
};
|
|
2649
|
+
const isToday = (date) => {
|
|
2650
|
+
return isSameDay(date, /* @__PURE__ */ new Date());
|
|
2651
|
+
};
|
|
2652
|
+
const isSelected = (date) => {
|
|
2653
|
+
return value && isSameDay(date, value);
|
|
2654
|
+
};
|
|
2655
|
+
const isCurrentMonth = (date) => {
|
|
2656
|
+
return date.getMonth() === month;
|
|
2657
|
+
};
|
|
2658
|
+
const isDisabled = (date) => {
|
|
2659
|
+
if (minDate && date < minDate) return true;
|
|
2660
|
+
if (maxDate && date > maxDate) return true;
|
|
2661
|
+
return false;
|
|
2662
|
+
};
|
|
2663
|
+
const handleDateClick = (date) => {
|
|
2664
|
+
if (isDisabled(date)) return;
|
|
2665
|
+
setCurrentDate(date);
|
|
2666
|
+
onChange?.(date);
|
|
2667
|
+
};
|
|
2668
|
+
const handlePrevMonth = () => {
|
|
2669
|
+
setViewDate(new Date(year, month - 1, 1));
|
|
2670
|
+
};
|
|
2671
|
+
const handleNextMonth = () => {
|
|
2672
|
+
setViewDate(new Date(year, month + 1, 1));
|
|
2673
|
+
};
|
|
2674
|
+
const handleToday = () => {
|
|
2675
|
+
const today = /* @__PURE__ */ new Date();
|
|
2676
|
+
setViewDate(today);
|
|
2677
|
+
setCurrentDate(today);
|
|
2678
|
+
onChange?.(today);
|
|
2679
|
+
};
|
|
2680
|
+
return /* @__PURE__ */ jsxs23("div", { className: `bg-white dark:bg-gray-800 rounded-lg border border-gray-200 dark:border-gray-700 p-4 ${className}`, children: [
|
|
2681
|
+
/* @__PURE__ */ jsxs23("div", { className: "flex items-center justify-between mb-4", children: [
|
|
2682
|
+
/* @__PURE__ */ jsx91(
|
|
2683
|
+
"button",
|
|
2684
|
+
{
|
|
2685
|
+
onClick: handlePrevMonth,
|
|
2686
|
+
className: "p-2 hover:bg-gray-100 dark:hover:bg-gray-700 rounded-lg transition-colors",
|
|
2687
|
+
"aria-label": "Previous month",
|
|
2688
|
+
children: /* @__PURE__ */ jsx91("svg", { className: "w-5 h-5 text-gray-600 dark:text-gray-400", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx91("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M15 19l-7-7 7-7" }) })
|
|
2689
|
+
}
|
|
2690
|
+
),
|
|
2691
|
+
/* @__PURE__ */ jsxs23("div", { className: "flex items-center gap-2", children: [
|
|
2692
|
+
/* @__PURE__ */ jsxs23("h2", { className: "text-lg font-semibold text-gray-900 dark:text-gray-100", children: [
|
|
2693
|
+
MONTHS3[month],
|
|
2694
|
+
" ",
|
|
2695
|
+
year
|
|
2696
|
+
] }),
|
|
2697
|
+
/* @__PURE__ */ jsx91(
|
|
2698
|
+
"button",
|
|
2699
|
+
{
|
|
2700
|
+
onClick: handleToday,
|
|
2701
|
+
className: "px-3 py-1 text-sm bg-blue-600 text-white rounded hover:bg-blue-700 transition-colors",
|
|
2702
|
+
children: "Today"
|
|
2703
|
+
}
|
|
2704
|
+
)
|
|
2705
|
+
] }),
|
|
2706
|
+
/* @__PURE__ */ jsx91(
|
|
2707
|
+
"button",
|
|
2708
|
+
{
|
|
2709
|
+
onClick: handleNextMonth,
|
|
2710
|
+
className: "p-2 hover:bg-gray-100 dark:hover:bg-gray-700 rounded-lg transition-colors",
|
|
2711
|
+
"aria-label": "Next month",
|
|
2712
|
+
children: /* @__PURE__ */ jsx91("svg", { className: "w-5 h-5 text-gray-600 dark:text-gray-400", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx91("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M9 5l7 7-7 7" }) })
|
|
2713
|
+
}
|
|
2714
|
+
)
|
|
2715
|
+
] }),
|
|
2716
|
+
/* @__PURE__ */ jsx91("div", { className: "grid grid-cols-7 gap-1 mb-2", children: DAYS3.map((day) => /* @__PURE__ */ jsx91(
|
|
2717
|
+
"div",
|
|
2718
|
+
{
|
|
2719
|
+
className: "text-center text-xs font-semibold text-gray-600 dark:text-gray-400 py-2",
|
|
2720
|
+
children: day
|
|
2721
|
+
},
|
|
2722
|
+
day
|
|
2723
|
+
)) }),
|
|
2724
|
+
/* @__PURE__ */ jsx91("div", { className: "grid grid-cols-7 gap-1", children: calendarDays.map((date, index) => {
|
|
2725
|
+
if (!date) return /* @__PURE__ */ jsx91("div", {}, index);
|
|
2726
|
+
const isCurrentMonthDay = isCurrentMonth(date);
|
|
2727
|
+
const isTodayDay = isToday(date);
|
|
2728
|
+
const isSelectedDay = isSelected(date);
|
|
2729
|
+
const isDisabledDay = isDisabled(date);
|
|
2730
|
+
return /* @__PURE__ */ jsx91(
|
|
2731
|
+
"button",
|
|
2732
|
+
{
|
|
2733
|
+
onClick: () => handleDateClick(date),
|
|
2734
|
+
disabled: isDisabledDay,
|
|
2735
|
+
className: `
|
|
2736
|
+
aspect-square p-2 rounded-lg text-sm font-medium transition-all
|
|
2737
|
+
${!isCurrentMonthDay ? "text-gray-400 dark:text-gray-600" : "text-gray-900 dark:text-gray-100"}
|
|
2738
|
+
${isTodayDay && !isSelectedDay ? "bg-blue-50 dark:bg-blue-900/20 text-blue-600 dark:text-blue-400 font-bold" : ""}
|
|
2739
|
+
${isSelectedDay ? "bg-blue-600 text-white hover:bg-blue-700" : ""}
|
|
2740
|
+
${!isSelectedDay && !isDisabledDay ? "hover:bg-gray-100 dark:hover:bg-gray-700" : ""}
|
|
2741
|
+
${isDisabledDay ? "opacity-30 cursor-not-allowed" : "cursor-pointer"}
|
|
2742
|
+
`,
|
|
2743
|
+
children: date.getDate()
|
|
2744
|
+
},
|
|
2745
|
+
index
|
|
2746
|
+
);
|
|
2747
|
+
}) })
|
|
2748
|
+
] });
|
|
2749
|
+
};
|
|
2750
|
+
|
|
2751
|
+
// src/components/Radio.tsx
|
|
2752
|
+
import React17 from "react";
|
|
2753
|
+
import { jsx as jsx92, jsxs as jsxs24 } from "react/jsx-runtime";
|
|
2754
|
+
var Radio = ({
|
|
2755
|
+
name,
|
|
2756
|
+
options,
|
|
2757
|
+
value: controlledValue,
|
|
2758
|
+
defaultValue,
|
|
2759
|
+
onChange,
|
|
2760
|
+
disabled = false,
|
|
2761
|
+
orientation = "vertical",
|
|
2762
|
+
className = ""
|
|
2763
|
+
}) => {
|
|
2764
|
+
const [internalValue, setInternalValue] = React17.useState(defaultValue || "");
|
|
2765
|
+
const value = controlledValue !== void 0 ? controlledValue : internalValue;
|
|
2766
|
+
const handleChange = (optionValue) => {
|
|
2767
|
+
if (disabled) return;
|
|
2768
|
+
setInternalValue(optionValue);
|
|
2769
|
+
onChange?.(optionValue);
|
|
2770
|
+
};
|
|
2771
|
+
const containerClass = orientation === "horizontal" ? "flex flex-wrap gap-4" : "flex flex-col gap-2";
|
|
2772
|
+
return /* @__PURE__ */ jsx92("div", { className: `${containerClass} ${className}`, role: "radiogroup", children: options.map((option) => {
|
|
2773
|
+
const isDisabled = disabled || option.disabled;
|
|
2774
|
+
const isChecked = value === option.value;
|
|
2775
|
+
const id = `${name}-${option.value}`;
|
|
2776
|
+
return /* @__PURE__ */ jsxs24(
|
|
2777
|
+
"label",
|
|
2778
|
+
{
|
|
2779
|
+
htmlFor: id,
|
|
2780
|
+
className: `flex items-center gap-2 cursor-pointer group ${isDisabled ? "opacity-50 cursor-not-allowed" : ""}`,
|
|
2781
|
+
children: [
|
|
2782
|
+
/* @__PURE__ */ jsxs24("div", { className: "relative inline-flex items-center", children: [
|
|
2783
|
+
/* @__PURE__ */ jsx92(
|
|
2784
|
+
"input",
|
|
2785
|
+
{
|
|
2786
|
+
type: "radio",
|
|
2787
|
+
id,
|
|
2788
|
+
name,
|
|
2789
|
+
value: option.value,
|
|
2790
|
+
checked: isChecked,
|
|
2791
|
+
onChange: () => handleChange(option.value),
|
|
2792
|
+
disabled: isDisabled,
|
|
2793
|
+
className: "sr-only peer"
|
|
2794
|
+
}
|
|
2795
|
+
),
|
|
2796
|
+
/* @__PURE__ */ jsx92("div", { className: `w-4 h-4 rounded-full border-2 transition-all duration-200 flex items-center justify-center
|
|
2797
|
+
border-gray-300 dark:border-gray-600
|
|
2798
|
+
${isDisabled ? "bg-gray-100 dark:bg-gray-800" : "peer-hover:border-gray-400 dark:peer-hover:border-gray-500"}
|
|
2799
|
+
${isChecked ? "border-blue-600 bg-white dark:bg-gray-900" : ""}
|
|
2800
|
+
peer-focus:ring-2 peer-focus:ring-blue-500 peer-focus:ring-offset-2
|
|
2801
|
+
`, children: /* @__PURE__ */ jsx92("div", { className: `w-2 h-2 rounded-full bg-blue-600 transition-all duration-200 ${isChecked ? "scale-100" : "scale-0"}` }) })
|
|
2802
|
+
] }),
|
|
2803
|
+
/* @__PURE__ */ jsx92("span", { className: `text-sm font-medium text-gray-900 dark:text-gray-300 ${!isDisabled && "group-hover:text-gray-700 dark:group-hover:text-gray-100"}`, children: option.label })
|
|
2804
|
+
]
|
|
2805
|
+
},
|
|
2806
|
+
option.value
|
|
2807
|
+
);
|
|
2808
|
+
}) });
|
|
2809
|
+
};
|
|
2810
|
+
|
|
2811
|
+
// src/components/ProgressBar.tsx
|
|
2812
|
+
import { jsx as jsx93, jsxs as jsxs25 } from "react/jsx-runtime";
|
|
2813
|
+
var ProgressBar = ({
|
|
2814
|
+
value,
|
|
2815
|
+
max = 100,
|
|
2816
|
+
size = "md",
|
|
2817
|
+
variant = "default",
|
|
2818
|
+
showLabel = false,
|
|
2819
|
+
label,
|
|
2820
|
+
className = ""
|
|
2821
|
+
}) => {
|
|
2822
|
+
const percentage = Math.min(Math.max(value / max * 100, 0), 100);
|
|
2823
|
+
const sizeClasses7 = {
|
|
2824
|
+
sm: "h-1",
|
|
2825
|
+
md: "h-2",
|
|
2826
|
+
lg: "h-3"
|
|
2827
|
+
};
|
|
2828
|
+
const variantClasses = {
|
|
2829
|
+
default: "bg-blue-600 dark:bg-blue-500",
|
|
2830
|
+
success: "bg-green-600 dark:bg-green-500",
|
|
2831
|
+
warning: "bg-yellow-500 dark:bg-yellow-400",
|
|
2832
|
+
danger: "bg-red-600 dark:bg-red-500"
|
|
2833
|
+
};
|
|
2834
|
+
return /* @__PURE__ */ jsxs25("div", { className: `w-full ${className}`, children: [
|
|
2835
|
+
(showLabel || label) && /* @__PURE__ */ jsxs25("div", { className: "flex justify-between items-center mb-1", children: [
|
|
2836
|
+
label && /* @__PURE__ */ jsx93("span", { className: "text-sm font-medium text-gray-700 dark:text-gray-300", children: label }),
|
|
2837
|
+
showLabel && /* @__PURE__ */ jsxs25("span", { className: "text-sm font-medium text-gray-700 dark:text-gray-300", children: [
|
|
2838
|
+
Math.round(percentage),
|
|
2839
|
+
"%"
|
|
2840
|
+
] })
|
|
2841
|
+
] }),
|
|
2842
|
+
/* @__PURE__ */ jsx93(
|
|
2843
|
+
"div",
|
|
2844
|
+
{
|
|
2845
|
+
className: `w-full bg-gray-200 dark:bg-gray-700 rounded-full overflow-hidden ${sizeClasses7[size]}`,
|
|
2846
|
+
role: "progressbar",
|
|
2847
|
+
"aria-valuenow": value,
|
|
2848
|
+
"aria-valuemin": 0,
|
|
2849
|
+
"aria-valuemax": max,
|
|
2850
|
+
children: /* @__PURE__ */ jsx93(
|
|
2851
|
+
"div",
|
|
2852
|
+
{
|
|
2853
|
+
className: `${sizeClasses7[size]} ${variantClasses[variant]} rounded-full transition-all duration-300 ease-out`,
|
|
2854
|
+
style: { width: `${percentage}%` }
|
|
2855
|
+
}
|
|
2856
|
+
)
|
|
2857
|
+
}
|
|
2858
|
+
)
|
|
2859
|
+
] });
|
|
2860
|
+
};
|
|
2861
|
+
|
|
2862
|
+
// src/components/Slider.tsx
|
|
2863
|
+
import React18, { useRef as useRef6 } from "react";
|
|
2864
|
+
import { jsx as jsx94, jsxs as jsxs26 } from "react/jsx-runtime";
|
|
2865
|
+
var Slider = ({
|
|
2866
|
+
value: controlledValue,
|
|
2867
|
+
defaultValue = 50,
|
|
2868
|
+
min = 0,
|
|
2869
|
+
max = 100,
|
|
2870
|
+
step = 1,
|
|
2871
|
+
onChange,
|
|
2872
|
+
disabled = false,
|
|
2873
|
+
showValue = false,
|
|
2874
|
+
label,
|
|
2875
|
+
className = "",
|
|
2876
|
+
range = false,
|
|
2877
|
+
rangeValue: controlledRangeValue,
|
|
2878
|
+
defaultRangeValue = [25, 75],
|
|
2879
|
+
onRangeChange
|
|
2880
|
+
}) => {
|
|
2881
|
+
const [internalValue, setInternalValue] = React18.useState(defaultValue);
|
|
2882
|
+
const [internalRangeValue, setInternalRangeValue] = React18.useState(defaultRangeValue);
|
|
2883
|
+
const trackRef = useRef6(null);
|
|
2884
|
+
const [isDragging, setIsDragging] = React18.useState(null);
|
|
2885
|
+
const value = controlledValue !== void 0 ? controlledValue : internalValue;
|
|
2886
|
+
const rangeValue = controlledRangeValue !== void 0 ? controlledRangeValue : internalRangeValue;
|
|
2887
|
+
const handleChange = (e) => {
|
|
2888
|
+
const newValue = Number(e.target.value);
|
|
2889
|
+
setInternalValue(newValue);
|
|
2890
|
+
onChange?.(newValue);
|
|
2891
|
+
};
|
|
2892
|
+
const handleRangeMouseDown = (e, handle) => {
|
|
2893
|
+
if (disabled) return;
|
|
2894
|
+
e.preventDefault();
|
|
2895
|
+
setIsDragging(handle);
|
|
2896
|
+
};
|
|
2897
|
+
const handleRangeMouseMove = (e) => {
|
|
2898
|
+
if (!isDragging || !trackRef.current || disabled) return;
|
|
2899
|
+
const rect = trackRef.current.getBoundingClientRect();
|
|
2900
|
+
const percentage2 = Math.max(0, Math.min(100, (e.clientX - rect.left) / rect.width * 100));
|
|
2901
|
+
const newValue = Math.round(percentage2 / 100 * (max - min) / step) * step + min;
|
|
2902
|
+
if (isDragging === "min") {
|
|
2903
|
+
const newMin = Math.min(newValue, rangeValue[1] - step);
|
|
2904
|
+
const newRange = [newMin, rangeValue[1]];
|
|
2905
|
+
setInternalRangeValue(newRange);
|
|
2906
|
+
onRangeChange?.(newRange);
|
|
2907
|
+
} else {
|
|
2908
|
+
const newMax = Math.max(newValue, rangeValue[0] + step);
|
|
2909
|
+
const newRange = [rangeValue[0], newMax];
|
|
2910
|
+
setInternalRangeValue(newRange);
|
|
2911
|
+
onRangeChange?.(newRange);
|
|
2912
|
+
}
|
|
2913
|
+
};
|
|
2914
|
+
const handleRangeMouseUp = () => {
|
|
2915
|
+
setIsDragging(null);
|
|
2916
|
+
};
|
|
2917
|
+
React18.useEffect(() => {
|
|
2918
|
+
if (isDragging) {
|
|
2919
|
+
document.addEventListener("mousemove", handleRangeMouseMove);
|
|
2920
|
+
document.addEventListener("mouseup", handleRangeMouseUp);
|
|
2921
|
+
return () => {
|
|
2922
|
+
document.removeEventListener("mousemove", handleRangeMouseMove);
|
|
2923
|
+
document.removeEventListener("mouseup", handleRangeMouseUp);
|
|
2924
|
+
};
|
|
2925
|
+
}
|
|
2926
|
+
}, [isDragging, rangeValue]);
|
|
2927
|
+
const percentage = (value - min) / (max - min) * 100;
|
|
2928
|
+
const minPercentage = (rangeValue[0] - min) / (max - min) * 100;
|
|
2929
|
+
const maxPercentage = (rangeValue[1] - min) / (max - min) * 100;
|
|
2930
|
+
if (range) {
|
|
2931
|
+
return /* @__PURE__ */ jsxs26("div", { className: `w-full ${className}`, children: [
|
|
2932
|
+
(label || showValue) && /* @__PURE__ */ jsxs26("div", { className: "flex justify-between items-center mb-2", children: [
|
|
2933
|
+
label && /* @__PURE__ */ jsx94("label", { className: "text-sm font-medium text-gray-700 dark:text-gray-300", children: label }),
|
|
2934
|
+
showValue && /* @__PURE__ */ jsxs26("span", { className: "text-sm font-medium text-gray-700 dark:text-gray-300", children: [
|
|
2935
|
+
rangeValue[0],
|
|
2936
|
+
" - ",
|
|
2937
|
+
rangeValue[1]
|
|
2938
|
+
] })
|
|
2939
|
+
] }),
|
|
2940
|
+
/* @__PURE__ */ jsxs26("div", { className: "relative h-10 flex items-center", ref: trackRef, children: [
|
|
2941
|
+
/* @__PURE__ */ jsx94("div", { className: "absolute w-full h-2 bg-gray-200 dark:bg-gray-700 rounded-full" }),
|
|
2942
|
+
/* @__PURE__ */ jsx94(
|
|
2943
|
+
"div",
|
|
2944
|
+
{
|
|
2945
|
+
className: "absolute h-2 bg-blue-600 dark:bg-blue-500 rounded-full pointer-events-none",
|
|
2946
|
+
style: {
|
|
2947
|
+
left: `${minPercentage}%`,
|
|
2948
|
+
width: `${maxPercentage - minPercentage}%`
|
|
2949
|
+
}
|
|
2950
|
+
}
|
|
2951
|
+
),
|
|
2952
|
+
/* @__PURE__ */ jsx94(
|
|
2953
|
+
"div",
|
|
2954
|
+
{
|
|
2955
|
+
className: `absolute w-4 h-4 -ml-2 rounded-sm bg-white dark:bg-gray-800 border-2 border-blue-600 shadow-md cursor-pointer z-10
|
|
2956
|
+
${disabled ? "opacity-50 cursor-not-allowed" : ""}
|
|
2957
|
+
`,
|
|
2958
|
+
style: { left: `${minPercentage}%` },
|
|
2959
|
+
onMouseDown: (e) => handleRangeMouseDown(e, "min"),
|
|
2960
|
+
role: "slider",
|
|
2961
|
+
"aria-label": `${label ? label + " " : ""}minimum value`,
|
|
2962
|
+
"aria-valuemin": min,
|
|
2963
|
+
"aria-valuemax": rangeValue[1],
|
|
2964
|
+
"aria-valuenow": rangeValue[0],
|
|
2965
|
+
tabIndex: disabled ? -1 : 0
|
|
2966
|
+
}
|
|
2967
|
+
),
|
|
2968
|
+
/* @__PURE__ */ jsx94(
|
|
2969
|
+
"div",
|
|
2970
|
+
{
|
|
2971
|
+
className: `absolute w-4 h-4 -ml-2 rounded-sm bg-white dark:bg-gray-800 border-2 border-blue-600 shadow-md cursor-pointer z-10
|
|
2972
|
+
${disabled ? "opacity-50 cursor-not-allowed" : ""}
|
|
2973
|
+
`,
|
|
2974
|
+
style: { left: `${maxPercentage}%` },
|
|
2975
|
+
onMouseDown: (e) => handleRangeMouseDown(e, "max"),
|
|
2976
|
+
role: "slider",
|
|
2977
|
+
"aria-label": `${label ? label + " " : ""}maximum value`,
|
|
2978
|
+
"aria-valuemin": rangeValue[0],
|
|
2979
|
+
"aria-valuemax": max,
|
|
2980
|
+
"aria-valuenow": rangeValue[1],
|
|
2981
|
+
tabIndex: disabled ? -1 : 0
|
|
2982
|
+
}
|
|
2983
|
+
)
|
|
2984
|
+
] })
|
|
2985
|
+
] });
|
|
2986
|
+
}
|
|
2987
|
+
return /* @__PURE__ */ jsxs26("div", { className: `w-full ${className}`, children: [
|
|
2988
|
+
(label || showValue) && /* @__PURE__ */ jsxs26("div", { className: "flex justify-between items-center mb-2", children: [
|
|
2989
|
+
label && /* @__PURE__ */ jsx94("label", { className: "text-sm font-medium text-gray-700 dark:text-gray-300", children: label }),
|
|
2990
|
+
showValue && /* @__PURE__ */ jsx94("span", { className: "text-sm font-medium text-gray-700 dark:text-gray-300", children: value })
|
|
2991
|
+
] }),
|
|
2992
|
+
/* @__PURE__ */ jsxs26("div", { className: "relative h-10 flex items-center", children: [
|
|
2993
|
+
/* @__PURE__ */ jsx94("div", { className: "absolute w-full h-2 bg-gray-200 dark:bg-gray-700 rounded-full" }),
|
|
2994
|
+
/* @__PURE__ */ jsx94(
|
|
2995
|
+
"div",
|
|
2996
|
+
{
|
|
2997
|
+
className: "absolute h-2 bg-blue-600 dark:bg-blue-500 rounded-full pointer-events-none",
|
|
2998
|
+
style: { width: `${percentage}%` }
|
|
2999
|
+
}
|
|
3000
|
+
),
|
|
3001
|
+
/* @__PURE__ */ jsx94(
|
|
3002
|
+
"div",
|
|
3003
|
+
{
|
|
3004
|
+
className: `absolute w-4 h-4 -ml-2 rounded-sm bg-white dark:bg-gray-800 border-2 border-blue-600 shadow-md pointer-events-none z-10
|
|
3005
|
+
${disabled ? "opacity-50" : ""}
|
|
3006
|
+
`,
|
|
3007
|
+
style: { left: `${percentage}%` }
|
|
3008
|
+
}
|
|
3009
|
+
),
|
|
3010
|
+
/* @__PURE__ */ jsx94(
|
|
3011
|
+
"input",
|
|
3012
|
+
{
|
|
3013
|
+
type: "range",
|
|
3014
|
+
min,
|
|
3015
|
+
max,
|
|
3016
|
+
step,
|
|
3017
|
+
value,
|
|
3018
|
+
onChange: handleChange,
|
|
3019
|
+
disabled,
|
|
3020
|
+
className: "relative w-full h-10 bg-transparent appearance-none cursor-pointer disabled:cursor-not-allowed z-20\n [&::-webkit-slider-thumb]:appearance-none [&::-webkit-slider-thumb]:w-4 [&::-webkit-slider-thumb]:h-4\n [&::-webkit-slider-thumb]:rounded-sm [&::-webkit-slider-thumb]:bg-transparent [&::-webkit-slider-thumb]:cursor-pointer\n [&::-moz-range-thumb]:w-4 [&::-moz-range-thumb]:h-4 [&::-moz-range-thumb]:rounded-sm\n [&::-moz-range-thumb]:bg-transparent [&::-moz-range-thumb]:cursor-pointer [&::-moz-range-thumb]:border-none",
|
|
3021
|
+
"aria-label": label,
|
|
3022
|
+
"aria-valuemin": min,
|
|
3023
|
+
"aria-valuemax": max,
|
|
3024
|
+
"aria-valuenow": value
|
|
3025
|
+
}
|
|
3026
|
+
)
|
|
3027
|
+
] })
|
|
3028
|
+
] });
|
|
3029
|
+
};
|
|
3030
|
+
|
|
3031
|
+
// src/components/Avatar.tsx
|
|
3032
|
+
import React19 from "react";
|
|
3033
|
+
import { jsx as jsx95 } from "react/jsx-runtime";
|
|
3034
|
+
var Avatar = ({
|
|
3035
|
+
src,
|
|
3036
|
+
alt,
|
|
3037
|
+
name,
|
|
3038
|
+
size = "md",
|
|
3039
|
+
shape = "circle",
|
|
3040
|
+
className = "",
|
|
3041
|
+
fallbackColor = "bg-blue-600"
|
|
3042
|
+
}) => {
|
|
3043
|
+
const [imageError, setImageError] = React19.useState(false);
|
|
3044
|
+
const sizeClasses7 = {
|
|
3045
|
+
xs: "w-6 h-6 text-xs",
|
|
3046
|
+
sm: "w-8 h-8 text-sm",
|
|
3047
|
+
md: "w-10 h-10 text-base",
|
|
3048
|
+
lg: "w-12 h-12 text-lg",
|
|
3049
|
+
xl: "w-16 h-16 text-2xl"
|
|
3050
|
+
};
|
|
3051
|
+
const shapeClass = shape === "circle" ? "rounded-full" : "rounded-md";
|
|
3052
|
+
const getInitials = (name2) => {
|
|
3053
|
+
const parts = name2.trim().split(" ");
|
|
3054
|
+
if (parts.length >= 2) {
|
|
3055
|
+
return `${parts[0][0]}${parts[parts.length - 1][0]}`.toUpperCase();
|
|
3056
|
+
}
|
|
3057
|
+
return name2.slice(0, 2).toUpperCase();
|
|
3058
|
+
};
|
|
3059
|
+
const showImage = src && !imageError;
|
|
3060
|
+
const showInitials = !showImage && name;
|
|
3061
|
+
return /* @__PURE__ */ jsx95(
|
|
3062
|
+
"div",
|
|
3063
|
+
{
|
|
3064
|
+
className: `${sizeClasses7[size]} ${shapeClass} flex items-center justify-center overflow-hidden ${showImage ? "bg-gray-200 dark:bg-gray-700" : `${fallbackColor} text-white`} ${className}`,
|
|
3065
|
+
children: showImage ? /* @__PURE__ */ jsx95(
|
|
3066
|
+
"img",
|
|
3067
|
+
{
|
|
3068
|
+
src,
|
|
3069
|
+
alt: alt || name || "Avatar",
|
|
3070
|
+
className: "w-full h-full object-cover",
|
|
3071
|
+
onError: () => setImageError(true)
|
|
3072
|
+
}
|
|
3073
|
+
) : showInitials ? /* @__PURE__ */ jsx95("span", { className: "font-semibold select-none", children: getInitials(name) }) : /* @__PURE__ */ jsx95(
|
|
3074
|
+
"svg",
|
|
3075
|
+
{
|
|
3076
|
+
className: "w-full h-full text-gray-400 dark:text-gray-600",
|
|
3077
|
+
fill: "currentColor",
|
|
3078
|
+
viewBox: "0 0 24 24",
|
|
3079
|
+
children: /* @__PURE__ */ jsx95("path", { d: "M12 12c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm0 2c-2.67 0-8 1.34-8 4v2h16v-2c0-2.66-5.33-4-8-4z" })
|
|
3080
|
+
}
|
|
3081
|
+
)
|
|
3082
|
+
}
|
|
3083
|
+
);
|
|
3084
|
+
};
|
|
3085
|
+
|
|
3086
|
+
// src/components/Textarea.tsx
|
|
3087
|
+
import { jsx as jsx96, jsxs as jsxs27 } from "react/jsx-runtime";
|
|
3088
|
+
var Textarea = ({
|
|
3089
|
+
label,
|
|
3090
|
+
error,
|
|
3091
|
+
helperText,
|
|
3092
|
+
size = "md",
|
|
3093
|
+
resize = "vertical",
|
|
3094
|
+
className = "",
|
|
3095
|
+
disabled,
|
|
3096
|
+
...props
|
|
3097
|
+
}) => {
|
|
3098
|
+
const sizeClasses7 = {
|
|
3099
|
+
sm: "px-3 py-1.5 text-sm min-h-[80px]",
|
|
3100
|
+
md: "px-4 py-2 text-base min-h-[100px]",
|
|
3101
|
+
lg: "px-4 py-3 text-lg min-h-[120px]"
|
|
3102
|
+
};
|
|
3103
|
+
const resizeClasses = {
|
|
3104
|
+
none: "resize-none",
|
|
3105
|
+
vertical: "resize-y",
|
|
3106
|
+
horizontal: "resize-x",
|
|
3107
|
+
both: "resize"
|
|
3108
|
+
};
|
|
3109
|
+
const baseClasses = `w-full rounded-lg border transition-colors duration-150 focus:outline-none focus:ring-2
|
|
3110
|
+
${error ? "border-red-500 focus:ring-red-500 focus:border-red-500 dark:border-red-400 dark:focus:ring-red-400" : "border-gray-300 focus:ring-blue-500 focus:border-blue-500 dark:border-gray-600 dark:focus:ring-blue-400"}
|
|
3111
|
+
bg-white dark:bg-gray-800 text-gray-900 dark:text-gray-100
|
|
3112
|
+
placeholder:text-gray-500 dark:placeholder:text-gray-400
|
|
3113
|
+
disabled:opacity-50 disabled:cursor-not-allowed disabled:bg-gray-50 dark:disabled:bg-gray-900`;
|
|
3114
|
+
return /* @__PURE__ */ jsxs27("div", { className: `w-full ${className}`, children: [
|
|
3115
|
+
label && /* @__PURE__ */ jsx96("label", { className: "block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1", children: label }),
|
|
3116
|
+
/* @__PURE__ */ jsx96(
|
|
3117
|
+
"textarea",
|
|
3118
|
+
{
|
|
3119
|
+
className: `${baseClasses} ${sizeClasses7[size]} ${resizeClasses[resize]}`,
|
|
3120
|
+
disabled,
|
|
3121
|
+
...props
|
|
3122
|
+
}
|
|
3123
|
+
),
|
|
3124
|
+
error && /* @__PURE__ */ jsx96("p", { className: "mt-1 text-sm text-red-600 dark:text-red-400", children: error }),
|
|
3125
|
+
helperText && !error && /* @__PURE__ */ jsx96("p", { className: "mt-1 text-sm text-gray-500 dark:text-gray-400", children: helperText })
|
|
3126
|
+
] });
|
|
3127
|
+
};
|
|
3128
|
+
|
|
3129
|
+
// src/components/RichTextEditor.tsx
|
|
3130
|
+
import { useRef as useRef7, useCallback, useState as useState12, useEffect as useEffect8, useLayoutEffect } from "react";
|
|
3131
|
+
import { jsx as jsx97, jsxs as jsxs28 } from "react/jsx-runtime";
|
|
3132
|
+
var RichTextEditor = ({
|
|
3133
|
+
value = "",
|
|
3134
|
+
onChange,
|
|
3135
|
+
placeholder = "Start typing...",
|
|
3136
|
+
className = "",
|
|
3137
|
+
minHeight = "200px",
|
|
3138
|
+
maxHeight = "500px",
|
|
3139
|
+
disabled = false,
|
|
3140
|
+
label,
|
|
3141
|
+
error,
|
|
3142
|
+
helperText
|
|
3143
|
+
}) => {
|
|
3144
|
+
const { themeName } = useTheme();
|
|
3145
|
+
const editorRef = useRef7(null);
|
|
3146
|
+
const [isFocused, setIsFocused] = useState12(false);
|
|
3147
|
+
const [activeFormats, setActiveFormats] = useState12(/* @__PURE__ */ new Set());
|
|
3148
|
+
const [showLinkModal, setShowLinkModal] = useState12(false);
|
|
3149
|
+
const [linkUrl, setLinkUrl] = useState12("");
|
|
3150
|
+
const [showImageModal, setShowImageModal] = useState12(false);
|
|
3151
|
+
const [imageUrl, setImageUrl] = useState12("");
|
|
3152
|
+
const [imageAlt, setImageAlt] = useState12("");
|
|
3153
|
+
useLayoutEffect(() => {
|
|
3154
|
+
const styleId = "rich-text-editor-styles";
|
|
3155
|
+
if (!document.getElementById(styleId)) {
|
|
3156
|
+
const style = document.createElement("style");
|
|
3157
|
+
style.id = styleId;
|
|
3158
|
+
style.textContent = `
|
|
3159
|
+
[contenteditable]:empty:before {
|
|
3160
|
+
content: attr(data-placeholder);
|
|
3161
|
+
color: #9ca3af;
|
|
3162
|
+
pointer-events: none;
|
|
3163
|
+
}
|
|
3164
|
+
[contenteditable] h1 {
|
|
3165
|
+
font-size: 2em;
|
|
3166
|
+
font-weight: bold;
|
|
3167
|
+
margin: 0.67em 0;
|
|
3168
|
+
}
|
|
3169
|
+
[contenteditable] h2 {
|
|
3170
|
+
font-size: 1.5em;
|
|
3171
|
+
font-weight: bold;
|
|
3172
|
+
margin: 0.75em 0;
|
|
3173
|
+
}
|
|
3174
|
+
[contenteditable] h3 {
|
|
3175
|
+
font-size: 1.17em;
|
|
3176
|
+
font-weight: bold;
|
|
3177
|
+
margin: 0.83em 0;
|
|
3178
|
+
}
|
|
3179
|
+
[contenteditable] ul, [contenteditable] ol {
|
|
3180
|
+
margin: 1em 0;
|
|
3181
|
+
padding-left: 2em;
|
|
3182
|
+
}
|
|
3183
|
+
[contenteditable] a {
|
|
3184
|
+
color: #3b82f6;
|
|
3185
|
+
text-decoration: underline;
|
|
3186
|
+
}
|
|
3187
|
+
.dark [contenteditable] a {
|
|
3188
|
+
color: #60a5fa;
|
|
3189
|
+
}
|
|
3190
|
+
[contenteditable] img {
|
|
3191
|
+
max-width: 100%;
|
|
3192
|
+
height: auto;
|
|
3193
|
+
border-radius: 0.5rem;
|
|
3194
|
+
margin: 1em 0;
|
|
3195
|
+
}
|
|
3196
|
+
[contenteditable] video {
|
|
3197
|
+
max-width: 100%;
|
|
3198
|
+
height: auto;
|
|
3199
|
+
border-radius: 0.5rem;
|
|
3200
|
+
margin: 1em 0;
|
|
3201
|
+
}
|
|
3202
|
+
`;
|
|
3203
|
+
document.head.appendChild(style);
|
|
3204
|
+
}
|
|
3205
|
+
}, []);
|
|
3206
|
+
const isInitialRender = useRef7(true);
|
|
3207
|
+
useEffect8(() => {
|
|
3208
|
+
if (!isInitialRender.current && editorRef.current && editorRef.current.innerHTML !== value) {
|
|
3209
|
+
editorRef.current.innerHTML = value;
|
|
3210
|
+
}
|
|
3211
|
+
isInitialRender.current = false;
|
|
3212
|
+
}, [value]);
|
|
3213
|
+
const updateActiveFormats = useCallback(() => {
|
|
3214
|
+
const formats = /* @__PURE__ */ new Set();
|
|
3215
|
+
if (document.queryCommandState("bold")) formats.add("bold");
|
|
3216
|
+
if (document.queryCommandState("italic")) formats.add("italic");
|
|
3217
|
+
if (document.queryCommandState("underline")) formats.add("underline");
|
|
3218
|
+
if (document.queryCommandState("strikeThrough")) formats.add("strikeThrough");
|
|
3219
|
+
if (document.queryCommandState("insertUnorderedList")) formats.add("ul");
|
|
3220
|
+
if (document.queryCommandState("insertOrderedList")) formats.add("ol");
|
|
3221
|
+
const parentNode = window.getSelection()?.anchorNode?.parentElement;
|
|
3222
|
+
if (parentNode) {
|
|
3223
|
+
const tagName = parentNode.tagName.toLowerCase();
|
|
3224
|
+
if (["h1", "h2", "h3"].includes(tagName)) {
|
|
3225
|
+
formats.add(tagName);
|
|
3226
|
+
}
|
|
3227
|
+
}
|
|
3228
|
+
setActiveFormats(formats);
|
|
3229
|
+
}, []);
|
|
3230
|
+
const handleInput = useCallback(() => {
|
|
3231
|
+
if (editorRef.current && onChange) {
|
|
3232
|
+
onChange(editorRef.current.innerHTML);
|
|
3233
|
+
}
|
|
3234
|
+
updateActiveFormats();
|
|
3235
|
+
}, [onChange, updateActiveFormats]);
|
|
3236
|
+
const handleFormat = useCallback((command) => {
|
|
3237
|
+
if (disabled) return;
|
|
3238
|
+
document.execCommand(command, false);
|
|
3239
|
+
editorRef.current?.focus();
|
|
3240
|
+
updateActiveFormats();
|
|
3241
|
+
handleInput();
|
|
3242
|
+
}, [disabled, updateActiveFormats, handleInput]);
|
|
3243
|
+
const handleList = useCallback((command) => {
|
|
3244
|
+
if (disabled) return;
|
|
3245
|
+
document.execCommand(command, false);
|
|
3246
|
+
editorRef.current?.focus();
|
|
3247
|
+
updateActiveFormats();
|
|
3248
|
+
handleInput();
|
|
3249
|
+
}, [disabled, updateActiveFormats, handleInput]);
|
|
3250
|
+
const handleHeading = useCallback((level) => {
|
|
3251
|
+
if (disabled) return;
|
|
3252
|
+
document.execCommand("formatBlock", false, level);
|
|
3253
|
+
editorRef.current?.focus();
|
|
3254
|
+
updateActiveFormats();
|
|
3255
|
+
handleInput();
|
|
3256
|
+
}, [disabled, updateActiveFormats, handleInput]);
|
|
3257
|
+
const handleLink = useCallback(() => {
|
|
3258
|
+
if (disabled) return;
|
|
3259
|
+
setShowLinkModal(true);
|
|
3260
|
+
}, [disabled]);
|
|
3261
|
+
const insertLink = useCallback(() => {
|
|
3262
|
+
if (linkUrl) {
|
|
3263
|
+
document.execCommand("createLink", false, linkUrl);
|
|
3264
|
+
setShowLinkModal(false);
|
|
3265
|
+
setLinkUrl("");
|
|
3266
|
+
editorRef.current?.focus();
|
|
3267
|
+
handleInput();
|
|
3268
|
+
}
|
|
3269
|
+
}, [linkUrl, handleInput]);
|
|
3270
|
+
const handleCode = useCallback(() => {
|
|
3271
|
+
if (disabled) return;
|
|
3272
|
+
const selection = window.getSelection();
|
|
3273
|
+
if (selection && selection.rangeCount > 0) {
|
|
3274
|
+
const range = selection.getRangeAt(0);
|
|
3275
|
+
const code = document.createElement("code");
|
|
3276
|
+
code.className = "bg-gray-100 dark:bg-gray-700 px-1.5 py-0.5 rounded text-sm font-mono";
|
|
3277
|
+
try {
|
|
3278
|
+
range.surroundContents(code);
|
|
3279
|
+
handleInput();
|
|
3280
|
+
} catch (e) {
|
|
3281
|
+
console.warn("Could not apply code formatting");
|
|
3282
|
+
}
|
|
3283
|
+
}
|
|
3284
|
+
editorRef.current?.focus();
|
|
3285
|
+
}, [disabled, handleInput]);
|
|
3286
|
+
const handleImage = useCallback(() => {
|
|
3287
|
+
if (disabled) return;
|
|
3288
|
+
setShowImageModal(true);
|
|
3289
|
+
}, [disabled]);
|
|
3290
|
+
const insertImage = useCallback(() => {
|
|
3291
|
+
if (!imageUrl) return;
|
|
3292
|
+
const img = document.createElement("img");
|
|
3293
|
+
img.src = imageUrl;
|
|
3294
|
+
img.alt = imageAlt || "";
|
|
3295
|
+
img.style.maxWidth = "100%";
|
|
3296
|
+
img.style.height = "auto";
|
|
3297
|
+
const selection = window.getSelection();
|
|
3298
|
+
if (selection && selection.rangeCount > 0) {
|
|
3299
|
+
const range = selection.getRangeAt(0);
|
|
3300
|
+
range.deleteContents();
|
|
3301
|
+
range.insertNode(img);
|
|
3302
|
+
range.setStartAfter(img);
|
|
3303
|
+
range.setEndAfter(img);
|
|
3304
|
+
selection.removeAllRanges();
|
|
3305
|
+
selection.addRange(range);
|
|
3306
|
+
} else if (editorRef.current) {
|
|
3307
|
+
editorRef.current.appendChild(img);
|
|
3308
|
+
}
|
|
3309
|
+
setShowImageModal(false);
|
|
3310
|
+
setImageUrl("");
|
|
3311
|
+
setImageAlt("");
|
|
3312
|
+
editorRef.current?.focus();
|
|
3313
|
+
handleInput();
|
|
3314
|
+
}, [imageUrl, imageAlt, handleInput, disabled]);
|
|
3315
|
+
const getButtonClass = (isActive) => {
|
|
3316
|
+
const baseClass = themeName === "minimalistic" ? "border border-white text-white transition-colors" : "border border-gray-300 dark:border-gray-600 text-gray-700 dark:text-gray-300 transition-colors";
|
|
3317
|
+
const activeClass = themeName === "minimalistic" ? "bg-white text-black" : "bg-blue-100 dark:bg-blue-900 border-blue-500 dark:border-blue-400";
|
|
3318
|
+
const hoverClass = themeName === "minimalistic" ? "hover:bg-white hover:text-black" : "hover:bg-gray-100 dark:hover:bg-gray-700";
|
|
3319
|
+
const disabledClass = disabled ? "opacity-50 cursor-not-allowed" : "cursor-pointer";
|
|
3320
|
+
return `px-2.5 py-1.5 rounded text-sm font-medium ${baseClass} ${isActive ? activeClass : hoverClass} ${disabledClass}`;
|
|
3321
|
+
};
|
|
3322
|
+
const editorBaseClass = themeName === "minimalistic" ? "bg-transparent border-2 border-white text-white placeholder:text-gray-500" : "bg-white dark:bg-gray-800 border border-gray-300 dark:border-gray-600 text-gray-900 dark:text-gray-100";
|
|
3323
|
+
const focusClass = isFocused && !disabled ? themeName === "minimalistic" ? "border-white" : "border-blue-500 dark:border-blue-400 ring-2 ring-blue-500/20" : "";
|
|
3324
|
+
const errorClass = error ? "border-red-500 dark:border-red-400" : "";
|
|
3325
|
+
return /* @__PURE__ */ jsxs28("div", { className: `w-full ${className}`, children: [
|
|
3326
|
+
label && /* @__PURE__ */ jsx97("label", { className: "block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2", children: label }),
|
|
3327
|
+
/* @__PURE__ */ jsxs28("div", { className: `rounded-t-lg border-b ${editorBaseClass} p-2 flex flex-wrap gap-1`, children: [
|
|
3328
|
+
/* @__PURE__ */ jsxs28("div", { className: "flex gap-1", children: [
|
|
3329
|
+
/* @__PURE__ */ jsx97(
|
|
3330
|
+
"button",
|
|
3331
|
+
{
|
|
3332
|
+
type: "button",
|
|
3333
|
+
onClick: () => handleFormat("bold"),
|
|
3334
|
+
className: getButtonClass(activeFormats.has("bold")),
|
|
3335
|
+
disabled,
|
|
3336
|
+
title: "Bold (Ctrl+B)",
|
|
3337
|
+
children: /* @__PURE__ */ jsx97("svg", { className: "w-4 h-4", fill: "currentColor", viewBox: "0 0 20 20", children: /* @__PURE__ */ jsx97("path", { d: "M12.78 4c1.09 0 2.04.38 2.84 1.14.8.76 1.2 1.74 1.2 2.94 0 .9-.25 1.68-.76 2.36-.51.68-1.2 1.14-2.04 1.38v.08c1.06.22 1.89.7 2.48 1.44.59.74.88 1.64.88 2.7 0 1.34-.47 2.43-1.41 3.27C14.96 19.77 13.74 20 12.24 20H4V4h8.78zm-.66 7.14c.62 0 1.12-.18 1.5-.54.38-.36.57-.84.57-1.44 0-.6-.19-1.08-.57-1.44-.38-.36-.88-.54-1.5-.54H7.5v3.96h4.62zm.24 6.86c.68 0 1.24-.19 1.68-.57.44-.38.66-.9.66-1.56 0-.66-.22-1.18-.66-1.56-.44-.38-1-.57-1.68-.57H7.5v4.26h4.86z" }) })
|
|
3338
|
+
}
|
|
3339
|
+
),
|
|
3340
|
+
/* @__PURE__ */ jsx97(
|
|
3341
|
+
"button",
|
|
3342
|
+
{
|
|
3343
|
+
type: "button",
|
|
3344
|
+
onClick: () => handleFormat("italic"),
|
|
3345
|
+
className: getButtonClass(activeFormats.has("italic")),
|
|
3346
|
+
disabled,
|
|
3347
|
+
title: "Italic (Ctrl+I)",
|
|
3348
|
+
children: /* @__PURE__ */ jsx97("svg", { className: "w-4 h-4", fill: "currentColor", viewBox: "0 0 20 20", children: /* @__PURE__ */ jsx97("path", { d: "M11.59 4H16v2h-1.71l-3.58 8H13v2H8v-2h1.71l3.58-8H11.59V4z" }) })
|
|
3349
|
+
}
|
|
3350
|
+
),
|
|
3351
|
+
/* @__PURE__ */ jsx97(
|
|
3352
|
+
"button",
|
|
3353
|
+
{
|
|
3354
|
+
type: "button",
|
|
3355
|
+
onClick: () => handleFormat("underline"),
|
|
3356
|
+
className: getButtonClass(activeFormats.has("underline")),
|
|
3357
|
+
disabled,
|
|
3358
|
+
title: "Underline (Ctrl+U)",
|
|
3359
|
+
children: /* @__PURE__ */ jsx97("svg", { className: "w-4 h-4", fill: "currentColor", viewBox: "0 0 20 20", children: /* @__PURE__ */ jsx97("path", { d: "M10 16c-2.21 0-4-1.79-4-4V4h2v8c0 1.1.9 2 2 2s2-.9 2-2V4h2v8c0 2.21-1.79 4-4 4zM4 18h12v2H4v-2z" }) })
|
|
3360
|
+
}
|
|
3361
|
+
),
|
|
3362
|
+
/* @__PURE__ */ jsx97(
|
|
3363
|
+
"button",
|
|
3364
|
+
{
|
|
3365
|
+
type: "button",
|
|
3366
|
+
onClick: () => handleFormat("strikeThrough"),
|
|
3367
|
+
className: getButtonClass(activeFormats.has("strikeThrough")),
|
|
3368
|
+
disabled,
|
|
3369
|
+
title: "Strikethrough",
|
|
3370
|
+
children: /* @__PURE__ */ jsx97("svg", { className: "w-4 h-4", fill: "currentColor", viewBox: "0 0 20 20", children: /* @__PURE__ */ jsx97("path", { d: "M10 4c-2 0-3.5.5-4.5 1.5S4 7.5 4 9h2c0-.7.2-1.2.6-1.6.4-.4 1-.6 1.9-.6.8 0 1.4.2 1.8.5.4.3.7.8.7 1.4 0 .5-.2.9-.5 1.2-.3.3-.9.6-1.8.9l-.7.2c-1.2.3-2.1.7-2.7 1.2C4.2 12.7 4 13.5 4 14.5c0 1.1.4 2 1.1 2.6.7.6 1.7.9 3 .9 2.1 0 3.6-.5 4.6-1.5.9-1 1.3-2.3 1.3-3.8h-2c0 .9-.2 1.6-.7 2.1-.5.5-1.2.7-2.2.7-.8 0-1.4-.2-1.8-.5-.4-.3-.6-.8-.6-1.4 0-.5.2-.9.5-1.2.3-.3.9-.6 1.8-.9l.7-.2c1.2-.3 2.1-.7 2.7-1.2.6-.5.9-1.3.9-2.3 0-1.2-.4-2.1-1.2-2.8-.8-.7-1.9-1-3.3-1zM2 10h16v1H2v-1z" }) })
|
|
3371
|
+
}
|
|
3372
|
+
)
|
|
3373
|
+
] }),
|
|
3374
|
+
/* @__PURE__ */ jsx97("div", { className: "w-px bg-gray-300 dark:bg-gray-600 mx-1" }),
|
|
3375
|
+
/* @__PURE__ */ jsxs28("div", { className: "flex gap-1", children: [
|
|
3376
|
+
/* @__PURE__ */ jsx97(
|
|
3377
|
+
"button",
|
|
3378
|
+
{
|
|
3379
|
+
type: "button",
|
|
3380
|
+
onClick: () => handleHeading("h1"),
|
|
3381
|
+
className: getButtonClass(activeFormats.has("h1")),
|
|
3382
|
+
disabled,
|
|
3383
|
+
title: "Heading 1",
|
|
3384
|
+
children: /* @__PURE__ */ jsx97("svg", { className: "w-4 h-4", fill: "currentColor", viewBox: "0 0 20 20", children: /* @__PURE__ */ jsx97("text", { x: "2", y: "16", fontSize: "14", fontWeight: "bold", children: "H1" }) })
|
|
3385
|
+
}
|
|
3386
|
+
),
|
|
3387
|
+
/* @__PURE__ */ jsx97(
|
|
3388
|
+
"button",
|
|
3389
|
+
{
|
|
3390
|
+
type: "button",
|
|
3391
|
+
onClick: () => handleHeading("h2"),
|
|
3392
|
+
className: getButtonClass(activeFormats.has("h2")),
|
|
3393
|
+
disabled,
|
|
3394
|
+
title: "Heading 2",
|
|
3395
|
+
children: /* @__PURE__ */ jsx97("svg", { className: "w-4 h-4", fill: "currentColor", viewBox: "0 0 20 20", children: /* @__PURE__ */ jsx97("text", { x: "2", y: "16", fontSize: "14", fontWeight: "bold", children: "H2" }) })
|
|
3396
|
+
}
|
|
3397
|
+
),
|
|
3398
|
+
/* @__PURE__ */ jsx97(
|
|
3399
|
+
"button",
|
|
3400
|
+
{
|
|
3401
|
+
type: "button",
|
|
3402
|
+
onClick: () => handleHeading("h3"),
|
|
3403
|
+
className: getButtonClass(activeFormats.has("h3")),
|
|
3404
|
+
disabled,
|
|
3405
|
+
title: "Heading 3",
|
|
3406
|
+
children: /* @__PURE__ */ jsx97("svg", { className: "w-4 h-4", fill: "currentColor", viewBox: "0 0 20 20", children: /* @__PURE__ */ jsx97("text", { x: "2", y: "16", fontSize: "14", fontWeight: "bold", children: "H3" }) })
|
|
3407
|
+
}
|
|
3408
|
+
)
|
|
3409
|
+
] }),
|
|
3410
|
+
/* @__PURE__ */ jsx97("div", { className: "w-px bg-gray-300 dark:bg-gray-600 mx-1" }),
|
|
3411
|
+
/* @__PURE__ */ jsxs28("div", { className: "flex gap-1", children: [
|
|
3412
|
+
/* @__PURE__ */ jsx97(
|
|
3413
|
+
"button",
|
|
3414
|
+
{
|
|
3415
|
+
type: "button",
|
|
3416
|
+
onClick: () => handleList("insertUnorderedList"),
|
|
3417
|
+
className: getButtonClass(activeFormats.has("ul")),
|
|
3418
|
+
disabled,
|
|
3419
|
+
title: "Bullet List",
|
|
3420
|
+
children: /* @__PURE__ */ jsx97("svg", { className: "w-4 h-4", fill: "currentColor", viewBox: "0 0 20 20", children: /* @__PURE__ */ jsx97("path", { d: "M4 4h2v2H4V4zm4 0h8v2H8V4zM4 8h2v2H4V8zm4 0h8v2H8V8zm-4 4h2v2H4v-2zm4 0h8v2H8v-2zm-4 4h2v2H4v-2zm4 0h8v2H8v-2z" }) })
|
|
3421
|
+
}
|
|
3422
|
+
),
|
|
3423
|
+
/* @__PURE__ */ jsx97(
|
|
3424
|
+
"button",
|
|
3425
|
+
{
|
|
3426
|
+
type: "button",
|
|
3427
|
+
onClick: () => handleList("insertOrderedList"),
|
|
3428
|
+
className: getButtonClass(activeFormats.has("ol")),
|
|
3429
|
+
disabled,
|
|
3430
|
+
title: "Numbered List",
|
|
3431
|
+
children: /* @__PURE__ */ jsx97("svg", { className: "w-4 h-4", fill: "currentColor", viewBox: "0 0 20 20", children: /* @__PURE__ */ jsx97("path", { d: "M4 4h1v3H4V4zm0 4h1v1H3V8h2v1H4zm1 2H3v1h2v1H3v1h2v-3zM8 4h8v2H8V4zm0 4h8v2H8V8zm0 4h8v2H8v-2zm0 4h8v2H8v-2z" }) })
|
|
3432
|
+
}
|
|
3433
|
+
)
|
|
3434
|
+
] }),
|
|
3435
|
+
/* @__PURE__ */ jsx97("div", { className: "w-px bg-gray-300 dark:bg-gray-600 mx-1" }),
|
|
3436
|
+
/* @__PURE__ */ jsxs28("div", { className: "flex gap-1", children: [
|
|
3437
|
+
/* @__PURE__ */ jsx97(
|
|
3438
|
+
"button",
|
|
3439
|
+
{
|
|
3440
|
+
type: "button",
|
|
3441
|
+
onClick: handleLink,
|
|
3442
|
+
className: getButtonClass(false),
|
|
3443
|
+
disabled,
|
|
3444
|
+
title: "Insert Link",
|
|
3445
|
+
children: /* @__PURE__ */ jsx97("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx97("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M13.828 10.172a4 4 0 00-5.656 0l-4 4a4 4 0 105.656 5.656l1.102-1.101m-.758-4.899a4 4 0 005.656 0l4-4a4 4 0 00-5.656-5.656l-1.1 1.1" }) })
|
|
3446
|
+
}
|
|
3447
|
+
),
|
|
3448
|
+
/* @__PURE__ */ jsx97(
|
|
3449
|
+
"button",
|
|
3450
|
+
{
|
|
3451
|
+
type: "button",
|
|
3452
|
+
onClick: handleImage,
|
|
3453
|
+
className: getButtonClass(false),
|
|
3454
|
+
disabled,
|
|
3455
|
+
title: "Insert Image/Video",
|
|
3456
|
+
children: /* @__PURE__ */ jsx97("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx97("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z" }) })
|
|
3457
|
+
}
|
|
3458
|
+
),
|
|
3459
|
+
/* @__PURE__ */ jsx97(
|
|
3460
|
+
"button",
|
|
3461
|
+
{
|
|
3462
|
+
type: "button",
|
|
3463
|
+
onClick: handleCode,
|
|
3464
|
+
className: getButtonClass(false),
|
|
3465
|
+
disabled,
|
|
3466
|
+
title: "Code",
|
|
3467
|
+
children: /* @__PURE__ */ jsx97("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx97("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M10 20l4-16m4 4l4 4-4 4M6 16l-4-4 4-4" }) })
|
|
3468
|
+
}
|
|
3469
|
+
)
|
|
3470
|
+
] })
|
|
3471
|
+
] }),
|
|
3472
|
+
/* @__PURE__ */ jsx97(
|
|
3473
|
+
"div",
|
|
3474
|
+
{
|
|
3475
|
+
ref: editorRef,
|
|
3476
|
+
contentEditable: !disabled,
|
|
3477
|
+
onInput: handleInput,
|
|
3478
|
+
onFocus: () => setIsFocused(true),
|
|
3479
|
+
onBlur: () => setIsFocused(false),
|
|
3480
|
+
onMouseUp: updateActiveFormats,
|
|
3481
|
+
onKeyUp: updateActiveFormats,
|
|
3482
|
+
dangerouslySetInnerHTML: { __html: value },
|
|
3483
|
+
className: `
|
|
3484
|
+
w-full px-4 py-3 rounded-b-lg outline-none overflow-y-auto
|
|
3485
|
+
${editorBaseClass} ${focusClass} ${errorClass}
|
|
3486
|
+
${disabled ? "opacity-50 cursor-not-allowed" : ""}
|
|
3487
|
+
prose prose-sm dark:prose-invert max-w-none
|
|
3488
|
+
`,
|
|
3489
|
+
style: {
|
|
3490
|
+
minHeight,
|
|
3491
|
+
maxHeight
|
|
3492
|
+
},
|
|
3493
|
+
"data-placeholder": placeholder,
|
|
3494
|
+
suppressContentEditableWarning: true
|
|
3495
|
+
}
|
|
3496
|
+
),
|
|
3497
|
+
error && /* @__PURE__ */ jsx97("p", { className: "mt-1 text-sm text-red-600 dark:text-red-400", children: error }),
|
|
3498
|
+
helperText && !error && /* @__PURE__ */ jsx97("p", { className: "mt-1 text-sm text-gray-500 dark:text-gray-400", children: helperText }),
|
|
3499
|
+
/* @__PURE__ */ jsx97(
|
|
3500
|
+
Modal,
|
|
3501
|
+
{
|
|
3502
|
+
isOpen: showLinkModal,
|
|
3503
|
+
onClose: () => {
|
|
3504
|
+
setShowLinkModal(false);
|
|
3505
|
+
setLinkUrl("");
|
|
3506
|
+
},
|
|
3507
|
+
title: "Insert Link",
|
|
3508
|
+
size: "sm",
|
|
3509
|
+
children: /* @__PURE__ */ jsxs28("div", { className: "space-y-4", children: [
|
|
3510
|
+
/* @__PURE__ */ jsx97(
|
|
3511
|
+
TextInput,
|
|
3512
|
+
{
|
|
3513
|
+
label: "URL",
|
|
3514
|
+
value: linkUrl,
|
|
3515
|
+
onChange: (e) => setLinkUrl(e.target.value),
|
|
3516
|
+
placeholder: "https://example.com",
|
|
3517
|
+
autoFocus: true,
|
|
3518
|
+
onKeyDown: (e) => {
|
|
3519
|
+
if (e.key === "Enter") {
|
|
3520
|
+
e.preventDefault();
|
|
3521
|
+
insertLink();
|
|
3522
|
+
}
|
|
3523
|
+
}
|
|
3524
|
+
}
|
|
3525
|
+
),
|
|
3526
|
+
/* @__PURE__ */ jsxs28("div", { className: "flex gap-2 justify-end", children: [
|
|
3527
|
+
/* @__PURE__ */ jsx97(
|
|
3528
|
+
Button,
|
|
3529
|
+
{
|
|
3530
|
+
variant: "secondary",
|
|
3531
|
+
onClick: () => {
|
|
3532
|
+
setShowLinkModal(false);
|
|
3533
|
+
setLinkUrl("");
|
|
3534
|
+
},
|
|
3535
|
+
children: "Cancel"
|
|
3536
|
+
}
|
|
3537
|
+
),
|
|
3538
|
+
/* @__PURE__ */ jsx97(
|
|
3539
|
+
Button,
|
|
3540
|
+
{
|
|
3541
|
+
variant: "primary",
|
|
3542
|
+
onClick: insertLink,
|
|
3543
|
+
disabled: !linkUrl,
|
|
3544
|
+
children: "Insert"
|
|
3545
|
+
}
|
|
3546
|
+
)
|
|
3547
|
+
] })
|
|
3548
|
+
] })
|
|
3549
|
+
}
|
|
3550
|
+
),
|
|
3551
|
+
/* @__PURE__ */ jsx97(
|
|
3552
|
+
Modal,
|
|
3553
|
+
{
|
|
3554
|
+
isOpen: showImageModal,
|
|
3555
|
+
onClose: () => {
|
|
3556
|
+
setShowImageModal(false);
|
|
3557
|
+
setImageUrl("");
|
|
3558
|
+
setImageAlt("");
|
|
3559
|
+
},
|
|
3560
|
+
title: "Insert Image",
|
|
3561
|
+
size: "sm",
|
|
3562
|
+
children: /* @__PURE__ */ jsxs28("div", { className: "space-y-4", children: [
|
|
3563
|
+
/* @__PURE__ */ jsx97(
|
|
3564
|
+
TextInput,
|
|
3565
|
+
{
|
|
3566
|
+
label: "Image URL",
|
|
3567
|
+
value: imageUrl,
|
|
3568
|
+
onChange: (e) => setImageUrl(e.target.value),
|
|
3569
|
+
placeholder: "https://example.com/image.jpg",
|
|
3570
|
+
autoFocus: true,
|
|
3571
|
+
onKeyDown: (e) => {
|
|
3572
|
+
if (e.key === "Enter") {
|
|
3573
|
+
e.preventDefault();
|
|
3574
|
+
insertImage();
|
|
3575
|
+
}
|
|
3576
|
+
}
|
|
3577
|
+
}
|
|
3578
|
+
),
|
|
3579
|
+
/* @__PURE__ */ jsx97(
|
|
3580
|
+
TextInput,
|
|
3581
|
+
{
|
|
3582
|
+
label: "Alt Text (optional)",
|
|
3583
|
+
value: imageAlt,
|
|
3584
|
+
onChange: (e) => setImageAlt(e.target.value),
|
|
3585
|
+
placeholder: "Describe the image"
|
|
3586
|
+
}
|
|
3587
|
+
),
|
|
3588
|
+
/* @__PURE__ */ jsxs28("div", { className: "flex gap-2 justify-end", children: [
|
|
3589
|
+
/* @__PURE__ */ jsx97(
|
|
3590
|
+
Button,
|
|
3591
|
+
{
|
|
3592
|
+
variant: "secondary",
|
|
3593
|
+
onClick: () => {
|
|
3594
|
+
setShowImageModal(false);
|
|
3595
|
+
setImageUrl("");
|
|
3596
|
+
setImageAlt("");
|
|
3597
|
+
},
|
|
3598
|
+
children: "Cancel"
|
|
3599
|
+
}
|
|
3600
|
+
),
|
|
3601
|
+
/* @__PURE__ */ jsx97(
|
|
3602
|
+
Button,
|
|
3603
|
+
{
|
|
3604
|
+
variant: "primary",
|
|
3605
|
+
onClick: insertImage,
|
|
3606
|
+
disabled: !imageUrl,
|
|
3607
|
+
children: "Insert"
|
|
3608
|
+
}
|
|
3609
|
+
)
|
|
3610
|
+
] })
|
|
3611
|
+
] })
|
|
3612
|
+
}
|
|
3613
|
+
)
|
|
3614
|
+
] });
|
|
3615
|
+
};
|
|
3616
|
+
|
|
3617
|
+
// src/components/Toast.tsx
|
|
3618
|
+
import { createContext as createContext3, useContext as useContext3, useState as useState13, useCallback as useCallback2 } from "react";
|
|
3619
|
+
import { jsx as jsx98, jsxs as jsxs29 } from "react/jsx-runtime";
|
|
3620
|
+
var ToastContext = createContext3(void 0);
|
|
3621
|
+
var useToast = () => {
|
|
3622
|
+
const context = useContext3(ToastContext);
|
|
3623
|
+
if (!context) {
|
|
3624
|
+
throw new Error("useToast must be used within a ToastProvider");
|
|
3625
|
+
}
|
|
3626
|
+
return context;
|
|
3627
|
+
};
|
|
3628
|
+
var ToastProvider = ({ children, position = "top-right" }) => {
|
|
3629
|
+
const [toasts, setToasts] = useState13([]);
|
|
3630
|
+
const addToast = useCallback2((toast2) => {
|
|
3631
|
+
const id = Math.random().toString(36).substring(7);
|
|
3632
|
+
const newToast = { ...toast2, id };
|
|
3633
|
+
setToasts((prev) => [...prev, newToast]);
|
|
3634
|
+
const duration = toast2.duration || 5e3;
|
|
3635
|
+
setTimeout(() => {
|
|
3636
|
+
removeToast(id);
|
|
3637
|
+
}, duration);
|
|
3638
|
+
}, []);
|
|
3639
|
+
const removeToast = useCallback2((id) => {
|
|
3640
|
+
setToasts((prev) => prev.filter((toast2) => toast2.id !== id));
|
|
3641
|
+
}, []);
|
|
3642
|
+
const positionClasses2 = {
|
|
3643
|
+
"top-right": "top-4 right-4",
|
|
3644
|
+
"top-left": "top-4 left-4",
|
|
3645
|
+
"bottom-right": "bottom-4 right-4",
|
|
3646
|
+
"bottom-left": "bottom-4 left-4",
|
|
3647
|
+
"top-center": "top-4 left-1/2 -translate-x-1/2",
|
|
3648
|
+
"bottom-center": "bottom-4 left-1/2 -translate-x-1/2"
|
|
3649
|
+
};
|
|
3650
|
+
return /* @__PURE__ */ jsxs29(ToastContext.Provider, { value: { toasts, addToast, removeToast }, children: [
|
|
3651
|
+
children,
|
|
3652
|
+
/* @__PURE__ */ jsx98("div", { className: `fixed ${positionClasses2[position]} z-50 flex flex-col gap-2 max-w-md`, children: toasts.map((toast2) => /* @__PURE__ */ jsx98(ToastItem, { toast: toast2, onClose: () => removeToast(toast2.id) }, toast2.id)) })
|
|
3653
|
+
] });
|
|
3654
|
+
};
|
|
3655
|
+
var ToastItem = ({ toast: toast2, onClose }) => {
|
|
3656
|
+
const typeStyles = {
|
|
3657
|
+
success: "bg-green-50 dark:bg-green-900/30 border-green-500 text-green-800 dark:text-green-200",
|
|
3658
|
+
error: "bg-red-50 dark:bg-red-900/30 border-red-500 text-red-800 dark:text-red-200",
|
|
3659
|
+
warning: "bg-yellow-50 dark:bg-yellow-900/30 border-yellow-500 text-yellow-800 dark:text-yellow-200",
|
|
3660
|
+
info: "bg-blue-50 dark:bg-blue-900/30 border-blue-500 text-blue-800 dark:text-blue-200"
|
|
3661
|
+
};
|
|
3662
|
+
const typeIcons = {
|
|
3663
|
+
success: /* @__PURE__ */ jsx98(CheckIcon, { size: "sm", className: "text-green-600 dark:text-green-400" }),
|
|
3664
|
+
error: /* @__PURE__ */ jsx98(CloseIcon, { size: "sm", className: "text-red-600 dark:text-red-400" }),
|
|
3665
|
+
warning: /* @__PURE__ */ jsx98("svg", { className: "w-4 h-4 text-yellow-600 dark:text-yellow-400", fill: "currentColor", viewBox: "0 0 20 20", children: /* @__PURE__ */ jsx98("path", { fillRule: "evenodd", d: "M8.257 3.099c.765-1.36 2.722-1.36 3.486 0l5.58 9.92c.75 1.334-.213 2.98-1.742 2.98H4.42c-1.53 0-2.493-1.646-1.743-2.98l5.58-9.92zM11 13a1 1 0 11-2 0 1 1 0 012 0zm-1-8a1 1 0 00-1 1v3a1 1 0 002 0V6a1 1 0 00-1-1z", clipRule: "evenodd" }) }),
|
|
3666
|
+
info: /* @__PURE__ */ jsx98("svg", { className: "w-4 h-4 text-blue-600 dark:text-blue-400", fill: "currentColor", viewBox: "0 0 20 20", children: /* @__PURE__ */ jsx98("path", { fillRule: "evenodd", d: "M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a1 1 0 000 2v3a1 1 0 001 1h1a1 1 0 100-2v-3a1 1 0 00-1-1H9z", clipRule: "evenodd" }) })
|
|
3667
|
+
};
|
|
3668
|
+
const type = toast2.type || "info";
|
|
3669
|
+
return /* @__PURE__ */ jsxs29(
|
|
3670
|
+
"div",
|
|
3671
|
+
{
|
|
3672
|
+
className: `flex items-start gap-3 p-4 rounded-lg border-l-4 shadow-lg backdrop-blur-sm ${typeStyles[type]} animate-slide-in`,
|
|
3673
|
+
role: "alert",
|
|
3674
|
+
children: [
|
|
3675
|
+
/* @__PURE__ */ jsx98("div", { className: "flex-shrink-0 mt-0.5", children: typeIcons[type] }),
|
|
3676
|
+
/* @__PURE__ */ jsx98("p", { className: "flex-1 text-sm font-medium", children: toast2.message }),
|
|
3677
|
+
/* @__PURE__ */ jsx98(
|
|
3678
|
+
"button",
|
|
3679
|
+
{
|
|
3680
|
+
onClick: onClose,
|
|
3681
|
+
className: "flex-shrink-0 text-gray-400 hover:text-gray-600 dark:hover:text-gray-200 transition-colors",
|
|
3682
|
+
"aria-label": "Close",
|
|
3683
|
+
children: /* @__PURE__ */ jsx98(CloseIcon, { size: "sm" })
|
|
3684
|
+
}
|
|
3685
|
+
)
|
|
3686
|
+
]
|
|
3687
|
+
}
|
|
3688
|
+
);
|
|
3689
|
+
};
|
|
3690
|
+
var toast = {
|
|
3691
|
+
success: (message, duration) => ({
|
|
3692
|
+
message,
|
|
3693
|
+
type: "success",
|
|
3694
|
+
duration
|
|
3695
|
+
}),
|
|
3696
|
+
error: (message, duration) => ({
|
|
3697
|
+
message,
|
|
3698
|
+
type: "error",
|
|
3699
|
+
duration
|
|
3700
|
+
}),
|
|
3701
|
+
warning: (message, duration) => ({
|
|
3702
|
+
message,
|
|
3703
|
+
type: "warning",
|
|
3704
|
+
duration
|
|
3705
|
+
}),
|
|
3706
|
+
info: (message, duration) => ({
|
|
3707
|
+
message,
|
|
3708
|
+
type: "info",
|
|
3709
|
+
duration
|
|
3710
|
+
})
|
|
3711
|
+
};
|
|
3712
|
+
|
|
3713
|
+
// src/components/Stepper.tsx
|
|
3714
|
+
import React22 from "react";
|
|
3715
|
+
import { jsx as jsx99, jsxs as jsxs30 } from "react/jsx-runtime";
|
|
3716
|
+
var Stepper = ({
|
|
3717
|
+
steps,
|
|
3718
|
+
currentStep,
|
|
3719
|
+
orientation = "horizontal",
|
|
3720
|
+
className = ""
|
|
3721
|
+
}) => {
|
|
3722
|
+
const isHorizontal = orientation === "horizontal";
|
|
3723
|
+
return /* @__PURE__ */ jsx99("div", { className: `${isHorizontal ? "flex items-center" : "flex flex-col"} ${className}`, children: steps.map((step, index) => {
|
|
3724
|
+
const stepNumber = index + 1;
|
|
3725
|
+
const isActive = stepNumber === currentStep;
|
|
3726
|
+
const isCompleted = stepNumber < currentStep;
|
|
3727
|
+
const isLast = index === steps.length - 1;
|
|
3728
|
+
return /* @__PURE__ */ jsxs30(React22.Fragment, { children: [
|
|
3729
|
+
/* @__PURE__ */ jsxs30("div", { className: `flex ${isHorizontal ? "flex-col items-center" : "flex-row items-start"} ${isHorizontal ? "" : "flex-1"}`, children: [
|
|
3730
|
+
/* @__PURE__ */ jsx99("div", { className: "flex items-center", children: /* @__PURE__ */ jsx99(
|
|
3731
|
+
"div",
|
|
3732
|
+
{
|
|
3733
|
+
className: `flex items-center justify-center w-10 h-10 rounded-full border-2 transition-all ${isCompleted ? "bg-blue-600 border-blue-600 dark:bg-blue-500 dark:border-blue-500" : isActive ? "border-blue-600 bg-white dark:border-blue-500 dark:bg-gray-800" : "border-gray-300 bg-white dark:border-gray-600 dark:bg-gray-800"}`,
|
|
3734
|
+
children: isCompleted ? /* @__PURE__ */ jsx99(CheckIcon, { size: "sm", className: "text-white" }) : /* @__PURE__ */ jsx99(
|
|
3735
|
+
"span",
|
|
3736
|
+
{
|
|
3737
|
+
className: `text-sm font-semibold ${isActive ? "text-blue-600 dark:text-blue-400" : "text-gray-500 dark:text-gray-400"}`,
|
|
3738
|
+
children: stepNumber
|
|
3739
|
+
}
|
|
3740
|
+
)
|
|
3741
|
+
}
|
|
3742
|
+
) }),
|
|
3743
|
+
/* @__PURE__ */ jsxs30("div", { className: `${isHorizontal ? "mt-2 text-center" : "ml-4 pb-8"} ${isLast && !isHorizontal ? "pb-0" : ""}`, children: [
|
|
3744
|
+
/* @__PURE__ */ jsx99(
|
|
3745
|
+
"p",
|
|
3746
|
+
{
|
|
3747
|
+
className: `text-sm font-medium ${isActive || isCompleted ? "text-gray-900 dark:text-gray-100" : "text-gray-500 dark:text-gray-400"}`,
|
|
3748
|
+
children: step.label
|
|
3749
|
+
}
|
|
3750
|
+
),
|
|
3751
|
+
step.description && /* @__PURE__ */ jsx99("p", { className: "text-xs text-gray-500 dark:text-gray-400 mt-1", children: step.description })
|
|
3752
|
+
] })
|
|
3753
|
+
] }),
|
|
3754
|
+
!isLast && /* @__PURE__ */ jsx99(
|
|
3755
|
+
"div",
|
|
3756
|
+
{
|
|
3757
|
+
className: `${isHorizontal ? "flex-1 h-0.5 mx-4" : "w-0.5 h-full ml-5 -mt-8"} ${isCompleted || isActive && stepNumber < currentStep ? "bg-blue-600 dark:bg-blue-500" : "bg-gray-300 dark:bg-gray-600"}`
|
|
3758
|
+
}
|
|
3759
|
+
)
|
|
3760
|
+
] }, index);
|
|
3761
|
+
}) });
|
|
3762
|
+
};
|
|
3763
|
+
|
|
3764
|
+
// src/components/Divider.tsx
|
|
3765
|
+
import { jsx as jsx100, jsxs as jsxs31 } from "react/jsx-runtime";
|
|
3766
|
+
var Divider = ({
|
|
3767
|
+
orientation = "horizontal",
|
|
3768
|
+
variant = "solid",
|
|
3769
|
+
className = "",
|
|
3770
|
+
label,
|
|
3771
|
+
labelPosition = "center"
|
|
3772
|
+
}) => {
|
|
3773
|
+
const variantClasses = {
|
|
3774
|
+
solid: "border-solid",
|
|
3775
|
+
dashed: "border-dashed",
|
|
3776
|
+
dotted: "border-dotted"
|
|
3777
|
+
};
|
|
3778
|
+
if (label && orientation === "horizontal") {
|
|
3779
|
+
const alignmentClasses = {
|
|
3780
|
+
left: "justify-start",
|
|
3781
|
+
center: "justify-center",
|
|
3782
|
+
right: "justify-end"
|
|
3783
|
+
};
|
|
3784
|
+
return /* @__PURE__ */ jsxs31("div", { className: `flex items-center ${alignmentClasses[labelPosition]} ${className}`, role: "separator", children: [
|
|
3785
|
+
labelPosition !== "left" && /* @__PURE__ */ jsx100("div", { className: `flex-1 border-t ${variantClasses[variant]} border-gray-300 dark:border-gray-600` }),
|
|
3786
|
+
/* @__PURE__ */ jsx100("span", { className: "px-4 text-sm text-gray-500 dark:text-gray-400", children: label }),
|
|
3787
|
+
labelPosition !== "right" && /* @__PURE__ */ jsx100("div", { className: `flex-1 border-t ${variantClasses[variant]} border-gray-300 dark:border-gray-600` })
|
|
3788
|
+
] });
|
|
3789
|
+
}
|
|
3790
|
+
if (orientation === "vertical") {
|
|
3791
|
+
return /* @__PURE__ */ jsx100(
|
|
3792
|
+
"div",
|
|
3793
|
+
{
|
|
3794
|
+
className: `inline-block h-full border-l ${variantClasses[variant]} border-gray-300 dark:border-gray-600 ${className}`,
|
|
3795
|
+
role: "separator",
|
|
3796
|
+
"aria-orientation": "vertical"
|
|
3797
|
+
}
|
|
3798
|
+
);
|
|
3799
|
+
}
|
|
3800
|
+
return /* @__PURE__ */ jsx100(
|
|
3801
|
+
"hr",
|
|
3802
|
+
{
|
|
3803
|
+
className: `border-t ${variantClasses[variant]} border-gray-300 dark:border-gray-600 ${className}`,
|
|
3804
|
+
role: "separator"
|
|
3805
|
+
}
|
|
3806
|
+
);
|
|
3807
|
+
};
|
|
3808
|
+
|
|
3809
|
+
// src/components/FileUpload.tsx
|
|
3810
|
+
import { useRef as useRef8, useState as useState14 } from "react";
|
|
3811
|
+
import { jsx as jsx101, jsxs as jsxs32 } from "react/jsx-runtime";
|
|
3812
|
+
var FileUpload = ({
|
|
3813
|
+
accept,
|
|
3814
|
+
multiple = false,
|
|
3815
|
+
maxSize,
|
|
3816
|
+
maxFiles = 10,
|
|
3817
|
+
disabled = false,
|
|
3818
|
+
onChange,
|
|
3819
|
+
onError,
|
|
3820
|
+
className = "",
|
|
3821
|
+
label,
|
|
3822
|
+
helperText
|
|
3823
|
+
}) => {
|
|
3824
|
+
const [files, setFiles] = useState14([]);
|
|
3825
|
+
const [isDragging, setIsDragging] = useState14(false);
|
|
3826
|
+
const fileInputRef = useRef8(null);
|
|
3827
|
+
const formatFileSize = (bytes) => {
|
|
3828
|
+
if (bytes === 0) return "0 Bytes";
|
|
3829
|
+
const k = 1024;
|
|
3830
|
+
const sizes = ["Bytes", "KB", "MB", "GB"];
|
|
3831
|
+
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
3832
|
+
return Math.round(bytes / Math.pow(k, i) * 100) / 100 + " " + sizes[i];
|
|
3833
|
+
};
|
|
3834
|
+
const validateFiles = (fileList) => {
|
|
3835
|
+
const validFiles = [];
|
|
3836
|
+
const filesArray = Array.from(fileList);
|
|
3837
|
+
if (filesArray.length + files.length > maxFiles) {
|
|
3838
|
+
onError?.(`Maximum ${maxFiles} files allowed`);
|
|
3839
|
+
return validFiles;
|
|
3840
|
+
}
|
|
3841
|
+
for (const file of filesArray) {
|
|
3842
|
+
if (maxSize && file.size > maxSize) {
|
|
3843
|
+
onError?.(`File ${file.name} exceeds maximum size of ${formatFileSize(maxSize)}`);
|
|
3844
|
+
continue;
|
|
3845
|
+
}
|
|
3846
|
+
validFiles.push(file);
|
|
3847
|
+
}
|
|
3848
|
+
return validFiles;
|
|
3849
|
+
};
|
|
3850
|
+
const handleFiles = (fileList) => {
|
|
3851
|
+
if (!fileList || disabled) return;
|
|
3852
|
+
const validFiles = validateFiles(fileList);
|
|
3853
|
+
if (validFiles.length > 0) {
|
|
3854
|
+
const newFiles = multiple ? [...files, ...validFiles] : validFiles;
|
|
3855
|
+
setFiles(newFiles);
|
|
3856
|
+
onChange?.(newFiles);
|
|
3857
|
+
}
|
|
3858
|
+
};
|
|
3859
|
+
const handleDrop = (e) => {
|
|
3860
|
+
e.preventDefault();
|
|
3861
|
+
setIsDragging(false);
|
|
3862
|
+
handleFiles(e.dataTransfer.files);
|
|
3863
|
+
};
|
|
3864
|
+
const handleDragOver = (e) => {
|
|
3865
|
+
e.preventDefault();
|
|
3866
|
+
if (!disabled) {
|
|
3867
|
+
setIsDragging(true);
|
|
3868
|
+
}
|
|
3869
|
+
};
|
|
3870
|
+
const handleDragLeave = (e) => {
|
|
3871
|
+
e.preventDefault();
|
|
3872
|
+
setIsDragging(false);
|
|
3873
|
+
};
|
|
3874
|
+
const handleClick = () => {
|
|
3875
|
+
if (!disabled) {
|
|
3876
|
+
fileInputRef.current?.click();
|
|
3877
|
+
}
|
|
3878
|
+
};
|
|
3879
|
+
const handleRemoveFile = (index) => {
|
|
3880
|
+
const newFiles = files.filter((_, i) => i !== index);
|
|
3881
|
+
setFiles(newFiles);
|
|
3882
|
+
onChange?.(newFiles);
|
|
3883
|
+
};
|
|
3884
|
+
return /* @__PURE__ */ jsxs32("div", { className: `w-full ${className}`, children: [
|
|
3885
|
+
label && /* @__PURE__ */ jsx101("label", { className: "block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2", children: label }),
|
|
3886
|
+
/* @__PURE__ */ jsxs32(
|
|
3887
|
+
"div",
|
|
3888
|
+
{
|
|
3889
|
+
onDrop: handleDrop,
|
|
3890
|
+
onDragOver: handleDragOver,
|
|
3891
|
+
onDragLeave: handleDragLeave,
|
|
3892
|
+
onClick: handleClick,
|
|
3893
|
+
className: `relative border-2 border-dashed rounded-lg p-8 text-center cursor-pointer transition-all ${isDragging ? "border-blue-500 bg-blue-50 dark:bg-blue-900/20" : "border-gray-300 dark:border-gray-600 hover:border-gray-400 dark:hover:border-gray-500"} ${disabled ? "opacity-50 cursor-not-allowed" : ""}`,
|
|
3894
|
+
children: [
|
|
3895
|
+
/* @__PURE__ */ jsx101(
|
|
3896
|
+
"input",
|
|
3897
|
+
{
|
|
3898
|
+
ref: fileInputRef,
|
|
3899
|
+
type: "file",
|
|
3900
|
+
accept,
|
|
3901
|
+
multiple,
|
|
3902
|
+
onChange: (e) => handleFiles(e.target.files),
|
|
3903
|
+
disabled,
|
|
3904
|
+
className: "hidden"
|
|
3905
|
+
}
|
|
3906
|
+
),
|
|
3907
|
+
/* @__PURE__ */ jsxs32("div", { className: "flex flex-col items-center gap-2", children: [
|
|
3908
|
+
/* @__PURE__ */ jsx101("div", { className: "w-12 h-12 rounded-full bg-gray-100 dark:bg-gray-800 flex items-center justify-center", children: /* @__PURE__ */ jsx101(UploadIcon, { size: "lg", className: "text-gray-400 dark:text-gray-500" }) }),
|
|
3909
|
+
/* @__PURE__ */ jsxs32("div", { children: [
|
|
3910
|
+
/* @__PURE__ */ jsxs32("p", { className: "text-sm font-medium text-gray-700 dark:text-gray-300", children: [
|
|
3911
|
+
/* @__PURE__ */ jsx101("span", { className: "text-blue-600 dark:text-blue-400", children: "Click to upload" }),
|
|
3912
|
+
" or drag and drop"
|
|
3913
|
+
] }),
|
|
3914
|
+
/* @__PURE__ */ jsxs32("p", { className: "text-xs text-gray-500 dark:text-gray-400 mt-1", children: [
|
|
3915
|
+
accept ? `Accepted: ${accept}` : "Any file type",
|
|
3916
|
+
maxSize && ` \u2022 Max size: ${formatFileSize(maxSize)}`
|
|
3917
|
+
] })
|
|
3918
|
+
] })
|
|
3919
|
+
] })
|
|
3920
|
+
]
|
|
3921
|
+
}
|
|
3922
|
+
),
|
|
3923
|
+
helperText && /* @__PURE__ */ jsx101("p", { className: "mt-2 text-sm text-gray-500 dark:text-gray-400", children: helperText }),
|
|
3924
|
+
files.length > 0 && /* @__PURE__ */ jsx101("div", { className: "mt-4 space-y-2", children: files.map((file, index) => /* @__PURE__ */ jsxs32(
|
|
3925
|
+
"div",
|
|
3926
|
+
{
|
|
3927
|
+
className: "flex items-center justify-between p-3 bg-gray-50 dark:bg-gray-800 rounded-lg border border-gray-200 dark:border-gray-700",
|
|
3928
|
+
children: [
|
|
3929
|
+
/* @__PURE__ */ jsxs32("div", { className: "flex-1 min-w-0", children: [
|
|
3930
|
+
/* @__PURE__ */ jsx101("p", { className: "text-sm font-medium text-gray-900 dark:text-gray-100 truncate", children: file.name }),
|
|
3931
|
+
/* @__PURE__ */ jsx101("p", { className: "text-xs text-gray-500 dark:text-gray-400", children: formatFileSize(file.size) })
|
|
3932
|
+
] }),
|
|
3933
|
+
/* @__PURE__ */ jsx101(
|
|
3934
|
+
"button",
|
|
3935
|
+
{
|
|
3936
|
+
onClick: (e) => {
|
|
3937
|
+
e.stopPropagation();
|
|
3938
|
+
handleRemoveFile(index);
|
|
3939
|
+
},
|
|
3940
|
+
className: "ml-4 text-gray-400 hover:text-red-600 dark:hover:text-red-400 transition-colors",
|
|
3941
|
+
"aria-label": "Remove file",
|
|
3942
|
+
children: /* @__PURE__ */ jsx101(CloseIcon, { size: "sm" })
|
|
3943
|
+
}
|
|
3944
|
+
)
|
|
3945
|
+
]
|
|
3946
|
+
},
|
|
3947
|
+
index
|
|
3948
|
+
)) })
|
|
3949
|
+
] });
|
|
3950
|
+
};
|
|
3951
|
+
|
|
3952
|
+
// src/components/AudioPlayer.tsx
|
|
3953
|
+
import { useRef as useRef9, useState as useState15, useEffect as useEffect9 } from "react";
|
|
3954
|
+
import { jsx as jsx102, jsxs as jsxs33 } from "react/jsx-runtime";
|
|
3955
|
+
var AudioPlayer = ({
|
|
3956
|
+
src,
|
|
3957
|
+
title,
|
|
3958
|
+
artist,
|
|
3959
|
+
album,
|
|
3960
|
+
coverArt,
|
|
3961
|
+
variant = "default",
|
|
3962
|
+
autoPlay = false,
|
|
3963
|
+
loop = false,
|
|
3964
|
+
preload = "metadata",
|
|
3965
|
+
onPlay,
|
|
3966
|
+
onPause,
|
|
3967
|
+
onEnded,
|
|
3968
|
+
onTimeUpdate,
|
|
3969
|
+
className = "",
|
|
3970
|
+
showSkipButtons = false,
|
|
3971
|
+
onSkipBack,
|
|
3972
|
+
onSkipForward
|
|
3973
|
+
}) => {
|
|
3974
|
+
const audioRef = useRef9(null);
|
|
3975
|
+
const [isPlaying, setIsPlaying] = useState15(false);
|
|
3976
|
+
const [currentTime, setCurrentTime] = useState15(0);
|
|
3977
|
+
const [duration, setDuration] = useState15(0);
|
|
3978
|
+
const [volume, setVolume] = useState15(1);
|
|
3979
|
+
const [isMuted, setIsMuted] = useState15(false);
|
|
3980
|
+
const [isLoading, setIsLoading] = useState15(true);
|
|
3981
|
+
useEffect9(() => {
|
|
3982
|
+
const audio = audioRef.current;
|
|
3983
|
+
if (!audio) return;
|
|
3984
|
+
const handleLoadedMetadata = () => {
|
|
3985
|
+
setDuration(audio.duration);
|
|
3986
|
+
setIsLoading(false);
|
|
3987
|
+
};
|
|
3988
|
+
const handleCanPlay = () => {
|
|
3989
|
+
setIsLoading(false);
|
|
3990
|
+
};
|
|
3991
|
+
const handleTimeUpdate = () => {
|
|
3992
|
+
setCurrentTime(audio.currentTime);
|
|
3993
|
+
onTimeUpdate?.(audio.currentTime);
|
|
3994
|
+
};
|
|
3995
|
+
const handleEnded = () => {
|
|
3996
|
+
setIsPlaying(false);
|
|
3997
|
+
onEnded?.();
|
|
3998
|
+
};
|
|
3999
|
+
const handlePlay = () => {
|
|
4000
|
+
setIsPlaying(true);
|
|
4001
|
+
onPlay?.();
|
|
4002
|
+
};
|
|
4003
|
+
const handlePause = () => {
|
|
4004
|
+
setIsPlaying(false);
|
|
4005
|
+
onPause?.();
|
|
4006
|
+
};
|
|
4007
|
+
const handleError = (e) => {
|
|
4008
|
+
console.error("Audio error:", e);
|
|
4009
|
+
setIsPlaying(false);
|
|
4010
|
+
setIsLoading(false);
|
|
4011
|
+
};
|
|
4012
|
+
const handleLoadStart = () => {
|
|
4013
|
+
setIsLoading(true);
|
|
4014
|
+
};
|
|
4015
|
+
audio.addEventListener("loadstart", handleLoadStart);
|
|
4016
|
+
audio.addEventListener("loadedmetadata", handleLoadedMetadata);
|
|
4017
|
+
audio.addEventListener("canplay", handleCanPlay);
|
|
4018
|
+
audio.addEventListener("timeupdate", handleTimeUpdate);
|
|
4019
|
+
audio.addEventListener("ended", handleEnded);
|
|
4020
|
+
audio.addEventListener("play", handlePlay);
|
|
4021
|
+
audio.addEventListener("pause", handlePause);
|
|
4022
|
+
audio.addEventListener("error", handleError);
|
|
4023
|
+
if (audio.readyState >= 2) {
|
|
4024
|
+
setIsLoading(false);
|
|
4025
|
+
setDuration(audio.duration);
|
|
4026
|
+
}
|
|
4027
|
+
return () => {
|
|
4028
|
+
audio.removeEventListener("loadstart", handleLoadStart);
|
|
4029
|
+
audio.removeEventListener("loadedmetadata", handleLoadedMetadata);
|
|
4030
|
+
audio.removeEventListener("canplay", handleCanPlay);
|
|
4031
|
+
audio.removeEventListener("timeupdate", handleTimeUpdate);
|
|
4032
|
+
audio.removeEventListener("ended", handleEnded);
|
|
4033
|
+
audio.removeEventListener("play", handlePlay);
|
|
4034
|
+
audio.removeEventListener("pause", handlePause);
|
|
4035
|
+
audio.removeEventListener("error", handleError);
|
|
4036
|
+
};
|
|
4037
|
+
}, [onPlay, onPause, onEnded, onTimeUpdate]);
|
|
4038
|
+
useEffect9(() => {
|
|
4039
|
+
const audio = audioRef.current;
|
|
4040
|
+
if (!audio) return;
|
|
4041
|
+
audio.load();
|
|
4042
|
+
}, [src]);
|
|
4043
|
+
const togglePlayPause = async () => {
|
|
4044
|
+
const audio = audioRef.current;
|
|
4045
|
+
if (!audio) return;
|
|
4046
|
+
try {
|
|
4047
|
+
if (isPlaying) {
|
|
4048
|
+
audio.pause();
|
|
4049
|
+
} else {
|
|
4050
|
+
await audio.play();
|
|
4051
|
+
}
|
|
4052
|
+
} catch (error) {
|
|
4053
|
+
console.error("Playback error:", error);
|
|
4054
|
+
setIsPlaying(false);
|
|
4055
|
+
}
|
|
4056
|
+
};
|
|
4057
|
+
const handleSeek = (e) => {
|
|
4058
|
+
const audio = audioRef.current;
|
|
4059
|
+
if (!audio) return;
|
|
4060
|
+
const time = parseFloat(e.target.value);
|
|
4061
|
+
audio.currentTime = time;
|
|
4062
|
+
setCurrentTime(time);
|
|
4063
|
+
};
|
|
4064
|
+
const handleVolumeChange = (e) => {
|
|
4065
|
+
const audio = audioRef.current;
|
|
4066
|
+
if (!audio) return;
|
|
4067
|
+
const vol = parseFloat(e.target.value);
|
|
4068
|
+
audio.volume = vol;
|
|
4069
|
+
setVolume(vol);
|
|
4070
|
+
setIsMuted(vol === 0);
|
|
4071
|
+
};
|
|
4072
|
+
const toggleMute = () => {
|
|
4073
|
+
const audio = audioRef.current;
|
|
4074
|
+
if (!audio) return;
|
|
4075
|
+
if (isMuted) {
|
|
4076
|
+
audio.volume = volume || 0.5;
|
|
4077
|
+
setIsMuted(false);
|
|
4078
|
+
} else {
|
|
4079
|
+
audio.volume = 0;
|
|
4080
|
+
setIsMuted(true);
|
|
4081
|
+
}
|
|
4082
|
+
};
|
|
4083
|
+
const formatTime = (time) => {
|
|
4084
|
+
if (!isFinite(time)) return "0:00";
|
|
4085
|
+
const minutes = Math.floor(time / 60);
|
|
4086
|
+
const seconds = Math.floor(time % 60);
|
|
4087
|
+
return `${minutes}:${seconds.toString().padStart(2, "0")}`;
|
|
4088
|
+
};
|
|
4089
|
+
const handleSkipBack = () => {
|
|
4090
|
+
const audio = audioRef.current;
|
|
4091
|
+
if (!audio) return;
|
|
4092
|
+
if (onSkipBack) {
|
|
4093
|
+
onSkipBack();
|
|
4094
|
+
} else {
|
|
4095
|
+
audio.currentTime = Math.max(0, audio.currentTime - 10);
|
|
4096
|
+
}
|
|
4097
|
+
};
|
|
4098
|
+
const handleSkipForward = () => {
|
|
4099
|
+
const audio = audioRef.current;
|
|
4100
|
+
if (!audio) return;
|
|
4101
|
+
if (onSkipForward) {
|
|
4102
|
+
onSkipForward();
|
|
4103
|
+
} else {
|
|
4104
|
+
audio.currentTime = Math.min(duration, audio.currentTime + 10);
|
|
4105
|
+
}
|
|
4106
|
+
};
|
|
4107
|
+
const progress = duration > 0 ? currentTime / duration * 100 : 0;
|
|
4108
|
+
if (variant === "mini") {
|
|
4109
|
+
return /* @__PURE__ */ jsxs33("div", { className: `flex items-center gap-2 p-2 bg-white dark:bg-gray-800 rounded-lg border border-gray-200 dark:border-gray-700 ${className}`, children: [
|
|
4110
|
+
/* @__PURE__ */ jsx102("audio", { ref: audioRef, src, preload, loop, autoPlay }),
|
|
4111
|
+
/* @__PURE__ */ jsx102(
|
|
4112
|
+
Button,
|
|
4113
|
+
{
|
|
4114
|
+
iconOnly: true,
|
|
4115
|
+
size: "sm",
|
|
4116
|
+
variant: "primary",
|
|
4117
|
+
onClick: togglePlayPause,
|
|
4118
|
+
disabled: isLoading,
|
|
4119
|
+
"aria-label": isPlaying ? "Pause" : "Play",
|
|
4120
|
+
children: isPlaying ? /* @__PURE__ */ jsx102(PauseIcon, { size: "sm" }) : /* @__PURE__ */ jsx102(PlayIcon, { size: "sm" })
|
|
4121
|
+
}
|
|
4122
|
+
),
|
|
4123
|
+
title && /* @__PURE__ */ jsx102("span", { className: "text-sm font-medium text-gray-700 dark:text-gray-300 truncate", children: title })
|
|
4124
|
+
] });
|
|
4125
|
+
}
|
|
4126
|
+
if (variant === "compact") {
|
|
4127
|
+
return /* @__PURE__ */ jsxs33("div", { className: `flex items-center gap-3 p-3 bg-white dark:bg-gray-800 rounded-lg border border-gray-200 dark:border-gray-700 shadow-sm ${className}`, children: [
|
|
4128
|
+
/* @__PURE__ */ jsx102("audio", { ref: audioRef, src, preload, loop, autoPlay }),
|
|
4129
|
+
/* @__PURE__ */ jsx102(
|
|
4130
|
+
Button,
|
|
4131
|
+
{
|
|
4132
|
+
iconOnly: true,
|
|
4133
|
+
size: "md",
|
|
4134
|
+
variant: "primary",
|
|
4135
|
+
onClick: togglePlayPause,
|
|
4136
|
+
disabled: isLoading,
|
|
4137
|
+
"aria-label": isPlaying ? "Pause" : "Play",
|
|
4138
|
+
children: isPlaying ? /* @__PURE__ */ jsx102(PauseIcon, { size: "md" }) : /* @__PURE__ */ jsx102(PlayIcon, { size: "md" })
|
|
4139
|
+
}
|
|
4140
|
+
),
|
|
4141
|
+
/* @__PURE__ */ jsxs33("div", { className: "flex-1 min-w-0", children: [
|
|
4142
|
+
title && /* @__PURE__ */ jsx102("div", { className: "text-sm font-medium text-gray-900 dark:text-gray-100 truncate", children: title }),
|
|
4143
|
+
artist && /* @__PURE__ */ jsx102("div", { className: "text-xs text-gray-500 dark:text-gray-400 truncate", children: artist })
|
|
4144
|
+
] }),
|
|
4145
|
+
/* @__PURE__ */ jsxs33("div", { className: "flex items-center gap-2 flex-1", children: [
|
|
4146
|
+
/* @__PURE__ */ jsx102("span", { className: "text-xs text-gray-500 dark:text-gray-400 tabular-nums", children: formatTime(currentTime) }),
|
|
4147
|
+
/* @__PURE__ */ jsxs33("div", { className: "relative flex-1 h-1.5 bg-gray-200 dark:bg-gray-700 rounded-full overflow-hidden", children: [
|
|
4148
|
+
/* @__PURE__ */ jsx102(
|
|
4149
|
+
"div",
|
|
4150
|
+
{
|
|
4151
|
+
className: "absolute h-full bg-blue-600 dark:bg-blue-500 rounded-full transition-all",
|
|
4152
|
+
style: { width: `${progress}%` }
|
|
4153
|
+
}
|
|
4154
|
+
),
|
|
4155
|
+
/* @__PURE__ */ jsx102(
|
|
4156
|
+
"input",
|
|
4157
|
+
{
|
|
4158
|
+
type: "range",
|
|
4159
|
+
min: 0,
|
|
4160
|
+
max: duration || 0,
|
|
4161
|
+
value: currentTime,
|
|
4162
|
+
onChange: handleSeek,
|
|
4163
|
+
disabled: isLoading,
|
|
4164
|
+
className: "absolute inset-0 w-full h-full opacity-0 cursor-pointer disabled:cursor-not-allowed",
|
|
4165
|
+
"aria-label": "Seek"
|
|
4166
|
+
}
|
|
4167
|
+
)
|
|
4168
|
+
] }),
|
|
4169
|
+
/* @__PURE__ */ jsx102("span", { className: "text-xs text-gray-500 dark:text-gray-400 tabular-nums", children: formatTime(duration) })
|
|
4170
|
+
] }),
|
|
4171
|
+
/* @__PURE__ */ jsxs33("div", { className: "flex items-center gap-2", children: [
|
|
4172
|
+
/* @__PURE__ */ jsx102(
|
|
4173
|
+
"button",
|
|
4174
|
+
{
|
|
4175
|
+
onClick: toggleMute,
|
|
4176
|
+
className: "text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-200",
|
|
4177
|
+
"aria-label": isMuted ? "Unmute" : "Mute",
|
|
4178
|
+
children: isMuted ? /* @__PURE__ */ jsx102(VolumeOffIcon, { size: "sm" }) : /* @__PURE__ */ jsx102(VolumeUpIcon, { size: "sm" })
|
|
4179
|
+
}
|
|
4180
|
+
),
|
|
4181
|
+
/* @__PURE__ */ jsx102(
|
|
4182
|
+
"input",
|
|
4183
|
+
{
|
|
4184
|
+
type: "range",
|
|
4185
|
+
min: 0,
|
|
4186
|
+
max: 1,
|
|
4187
|
+
step: 0.01,
|
|
4188
|
+
value: isMuted ? 0 : volume,
|
|
4189
|
+
onChange: handleVolumeChange,
|
|
4190
|
+
className: "w-16 h-1.5 bg-gray-200 dark:bg-gray-700 rounded-full appearance-none cursor-pointer\n [&::-webkit-slider-thumb]:appearance-none [&::-webkit-slider-thumb]:w-3 [&::-webkit-slider-thumb]:h-3\n [&::-webkit-slider-thumb]:rounded-full [&::-webkit-slider-thumb]:bg-blue-600 [&::-webkit-slider-thumb]:cursor-pointer\n [&::-moz-range-thumb]:w-3 [&::-moz-range-thumb]:h-3 [&::-moz-range-thumb]:rounded-full\n [&::-moz-range-thumb]:bg-blue-600 [&::-moz-range-thumb]:cursor-pointer [&::-moz-range-thumb]:border-none",
|
|
4191
|
+
"aria-label": "Volume"
|
|
4192
|
+
}
|
|
4193
|
+
)
|
|
4194
|
+
] })
|
|
4195
|
+
] });
|
|
4196
|
+
}
|
|
4197
|
+
return /* @__PURE__ */ jsxs33("div", { className: `bg-white dark:bg-gray-800 rounded-lg border border-gray-200 dark:border-gray-700 shadow-md overflow-hidden ${className}`, children: [
|
|
4198
|
+
/* @__PURE__ */ jsx102("audio", { ref: audioRef, src, preload, loop, autoPlay }),
|
|
4199
|
+
/* @__PURE__ */ jsxs33("div", { className: "flex items-center gap-4 p-4 border-b border-gray-200 dark:border-gray-700", children: [
|
|
4200
|
+
coverArt && /* @__PURE__ */ jsx102("div", { className: "w-16 h-16 flex-shrink-0 rounded-md overflow-hidden bg-gray-100 dark:bg-gray-700", children: /* @__PURE__ */ jsx102(
|
|
4201
|
+
"img",
|
|
4202
|
+
{
|
|
4203
|
+
src: coverArt,
|
|
4204
|
+
alt: `${title || "Track"} cover art`,
|
|
4205
|
+
className: "w-full h-full object-cover"
|
|
4206
|
+
}
|
|
4207
|
+
) }),
|
|
4208
|
+
/* @__PURE__ */ jsxs33("div", { className: "flex-1 min-w-0", children: [
|
|
4209
|
+
title && /* @__PURE__ */ jsx102("h3", { className: "text-base font-semibold text-gray-900 dark:text-gray-100 truncate", children: title }),
|
|
4210
|
+
artist && /* @__PURE__ */ jsx102("p", { className: "text-sm text-gray-600 dark:text-gray-400 truncate", children: artist }),
|
|
4211
|
+
album && /* @__PURE__ */ jsx102("p", { className: "text-xs text-gray-500 dark:text-gray-500 truncate", children: album })
|
|
4212
|
+
] })
|
|
4213
|
+
] }),
|
|
4214
|
+
/* @__PURE__ */ jsxs33("div", { className: "px-4 pt-4", children: [
|
|
4215
|
+
/* @__PURE__ */ jsxs33("div", { className: "relative h-2 bg-gray-200 dark:bg-gray-700 rounded-full overflow-hidden", children: [
|
|
4216
|
+
/* @__PURE__ */ jsx102(
|
|
4217
|
+
"div",
|
|
4218
|
+
{
|
|
4219
|
+
className: "absolute h-full bg-blue-600 dark:bg-blue-500 rounded-full transition-all",
|
|
4220
|
+
style: { width: `${progress}%` }
|
|
4221
|
+
}
|
|
4222
|
+
),
|
|
4223
|
+
/* @__PURE__ */ jsx102(
|
|
4224
|
+
"input",
|
|
4225
|
+
{
|
|
4226
|
+
type: "range",
|
|
4227
|
+
min: 0,
|
|
4228
|
+
max: duration || 0,
|
|
4229
|
+
value: currentTime,
|
|
4230
|
+
onChange: handleSeek,
|
|
4231
|
+
disabled: isLoading,
|
|
4232
|
+
className: "absolute inset-0 w-full h-full opacity-0 cursor-pointer disabled:cursor-not-allowed",
|
|
4233
|
+
"aria-label": "Seek"
|
|
4234
|
+
}
|
|
4235
|
+
)
|
|
4236
|
+
] }),
|
|
4237
|
+
/* @__PURE__ */ jsxs33("div", { className: "flex justify-between items-center mt-1 text-xs text-gray-500 dark:text-gray-400 tabular-nums", children: [
|
|
4238
|
+
/* @__PURE__ */ jsx102("span", { children: formatTime(currentTime) }),
|
|
4239
|
+
/* @__PURE__ */ jsx102("span", { children: formatTime(duration) })
|
|
4240
|
+
] })
|
|
4241
|
+
] }),
|
|
4242
|
+
/* @__PURE__ */ jsxs33("div", { className: "flex items-center justify-between px-4 py-4", children: [
|
|
4243
|
+
/* @__PURE__ */ jsxs33("div", { className: "flex items-center gap-2 flex-1", children: [
|
|
4244
|
+
/* @__PURE__ */ jsx102(
|
|
4245
|
+
"button",
|
|
4246
|
+
{
|
|
4247
|
+
onClick: toggleMute,
|
|
4248
|
+
className: "text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-200 transition-colors",
|
|
4249
|
+
"aria-label": isMuted ? "Unmute" : "Mute",
|
|
4250
|
+
children: isMuted ? /* @__PURE__ */ jsx102(VolumeOffIcon, { size: "md" }) : /* @__PURE__ */ jsx102(VolumeUpIcon, { size: "md" })
|
|
4251
|
+
}
|
|
4252
|
+
),
|
|
4253
|
+
/* @__PURE__ */ jsx102(
|
|
4254
|
+
"input",
|
|
4255
|
+
{
|
|
4256
|
+
type: "range",
|
|
4257
|
+
min: 0,
|
|
4258
|
+
max: 1,
|
|
4259
|
+
step: 0.01,
|
|
4260
|
+
value: isMuted ? 0 : volume,
|
|
4261
|
+
onChange: handleVolumeChange,
|
|
4262
|
+
className: "w-20 h-1.5 bg-gray-200 dark:bg-gray-700 rounded-full appearance-none cursor-pointer\n [&::-webkit-slider-thumb]:appearance-none [&::-webkit-slider-thumb]:w-3 [&::-webkit-slider-thumb]:h-3\n [&::-webkit-slider-thumb]:rounded-full [&::-webkit-slider-thumb]:bg-blue-600 [&::-webkit-slider-thumb]:cursor-pointer\n [&::-moz-range-thumb]:w-3 [&::-moz-range-thumb]:h-3 [&::-moz-range-thumb]:rounded-full\n [&::-moz-range-thumb]:bg-blue-600 [&::-moz-range-thumb]:cursor-pointer [&::-moz-range-thumb]:border-none",
|
|
4263
|
+
"aria-label": "Volume"
|
|
4264
|
+
}
|
|
4265
|
+
)
|
|
4266
|
+
] }),
|
|
4267
|
+
/* @__PURE__ */ jsxs33("div", { className: "flex items-center gap-2", children: [
|
|
4268
|
+
showSkipButtons && /* @__PURE__ */ jsx102(
|
|
4269
|
+
Button,
|
|
4270
|
+
{
|
|
4271
|
+
iconOnly: true,
|
|
4272
|
+
size: "md",
|
|
4273
|
+
variant: "secondary",
|
|
4274
|
+
onClick: handleSkipBack,
|
|
4275
|
+
disabled: isLoading,
|
|
4276
|
+
"aria-label": "Skip back 10 seconds",
|
|
4277
|
+
children: /* @__PURE__ */ jsx102(SkipBackIcon, { size: "md" })
|
|
4278
|
+
}
|
|
4279
|
+
),
|
|
4280
|
+
/* @__PURE__ */ jsx102(
|
|
4281
|
+
Button,
|
|
4282
|
+
{
|
|
4283
|
+
iconOnly: true,
|
|
4284
|
+
size: "lg",
|
|
4285
|
+
variant: "primary",
|
|
4286
|
+
onClick: togglePlayPause,
|
|
4287
|
+
disabled: isLoading,
|
|
4288
|
+
"aria-label": isPlaying ? "Pause" : "Play",
|
|
4289
|
+
children: isPlaying ? /* @__PURE__ */ jsx102(PauseIcon, { size: "lg" }) : /* @__PURE__ */ jsx102(PlayIcon, { size: "lg" })
|
|
4290
|
+
}
|
|
4291
|
+
),
|
|
4292
|
+
showSkipButtons && /* @__PURE__ */ jsx102(
|
|
4293
|
+
Button,
|
|
4294
|
+
{
|
|
4295
|
+
iconOnly: true,
|
|
4296
|
+
size: "md",
|
|
4297
|
+
variant: "secondary",
|
|
4298
|
+
onClick: handleSkipForward,
|
|
4299
|
+
disabled: isLoading,
|
|
4300
|
+
"aria-label": "Skip forward 10 seconds",
|
|
4301
|
+
children: /* @__PURE__ */ jsx102(SkipForwardIcon, { size: "md" })
|
|
4302
|
+
}
|
|
4303
|
+
)
|
|
4304
|
+
] }),
|
|
4305
|
+
/* @__PURE__ */ jsx102("div", { className: "flex-1" })
|
|
4306
|
+
] })
|
|
282
4307
|
] });
|
|
283
4308
|
};
|
|
284
4309
|
|
|
@@ -315,12 +4340,113 @@ function getThemeScript() {
|
|
|
315
4340
|
return themeScript;
|
|
316
4341
|
}
|
|
317
4342
|
export {
|
|
4343
|
+
ActionMenu,
|
|
4344
|
+
Alert,
|
|
4345
|
+
AlertCircleIcon,
|
|
4346
|
+
AppShell,
|
|
4347
|
+
AppleIcon,
|
|
4348
|
+
ArrowLeftIcon,
|
|
4349
|
+
ArrowRightIcon,
|
|
4350
|
+
AudioPlayer,
|
|
4351
|
+
Avatar,
|
|
4352
|
+
Badge,
|
|
4353
|
+
BeakerIcon,
|
|
4354
|
+
BellIcon,
|
|
4355
|
+
BookIcon,
|
|
4356
|
+
BrainIcon,
|
|
318
4357
|
Button,
|
|
4358
|
+
Calendar,
|
|
4359
|
+
CalendarIcon,
|
|
4360
|
+
CameraIcon,
|
|
4361
|
+
Card,
|
|
4362
|
+
ChatIcon,
|
|
4363
|
+
CheckCircleIcon,
|
|
4364
|
+
CheckIcon,
|
|
4365
|
+
Checkbox,
|
|
4366
|
+
ChevronDownIcon,
|
|
4367
|
+
ChevronLeftIcon,
|
|
4368
|
+
ChevronRightIcon,
|
|
4369
|
+
ChevronUpIcon,
|
|
4370
|
+
CloseIcon,
|
|
4371
|
+
CloudIcon,
|
|
4372
|
+
CodeIcon,
|
|
4373
|
+
CopyIcon,
|
|
4374
|
+
DatabaseIcon,
|
|
4375
|
+
DatePicker,
|
|
4376
|
+
DateTimePicker,
|
|
4377
|
+
Divider,
|
|
4378
|
+
DownloadIcon,
|
|
4379
|
+
Drawer,
|
|
4380
|
+
EditIcon,
|
|
4381
|
+
ExternalLinkIcon,
|
|
4382
|
+
EyeIcon,
|
|
4383
|
+
EyeOffIcon,
|
|
4384
|
+
FacebookIcon,
|
|
4385
|
+
FileIcon,
|
|
4386
|
+
FileUpload,
|
|
4387
|
+
FolderIcon,
|
|
4388
|
+
GitHubIcon,
|
|
4389
|
+
GlobeIcon,
|
|
4390
|
+
GoogleIcon,
|
|
4391
|
+
HeartIcon,
|
|
4392
|
+
HomeIcon,
|
|
4393
|
+
ImageIcon,
|
|
4394
|
+
InfoCircleIcon,
|
|
4395
|
+
KeyIcon,
|
|
4396
|
+
LinkedInIcon,
|
|
4397
|
+
LockIcon,
|
|
4398
|
+
MailIcon,
|
|
4399
|
+
MenuIcon,
|
|
4400
|
+
Modal,
|
|
4401
|
+
Navbar,
|
|
4402
|
+
NumberInput,
|
|
4403
|
+
Pagination,
|
|
4404
|
+
PauseIcon,
|
|
4405
|
+
PlayIcon,
|
|
4406
|
+
PlugIcon,
|
|
4407
|
+
PlusIcon,
|
|
4408
|
+
ProgressBar,
|
|
4409
|
+
Radio,
|
|
4410
|
+
RefreshIcon,
|
|
4411
|
+
RichTextEditor,
|
|
4412
|
+
SaveIcon,
|
|
4413
|
+
SearchIcon,
|
|
319
4414
|
Select,
|
|
4415
|
+
SettingsIcon,
|
|
4416
|
+
ShieldIcon,
|
|
4417
|
+
Sidebar,
|
|
4418
|
+
SidebarProvider,
|
|
4419
|
+
SkipBackIcon,
|
|
4420
|
+
SkipForwardIcon,
|
|
4421
|
+
SlackIcon,
|
|
4422
|
+
Slider,
|
|
4423
|
+
SparklesIcon,
|
|
4424
|
+
Spinner,
|
|
4425
|
+
StarIcon,
|
|
4426
|
+
Stepper,
|
|
4427
|
+
StopIcon,
|
|
4428
|
+
Table,
|
|
4429
|
+
Tabs,
|
|
4430
|
+
TerminalIcon,
|
|
4431
|
+
TextInput,
|
|
4432
|
+
Textarea,
|
|
320
4433
|
ThemeProvider,
|
|
4434
|
+
TimePicker,
|
|
4435
|
+
ToastProvider,
|
|
4436
|
+
Toggle,
|
|
4437
|
+
TrashIcon,
|
|
4438
|
+
TwitterIcon,
|
|
4439
|
+
UploadIcon,
|
|
4440
|
+
UserIcon,
|
|
4441
|
+
VolumeOffIcon,
|
|
4442
|
+
VolumeUpIcon,
|
|
4443
|
+
YouTubeIcon,
|
|
321
4444
|
getThemeScript,
|
|
322
4445
|
themeScript,
|
|
323
4446
|
themes,
|
|
324
|
-
|
|
4447
|
+
toast,
|
|
4448
|
+
useSidebar,
|
|
4449
|
+
useTheme,
|
|
4450
|
+
useToast
|
|
325
4451
|
};
|
|
326
4452
|
//# sourceMappingURL=index.mjs.map
|