@web-my-money/blocks 1.0.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/app.js ADDED
@@ -0,0 +1,1293 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/app.ts
31
+ var app_exports = {};
32
+ __export(app_exports, {
33
+ ActivityFeed: () => ActivityFeed,
34
+ AppBrand: () => AppBrand,
35
+ AppShell: () => AppShell,
36
+ AppearanceSettings: () => AppearanceSettings,
37
+ BrandFrame: () => BrandFrame,
38
+ DashboardHeader: () => DashboardHeader,
39
+ DataSummaryCards: () => DataSummaryCards,
40
+ DataTable: () => DataTable,
41
+ EmptyState: () => EmptyState,
42
+ GlassPanel: () => GlassPanel,
43
+ KPIRow: () => KPIRow,
44
+ LayoutToggle: () => LayoutToggle,
45
+ LightboxGallery: () => LightboxGallery,
46
+ NotificationBanner: () => NotificationBanner,
47
+ PageHeader: () => PageHeader,
48
+ PageHeaderBanner: () => PageHeaderBanner,
49
+ SidebarNavigation: () => SidebarNavigation,
50
+ StatCard: () => StatCard,
51
+ SubTabs: () => SubTabs,
52
+ Thumbnail: () => Thumbnail,
53
+ useActionRunner: () => useActionRunner,
54
+ useLayoutPreference: () => useLayoutPreference,
55
+ useOptimisticAction: () => useOptimisticAction
56
+ });
57
+ module.exports = __toCommonJS(app_exports);
58
+
59
+ // src/notification-banner/index.tsx
60
+ var React = __toESM(require("react"));
61
+ var import_framer_motion = require("framer-motion");
62
+ var import_lucide_react = require("lucide-react");
63
+
64
+ // src/utils.ts
65
+ var import_clsx = require("clsx");
66
+ var import_tailwind_merge = require("tailwind-merge");
67
+ function cn(...inputs) {
68
+ return (0, import_tailwind_merge.twMerge)((0, import_clsx.clsx)(inputs));
69
+ }
70
+
71
+ // src/notification-banner/index.tsx
72
+ var import_jsx_runtime = require("react/jsx-runtime");
73
+ var variantConfig = {
74
+ info: { icon: import_lucide_react.Info, classes: "bg-primary/10 border-primary/20", iconClass: "text-primary" },
75
+ success: { icon: import_lucide_react.CheckCircle2, classes: "bg-emerald-500/10 border-emerald-500/20", iconClass: "text-emerald-500" },
76
+ warning: { icon: import_lucide_react.AlertTriangle, classes: "bg-amber-500/10 border-amber-500/20", iconClass: "text-amber-500" },
77
+ danger: { icon: import_lucide_react.AlertCircle, classes: "bg-destructive/10 border-destructive/20", iconClass: "text-destructive" },
78
+ brand: { icon: import_lucide_react.Info, classes: "border-0", iconClass: "text-white" }
79
+ };
80
+ function NotificationBanner({
81
+ variant = "info",
82
+ message,
83
+ action,
84
+ dismissible = true,
85
+ onDismiss,
86
+ visible = true,
87
+ className
88
+ }) {
89
+ const [open, setOpen] = React.useState(true);
90
+ const show = visible && open;
91
+ const dismiss = () => {
92
+ setOpen(false);
93
+ onDismiss?.();
94
+ };
95
+ const cfg = variantConfig[variant];
96
+ const Icon = cfg.icon;
97
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_framer_motion.AnimatePresence, { children: show && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
98
+ import_framer_motion.motion.div,
99
+ {
100
+ initial: { height: 0, opacity: 0 },
101
+ animate: { height: "auto", opacity: 1 },
102
+ exit: { height: 0, opacity: 0 },
103
+ transition: { duration: 0.2, ease: "easeInOut" },
104
+ className: "overflow-hidden",
105
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
106
+ "div",
107
+ {
108
+ className: cn(
109
+ "relative flex items-center justify-center gap-3 px-4 py-2.5 text-sm border-b",
110
+ variant === "brand" ? "text-white" : "text-foreground",
111
+ cfg.classes,
112
+ className
113
+ ),
114
+ style: variant === "brand" ? { background: "var(--gradient-primary, var(--primary))" } : void 0,
115
+ children: [
116
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Icon, { size: 15, className: cn("shrink-0", cfg.iconClass) }),
117
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", { className: cn("text-center", variant === "brand" ? "text-white" : "text-foreground/90"), children: [
118
+ message,
119
+ action && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
120
+ " ",
121
+ action.href ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
122
+ "a",
123
+ {
124
+ href: action.href,
125
+ className: cn(
126
+ "underline underline-offset-2 font-medium ml-1",
127
+ variant === "brand" ? "text-white/90 hover:text-white" : "text-primary hover:text-primary/80"
128
+ ),
129
+ children: action.label
130
+ }
131
+ ) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
132
+ "button",
133
+ {
134
+ onClick: action.onClick,
135
+ className: cn(
136
+ "underline underline-offset-2 font-medium ml-1",
137
+ variant === "brand" ? "text-white/90 hover:text-white" : "text-primary hover:text-primary/80"
138
+ ),
139
+ children: action.label
140
+ }
141
+ )
142
+ ] })
143
+ ] }),
144
+ dismissible && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
145
+ "button",
146
+ {
147
+ onClick: dismiss,
148
+ "aria-label": "Dismiss",
149
+ className: cn(
150
+ "absolute right-3 rounded p-1 transition-colors",
151
+ variant === "brand" ? "text-white/70 hover:text-white hover:bg-white/10" : "text-muted-foreground hover:text-foreground hover:bg-accent"
152
+ ),
153
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.X, { size: 14 })
154
+ }
155
+ )
156
+ ]
157
+ }
158
+ )
159
+ },
160
+ "banner"
161
+ ) });
162
+ }
163
+
164
+ // src/stat-card/index.tsx
165
+ var import_lucide_react2 = require("lucide-react");
166
+ var import_jsx_runtime2 = require("react/jsx-runtime");
167
+ function inferStatus(delta) {
168
+ if (!delta) return "flat";
169
+ if (delta.startsWith("+") || !delta.startsWith("-") && parseFloat(delta) > 0) return "up";
170
+ if (delta.startsWith("-") || parseFloat(delta) < 0) return "down";
171
+ return "flat";
172
+ }
173
+ var statusColors = {
174
+ success: "text-emerald-500",
175
+ warning: "text-amber-500",
176
+ danger: "text-red-500",
177
+ info: "text-primary"
178
+ };
179
+ function StatCard({
180
+ title,
181
+ value,
182
+ delta,
183
+ deltaLabel,
184
+ icon,
185
+ chart,
186
+ status,
187
+ className
188
+ }) {
189
+ const trend = inferStatus(delta);
190
+ const deltaColor = status ? statusColors[status] : trend === "up" ? "text-emerald-500" : trend === "down" ? "text-red-500" : "text-muted-foreground";
191
+ const TrendIcon = trend === "up" ? import_lucide_react2.TrendingUp : trend === "down" ? import_lucide_react2.TrendingDown : import_lucide_react2.Minus;
192
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
193
+ "div",
194
+ {
195
+ className: cn(
196
+ "relative flex flex-col gap-3 rounded-xl border bg-card p-5 overflow-hidden",
197
+ "border-border",
198
+ className
199
+ ),
200
+ style: { boxShadow: "var(--shadow-card)" },
201
+ children: [
202
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
203
+ "div",
204
+ {
205
+ "aria-hidden": true,
206
+ className: "absolute inset-x-0 top-0 h-px opacity-60",
207
+ style: { background: "var(--gradient-primary, var(--primary))" }
208
+ }
209
+ ),
210
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "flex items-start justify-between gap-2", children: [
211
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "text-xs font-medium text-muted-foreground uppercase tracking-wider truncate", children: title }),
212
+ icon && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "shrink-0 text-muted-foreground/60", children: icon })
213
+ ] }),
214
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "text-3xl font-bold text-foreground tracking-tight tabular-nums", children: typeof value === "number" ? value.toLocaleString() : value }),
215
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "flex items-end justify-between gap-2 mt-auto", children: [
216
+ delta ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: cn("flex items-center gap-1 text-xs font-medium", deltaColor), children: [
217
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(TrendIcon, { size: 13, strokeWidth: 2.5 }),
218
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: delta }),
219
+ deltaLabel && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "text-muted-foreground font-normal", children: deltaLabel })
220
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", {}),
221
+ chart && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "shrink-0", children: chart })
222
+ ] })
223
+ ]
224
+ }
225
+ );
226
+ }
227
+
228
+ // src/page-header/index.tsx
229
+ var import_lucide_react3 = require("lucide-react");
230
+ var import_jsx_runtime3 = require("react/jsx-runtime");
231
+ function PageHeader({
232
+ title,
233
+ description,
234
+ breadcrumb,
235
+ actions,
236
+ below,
237
+ className
238
+ }) {
239
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
240
+ "header",
241
+ {
242
+ className: cn(
243
+ "flex flex-col gap-4 pb-6 border-b border-border",
244
+ className
245
+ ),
246
+ children: [
247
+ breadcrumb && breadcrumb.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("nav", { "aria-label": "Breadcrumb", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("ol", { className: "flex items-center gap-1 flex-wrap", children: breadcrumb.map((item, i) => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("li", { className: "flex items-center gap-1", children: [
248
+ i > 0 && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_lucide_react3.ChevronRight, { size: 12, className: "text-muted-foreground/50" }),
249
+ item.href ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
250
+ "a",
251
+ {
252
+ href: item.href,
253
+ className: "text-xs text-muted-foreground hover:text-foreground transition-colors",
254
+ children: item.label
255
+ }
256
+ ) : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "text-xs text-muted-foreground", children: item.label })
257
+ ] }, i)) }) }),
258
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "flex items-start justify-between gap-4 flex-wrap", children: [
259
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "space-y-1", children: [
260
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("h1", { className: "text-2xl font-bold tracking-tight text-foreground", children: title }),
261
+ description && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: "text-sm text-muted-foreground max-w-xl", children: description })
262
+ ] }),
263
+ actions && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "flex items-center gap-2 flex-wrap", children: actions })
264
+ ] }),
265
+ below && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { children: below })
266
+ ]
267
+ }
268
+ );
269
+ }
270
+
271
+ // src/empty-state/index.tsx
272
+ var import_jsx_runtime4 = require("react/jsx-runtime");
273
+ function EmptyState({
274
+ icon,
275
+ title,
276
+ description,
277
+ action,
278
+ secondaryAction,
279
+ variant = "page",
280
+ className
281
+ }) {
282
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
283
+ "div",
284
+ {
285
+ className: cn(
286
+ "flex flex-col items-center text-center",
287
+ variant === "page" ? "min-h-[360px] justify-center px-6 py-20" : "rounded-xl border border-border border-dashed bg-card/50 px-6 py-12",
288
+ className
289
+ ),
290
+ children: [
291
+ icon && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
292
+ "div",
293
+ {
294
+ className: "mb-5 flex h-14 w-14 items-center justify-center rounded-xl border border-border bg-muted/40 text-muted-foreground",
295
+ children: icon
296
+ }
297
+ ),
298
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { className: "text-base font-semibold text-foreground mb-2", children: title }),
299
+ description && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { className: "text-sm text-muted-foreground max-w-xs mb-6", children: description }),
300
+ (action || secondaryAction) && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "flex flex-col sm:flex-row items-center gap-3", children: [
301
+ action,
302
+ secondaryAction
303
+ ] })
304
+ ]
305
+ }
306
+ );
307
+ }
308
+
309
+ // src/dashboard-header/index.tsx
310
+ var import_jsx_runtime5 = require("react/jsx-runtime");
311
+ function DashboardHeader({
312
+ pageTitle,
313
+ notificationsCount = 0,
314
+ actions,
315
+ className
316
+ }) {
317
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
318
+ "header",
319
+ {
320
+ className: cn(
321
+ "flex h-14 lg:h-[60px] items-center gap-4 border-b bg-muted/20 px-6 justify-between",
322
+ className
323
+ ),
324
+ children: [
325
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "font-semibold text-lg", children: pageTitle }),
326
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex items-center gap-4", children: [
327
+ notificationsCount > 0 && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "relative", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "h-5 w-5 rounded-full bg-primary/20 aspect-square text-[10px] font-bold flex items-center justify-center", children: notificationsCount }) }),
328
+ actions
329
+ ] })
330
+ ]
331
+ }
332
+ );
333
+ }
334
+
335
+ // src/data-summary-cards/index.tsx
336
+ var import_jsx_runtime6 = require("react/jsx-runtime");
337
+ function DataSummaryCards({
338
+ metrics,
339
+ columns = 4,
340
+ className
341
+ }) {
342
+ const gridCols = {
343
+ 2: "md:grid-cols-2",
344
+ 3: "md:grid-cols-3",
345
+ 4: "md:grid-cols-2 lg:grid-cols-4"
346
+ };
347
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: cn("grid gap-4", gridCols[columns], className), children: metrics.map((item, i) => /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
348
+ "div",
349
+ {
350
+ className: "rounded-xl bg-card p-4 text-card-foreground ring-1 ring-foreground/10",
351
+ children: [
352
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "flex items-center justify-between mb-2", children: [
353
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "text-sm font-medium text-muted-foreground", children: item.title }),
354
+ item.icon ?? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "h-4 w-4 rounded bg-muted-foreground/20" })
355
+ ] }),
356
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "text-2xl font-bold", children: item.value }),
357
+ item.description && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "text-xs text-muted-foreground mt-1", children: item.description })
358
+ ]
359
+ },
360
+ i
361
+ )) });
362
+ }
363
+
364
+ // src/data-table/index.tsx
365
+ var React2 = __toESM(require("react"));
366
+ var import_pagination = require("@web-my-money/primitives/pagination");
367
+ var import_jsx_runtime7 = require("react/jsx-runtime");
368
+ function DataTable({
369
+ title,
370
+ columns,
371
+ rows,
372
+ activeBadgeLabel = "Active",
373
+ className,
374
+ pageSize,
375
+ page: controlledPage,
376
+ onPageChange
377
+ }) {
378
+ const [uncontrolledPage, setUncontrolledPage] = React2.useState(1);
379
+ const page = controlledPage ?? uncontrolledPage;
380
+ const pageCount = pageSize ? Math.max(1, Math.ceil(rows.length / pageSize)) : 1;
381
+ const visibleRows = pageSize ? rows.slice((page - 1) * pageSize, page * pageSize) : rows;
382
+ const setPage = (next) => {
383
+ setUncontrolledPage(next);
384
+ onPageChange?.(next);
385
+ };
386
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: cn("rounded-md border", className), children: [
387
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "p-4 border-b bg-muted/10 font-medium text-lg", children: title }),
388
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "p-0", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("table", { className: "w-full text-sm", children: [
389
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("thead", { className: "border-b bg-muted/20", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("tr", { children: columns.map((col, i) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
390
+ "th",
391
+ {
392
+ className: cn(
393
+ "font-medium p-4",
394
+ i === 0 ? "text-left" : i === columns.length - 1 ? "text-right" : "text-left"
395
+ ),
396
+ children: col
397
+ },
398
+ col
399
+ )) }) }),
400
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("tbody", { children: visibleRows.map((row) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
401
+ "tr",
402
+ {
403
+ className: "border-b last:border-0 hover:bg-muted/10 transition-colors",
404
+ children: row.cells.map((cell, i) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
405
+ "td",
406
+ {
407
+ className: cn(
408
+ "p-4",
409
+ i === 0 ? "font-medium" : i === columns.length - 1 ? "text-right font-medium" : "text-muted-foreground"
410
+ ),
411
+ children: i === 1 && row.isActive ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold bg-primary/10 text-primary", children: activeBadgeLabel }) : cell
412
+ },
413
+ i
414
+ ))
415
+ },
416
+ row.id
417
+ )) })
418
+ ] }) }),
419
+ pageSize && pageCount > 1 && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "flex justify-center border-t p-3", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_pagination.PaginationBar, { page, pageCount, onPageChange: setPage }) })
420
+ ] });
421
+ }
422
+
423
+ // src/sidebar-navigation/index.tsx
424
+ var import_jsx_runtime8 = require("react/jsx-runtime");
425
+ function SidebarNavigation({
426
+ appName,
427
+ userName,
428
+ menuItems,
429
+ footer,
430
+ className
431
+ }) {
432
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
433
+ "aside",
434
+ {
435
+ className: cn(
436
+ "w-64 border-r bg-muted/20 h-screen hidden md:flex flex-col",
437
+ className
438
+ ),
439
+ children: [
440
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "h-14 border-b flex items-center px-4 font-bold text-lg", children: appName }),
441
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("nav", { className: "flex-1 overflow-auto py-4 px-2 space-y-2", children: menuItems.map((item, i) => /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
442
+ "a",
443
+ {
444
+ href: item.href ?? "#",
445
+ className: cn(
446
+ "flex items-center px-3 py-2 text-sm font-medium rounded-md cursor-pointer transition-colors",
447
+ item.active ? "bg-primary/10 text-primary" : "hover:bg-muted text-muted-foreground"
448
+ ),
449
+ children: [
450
+ item.icon ?? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
451
+ "span",
452
+ {
453
+ className: cn(
454
+ "h-4 w-4 mr-3 rounded",
455
+ item.active ? "bg-primary/50" : "bg-muted-foreground/30"
456
+ )
457
+ }
458
+ ),
459
+ item.label
460
+ ]
461
+ },
462
+ i
463
+ )) }),
464
+ (userName || footer) && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "p-4 border-t text-sm font-medium", children: footer ?? userName })
465
+ ]
466
+ }
467
+ );
468
+ }
469
+
470
+ // src/kpi-row/index.tsx
471
+ var import_lucide_react4 = require("lucide-react");
472
+ var import_jsx_runtime9 = require("react/jsx-runtime");
473
+ function inferTrend(delta) {
474
+ if (!delta) return "flat";
475
+ if (delta.startsWith("+") || parseFloat(delta) > 0) return "up";
476
+ if (delta.startsWith("-") || parseFloat(delta) < 0) return "down";
477
+ return "flat";
478
+ }
479
+ var deltaColorMap = {
480
+ up: "text-emerald-500",
481
+ down: "text-red-500",
482
+ flat: "text-muted-foreground"
483
+ };
484
+ var statusColorMap = {
485
+ success: "text-emerald-500",
486
+ warning: "text-amber-500",
487
+ danger: "text-red-500",
488
+ neutral: "text-muted-foreground"
489
+ };
490
+ function KPIRow({ items, dividers = true, className }) {
491
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
492
+ "div",
493
+ {
494
+ className: cn(
495
+ "grid w-full rounded-xl border border-border bg-card",
496
+ `grid-cols-${Math.min(items.length, 4)} sm:grid-cols-${items.length}`,
497
+ className
498
+ ),
499
+ style: { gridTemplateColumns: `repeat(${items.length}, minmax(0, 1fr))` },
500
+ children: items.map((item, i) => {
501
+ const trend = inferTrend(item.delta);
502
+ const deltaColor = item.status ? statusColorMap[item.status] : deltaColorMap[trend];
503
+ const TrendIcon = trend === "up" ? import_lucide_react4.TrendingUp : trend === "down" ? import_lucide_react4.TrendingDown : import_lucide_react4.Minus;
504
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
505
+ "div",
506
+ {
507
+ className: cn(
508
+ "flex flex-col gap-1 px-5 py-4",
509
+ dividers && i < items.length - 1 && "border-r border-border"
510
+ ),
511
+ children: [
512
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("p", { className: "text-xs font-medium uppercase tracking-wider text-muted-foreground truncate", children: item.label }),
513
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("p", { className: "text-2xl font-bold tabular-nums text-foreground", children: [
514
+ item.prefix && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "text-lg font-medium text-muted-foreground", children: item.prefix }),
515
+ typeof item.value === "number" ? item.value.toLocaleString() : item.value,
516
+ item.suffix && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "text-lg font-medium text-muted-foreground ml-0.5", children: item.suffix })
517
+ ] }),
518
+ item.delta && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: cn("flex items-center gap-1 text-xs font-medium", deltaColor), children: [
519
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(TrendIcon, { size: 11, strokeWidth: 2.5, "aria-hidden": true }),
520
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { children: item.delta }),
521
+ item.deltaLabel && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "font-normal text-muted-foreground", children: item.deltaLabel })
522
+ ] })
523
+ ]
524
+ },
525
+ i
526
+ );
527
+ })
528
+ }
529
+ );
530
+ }
531
+
532
+ // src/activity-feed/index.tsx
533
+ var import_jsx_runtime10 = require("react/jsx-runtime");
534
+ var typeDot = {
535
+ task: "bg-primary",
536
+ comment: "bg-sky-500",
537
+ alert: "bg-amber-500",
538
+ success: "bg-emerald-500",
539
+ info: "bg-muted-foreground",
540
+ user: "bg-violet-500"
541
+ };
542
+ function getInitials(text) {
543
+ if (!text) return "?";
544
+ const w = text.trim().split(/\s+/);
545
+ return w.length === 1 ? w[0].slice(0, 2).toUpperCase() : (w[0][0] + w[w.length - 1][0]).toUpperCase();
546
+ }
547
+ function ActivityFeed({
548
+ items,
549
+ timeline = true,
550
+ compact = false,
551
+ className,
552
+ emptyMessage = "No activity yet."
553
+ }) {
554
+ if (!items.length) {
555
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: cn("py-10 text-center text-sm text-muted-foreground", className), children: emptyMessage });
556
+ }
557
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("ul", { className: cn("flex flex-col", compact ? "gap-1" : "gap-0", className), children: items.map((item, i) => {
558
+ const dotColor = item.dotColor ?? typeDot[item.type ?? "info"];
559
+ const isLast = i === items.length - 1;
560
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("li", { className: cn("relative flex gap-4", compact ? "py-2 px-1" : "py-3 px-1"), children: [
561
+ timeline && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex flex-col items-center shrink-0", style: { width: 28 }, children: [
562
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: cn("mt-0.5 size-2.5 rounded-full ring-2 ring-background shrink-0", dotColor) }),
563
+ !isLast && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "mt-1 w-px flex-1 bg-border", style: { minHeight: compact ? 16 : 24 } })
564
+ ] }),
565
+ !timeline && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "mt-0.5 shrink-0 inline-flex size-8 items-center justify-center rounded-full bg-muted text-xs font-medium text-muted-foreground overflow-hidden", children: item.icon ?? (item.avatar ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("img", { src: item.avatar, alt: item.initials ?? "", className: "size-full object-cover" }) : getInitials(item.initials ?? item.title)) }),
566
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex-1 min-w-0", children: [
567
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex items-start justify-between gap-2", children: [
568
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("p", { className: cn("text-sm font-medium text-foreground leading-snug", compact && "text-xs"), children: item.title }),
569
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "shrink-0 text-xs text-muted-foreground whitespace-nowrap", children: item.timestamp })
570
+ ] }),
571
+ item.description && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("p", { className: "mt-0.5 text-xs text-muted-foreground line-clamp-2", children: item.description }),
572
+ item.meta && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("p", { className: "mt-1 text-[11px] text-muted-foreground/70", children: item.meta })
573
+ ] })
574
+ ] }, item.id);
575
+ }) });
576
+ }
577
+
578
+ // src/app-shell/index.tsx
579
+ var React3 = __toESM(require("react"));
580
+ var import_lucide_react5 = require("lucide-react");
581
+ var import_dropdown_menu = require("@web-my-money/primitives/dropdown-menu");
582
+
583
+ // src/app-brand/index.tsx
584
+ var import_jsx_runtime11 = (
585
+ // Mini-logo placeholder — first letter on a primary chip.
586
+ require("react/jsx-runtime")
587
+ );
588
+ var MARK_SIZE = { sm: "size-6 text-xs", md: "size-7 text-sm" };
589
+ var TITLE_SIZE = { sm: "text-[13px]", md: "text-sm" };
590
+ function AppBrand({
591
+ appName,
592
+ prefix = "WMM",
593
+ logo,
594
+ subtitle,
595
+ badge,
596
+ href,
597
+ collapsed = false,
598
+ size = "md",
599
+ renderLink,
600
+ className
601
+ }) {
602
+ const mark = logo ?? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
603
+ "span",
604
+ {
605
+ className: cn(
606
+ "grid shrink-0 place-items-center rounded-lg bg-primary font-bold text-primary-foreground",
607
+ MARK_SIZE[size]
608
+ ),
609
+ "aria-hidden": true,
610
+ children: appName.slice(0, 1)
611
+ }
612
+ );
613
+ const inner = /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("span", { className: "flex items-center gap-2.5", children: [
614
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "grid shrink-0 place-items-center [&_svg]:h-auto", children: mark }),
615
+ !collapsed && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("span", { className: "flex min-w-0 items-center gap-2", children: [
616
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("span", { className: "flex min-w-0 flex-col leading-tight", children: [
617
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("span", { className: cn("truncate font-semibold tracking-tight", TITLE_SIZE[size]), children: [
618
+ prefix && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("span", { className: "text-muted-foreground", children: [
619
+ prefix,
620
+ " "
621
+ ] }),
622
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "text-primary", children: appName })
623
+ ] }),
624
+ subtitle && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "truncate text-[11px] text-muted-foreground", children: subtitle })
625
+ ] }),
626
+ badge != null && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "border-l border-border pl-2 text-sm font-semibold text-muted-foreground", children: badge })
627
+ ] })
628
+ ] });
629
+ const cls = cn("inline-flex items-center", className);
630
+ if (href && renderLink) return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_jsx_runtime11.Fragment, { children: renderLink({ href, className: cls, children: inner }) });
631
+ if (href)
632
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("a", { href, className: cls, children: inner });
633
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: cls, children: inner });
634
+ }
635
+
636
+ // src/app-shell/index.tsx
637
+ var import_jsx_runtime12 = require("react/jsx-runtime");
638
+ var railW = "w-14";
639
+ var openW = "w-56";
640
+ var LAYOUT_KEY = "wmm-app-layout";
641
+ function isGroup(n) {
642
+ return Array.isArray(n.items) && !("href" in n) && !("onClick" in n) && !("icon" in n) && !("badge" in n) && !("shortLabel" in n) && !("external" in n);
643
+ }
644
+ function toGroups(nav) {
645
+ if (!nav.length) return [];
646
+ return isGroup(nav[0]) ? nav : [{ items: nav }];
647
+ }
648
+ function allItems(groups) {
649
+ return groups.flatMap((g) => g.items);
650
+ }
651
+ function withActive(item, pathname) {
652
+ if (item.active !== void 0 || !pathname || !item.href) return item;
653
+ const active = item.href === "/" ? pathname === "/" : pathname.startsWith(item.href);
654
+ return active ? { ...item, active } : item;
655
+ }
656
+ var LayoutContext = React3.createContext(null);
657
+ function useLayoutPreference(defaultLayout = "sidebar") {
658
+ const [layout, setLayoutState] = React3.useState(defaultLayout);
659
+ React3.useEffect(() => {
660
+ try {
661
+ const saved = window.localStorage.getItem(LAYOUT_KEY);
662
+ if (saved === "sidebar" || saved === "top") setLayoutState(saved);
663
+ } catch {
664
+ }
665
+ }, []);
666
+ const setLayout = React3.useCallback((l) => {
667
+ setLayoutState(l);
668
+ try {
669
+ window.localStorage.setItem(LAYOUT_KEY, l);
670
+ } catch {
671
+ }
672
+ }, []);
673
+ return [layout, setLayout];
674
+ }
675
+ function LayoutToggle({ className }) {
676
+ const ctx = React3.useContext(LayoutContext);
677
+ if (!ctx) return null;
678
+ const next = ctx.layout === "sidebar" ? "top" : "sidebar";
679
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
680
+ "button",
681
+ {
682
+ type: "button",
683
+ onClick: () => ctx.setLayout(next),
684
+ className: cn(
685
+ "inline-flex items-center justify-center rounded-md p-1.5 text-muted-foreground transition-colors hover:bg-muted hover:text-foreground",
686
+ className
687
+ ),
688
+ "aria-label": `Switch to ${next} layout`,
689
+ title: `Switch to ${next} layout`,
690
+ children: ctx.layout === "sidebar" ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_lucide_react5.PanelTop, { className: "size-4" }) : /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_lucide_react5.PanelLeft, { className: "size-4" })
691
+ }
692
+ );
693
+ }
694
+ function SidebarNavRow({
695
+ item,
696
+ collapsed,
697
+ renderLink,
698
+ onNavigate,
699
+ nested
700
+ }) {
701
+ const inner = /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
702
+ "span",
703
+ {
704
+ className: cn(
705
+ "flex items-center gap-2.5 rounded-md px-2.5 py-2 text-[13px] font-medium transition-colors",
706
+ item.active ? "bg-primary/15 text-primary" : "text-muted-foreground hover:bg-muted hover:text-foreground",
707
+ collapsed && "justify-center px-0",
708
+ nested && !collapsed && "ml-3.5 py-1.5"
709
+ ),
710
+ children: [
711
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "grid size-[15px] shrink-0 place-items-center [&_svg]:size-[15px]", children: item.icon }),
712
+ !collapsed && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("span", { className: "flex-1 truncate", children: [
713
+ item.label,
714
+ item.external && " \u2197"
715
+ ] }),
716
+ !collapsed && item.badge != null && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "rounded bg-danger/20 px-1.5 py-px text-[10px] font-semibold text-danger", children: item.badge })
717
+ ]
718
+ }
719
+ );
720
+ const cls = "block";
721
+ if (item.href && item.external)
722
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("a", { href: item.href, target: "_blank", rel: "noopener noreferrer", className: cls, onClick: onNavigate, children: inner });
723
+ if (item.href && renderLink) return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_jsx_runtime12.Fragment, { children: renderLink({ href: item.href, className: cls, children: inner }) });
724
+ if (item.href)
725
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("a", { href: item.href, className: cls, onClick: onNavigate, children: inner });
726
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("button", { type: "button", className: cn(cls, "w-full text-left"), onClick: () => {
727
+ item.onClick?.();
728
+ onNavigate?.();
729
+ }, children: inner });
730
+ }
731
+ function SectionHeader({
732
+ group,
733
+ open,
734
+ onToggle
735
+ }) {
736
+ if (!group.collapsible) {
737
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "px-2.5 pb-1 pt-3 text-[10px] font-semibold uppercase tracking-widest text-muted-foreground", children: group.label });
738
+ }
739
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
740
+ "button",
741
+ {
742
+ type: "button",
743
+ onClick: onToggle,
744
+ className: "flex w-full items-center gap-1 px-2.5 pb-1 pt-3 text-[10px] font-semibold uppercase tracking-widest text-muted-foreground transition-colors hover:text-foreground",
745
+ children: [
746
+ open ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_lucide_react5.ChevronDown, { className: "size-3" }) : /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_lucide_react5.ChevronRight, { className: "size-3" }),
747
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "flex-1 text-left", children: group.label })
748
+ ]
749
+ }
750
+ );
751
+ }
752
+ function TopLink({
753
+ item,
754
+ renderLink
755
+ }) {
756
+ const inner = /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
757
+ "span",
758
+ {
759
+ className: cn(
760
+ "inline-flex items-center gap-1.5 rounded-md px-2.5 py-1.5 text-[13px] font-medium transition-colors [&_svg]:size-4",
761
+ item.active ? "bg-primary/10 text-primary" : "text-muted-foreground hover:bg-muted hover:text-foreground"
762
+ ),
763
+ children: [
764
+ item.icon,
765
+ item.label,
766
+ item.external && " \u2197",
767
+ item.badge != null && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "rounded bg-danger/20 px-1.5 text-[10px] font-semibold text-danger", children: item.badge })
768
+ ]
769
+ }
770
+ );
771
+ if (item.href && item.external)
772
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("a", { href: item.href, target: "_blank", rel: "noopener noreferrer", children: inner });
773
+ if (item.href && renderLink) return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_jsx_runtime12.Fragment, { children: renderLink({ href: item.href, children: inner }) });
774
+ if (item.href) return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("a", { href: item.href, children: inner });
775
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("button", { type: "button", onClick: item.onClick, children: inner });
776
+ }
777
+ function TopDropdown({
778
+ label,
779
+ items,
780
+ renderLink
781
+ }) {
782
+ const hasBadge = items.some((i) => i.badge != null && i.badge !== 0);
783
+ const anyActive = items.some((i) => i.active);
784
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_dropdown_menu.DropdownMenu, { children: [
785
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
786
+ import_dropdown_menu.DropdownMenuTrigger,
787
+ {
788
+ className: cn(
789
+ "inline-flex items-center gap-1 rounded-md px-2.5 py-1.5 text-[13px] font-medium transition-colors hover:bg-muted hover:text-foreground",
790
+ anyActive ? "text-foreground" : "text-muted-foreground"
791
+ ),
792
+ children: [
793
+ label,
794
+ hasBadge && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "size-1.5 rounded-full bg-primary", "aria-hidden": true }),
795
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_lucide_react5.ChevronDown, { className: "size-3.5 opacity-50" })
796
+ ]
797
+ }
798
+ ),
799
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_dropdown_menu.DropdownMenuContent, { align: "start", children: items.map((item, i) => /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
800
+ import_dropdown_menu.DropdownMenuItem,
801
+ {
802
+ className: cn(item.active && "text-primary"),
803
+ onClick: item.onClick,
804
+ render: item.href ? item.external ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("a", { href: item.href, target: "_blank", rel: "noopener noreferrer" }) : /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("a", { href: item.href }) : void 0,
805
+ children: [
806
+ item.icon,
807
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("span", { className: "flex-1", children: [
808
+ item.label,
809
+ item.external && " \u2197"
810
+ ] }),
811
+ item.badge != null && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "rounded bg-danger/20 px-1.5 text-[10px] font-semibold text-danger", children: item.badge })
812
+ ]
813
+ },
814
+ i
815
+ )) })
816
+ ] });
817
+ }
818
+ function AppShell({
819
+ appName,
820
+ brandPrefix,
821
+ logo,
822
+ brandSubtitle,
823
+ brandBadge,
824
+ nav,
825
+ mobileTabs,
826
+ user,
827
+ headerActions,
828
+ sidebarFooter,
829
+ layout: layoutProp,
830
+ defaultLayout = "sidebar",
831
+ onLayoutChange,
832
+ pathname,
833
+ contained = false,
834
+ defaultCollapsed = false,
835
+ renderLink,
836
+ children,
837
+ className
838
+ }) {
839
+ const [uncontrolled, setUncontrolled] = useLayoutPreference(defaultLayout);
840
+ const layout = layoutProp ?? uncontrolled;
841
+ const setLayout = React3.useCallback(
842
+ (l) => {
843
+ onLayoutChange?.(l);
844
+ if (layoutProp === void 0) setUncontrolled(l);
845
+ },
846
+ [onLayoutChange, layoutProp, setUncontrolled]
847
+ );
848
+ const layoutCtx = React3.useMemo(() => ({ layout, setLayout }), [layout, setLayout]);
849
+ const [collapsed, setCollapsed] = React3.useState(defaultCollapsed);
850
+ const [drawer, setDrawer] = React3.useState(false);
851
+ const [open, setOpen] = React3.useState({});
852
+ const groups = React3.useMemo(() => {
853
+ const gs = toGroups(nav);
854
+ return gs.map((g) => ({ ...g, items: g.items.map((it) => withActive(it, pathname)) }));
855
+ }, [nav, pathname]);
856
+ const flat = React3.useMemo(() => allItems(groups), [groups]);
857
+ const tabs = (mobileTabs ?? flat).slice(0, 5);
858
+ const brand = /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
859
+ AppBrand,
860
+ {
861
+ appName,
862
+ prefix: brandPrefix,
863
+ logo,
864
+ subtitle: brandSubtitle,
865
+ badge: brandBadge,
866
+ renderLink
867
+ }
868
+ );
869
+ const isOpen = (g, i) => !g.collapsible || (open[g.label ?? String(i)] ?? g.defaultOpen ?? true);
870
+ const SidebarBody = ({ isCollapsed, onNavigate }) => /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "flex h-full flex-col", children: [
871
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: cn("flex h-12 items-center gap-2 border-b border-border px-3", isCollapsed && "justify-center px-0"), children: [
872
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(AppBrand, { appName, prefix: brandPrefix, logo, subtitle: brandSubtitle, collapsed: isCollapsed, renderLink, href: "/" }),
873
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
874
+ "button",
875
+ {
876
+ type: "button",
877
+ onClick: () => setCollapsed((c) => !c),
878
+ className: "ml-auto hidden rounded-md p-1 text-muted-foreground hover:bg-muted hover:text-foreground md:inline-flex",
879
+ "aria-label": "Toggle sidebar",
880
+ children: isCollapsed ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_lucide_react5.PanelLeft, { className: "size-4" }) : /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_lucide_react5.PanelLeftClose, { className: "size-4" })
881
+ }
882
+ )
883
+ ] }),
884
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("nav", { className: "flex-1 space-y-0.5 overflow-y-auto p-2", children: groups.map((g, gi) => /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: cn(gi > 0 && !g.label && "mt-1"), children: [
885
+ g.label && !isCollapsed && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
886
+ SectionHeader,
887
+ {
888
+ group: g,
889
+ open: isOpen(g, gi),
890
+ onToggle: () => setOpen((o) => ({ ...o, [g.label ?? String(gi)]: !isOpen(g, gi) }))
891
+ }
892
+ ),
893
+ isOpen(g, gi) && g.items.map((item, i) => /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(React3.Fragment, { children: [
894
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(SidebarNavRow, { item, collapsed: isCollapsed, renderLink, onNavigate }),
895
+ !isCollapsed && item.items?.map((sub, si) => /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(SidebarNavRow, { item: withActive(sub, pathname), renderLink, onNavigate, nested: true }, si))
896
+ ] }, i))
897
+ ] }, g.label ?? gi)) }),
898
+ (sidebarFooter || user) && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "border-t border-border p-2", children: [
899
+ sidebarFooter,
900
+ user && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: cn("mt-1", isCollapsed && "flex justify-center"), children: user })
901
+ ] })
902
+ ] });
903
+ const MobileDrawer = () => drawer ? /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "fixed inset-0 z-50 md:hidden", role: "dialog", "aria-modal": true, children: [
904
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "absolute inset-0 bg-black/50", onClick: () => setDrawer(false) }),
905
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "absolute inset-y-0 left-0 w-[80vw] max-w-xs border-r border-border bg-card", children: [
906
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
907
+ "button",
908
+ {
909
+ type: "button",
910
+ onClick: () => setDrawer(false),
911
+ className: "absolute right-2 top-2 rounded-md p-1.5 text-muted-foreground hover:bg-muted",
912
+ "aria-label": "Close menu",
913
+ children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_lucide_react5.X, { className: "size-4" })
914
+ }
915
+ ),
916
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(SidebarBody, { isCollapsed: false, onNavigate: () => setDrawer(false) })
917
+ ] })
918
+ ] }) : null;
919
+ const BottomTabs = () => /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
920
+ "nav",
921
+ {
922
+ className: "fixed inset-x-0 bottom-0 z-40 flex h-14 items-stretch border-t border-border bg-card md:hidden",
923
+ style: { paddingBottom: "env(safe-area-inset-bottom)" },
924
+ children: tabs.map((item, i) => {
925
+ const content = /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("span", { className: cn("flex h-full flex-1 flex-col items-center justify-center gap-0.5", item.active ? "text-primary" : "text-muted-foreground"), children: [
926
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "grid size-5 place-items-center [&_svg]:size-5", children: item.icon }),
927
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "text-[10px] font-medium leading-none", children: item.shortLabel ?? item.label })
928
+ ] });
929
+ return item.href && item.external ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("a", { href: item.href, target: "_blank", rel: "noopener noreferrer", className: "flex-1", children: content }, i) : item.href && renderLink ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(React3.Fragment, { children: renderLink({ href: item.href, className: "flex-1", children: content }) }, i) : item.href ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("a", { href: item.href, className: "flex-1", children: content }, i) : /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("button", { type: "button", className: "flex-1", onClick: item.onClick, children: content }, i);
930
+ })
931
+ }
932
+ );
933
+ const MobileTopBar = () => /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("header", { className: "flex h-12 shrink-0 items-center gap-2 border-b border-border px-3 md:hidden", children: [
934
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("button", { type: "button", onClick: () => setDrawer(true), className: "rounded-md p-1.5 text-muted-foreground hover:bg-muted", "aria-label": "Open menu", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_lucide_react5.Menu, { className: "size-5" }) }),
935
+ brand,
936
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "ml-auto flex items-center gap-1", children: headerActions })
937
+ ] });
938
+ if (layout === "top") {
939
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(LayoutContext.Provider, { value: layoutCtx, children: /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: cn("flex min-h-screen flex-col bg-background text-foreground", className), children: [
940
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("header", { className: "sticky top-0 z-40 hidden h-14 shrink-0 items-center gap-1 border-b border-border bg-card/95 px-4 backdrop-blur md:flex", children: [
941
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "shrink-0", children: brand }),
942
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("nav", { className: "ml-4 flex items-center gap-0.5", children: groups.map(
943
+ (g, gi) => g.label ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(TopDropdown, { label: g.label, items: g.items, renderLink }, gi) : g.items.map(
944
+ (item, i) => item.items ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(TopDropdown, { label: item.label, items: item.items, renderLink }, `${gi}-${i}`) : /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(TopLink, { item, renderLink }, `${gi}-${i}`)
945
+ )
946
+ ) }),
947
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "ml-auto flex items-center gap-2", children: [
948
+ headerActions,
949
+ user
950
+ ] })
951
+ ] }),
952
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(MobileTopBar, {}),
953
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(MobileDrawer, {}),
954
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("main", { className: "flex-1 overflow-y-auto pb-20 md:pb-0", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: cn(contained ? "mx-auto max-w-7xl px-4 py-6 sm:px-6 sm:py-8" : "p-4 sm:p-6"), children }) }),
955
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(BottomTabs, {})
956
+ ] }) });
957
+ }
958
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(LayoutContext.Provider, { value: layoutCtx, children: /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: cn("flex h-screen overflow-hidden bg-background text-foreground", className), children: [
959
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("aside", { className: cn("hidden shrink-0 border-r border-border transition-[width] duration-200 md:block", collapsed ? railW : openW), children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(SidebarBody, { isCollapsed: collapsed }) }),
960
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(MobileDrawer, {}),
961
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "flex min-w-0 flex-1 flex-col", children: [
962
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(MobileTopBar, {}),
963
+ headerActions && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("header", { className: "hidden h-12 shrink-0 items-center border-b border-border px-4 md:flex", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "ml-auto flex items-center gap-2", children: headerActions }) }),
964
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("main", { className: "flex-1 overflow-y-auto pb-20 md:pb-0", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: cn(contained ? "mx-auto max-w-7xl px-4 py-6 sm:px-6 sm:py-8" : "p-4 sm:p-6"), children }) }),
965
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(BottomTabs, {})
966
+ ] })
967
+ ] }) });
968
+ }
969
+
970
+ // src/sub-tabs/index.tsx
971
+ var import_jsx_runtime13 = require("react/jsx-runtime");
972
+ function SubTabs({
973
+ items,
974
+ value,
975
+ onChange,
976
+ className,
977
+ "aria-label": ariaLabel
978
+ }) {
979
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
980
+ "div",
981
+ {
982
+ role: "tablist",
983
+ "aria-label": ariaLabel,
984
+ className: cn("inline-flex rounded-lg border border-border bg-card p-0.5", className),
985
+ children: items.map((it) => {
986
+ const selected = value === it.id;
987
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
988
+ "button",
989
+ {
990
+ type: "button",
991
+ role: "tab",
992
+ "aria-selected": selected,
993
+ onClick: () => onChange(it.id),
994
+ className: cn(
995
+ "inline-flex items-center gap-1.5 rounded-md px-3 py-1.5 text-sm transition-colors [&_svg]:size-4",
996
+ selected ? "bg-primary/10 text-primary" : "text-muted-foreground hover:text-foreground"
997
+ ),
998
+ children: [
999
+ it.icon,
1000
+ it.label
1001
+ ]
1002
+ },
1003
+ it.id
1004
+ );
1005
+ })
1006
+ }
1007
+ );
1008
+ }
1009
+
1010
+ // src/page-header-banner/index.tsx
1011
+ var import_jsx_runtime14 = require("react/jsx-runtime");
1012
+ function PageHeaderBanner({
1013
+ title,
1014
+ subtitle,
1015
+ actions,
1016
+ gradient = true,
1017
+ icon,
1018
+ className
1019
+ }) {
1020
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
1021
+ "div",
1022
+ {
1023
+ className: cn(
1024
+ "mb-6 flex flex-col gap-4 rounded-xl border border-border p-6 sm:mb-8 sm:flex-row sm:items-center sm:p-8",
1025
+ className
1026
+ ),
1027
+ style: gradient ? {
1028
+ background: "linear-gradient(135deg, color-mix(in srgb, var(--primary) 10%, transparent), color-mix(in srgb, var(--accent) 5%, transparent))"
1029
+ } : { background: "var(--card)" },
1030
+ children: [
1031
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "flex min-w-0 items-center gap-4", children: [
1032
+ icon && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "grid size-12 shrink-0 place-items-center rounded-xl bg-primary/15 text-primary [&_svg]:size-6", children: icon }),
1033
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "min-w-0", children: [
1034
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("h1", { className: "font-heading text-2xl font-bold tracking-tight text-foreground sm:text-3xl", children: title }),
1035
+ subtitle && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("p", { className: "mt-1 text-sm text-muted-foreground", children: subtitle })
1036
+ ] })
1037
+ ] }),
1038
+ actions && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "flex shrink-0 items-center gap-2 sm:ml-auto", children: actions })
1039
+ ]
1040
+ }
1041
+ );
1042
+ }
1043
+
1044
+ // src/glass-panel/index.tsx
1045
+ var import_jsx_runtime15 = require("react/jsx-runtime");
1046
+ function GlassPanel({ strong, glow, className, style, ...props }) {
1047
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
1048
+ "div",
1049
+ {
1050
+ className: cn("rounded-2xl border", className),
1051
+ style: {
1052
+ background: strong ? "var(--glass-bg-strong, rgba(255,255,255,0.08))" : "var(--glass-bg, rgba(255,255,255,0.04))",
1053
+ borderColor: "var(--glass-border, var(--border))",
1054
+ backdropFilter: "var(--glass-blur, blur(20px))",
1055
+ WebkitBackdropFilter: "var(--glass-blur, blur(20px))",
1056
+ boxShadow: glow ? "var(--shadow-glow)" : "var(--shadow-elevated, 0 8px 32px rgba(0,0,0,0.2))",
1057
+ ...style
1058
+ },
1059
+ ...props
1060
+ }
1061
+ );
1062
+ }
1063
+
1064
+ // src/brand-frame/index.tsx
1065
+ var import_jsx_runtime16 = require("react/jsx-runtime");
1066
+ var POS = {
1067
+ "top-right": "top-4 right-4",
1068
+ "bottom-right": "bottom-4 right-4",
1069
+ center: "inset-0 flex items-center justify-center"
1070
+ };
1071
+ function BrandFrame({
1072
+ watermark,
1073
+ watermarkPosition = "top-right",
1074
+ watermarkOpacity = 0.06,
1075
+ glow = false,
1076
+ glass = false,
1077
+ animated = false,
1078
+ header,
1079
+ backdrop,
1080
+ className,
1081
+ children,
1082
+ style,
1083
+ ...props
1084
+ }) {
1085
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
1086
+ "div",
1087
+ {
1088
+ className: cn(
1089
+ "relative overflow-hidden rounded-2xl border border-border",
1090
+ glass ? "backdrop-blur-xl" : "bg-card",
1091
+ className
1092
+ ),
1093
+ style: {
1094
+ ...glass ? { background: "var(--glass-bg, color-mix(in srgb, var(--card) 70%, transparent))" } : null,
1095
+ ...glow ? { boxShadow: "var(--shadow-glow, 0 4px 24px color-mix(in srgb, var(--primary) 28%, transparent))" } : null,
1096
+ ...style
1097
+ },
1098
+ ...props,
1099
+ children: [
1100
+ animated && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
1101
+ "span",
1102
+ {
1103
+ "aria-hidden": true,
1104
+ "data-wmm-fx": true,
1105
+ className: "pointer-events-none absolute inset-x-0 top-0 h-px",
1106
+ style: {
1107
+ background: "var(--gradient-primary, linear-gradient(90deg, var(--primary), var(--accent)))",
1108
+ backgroundSize: "200% 100%",
1109
+ animation: "wmm-shimmer 3s linear infinite"
1110
+ }
1111
+ }
1112
+ ),
1113
+ backdrop && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { className: "pointer-events-none absolute inset-0", children: backdrop }),
1114
+ watermark && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
1115
+ "div",
1116
+ {
1117
+ "aria-hidden": true,
1118
+ className: cn("pointer-events-none absolute", POS[watermarkPosition]),
1119
+ style: { opacity: watermarkOpacity },
1120
+ children: watermark
1121
+ }
1122
+ ),
1123
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "relative", children: [
1124
+ header && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { className: "flex items-center justify-between gap-3 border-b border-border px-5 py-3", children: header }),
1125
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { className: "p-5", children })
1126
+ ] })
1127
+ ]
1128
+ }
1129
+ );
1130
+ }
1131
+
1132
+ // src/use-action-runner.ts
1133
+ var React4 = __toESM(require("react"));
1134
+ var import_toast = require("@web-my-money/primitives/toast");
1135
+ function useActionRunner() {
1136
+ const toast = (0, import_toast.useToast)();
1137
+ const [pending, setPending] = React4.useState(false);
1138
+ const run = React4.useCallback(
1139
+ async (action, options = {}) => {
1140
+ setPending(true);
1141
+ try {
1142
+ const result = await action();
1143
+ if (result.ok) {
1144
+ if (options.successMessage) {
1145
+ const title = typeof options.successMessage === "function" ? options.successMessage(result.data) : options.successMessage;
1146
+ toast.add({
1147
+ title,
1148
+ actionProps: options.undo ? {
1149
+ children: options.undo.label ?? "Undo",
1150
+ onClick: () => {
1151
+ void options.undo.action();
1152
+ }
1153
+ } : void 0
1154
+ });
1155
+ }
1156
+ options.onSuccess?.(result.data);
1157
+ } else {
1158
+ const title = typeof options.errorMessage === "function" ? options.errorMessage(result.error) : options.errorMessage ?? result.error;
1159
+ toast.add({ title, type: "error" });
1160
+ options.onError?.(result.error);
1161
+ }
1162
+ return result;
1163
+ } finally {
1164
+ setPending(false);
1165
+ options.onSettled?.();
1166
+ }
1167
+ },
1168
+ [toast]
1169
+ );
1170
+ return { run, pending };
1171
+ }
1172
+
1173
+ // src/use-optimistic-action.ts
1174
+ var React5 = __toESM(require("react"));
1175
+ function useOptimisticAction(state, reducer) {
1176
+ const [optimisticState, setOptimistic] = React5.useOptimistic(state, reducer);
1177
+ const [isPending, startTransition] = React5.useTransition();
1178
+ const apply = React5.useCallback(
1179
+ (optimisticValue, action, onResult) => {
1180
+ startTransition(async () => {
1181
+ setOptimistic(optimisticValue);
1182
+ const result = await action();
1183
+ onResult?.(result);
1184
+ });
1185
+ },
1186
+ [setOptimistic]
1187
+ );
1188
+ return [optimisticState, apply, isPending];
1189
+ }
1190
+
1191
+ // src/lightbox/index.tsx
1192
+ var React6 = __toESM(require("react"));
1193
+ var import_lightbox = require("@web-my-money/primitives/lightbox");
1194
+ var import_jsx_runtime17 = require("react/jsx-runtime");
1195
+ function Thumbnail({ image, onClick, className }) {
1196
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
1197
+ "button",
1198
+ {
1199
+ type: "button",
1200
+ "data-slot": "thumbnail",
1201
+ onClick,
1202
+ className: cn(
1203
+ "group relative aspect-square overflow-hidden rounded-lg border border-border outline-none focus-visible:ring-3 focus-visible:ring-ring/50",
1204
+ className
1205
+ ),
1206
+ children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
1207
+ "img",
1208
+ {
1209
+ src: image.thumbnailSrc ?? image.src,
1210
+ alt: image.alt ?? "",
1211
+ className: "size-full object-cover transition-transform duration-200 group-hover:scale-105",
1212
+ loading: "lazy"
1213
+ }
1214
+ )
1215
+ }
1216
+ );
1217
+ }
1218
+ function LightboxGallery({ images, className, gridClassName }) {
1219
+ const [openIndex, setOpenIndex] = React6.useState(null);
1220
+ const hasImages = images.length > 0;
1221
+ const active = openIndex !== null ? images[openIndex] : null;
1222
+ const goTo = (dir) => {
1223
+ setOpenIndex((i) => {
1224
+ if (i === null) return i;
1225
+ return (i + dir + images.length) % images.length;
1226
+ });
1227
+ };
1228
+ if (!hasImages) return null;
1229
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { "data-slot": "lightbox-gallery", className, children: [
1230
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: cn("grid grid-cols-2 gap-3 sm:grid-cols-3 md:grid-cols-4", gridClassName), children: images.map((image, i) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Thumbnail, { image, onClick: () => setOpenIndex(i) }, image.src)) }),
1231
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_lightbox.Lightbox, { open: openIndex !== null, onOpenChange: (open) => !open && setOpenIndex(null), children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_lightbox.LightboxContent, { children: active && /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(import_jsx_runtime17.Fragment, { children: [
1232
+ images.length > 1 && /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(import_jsx_runtime17.Fragment, { children: [
1233
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_lightbox.LightboxNavButton, { direction: "prev", onClick: () => goTo(-1) }),
1234
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_lightbox.LightboxNavButton, { direction: "next", onClick: () => goTo(1) })
1235
+ ] }),
1236
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_lightbox.LightboxImage, { src: active.src, alt: active.alt ?? "" }),
1237
+ active.caption && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_lightbox.LightboxCaption, { children: active.caption }),
1238
+ images.length > 1 && /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("p", { className: "text-xs text-white/60", "aria-live": "polite", children: [
1239
+ (openIndex ?? 0) + 1,
1240
+ " / ",
1241
+ images.length
1242
+ ] })
1243
+ ] }) }) })
1244
+ ] });
1245
+ }
1246
+
1247
+ // src/appearance-settings/index.tsx
1248
+ var import_react = require("@web-my-money/tokens/react");
1249
+ var import_jsx_runtime18 = require("react/jsx-runtime");
1250
+ function AppearanceSettings({ className }) {
1251
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: cn("space-y-6", className), "data-slot": "appearance-settings", children: [
1252
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "flex items-center justify-between gap-4", "data-slot": "appearance-settings-row", children: [
1253
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { children: [
1254
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: "text-sm font-medium text-foreground", children: "Theme" }),
1255
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: "text-xs text-muted-foreground", children: "Light, dark, or the WMM brand theme." })
1256
+ ] }),
1257
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_react.ThemeToggle, {})
1258
+ ] }),
1259
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "flex items-center justify-between gap-4", "data-slot": "appearance-settings-row", children: [
1260
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { children: [
1261
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: "text-sm font-medium text-foreground", children: "Text size" }),
1262
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: "text-xs text-muted-foreground", children: "Scales the whole interface." })
1263
+ ] }),
1264
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_react.FontSizeToggle, {})
1265
+ ] })
1266
+ ] });
1267
+ }
1268
+ // Annotate the CommonJS export names for ESM import in node:
1269
+ 0 && (module.exports = {
1270
+ ActivityFeed,
1271
+ AppBrand,
1272
+ AppShell,
1273
+ AppearanceSettings,
1274
+ BrandFrame,
1275
+ DashboardHeader,
1276
+ DataSummaryCards,
1277
+ DataTable,
1278
+ EmptyState,
1279
+ GlassPanel,
1280
+ KPIRow,
1281
+ LayoutToggle,
1282
+ LightboxGallery,
1283
+ NotificationBanner,
1284
+ PageHeader,
1285
+ PageHeaderBanner,
1286
+ SidebarNavigation,
1287
+ StatCard,
1288
+ SubTabs,
1289
+ Thumbnail,
1290
+ useActionRunner,
1291
+ useLayoutPreference,
1292
+ useOptimisticAction
1293
+ });