@jameskabz/nextcraft-ui 0.3.0 → 0.4.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 +1188 -29
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +220 -1
- package/dist/index.d.ts +220 -1
- package/dist/index.js +1163 -29
- package/dist/index.js.map +1 -1
- package/dist/styles.css +649 -37
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -30,11 +30,36 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
30
30
|
// src/index.ts
|
|
31
31
|
var index_exports = {};
|
|
32
32
|
__export(index_exports, {
|
|
33
|
+
AppShell: () => AppShell,
|
|
34
|
+
AuthLayout: () => AuthLayout,
|
|
35
|
+
Breadcrumbs: () => Breadcrumbs,
|
|
36
|
+
Container: () => Container,
|
|
37
|
+
CraftBadge: () => CraftBadge,
|
|
33
38
|
CraftButton: () => CraftButton,
|
|
39
|
+
CraftCard: () => CraftCard,
|
|
40
|
+
CraftCheckbox: () => CraftCheckbox,
|
|
41
|
+
CraftCurrencyInput: () => CraftCurrencyInput,
|
|
42
|
+
CraftDatePicker: () => CraftDatePicker,
|
|
43
|
+
CraftDrawer: () => CraftDrawer,
|
|
44
|
+
CraftEmptyState: () => CraftEmptyState,
|
|
34
45
|
CraftInput: () => CraftInput,
|
|
46
|
+
CraftModal: () => CraftModal,
|
|
47
|
+
CraftNumberInput: () => CraftNumberInput,
|
|
48
|
+
CraftSelect: () => CraftSelect,
|
|
49
|
+
CraftSkeleton: () => CraftSkeleton,
|
|
50
|
+
CraftSwitch: () => CraftSwitch,
|
|
51
|
+
CraftTabs: () => CraftTabs,
|
|
52
|
+
CraftTextarea: () => CraftTextarea,
|
|
53
|
+
CraftToastHost: () => CraftToastHost,
|
|
54
|
+
CraftTooltip: () => CraftTooltip,
|
|
35
55
|
GlassCard: () => GlassCard,
|
|
56
|
+
Grid: () => Grid,
|
|
57
|
+
PageHeader: () => PageHeader,
|
|
58
|
+
Sidebar: () => Sidebar,
|
|
36
59
|
ThemeProvider: () => ThemeProvider,
|
|
37
60
|
ThemeSwitcher: () => ThemeSwitcher,
|
|
61
|
+
TopNav: () => TopNav,
|
|
62
|
+
useCraftToast: () => useCraftToast,
|
|
38
63
|
useTheme: () => useTheme
|
|
39
64
|
});
|
|
40
65
|
module.exports = __toCommonJS(index_exports);
|
|
@@ -53,7 +78,7 @@ var sizeClasses = {
|
|
|
53
78
|
};
|
|
54
79
|
var variantClasses = {
|
|
55
80
|
solid: "bg-gradient-to-br from-[rgb(var(--nc-accent-1))] via-[rgb(var(--nc-accent-2))] to-[rgb(var(--nc-accent-3))] text-white shadow-[0_12px_30px_rgb(var(--nc-accent-1)/0.45)] hover:shadow-[0_16px_36px_rgb(var(--nc-accent-1)/0.6)] hover:scale-[1.02] active:scale-[0.98]",
|
|
56
|
-
ghost: "bg-
|
|
81
|
+
ghost: "bg-[color:rgb(var(--nc-surface)/0.12)] text-[rgb(var(--nc-fg))] hover:bg-[color:rgb(var(--nc-surface)/0.18)] backdrop-blur-sm border border-[rgb(var(--nc-border)/0.35)] hover:border-[color:rgb(var(--nc-border)/0.5)]",
|
|
57
82
|
outline: "bg-transparent text-[color:rgb(var(--nc-accent-1))] border-2 border-[color:rgb(var(--nc-accent-1)/0.5)] hover:border-[color:rgb(var(--nc-accent-1))] hover:bg-[color:rgb(var(--nc-accent-1)/0.1)]",
|
|
58
83
|
gradient: "bg-gradient-to-r from-[rgb(var(--nc-accent-1))] via-[rgb(var(--nc-accent-2))] to-[rgb(var(--nc-accent-3))] text-white shadow-[0_12px_30px_rgb(var(--nc-accent-2)/0.45)] hover:shadow-[0_16px_36px_rgb(var(--nc-accent-2)/0.6)] hover:scale-[1.02] active:scale-[0.98]"
|
|
59
84
|
};
|
|
@@ -102,7 +127,7 @@ function GlassCard({
|
|
|
102
127
|
"div",
|
|
103
128
|
{
|
|
104
129
|
className: cn(
|
|
105
|
-
"relative overflow-hidden rounded-3xl p-6 text-
|
|
130
|
+
"relative overflow-hidden rounded-3xl p-6 text-[rgb(var(--nc-fg))]",
|
|
106
131
|
"shadow-[0_8px_32px_rgba(0,0,0,0.3)]",
|
|
107
132
|
"transition-all duration-300",
|
|
108
133
|
"hover:shadow-[0_8px_40px_rgba(0,0,0,0.4)]",
|
|
@@ -131,21 +156,21 @@ var inputSizeClasses = {
|
|
|
131
156
|
var CraftInput = React.forwardRef(
|
|
132
157
|
({ className, tone, inputSize = "md", glow = true, icon, ...props }, ref) => {
|
|
133
158
|
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "relative w-full", "data-nc-theme": tone, children: [
|
|
134
|
-
icon && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "absolute left-4 top-1/2 -translate-y-1/2 text-
|
|
159
|
+
icon && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "absolute left-4 top-1/2 -translate-y-1/2 text-[rgb(var(--nc-fg-soft))]", children: icon }),
|
|
135
160
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
136
161
|
"input",
|
|
137
162
|
{
|
|
138
163
|
ref,
|
|
139
164
|
className: cn(
|
|
140
|
-
"w-full rounded-2xl border-2 bg-
|
|
165
|
+
"w-full rounded-2xl border-2 bg-[rgb(var(--nc-surface)/0.08)] text-[rgb(var(--nc-fg))] backdrop-blur-xl",
|
|
141
166
|
"shadow-[inset_0_2px_8px_rgba(0,0,0,0.3)]",
|
|
142
167
|
"focus:outline-none focus:ring-4",
|
|
143
168
|
"transition-all duration-300",
|
|
144
169
|
"disabled:opacity-50 disabled:cursor-not-allowed",
|
|
145
170
|
inputSizeClasses[inputSize],
|
|
146
|
-
"border-[rgb(var(--nc-
|
|
171
|
+
"border-[rgb(var(--nc-border)/0.35)]",
|
|
147
172
|
"focus:border-[rgb(var(--nc-accent-1)/0.8)] focus:ring-[rgb(var(--nc-accent-1)/0.3)]",
|
|
148
|
-
"placeholder:text-[rgb(var(--nc-
|
|
173
|
+
"placeholder:text-[rgb(var(--nc-fg-soft))]",
|
|
149
174
|
glow ? "focus:shadow-[0_0_30px_-5px_var(--glow-color)]" : "",
|
|
150
175
|
icon ? "pl-12" : "",
|
|
151
176
|
className
|
|
@@ -161,9 +186,1118 @@ var CraftInput = React.forwardRef(
|
|
|
161
186
|
);
|
|
162
187
|
CraftInput.displayName = "CraftInput";
|
|
163
188
|
|
|
164
|
-
// src/
|
|
189
|
+
// src/components/craft-textarea.tsx
|
|
165
190
|
var React2 = __toESM(require("react"), 1);
|
|
166
191
|
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
192
|
+
var CraftTextarea = React2.forwardRef(
|
|
193
|
+
({ className, tone, rows = 4, ...props }, ref) => {
|
|
194
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "relative w-full", "data-nc-theme": tone, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
195
|
+
"textarea",
|
|
196
|
+
{
|
|
197
|
+
ref,
|
|
198
|
+
rows,
|
|
199
|
+
className: cn(
|
|
200
|
+
"w-full rounded-2xl border-2 bg-[rgb(var(--nc-surface)/0.08)] text-[rgb(var(--nc-fg))] backdrop-blur-xl",
|
|
201
|
+
"shadow-[inset_0_2px_8px_rgba(0,0,0,0.3)]",
|
|
202
|
+
"focus:outline-none focus:ring-4",
|
|
203
|
+
"transition-all duration-300",
|
|
204
|
+
"disabled:opacity-50 disabled:cursor-not-allowed",
|
|
205
|
+
"border-[rgb(var(--nc-border)/0.35)]",
|
|
206
|
+
"focus:border-[rgb(var(--nc-accent-1)/0.8)] focus:ring-[rgb(var(--nc-accent-1)/0.3)]",
|
|
207
|
+
"placeholder:text-[rgb(var(--nc-fg-soft))]",
|
|
208
|
+
"px-5 py-3 text-base",
|
|
209
|
+
className
|
|
210
|
+
),
|
|
211
|
+
style: {
|
|
212
|
+
"--glow-color": "rgb(var(--nc-accent-1) / 0.5)"
|
|
213
|
+
},
|
|
214
|
+
...props
|
|
215
|
+
}
|
|
216
|
+
) });
|
|
217
|
+
}
|
|
218
|
+
);
|
|
219
|
+
CraftTextarea.displayName = "CraftTextarea";
|
|
220
|
+
|
|
221
|
+
// src/components/craft-select.tsx
|
|
222
|
+
var React3 = __toESM(require("react"), 1);
|
|
223
|
+
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
224
|
+
var CraftSelect = React3.forwardRef(
|
|
225
|
+
({ className, tone, children, ...props }, ref) => {
|
|
226
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "relative w-full", "data-nc-theme": tone, children: [
|
|
227
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
228
|
+
"select",
|
|
229
|
+
{
|
|
230
|
+
ref,
|
|
231
|
+
className: cn(
|
|
232
|
+
"w-full appearance-none rounded-2xl border-2 bg-[rgb(var(--nc-surface)/0.08)] text-[rgb(var(--nc-fg))] backdrop-blur-xl",
|
|
233
|
+
"shadow-[inset_0_2px_8px_rgba(0,0,0,0.3)]",
|
|
234
|
+
"focus:outline-none focus:ring-4",
|
|
235
|
+
"transition-all duration-300",
|
|
236
|
+
"disabled:opacity-50 disabled:cursor-not-allowed",
|
|
237
|
+
"border-[rgb(var(--nc-border)/0.35)]",
|
|
238
|
+
"focus:border-[rgb(var(--nc-accent-1)/0.8)] focus:ring-[rgb(var(--nc-accent-1)/0.3)]",
|
|
239
|
+
"px-5 py-3 pr-10 text-base",
|
|
240
|
+
className
|
|
241
|
+
),
|
|
242
|
+
...props,
|
|
243
|
+
children
|
|
244
|
+
}
|
|
245
|
+
),
|
|
246
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
247
|
+
"svg",
|
|
248
|
+
{
|
|
249
|
+
className: "pointer-events-none absolute right-4 top-1/2 h-4 w-4 -translate-y-1/2 text-[rgb(var(--nc-fg-soft))]",
|
|
250
|
+
viewBox: "0 0 20 20",
|
|
251
|
+
fill: "currentColor",
|
|
252
|
+
"aria-hidden": "true",
|
|
253
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
254
|
+
"path",
|
|
255
|
+
{
|
|
256
|
+
fillRule: "evenodd",
|
|
257
|
+
d: "M5.23 7.21a.75.75 0 011.06.02L10 10.94l3.71-3.7a.75.75 0 111.06 1.06l-4.24 4.24a.75.75 0 01-1.06 0L5.21 8.29a.75.75 0 01.02-1.08z",
|
|
258
|
+
clipRule: "evenodd"
|
|
259
|
+
}
|
|
260
|
+
)
|
|
261
|
+
}
|
|
262
|
+
)
|
|
263
|
+
] });
|
|
264
|
+
}
|
|
265
|
+
);
|
|
266
|
+
CraftSelect.displayName = "CraftSelect";
|
|
267
|
+
|
|
268
|
+
// src/components/craft-checkbox.tsx
|
|
269
|
+
var React4 = __toESM(require("react"), 1);
|
|
270
|
+
var import_jsx_runtime6 = require("react/jsx-runtime");
|
|
271
|
+
var CraftCheckbox = React4.forwardRef(
|
|
272
|
+
({ className, tone, label, description, ...props }, ref) => {
|
|
273
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
|
|
274
|
+
"label",
|
|
275
|
+
{
|
|
276
|
+
className: cn(
|
|
277
|
+
"flex items-start gap-3 text-sm text-[rgb(var(--nc-fg))]",
|
|
278
|
+
props.disabled ? "opacity-60" : "cursor-pointer",
|
|
279
|
+
className
|
|
280
|
+
),
|
|
281
|
+
"data-nc-theme": tone,
|
|
282
|
+
children: [
|
|
283
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: "relative mt-0.5", children: [
|
|
284
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
285
|
+
"input",
|
|
286
|
+
{
|
|
287
|
+
ref,
|
|
288
|
+
type: "checkbox",
|
|
289
|
+
className: "peer sr-only",
|
|
290
|
+
...props
|
|
291
|
+
}
|
|
292
|
+
),
|
|
293
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
294
|
+
"span",
|
|
295
|
+
{
|
|
296
|
+
className: cn(
|
|
297
|
+
"flex h-5 w-5 items-center justify-center rounded-md border-2",
|
|
298
|
+
"border-[rgb(var(--nc-border)/0.45)] bg-[rgb(var(--nc-surface)/0.08)]",
|
|
299
|
+
"transition-all duration-200",
|
|
300
|
+
"peer-checked:border-[rgb(var(--nc-accent-1))] peer-checked:bg-[rgb(var(--nc-accent-1)/0.25)]",
|
|
301
|
+
"peer-focus-visible:ring-2 peer-focus-visible:ring-[rgb(var(--nc-accent-1)/0.5)]"
|
|
302
|
+
),
|
|
303
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
304
|
+
"svg",
|
|
305
|
+
{
|
|
306
|
+
className: "h-3 w-3 text-[rgb(var(--nc-fg))] opacity-0 transition-opacity peer-checked:opacity-100",
|
|
307
|
+
viewBox: "0 0 20 20",
|
|
308
|
+
fill: "currentColor",
|
|
309
|
+
"aria-hidden": "true",
|
|
310
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
311
|
+
"path",
|
|
312
|
+
{
|
|
313
|
+
fillRule: "evenodd",
|
|
314
|
+
d: "M16.704 5.29a1 1 0 010 1.415l-7.2 7.2a1 1 0 01-1.415 0l-3.2-3.2a1 1 0 111.415-1.415l2.492 2.493 6.493-6.493a1 1 0 011.415 0z",
|
|
315
|
+
clipRule: "evenodd"
|
|
316
|
+
}
|
|
317
|
+
)
|
|
318
|
+
}
|
|
319
|
+
)
|
|
320
|
+
}
|
|
321
|
+
)
|
|
322
|
+
] }),
|
|
323
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: "space-y-1", children: [
|
|
324
|
+
label && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "block font-medium text-[rgb(var(--nc-fg))]", children: label }),
|
|
325
|
+
description && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "block text-xs text-[rgb(var(--nc-fg-muted))]", children: description })
|
|
326
|
+
] })
|
|
327
|
+
]
|
|
328
|
+
}
|
|
329
|
+
);
|
|
330
|
+
}
|
|
331
|
+
);
|
|
332
|
+
CraftCheckbox.displayName = "CraftCheckbox";
|
|
333
|
+
|
|
334
|
+
// src/components/craft-switch.tsx
|
|
335
|
+
var React5 = __toESM(require("react"), 1);
|
|
336
|
+
var import_jsx_runtime7 = require("react/jsx-runtime");
|
|
337
|
+
var CraftSwitch = React5.forwardRef(
|
|
338
|
+
({ className, tone, label, ...props }, ref) => {
|
|
339
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
|
|
340
|
+
"label",
|
|
341
|
+
{
|
|
342
|
+
className: cn(
|
|
343
|
+
"inline-flex items-center gap-3 text-sm text-[rgb(var(--nc-fg))]",
|
|
344
|
+
props.disabled ? "opacity-60" : "cursor-pointer",
|
|
345
|
+
className
|
|
346
|
+
),
|
|
347
|
+
"data-nc-theme": tone,
|
|
348
|
+
children: [
|
|
349
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("input", { ref, type: "checkbox", className: "peer sr-only", ...props }),
|
|
350
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
351
|
+
"span",
|
|
352
|
+
{
|
|
353
|
+
className: cn(
|
|
354
|
+
"relative h-6 w-11 rounded-full border-2 border-[rgb(var(--nc-border)/0.35)] bg-[rgb(var(--nc-surface)/0.08)]",
|
|
355
|
+
"transition-all duration-200",
|
|
356
|
+
"peer-focus-visible:ring-2 peer-focus-visible:ring-[rgb(var(--nc-accent-1)/0.5)]",
|
|
357
|
+
"peer-checked:border-[rgb(var(--nc-accent-1)/0.6)] peer-checked:bg-[rgb(var(--nc-accent-1)/0.25)]"
|
|
358
|
+
),
|
|
359
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
360
|
+
"span",
|
|
361
|
+
{
|
|
362
|
+
className: cn(
|
|
363
|
+
"absolute left-0.5 top-0.5 h-4 w-4 rounded-full bg-[rgb(var(--nc-surface-muted)/0.9)]",
|
|
364
|
+
"transition-all duration-200",
|
|
365
|
+
"peer-checked:translate-x-5 peer-checked:bg-[rgb(var(--nc-surface-muted))]"
|
|
366
|
+
)
|
|
367
|
+
}
|
|
368
|
+
)
|
|
369
|
+
}
|
|
370
|
+
),
|
|
371
|
+
label && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { children: label })
|
|
372
|
+
]
|
|
373
|
+
}
|
|
374
|
+
);
|
|
375
|
+
}
|
|
376
|
+
);
|
|
377
|
+
CraftSwitch.displayName = "CraftSwitch";
|
|
378
|
+
|
|
379
|
+
// src/components/craft-badge.tsx
|
|
380
|
+
var import_jsx_runtime8 = require("react/jsx-runtime");
|
|
381
|
+
var variantClasses2 = {
|
|
382
|
+
solid: "bg-[color:rgb(var(--nc-accent-1))] text-white shadow-[0_10px_20px_rgb(var(--nc-accent-1)/0.35)]",
|
|
383
|
+
soft: "bg-[color:rgb(var(--nc-accent-1)/0.2)] text-[rgb(var(--nc-fg))]",
|
|
384
|
+
outline: "border border-[color:rgb(var(--nc-accent-1)/0.6)] text-[rgb(var(--nc-fg))]"
|
|
385
|
+
};
|
|
386
|
+
function CraftBadge({
|
|
387
|
+
className,
|
|
388
|
+
variant = "soft",
|
|
389
|
+
tone,
|
|
390
|
+
...props
|
|
391
|
+
}) {
|
|
392
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
393
|
+
"span",
|
|
394
|
+
{
|
|
395
|
+
className: cn(
|
|
396
|
+
"inline-flex items-center rounded-full px-3 py-1 text-xs font-semibold uppercase tracking-wide",
|
|
397
|
+
variantClasses2[variant],
|
|
398
|
+
className
|
|
399
|
+
),
|
|
400
|
+
"data-nc-theme": tone,
|
|
401
|
+
...props
|
|
402
|
+
}
|
|
403
|
+
);
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
// src/components/craft-card.tsx
|
|
407
|
+
var import_jsx_runtime9 = require("react/jsx-runtime");
|
|
408
|
+
function CraftCard({ className, tone, elevated = true, ...props }) {
|
|
409
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
410
|
+
"div",
|
|
411
|
+
{
|
|
412
|
+
className: cn(
|
|
413
|
+
"rounded-3xl border border-[rgb(var(--nc-border)/0.3)] bg-[rgb(var(--nc-surface)/0.08)] p-6 text-[rgb(var(--nc-fg))] backdrop-blur-xl",
|
|
414
|
+
elevated && "shadow-[0_18px_40px_rgba(0,0,0,0.35)]",
|
|
415
|
+
"transition-all duration-300",
|
|
416
|
+
className
|
|
417
|
+
),
|
|
418
|
+
"data-nc-theme": tone,
|
|
419
|
+
...props
|
|
420
|
+
}
|
|
421
|
+
);
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
// src/components/craft-modal.tsx
|
|
425
|
+
var React6 = __toESM(require("react"), 1);
|
|
426
|
+
var import_react_dom = require("react-dom");
|
|
427
|
+
var import_jsx_runtime10 = require("react/jsx-runtime");
|
|
428
|
+
var FOCUSABLE_SELECTORS = [
|
|
429
|
+
"a[href]",
|
|
430
|
+
"button:not([disabled])",
|
|
431
|
+
"textarea:not([disabled])",
|
|
432
|
+
"input:not([disabled])",
|
|
433
|
+
"select:not([disabled])",
|
|
434
|
+
"[tabindex]:not([tabindex='-1'])"
|
|
435
|
+
].join(",");
|
|
436
|
+
function useFocusTrap(active) {
|
|
437
|
+
const ref = React6.useRef(null);
|
|
438
|
+
React6.useEffect(() => {
|
|
439
|
+
if (!active || !ref.current) return;
|
|
440
|
+
const root = ref.current;
|
|
441
|
+
const getFocusable = () => Array.from(root.querySelectorAll(FOCUSABLE_SELECTORS));
|
|
442
|
+
const focusables = getFocusable();
|
|
443
|
+
if (focusables.length) {
|
|
444
|
+
focusables[0].focus();
|
|
445
|
+
} else {
|
|
446
|
+
root.focus();
|
|
447
|
+
}
|
|
448
|
+
const handleKeyDown = (event) => {
|
|
449
|
+
if (event.key !== "Tab") return;
|
|
450
|
+
const items = getFocusable();
|
|
451
|
+
if (!items.length) return;
|
|
452
|
+
const first = items[0];
|
|
453
|
+
const last = items[items.length - 1];
|
|
454
|
+
const activeEl = document.activeElement;
|
|
455
|
+
if (event.shiftKey && activeEl === first) {
|
|
456
|
+
event.preventDefault();
|
|
457
|
+
last.focus();
|
|
458
|
+
} else if (!event.shiftKey && activeEl === last) {
|
|
459
|
+
event.preventDefault();
|
|
460
|
+
first.focus();
|
|
461
|
+
}
|
|
462
|
+
};
|
|
463
|
+
root.addEventListener("keydown", handleKeyDown);
|
|
464
|
+
return () => root.removeEventListener("keydown", handleKeyDown);
|
|
465
|
+
}, [active]);
|
|
466
|
+
return ref;
|
|
467
|
+
}
|
|
468
|
+
function CraftModal({
|
|
469
|
+
open,
|
|
470
|
+
defaultOpen = false,
|
|
471
|
+
onOpenChange,
|
|
472
|
+
tone,
|
|
473
|
+
title,
|
|
474
|
+
description,
|
|
475
|
+
children,
|
|
476
|
+
trigger,
|
|
477
|
+
footer,
|
|
478
|
+
className
|
|
479
|
+
}) {
|
|
480
|
+
const [uncontrolledOpen, setUncontrolledOpen] = React6.useState(defaultOpen);
|
|
481
|
+
const isControlled = typeof open === "boolean";
|
|
482
|
+
const isOpen = isControlled ? open : uncontrolledOpen;
|
|
483
|
+
const setOpen = React6.useCallback(
|
|
484
|
+
(next) => {
|
|
485
|
+
if (!isControlled) {
|
|
486
|
+
setUncontrolledOpen(next);
|
|
487
|
+
}
|
|
488
|
+
onOpenChange == null ? void 0 : onOpenChange(next);
|
|
489
|
+
},
|
|
490
|
+
[isControlled, onOpenChange]
|
|
491
|
+
);
|
|
492
|
+
React6.useEffect(() => {
|
|
493
|
+
if (!isOpen) return;
|
|
494
|
+
const handleKey = (event) => {
|
|
495
|
+
if (event.key === "Escape") setOpen(false);
|
|
496
|
+
};
|
|
497
|
+
document.addEventListener("keydown", handleKey);
|
|
498
|
+
return () => document.removeEventListener("keydown", handleKey);
|
|
499
|
+
}, [isOpen, setOpen]);
|
|
500
|
+
const ref = useFocusTrap(isOpen);
|
|
501
|
+
const content = isOpen ? /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "fixed inset-0 z-50 flex items-center justify-center px-4 py-8", children: [
|
|
502
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
503
|
+
"div",
|
|
504
|
+
{
|
|
505
|
+
className: "absolute inset-0 backdrop-blur-sm",
|
|
506
|
+
onClick: () => setOpen(false)
|
|
507
|
+
}
|
|
508
|
+
),
|
|
509
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
|
|
510
|
+
"div",
|
|
511
|
+
{
|
|
512
|
+
ref,
|
|
513
|
+
tabIndex: -1,
|
|
514
|
+
className: cn(
|
|
515
|
+
"relative z-10 w-full max-w-lg rounded-3xl border border-[rgb(var(--nc-border)/0.3)] bg-[rgb(var(--nc-surface)/0.12)] p-6 text-[rgb(var(--nc-fg))] shadow-[0_20px_60px_rgba(0,0,0,0.45)] backdrop-blur-2xl",
|
|
516
|
+
className
|
|
517
|
+
),
|
|
518
|
+
"data-nc-theme": tone,
|
|
519
|
+
children: [
|
|
520
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex items-start justify-between gap-4", children: [
|
|
521
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "space-y-1", children: [
|
|
522
|
+
title && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("h3", { className: "text-2xl font-semibold", children: title }),
|
|
523
|
+
description && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("p", { className: "text-[rgb(var(--nc-fg-muted))]", children: description })
|
|
524
|
+
] }),
|
|
525
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
526
|
+
"button",
|
|
527
|
+
{
|
|
528
|
+
className: "rounded-full border border-[rgb(var(--nc-border)/0.3)] bg-[rgb(var(--nc-surface)/0.12)] p-2 text-[rgb(var(--nc-fg-soft))] transition hover:text-[rgb(var(--nc-fg))]",
|
|
529
|
+
onClick: () => setOpen(false),
|
|
530
|
+
"aria-label": "Close",
|
|
531
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("svg", { viewBox: "0 0 20 20", className: "h-4 w-4", fill: "currentColor", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("path", { d: "M6.28 5.22a.75.75 0 00-1.06 1.06L8.94 10l-3.72 3.72a.75.75 0 101.06 1.06L10 11.06l3.72 3.72a.75.75 0 101.06-1.06L11.06 10l3.72-3.72a.75.75 0 00-1.06-1.06L10 8.94 6.28 5.22z" }) })
|
|
532
|
+
}
|
|
533
|
+
)
|
|
534
|
+
] }),
|
|
535
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "mt-5 space-y-4", children }),
|
|
536
|
+
footer && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "mt-6", children: footer })
|
|
537
|
+
]
|
|
538
|
+
}
|
|
539
|
+
)
|
|
540
|
+
] }) : null;
|
|
541
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_jsx_runtime10.Fragment, { children: [
|
|
542
|
+
trigger && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
543
|
+
"span",
|
|
544
|
+
{
|
|
545
|
+
onClick: () => setOpen(true),
|
|
546
|
+
onKeyDown: (event) => {
|
|
547
|
+
if (event.key === "Enter" || event.key === " ") setOpen(true);
|
|
548
|
+
},
|
|
549
|
+
role: "button",
|
|
550
|
+
tabIndex: 0,
|
|
551
|
+
className: "inline-flex",
|
|
552
|
+
children: trigger
|
|
553
|
+
}
|
|
554
|
+
),
|
|
555
|
+
typeof document !== "undefined" && content ? (0, import_react_dom.createPortal)(content, document.body) : content
|
|
556
|
+
] });
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
// src/components/craft-drawer.tsx
|
|
560
|
+
var React7 = __toESM(require("react"), 1);
|
|
561
|
+
var import_react_dom2 = require("react-dom");
|
|
562
|
+
var import_jsx_runtime11 = require("react/jsx-runtime");
|
|
563
|
+
function CraftDrawer({
|
|
564
|
+
open,
|
|
565
|
+
defaultOpen = false,
|
|
566
|
+
onOpenChange,
|
|
567
|
+
tone,
|
|
568
|
+
side = "left",
|
|
569
|
+
title,
|
|
570
|
+
children,
|
|
571
|
+
trigger,
|
|
572
|
+
footer,
|
|
573
|
+
className
|
|
574
|
+
}) {
|
|
575
|
+
const [uncontrolledOpen, setUncontrolledOpen] = React7.useState(defaultOpen);
|
|
576
|
+
const isControlled = typeof open === "boolean";
|
|
577
|
+
const isOpen = isControlled ? open : uncontrolledOpen;
|
|
578
|
+
const setOpen = React7.useCallback(
|
|
579
|
+
(next) => {
|
|
580
|
+
if (!isControlled) setUncontrolledOpen(next);
|
|
581
|
+
onOpenChange == null ? void 0 : onOpenChange(next);
|
|
582
|
+
},
|
|
583
|
+
[isControlled, onOpenChange]
|
|
584
|
+
);
|
|
585
|
+
React7.useEffect(() => {
|
|
586
|
+
if (!isOpen) return;
|
|
587
|
+
const handleKey = (event) => {
|
|
588
|
+
if (event.key === "Escape") setOpen(false);
|
|
589
|
+
};
|
|
590
|
+
document.addEventListener("keydown", handleKey);
|
|
591
|
+
return () => document.removeEventListener("keydown", handleKey);
|
|
592
|
+
}, [isOpen, setOpen]);
|
|
593
|
+
const content = isOpen ? /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "fixed inset-0 z-50 overflow-hidden", children: [
|
|
594
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
595
|
+
"div",
|
|
596
|
+
{
|
|
597
|
+
className: "absolute inset-0 backdrop-blur-sm",
|
|
598
|
+
onClick: () => setOpen(false)
|
|
599
|
+
}
|
|
600
|
+
),
|
|
601
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
|
|
602
|
+
"div",
|
|
603
|
+
{
|
|
604
|
+
className: cn(
|
|
605
|
+
"absolute top-0 h-full w-full max-w-md border border-[rgb(var(--nc-border)/0.3)] bg-[rgb(var(--nc-surface)/0.12)] text-[rgb(var(--nc-fg))] shadow-[0_20px_60px_rgba(0,0,0,0.45)] backdrop-blur-2xl",
|
|
606
|
+
side === "right" ? "right-0" : "left-0",
|
|
607
|
+
className
|
|
608
|
+
),
|
|
609
|
+
"data-nc-theme": tone,
|
|
610
|
+
children: [
|
|
611
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex items-center justify-between border-b border-[rgb(var(--nc-border)/0.3)] p-6", children: [
|
|
612
|
+
title && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("h3", { className: "text-xl font-semibold", children: title }),
|
|
613
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
614
|
+
"button",
|
|
615
|
+
{
|
|
616
|
+
className: "rounded-full border border-[rgb(var(--nc-border)/0.3)] bg-[rgb(var(--nc-surface)/0.12)] p-2 text-[rgb(var(--nc-fg-soft))] transition hover:text-[rgb(var(--nc-fg))]",
|
|
617
|
+
onClick: () => setOpen(false),
|
|
618
|
+
"aria-label": "Close",
|
|
619
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("svg", { viewBox: "0 0 20 20", className: "h-4 w-4", fill: "currentColor", children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("path", { d: "M6.28 5.22a.75.75 0 00-1.06 1.06L8.94 10l-3.72 3.72a.75.75 0 101.06 1.06L10 11.06l3.72 3.72a.75.75 0 101.06-1.06L11.06 10l3.72-3.72a.75.75 0 00-1.06-1.06L10 8.94 6.28 5.22z" }) })
|
|
620
|
+
}
|
|
621
|
+
)
|
|
622
|
+
] }),
|
|
623
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "p-6 space-y-4 overflow-y-auto h-[calc(100%-5.5rem)]", children }),
|
|
624
|
+
footer && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "border-t border-[rgb(var(--nc-border)/0.3)] p-6", children: footer })
|
|
625
|
+
]
|
|
626
|
+
}
|
|
627
|
+
)
|
|
628
|
+
] }) : null;
|
|
629
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_jsx_runtime11.Fragment, { children: [
|
|
630
|
+
trigger && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
631
|
+
"span",
|
|
632
|
+
{
|
|
633
|
+
onClick: () => setOpen(true),
|
|
634
|
+
onKeyDown: (event) => {
|
|
635
|
+
if (event.key === "Enter" || event.key === " ") setOpen(true);
|
|
636
|
+
},
|
|
637
|
+
role: "button",
|
|
638
|
+
tabIndex: 0,
|
|
639
|
+
className: "inline-flex",
|
|
640
|
+
children: trigger
|
|
641
|
+
}
|
|
642
|
+
),
|
|
643
|
+
typeof document !== "undefined" && content ? (0, import_react_dom2.createPortal)(content, document.body) : content
|
|
644
|
+
] });
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
// src/components/craft-tabs.tsx
|
|
648
|
+
var React8 = __toESM(require("react"), 1);
|
|
649
|
+
var import_jsx_runtime12 = require("react/jsx-runtime");
|
|
650
|
+
function CraftTabs({
|
|
651
|
+
value,
|
|
652
|
+
defaultValue,
|
|
653
|
+
onValueChange,
|
|
654
|
+
tone,
|
|
655
|
+
tabs,
|
|
656
|
+
panels,
|
|
657
|
+
className
|
|
658
|
+
}) {
|
|
659
|
+
var _a, _b;
|
|
660
|
+
const fallback = (_b = (_a = tabs[0]) == null ? void 0 : _a.value) != null ? _b : "";
|
|
661
|
+
const [uncontrolledValue, setUncontrolledValue] = React8.useState(
|
|
662
|
+
defaultValue != null ? defaultValue : fallback
|
|
663
|
+
);
|
|
664
|
+
const isControlled = value !== void 0;
|
|
665
|
+
const activeValue = isControlled ? value : uncontrolledValue;
|
|
666
|
+
const setValue = React8.useCallback(
|
|
667
|
+
(next) => {
|
|
668
|
+
if (!isControlled) setUncontrolledValue(next);
|
|
669
|
+
onValueChange == null ? void 0 : onValueChange(next);
|
|
670
|
+
},
|
|
671
|
+
[isControlled, onValueChange]
|
|
672
|
+
);
|
|
673
|
+
const onKeyDown = (event) => {
|
|
674
|
+
if (!tabs.length) return;
|
|
675
|
+
const currentIndex = tabs.findIndex((tab) => tab.value === activeValue);
|
|
676
|
+
if (event.key === "ArrowRight") {
|
|
677
|
+
event.preventDefault();
|
|
678
|
+
const next = tabs[(currentIndex + 1) % tabs.length];
|
|
679
|
+
setValue(next.value);
|
|
680
|
+
}
|
|
681
|
+
if (event.key === "ArrowLeft") {
|
|
682
|
+
event.preventDefault();
|
|
683
|
+
const next = tabs[(currentIndex - 1 + tabs.length) % tabs.length];
|
|
684
|
+
setValue(next.value);
|
|
685
|
+
}
|
|
686
|
+
};
|
|
687
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: cn("space-y-4", className), "data-nc-theme": tone, children: [
|
|
688
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
689
|
+
"div",
|
|
690
|
+
{
|
|
691
|
+
className: "inline-flex flex-wrap items-center gap-2 rounded-full border border-[rgb(var(--nc-border)/0.3)] bg-[rgb(var(--nc-surface)/0.08)] p-2",
|
|
692
|
+
role: "tablist",
|
|
693
|
+
onKeyDown,
|
|
694
|
+
children: tabs.map((tab) => /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
695
|
+
"button",
|
|
696
|
+
{
|
|
697
|
+
role: "tab",
|
|
698
|
+
"aria-selected": activeValue === tab.value,
|
|
699
|
+
onClick: () => setValue(tab.value),
|
|
700
|
+
className: cn(
|
|
701
|
+
"rounded-full px-4 py-2 text-sm font-semibold transition-all",
|
|
702
|
+
activeValue === tab.value ? "bg-[rgb(var(--nc-accent-1)/0.65)] text-white shadow-[0_7px_5px_rgb(var(--nc-accent-1)/0.35)]" : "text-[rgb(var(--nc-fg-muted))] hover:text-[rgb(var(--nc-fg))]"
|
|
703
|
+
),
|
|
704
|
+
children: tab.label
|
|
705
|
+
},
|
|
706
|
+
tab.value
|
|
707
|
+
))
|
|
708
|
+
}
|
|
709
|
+
),
|
|
710
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "rounded-2xl border border-[rgb(var(--nc-border)/0.3)] bg-[rgb(var(--nc-surface)/0.08)] p-4 text-[rgb(var(--nc-fg))]", children: panels[activeValue] })
|
|
711
|
+
] });
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
// src/components/craft-tooltip.tsx
|
|
715
|
+
var React9 = __toESM(require("react"), 1);
|
|
716
|
+
var import_jsx_runtime13 = require("react/jsx-runtime");
|
|
717
|
+
function CraftTooltip({ content, tone, children, side = "top" }) {
|
|
718
|
+
const [open, setOpen] = React9.useState(false);
|
|
719
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
|
|
720
|
+
"span",
|
|
721
|
+
{
|
|
722
|
+
className: "relative inline-flex",
|
|
723
|
+
onMouseEnter: () => setOpen(true),
|
|
724
|
+
onMouseLeave: () => setOpen(false),
|
|
725
|
+
onFocus: () => setOpen(true),
|
|
726
|
+
onBlur: () => setOpen(false),
|
|
727
|
+
children: [
|
|
728
|
+
children,
|
|
729
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
730
|
+
"span",
|
|
731
|
+
{
|
|
732
|
+
className: cn(
|
|
733
|
+
"pointer-events-none absolute z-20 whitespace-nowrap rounded-lg border border-white/10 bg-black/80 px-3 py-2 text-xs text-white shadow-lg transition-all",
|
|
734
|
+
"backdrop-blur-xl",
|
|
735
|
+
open ? "opacity-100 translate-y-0" : "opacity-0 translate-y-1",
|
|
736
|
+
side === "top" && "bottom-full left-1/2 -translate-x-1/2 -translate-y-2",
|
|
737
|
+
side === "bottom" && "top-full left-1/2 -translate-x-1/2 translate-y-2",
|
|
738
|
+
side === "left" && "right-full top-1/2 -translate-y-1/2 -translate-x-2",
|
|
739
|
+
side === "right" && "left-full top-1/2 -translate-y-1/2 translate-x-2"
|
|
740
|
+
),
|
|
741
|
+
"data-nc-theme": tone,
|
|
742
|
+
role: "tooltip",
|
|
743
|
+
children: content
|
|
744
|
+
}
|
|
745
|
+
)
|
|
746
|
+
]
|
|
747
|
+
}
|
|
748
|
+
);
|
|
749
|
+
}
|
|
750
|
+
|
|
751
|
+
// src/components/craft-toast.tsx
|
|
752
|
+
var React10 = __toESM(require("react"), 1);
|
|
753
|
+
var import_jsx_runtime14 = require("react/jsx-runtime");
|
|
754
|
+
var variantClasses3 = {
|
|
755
|
+
info: "border-[color:rgb(var(--nc-accent-1)/0.4)]",
|
|
756
|
+
success: "border-emerald-400/40",
|
|
757
|
+
warning: "border-amber-400/40",
|
|
758
|
+
error: "border-rose-400/40"
|
|
759
|
+
};
|
|
760
|
+
function useCraftToast() {
|
|
761
|
+
const [toasts, setToasts] = React10.useState([]);
|
|
762
|
+
const push = React10.useCallback((toast) => {
|
|
763
|
+
const id = `${Date.now()}-${Math.random().toString(16).slice(2)}`;
|
|
764
|
+
setToasts((prev) => [...prev, { ...toast, id }]);
|
|
765
|
+
return id;
|
|
766
|
+
}, []);
|
|
767
|
+
const remove = React10.useCallback((id) => {
|
|
768
|
+
setToasts((prev) => prev.filter((toast) => toast.id !== id));
|
|
769
|
+
}, []);
|
|
770
|
+
return { toasts, push, remove };
|
|
771
|
+
}
|
|
772
|
+
function CraftToastHost({ toasts, onDismiss, tone }) {
|
|
773
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
774
|
+
"div",
|
|
775
|
+
{
|
|
776
|
+
className: "fixed right-6 top-6 z-50 flex w-full max-w-sm flex-col gap-3",
|
|
777
|
+
"data-nc-theme": tone,
|
|
778
|
+
children: toasts.map((toast) => {
|
|
779
|
+
var _a;
|
|
780
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
781
|
+
"div",
|
|
782
|
+
{
|
|
783
|
+
className: cn(
|
|
784
|
+
"rounded-2xl border bg-[rgb(var(--nc-surface)/0.12)] p-4 text-[rgb(var(--nc-fg))] shadow-[0_15px_35px_rgba(0,0,0,0.35)] backdrop-blur-xl",
|
|
785
|
+
variantClasses3[(_a = toast.variant) != null ? _a : "info"]
|
|
786
|
+
),
|
|
787
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "flex items-start justify-between gap-4", children: [
|
|
788
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { children: [
|
|
789
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("p", { className: "text-sm font-semibold", children: toast.title }),
|
|
790
|
+
toast.description && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("p", { className: "text-xs text-[rgb(var(--nc-fg-muted))]", children: toast.description })
|
|
791
|
+
] }),
|
|
792
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
793
|
+
"button",
|
|
794
|
+
{
|
|
795
|
+
className: "text-[rgb(var(--nc-fg-soft))] hover:text-[rgb(var(--nc-fg))]",
|
|
796
|
+
onClick: () => onDismiss(toast.id),
|
|
797
|
+
children: "\u2715"
|
|
798
|
+
}
|
|
799
|
+
)
|
|
800
|
+
] })
|
|
801
|
+
},
|
|
802
|
+
toast.id
|
|
803
|
+
);
|
|
804
|
+
})
|
|
805
|
+
}
|
|
806
|
+
);
|
|
807
|
+
}
|
|
808
|
+
|
|
809
|
+
// src/components/craft-skeleton.tsx
|
|
810
|
+
var import_jsx_runtime15 = require("react/jsx-runtime");
|
|
811
|
+
function CraftSkeleton({ className, tone, ...props }) {
|
|
812
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
813
|
+
"div",
|
|
814
|
+
{
|
|
815
|
+
className: cn(
|
|
816
|
+
"relative overflow-hidden rounded-2xl bg-[rgb(var(--nc-surface)/0.12)]",
|
|
817
|
+
"after:absolute after:inset-0 after:-translate-x-full after:bg-linear-to-r after:from-transparent after:via-white/20 after:to-transparent",
|
|
818
|
+
"after:animate-[shimmer_1.6s_infinite]",
|
|
819
|
+
className
|
|
820
|
+
),
|
|
821
|
+
"data-nc-theme": tone,
|
|
822
|
+
...props
|
|
823
|
+
}
|
|
824
|
+
);
|
|
825
|
+
}
|
|
826
|
+
|
|
827
|
+
// src/components/craft-empty-state.tsx
|
|
828
|
+
var import_jsx_runtime16 = require("react/jsx-runtime");
|
|
829
|
+
function CraftEmptyState({
|
|
830
|
+
className,
|
|
831
|
+
tone,
|
|
832
|
+
title,
|
|
833
|
+
description,
|
|
834
|
+
icon,
|
|
835
|
+
action,
|
|
836
|
+
...props
|
|
837
|
+
}) {
|
|
838
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
|
|
839
|
+
"div",
|
|
840
|
+
{
|
|
841
|
+
className: cn(
|
|
842
|
+
"rounded-3xl border border-[rgb(var(--nc-border)/0.3)] bg-[rgb(var(--nc-surface)/0.08)] p-8 text-center text-[rgb(var(--nc-fg))] backdrop-blur-xl",
|
|
843
|
+
"shadow-[0_18px_40px_rgba(0,0,0,0.25)]",
|
|
844
|
+
className
|
|
845
|
+
),
|
|
846
|
+
"data-nc-theme": tone,
|
|
847
|
+
...props,
|
|
848
|
+
children: [
|
|
849
|
+
icon && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { className: "mx-auto mb-4 flex h-12 w-12 items-center justify-center rounded-2xl bg-[rgb(var(--nc-accent-1)/0.2)] text-[rgb(var(--nc-accent-1))]", children: icon }),
|
|
850
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("h3", { className: "text-xl font-semibold", children: title }),
|
|
851
|
+
description && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("p", { className: "mt-2 text-sm text-[rgb(var(--nc-fg-muted))]", children: description }),
|
|
852
|
+
action && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { className: "mt-6 flex justify-center", children: action })
|
|
853
|
+
]
|
|
854
|
+
}
|
|
855
|
+
);
|
|
856
|
+
}
|
|
857
|
+
|
|
858
|
+
// src/components/craft-date-picker.tsx
|
|
859
|
+
var React11 = __toESM(require("react"), 1);
|
|
860
|
+
var import_jsx_runtime17 = require("react/jsx-runtime");
|
|
861
|
+
var WEEK_DAYS = ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"];
|
|
862
|
+
function formatDate(date) {
|
|
863
|
+
const year = date.getFullYear();
|
|
864
|
+
const month = `${date.getMonth() + 1}`.padStart(2, "0");
|
|
865
|
+
const day = `${date.getDate()}`.padStart(2, "0");
|
|
866
|
+
return `${year}-${month}-${day}`;
|
|
867
|
+
}
|
|
868
|
+
function parseDate(value) {
|
|
869
|
+
if (!value) return null;
|
|
870
|
+
const [year, month, day] = value.split("-").map(Number);
|
|
871
|
+
if (!year || !month || !day) return null;
|
|
872
|
+
return new Date(year, month - 1, day);
|
|
873
|
+
}
|
|
874
|
+
function isSameDay(a, b) {
|
|
875
|
+
return a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate();
|
|
876
|
+
}
|
|
877
|
+
function isOutsideRange(date, min, max) {
|
|
878
|
+
const minDate = parseDate(min);
|
|
879
|
+
const maxDate = parseDate(max);
|
|
880
|
+
if (minDate && date < minDate) return true;
|
|
881
|
+
if (maxDate && date > maxDate) return true;
|
|
882
|
+
return false;
|
|
883
|
+
}
|
|
884
|
+
function CraftDatePicker({
|
|
885
|
+
value,
|
|
886
|
+
defaultValue,
|
|
887
|
+
onChange,
|
|
888
|
+
tone,
|
|
889
|
+
min,
|
|
890
|
+
max,
|
|
891
|
+
placeholder = "Select date",
|
|
892
|
+
className
|
|
893
|
+
}) {
|
|
894
|
+
const [open, setOpen] = React11.useState(false);
|
|
895
|
+
const [uncontrolledValue, setUncontrolledValue] = React11.useState(defaultValue != null ? defaultValue : "");
|
|
896
|
+
const isControlled = value !== void 0;
|
|
897
|
+
const selectedValue = isControlled ? value != null ? value : "" : uncontrolledValue;
|
|
898
|
+
const selectedDate = parseDate(selectedValue);
|
|
899
|
+
const initialMonth = selectedDate != null ? selectedDate : /* @__PURE__ */ new Date();
|
|
900
|
+
const [viewDate, setViewDate] = React11.useState(initialMonth);
|
|
901
|
+
React11.useEffect(() => {
|
|
902
|
+
if (selectedDate) setViewDate(selectedDate);
|
|
903
|
+
}, [selectedDate]);
|
|
904
|
+
const wrapperRef = React11.useRef(null);
|
|
905
|
+
React11.useEffect(() => {
|
|
906
|
+
if (!open) return;
|
|
907
|
+
const handleClick = (event) => {
|
|
908
|
+
var _a;
|
|
909
|
+
if (!((_a = wrapperRef.current) == null ? void 0 : _a.contains(event.target))) {
|
|
910
|
+
setOpen(false);
|
|
911
|
+
}
|
|
912
|
+
};
|
|
913
|
+
const handleKey = (event) => {
|
|
914
|
+
if (event.key === "Escape") setOpen(false);
|
|
915
|
+
};
|
|
916
|
+
document.addEventListener("mousedown", handleClick);
|
|
917
|
+
document.addEventListener("keydown", handleKey);
|
|
918
|
+
return () => {
|
|
919
|
+
document.removeEventListener("mousedown", handleClick);
|
|
920
|
+
document.removeEventListener("keydown", handleKey);
|
|
921
|
+
};
|
|
922
|
+
}, [open]);
|
|
923
|
+
const setValue = React11.useCallback(
|
|
924
|
+
(next) => {
|
|
925
|
+
if (!isControlled) setUncontrolledValue(next);
|
|
926
|
+
onChange == null ? void 0 : onChange(next);
|
|
927
|
+
},
|
|
928
|
+
[isControlled, onChange]
|
|
929
|
+
);
|
|
930
|
+
const monthStart = new Date(viewDate.getFullYear(), viewDate.getMonth(), 1);
|
|
931
|
+
const monthEnd = new Date(viewDate.getFullYear(), viewDate.getMonth() + 1, 0);
|
|
932
|
+
const startDay = monthStart.getDay();
|
|
933
|
+
const daysInMonth = monthEnd.getDate();
|
|
934
|
+
const cells = Array.from({ length: startDay + daysInMonth }, (_, i) => {
|
|
935
|
+
const dayNumber = i - startDay + 1;
|
|
936
|
+
if (dayNumber < 1) return null;
|
|
937
|
+
return new Date(viewDate.getFullYear(), viewDate.getMonth(), dayNumber);
|
|
938
|
+
});
|
|
939
|
+
const handleDaySelect = (date) => {
|
|
940
|
+
if (isOutsideRange(date, min, max)) return;
|
|
941
|
+
const next = formatDate(date);
|
|
942
|
+
setValue(next);
|
|
943
|
+
setOpen(false);
|
|
944
|
+
};
|
|
945
|
+
const handleKeyDown = (event) => {
|
|
946
|
+
if (!open) return;
|
|
947
|
+
if (!selectedDate) return;
|
|
948
|
+
const next = new Date(selectedDate);
|
|
949
|
+
if (event.key === "ArrowRight") next.setDate(next.getDate() + 1);
|
|
950
|
+
if (event.key === "ArrowLeft") next.setDate(next.getDate() - 1);
|
|
951
|
+
if (event.key === "ArrowDown") next.setDate(next.getDate() + 7);
|
|
952
|
+
if (event.key === "ArrowUp") next.setDate(next.getDate() - 7);
|
|
953
|
+
if (event.key === "Enter") {
|
|
954
|
+
event.preventDefault();
|
|
955
|
+
handleDaySelect(selectedDate);
|
|
956
|
+
return;
|
|
957
|
+
}
|
|
958
|
+
if (next.getTime() !== selectedDate.getTime()) {
|
|
959
|
+
event.preventDefault();
|
|
960
|
+
if (!isOutsideRange(next, min, max)) {
|
|
961
|
+
setValue(formatDate(next));
|
|
962
|
+
setViewDate(next);
|
|
963
|
+
}
|
|
964
|
+
}
|
|
965
|
+
};
|
|
966
|
+
return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "relative w-full", "data-nc-theme": tone, ref: wrapperRef, children: [
|
|
967
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
|
|
968
|
+
"button",
|
|
969
|
+
{
|
|
970
|
+
type: "button",
|
|
971
|
+
onClick: () => setOpen((prev) => !prev),
|
|
972
|
+
className: cn(
|
|
973
|
+
"flex w-full items-center justify-between rounded-2xl border-2 bg-[rgb(var(--nc-surface)/0.08)] px-5 py-3 text-left text-base text-[rgb(var(--nc-fg))] backdrop-blur-xl",
|
|
974
|
+
"shadow-[inset_0_2px_8px_rgba(0,0,0,0.3)]",
|
|
975
|
+
"transition-all duration-300",
|
|
976
|
+
"border-[rgb(var(--nc-border)/0.35)]",
|
|
977
|
+
"focus:outline-none focus:ring-4 focus:ring-[rgb(var(--nc-accent-1)/0.3)]",
|
|
978
|
+
className
|
|
979
|
+
),
|
|
980
|
+
children: [
|
|
981
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: selectedValue ? "text-[rgb(var(--nc-fg))]" : "text-[rgb(var(--nc-fg-soft))]", children: selectedValue || placeholder }),
|
|
982
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("svg", { className: "h-4 w-4 text-[rgb(var(--nc-fg-soft))]", viewBox: "0 0 20 20", fill: "currentColor", children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("path", { d: "M6 2a1 1 0 011 1v1h6V3a1 1 0 112 0v1h1a2 2 0 012 2v10a2 2 0 01-2 2H4a2 2 0 01-2-2V6a2 2 0 012-2h1V3a1 1 0 011-1zm10 6H4v8h12V8z" }) })
|
|
983
|
+
]
|
|
984
|
+
}
|
|
985
|
+
),
|
|
986
|
+
open && /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
|
|
987
|
+
"div",
|
|
988
|
+
{
|
|
989
|
+
className: cn(
|
|
990
|
+
"absolute left-0 top-full z-20 mt-3 w-full rounded-3xl border border-[rgb(var(--nc-border)/0.3)] bg-[rgb(var(--nc-surface)/1.52)] p-4 text-[rgb(var(--nc-fg))] shadow-[0_20px_60px_rgba(0,0,0,0.55)] backdrop-blur-10xl"
|
|
991
|
+
),
|
|
992
|
+
onKeyDown: handleKeyDown,
|
|
993
|
+
tabIndex: -1,
|
|
994
|
+
children: [
|
|
995
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "flex items-center justify-between", children: [
|
|
996
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
997
|
+
"button",
|
|
998
|
+
{
|
|
999
|
+
type: "button",
|
|
1000
|
+
className: "rounded-xl border border-[rgb(var(--nc-border)/0.3)] bg-[rgb(var(--nc-surface)/0.12)] px-3 py-1 text-sm text-[rgb(var(--nc-fg))]",
|
|
1001
|
+
onClick: () => setViewDate(
|
|
1002
|
+
new Date(viewDate.getFullYear(), viewDate.getMonth() - 1, 1)
|
|
1003
|
+
),
|
|
1004
|
+
children: "Prev"
|
|
1005
|
+
}
|
|
1006
|
+
),
|
|
1007
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: "text-sm font-semibold", children: viewDate.toLocaleString(void 0, { month: "long", year: "numeric" }) }),
|
|
1008
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
1009
|
+
"button",
|
|
1010
|
+
{
|
|
1011
|
+
type: "button",
|
|
1012
|
+
className: "rounded-xl border border-[rgb(var(--nc-border)/0.3)] bg-[rgb(var(--nc-surface)/0.12)] px-3 py-1 text-sm text-[rgb(var(--nc-fg))]",
|
|
1013
|
+
onClick: () => setViewDate(
|
|
1014
|
+
new Date(viewDate.getFullYear(), viewDate.getMonth() + 1, 1)
|
|
1015
|
+
),
|
|
1016
|
+
children: "Next"
|
|
1017
|
+
}
|
|
1018
|
+
)
|
|
1019
|
+
] }),
|
|
1020
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: "mt-4 grid grid-cols-7 gap-2 text-xs text-[rgb(var(--nc-fg-muted))]", children: WEEK_DAYS.map((day) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: "text-center", children: day }, day)) }),
|
|
1021
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: "mt-2 grid grid-cols-7 gap-2", children: cells.map((date, index) => {
|
|
1022
|
+
if (!date) return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", {}, `empty-${index}`);
|
|
1023
|
+
const disabled = isOutsideRange(date, min, max);
|
|
1024
|
+
const selected = selectedDate && isSameDay(date, selectedDate);
|
|
1025
|
+
return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
1026
|
+
"button",
|
|
1027
|
+
{
|
|
1028
|
+
type: "button",
|
|
1029
|
+
onClick: () => handleDaySelect(date),
|
|
1030
|
+
disabled,
|
|
1031
|
+
className: cn(
|
|
1032
|
+
"rounded-lg py-2 text-sm transition-all",
|
|
1033
|
+
selected ? "bg-[rgb(var(--nc-accent-1)/0.3)] text-[rgb(var(--nc-fg))]" : "text-[rgb(var(--nc-fg-muted))] hover:bg-[rgb(var(--nc-surface)/0.12)]",
|
|
1034
|
+
disabled && "opacity-40 hover:bg-transparent"
|
|
1035
|
+
),
|
|
1036
|
+
children: date.getDate()
|
|
1037
|
+
},
|
|
1038
|
+
date.toISOString()
|
|
1039
|
+
);
|
|
1040
|
+
}) })
|
|
1041
|
+
]
|
|
1042
|
+
}
|
|
1043
|
+
)
|
|
1044
|
+
] });
|
|
1045
|
+
}
|
|
1046
|
+
|
|
1047
|
+
// src/components/craft-number-input.tsx
|
|
1048
|
+
var React12 = __toESM(require("react"), 1);
|
|
1049
|
+
var import_jsx_runtime18 = require("react/jsx-runtime");
|
|
1050
|
+
var CraftNumberInput = React12.forwardRef(({ className, tone, ...props }, ref) => {
|
|
1051
|
+
return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: "relative w-full", "data-nc-theme": tone, children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
1052
|
+
"input",
|
|
1053
|
+
{
|
|
1054
|
+
ref,
|
|
1055
|
+
type: "number",
|
|
1056
|
+
className: cn(
|
|
1057
|
+
"w-full rounded-2xl border-2 bg-[rgb(var(--nc-surface)/0.08)] text-[rgb(var(--nc-fg))] backdrop-blur-xl",
|
|
1058
|
+
"shadow-[inset_0_2px_8px_rgba(0,0,0,0.3)]",
|
|
1059
|
+
"focus:outline-none focus:ring-4",
|
|
1060
|
+
"transition-all duration-300",
|
|
1061
|
+
"disabled:opacity-50 disabled:cursor-not-allowed",
|
|
1062
|
+
"border-[rgb(var(--nc-border)/0.35)]",
|
|
1063
|
+
"focus:border-[rgb(var(--nc-accent-1)/0.8)] focus:ring-[rgb(var(--nc-accent-1)/0.3)]",
|
|
1064
|
+
"px-5 py-3 text-base",
|
|
1065
|
+
className
|
|
1066
|
+
),
|
|
1067
|
+
...props
|
|
1068
|
+
}
|
|
1069
|
+
) });
|
|
1070
|
+
});
|
|
1071
|
+
CraftNumberInput.displayName = "CraftNumberInput";
|
|
1072
|
+
|
|
1073
|
+
// src/components/craft-currency-input.tsx
|
|
1074
|
+
var React13 = __toESM(require("react"), 1);
|
|
1075
|
+
var import_jsx_runtime19 = require("react/jsx-runtime");
|
|
1076
|
+
var CraftCurrencyInput = React13.forwardRef(({ className, tone, currencySymbol = "$", ...props }, ref) => {
|
|
1077
|
+
return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "relative w-full", "data-nc-theme": tone, children: [
|
|
1078
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "pointer-events-none absolute left-4 top-1/2 -translate-y-1/2 text-[rgb(var(--nc-fg-soft))]", children: currencySymbol }),
|
|
1079
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
1080
|
+
"input",
|
|
1081
|
+
{
|
|
1082
|
+
ref,
|
|
1083
|
+
type: "text",
|
|
1084
|
+
inputMode: "decimal",
|
|
1085
|
+
className: cn(
|
|
1086
|
+
"w-full rounded-2xl border-2 bg-[rgb(var(--nc-surface)/0.08)] text-[rgb(var(--nc-fg))] backdrop-blur-xl",
|
|
1087
|
+
"shadow-[inset_0_2px_8px_rgba(0,0,0,0.3)]",
|
|
1088
|
+
"focus:outline-none focus:ring-4",
|
|
1089
|
+
"transition-all duration-300",
|
|
1090
|
+
"disabled:opacity-50 disabled:cursor-not-allowed",
|
|
1091
|
+
"border-[rgb(var(--nc-border)/0.35)]",
|
|
1092
|
+
"focus:border-[rgb(var(--nc-accent-1)/0.8)] focus:ring-[rgb(var(--nc-accent-1)/0.3)]",
|
|
1093
|
+
"placeholder:text-[rgb(var(--nc-fg-soft))]",
|
|
1094
|
+
"px-5 py-3 pl-9 text-base",
|
|
1095
|
+
className
|
|
1096
|
+
),
|
|
1097
|
+
...props
|
|
1098
|
+
}
|
|
1099
|
+
)
|
|
1100
|
+
] });
|
|
1101
|
+
});
|
|
1102
|
+
CraftCurrencyInput.displayName = "CraftCurrencyInput";
|
|
1103
|
+
|
|
1104
|
+
// src/components/layout/app-shell.tsx
|
|
1105
|
+
var import_jsx_runtime20 = require("react/jsx-runtime");
|
|
1106
|
+
function AppShell({ className, sidebar, topNav, children, ...props }) {
|
|
1107
|
+
return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
|
|
1108
|
+
"div",
|
|
1109
|
+
{
|
|
1110
|
+
className: cn(
|
|
1111
|
+
"grid min-h-screen grid-cols-1 gap-6 bg-background p-6 lg:grid-cols-[260px_1fr]",
|
|
1112
|
+
className
|
|
1113
|
+
),
|
|
1114
|
+
...props,
|
|
1115
|
+
children: [
|
|
1116
|
+
sidebar && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { className: "h-full", children: sidebar }),
|
|
1117
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "flex flex-col gap-6", children: [
|
|
1118
|
+
topNav,
|
|
1119
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("main", { className: "flex-1", children })
|
|
1120
|
+
] })
|
|
1121
|
+
]
|
|
1122
|
+
}
|
|
1123
|
+
);
|
|
1124
|
+
}
|
|
1125
|
+
|
|
1126
|
+
// src/components/layout/sidebar.tsx
|
|
1127
|
+
var import_jsx_runtime21 = require("react/jsx-runtime");
|
|
1128
|
+
function Sidebar({ className, title, items, footer, ...props }) {
|
|
1129
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
|
|
1130
|
+
"aside",
|
|
1131
|
+
{
|
|
1132
|
+
className: cn(
|
|
1133
|
+
"flex h-full w-full flex-col gap-6 rounded-3xl border border-[rgb(var(--nc-border)/0.3)] bg-[rgb(var(--nc-surface)/0.08)] p-6 text-[rgb(var(--nc-fg))] backdrop-blur-xl",
|
|
1134
|
+
className
|
|
1135
|
+
),
|
|
1136
|
+
...props,
|
|
1137
|
+
children: [
|
|
1138
|
+
title && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: "text-lg font-semibold", children: title }),
|
|
1139
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("nav", { className: "flex flex-col gap-2", children: items.map((item, index) => {
|
|
1140
|
+
var _a;
|
|
1141
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
|
|
1142
|
+
"a",
|
|
1143
|
+
{
|
|
1144
|
+
href: (_a = item.href) != null ? _a : "#",
|
|
1145
|
+
className: cn(
|
|
1146
|
+
"flex items-center gap-3 rounded-2xl px-3 py-2 text-sm transition",
|
|
1147
|
+
item.active ? "bg-[rgb(var(--nc-accent-1)/0.25)] text-[rgb(var(--nc-fg))]" : "text-[rgb(var(--nc-fg-muted))] hover:bg-[rgb(var(--nc-surface)/0.12)] hover:text-[rgb(var(--nc-fg))]"
|
|
1148
|
+
),
|
|
1149
|
+
children: [
|
|
1150
|
+
item.icon,
|
|
1151
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { children: item.label })
|
|
1152
|
+
]
|
|
1153
|
+
},
|
|
1154
|
+
`${item.label}-${index}`
|
|
1155
|
+
);
|
|
1156
|
+
}) }),
|
|
1157
|
+
footer && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: "mt-auto pt-4", children: footer })
|
|
1158
|
+
]
|
|
1159
|
+
}
|
|
1160
|
+
);
|
|
1161
|
+
}
|
|
1162
|
+
|
|
1163
|
+
// src/components/layout/top-nav.tsx
|
|
1164
|
+
var import_jsx_runtime22 = require("react/jsx-runtime");
|
|
1165
|
+
function TopNav({ className, title, actions, breadcrumb, ...props }) {
|
|
1166
|
+
return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
|
|
1167
|
+
"header",
|
|
1168
|
+
{
|
|
1169
|
+
className: cn(
|
|
1170
|
+
"flex flex-wrap items-center justify-between gap-4 rounded-3xl border border-[rgb(var(--nc-border)/0.3)] bg-[rgb(var(--nc-surface)/0.08)] px-6 py-4 text-[rgb(var(--nc-fg))] backdrop-blur-xl",
|
|
1171
|
+
className
|
|
1172
|
+
),
|
|
1173
|
+
...props,
|
|
1174
|
+
children: [
|
|
1175
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "space-y-1", children: [
|
|
1176
|
+
breadcrumb,
|
|
1177
|
+
title && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { className: "text-xl font-semibold", children: title })
|
|
1178
|
+
] }),
|
|
1179
|
+
actions && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { className: "flex flex-wrap gap-3", children: actions })
|
|
1180
|
+
]
|
|
1181
|
+
}
|
|
1182
|
+
);
|
|
1183
|
+
}
|
|
1184
|
+
|
|
1185
|
+
// src/components/layout/page-header.tsx
|
|
1186
|
+
var import_jsx_runtime23 = require("react/jsx-runtime");
|
|
1187
|
+
function PageHeader({
|
|
1188
|
+
className,
|
|
1189
|
+
title,
|
|
1190
|
+
description,
|
|
1191
|
+
actions,
|
|
1192
|
+
...props
|
|
1193
|
+
}) {
|
|
1194
|
+
return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
|
|
1195
|
+
"div",
|
|
1196
|
+
{
|
|
1197
|
+
className: cn("flex flex-wrap items-start justify-between gap-6", className),
|
|
1198
|
+
...props,
|
|
1199
|
+
children: [
|
|
1200
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "space-y-2", children: [
|
|
1201
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)("h1", { className: "text-3xl font-bold text-[rgb(var(--nc-fg))]", children: title }),
|
|
1202
|
+
description && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("p", { className: "text-[rgb(var(--nc-fg-muted))]", children: description })
|
|
1203
|
+
] }),
|
|
1204
|
+
actions && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "flex flex-wrap gap-3", children: actions })
|
|
1205
|
+
]
|
|
1206
|
+
}
|
|
1207
|
+
);
|
|
1208
|
+
}
|
|
1209
|
+
|
|
1210
|
+
// src/components/layout/breadcrumbs.tsx
|
|
1211
|
+
var import_jsx_runtime24 = require("react/jsx-runtime");
|
|
1212
|
+
function Breadcrumbs({ className, items, ...props }) {
|
|
1213
|
+
return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("nav", { className: cn("flex items-center text-sm text-[rgb(var(--nc-fg-muted))]", className), ...props, children: items.map((item, index) => {
|
|
1214
|
+
const content = item.href ? /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("a", { href: item.href, className: "transition hover:text-[rgb(var(--nc-fg))]", children: item.label }) : /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { className: "text-[rgb(var(--nc-fg))]", children: item.label });
|
|
1215
|
+
return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("span", { className: "flex items-center", children: [
|
|
1216
|
+
content,
|
|
1217
|
+
index < items.length - 1 && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { className: "mx-2 text-[rgb(var(--nc-fg-soft))]", children: "/" })
|
|
1218
|
+
] }, `${item.label}-${index}`);
|
|
1219
|
+
}) });
|
|
1220
|
+
}
|
|
1221
|
+
|
|
1222
|
+
// src/components/layout/auth-layout.tsx
|
|
1223
|
+
var import_jsx_runtime25 = require("react/jsx-runtime");
|
|
1224
|
+
function AuthLayout({
|
|
1225
|
+
className,
|
|
1226
|
+
title,
|
|
1227
|
+
description,
|
|
1228
|
+
footer,
|
|
1229
|
+
graphic,
|
|
1230
|
+
children,
|
|
1231
|
+
...props
|
|
1232
|
+
}) {
|
|
1233
|
+
return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
|
|
1234
|
+
"div",
|
|
1235
|
+
{
|
|
1236
|
+
className: cn(
|
|
1237
|
+
"grid min-h-screen grid-cols-1 bg-background",
|
|
1238
|
+
"lg:grid-cols-[1.1fr_0.9fr]",
|
|
1239
|
+
className
|
|
1240
|
+
),
|
|
1241
|
+
...props,
|
|
1242
|
+
children: [
|
|
1243
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { className: "flex flex-col justify-center px-6 py-16 sm:px-12", children: /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "mx-auto w-full max-w-md space-y-6", children: [
|
|
1244
|
+
(title || description) && /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "space-y-2", children: [
|
|
1245
|
+
title && /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("h1", { className: "text-3xl font-bold text-[rgb(var(--nc-fg))]", children: title }),
|
|
1246
|
+
description && /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("p", { className: "text-[rgb(var(--nc-fg-muted))]", children: description })
|
|
1247
|
+
] }),
|
|
1248
|
+
children,
|
|
1249
|
+
footer && /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { className: "text-sm text-[rgb(var(--nc-fg-muted))]", children: footer })
|
|
1250
|
+
] }) }),
|
|
1251
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { className: "hidden items-center justify-center border-l border-[rgb(var(--nc-border)/0.3)] bg-[rgb(var(--nc-surface)/0.08)] p-12 text-[rgb(var(--nc-fg))] lg:flex", children: graphic != null ? graphic : /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "max-w-sm space-y-4 text-center", children: [
|
|
1252
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)("h2", { className: "text-2xl font-semibold", children: "Crafted experiences" }),
|
|
1253
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)("p", { className: "text-[rgb(var(--nc-fg-muted))]", children: "Build authentication flows that feel premium and cohesive." })
|
|
1254
|
+
] }) })
|
|
1255
|
+
]
|
|
1256
|
+
}
|
|
1257
|
+
);
|
|
1258
|
+
}
|
|
1259
|
+
|
|
1260
|
+
// src/components/layout/container.tsx
|
|
1261
|
+
var import_jsx_runtime26 = require("react/jsx-runtime");
|
|
1262
|
+
var sizeClasses2 = {
|
|
1263
|
+
sm: "max-w-3xl",
|
|
1264
|
+
md: "max-w-5xl",
|
|
1265
|
+
lg: "max-w-6xl",
|
|
1266
|
+
xl: "max-w-7xl"
|
|
1267
|
+
};
|
|
1268
|
+
function Container({ className, size = "lg", ...props }) {
|
|
1269
|
+
return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
|
|
1270
|
+
"div",
|
|
1271
|
+
{
|
|
1272
|
+
className: cn("mx-auto w-full px-4 sm:px-6 lg:px-8", sizeClasses2[size], className),
|
|
1273
|
+
...props
|
|
1274
|
+
}
|
|
1275
|
+
);
|
|
1276
|
+
}
|
|
1277
|
+
|
|
1278
|
+
// src/components/layout/grid.tsx
|
|
1279
|
+
var import_jsx_runtime27 = require("react/jsx-runtime");
|
|
1280
|
+
var colClasses = {
|
|
1281
|
+
1: "grid-cols-1",
|
|
1282
|
+
2: "grid-cols-1 md:grid-cols-2",
|
|
1283
|
+
3: "grid-cols-1 md:grid-cols-2 lg:grid-cols-3",
|
|
1284
|
+
4: "grid-cols-1 md:grid-cols-2 lg:grid-cols-4",
|
|
1285
|
+
5: "grid-cols-1 md:grid-cols-2 lg:grid-cols-5",
|
|
1286
|
+
6: "grid-cols-1 md:grid-cols-3 lg:grid-cols-6"
|
|
1287
|
+
};
|
|
1288
|
+
var gapClasses = {
|
|
1289
|
+
sm: "gap-4",
|
|
1290
|
+
md: "gap-6",
|
|
1291
|
+
lg: "gap-8",
|
|
1292
|
+
xl: "gap-10"
|
|
1293
|
+
};
|
|
1294
|
+
function Grid({ className, columns = 3, gap = "md", ...props }) {
|
|
1295
|
+
return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { className: cn("grid", colClasses[columns], gapClasses[gap], className), ...props });
|
|
1296
|
+
}
|
|
1297
|
+
|
|
1298
|
+
// src/theme/theme-context.tsx
|
|
1299
|
+
var React14 = __toESM(require("react"), 1);
|
|
1300
|
+
var import_jsx_runtime28 = require("react/jsx-runtime");
|
|
167
1301
|
var THEME_NAMES = [
|
|
168
1302
|
"aurora",
|
|
169
1303
|
"ember",
|
|
@@ -171,7 +1305,7 @@ var THEME_NAMES = [
|
|
|
171
1305
|
"midnight",
|
|
172
1306
|
"cosmic"
|
|
173
1307
|
];
|
|
174
|
-
var ThemeContext =
|
|
1308
|
+
var ThemeContext = React14.createContext(null);
|
|
175
1309
|
var DEFAULT_THEME_KEY = "nextcraft-theme";
|
|
176
1310
|
var DEFAULT_MODE_KEY = "nextcraft-mode";
|
|
177
1311
|
function ThemeProvider({
|
|
@@ -181,9 +1315,9 @@ function ThemeProvider({
|
|
|
181
1315
|
storageKeyTheme = DEFAULT_THEME_KEY,
|
|
182
1316
|
storageKeyMode = DEFAULT_MODE_KEY
|
|
183
1317
|
}) {
|
|
184
|
-
const [theme, setTheme] =
|
|
185
|
-
const [mode, setMode] =
|
|
186
|
-
|
|
1318
|
+
const [theme, setTheme] = React14.useState(defaultTheme);
|
|
1319
|
+
const [mode, setMode] = React14.useState(defaultMode);
|
|
1320
|
+
React14.useEffect(() => {
|
|
187
1321
|
if (typeof window === "undefined") return;
|
|
188
1322
|
try {
|
|
189
1323
|
const storedTheme = window.localStorage.getItem(storageKeyTheme);
|
|
@@ -193,7 +1327,7 @@ function ThemeProvider({
|
|
|
193
1327
|
} catch {
|
|
194
1328
|
}
|
|
195
1329
|
}, [storageKeyTheme, storageKeyMode]);
|
|
196
|
-
|
|
1330
|
+
React14.useEffect(() => {
|
|
197
1331
|
if (typeof window === "undefined") return;
|
|
198
1332
|
try {
|
|
199
1333
|
window.localStorage.setItem(storageKeyTheme, theme);
|
|
@@ -201,7 +1335,7 @@ function ThemeProvider({
|
|
|
201
1335
|
} catch {
|
|
202
1336
|
}
|
|
203
1337
|
}, [theme, mode, storageKeyTheme, storageKeyMode]);
|
|
204
|
-
|
|
1338
|
+
React14.useEffect(() => {
|
|
205
1339
|
if (typeof document === "undefined") return;
|
|
206
1340
|
const root = document.documentElement;
|
|
207
1341
|
root.dataset.ncTheme = theme;
|
|
@@ -221,14 +1355,14 @@ function ThemeProvider({
|
|
|
221
1355
|
mediaQuery.addListener(applySystem);
|
|
222
1356
|
return () => mediaQuery.removeListener(applySystem);
|
|
223
1357
|
}, [theme, mode]);
|
|
224
|
-
const value =
|
|
1358
|
+
const value = React14.useMemo(
|
|
225
1359
|
() => ({ theme, mode, setTheme, setMode }),
|
|
226
1360
|
[theme, mode]
|
|
227
1361
|
);
|
|
228
|
-
return /* @__PURE__ */ (0,
|
|
1362
|
+
return /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(ThemeContext.Provider, { value, children });
|
|
229
1363
|
}
|
|
230
1364
|
function useTheme() {
|
|
231
|
-
const context =
|
|
1365
|
+
const context = React14.useContext(ThemeContext);
|
|
232
1366
|
if (!context) {
|
|
233
1367
|
throw new Error("useTheme must be used within ThemeProvider");
|
|
234
1368
|
}
|
|
@@ -236,40 +1370,40 @@ function useTheme() {
|
|
|
236
1370
|
}
|
|
237
1371
|
|
|
238
1372
|
// src/components/theme-switcher.tsx
|
|
239
|
-
var
|
|
1373
|
+
var import_jsx_runtime29 = require("react/jsx-runtime");
|
|
240
1374
|
var MODE_OPTIONS = ["system", "light", "dark"];
|
|
241
1375
|
function ThemeSwitcher({ className, showLabels = true, ...props }) {
|
|
242
1376
|
const { theme, mode, setTheme, setMode } = useTheme();
|
|
243
|
-
return /* @__PURE__ */ (0,
|
|
1377
|
+
return /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(
|
|
244
1378
|
"div",
|
|
245
1379
|
{
|
|
246
1380
|
className: cn(
|
|
247
|
-
"flex flex-wrap items-center gap-3 rounded-2xl border border-
|
|
1381
|
+
"flex flex-wrap items-center gap-3 rounded-2xl border border-[rgb(var(--nc-border)/0.3)] bg-[rgb(var(--nc-surface)/0.08)] px-4 py-3 text-sm text-[rgb(var(--nc-fg))] shadow-[inset_0_1px_0_rgba(255,255,255,0.06)]",
|
|
248
1382
|
className
|
|
249
1383
|
),
|
|
250
1384
|
...props,
|
|
251
1385
|
children: [
|
|
252
|
-
/* @__PURE__ */ (0,
|
|
253
|
-
showLabels && /* @__PURE__ */ (0,
|
|
254
|
-
/* @__PURE__ */ (0,
|
|
1386
|
+
/* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("label", { className: "flex items-center gap-2", children: [
|
|
1387
|
+
showLabels && /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("span", { className: "text-[rgb(var(--nc-fg-muted))]", children: "Theme" }),
|
|
1388
|
+
/* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
|
|
255
1389
|
"select",
|
|
256
1390
|
{
|
|
257
|
-
className: "rounded-lg border border-
|
|
1391
|
+
className: "rounded-lg border border-[rgb(var(--nc-border)/0.3)] bg-[rgb(var(--nc-surface)/0.12)] px-3 py-1 text-[rgb(var(--nc-fg))] outline-none focus:ring-2 focus:ring-[rgb(var(--nc-accent-1)/0.5)]",
|
|
258
1392
|
value: theme,
|
|
259
1393
|
onChange: (event) => setTheme(event.target.value),
|
|
260
|
-
children: THEME_NAMES.map((name) => /* @__PURE__ */ (0,
|
|
1394
|
+
children: THEME_NAMES.map((name) => /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("option", { value: name, className: "text-slate-900", children: name }, name))
|
|
261
1395
|
}
|
|
262
1396
|
)
|
|
263
1397
|
] }),
|
|
264
|
-
/* @__PURE__ */ (0,
|
|
265
|
-
showLabels && /* @__PURE__ */ (0,
|
|
266
|
-
/* @__PURE__ */ (0,
|
|
1398
|
+
/* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("label", { className: "flex items-center gap-2", children: [
|
|
1399
|
+
showLabels && /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("span", { className: "text-[rgb(var(--nc-fg-muted))]", children: "Mode" }),
|
|
1400
|
+
/* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
|
|
267
1401
|
"select",
|
|
268
1402
|
{
|
|
269
|
-
className: "rounded-lg border border-
|
|
1403
|
+
className: "rounded-lg border border-[rgb(var(--nc-border)/0.3)] bg-[rgb(var(--nc-surface)/0.12)] px-3 py-1 text-[rgb(var(--nc-fg))] outline-none focus:ring-2 focus:ring-[rgb(var(--nc-accent-1)/0.5)]",
|
|
270
1404
|
value: mode,
|
|
271
1405
|
onChange: (event) => setMode(event.target.value),
|
|
272
|
-
children: MODE_OPTIONS.map((value) => /* @__PURE__ */ (0,
|
|
1406
|
+
children: MODE_OPTIONS.map((value) => /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("option", { value, className: "text-slate-900", children: value }, value))
|
|
273
1407
|
}
|
|
274
1408
|
)
|
|
275
1409
|
] })
|
|
@@ -279,11 +1413,36 @@ function ThemeSwitcher({ className, showLabels = true, ...props }) {
|
|
|
279
1413
|
}
|
|
280
1414
|
// Annotate the CommonJS export names for ESM import in node:
|
|
281
1415
|
0 && (module.exports = {
|
|
1416
|
+
AppShell,
|
|
1417
|
+
AuthLayout,
|
|
1418
|
+
Breadcrumbs,
|
|
1419
|
+
Container,
|
|
1420
|
+
CraftBadge,
|
|
282
1421
|
CraftButton,
|
|
1422
|
+
CraftCard,
|
|
1423
|
+
CraftCheckbox,
|
|
1424
|
+
CraftCurrencyInput,
|
|
1425
|
+
CraftDatePicker,
|
|
1426
|
+
CraftDrawer,
|
|
1427
|
+
CraftEmptyState,
|
|
283
1428
|
CraftInput,
|
|
1429
|
+
CraftModal,
|
|
1430
|
+
CraftNumberInput,
|
|
1431
|
+
CraftSelect,
|
|
1432
|
+
CraftSkeleton,
|
|
1433
|
+
CraftSwitch,
|
|
1434
|
+
CraftTabs,
|
|
1435
|
+
CraftTextarea,
|
|
1436
|
+
CraftToastHost,
|
|
1437
|
+
CraftTooltip,
|
|
284
1438
|
GlassCard,
|
|
1439
|
+
Grid,
|
|
1440
|
+
PageHeader,
|
|
1441
|
+
Sidebar,
|
|
285
1442
|
ThemeProvider,
|
|
286
1443
|
ThemeSwitcher,
|
|
1444
|
+
TopNav,
|
|
1445
|
+
useCraftToast,
|
|
287
1446
|
useTheme
|
|
288
1447
|
});
|
|
289
1448
|
//# sourceMappingURL=index.cjs.map
|