@pattern-stack/frontend-patterns 0.2.0-alpha.8 → 0.2.0-alpha.9
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/atoms/components/core/Badge/Badge.d.ts +1 -1
- package/dist/atoms/components/data/DataTable/DataTable.d.ts +2 -2
- package/dist/atoms/components/data/DataTable/DataTable.d.ts.map +1 -1
- package/dist/atoms/components/data/DataTable/DataTable.types.d.ts +40 -2
- package/dist/atoms/components/data/DataTable/DataTable.types.d.ts.map +1 -1
- package/dist/atoms/hooks/index.d.ts +1 -0
- package/dist/atoms/hooks/index.d.ts.map +1 -1
- package/dist/atoms/hooks/useAdaptiveTable.d.ts +49 -0
- package/dist/atoms/hooks/useAdaptiveTable.d.ts.map +1 -0
- package/dist/atoms/hooks/useApi.d.ts +1 -1
- package/dist/atoms/hooks/useApi.d.ts.map +1 -1
- package/dist/atoms/hooks/useResponsiveTable.d.ts +44 -24
- package/dist/atoms/hooks/useResponsiveTable.d.ts.map +1 -1
- package/dist/atoms/shared/config/table-config.d.ts +79 -0
- package/dist/atoms/shared/config/table-config.d.ts.map +1 -0
- package/dist/atoms/shared/index.d.ts +1 -0
- package/dist/atoms/shared/index.d.ts.map +1 -1
- package/dist/atoms/utils/entity-card-mapping.d.ts +1 -1
- package/dist/atoms/utils/entity-card-mapping.d.ts.map +1 -1
- package/dist/atoms/utils/index.d.ts +1 -0
- package/dist/atoms/utils/index.d.ts.map +1 -1
- package/dist/index.es.js +917 -179
- package/dist/index.es.js.map +1 -1
- package/dist/index.js +915 -177
- package/dist/index.js.map +1 -1
- package/dist/molecules/layout/navigation-context.d.ts.map +1 -1
- package/dist/templates/factory.d.ts +11 -0
- package/dist/templates/factory.d.ts.map +1 -1
- package/package.json +5 -3
package/dist/index.js
CHANGED
|
@@ -179,6 +179,141 @@ const RESPONSIVE_CHART_HEIGHTS = {
|
|
|
179
179
|
secondary: DASHBOARD_CHART_HEIGHTS.medium
|
|
180
180
|
}
|
|
181
181
|
};
|
|
182
|
+
const COLUMN_WIDTHS = {
|
|
183
|
+
// Text
|
|
184
|
+
text: 180,
|
|
185
|
+
password: 120,
|
|
186
|
+
// Numbers
|
|
187
|
+
number: 80,
|
|
188
|
+
money: 100,
|
|
189
|
+
percent: 70,
|
|
190
|
+
// Dates
|
|
191
|
+
date: 100,
|
|
192
|
+
datetime: 140,
|
|
193
|
+
// Contact/Links
|
|
194
|
+
email: 180,
|
|
195
|
+
phone: 120,
|
|
196
|
+
url: 160,
|
|
197
|
+
// Visual indicators
|
|
198
|
+
status: 90,
|
|
199
|
+
badge: 90,
|
|
200
|
+
boolean: 60,
|
|
201
|
+
rating: 80,
|
|
202
|
+
color: 60,
|
|
203
|
+
// Entity references
|
|
204
|
+
entity: 140,
|
|
205
|
+
user: 140,
|
|
206
|
+
// Special
|
|
207
|
+
image: 60,
|
|
208
|
+
file: 100,
|
|
209
|
+
json: 200
|
|
210
|
+
};
|
|
211
|
+
const COMPACT_COLUMN_WIDTHS = {
|
|
212
|
+
text: 120,
|
|
213
|
+
// With truncation
|
|
214
|
+
money: 60,
|
|
215
|
+
// $2.5k format
|
|
216
|
+
date: 55,
|
|
217
|
+
// "Dec 5" or "Tu"
|
|
218
|
+
datetime: 65,
|
|
219
|
+
// "5m ago"
|
|
220
|
+
email: 100,
|
|
221
|
+
// Truncated
|
|
222
|
+
phone: 80,
|
|
223
|
+
url: 80,
|
|
224
|
+
entity: 100,
|
|
225
|
+
user: 80,
|
|
226
|
+
json: 80
|
|
227
|
+
};
|
|
228
|
+
const COMPACT_FORMATTERS = {
|
|
229
|
+
money: "compactCurrency",
|
|
230
|
+
// $2,456.99 → $2.5k
|
|
231
|
+
date: "shortDate",
|
|
232
|
+
// 2024-01-15 → Dec 5
|
|
233
|
+
datetime: "relative",
|
|
234
|
+
// 2024-01-15T10:30 → 5m ago
|
|
235
|
+
text: "truncate",
|
|
236
|
+
// Long customer name → Long cust...
|
|
237
|
+
email: "truncate",
|
|
238
|
+
url: "domain",
|
|
239
|
+
// https://example.com/path → example.com
|
|
240
|
+
number: "compact"
|
|
241
|
+
// 1234567 → 1.2M
|
|
242
|
+
};
|
|
243
|
+
const COMPACT_LABELS = {
|
|
244
|
+
// Common field names → short versions
|
|
245
|
+
customer: "Cust",
|
|
246
|
+
description: "Desc",
|
|
247
|
+
quantity: "Qty",
|
|
248
|
+
amount: "Amt",
|
|
249
|
+
total: "Tot",
|
|
250
|
+
priority: "Pri",
|
|
251
|
+
status: "Stat",
|
|
252
|
+
created_at: "Created",
|
|
253
|
+
updated_at: "Updated",
|
|
254
|
+
email: "Email",
|
|
255
|
+
phone: "Ph",
|
|
256
|
+
category: "Cat",
|
|
257
|
+
// Time fields
|
|
258
|
+
time: "Time",
|
|
259
|
+
timeAgo: "Time",
|
|
260
|
+
timestamp: "Time",
|
|
261
|
+
// ID fields
|
|
262
|
+
order_id: "#",
|
|
263
|
+
id: "#",
|
|
264
|
+
transaction_id: "Txn"
|
|
265
|
+
};
|
|
266
|
+
const TABLE_BREAKPOINTS = {
|
|
267
|
+
/** Below this width (px), always use cards */
|
|
268
|
+
minForTable: 400,
|
|
269
|
+
/** Buffer (px) to add when calculating if columns fit */
|
|
270
|
+
widthBuffer: 50,
|
|
271
|
+
/** Minimum columns to show in compact mode */
|
|
272
|
+
minCompactColumns: 3,
|
|
273
|
+
/** Maximum columns in compact mode */
|
|
274
|
+
maxCompactColumns: 6
|
|
275
|
+
};
|
|
276
|
+
const IMPORTANCE_VISIBILITY = {
|
|
277
|
+
full: ["primary", "secondary", "tertiary", "critical", "high", "medium", "low", "minimal"],
|
|
278
|
+
compact: ["primary", "secondary", "critical", "high", "medium"],
|
|
279
|
+
cards: ["primary", "critical", "high"]
|
|
280
|
+
};
|
|
281
|
+
function getColumnWidth(type, mode = "full") {
|
|
282
|
+
if (mode === "compact" && type in COMPACT_COLUMN_WIDTHS) {
|
|
283
|
+
return COMPACT_COLUMN_WIDTHS[type];
|
|
284
|
+
}
|
|
285
|
+
return COLUMN_WIDTHS[type] ?? COLUMN_WIDTHS.text;
|
|
286
|
+
}
|
|
287
|
+
function calculateTableWidth(columns, mode = "full") {
|
|
288
|
+
return columns.reduce((sum, col) => sum + getColumnWidth(col.type, mode), 0);
|
|
289
|
+
}
|
|
290
|
+
function getCompactLabel(fieldName, originalLabel) {
|
|
291
|
+
const normalized = fieldName.toLowerCase();
|
|
292
|
+
return COMPACT_LABELS[normalized] ?? originalLabel;
|
|
293
|
+
}
|
|
294
|
+
function getCompactFormatter(type) {
|
|
295
|
+
return COMPACT_FORMATTERS[type];
|
|
296
|
+
}
|
|
297
|
+
function determineTableMode(containerWidth, columns) {
|
|
298
|
+
const { minForTable, widthBuffer } = TABLE_BREAKPOINTS;
|
|
299
|
+
if (containerWidth < minForTable) {
|
|
300
|
+
return "cards";
|
|
301
|
+
}
|
|
302
|
+
const fullWidth = calculateTableWidth(columns, "full");
|
|
303
|
+
const compactColumns = columns.filter(
|
|
304
|
+
(col) => IMPORTANCE_VISIBILITY.compact.includes(
|
|
305
|
+
col.importance ?? "medium"
|
|
306
|
+
)
|
|
307
|
+
);
|
|
308
|
+
const compactWidth = calculateTableWidth(compactColumns, "compact");
|
|
309
|
+
if (fullWidth + widthBuffer <= containerWidth) {
|
|
310
|
+
return "full";
|
|
311
|
+
}
|
|
312
|
+
if (compactWidth + widthBuffer <= containerWidth) {
|
|
313
|
+
return "compact";
|
|
314
|
+
}
|
|
315
|
+
return "cards";
|
|
316
|
+
}
|
|
182
317
|
const breakpoints = {
|
|
183
318
|
"2xs": 400,
|
|
184
319
|
xs: 500,
|
|
@@ -2052,6 +2187,498 @@ function renderField(value, fieldName, fieldType, breakpoint, item, customRender
|
|
|
2052
2187
|
function cn(...inputs) {
|
|
2053
2188
|
return tailwindMerge.twMerge(clsx.clsx(inputs));
|
|
2054
2189
|
}
|
|
2190
|
+
const IconBadge = ({
|
|
2191
|
+
children,
|
|
2192
|
+
icon,
|
|
2193
|
+
variant = "category",
|
|
2194
|
+
category = 1,
|
|
2195
|
+
status = "neutral",
|
|
2196
|
+
size = "md",
|
|
2197
|
+
interactive = false,
|
|
2198
|
+
onClick,
|
|
2199
|
+
className,
|
|
2200
|
+
tooltip
|
|
2201
|
+
}) => {
|
|
2202
|
+
const currentSize = useResponsiveValue(size);
|
|
2203
|
+
const sizeConfig = responsiveScales.components.iconBadge[currentSize];
|
|
2204
|
+
const sizeClasses2 = {
|
|
2205
|
+
xs: `${(sizeConfig == null ? void 0 : sizeConfig.size) || "w-6 h-6"} ${(sizeConfig == null ? void 0 : sizeConfig.text) || "text-[10px]"} ${(sizeConfig == null ? void 0 : sizeConfig.rounded) || "rounded-md"}`,
|
|
2206
|
+
sm: "w-8 h-8 text-xs rounded-lg",
|
|
2207
|
+
md: "w-10 h-10 text-sm rounded-xl",
|
|
2208
|
+
lg: "w-12 h-12 text-base rounded-xl"
|
|
2209
|
+
};
|
|
2210
|
+
const baseClasses = cn(
|
|
2211
|
+
"inline-flex items-center justify-center font-bold shadow-md",
|
|
2212
|
+
sizeClasses2[currentSize],
|
|
2213
|
+
interactive && [
|
|
2214
|
+
"cursor-pointer",
|
|
2215
|
+
getAnimationClasses({
|
|
2216
|
+
...animationPresets.dataBadge,
|
|
2217
|
+
size: currentSize === "lg" ? "lg" : currentSize === "sm" || currentSize === "xs" ? "sm" : "md"
|
|
2218
|
+
})
|
|
2219
|
+
],
|
|
2220
|
+
className
|
|
2221
|
+
);
|
|
2222
|
+
const gradientClasses = variant === "category" ? `bg-gradient-to-br from-category-${category} to-category-${Math.min(category + 1, 8)}` : variant === "status" ? `bg-gradient-to-br from-status-${status} to-status-${status}` : "bg-gradient-to-br from-category-1 to-category-2";
|
|
2223
|
+
const badge = /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2224
|
+
"div",
|
|
2225
|
+
{
|
|
2226
|
+
className: cn(baseClasses, gradientClasses, "animate-fade-in"),
|
|
2227
|
+
onClick,
|
|
2228
|
+
role: interactive ? "button" : void 0,
|
|
2229
|
+
tabIndex: interactive ? 0 : void 0,
|
|
2230
|
+
onKeyDown: interactive ? (e) => {
|
|
2231
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
2232
|
+
e.preventDefault();
|
|
2233
|
+
onClick == null ? void 0 : onClick();
|
|
2234
|
+
}
|
|
2235
|
+
} : void 0,
|
|
2236
|
+
"data-component-name": "IconBadge",
|
|
2237
|
+
children: [
|
|
2238
|
+
icon && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-primary-foreground drop-shadow", children: icon }),
|
|
2239
|
+
children && !icon && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-primary-foreground font-bold", children })
|
|
2240
|
+
]
|
|
2241
|
+
}
|
|
2242
|
+
);
|
|
2243
|
+
if (tooltip) {
|
|
2244
|
+
return /* @__PURE__ */ jsxRuntime.jsx(Tooltip, { content: tooltip, position: "top", size: "sm", children: badge });
|
|
2245
|
+
}
|
|
2246
|
+
return badge;
|
|
2247
|
+
};
|
|
2248
|
+
const valueColorMap = {
|
|
2249
|
+
success: "text-green-600",
|
|
2250
|
+
error: "text-red-600",
|
|
2251
|
+
warning: "text-yellow-600",
|
|
2252
|
+
info: "text-blue-600",
|
|
2253
|
+
neutral: "text-muted-foreground",
|
|
2254
|
+
default: "text-foreground"
|
|
2255
|
+
};
|
|
2256
|
+
function ListCard({
|
|
2257
|
+
icon,
|
|
2258
|
+
title,
|
|
2259
|
+
subtitle,
|
|
2260
|
+
metadata,
|
|
2261
|
+
value,
|
|
2262
|
+
badge,
|
|
2263
|
+
onClick,
|
|
2264
|
+
className,
|
|
2265
|
+
children
|
|
2266
|
+
}) {
|
|
2267
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2268
|
+
"div",
|
|
2269
|
+
{
|
|
2270
|
+
className: cn(
|
|
2271
|
+
"flex items-start gap-3 p-3 rounded-lg border border-border transition-colors",
|
|
2272
|
+
onClick && "hover:bg-muted/50 cursor-pointer",
|
|
2273
|
+
className
|
|
2274
|
+
),
|
|
2275
|
+
onClick,
|
|
2276
|
+
children: [
|
|
2277
|
+
icon && /* @__PURE__ */ jsxRuntime.jsx(
|
|
2278
|
+
IconBadge,
|
|
2279
|
+
{
|
|
2280
|
+
variant: icon.variant || "category",
|
|
2281
|
+
category: icon.variant === "category" ? icon.category || 1 : void 0,
|
|
2282
|
+
status: icon.variant === "status" ? icon.status || "neutral" : void 0,
|
|
2283
|
+
size: icon.size || "sm",
|
|
2284
|
+
icon: icon.icon,
|
|
2285
|
+
tooltip: icon.tooltip
|
|
2286
|
+
}
|
|
2287
|
+
),
|
|
2288
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 min-w-0", children: [
|
|
2289
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start justify-between gap-2", children: [
|
|
2290
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1", children: [
|
|
2291
|
+
/* @__PURE__ */ jsxRuntime.jsx("h4", { className: "text-sm font-medium text-foreground truncate", children: title }),
|
|
2292
|
+
subtitle && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground mt-0.5", children: subtitle }),
|
|
2293
|
+
metadata && metadata.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center gap-3 mt-1", children: metadata.map((item, index) => /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-muted-foreground", children: item }, index)) })
|
|
2294
|
+
] }),
|
|
2295
|
+
(value || badge) && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-right", children: [
|
|
2296
|
+
value && /* @__PURE__ */ jsxRuntime.jsx(
|
|
2297
|
+
"p",
|
|
2298
|
+
{
|
|
2299
|
+
className: cn(
|
|
2300
|
+
"text-sm font-semibold",
|
|
2301
|
+
value.variant && valueColorMap[value.variant],
|
|
2302
|
+
value.className
|
|
2303
|
+
),
|
|
2304
|
+
children: value.text
|
|
2305
|
+
}
|
|
2306
|
+
),
|
|
2307
|
+
badge && /* @__PURE__ */ jsxRuntime.jsx(
|
|
2308
|
+
DataBadge,
|
|
2309
|
+
{
|
|
2310
|
+
variant: badge.variant,
|
|
2311
|
+
status: badge.variant === "status" ? badge.status : void 0,
|
|
2312
|
+
category: badge.variant === "category" ? badge.category : void 0,
|
|
2313
|
+
size: badge.size || "sm",
|
|
2314
|
+
icon: badge.icon,
|
|
2315
|
+
className: "mt-1",
|
|
2316
|
+
children: badge.text
|
|
2317
|
+
}
|
|
2318
|
+
)
|
|
2319
|
+
] })
|
|
2320
|
+
] }),
|
|
2321
|
+
children
|
|
2322
|
+
] })
|
|
2323
|
+
]
|
|
2324
|
+
}
|
|
2325
|
+
);
|
|
2326
|
+
}
|
|
2327
|
+
const STATUS_COLOR_MAP = {
|
|
2328
|
+
// Success states
|
|
2329
|
+
active: "success",
|
|
2330
|
+
completed: "success",
|
|
2331
|
+
approved: "success",
|
|
2332
|
+
paid: "success",
|
|
2333
|
+
delivered: "success",
|
|
2334
|
+
resolved: "success",
|
|
2335
|
+
closed: "success",
|
|
2336
|
+
// Warning states
|
|
2337
|
+
pending: "warning",
|
|
2338
|
+
processing: "warning",
|
|
2339
|
+
review: "warning",
|
|
2340
|
+
draft: "warning",
|
|
2341
|
+
waiting: "warning",
|
|
2342
|
+
// Error states
|
|
2343
|
+
failed: "error",
|
|
2344
|
+
rejected: "error",
|
|
2345
|
+
cancelled: "error",
|
|
2346
|
+
overdue: "error",
|
|
2347
|
+
blocked: "error",
|
|
2348
|
+
// Info states
|
|
2349
|
+
new: "info",
|
|
2350
|
+
open: "info",
|
|
2351
|
+
in_progress: "info",
|
|
2352
|
+
scheduled: "info",
|
|
2353
|
+
// Neutral (default)
|
|
2354
|
+
inactive: "neutral",
|
|
2355
|
+
archived: "neutral",
|
|
2356
|
+
unknown: "neutral"
|
|
2357
|
+
};
|
|
2358
|
+
function getStatusColor(value) {
|
|
2359
|
+
if (typeof value !== "string") return "neutral";
|
|
2360
|
+
const normalized = value.toLowerCase().replace(/[_-]/g, "_");
|
|
2361
|
+
return STATUS_COLOR_MAP[normalized] ?? "neutral";
|
|
2362
|
+
}
|
|
2363
|
+
const CATEGORY_MAP = {
|
|
2364
|
+
account: 1,
|
|
2365
|
+
customer: 1,
|
|
2366
|
+
client: 1,
|
|
2367
|
+
user: 2,
|
|
2368
|
+
contact: 2,
|
|
2369
|
+
person: 2,
|
|
2370
|
+
order: 3,
|
|
2371
|
+
sale: 3,
|
|
2372
|
+
transaction: 3,
|
|
2373
|
+
product: 4,
|
|
2374
|
+
item: 4,
|
|
2375
|
+
inventory: 4,
|
|
2376
|
+
task: 5,
|
|
2377
|
+
activity: 5,
|
|
2378
|
+
event: 5,
|
|
2379
|
+
file: 6,
|
|
2380
|
+
document: 6,
|
|
2381
|
+
report: 6,
|
|
2382
|
+
tag: 7,
|
|
2383
|
+
category: 7,
|
|
2384
|
+
label: 7,
|
|
2385
|
+
default: 8
|
|
2386
|
+
};
|
|
2387
|
+
function getCategoryForEntity(entityType) {
|
|
2388
|
+
if (!entityType) return 8;
|
|
2389
|
+
const normalized = entityType.toLowerCase();
|
|
2390
|
+
for (const [key, value] of Object.entries(CATEGORY_MAP)) {
|
|
2391
|
+
if (normalized.includes(key)) return value;
|
|
2392
|
+
}
|
|
2393
|
+
return 8;
|
|
2394
|
+
}
|
|
2395
|
+
function getIconForEntity(entityType) {
|
|
2396
|
+
if (!entityType) return /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Circle, { className: "w-4 h-4" });
|
|
2397
|
+
const normalized = entityType.toLowerCase();
|
|
2398
|
+
if (normalized.includes("account") || normalized.includes("customer") || normalized.includes("client")) {
|
|
2399
|
+
return /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Building2, { className: "w-4 h-4" });
|
|
2400
|
+
}
|
|
2401
|
+
if (normalized.includes("user") || normalized.includes("contact") || normalized.includes("person")) {
|
|
2402
|
+
return /* @__PURE__ */ jsxRuntime.jsx(lucideReact.User, { className: "w-4 h-4" });
|
|
2403
|
+
}
|
|
2404
|
+
if (normalized.includes("product") || normalized.includes("item")) {
|
|
2405
|
+
return /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Package, { className: "w-4 h-4" });
|
|
2406
|
+
}
|
|
2407
|
+
if (normalized.includes("file") || normalized.includes("document")) {
|
|
2408
|
+
return /* @__PURE__ */ jsxRuntime.jsx(lucideReact.FileText, { className: "w-4 h-4" });
|
|
2409
|
+
}
|
|
2410
|
+
if (normalized.includes("tag") || normalized.includes("category")) {
|
|
2411
|
+
return /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Tag, { className: "w-4 h-4" });
|
|
2412
|
+
}
|
|
2413
|
+
return /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Circle, { className: "w-4 h-4" });
|
|
2414
|
+
}
|
|
2415
|
+
function normalizeImportance(importance) {
|
|
2416
|
+
switch (importance) {
|
|
2417
|
+
case "critical":
|
|
2418
|
+
case "high":
|
|
2419
|
+
case "primary":
|
|
2420
|
+
return "primary";
|
|
2421
|
+
case "medium":
|
|
2422
|
+
case "secondary":
|
|
2423
|
+
return "secondary";
|
|
2424
|
+
default:
|
|
2425
|
+
return "tertiary";
|
|
2426
|
+
}
|
|
2427
|
+
}
|
|
2428
|
+
function isPrimaryImportance(importance) {
|
|
2429
|
+
return normalizeImportance(importance) === "primary";
|
|
2430
|
+
}
|
|
2431
|
+
function formatValueForCard(value, type, format) {
|
|
2432
|
+
if (value === null || value === void 0) return "—";
|
|
2433
|
+
switch (type) {
|
|
2434
|
+
case "money": {
|
|
2435
|
+
const num = Number(value);
|
|
2436
|
+
const currency = (format == null ? void 0 : format.currency) ?? "USD";
|
|
2437
|
+
if (num >= 1e6) {
|
|
2438
|
+
return new Intl.NumberFormat("en-US", {
|
|
2439
|
+
style: "currency",
|
|
2440
|
+
currency,
|
|
2441
|
+
notation: "compact",
|
|
2442
|
+
maximumFractionDigits: 1
|
|
2443
|
+
}).format(num);
|
|
2444
|
+
}
|
|
2445
|
+
if (num >= 1e3) {
|
|
2446
|
+
return new Intl.NumberFormat("en-US", {
|
|
2447
|
+
style: "currency",
|
|
2448
|
+
currency,
|
|
2449
|
+
notation: "compact",
|
|
2450
|
+
maximumFractionDigits: 1
|
|
2451
|
+
}).format(num);
|
|
2452
|
+
}
|
|
2453
|
+
return new Intl.NumberFormat("en-US", {
|
|
2454
|
+
style: "currency",
|
|
2455
|
+
currency,
|
|
2456
|
+
maximumFractionDigits: 0
|
|
2457
|
+
}).format(num);
|
|
2458
|
+
}
|
|
2459
|
+
case "percent": {
|
|
2460
|
+
const num = Number(value);
|
|
2461
|
+
return `${num.toFixed(0)}%`;
|
|
2462
|
+
}
|
|
2463
|
+
case "number": {
|
|
2464
|
+
const num = Number(value);
|
|
2465
|
+
if (num >= 1e6) return `${(num / 1e6).toFixed(1)}M`;
|
|
2466
|
+
if (num >= 1e3) return `${(num / 1e3).toFixed(1)}K`;
|
|
2467
|
+
return String(num);
|
|
2468
|
+
}
|
|
2469
|
+
case "date":
|
|
2470
|
+
case "datetime": {
|
|
2471
|
+
const date = new Date(String(value));
|
|
2472
|
+
if (isNaN(date.getTime())) return String(value);
|
|
2473
|
+
return date.toLocaleDateString("en-US", {
|
|
2474
|
+
month: "short",
|
|
2475
|
+
day: "numeric"
|
|
2476
|
+
});
|
|
2477
|
+
}
|
|
2478
|
+
case "boolean":
|
|
2479
|
+
return value ? "Yes" : "No";
|
|
2480
|
+
default:
|
|
2481
|
+
return String(value);
|
|
2482
|
+
}
|
|
2483
|
+
}
|
|
2484
|
+
function autoDetectMapping(columns) {
|
|
2485
|
+
var _a, _b, _c, _d, _e, _f;
|
|
2486
|
+
const primaryCols = columns.filter((c) => isPrimaryImportance(c.importance));
|
|
2487
|
+
const titleField = ((_a = primaryCols.find((c) => ["text", "entity", "user"].includes(c.type))) == null ? void 0 : _a.field) ?? ((_b = primaryCols[0]) == null ? void 0 : _b.field) ?? ((_c = columns[0]) == null ? void 0 : _c.field);
|
|
2488
|
+
const valueField = (_d = primaryCols.find((c) => c.type === "money")) == null ? void 0 : _d.field;
|
|
2489
|
+
const statusField = (_e = primaryCols.find(
|
|
2490
|
+
(c) => c.type === "status" || c.type === "badge"
|
|
2491
|
+
)) == null ? void 0 : _e.field;
|
|
2492
|
+
const usedForMain = new Set([titleField, valueField, statusField].filter(Boolean));
|
|
2493
|
+
const remainingPrimary = primaryCols.filter((c) => !usedForMain.has(c.field));
|
|
2494
|
+
const subtitleField = (_f = remainingPrimary[0]) == null ? void 0 : _f.field;
|
|
2495
|
+
const usedFields = new Set(
|
|
2496
|
+
[titleField, valueField, statusField, subtitleField].filter(Boolean)
|
|
2497
|
+
);
|
|
2498
|
+
const metadataFields = primaryCols.filter((c) => !usedFields.has(c.field)).slice(0, 3).map((c) => c.field);
|
|
2499
|
+
return {
|
|
2500
|
+
titleField: titleField ?? "id",
|
|
2501
|
+
subtitleField,
|
|
2502
|
+
valueField,
|
|
2503
|
+
statusField,
|
|
2504
|
+
metadataFields,
|
|
2505
|
+
iconConfig: void 0
|
|
2506
|
+
};
|
|
2507
|
+
}
|
|
2508
|
+
function entityToListCardProps(item, columns, mapping, entityType) {
|
|
2509
|
+
const autoMapping = autoDetectMapping(columns);
|
|
2510
|
+
const effectiveMapping = { ...autoMapping, ...mapping };
|
|
2511
|
+
const {
|
|
2512
|
+
titleField,
|
|
2513
|
+
subtitleField,
|
|
2514
|
+
valueField,
|
|
2515
|
+
statusField,
|
|
2516
|
+
metadataFields,
|
|
2517
|
+
iconConfig
|
|
2518
|
+
} = effectiveMapping;
|
|
2519
|
+
const getColumn = (field) => field ? columns.find((c) => c.field === field) : void 0;
|
|
2520
|
+
const title = item[titleField] != null ? String(item[titleField]) : "—";
|
|
2521
|
+
const subtitle = subtitleField && item[subtitleField] != null ? String(item[subtitleField]) : void 0;
|
|
2522
|
+
let value;
|
|
2523
|
+
if (valueField && item[valueField] != null) {
|
|
2524
|
+
const valueCol = getColumn(valueField);
|
|
2525
|
+
const formatted = formatValueForCard(
|
|
2526
|
+
item[valueField],
|
|
2527
|
+
(valueCol == null ? void 0 : valueCol.type) ?? "text",
|
|
2528
|
+
valueCol == null ? void 0 : valueCol.format
|
|
2529
|
+
);
|
|
2530
|
+
value = {
|
|
2531
|
+
text: formatted,
|
|
2532
|
+
variant: "success"
|
|
2533
|
+
// Money typically green
|
|
2534
|
+
};
|
|
2535
|
+
}
|
|
2536
|
+
let badge;
|
|
2537
|
+
if (statusField && item[statusField] != null) {
|
|
2538
|
+
const statusValue = String(item[statusField]);
|
|
2539
|
+
badge = {
|
|
2540
|
+
text: statusValue,
|
|
2541
|
+
variant: "status",
|
|
2542
|
+
status: getStatusColor(statusValue),
|
|
2543
|
+
size: "sm"
|
|
2544
|
+
};
|
|
2545
|
+
}
|
|
2546
|
+
const metadata = metadataFields == null ? void 0 : metadataFields.map((field) => {
|
|
2547
|
+
const col = getColumn(field);
|
|
2548
|
+
if (!col || item[field] == null) return null;
|
|
2549
|
+
return formatValueForCard(item[field], col.type, col.format);
|
|
2550
|
+
}).filter((v) => v !== null);
|
|
2551
|
+
let icon;
|
|
2552
|
+
if (iconConfig) {
|
|
2553
|
+
const iconValue = iconConfig.field ? item[iconConfig.field] : void 0;
|
|
2554
|
+
if (iconConfig.variant === "status" && iconValue) {
|
|
2555
|
+
icon = {
|
|
2556
|
+
icon: iconConfig.icon ?? getIconForEntity(entityType),
|
|
2557
|
+
variant: "status",
|
|
2558
|
+
status: getStatusColor(iconValue),
|
|
2559
|
+
size: "sm"
|
|
2560
|
+
};
|
|
2561
|
+
} else {
|
|
2562
|
+
icon = {
|
|
2563
|
+
icon: iconConfig.icon ?? getIconForEntity(entityType),
|
|
2564
|
+
variant: "category",
|
|
2565
|
+
category: getCategoryForEntity(entityType),
|
|
2566
|
+
size: "sm"
|
|
2567
|
+
};
|
|
2568
|
+
}
|
|
2569
|
+
} else {
|
|
2570
|
+
icon = {
|
|
2571
|
+
icon: getIconForEntity(entityType),
|
|
2572
|
+
variant: "category",
|
|
2573
|
+
category: getCategoryForEntity(entityType),
|
|
2574
|
+
size: "sm"
|
|
2575
|
+
};
|
|
2576
|
+
}
|
|
2577
|
+
return {
|
|
2578
|
+
icon,
|
|
2579
|
+
title,
|
|
2580
|
+
subtitle,
|
|
2581
|
+
metadata,
|
|
2582
|
+
value,
|
|
2583
|
+
badge
|
|
2584
|
+
};
|
|
2585
|
+
}
|
|
2586
|
+
const HEADER_ABBREVIATIONS = {
|
|
2587
|
+
customer: "Cust",
|
|
2588
|
+
account: "Acct",
|
|
2589
|
+
amount: "Amt",
|
|
2590
|
+
quantity: "Qty",
|
|
2591
|
+
priority: "Pri",
|
|
2592
|
+
status: "Status",
|
|
2593
|
+
created: "Created",
|
|
2594
|
+
updated: "Updated",
|
|
2595
|
+
description: "Desc",
|
|
2596
|
+
total: "Total",
|
|
2597
|
+
items: "Items",
|
|
2598
|
+
number: "#",
|
|
2599
|
+
date: "Date",
|
|
2600
|
+
time: "Time"
|
|
2601
|
+
};
|
|
2602
|
+
function abbreviateHeader(label) {
|
|
2603
|
+
const lower = label.toLowerCase();
|
|
2604
|
+
for (const [key, abbrev] of Object.entries(HEADER_ABBREVIATIONS)) {
|
|
2605
|
+
if (lower.includes(key)) return abbrev;
|
|
2606
|
+
}
|
|
2607
|
+
if (label.length > 8) return label.slice(0, 6) + "…";
|
|
2608
|
+
return label;
|
|
2609
|
+
}
|
|
2610
|
+
function generateCompactColumns(columns, options = {}) {
|
|
2611
|
+
const {
|
|
2612
|
+
maxColumns = 5,
|
|
2613
|
+
abbreviateHeaders = true,
|
|
2614
|
+
requiredFields = [],
|
|
2615
|
+
excludeFields = []
|
|
2616
|
+
} = options;
|
|
2617
|
+
const excludeSet = new Set(excludeFields);
|
|
2618
|
+
const requiredSet = new Set(requiredFields);
|
|
2619
|
+
const filteredColumns = columns.filter((col) => {
|
|
2620
|
+
if (excludeSet.has(col.field)) return false;
|
|
2621
|
+
return true;
|
|
2622
|
+
});
|
|
2623
|
+
const required = filteredColumns.filter((c) => requiredSet.has(c.field));
|
|
2624
|
+
const primary = filteredColumns.filter(
|
|
2625
|
+
(c) => !requiredSet.has(c.field) && normalizeImportance(c.importance) === "primary"
|
|
2626
|
+
);
|
|
2627
|
+
const secondary = filteredColumns.filter(
|
|
2628
|
+
(c) => !requiredSet.has(c.field) && normalizeImportance(c.importance) === "secondary"
|
|
2629
|
+
);
|
|
2630
|
+
const selectedColumns = [...required, ...primary, ...secondary].slice(
|
|
2631
|
+
0,
|
|
2632
|
+
maxColumns
|
|
2633
|
+
);
|
|
2634
|
+
return selectedColumns.map((col) => ({
|
|
2635
|
+
key: col.field,
|
|
2636
|
+
header: abbreviateHeaders ? abbreviateHeader(col.label) : col.label,
|
|
2637
|
+
sortable: col.sortable,
|
|
2638
|
+
type: col.type,
|
|
2639
|
+
format: col.format,
|
|
2640
|
+
// Compact widths
|
|
2641
|
+
width: getCompactWidth(col.type)
|
|
2642
|
+
}));
|
|
2643
|
+
}
|
|
2644
|
+
function getCompactWidth(type) {
|
|
2645
|
+
switch (type) {
|
|
2646
|
+
case "money":
|
|
2647
|
+
return "70px";
|
|
2648
|
+
case "number":
|
|
2649
|
+
case "percent":
|
|
2650
|
+
return "50px";
|
|
2651
|
+
case "status":
|
|
2652
|
+
case "badge":
|
|
2653
|
+
return "80px";
|
|
2654
|
+
case "date":
|
|
2655
|
+
return "70px";
|
|
2656
|
+
case "datetime":
|
|
2657
|
+
return "90px";
|
|
2658
|
+
case "boolean":
|
|
2659
|
+
return "50px";
|
|
2660
|
+
default:
|
|
2661
|
+
return "120px";
|
|
2662
|
+
}
|
|
2663
|
+
}
|
|
2664
|
+
function createMobileCardRenderer(columns, mapping, entityType) {
|
|
2665
|
+
return ({ data, onItemClick }) => /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-2", children: data.map((item, index) => {
|
|
2666
|
+
const cardProps = entityToListCardProps(
|
|
2667
|
+
item,
|
|
2668
|
+
columns,
|
|
2669
|
+
mapping,
|
|
2670
|
+
entityType
|
|
2671
|
+
);
|
|
2672
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
2673
|
+
ListCard,
|
|
2674
|
+
{
|
|
2675
|
+
...cardProps,
|
|
2676
|
+
onClick: onItemClick ? () => onItemClick(item) : void 0
|
|
2677
|
+
},
|
|
2678
|
+
item.id ?? index
|
|
2679
|
+
);
|
|
2680
|
+
}) });
|
|
2681
|
+
}
|
|
2055
2682
|
let globalAuthService = null;
|
|
2056
2683
|
function setGlobalAuthService(authService) {
|
|
2057
2684
|
globalAuthService = authService;
|
|
@@ -2217,10 +2844,10 @@ function useApiMutation(mutationFn, options) {
|
|
|
2217
2844
|
const queryClient = reactQuery.useQueryClient();
|
|
2218
2845
|
return reactQuery.useMutation({
|
|
2219
2846
|
mutationFn,
|
|
2220
|
-
onSuccess: (
|
|
2847
|
+
onSuccess: (...args) => {
|
|
2221
2848
|
var _a;
|
|
2222
|
-
queryClient.invalidateQueries();
|
|
2223
|
-
(_a = options == null ? void 0 : options.onSuccess) == null ? void 0 : _a.call(options,
|
|
2849
|
+
void queryClient.invalidateQueries({});
|
|
2850
|
+
(_a = options == null ? void 0 : options.onSuccess) == null ? void 0 : _a.call(options, ...args);
|
|
2224
2851
|
},
|
|
2225
2852
|
...options
|
|
2226
2853
|
});
|
|
@@ -2295,43 +2922,87 @@ function useFieldMetadata({
|
|
|
2295
2922
|
}
|
|
2296
2923
|
function useResponsiveTable(options = {}) {
|
|
2297
2924
|
const {
|
|
2925
|
+
columns,
|
|
2298
2926
|
initialView = "full",
|
|
2299
2927
|
autoSwitch = true,
|
|
2300
|
-
minWidthForCompact =
|
|
2928
|
+
minWidthForCompact = TABLE_BREAKPOINTS.minForTable,
|
|
2301
2929
|
debounceMs = 100,
|
|
2302
2930
|
onViewChange
|
|
2303
2931
|
} = options;
|
|
2304
2932
|
const [viewMode, setViewModeState] = React.useState(initialView);
|
|
2305
2933
|
const [isAutoSwitching, setIsAutoSwitching] = React.useState(autoSwitch);
|
|
2934
|
+
const [containerWidth, setContainerWidth] = React.useState(0);
|
|
2306
2935
|
const [overflowState, setOverflowState] = React.useState({
|
|
2307
2936
|
fullOverflows: false,
|
|
2308
2937
|
compactOverflows: false
|
|
2309
2938
|
});
|
|
2939
|
+
const containerRef = React.useRef(null);
|
|
2310
2940
|
const fullTableRef = React.useRef(null);
|
|
2311
2941
|
const compactTableRef = React.useRef(null);
|
|
2312
2942
|
const debounceTimerRef = React.useRef(null);
|
|
2313
2943
|
const isTransitioningRef = React.useRef(false);
|
|
2944
|
+
const compactColumns = React.useCallback(() => {
|
|
2945
|
+
if (!columns) return null;
|
|
2946
|
+
const validImportance = IMPORTANCE_VISIBILITY.compact;
|
|
2947
|
+
const filtered = columns.filter(
|
|
2948
|
+
(col) => validImportance.includes(col.importance ?? "medium")
|
|
2949
|
+
);
|
|
2950
|
+
const limited = filtered.slice(0, TABLE_BREAKPOINTS.maxCompactColumns);
|
|
2951
|
+
return limited.map((col) => ({
|
|
2952
|
+
...col,
|
|
2953
|
+
label: getCompactLabel(col.field, col.label)
|
|
2954
|
+
}));
|
|
2955
|
+
}, [columns])();
|
|
2956
|
+
const calculatedWidths = React.useCallback(() => {
|
|
2957
|
+
if (!columns) {
|
|
2958
|
+
return { full: 0, compact: 0, container: containerWidth };
|
|
2959
|
+
}
|
|
2960
|
+
const fullWidth = calculateTableWidth(
|
|
2961
|
+
columns.map((c) => ({ type: c.type })),
|
|
2962
|
+
"full"
|
|
2963
|
+
);
|
|
2964
|
+
const compactCols = compactColumns ?? [];
|
|
2965
|
+
const compactWidth = calculateTableWidth(
|
|
2966
|
+
compactCols.map((c) => ({ type: c.type })),
|
|
2967
|
+
"compact"
|
|
2968
|
+
);
|
|
2969
|
+
return {
|
|
2970
|
+
full: fullWidth,
|
|
2971
|
+
compact: compactWidth,
|
|
2972
|
+
container: containerWidth
|
|
2973
|
+
};
|
|
2974
|
+
}, [columns, compactColumns, containerWidth])();
|
|
2314
2975
|
const hasOverflow = React.useCallback((element) => {
|
|
2315
2976
|
if (!element) return false;
|
|
2316
2977
|
return element.scrollWidth > element.clientWidth + 2;
|
|
2317
2978
|
}, []);
|
|
2318
2979
|
const determineView = React.useCallback(() => {
|
|
2319
|
-
var _a, _b, _c, _d;
|
|
2320
|
-
|
|
2321
|
-
|
|
2980
|
+
var _a, _b, _c, _d, _e;
|
|
2981
|
+
if (columns && containerWidth > 0) {
|
|
2982
|
+
const { full, compact } = calculatedWidths;
|
|
2983
|
+
const buffer = TABLE_BREAKPOINTS.widthBuffer;
|
|
2984
|
+
if (containerWidth < minWidthForCompact) {
|
|
2985
|
+
return "cards";
|
|
2986
|
+
}
|
|
2987
|
+
if (full + buffer <= containerWidth) {
|
|
2988
|
+
return "full";
|
|
2989
|
+
}
|
|
2990
|
+
if (compact + buffer <= containerWidth) {
|
|
2991
|
+
return "compact";
|
|
2992
|
+
}
|
|
2993
|
+
return "cards";
|
|
2994
|
+
}
|
|
2995
|
+
const width = ((_a = containerRef.current) == null ? void 0 : _a.clientWidth) || ((_c = (_b = fullTableRef.current) == null ? void 0 : _b.parentElement) == null ? void 0 : _c.clientWidth) || ((_e = (_d = compactTableRef.current) == null ? void 0 : _d.parentElement) == null ? void 0 : _e.clientWidth) || window.innerWidth;
|
|
2996
|
+
if (width < minWidthForCompact) {
|
|
2322
2997
|
return "cards";
|
|
2323
2998
|
}
|
|
2324
2999
|
const fullOverflows = hasOverflow(fullTableRef.current);
|
|
2325
3000
|
const compactOverflows = hasOverflow(compactTableRef.current);
|
|
2326
3001
|
setOverflowState({ fullOverflows, compactOverflows });
|
|
2327
|
-
if (!fullOverflows)
|
|
2328
|
-
|
|
2329
|
-
}
|
|
2330
|
-
if (!compactOverflows) {
|
|
2331
|
-
return "compact";
|
|
2332
|
-
}
|
|
3002
|
+
if (!fullOverflows) return "full";
|
|
3003
|
+
if (!compactOverflows) return "compact";
|
|
2333
3004
|
return "cards";
|
|
2334
|
-
}, [
|
|
3005
|
+
}, [columns, containerWidth, calculatedWidths, minWidthForCompact, hasOverflow]);
|
|
2335
3006
|
const checkAndUpdate = React.useCallback(() => {
|
|
2336
3007
|
if (!isAutoSwitching || isTransitioningRef.current) return;
|
|
2337
3008
|
if (debounceTimerRef.current) {
|
|
@@ -2363,42 +3034,49 @@ function useResponsiveTable(options = {}) {
|
|
|
2363
3034
|
React.useEffect(() => {
|
|
2364
3035
|
var _a, _b;
|
|
2365
3036
|
if (!isAutoSwitching) return;
|
|
2366
|
-
const
|
|
3037
|
+
const updateContainerWidth = () => {
|
|
3038
|
+
var _a2;
|
|
3039
|
+
const ref = containerRef.current || ((_a2 = fullTableRef.current) == null ? void 0 : _a2.parentElement);
|
|
3040
|
+
if (ref) {
|
|
3041
|
+
setContainerWidth(ref.clientWidth);
|
|
3042
|
+
}
|
|
3043
|
+
};
|
|
3044
|
+
const initialTimer = setTimeout(updateContainerWidth, 50);
|
|
2367
3045
|
const resizeObserver = new ResizeObserver(() => {
|
|
3046
|
+
updateContainerWidth();
|
|
2368
3047
|
checkAndUpdate();
|
|
2369
3048
|
});
|
|
2370
|
-
|
|
2371
|
-
|
|
3049
|
+
const observeTarget = containerRef.current || ((_a = fullTableRef.current) == null ? void 0 : _a.parentElement) || ((_b = compactTableRef.current) == null ? void 0 : _b.parentElement);
|
|
3050
|
+
if (observeTarget) {
|
|
3051
|
+
resizeObserver.observe(observeTarget);
|
|
2372
3052
|
}
|
|
2373
|
-
if (
|
|
2374
|
-
resizeObserver.observe(
|
|
2375
|
-
|
|
2376
|
-
const parent = ((_a = fullTableRef.current) == null ? void 0 : _a.parentElement) || ((_b = compactTableRef.current) == null ? void 0 : _b.parentElement);
|
|
2377
|
-
if (parent) {
|
|
2378
|
-
resizeObserver.observe(parent);
|
|
3053
|
+
if (!columns) {
|
|
3054
|
+
if (fullTableRef.current) resizeObserver.observe(fullTableRef.current);
|
|
3055
|
+
if (compactTableRef.current) resizeObserver.observe(compactTableRef.current);
|
|
2379
3056
|
}
|
|
2380
3057
|
window.addEventListener("resize", checkAndUpdate);
|
|
2381
3058
|
return () => {
|
|
2382
|
-
clearTimeout(
|
|
2383
|
-
if (debounceTimerRef.current)
|
|
2384
|
-
clearTimeout(debounceTimerRef.current);
|
|
2385
|
-
}
|
|
3059
|
+
clearTimeout(initialTimer);
|
|
3060
|
+
if (debounceTimerRef.current) clearTimeout(debounceTimerRef.current);
|
|
2386
3061
|
resizeObserver.disconnect();
|
|
2387
3062
|
window.removeEventListener("resize", checkAndUpdate);
|
|
2388
3063
|
};
|
|
2389
|
-
}, [isAutoSwitching, checkAndUpdate]);
|
|
3064
|
+
}, [isAutoSwitching, columns, checkAndUpdate]);
|
|
2390
3065
|
React.useEffect(() => {
|
|
2391
3066
|
if (!isAutoSwitching) return;
|
|
2392
3067
|
const timer = setTimeout(checkAndUpdate, 100);
|
|
2393
3068
|
return () => clearTimeout(timer);
|
|
2394
|
-
}, [viewMode, isAutoSwitching, checkAndUpdate]);
|
|
3069
|
+
}, [viewMode, containerWidth, isAutoSwitching, checkAndUpdate]);
|
|
2395
3070
|
return {
|
|
2396
3071
|
viewMode,
|
|
2397
3072
|
setViewMode,
|
|
2398
3073
|
enableAutoSwitch,
|
|
2399
3074
|
isAutoSwitching,
|
|
3075
|
+
containerRef,
|
|
2400
3076
|
fullTableRef,
|
|
2401
3077
|
compactTableRef,
|
|
3078
|
+
compactColumns,
|
|
3079
|
+
calculatedWidths,
|
|
2402
3080
|
overflowState
|
|
2403
3081
|
};
|
|
2404
3082
|
}
|
|
@@ -2417,6 +3095,154 @@ function useOverflowDetection(ref) {
|
|
|
2417
3095
|
}, [ref]);
|
|
2418
3096
|
return hasOverflow;
|
|
2419
3097
|
}
|
|
3098
|
+
const IMPORTANCE_PRIORITY = {
|
|
3099
|
+
minimal: 0,
|
|
3100
|
+
low: 1,
|
|
3101
|
+
tertiary: 2,
|
|
3102
|
+
medium: 3,
|
|
3103
|
+
secondary: 4,
|
|
3104
|
+
high: 5,
|
|
3105
|
+
critical: 6,
|
|
3106
|
+
primary: 7
|
|
3107
|
+
};
|
|
3108
|
+
function getColumnModeWidth(col, mode) {
|
|
3109
|
+
if (mode === "hidden") return 0;
|
|
3110
|
+
return getColumnWidth(col.type, mode === "compact" ? "compact" : "full");
|
|
3111
|
+
}
|
|
3112
|
+
function calculateAdaptiveWidth(columns, modes) {
|
|
3113
|
+
return columns.reduce((sum, col) => sum + getColumnModeWidth(col, modes[col.field] ?? "full"), 0);
|
|
3114
|
+
}
|
|
3115
|
+
function calculateColumnModes(columns, containerWidth, protectedColumns, minColumnsVisible) {
|
|
3116
|
+
const buffer = TABLE_BREAKPOINTS.widthBuffer;
|
|
3117
|
+
const sortedByImportance = [...columns].sort((a, b) => {
|
|
3118
|
+
const priorityA = IMPORTANCE_PRIORITY[a.importance ?? "tertiary"];
|
|
3119
|
+
const priorityB = IMPORTANCE_PRIORITY[b.importance ?? "tertiary"];
|
|
3120
|
+
return priorityA - priorityB;
|
|
3121
|
+
});
|
|
3122
|
+
const modes = {};
|
|
3123
|
+
columns.forEach((col) => modes[col.field] = "full");
|
|
3124
|
+
let currentWidth = calculateAdaptiveWidth(columns, modes);
|
|
3125
|
+
if (currentWidth + buffer <= containerWidth) {
|
|
3126
|
+
return { modes, degradationLevel: 0 };
|
|
3127
|
+
}
|
|
3128
|
+
let degradationLevel = 1;
|
|
3129
|
+
for (const col of sortedByImportance) {
|
|
3130
|
+
if (protectedColumns.has(col.field)) continue;
|
|
3131
|
+
const priority = IMPORTANCE_PRIORITY[col.importance ?? "tertiary"];
|
|
3132
|
+
if (priority > 2) break;
|
|
3133
|
+
modes[col.field] = "compact";
|
|
3134
|
+
currentWidth = calculateAdaptiveWidth(columns, modes);
|
|
3135
|
+
if (currentWidth + buffer <= containerWidth) return { modes, degradationLevel };
|
|
3136
|
+
}
|
|
3137
|
+
degradationLevel = 2;
|
|
3138
|
+
for (const col of sortedByImportance) {
|
|
3139
|
+
if (protectedColumns.has(col.field)) continue;
|
|
3140
|
+
const priority = IMPORTANCE_PRIORITY[col.importance ?? "tertiary"];
|
|
3141
|
+
if (priority <= 2) continue;
|
|
3142
|
+
if (priority > 4) break;
|
|
3143
|
+
modes[col.field] = "compact";
|
|
3144
|
+
currentWidth = calculateAdaptiveWidth(columns, modes);
|
|
3145
|
+
if (currentWidth + buffer <= containerWidth) return { modes, degradationLevel };
|
|
3146
|
+
}
|
|
3147
|
+
degradationLevel = 3;
|
|
3148
|
+
let visibleCount = columns.length;
|
|
3149
|
+
for (const col of sortedByImportance) {
|
|
3150
|
+
const priority = IMPORTANCE_PRIORITY[col.importance ?? "tertiary"];
|
|
3151
|
+
if (priority > 2) break;
|
|
3152
|
+
if (visibleCount <= minColumnsVisible) break;
|
|
3153
|
+
modes[col.field] = "hidden";
|
|
3154
|
+
visibleCount--;
|
|
3155
|
+
currentWidth = calculateAdaptiveWidth(columns, modes);
|
|
3156
|
+
if (currentWidth + buffer <= containerWidth) return { modes, degradationLevel };
|
|
3157
|
+
}
|
|
3158
|
+
degradationLevel = 4;
|
|
3159
|
+
for (const col of sortedByImportance) {
|
|
3160
|
+
const priority = IMPORTANCE_PRIORITY[col.importance ?? "tertiary"];
|
|
3161
|
+
if (priority <= 2) continue;
|
|
3162
|
+
if (priority > 4) break;
|
|
3163
|
+
if (visibleCount <= minColumnsVisible) break;
|
|
3164
|
+
modes[col.field] = "hidden";
|
|
3165
|
+
visibleCount--;
|
|
3166
|
+
currentWidth = calculateAdaptiveWidth(columns, modes);
|
|
3167
|
+
if (currentWidth + buffer <= containerWidth) return { modes, degradationLevel };
|
|
3168
|
+
}
|
|
3169
|
+
degradationLevel = 5;
|
|
3170
|
+
for (const col of sortedByImportance) {
|
|
3171
|
+
if (modes[col.field] === "hidden") continue;
|
|
3172
|
+
modes[col.field] = "compact";
|
|
3173
|
+
currentWidth = calculateAdaptiveWidth(columns, modes);
|
|
3174
|
+
if (currentWidth + buffer <= containerWidth) return { modes, degradationLevel };
|
|
3175
|
+
}
|
|
3176
|
+
return { modes, degradationLevel: 6 };
|
|
3177
|
+
}
|
|
3178
|
+
function useAdaptiveTable(options) {
|
|
3179
|
+
const {
|
|
3180
|
+
columns,
|
|
3181
|
+
protectedColumns = [],
|
|
3182
|
+
minColumnsVisible = 2,
|
|
3183
|
+
minWidthForTable = TABLE_BREAKPOINTS.minForTable,
|
|
3184
|
+
debounceMs = 100,
|
|
3185
|
+
onModeChange
|
|
3186
|
+
} = options;
|
|
3187
|
+
const containerRef = React.useRef(null);
|
|
3188
|
+
const [containerWidth, setContainerWidth] = React.useState(0);
|
|
3189
|
+
const debounceTimerRef = React.useRef(null);
|
|
3190
|
+
const protectedSet = React.useMemo(() => new Set(protectedColumns), [protectedColumns]);
|
|
3191
|
+
const { modes: columnModes, degradationLevel } = React.useMemo(() => {
|
|
3192
|
+
if (containerWidth === 0) {
|
|
3193
|
+
const modes = {};
|
|
3194
|
+
columns.forEach((col) => modes[col.field] = "full");
|
|
3195
|
+
return { modes, degradationLevel: 0 };
|
|
3196
|
+
}
|
|
3197
|
+
return calculateColumnModes(columns, containerWidth, protectedSet, minColumnsVisible);
|
|
3198
|
+
}, [columns, containerWidth, protectedSet, minColumnsVisible]);
|
|
3199
|
+
const visibleColumns = React.useMemo(() => {
|
|
3200
|
+
return columns.filter((col) => columnModes[col.field] !== "hidden").map(
|
|
3201
|
+
(col) => columnModes[col.field] === "compact" ? { ...col, label: getCompactLabel(col.field, col.label) } : col
|
|
3202
|
+
);
|
|
3203
|
+
}, [columns, columnModes]);
|
|
3204
|
+
const calculatedWidth = React.useMemo(
|
|
3205
|
+
() => calculateAdaptiveWidth(columns, columnModes),
|
|
3206
|
+
[columns, columnModes]
|
|
3207
|
+
);
|
|
3208
|
+
const viewMode = React.useMemo(() => {
|
|
3209
|
+
if (containerWidth > 0 && containerWidth < minWidthForTable) return "cards";
|
|
3210
|
+
if (visibleColumns.length < minColumnsVisible) return "cards";
|
|
3211
|
+
return "table";
|
|
3212
|
+
}, [containerWidth, minWidthForTable, visibleColumns.length, minColumnsVisible]);
|
|
3213
|
+
React.useEffect(() => {
|
|
3214
|
+
const updateWidth = () => {
|
|
3215
|
+
if (containerRef.current) setContainerWidth(containerRef.current.clientWidth);
|
|
3216
|
+
};
|
|
3217
|
+
const initialTimer = setTimeout(updateWidth, 50);
|
|
3218
|
+
const resizeObserver = new ResizeObserver(() => {
|
|
3219
|
+
if (debounceTimerRef.current) clearTimeout(debounceTimerRef.current);
|
|
3220
|
+
debounceTimerRef.current = setTimeout(updateWidth, debounceMs);
|
|
3221
|
+
});
|
|
3222
|
+
if (containerRef.current) resizeObserver.observe(containerRef.current);
|
|
3223
|
+
return () => {
|
|
3224
|
+
clearTimeout(initialTimer);
|
|
3225
|
+
if (debounceTimerRef.current) clearTimeout(debounceTimerRef.current);
|
|
3226
|
+
resizeObserver.disconnect();
|
|
3227
|
+
};
|
|
3228
|
+
}, [debounceMs]);
|
|
3229
|
+
const prevModesRef = React.useRef(columnModes);
|
|
3230
|
+
React.useEffect(() => {
|
|
3231
|
+
if (onModeChange && columnModes !== prevModesRef.current) {
|
|
3232
|
+
onModeChange(columnModes);
|
|
3233
|
+
prevModesRef.current = columnModes;
|
|
3234
|
+
}
|
|
3235
|
+
}, [columnModes, onModeChange]);
|
|
3236
|
+
return {
|
|
3237
|
+
containerRef,
|
|
3238
|
+
columnModes,
|
|
3239
|
+
visibleColumns,
|
|
3240
|
+
viewMode,
|
|
3241
|
+
calculatedWidth,
|
|
3242
|
+
containerWidth,
|
|
3243
|
+
degradationLevel
|
|
3244
|
+
};
|
|
3245
|
+
}
|
|
2420
3246
|
function useEntityData(entity, options = {}) {
|
|
2421
3247
|
var _a, _b, _c;
|
|
2422
3248
|
const {
|
|
@@ -4299,8 +5125,9 @@ function normalizeColumn(col) {
|
|
|
4299
5125
|
return col;
|
|
4300
5126
|
}
|
|
4301
5127
|
function DataTable({
|
|
4302
|
-
data,
|
|
4303
|
-
columns,
|
|
5128
|
+
data: dataProp,
|
|
5129
|
+
columns: columnsProp,
|
|
5130
|
+
query,
|
|
4304
5131
|
searchPlaceholder = "Search...",
|
|
4305
5132
|
pageSize = 10,
|
|
4306
5133
|
showPagination = true,
|
|
@@ -4309,12 +5136,12 @@ function DataTable({
|
|
|
4309
5136
|
emptyMessage = "No data available",
|
|
4310
5137
|
className = "",
|
|
4311
5138
|
hover = false,
|
|
4312
|
-
isLoading = false,
|
|
5139
|
+
isLoading: isLoadingProp = false,
|
|
4313
5140
|
loadingItemCount = 5,
|
|
4314
5141
|
responsive = true,
|
|
4315
5142
|
renderMobileCard,
|
|
4316
5143
|
ui,
|
|
4317
|
-
error = null,
|
|
5144
|
+
error: errorProp = null,
|
|
4318
5145
|
errorTitle,
|
|
4319
5146
|
errorRetry,
|
|
4320
5147
|
selectable = false,
|
|
@@ -4329,6 +5156,10 @@ function DataTable({
|
|
|
4329
5156
|
const [currentPage, setCurrentPage] = React.useState(1);
|
|
4330
5157
|
const currentBreakpoint = useBreakpoint();
|
|
4331
5158
|
const isMobile = currentBreakpoint === "xs" || currentBreakpoint === "2xs" || currentBreakpoint === "sm";
|
|
5159
|
+
const data = dataProp ?? (query == null ? void 0 : query.data) ?? [];
|
|
5160
|
+
const columns = columnsProp ?? (query == null ? void 0 : query.columns) ?? [];
|
|
5161
|
+
const isLoading = isLoadingProp || (query == null ? void 0 : query.isLoading) || (query == null ? void 0 : query.isLoadingMetadata) || false;
|
|
5162
|
+
const error = errorProp ?? (query == null ? void 0 : query.error) ?? (query == null ? void 0 : query.metadataError) ?? null;
|
|
4332
5163
|
const normalizedColumns = React.useMemo(
|
|
4333
5164
|
() => columns.map((col) => normalizeColumn(col)),
|
|
4334
5165
|
[columns]
|
|
@@ -4715,64 +5546,6 @@ const TableHead = TableHead$1;
|
|
|
4715
5546
|
const TableHeader = TableHeader$1;
|
|
4716
5547
|
const TableRow = TableRow$1;
|
|
4717
5548
|
const TableFooter = TableFooter$1;
|
|
4718
|
-
const IconBadge = ({
|
|
4719
|
-
children,
|
|
4720
|
-
icon,
|
|
4721
|
-
variant = "category",
|
|
4722
|
-
category = 1,
|
|
4723
|
-
status = "neutral",
|
|
4724
|
-
size = "md",
|
|
4725
|
-
interactive = false,
|
|
4726
|
-
onClick,
|
|
4727
|
-
className,
|
|
4728
|
-
tooltip
|
|
4729
|
-
}) => {
|
|
4730
|
-
const currentSize = useResponsiveValue(size);
|
|
4731
|
-
const sizeConfig = responsiveScales.components.iconBadge[currentSize];
|
|
4732
|
-
const sizeClasses2 = {
|
|
4733
|
-
xs: `${(sizeConfig == null ? void 0 : sizeConfig.size) || "w-6 h-6"} ${(sizeConfig == null ? void 0 : sizeConfig.text) || "text-[10px]"} ${(sizeConfig == null ? void 0 : sizeConfig.rounded) || "rounded-md"}`,
|
|
4734
|
-
sm: "w-8 h-8 text-xs rounded-lg",
|
|
4735
|
-
md: "w-10 h-10 text-sm rounded-xl",
|
|
4736
|
-
lg: "w-12 h-12 text-base rounded-xl"
|
|
4737
|
-
};
|
|
4738
|
-
const baseClasses = cn(
|
|
4739
|
-
"inline-flex items-center justify-center font-bold shadow-md",
|
|
4740
|
-
sizeClasses2[currentSize],
|
|
4741
|
-
interactive && [
|
|
4742
|
-
"cursor-pointer",
|
|
4743
|
-
getAnimationClasses({
|
|
4744
|
-
...animationPresets.dataBadge,
|
|
4745
|
-
size: currentSize === "lg" ? "lg" : currentSize === "sm" || currentSize === "xs" ? "sm" : "md"
|
|
4746
|
-
})
|
|
4747
|
-
],
|
|
4748
|
-
className
|
|
4749
|
-
);
|
|
4750
|
-
const gradientClasses = variant === "category" ? `bg-gradient-to-br from-category-${category} to-category-${Math.min(category + 1, 8)}` : variant === "status" ? `bg-gradient-to-br from-status-${status} to-status-${status}` : "bg-gradient-to-br from-category-1 to-category-2";
|
|
4751
|
-
const badge = /* @__PURE__ */ jsxRuntime.jsxs(
|
|
4752
|
-
"div",
|
|
4753
|
-
{
|
|
4754
|
-
className: cn(baseClasses, gradientClasses, "animate-fade-in"),
|
|
4755
|
-
onClick,
|
|
4756
|
-
role: interactive ? "button" : void 0,
|
|
4757
|
-
tabIndex: interactive ? 0 : void 0,
|
|
4758
|
-
onKeyDown: interactive ? (e) => {
|
|
4759
|
-
if (e.key === "Enter" || e.key === " ") {
|
|
4760
|
-
e.preventDefault();
|
|
4761
|
-
onClick == null ? void 0 : onClick();
|
|
4762
|
-
}
|
|
4763
|
-
} : void 0,
|
|
4764
|
-
"data-component-name": "IconBadge",
|
|
4765
|
-
children: [
|
|
4766
|
-
icon && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-primary-foreground drop-shadow", children: icon }),
|
|
4767
|
-
children && !icon && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-primary-foreground font-bold", children })
|
|
4768
|
-
]
|
|
4769
|
-
}
|
|
4770
|
-
);
|
|
4771
|
-
if (tooltip) {
|
|
4772
|
-
return /* @__PURE__ */ jsxRuntime.jsx(Tooltip, { content: tooltip, position: "top", size: "sm", children: badge });
|
|
4773
|
-
}
|
|
4774
|
-
return badge;
|
|
4775
|
-
};
|
|
4776
5549
|
const Chart = ({
|
|
4777
5550
|
title,
|
|
4778
5551
|
subtitle,
|
|
@@ -5535,85 +6308,6 @@ const ProgressBar = ({
|
|
|
5535
6308
|
)
|
|
5536
6309
|
] });
|
|
5537
6310
|
};
|
|
5538
|
-
const valueColorMap = {
|
|
5539
|
-
success: "text-green-600",
|
|
5540
|
-
error: "text-red-600",
|
|
5541
|
-
warning: "text-yellow-600",
|
|
5542
|
-
info: "text-blue-600",
|
|
5543
|
-
neutral: "text-muted-foreground",
|
|
5544
|
-
default: "text-foreground"
|
|
5545
|
-
};
|
|
5546
|
-
function ListCard({
|
|
5547
|
-
icon,
|
|
5548
|
-
title,
|
|
5549
|
-
subtitle,
|
|
5550
|
-
metadata,
|
|
5551
|
-
value,
|
|
5552
|
-
badge,
|
|
5553
|
-
onClick,
|
|
5554
|
-
className,
|
|
5555
|
-
children
|
|
5556
|
-
}) {
|
|
5557
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
5558
|
-
"div",
|
|
5559
|
-
{
|
|
5560
|
-
className: cn(
|
|
5561
|
-
"flex items-start gap-3 p-3 rounded-lg border border-border transition-colors",
|
|
5562
|
-
onClick && "hover:bg-muted/50 cursor-pointer",
|
|
5563
|
-
className
|
|
5564
|
-
),
|
|
5565
|
-
onClick,
|
|
5566
|
-
children: [
|
|
5567
|
-
icon && /* @__PURE__ */ jsxRuntime.jsx(
|
|
5568
|
-
IconBadge,
|
|
5569
|
-
{
|
|
5570
|
-
variant: icon.variant || "category",
|
|
5571
|
-
category: icon.variant === "category" ? icon.category || 1 : void 0,
|
|
5572
|
-
status: icon.variant === "status" ? icon.status || "neutral" : void 0,
|
|
5573
|
-
size: icon.size || "sm",
|
|
5574
|
-
icon: icon.icon,
|
|
5575
|
-
tooltip: icon.tooltip
|
|
5576
|
-
}
|
|
5577
|
-
),
|
|
5578
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 min-w-0", children: [
|
|
5579
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start justify-between gap-2", children: [
|
|
5580
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1", children: [
|
|
5581
|
-
/* @__PURE__ */ jsxRuntime.jsx("h4", { className: "text-sm font-medium text-foreground truncate", children: title }),
|
|
5582
|
-
subtitle && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground mt-0.5", children: subtitle }),
|
|
5583
|
-
metadata && metadata.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center gap-3 mt-1", children: metadata.map((item, index) => /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-muted-foreground", children: item }, index)) })
|
|
5584
|
-
] }),
|
|
5585
|
-
(value || badge) && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-right", children: [
|
|
5586
|
-
value && /* @__PURE__ */ jsxRuntime.jsx(
|
|
5587
|
-
"p",
|
|
5588
|
-
{
|
|
5589
|
-
className: cn(
|
|
5590
|
-
"text-sm font-semibold",
|
|
5591
|
-
value.variant && valueColorMap[value.variant],
|
|
5592
|
-
value.className
|
|
5593
|
-
),
|
|
5594
|
-
children: value.text
|
|
5595
|
-
}
|
|
5596
|
-
),
|
|
5597
|
-
badge && /* @__PURE__ */ jsxRuntime.jsx(
|
|
5598
|
-
DataBadge,
|
|
5599
|
-
{
|
|
5600
|
-
variant: badge.variant,
|
|
5601
|
-
status: badge.variant === "status" ? badge.status : void 0,
|
|
5602
|
-
category: badge.variant === "category" ? badge.category : void 0,
|
|
5603
|
-
size: badge.size || "sm",
|
|
5604
|
-
icon: badge.icon,
|
|
5605
|
-
className: "mt-1",
|
|
5606
|
-
children: badge.text
|
|
5607
|
-
}
|
|
5608
|
-
)
|
|
5609
|
-
] })
|
|
5610
|
-
] }),
|
|
5611
|
-
children
|
|
5612
|
-
] })
|
|
5613
|
-
]
|
|
5614
|
-
}
|
|
5615
|
-
);
|
|
5616
|
-
}
|
|
5617
6311
|
const TruncatedText = ({
|
|
5618
6312
|
text,
|
|
5619
6313
|
className,
|
|
@@ -8934,6 +9628,13 @@ const defaultShowcaseNavigation = [
|
|
|
8934
9628
|
path: "/admin/dashboard",
|
|
8935
9629
|
category: 2
|
|
8936
9630
|
},
|
|
9631
|
+
{
|
|
9632
|
+
value: "admin-dashboard-v2",
|
|
9633
|
+
label: "Admin Dashboard V2",
|
|
9634
|
+
icon: "Shield",
|
|
9635
|
+
path: "/admin/dashboard-v2",
|
|
9636
|
+
category: 2
|
|
9637
|
+
},
|
|
8937
9638
|
{
|
|
8938
9639
|
value: "admin-users",
|
|
8939
9640
|
label: "User Management",
|
|
@@ -9204,7 +9905,6 @@ const Sidebar = ({ className }) => {
|
|
|
9204
9905
|
);
|
|
9205
9906
|
};
|
|
9206
9907
|
const AppHeader = ({ className }) => {
|
|
9207
|
-
const isTrialMode = false;
|
|
9208
9908
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
9209
9909
|
"header",
|
|
9210
9910
|
{
|
|
@@ -9217,7 +9917,7 @@ const AppHeader = ({ className }) => {
|
|
|
9217
9917
|
children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mx-auto max-w-7xl px-4 sm:px-6 lg:px-8", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex h-16 items-center justify-between", children: [
|
|
9218
9918
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [
|
|
9219
9919
|
/* @__PURE__ */ jsxRuntime.jsx("h1", { className: "text-xl font-bold text-foreground", children: "Frontend Template" }),
|
|
9220
|
-
|
|
9920
|
+
/* @__PURE__ */ jsxRuntime.jsx(DataBadge, { variant: "status", status: "info", display: "icon-text", children: "Trial Mode" })
|
|
9221
9921
|
] }),
|
|
9222
9922
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 max-w-2xl mx-8", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
9223
9923
|
GlobalSearch,
|
|
@@ -14001,18 +14701,41 @@ function createReactApp(config) {
|
|
|
14001
14701
|
enableRouting = true,
|
|
14002
14702
|
auth,
|
|
14003
14703
|
navigation,
|
|
14004
|
-
customProviders = []
|
|
14704
|
+
customProviders = [],
|
|
14705
|
+
persistQueryCache = false,
|
|
14706
|
+
queryCacheKey = "PATTERN_STACK_QUERY_CACHE"
|
|
14005
14707
|
} = appConfig;
|
|
14006
14708
|
const queryClient = new reactQuery.QueryClient({
|
|
14007
14709
|
defaultOptions: {
|
|
14008
14710
|
queries: {
|
|
14009
14711
|
retry: 1,
|
|
14010
14712
|
refetchOnWindowFocus: false,
|
|
14011
|
-
staleTime: 5 * 60 * 1e3
|
|
14713
|
+
staleTime: 5 * 60 * 1e3,
|
|
14012
14714
|
// 5 minutes
|
|
14715
|
+
// Keep data longer when persistence is enabled
|
|
14716
|
+
gcTime: persistQueryCache ? 1e3 * 60 * 60 * 24 : 1e3 * 60 * 5
|
|
14013
14717
|
}
|
|
14014
14718
|
}
|
|
14015
14719
|
});
|
|
14720
|
+
if (persistQueryCache && typeof window !== "undefined") {
|
|
14721
|
+
import("@tanstack/react-query-persist-client").then(({ persistQueryClient }) => {
|
|
14722
|
+
import("@tanstack/query-sync-storage-persister").then(({ createSyncStoragePersister }) => {
|
|
14723
|
+
const persister = createSyncStoragePersister({
|
|
14724
|
+
storage: window.localStorage,
|
|
14725
|
+
key: queryCacheKey
|
|
14726
|
+
});
|
|
14727
|
+
persistQueryClient({
|
|
14728
|
+
queryClient,
|
|
14729
|
+
persister,
|
|
14730
|
+
maxAge: 1e3 * 60 * 60 * 24
|
|
14731
|
+
// 24 hours
|
|
14732
|
+
});
|
|
14733
|
+
console.info("[app] Query cache persistence enabled");
|
|
14734
|
+
});
|
|
14735
|
+
}).catch((err) => {
|
|
14736
|
+
console.warn("[app] Query persistence not available:", err.message);
|
|
14737
|
+
});
|
|
14738
|
+
}
|
|
14016
14739
|
const routes = [];
|
|
14017
14740
|
const DefaultHome = () => /* @__PURE__ */ jsxRuntime.jsx(DashboardTemplate, { title, description, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-center justify-center min-h-[400px] text-center", children: [
|
|
14018
14741
|
/* @__PURE__ */ jsxRuntime.jsxs("h1", { className: "text-4xl font-bold text-foreground mb-4", children: [
|
|
@@ -14031,7 +14754,7 @@ function createReactApp(config) {
|
|
|
14031
14754
|
] }) });
|
|
14032
14755
|
const createProviderTree = (children) => {
|
|
14033
14756
|
let tree = children;
|
|
14034
|
-
customProviders.reverse().forEach((Provider) => {
|
|
14757
|
+
[...customProviders].reverse().forEach((Provider) => {
|
|
14035
14758
|
tree = /* @__PURE__ */ jsxRuntime.jsx(Provider, { children: tree }, Provider.name);
|
|
14036
14759
|
});
|
|
14037
14760
|
if (enableRouting) {
|
|
@@ -14074,10 +14797,10 @@ function createReactApp(config) {
|
|
|
14074
14797
|
}
|
|
14075
14798
|
return component;
|
|
14076
14799
|
};
|
|
14077
|
-
const AppContent = () => /* @__PURE__ */ jsxRuntime.jsx(reactRouterDom.Routes, { children: /* @__PURE__ */ jsxRuntime.jsxs(reactRouterDom.Route, { path: "/", element: /* @__PURE__ */ jsxRuntime.jsx(AppLayout, {}), children: [
|
|
14800
|
+
const AppContent = () => /* @__PURE__ */ jsxRuntime.jsx(React.Suspense, { fallback: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-center min-h-screen", children: "Loading..." }), children: /* @__PURE__ */ jsxRuntime.jsx(reactRouterDom.Routes, { children: /* @__PURE__ */ jsxRuntime.jsxs(reactRouterDom.Route, { path: "/", element: /* @__PURE__ */ jsxRuntime.jsx(AppLayout, {}), children: [
|
|
14078
14801
|
/* @__PURE__ */ jsxRuntime.jsx(reactRouterDom.Route, { index: true, element: wrapWithProtection("/", /* @__PURE__ */ jsxRuntime.jsx(DefaultHome, {})) }),
|
|
14079
14802
|
routes.map(({ path, component }, index) => /* @__PURE__ */ jsxRuntime.jsx(reactRouterDom.Route, { path, element: wrapWithProtection(path, component) }, index))
|
|
14080
|
-
] }) });
|
|
14803
|
+
] }) }) });
|
|
14081
14804
|
return createProviderTree(/* @__PURE__ */ jsxRuntime.jsx(AppContent, {}));
|
|
14082
14805
|
},
|
|
14083
14806
|
mount(elementId = "root") {
|
|
@@ -17272,6 +17995,10 @@ exports.Badge = Badge;
|
|
|
17272
17995
|
exports.Breadcrumb = Breadcrumb;
|
|
17273
17996
|
exports.BulkSelectionBar = BulkSelectionBar;
|
|
17274
17997
|
exports.Button = Button;
|
|
17998
|
+
exports.COLUMN_WIDTHS = COLUMN_WIDTHS;
|
|
17999
|
+
exports.COMPACT_COLUMN_WIDTHS = COMPACT_COLUMN_WIDTHS;
|
|
18000
|
+
exports.COMPACT_FORMATTERS = COMPACT_FORMATTERS;
|
|
18001
|
+
exports.COMPACT_LABELS = COMPACT_LABELS;
|
|
17275
18002
|
exports.Card = Card;
|
|
17276
18003
|
exports.CardContent = CardContent;
|
|
17277
18004
|
exports.CardDescription = CardDescription;
|
|
@@ -17330,6 +18057,7 @@ exports.FileUpload = FileUpload;
|
|
|
17330
18057
|
exports.FormField = FormField;
|
|
17331
18058
|
exports.FormGroup = FormGroup;
|
|
17332
18059
|
exports.GlobalSearch = GlobalSearch;
|
|
18060
|
+
exports.IMPORTANCE_VISIBILITY = IMPORTANCE_VISIBILITY;
|
|
17333
18061
|
exports.Icon = Icon;
|
|
17334
18062
|
exports.IconBadge = IconBadge;
|
|
17335
18063
|
exports.Input = Input;
|
|
@@ -17385,6 +18113,7 @@ exports.Spinner = Spinner;
|
|
|
17385
18113
|
exports.StatCard = StatCard;
|
|
17386
18114
|
exports.StyleGuide = StyleGuide;
|
|
17387
18115
|
exports.Switch = Switch;
|
|
18116
|
+
exports.TABLE_BREAKPOINTS = TABLE_BREAKPOINTS;
|
|
17388
18117
|
exports.Table = Table;
|
|
17389
18118
|
exports.TableBody = TableBody;
|
|
17390
18119
|
exports.TableCaption = TableCaption;
|
|
@@ -17407,19 +18136,27 @@ exports.UserMenu = UserMenu;
|
|
|
17407
18136
|
exports.animationPresets = animationPresets;
|
|
17408
18137
|
exports.apiClient = apiClient;
|
|
17409
18138
|
exports.breakpoints = breakpoints;
|
|
18139
|
+
exports.calculateTableWidth = calculateTableWidth;
|
|
17410
18140
|
exports.cn = cn;
|
|
17411
18141
|
exports.createAPIDataTemplate = createAPIDataTemplate;
|
|
17412
18142
|
exports.createApiClient = createApiClient;
|
|
18143
|
+
exports.createMobileCardRenderer = createMobileCardRenderer;
|
|
17413
18144
|
exports.createReactApp = createReactApp;
|
|
17414
18145
|
exports.createSimpleApp = createSimpleApp;
|
|
17415
18146
|
exports.defaultFieldRenderers = defaultFieldRenderers;
|
|
17416
18147
|
exports.detectBulkOperationType = detectBulkOperationType;
|
|
17417
18148
|
exports.detectUIConfig = detectUIConfig;
|
|
18149
|
+
exports.determineTableMode = determineTableMode;
|
|
18150
|
+
exports.entityToListCardProps = entityToListCardProps;
|
|
17418
18151
|
exports.env = env;
|
|
17419
18152
|
exports.formatNumberWithTooltip = formatNumberWithTooltip;
|
|
17420
18153
|
exports.generateBulkOperationName = generateBulkOperationName;
|
|
18154
|
+
exports.generateCompactColumns = generateCompactColumns;
|
|
17421
18155
|
exports.getAnimationClasses = getAnimationClasses;
|
|
17422
18156
|
exports.getChartHeight = getChartHeight;
|
|
18157
|
+
exports.getColumnWidth = getColumnWidth;
|
|
18158
|
+
exports.getCompactFormatter = getCompactFormatter;
|
|
18159
|
+
exports.getCompactLabel = getCompactLabel;
|
|
17423
18160
|
exports.getContainerHeightClass = getContainerHeightClass;
|
|
17424
18161
|
exports.getCurrentBreakpoint = getCurrentBreakpoint;
|
|
17425
18162
|
exports.getFieldType = getFieldType;
|
|
@@ -17438,6 +18175,7 @@ exports.renderField = renderField;
|
|
|
17438
18175
|
exports.responsiveScales = responsiveScales;
|
|
17439
18176
|
exports.setGlobalAuthService = setGlobalAuthService;
|
|
17440
18177
|
exports.tooltipContent = tooltipContent;
|
|
18178
|
+
exports.useAdaptiveTable = useAdaptiveTable;
|
|
17441
18179
|
exports.useApiMutation = useApiMutation;
|
|
17442
18180
|
exports.useApiQuery = useApiQuery;
|
|
17443
18181
|
exports.useAuth = useAuth;
|