@marcoschwartz/lite-ui 0.1.1 → 0.2.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 +476 -2
- package/dist/index.d.ts +476 -2
- package/dist/index.js +3593 -52
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +3520 -53
- package/dist/index.mjs.map +1 -1
- package/dist/styles.css +1 -1
- package/package.json +6 -1
package/dist/index.js
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
"use strict";
|
|
3
|
+
var __create = Object.create;
|
|
3
4
|
var __defProp = Object.defineProperty;
|
|
4
5
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
6
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
6
8
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
9
|
var __export = (target, all) => {
|
|
8
10
|
for (var name in all)
|
|
@@ -16,18 +18,90 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
16
18
|
}
|
|
17
19
|
return to;
|
|
18
20
|
};
|
|
21
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
22
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
23
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
24
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
25
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
26
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
27
|
+
mod
|
|
28
|
+
));
|
|
19
29
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
20
30
|
|
|
21
31
|
// src/index.ts
|
|
22
32
|
var index_exports = {};
|
|
23
33
|
__export(index_exports, {
|
|
34
|
+
ActionMenu: () => ActionMenu,
|
|
35
|
+
Alert: () => Alert,
|
|
36
|
+
AppShell: () => AppShell,
|
|
37
|
+
AppleIcon: () => AppleIcon,
|
|
38
|
+
Avatar: () => Avatar,
|
|
39
|
+
Badge: () => Badge,
|
|
40
|
+
BellIcon: () => BellIcon,
|
|
24
41
|
Button: () => Button,
|
|
42
|
+
Calendar: () => Calendar,
|
|
43
|
+
CalendarIcon: () => CalendarIcon,
|
|
44
|
+
CameraIcon: () => CameraIcon,
|
|
45
|
+
Card: () => Card,
|
|
46
|
+
CheckIcon: () => CheckIcon,
|
|
47
|
+
Checkbox: () => Checkbox,
|
|
48
|
+
ChevronDownIcon: () => ChevronDownIcon,
|
|
49
|
+
ChevronRightIcon: () => ChevronRightIcon,
|
|
50
|
+
CloseIcon: () => CloseIcon,
|
|
51
|
+
DatePicker: () => DatePicker,
|
|
52
|
+
DateTimePicker: () => DateTimePicker,
|
|
53
|
+
Divider: () => Divider,
|
|
54
|
+
DownloadIcon: () => DownloadIcon,
|
|
55
|
+
Drawer: () => Drawer,
|
|
56
|
+
EditIcon: () => EditIcon,
|
|
57
|
+
FacebookIcon: () => FacebookIcon,
|
|
58
|
+
FileUpload: () => FileUpload,
|
|
59
|
+
GitHubIcon: () => GitHubIcon,
|
|
60
|
+
GoogleIcon: () => GoogleIcon,
|
|
61
|
+
HeartIcon: () => HeartIcon,
|
|
62
|
+
HomeIcon: () => HomeIcon,
|
|
63
|
+
LinkedInIcon: () => LinkedInIcon,
|
|
64
|
+
LockIcon: () => LockIcon,
|
|
65
|
+
MailIcon: () => MailIcon,
|
|
66
|
+
MenuIcon: () => MenuIcon,
|
|
67
|
+
Modal: () => Modal,
|
|
68
|
+
Navbar: () => Navbar,
|
|
69
|
+
NumberInput: () => NumberInput,
|
|
70
|
+
Pagination: () => Pagination,
|
|
71
|
+
PlusIcon: () => PlusIcon,
|
|
72
|
+
ProgressBar: () => ProgressBar,
|
|
73
|
+
Radio: () => Radio,
|
|
74
|
+
RichTextEditor: () => RichTextEditor,
|
|
75
|
+
SearchIcon: () => SearchIcon,
|
|
25
76
|
Select: () => Select,
|
|
77
|
+
SettingsIcon: () => SettingsIcon,
|
|
78
|
+
Sidebar: () => Sidebar,
|
|
79
|
+
SidebarProvider: () => SidebarProvider,
|
|
80
|
+
SlackIcon: () => SlackIcon,
|
|
81
|
+
Slider: () => Slider,
|
|
82
|
+
Spinner: () => Spinner,
|
|
83
|
+
StarIcon: () => StarIcon,
|
|
84
|
+
Stepper: () => Stepper,
|
|
85
|
+
Table: () => Table,
|
|
86
|
+
Tabs: () => Tabs,
|
|
87
|
+
TextInput: () => TextInput,
|
|
88
|
+
Textarea: () => Textarea,
|
|
26
89
|
ThemeProvider: () => ThemeProvider,
|
|
90
|
+
TimePicker: () => TimePicker,
|
|
91
|
+
ToastProvider: () => ToastProvider,
|
|
92
|
+
Toggle: () => Toggle,
|
|
93
|
+
TrashIcon: () => TrashIcon,
|
|
94
|
+
TwitterIcon: () => TwitterIcon,
|
|
95
|
+
UploadIcon: () => UploadIcon,
|
|
96
|
+
UserIcon: () => UserIcon,
|
|
97
|
+
YouTubeIcon: () => YouTubeIcon,
|
|
27
98
|
getThemeScript: () => getThemeScript,
|
|
28
99
|
themeScript: () => themeScript,
|
|
29
100
|
themes: () => themes,
|
|
30
|
-
|
|
101
|
+
toast: () => toast,
|
|
102
|
+
useSidebar: () => useSidebar,
|
|
103
|
+
useTheme: () => useTheme,
|
|
104
|
+
useToast: () => useToast
|
|
31
105
|
});
|
|
32
106
|
module.exports = __toCommonJS(index_exports);
|
|
33
107
|
|
|
@@ -39,7 +113,7 @@ var themes = {
|
|
|
39
113
|
default: {
|
|
40
114
|
name: "default",
|
|
41
115
|
button: {
|
|
42
|
-
base: "font-semibold rounded-lg transition-all duration-150 focus:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 active:scale-95",
|
|
116
|
+
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",
|
|
43
117
|
variants: {
|
|
44
118
|
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",
|
|
45
119
|
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",
|
|
@@ -49,15 +123,15 @@ var themes = {
|
|
|
49
123
|
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"
|
|
50
124
|
},
|
|
51
125
|
sizes: {
|
|
52
|
-
sm: "px-3 py-1.5 text-sm",
|
|
53
|
-
md: "px-4 py-2 text-base",
|
|
54
|
-
lg: "px-6 py-3 text-lg",
|
|
55
|
-
xl: "px-8 py-4 text-xl"
|
|
126
|
+
sm: "px-3 py-1.5 text-sm min-h-[30px]",
|
|
127
|
+
md: "px-4 py-2 text-base min-h-[38px]",
|
|
128
|
+
lg: "px-6 py-3 text-lg min-h-[48px]",
|
|
129
|
+
xl: "px-8 py-4 text-xl min-h-[60px]"
|
|
56
130
|
},
|
|
57
131
|
disabled: "opacity-50 cursor-not-allowed hover:shadow-sm active:scale-100"
|
|
58
132
|
},
|
|
59
133
|
select: {
|
|
60
|
-
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",
|
|
134
|
+
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",
|
|
61
135
|
sizes: {
|
|
62
136
|
sm: "px-3 py-1.5 text-sm",
|
|
63
137
|
md: "px-4 py-2.5 text-base",
|
|
@@ -70,7 +144,7 @@ var themes = {
|
|
|
70
144
|
minimalistic: {
|
|
71
145
|
name: "minimalistic",
|
|
72
146
|
button: {
|
|
73
|
-
base: "font-normal rounded-none transition-colors duration-200 focus:outline-none border-2",
|
|
147
|
+
base: "font-normal rounded-none transition-colors duration-200 focus:outline-none border-2 gap-2",
|
|
74
148
|
variants: {
|
|
75
149
|
primary: "bg-transparent border-white text-white hover:bg-white hover:text-black",
|
|
76
150
|
secondary: "bg-transparent border-gray-400 text-gray-400 hover:bg-gray-400 hover:text-black",
|
|
@@ -80,15 +154,15 @@ var themes = {
|
|
|
80
154
|
info: "bg-transparent border-blue-400 text-blue-400 hover:bg-blue-400 hover:text-black"
|
|
81
155
|
},
|
|
82
156
|
sizes: {
|
|
83
|
-
sm: "px-4 py-2 text-sm uppercase tracking-wide",
|
|
84
|
-
md: "px-6 py-3 text-base uppercase tracking-wide",
|
|
85
|
-
lg: "px-8 py-4 text-lg uppercase tracking-wider",
|
|
86
|
-
xl: "px-10 py-5 text-xl uppercase tracking-wider"
|
|
157
|
+
sm: "px-4 py-2 text-sm uppercase tracking-wide min-h-[36px]",
|
|
158
|
+
md: "px-6 py-3 text-base uppercase tracking-wide min-h-[48px]",
|
|
159
|
+
lg: "px-8 py-4 text-lg uppercase tracking-wider min-h-[60px]",
|
|
160
|
+
xl: "px-10 py-5 text-xl uppercase tracking-wider min-h-[72px]"
|
|
87
161
|
},
|
|
88
162
|
disabled: "opacity-30 cursor-not-allowed hover:bg-transparent"
|
|
89
163
|
},
|
|
90
164
|
select: {
|
|
91
|
-
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",
|
|
165
|
+
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",
|
|
92
166
|
sizes: {
|
|
93
167
|
sm: "px-4 py-2 text-sm uppercase tracking-wide",
|
|
94
168
|
md: "px-4 py-3 text-base uppercase tracking-wide",
|
|
@@ -106,7 +180,20 @@ var ThemeContext = (0, import_react.createContext)(void 0);
|
|
|
106
180
|
function useTheme() {
|
|
107
181
|
const context = (0, import_react.useContext)(ThemeContext);
|
|
108
182
|
if (!context) {
|
|
109
|
-
|
|
183
|
+
const warnOnce = () => {
|
|
184
|
+
if (process.env.NODE_ENV === "development") {
|
|
185
|
+
console.warn("useTheme: Component used outside ThemeProvider. Using default theme. Wrap your app with <ThemeProvider> for full functionality.");
|
|
186
|
+
}
|
|
187
|
+
};
|
|
188
|
+
return {
|
|
189
|
+
theme: themes.default,
|
|
190
|
+
themeName: "default",
|
|
191
|
+
setTheme: () => warnOnce(),
|
|
192
|
+
colorMode: "light",
|
|
193
|
+
setColorMode: () => warnOnce(),
|
|
194
|
+
toggleColorMode: () => warnOnce(),
|
|
195
|
+
resolvedColorMode: "light"
|
|
196
|
+
};
|
|
110
197
|
}
|
|
111
198
|
return context;
|
|
112
199
|
}
|
|
@@ -154,6 +241,13 @@ function ThemeProvider({
|
|
|
154
241
|
document.documentElement.classList.remove("dark");
|
|
155
242
|
}
|
|
156
243
|
};
|
|
244
|
+
const toggleColorMode = () => {
|
|
245
|
+
if (colorMode === "system") {
|
|
246
|
+
setColorMode(resolvedColorMode === "dark" ? "light" : "dark");
|
|
247
|
+
} else {
|
|
248
|
+
setColorMode(colorMode === "dark" ? "light" : "dark");
|
|
249
|
+
}
|
|
250
|
+
};
|
|
157
251
|
(0, import_react.useEffect)(() => {
|
|
158
252
|
if (!mounted) return;
|
|
159
253
|
const mediaQuery = window.matchMedia("(prefers-color-scheme: dark)");
|
|
@@ -178,6 +272,7 @@ function ThemeProvider({
|
|
|
178
272
|
setTheme,
|
|
179
273
|
colorMode,
|
|
180
274
|
setColorMode,
|
|
275
|
+
toggleColorMode,
|
|
181
276
|
resolvedColorMode
|
|
182
277
|
}, children });
|
|
183
278
|
}
|
|
@@ -190,21 +285,29 @@ var Button = ({
|
|
|
190
285
|
className = "",
|
|
191
286
|
children,
|
|
192
287
|
disabled,
|
|
288
|
+
leftIcon,
|
|
289
|
+
rightIcon,
|
|
290
|
+
iconOnly = false,
|
|
193
291
|
...props
|
|
194
292
|
}) => {
|
|
195
293
|
const { theme } = useTheme();
|
|
196
294
|
const baseStyles = theme.button.base;
|
|
197
|
-
const
|
|
198
|
-
const
|
|
295
|
+
const variantStyles3 = theme.button.variants[variant];
|
|
296
|
+
const sizeStyles2 = theme.button.sizes[size];
|
|
199
297
|
const disabledStyles = disabled ? theme.button.disabled : "";
|
|
200
|
-
const
|
|
298
|
+
const iconOnlyStyles = iconOnly ? "!p-0 aspect-square" : "";
|
|
299
|
+
const classes = `inline-flex items-center justify-center ${baseStyles} ${variantStyles3} ${sizeStyles2} ${disabledStyles} ${iconOnlyStyles} ${className}`.trim();
|
|
201
300
|
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
202
301
|
"button",
|
|
203
302
|
{
|
|
204
303
|
className: classes,
|
|
205
304
|
disabled,
|
|
206
305
|
...props,
|
|
207
|
-
children
|
|
306
|
+
children: iconOnly ? children : /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
|
|
307
|
+
leftIcon && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "inline-flex shrink-0", children: leftIcon }),
|
|
308
|
+
children && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "inline-flex items-center", children }),
|
|
309
|
+
rightIcon && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "inline-flex shrink-0", children: rightIcon })
|
|
310
|
+
] })
|
|
208
311
|
}
|
|
209
312
|
);
|
|
210
313
|
};
|
|
@@ -221,19 +324,30 @@ var Select = ({
|
|
|
221
324
|
value: controlledValue,
|
|
222
325
|
defaultValue,
|
|
223
326
|
onChange,
|
|
327
|
+
label,
|
|
328
|
+
error,
|
|
329
|
+
helperText,
|
|
330
|
+
searchable = false,
|
|
331
|
+
searchPlaceholder = "Search...",
|
|
224
332
|
...props
|
|
225
333
|
}) => {
|
|
226
334
|
const { theme, themeName } = useTheme();
|
|
227
335
|
const [isOpen, setIsOpen] = (0, import_react2.useState)(false);
|
|
228
336
|
const [internalValue, setInternalValue] = (0, import_react2.useState)(defaultValue || "");
|
|
337
|
+
const [searchQuery, setSearchQuery] = (0, import_react2.useState)("");
|
|
229
338
|
const dropdownRef = (0, import_react2.useRef)(null);
|
|
339
|
+
const searchInputRef = (0, import_react2.useRef)(null);
|
|
230
340
|
const value = controlledValue !== void 0 ? controlledValue : internalValue;
|
|
231
341
|
const selectedOption = options.find((opt) => opt.value === value);
|
|
232
342
|
const displayText = selectedOption ? selectedOption.label : placeholder || "Select...";
|
|
343
|
+
const filteredOptions = searchable && searchQuery ? options.filter(
|
|
344
|
+
(option) => option.label.toLowerCase().includes(searchQuery.toLowerCase())
|
|
345
|
+
) : options;
|
|
233
346
|
(0, import_react2.useEffect)(() => {
|
|
234
347
|
const handleClickOutside = (event) => {
|
|
235
348
|
if (dropdownRef.current && !dropdownRef.current.contains(event.target)) {
|
|
236
349
|
setIsOpen(false);
|
|
350
|
+
setSearchQuery("");
|
|
237
351
|
}
|
|
238
352
|
};
|
|
239
353
|
if (isOpen) {
|
|
@@ -241,11 +355,17 @@ var Select = ({
|
|
|
241
355
|
return () => document.removeEventListener("mousedown", handleClickOutside);
|
|
242
356
|
}
|
|
243
357
|
}, [isOpen]);
|
|
358
|
+
(0, import_react2.useEffect)(() => {
|
|
359
|
+
if (isOpen && searchable && searchInputRef.current) {
|
|
360
|
+
searchInputRef.current.focus();
|
|
361
|
+
}
|
|
362
|
+
}, [isOpen, searchable]);
|
|
244
363
|
const handleSelect = (optionValue) => {
|
|
245
364
|
if (disabled) return;
|
|
246
365
|
setInternalValue(optionValue);
|
|
247
366
|
onChange?.(optionValue);
|
|
248
367
|
setIsOpen(false);
|
|
368
|
+
setSearchQuery("");
|
|
249
369
|
};
|
|
250
370
|
const handleToggle = () => {
|
|
251
371
|
if (!disabled) {
|
|
@@ -253,9 +373,10 @@ var Select = ({
|
|
|
253
373
|
}
|
|
254
374
|
};
|
|
255
375
|
const baseStyles = theme.select.base;
|
|
256
|
-
const
|
|
376
|
+
const sizeStyles2 = theme.select.sizes[size];
|
|
257
377
|
const disabledStyles = disabled ? theme.select.disabled : "";
|
|
258
|
-
const
|
|
378
|
+
const errorStyles = error ? "border-red-500 focus:ring-red-500 dark:border-red-500" : "";
|
|
379
|
+
const buttonClasses = `${baseStyles} ${sizeStyles2} ${disabledStyles} ${errorStyles}`.trim();
|
|
259
380
|
const iconColor = themeName === "minimalistic" ? disabled ? "text-gray-600" : "text-white" : disabled ? "text-gray-400" : "text-gray-500";
|
|
260
381
|
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";
|
|
261
382
|
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";
|
|
@@ -265,51 +386,3407 @@ var Select = ({
|
|
|
265
386
|
lg: "px-4 py-3 text-lg",
|
|
266
387
|
xl: "px-5 py-4 text-xl"
|
|
267
388
|
}[size];
|
|
268
|
-
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className:
|
|
269
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
389
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: `w-full ${className}`, children: [
|
|
390
|
+
label && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("label", { className: "block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1", children: label }),
|
|
391
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "relative inline-block w-full", ref: dropdownRef, ...props, children: [
|
|
392
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
393
|
+
"button",
|
|
394
|
+
{
|
|
395
|
+
type: "button",
|
|
396
|
+
className: buttonClasses,
|
|
397
|
+
onClick: handleToggle,
|
|
398
|
+
disabled,
|
|
399
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: !selectedOption && placeholder ? "opacity-50" : "", children: displayText })
|
|
400
|
+
}
|
|
401
|
+
),
|
|
402
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "pointer-events-none absolute inset-y-0 right-0 flex items-center pr-4", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
403
|
+
"svg",
|
|
404
|
+
{
|
|
405
|
+
className: `h-5 w-5 transition-transform duration-200 ${iconColor} ${isOpen ? "rotate-180" : ""}`,
|
|
406
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
407
|
+
viewBox: "0 0 20 20",
|
|
408
|
+
fill: "currentColor",
|
|
409
|
+
"aria-hidden": "true",
|
|
410
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
411
|
+
"path",
|
|
412
|
+
{
|
|
413
|
+
fillRule: "evenodd",
|
|
414
|
+
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",
|
|
415
|
+
clipRule: "evenodd"
|
|
416
|
+
}
|
|
417
|
+
)
|
|
418
|
+
}
|
|
419
|
+
) }),
|
|
420
|
+
isOpen && !disabled && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
421
|
+
"div",
|
|
422
|
+
{
|
|
423
|
+
className: `absolute z-50 w-full mt-1 ${dropdownBaseStyles} rounded-lg overflow-hidden`,
|
|
424
|
+
children: [
|
|
425
|
+
searchable && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("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__ */ (0, import_jsx_runtime3.jsx)(
|
|
426
|
+
"input",
|
|
427
|
+
{
|
|
428
|
+
ref: searchInputRef,
|
|
429
|
+
type: "text",
|
|
430
|
+
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"}`,
|
|
431
|
+
placeholder: searchPlaceholder,
|
|
432
|
+
value: searchQuery,
|
|
433
|
+
onChange: (e) => setSearchQuery(e.target.value),
|
|
434
|
+
onClick: (e) => e.stopPropagation()
|
|
435
|
+
}
|
|
436
|
+
) }),
|
|
437
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("style", { children: `
|
|
438
|
+
.select-dropdown-scroll {
|
|
439
|
+
scrollbar-width: thin;
|
|
440
|
+
scrollbar-color: rgba(156, 163, 175, 0.5) transparent;
|
|
441
|
+
}
|
|
442
|
+
.select-dropdown-scroll::-webkit-scrollbar {
|
|
443
|
+
width: 8px;
|
|
444
|
+
}
|
|
445
|
+
.select-dropdown-scroll::-webkit-scrollbar-track {
|
|
446
|
+
background: transparent;
|
|
447
|
+
}
|
|
448
|
+
.select-dropdown-scroll::-webkit-scrollbar-thumb {
|
|
449
|
+
background-color: rgba(156, 163, 175, 0.5);
|
|
450
|
+
border-radius: 4px;
|
|
451
|
+
border: 2px solid transparent;
|
|
452
|
+
background-clip: padding-box;
|
|
453
|
+
}
|
|
454
|
+
.select-dropdown-scroll::-webkit-scrollbar-thumb:hover {
|
|
455
|
+
background-color: rgba(156, 163, 175, 0.7);
|
|
456
|
+
}
|
|
457
|
+
.dark .select-dropdown-scroll {
|
|
458
|
+
scrollbar-color: rgba(75, 85, 99, 0.6) transparent;
|
|
459
|
+
}
|
|
460
|
+
.dark .select-dropdown-scroll::-webkit-scrollbar-thumb {
|
|
461
|
+
background-color: rgba(75, 85, 99, 0.6);
|
|
462
|
+
}
|
|
463
|
+
.dark .select-dropdown-scroll::-webkit-scrollbar-thumb:hover {
|
|
464
|
+
background-color: rgba(75, 85, 99, 0.8);
|
|
465
|
+
}
|
|
466
|
+
` }),
|
|
467
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
468
|
+
"div",
|
|
469
|
+
{
|
|
470
|
+
className: "select-dropdown-scroll",
|
|
471
|
+
style: { maxHeight: "300px", overflowY: "auto" },
|
|
472
|
+
children: filteredOptions.length > 0 ? filteredOptions.map((option) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
473
|
+
"div",
|
|
474
|
+
{
|
|
475
|
+
className: `${optionBaseStyles} ${optionSizeStyles} cursor-pointer ${value === option.value ? themeName === "minimalistic" ? "bg-white text-black" : "bg-blue-50 dark:bg-gray-700" : ""}`,
|
|
476
|
+
onClick: () => handleSelect(option.value),
|
|
477
|
+
children: option.label
|
|
478
|
+
},
|
|
479
|
+
option.value
|
|
480
|
+
)) : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: `${optionSizeStyles} ${themeName === "minimalistic" ? "text-gray-500" : "text-gray-500 dark:text-gray-400"} text-center`, children: "No results found" })
|
|
481
|
+
}
|
|
482
|
+
)
|
|
483
|
+
]
|
|
484
|
+
}
|
|
485
|
+
)
|
|
486
|
+
] }),
|
|
487
|
+
error && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: "mt-1 text-sm text-red-600 dark:text-red-400", children: error }),
|
|
488
|
+
helperText && !error && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: "mt-1 text-sm text-gray-500 dark:text-gray-400", children: helperText })
|
|
489
|
+
] });
|
|
490
|
+
};
|
|
491
|
+
|
|
492
|
+
// src/components/Modal.tsx
|
|
493
|
+
var import_react3 = require("react");
|
|
494
|
+
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
495
|
+
var sizeClasses = {
|
|
496
|
+
sm: "max-w-md",
|
|
497
|
+
md: "max-w-lg",
|
|
498
|
+
lg: "max-w-2xl",
|
|
499
|
+
xl: "max-w-4xl"
|
|
500
|
+
};
|
|
501
|
+
var Modal = ({
|
|
502
|
+
isOpen,
|
|
503
|
+
onClose,
|
|
504
|
+
title,
|
|
505
|
+
children,
|
|
506
|
+
size = "md",
|
|
507
|
+
showCloseButton = true
|
|
508
|
+
}) => {
|
|
509
|
+
const { theme } = useTheme();
|
|
510
|
+
(0, import_react3.useEffect)(() => {
|
|
511
|
+
const handleEscape = (e) => {
|
|
512
|
+
if (e.key === "Escape" && isOpen) {
|
|
513
|
+
onClose();
|
|
277
514
|
}
|
|
278
|
-
|
|
279
|
-
|
|
515
|
+
};
|
|
516
|
+
if (isOpen) {
|
|
517
|
+
document.addEventListener("keydown", handleEscape);
|
|
518
|
+
document.body.style.overflow = "hidden";
|
|
519
|
+
}
|
|
520
|
+
return () => {
|
|
521
|
+
document.removeEventListener("keydown", handleEscape);
|
|
522
|
+
document.body.style.overflow = "unset";
|
|
523
|
+
};
|
|
524
|
+
}, [isOpen, onClose]);
|
|
525
|
+
if (!isOpen) return null;
|
|
526
|
+
const sizeClass = sizeClasses[size];
|
|
527
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
528
|
+
"div",
|
|
529
|
+
{
|
|
530
|
+
className: "fixed inset-0 z-50 flex items-center justify-center p-4 bg-black/60 backdrop-blur-sm transition-all duration-200",
|
|
531
|
+
onClick: onClose,
|
|
532
|
+
role: "dialog",
|
|
533
|
+
"aria-modal": "true",
|
|
534
|
+
"aria-labelledby": title ? "modal-title" : void 0,
|
|
535
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
536
|
+
"div",
|
|
537
|
+
{
|
|
538
|
+
className: `relative w-full ${sizeClass} bg-white dark:bg-gray-800 rounded-lg shadow-2xl transform transition-all duration-200 scale-100 animate-in`,
|
|
539
|
+
onClick: (e) => e.stopPropagation(),
|
|
540
|
+
children: [
|
|
541
|
+
(title || showCloseButton) && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "flex items-center justify-between p-6 border-b border-gray-200 dark:border-gray-700", children: [
|
|
542
|
+
title && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("h3", { id: "modal-title", className: "text-xl font-semibold text-gray-900 dark:text-gray-100", children: title }),
|
|
543
|
+
showCloseButton && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
544
|
+
"button",
|
|
545
|
+
{
|
|
546
|
+
onClick: onClose,
|
|
547
|
+
className: "ml-auto text-gray-400 hover:text-gray-600 dark:hover:text-gray-300 transition-colors",
|
|
548
|
+
"aria-label": "Close modal",
|
|
549
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("svg", { className: "w-6 h-6", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M6 18L18 6M6 6l12 12" }) })
|
|
550
|
+
}
|
|
551
|
+
)
|
|
552
|
+
] }),
|
|
553
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "p-6", children })
|
|
554
|
+
]
|
|
555
|
+
}
|
|
556
|
+
)
|
|
557
|
+
}
|
|
558
|
+
);
|
|
559
|
+
};
|
|
560
|
+
|
|
561
|
+
// src/components/Navbar.tsx
|
|
562
|
+
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
563
|
+
var Navbar = ({
|
|
564
|
+
logo,
|
|
565
|
+
children,
|
|
566
|
+
className = "",
|
|
567
|
+
sticky = false
|
|
568
|
+
}) => {
|
|
569
|
+
const { theme } = useTheme();
|
|
570
|
+
const baseClasses = sticky ? "sticky top-0 z-40" : "";
|
|
571
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("nav", { className: `bg-white dark:bg-gray-800 border-b border-gray-200 dark:border-gray-700 ${baseClasses} ${className}`, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "max-w-7xl mx-auto px-4 sm:px-6 lg:px-8", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex justify-between items-center h-16", children: [
|
|
572
|
+
logo && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "flex items-center", children: logo }),
|
|
573
|
+
children && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "flex items-center gap-6", children })
|
|
574
|
+
] }) }) });
|
|
575
|
+
};
|
|
576
|
+
|
|
577
|
+
// src/components/Sidebar.tsx
|
|
578
|
+
var import_jsx_runtime6 = require("react/jsx-runtime");
|
|
579
|
+
var widthClasses = {
|
|
580
|
+
sm: "w-48",
|
|
581
|
+
md: "w-64",
|
|
582
|
+
lg: "w-80"
|
|
583
|
+
};
|
|
584
|
+
var Sidebar = ({
|
|
585
|
+
children,
|
|
586
|
+
className = "",
|
|
587
|
+
width = "md",
|
|
588
|
+
position = "left"
|
|
589
|
+
}) => {
|
|
590
|
+
const { theme } = useTheme();
|
|
591
|
+
const widthClass = widthClasses[width];
|
|
592
|
+
const borderClass = position === "left" ? "border-r" : "border-l";
|
|
593
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
594
|
+
"aside",
|
|
595
|
+
{
|
|
596
|
+
className: `${widthClass} bg-white dark:bg-gray-800 ${borderClass} border-gray-200 dark:border-gray-700 h-full overflow-y-auto ${className}`,
|
|
597
|
+
children
|
|
598
|
+
}
|
|
599
|
+
);
|
|
600
|
+
};
|
|
601
|
+
|
|
602
|
+
// src/components/SidebarProvider.tsx
|
|
603
|
+
var import_react4 = require("react");
|
|
604
|
+
var import_jsx_runtime7 = require("react/jsx-runtime");
|
|
605
|
+
var SidebarContext = (0, import_react4.createContext)(void 0);
|
|
606
|
+
var SidebarProvider = ({
|
|
607
|
+
children,
|
|
608
|
+
defaultOpen = false
|
|
609
|
+
}) => {
|
|
610
|
+
const [isOpen, setIsOpen] = (0, import_react4.useState)(defaultOpen);
|
|
611
|
+
const [isMobile, setIsMobile] = (0, import_react4.useState)(false);
|
|
612
|
+
const open = () => setIsOpen(true);
|
|
613
|
+
const close = () => setIsOpen(false);
|
|
614
|
+
const toggle = () => setIsOpen((prev) => !prev);
|
|
615
|
+
const value = {
|
|
616
|
+
isOpen,
|
|
617
|
+
isMobile,
|
|
618
|
+
open,
|
|
619
|
+
close,
|
|
620
|
+
toggle,
|
|
621
|
+
setIsMobile
|
|
622
|
+
};
|
|
623
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(SidebarContext.Provider, { value, children });
|
|
624
|
+
};
|
|
625
|
+
var useSidebar = () => {
|
|
626
|
+
const context = (0, import_react4.useContext)(SidebarContext);
|
|
627
|
+
if (!context) {
|
|
628
|
+
throw new Error("useSidebar must be used within a SidebarProvider");
|
|
629
|
+
}
|
|
630
|
+
return context;
|
|
631
|
+
};
|
|
632
|
+
|
|
633
|
+
// src/components/AppShell.tsx
|
|
634
|
+
var import_react5 = require("react");
|
|
635
|
+
|
|
636
|
+
// src/icons/icon-utils.tsx
|
|
637
|
+
var import_jsx_runtime8 = require("react/jsx-runtime");
|
|
638
|
+
var sizeClasses2 = {
|
|
639
|
+
xs: "w-3 h-3",
|
|
640
|
+
sm: "w-4 h-4",
|
|
641
|
+
md: "w-5 h-5",
|
|
642
|
+
lg: "w-6 h-6",
|
|
643
|
+
xl: "w-8 h-8"
|
|
644
|
+
};
|
|
645
|
+
var createIcon = (displayName, path, filled = false) => {
|
|
646
|
+
const Icon = ({ size = "md", className = "", color = "currentColor" }) => {
|
|
647
|
+
const sizeClass = sizeClasses2[size];
|
|
648
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
280
649
|
"svg",
|
|
281
650
|
{
|
|
282
|
-
className:
|
|
283
|
-
|
|
284
|
-
viewBox: "0 0
|
|
285
|
-
|
|
651
|
+
className: `${sizeClass} ${className}`,
|
|
652
|
+
fill: filled ? color : "none",
|
|
653
|
+
viewBox: "0 0 24 24",
|
|
654
|
+
stroke: filled ? "none" : color,
|
|
286
655
|
"aria-hidden": "true",
|
|
287
|
-
children:
|
|
288
|
-
|
|
656
|
+
children: path
|
|
657
|
+
}
|
|
658
|
+
);
|
|
659
|
+
};
|
|
660
|
+
Icon.displayName = displayName;
|
|
661
|
+
return Icon;
|
|
662
|
+
};
|
|
663
|
+
|
|
664
|
+
// src/icons/HomeIcon.tsx
|
|
665
|
+
var import_jsx_runtime9 = require("react/jsx-runtime");
|
|
666
|
+
var HomeIcon = createIcon(
|
|
667
|
+
"HomeIcon",
|
|
668
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("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" })
|
|
669
|
+
);
|
|
670
|
+
|
|
671
|
+
// src/icons/UserIcon.tsx
|
|
672
|
+
var import_jsx_runtime10 = require("react/jsx-runtime");
|
|
673
|
+
var UserIcon = createIcon(
|
|
674
|
+
"UserIcon",
|
|
675
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("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" })
|
|
676
|
+
);
|
|
677
|
+
|
|
678
|
+
// src/icons/SearchIcon.tsx
|
|
679
|
+
var import_jsx_runtime11 = require("react/jsx-runtime");
|
|
680
|
+
var SearchIcon = createIcon(
|
|
681
|
+
"SearchIcon",
|
|
682
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" })
|
|
683
|
+
);
|
|
684
|
+
|
|
685
|
+
// src/icons/BellIcon.tsx
|
|
686
|
+
var import_jsx_runtime12 = require("react/jsx-runtime");
|
|
687
|
+
var BellIcon = createIcon(
|
|
688
|
+
"BellIcon",
|
|
689
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("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" })
|
|
690
|
+
);
|
|
691
|
+
|
|
692
|
+
// src/icons/SettingsIcon.tsx
|
|
693
|
+
var import_jsx_runtime13 = require("react/jsx-runtime");
|
|
694
|
+
var SettingsIcon = createIcon(
|
|
695
|
+
"SettingsIcon",
|
|
696
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_jsx_runtime13.Fragment, { children: [
|
|
697
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("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" }),
|
|
698
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M15 12a3 3 0 11-6 0 3 3 0 016 0z" })
|
|
699
|
+
] })
|
|
700
|
+
);
|
|
701
|
+
|
|
702
|
+
// src/icons/MenuIcon.tsx
|
|
703
|
+
var import_jsx_runtime14 = require("react/jsx-runtime");
|
|
704
|
+
var MenuIcon = createIcon(
|
|
705
|
+
"MenuIcon",
|
|
706
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M4 6h16M4 12h16M4 18h16" })
|
|
707
|
+
);
|
|
708
|
+
|
|
709
|
+
// src/icons/CloseIcon.tsx
|
|
710
|
+
var import_jsx_runtime15 = require("react/jsx-runtime");
|
|
711
|
+
var CloseIcon = createIcon(
|
|
712
|
+
"CloseIcon",
|
|
713
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M6 18L18 6M6 6l12 12" })
|
|
714
|
+
);
|
|
715
|
+
|
|
716
|
+
// src/icons/ChevronDownIcon.tsx
|
|
717
|
+
var import_jsx_runtime16 = require("react/jsx-runtime");
|
|
718
|
+
var ChevronDownIcon = createIcon(
|
|
719
|
+
"ChevronDownIcon",
|
|
720
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M19 9l-7 7-7-7" })
|
|
721
|
+
);
|
|
722
|
+
|
|
723
|
+
// src/icons/ChevronRightIcon.tsx
|
|
724
|
+
var import_jsx_runtime17 = require("react/jsx-runtime");
|
|
725
|
+
var ChevronRightIcon = createIcon(
|
|
726
|
+
"ChevronRightIcon",
|
|
727
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M9 5l7 7-7 7" })
|
|
728
|
+
);
|
|
729
|
+
|
|
730
|
+
// src/icons/CheckIcon.tsx
|
|
731
|
+
var import_jsx_runtime18 = require("react/jsx-runtime");
|
|
732
|
+
var CheckIcon = createIcon(
|
|
733
|
+
"CheckIcon",
|
|
734
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M5 13l4 4L19 7" })
|
|
735
|
+
);
|
|
736
|
+
|
|
737
|
+
// src/icons/PlusIcon.tsx
|
|
738
|
+
var import_jsx_runtime19 = require("react/jsx-runtime");
|
|
739
|
+
var PlusIcon = createIcon(
|
|
740
|
+
"PlusIcon",
|
|
741
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 4v16m8-8H4" })
|
|
742
|
+
);
|
|
743
|
+
|
|
744
|
+
// src/icons/TrashIcon.tsx
|
|
745
|
+
var import_jsx_runtime20 = require("react/jsx-runtime");
|
|
746
|
+
var TrashIcon = createIcon(
|
|
747
|
+
"TrashIcon",
|
|
748
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("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" })
|
|
749
|
+
);
|
|
750
|
+
|
|
751
|
+
// src/icons/EditIcon.tsx
|
|
752
|
+
var import_jsx_runtime21 = require("react/jsx-runtime");
|
|
753
|
+
var EditIcon = createIcon(
|
|
754
|
+
"EditIcon",
|
|
755
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("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" })
|
|
756
|
+
);
|
|
757
|
+
|
|
758
|
+
// src/icons/MailIcon.tsx
|
|
759
|
+
var import_jsx_runtime22 = require("react/jsx-runtime");
|
|
760
|
+
var MailIcon = createIcon(
|
|
761
|
+
"MailIcon",
|
|
762
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)("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" })
|
|
763
|
+
);
|
|
764
|
+
|
|
765
|
+
// src/icons/StarIcon.tsx
|
|
766
|
+
var import_jsx_runtime23 = require("react/jsx-runtime");
|
|
767
|
+
var StarIcon = createIcon(
|
|
768
|
+
"StarIcon",
|
|
769
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)("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" })
|
|
770
|
+
);
|
|
771
|
+
|
|
772
|
+
// src/icons/HeartIcon.tsx
|
|
773
|
+
var import_jsx_runtime24 = require("react/jsx-runtime");
|
|
774
|
+
var HeartIcon = createIcon(
|
|
775
|
+
"HeartIcon",
|
|
776
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)("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" })
|
|
777
|
+
);
|
|
778
|
+
|
|
779
|
+
// src/icons/DownloadIcon.tsx
|
|
780
|
+
var import_jsx_runtime25 = require("react/jsx-runtime");
|
|
781
|
+
var DownloadIcon = createIcon(
|
|
782
|
+
"DownloadIcon",
|
|
783
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)("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" })
|
|
784
|
+
);
|
|
785
|
+
|
|
786
|
+
// src/icons/UploadIcon.tsx
|
|
787
|
+
var import_jsx_runtime26 = require("react/jsx-runtime");
|
|
788
|
+
var UploadIcon = createIcon(
|
|
789
|
+
"UploadIcon",
|
|
790
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)("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" })
|
|
791
|
+
);
|
|
792
|
+
|
|
793
|
+
// src/icons/CameraIcon.tsx
|
|
794
|
+
var import_jsx_runtime27 = require("react/jsx-runtime");
|
|
795
|
+
var CameraIcon = createIcon(
|
|
796
|
+
"CameraIcon",
|
|
797
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(import_jsx_runtime27.Fragment, { children: [
|
|
798
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)("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" }),
|
|
799
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M15 13a3 3 0 11-6 0 3 3 0 016 0z" })
|
|
800
|
+
] })
|
|
801
|
+
);
|
|
802
|
+
|
|
803
|
+
// src/icons/LockIcon.tsx
|
|
804
|
+
var import_jsx_runtime28 = require("react/jsx-runtime");
|
|
805
|
+
var LockIcon = createIcon(
|
|
806
|
+
"LockIcon",
|
|
807
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)("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" })
|
|
808
|
+
);
|
|
809
|
+
|
|
810
|
+
// src/icons/CalendarIcon.tsx
|
|
811
|
+
var import_jsx_runtime29 = require("react/jsx-runtime");
|
|
812
|
+
var CalendarIcon = createIcon(
|
|
813
|
+
"CalendarIcon",
|
|
814
|
+
/* @__PURE__ */ (0, import_jsx_runtime29.jsx)("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" })
|
|
815
|
+
);
|
|
816
|
+
|
|
817
|
+
// src/icons/GoogleIcon.tsx
|
|
818
|
+
var import_jsx_runtime30 = require("react/jsx-runtime");
|
|
819
|
+
var GoogleIcon = createIcon(
|
|
820
|
+
"GoogleIcon",
|
|
821
|
+
/* @__PURE__ */ (0, import_jsx_runtime30.jsx)("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" }),
|
|
822
|
+
true
|
|
823
|
+
);
|
|
824
|
+
|
|
825
|
+
// src/icons/GitHubIcon.tsx
|
|
826
|
+
var import_jsx_runtime31 = require("react/jsx-runtime");
|
|
827
|
+
var GitHubIcon = createIcon(
|
|
828
|
+
"GitHubIcon",
|
|
829
|
+
/* @__PURE__ */ (0, import_jsx_runtime31.jsx)("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" }),
|
|
830
|
+
true
|
|
831
|
+
);
|
|
832
|
+
|
|
833
|
+
// src/icons/TwitterIcon.tsx
|
|
834
|
+
var import_jsx_runtime32 = require("react/jsx-runtime");
|
|
835
|
+
var TwitterIcon = createIcon(
|
|
836
|
+
"TwitterIcon",
|
|
837
|
+
/* @__PURE__ */ (0, import_jsx_runtime32.jsx)("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" }),
|
|
838
|
+
true
|
|
839
|
+
);
|
|
840
|
+
|
|
841
|
+
// src/icons/FacebookIcon.tsx
|
|
842
|
+
var import_jsx_runtime33 = require("react/jsx-runtime");
|
|
843
|
+
var FacebookIcon = createIcon(
|
|
844
|
+
"FacebookIcon",
|
|
845
|
+
/* @__PURE__ */ (0, import_jsx_runtime33.jsx)("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" }),
|
|
846
|
+
true
|
|
847
|
+
);
|
|
848
|
+
|
|
849
|
+
// src/icons/AppleIcon.tsx
|
|
850
|
+
var import_jsx_runtime34 = require("react/jsx-runtime");
|
|
851
|
+
var AppleIcon = createIcon(
|
|
852
|
+
"AppleIcon",
|
|
853
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)("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" }),
|
|
854
|
+
true
|
|
855
|
+
);
|
|
856
|
+
|
|
857
|
+
// src/icons/LinkedInIcon.tsx
|
|
858
|
+
var import_jsx_runtime35 = require("react/jsx-runtime");
|
|
859
|
+
var LinkedInIcon = createIcon(
|
|
860
|
+
"LinkedInIcon",
|
|
861
|
+
/* @__PURE__ */ (0, import_jsx_runtime35.jsx)("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" }),
|
|
862
|
+
true
|
|
863
|
+
);
|
|
864
|
+
|
|
865
|
+
// src/icons/YouTubeIcon.tsx
|
|
866
|
+
var import_jsx_runtime36 = require("react/jsx-runtime");
|
|
867
|
+
var YouTubeIcon = createIcon(
|
|
868
|
+
"YouTubeIcon",
|
|
869
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)("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" }),
|
|
870
|
+
true
|
|
871
|
+
);
|
|
872
|
+
|
|
873
|
+
// src/icons/SlackIcon.tsx
|
|
874
|
+
var import_jsx_runtime37 = require("react/jsx-runtime");
|
|
875
|
+
var SlackIcon = createIcon(
|
|
876
|
+
"SlackIcon",
|
|
877
|
+
/* @__PURE__ */ (0, import_jsx_runtime37.jsx)("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" }),
|
|
878
|
+
true
|
|
879
|
+
);
|
|
880
|
+
|
|
881
|
+
// src/components/AppShell.tsx
|
|
882
|
+
var import_jsx_runtime38 = require("react/jsx-runtime");
|
|
883
|
+
var widthClasses2 = {
|
|
884
|
+
sm: "w-48",
|
|
885
|
+
md: "w-64",
|
|
886
|
+
lg: "w-80"
|
|
887
|
+
};
|
|
888
|
+
var breakpointClasses = {
|
|
889
|
+
sm: "sm",
|
|
890
|
+
md: "md",
|
|
891
|
+
lg: "lg",
|
|
892
|
+
xl: "xl"
|
|
893
|
+
};
|
|
894
|
+
var AppShell = ({
|
|
895
|
+
children,
|
|
896
|
+
navbar,
|
|
897
|
+
header,
|
|
898
|
+
navbarTitle,
|
|
899
|
+
navbarLogo,
|
|
900
|
+
defaultNavbarOpen = false,
|
|
901
|
+
responsive = true,
|
|
902
|
+
className = ""
|
|
903
|
+
}) => {
|
|
904
|
+
const { theme } = useTheme();
|
|
905
|
+
const [isMobileNavbarOpen, setIsMobileNavbarOpen] = (0, import_react5.useState)(defaultNavbarOpen);
|
|
906
|
+
const navbarWidth = navbar?.width || "md";
|
|
907
|
+
const navbarBreakpoint = navbar?.breakpoint || "md";
|
|
908
|
+
const navbarPosition = navbar?.position || "side";
|
|
909
|
+
const widthClass = widthClasses2[navbarWidth];
|
|
910
|
+
const breakpoint = breakpointClasses[navbarBreakpoint];
|
|
911
|
+
if (!responsive && navbar) {
|
|
912
|
+
return /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("div", { className: `min-h-screen flex flex-col ${className}`, children: [
|
|
913
|
+
header && /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("div", { className: "w-full", children: header }),
|
|
914
|
+
/* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("div", { className: "flex flex-1", children: [
|
|
915
|
+
/* @__PURE__ */ (0, import_jsx_runtime38.jsx)("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 }),
|
|
916
|
+
/* @__PURE__ */ (0, import_jsx_runtime38.jsx)("main", { className: "flex-1 overflow-y-auto", children })
|
|
917
|
+
] })
|
|
918
|
+
] });
|
|
919
|
+
}
|
|
920
|
+
if (!responsive) {
|
|
921
|
+
return /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("div", { className: `min-h-screen flex flex-col ${className}`, children: [
|
|
922
|
+
header && /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("div", { className: "w-full", children: header }),
|
|
923
|
+
/* @__PURE__ */ (0, import_jsx_runtime38.jsx)("main", { className: "flex-1 overflow-y-auto", children })
|
|
924
|
+
] });
|
|
925
|
+
}
|
|
926
|
+
if (navbar && navbarPosition === "top") {
|
|
927
|
+
const mobileMenuClass = navbarBreakpoint === "sm" ? "sm:hidden" : navbarBreakpoint === "md" ? "md:hidden" : navbarBreakpoint === "lg" ? "lg:hidden" : "xl:hidden";
|
|
928
|
+
const desktopNavClass = navbarBreakpoint === "sm" ? "sm:flex" : navbarBreakpoint === "md" ? "md:flex" : navbarBreakpoint === "lg" ? "lg:flex" : "xl:flex";
|
|
929
|
+
return /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("div", { className: `min-h-screen flex flex-col bg-gray-50 dark:bg-gray-900 ${className}`, children: [
|
|
930
|
+
/* @__PURE__ */ (0, import_jsx_runtime38.jsx)("nav", { className: "sticky top-0 z-30 bg-white dark:bg-gray-800 border-b border-gray-200 dark:border-gray-700", children: /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("div", { className: "max-w-7xl mx-auto px-4 sm:px-6 lg:px-8", children: /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("div", { className: "flex justify-between items-center h-16", children: [
|
|
931
|
+
/* @__PURE__ */ (0, import_jsx_runtime38.jsx)("div", { className: "flex items-center", children: navbarLogo ? /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("div", { children: navbarLogo }) : navbarTitle ? /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("span", { className: "text-xl font-bold text-gray-900 dark:text-gray-100", children: navbarTitle }) : null }),
|
|
932
|
+
/* @__PURE__ */ (0, import_jsx_runtime38.jsx)("div", { className: `hidden ${desktopNavClass} items-center gap-6`, children: navbar.content }),
|
|
933
|
+
/* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
|
|
934
|
+
"button",
|
|
289
935
|
{
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
936
|
+
className: `${mobileMenuClass} p-2 rounded-lg hover:bg-gray-100 dark:hover:bg-gray-700 transition-colors`,
|
|
937
|
+
onClick: () => setIsMobileNavbarOpen(!isMobileNavbarOpen),
|
|
938
|
+
"aria-label": "Toggle menu",
|
|
939
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(MenuIcon, { size: "md" })
|
|
293
940
|
}
|
|
294
941
|
)
|
|
942
|
+
] }) }) }),
|
|
943
|
+
header && /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("div", { className: "w-full", children: header }),
|
|
944
|
+
isMobileNavbarOpen && /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(import_jsx_runtime38.Fragment, { children: [
|
|
945
|
+
/* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
|
|
946
|
+
"div",
|
|
947
|
+
{
|
|
948
|
+
className: `${mobileMenuClass} fixed inset-0 z-40 bg-black/60 backdrop-blur-sm animate-in fade-in duration-200`,
|
|
949
|
+
onClick: () => setIsMobileNavbarOpen(false)
|
|
950
|
+
}
|
|
951
|
+
),
|
|
952
|
+
/* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("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: [
|
|
953
|
+
/* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("div", { className: "p-4 border-b border-gray-200 dark:border-gray-700 flex items-center justify-between", children: [
|
|
954
|
+
navbarLogo ? /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("div", { children: navbarLogo }) : navbarTitle ? /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("span", { className: "text-xl font-bold text-gray-900 dark:text-gray-100", children: navbarTitle }) : null,
|
|
955
|
+
/* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
|
|
956
|
+
"button",
|
|
957
|
+
{
|
|
958
|
+
className: "p-1 rounded hover:bg-gray-100 dark:hover:bg-gray-700 transition-colors",
|
|
959
|
+
onClick: () => setIsMobileNavbarOpen(false),
|
|
960
|
+
"aria-label": "Close menu",
|
|
961
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("svg", { className: "w-6 h-6", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M6 18L18 6M6 6l12 12" }) })
|
|
962
|
+
}
|
|
963
|
+
)
|
|
964
|
+
] }),
|
|
965
|
+
/* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
|
|
966
|
+
"div",
|
|
967
|
+
{
|
|
968
|
+
className: "p-4 flex flex-col gap-4",
|
|
969
|
+
onClick: () => setIsMobileNavbarOpen(false),
|
|
970
|
+
children: navbar.content
|
|
971
|
+
}
|
|
972
|
+
)
|
|
973
|
+
] })
|
|
974
|
+
] }),
|
|
975
|
+
/* @__PURE__ */ (0, import_jsx_runtime38.jsx)("main", { className: "flex-1 overflow-y-auto", children })
|
|
976
|
+
] });
|
|
977
|
+
}
|
|
978
|
+
if (navbar) {
|
|
979
|
+
const mobileHeaderClass = navbarBreakpoint === "sm" ? "sm:hidden" : navbarBreakpoint === "md" ? "md:hidden" : navbarBreakpoint === "lg" ? "lg:hidden" : "xl:hidden";
|
|
980
|
+
const desktopNavbarClass = navbarBreakpoint === "sm" ? "sm:block" : navbarBreakpoint === "md" ? "md:block" : navbarBreakpoint === "lg" ? "lg:block" : "xl:block";
|
|
981
|
+
const mobileDrawerClass = navbarBreakpoint === "sm" ? "sm:hidden" : navbarBreakpoint === "md" ? "md:hidden" : navbarBreakpoint === "lg" ? "lg:hidden" : "xl:hidden";
|
|
982
|
+
const sidebarWidthClass = navbarWidth === "sm" ? "w-48" : navbarWidth === "lg" ? "w-80" : "w-64";
|
|
983
|
+
return /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("div", { className: `min-h-screen flex flex-col bg-gray-50 dark:bg-gray-900 ${className}`, children: [
|
|
984
|
+
/* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("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: [
|
|
985
|
+
navbarLogo ? /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("div", { children: navbarLogo }) : navbarTitle ? /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("span", { className: "text-xl font-bold text-gray-900 dark:text-gray-100", children: navbarTitle }) : null,
|
|
986
|
+
/* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
|
|
987
|
+
"button",
|
|
988
|
+
{
|
|
989
|
+
className: "p-2 rounded-lg hover:bg-gray-100 dark:hover:bg-gray-700 transition-colors",
|
|
990
|
+
onClick: () => setIsMobileNavbarOpen(!isMobileNavbarOpen),
|
|
991
|
+
"aria-label": "Toggle menu",
|
|
992
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(MenuIcon, { size: "md" })
|
|
993
|
+
}
|
|
994
|
+
)
|
|
995
|
+
] }),
|
|
996
|
+
header && /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("div", { className: "w-full", children: header }),
|
|
997
|
+
/* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("div", { className: "flex flex-1 min-h-0", children: [
|
|
998
|
+
/* @__PURE__ */ (0, import_jsx_runtime38.jsx)("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 }),
|
|
999
|
+
isMobileNavbarOpen && /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(import_jsx_runtime38.Fragment, { children: [
|
|
1000
|
+
/* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
|
|
1001
|
+
"div",
|
|
1002
|
+
{
|
|
1003
|
+
className: `${mobileDrawerClass} fixed inset-0 z-40 bg-black/60 backdrop-blur-sm animate-in fade-in duration-200`,
|
|
1004
|
+
onClick: () => setIsMobileNavbarOpen(false)
|
|
1005
|
+
}
|
|
1006
|
+
),
|
|
1007
|
+
/* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("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: [
|
|
1008
|
+
/* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("div", { className: "p-4 border-b border-gray-200 dark:border-gray-700 flex items-center justify-between", children: [
|
|
1009
|
+
navbarLogo ? /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("div", { children: navbarLogo }) : navbarTitle ? /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("span", { className: "text-xl font-bold text-gray-900 dark:text-gray-100", children: navbarTitle }) : null,
|
|
1010
|
+
/* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
|
|
1011
|
+
"button",
|
|
1012
|
+
{
|
|
1013
|
+
className: "p-1 rounded hover:bg-gray-100 dark:hover:bg-gray-700 transition-colors",
|
|
1014
|
+
onClick: () => setIsMobileNavbarOpen(false),
|
|
1015
|
+
"aria-label": "Close menu",
|
|
1016
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("svg", { className: "w-6 h-6", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M6 18L18 6M6 6l12 12" }) })
|
|
1017
|
+
}
|
|
1018
|
+
)
|
|
1019
|
+
] }),
|
|
1020
|
+
/* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
|
|
1021
|
+
"div",
|
|
1022
|
+
{
|
|
1023
|
+
className: "overflow-y-auto h-[calc(100vh-73px)]",
|
|
1024
|
+
onClick: () => setIsMobileNavbarOpen(false),
|
|
1025
|
+
children: navbar.content
|
|
1026
|
+
}
|
|
1027
|
+
)
|
|
1028
|
+
] })
|
|
1029
|
+
] }),
|
|
1030
|
+
/* @__PURE__ */ (0, import_jsx_runtime38.jsx)("main", { className: "flex-1 overflow-y-auto min-h-screen", children })
|
|
1031
|
+
] })
|
|
1032
|
+
] });
|
|
1033
|
+
}
|
|
1034
|
+
return /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("div", { className: `min-h-screen flex flex-col ${className}`, children: [
|
|
1035
|
+
header && /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("div", { className: "w-full", children: header }),
|
|
1036
|
+
/* @__PURE__ */ (0, import_jsx_runtime38.jsx)("main", { className: "flex-1 overflow-y-auto", children })
|
|
1037
|
+
] });
|
|
1038
|
+
};
|
|
1039
|
+
|
|
1040
|
+
// src/components/Drawer.tsx
|
|
1041
|
+
var import_react6 = require("react");
|
|
1042
|
+
var import_jsx_runtime39 = require("react/jsx-runtime");
|
|
1043
|
+
var sizeClasses3 = {
|
|
1044
|
+
left: {
|
|
1045
|
+
sm: "w-64",
|
|
1046
|
+
md: "w-80",
|
|
1047
|
+
lg: "w-96"
|
|
1048
|
+
},
|
|
1049
|
+
right: {
|
|
1050
|
+
sm: "w-64",
|
|
1051
|
+
md: "w-80",
|
|
1052
|
+
lg: "w-96"
|
|
1053
|
+
},
|
|
1054
|
+
top: {
|
|
1055
|
+
sm: "h-48",
|
|
1056
|
+
md: "h-64",
|
|
1057
|
+
lg: "h-80"
|
|
1058
|
+
},
|
|
1059
|
+
bottom: {
|
|
1060
|
+
sm: "h-48",
|
|
1061
|
+
md: "h-64",
|
|
1062
|
+
lg: "h-80"
|
|
1063
|
+
}
|
|
1064
|
+
};
|
|
1065
|
+
var positionClasses = {
|
|
1066
|
+
left: "left-0 top-0 h-full",
|
|
1067
|
+
right: "right-0 top-0 h-full",
|
|
1068
|
+
top: "top-0 left-0 w-full",
|
|
1069
|
+
bottom: "bottom-0 left-0 w-full"
|
|
1070
|
+
};
|
|
1071
|
+
var slideClasses = {
|
|
1072
|
+
left: "transform transition-transform duration-300",
|
|
1073
|
+
right: "transform transition-transform duration-300",
|
|
1074
|
+
top: "transform transition-transform duration-300",
|
|
1075
|
+
bottom: "transform transition-transform duration-300"
|
|
1076
|
+
};
|
|
1077
|
+
var Drawer = ({
|
|
1078
|
+
isOpen,
|
|
1079
|
+
onClose,
|
|
1080
|
+
title,
|
|
1081
|
+
children,
|
|
1082
|
+
position = "right",
|
|
1083
|
+
size = "md",
|
|
1084
|
+
showCloseButton = true
|
|
1085
|
+
}) => {
|
|
1086
|
+
const { theme } = useTheme();
|
|
1087
|
+
(0, import_react6.useEffect)(() => {
|
|
1088
|
+
const handleEscape = (e) => {
|
|
1089
|
+
if (e.key === "Escape" && isOpen) {
|
|
1090
|
+
onClose();
|
|
1091
|
+
}
|
|
1092
|
+
};
|
|
1093
|
+
if (isOpen) {
|
|
1094
|
+
document.addEventListener("keydown", handleEscape);
|
|
1095
|
+
document.body.style.overflow = "hidden";
|
|
1096
|
+
}
|
|
1097
|
+
return () => {
|
|
1098
|
+
document.removeEventListener("keydown", handleEscape);
|
|
1099
|
+
document.body.style.overflow = "unset";
|
|
1100
|
+
};
|
|
1101
|
+
}, [isOpen, onClose]);
|
|
1102
|
+
if (!isOpen) return null;
|
|
1103
|
+
const sizeClass = sizeClasses3[position][size];
|
|
1104
|
+
const positionClass = positionClasses[position];
|
|
1105
|
+
return /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)(import_jsx_runtime39.Fragment, { children: [
|
|
1106
|
+
/* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
|
|
1107
|
+
"div",
|
|
1108
|
+
{
|
|
1109
|
+
className: "fixed inset-0 z-40 bg-black/60 backdrop-blur-sm transition-all duration-200",
|
|
1110
|
+
onClick: onClose
|
|
295
1111
|
}
|
|
296
|
-
)
|
|
297
|
-
|
|
1112
|
+
),
|
|
1113
|
+
/* @__PURE__ */ (0, import_jsx_runtime39.jsxs)(
|
|
298
1114
|
"div",
|
|
299
1115
|
{
|
|
300
|
-
className: `
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
1116
|
+
className: `fixed z-50 ${positionClass} ${sizeClass} bg-white dark:bg-gray-800 shadow-2xl overflow-hidden flex flex-col ${slideClasses[position]}`,
|
|
1117
|
+
children: [
|
|
1118
|
+
(title || showCloseButton) && /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("div", { className: "flex items-center justify-between p-6 border-b border-gray-200 dark:border-gray-700", children: [
|
|
1119
|
+
title && /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("h3", { className: "text-xl font-semibold text-gray-900 dark:text-gray-100", children: title }),
|
|
1120
|
+
showCloseButton && /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
|
|
1121
|
+
"button",
|
|
1122
|
+
{
|
|
1123
|
+
onClick: onClose,
|
|
1124
|
+
className: "ml-auto text-gray-400 hover:text-gray-600 dark:hover:text-gray-300 transition-colors",
|
|
1125
|
+
"aria-label": "Close drawer",
|
|
1126
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("svg", { className: "w-6 h-6", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M6 18L18 6M6 6l12 12" }) })
|
|
1127
|
+
}
|
|
1128
|
+
)
|
|
1129
|
+
] }),
|
|
1130
|
+
/* @__PURE__ */ (0, import_jsx_runtime39.jsx)("div", { className: "flex-1 p-6 overflow-y-auto", children })
|
|
1131
|
+
]
|
|
1132
|
+
}
|
|
1133
|
+
)
|
|
1134
|
+
] });
|
|
1135
|
+
};
|
|
1136
|
+
|
|
1137
|
+
// src/components/TextInput.tsx
|
|
1138
|
+
var import_react7 = require("react");
|
|
1139
|
+
var import_jsx_runtime40 = require("react/jsx-runtime");
|
|
1140
|
+
var sizeClasses4 = {
|
|
1141
|
+
sm: "px-3 py-1.5 text-sm",
|
|
1142
|
+
md: "px-4 py-2.5 text-base",
|
|
1143
|
+
lg: "px-4 py-3 text-lg"
|
|
1144
|
+
};
|
|
1145
|
+
var TextInput = (0, import_react7.forwardRef)(
|
|
1146
|
+
({
|
|
1147
|
+
label,
|
|
1148
|
+
error,
|
|
1149
|
+
helperText,
|
|
1150
|
+
size = "md",
|
|
1151
|
+
fullWidth = false,
|
|
1152
|
+
leftIcon,
|
|
1153
|
+
rightIcon,
|
|
1154
|
+
className = "",
|
|
1155
|
+
disabled,
|
|
1156
|
+
...props
|
|
1157
|
+
}, ref) => {
|
|
1158
|
+
const { theme, themeName } = useTheme();
|
|
1159
|
+
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";
|
|
1160
|
+
const sizeStyle = sizeClasses4[size];
|
|
1161
|
+
const errorStyles = error ? "border-red-500 focus:ring-red-500 dark:border-red-500" : "";
|
|
1162
|
+
const disabledStyles = disabled ? "opacity-50 cursor-not-allowed bg-gray-50 dark:bg-gray-900" : "";
|
|
1163
|
+
const widthStyle = fullWidth ? "w-full" : "";
|
|
1164
|
+
const paddingWithIcon = leftIcon ? "pl-10" : rightIcon ? "pr-10" : "";
|
|
1165
|
+
return /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("div", { className: `${widthStyle} ${className}`, children: [
|
|
1166
|
+
label && /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("label", { className: "block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1", children: label }),
|
|
1167
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("div", { className: "relative", children: [
|
|
1168
|
+
leftIcon && /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("div", { className: "absolute left-3 top-1/2 transform -translate-y-1/2 text-gray-400 dark:text-gray-500", children: leftIcon }),
|
|
1169
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
|
|
1170
|
+
"input",
|
|
1171
|
+
{
|
|
1172
|
+
ref,
|
|
1173
|
+
className: `${baseStyles} ${sizeStyle} ${errorStyles} ${disabledStyles} ${paddingWithIcon}`.trim(),
|
|
1174
|
+
disabled,
|
|
1175
|
+
...props
|
|
1176
|
+
}
|
|
1177
|
+
),
|
|
1178
|
+
rightIcon && /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("div", { className: "absolute right-3 top-1/2 transform -translate-y-1/2 text-gray-400 dark:text-gray-500", children: rightIcon })
|
|
1179
|
+
] }),
|
|
1180
|
+
error && /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("p", { className: "mt-1 text-sm text-red-600 dark:text-red-400", children: error }),
|
|
1181
|
+
helperText && !error && /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("p", { className: "mt-1 text-sm text-gray-500 dark:text-gray-400", children: helperText })
|
|
1182
|
+
] });
|
|
1183
|
+
}
|
|
1184
|
+
);
|
|
1185
|
+
TextInput.displayName = "TextInput";
|
|
1186
|
+
|
|
1187
|
+
// src/components/NumberInput.tsx
|
|
1188
|
+
var import_react8 = require("react");
|
|
1189
|
+
var import_jsx_runtime41 = require("react/jsx-runtime");
|
|
1190
|
+
var sizeClasses5 = {
|
|
1191
|
+
sm: "px-3 py-1.5 text-sm",
|
|
1192
|
+
md: "px-4 py-2.5 text-base",
|
|
1193
|
+
lg: "px-4 py-3 text-lg"
|
|
1194
|
+
};
|
|
1195
|
+
var NumberInput = ({
|
|
1196
|
+
label,
|
|
1197
|
+
error,
|
|
1198
|
+
helperText,
|
|
1199
|
+
value,
|
|
1200
|
+
onChange,
|
|
1201
|
+
min,
|
|
1202
|
+
max,
|
|
1203
|
+
step = 1,
|
|
1204
|
+
precision,
|
|
1205
|
+
disabled = false,
|
|
1206
|
+
hideControls = false,
|
|
1207
|
+
size = "md",
|
|
1208
|
+
fullWidth = false,
|
|
1209
|
+
placeholder,
|
|
1210
|
+
className = ""
|
|
1211
|
+
}) => {
|
|
1212
|
+
const { theme } = useTheme();
|
|
1213
|
+
const inputRef = (0, import_react8.useRef)(null);
|
|
1214
|
+
const [isFocused, setIsFocused] = (0, import_react8.useState)(false);
|
|
1215
|
+
const clampValue = (val) => {
|
|
1216
|
+
let clamped = val;
|
|
1217
|
+
if (min !== void 0 && clamped < min) clamped = min;
|
|
1218
|
+
if (max !== void 0 && clamped > max) clamped = max;
|
|
1219
|
+
if (precision !== void 0) {
|
|
1220
|
+
clamped = parseFloat(clamped.toFixed(precision));
|
|
1221
|
+
}
|
|
1222
|
+
return clamped;
|
|
1223
|
+
};
|
|
1224
|
+
const handleIncrement = () => {
|
|
1225
|
+
if (disabled) return;
|
|
1226
|
+
const currentValue = value ?? 0;
|
|
1227
|
+
const newValue = clampValue(currentValue + step);
|
|
1228
|
+
onChange?.(newValue);
|
|
1229
|
+
};
|
|
1230
|
+
const handleDecrement = () => {
|
|
1231
|
+
if (disabled) return;
|
|
1232
|
+
const currentValue = value ?? 0;
|
|
1233
|
+
const newValue = clampValue(currentValue - step);
|
|
1234
|
+
onChange?.(newValue);
|
|
1235
|
+
};
|
|
1236
|
+
const handleInputChange = (e) => {
|
|
1237
|
+
const inputValue = e.target.value;
|
|
1238
|
+
if (inputValue === "" || inputValue === "-") {
|
|
1239
|
+
onChange?.(void 0);
|
|
1240
|
+
return;
|
|
1241
|
+
}
|
|
1242
|
+
const numValue = parseFloat(inputValue);
|
|
1243
|
+
if (!isNaN(numValue)) {
|
|
1244
|
+
const clamped = clampValue(numValue);
|
|
1245
|
+
onChange?.(clamped);
|
|
1246
|
+
}
|
|
1247
|
+
};
|
|
1248
|
+
const handleKeyDown = (e) => {
|
|
1249
|
+
if (e.key === "ArrowUp") {
|
|
1250
|
+
e.preventDefault();
|
|
1251
|
+
handleIncrement();
|
|
1252
|
+
} else if (e.key === "ArrowDown") {
|
|
1253
|
+
e.preventDefault();
|
|
1254
|
+
handleDecrement();
|
|
1255
|
+
}
|
|
1256
|
+
};
|
|
1257
|
+
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";
|
|
1258
|
+
const sizeStyle = sizeClasses5[size];
|
|
1259
|
+
const errorStyles = error ? "border-red-500 focus:ring-red-500 dark:border-red-500" : "";
|
|
1260
|
+
const disabledStyles = disabled ? "opacity-50 cursor-not-allowed bg-gray-50 dark:bg-gray-900" : "";
|
|
1261
|
+
const widthStyle = fullWidth ? "w-full" : "";
|
|
1262
|
+
const paddingWithControls = !hideControls ? "pr-8" : "";
|
|
1263
|
+
const displayValue = value !== void 0 ? value.toString() : "";
|
|
1264
|
+
return /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { className: `${widthStyle} ${className}`, children: [
|
|
1265
|
+
label && /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("label", { className: "block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1", children: label }),
|
|
1266
|
+
/* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { className: "relative", children: [
|
|
1267
|
+
/* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
|
|
1268
|
+
"input",
|
|
1269
|
+
{
|
|
1270
|
+
ref: inputRef,
|
|
1271
|
+
type: "number",
|
|
1272
|
+
value: displayValue,
|
|
1273
|
+
onChange: handleInputChange,
|
|
1274
|
+
onKeyDown: handleKeyDown,
|
|
1275
|
+
onFocus: () => setIsFocused(true),
|
|
1276
|
+
onBlur: () => setIsFocused(false),
|
|
1277
|
+
disabled,
|
|
1278
|
+
placeholder,
|
|
1279
|
+
min,
|
|
1280
|
+
max,
|
|
1281
|
+
step,
|
|
1282
|
+
className: `${baseStyles} ${sizeStyle} ${errorStyles} ${disabledStyles} ${paddingWithControls} [appearance:textfield] [&::-webkit-outer-spin-button]:appearance-none [&::-webkit-inner-spin-button]:appearance-none`.trim()
|
|
1283
|
+
}
|
|
1284
|
+
),
|
|
1285
|
+
!hideControls && /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { className: "absolute right-1 top-1/2 -translate-y-1/2 flex flex-col", children: [
|
|
1286
|
+
/* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
|
|
1287
|
+
"button",
|
|
1288
|
+
{
|
|
1289
|
+
type: "button",
|
|
1290
|
+
onClick: handleIncrement,
|
|
1291
|
+
disabled: disabled || max !== void 0 && value !== void 0 && value >= max,
|
|
1292
|
+
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",
|
|
1293
|
+
tabIndex: -1,
|
|
1294
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("svg", { className: "w-3 h-3 text-gray-600 dark:text-gray-400", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 3, d: "M5 15l7-7 7 7" }) })
|
|
1295
|
+
}
|
|
1296
|
+
),
|
|
1297
|
+
/* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
|
|
1298
|
+
"button",
|
|
1299
|
+
{
|
|
1300
|
+
type: "button",
|
|
1301
|
+
onClick: handleDecrement,
|
|
1302
|
+
disabled: disabled || min !== void 0 && value !== void 0 && value <= min,
|
|
1303
|
+
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",
|
|
1304
|
+
tabIndex: -1,
|
|
1305
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("svg", { className: "w-3 h-3 text-gray-600 dark:text-gray-400", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 3, d: "M19 9l-7 7-7-7" }) })
|
|
1306
|
+
}
|
|
1307
|
+
)
|
|
1308
|
+
] })
|
|
1309
|
+
] }),
|
|
1310
|
+
error && /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("p", { className: "mt-1 text-sm text-red-600 dark:text-red-400", children: error }),
|
|
1311
|
+
helperText && !error && /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("p", { className: "mt-1 text-sm text-gray-500 dark:text-gray-400", children: helperText })
|
|
1312
|
+
] });
|
|
1313
|
+
};
|
|
1314
|
+
NumberInput.displayName = "NumberInput";
|
|
1315
|
+
|
|
1316
|
+
// src/components/ActionMenu.tsx
|
|
1317
|
+
var import_react9 = require("react");
|
|
1318
|
+
var import_react_dom = require("react-dom");
|
|
1319
|
+
var import_jsx_runtime42 = require("react/jsx-runtime");
|
|
1320
|
+
var ActionMenu = ({
|
|
1321
|
+
items,
|
|
1322
|
+
trigger,
|
|
1323
|
+
position = "right",
|
|
1324
|
+
placement = "bottom"
|
|
1325
|
+
}) => {
|
|
1326
|
+
const { themeName } = useTheme();
|
|
1327
|
+
const [isOpen, setIsOpen] = (0, import_react9.useState)(false);
|
|
1328
|
+
const [menuPosition, setMenuPosition] = (0, import_react9.useState)(null);
|
|
1329
|
+
const [mounted, setMounted] = (0, import_react9.useState)(false);
|
|
1330
|
+
const menuRef = (0, import_react9.useRef)(null);
|
|
1331
|
+
const triggerRef = (0, import_react9.useRef)(null);
|
|
1332
|
+
(0, import_react9.useEffect)(() => {
|
|
1333
|
+
setMounted(true);
|
|
1334
|
+
}, []);
|
|
1335
|
+
(0, import_react9.useEffect)(() => {
|
|
1336
|
+
const handleClickOutside = (event) => {
|
|
1337
|
+
if (menuRef.current && !menuRef.current.contains(event.target) && triggerRef.current && !triggerRef.current.contains(event.target)) {
|
|
1338
|
+
setIsOpen(false);
|
|
1339
|
+
}
|
|
1340
|
+
};
|
|
1341
|
+
if (isOpen) {
|
|
1342
|
+
document.addEventListener("mousedown", handleClickOutside);
|
|
1343
|
+
return () => document.removeEventListener("mousedown", handleClickOutside);
|
|
1344
|
+
}
|
|
1345
|
+
}, [isOpen]);
|
|
1346
|
+
(0, import_react9.useEffect)(() => {
|
|
1347
|
+
if (isOpen && triggerRef.current) {
|
|
1348
|
+
const rect = triggerRef.current.getBoundingClientRect();
|
|
1349
|
+
const menuWidth = 224;
|
|
1350
|
+
const menuHeight = 300;
|
|
1351
|
+
const spacing = 8;
|
|
1352
|
+
let top = 0;
|
|
1353
|
+
let left = 0;
|
|
1354
|
+
switch (placement) {
|
|
1355
|
+
case "top":
|
|
1356
|
+
top = rect.top - menuHeight - spacing;
|
|
1357
|
+
left = position === "left" ? rect.left : rect.right - menuWidth;
|
|
1358
|
+
break;
|
|
1359
|
+
case "bottom":
|
|
1360
|
+
top = rect.bottom + spacing;
|
|
1361
|
+
left = position === "left" ? rect.left : rect.right - menuWidth;
|
|
1362
|
+
break;
|
|
1363
|
+
case "left":
|
|
1364
|
+
top = rect.top;
|
|
1365
|
+
left = rect.left - menuWidth - spacing;
|
|
1366
|
+
break;
|
|
1367
|
+
case "right":
|
|
1368
|
+
top = rect.top;
|
|
1369
|
+
left = rect.right + spacing;
|
|
1370
|
+
break;
|
|
1371
|
+
}
|
|
1372
|
+
setMenuPosition({ top, left });
|
|
1373
|
+
} else {
|
|
1374
|
+
setMenuPosition(null);
|
|
1375
|
+
}
|
|
1376
|
+
}, [isOpen, position, placement]);
|
|
1377
|
+
const handleItemClick = (item) => {
|
|
1378
|
+
if (item.type === "divider") return;
|
|
1379
|
+
if (!item.disabled) {
|
|
1380
|
+
item.onClick();
|
|
1381
|
+
setIsOpen(false);
|
|
1382
|
+
}
|
|
1383
|
+
};
|
|
1384
|
+
const defaultTrigger = /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
|
|
1385
|
+
"button",
|
|
1386
|
+
{
|
|
1387
|
+
className: "p-2 rounded-md hover:bg-gray-100 dark:hover:bg-gray-700 transition-colors",
|
|
1388
|
+
"aria-label": "Open menu",
|
|
1389
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("svg", { className: "w-5 h-5 text-gray-600 dark:text-gray-400", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("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" }) })
|
|
1390
|
+
}
|
|
1391
|
+
);
|
|
1392
|
+
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";
|
|
1393
|
+
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";
|
|
1394
|
+
const menu = isOpen && mounted && menuPosition ? /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
|
|
1395
|
+
"div",
|
|
1396
|
+
{
|
|
1397
|
+
ref: menuRef,
|
|
1398
|
+
className: `fixed w-56 rounded-lg ${menuBaseStyles} z-[9999] max-h-[80vh] overflow-auto`,
|
|
1399
|
+
style: {
|
|
1400
|
+
minWidth: "14rem",
|
|
1401
|
+
top: `${menuPosition.top}px`,
|
|
1402
|
+
left: `${menuPosition.left}px`
|
|
1403
|
+
},
|
|
1404
|
+
children: items.map((item, index) => {
|
|
1405
|
+
if (item.type === "divider") {
|
|
1406
|
+
return /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
|
|
1407
|
+
"div",
|
|
1408
|
+
{
|
|
1409
|
+
className: "my-1 border-t border-gray-200 dark:border-gray-700"
|
|
1410
|
+
},
|
|
1411
|
+
index
|
|
1412
|
+
);
|
|
1413
|
+
}
|
|
1414
|
+
return /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)(
|
|
1415
|
+
"button",
|
|
304
1416
|
{
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
1417
|
+
onClick: () => handleItemClick(item),
|
|
1418
|
+
disabled: item.disabled,
|
|
1419
|
+
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" : ""}`,
|
|
1420
|
+
children: [
|
|
1421
|
+
item.icon && /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { className: "flex-shrink-0", children: item.icon }),
|
|
1422
|
+
/* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { className: "flex-1", children: item.label })
|
|
1423
|
+
]
|
|
308
1424
|
},
|
|
309
|
-
|
|
310
|
-
)
|
|
1425
|
+
index
|
|
1426
|
+
);
|
|
1427
|
+
})
|
|
1428
|
+
}
|
|
1429
|
+
) : null;
|
|
1430
|
+
return /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)(import_jsx_runtime42.Fragment, { children: [
|
|
1431
|
+
/* @__PURE__ */ (0, import_jsx_runtime42.jsx)("div", { className: "relative inline-block", ref: triggerRef, children: /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("div", { onClick: () => setIsOpen(!isOpen), children: trigger || defaultTrigger }) }),
|
|
1432
|
+
mounted && (0, import_react_dom.createPortal)(menu, document.body)
|
|
1433
|
+
] });
|
|
1434
|
+
};
|
|
1435
|
+
|
|
1436
|
+
// src/components/Card.tsx
|
|
1437
|
+
var import_jsx_runtime43 = require("react/jsx-runtime");
|
|
1438
|
+
var paddingClasses = {
|
|
1439
|
+
none: "",
|
|
1440
|
+
sm: "p-4",
|
|
1441
|
+
md: "p-6",
|
|
1442
|
+
lg: "p-8"
|
|
1443
|
+
};
|
|
1444
|
+
var Card = ({
|
|
1445
|
+
children,
|
|
1446
|
+
className = "",
|
|
1447
|
+
padding = "md",
|
|
1448
|
+
hover = false,
|
|
1449
|
+
...props
|
|
1450
|
+
}) => {
|
|
1451
|
+
const { theme } = useTheme();
|
|
1452
|
+
const paddingClass = paddingClasses[padding];
|
|
1453
|
+
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" : "";
|
|
1454
|
+
return /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
|
|
1455
|
+
"div",
|
|
1456
|
+
{
|
|
1457
|
+
className: `bg-white dark:bg-gray-800 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700 ${paddingClass} ${hoverClass} ${className}`,
|
|
1458
|
+
...props,
|
|
1459
|
+
children
|
|
1460
|
+
}
|
|
1461
|
+
);
|
|
1462
|
+
};
|
|
1463
|
+
|
|
1464
|
+
// src/components/Alert.tsx
|
|
1465
|
+
var import_jsx_runtime44 = require("react/jsx-runtime");
|
|
1466
|
+
var variantStyles = {
|
|
1467
|
+
info: "bg-blue-50 dark:bg-blue-900/20 border-blue-200 dark:border-blue-800 text-blue-900 dark:text-blue-100",
|
|
1468
|
+
success: "bg-green-50 dark:bg-green-900/20 border-green-200 dark:border-green-800 text-green-900 dark:text-green-100",
|
|
1469
|
+
warning: "bg-yellow-50 dark:bg-yellow-900/20 border-yellow-200 dark:border-yellow-800 text-yellow-900 dark:text-yellow-100",
|
|
1470
|
+
error: "bg-red-50 dark:bg-red-900/20 border-red-200 dark:border-red-800 text-red-900 dark:text-red-100"
|
|
1471
|
+
};
|
|
1472
|
+
var iconStyles = {
|
|
1473
|
+
info: "text-blue-600 dark:text-blue-400",
|
|
1474
|
+
success: "text-green-600 dark:text-green-400",
|
|
1475
|
+
warning: "text-yellow-600 dark:text-yellow-400",
|
|
1476
|
+
error: "text-red-600 dark:text-red-400"
|
|
1477
|
+
};
|
|
1478
|
+
var Alert = ({
|
|
1479
|
+
variant = "info",
|
|
1480
|
+
title,
|
|
1481
|
+
children,
|
|
1482
|
+
onClose,
|
|
1483
|
+
className = ""
|
|
1484
|
+
}) => {
|
|
1485
|
+
const { theme } = useTheme();
|
|
1486
|
+
const variantClass = variantStyles[variant];
|
|
1487
|
+
const iconClass = iconStyles[variant];
|
|
1488
|
+
return /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("div", { className: `rounded-lg border p-4 ${variantClass} ${className}`, role: "alert", children: /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("div", { className: "flex items-start gap-3", children: [
|
|
1489
|
+
/* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("div", { className: `flex-shrink-0 ${iconClass}`, children: [
|
|
1490
|
+
variant === "info" && /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("svg", { className: "w-5 h-5", fill: "currentColor", viewBox: "0 0 20 20", children: /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("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" }) }),
|
|
1491
|
+
variant === "success" && /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("svg", { className: "w-5 h-5", fill: "currentColor", viewBox: "0 0 20 20", children: /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("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" }) }),
|
|
1492
|
+
variant === "warning" && /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("svg", { className: "w-5 h-5", fill: "currentColor", viewBox: "0 0 20 20", children: /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("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" }) }),
|
|
1493
|
+
variant === "error" && /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("svg", { className: "w-5 h-5", fill: "currentColor", viewBox: "0 0 20 20", children: /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("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" }) })
|
|
1494
|
+
] }),
|
|
1495
|
+
/* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("div", { className: "flex-1", children: [
|
|
1496
|
+
title && /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("h3", { className: "font-semibold mb-1", children: title }),
|
|
1497
|
+
/* @__PURE__ */ (0, import_jsx_runtime44.jsx)("div", { className: "text-sm", children })
|
|
1498
|
+
] }),
|
|
1499
|
+
onClose && /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
|
|
1500
|
+
"button",
|
|
1501
|
+
{
|
|
1502
|
+
onClick: onClose,
|
|
1503
|
+
className: `flex-shrink-0 ${iconClass} hover:opacity-70 transition-opacity`,
|
|
1504
|
+
"aria-label": "Close alert",
|
|
1505
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("svg", { className: "w-5 h-5", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M6 18L18 6M6 6l12 12" }) })
|
|
311
1506
|
}
|
|
312
1507
|
)
|
|
1508
|
+
] }) });
|
|
1509
|
+
};
|
|
1510
|
+
|
|
1511
|
+
// src/components/Checkbox.tsx
|
|
1512
|
+
var import_react10 = require("react");
|
|
1513
|
+
var import_jsx_runtime45 = require("react/jsx-runtime");
|
|
1514
|
+
var Checkbox = (0, import_react10.forwardRef)(
|
|
1515
|
+
({ label, error, className = "", disabled, checked, ...props }, ref) => {
|
|
1516
|
+
const { theme } = useTheme();
|
|
1517
|
+
return /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("div", { className, children: [
|
|
1518
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("label", { className: "flex items-center gap-2 cursor-pointer group", children: [
|
|
1519
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("div", { className: "relative inline-flex items-center", children: [
|
|
1520
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
|
|
1521
|
+
"input",
|
|
1522
|
+
{
|
|
1523
|
+
ref,
|
|
1524
|
+
type: "checkbox",
|
|
1525
|
+
disabled,
|
|
1526
|
+
checked,
|
|
1527
|
+
className: "sr-only peer",
|
|
1528
|
+
...props
|
|
1529
|
+
}
|
|
1530
|
+
),
|
|
1531
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("div", { className: `w-4 h-4 border-2 rounded transition-all duration-200 flex items-center justify-center
|
|
1532
|
+
${error ? "border-red-500 dark:border-red-500" : "border-gray-300 dark:border-gray-600"}
|
|
1533
|
+
${disabled ? "opacity-50 cursor-not-allowed bg-gray-100 dark:bg-gray-800" : "peer-hover:border-gray-400 dark:peer-hover:border-gray-500"}
|
|
1534
|
+
peer-checked:bg-blue-600 peer-checked:border-blue-600
|
|
1535
|
+
peer-focus:ring-2 peer-focus:ring-blue-500 peer-focus:ring-offset-2
|
|
1536
|
+
`, children: /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
|
|
1537
|
+
"svg",
|
|
1538
|
+
{
|
|
1539
|
+
className: `w-3 h-3 text-white transition-opacity duration-200 ${checked ? "opacity-100" : "opacity-0"}`,
|
|
1540
|
+
viewBox: "0 0 12 12",
|
|
1541
|
+
fill: "none",
|
|
1542
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
1543
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
|
|
1544
|
+
"path",
|
|
1545
|
+
{
|
|
1546
|
+
d: "M10 3L4.5 8.5L2 6",
|
|
1547
|
+
stroke: "currentColor",
|
|
1548
|
+
strokeWidth: "2",
|
|
1549
|
+
strokeLinecap: "round",
|
|
1550
|
+
strokeLinejoin: "round"
|
|
1551
|
+
}
|
|
1552
|
+
)
|
|
1553
|
+
}
|
|
1554
|
+
) })
|
|
1555
|
+
] }),
|
|
1556
|
+
label && /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("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 })
|
|
1557
|
+
] }),
|
|
1558
|
+
error && /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("p", { className: "mt-1 text-sm text-red-600 dark:text-red-400", children: error })
|
|
1559
|
+
] });
|
|
1560
|
+
}
|
|
1561
|
+
);
|
|
1562
|
+
Checkbox.displayName = "Checkbox";
|
|
1563
|
+
|
|
1564
|
+
// src/components/Toggle.tsx
|
|
1565
|
+
var import_react11 = require("react");
|
|
1566
|
+
var import_jsx_runtime46 = require("react/jsx-runtime");
|
|
1567
|
+
var Toggle = (0, import_react11.forwardRef)(
|
|
1568
|
+
({ label, size = "md", className = "", disabled, checked, ...props }, ref) => {
|
|
1569
|
+
const { theme } = useTheme();
|
|
1570
|
+
const toggleClasses = {
|
|
1571
|
+
sm: {
|
|
1572
|
+
switch: "w-9 h-5",
|
|
1573
|
+
thumb: "w-4 h-4 peer-checked:translate-x-4"
|
|
1574
|
+
},
|
|
1575
|
+
md: {
|
|
1576
|
+
switch: "w-11 h-6",
|
|
1577
|
+
thumb: "w-5 h-5 peer-checked:translate-x-5"
|
|
1578
|
+
},
|
|
1579
|
+
lg: {
|
|
1580
|
+
switch: "w-14 h-7",
|
|
1581
|
+
thumb: "w-6 h-6 peer-checked:translate-x-7"
|
|
1582
|
+
}
|
|
1583
|
+
};
|
|
1584
|
+
const currentSize = toggleClasses[size];
|
|
1585
|
+
return /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("label", { className: `inline-flex items-center gap-3 cursor-pointer ${disabled ? "opacity-50 cursor-not-allowed" : ""} ${className}`, children: [
|
|
1586
|
+
/* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("div", { className: "relative", children: [
|
|
1587
|
+
/* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
|
|
1588
|
+
"input",
|
|
1589
|
+
{
|
|
1590
|
+
ref,
|
|
1591
|
+
type: "checkbox",
|
|
1592
|
+
className: "sr-only peer",
|
|
1593
|
+
disabled,
|
|
1594
|
+
checked,
|
|
1595
|
+
...props
|
|
1596
|
+
}
|
|
1597
|
+
),
|
|
1598
|
+
/* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
|
|
1599
|
+
"div",
|
|
1600
|
+
{
|
|
1601
|
+
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`
|
|
1602
|
+
}
|
|
1603
|
+
),
|
|
1604
|
+
/* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
|
|
1605
|
+
"div",
|
|
1606
|
+
{
|
|
1607
|
+
className: `${currentSize.thumb} bg-white rounded-full shadow-md absolute top-0.5 left-0.5 transition-transform`
|
|
1608
|
+
}
|
|
1609
|
+
)
|
|
1610
|
+
] }),
|
|
1611
|
+
label && /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("span", { className: "text-sm font-medium text-gray-700 dark:text-gray-300", children: label })
|
|
1612
|
+
] });
|
|
1613
|
+
}
|
|
1614
|
+
);
|
|
1615
|
+
Toggle.displayName = "Toggle";
|
|
1616
|
+
|
|
1617
|
+
// src/components/Badge.tsx
|
|
1618
|
+
var import_jsx_runtime47 = require("react/jsx-runtime");
|
|
1619
|
+
var variantStyles2 = {
|
|
1620
|
+
default: "bg-gray-100 dark:bg-gray-700 text-gray-800 dark:text-gray-200",
|
|
1621
|
+
primary: "bg-blue-100 dark:bg-blue-900/30 text-blue-800 dark:text-blue-200",
|
|
1622
|
+
success: "bg-green-100 dark:bg-green-900/30 text-green-800 dark:text-green-200",
|
|
1623
|
+
warning: "bg-yellow-100 dark:bg-yellow-900/30 text-yellow-800 dark:text-yellow-200",
|
|
1624
|
+
error: "bg-red-100 dark:bg-red-900/30 text-red-800 dark:text-red-200",
|
|
1625
|
+
info: "bg-cyan-100 dark:bg-cyan-900/30 text-cyan-800 dark:text-cyan-200"
|
|
1626
|
+
};
|
|
1627
|
+
var sizeStyles = {
|
|
1628
|
+
sm: "px-2 py-0.5 text-xs",
|
|
1629
|
+
md: "px-2.5 py-1 text-sm",
|
|
1630
|
+
lg: "px-3 py-1.5 text-base"
|
|
1631
|
+
};
|
|
1632
|
+
var Badge = ({
|
|
1633
|
+
children,
|
|
1634
|
+
variant = "default",
|
|
1635
|
+
size = "md",
|
|
1636
|
+
className = ""
|
|
1637
|
+
}) => {
|
|
1638
|
+
const { theme } = useTheme();
|
|
1639
|
+
const variantClass = variantStyles2[variant];
|
|
1640
|
+
const sizeClass = sizeStyles[size];
|
|
1641
|
+
return /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("span", { className: `inline-flex items-center font-medium rounded-full ${variantClass} ${sizeClass} ${className}`, children });
|
|
1642
|
+
};
|
|
1643
|
+
|
|
1644
|
+
// src/components/Spinner.tsx
|
|
1645
|
+
var import_jsx_runtime48 = require("react/jsx-runtime");
|
|
1646
|
+
var sizeClasses6 = {
|
|
1647
|
+
sm: "w-4 h-4 border-2",
|
|
1648
|
+
md: "w-8 h-8 border-2",
|
|
1649
|
+
lg: "w-12 h-12 border-3",
|
|
1650
|
+
xl: "w-16 h-16 border-4"
|
|
1651
|
+
};
|
|
1652
|
+
var colorClasses = {
|
|
1653
|
+
primary: "border-blue-600 border-t-transparent",
|
|
1654
|
+
secondary: "border-gray-600 border-t-transparent",
|
|
1655
|
+
white: "border-white border-t-transparent"
|
|
1656
|
+
};
|
|
1657
|
+
var Spinner = ({
|
|
1658
|
+
size = "md",
|
|
1659
|
+
color = "primary",
|
|
1660
|
+
className = ""
|
|
1661
|
+
}) => {
|
|
1662
|
+
const { theme } = useTheme();
|
|
1663
|
+
const sizeClass = sizeClasses6[size];
|
|
1664
|
+
const colorClass = colorClasses[color];
|
|
1665
|
+
return /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
|
|
1666
|
+
"div",
|
|
1667
|
+
{
|
|
1668
|
+
className: `inline-block rounded-full animate-spin ${sizeClass} ${colorClass} ${className}`,
|
|
1669
|
+
role: "status",
|
|
1670
|
+
"aria-label": "Loading",
|
|
1671
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("span", { className: "sr-only", children: "Loading..." })
|
|
1672
|
+
}
|
|
1673
|
+
);
|
|
1674
|
+
};
|
|
1675
|
+
|
|
1676
|
+
// src/components/Tabs.tsx
|
|
1677
|
+
var import_react12 = require("react");
|
|
1678
|
+
var import_jsx_runtime49 = require("react/jsx-runtime");
|
|
1679
|
+
var Tabs = ({
|
|
1680
|
+
tabs,
|
|
1681
|
+
defaultIndex = 0,
|
|
1682
|
+
onChange,
|
|
1683
|
+
className = ""
|
|
1684
|
+
}) => {
|
|
1685
|
+
const { theme } = useTheme();
|
|
1686
|
+
const [activeIndex, setActiveIndex] = (0, import_react12.useState)(defaultIndex);
|
|
1687
|
+
const handleTabClick = (index) => {
|
|
1688
|
+
if (tabs[index].disabled) return;
|
|
1689
|
+
setActiveIndex(index);
|
|
1690
|
+
onChange?.(index);
|
|
1691
|
+
};
|
|
1692
|
+
return /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("div", { className, children: [
|
|
1693
|
+
/* @__PURE__ */ (0, import_jsx_runtime49.jsx)("div", { className: "border-b border-gray-200 dark:border-gray-700", children: /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("nav", { className: "flex gap-8 px-6", "aria-label": "Tabs", children: tabs.map((tab, index) => /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(
|
|
1694
|
+
"button",
|
|
1695
|
+
{
|
|
1696
|
+
onClick: () => handleTabClick(index),
|
|
1697
|
+
disabled: tab.disabled,
|
|
1698
|
+
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"}`,
|
|
1699
|
+
"aria-current": activeIndex === index ? "page" : void 0,
|
|
1700
|
+
children: tab.label
|
|
1701
|
+
},
|
|
1702
|
+
index
|
|
1703
|
+
)) }) }),
|
|
1704
|
+
/* @__PURE__ */ (0, import_jsx_runtime49.jsx)("div", { children: tabs[activeIndex]?.content })
|
|
1705
|
+
] });
|
|
1706
|
+
};
|
|
1707
|
+
|
|
1708
|
+
// src/components/Table.tsx
|
|
1709
|
+
var import_jsx_runtime50 = require("react/jsx-runtime");
|
|
1710
|
+
function Table({
|
|
1711
|
+
columns,
|
|
1712
|
+
data,
|
|
1713
|
+
keyField = "id",
|
|
1714
|
+
striped = false,
|
|
1715
|
+
hoverable = true,
|
|
1716
|
+
className = ""
|
|
1717
|
+
}) {
|
|
1718
|
+
const { theme } = useTheme();
|
|
1719
|
+
return /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)("div", { className: `overflow-x-auto ${className}`, children: [
|
|
1720
|
+
/* @__PURE__ */ (0, import_jsx_runtime50.jsxs)("table", { className: "w-full text-left", children: [
|
|
1721
|
+
/* @__PURE__ */ (0, import_jsx_runtime50.jsx)("thead", { className: "bg-gray-50 dark:bg-gray-800 border-b border-gray-200 dark:border-gray-700", children: /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("tr", { children: columns.map((column, colIndex) => {
|
|
1722
|
+
const isLast = colIndex === columns.length - 1;
|
|
1723
|
+
return /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(
|
|
1724
|
+
"th",
|
|
1725
|
+
{
|
|
1726
|
+
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",
|
|
1727
|
+
style: { width: column.width },
|
|
1728
|
+
children: column.title
|
|
1729
|
+
},
|
|
1730
|
+
column.key
|
|
1731
|
+
);
|
|
1732
|
+
}) }) }),
|
|
1733
|
+
/* @__PURE__ */ (0, import_jsx_runtime50.jsx)("tbody", { className: "bg-white dark:bg-gray-900 divide-y divide-gray-200 dark:divide-gray-700", children: data.map((row, rowIndex) => {
|
|
1734
|
+
const rowClasses = [
|
|
1735
|
+
striped && rowIndex % 2 === 1 ? "bg-gray-50 dark:bg-gray-800/50" : "",
|
|
1736
|
+
hoverable ? "hover:bg-gray-100 dark:hover:bg-gray-800 transition-colors" : ""
|
|
1737
|
+
].filter(Boolean).join(" ");
|
|
1738
|
+
return /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(
|
|
1739
|
+
"tr",
|
|
1740
|
+
{
|
|
1741
|
+
className: rowClasses,
|
|
1742
|
+
children: columns.map((column, colIndex) => {
|
|
1743
|
+
const isLast = colIndex === columns.length - 1;
|
|
1744
|
+
return /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(
|
|
1745
|
+
"td",
|
|
1746
|
+
{
|
|
1747
|
+
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",
|
|
1748
|
+
children: column.render ? column.render(row[column.key], row, rowIndex) : row[column.key]
|
|
1749
|
+
},
|
|
1750
|
+
column.key
|
|
1751
|
+
);
|
|
1752
|
+
})
|
|
1753
|
+
},
|
|
1754
|
+
row[keyField] || rowIndex
|
|
1755
|
+
);
|
|
1756
|
+
}) })
|
|
1757
|
+
] }),
|
|
1758
|
+
data.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("div", { className: "text-center py-8 text-gray-500 dark:text-gray-400", children: "No data available" })
|
|
1759
|
+
] });
|
|
1760
|
+
}
|
|
1761
|
+
|
|
1762
|
+
// src/components/Pagination.tsx
|
|
1763
|
+
var import_jsx_runtime51 = require("react/jsx-runtime");
|
|
1764
|
+
var Pagination = ({
|
|
1765
|
+
currentPage,
|
|
1766
|
+
totalPages,
|
|
1767
|
+
onPageChange,
|
|
1768
|
+
siblingCount = 1,
|
|
1769
|
+
className = ""
|
|
1770
|
+
}) => {
|
|
1771
|
+
const { theme } = useTheme();
|
|
1772
|
+
const range = (start, end) => {
|
|
1773
|
+
const length = end - start + 1;
|
|
1774
|
+
return Array.from({ length }, (_, idx) => idx + start);
|
|
1775
|
+
};
|
|
1776
|
+
const paginationRange = () => {
|
|
1777
|
+
const totalPageNumbers = siblingCount + 5;
|
|
1778
|
+
if (totalPageNumbers >= totalPages) {
|
|
1779
|
+
return range(1, totalPages);
|
|
1780
|
+
}
|
|
1781
|
+
const leftSiblingIndex = Math.max(currentPage - siblingCount, 1);
|
|
1782
|
+
const rightSiblingIndex = Math.min(currentPage + siblingCount, totalPages);
|
|
1783
|
+
const shouldShowLeftDots = leftSiblingIndex > 2;
|
|
1784
|
+
const shouldShowRightDots = rightSiblingIndex < totalPages - 2;
|
|
1785
|
+
const firstPageIndex = 1;
|
|
1786
|
+
const lastPageIndex = totalPages;
|
|
1787
|
+
if (!shouldShowLeftDots && shouldShowRightDots) {
|
|
1788
|
+
const leftItemCount = 3 + 2 * siblingCount;
|
|
1789
|
+
const leftRange = range(1, leftItemCount);
|
|
1790
|
+
return [...leftRange, "...", totalPages];
|
|
1791
|
+
}
|
|
1792
|
+
if (shouldShowLeftDots && !shouldShowRightDots) {
|
|
1793
|
+
const rightItemCount = 3 + 2 * siblingCount;
|
|
1794
|
+
const rightRange = range(totalPages - rightItemCount + 1, totalPages);
|
|
1795
|
+
return [firstPageIndex, "...", ...rightRange];
|
|
1796
|
+
}
|
|
1797
|
+
if (shouldShowLeftDots && shouldShowRightDots) {
|
|
1798
|
+
const middleRange = range(leftSiblingIndex, rightSiblingIndex);
|
|
1799
|
+
return [firstPageIndex, "...", ...middleRange, "...", lastPageIndex];
|
|
1800
|
+
}
|
|
1801
|
+
return range(1, totalPages);
|
|
1802
|
+
};
|
|
1803
|
+
const pages = paginationRange();
|
|
1804
|
+
return /* @__PURE__ */ (0, import_jsx_runtime51.jsxs)("nav", { className: `flex items-center gap-1 ${className}`, "aria-label": "Pagination", children: [
|
|
1805
|
+
/* @__PURE__ */ (0, import_jsx_runtime51.jsx)(
|
|
1806
|
+
"button",
|
|
1807
|
+
{
|
|
1808
|
+
onClick: () => onPageChange(currentPage - 1),
|
|
1809
|
+
disabled: currentPage === 1,
|
|
1810
|
+
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",
|
|
1811
|
+
"aria-label": "Previous page",
|
|
1812
|
+
children: "Previous"
|
|
1813
|
+
}
|
|
1814
|
+
),
|
|
1815
|
+
pages.map((page, index) => {
|
|
1816
|
+
if (page === "...") {
|
|
1817
|
+
return /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(
|
|
1818
|
+
"span",
|
|
1819
|
+
{
|
|
1820
|
+
className: "px-3 py-2 text-gray-700 dark:text-gray-300",
|
|
1821
|
+
children: "..."
|
|
1822
|
+
},
|
|
1823
|
+
`dots-${index}`
|
|
1824
|
+
);
|
|
1825
|
+
}
|
|
1826
|
+
return /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(
|
|
1827
|
+
"button",
|
|
1828
|
+
{
|
|
1829
|
+
onClick: () => onPageChange(page),
|
|
1830
|
+
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"}`,
|
|
1831
|
+
"aria-label": `Page ${page}`,
|
|
1832
|
+
"aria-current": currentPage === page ? "page" : void 0,
|
|
1833
|
+
children: page
|
|
1834
|
+
},
|
|
1835
|
+
page
|
|
1836
|
+
);
|
|
1837
|
+
}),
|
|
1838
|
+
/* @__PURE__ */ (0, import_jsx_runtime51.jsx)(
|
|
1839
|
+
"button",
|
|
1840
|
+
{
|
|
1841
|
+
onClick: () => onPageChange(currentPage + 1),
|
|
1842
|
+
disabled: currentPage === totalPages,
|
|
1843
|
+
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",
|
|
1844
|
+
"aria-label": "Next page",
|
|
1845
|
+
children: "Next"
|
|
1846
|
+
}
|
|
1847
|
+
)
|
|
1848
|
+
] });
|
|
1849
|
+
};
|
|
1850
|
+
|
|
1851
|
+
// src/components/DatePicker.tsx
|
|
1852
|
+
var import_react13 = require("react");
|
|
1853
|
+
var import_react_dom2 = require("react-dom");
|
|
1854
|
+
var import_jsx_runtime52 = require("react/jsx-runtime");
|
|
1855
|
+
var DAYS = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
|
|
1856
|
+
var MONTHS = [
|
|
1857
|
+
"January",
|
|
1858
|
+
"February",
|
|
1859
|
+
"March",
|
|
1860
|
+
"April",
|
|
1861
|
+
"May",
|
|
1862
|
+
"June",
|
|
1863
|
+
"July",
|
|
1864
|
+
"August",
|
|
1865
|
+
"September",
|
|
1866
|
+
"October",
|
|
1867
|
+
"November",
|
|
1868
|
+
"December"
|
|
1869
|
+
];
|
|
1870
|
+
var DatePicker = ({
|
|
1871
|
+
label,
|
|
1872
|
+
error,
|
|
1873
|
+
helperText,
|
|
1874
|
+
value,
|
|
1875
|
+
onChange,
|
|
1876
|
+
minDate,
|
|
1877
|
+
maxDate,
|
|
1878
|
+
disabled,
|
|
1879
|
+
className = "",
|
|
1880
|
+
placeholder = "Select date..."
|
|
1881
|
+
}) => {
|
|
1882
|
+
const { theme } = useTheme();
|
|
1883
|
+
const [isOpen, setIsOpen] = (0, import_react13.useState)(false);
|
|
1884
|
+
const [viewDate, setViewDate] = (0, import_react13.useState)(value || /* @__PURE__ */ new Date());
|
|
1885
|
+
const [mounted, setMounted] = (0, import_react13.useState)(false);
|
|
1886
|
+
const [calendarPosition, setCalendarPosition] = (0, import_react13.useState)(null);
|
|
1887
|
+
const inputRef = (0, import_react13.useRef)(null);
|
|
1888
|
+
const calendarRef = (0, import_react13.useRef)(null);
|
|
1889
|
+
(0, import_react13.useEffect)(() => {
|
|
1890
|
+
setMounted(true);
|
|
1891
|
+
}, []);
|
|
1892
|
+
(0, import_react13.useEffect)(() => {
|
|
1893
|
+
const handleClickOutside = (event) => {
|
|
1894
|
+
if (calendarRef.current && !calendarRef.current.contains(event.target) && inputRef.current && !inputRef.current.contains(event.target)) {
|
|
1895
|
+
setIsOpen(false);
|
|
1896
|
+
}
|
|
1897
|
+
};
|
|
1898
|
+
if (isOpen) {
|
|
1899
|
+
document.addEventListener("mousedown", handleClickOutside);
|
|
1900
|
+
return () => document.removeEventListener("mousedown", handleClickOutside);
|
|
1901
|
+
}
|
|
1902
|
+
}, [isOpen]);
|
|
1903
|
+
(0, import_react13.useEffect)(() => {
|
|
1904
|
+
if (isOpen && inputRef.current) {
|
|
1905
|
+
const rect = inputRef.current.getBoundingClientRect();
|
|
1906
|
+
setCalendarPosition({
|
|
1907
|
+
top: rect.bottom + 8,
|
|
1908
|
+
left: rect.left
|
|
1909
|
+
});
|
|
1910
|
+
} else {
|
|
1911
|
+
setCalendarPosition(null);
|
|
1912
|
+
}
|
|
1913
|
+
}, [isOpen]);
|
|
1914
|
+
const year = viewDate.getFullYear();
|
|
1915
|
+
const month = viewDate.getMonth();
|
|
1916
|
+
const firstDayOfMonth = new Date(year, month, 1).getDay();
|
|
1917
|
+
const daysInMonth = new Date(year, month + 1, 0).getDate();
|
|
1918
|
+
const daysInPrevMonth = new Date(year, month, 0).getDate();
|
|
1919
|
+
const calendarDays = [];
|
|
1920
|
+
for (let i = firstDayOfMonth - 1; i >= 0; i--) {
|
|
1921
|
+
calendarDays.push(new Date(year, month - 1, daysInPrevMonth - i));
|
|
1922
|
+
}
|
|
1923
|
+
for (let i = 1; i <= daysInMonth; i++) {
|
|
1924
|
+
calendarDays.push(new Date(year, month, i));
|
|
1925
|
+
}
|
|
1926
|
+
const remainingDays = 42 - calendarDays.length;
|
|
1927
|
+
for (let i = 1; i <= remainingDays; i++) {
|
|
1928
|
+
calendarDays.push(new Date(year, month + 1, i));
|
|
1929
|
+
}
|
|
1930
|
+
const isSameDay = (date1, date2) => {
|
|
1931
|
+
return date1.getDate() === date2.getDate() && date1.getMonth() === date2.getMonth() && date1.getFullYear() === date2.getFullYear();
|
|
1932
|
+
};
|
|
1933
|
+
const isToday = (date) => {
|
|
1934
|
+
return isSameDay(date, /* @__PURE__ */ new Date());
|
|
1935
|
+
};
|
|
1936
|
+
const isSelected = (date) => {
|
|
1937
|
+
return value && isSameDay(date, value);
|
|
1938
|
+
};
|
|
1939
|
+
const isCurrentMonth = (date) => {
|
|
1940
|
+
return date.getMonth() === month;
|
|
1941
|
+
};
|
|
1942
|
+
const isDisabled = (date) => {
|
|
1943
|
+
if (minDate && date < minDate) return true;
|
|
1944
|
+
if (maxDate && date > maxDate) return true;
|
|
1945
|
+
return false;
|
|
1946
|
+
};
|
|
1947
|
+
const handleDateClick = (date) => {
|
|
1948
|
+
if (isDisabled(date)) return;
|
|
1949
|
+
onChange?.(date);
|
|
1950
|
+
setIsOpen(false);
|
|
1951
|
+
};
|
|
1952
|
+
const handlePrevMonth = () => {
|
|
1953
|
+
setViewDate(new Date(year, month - 1, 1));
|
|
1954
|
+
};
|
|
1955
|
+
const handleNextMonth = () => {
|
|
1956
|
+
setViewDate(new Date(year, month + 1, 1));
|
|
1957
|
+
};
|
|
1958
|
+
const handleToday = () => {
|
|
1959
|
+
const today = /* @__PURE__ */ new Date();
|
|
1960
|
+
setViewDate(today);
|
|
1961
|
+
onChange?.(today);
|
|
1962
|
+
setIsOpen(false);
|
|
1963
|
+
};
|
|
1964
|
+
const formatDate = (date) => {
|
|
1965
|
+
if (!date) return "";
|
|
1966
|
+
return date.toLocaleDateString("en-US", {
|
|
1967
|
+
month: "short",
|
|
1968
|
+
day: "numeric",
|
|
1969
|
+
year: "numeric"
|
|
1970
|
+
});
|
|
1971
|
+
};
|
|
1972
|
+
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";
|
|
1973
|
+
const errorStyles = error ? "border-red-500 focus:ring-red-500 dark:border-red-500" : "";
|
|
1974
|
+
const disabledStyles = disabled ? "opacity-50 cursor-not-allowed bg-gray-50 dark:bg-gray-900" : "";
|
|
1975
|
+
const calendar = isOpen && mounted && calendarPosition ? /* @__PURE__ */ (0, import_jsx_runtime52.jsxs)(
|
|
1976
|
+
"div",
|
|
1977
|
+
{
|
|
1978
|
+
ref: calendarRef,
|
|
1979
|
+
className: "fixed z-[9999] bg-white dark:bg-gray-800 rounded-lg border border-gray-200 dark:border-gray-700 shadow-xl p-4",
|
|
1980
|
+
style: {
|
|
1981
|
+
top: `${calendarPosition.top}px`,
|
|
1982
|
+
left: `${calendarPosition.left}px`,
|
|
1983
|
+
minWidth: "320px"
|
|
1984
|
+
},
|
|
1985
|
+
children: [
|
|
1986
|
+
/* @__PURE__ */ (0, import_jsx_runtime52.jsxs)("div", { className: "flex items-center justify-between mb-4", children: [
|
|
1987
|
+
/* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
|
|
1988
|
+
"button",
|
|
1989
|
+
{
|
|
1990
|
+
onClick: handlePrevMonth,
|
|
1991
|
+
className: "p-2 hover:bg-gray-100 dark:hover:bg-gray-700 rounded-lg transition-colors",
|
|
1992
|
+
"aria-label": "Previous month",
|
|
1993
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime52.jsx)("svg", { className: "w-5 h-5 text-gray-600 dark:text-gray-400", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime52.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M15 19l-7-7 7-7" }) })
|
|
1994
|
+
}
|
|
1995
|
+
),
|
|
1996
|
+
/* @__PURE__ */ (0, import_jsx_runtime52.jsxs)("div", { className: "flex items-center gap-2", children: [
|
|
1997
|
+
/* @__PURE__ */ (0, import_jsx_runtime52.jsxs)("h2", { className: "text-base font-semibold text-gray-900 dark:text-gray-100", children: [
|
|
1998
|
+
MONTHS[month],
|
|
1999
|
+
" ",
|
|
2000
|
+
year
|
|
2001
|
+
] }),
|
|
2002
|
+
/* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
|
|
2003
|
+
"button",
|
|
2004
|
+
{
|
|
2005
|
+
onClick: handleToday,
|
|
2006
|
+
className: "px-2 py-1 text-xs bg-blue-600 text-white rounded hover:bg-blue-700 transition-colors",
|
|
2007
|
+
children: "Today"
|
|
2008
|
+
}
|
|
2009
|
+
)
|
|
2010
|
+
] }),
|
|
2011
|
+
/* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
|
|
2012
|
+
"button",
|
|
2013
|
+
{
|
|
2014
|
+
onClick: handleNextMonth,
|
|
2015
|
+
className: "p-2 hover:bg-gray-100 dark:hover:bg-gray-700 rounded-lg transition-colors",
|
|
2016
|
+
"aria-label": "Next month",
|
|
2017
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime52.jsx)("svg", { className: "w-5 h-5 text-gray-600 dark:text-gray-400", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime52.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M9 5l7 7-7 7" }) })
|
|
2018
|
+
}
|
|
2019
|
+
)
|
|
2020
|
+
] }),
|
|
2021
|
+
/* @__PURE__ */ (0, import_jsx_runtime52.jsx)("div", { className: "grid grid-cols-7 gap-1 mb-2", children: DAYS.map((day) => /* @__PURE__ */ (0, import_jsx_runtime52.jsx)("div", { className: "text-center text-xs font-semibold text-gray-600 dark:text-gray-400 py-1", children: day }, day)) }),
|
|
2022
|
+
/* @__PURE__ */ (0, import_jsx_runtime52.jsx)("div", { className: "grid grid-cols-7 gap-1", children: calendarDays.map((date, index) => {
|
|
2023
|
+
const isCurrentMonthDay = isCurrentMonth(date);
|
|
2024
|
+
const isTodayDay = isToday(date);
|
|
2025
|
+
const isSelectedDay = isSelected(date);
|
|
2026
|
+
const isDisabledDay = isDisabled(date);
|
|
2027
|
+
return /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
|
|
2028
|
+
"button",
|
|
2029
|
+
{
|
|
2030
|
+
onClick: () => handleDateClick(date),
|
|
2031
|
+
disabled: isDisabledDay,
|
|
2032
|
+
className: `
|
|
2033
|
+
aspect-square p-1 rounded-lg text-sm font-medium transition-all
|
|
2034
|
+
${!isCurrentMonthDay ? "text-gray-400 dark:text-gray-600" : "text-gray-900 dark:text-gray-100"}
|
|
2035
|
+
${isTodayDay && !isSelectedDay ? "bg-blue-50 dark:bg-blue-900/20 text-blue-600 dark:text-blue-400 font-bold" : ""}
|
|
2036
|
+
${isSelectedDay ? "bg-blue-600 text-white hover:bg-blue-700" : ""}
|
|
2037
|
+
${!isSelectedDay && !isDisabledDay ? "hover:bg-gray-100 dark:hover:bg-gray-700" : ""}
|
|
2038
|
+
${isDisabledDay ? "opacity-30 cursor-not-allowed" : "cursor-pointer"}
|
|
2039
|
+
`,
|
|
2040
|
+
children: date.getDate()
|
|
2041
|
+
},
|
|
2042
|
+
index
|
|
2043
|
+
);
|
|
2044
|
+
}) })
|
|
2045
|
+
]
|
|
2046
|
+
}
|
|
2047
|
+
) : null;
|
|
2048
|
+
return /* @__PURE__ */ (0, import_jsx_runtime52.jsxs)("div", { className, children: [
|
|
2049
|
+
label && /* @__PURE__ */ (0, import_jsx_runtime52.jsx)("label", { className: "block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1", children: label }),
|
|
2050
|
+
/* @__PURE__ */ (0, import_jsx_runtime52.jsxs)(
|
|
2051
|
+
"div",
|
|
2052
|
+
{
|
|
2053
|
+
ref: inputRef,
|
|
2054
|
+
onClick: () => !disabled && setIsOpen(!isOpen),
|
|
2055
|
+
className: `${baseStyles} ${errorStyles} ${disabledStyles} flex items-center justify-between`.trim(),
|
|
2056
|
+
children: [
|
|
2057
|
+
/* @__PURE__ */ (0, import_jsx_runtime52.jsx)("span", { className: !value ? "text-gray-500 dark:text-gray-400" : "", children: value ? formatDate(value) : placeholder }),
|
|
2058
|
+
/* @__PURE__ */ (0, import_jsx_runtime52.jsx)("svg", { className: "w-5 h-5 text-gray-400", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime52.jsx)("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" }) })
|
|
2059
|
+
]
|
|
2060
|
+
}
|
|
2061
|
+
),
|
|
2062
|
+
error && /* @__PURE__ */ (0, import_jsx_runtime52.jsx)("p", { className: "mt-1 text-sm text-red-600 dark:text-red-400", children: error }),
|
|
2063
|
+
helperText && !error && /* @__PURE__ */ (0, import_jsx_runtime52.jsx)("p", { className: "mt-1 text-sm text-gray-500 dark:text-gray-400", children: helperText }),
|
|
2064
|
+
mounted && (0, import_react_dom2.createPortal)(calendar, document.body)
|
|
2065
|
+
] });
|
|
2066
|
+
};
|
|
2067
|
+
DatePicker.displayName = "DatePicker";
|
|
2068
|
+
|
|
2069
|
+
// src/components/TimePicker.tsx
|
|
2070
|
+
var import_react14 = require("react");
|
|
2071
|
+
var import_jsx_runtime53 = require("react/jsx-runtime");
|
|
2072
|
+
var TimePicker = (0, import_react14.forwardRef)(
|
|
2073
|
+
({ label, error, helperText, className = "", disabled, ...props }, ref) => {
|
|
2074
|
+
const { theme } = useTheme();
|
|
2075
|
+
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";
|
|
2076
|
+
const errorStyles = error ? "border-red-500 focus:ring-red-500 dark:border-red-500" : "";
|
|
2077
|
+
const disabledStyles = disabled ? "opacity-50 cursor-not-allowed bg-gray-50 dark:bg-gray-900" : "";
|
|
2078
|
+
return /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)("div", { className, children: [
|
|
2079
|
+
label && /* @__PURE__ */ (0, import_jsx_runtime53.jsx)("label", { className: "block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1", children: label }),
|
|
2080
|
+
/* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
|
|
2081
|
+
"input",
|
|
2082
|
+
{
|
|
2083
|
+
ref,
|
|
2084
|
+
type: "time",
|
|
2085
|
+
disabled,
|
|
2086
|
+
className: `${baseStyles} ${errorStyles} ${disabledStyles}`.trim(),
|
|
2087
|
+
...props
|
|
2088
|
+
}
|
|
2089
|
+
),
|
|
2090
|
+
error && /* @__PURE__ */ (0, import_jsx_runtime53.jsx)("p", { className: "mt-1 text-sm text-red-600 dark:text-red-400", children: error }),
|
|
2091
|
+
helperText && !error && /* @__PURE__ */ (0, import_jsx_runtime53.jsx)("p", { className: "mt-1 text-sm text-gray-500 dark:text-gray-400", children: helperText })
|
|
2092
|
+
] });
|
|
2093
|
+
}
|
|
2094
|
+
);
|
|
2095
|
+
TimePicker.displayName = "TimePicker";
|
|
2096
|
+
|
|
2097
|
+
// src/components/DateTimePicker.tsx
|
|
2098
|
+
var import_react15 = require("react");
|
|
2099
|
+
var import_react_dom3 = require("react-dom");
|
|
2100
|
+
var import_jsx_runtime54 = require("react/jsx-runtime");
|
|
2101
|
+
var DAYS2 = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
|
|
2102
|
+
var MONTHS2 = [
|
|
2103
|
+
"January",
|
|
2104
|
+
"February",
|
|
2105
|
+
"March",
|
|
2106
|
+
"April",
|
|
2107
|
+
"May",
|
|
2108
|
+
"June",
|
|
2109
|
+
"July",
|
|
2110
|
+
"August",
|
|
2111
|
+
"September",
|
|
2112
|
+
"October",
|
|
2113
|
+
"November",
|
|
2114
|
+
"December"
|
|
2115
|
+
];
|
|
2116
|
+
var DateTimePicker = ({
|
|
2117
|
+
label,
|
|
2118
|
+
error,
|
|
2119
|
+
helperText,
|
|
2120
|
+
value,
|
|
2121
|
+
onChange,
|
|
2122
|
+
minDate,
|
|
2123
|
+
maxDate,
|
|
2124
|
+
disabled,
|
|
2125
|
+
className = "",
|
|
2126
|
+
placeholder = "Select date and time..."
|
|
2127
|
+
}) => {
|
|
2128
|
+
const { theme } = useTheme();
|
|
2129
|
+
const [isOpen, setIsOpen] = (0, import_react15.useState)(false);
|
|
2130
|
+
const [viewDate, setViewDate] = (0, import_react15.useState)(value || /* @__PURE__ */ new Date());
|
|
2131
|
+
const [selectedTime, setSelectedTime] = (0, import_react15.useState)(
|
|
2132
|
+
value ? { hours: value.getHours(), minutes: value.getMinutes() } : { hours: 12, minutes: 0 }
|
|
2133
|
+
);
|
|
2134
|
+
const [mounted, setMounted] = (0, import_react15.useState)(false);
|
|
2135
|
+
const [pickerPosition, setPickerPosition] = (0, import_react15.useState)(null);
|
|
2136
|
+
const inputRef = (0, import_react15.useRef)(null);
|
|
2137
|
+
const pickerRef = (0, import_react15.useRef)(null);
|
|
2138
|
+
(0, import_react15.useEffect)(() => {
|
|
2139
|
+
setMounted(true);
|
|
2140
|
+
}, []);
|
|
2141
|
+
(0, import_react15.useEffect)(() => {
|
|
2142
|
+
const handleClickOutside = (event) => {
|
|
2143
|
+
if (pickerRef.current && !pickerRef.current.contains(event.target) && inputRef.current && !inputRef.current.contains(event.target)) {
|
|
2144
|
+
setIsOpen(false);
|
|
2145
|
+
}
|
|
2146
|
+
};
|
|
2147
|
+
if (isOpen) {
|
|
2148
|
+
document.addEventListener("mousedown", handleClickOutside);
|
|
2149
|
+
return () => document.removeEventListener("mousedown", handleClickOutside);
|
|
2150
|
+
}
|
|
2151
|
+
}, [isOpen]);
|
|
2152
|
+
(0, import_react15.useEffect)(() => {
|
|
2153
|
+
if (isOpen && inputRef.current) {
|
|
2154
|
+
const rect = inputRef.current.getBoundingClientRect();
|
|
2155
|
+
setPickerPosition({
|
|
2156
|
+
top: rect.bottom + 8,
|
|
2157
|
+
left: rect.left
|
|
2158
|
+
});
|
|
2159
|
+
} else {
|
|
2160
|
+
setPickerPosition(null);
|
|
2161
|
+
}
|
|
2162
|
+
}, [isOpen]);
|
|
2163
|
+
const year = viewDate.getFullYear();
|
|
2164
|
+
const month = viewDate.getMonth();
|
|
2165
|
+
const firstDayOfMonth = new Date(year, month, 1).getDay();
|
|
2166
|
+
const daysInMonth = new Date(year, month + 1, 0).getDate();
|
|
2167
|
+
const daysInPrevMonth = new Date(year, month, 0).getDate();
|
|
2168
|
+
const calendarDays = [];
|
|
2169
|
+
for (let i = firstDayOfMonth - 1; i >= 0; i--) {
|
|
2170
|
+
calendarDays.push(new Date(year, month - 1, daysInPrevMonth - i));
|
|
2171
|
+
}
|
|
2172
|
+
for (let i = 1; i <= daysInMonth; i++) {
|
|
2173
|
+
calendarDays.push(new Date(year, month, i));
|
|
2174
|
+
}
|
|
2175
|
+
const remainingDays = 42 - calendarDays.length;
|
|
2176
|
+
for (let i = 1; i <= remainingDays; i++) {
|
|
2177
|
+
calendarDays.push(new Date(year, month + 1, i));
|
|
2178
|
+
}
|
|
2179
|
+
const isSameDay = (date1, date2) => {
|
|
2180
|
+
return date1.getDate() === date2.getDate() && date1.getMonth() === date2.getMonth() && date1.getFullYear() === date2.getFullYear();
|
|
2181
|
+
};
|
|
2182
|
+
const isToday = (date) => {
|
|
2183
|
+
return isSameDay(date, /* @__PURE__ */ new Date());
|
|
2184
|
+
};
|
|
2185
|
+
const isSelected = (date) => {
|
|
2186
|
+
return value && isSameDay(date, value);
|
|
2187
|
+
};
|
|
2188
|
+
const isCurrentMonth = (date) => {
|
|
2189
|
+
return date.getMonth() === month;
|
|
2190
|
+
};
|
|
2191
|
+
const isDisabled = (date) => {
|
|
2192
|
+
if (minDate && date < minDate) return true;
|
|
2193
|
+
if (maxDate && date > maxDate) return true;
|
|
2194
|
+
return false;
|
|
2195
|
+
};
|
|
2196
|
+
const handleDateClick = (date) => {
|
|
2197
|
+
if (isDisabled(date)) return;
|
|
2198
|
+
const newDateTime = new Date(
|
|
2199
|
+
date.getFullYear(),
|
|
2200
|
+
date.getMonth(),
|
|
2201
|
+
date.getDate(),
|
|
2202
|
+
selectedTime.hours,
|
|
2203
|
+
selectedTime.minutes
|
|
2204
|
+
);
|
|
2205
|
+
onChange?.(newDateTime);
|
|
2206
|
+
};
|
|
2207
|
+
const handleTimeChange = (hours, minutes) => {
|
|
2208
|
+
setSelectedTime({ hours, minutes });
|
|
2209
|
+
if (value) {
|
|
2210
|
+
const newDateTime = new Date(
|
|
2211
|
+
value.getFullYear(),
|
|
2212
|
+
value.getMonth(),
|
|
2213
|
+
value.getDate(),
|
|
2214
|
+
hours,
|
|
2215
|
+
minutes
|
|
2216
|
+
);
|
|
2217
|
+
onChange?.(newDateTime);
|
|
2218
|
+
}
|
|
2219
|
+
};
|
|
2220
|
+
const handleDone = () => {
|
|
2221
|
+
if (value) {
|
|
2222
|
+
setIsOpen(false);
|
|
2223
|
+
}
|
|
2224
|
+
};
|
|
2225
|
+
const handlePrevMonth = () => {
|
|
2226
|
+
setViewDate(new Date(year, month - 1, 1));
|
|
2227
|
+
};
|
|
2228
|
+
const handleNextMonth = () => {
|
|
2229
|
+
setViewDate(new Date(year, month + 1, 1));
|
|
2230
|
+
};
|
|
2231
|
+
const handleToday = () => {
|
|
2232
|
+
const now = /* @__PURE__ */ new Date();
|
|
2233
|
+
setViewDate(now);
|
|
2234
|
+
setSelectedTime({ hours: now.getHours(), minutes: now.getMinutes() });
|
|
2235
|
+
onChange?.(now);
|
|
2236
|
+
};
|
|
2237
|
+
const formatDateTime = (date) => {
|
|
2238
|
+
if (!date) return "";
|
|
2239
|
+
return date.toLocaleString("en-US", {
|
|
2240
|
+
month: "short",
|
|
2241
|
+
day: "numeric",
|
|
2242
|
+
year: "numeric",
|
|
2243
|
+
hour: "numeric",
|
|
2244
|
+
minute: "2-digit",
|
|
2245
|
+
hour12: true
|
|
2246
|
+
});
|
|
2247
|
+
};
|
|
2248
|
+
const formatTime = (hours, minutes) => {
|
|
2249
|
+
const period = hours >= 12 ? "PM" : "AM";
|
|
2250
|
+
const displayHours = hours % 12 || 12;
|
|
2251
|
+
const displayMinutes = minutes.toString().padStart(2, "0");
|
|
2252
|
+
return `${displayHours}:${displayMinutes} ${period}`;
|
|
2253
|
+
};
|
|
2254
|
+
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";
|
|
2255
|
+
const errorStyles = error ? "border-red-500 focus:ring-red-500 dark:border-red-500" : "";
|
|
2256
|
+
const disabledStyles = disabled ? "opacity-50 cursor-not-allowed bg-gray-50 dark:bg-gray-900" : "";
|
|
2257
|
+
const picker = isOpen && mounted && pickerPosition ? /* @__PURE__ */ (0, import_jsx_runtime54.jsxs)(
|
|
2258
|
+
"div",
|
|
2259
|
+
{
|
|
2260
|
+
ref: pickerRef,
|
|
2261
|
+
className: "fixed z-[9999] bg-white dark:bg-gray-800 rounded-lg border border-gray-200 dark:border-gray-700 shadow-xl p-4",
|
|
2262
|
+
style: {
|
|
2263
|
+
top: `${pickerPosition.top}px`,
|
|
2264
|
+
left: `${pickerPosition.left}px`,
|
|
2265
|
+
minWidth: "360px"
|
|
2266
|
+
},
|
|
2267
|
+
children: [
|
|
2268
|
+
/* @__PURE__ */ (0, import_jsx_runtime54.jsxs)("div", { className: "flex items-center justify-between mb-4", children: [
|
|
2269
|
+
/* @__PURE__ */ (0, import_jsx_runtime54.jsx)(
|
|
2270
|
+
"button",
|
|
2271
|
+
{
|
|
2272
|
+
onClick: handlePrevMonth,
|
|
2273
|
+
className: "p-2 hover:bg-gray-100 dark:hover:bg-gray-700 rounded-lg transition-colors",
|
|
2274
|
+
"aria-label": "Previous month",
|
|
2275
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime54.jsx)("svg", { className: "w-5 h-5 text-gray-600 dark:text-gray-400", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime54.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M15 19l-7-7 7-7" }) })
|
|
2276
|
+
}
|
|
2277
|
+
),
|
|
2278
|
+
/* @__PURE__ */ (0, import_jsx_runtime54.jsxs)("div", { className: "flex items-center gap-2", children: [
|
|
2279
|
+
/* @__PURE__ */ (0, import_jsx_runtime54.jsxs)("h2", { className: "text-base font-semibold text-gray-900 dark:text-gray-100", children: [
|
|
2280
|
+
MONTHS2[month],
|
|
2281
|
+
" ",
|
|
2282
|
+
year
|
|
2283
|
+
] }),
|
|
2284
|
+
/* @__PURE__ */ (0, import_jsx_runtime54.jsx)(
|
|
2285
|
+
"button",
|
|
2286
|
+
{
|
|
2287
|
+
onClick: handleToday,
|
|
2288
|
+
className: "px-2 py-1 text-xs bg-blue-600 text-white rounded hover:bg-blue-700 transition-colors",
|
|
2289
|
+
children: "Now"
|
|
2290
|
+
}
|
|
2291
|
+
)
|
|
2292
|
+
] }),
|
|
2293
|
+
/* @__PURE__ */ (0, import_jsx_runtime54.jsx)(
|
|
2294
|
+
"button",
|
|
2295
|
+
{
|
|
2296
|
+
onClick: handleNextMonth,
|
|
2297
|
+
className: "p-2 hover:bg-gray-100 dark:hover:bg-gray-700 rounded-lg transition-colors",
|
|
2298
|
+
"aria-label": "Next month",
|
|
2299
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime54.jsx)("svg", { className: "w-5 h-5 text-gray-600 dark:text-gray-400", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime54.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M9 5l7 7-7 7" }) })
|
|
2300
|
+
}
|
|
2301
|
+
)
|
|
2302
|
+
] }),
|
|
2303
|
+
/* @__PURE__ */ (0, import_jsx_runtime54.jsx)("div", { className: "grid grid-cols-7 gap-1 mb-2", children: DAYS2.map((day) => /* @__PURE__ */ (0, import_jsx_runtime54.jsx)("div", { className: "text-center text-xs font-semibold text-gray-600 dark:text-gray-400 py-1", children: day }, day)) }),
|
|
2304
|
+
/* @__PURE__ */ (0, import_jsx_runtime54.jsx)("div", { className: "grid grid-cols-7 gap-1 mb-4", children: calendarDays.map((date, index) => {
|
|
2305
|
+
const isCurrentMonthDay = isCurrentMonth(date);
|
|
2306
|
+
const isTodayDay = isToday(date);
|
|
2307
|
+
const isSelectedDay = isSelected(date);
|
|
2308
|
+
const isDisabledDay = isDisabled(date);
|
|
2309
|
+
return /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(
|
|
2310
|
+
"button",
|
|
2311
|
+
{
|
|
2312
|
+
onClick: () => handleDateClick(date),
|
|
2313
|
+
disabled: isDisabledDay,
|
|
2314
|
+
className: `
|
|
2315
|
+
aspect-square p-1 rounded-lg text-sm font-medium transition-all
|
|
2316
|
+
${!isCurrentMonthDay ? "text-gray-400 dark:text-gray-600" : "text-gray-900 dark:text-gray-100"}
|
|
2317
|
+
${isTodayDay && !isSelectedDay ? "bg-blue-50 dark:bg-blue-900/20 text-blue-600 dark:text-blue-400 font-bold" : ""}
|
|
2318
|
+
${isSelectedDay ? "bg-blue-600 text-white hover:bg-blue-700" : ""}
|
|
2319
|
+
${!isSelectedDay && !isDisabledDay ? "hover:bg-gray-100 dark:hover:bg-gray-700" : ""}
|
|
2320
|
+
${isDisabledDay ? "opacity-30 cursor-not-allowed" : "cursor-pointer"}
|
|
2321
|
+
`,
|
|
2322
|
+
children: date.getDate()
|
|
2323
|
+
},
|
|
2324
|
+
index
|
|
2325
|
+
);
|
|
2326
|
+
}) }),
|
|
2327
|
+
/* @__PURE__ */ (0, import_jsx_runtime54.jsxs)("div", { className: "border-t border-gray-200 dark:border-gray-700 pt-4", children: [
|
|
2328
|
+
/* @__PURE__ */ (0, import_jsx_runtime54.jsxs)("div", { className: "flex items-center justify-center gap-4 mb-4", children: [
|
|
2329
|
+
/* @__PURE__ */ (0, import_jsx_runtime54.jsxs)("div", { className: "flex flex-col items-center", children: [
|
|
2330
|
+
/* @__PURE__ */ (0, import_jsx_runtime54.jsx)("label", { className: "text-xs font-semibold text-gray-600 dark:text-gray-400 mb-2", children: "Hour" }),
|
|
2331
|
+
/* @__PURE__ */ (0, import_jsx_runtime54.jsxs)("div", { className: "flex flex-col items-center gap-1", children: [
|
|
2332
|
+
/* @__PURE__ */ (0, import_jsx_runtime54.jsx)(
|
|
2333
|
+
"button",
|
|
2334
|
+
{
|
|
2335
|
+
type: "button",
|
|
2336
|
+
onClick: () => handleTimeChange((selectedTime.hours + 1) % 24, selectedTime.minutes),
|
|
2337
|
+
className: "p-1 hover:bg-gray-100 dark:hover:bg-gray-700 rounded transition-colors",
|
|
2338
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime54.jsx)("svg", { className: "w-4 h-4 text-gray-600 dark:text-gray-400", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime54.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M5 15l7-7 7 7" }) })
|
|
2339
|
+
}
|
|
2340
|
+
),
|
|
2341
|
+
/* @__PURE__ */ (0, import_jsx_runtime54.jsx)(
|
|
2342
|
+
"input",
|
|
2343
|
+
{
|
|
2344
|
+
type: "number",
|
|
2345
|
+
min: "0",
|
|
2346
|
+
max: "23",
|
|
2347
|
+
value: selectedTime.hours,
|
|
2348
|
+
onChange: (e) => {
|
|
2349
|
+
const val = parseInt(e.target.value);
|
|
2350
|
+
if (!isNaN(val) && val >= 0 && val <= 23) {
|
|
2351
|
+
handleTimeChange(val, selectedTime.minutes);
|
|
2352
|
+
}
|
|
2353
|
+
},
|
|
2354
|
+
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"
|
|
2355
|
+
}
|
|
2356
|
+
),
|
|
2357
|
+
/* @__PURE__ */ (0, import_jsx_runtime54.jsx)(
|
|
2358
|
+
"button",
|
|
2359
|
+
{
|
|
2360
|
+
type: "button",
|
|
2361
|
+
onClick: () => handleTimeChange((selectedTime.hours - 1 + 24) % 24, selectedTime.minutes),
|
|
2362
|
+
className: "p-1 hover:bg-gray-100 dark:hover:bg-gray-700 rounded transition-colors",
|
|
2363
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime54.jsx)("svg", { className: "w-4 h-4 text-gray-600 dark:text-gray-400", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime54.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M19 9l-7 7-7-7" }) })
|
|
2364
|
+
}
|
|
2365
|
+
)
|
|
2366
|
+
] })
|
|
2367
|
+
] }),
|
|
2368
|
+
/* @__PURE__ */ (0, import_jsx_runtime54.jsx)("span", { className: "text-2xl font-bold text-gray-600 dark:text-gray-400 mt-8", children: ":" }),
|
|
2369
|
+
/* @__PURE__ */ (0, import_jsx_runtime54.jsxs)("div", { className: "flex flex-col items-center", children: [
|
|
2370
|
+
/* @__PURE__ */ (0, import_jsx_runtime54.jsx)("label", { className: "text-xs font-semibold text-gray-600 dark:text-gray-400 mb-2", children: "Minute" }),
|
|
2371
|
+
/* @__PURE__ */ (0, import_jsx_runtime54.jsxs)("div", { className: "flex flex-col items-center gap-1", children: [
|
|
2372
|
+
/* @__PURE__ */ (0, import_jsx_runtime54.jsx)(
|
|
2373
|
+
"button",
|
|
2374
|
+
{
|
|
2375
|
+
type: "button",
|
|
2376
|
+
onClick: () => handleTimeChange(selectedTime.hours, (selectedTime.minutes + 1) % 60),
|
|
2377
|
+
className: "p-1 hover:bg-gray-100 dark:hover:bg-gray-700 rounded transition-colors",
|
|
2378
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime54.jsx)("svg", { className: "w-4 h-4 text-gray-600 dark:text-gray-400", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime54.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M5 15l7-7 7 7" }) })
|
|
2379
|
+
}
|
|
2380
|
+
),
|
|
2381
|
+
/* @__PURE__ */ (0, import_jsx_runtime54.jsx)(
|
|
2382
|
+
"input",
|
|
2383
|
+
{
|
|
2384
|
+
type: "number",
|
|
2385
|
+
min: "0",
|
|
2386
|
+
max: "59",
|
|
2387
|
+
value: selectedTime.minutes,
|
|
2388
|
+
onChange: (e) => {
|
|
2389
|
+
const val = parseInt(e.target.value);
|
|
2390
|
+
if (!isNaN(val) && val >= 0 && val <= 59) {
|
|
2391
|
+
handleTimeChange(selectedTime.hours, val);
|
|
2392
|
+
}
|
|
2393
|
+
},
|
|
2394
|
+
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"
|
|
2395
|
+
}
|
|
2396
|
+
),
|
|
2397
|
+
/* @__PURE__ */ (0, import_jsx_runtime54.jsx)(
|
|
2398
|
+
"button",
|
|
2399
|
+
{
|
|
2400
|
+
type: "button",
|
|
2401
|
+
onClick: () => handleTimeChange(selectedTime.hours, (selectedTime.minutes - 1 + 60) % 60),
|
|
2402
|
+
className: "p-1 hover:bg-gray-100 dark:hover:bg-gray-700 rounded transition-colors",
|
|
2403
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime54.jsx)("svg", { className: "w-4 h-4 text-gray-600 dark:text-gray-400", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime54.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M19 9l-7 7-7-7" }) })
|
|
2404
|
+
}
|
|
2405
|
+
)
|
|
2406
|
+
] })
|
|
2407
|
+
] })
|
|
2408
|
+
] }),
|
|
2409
|
+
/* @__PURE__ */ (0, import_jsx_runtime54.jsx)("div", { className: "text-center text-sm text-gray-600 dark:text-gray-400 mb-4", children: formatTime(selectedTime.hours, selectedTime.minutes) }),
|
|
2410
|
+
/* @__PURE__ */ (0, import_jsx_runtime54.jsx)(
|
|
2411
|
+
"button",
|
|
2412
|
+
{
|
|
2413
|
+
onClick: handleDone,
|
|
2414
|
+
className: "w-full px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors font-medium",
|
|
2415
|
+
children: "Done"
|
|
2416
|
+
}
|
|
2417
|
+
)
|
|
2418
|
+
] })
|
|
2419
|
+
]
|
|
2420
|
+
}
|
|
2421
|
+
) : null;
|
|
2422
|
+
return /* @__PURE__ */ (0, import_jsx_runtime54.jsxs)("div", { className, children: [
|
|
2423
|
+
label && /* @__PURE__ */ (0, import_jsx_runtime54.jsx)("label", { className: "block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1", children: label }),
|
|
2424
|
+
/* @__PURE__ */ (0, import_jsx_runtime54.jsxs)(
|
|
2425
|
+
"div",
|
|
2426
|
+
{
|
|
2427
|
+
ref: inputRef,
|
|
2428
|
+
onClick: () => !disabled && setIsOpen(!isOpen),
|
|
2429
|
+
className: `${baseStyles} ${errorStyles} ${disabledStyles} flex items-center justify-between`.trim(),
|
|
2430
|
+
children: [
|
|
2431
|
+
/* @__PURE__ */ (0, import_jsx_runtime54.jsx)("span", { className: !value ? "text-gray-500 dark:text-gray-400" : "", children: value ? formatDateTime(value) : placeholder }),
|
|
2432
|
+
/* @__PURE__ */ (0, import_jsx_runtime54.jsx)("svg", { className: "w-5 h-5 text-gray-400", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime54.jsx)("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" }) })
|
|
2433
|
+
]
|
|
2434
|
+
}
|
|
2435
|
+
),
|
|
2436
|
+
error && /* @__PURE__ */ (0, import_jsx_runtime54.jsx)("p", { className: "mt-1 text-sm text-red-600 dark:text-red-400", children: error }),
|
|
2437
|
+
helperText && !error && /* @__PURE__ */ (0, import_jsx_runtime54.jsx)("p", { className: "mt-1 text-sm text-gray-500 dark:text-gray-400", children: helperText }),
|
|
2438
|
+
mounted && (0, import_react_dom3.createPortal)(picker, document.body)
|
|
2439
|
+
] });
|
|
2440
|
+
};
|
|
2441
|
+
DateTimePicker.displayName = "DateTimePicker";
|
|
2442
|
+
|
|
2443
|
+
// src/components/Calendar.tsx
|
|
2444
|
+
var import_react16 = require("react");
|
|
2445
|
+
var import_jsx_runtime55 = require("react/jsx-runtime");
|
|
2446
|
+
var DAYS3 = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
|
|
2447
|
+
var MONTHS3 = [
|
|
2448
|
+
"January",
|
|
2449
|
+
"February",
|
|
2450
|
+
"March",
|
|
2451
|
+
"April",
|
|
2452
|
+
"May",
|
|
2453
|
+
"June",
|
|
2454
|
+
"July",
|
|
2455
|
+
"August",
|
|
2456
|
+
"September",
|
|
2457
|
+
"October",
|
|
2458
|
+
"November",
|
|
2459
|
+
"December"
|
|
2460
|
+
];
|
|
2461
|
+
var Calendar = ({
|
|
2462
|
+
value,
|
|
2463
|
+
onChange,
|
|
2464
|
+
minDate,
|
|
2465
|
+
maxDate,
|
|
2466
|
+
className = ""
|
|
2467
|
+
}) => {
|
|
2468
|
+
const { theme } = useTheme();
|
|
2469
|
+
const [currentDate, setCurrentDate] = (0, import_react16.useState)(value || /* @__PURE__ */ new Date());
|
|
2470
|
+
const [viewDate, setViewDate] = (0, import_react16.useState)(value || /* @__PURE__ */ new Date());
|
|
2471
|
+
const year = viewDate.getFullYear();
|
|
2472
|
+
const month = viewDate.getMonth();
|
|
2473
|
+
const firstDayOfMonth = new Date(year, month, 1).getDay();
|
|
2474
|
+
const daysInMonth = new Date(year, month + 1, 0).getDate();
|
|
2475
|
+
const daysInPrevMonth = new Date(year, month, 0).getDate();
|
|
2476
|
+
const calendarDays = [];
|
|
2477
|
+
for (let i = firstDayOfMonth - 1; i >= 0; i--) {
|
|
2478
|
+
calendarDays.push(new Date(year, month - 1, daysInPrevMonth - i));
|
|
2479
|
+
}
|
|
2480
|
+
for (let i = 1; i <= daysInMonth; i++) {
|
|
2481
|
+
calendarDays.push(new Date(year, month, i));
|
|
2482
|
+
}
|
|
2483
|
+
const remainingDays = 42 - calendarDays.length;
|
|
2484
|
+
for (let i = 1; i <= remainingDays; i++) {
|
|
2485
|
+
calendarDays.push(new Date(year, month + 1, i));
|
|
2486
|
+
}
|
|
2487
|
+
const isSameDay = (date1, date2) => {
|
|
2488
|
+
return date1.getDate() === date2.getDate() && date1.getMonth() === date2.getMonth() && date1.getFullYear() === date2.getFullYear();
|
|
2489
|
+
};
|
|
2490
|
+
const isToday = (date) => {
|
|
2491
|
+
return isSameDay(date, /* @__PURE__ */ new Date());
|
|
2492
|
+
};
|
|
2493
|
+
const isSelected = (date) => {
|
|
2494
|
+
return value && isSameDay(date, value);
|
|
2495
|
+
};
|
|
2496
|
+
const isCurrentMonth = (date) => {
|
|
2497
|
+
return date.getMonth() === month;
|
|
2498
|
+
};
|
|
2499
|
+
const isDisabled = (date) => {
|
|
2500
|
+
if (minDate && date < minDate) return true;
|
|
2501
|
+
if (maxDate && date > maxDate) return true;
|
|
2502
|
+
return false;
|
|
2503
|
+
};
|
|
2504
|
+
const handleDateClick = (date) => {
|
|
2505
|
+
if (isDisabled(date)) return;
|
|
2506
|
+
setCurrentDate(date);
|
|
2507
|
+
onChange?.(date);
|
|
2508
|
+
};
|
|
2509
|
+
const handlePrevMonth = () => {
|
|
2510
|
+
setViewDate(new Date(year, month - 1, 1));
|
|
2511
|
+
};
|
|
2512
|
+
const handleNextMonth = () => {
|
|
2513
|
+
setViewDate(new Date(year, month + 1, 1));
|
|
2514
|
+
};
|
|
2515
|
+
const handleToday = () => {
|
|
2516
|
+
const today = /* @__PURE__ */ new Date();
|
|
2517
|
+
setViewDate(today);
|
|
2518
|
+
setCurrentDate(today);
|
|
2519
|
+
onChange?.(today);
|
|
2520
|
+
};
|
|
2521
|
+
return /* @__PURE__ */ (0, import_jsx_runtime55.jsxs)("div", { className: `bg-white dark:bg-gray-800 rounded-lg border border-gray-200 dark:border-gray-700 p-4 ${className}`, children: [
|
|
2522
|
+
/* @__PURE__ */ (0, import_jsx_runtime55.jsxs)("div", { className: "flex items-center justify-between mb-4", children: [
|
|
2523
|
+
/* @__PURE__ */ (0, import_jsx_runtime55.jsx)(
|
|
2524
|
+
"button",
|
|
2525
|
+
{
|
|
2526
|
+
onClick: handlePrevMonth,
|
|
2527
|
+
className: "p-2 hover:bg-gray-100 dark:hover:bg-gray-700 rounded-lg transition-colors",
|
|
2528
|
+
"aria-label": "Previous month",
|
|
2529
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime55.jsx)("svg", { className: "w-5 h-5 text-gray-600 dark:text-gray-400", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime55.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M15 19l-7-7 7-7" }) })
|
|
2530
|
+
}
|
|
2531
|
+
),
|
|
2532
|
+
/* @__PURE__ */ (0, import_jsx_runtime55.jsxs)("div", { className: "flex items-center gap-2", children: [
|
|
2533
|
+
/* @__PURE__ */ (0, import_jsx_runtime55.jsxs)("h2", { className: "text-lg font-semibold text-gray-900 dark:text-gray-100", children: [
|
|
2534
|
+
MONTHS3[month],
|
|
2535
|
+
" ",
|
|
2536
|
+
year
|
|
2537
|
+
] }),
|
|
2538
|
+
/* @__PURE__ */ (0, import_jsx_runtime55.jsx)(
|
|
2539
|
+
"button",
|
|
2540
|
+
{
|
|
2541
|
+
onClick: handleToday,
|
|
2542
|
+
className: "px-3 py-1 text-sm bg-blue-600 text-white rounded hover:bg-blue-700 transition-colors",
|
|
2543
|
+
children: "Today"
|
|
2544
|
+
}
|
|
2545
|
+
)
|
|
2546
|
+
] }),
|
|
2547
|
+
/* @__PURE__ */ (0, import_jsx_runtime55.jsx)(
|
|
2548
|
+
"button",
|
|
2549
|
+
{
|
|
2550
|
+
onClick: handleNextMonth,
|
|
2551
|
+
className: "p-2 hover:bg-gray-100 dark:hover:bg-gray-700 rounded-lg transition-colors",
|
|
2552
|
+
"aria-label": "Next month",
|
|
2553
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime55.jsx)("svg", { className: "w-5 h-5 text-gray-600 dark:text-gray-400", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime55.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M9 5l7 7-7 7" }) })
|
|
2554
|
+
}
|
|
2555
|
+
)
|
|
2556
|
+
] }),
|
|
2557
|
+
/* @__PURE__ */ (0, import_jsx_runtime55.jsx)("div", { className: "grid grid-cols-7 gap-1 mb-2", children: DAYS3.map((day) => /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(
|
|
2558
|
+
"div",
|
|
2559
|
+
{
|
|
2560
|
+
className: "text-center text-xs font-semibold text-gray-600 dark:text-gray-400 py-2",
|
|
2561
|
+
children: day
|
|
2562
|
+
},
|
|
2563
|
+
day
|
|
2564
|
+
)) }),
|
|
2565
|
+
/* @__PURE__ */ (0, import_jsx_runtime55.jsx)("div", { className: "grid grid-cols-7 gap-1", children: calendarDays.map((date, index) => {
|
|
2566
|
+
if (!date) return /* @__PURE__ */ (0, import_jsx_runtime55.jsx)("div", {}, index);
|
|
2567
|
+
const isCurrentMonthDay = isCurrentMonth(date);
|
|
2568
|
+
const isTodayDay = isToday(date);
|
|
2569
|
+
const isSelectedDay = isSelected(date);
|
|
2570
|
+
const isDisabledDay = isDisabled(date);
|
|
2571
|
+
return /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(
|
|
2572
|
+
"button",
|
|
2573
|
+
{
|
|
2574
|
+
onClick: () => handleDateClick(date),
|
|
2575
|
+
disabled: isDisabledDay,
|
|
2576
|
+
className: `
|
|
2577
|
+
aspect-square p-2 rounded-lg text-sm font-medium transition-all
|
|
2578
|
+
${!isCurrentMonthDay ? "text-gray-400 dark:text-gray-600" : "text-gray-900 dark:text-gray-100"}
|
|
2579
|
+
${isTodayDay && !isSelectedDay ? "bg-blue-50 dark:bg-blue-900/20 text-blue-600 dark:text-blue-400 font-bold" : ""}
|
|
2580
|
+
${isSelectedDay ? "bg-blue-600 text-white hover:bg-blue-700" : ""}
|
|
2581
|
+
${!isSelectedDay && !isDisabledDay ? "hover:bg-gray-100 dark:hover:bg-gray-700" : ""}
|
|
2582
|
+
${isDisabledDay ? "opacity-30 cursor-not-allowed" : "cursor-pointer"}
|
|
2583
|
+
`,
|
|
2584
|
+
children: date.getDate()
|
|
2585
|
+
},
|
|
2586
|
+
index
|
|
2587
|
+
);
|
|
2588
|
+
}) })
|
|
2589
|
+
] });
|
|
2590
|
+
};
|
|
2591
|
+
|
|
2592
|
+
// src/components/Radio.tsx
|
|
2593
|
+
var import_react17 = __toESM(require("react"));
|
|
2594
|
+
var import_jsx_runtime56 = require("react/jsx-runtime");
|
|
2595
|
+
var Radio = ({
|
|
2596
|
+
name,
|
|
2597
|
+
options,
|
|
2598
|
+
value: controlledValue,
|
|
2599
|
+
defaultValue,
|
|
2600
|
+
onChange,
|
|
2601
|
+
disabled = false,
|
|
2602
|
+
orientation = "vertical",
|
|
2603
|
+
className = ""
|
|
2604
|
+
}) => {
|
|
2605
|
+
const [internalValue, setInternalValue] = import_react17.default.useState(defaultValue || "");
|
|
2606
|
+
const value = controlledValue !== void 0 ? controlledValue : internalValue;
|
|
2607
|
+
const handleChange = (optionValue) => {
|
|
2608
|
+
if (disabled) return;
|
|
2609
|
+
setInternalValue(optionValue);
|
|
2610
|
+
onChange?.(optionValue);
|
|
2611
|
+
};
|
|
2612
|
+
const containerClass = orientation === "horizontal" ? "flex flex-wrap gap-4" : "flex flex-col gap-2";
|
|
2613
|
+
return /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("div", { className: `${containerClass} ${className}`, role: "radiogroup", children: options.map((option) => {
|
|
2614
|
+
const isDisabled = disabled || option.disabled;
|
|
2615
|
+
const isChecked = value === option.value;
|
|
2616
|
+
const id = `${name}-${option.value}`;
|
|
2617
|
+
return /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)(
|
|
2618
|
+
"label",
|
|
2619
|
+
{
|
|
2620
|
+
htmlFor: id,
|
|
2621
|
+
className: `flex items-center gap-2 cursor-pointer group ${isDisabled ? "opacity-50 cursor-not-allowed" : ""}`,
|
|
2622
|
+
children: [
|
|
2623
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsxs)("div", { className: "relative inline-flex items-center", children: [
|
|
2624
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsx)(
|
|
2625
|
+
"input",
|
|
2626
|
+
{
|
|
2627
|
+
type: "radio",
|
|
2628
|
+
id,
|
|
2629
|
+
name,
|
|
2630
|
+
value: option.value,
|
|
2631
|
+
checked: isChecked,
|
|
2632
|
+
onChange: () => handleChange(option.value),
|
|
2633
|
+
disabled: isDisabled,
|
|
2634
|
+
className: "sr-only peer"
|
|
2635
|
+
}
|
|
2636
|
+
),
|
|
2637
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsx)("div", { className: `w-4 h-4 rounded-full border-2 transition-all duration-200 flex items-center justify-center
|
|
2638
|
+
border-gray-300 dark:border-gray-600
|
|
2639
|
+
${isDisabled ? "bg-gray-100 dark:bg-gray-800" : "peer-hover:border-gray-400 dark:peer-hover:border-gray-500"}
|
|
2640
|
+
${isChecked ? "border-blue-600 bg-white dark:bg-gray-900" : ""}
|
|
2641
|
+
peer-focus:ring-2 peer-focus:ring-blue-500 peer-focus:ring-offset-2
|
|
2642
|
+
`, children: /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("div", { className: `w-2 h-2 rounded-full bg-blue-600 transition-all duration-200 ${isChecked ? "scale-100" : "scale-0"}` }) })
|
|
2643
|
+
] }),
|
|
2644
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsx)("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 })
|
|
2645
|
+
]
|
|
2646
|
+
},
|
|
2647
|
+
option.value
|
|
2648
|
+
);
|
|
2649
|
+
}) });
|
|
2650
|
+
};
|
|
2651
|
+
|
|
2652
|
+
// src/components/ProgressBar.tsx
|
|
2653
|
+
var import_jsx_runtime57 = require("react/jsx-runtime");
|
|
2654
|
+
var ProgressBar = ({
|
|
2655
|
+
value,
|
|
2656
|
+
max = 100,
|
|
2657
|
+
size = "md",
|
|
2658
|
+
variant = "default",
|
|
2659
|
+
showLabel = false,
|
|
2660
|
+
label,
|
|
2661
|
+
className = ""
|
|
2662
|
+
}) => {
|
|
2663
|
+
const percentage = Math.min(Math.max(value / max * 100, 0), 100);
|
|
2664
|
+
const sizeClasses7 = {
|
|
2665
|
+
sm: "h-1",
|
|
2666
|
+
md: "h-2",
|
|
2667
|
+
lg: "h-3"
|
|
2668
|
+
};
|
|
2669
|
+
const variantClasses = {
|
|
2670
|
+
default: "bg-blue-600 dark:bg-blue-500",
|
|
2671
|
+
success: "bg-green-600 dark:bg-green-500",
|
|
2672
|
+
warning: "bg-yellow-500 dark:bg-yellow-400",
|
|
2673
|
+
danger: "bg-red-600 dark:bg-red-500"
|
|
2674
|
+
};
|
|
2675
|
+
return /* @__PURE__ */ (0, import_jsx_runtime57.jsxs)("div", { className: `w-full ${className}`, children: [
|
|
2676
|
+
(showLabel || label) && /* @__PURE__ */ (0, import_jsx_runtime57.jsxs)("div", { className: "flex justify-between items-center mb-1", children: [
|
|
2677
|
+
label && /* @__PURE__ */ (0, import_jsx_runtime57.jsx)("span", { className: "text-sm font-medium text-gray-700 dark:text-gray-300", children: label }),
|
|
2678
|
+
showLabel && /* @__PURE__ */ (0, import_jsx_runtime57.jsxs)("span", { className: "text-sm font-medium text-gray-700 dark:text-gray-300", children: [
|
|
2679
|
+
Math.round(percentage),
|
|
2680
|
+
"%"
|
|
2681
|
+
] })
|
|
2682
|
+
] }),
|
|
2683
|
+
/* @__PURE__ */ (0, import_jsx_runtime57.jsx)(
|
|
2684
|
+
"div",
|
|
2685
|
+
{
|
|
2686
|
+
className: `w-full bg-gray-200 dark:bg-gray-700 rounded-full overflow-hidden ${sizeClasses7[size]}`,
|
|
2687
|
+
role: "progressbar",
|
|
2688
|
+
"aria-valuenow": value,
|
|
2689
|
+
"aria-valuemin": 0,
|
|
2690
|
+
"aria-valuemax": max,
|
|
2691
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(
|
|
2692
|
+
"div",
|
|
2693
|
+
{
|
|
2694
|
+
className: `${sizeClasses7[size]} ${variantClasses[variant]} rounded-full transition-all duration-300 ease-out`,
|
|
2695
|
+
style: { width: `${percentage}%` }
|
|
2696
|
+
}
|
|
2697
|
+
)
|
|
2698
|
+
}
|
|
2699
|
+
)
|
|
2700
|
+
] });
|
|
2701
|
+
};
|
|
2702
|
+
|
|
2703
|
+
// src/components/Slider.tsx
|
|
2704
|
+
var import_react18 = __toESM(require("react"));
|
|
2705
|
+
var import_jsx_runtime58 = require("react/jsx-runtime");
|
|
2706
|
+
var Slider = ({
|
|
2707
|
+
value: controlledValue,
|
|
2708
|
+
defaultValue = 50,
|
|
2709
|
+
min = 0,
|
|
2710
|
+
max = 100,
|
|
2711
|
+
step = 1,
|
|
2712
|
+
onChange,
|
|
2713
|
+
disabled = false,
|
|
2714
|
+
showValue = false,
|
|
2715
|
+
label,
|
|
2716
|
+
className = "",
|
|
2717
|
+
range = false,
|
|
2718
|
+
rangeValue: controlledRangeValue,
|
|
2719
|
+
defaultRangeValue = [25, 75],
|
|
2720
|
+
onRangeChange
|
|
2721
|
+
}) => {
|
|
2722
|
+
const [internalValue, setInternalValue] = import_react18.default.useState(defaultValue);
|
|
2723
|
+
const [internalRangeValue, setInternalRangeValue] = import_react18.default.useState(defaultRangeValue);
|
|
2724
|
+
const trackRef = (0, import_react18.useRef)(null);
|
|
2725
|
+
const [isDragging, setIsDragging] = import_react18.default.useState(null);
|
|
2726
|
+
const value = controlledValue !== void 0 ? controlledValue : internalValue;
|
|
2727
|
+
const rangeValue = controlledRangeValue !== void 0 ? controlledRangeValue : internalRangeValue;
|
|
2728
|
+
const handleChange = (e) => {
|
|
2729
|
+
const newValue = Number(e.target.value);
|
|
2730
|
+
setInternalValue(newValue);
|
|
2731
|
+
onChange?.(newValue);
|
|
2732
|
+
};
|
|
2733
|
+
const handleRangeMouseDown = (e, handle) => {
|
|
2734
|
+
if (disabled) return;
|
|
2735
|
+
e.preventDefault();
|
|
2736
|
+
setIsDragging(handle);
|
|
2737
|
+
};
|
|
2738
|
+
const handleRangeMouseMove = (e) => {
|
|
2739
|
+
if (!isDragging || !trackRef.current || disabled) return;
|
|
2740
|
+
const rect = trackRef.current.getBoundingClientRect();
|
|
2741
|
+
const percentage2 = Math.max(0, Math.min(100, (e.clientX - rect.left) / rect.width * 100));
|
|
2742
|
+
const newValue = Math.round(percentage2 / 100 * (max - min) / step) * step + min;
|
|
2743
|
+
if (isDragging === "min") {
|
|
2744
|
+
const newMin = Math.min(newValue, rangeValue[1] - step);
|
|
2745
|
+
const newRange = [newMin, rangeValue[1]];
|
|
2746
|
+
setInternalRangeValue(newRange);
|
|
2747
|
+
onRangeChange?.(newRange);
|
|
2748
|
+
} else {
|
|
2749
|
+
const newMax = Math.max(newValue, rangeValue[0] + step);
|
|
2750
|
+
const newRange = [rangeValue[0], newMax];
|
|
2751
|
+
setInternalRangeValue(newRange);
|
|
2752
|
+
onRangeChange?.(newRange);
|
|
2753
|
+
}
|
|
2754
|
+
};
|
|
2755
|
+
const handleRangeMouseUp = () => {
|
|
2756
|
+
setIsDragging(null);
|
|
2757
|
+
};
|
|
2758
|
+
import_react18.default.useEffect(() => {
|
|
2759
|
+
if (isDragging) {
|
|
2760
|
+
document.addEventListener("mousemove", handleRangeMouseMove);
|
|
2761
|
+
document.addEventListener("mouseup", handleRangeMouseUp);
|
|
2762
|
+
return () => {
|
|
2763
|
+
document.removeEventListener("mousemove", handleRangeMouseMove);
|
|
2764
|
+
document.removeEventListener("mouseup", handleRangeMouseUp);
|
|
2765
|
+
};
|
|
2766
|
+
}
|
|
2767
|
+
}, [isDragging, rangeValue]);
|
|
2768
|
+
const percentage = (value - min) / (max - min) * 100;
|
|
2769
|
+
const minPercentage = (rangeValue[0] - min) / (max - min) * 100;
|
|
2770
|
+
const maxPercentage = (rangeValue[1] - min) / (max - min) * 100;
|
|
2771
|
+
if (range) {
|
|
2772
|
+
return /* @__PURE__ */ (0, import_jsx_runtime58.jsxs)("div", { className: `w-full ${className}`, children: [
|
|
2773
|
+
(label || showValue) && /* @__PURE__ */ (0, import_jsx_runtime58.jsxs)("div", { className: "flex justify-between items-center mb-2", children: [
|
|
2774
|
+
label && /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("label", { className: "text-sm font-medium text-gray-700 dark:text-gray-300", children: label }),
|
|
2775
|
+
showValue && /* @__PURE__ */ (0, import_jsx_runtime58.jsxs)("span", { className: "text-sm font-medium text-gray-700 dark:text-gray-300", children: [
|
|
2776
|
+
rangeValue[0],
|
|
2777
|
+
" - ",
|
|
2778
|
+
rangeValue[1]
|
|
2779
|
+
] })
|
|
2780
|
+
] }),
|
|
2781
|
+
/* @__PURE__ */ (0, import_jsx_runtime58.jsxs)("div", { className: "relative h-10 flex items-center", ref: trackRef, children: [
|
|
2782
|
+
/* @__PURE__ */ (0, import_jsx_runtime58.jsx)("div", { className: "absolute w-full h-2 bg-gray-200 dark:bg-gray-700 rounded-full" }),
|
|
2783
|
+
/* @__PURE__ */ (0, import_jsx_runtime58.jsx)(
|
|
2784
|
+
"div",
|
|
2785
|
+
{
|
|
2786
|
+
className: "absolute h-2 bg-blue-600 dark:bg-blue-500 rounded-full pointer-events-none",
|
|
2787
|
+
style: {
|
|
2788
|
+
left: `${minPercentage}%`,
|
|
2789
|
+
width: `${maxPercentage - minPercentage}%`
|
|
2790
|
+
}
|
|
2791
|
+
}
|
|
2792
|
+
),
|
|
2793
|
+
/* @__PURE__ */ (0, import_jsx_runtime58.jsx)(
|
|
2794
|
+
"div",
|
|
2795
|
+
{
|
|
2796
|
+
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
|
|
2797
|
+
${disabled ? "opacity-50 cursor-not-allowed" : ""}
|
|
2798
|
+
`,
|
|
2799
|
+
style: { left: `${minPercentage}%` },
|
|
2800
|
+
onMouseDown: (e) => handleRangeMouseDown(e, "min"),
|
|
2801
|
+
role: "slider",
|
|
2802
|
+
"aria-label": `${label ? label + " " : ""}minimum value`,
|
|
2803
|
+
"aria-valuemin": min,
|
|
2804
|
+
"aria-valuemax": rangeValue[1],
|
|
2805
|
+
"aria-valuenow": rangeValue[0],
|
|
2806
|
+
tabIndex: disabled ? -1 : 0
|
|
2807
|
+
}
|
|
2808
|
+
),
|
|
2809
|
+
/* @__PURE__ */ (0, import_jsx_runtime58.jsx)(
|
|
2810
|
+
"div",
|
|
2811
|
+
{
|
|
2812
|
+
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
|
|
2813
|
+
${disabled ? "opacity-50 cursor-not-allowed" : ""}
|
|
2814
|
+
`,
|
|
2815
|
+
style: { left: `${maxPercentage}%` },
|
|
2816
|
+
onMouseDown: (e) => handleRangeMouseDown(e, "max"),
|
|
2817
|
+
role: "slider",
|
|
2818
|
+
"aria-label": `${label ? label + " " : ""}maximum value`,
|
|
2819
|
+
"aria-valuemin": rangeValue[0],
|
|
2820
|
+
"aria-valuemax": max,
|
|
2821
|
+
"aria-valuenow": rangeValue[1],
|
|
2822
|
+
tabIndex: disabled ? -1 : 0
|
|
2823
|
+
}
|
|
2824
|
+
)
|
|
2825
|
+
] })
|
|
2826
|
+
] });
|
|
2827
|
+
}
|
|
2828
|
+
return /* @__PURE__ */ (0, import_jsx_runtime58.jsxs)("div", { className: `w-full ${className}`, children: [
|
|
2829
|
+
(label || showValue) && /* @__PURE__ */ (0, import_jsx_runtime58.jsxs)("div", { className: "flex justify-between items-center mb-2", children: [
|
|
2830
|
+
label && /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("label", { className: "text-sm font-medium text-gray-700 dark:text-gray-300", children: label }),
|
|
2831
|
+
showValue && /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("span", { className: "text-sm font-medium text-gray-700 dark:text-gray-300", children: value })
|
|
2832
|
+
] }),
|
|
2833
|
+
/* @__PURE__ */ (0, import_jsx_runtime58.jsxs)("div", { className: "relative h-10 flex items-center", children: [
|
|
2834
|
+
/* @__PURE__ */ (0, import_jsx_runtime58.jsx)("div", { className: "absolute w-full h-2 bg-gray-200 dark:bg-gray-700 rounded-full" }),
|
|
2835
|
+
/* @__PURE__ */ (0, import_jsx_runtime58.jsx)(
|
|
2836
|
+
"div",
|
|
2837
|
+
{
|
|
2838
|
+
className: "absolute h-2 bg-blue-600 dark:bg-blue-500 rounded-full pointer-events-none",
|
|
2839
|
+
style: { width: `${percentage}%` }
|
|
2840
|
+
}
|
|
2841
|
+
),
|
|
2842
|
+
/* @__PURE__ */ (0, import_jsx_runtime58.jsx)(
|
|
2843
|
+
"div",
|
|
2844
|
+
{
|
|
2845
|
+
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
|
|
2846
|
+
${disabled ? "opacity-50" : ""}
|
|
2847
|
+
`,
|
|
2848
|
+
style: { left: `${percentage}%` }
|
|
2849
|
+
}
|
|
2850
|
+
),
|
|
2851
|
+
/* @__PURE__ */ (0, import_jsx_runtime58.jsx)(
|
|
2852
|
+
"input",
|
|
2853
|
+
{
|
|
2854
|
+
type: "range",
|
|
2855
|
+
min,
|
|
2856
|
+
max,
|
|
2857
|
+
step,
|
|
2858
|
+
value,
|
|
2859
|
+
onChange: handleChange,
|
|
2860
|
+
disabled,
|
|
2861
|
+
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",
|
|
2862
|
+
"aria-label": label,
|
|
2863
|
+
"aria-valuemin": min,
|
|
2864
|
+
"aria-valuemax": max,
|
|
2865
|
+
"aria-valuenow": value
|
|
2866
|
+
}
|
|
2867
|
+
)
|
|
2868
|
+
] })
|
|
2869
|
+
] });
|
|
2870
|
+
};
|
|
2871
|
+
|
|
2872
|
+
// src/components/Avatar.tsx
|
|
2873
|
+
var import_react19 = __toESM(require("react"));
|
|
2874
|
+
var import_jsx_runtime59 = require("react/jsx-runtime");
|
|
2875
|
+
var Avatar = ({
|
|
2876
|
+
src,
|
|
2877
|
+
alt,
|
|
2878
|
+
name,
|
|
2879
|
+
size = "md",
|
|
2880
|
+
shape = "circle",
|
|
2881
|
+
className = "",
|
|
2882
|
+
fallbackColor = "bg-blue-600"
|
|
2883
|
+
}) => {
|
|
2884
|
+
const [imageError, setImageError] = import_react19.default.useState(false);
|
|
2885
|
+
const sizeClasses7 = {
|
|
2886
|
+
xs: "w-6 h-6 text-xs",
|
|
2887
|
+
sm: "w-8 h-8 text-sm",
|
|
2888
|
+
md: "w-10 h-10 text-base",
|
|
2889
|
+
lg: "w-12 h-12 text-lg",
|
|
2890
|
+
xl: "w-16 h-16 text-2xl"
|
|
2891
|
+
};
|
|
2892
|
+
const shapeClass = shape === "circle" ? "rounded-full" : "rounded-md";
|
|
2893
|
+
const getInitials = (name2) => {
|
|
2894
|
+
const parts = name2.trim().split(" ");
|
|
2895
|
+
if (parts.length >= 2) {
|
|
2896
|
+
return `${parts[0][0]}${parts[parts.length - 1][0]}`.toUpperCase();
|
|
2897
|
+
}
|
|
2898
|
+
return name2.slice(0, 2).toUpperCase();
|
|
2899
|
+
};
|
|
2900
|
+
const showImage = src && !imageError;
|
|
2901
|
+
const showInitials = !showImage && name;
|
|
2902
|
+
return /* @__PURE__ */ (0, import_jsx_runtime59.jsx)(
|
|
2903
|
+
"div",
|
|
2904
|
+
{
|
|
2905
|
+
className: `${sizeClasses7[size]} ${shapeClass} flex items-center justify-center overflow-hidden ${showImage ? "bg-gray-200 dark:bg-gray-700" : `${fallbackColor} text-white`} ${className}`,
|
|
2906
|
+
children: showImage ? /* @__PURE__ */ (0, import_jsx_runtime59.jsx)(
|
|
2907
|
+
"img",
|
|
2908
|
+
{
|
|
2909
|
+
src,
|
|
2910
|
+
alt: alt || name || "Avatar",
|
|
2911
|
+
className: "w-full h-full object-cover",
|
|
2912
|
+
onError: () => setImageError(true)
|
|
2913
|
+
}
|
|
2914
|
+
) : showInitials ? /* @__PURE__ */ (0, import_jsx_runtime59.jsx)("span", { className: "font-semibold select-none", children: getInitials(name) }) : /* @__PURE__ */ (0, import_jsx_runtime59.jsx)(
|
|
2915
|
+
"svg",
|
|
2916
|
+
{
|
|
2917
|
+
className: "w-full h-full text-gray-400 dark:text-gray-600",
|
|
2918
|
+
fill: "currentColor",
|
|
2919
|
+
viewBox: "0 0 24 24",
|
|
2920
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime59.jsx)("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" })
|
|
2921
|
+
}
|
|
2922
|
+
)
|
|
2923
|
+
}
|
|
2924
|
+
);
|
|
2925
|
+
};
|
|
2926
|
+
|
|
2927
|
+
// src/components/Textarea.tsx
|
|
2928
|
+
var import_jsx_runtime60 = require("react/jsx-runtime");
|
|
2929
|
+
var Textarea = ({
|
|
2930
|
+
label,
|
|
2931
|
+
error,
|
|
2932
|
+
helperText,
|
|
2933
|
+
size = "md",
|
|
2934
|
+
resize = "vertical",
|
|
2935
|
+
className = "",
|
|
2936
|
+
disabled,
|
|
2937
|
+
...props
|
|
2938
|
+
}) => {
|
|
2939
|
+
const sizeClasses7 = {
|
|
2940
|
+
sm: "px-3 py-1.5 text-sm min-h-[80px]",
|
|
2941
|
+
md: "px-4 py-2 text-base min-h-[100px]",
|
|
2942
|
+
lg: "px-4 py-3 text-lg min-h-[120px]"
|
|
2943
|
+
};
|
|
2944
|
+
const resizeClasses = {
|
|
2945
|
+
none: "resize-none",
|
|
2946
|
+
vertical: "resize-y",
|
|
2947
|
+
horizontal: "resize-x",
|
|
2948
|
+
both: "resize"
|
|
2949
|
+
};
|
|
2950
|
+
const baseClasses = `w-full rounded-lg border transition-colors duration-150 focus:outline-none focus:ring-2
|
|
2951
|
+
${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"}
|
|
2952
|
+
bg-white dark:bg-gray-800 text-gray-900 dark:text-gray-100
|
|
2953
|
+
placeholder:text-gray-500 dark:placeholder:text-gray-400
|
|
2954
|
+
disabled:opacity-50 disabled:cursor-not-allowed disabled:bg-gray-50 dark:disabled:bg-gray-900`;
|
|
2955
|
+
return /* @__PURE__ */ (0, import_jsx_runtime60.jsxs)("div", { className: `w-full ${className}`, children: [
|
|
2956
|
+
label && /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("label", { className: "block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1", children: label }),
|
|
2957
|
+
/* @__PURE__ */ (0, import_jsx_runtime60.jsx)(
|
|
2958
|
+
"textarea",
|
|
2959
|
+
{
|
|
2960
|
+
className: `${baseClasses} ${sizeClasses7[size]} ${resizeClasses[resize]}`,
|
|
2961
|
+
disabled,
|
|
2962
|
+
...props
|
|
2963
|
+
}
|
|
2964
|
+
),
|
|
2965
|
+
error && /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("p", { className: "mt-1 text-sm text-red-600 dark:text-red-400", children: error }),
|
|
2966
|
+
helperText && !error && /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("p", { className: "mt-1 text-sm text-gray-500 dark:text-gray-400", children: helperText })
|
|
2967
|
+
] });
|
|
2968
|
+
};
|
|
2969
|
+
|
|
2970
|
+
// src/components/RichTextEditor.tsx
|
|
2971
|
+
var import_react20 = require("react");
|
|
2972
|
+
var import_jsx_runtime61 = require("react/jsx-runtime");
|
|
2973
|
+
var RichTextEditor = ({
|
|
2974
|
+
value = "",
|
|
2975
|
+
onChange,
|
|
2976
|
+
placeholder = "Start typing...",
|
|
2977
|
+
className = "",
|
|
2978
|
+
minHeight = "200px",
|
|
2979
|
+
maxHeight = "500px",
|
|
2980
|
+
disabled = false,
|
|
2981
|
+
label,
|
|
2982
|
+
error,
|
|
2983
|
+
helperText
|
|
2984
|
+
}) => {
|
|
2985
|
+
const { themeName } = useTheme();
|
|
2986
|
+
const editorRef = (0, import_react20.useRef)(null);
|
|
2987
|
+
const [isFocused, setIsFocused] = (0, import_react20.useState)(false);
|
|
2988
|
+
const [activeFormats, setActiveFormats] = (0, import_react20.useState)(/* @__PURE__ */ new Set());
|
|
2989
|
+
const [showLinkModal, setShowLinkModal] = (0, import_react20.useState)(false);
|
|
2990
|
+
const [linkUrl, setLinkUrl] = (0, import_react20.useState)("");
|
|
2991
|
+
const [showImageModal, setShowImageModal] = (0, import_react20.useState)(false);
|
|
2992
|
+
const [imageUrl, setImageUrl] = (0, import_react20.useState)("");
|
|
2993
|
+
const [imageAlt, setImageAlt] = (0, import_react20.useState)("");
|
|
2994
|
+
(0, import_react20.useLayoutEffect)(() => {
|
|
2995
|
+
const styleId = "rich-text-editor-styles";
|
|
2996
|
+
if (!document.getElementById(styleId)) {
|
|
2997
|
+
const style = document.createElement("style");
|
|
2998
|
+
style.id = styleId;
|
|
2999
|
+
style.textContent = `
|
|
3000
|
+
[contenteditable]:empty:before {
|
|
3001
|
+
content: attr(data-placeholder);
|
|
3002
|
+
color: #9ca3af;
|
|
3003
|
+
pointer-events: none;
|
|
3004
|
+
}
|
|
3005
|
+
[contenteditable] h1 {
|
|
3006
|
+
font-size: 2em;
|
|
3007
|
+
font-weight: bold;
|
|
3008
|
+
margin: 0.67em 0;
|
|
3009
|
+
}
|
|
3010
|
+
[contenteditable] h2 {
|
|
3011
|
+
font-size: 1.5em;
|
|
3012
|
+
font-weight: bold;
|
|
3013
|
+
margin: 0.75em 0;
|
|
3014
|
+
}
|
|
3015
|
+
[contenteditable] h3 {
|
|
3016
|
+
font-size: 1.17em;
|
|
3017
|
+
font-weight: bold;
|
|
3018
|
+
margin: 0.83em 0;
|
|
3019
|
+
}
|
|
3020
|
+
[contenteditable] ul, [contenteditable] ol {
|
|
3021
|
+
margin: 1em 0;
|
|
3022
|
+
padding-left: 2em;
|
|
3023
|
+
}
|
|
3024
|
+
[contenteditable] a {
|
|
3025
|
+
color: #3b82f6;
|
|
3026
|
+
text-decoration: underline;
|
|
3027
|
+
}
|
|
3028
|
+
.dark [contenteditable] a {
|
|
3029
|
+
color: #60a5fa;
|
|
3030
|
+
}
|
|
3031
|
+
[contenteditable] img {
|
|
3032
|
+
max-width: 100%;
|
|
3033
|
+
height: auto;
|
|
3034
|
+
border-radius: 0.5rem;
|
|
3035
|
+
margin: 1em 0;
|
|
3036
|
+
}
|
|
3037
|
+
[contenteditable] video {
|
|
3038
|
+
max-width: 100%;
|
|
3039
|
+
height: auto;
|
|
3040
|
+
border-radius: 0.5rem;
|
|
3041
|
+
margin: 1em 0;
|
|
3042
|
+
}
|
|
3043
|
+
`;
|
|
3044
|
+
document.head.appendChild(style);
|
|
3045
|
+
}
|
|
3046
|
+
}, []);
|
|
3047
|
+
const isInitialRender = (0, import_react20.useRef)(true);
|
|
3048
|
+
(0, import_react20.useEffect)(() => {
|
|
3049
|
+
if (!isInitialRender.current && editorRef.current && editorRef.current.innerHTML !== value) {
|
|
3050
|
+
editorRef.current.innerHTML = value;
|
|
3051
|
+
}
|
|
3052
|
+
isInitialRender.current = false;
|
|
3053
|
+
}, [value]);
|
|
3054
|
+
const updateActiveFormats = (0, import_react20.useCallback)(() => {
|
|
3055
|
+
const formats = /* @__PURE__ */ new Set();
|
|
3056
|
+
if (document.queryCommandState("bold")) formats.add("bold");
|
|
3057
|
+
if (document.queryCommandState("italic")) formats.add("italic");
|
|
3058
|
+
if (document.queryCommandState("underline")) formats.add("underline");
|
|
3059
|
+
if (document.queryCommandState("strikeThrough")) formats.add("strikeThrough");
|
|
3060
|
+
if (document.queryCommandState("insertUnorderedList")) formats.add("ul");
|
|
3061
|
+
if (document.queryCommandState("insertOrderedList")) formats.add("ol");
|
|
3062
|
+
const parentNode = window.getSelection()?.anchorNode?.parentElement;
|
|
3063
|
+
if (parentNode) {
|
|
3064
|
+
const tagName = parentNode.tagName.toLowerCase();
|
|
3065
|
+
if (["h1", "h2", "h3"].includes(tagName)) {
|
|
3066
|
+
formats.add(tagName);
|
|
3067
|
+
}
|
|
3068
|
+
}
|
|
3069
|
+
setActiveFormats(formats);
|
|
3070
|
+
}, []);
|
|
3071
|
+
const handleInput = (0, import_react20.useCallback)(() => {
|
|
3072
|
+
if (editorRef.current && onChange) {
|
|
3073
|
+
onChange(editorRef.current.innerHTML);
|
|
3074
|
+
}
|
|
3075
|
+
updateActiveFormats();
|
|
3076
|
+
}, [onChange, updateActiveFormats]);
|
|
3077
|
+
const handleFormat = (0, import_react20.useCallback)((command) => {
|
|
3078
|
+
if (disabled) return;
|
|
3079
|
+
document.execCommand(command, false);
|
|
3080
|
+
editorRef.current?.focus();
|
|
3081
|
+
updateActiveFormats();
|
|
3082
|
+
handleInput();
|
|
3083
|
+
}, [disabled, updateActiveFormats, handleInput]);
|
|
3084
|
+
const handleList = (0, import_react20.useCallback)((command) => {
|
|
3085
|
+
if (disabled) return;
|
|
3086
|
+
document.execCommand(command, false);
|
|
3087
|
+
editorRef.current?.focus();
|
|
3088
|
+
updateActiveFormats();
|
|
3089
|
+
handleInput();
|
|
3090
|
+
}, [disabled, updateActiveFormats, handleInput]);
|
|
3091
|
+
const handleHeading = (0, import_react20.useCallback)((level) => {
|
|
3092
|
+
if (disabled) return;
|
|
3093
|
+
document.execCommand("formatBlock", false, level);
|
|
3094
|
+
editorRef.current?.focus();
|
|
3095
|
+
updateActiveFormats();
|
|
3096
|
+
handleInput();
|
|
3097
|
+
}, [disabled, updateActiveFormats, handleInput]);
|
|
3098
|
+
const handleLink = (0, import_react20.useCallback)(() => {
|
|
3099
|
+
if (disabled) return;
|
|
3100
|
+
setShowLinkModal(true);
|
|
3101
|
+
}, [disabled]);
|
|
3102
|
+
const insertLink = (0, import_react20.useCallback)(() => {
|
|
3103
|
+
if (linkUrl) {
|
|
3104
|
+
document.execCommand("createLink", false, linkUrl);
|
|
3105
|
+
setShowLinkModal(false);
|
|
3106
|
+
setLinkUrl("");
|
|
3107
|
+
editorRef.current?.focus();
|
|
3108
|
+
handleInput();
|
|
3109
|
+
}
|
|
3110
|
+
}, [linkUrl, handleInput]);
|
|
3111
|
+
const handleCode = (0, import_react20.useCallback)(() => {
|
|
3112
|
+
if (disabled) return;
|
|
3113
|
+
const selection = window.getSelection();
|
|
3114
|
+
if (selection && selection.rangeCount > 0) {
|
|
3115
|
+
const range = selection.getRangeAt(0);
|
|
3116
|
+
const code = document.createElement("code");
|
|
3117
|
+
code.className = "bg-gray-100 dark:bg-gray-700 px-1.5 py-0.5 rounded text-sm font-mono";
|
|
3118
|
+
try {
|
|
3119
|
+
range.surroundContents(code);
|
|
3120
|
+
handleInput();
|
|
3121
|
+
} catch (e) {
|
|
3122
|
+
console.warn("Could not apply code formatting");
|
|
3123
|
+
}
|
|
3124
|
+
}
|
|
3125
|
+
editorRef.current?.focus();
|
|
3126
|
+
}, [disabled, handleInput]);
|
|
3127
|
+
const handleImage = (0, import_react20.useCallback)(() => {
|
|
3128
|
+
if (disabled) return;
|
|
3129
|
+
setShowImageModal(true);
|
|
3130
|
+
}, [disabled]);
|
|
3131
|
+
const insertImage = (0, import_react20.useCallback)(() => {
|
|
3132
|
+
if (!imageUrl) return;
|
|
3133
|
+
const img = document.createElement("img");
|
|
3134
|
+
img.src = imageUrl;
|
|
3135
|
+
img.alt = imageAlt || "";
|
|
3136
|
+
img.style.maxWidth = "100%";
|
|
3137
|
+
img.style.height = "auto";
|
|
3138
|
+
const selection = window.getSelection();
|
|
3139
|
+
if (selection && selection.rangeCount > 0) {
|
|
3140
|
+
const range = selection.getRangeAt(0);
|
|
3141
|
+
range.deleteContents();
|
|
3142
|
+
range.insertNode(img);
|
|
3143
|
+
range.setStartAfter(img);
|
|
3144
|
+
range.setEndAfter(img);
|
|
3145
|
+
selection.removeAllRanges();
|
|
3146
|
+
selection.addRange(range);
|
|
3147
|
+
} else if (editorRef.current) {
|
|
3148
|
+
editorRef.current.appendChild(img);
|
|
3149
|
+
}
|
|
3150
|
+
setShowImageModal(false);
|
|
3151
|
+
setImageUrl("");
|
|
3152
|
+
setImageAlt("");
|
|
3153
|
+
editorRef.current?.focus();
|
|
3154
|
+
handleInput();
|
|
3155
|
+
}, [imageUrl, imageAlt, handleInput, disabled]);
|
|
3156
|
+
const getButtonClass = (isActive) => {
|
|
3157
|
+
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";
|
|
3158
|
+
const activeClass = themeName === "minimalistic" ? "bg-white text-black" : "bg-blue-100 dark:bg-blue-900 border-blue-500 dark:border-blue-400";
|
|
3159
|
+
const hoverClass = themeName === "minimalistic" ? "hover:bg-white hover:text-black" : "hover:bg-gray-100 dark:hover:bg-gray-700";
|
|
3160
|
+
const disabledClass = disabled ? "opacity-50 cursor-not-allowed" : "cursor-pointer";
|
|
3161
|
+
return `px-2.5 py-1.5 rounded text-sm font-medium ${baseClass} ${isActive ? activeClass : hoverClass} ${disabledClass}`;
|
|
3162
|
+
};
|
|
3163
|
+
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";
|
|
3164
|
+
const focusClass = isFocused && !disabled ? themeName === "minimalistic" ? "border-white" : "border-blue-500 dark:border-blue-400 ring-2 ring-blue-500/20" : "";
|
|
3165
|
+
const errorClass = error ? "border-red-500 dark:border-red-400" : "";
|
|
3166
|
+
return /* @__PURE__ */ (0, import_jsx_runtime61.jsxs)("div", { className: `w-full ${className}`, children: [
|
|
3167
|
+
label && /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("label", { className: "block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2", children: label }),
|
|
3168
|
+
/* @__PURE__ */ (0, import_jsx_runtime61.jsxs)("div", { className: `rounded-t-lg border-b ${editorBaseClass} p-2 flex flex-wrap gap-1`, children: [
|
|
3169
|
+
/* @__PURE__ */ (0, import_jsx_runtime61.jsxs)("div", { className: "flex gap-1", children: [
|
|
3170
|
+
/* @__PURE__ */ (0, import_jsx_runtime61.jsx)(
|
|
3171
|
+
"button",
|
|
3172
|
+
{
|
|
3173
|
+
type: "button",
|
|
3174
|
+
onClick: () => handleFormat("bold"),
|
|
3175
|
+
className: getButtonClass(activeFormats.has("bold")),
|
|
3176
|
+
disabled,
|
|
3177
|
+
title: "Bold (Ctrl+B)",
|
|
3178
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("svg", { className: "w-4 h-4", fill: "currentColor", viewBox: "0 0 20 20", children: /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("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" }) })
|
|
3179
|
+
}
|
|
3180
|
+
),
|
|
3181
|
+
/* @__PURE__ */ (0, import_jsx_runtime61.jsx)(
|
|
3182
|
+
"button",
|
|
3183
|
+
{
|
|
3184
|
+
type: "button",
|
|
3185
|
+
onClick: () => handleFormat("italic"),
|
|
3186
|
+
className: getButtonClass(activeFormats.has("italic")),
|
|
3187
|
+
disabled,
|
|
3188
|
+
title: "Italic (Ctrl+I)",
|
|
3189
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("svg", { className: "w-4 h-4", fill: "currentColor", viewBox: "0 0 20 20", children: /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("path", { d: "M11.59 4H16v2h-1.71l-3.58 8H13v2H8v-2h1.71l3.58-8H11.59V4z" }) })
|
|
3190
|
+
}
|
|
3191
|
+
),
|
|
3192
|
+
/* @__PURE__ */ (0, import_jsx_runtime61.jsx)(
|
|
3193
|
+
"button",
|
|
3194
|
+
{
|
|
3195
|
+
type: "button",
|
|
3196
|
+
onClick: () => handleFormat("underline"),
|
|
3197
|
+
className: getButtonClass(activeFormats.has("underline")),
|
|
3198
|
+
disabled,
|
|
3199
|
+
title: "Underline (Ctrl+U)",
|
|
3200
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("svg", { className: "w-4 h-4", fill: "currentColor", viewBox: "0 0 20 20", children: /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("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" }) })
|
|
3201
|
+
}
|
|
3202
|
+
),
|
|
3203
|
+
/* @__PURE__ */ (0, import_jsx_runtime61.jsx)(
|
|
3204
|
+
"button",
|
|
3205
|
+
{
|
|
3206
|
+
type: "button",
|
|
3207
|
+
onClick: () => handleFormat("strikeThrough"),
|
|
3208
|
+
className: getButtonClass(activeFormats.has("strikeThrough")),
|
|
3209
|
+
disabled,
|
|
3210
|
+
title: "Strikethrough",
|
|
3211
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("svg", { className: "w-4 h-4", fill: "currentColor", viewBox: "0 0 20 20", children: /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("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" }) })
|
|
3212
|
+
}
|
|
3213
|
+
)
|
|
3214
|
+
] }),
|
|
3215
|
+
/* @__PURE__ */ (0, import_jsx_runtime61.jsx)("div", { className: "w-px bg-gray-300 dark:bg-gray-600 mx-1" }),
|
|
3216
|
+
/* @__PURE__ */ (0, import_jsx_runtime61.jsxs)("div", { className: "flex gap-1", children: [
|
|
3217
|
+
/* @__PURE__ */ (0, import_jsx_runtime61.jsx)(
|
|
3218
|
+
"button",
|
|
3219
|
+
{
|
|
3220
|
+
type: "button",
|
|
3221
|
+
onClick: () => handleHeading("h1"),
|
|
3222
|
+
className: getButtonClass(activeFormats.has("h1")),
|
|
3223
|
+
disabled,
|
|
3224
|
+
title: "Heading 1",
|
|
3225
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("svg", { className: "w-4 h-4", fill: "currentColor", viewBox: "0 0 20 20", children: /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("text", { x: "2", y: "16", fontSize: "14", fontWeight: "bold", children: "H1" }) })
|
|
3226
|
+
}
|
|
3227
|
+
),
|
|
3228
|
+
/* @__PURE__ */ (0, import_jsx_runtime61.jsx)(
|
|
3229
|
+
"button",
|
|
3230
|
+
{
|
|
3231
|
+
type: "button",
|
|
3232
|
+
onClick: () => handleHeading("h2"),
|
|
3233
|
+
className: getButtonClass(activeFormats.has("h2")),
|
|
3234
|
+
disabled,
|
|
3235
|
+
title: "Heading 2",
|
|
3236
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("svg", { className: "w-4 h-4", fill: "currentColor", viewBox: "0 0 20 20", children: /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("text", { x: "2", y: "16", fontSize: "14", fontWeight: "bold", children: "H2" }) })
|
|
3237
|
+
}
|
|
3238
|
+
),
|
|
3239
|
+
/* @__PURE__ */ (0, import_jsx_runtime61.jsx)(
|
|
3240
|
+
"button",
|
|
3241
|
+
{
|
|
3242
|
+
type: "button",
|
|
3243
|
+
onClick: () => handleHeading("h3"),
|
|
3244
|
+
className: getButtonClass(activeFormats.has("h3")),
|
|
3245
|
+
disabled,
|
|
3246
|
+
title: "Heading 3",
|
|
3247
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("svg", { className: "w-4 h-4", fill: "currentColor", viewBox: "0 0 20 20", children: /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("text", { x: "2", y: "16", fontSize: "14", fontWeight: "bold", children: "H3" }) })
|
|
3248
|
+
}
|
|
3249
|
+
)
|
|
3250
|
+
] }),
|
|
3251
|
+
/* @__PURE__ */ (0, import_jsx_runtime61.jsx)("div", { className: "w-px bg-gray-300 dark:bg-gray-600 mx-1" }),
|
|
3252
|
+
/* @__PURE__ */ (0, import_jsx_runtime61.jsxs)("div", { className: "flex gap-1", children: [
|
|
3253
|
+
/* @__PURE__ */ (0, import_jsx_runtime61.jsx)(
|
|
3254
|
+
"button",
|
|
3255
|
+
{
|
|
3256
|
+
type: "button",
|
|
3257
|
+
onClick: () => handleList("insertUnorderedList"),
|
|
3258
|
+
className: getButtonClass(activeFormats.has("ul")),
|
|
3259
|
+
disabled,
|
|
3260
|
+
title: "Bullet List",
|
|
3261
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("svg", { className: "w-4 h-4", fill: "currentColor", viewBox: "0 0 20 20", children: /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("path", { d: "M4 4h2v2H4V4zm4 0h8v2H8V4zM4 8h2v2H4V8zm4 0h8v2H8V8zm-4 4h2v2H4v-2zm4 0h8v2H8v-2zm-4 4h2v2H4v-2zm4 0h8v2H8v-2z" }) })
|
|
3262
|
+
}
|
|
3263
|
+
),
|
|
3264
|
+
/* @__PURE__ */ (0, import_jsx_runtime61.jsx)(
|
|
3265
|
+
"button",
|
|
3266
|
+
{
|
|
3267
|
+
type: "button",
|
|
3268
|
+
onClick: () => handleList("insertOrderedList"),
|
|
3269
|
+
className: getButtonClass(activeFormats.has("ol")),
|
|
3270
|
+
disabled,
|
|
3271
|
+
title: "Numbered List",
|
|
3272
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("svg", { className: "w-4 h-4", fill: "currentColor", viewBox: "0 0 20 20", children: /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("path", { d: "M4 4h1v3H4V4zm0 4h1v1H3V8h2v1H4zm1 2H3v1h2v1H3v1h2v-3zM8 4h8v2H8V4zm0 4h8v2H8V8zm0 4h8v2H8v-2zm0 4h8v2H8v-2z" }) })
|
|
3273
|
+
}
|
|
3274
|
+
)
|
|
3275
|
+
] }),
|
|
3276
|
+
/* @__PURE__ */ (0, import_jsx_runtime61.jsx)("div", { className: "w-px bg-gray-300 dark:bg-gray-600 mx-1" }),
|
|
3277
|
+
/* @__PURE__ */ (0, import_jsx_runtime61.jsxs)("div", { className: "flex gap-1", children: [
|
|
3278
|
+
/* @__PURE__ */ (0, import_jsx_runtime61.jsx)(
|
|
3279
|
+
"button",
|
|
3280
|
+
{
|
|
3281
|
+
type: "button",
|
|
3282
|
+
onClick: handleLink,
|
|
3283
|
+
className: getButtonClass(false),
|
|
3284
|
+
disabled,
|
|
3285
|
+
title: "Insert Link",
|
|
3286
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("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" }) })
|
|
3287
|
+
}
|
|
3288
|
+
),
|
|
3289
|
+
/* @__PURE__ */ (0, import_jsx_runtime61.jsx)(
|
|
3290
|
+
"button",
|
|
3291
|
+
{
|
|
3292
|
+
type: "button",
|
|
3293
|
+
onClick: handleImage,
|
|
3294
|
+
className: getButtonClass(false),
|
|
3295
|
+
disabled,
|
|
3296
|
+
title: "Insert Image/Video",
|
|
3297
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("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" }) })
|
|
3298
|
+
}
|
|
3299
|
+
),
|
|
3300
|
+
/* @__PURE__ */ (0, import_jsx_runtime61.jsx)(
|
|
3301
|
+
"button",
|
|
3302
|
+
{
|
|
3303
|
+
type: "button",
|
|
3304
|
+
onClick: handleCode,
|
|
3305
|
+
className: getButtonClass(false),
|
|
3306
|
+
disabled,
|
|
3307
|
+
title: "Code",
|
|
3308
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M10 20l4-16m4 4l4 4-4 4M6 16l-4-4 4-4" }) })
|
|
3309
|
+
}
|
|
3310
|
+
)
|
|
3311
|
+
] })
|
|
3312
|
+
] }),
|
|
3313
|
+
/* @__PURE__ */ (0, import_jsx_runtime61.jsx)(
|
|
3314
|
+
"div",
|
|
3315
|
+
{
|
|
3316
|
+
ref: editorRef,
|
|
3317
|
+
contentEditable: !disabled,
|
|
3318
|
+
onInput: handleInput,
|
|
3319
|
+
onFocus: () => setIsFocused(true),
|
|
3320
|
+
onBlur: () => setIsFocused(false),
|
|
3321
|
+
onMouseUp: updateActiveFormats,
|
|
3322
|
+
onKeyUp: updateActiveFormats,
|
|
3323
|
+
dangerouslySetInnerHTML: { __html: value },
|
|
3324
|
+
className: `
|
|
3325
|
+
w-full px-4 py-3 rounded-b-lg outline-none overflow-y-auto
|
|
3326
|
+
${editorBaseClass} ${focusClass} ${errorClass}
|
|
3327
|
+
${disabled ? "opacity-50 cursor-not-allowed" : ""}
|
|
3328
|
+
prose prose-sm dark:prose-invert max-w-none
|
|
3329
|
+
`,
|
|
3330
|
+
style: {
|
|
3331
|
+
minHeight,
|
|
3332
|
+
maxHeight
|
|
3333
|
+
},
|
|
3334
|
+
"data-placeholder": placeholder,
|
|
3335
|
+
suppressContentEditableWarning: true
|
|
3336
|
+
}
|
|
3337
|
+
),
|
|
3338
|
+
error && /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("p", { className: "mt-1 text-sm text-red-600 dark:text-red-400", children: error }),
|
|
3339
|
+
helperText && !error && /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("p", { className: "mt-1 text-sm text-gray-500 dark:text-gray-400", children: helperText }),
|
|
3340
|
+
/* @__PURE__ */ (0, import_jsx_runtime61.jsx)(
|
|
3341
|
+
Modal,
|
|
3342
|
+
{
|
|
3343
|
+
isOpen: showLinkModal,
|
|
3344
|
+
onClose: () => {
|
|
3345
|
+
setShowLinkModal(false);
|
|
3346
|
+
setLinkUrl("");
|
|
3347
|
+
},
|
|
3348
|
+
title: "Insert Link",
|
|
3349
|
+
size: "sm",
|
|
3350
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime61.jsxs)("div", { className: "space-y-4", children: [
|
|
3351
|
+
/* @__PURE__ */ (0, import_jsx_runtime61.jsx)(
|
|
3352
|
+
TextInput,
|
|
3353
|
+
{
|
|
3354
|
+
label: "URL",
|
|
3355
|
+
value: linkUrl,
|
|
3356
|
+
onChange: (e) => setLinkUrl(e.target.value),
|
|
3357
|
+
placeholder: "https://example.com",
|
|
3358
|
+
autoFocus: true,
|
|
3359
|
+
onKeyDown: (e) => {
|
|
3360
|
+
if (e.key === "Enter") {
|
|
3361
|
+
e.preventDefault();
|
|
3362
|
+
insertLink();
|
|
3363
|
+
}
|
|
3364
|
+
}
|
|
3365
|
+
}
|
|
3366
|
+
),
|
|
3367
|
+
/* @__PURE__ */ (0, import_jsx_runtime61.jsxs)("div", { className: "flex gap-2 justify-end", children: [
|
|
3368
|
+
/* @__PURE__ */ (0, import_jsx_runtime61.jsx)(
|
|
3369
|
+
Button,
|
|
3370
|
+
{
|
|
3371
|
+
variant: "secondary",
|
|
3372
|
+
onClick: () => {
|
|
3373
|
+
setShowLinkModal(false);
|
|
3374
|
+
setLinkUrl("");
|
|
3375
|
+
},
|
|
3376
|
+
children: "Cancel"
|
|
3377
|
+
}
|
|
3378
|
+
),
|
|
3379
|
+
/* @__PURE__ */ (0, import_jsx_runtime61.jsx)(
|
|
3380
|
+
Button,
|
|
3381
|
+
{
|
|
3382
|
+
variant: "primary",
|
|
3383
|
+
onClick: insertLink,
|
|
3384
|
+
disabled: !linkUrl,
|
|
3385
|
+
children: "Insert"
|
|
3386
|
+
}
|
|
3387
|
+
)
|
|
3388
|
+
] })
|
|
3389
|
+
] })
|
|
3390
|
+
}
|
|
3391
|
+
),
|
|
3392
|
+
/* @__PURE__ */ (0, import_jsx_runtime61.jsx)(
|
|
3393
|
+
Modal,
|
|
3394
|
+
{
|
|
3395
|
+
isOpen: showImageModal,
|
|
3396
|
+
onClose: () => {
|
|
3397
|
+
setShowImageModal(false);
|
|
3398
|
+
setImageUrl("");
|
|
3399
|
+
setImageAlt("");
|
|
3400
|
+
},
|
|
3401
|
+
title: "Insert Image",
|
|
3402
|
+
size: "sm",
|
|
3403
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime61.jsxs)("div", { className: "space-y-4", children: [
|
|
3404
|
+
/* @__PURE__ */ (0, import_jsx_runtime61.jsx)(
|
|
3405
|
+
TextInput,
|
|
3406
|
+
{
|
|
3407
|
+
label: "Image URL",
|
|
3408
|
+
value: imageUrl,
|
|
3409
|
+
onChange: (e) => setImageUrl(e.target.value),
|
|
3410
|
+
placeholder: "https://example.com/image.jpg",
|
|
3411
|
+
autoFocus: true,
|
|
3412
|
+
onKeyDown: (e) => {
|
|
3413
|
+
if (e.key === "Enter") {
|
|
3414
|
+
e.preventDefault();
|
|
3415
|
+
insertImage();
|
|
3416
|
+
}
|
|
3417
|
+
}
|
|
3418
|
+
}
|
|
3419
|
+
),
|
|
3420
|
+
/* @__PURE__ */ (0, import_jsx_runtime61.jsx)(
|
|
3421
|
+
TextInput,
|
|
3422
|
+
{
|
|
3423
|
+
label: "Alt Text (optional)",
|
|
3424
|
+
value: imageAlt,
|
|
3425
|
+
onChange: (e) => setImageAlt(e.target.value),
|
|
3426
|
+
placeholder: "Describe the image"
|
|
3427
|
+
}
|
|
3428
|
+
),
|
|
3429
|
+
/* @__PURE__ */ (0, import_jsx_runtime61.jsxs)("div", { className: "flex gap-2 justify-end", children: [
|
|
3430
|
+
/* @__PURE__ */ (0, import_jsx_runtime61.jsx)(
|
|
3431
|
+
Button,
|
|
3432
|
+
{
|
|
3433
|
+
variant: "secondary",
|
|
3434
|
+
onClick: () => {
|
|
3435
|
+
setShowImageModal(false);
|
|
3436
|
+
setImageUrl("");
|
|
3437
|
+
setImageAlt("");
|
|
3438
|
+
},
|
|
3439
|
+
children: "Cancel"
|
|
3440
|
+
}
|
|
3441
|
+
),
|
|
3442
|
+
/* @__PURE__ */ (0, import_jsx_runtime61.jsx)(
|
|
3443
|
+
Button,
|
|
3444
|
+
{
|
|
3445
|
+
variant: "primary",
|
|
3446
|
+
onClick: insertImage,
|
|
3447
|
+
disabled: !imageUrl,
|
|
3448
|
+
children: "Insert"
|
|
3449
|
+
}
|
|
3450
|
+
)
|
|
3451
|
+
] })
|
|
3452
|
+
] })
|
|
3453
|
+
}
|
|
3454
|
+
)
|
|
3455
|
+
] });
|
|
3456
|
+
};
|
|
3457
|
+
|
|
3458
|
+
// src/components/Toast.tsx
|
|
3459
|
+
var import_react21 = require("react");
|
|
3460
|
+
var import_jsx_runtime62 = require("react/jsx-runtime");
|
|
3461
|
+
var ToastContext = (0, import_react21.createContext)(void 0);
|
|
3462
|
+
var useToast = () => {
|
|
3463
|
+
const context = (0, import_react21.useContext)(ToastContext);
|
|
3464
|
+
if (!context) {
|
|
3465
|
+
throw new Error("useToast must be used within a ToastProvider");
|
|
3466
|
+
}
|
|
3467
|
+
return context;
|
|
3468
|
+
};
|
|
3469
|
+
var ToastProvider = ({ children, position = "top-right" }) => {
|
|
3470
|
+
const [toasts, setToasts] = (0, import_react21.useState)([]);
|
|
3471
|
+
const addToast = (0, import_react21.useCallback)((toast2) => {
|
|
3472
|
+
const id = Math.random().toString(36).substring(7);
|
|
3473
|
+
const newToast = { ...toast2, id };
|
|
3474
|
+
setToasts((prev) => [...prev, newToast]);
|
|
3475
|
+
const duration = toast2.duration || 5e3;
|
|
3476
|
+
setTimeout(() => {
|
|
3477
|
+
removeToast(id);
|
|
3478
|
+
}, duration);
|
|
3479
|
+
}, []);
|
|
3480
|
+
const removeToast = (0, import_react21.useCallback)((id) => {
|
|
3481
|
+
setToasts((prev) => prev.filter((toast2) => toast2.id !== id));
|
|
3482
|
+
}, []);
|
|
3483
|
+
const positionClasses2 = {
|
|
3484
|
+
"top-right": "top-4 right-4",
|
|
3485
|
+
"top-left": "top-4 left-4",
|
|
3486
|
+
"bottom-right": "bottom-4 right-4",
|
|
3487
|
+
"bottom-left": "bottom-4 left-4",
|
|
3488
|
+
"top-center": "top-4 left-1/2 -translate-x-1/2",
|
|
3489
|
+
"bottom-center": "bottom-4 left-1/2 -translate-x-1/2"
|
|
3490
|
+
};
|
|
3491
|
+
return /* @__PURE__ */ (0, import_jsx_runtime62.jsxs)(ToastContext.Provider, { value: { toasts, addToast, removeToast }, children: [
|
|
3492
|
+
children,
|
|
3493
|
+
/* @__PURE__ */ (0, import_jsx_runtime62.jsx)("div", { className: `fixed ${positionClasses2[position]} z-50 flex flex-col gap-2 max-w-md`, children: toasts.map((toast2) => /* @__PURE__ */ (0, import_jsx_runtime62.jsx)(ToastItem, { toast: toast2, onClose: () => removeToast(toast2.id) }, toast2.id)) })
|
|
3494
|
+
] });
|
|
3495
|
+
};
|
|
3496
|
+
var ToastItem = ({ toast: toast2, onClose }) => {
|
|
3497
|
+
const typeStyles = {
|
|
3498
|
+
success: "bg-green-50 dark:bg-green-900/30 border-green-500 text-green-800 dark:text-green-200",
|
|
3499
|
+
error: "bg-red-50 dark:bg-red-900/30 border-red-500 text-red-800 dark:text-red-200",
|
|
3500
|
+
warning: "bg-yellow-50 dark:bg-yellow-900/30 border-yellow-500 text-yellow-800 dark:text-yellow-200",
|
|
3501
|
+
info: "bg-blue-50 dark:bg-blue-900/30 border-blue-500 text-blue-800 dark:text-blue-200"
|
|
3502
|
+
};
|
|
3503
|
+
const typeIcons = {
|
|
3504
|
+
success: /* @__PURE__ */ (0, import_jsx_runtime62.jsx)(CheckIcon, { size: "sm", className: "text-green-600 dark:text-green-400" }),
|
|
3505
|
+
error: /* @__PURE__ */ (0, import_jsx_runtime62.jsx)(CloseIcon, { size: "sm", className: "text-red-600 dark:text-red-400" }),
|
|
3506
|
+
warning: /* @__PURE__ */ (0, import_jsx_runtime62.jsx)("svg", { className: "w-4 h-4 text-yellow-600 dark:text-yellow-400", fill: "currentColor", viewBox: "0 0 20 20", children: /* @__PURE__ */ (0, import_jsx_runtime62.jsx)("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" }) }),
|
|
3507
|
+
info: /* @__PURE__ */ (0, import_jsx_runtime62.jsx)("svg", { className: "w-4 h-4 text-blue-600 dark:text-blue-400", fill: "currentColor", viewBox: "0 0 20 20", children: /* @__PURE__ */ (0, import_jsx_runtime62.jsx)("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" }) })
|
|
3508
|
+
};
|
|
3509
|
+
const type = toast2.type || "info";
|
|
3510
|
+
return /* @__PURE__ */ (0, import_jsx_runtime62.jsxs)(
|
|
3511
|
+
"div",
|
|
3512
|
+
{
|
|
3513
|
+
className: `flex items-start gap-3 p-4 rounded-lg border-l-4 shadow-lg backdrop-blur-sm ${typeStyles[type]} animate-slide-in`,
|
|
3514
|
+
role: "alert",
|
|
3515
|
+
children: [
|
|
3516
|
+
/* @__PURE__ */ (0, import_jsx_runtime62.jsx)("div", { className: "flex-shrink-0 mt-0.5", children: typeIcons[type] }),
|
|
3517
|
+
/* @__PURE__ */ (0, import_jsx_runtime62.jsx)("p", { className: "flex-1 text-sm font-medium", children: toast2.message }),
|
|
3518
|
+
/* @__PURE__ */ (0, import_jsx_runtime62.jsx)(
|
|
3519
|
+
"button",
|
|
3520
|
+
{
|
|
3521
|
+
onClick: onClose,
|
|
3522
|
+
className: "flex-shrink-0 text-gray-400 hover:text-gray-600 dark:hover:text-gray-200 transition-colors",
|
|
3523
|
+
"aria-label": "Close",
|
|
3524
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime62.jsx)(CloseIcon, { size: "sm" })
|
|
3525
|
+
}
|
|
3526
|
+
)
|
|
3527
|
+
]
|
|
3528
|
+
}
|
|
3529
|
+
);
|
|
3530
|
+
};
|
|
3531
|
+
var toast = {
|
|
3532
|
+
success: (message, duration) => ({
|
|
3533
|
+
message,
|
|
3534
|
+
type: "success",
|
|
3535
|
+
duration
|
|
3536
|
+
}),
|
|
3537
|
+
error: (message, duration) => ({
|
|
3538
|
+
message,
|
|
3539
|
+
type: "error",
|
|
3540
|
+
duration
|
|
3541
|
+
}),
|
|
3542
|
+
warning: (message, duration) => ({
|
|
3543
|
+
message,
|
|
3544
|
+
type: "warning",
|
|
3545
|
+
duration
|
|
3546
|
+
}),
|
|
3547
|
+
info: (message, duration) => ({
|
|
3548
|
+
message,
|
|
3549
|
+
type: "info",
|
|
3550
|
+
duration
|
|
3551
|
+
})
|
|
3552
|
+
};
|
|
3553
|
+
|
|
3554
|
+
// src/components/Stepper.tsx
|
|
3555
|
+
var import_react22 = __toESM(require("react"));
|
|
3556
|
+
var import_jsx_runtime63 = require("react/jsx-runtime");
|
|
3557
|
+
var Stepper = ({
|
|
3558
|
+
steps,
|
|
3559
|
+
currentStep,
|
|
3560
|
+
orientation = "horizontal",
|
|
3561
|
+
className = ""
|
|
3562
|
+
}) => {
|
|
3563
|
+
const isHorizontal = orientation === "horizontal";
|
|
3564
|
+
return /* @__PURE__ */ (0, import_jsx_runtime63.jsx)("div", { className: `${isHorizontal ? "flex items-center" : "flex flex-col"} ${className}`, children: steps.map((step, index) => {
|
|
3565
|
+
const stepNumber = index + 1;
|
|
3566
|
+
const isActive = stepNumber === currentStep;
|
|
3567
|
+
const isCompleted = stepNumber < currentStep;
|
|
3568
|
+
const isLast = index === steps.length - 1;
|
|
3569
|
+
return /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)(import_react22.default.Fragment, { children: [
|
|
3570
|
+
/* @__PURE__ */ (0, import_jsx_runtime63.jsxs)("div", { className: `flex ${isHorizontal ? "flex-col items-center" : "flex-row items-start"} ${isHorizontal ? "" : "flex-1"}`, children: [
|
|
3571
|
+
/* @__PURE__ */ (0, import_jsx_runtime63.jsx)("div", { className: "flex items-center", children: /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(
|
|
3572
|
+
"div",
|
|
3573
|
+
{
|
|
3574
|
+
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"}`,
|
|
3575
|
+
children: isCompleted ? /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(CheckIcon, { size: "sm", className: "text-white" }) : /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(
|
|
3576
|
+
"span",
|
|
3577
|
+
{
|
|
3578
|
+
className: `text-sm font-semibold ${isActive ? "text-blue-600 dark:text-blue-400" : "text-gray-500 dark:text-gray-400"}`,
|
|
3579
|
+
children: stepNumber
|
|
3580
|
+
}
|
|
3581
|
+
)
|
|
3582
|
+
}
|
|
3583
|
+
) }),
|
|
3584
|
+
/* @__PURE__ */ (0, import_jsx_runtime63.jsxs)("div", { className: `${isHorizontal ? "mt-2 text-center" : "ml-4 pb-8"} ${isLast && !isHorizontal ? "pb-0" : ""}`, children: [
|
|
3585
|
+
/* @__PURE__ */ (0, import_jsx_runtime63.jsx)(
|
|
3586
|
+
"p",
|
|
3587
|
+
{
|
|
3588
|
+
className: `text-sm font-medium ${isActive || isCompleted ? "text-gray-900 dark:text-gray-100" : "text-gray-500 dark:text-gray-400"}`,
|
|
3589
|
+
children: step.label
|
|
3590
|
+
}
|
|
3591
|
+
),
|
|
3592
|
+
step.description && /* @__PURE__ */ (0, import_jsx_runtime63.jsx)("p", { className: "text-xs text-gray-500 dark:text-gray-400 mt-1", children: step.description })
|
|
3593
|
+
] })
|
|
3594
|
+
] }),
|
|
3595
|
+
!isLast && /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(
|
|
3596
|
+
"div",
|
|
3597
|
+
{
|
|
3598
|
+
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"}`
|
|
3599
|
+
}
|
|
3600
|
+
)
|
|
3601
|
+
] }, index);
|
|
3602
|
+
}) });
|
|
3603
|
+
};
|
|
3604
|
+
|
|
3605
|
+
// src/components/Divider.tsx
|
|
3606
|
+
var import_jsx_runtime64 = require("react/jsx-runtime");
|
|
3607
|
+
var Divider = ({
|
|
3608
|
+
orientation = "horizontal",
|
|
3609
|
+
variant = "solid",
|
|
3610
|
+
className = "",
|
|
3611
|
+
label,
|
|
3612
|
+
labelPosition = "center"
|
|
3613
|
+
}) => {
|
|
3614
|
+
const variantClasses = {
|
|
3615
|
+
solid: "border-solid",
|
|
3616
|
+
dashed: "border-dashed",
|
|
3617
|
+
dotted: "border-dotted"
|
|
3618
|
+
};
|
|
3619
|
+
if (label && orientation === "horizontal") {
|
|
3620
|
+
const alignmentClasses = {
|
|
3621
|
+
left: "justify-start",
|
|
3622
|
+
center: "justify-center",
|
|
3623
|
+
right: "justify-end"
|
|
3624
|
+
};
|
|
3625
|
+
return /* @__PURE__ */ (0, import_jsx_runtime64.jsxs)("div", { className: `flex items-center ${alignmentClasses[labelPosition]} ${className}`, role: "separator", children: [
|
|
3626
|
+
labelPosition !== "left" && /* @__PURE__ */ (0, import_jsx_runtime64.jsx)("div", { className: `flex-1 border-t ${variantClasses[variant]} border-gray-300 dark:border-gray-600` }),
|
|
3627
|
+
/* @__PURE__ */ (0, import_jsx_runtime64.jsx)("span", { className: "px-4 text-sm text-gray-500 dark:text-gray-400", children: label }),
|
|
3628
|
+
labelPosition !== "right" && /* @__PURE__ */ (0, import_jsx_runtime64.jsx)("div", { className: `flex-1 border-t ${variantClasses[variant]} border-gray-300 dark:border-gray-600` })
|
|
3629
|
+
] });
|
|
3630
|
+
}
|
|
3631
|
+
if (orientation === "vertical") {
|
|
3632
|
+
return /* @__PURE__ */ (0, import_jsx_runtime64.jsx)(
|
|
3633
|
+
"div",
|
|
3634
|
+
{
|
|
3635
|
+
className: `inline-block h-full border-l ${variantClasses[variant]} border-gray-300 dark:border-gray-600 ${className}`,
|
|
3636
|
+
role: "separator",
|
|
3637
|
+
"aria-orientation": "vertical"
|
|
3638
|
+
}
|
|
3639
|
+
);
|
|
3640
|
+
}
|
|
3641
|
+
return /* @__PURE__ */ (0, import_jsx_runtime64.jsx)(
|
|
3642
|
+
"hr",
|
|
3643
|
+
{
|
|
3644
|
+
className: `border-t ${variantClasses[variant]} border-gray-300 dark:border-gray-600 ${className}`,
|
|
3645
|
+
role: "separator"
|
|
3646
|
+
}
|
|
3647
|
+
);
|
|
3648
|
+
};
|
|
3649
|
+
|
|
3650
|
+
// src/components/FileUpload.tsx
|
|
3651
|
+
var import_react23 = require("react");
|
|
3652
|
+
var import_jsx_runtime65 = require("react/jsx-runtime");
|
|
3653
|
+
var FileUpload = ({
|
|
3654
|
+
accept,
|
|
3655
|
+
multiple = false,
|
|
3656
|
+
maxSize,
|
|
3657
|
+
maxFiles = 10,
|
|
3658
|
+
disabled = false,
|
|
3659
|
+
onChange,
|
|
3660
|
+
onError,
|
|
3661
|
+
className = "",
|
|
3662
|
+
label,
|
|
3663
|
+
helperText
|
|
3664
|
+
}) => {
|
|
3665
|
+
const [files, setFiles] = (0, import_react23.useState)([]);
|
|
3666
|
+
const [isDragging, setIsDragging] = (0, import_react23.useState)(false);
|
|
3667
|
+
const fileInputRef = (0, import_react23.useRef)(null);
|
|
3668
|
+
const formatFileSize = (bytes) => {
|
|
3669
|
+
if (bytes === 0) return "0 Bytes";
|
|
3670
|
+
const k = 1024;
|
|
3671
|
+
const sizes = ["Bytes", "KB", "MB", "GB"];
|
|
3672
|
+
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
3673
|
+
return Math.round(bytes / Math.pow(k, i) * 100) / 100 + " " + sizes[i];
|
|
3674
|
+
};
|
|
3675
|
+
const validateFiles = (fileList) => {
|
|
3676
|
+
const validFiles = [];
|
|
3677
|
+
const filesArray = Array.from(fileList);
|
|
3678
|
+
if (filesArray.length + files.length > maxFiles) {
|
|
3679
|
+
onError?.(`Maximum ${maxFiles} files allowed`);
|
|
3680
|
+
return validFiles;
|
|
3681
|
+
}
|
|
3682
|
+
for (const file of filesArray) {
|
|
3683
|
+
if (maxSize && file.size > maxSize) {
|
|
3684
|
+
onError?.(`File ${file.name} exceeds maximum size of ${formatFileSize(maxSize)}`);
|
|
3685
|
+
continue;
|
|
3686
|
+
}
|
|
3687
|
+
validFiles.push(file);
|
|
3688
|
+
}
|
|
3689
|
+
return validFiles;
|
|
3690
|
+
};
|
|
3691
|
+
const handleFiles = (fileList) => {
|
|
3692
|
+
if (!fileList || disabled) return;
|
|
3693
|
+
const validFiles = validateFiles(fileList);
|
|
3694
|
+
if (validFiles.length > 0) {
|
|
3695
|
+
const newFiles = multiple ? [...files, ...validFiles] : validFiles;
|
|
3696
|
+
setFiles(newFiles);
|
|
3697
|
+
onChange?.(newFiles);
|
|
3698
|
+
}
|
|
3699
|
+
};
|
|
3700
|
+
const handleDrop = (e) => {
|
|
3701
|
+
e.preventDefault();
|
|
3702
|
+
setIsDragging(false);
|
|
3703
|
+
handleFiles(e.dataTransfer.files);
|
|
3704
|
+
};
|
|
3705
|
+
const handleDragOver = (e) => {
|
|
3706
|
+
e.preventDefault();
|
|
3707
|
+
if (!disabled) {
|
|
3708
|
+
setIsDragging(true);
|
|
3709
|
+
}
|
|
3710
|
+
};
|
|
3711
|
+
const handleDragLeave = (e) => {
|
|
3712
|
+
e.preventDefault();
|
|
3713
|
+
setIsDragging(false);
|
|
3714
|
+
};
|
|
3715
|
+
const handleClick = () => {
|
|
3716
|
+
if (!disabled) {
|
|
3717
|
+
fileInputRef.current?.click();
|
|
3718
|
+
}
|
|
3719
|
+
};
|
|
3720
|
+
const handleRemoveFile = (index) => {
|
|
3721
|
+
const newFiles = files.filter((_, i) => i !== index);
|
|
3722
|
+
setFiles(newFiles);
|
|
3723
|
+
onChange?.(newFiles);
|
|
3724
|
+
};
|
|
3725
|
+
return /* @__PURE__ */ (0, import_jsx_runtime65.jsxs)("div", { className: `w-full ${className}`, children: [
|
|
3726
|
+
label && /* @__PURE__ */ (0, import_jsx_runtime65.jsx)("label", { className: "block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2", children: label }),
|
|
3727
|
+
/* @__PURE__ */ (0, import_jsx_runtime65.jsxs)(
|
|
3728
|
+
"div",
|
|
3729
|
+
{
|
|
3730
|
+
onDrop: handleDrop,
|
|
3731
|
+
onDragOver: handleDragOver,
|
|
3732
|
+
onDragLeave: handleDragLeave,
|
|
3733
|
+
onClick: handleClick,
|
|
3734
|
+
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" : ""}`,
|
|
3735
|
+
children: [
|
|
3736
|
+
/* @__PURE__ */ (0, import_jsx_runtime65.jsx)(
|
|
3737
|
+
"input",
|
|
3738
|
+
{
|
|
3739
|
+
ref: fileInputRef,
|
|
3740
|
+
type: "file",
|
|
3741
|
+
accept,
|
|
3742
|
+
multiple,
|
|
3743
|
+
onChange: (e) => handleFiles(e.target.files),
|
|
3744
|
+
disabled,
|
|
3745
|
+
className: "hidden"
|
|
3746
|
+
}
|
|
3747
|
+
),
|
|
3748
|
+
/* @__PURE__ */ (0, import_jsx_runtime65.jsxs)("div", { className: "flex flex-col items-center gap-2", children: [
|
|
3749
|
+
/* @__PURE__ */ (0, import_jsx_runtime65.jsx)("div", { className: "w-12 h-12 rounded-full bg-gray-100 dark:bg-gray-800 flex items-center justify-center", children: /* @__PURE__ */ (0, import_jsx_runtime65.jsx)(UploadIcon, { size: "lg", className: "text-gray-400 dark:text-gray-500" }) }),
|
|
3750
|
+
/* @__PURE__ */ (0, import_jsx_runtime65.jsxs)("div", { children: [
|
|
3751
|
+
/* @__PURE__ */ (0, import_jsx_runtime65.jsxs)("p", { className: "text-sm font-medium text-gray-700 dark:text-gray-300", children: [
|
|
3752
|
+
/* @__PURE__ */ (0, import_jsx_runtime65.jsx)("span", { className: "text-blue-600 dark:text-blue-400", children: "Click to upload" }),
|
|
3753
|
+
" or drag and drop"
|
|
3754
|
+
] }),
|
|
3755
|
+
/* @__PURE__ */ (0, import_jsx_runtime65.jsxs)("p", { className: "text-xs text-gray-500 dark:text-gray-400 mt-1", children: [
|
|
3756
|
+
accept ? `Accepted: ${accept}` : "Any file type",
|
|
3757
|
+
maxSize && ` \u2022 Max size: ${formatFileSize(maxSize)}`
|
|
3758
|
+
] })
|
|
3759
|
+
] })
|
|
3760
|
+
] })
|
|
3761
|
+
]
|
|
3762
|
+
}
|
|
3763
|
+
),
|
|
3764
|
+
helperText && /* @__PURE__ */ (0, import_jsx_runtime65.jsx)("p", { className: "mt-2 text-sm text-gray-500 dark:text-gray-400", children: helperText }),
|
|
3765
|
+
files.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime65.jsx)("div", { className: "mt-4 space-y-2", children: files.map((file, index) => /* @__PURE__ */ (0, import_jsx_runtime65.jsxs)(
|
|
3766
|
+
"div",
|
|
3767
|
+
{
|
|
3768
|
+
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",
|
|
3769
|
+
children: [
|
|
3770
|
+
/* @__PURE__ */ (0, import_jsx_runtime65.jsxs)("div", { className: "flex-1 min-w-0", children: [
|
|
3771
|
+
/* @__PURE__ */ (0, import_jsx_runtime65.jsx)("p", { className: "text-sm font-medium text-gray-900 dark:text-gray-100 truncate", children: file.name }),
|
|
3772
|
+
/* @__PURE__ */ (0, import_jsx_runtime65.jsx)("p", { className: "text-xs text-gray-500 dark:text-gray-400", children: formatFileSize(file.size) })
|
|
3773
|
+
] }),
|
|
3774
|
+
/* @__PURE__ */ (0, import_jsx_runtime65.jsx)(
|
|
3775
|
+
"button",
|
|
3776
|
+
{
|
|
3777
|
+
onClick: (e) => {
|
|
3778
|
+
e.stopPropagation();
|
|
3779
|
+
handleRemoveFile(index);
|
|
3780
|
+
},
|
|
3781
|
+
className: "ml-4 text-gray-400 hover:text-red-600 dark:hover:text-red-400 transition-colors",
|
|
3782
|
+
"aria-label": "Remove file",
|
|
3783
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime65.jsx)(CloseIcon, { size: "sm" })
|
|
3784
|
+
}
|
|
3785
|
+
)
|
|
3786
|
+
]
|
|
3787
|
+
},
|
|
3788
|
+
index
|
|
3789
|
+
)) })
|
|
313
3790
|
] });
|
|
314
3791
|
};
|
|
315
3792
|
|
|
@@ -347,12 +3824,76 @@ function getThemeScript() {
|
|
|
347
3824
|
}
|
|
348
3825
|
// Annotate the CommonJS export names for ESM import in node:
|
|
349
3826
|
0 && (module.exports = {
|
|
3827
|
+
ActionMenu,
|
|
3828
|
+
Alert,
|
|
3829
|
+
AppShell,
|
|
3830
|
+
AppleIcon,
|
|
3831
|
+
Avatar,
|
|
3832
|
+
Badge,
|
|
3833
|
+
BellIcon,
|
|
350
3834
|
Button,
|
|
3835
|
+
Calendar,
|
|
3836
|
+
CalendarIcon,
|
|
3837
|
+
CameraIcon,
|
|
3838
|
+
Card,
|
|
3839
|
+
CheckIcon,
|
|
3840
|
+
Checkbox,
|
|
3841
|
+
ChevronDownIcon,
|
|
3842
|
+
ChevronRightIcon,
|
|
3843
|
+
CloseIcon,
|
|
3844
|
+
DatePicker,
|
|
3845
|
+
DateTimePicker,
|
|
3846
|
+
Divider,
|
|
3847
|
+
DownloadIcon,
|
|
3848
|
+
Drawer,
|
|
3849
|
+
EditIcon,
|
|
3850
|
+
FacebookIcon,
|
|
3851
|
+
FileUpload,
|
|
3852
|
+
GitHubIcon,
|
|
3853
|
+
GoogleIcon,
|
|
3854
|
+
HeartIcon,
|
|
3855
|
+
HomeIcon,
|
|
3856
|
+
LinkedInIcon,
|
|
3857
|
+
LockIcon,
|
|
3858
|
+
MailIcon,
|
|
3859
|
+
MenuIcon,
|
|
3860
|
+
Modal,
|
|
3861
|
+
Navbar,
|
|
3862
|
+
NumberInput,
|
|
3863
|
+
Pagination,
|
|
3864
|
+
PlusIcon,
|
|
3865
|
+
ProgressBar,
|
|
3866
|
+
Radio,
|
|
3867
|
+
RichTextEditor,
|
|
3868
|
+
SearchIcon,
|
|
351
3869
|
Select,
|
|
3870
|
+
SettingsIcon,
|
|
3871
|
+
Sidebar,
|
|
3872
|
+
SidebarProvider,
|
|
3873
|
+
SlackIcon,
|
|
3874
|
+
Slider,
|
|
3875
|
+
Spinner,
|
|
3876
|
+
StarIcon,
|
|
3877
|
+
Stepper,
|
|
3878
|
+
Table,
|
|
3879
|
+
Tabs,
|
|
3880
|
+
TextInput,
|
|
3881
|
+
Textarea,
|
|
352
3882
|
ThemeProvider,
|
|
3883
|
+
TimePicker,
|
|
3884
|
+
ToastProvider,
|
|
3885
|
+
Toggle,
|
|
3886
|
+
TrashIcon,
|
|
3887
|
+
TwitterIcon,
|
|
3888
|
+
UploadIcon,
|
|
3889
|
+
UserIcon,
|
|
3890
|
+
YouTubeIcon,
|
|
353
3891
|
getThemeScript,
|
|
354
3892
|
themeScript,
|
|
355
3893
|
themes,
|
|
356
|
-
|
|
3894
|
+
toast,
|
|
3895
|
+
useSidebar,
|
|
3896
|
+
useTheme,
|
|
3897
|
+
useToast
|
|
357
3898
|
});
|
|
358
3899
|
//# sourceMappingURL=index.js.map
|