@mohasinac/ui 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +2440 -0
- package/dist/index.d.cts +829 -0
- package/dist/index.d.ts +829 -0
- package/dist/index.js +2371 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/package.json +42 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,2371 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __defProps = Object.defineProperties;
|
|
3
|
+
var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
|
|
4
|
+
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __propIsEnum = Object.prototype.propertyIsEnumerable;
|
|
7
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
8
|
+
var __spreadValues = (a, b) => {
|
|
9
|
+
for (var prop in b || (b = {}))
|
|
10
|
+
if (__hasOwnProp.call(b, prop))
|
|
11
|
+
__defNormalProp(a, prop, b[prop]);
|
|
12
|
+
if (__getOwnPropSymbols)
|
|
13
|
+
for (var prop of __getOwnPropSymbols(b)) {
|
|
14
|
+
if (__propIsEnum.call(b, prop))
|
|
15
|
+
__defNormalProp(a, prop, b[prop]);
|
|
16
|
+
}
|
|
17
|
+
return a;
|
|
18
|
+
};
|
|
19
|
+
var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
|
|
20
|
+
var __objRest = (source, exclude) => {
|
|
21
|
+
var target = {};
|
|
22
|
+
for (var prop in source)
|
|
23
|
+
if (__hasOwnProp.call(source, prop) && exclude.indexOf(prop) < 0)
|
|
24
|
+
target[prop] = source[prop];
|
|
25
|
+
if (source != null && __getOwnPropSymbols)
|
|
26
|
+
for (var prop of __getOwnPropSymbols(source)) {
|
|
27
|
+
if (exclude.indexOf(prop) < 0 && __propIsEnum.call(source, prop))
|
|
28
|
+
target[prop] = source[prop];
|
|
29
|
+
}
|
|
30
|
+
return target;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
// src/components/Semantic.tsx
|
|
34
|
+
import React from "react";
|
|
35
|
+
import { jsx } from "react/jsx-runtime";
|
|
36
|
+
var Section = React.forwardRef(
|
|
37
|
+
(_a, ref) => {
|
|
38
|
+
var _b = _a, { className = "", children } = _b, props = __objRest(_b, ["className", "children"]);
|
|
39
|
+
return /* @__PURE__ */ jsx("section", __spreadProps(__spreadValues({ className, ref }, props), { children }));
|
|
40
|
+
}
|
|
41
|
+
);
|
|
42
|
+
Section.displayName = "Section";
|
|
43
|
+
function Article(_a) {
|
|
44
|
+
var _b = _a, { className = "", children } = _b, props = __objRest(_b, ["className", "children"]);
|
|
45
|
+
return /* @__PURE__ */ jsx("article", __spreadProps(__spreadValues({ className }, props), { children }));
|
|
46
|
+
}
|
|
47
|
+
function Main(_a) {
|
|
48
|
+
var _b = _a, { className = "", children } = _b, props = __objRest(_b, ["className", "children"]);
|
|
49
|
+
return /* @__PURE__ */ jsx("main", __spreadProps(__spreadValues({ className }, props), { children }));
|
|
50
|
+
}
|
|
51
|
+
var Aside = React.forwardRef(
|
|
52
|
+
(_a, ref) => {
|
|
53
|
+
var _b = _a, { className = "", children } = _b, props = __objRest(_b, ["className", "children"]);
|
|
54
|
+
return /* @__PURE__ */ jsx("aside", __spreadProps(__spreadValues({ className, ref }, props), { children }));
|
|
55
|
+
}
|
|
56
|
+
);
|
|
57
|
+
Aside.displayName = "Aside";
|
|
58
|
+
function Nav(_a) {
|
|
59
|
+
var _b = _a, { className = "", children } = _b, props = __objRest(_b, ["className", "children"]);
|
|
60
|
+
return /* @__PURE__ */ jsx("nav", __spreadProps(__spreadValues({ className }, props), { children }));
|
|
61
|
+
}
|
|
62
|
+
function BlockHeader(_a) {
|
|
63
|
+
var _b = _a, {
|
|
64
|
+
className = "",
|
|
65
|
+
children
|
|
66
|
+
} = _b, props = __objRest(_b, [
|
|
67
|
+
"className",
|
|
68
|
+
"children"
|
|
69
|
+
]);
|
|
70
|
+
return /* @__PURE__ */ jsx("header", __spreadProps(__spreadValues({ className }, props), { children }));
|
|
71
|
+
}
|
|
72
|
+
function BlockFooter(_a) {
|
|
73
|
+
var _b = _a, {
|
|
74
|
+
className = "",
|
|
75
|
+
children
|
|
76
|
+
} = _b, props = __objRest(_b, [
|
|
77
|
+
"className",
|
|
78
|
+
"children"
|
|
79
|
+
]);
|
|
80
|
+
return /* @__PURE__ */ jsx("footer", __spreadProps(__spreadValues({ className }, props), { children }));
|
|
81
|
+
}
|
|
82
|
+
function Ul(_a) {
|
|
83
|
+
var _b = _a, { className = "", children } = _b, props = __objRest(_b, ["className", "children"]);
|
|
84
|
+
return /* @__PURE__ */ jsx("ul", __spreadProps(__spreadValues({ className }, props), { children }));
|
|
85
|
+
}
|
|
86
|
+
function Ol(_a) {
|
|
87
|
+
var _b = _a, { className = "", children } = _b, props = __objRest(_b, ["className", "children"]);
|
|
88
|
+
return /* @__PURE__ */ jsx("ol", __spreadProps(__spreadValues({ className }, props), { children }));
|
|
89
|
+
}
|
|
90
|
+
function Li(_a) {
|
|
91
|
+
var _b = _a, { className = "", children } = _b, props = __objRest(_b, ["className", "children"]);
|
|
92
|
+
return /* @__PURE__ */ jsx("li", __spreadProps(__spreadValues({ className }, props), { children }));
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// src/components/Typography.tsx
|
|
96
|
+
import { jsx as jsx2, jsxs } from "react/jsx-runtime";
|
|
97
|
+
var UI_THEME = {
|
|
98
|
+
typography: {
|
|
99
|
+
h1: "text-3xl md:text-4xl lg:text-5xl font-bold tracking-tight font-display",
|
|
100
|
+
h2: "text-2xl md:text-3xl lg:text-4xl font-bold tracking-tight font-display",
|
|
101
|
+
h3: "text-xl md:text-2xl lg:text-3xl font-bold tracking-tight font-display",
|
|
102
|
+
h4: "text-lg md:text-xl lg:text-2xl font-bold font-display",
|
|
103
|
+
h5: "text-base md:text-lg lg:text-xl font-medium",
|
|
104
|
+
h6: "text-sm md:text-base lg:text-lg font-medium",
|
|
105
|
+
body: "text-base lg:text-lg",
|
|
106
|
+
small: "text-sm lg:text-base",
|
|
107
|
+
xs: "text-xs lg:text-sm"
|
|
108
|
+
},
|
|
109
|
+
themed: {
|
|
110
|
+
textPrimary: "text-zinc-900 dark:text-zinc-50",
|
|
111
|
+
textSecondary: "text-zinc-500 dark:text-zinc-400",
|
|
112
|
+
textMuted: "text-zinc-400 dark:text-zinc-500",
|
|
113
|
+
textError: "text-red-600 dark:text-red-400",
|
|
114
|
+
textSuccess: "text-emerald-600 dark:text-emerald-400"
|
|
115
|
+
},
|
|
116
|
+
colors: {
|
|
117
|
+
form: {
|
|
118
|
+
required: "text-red-500"
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
function Heading(_a) {
|
|
123
|
+
var _b = _a, {
|
|
124
|
+
level = 1,
|
|
125
|
+
variant = "primary",
|
|
126
|
+
className = "",
|
|
127
|
+
children
|
|
128
|
+
} = _b, props = __objRest(_b, [
|
|
129
|
+
"level",
|
|
130
|
+
"variant",
|
|
131
|
+
"className",
|
|
132
|
+
"children"
|
|
133
|
+
]);
|
|
134
|
+
const Tag = `h${level}`;
|
|
135
|
+
const { typography, themed } = UI_THEME;
|
|
136
|
+
const sizeClasses = {
|
|
137
|
+
1: typography.h1,
|
|
138
|
+
2: typography.h2,
|
|
139
|
+
3: typography.h3,
|
|
140
|
+
4: typography.h4,
|
|
141
|
+
5: typography.h5,
|
|
142
|
+
6: typography.h6
|
|
143
|
+
};
|
|
144
|
+
const variantClasses = {
|
|
145
|
+
primary: themed.textPrimary,
|
|
146
|
+
secondary: themed.textSecondary,
|
|
147
|
+
muted: themed.textMuted,
|
|
148
|
+
none: ""
|
|
149
|
+
};
|
|
150
|
+
return /* @__PURE__ */ jsx2(
|
|
151
|
+
Tag,
|
|
152
|
+
__spreadProps(__spreadValues({
|
|
153
|
+
className: `${sizeClasses[level]} ${variantClasses[variant]} ${className}`
|
|
154
|
+
}, props), {
|
|
155
|
+
children
|
|
156
|
+
})
|
|
157
|
+
);
|
|
158
|
+
}
|
|
159
|
+
function Text(_a) {
|
|
160
|
+
var _b = _a, {
|
|
161
|
+
variant = "primary",
|
|
162
|
+
size = "base",
|
|
163
|
+
weight = "normal",
|
|
164
|
+
className = "",
|
|
165
|
+
children
|
|
166
|
+
} = _b, props = __objRest(_b, [
|
|
167
|
+
"variant",
|
|
168
|
+
"size",
|
|
169
|
+
"weight",
|
|
170
|
+
"className",
|
|
171
|
+
"children"
|
|
172
|
+
]);
|
|
173
|
+
const { typography, themed } = UI_THEME;
|
|
174
|
+
const sizeClasses = {
|
|
175
|
+
xs: typography.xs,
|
|
176
|
+
sm: typography.small,
|
|
177
|
+
base: typography.body,
|
|
178
|
+
lg: "text-lg",
|
|
179
|
+
xl: "text-xl"
|
|
180
|
+
};
|
|
181
|
+
const weightClasses = {
|
|
182
|
+
normal: "font-normal",
|
|
183
|
+
medium: "font-medium",
|
|
184
|
+
semibold: "font-semibold",
|
|
185
|
+
bold: "font-bold"
|
|
186
|
+
};
|
|
187
|
+
const variantClasses = {
|
|
188
|
+
primary: themed.textPrimary,
|
|
189
|
+
secondary: themed.textSecondary,
|
|
190
|
+
muted: themed.textMuted,
|
|
191
|
+
error: themed.textError,
|
|
192
|
+
success: themed.textSuccess,
|
|
193
|
+
none: ""
|
|
194
|
+
};
|
|
195
|
+
return /* @__PURE__ */ jsx2(
|
|
196
|
+
"p",
|
|
197
|
+
__spreadProps(__spreadValues({
|
|
198
|
+
className: `${sizeClasses[size]} ${weightClasses[weight]} ${variantClasses[variant]} ${className}`
|
|
199
|
+
}, props), {
|
|
200
|
+
children
|
|
201
|
+
})
|
|
202
|
+
);
|
|
203
|
+
}
|
|
204
|
+
function Label(_a) {
|
|
205
|
+
var _b = _a, {
|
|
206
|
+
required,
|
|
207
|
+
className = "",
|
|
208
|
+
children
|
|
209
|
+
} = _b, props = __objRest(_b, [
|
|
210
|
+
"required",
|
|
211
|
+
"className",
|
|
212
|
+
"children"
|
|
213
|
+
]);
|
|
214
|
+
const { themed, typography, colors } = UI_THEME;
|
|
215
|
+
return /* @__PURE__ */ jsxs(
|
|
216
|
+
"label",
|
|
217
|
+
__spreadProps(__spreadValues({
|
|
218
|
+
className: `block ${typography.small} font-medium ${themed.textSecondary} mb-1.5 ${className}`
|
|
219
|
+
}, props), {
|
|
220
|
+
children: [
|
|
221
|
+
children,
|
|
222
|
+
required && /* @__PURE__ */ jsx2("span", { className: `${colors.form.required} ml-1`, children: "*" })
|
|
223
|
+
]
|
|
224
|
+
})
|
|
225
|
+
);
|
|
226
|
+
}
|
|
227
|
+
function Caption(_a) {
|
|
228
|
+
var _b = _a, {
|
|
229
|
+
variant = "default",
|
|
230
|
+
className = "",
|
|
231
|
+
children
|
|
232
|
+
} = _b, props = __objRest(_b, [
|
|
233
|
+
"variant",
|
|
234
|
+
"className",
|
|
235
|
+
"children"
|
|
236
|
+
]);
|
|
237
|
+
const { themed, typography } = UI_THEME;
|
|
238
|
+
const variantClasses = {
|
|
239
|
+
default: themed.textMuted,
|
|
240
|
+
accent: "text-primary font-semibold",
|
|
241
|
+
inverse: "text-primary/40"
|
|
242
|
+
};
|
|
243
|
+
return /* @__PURE__ */ jsx2(
|
|
244
|
+
"span",
|
|
245
|
+
__spreadProps(__spreadValues({
|
|
246
|
+
className: `${typography.xs} ${variantClasses[variant]} ${className}`
|
|
247
|
+
}, props), {
|
|
248
|
+
children
|
|
249
|
+
})
|
|
250
|
+
);
|
|
251
|
+
}
|
|
252
|
+
function Span(_a) {
|
|
253
|
+
var _b = _a, {
|
|
254
|
+
variant = "inherit",
|
|
255
|
+
size,
|
|
256
|
+
weight,
|
|
257
|
+
className = "",
|
|
258
|
+
children
|
|
259
|
+
} = _b, props = __objRest(_b, [
|
|
260
|
+
"variant",
|
|
261
|
+
"size",
|
|
262
|
+
"weight",
|
|
263
|
+
"className",
|
|
264
|
+
"children"
|
|
265
|
+
]);
|
|
266
|
+
const { themed, typography } = UI_THEME;
|
|
267
|
+
const variantClasses = {
|
|
268
|
+
inherit: "",
|
|
269
|
+
primary: themed.textPrimary,
|
|
270
|
+
secondary: themed.textSecondary,
|
|
271
|
+
muted: themed.textMuted,
|
|
272
|
+
error: themed.textError,
|
|
273
|
+
success: themed.textSuccess,
|
|
274
|
+
accent: "text-primary"
|
|
275
|
+
};
|
|
276
|
+
const sizeClasses = {
|
|
277
|
+
xs: typography.xs,
|
|
278
|
+
sm: typography.small,
|
|
279
|
+
base: typography.body,
|
|
280
|
+
lg: "text-lg",
|
|
281
|
+
xl: "text-xl"
|
|
282
|
+
};
|
|
283
|
+
const weightClasses = {
|
|
284
|
+
normal: "font-normal",
|
|
285
|
+
medium: "font-medium",
|
|
286
|
+
semibold: "font-semibold",
|
|
287
|
+
bold: "font-bold"
|
|
288
|
+
};
|
|
289
|
+
const classes = [
|
|
290
|
+
size ? sizeClasses[size] : "",
|
|
291
|
+
weight ? weightClasses[weight] : "",
|
|
292
|
+
variantClasses[variant],
|
|
293
|
+
className
|
|
294
|
+
].filter(Boolean).join(" ");
|
|
295
|
+
return /* @__PURE__ */ jsx2("span", __spreadProps(__spreadValues({ className: classes }, props), { children }));
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
// src/components/Spinner.tsx
|
|
299
|
+
import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
300
|
+
function Spinner({
|
|
301
|
+
size = "md",
|
|
302
|
+
variant = "primary",
|
|
303
|
+
className = "",
|
|
304
|
+
label = "Loading..."
|
|
305
|
+
}) {
|
|
306
|
+
const sizeClasses = {
|
|
307
|
+
sm: "w-4 h-4 border-2",
|
|
308
|
+
md: "w-8 h-8 border-2",
|
|
309
|
+
lg: "w-12 h-12 border-[3px]",
|
|
310
|
+
xl: "w-16 h-16 border-4"
|
|
311
|
+
};
|
|
312
|
+
const variantClasses = {
|
|
313
|
+
primary: "border-primary-600 border-t-transparent dark:border-secondary-500 dark:border-t-transparent",
|
|
314
|
+
white: "border-white border-t-transparent",
|
|
315
|
+
current: "border-current border-t-transparent"
|
|
316
|
+
};
|
|
317
|
+
return /* @__PURE__ */ jsxs2(
|
|
318
|
+
"div",
|
|
319
|
+
{
|
|
320
|
+
className: `inline-flex items-center gap-3 ${className}`,
|
|
321
|
+
role: "status",
|
|
322
|
+
"aria-label": label,
|
|
323
|
+
children: [
|
|
324
|
+
/* @__PURE__ */ jsx3(
|
|
325
|
+
"div",
|
|
326
|
+
{
|
|
327
|
+
className: `${sizeClasses[size]} ${variantClasses[variant]} rounded-full animate-spin`
|
|
328
|
+
}
|
|
329
|
+
),
|
|
330
|
+
label && /* @__PURE__ */ jsx3("span", { className: "sr-only", children: label })
|
|
331
|
+
]
|
|
332
|
+
}
|
|
333
|
+
);
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
// src/components/Skeleton.tsx
|
|
337
|
+
import { Fragment, jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
338
|
+
var BG_TERTIARY = "bg-zinc-100 dark:bg-slate-800";
|
|
339
|
+
var WAVE_CSS = `
|
|
340
|
+
@keyframes lir-skeleton-wave {
|
|
341
|
+
0% { transform: translateX(-100%); }
|
|
342
|
+
50%, 100% { transform: translateX(100%); }
|
|
343
|
+
}
|
|
344
|
+
.lir-skeleton-wave {
|
|
345
|
+
position: relative;
|
|
346
|
+
overflow: hidden;
|
|
347
|
+
}
|
|
348
|
+
.lir-skeleton-wave::after {
|
|
349
|
+
content: "";
|
|
350
|
+
position: absolute;
|
|
351
|
+
top: 0; left: 0; right: 0; bottom: 0;
|
|
352
|
+
background: linear-gradient(90deg, transparent, rgba(255,255,255,0.5), transparent);
|
|
353
|
+
animation: lir-skeleton-wave 1.5s infinite;
|
|
354
|
+
}
|
|
355
|
+
`;
|
|
356
|
+
function Skeleton({
|
|
357
|
+
variant = "text",
|
|
358
|
+
width,
|
|
359
|
+
height,
|
|
360
|
+
className = "",
|
|
361
|
+
animation = "pulse"
|
|
362
|
+
}) {
|
|
363
|
+
const variantClass = variant === "circular" ? "rounded-full" : "rounded";
|
|
364
|
+
const defaultSize = {
|
|
365
|
+
circular: { width: "40px", height: "40px" },
|
|
366
|
+
rectangular: { width: "100%", height: "140px" },
|
|
367
|
+
text: { width: "100%", height: "1em" }
|
|
368
|
+
}[variant];
|
|
369
|
+
const animationClass = {
|
|
370
|
+
pulse: "animate-pulse",
|
|
371
|
+
wave: "lir-skeleton-wave",
|
|
372
|
+
none: ""
|
|
373
|
+
}[animation];
|
|
374
|
+
const style = {
|
|
375
|
+
width: width != null ? width : defaultSize.width,
|
|
376
|
+
height: height != null ? height : defaultSize.height
|
|
377
|
+
};
|
|
378
|
+
return /* @__PURE__ */ jsxs3(Fragment, { children: [
|
|
379
|
+
animation === "wave" && // eslint-disable-next-line react/no-danger
|
|
380
|
+
/* @__PURE__ */ jsx4("style", { dangerouslySetInnerHTML: { __html: WAVE_CSS } }),
|
|
381
|
+
/* @__PURE__ */ jsx4(
|
|
382
|
+
"div",
|
|
383
|
+
{
|
|
384
|
+
className: `${BG_TERTIARY} ${variantClass} ${animationClass} ${className}`,
|
|
385
|
+
style,
|
|
386
|
+
role: "status",
|
|
387
|
+
"aria-label": "Loading",
|
|
388
|
+
children: /* @__PURE__ */ jsx4("span", { className: "sr-only", children: "Loading..." })
|
|
389
|
+
}
|
|
390
|
+
)
|
|
391
|
+
] });
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
// src/components/Button.tsx
|
|
395
|
+
import { twMerge } from "tailwind-merge";
|
|
396
|
+
import { Loader2 } from "lucide-react";
|
|
397
|
+
import { jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
398
|
+
var UI_BUTTON = {
|
|
399
|
+
base: "inline-flex items-center justify-center font-medium rounded-xl transition-all duration-200 focus:outline-none focus:ring-2 focus:ring-offset-2 disabled:opacity-50 disabled:cursor-not-allowed",
|
|
400
|
+
active: "active:scale-95",
|
|
401
|
+
variants: {
|
|
402
|
+
primary: "bg-primary-600 text-white hover:bg-primary-700 active:bg-primary-800 shadow-sm focus:ring-primary-500/30 dark:bg-secondary-500 dark:text-white dark:hover:bg-secondary-400 dark:active:bg-secondary-600 dark:focus:ring-secondary-400/30",
|
|
403
|
+
secondary: "bg-primary-700 text-white hover:bg-primary-600 active:bg-primary-800 shadow-md focus:ring-primary-500 dark:bg-secondary-700 dark:text-white dark:hover:bg-secondary-600 dark:active:bg-secondary-800 dark:focus:ring-secondary-500",
|
|
404
|
+
outline: "border border-zinc-200 dark:border-slate-700 bg-white dark:bg-transparent text-zinc-900 dark:text-zinc-100 hover:bg-zinc-50 dark:hover:bg-slate-800 focus:ring-zinc-400",
|
|
405
|
+
ghost: "text-zinc-700 dark:text-zinc-300 hover:bg-zinc-100 dark:hover:bg-slate-800 focus:ring-zinc-400",
|
|
406
|
+
danger: "bg-red-600 text-white hover:bg-red-500 active:bg-red-700 shadow-sm shadow-red-600/10 focus:ring-red-500",
|
|
407
|
+
warning: "bg-amber-500 text-white hover:bg-amber-400 active:bg-amber-600 shadow-sm shadow-amber-500/10 focus:ring-amber-500"
|
|
408
|
+
},
|
|
409
|
+
sizes: {
|
|
410
|
+
sm: "px-2.5 py-1.5 text-xs sm:px-3 sm:text-sm gap-1.5 min-h-[36px]",
|
|
411
|
+
md: "px-3 py-2 text-sm sm:px-4 sm:py-2.5 sm:text-base gap-2 min-h-[44px]",
|
|
412
|
+
lg: "px-4 py-2.5 text-base sm:px-6 sm:py-3 sm:text-lg gap-2.5 min-h-[44px]"
|
|
413
|
+
}
|
|
414
|
+
};
|
|
415
|
+
function Button(_a) {
|
|
416
|
+
var _b = _a, {
|
|
417
|
+
variant = "primary",
|
|
418
|
+
size = "md",
|
|
419
|
+
className = "",
|
|
420
|
+
isLoading = false,
|
|
421
|
+
disabled,
|
|
422
|
+
children
|
|
423
|
+
} = _b, props = __objRest(_b, [
|
|
424
|
+
"variant",
|
|
425
|
+
"size",
|
|
426
|
+
"className",
|
|
427
|
+
"isLoading",
|
|
428
|
+
"disabled",
|
|
429
|
+
"children"
|
|
430
|
+
]);
|
|
431
|
+
return /* @__PURE__ */ jsxs4(
|
|
432
|
+
"button",
|
|
433
|
+
__spreadProps(__spreadValues({
|
|
434
|
+
className: twMerge(
|
|
435
|
+
UI_BUTTON.base,
|
|
436
|
+
UI_BUTTON.active,
|
|
437
|
+
UI_BUTTON.variants[variant],
|
|
438
|
+
UI_BUTTON.sizes[size],
|
|
439
|
+
className
|
|
440
|
+
),
|
|
441
|
+
disabled: disabled || isLoading,
|
|
442
|
+
"aria-busy": isLoading || void 0
|
|
443
|
+
}, props), {
|
|
444
|
+
children: [
|
|
445
|
+
isLoading && /* @__PURE__ */ jsx5(
|
|
446
|
+
Loader2,
|
|
447
|
+
{
|
|
448
|
+
className: "w-4 h-4 animate-spin flex-shrink-0",
|
|
449
|
+
"aria-hidden": "true"
|
|
450
|
+
}
|
|
451
|
+
),
|
|
452
|
+
isLoading ? /* @__PURE__ */ jsx5("span", { className: "opacity-70", children }) : children
|
|
453
|
+
]
|
|
454
|
+
})
|
|
455
|
+
);
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
// src/components/Badge.tsx
|
|
459
|
+
import { jsx as jsx6 } from "react/jsx-runtime";
|
|
460
|
+
var BADGE_CLASSES = {
|
|
461
|
+
// Status badges
|
|
462
|
+
active: "inline-flex items-center gap-1 px-2.5 py-0.5 text-xs font-semibold rounded-full bg-emerald-50 text-emerald-700 ring-1 ring-emerald-600/20 dark:bg-emerald-900/30 dark:text-emerald-300 dark:ring-emerald-400/20",
|
|
463
|
+
inactive: "inline-flex items-center gap-1 px-2.5 py-0.5 text-xs font-semibold rounded-full bg-zinc-100 text-zinc-600 ring-1 ring-zinc-500/10 dark:bg-slate-800 dark:text-zinc-400 dark:ring-zinc-400/20",
|
|
464
|
+
pending: "inline-flex items-center gap-1 px-2.5 py-0.5 text-xs font-semibold rounded-full bg-amber-50 text-amber-700 ring-1 ring-amber-600/20 dark:bg-amber-900/30 dark:text-amber-300 dark:ring-amber-400/20",
|
|
465
|
+
approved: "inline-flex items-center gap-1 px-2.5 py-0.5 text-xs font-semibold rounded-full bg-emerald-50 text-emerald-700 ring-1 ring-emerald-600/20 dark:bg-emerald-900/30 dark:text-emerald-300 dark:ring-emerald-400/20",
|
|
466
|
+
rejected: "inline-flex items-center gap-1 px-2.5 py-0.5 text-xs font-semibold rounded-full bg-rose-50 text-rose-700 ring-1 ring-rose-600/20 dark:bg-rose-900/30 dark:text-rose-300 dark:ring-rose-400/20",
|
|
467
|
+
// Semantic badges
|
|
468
|
+
success: "inline-flex items-center gap-1 px-2.5 py-0.5 text-xs font-semibold rounded-full bg-emerald-50 text-emerald-700 ring-1 ring-emerald-600/20 dark:bg-emerald-900/30 dark:text-emerald-300 dark:ring-emerald-400/20",
|
|
469
|
+
warning: "inline-flex items-center gap-1 px-2.5 py-0.5 text-xs font-semibold rounded-full bg-amber-50 text-amber-700 ring-1 ring-amber-600/20 dark:bg-amber-900/30 dark:text-amber-300 dark:ring-amber-400/20",
|
|
470
|
+
danger: "inline-flex items-center gap-1 px-2.5 py-0.5 text-xs font-semibold rounded-full bg-rose-50 text-rose-700 ring-1 ring-rose-600/20 dark:bg-rose-900/30 dark:text-rose-300 dark:ring-rose-400/20",
|
|
471
|
+
info: "inline-flex items-center gap-1 px-2.5 py-0.5 text-xs font-semibold rounded-full bg-sky-50 text-sky-700 ring-1 ring-sky-600/20 dark:bg-sky-900/30 dark:text-sky-300 dark:ring-sky-400/20",
|
|
472
|
+
// Role badges
|
|
473
|
+
admin: "inline-flex items-center gap-1 px-2.5 py-0.5 text-xs font-semibold rounded-full bg-purple-50 text-purple-700 ring-1 ring-purple-600/20 dark:bg-purple-900/30 dark:text-purple-300 dark:ring-purple-400/20",
|
|
474
|
+
moderator: "inline-flex items-center gap-1 px-2.5 py-0.5 text-xs font-semibold rounded-full bg-sky-50 text-sky-700 ring-1 ring-sky-600/20 dark:bg-sky-900/30 dark:text-sky-300 dark:ring-sky-400/20",
|
|
475
|
+
seller: "inline-flex items-center gap-1 px-2.5 py-0.5 text-xs font-semibold rounded-full bg-teal-50 text-teal-700 ring-1 ring-teal-600/20 dark:bg-teal-900/30 dark:text-teal-300 dark:ring-teal-400/20",
|
|
476
|
+
user: "inline-flex items-center gap-1 px-2.5 py-0.5 text-xs font-semibold rounded-full bg-zinc-100 text-zinc-700 ring-1 ring-zinc-500/10 dark:bg-slate-800 dark:text-zinc-300 dark:ring-zinc-400/20",
|
|
477
|
+
// Legacy / generic variants
|
|
478
|
+
default: "inline-flex items-center gap-1 px-2.5 py-0.5 text-xs font-semibold rounded-full bg-zinc-100 text-zinc-700 ring-1 ring-zinc-500/10 dark:bg-slate-800 dark:text-zinc-300 dark:ring-zinc-400/20",
|
|
479
|
+
primary: "inline-flex items-center gap-1 px-2.5 py-0.5 text-xs font-semibold rounded-full bg-primary-100 text-primary-700 dark:bg-primary-900/50 dark:text-primary-300",
|
|
480
|
+
secondary: "inline-flex items-center gap-1 px-2.5 py-0.5 text-xs font-semibold rounded-full bg-primary-100 text-primary-700 dark:bg-primary-900/50 dark:text-primary-300"
|
|
481
|
+
};
|
|
482
|
+
function Badge({
|
|
483
|
+
children,
|
|
484
|
+
variant = "default",
|
|
485
|
+
className = ""
|
|
486
|
+
}) {
|
|
487
|
+
return /* @__PURE__ */ jsx6(Span, { className: `${BADGE_CLASSES[variant]} ${className}`, children });
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
// src/components/Alert.tsx
|
|
491
|
+
import { jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
492
|
+
var ALERT_STYLES = {
|
|
493
|
+
info: {
|
|
494
|
+
container: "bg-sky-50 border-sky-200/80 dark:bg-sky-950/30 dark:border-sky-800/50",
|
|
495
|
+
icon: "text-sky-600 dark:text-sky-400",
|
|
496
|
+
title: "text-sky-900 dark:text-sky-200",
|
|
497
|
+
text: "text-sky-800 dark:text-sky-300"
|
|
498
|
+
},
|
|
499
|
+
success: {
|
|
500
|
+
container: "bg-emerald-50 border-emerald-200/80 dark:bg-emerald-950/30 dark:border-emerald-800/50",
|
|
501
|
+
icon: "text-emerald-600 dark:text-emerald-400",
|
|
502
|
+
title: "text-emerald-900 dark:text-emerald-200",
|
|
503
|
+
text: "text-emerald-800 dark:text-emerald-300"
|
|
504
|
+
},
|
|
505
|
+
warning: {
|
|
506
|
+
container: "bg-amber-50 border-amber-200/80 dark:bg-amber-950/30 dark:border-amber-800/50",
|
|
507
|
+
icon: "text-amber-600 dark:text-amber-400",
|
|
508
|
+
title: "text-amber-900 dark:text-amber-200",
|
|
509
|
+
text: "text-amber-800 dark:text-amber-300"
|
|
510
|
+
},
|
|
511
|
+
error: {
|
|
512
|
+
container: "bg-red-50 border-red-200/80 dark:bg-red-950/30 dark:border-red-800/50",
|
|
513
|
+
icon: "text-red-600 dark:text-red-400",
|
|
514
|
+
title: "text-red-900 dark:text-red-200",
|
|
515
|
+
text: "text-red-800 dark:text-red-300"
|
|
516
|
+
}
|
|
517
|
+
};
|
|
518
|
+
var ALERT_CLOSE_HOVER = "hover:bg-black/5 dark:hover:bg-white/5";
|
|
519
|
+
var ICONS = {
|
|
520
|
+
info: /* @__PURE__ */ jsx7(
|
|
521
|
+
"svg",
|
|
522
|
+
{
|
|
523
|
+
className: "w-5 h-5",
|
|
524
|
+
fill: "currentColor",
|
|
525
|
+
viewBox: "0 0 20 20",
|
|
526
|
+
"aria-hidden": "true",
|
|
527
|
+
children: /* @__PURE__ */ jsx7(
|
|
528
|
+
"path",
|
|
529
|
+
{
|
|
530
|
+
fillRule: "evenodd",
|
|
531
|
+
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",
|
|
532
|
+
clipRule: "evenodd"
|
|
533
|
+
}
|
|
534
|
+
)
|
|
535
|
+
}
|
|
536
|
+
),
|
|
537
|
+
success: /* @__PURE__ */ jsx7(
|
|
538
|
+
"svg",
|
|
539
|
+
{
|
|
540
|
+
className: "w-5 h-5",
|
|
541
|
+
fill: "currentColor",
|
|
542
|
+
viewBox: "0 0 20 20",
|
|
543
|
+
"aria-hidden": "true",
|
|
544
|
+
children: /* @__PURE__ */ jsx7(
|
|
545
|
+
"path",
|
|
546
|
+
{
|
|
547
|
+
fillRule: "evenodd",
|
|
548
|
+
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",
|
|
549
|
+
clipRule: "evenodd"
|
|
550
|
+
}
|
|
551
|
+
)
|
|
552
|
+
}
|
|
553
|
+
),
|
|
554
|
+
warning: /* @__PURE__ */ jsx7(
|
|
555
|
+
"svg",
|
|
556
|
+
{
|
|
557
|
+
className: "w-5 h-5",
|
|
558
|
+
fill: "currentColor",
|
|
559
|
+
viewBox: "0 0 20 20",
|
|
560
|
+
"aria-hidden": "true",
|
|
561
|
+
children: /* @__PURE__ */ jsx7(
|
|
562
|
+
"path",
|
|
563
|
+
{
|
|
564
|
+
fillRule: "evenodd",
|
|
565
|
+
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",
|
|
566
|
+
clipRule: "evenodd"
|
|
567
|
+
}
|
|
568
|
+
)
|
|
569
|
+
}
|
|
570
|
+
),
|
|
571
|
+
error: /* @__PURE__ */ jsx7(
|
|
572
|
+
"svg",
|
|
573
|
+
{
|
|
574
|
+
className: "w-5 h-5",
|
|
575
|
+
fill: "currentColor",
|
|
576
|
+
viewBox: "0 0 20 20",
|
|
577
|
+
"aria-hidden": "true",
|
|
578
|
+
children: /* @__PURE__ */ jsx7(
|
|
579
|
+
"path",
|
|
580
|
+
{
|
|
581
|
+
fillRule: "evenodd",
|
|
582
|
+
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",
|
|
583
|
+
clipRule: "evenodd"
|
|
584
|
+
}
|
|
585
|
+
)
|
|
586
|
+
}
|
|
587
|
+
)
|
|
588
|
+
};
|
|
589
|
+
function Alert({
|
|
590
|
+
children,
|
|
591
|
+
variant = "info",
|
|
592
|
+
title,
|
|
593
|
+
onClose,
|
|
594
|
+
className = ""
|
|
595
|
+
}) {
|
|
596
|
+
const styles = ALERT_STYLES[variant];
|
|
597
|
+
return /* @__PURE__ */ jsx7(
|
|
598
|
+
"div",
|
|
599
|
+
{
|
|
600
|
+
className: `relative p-4 rounded-xl border ${styles.container} ${className}`,
|
|
601
|
+
role: "alert",
|
|
602
|
+
children: /* @__PURE__ */ jsxs5("div", { className: "flex gap-3", children: [
|
|
603
|
+
/* @__PURE__ */ jsx7("div", { className: `flex-shrink-0 ${styles.icon}`, children: ICONS[variant] }),
|
|
604
|
+
/* @__PURE__ */ jsxs5("div", { className: "flex-1 min-w-0", children: [
|
|
605
|
+
title && /* @__PURE__ */ jsx7(
|
|
606
|
+
Heading,
|
|
607
|
+
{
|
|
608
|
+
level: 3,
|
|
609
|
+
className: `text-sm font-semibold mb-1 ${styles.title}`,
|
|
610
|
+
children: title
|
|
611
|
+
}
|
|
612
|
+
),
|
|
613
|
+
/* @__PURE__ */ jsx7("div", { className: `text-sm ${styles.text}`, children })
|
|
614
|
+
] }),
|
|
615
|
+
onClose && /* @__PURE__ */ jsx7(
|
|
616
|
+
Button,
|
|
617
|
+
{
|
|
618
|
+
variant: "ghost",
|
|
619
|
+
size: "sm",
|
|
620
|
+
onClick: onClose,
|
|
621
|
+
className: `flex-shrink-0 ml-3 rounded-lg p-1.5 min-h-0 ${styles.icon} ${ALERT_CLOSE_HOVER}`,
|
|
622
|
+
"aria-label": "Close",
|
|
623
|
+
children: /* @__PURE__ */ jsx7(
|
|
624
|
+
"svg",
|
|
625
|
+
{
|
|
626
|
+
className: "w-5 h-5",
|
|
627
|
+
fill: "currentColor",
|
|
628
|
+
viewBox: "0 0 20 20",
|
|
629
|
+
"aria-hidden": "true",
|
|
630
|
+
children: /* @__PURE__ */ jsx7(
|
|
631
|
+
"path",
|
|
632
|
+
{
|
|
633
|
+
fillRule: "evenodd",
|
|
634
|
+
d: "M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z",
|
|
635
|
+
clipRule: "evenodd"
|
|
636
|
+
}
|
|
637
|
+
)
|
|
638
|
+
}
|
|
639
|
+
)
|
|
640
|
+
}
|
|
641
|
+
)
|
|
642
|
+
] })
|
|
643
|
+
}
|
|
644
|
+
);
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
// src/components/Divider.tsx
|
|
648
|
+
import { jsx as jsx8, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
649
|
+
var BORDER_LIGHT = "border-zinc-100 dark:border-slate-700/60";
|
|
650
|
+
var TEXT_MUTED = "text-zinc-400 dark:text-zinc-500";
|
|
651
|
+
function Divider({
|
|
652
|
+
label,
|
|
653
|
+
orientation = "horizontal",
|
|
654
|
+
className = ""
|
|
655
|
+
}) {
|
|
656
|
+
if (orientation === "vertical") {
|
|
657
|
+
return /* @__PURE__ */ jsx8(
|
|
658
|
+
"div",
|
|
659
|
+
{
|
|
660
|
+
className: `w-px h-full border-l ${BORDER_LIGHT} ${className}`,
|
|
661
|
+
role: "separator",
|
|
662
|
+
"aria-orientation": "vertical"
|
|
663
|
+
}
|
|
664
|
+
);
|
|
665
|
+
}
|
|
666
|
+
if (label) {
|
|
667
|
+
return /* @__PURE__ */ jsxs6("div", { className: `flex items-center gap-4 ${className}`, role: "separator", children: [
|
|
668
|
+
/* @__PURE__ */ jsx8("div", { className: `flex-1 h-px border-t ${BORDER_LIGHT}` }),
|
|
669
|
+
/* @__PURE__ */ jsx8(Span, { className: `text-sm font-medium ${TEXT_MUTED}`, children: label }),
|
|
670
|
+
/* @__PURE__ */ jsx8("div", { className: `flex-1 h-px border-t ${BORDER_LIGHT}` })
|
|
671
|
+
] });
|
|
672
|
+
}
|
|
673
|
+
return /* @__PURE__ */ jsx8(
|
|
674
|
+
"div",
|
|
675
|
+
{
|
|
676
|
+
className: `w-full h-px border-t ${BORDER_LIGHT} ${className}`,
|
|
677
|
+
role: "separator",
|
|
678
|
+
"aria-orientation": "horizontal"
|
|
679
|
+
}
|
|
680
|
+
);
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
// src/components/Progress.tsx
|
|
684
|
+
import { jsx as jsx9, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
685
|
+
var TEXT_PRIMARY = "text-zinc-900 dark:text-zinc-50";
|
|
686
|
+
var TEXT_SECONDARY = "text-zinc-500 dark:text-zinc-400";
|
|
687
|
+
var BG_SECONDARY = "bg-zinc-50 dark:bg-slate-900";
|
|
688
|
+
var FLEX_BETWEEN = "flex items-center justify-between";
|
|
689
|
+
var INDETERMINATE_CSS = `
|
|
690
|
+
@keyframes lir-progress-indeterminate {
|
|
691
|
+
0% { transform: translateX(-100%); }
|
|
692
|
+
100% { transform: translateX(350%); }
|
|
693
|
+
}
|
|
694
|
+
.lir-progress-indeterminate {
|
|
695
|
+
animation: lir-progress-indeterminate 1.5s ease-in-out infinite;
|
|
696
|
+
}
|
|
697
|
+
`;
|
|
698
|
+
function Progress({
|
|
699
|
+
value,
|
|
700
|
+
max = 100,
|
|
701
|
+
variant = "primary",
|
|
702
|
+
size = "md",
|
|
703
|
+
label,
|
|
704
|
+
showValue = false,
|
|
705
|
+
className = ""
|
|
706
|
+
}) {
|
|
707
|
+
const percentage = Math.min(Math.max(value / max * 100, 0), 100);
|
|
708
|
+
const sizeClasses = {
|
|
709
|
+
sm: "h-1",
|
|
710
|
+
md: "h-2",
|
|
711
|
+
lg: "h-3"
|
|
712
|
+
};
|
|
713
|
+
const variantClasses = {
|
|
714
|
+
primary: "bg-primary",
|
|
715
|
+
success: "bg-green-600 dark:bg-green-500",
|
|
716
|
+
warning: "bg-yellow-600 dark:bg-yellow-500",
|
|
717
|
+
error: "bg-red-600 dark:bg-red-500"
|
|
718
|
+
};
|
|
719
|
+
return /* @__PURE__ */ jsxs7("div", { className, children: [
|
|
720
|
+
(label || showValue) && /* @__PURE__ */ jsxs7("div", { className: `${FLEX_BETWEEN} mb-2`, children: [
|
|
721
|
+
label && /* @__PURE__ */ jsx9(Span, { className: `text-sm font-medium ${TEXT_PRIMARY}`, children: label }),
|
|
722
|
+
showValue && /* @__PURE__ */ jsxs7(Span, { className: `text-sm font-medium ${TEXT_SECONDARY}`, children: [
|
|
723
|
+
Math.round(percentage),
|
|
724
|
+
"%"
|
|
725
|
+
] })
|
|
726
|
+
] }),
|
|
727
|
+
/* @__PURE__ */ jsx9(
|
|
728
|
+
"div",
|
|
729
|
+
{
|
|
730
|
+
className: `w-full ${sizeClasses[size]} rounded-full overflow-hidden ${BG_SECONDARY}`,
|
|
731
|
+
role: "progressbar",
|
|
732
|
+
"aria-valuenow": value,
|
|
733
|
+
"aria-valuemin": 0,
|
|
734
|
+
"aria-valuemax": max,
|
|
735
|
+
"aria-label": label || `Progress: ${Math.round(percentage)}%`,
|
|
736
|
+
children: /* @__PURE__ */ jsx9(
|
|
737
|
+
"div",
|
|
738
|
+
{
|
|
739
|
+
className: `h-full ${variantClasses[variant]} transition-all duration-300 ease-in-out rounded-full`,
|
|
740
|
+
style: { width: `${percentage}%` }
|
|
741
|
+
}
|
|
742
|
+
)
|
|
743
|
+
}
|
|
744
|
+
)
|
|
745
|
+
] });
|
|
746
|
+
}
|
|
747
|
+
function IndeterminateProgress({
|
|
748
|
+
variant = "primary",
|
|
749
|
+
size = "md",
|
|
750
|
+
label,
|
|
751
|
+
className = ""
|
|
752
|
+
}) {
|
|
753
|
+
const sizeClasses = {
|
|
754
|
+
sm: "h-1",
|
|
755
|
+
md: "h-2",
|
|
756
|
+
lg: "h-3"
|
|
757
|
+
};
|
|
758
|
+
const variantClasses = {
|
|
759
|
+
primary: "bg-primary",
|
|
760
|
+
success: "bg-green-600 dark:bg-green-500",
|
|
761
|
+
warning: "bg-yellow-600 dark:bg-yellow-500",
|
|
762
|
+
error: "bg-red-600 dark:bg-red-500"
|
|
763
|
+
};
|
|
764
|
+
return /* @__PURE__ */ jsxs7("div", { className, children: [
|
|
765
|
+
/* @__PURE__ */ jsx9("style", { dangerouslySetInnerHTML: { __html: INDETERMINATE_CSS } }),
|
|
766
|
+
label && /* @__PURE__ */ jsx9(Span, { className: `block text-sm font-medium mb-2 ${TEXT_PRIMARY}`, children: label }),
|
|
767
|
+
/* @__PURE__ */ jsx9(
|
|
768
|
+
"div",
|
|
769
|
+
{
|
|
770
|
+
className: `w-full ${sizeClasses[size]} rounded-full overflow-hidden ${BG_SECONDARY} relative`,
|
|
771
|
+
role: "progressbar",
|
|
772
|
+
"aria-label": label || "Loading...",
|
|
773
|
+
children: /* @__PURE__ */ jsx9(
|
|
774
|
+
"div",
|
|
775
|
+
{
|
|
776
|
+
className: `absolute inset-0 ${variantClasses[variant]} lir-progress-indeterminate rounded-full`,
|
|
777
|
+
style: { width: "40%" }
|
|
778
|
+
}
|
|
779
|
+
)
|
|
780
|
+
}
|
|
781
|
+
)
|
|
782
|
+
] });
|
|
783
|
+
}
|
|
784
|
+
|
|
785
|
+
// src/components/Pagination.tsx
|
|
786
|
+
import { DEFAULT_PAGINATION_CONFIG } from "@mohasinac/contracts";
|
|
787
|
+
import { jsx as jsx10, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
788
|
+
function getPageNumbers(currentPage, totalPages, maxVisible) {
|
|
789
|
+
if (totalPages <= maxVisible) {
|
|
790
|
+
return Array.from({ length: totalPages }, (_, i) => i + 1);
|
|
791
|
+
}
|
|
792
|
+
const pages = [];
|
|
793
|
+
const halfVisible = Math.floor(maxVisible / 2);
|
|
794
|
+
let startPage = Math.max(1, currentPage - halfVisible);
|
|
795
|
+
let endPage = Math.min(totalPages, currentPage + halfVisible);
|
|
796
|
+
if (currentPage <= halfVisible) endPage = maxVisible;
|
|
797
|
+
if (currentPage >= totalPages - halfVisible)
|
|
798
|
+
startPage = totalPages - maxVisible + 1;
|
|
799
|
+
if (startPage > 1) {
|
|
800
|
+
pages.push(1);
|
|
801
|
+
if (startPage > 2) pages.push("...");
|
|
802
|
+
}
|
|
803
|
+
for (let i = startPage; i <= endPage; i++) pages.push(i);
|
|
804
|
+
if (endPage < totalPages) {
|
|
805
|
+
if (endPage < totalPages - 1) pages.push("...");
|
|
806
|
+
pages.push(totalPages);
|
|
807
|
+
}
|
|
808
|
+
return pages;
|
|
809
|
+
}
|
|
810
|
+
var SIZE_CLASSES = {
|
|
811
|
+
sm: "text-xs px-2 py-1 min-w-[28px]",
|
|
812
|
+
md: "text-sm px-3 py-1.5 min-w-[36px]",
|
|
813
|
+
lg: "text-base px-4 py-2 min-w-[44px]"
|
|
814
|
+
};
|
|
815
|
+
function Pagination({
|
|
816
|
+
currentPage,
|
|
817
|
+
totalPages,
|
|
818
|
+
onPageChange,
|
|
819
|
+
paginationConfig,
|
|
820
|
+
maxVisible: maxVisibleProp,
|
|
821
|
+
showFirstLast: showFirstLastProp,
|
|
822
|
+
showPrevNext: showPrevNextProp,
|
|
823
|
+
disabled = false,
|
|
824
|
+
size: sizeProp,
|
|
825
|
+
className = ""
|
|
826
|
+
}) {
|
|
827
|
+
const resolved = __spreadValues(__spreadValues({}, DEFAULT_PAGINATION_CONFIG), paginationConfig);
|
|
828
|
+
const maxVisible = maxVisibleProp != null ? maxVisibleProp : resolved.maxVisible;
|
|
829
|
+
const showFirstLast = showFirstLastProp != null ? showFirstLastProp : resolved.showFirstLast;
|
|
830
|
+
const showPrevNext = showPrevNextProp != null ? showPrevNextProp : resolved.showPrevNext;
|
|
831
|
+
const size = sizeProp != null ? sizeProp : resolved.size;
|
|
832
|
+
const handle = (page) => {
|
|
833
|
+
if (disabled || page < 1 || page > totalPages || page === currentPage)
|
|
834
|
+
return;
|
|
835
|
+
onPageChange(page);
|
|
836
|
+
};
|
|
837
|
+
const btnClass = (active, off) => {
|
|
838
|
+
const base = `${SIZE_CLASSES[size]} rounded border font-medium transition-colors`;
|
|
839
|
+
if (off)
|
|
840
|
+
return `${base} bg-zinc-100 dark:bg-slate-800 opacity-50 text-zinc-400 dark:text-zinc-500 border-zinc-200 dark:border-slate-700 cursor-not-allowed`;
|
|
841
|
+
if (active)
|
|
842
|
+
return `${base} bg-primary-600 text-white border-primary-600 cursor-default`;
|
|
843
|
+
return `${base} bg-white dark:bg-slate-900 text-zinc-700 dark:text-zinc-300 border-zinc-200 dark:border-slate-700 hover:bg-zinc-50 dark:hover:bg-slate-800 hover:border-zinc-300 dark:hover:border-slate-600 cursor-pointer`;
|
|
844
|
+
};
|
|
845
|
+
const pages = getPageNumbers(currentPage, totalPages, maxVisible);
|
|
846
|
+
return /* @__PURE__ */ jsxs8(
|
|
847
|
+
"nav",
|
|
848
|
+
{
|
|
849
|
+
className: `flex items-center gap-1 ${className}`,
|
|
850
|
+
"aria-label": "Pagination",
|
|
851
|
+
children: [
|
|
852
|
+
showFirstLast && /* @__PURE__ */ jsx10(
|
|
853
|
+
"button",
|
|
854
|
+
{
|
|
855
|
+
type: "button",
|
|
856
|
+
className: btnClass(false, disabled || currentPage === 1),
|
|
857
|
+
onClick: () => handle(1),
|
|
858
|
+
disabled: disabled || currentPage === 1,
|
|
859
|
+
"aria-label": "First page",
|
|
860
|
+
children: "\xAB"
|
|
861
|
+
}
|
|
862
|
+
),
|
|
863
|
+
showPrevNext && /* @__PURE__ */ jsx10(
|
|
864
|
+
"button",
|
|
865
|
+
{
|
|
866
|
+
type: "button",
|
|
867
|
+
className: btnClass(false, disabled || currentPage === 1),
|
|
868
|
+
onClick: () => handle(currentPage - 1),
|
|
869
|
+
disabled: disabled || currentPage === 1,
|
|
870
|
+
"aria-label": "Previous page",
|
|
871
|
+
children: "\u2039"
|
|
872
|
+
}
|
|
873
|
+
),
|
|
874
|
+
pages.map(
|
|
875
|
+
(page, i) => page === "..." ? /* @__PURE__ */ jsx10(
|
|
876
|
+
"span",
|
|
877
|
+
{
|
|
878
|
+
className: `${SIZE_CLASSES[size]} text-zinc-400 dark:text-zinc-500 text-center`,
|
|
879
|
+
"aria-hidden": "true",
|
|
880
|
+
children: "\u2026"
|
|
881
|
+
},
|
|
882
|
+
`ellipsis-${i}`
|
|
883
|
+
) : /* @__PURE__ */ jsx10(
|
|
884
|
+
"button",
|
|
885
|
+
{
|
|
886
|
+
type: "button",
|
|
887
|
+
className: btnClass(
|
|
888
|
+
page === currentPage,
|
|
889
|
+
disabled && page !== currentPage
|
|
890
|
+
),
|
|
891
|
+
onClick: () => handle(page),
|
|
892
|
+
disabled,
|
|
893
|
+
"aria-label": `Page ${page}`,
|
|
894
|
+
"aria-current": page === currentPage ? "page" : void 0,
|
|
895
|
+
children: page
|
|
896
|
+
},
|
|
897
|
+
page
|
|
898
|
+
)
|
|
899
|
+
),
|
|
900
|
+
showPrevNext && /* @__PURE__ */ jsx10(
|
|
901
|
+
"button",
|
|
902
|
+
{
|
|
903
|
+
type: "button",
|
|
904
|
+
className: btnClass(false, disabled || currentPage === totalPages),
|
|
905
|
+
onClick: () => handle(currentPage + 1),
|
|
906
|
+
disabled: disabled || currentPage === totalPages,
|
|
907
|
+
"aria-label": "Next page",
|
|
908
|
+
children: "\u203A"
|
|
909
|
+
}
|
|
910
|
+
),
|
|
911
|
+
showFirstLast && /* @__PURE__ */ jsx10(
|
|
912
|
+
"button",
|
|
913
|
+
{
|
|
914
|
+
type: "button",
|
|
915
|
+
className: btnClass(false, disabled || currentPage === totalPages),
|
|
916
|
+
onClick: () => handle(totalPages),
|
|
917
|
+
disabled: disabled || currentPage === totalPages,
|
|
918
|
+
"aria-label": "Last page",
|
|
919
|
+
children: "\xBB"
|
|
920
|
+
}
|
|
921
|
+
)
|
|
922
|
+
]
|
|
923
|
+
}
|
|
924
|
+
);
|
|
925
|
+
}
|
|
926
|
+
|
|
927
|
+
// src/components/StatusBadge.tsx
|
|
928
|
+
import { jsx as jsx11 } from "react/jsx-runtime";
|
|
929
|
+
var STATUS_TO_VARIANT = {
|
|
930
|
+
// Generic
|
|
931
|
+
active: "active",
|
|
932
|
+
inactive: "inactive",
|
|
933
|
+
pending: "pending",
|
|
934
|
+
approved: "approved",
|
|
935
|
+
rejected: "rejected",
|
|
936
|
+
success: "success",
|
|
937
|
+
warning: "warning",
|
|
938
|
+
danger: "danger",
|
|
939
|
+
info: "info",
|
|
940
|
+
// Order
|
|
941
|
+
confirmed: "success",
|
|
942
|
+
processing: "info",
|
|
943
|
+
shipped: "info",
|
|
944
|
+
delivered: "success",
|
|
945
|
+
cancelled: "danger",
|
|
946
|
+
refunded: "warning",
|
|
947
|
+
failed: "danger",
|
|
948
|
+
// Payment
|
|
949
|
+
paid: "success",
|
|
950
|
+
partially_refunded: "warning",
|
|
951
|
+
// Review (pending/approved/rejected already covered)
|
|
952
|
+
// Ticket
|
|
953
|
+
open: "warning",
|
|
954
|
+
in_progress: "info",
|
|
955
|
+
resolved: "success",
|
|
956
|
+
closed: "inactive"
|
|
957
|
+
};
|
|
958
|
+
var STATUS_LABELS = {
|
|
959
|
+
active: "Active",
|
|
960
|
+
inactive: "Inactive",
|
|
961
|
+
pending: "Pending",
|
|
962
|
+
approved: "Approved",
|
|
963
|
+
rejected: "Rejected",
|
|
964
|
+
success: "Success",
|
|
965
|
+
warning: "Warning",
|
|
966
|
+
danger: "Danger",
|
|
967
|
+
info: "Info",
|
|
968
|
+
confirmed: "Confirmed",
|
|
969
|
+
processing: "Processing",
|
|
970
|
+
shipped: "Shipped",
|
|
971
|
+
delivered: "Delivered",
|
|
972
|
+
cancelled: "Cancelled",
|
|
973
|
+
refunded: "Refunded",
|
|
974
|
+
failed: "Failed",
|
|
975
|
+
paid: "Paid",
|
|
976
|
+
partially_refunded: "Partially Refunded",
|
|
977
|
+
open: "Open",
|
|
978
|
+
in_progress: "In Progress",
|
|
979
|
+
resolved: "Resolved",
|
|
980
|
+
closed: "Closed"
|
|
981
|
+
};
|
|
982
|
+
function StatusBadge({ status, label, className }) {
|
|
983
|
+
var _a, _b;
|
|
984
|
+
const variant = (_a = STATUS_TO_VARIANT[status]) != null ? _a : "default";
|
|
985
|
+
const displayLabel = (_b = label != null ? label : STATUS_LABELS[status]) != null ? _b : status;
|
|
986
|
+
return /* @__PURE__ */ jsx11(Badge, { variant, className, children: displayLabel });
|
|
987
|
+
}
|
|
988
|
+
|
|
989
|
+
// src/components/Modal.tsx
|
|
990
|
+
import { useCallback, useEffect, useId, useRef } from "react";
|
|
991
|
+
import { createPortal } from "react-dom";
|
|
992
|
+
import { X } from "lucide-react";
|
|
993
|
+
import { jsx as jsx12, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
994
|
+
var SIZE_CLASSES2 = {
|
|
995
|
+
sm: "max-w-sm",
|
|
996
|
+
md: "max-w-lg",
|
|
997
|
+
lg: "max-w-2xl",
|
|
998
|
+
xl: "max-w-4xl",
|
|
999
|
+
full: "max-w-[95vw] max-h-[95vh]"
|
|
1000
|
+
};
|
|
1001
|
+
function Modal({
|
|
1002
|
+
isOpen,
|
|
1003
|
+
onClose,
|
|
1004
|
+
title,
|
|
1005
|
+
children,
|
|
1006
|
+
size = "md",
|
|
1007
|
+
showCloseButton = true,
|
|
1008
|
+
className = ""
|
|
1009
|
+
}) {
|
|
1010
|
+
const titleId = useId();
|
|
1011
|
+
const panelRef = useRef(null);
|
|
1012
|
+
const prevFocusRef = useRef(null);
|
|
1013
|
+
useEffect(() => {
|
|
1014
|
+
if (!isOpen) return;
|
|
1015
|
+
const prev = document.body.style.overflow;
|
|
1016
|
+
document.body.style.overflow = "hidden";
|
|
1017
|
+
return () => {
|
|
1018
|
+
document.body.style.overflow = prev;
|
|
1019
|
+
};
|
|
1020
|
+
}, [isOpen]);
|
|
1021
|
+
useEffect(() => {
|
|
1022
|
+
var _a;
|
|
1023
|
+
if (isOpen) {
|
|
1024
|
+
prevFocusRef.current = document.activeElement;
|
|
1025
|
+
requestAnimationFrame(() => {
|
|
1026
|
+
var _a2;
|
|
1027
|
+
return (_a2 = panelRef.current) == null ? void 0 : _a2.focus();
|
|
1028
|
+
});
|
|
1029
|
+
} else {
|
|
1030
|
+
(_a = prevFocusRef.current) == null ? void 0 : _a.focus();
|
|
1031
|
+
}
|
|
1032
|
+
}, [isOpen]);
|
|
1033
|
+
const handleKeyDown = useCallback(
|
|
1034
|
+
(e) => {
|
|
1035
|
+
if (e.key === "Escape") {
|
|
1036
|
+
onClose();
|
|
1037
|
+
return;
|
|
1038
|
+
}
|
|
1039
|
+
if (e.key !== "Tab") return;
|
|
1040
|
+
const panel = panelRef.current;
|
|
1041
|
+
if (!panel) return;
|
|
1042
|
+
const focusable = Array.from(
|
|
1043
|
+
panel.querySelectorAll(
|
|
1044
|
+
'a[href],button:not([disabled]),textarea,input,select,[tabindex]:not([tabindex="-1"])'
|
|
1045
|
+
)
|
|
1046
|
+
);
|
|
1047
|
+
if (!focusable.length) return;
|
|
1048
|
+
const first = focusable[0];
|
|
1049
|
+
const last = focusable[focusable.length - 1];
|
|
1050
|
+
if (e.shiftKey && document.activeElement === first) {
|
|
1051
|
+
e.preventDefault();
|
|
1052
|
+
last.focus();
|
|
1053
|
+
} else if (!e.shiftKey && document.activeElement === last) {
|
|
1054
|
+
e.preventDefault();
|
|
1055
|
+
first.focus();
|
|
1056
|
+
}
|
|
1057
|
+
},
|
|
1058
|
+
[onClose]
|
|
1059
|
+
);
|
|
1060
|
+
if (!isOpen) return null;
|
|
1061
|
+
if (typeof document === "undefined") return null;
|
|
1062
|
+
return createPortal(
|
|
1063
|
+
/* @__PURE__ */ jsxs9(
|
|
1064
|
+
"div",
|
|
1065
|
+
{
|
|
1066
|
+
className: "fixed inset-0 z-50 flex items-center justify-center p-4",
|
|
1067
|
+
role: "dialog",
|
|
1068
|
+
"aria-modal": "true",
|
|
1069
|
+
"aria-labelledby": title ? titleId : void 0,
|
|
1070
|
+
onKeyDown: handleKeyDown,
|
|
1071
|
+
children: [
|
|
1072
|
+
/* @__PURE__ */ jsx12(
|
|
1073
|
+
"div",
|
|
1074
|
+
{
|
|
1075
|
+
className: "absolute inset-0 bg-black/60 backdrop-blur-sm",
|
|
1076
|
+
"aria-hidden": "true",
|
|
1077
|
+
onClick: onClose
|
|
1078
|
+
}
|
|
1079
|
+
),
|
|
1080
|
+
/* @__PURE__ */ jsxs9(
|
|
1081
|
+
"div",
|
|
1082
|
+
{
|
|
1083
|
+
ref: panelRef,
|
|
1084
|
+
tabIndex: -1,
|
|
1085
|
+
className: [
|
|
1086
|
+
"relative w-full rounded-2xl bg-white dark:bg-slate-900",
|
|
1087
|
+
"shadow-2xl ring-1 ring-zinc-200 dark:ring-slate-700",
|
|
1088
|
+
"flex flex-col max-h-[90vh] overflow-hidden",
|
|
1089
|
+
"animate-[fadeInUp_0.15s_ease_forwards]",
|
|
1090
|
+
SIZE_CLASSES2[size],
|
|
1091
|
+
className
|
|
1092
|
+
].join(" "),
|
|
1093
|
+
children: [
|
|
1094
|
+
(title || showCloseButton) && /* @__PURE__ */ jsxs9("div", { className: "flex items-center justify-between px-6 py-4 border-b border-zinc-100 dark:border-slate-800 flex-shrink-0", children: [
|
|
1095
|
+
title && /* @__PURE__ */ jsx12(
|
|
1096
|
+
Heading,
|
|
1097
|
+
{
|
|
1098
|
+
level: 2,
|
|
1099
|
+
id: titleId,
|
|
1100
|
+
className: "!text-lg !font-semibold !font-sans tracking-tight",
|
|
1101
|
+
children: title
|
|
1102
|
+
}
|
|
1103
|
+
),
|
|
1104
|
+
showCloseButton && /* @__PURE__ */ jsx12(
|
|
1105
|
+
Button,
|
|
1106
|
+
{
|
|
1107
|
+
variant: "ghost",
|
|
1108
|
+
size: "sm",
|
|
1109
|
+
type: "button",
|
|
1110
|
+
onClick: onClose,
|
|
1111
|
+
className: "ml-auto p-1.5 !min-h-0 rounded-lg text-zinc-400 hover:text-zinc-600 dark:text-zinc-500 dark:hover:text-zinc-300",
|
|
1112
|
+
"aria-label": "Close",
|
|
1113
|
+
children: /* @__PURE__ */ jsx12(X, { className: "w-5 h-5" })
|
|
1114
|
+
}
|
|
1115
|
+
)
|
|
1116
|
+
] }),
|
|
1117
|
+
/* @__PURE__ */ jsx12("div", { className: "overflow-y-auto flex-1 px-6 py-4", children })
|
|
1118
|
+
]
|
|
1119
|
+
}
|
|
1120
|
+
)
|
|
1121
|
+
]
|
|
1122
|
+
}
|
|
1123
|
+
),
|
|
1124
|
+
document.body
|
|
1125
|
+
);
|
|
1126
|
+
}
|
|
1127
|
+
|
|
1128
|
+
// src/components/Drawer.tsx
|
|
1129
|
+
import { useCallback as useCallback2, useEffect as useEffect2, useRef as useRef2 } from "react";
|
|
1130
|
+
import { createPortal as createPortal2 } from "react-dom";
|
|
1131
|
+
import { X as X2 } from "lucide-react";
|
|
1132
|
+
import { jsx as jsx13, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
1133
|
+
var SIDE_TRANSLATE = {
|
|
1134
|
+
left: {
|
|
1135
|
+
closed: "-translate-x-full",
|
|
1136
|
+
open: "translate-x-0",
|
|
1137
|
+
base: "left-0 top-0 bottom-0"
|
|
1138
|
+
},
|
|
1139
|
+
right: {
|
|
1140
|
+
closed: "translate-x-full",
|
|
1141
|
+
open: "translate-x-0",
|
|
1142
|
+
base: "right-0 top-0 bottom-0"
|
|
1143
|
+
},
|
|
1144
|
+
bottom: {
|
|
1145
|
+
closed: "translate-y-full",
|
|
1146
|
+
open: "translate-y-0",
|
|
1147
|
+
base: "bottom-0 left-0 right-0"
|
|
1148
|
+
}
|
|
1149
|
+
};
|
|
1150
|
+
var SIDE_SIZE = {
|
|
1151
|
+
sm: "w-72",
|
|
1152
|
+
md: "w-80 sm:w-96",
|
|
1153
|
+
lg: "w-full sm:w-[480px]",
|
|
1154
|
+
full: "w-full"
|
|
1155
|
+
};
|
|
1156
|
+
function Drawer({
|
|
1157
|
+
isOpen,
|
|
1158
|
+
onClose,
|
|
1159
|
+
title,
|
|
1160
|
+
children,
|
|
1161
|
+
footer,
|
|
1162
|
+
side = "right",
|
|
1163
|
+
size = "md",
|
|
1164
|
+
showCloseButton = true,
|
|
1165
|
+
className = ""
|
|
1166
|
+
}) {
|
|
1167
|
+
const panelRef = useRef2(null);
|
|
1168
|
+
const prevFocusRef = useRef2(null);
|
|
1169
|
+
useEffect2(() => {
|
|
1170
|
+
if (!isOpen) return;
|
|
1171
|
+
const prev = document.body.style.overflow;
|
|
1172
|
+
document.body.style.overflow = "hidden";
|
|
1173
|
+
return () => {
|
|
1174
|
+
document.body.style.overflow = prev;
|
|
1175
|
+
};
|
|
1176
|
+
}, [isOpen]);
|
|
1177
|
+
useEffect2(() => {
|
|
1178
|
+
var _a;
|
|
1179
|
+
if (isOpen) {
|
|
1180
|
+
prevFocusRef.current = document.activeElement;
|
|
1181
|
+
requestAnimationFrame(() => {
|
|
1182
|
+
var _a2;
|
|
1183
|
+
return (_a2 = panelRef.current) == null ? void 0 : _a2.focus();
|
|
1184
|
+
});
|
|
1185
|
+
} else {
|
|
1186
|
+
(_a = prevFocusRef.current) == null ? void 0 : _a.focus();
|
|
1187
|
+
}
|
|
1188
|
+
}, [isOpen]);
|
|
1189
|
+
const handleKeyDown = useCallback2(
|
|
1190
|
+
(e) => {
|
|
1191
|
+
if (e.key === "Escape") onClose();
|
|
1192
|
+
},
|
|
1193
|
+
[onClose]
|
|
1194
|
+
);
|
|
1195
|
+
const { closed, open, base } = SIDE_TRANSLATE[side];
|
|
1196
|
+
const isBottom = side === "bottom";
|
|
1197
|
+
if (typeof document === "undefined") return null;
|
|
1198
|
+
return createPortal2(
|
|
1199
|
+
/* @__PURE__ */ jsxs10(
|
|
1200
|
+
"div",
|
|
1201
|
+
{
|
|
1202
|
+
className: `fixed inset-0 z-50 ${isOpen ? "pointer-events-auto" : "pointer-events-none"}`,
|
|
1203
|
+
onKeyDown: handleKeyDown,
|
|
1204
|
+
children: [
|
|
1205
|
+
/* @__PURE__ */ jsx13(
|
|
1206
|
+
"div",
|
|
1207
|
+
{
|
|
1208
|
+
className: `absolute inset-0 bg-black/50 backdrop-blur-sm transition-opacity duration-300 ${isOpen ? "opacity-100" : "opacity-0"}`,
|
|
1209
|
+
"aria-hidden": "true",
|
|
1210
|
+
onClick: onClose
|
|
1211
|
+
}
|
|
1212
|
+
),
|
|
1213
|
+
/* @__PURE__ */ jsxs10(
|
|
1214
|
+
"div",
|
|
1215
|
+
{
|
|
1216
|
+
ref: panelRef,
|
|
1217
|
+
tabIndex: -1,
|
|
1218
|
+
role: "dialog",
|
|
1219
|
+
"aria-modal": "true",
|
|
1220
|
+
className: [
|
|
1221
|
+
"absolute bg-white dark:bg-slate-900",
|
|
1222
|
+
"shadow-2xl ring-1 ring-zinc-200 dark:ring-slate-700",
|
|
1223
|
+
"flex flex-col",
|
|
1224
|
+
"transition-transform duration-300 ease-out",
|
|
1225
|
+
base,
|
|
1226
|
+
isBottom ? "rounded-t-2xl max-h-[90vh]" : `${SIDE_SIZE[size]} h-full`,
|
|
1227
|
+
isOpen ? open : closed,
|
|
1228
|
+
className
|
|
1229
|
+
].join(" "),
|
|
1230
|
+
children: [
|
|
1231
|
+
isBottom && /* @__PURE__ */ jsx13("div", { className: "flex justify-center pt-3 pb-1 flex-shrink-0", children: /* @__PURE__ */ jsx13(
|
|
1232
|
+
"div",
|
|
1233
|
+
{
|
|
1234
|
+
className: "w-10 h-1 rounded-full bg-zinc-300 dark:bg-slate-600",
|
|
1235
|
+
"aria-hidden": "true"
|
|
1236
|
+
}
|
|
1237
|
+
) }),
|
|
1238
|
+
(title || showCloseButton) && /* @__PURE__ */ jsxs10("div", { className: "flex items-center justify-between px-5 py-4 border-b border-zinc-100 dark:border-slate-800 flex-shrink-0", children: [
|
|
1239
|
+
title && /* @__PURE__ */ jsx13(
|
|
1240
|
+
Heading,
|
|
1241
|
+
{
|
|
1242
|
+
level: 2,
|
|
1243
|
+
className: "!text-base !font-semibold !font-sans",
|
|
1244
|
+
children: title
|
|
1245
|
+
}
|
|
1246
|
+
),
|
|
1247
|
+
showCloseButton && /* @__PURE__ */ jsx13(
|
|
1248
|
+
Button,
|
|
1249
|
+
{
|
|
1250
|
+
variant: "ghost",
|
|
1251
|
+
size: "sm",
|
|
1252
|
+
type: "button",
|
|
1253
|
+
onClick: onClose,
|
|
1254
|
+
className: "ml-auto p-1.5 !min-h-0 rounded-lg text-zinc-400 hover:text-zinc-700 dark:text-zinc-500 dark:hover:text-zinc-300",
|
|
1255
|
+
"aria-label": "Close",
|
|
1256
|
+
children: /* @__PURE__ */ jsx13(X2, { className: "w-5 h-5" })
|
|
1257
|
+
}
|
|
1258
|
+
)
|
|
1259
|
+
] }),
|
|
1260
|
+
/* @__PURE__ */ jsx13("div", { className: "flex-1 overflow-y-auto px-5 py-4", children }),
|
|
1261
|
+
footer && /* @__PURE__ */ jsx13("div", { className: "flex-shrink-0 border-t border-zinc-100 dark:border-slate-800 px-5 py-4", children: footer })
|
|
1262
|
+
]
|
|
1263
|
+
}
|
|
1264
|
+
)
|
|
1265
|
+
]
|
|
1266
|
+
}
|
|
1267
|
+
),
|
|
1268
|
+
document.body
|
|
1269
|
+
);
|
|
1270
|
+
}
|
|
1271
|
+
|
|
1272
|
+
// src/components/Select.tsx
|
|
1273
|
+
import { useCallback as useCallback3, useEffect as useEffect3, useId as useId2, useRef as useRef3, useState } from "react";
|
|
1274
|
+
import { Check, ChevronDown } from "lucide-react";
|
|
1275
|
+
import { jsx as jsx14, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
1276
|
+
function Select({
|
|
1277
|
+
options,
|
|
1278
|
+
value,
|
|
1279
|
+
onChange,
|
|
1280
|
+
placeholder = "Select\u2026",
|
|
1281
|
+
label,
|
|
1282
|
+
error,
|
|
1283
|
+
disabled = false,
|
|
1284
|
+
required,
|
|
1285
|
+
className = "",
|
|
1286
|
+
id: externalId
|
|
1287
|
+
}) {
|
|
1288
|
+
var _a;
|
|
1289
|
+
const generatedId = useId2();
|
|
1290
|
+
const id = externalId != null ? externalId : generatedId;
|
|
1291
|
+
const [open, setOpen] = useState(false);
|
|
1292
|
+
const [openUp, setOpenUp] = useState(false);
|
|
1293
|
+
const ref = useRef3(null);
|
|
1294
|
+
const selected = options.find((o) => o.value === value);
|
|
1295
|
+
const toggle = useCallback3(() => {
|
|
1296
|
+
if (!disabled) {
|
|
1297
|
+
if (!open && ref.current) {
|
|
1298
|
+
const rect = ref.current.getBoundingClientRect();
|
|
1299
|
+
const spaceBelow = window.innerHeight - rect.bottom;
|
|
1300
|
+
const spaceAbove = rect.top;
|
|
1301
|
+
setOpenUp(spaceBelow < 160 && spaceAbove > spaceBelow);
|
|
1302
|
+
}
|
|
1303
|
+
setOpen((v) => !v);
|
|
1304
|
+
}
|
|
1305
|
+
}, [disabled, open]);
|
|
1306
|
+
const handleSelect = useCallback3(
|
|
1307
|
+
(val) => {
|
|
1308
|
+
onChange == null ? void 0 : onChange(val);
|
|
1309
|
+
setOpen(false);
|
|
1310
|
+
},
|
|
1311
|
+
[onChange]
|
|
1312
|
+
);
|
|
1313
|
+
useEffect3(() => {
|
|
1314
|
+
const handler = (e) => {
|
|
1315
|
+
if (ref.current && !ref.current.contains(e.target)) {
|
|
1316
|
+
setOpen(false);
|
|
1317
|
+
}
|
|
1318
|
+
};
|
|
1319
|
+
if (open) document.addEventListener("mousedown", handler);
|
|
1320
|
+
return () => document.removeEventListener("mousedown", handler);
|
|
1321
|
+
}, [open]);
|
|
1322
|
+
const handleKeyDown = useCallback3(
|
|
1323
|
+
(e) => {
|
|
1324
|
+
if (e.key === "Escape") {
|
|
1325
|
+
setOpen(false);
|
|
1326
|
+
return;
|
|
1327
|
+
}
|
|
1328
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
1329
|
+
toggle();
|
|
1330
|
+
e.preventDefault();
|
|
1331
|
+
return;
|
|
1332
|
+
}
|
|
1333
|
+
if (e.key === "ArrowDown" && !open) {
|
|
1334
|
+
setOpen(true);
|
|
1335
|
+
e.preventDefault();
|
|
1336
|
+
return;
|
|
1337
|
+
}
|
|
1338
|
+
if (e.key === "ArrowDown") {
|
|
1339
|
+
e.preventDefault();
|
|
1340
|
+
const idx = options.findIndex((o) => o.value === value);
|
|
1341
|
+
const next = options.slice(idx < 0 ? 0 : idx + 1).find((o) => !o.disabled);
|
|
1342
|
+
if (next) onChange == null ? void 0 : onChange(next.value);
|
|
1343
|
+
}
|
|
1344
|
+
if (e.key === "ArrowUp") {
|
|
1345
|
+
e.preventDefault();
|
|
1346
|
+
const idx = options.findIndex((o) => o.value === value);
|
|
1347
|
+
if (idx < 0) return;
|
|
1348
|
+
const prev = [...options].slice(0, idx).reverse().find((o) => !o.disabled);
|
|
1349
|
+
if (prev) onChange == null ? void 0 : onChange(prev.value);
|
|
1350
|
+
}
|
|
1351
|
+
},
|
|
1352
|
+
[open, options, value, onChange, toggle]
|
|
1353
|
+
);
|
|
1354
|
+
const triggerClass = [
|
|
1355
|
+
"flex h-10 w-full items-center justify-between rounded-lg border px-3 py-2 text-sm",
|
|
1356
|
+
"transition-colors bg-white dark:bg-slate-800/60",
|
|
1357
|
+
"focus:outline-none focus:ring-2 focus:ring-offset-0",
|
|
1358
|
+
error ? "border-red-400 dark:border-red-500 focus:ring-red-500/20" : "border-zinc-200 dark:border-slate-700 focus:ring-primary-500/20 dark:focus:ring-secondary-400/20 focus:border-primary-500 dark:focus:border-secondary-400",
|
|
1359
|
+
disabled ? "opacity-50 cursor-not-allowed" : "cursor-pointer",
|
|
1360
|
+
className
|
|
1361
|
+
].join(" ");
|
|
1362
|
+
return /* @__PURE__ */ jsxs11("div", { ref, className: "relative w-full", children: [
|
|
1363
|
+
label && /* @__PURE__ */ jsx14(
|
|
1364
|
+
Label,
|
|
1365
|
+
{
|
|
1366
|
+
htmlFor: id,
|
|
1367
|
+
className: "!text-zinc-700 dark:!text-zinc-300",
|
|
1368
|
+
required,
|
|
1369
|
+
children: label
|
|
1370
|
+
}
|
|
1371
|
+
),
|
|
1372
|
+
/* @__PURE__ */ jsxs11(
|
|
1373
|
+
Button,
|
|
1374
|
+
{
|
|
1375
|
+
id,
|
|
1376
|
+
type: "button",
|
|
1377
|
+
role: "combobox",
|
|
1378
|
+
"aria-expanded": open,
|
|
1379
|
+
"aria-haspopup": "listbox",
|
|
1380
|
+
"aria-disabled": disabled,
|
|
1381
|
+
disabled,
|
|
1382
|
+
variant: "ghost",
|
|
1383
|
+
className: triggerClass,
|
|
1384
|
+
onClick: toggle,
|
|
1385
|
+
onKeyDown: handleKeyDown,
|
|
1386
|
+
children: [
|
|
1387
|
+
/* @__PURE__ */ jsx14(
|
|
1388
|
+
Span,
|
|
1389
|
+
{
|
|
1390
|
+
className: selected ? "text-zinc-900 dark:text-zinc-50" : "text-zinc-400 dark:text-zinc-500",
|
|
1391
|
+
children: (_a = selected == null ? void 0 : selected.label) != null ? _a : placeholder
|
|
1392
|
+
}
|
|
1393
|
+
),
|
|
1394
|
+
/* @__PURE__ */ jsx14(
|
|
1395
|
+
ChevronDown,
|
|
1396
|
+
{
|
|
1397
|
+
className: `h-4 w-4 flex-shrink-0 text-zinc-400 transition-transform duration-200 ${open ? "rotate-180" : ""}`,
|
|
1398
|
+
"aria-hidden": "true"
|
|
1399
|
+
}
|
|
1400
|
+
)
|
|
1401
|
+
]
|
|
1402
|
+
}
|
|
1403
|
+
),
|
|
1404
|
+
open && /* @__PURE__ */ jsx14(
|
|
1405
|
+
Ul,
|
|
1406
|
+
{
|
|
1407
|
+
role: "listbox",
|
|
1408
|
+
className: [
|
|
1409
|
+
"absolute z-50 w-full overflow-auto rounded-lg border border-zinc-200 dark:border-slate-700 bg-white dark:bg-slate-800 shadow-lg max-h-60 py-1",
|
|
1410
|
+
openUp ? "bottom-full mb-1" : "top-full mt-1"
|
|
1411
|
+
].join(" "),
|
|
1412
|
+
children: options.map((option) => {
|
|
1413
|
+
const isSelected = option.value === value;
|
|
1414
|
+
return /* @__PURE__ */ jsxs11(
|
|
1415
|
+
Li,
|
|
1416
|
+
{
|
|
1417
|
+
role: "option",
|
|
1418
|
+
"aria-selected": isSelected,
|
|
1419
|
+
"aria-disabled": option.disabled,
|
|
1420
|
+
className: [
|
|
1421
|
+
"relative flex cursor-pointer items-center px-3 py-2 text-sm select-none",
|
|
1422
|
+
option.disabled ? "opacity-40 cursor-not-allowed" : isSelected ? "bg-primary-50 dark:bg-primary-900/20 text-primary-700 dark:text-primary-300" : "text-zinc-700 dark:text-zinc-300 hover:bg-zinc-50 dark:hover:bg-slate-700"
|
|
1423
|
+
].join(" "),
|
|
1424
|
+
onClick: () => !option.disabled && handleSelect(option.value),
|
|
1425
|
+
children: [
|
|
1426
|
+
/* @__PURE__ */ jsx14(Span, { className: "flex-1", children: option.label }),
|
|
1427
|
+
isSelected && /* @__PURE__ */ jsx14(
|
|
1428
|
+
Check,
|
|
1429
|
+
{
|
|
1430
|
+
className: "h-4 w-4 ml-2 flex-shrink-0",
|
|
1431
|
+
"aria-hidden": "true"
|
|
1432
|
+
}
|
|
1433
|
+
)
|
|
1434
|
+
]
|
|
1435
|
+
},
|
|
1436
|
+
option.value
|
|
1437
|
+
);
|
|
1438
|
+
})
|
|
1439
|
+
}
|
|
1440
|
+
),
|
|
1441
|
+
error && /* @__PURE__ */ jsx14(Text, { size: "xs", variant: "error", className: "mt-1.5", role: "alert", children: error })
|
|
1442
|
+
] });
|
|
1443
|
+
}
|
|
1444
|
+
|
|
1445
|
+
// src/components/StarRating.tsx
|
|
1446
|
+
import { useState as useState2 } from "react";
|
|
1447
|
+
import { Star } from "lucide-react";
|
|
1448
|
+
import { jsx as jsx15, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
1449
|
+
var SIZE_PX = { sm: "w-4 h-4", md: "w-5 h-5", lg: "w-6 h-6" };
|
|
1450
|
+
function StarRating({
|
|
1451
|
+
value = 0,
|
|
1452
|
+
onChange,
|
|
1453
|
+
max = 5,
|
|
1454
|
+
size = "md",
|
|
1455
|
+
readOnly = false,
|
|
1456
|
+
className = "",
|
|
1457
|
+
label
|
|
1458
|
+
}) {
|
|
1459
|
+
const [hovered, setHovered] = useState2(null);
|
|
1460
|
+
const displayed = hovered != null ? hovered : value;
|
|
1461
|
+
return /* @__PURE__ */ jsxs12(
|
|
1462
|
+
Span,
|
|
1463
|
+
{
|
|
1464
|
+
className: `inline-flex items-center gap-0.5 ${className}`,
|
|
1465
|
+
role: readOnly ? "img" : "group",
|
|
1466
|
+
"aria-label": label != null ? label : `${value} out of ${max} stars`,
|
|
1467
|
+
children: [
|
|
1468
|
+
Array.from({ length: max }, (_, i) => {
|
|
1469
|
+
const starValue = i + 1;
|
|
1470
|
+
const filled = starValue <= displayed;
|
|
1471
|
+
const half = !filled && starValue - 0.5 <= displayed;
|
|
1472
|
+
return /* @__PURE__ */ jsx15(
|
|
1473
|
+
Span,
|
|
1474
|
+
{
|
|
1475
|
+
className: readOnly ? void 0 : "cursor-pointer",
|
|
1476
|
+
onClick: () => !readOnly && (onChange == null ? void 0 : onChange(starValue)),
|
|
1477
|
+
onMouseEnter: () => !readOnly && setHovered(starValue),
|
|
1478
|
+
onMouseLeave: () => !readOnly && setHovered(null),
|
|
1479
|
+
"aria-hidden": !readOnly ? "true" : void 0,
|
|
1480
|
+
children: /* @__PURE__ */ jsx15(
|
|
1481
|
+
Star,
|
|
1482
|
+
{
|
|
1483
|
+
className: [
|
|
1484
|
+
SIZE_PX[size],
|
|
1485
|
+
"transition-colors duration-100",
|
|
1486
|
+
filled || half ? "fill-amber-400 text-amber-400" : "fill-transparent text-zinc-300 dark:text-slate-600",
|
|
1487
|
+
!readOnly && !filled ? "hover:fill-amber-300 hover:text-amber-300" : ""
|
|
1488
|
+
].join(" "),
|
|
1489
|
+
"aria-hidden": "true"
|
|
1490
|
+
}
|
|
1491
|
+
)
|
|
1492
|
+
},
|
|
1493
|
+
starValue
|
|
1494
|
+
);
|
|
1495
|
+
}),
|
|
1496
|
+
!readOnly && /* @__PURE__ */ jsxs12(Span, { className: "sr-only", children: [
|
|
1497
|
+
value,
|
|
1498
|
+
" out of ",
|
|
1499
|
+
max
|
|
1500
|
+
] })
|
|
1501
|
+
]
|
|
1502
|
+
}
|
|
1503
|
+
);
|
|
1504
|
+
}
|
|
1505
|
+
|
|
1506
|
+
// src/components/Breadcrumb.tsx
|
|
1507
|
+
import { ChevronRight } from "lucide-react";
|
|
1508
|
+
import { jsx as jsx16, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
1509
|
+
function Breadcrumb({ items, className = "" }) {
|
|
1510
|
+
return /* @__PURE__ */ jsx16(Nav, { "aria-label": "Breadcrumb", className, children: /* @__PURE__ */ jsx16(Ol, { className: "flex items-center gap-1 flex-wrap text-sm text-zinc-500 dark:text-zinc-400", children: items.map((item, i) => {
|
|
1511
|
+
const isLast = i === items.length - 1;
|
|
1512
|
+
return /* @__PURE__ */ jsxs13(Li, { className: "flex items-center gap-1", children: [
|
|
1513
|
+
i > 0 && /* @__PURE__ */ jsx16(
|
|
1514
|
+
ChevronRight,
|
|
1515
|
+
{
|
|
1516
|
+
className: "w-3.5 h-3.5 flex-shrink-0 text-zinc-400 dark:text-zinc-600",
|
|
1517
|
+
"aria-hidden": "true"
|
|
1518
|
+
}
|
|
1519
|
+
),
|
|
1520
|
+
isLast || !item.href ? /* @__PURE__ */ jsx16(
|
|
1521
|
+
Span,
|
|
1522
|
+
{
|
|
1523
|
+
className: isLast ? "font-medium text-zinc-900 dark:text-zinc-50" : "text-zinc-500 dark:text-zinc-400",
|
|
1524
|
+
"aria-current": isLast ? "page" : void 0,
|
|
1525
|
+
children: item.label
|
|
1526
|
+
}
|
|
1527
|
+
) : /* @__PURE__ */ jsx16(
|
|
1528
|
+
"a",
|
|
1529
|
+
{
|
|
1530
|
+
href: item.href,
|
|
1531
|
+
className: "hover:text-primary-600 dark:hover:text-primary-400 transition-colors",
|
|
1532
|
+
children: item.label
|
|
1533
|
+
}
|
|
1534
|
+
)
|
|
1535
|
+
] }, i);
|
|
1536
|
+
}) }) });
|
|
1537
|
+
}
|
|
1538
|
+
|
|
1539
|
+
// src/components/ImageLightbox.tsx
|
|
1540
|
+
import { useCallback as useCallback4, useEffect as useEffect4, useRef as useRef4, useState as useState3 } from "react";
|
|
1541
|
+
import { createPortal as createPortal3 } from "react-dom";
|
|
1542
|
+
import { ChevronLeft, ChevronRight as ChevronRight2, X as X3, ZoomIn } from "lucide-react";
|
|
1543
|
+
import { jsx as jsx17, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
1544
|
+
function ImageLightbox({
|
|
1545
|
+
images,
|
|
1546
|
+
activeIndex,
|
|
1547
|
+
onClose,
|
|
1548
|
+
onNavigate
|
|
1549
|
+
}) {
|
|
1550
|
+
var _a;
|
|
1551
|
+
const [currentIndex, setCurrentIndex] = useState3(activeIndex != null ? activeIndex : 0);
|
|
1552
|
+
const overlayRef = useRef4(null);
|
|
1553
|
+
useEffect4(() => {
|
|
1554
|
+
if (activeIndex !== null && activeIndex >= 0) {
|
|
1555
|
+
setCurrentIndex(activeIndex);
|
|
1556
|
+
}
|
|
1557
|
+
}, [activeIndex]);
|
|
1558
|
+
const isOpen = activeIndex !== null && activeIndex >= 0 && images.length > 0;
|
|
1559
|
+
useEffect4(() => {
|
|
1560
|
+
if (!isOpen) return;
|
|
1561
|
+
const prev = document.body.style.overflow;
|
|
1562
|
+
document.body.style.overflow = "hidden";
|
|
1563
|
+
return () => {
|
|
1564
|
+
document.body.style.overflow = prev;
|
|
1565
|
+
};
|
|
1566
|
+
}, [isOpen]);
|
|
1567
|
+
const navigate = useCallback4(
|
|
1568
|
+
(dir) => {
|
|
1569
|
+
setCurrentIndex((prev) => {
|
|
1570
|
+
const next = (prev + dir + images.length) % images.length;
|
|
1571
|
+
onNavigate == null ? void 0 : onNavigate(next);
|
|
1572
|
+
return next;
|
|
1573
|
+
});
|
|
1574
|
+
},
|
|
1575
|
+
[images.length, onNavigate]
|
|
1576
|
+
);
|
|
1577
|
+
const handleKeyDown = useCallback4(
|
|
1578
|
+
(e) => {
|
|
1579
|
+
if (e.key === "Escape") {
|
|
1580
|
+
onClose();
|
|
1581
|
+
return;
|
|
1582
|
+
}
|
|
1583
|
+
if (e.key === "ArrowLeft") {
|
|
1584
|
+
navigate(-1);
|
|
1585
|
+
return;
|
|
1586
|
+
}
|
|
1587
|
+
if (e.key === "ArrowRight") {
|
|
1588
|
+
navigate(1);
|
|
1589
|
+
return;
|
|
1590
|
+
}
|
|
1591
|
+
},
|
|
1592
|
+
[onClose, navigate]
|
|
1593
|
+
);
|
|
1594
|
+
useEffect4(() => {
|
|
1595
|
+
if (isOpen) {
|
|
1596
|
+
requestAnimationFrame(() => {
|
|
1597
|
+
var _a2;
|
|
1598
|
+
return (_a2 = overlayRef.current) == null ? void 0 : _a2.focus();
|
|
1599
|
+
});
|
|
1600
|
+
}
|
|
1601
|
+
}, [isOpen]);
|
|
1602
|
+
if (!isOpen || typeof document === "undefined") return null;
|
|
1603
|
+
const image = images[currentIndex];
|
|
1604
|
+
const hasMultiple = images.length > 1;
|
|
1605
|
+
return createPortal3(
|
|
1606
|
+
/* @__PURE__ */ jsxs14(
|
|
1607
|
+
"div",
|
|
1608
|
+
{
|
|
1609
|
+
ref: overlayRef,
|
|
1610
|
+
tabIndex: -1,
|
|
1611
|
+
className: "fixed inset-0 z-[9999] bg-black/95 flex flex-col items-center justify-center outline-none",
|
|
1612
|
+
role: "dialog",
|
|
1613
|
+
"aria-modal": "true",
|
|
1614
|
+
"aria-label": "Image lightbox",
|
|
1615
|
+
onKeyDown: handleKeyDown,
|
|
1616
|
+
children: [
|
|
1617
|
+
/* @__PURE__ */ jsx17(
|
|
1618
|
+
Button,
|
|
1619
|
+
{
|
|
1620
|
+
variant: "ghost",
|
|
1621
|
+
size: "sm",
|
|
1622
|
+
type: "button",
|
|
1623
|
+
onClick: onClose,
|
|
1624
|
+
className: "absolute top-4 right-4 z-10 w-12 h-12 p-0 !min-h-0 rounded-full bg-white/15 hover:bg-red-500/50 text-white flex items-center justify-center",
|
|
1625
|
+
"aria-label": "Close lightbox",
|
|
1626
|
+
children: /* @__PURE__ */ jsx17(X3, { className: "w-7 h-7" })
|
|
1627
|
+
}
|
|
1628
|
+
),
|
|
1629
|
+
hasMultiple && /* @__PURE__ */ jsxs14("div", { className: "absolute top-4 left-1/2 -translate-x-1/2 text-white/70 text-sm font-medium", children: [
|
|
1630
|
+
currentIndex + 1,
|
|
1631
|
+
" / ",
|
|
1632
|
+
images.length
|
|
1633
|
+
] }),
|
|
1634
|
+
hasMultiple && /* @__PURE__ */ jsx17(
|
|
1635
|
+
Button,
|
|
1636
|
+
{
|
|
1637
|
+
variant: "ghost",
|
|
1638
|
+
size: "sm",
|
|
1639
|
+
type: "button",
|
|
1640
|
+
onClick: () => navigate(-1),
|
|
1641
|
+
className: "absolute left-4 top-1/2 -translate-y-1/2 w-12 h-12 p-0 !min-h-0 rounded-full bg-white/15 hover:bg-white/30 text-white z-10 flex items-center justify-center",
|
|
1642
|
+
"aria-label": "Previous image",
|
|
1643
|
+
children: /* @__PURE__ */ jsx17(ChevronLeft, { className: "w-7 h-7" })
|
|
1644
|
+
}
|
|
1645
|
+
),
|
|
1646
|
+
/* @__PURE__ */ jsxs14("div", { className: "flex-1 flex items-center justify-center p-16 w-full h-full relative", children: [
|
|
1647
|
+
/* @__PURE__ */ jsx17(
|
|
1648
|
+
"img",
|
|
1649
|
+
{
|
|
1650
|
+
src: image.src,
|
|
1651
|
+
alt: (_a = image.alt) != null ? _a : "",
|
|
1652
|
+
className: "max-h-full max-w-full object-contain select-none",
|
|
1653
|
+
draggable: false
|
|
1654
|
+
}
|
|
1655
|
+
),
|
|
1656
|
+
/* @__PURE__ */ jsxs14("div", { className: "absolute bottom-4 right-4 text-white/40 flex items-center gap-1 text-xs", children: [
|
|
1657
|
+
/* @__PURE__ */ jsx17(ZoomIn, { className: "w-4 h-4" }),
|
|
1658
|
+
/* @__PURE__ */ jsx17(Span, { className: "text-xs", children: "Scroll to zoom" })
|
|
1659
|
+
] })
|
|
1660
|
+
] }),
|
|
1661
|
+
image.caption && /* @__PURE__ */ jsx17(
|
|
1662
|
+
Text,
|
|
1663
|
+
{
|
|
1664
|
+
size: "sm",
|
|
1665
|
+
variant: "secondary",
|
|
1666
|
+
className: "flex-shrink-0 !text-white/70 text-center px-8 pb-4",
|
|
1667
|
+
children: image.caption
|
|
1668
|
+
}
|
|
1669
|
+
),
|
|
1670
|
+
hasMultiple && /* @__PURE__ */ jsx17(
|
|
1671
|
+
Button,
|
|
1672
|
+
{
|
|
1673
|
+
variant: "ghost",
|
|
1674
|
+
size: "sm",
|
|
1675
|
+
type: "button",
|
|
1676
|
+
onClick: () => navigate(1),
|
|
1677
|
+
className: "absolute right-4 top-1/2 -translate-y-1/2 w-12 h-12 p-0 !min-h-0 rounded-full bg-white/15 hover:bg-white/30 text-white z-10 flex items-center justify-center",
|
|
1678
|
+
"aria-label": "Next image",
|
|
1679
|
+
children: /* @__PURE__ */ jsx17(ChevronRight2, { className: "w-7 h-7" })
|
|
1680
|
+
}
|
|
1681
|
+
)
|
|
1682
|
+
]
|
|
1683
|
+
}
|
|
1684
|
+
),
|
|
1685
|
+
document.body
|
|
1686
|
+
);
|
|
1687
|
+
}
|
|
1688
|
+
|
|
1689
|
+
// src/DataTable.tsx
|
|
1690
|
+
import { useState as useState4, useMemo } from "react";
|
|
1691
|
+
|
|
1692
|
+
// src/components/Layout.tsx
|
|
1693
|
+
import { jsx as jsx18 } from "react/jsx-runtime";
|
|
1694
|
+
var GAP_MAP = {
|
|
1695
|
+
none: "",
|
|
1696
|
+
px: "gap-px",
|
|
1697
|
+
xs: "gap-1",
|
|
1698
|
+
sm: "gap-2",
|
|
1699
|
+
"2.5": "gap-2.5",
|
|
1700
|
+
"3": "gap-3",
|
|
1701
|
+
md: "gap-4",
|
|
1702
|
+
lg: "gap-6",
|
|
1703
|
+
xl: "gap-8",
|
|
1704
|
+
"2xl": "gap-12"
|
|
1705
|
+
};
|
|
1706
|
+
var CONTAINER_MAP = {
|
|
1707
|
+
/** `max-w-3xl` — blog posts, legal / policy pages */
|
|
1708
|
+
sm: "max-w-3xl mx-auto px-4 sm:px-6 lg:px-8",
|
|
1709
|
+
/** `max-w-4xl` — narrow content, contact, about */
|
|
1710
|
+
md: "max-w-4xl mx-auto px-4 sm:px-6 lg:px-8",
|
|
1711
|
+
/** `max-w-5xl` — medium content, checkout, help */
|
|
1712
|
+
lg: "max-w-5xl mx-auto px-4 sm:px-6 lg:px-8",
|
|
1713
|
+
/** `max-w-6xl` — product detail, cart */
|
|
1714
|
+
xl: "max-w-6xl mx-auto px-4 sm:px-6 lg:px-8",
|
|
1715
|
+
/** `max-w-7xl` — main content grids (default) */
|
|
1716
|
+
"2xl": "max-w-7xl mx-auto px-4 sm:px-6 lg:px-8",
|
|
1717
|
+
/** `max-w-screen-2xl` — full-bleed wide content */
|
|
1718
|
+
full: "max-w-screen-2xl mx-auto px-4 sm:px-6 lg:px-8",
|
|
1719
|
+
/** `max-w-screen-2xl` — wide store/seller layouts (no lg:px-8) */
|
|
1720
|
+
wide: "max-w-screen-2xl mx-auto px-4 sm:px-6"
|
|
1721
|
+
};
|
|
1722
|
+
var GRID_MAP = {
|
|
1723
|
+
1: "grid grid-cols-1",
|
|
1724
|
+
2: "grid grid-cols-1 sm:grid-cols-2",
|
|
1725
|
+
3: "grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-3 2xl:grid-cols-3",
|
|
1726
|
+
4: "grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 2xl:grid-cols-4",
|
|
1727
|
+
5: "grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 xl:grid-cols-4 2xl:grid-cols-5",
|
|
1728
|
+
6: "grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 xl:grid-cols-5 2xl:grid-cols-6",
|
|
1729
|
+
/** Card grid — starts at 2 on mobile, max 5 on 2xl */
|
|
1730
|
+
cards: "grid grid-cols-2 md:grid-cols-3 lg:grid-cols-4 xl:grid-cols-4 2xl:grid-cols-5",
|
|
1731
|
+
/** Equal halves on md+ */
|
|
1732
|
+
halves: "grid grid-cols-1 md:grid-cols-2 xl:grid-cols-2 2xl:grid-cols-2",
|
|
1733
|
+
/** 2fr / 1fr split on md+ */
|
|
1734
|
+
twoThird: "grid grid-cols-1 md:grid-cols-[2fr_1fr]",
|
|
1735
|
+
/** 1fr / 2fr split on md+ */
|
|
1736
|
+
oneThird: "grid grid-cols-1 md:grid-cols-[1fr_2fr]",
|
|
1737
|
+
/** Fixed 280px left sidebar + 1fr on lg+ */
|
|
1738
|
+
sidebar: "grid grid-cols-1 lg:grid-cols-[280px_1fr]",
|
|
1739
|
+
/** 1fr + fixed 280px right sidebar on lg+ */
|
|
1740
|
+
sidebarRight: "grid grid-cols-1 lg:grid-cols-[1fr_280px]",
|
|
1741
|
+
/** Fixed 320px left sidebar + 1fr on lg+ (admin layout) */
|
|
1742
|
+
sidebarWide: "grid grid-cols-1 lg:grid-cols-[320px_1fr]",
|
|
1743
|
+
/** CSS auto-fill, min 200px columns */
|
|
1744
|
+
autoSm: "grid grid-cols-[repeat(auto-fill,minmax(200px,1fr))]",
|
|
1745
|
+
/** CSS auto-fill, min 280px columns */
|
|
1746
|
+
autoMd: "grid grid-cols-[repeat(auto-fill,minmax(280px,1fr))]",
|
|
1747
|
+
/** CSS auto-fill, min 360px columns */
|
|
1748
|
+
autoLg: "grid grid-cols-[repeat(auto-fill,minmax(360px,1fr))]"
|
|
1749
|
+
};
|
|
1750
|
+
var ITEMS_MAP = {
|
|
1751
|
+
start: "items-start",
|
|
1752
|
+
center: "items-center",
|
|
1753
|
+
end: "items-end",
|
|
1754
|
+
stretch: "items-stretch",
|
|
1755
|
+
baseline: "items-baseline"
|
|
1756
|
+
};
|
|
1757
|
+
var JUSTIFY_MAP = {
|
|
1758
|
+
start: "justify-start",
|
|
1759
|
+
center: "justify-center",
|
|
1760
|
+
end: "justify-end",
|
|
1761
|
+
between: "justify-between",
|
|
1762
|
+
around: "justify-around",
|
|
1763
|
+
evenly: "justify-evenly"
|
|
1764
|
+
};
|
|
1765
|
+
function Container(_a) {
|
|
1766
|
+
var _b = _a, {
|
|
1767
|
+
size = "2xl",
|
|
1768
|
+
as,
|
|
1769
|
+
className = "",
|
|
1770
|
+
children
|
|
1771
|
+
} = _b, props = __objRest(_b, [
|
|
1772
|
+
"size",
|
|
1773
|
+
"as",
|
|
1774
|
+
"className",
|
|
1775
|
+
"children"
|
|
1776
|
+
]);
|
|
1777
|
+
const Tag = as != null ? as : "div";
|
|
1778
|
+
return /* @__PURE__ */ jsx18(
|
|
1779
|
+
Tag,
|
|
1780
|
+
__spreadProps(__spreadValues({
|
|
1781
|
+
className: [CONTAINER_MAP[size], className].filter(Boolean).join(" ")
|
|
1782
|
+
}, props), {
|
|
1783
|
+
children
|
|
1784
|
+
})
|
|
1785
|
+
);
|
|
1786
|
+
}
|
|
1787
|
+
function Stack(_a) {
|
|
1788
|
+
var _b = _a, {
|
|
1789
|
+
gap = "md",
|
|
1790
|
+
align = "stretch",
|
|
1791
|
+
as,
|
|
1792
|
+
className = "",
|
|
1793
|
+
children
|
|
1794
|
+
} = _b, props = __objRest(_b, [
|
|
1795
|
+
"gap",
|
|
1796
|
+
"align",
|
|
1797
|
+
"as",
|
|
1798
|
+
"className",
|
|
1799
|
+
"children"
|
|
1800
|
+
]);
|
|
1801
|
+
const Tag = as != null ? as : "div";
|
|
1802
|
+
const classes = [
|
|
1803
|
+
"flex flex-col",
|
|
1804
|
+
GAP_MAP[gap],
|
|
1805
|
+
align !== "stretch" ? ITEMS_MAP[align] : "",
|
|
1806
|
+
className
|
|
1807
|
+
].filter(Boolean).join(" ");
|
|
1808
|
+
return /* @__PURE__ */ jsx18(Tag, __spreadProps(__spreadValues({ className: classes }, props), { children }));
|
|
1809
|
+
}
|
|
1810
|
+
function Row(_a) {
|
|
1811
|
+
var _b = _a, {
|
|
1812
|
+
gap = "md",
|
|
1813
|
+
align = "center",
|
|
1814
|
+
justify = "start",
|
|
1815
|
+
wrap = false,
|
|
1816
|
+
as,
|
|
1817
|
+
className = "",
|
|
1818
|
+
children
|
|
1819
|
+
} = _b, props = __objRest(_b, [
|
|
1820
|
+
"gap",
|
|
1821
|
+
"align",
|
|
1822
|
+
"justify",
|
|
1823
|
+
"wrap",
|
|
1824
|
+
"as",
|
|
1825
|
+
"className",
|
|
1826
|
+
"children"
|
|
1827
|
+
]);
|
|
1828
|
+
const Tag = as != null ? as : "div";
|
|
1829
|
+
const classes = [
|
|
1830
|
+
"flex flex-row",
|
|
1831
|
+
ITEMS_MAP[align],
|
|
1832
|
+
justify !== "start" ? JUSTIFY_MAP[justify] : "",
|
|
1833
|
+
GAP_MAP[gap],
|
|
1834
|
+
wrap ? "flex-wrap" : "",
|
|
1835
|
+
className
|
|
1836
|
+
].filter(Boolean).join(" ");
|
|
1837
|
+
return /* @__PURE__ */ jsx18(Tag, __spreadProps(__spreadValues({ className: classes }, props), { children }));
|
|
1838
|
+
}
|
|
1839
|
+
function Grid(_a) {
|
|
1840
|
+
var _b = _a, {
|
|
1841
|
+
cols,
|
|
1842
|
+
gap = "md",
|
|
1843
|
+
as,
|
|
1844
|
+
className = "",
|
|
1845
|
+
children
|
|
1846
|
+
} = _b, props = __objRest(_b, [
|
|
1847
|
+
"cols",
|
|
1848
|
+
"gap",
|
|
1849
|
+
"as",
|
|
1850
|
+
"className",
|
|
1851
|
+
"children"
|
|
1852
|
+
]);
|
|
1853
|
+
const Tag = as != null ? as : "div";
|
|
1854
|
+
const baseClass = cols !== void 0 ? GRID_MAP[cols] : "grid";
|
|
1855
|
+
const classes = [baseClass, GAP_MAP[gap], className].filter(Boolean).join(" ");
|
|
1856
|
+
return /* @__PURE__ */ jsx18(Tag, __spreadProps(__spreadValues({ className: classes }, props), { children }));
|
|
1857
|
+
}
|
|
1858
|
+
|
|
1859
|
+
// src/DataTable.tsx
|
|
1860
|
+
import { mergeTableConfig, DEFAULT_PAGINATION_CONFIG as DEFAULT_PAGINATION_CONFIG2 } from "@mohasinac/contracts";
|
|
1861
|
+
import { Fragment as Fragment2, jsx as jsx19, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
1862
|
+
function DataTable({
|
|
1863
|
+
data,
|
|
1864
|
+
columns,
|
|
1865
|
+
keyExtractor,
|
|
1866
|
+
onRowClick,
|
|
1867
|
+
loading = false,
|
|
1868
|
+
emptyMessage,
|
|
1869
|
+
actions,
|
|
1870
|
+
mobileCardRender,
|
|
1871
|
+
emptyState,
|
|
1872
|
+
emptyIcon,
|
|
1873
|
+
emptyTitle,
|
|
1874
|
+
tableConfig,
|
|
1875
|
+
paginationConfig,
|
|
1876
|
+
externalPagination = false,
|
|
1877
|
+
// Explicit flat props — override tableConfig when provided
|
|
1878
|
+
pageSize: pageSizeProp,
|
|
1879
|
+
stickyHeader: stickyHeaderProp,
|
|
1880
|
+
striped: stripedProp,
|
|
1881
|
+
showViewToggle: showViewToggleProp,
|
|
1882
|
+
showTableView = true,
|
|
1883
|
+
viewMode: controlledViewMode,
|
|
1884
|
+
defaultViewMode: defaultViewModeProp,
|
|
1885
|
+
onViewModeChange,
|
|
1886
|
+
selectable: selectableProp,
|
|
1887
|
+
selectedIds = [],
|
|
1888
|
+
onSelectionChange,
|
|
1889
|
+
gridCols = "cards",
|
|
1890
|
+
labels = {}
|
|
1891
|
+
}) {
|
|
1892
|
+
const resolvedTable = mergeTableConfig(tableConfig);
|
|
1893
|
+
const resolvedPag = __spreadValues(__spreadValues(__spreadValues({}, DEFAULT_PAGINATION_CONFIG2), tableConfig == null ? void 0 : tableConfig.pagination), paginationConfig);
|
|
1894
|
+
const pageSize = pageSizeProp != null ? pageSizeProp : resolvedTable.pageSize;
|
|
1895
|
+
const stickyHeader = stickyHeaderProp != null ? stickyHeaderProp : resolvedTable.sticky.enabled;
|
|
1896
|
+
const striped = stripedProp != null ? stripedProp : resolvedTable.striped;
|
|
1897
|
+
const showViewToggle = showViewToggleProp != null ? showViewToggleProp : resolvedTable.showViewToggle;
|
|
1898
|
+
const selectable = selectableProp != null ? selectableProp : resolvedTable.selectable;
|
|
1899
|
+
const defaultViewMode = defaultViewModeProp != null ? defaultViewModeProp : resolvedTable.defaultViewMode;
|
|
1900
|
+
const [sortKey, setSortKey] = useState4(null);
|
|
1901
|
+
const [sortDirection, setSortDirection] = useState4(null);
|
|
1902
|
+
const [currentPage, setCurrentPage] = useState4(1);
|
|
1903
|
+
const [internalViewMode, setInternalViewMode] = useState4(defaultViewMode);
|
|
1904
|
+
const activeViewMode = controlledViewMode != null ? controlledViewMode : internalViewMode;
|
|
1905
|
+
const {
|
|
1906
|
+
loading: labelLoading = "Loading\u2026",
|
|
1907
|
+
noDataTitle = "No data found",
|
|
1908
|
+
noDataDescription = "There are no items to display.",
|
|
1909
|
+
actions: labelActions = "Actions",
|
|
1910
|
+
tableView = "Table view",
|
|
1911
|
+
gridView = "Grid view",
|
|
1912
|
+
listView = "List view"
|
|
1913
|
+
} = labels;
|
|
1914
|
+
const handleViewModeChange = (mode) => {
|
|
1915
|
+
if (controlledViewMode === void 0) setInternalViewMode(mode);
|
|
1916
|
+
onViewModeChange == null ? void 0 : onViewModeChange(mode);
|
|
1917
|
+
};
|
|
1918
|
+
const handleSort = (key) => {
|
|
1919
|
+
const col = columns.find((c) => c.key === key);
|
|
1920
|
+
if (!(col == null ? void 0 : col.sortable)) return;
|
|
1921
|
+
if (sortKey === key) {
|
|
1922
|
+
if (sortDirection === "asc") setSortDirection("desc");
|
|
1923
|
+
else {
|
|
1924
|
+
setSortKey(null);
|
|
1925
|
+
setSortDirection(null);
|
|
1926
|
+
}
|
|
1927
|
+
} else {
|
|
1928
|
+
setSortKey(key);
|
|
1929
|
+
setSortDirection("asc");
|
|
1930
|
+
}
|
|
1931
|
+
};
|
|
1932
|
+
const sortedData = useMemo(() => {
|
|
1933
|
+
const sorted = [...data];
|
|
1934
|
+
if (sortKey && sortDirection) {
|
|
1935
|
+
sorted.sort((a, b) => {
|
|
1936
|
+
const aVal = a[sortKey];
|
|
1937
|
+
const bVal = b[sortKey];
|
|
1938
|
+
if (aVal == null) return 1;
|
|
1939
|
+
if (bVal == null) return -1;
|
|
1940
|
+
if (typeof aVal === "string" && typeof bVal === "string") {
|
|
1941
|
+
return sortDirection === "asc" ? aVal.localeCompare(bVal) : bVal.localeCompare(aVal);
|
|
1942
|
+
}
|
|
1943
|
+
if (aVal < bVal) return sortDirection === "asc" ? -1 : 1;
|
|
1944
|
+
if (aVal > bVal) return sortDirection === "asc" ? 1 : -1;
|
|
1945
|
+
return 0;
|
|
1946
|
+
});
|
|
1947
|
+
}
|
|
1948
|
+
return sorted;
|
|
1949
|
+
}, [data, sortKey, sortDirection]);
|
|
1950
|
+
const paginatedData = useMemo(() => {
|
|
1951
|
+
if (externalPagination) return sortedData;
|
|
1952
|
+
const start = (currentPage - 1) * pageSize;
|
|
1953
|
+
return sortedData.slice(start, start + pageSize);
|
|
1954
|
+
}, [sortedData, currentPage, externalPagination, pageSize]);
|
|
1955
|
+
const totalPages = Math.ceil(sortedData.length / pageSize);
|
|
1956
|
+
if (loading) {
|
|
1957
|
+
return /* @__PURE__ */ jsx19("div", { className: "rounded-2xl border border-zinc-200 dark:border-slate-700 overflow-hidden", children: /* @__PURE__ */ jsx19("div", { className: "flex items-center justify-center h-64", children: /* @__PURE__ */ jsx19(Spinner, { size: "lg", label: labelLoading }) }) });
|
|
1958
|
+
}
|
|
1959
|
+
if (data.length === 0) {
|
|
1960
|
+
if (emptyState) return /* @__PURE__ */ jsx19(Fragment2, { children: emptyState });
|
|
1961
|
+
return /* @__PURE__ */ jsx19("div", { className: "rounded-2xl border border-zinc-200 dark:border-slate-700 overflow-hidden", children: /* @__PURE__ */ jsx19("div", { className: "flex items-center justify-center h-64", children: /* @__PURE__ */ jsxs15("div", { className: "text-center px-4", children: [
|
|
1962
|
+
emptyIcon != null ? emptyIcon : /* @__PURE__ */ jsx19(
|
|
1963
|
+
"svg",
|
|
1964
|
+
{
|
|
1965
|
+
className: "mx-auto h-12 w-12 text-zinc-400",
|
|
1966
|
+
fill: "none",
|
|
1967
|
+
viewBox: "0 0 24 24",
|
|
1968
|
+
stroke: "currentColor",
|
|
1969
|
+
"aria-hidden": "true",
|
|
1970
|
+
children: /* @__PURE__ */ jsx19(
|
|
1971
|
+
"path",
|
|
1972
|
+
{
|
|
1973
|
+
strokeLinecap: "round",
|
|
1974
|
+
strokeLinejoin: "round",
|
|
1975
|
+
strokeWidth: 1.5,
|
|
1976
|
+
d: "M20 13V6a2 2 0 00-2-2H6a2 2 0 00-2 2v7m16 0v5a2 2 0 01-2 2H6a2 2 0 01-2-2v-5m16 0h-2.586a1 1 0 00-.707.293l-2.414 2.414a1 1 0 01-.707.293h-3.172a1 1 0 01-.707-.293l-2.414-2.414A1 1 0 006.586 13H4"
|
|
1977
|
+
}
|
|
1978
|
+
)
|
|
1979
|
+
}
|
|
1980
|
+
),
|
|
1981
|
+
/* @__PURE__ */ jsx19(Text, { size: "sm", weight: "semibold", className: "mt-4", children: emptyTitle != null ? emptyTitle : noDataTitle }),
|
|
1982
|
+
/* @__PURE__ */ jsx19(Text, { size: "sm", variant: "secondary", className: "mt-1", children: emptyMessage != null ? emptyMessage : noDataDescription })
|
|
1983
|
+
] }) }) });
|
|
1984
|
+
}
|
|
1985
|
+
const renderViewToggle = () => {
|
|
1986
|
+
if (!showViewToggle) return null;
|
|
1987
|
+
return /* @__PURE__ */ jsxs15(
|
|
1988
|
+
"div",
|
|
1989
|
+
{
|
|
1990
|
+
className: "flex justify-end gap-1",
|
|
1991
|
+
role: "toolbar",
|
|
1992
|
+
"aria-label": "View mode",
|
|
1993
|
+
children: [
|
|
1994
|
+
showTableView && /* @__PURE__ */ jsx19(
|
|
1995
|
+
Button,
|
|
1996
|
+
{
|
|
1997
|
+
type: "button",
|
|
1998
|
+
variant: "ghost",
|
|
1999
|
+
size: "sm",
|
|
2000
|
+
onClick: () => handleViewModeChange("table"),
|
|
2001
|
+
"aria-label": tableView,
|
|
2002
|
+
"aria-pressed": activeViewMode === "table",
|
|
2003
|
+
className: `hidden sm:flex items-center justify-center p-2 rounded-lg ring-1 transition-colors ${activeViewMode === "table" ? "bg-primary/5 text-primary dark:bg-primary/10 ring-primary/30" : "text-zinc-500 dark:text-zinc-400 ring-zinc-200 dark:ring-slate-700 hover:bg-zinc-100 dark:hover:bg-slate-800"}`,
|
|
2004
|
+
children: /* @__PURE__ */ jsx19(
|
|
2005
|
+
"svg",
|
|
2006
|
+
{
|
|
2007
|
+
className: "w-4 h-4",
|
|
2008
|
+
fill: "none",
|
|
2009
|
+
viewBox: "0 0 24 24",
|
|
2010
|
+
stroke: "currentColor",
|
|
2011
|
+
strokeWidth: 1.5,
|
|
2012
|
+
"aria-hidden": "true",
|
|
2013
|
+
children: /* @__PURE__ */ jsx19(
|
|
2014
|
+
"path",
|
|
2015
|
+
{
|
|
2016
|
+
strokeLinecap: "round",
|
|
2017
|
+
strokeLinejoin: "round",
|
|
2018
|
+
d: "M3 10h18M3 6h18M3 14h18M3 18h18"
|
|
2019
|
+
}
|
|
2020
|
+
)
|
|
2021
|
+
}
|
|
2022
|
+
)
|
|
2023
|
+
}
|
|
2024
|
+
),
|
|
2025
|
+
/* @__PURE__ */ jsx19(
|
|
2026
|
+
Button,
|
|
2027
|
+
{
|
|
2028
|
+
type: "button",
|
|
2029
|
+
variant: "ghost",
|
|
2030
|
+
size: "sm",
|
|
2031
|
+
onClick: () => handleViewModeChange("grid"),
|
|
2032
|
+
"aria-label": gridView,
|
|
2033
|
+
"aria-pressed": activeViewMode === "grid",
|
|
2034
|
+
className: `flex items-center justify-center p-2 rounded-lg ring-1 transition-colors ${activeViewMode === "grid" ? "bg-primary/5 text-primary dark:bg-primary/10 ring-primary/30" : "text-zinc-500 dark:text-zinc-400 ring-zinc-200 dark:ring-slate-700 hover:bg-zinc-100 dark:hover:bg-slate-800"}`,
|
|
2035
|
+
children: /* @__PURE__ */ jsx19(
|
|
2036
|
+
"svg",
|
|
2037
|
+
{
|
|
2038
|
+
className: "w-4 h-4",
|
|
2039
|
+
fill: "none",
|
|
2040
|
+
viewBox: "0 0 24 24",
|
|
2041
|
+
stroke: "currentColor",
|
|
2042
|
+
strokeWidth: 1.5,
|
|
2043
|
+
"aria-hidden": "true",
|
|
2044
|
+
children: /* @__PURE__ */ jsx19(
|
|
2045
|
+
"path",
|
|
2046
|
+
{
|
|
2047
|
+
strokeLinecap: "round",
|
|
2048
|
+
strokeLinejoin: "round",
|
|
2049
|
+
d: "M3.75 6A2.25 2.25 0 016 3.75h2.25A2.25 2.25 0 0110.5 6v2.25a2.25 2.25 0 01-2.25 2.25H6a2.25 2.25 0 01-2.25-2.25V6zM3.75 15.75A2.25 2.25 0 016 13.5h2.25a2.25 2.25 0 012.25 2.25V18a2.25 2.25 0 01-2.25 2.25H6A2.25 2.25 0 013.75 18v-2.25zM13.5 6a2.25 2.25 0 012.25-2.25H18A2.25 2.25 0 0120.25 6v2.25A2.25 2.25 0 0118 10.5h-2.25a2.25 2.25 0 01-2.25-2.25V6zM13.5 15.75a2.25 2.25 0 012.25-2.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-2.25A2.25 2.25 0 0113.5 18v-2.25z"
|
|
2050
|
+
}
|
|
2051
|
+
)
|
|
2052
|
+
}
|
|
2053
|
+
)
|
|
2054
|
+
}
|
|
2055
|
+
),
|
|
2056
|
+
/* @__PURE__ */ jsx19(
|
|
2057
|
+
Button,
|
|
2058
|
+
{
|
|
2059
|
+
type: "button",
|
|
2060
|
+
variant: "ghost",
|
|
2061
|
+
size: "sm",
|
|
2062
|
+
onClick: () => handleViewModeChange("list"),
|
|
2063
|
+
"aria-label": listView,
|
|
2064
|
+
"aria-pressed": activeViewMode === "list",
|
|
2065
|
+
className: `flex items-center justify-center p-2 rounded-lg ring-1 transition-colors ${activeViewMode === "list" ? "bg-primary/5 text-primary dark:bg-primary/10 ring-primary/30" : "text-zinc-500 dark:text-zinc-400 ring-zinc-200 dark:ring-slate-700 hover:bg-zinc-100 dark:hover:bg-slate-800"}`,
|
|
2066
|
+
children: /* @__PURE__ */ jsx19(
|
|
2067
|
+
"svg",
|
|
2068
|
+
{
|
|
2069
|
+
className: "w-4 h-4",
|
|
2070
|
+
fill: "none",
|
|
2071
|
+
viewBox: "0 0 24 24",
|
|
2072
|
+
stroke: "currentColor",
|
|
2073
|
+
strokeWidth: 1.5,
|
|
2074
|
+
"aria-hidden": "true",
|
|
2075
|
+
children: /* @__PURE__ */ jsx19(
|
|
2076
|
+
"path",
|
|
2077
|
+
{
|
|
2078
|
+
strokeLinecap: "round",
|
|
2079
|
+
strokeLinejoin: "round",
|
|
2080
|
+
d: "M8.25 6.75h12M8.25 12h12m-12 5.25h12M3.75 6.75h.007v.008H3.75V6.75zm.375 0a.375.375 0 11-.75 0 .375.375 0 01.75 0zM3.75 12h.007v.008H3.75V12zm.375 0a.375.375 0 11-.75 0 .375.375 0 01.75 0zm-.375 5.25h.007v.008H3.75v-.008zm.375 0a.375.375 0 11-.75 0 .375.375 0 01.75 0z"
|
|
2081
|
+
}
|
|
2082
|
+
)
|
|
2083
|
+
}
|
|
2084
|
+
)
|
|
2085
|
+
}
|
|
2086
|
+
)
|
|
2087
|
+
]
|
|
2088
|
+
}
|
|
2089
|
+
);
|
|
2090
|
+
};
|
|
2091
|
+
const renderCardGrid = (mode) => {
|
|
2092
|
+
if (!mobileCardRender) return null;
|
|
2093
|
+
return /* @__PURE__ */ jsx19(
|
|
2094
|
+
"div",
|
|
2095
|
+
{
|
|
2096
|
+
className: mode === "grid" ? `${GRID_MAP[gridCols]} gap-6` : "flex flex-col gap-4",
|
|
2097
|
+
children: paginatedData.map((item) => /* @__PURE__ */ jsx19(
|
|
2098
|
+
SelectableCard,
|
|
2099
|
+
{
|
|
2100
|
+
id: keyExtractor(item),
|
|
2101
|
+
selectable,
|
|
2102
|
+
selected: selectedIds.includes(keyExtractor(item)),
|
|
2103
|
+
listMode: mode === "list",
|
|
2104
|
+
onToggle: (id, checked) => onSelectionChange == null ? void 0 : onSelectionChange(
|
|
2105
|
+
checked ? [...selectedIds, id] : selectedIds.filter((s) => s !== id)
|
|
2106
|
+
),
|
|
2107
|
+
children: mobileCardRender(item)
|
|
2108
|
+
},
|
|
2109
|
+
keyExtractor(item)
|
|
2110
|
+
))
|
|
2111
|
+
}
|
|
2112
|
+
);
|
|
2113
|
+
};
|
|
2114
|
+
return /* @__PURE__ */ jsxs15("div", { className: "space-y-4", children: [
|
|
2115
|
+
renderViewToggle(),
|
|
2116
|
+
activeViewMode !== "table" && mobileCardRender && renderCardGrid(activeViewMode),
|
|
2117
|
+
activeViewMode === "table" && mobileCardRender && /* @__PURE__ */ jsx19("div", { className: "md:hidden space-y-6", children: paginatedData.map((item) => /* @__PURE__ */ jsx19(
|
|
2118
|
+
SelectableCard,
|
|
2119
|
+
{
|
|
2120
|
+
id: keyExtractor(item),
|
|
2121
|
+
selectable,
|
|
2122
|
+
selected: selectedIds.includes(keyExtractor(item)),
|
|
2123
|
+
onToggle: (id, checked) => onSelectionChange == null ? void 0 : onSelectionChange(
|
|
2124
|
+
checked ? [...selectedIds, id] : selectedIds.filter((s) => s !== id)
|
|
2125
|
+
),
|
|
2126
|
+
children: mobileCardRender(item)
|
|
2127
|
+
},
|
|
2128
|
+
keyExtractor(item)
|
|
2129
|
+
)) }),
|
|
2130
|
+
activeViewMode === "table" && /* @__PURE__ */ jsx19("div", { className: "rounded-2xl border border-zinc-200 dark:border-slate-700 overflow-hidden", children: /* @__PURE__ */ jsx19(
|
|
2131
|
+
"div",
|
|
2132
|
+
{
|
|
2133
|
+
className: `overflow-x-auto ${stickyHeader ? "max-h-[600px] overflow-y-auto" : ""}`,
|
|
2134
|
+
children: /* @__PURE__ */ jsxs15("table", { className: "min-w-full divide-y divide-zinc-200 dark:divide-slate-700", children: [
|
|
2135
|
+
/* @__PURE__ */ jsx19(
|
|
2136
|
+
"thead",
|
|
2137
|
+
{
|
|
2138
|
+
className: `bg-zinc-50 dark:bg-slate-800 ${stickyHeader ? "sticky top-0 z-10" : ""}`,
|
|
2139
|
+
children: /* @__PURE__ */ jsxs15("tr", { children: [
|
|
2140
|
+
selectable && /* @__PURE__ */ jsx19("th", { scope: "col", className: "px-4 py-3 w-8", children: /* @__PURE__ */ jsx19(
|
|
2141
|
+
"input",
|
|
2142
|
+
{
|
|
2143
|
+
type: "checkbox",
|
|
2144
|
+
className: "rounded border-zinc-300",
|
|
2145
|
+
"aria-label": "Select all on page",
|
|
2146
|
+
checked: paginatedData.length > 0 && paginatedData.every(
|
|
2147
|
+
(item) => selectedIds.includes(keyExtractor(item))
|
|
2148
|
+
),
|
|
2149
|
+
onChange: (e) => {
|
|
2150
|
+
const pageIds = paginatedData.map(keyExtractor);
|
|
2151
|
+
onSelectionChange == null ? void 0 : onSelectionChange(
|
|
2152
|
+
e.target.checked ? [.../* @__PURE__ */ new Set([...selectedIds, ...pageIds])] : selectedIds.filter(
|
|
2153
|
+
(id) => !pageIds.includes(id)
|
|
2154
|
+
)
|
|
2155
|
+
);
|
|
2156
|
+
}
|
|
2157
|
+
}
|
|
2158
|
+
) }),
|
|
2159
|
+
columns.map((col) => /* @__PURE__ */ jsx19(
|
|
2160
|
+
"th",
|
|
2161
|
+
{
|
|
2162
|
+
scope: "col",
|
|
2163
|
+
"aria-sort": col.sortable ? sortKey === col.key ? sortDirection === "asc" ? "ascending" : "descending" : "none" : void 0,
|
|
2164
|
+
className: `px-6 py-3 text-left text-xs font-medium text-zinc-500 dark:text-zinc-400 uppercase tracking-wider ${col.sortable ? "cursor-pointer select-none hover:bg-zinc-100 dark:hover:bg-slate-700" : ""}`,
|
|
2165
|
+
style: { width: col.width },
|
|
2166
|
+
onClick: () => col.sortable && handleSort(col.key),
|
|
2167
|
+
children: /* @__PURE__ */ jsxs15("div", { className: "flex items-center gap-2", children: [
|
|
2168
|
+
col.header,
|
|
2169
|
+
col.sortable && /* @__PURE__ */ jsx19("span", { className: "text-zinc-400", "aria-hidden": "true", children: sortKey === col.key ? sortDirection === "asc" ? "\u2191" : "\u2193" : /* @__PURE__ */ jsx19("span", { className: "opacity-30", children: "\u2195" }) })
|
|
2170
|
+
] })
|
|
2171
|
+
},
|
|
2172
|
+
col.key
|
|
2173
|
+
)),
|
|
2174
|
+
actions && /* @__PURE__ */ jsx19(
|
|
2175
|
+
"th",
|
|
2176
|
+
{
|
|
2177
|
+
scope: "col",
|
|
2178
|
+
className: "px-6 py-3 text-right text-xs font-medium text-zinc-500 dark:text-zinc-400 uppercase tracking-wider",
|
|
2179
|
+
children: labelActions
|
|
2180
|
+
}
|
|
2181
|
+
)
|
|
2182
|
+
] })
|
|
2183
|
+
}
|
|
2184
|
+
),
|
|
2185
|
+
/* @__PURE__ */ jsx19("tbody", { className: "bg-white dark:bg-slate-900 divide-y divide-zinc-200 dark:divide-slate-700", children: paginatedData.map((item, index) => /* @__PURE__ */ jsxs15(
|
|
2186
|
+
"tr",
|
|
2187
|
+
{
|
|
2188
|
+
className: [
|
|
2189
|
+
striped && index % 2 === 1 ? "bg-zinc-50 dark:bg-slate-800" : "",
|
|
2190
|
+
onRowClick ? "cursor-pointer hover:bg-zinc-50 dark:hover:bg-slate-800/60" : "",
|
|
2191
|
+
"transition-colors duration-150"
|
|
2192
|
+
].join(" "),
|
|
2193
|
+
onClick: () => onRowClick == null ? void 0 : onRowClick(item),
|
|
2194
|
+
children: [
|
|
2195
|
+
selectable && /* @__PURE__ */ jsx19(
|
|
2196
|
+
"td",
|
|
2197
|
+
{
|
|
2198
|
+
className: "px-4 py-4 w-8",
|
|
2199
|
+
onClick: (e) => e.stopPropagation(),
|
|
2200
|
+
children: /* @__PURE__ */ jsx19(
|
|
2201
|
+
"input",
|
|
2202
|
+
{
|
|
2203
|
+
type: "checkbox",
|
|
2204
|
+
className: "rounded border-zinc-300",
|
|
2205
|
+
"aria-label": "Select row",
|
|
2206
|
+
checked: selectedIds.includes(keyExtractor(item)),
|
|
2207
|
+
onChange: (e) => {
|
|
2208
|
+
const id = keyExtractor(item);
|
|
2209
|
+
onSelectionChange == null ? void 0 : onSelectionChange(
|
|
2210
|
+
e.target.checked ? [...selectedIds, id] : selectedIds.filter((s) => s !== id)
|
|
2211
|
+
);
|
|
2212
|
+
}
|
|
2213
|
+
}
|
|
2214
|
+
)
|
|
2215
|
+
}
|
|
2216
|
+
),
|
|
2217
|
+
columns.map((col) => {
|
|
2218
|
+
var _a;
|
|
2219
|
+
return /* @__PURE__ */ jsx19(
|
|
2220
|
+
"td",
|
|
2221
|
+
{
|
|
2222
|
+
className: "px-6 py-4 whitespace-nowrap text-sm text-zinc-900 dark:text-zinc-100",
|
|
2223
|
+
children: col.render ? col.render(item) : (_a = item[col.key]) != null ? _a : "-"
|
|
2224
|
+
},
|
|
2225
|
+
col.key
|
|
2226
|
+
);
|
|
2227
|
+
}),
|
|
2228
|
+
actions && /* @__PURE__ */ jsx19(
|
|
2229
|
+
"td",
|
|
2230
|
+
{
|
|
2231
|
+
className: "px-6 py-4 whitespace-nowrap text-right text-sm font-medium",
|
|
2232
|
+
onClick: (e) => e.stopPropagation(),
|
|
2233
|
+
children: actions(item)
|
|
2234
|
+
}
|
|
2235
|
+
)
|
|
2236
|
+
]
|
|
2237
|
+
},
|
|
2238
|
+
keyExtractor(item)
|
|
2239
|
+
)) })
|
|
2240
|
+
] })
|
|
2241
|
+
}
|
|
2242
|
+
) }),
|
|
2243
|
+
!externalPagination && totalPages > 1 && /* @__PURE__ */ jsx19("div", { className: "flex justify-center", children: /* @__PURE__ */ jsx19(
|
|
2244
|
+
Pagination,
|
|
2245
|
+
{
|
|
2246
|
+
currentPage,
|
|
2247
|
+
totalPages,
|
|
2248
|
+
onPageChange: setCurrentPage,
|
|
2249
|
+
maxVisible: resolvedPag.maxVisible,
|
|
2250
|
+
showFirstLast: resolvedPag.showFirstLast,
|
|
2251
|
+
showPrevNext: resolvedPag.showPrevNext,
|
|
2252
|
+
size: resolvedPag.size
|
|
2253
|
+
}
|
|
2254
|
+
) })
|
|
2255
|
+
] });
|
|
2256
|
+
}
|
|
2257
|
+
function SelectableCard({
|
|
2258
|
+
id,
|
|
2259
|
+
selectable,
|
|
2260
|
+
selected,
|
|
2261
|
+
onToggle,
|
|
2262
|
+
children,
|
|
2263
|
+
listMode = false
|
|
2264
|
+
}) {
|
|
2265
|
+
if (!selectable) return /* @__PURE__ */ jsx19("div", { className: "h-full", children });
|
|
2266
|
+
return /* @__PURE__ */ jsxs15("div", { className: "relative group h-full", children: [
|
|
2267
|
+
/* @__PURE__ */ jsx19(
|
|
2268
|
+
"div",
|
|
2269
|
+
{
|
|
2270
|
+
className: [
|
|
2271
|
+
"absolute z-10",
|
|
2272
|
+
listMode ? "left-2 top-1/2 -translate-y-1/2" : "top-2 left-2"
|
|
2273
|
+
].join(" "),
|
|
2274
|
+
onClick: (e) => e.stopPropagation(),
|
|
2275
|
+
children: /* @__PURE__ */ jsx19("div", { className: "w-6 h-6 rounded-md bg-white/95 dark:bg-slate-800/95 shadow-md flex items-center justify-center", children: /* @__PURE__ */ jsxs15("div", { className: "relative flex items-center justify-center", children: [
|
|
2276
|
+
/* @__PURE__ */ jsx19(
|
|
2277
|
+
"input",
|
|
2278
|
+
{
|
|
2279
|
+
type: "checkbox",
|
|
2280
|
+
className: [
|
|
2281
|
+
"w-4 h-4 rounded cursor-pointer transition-all appearance-none",
|
|
2282
|
+
selected ? "border-2 border-primary bg-primary" : "border-2 border-zinc-500 dark:border-slate-400 bg-transparent group-hover:border-primary"
|
|
2283
|
+
].join(" "),
|
|
2284
|
+
checked: selected,
|
|
2285
|
+
onChange: (e) => onToggle(id, e.target.checked),
|
|
2286
|
+
"aria-label": "Select item"
|
|
2287
|
+
}
|
|
2288
|
+
),
|
|
2289
|
+
selected && /* @__PURE__ */ jsx19(
|
|
2290
|
+
"svg",
|
|
2291
|
+
{
|
|
2292
|
+
className: "absolute inset-0 m-auto w-2.5 h-2.5 text-white pointer-events-none",
|
|
2293
|
+
fill: "none",
|
|
2294
|
+
stroke: "currentColor",
|
|
2295
|
+
viewBox: "0 0 24 24",
|
|
2296
|
+
"aria-hidden": "true",
|
|
2297
|
+
children: /* @__PURE__ */ jsx19(
|
|
2298
|
+
"path",
|
|
2299
|
+
{
|
|
2300
|
+
strokeLinecap: "round",
|
|
2301
|
+
strokeLinejoin: "round",
|
|
2302
|
+
strokeWidth: 3,
|
|
2303
|
+
d: "M5 13l4 4L19 7"
|
|
2304
|
+
}
|
|
2305
|
+
)
|
|
2306
|
+
}
|
|
2307
|
+
)
|
|
2308
|
+
] }) })
|
|
2309
|
+
}
|
|
2310
|
+
),
|
|
2311
|
+
selected && /* @__PURE__ */ jsx19(
|
|
2312
|
+
"div",
|
|
2313
|
+
{
|
|
2314
|
+
className: "absolute inset-0 z-[5] rounded-xl ring-2 ring-primary ring-offset-0 pointer-events-none",
|
|
2315
|
+
"aria-hidden": "true"
|
|
2316
|
+
}
|
|
2317
|
+
),
|
|
2318
|
+
children
|
|
2319
|
+
] });
|
|
2320
|
+
}
|
|
2321
|
+
|
|
2322
|
+
// src/index.ts
|
|
2323
|
+
import {
|
|
2324
|
+
DEFAULT_TABLE_CONFIG,
|
|
2325
|
+
DEFAULT_PAGINATION_CONFIG as DEFAULT_PAGINATION_CONFIG3,
|
|
2326
|
+
DEFAULT_STICKY_CONFIG,
|
|
2327
|
+
mergeTableConfig as mergeTableConfig2
|
|
2328
|
+
} from "@mohasinac/contracts";
|
|
2329
|
+
export {
|
|
2330
|
+
Alert,
|
|
2331
|
+
Article,
|
|
2332
|
+
Aside,
|
|
2333
|
+
Badge,
|
|
2334
|
+
BlockFooter,
|
|
2335
|
+
BlockHeader,
|
|
2336
|
+
Breadcrumb,
|
|
2337
|
+
Button,
|
|
2338
|
+
Caption,
|
|
2339
|
+
Container,
|
|
2340
|
+
DEFAULT_PAGINATION_CONFIG3 as DEFAULT_PAGINATION_CONFIG,
|
|
2341
|
+
DEFAULT_STICKY_CONFIG,
|
|
2342
|
+
DEFAULT_TABLE_CONFIG,
|
|
2343
|
+
DataTable,
|
|
2344
|
+
Divider,
|
|
2345
|
+
Drawer,
|
|
2346
|
+
GRID_MAP,
|
|
2347
|
+
Grid,
|
|
2348
|
+
Heading,
|
|
2349
|
+
ImageLightbox,
|
|
2350
|
+
IndeterminateProgress,
|
|
2351
|
+
Label,
|
|
2352
|
+
Li,
|
|
2353
|
+
Main,
|
|
2354
|
+
Modal,
|
|
2355
|
+
Nav,
|
|
2356
|
+
Ol,
|
|
2357
|
+
Pagination,
|
|
2358
|
+
Progress,
|
|
2359
|
+
Row,
|
|
2360
|
+
Section,
|
|
2361
|
+
Select,
|
|
2362
|
+
Skeleton,
|
|
2363
|
+
Span,
|
|
2364
|
+
Spinner,
|
|
2365
|
+
Stack,
|
|
2366
|
+
StarRating,
|
|
2367
|
+
StatusBadge,
|
|
2368
|
+
Text,
|
|
2369
|
+
Ul,
|
|
2370
|
+
mergeTableConfig2 as mergeTableConfig
|
|
2371
|
+
};
|