@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.es.js
CHANGED
|
@@ -7,9 +7,9 @@ import { twMerge } from "tailwind-merge";
|
|
|
7
7
|
import axios from "axios";
|
|
8
8
|
import { jsx, jsxs, Fragment } from "react/jsx-runtime";
|
|
9
9
|
import * as React from "react";
|
|
10
|
-
import React__default, { useRef, useState, useEffect, useMemo, forwardRef, useCallback, useContext, createContext, useId, Component } from "react";
|
|
10
|
+
import React__default, { useRef, useState, useEffect, useMemo, forwardRef, useCallback, useContext, createContext, useId, Component, Suspense } from "react";
|
|
11
11
|
import * as SheetPrimitive from "@radix-ui/react-dialog";
|
|
12
|
-
import { Map as Map$1, Calculator, Brain, User, Handshake, Truck, Building, HelpCircle, Info, AlertCircle, Check, ArrowDown, ArrowUp, ArrowLeft, ArrowRight, ChevronUp, ChevronLeft, ChevronDown, ChevronRight, Music, Video, Image, Folder, File, Flag, Tag, Bookmark, Heart, Star, MapPin, Clock, Calendar, Phone, Mail, Unlock, Lock, Share, Upload, Download, Eye, Trash2, Edit, Plus, Search, Bell, Settings, Home, Layout, TrendingUp, Database, BarChart3, Users, Shield, X, Menu, Palette, Loader2, EyeOff, InfoIcon,
|
|
12
|
+
import { Map as Map$1, Calculator, Brain, User, Handshake, Truck, Building, HelpCircle, Info, AlertCircle, Check, ArrowDown, ArrowUp, ArrowLeft, ArrowRight, ChevronUp, ChevronLeft, ChevronDown, ChevronRight, Music, Video, Image, Folder, File, Flag, Tag, Bookmark, Heart, Star, MapPin, Clock, Calendar, Phone, Mail, Unlock, Lock, Share, Upload, Download, Eye, Trash2, Edit, Plus, Search, Bell, Settings, Home, Layout, TrendingUp, Database, BarChart3, Users, Shield, X, Menu, Palette, Circle, Building2, Package, FileText, Loader2, EyeOff, InfoIcon, ChevronsUpDown, AreaChart, LineChart, TrendingDown, Minus, AlertTriangle, Activity, WifiOff, CloudOff, Cloud, CheckCircle, FileX, Sun, Moon, LogOut, Square, Waves, Zap, TreePine, Sparkles, Sunset, DollarSign, ShoppingCart, Target, ExternalLink, MoreHorizontal, Filter, Edit2, Undo2, RefreshCw, History, Save, Copy, Grid3X3, Layers, XCircle, Briefcase } from "lucide-react";
|
|
13
13
|
import * as LabelPrimitive from "@radix-ui/react-label";
|
|
14
14
|
import { cva } from "class-variance-authority";
|
|
15
15
|
import * as AvatarPrimitive from "@radix-ui/react-avatar";
|
|
@@ -136,6 +136,141 @@ const RESPONSIVE_CHART_HEIGHTS = {
|
|
|
136
136
|
secondary: DASHBOARD_CHART_HEIGHTS.medium
|
|
137
137
|
}
|
|
138
138
|
};
|
|
139
|
+
const COLUMN_WIDTHS = {
|
|
140
|
+
// Text
|
|
141
|
+
text: 180,
|
|
142
|
+
password: 120,
|
|
143
|
+
// Numbers
|
|
144
|
+
number: 80,
|
|
145
|
+
money: 100,
|
|
146
|
+
percent: 70,
|
|
147
|
+
// Dates
|
|
148
|
+
date: 100,
|
|
149
|
+
datetime: 140,
|
|
150
|
+
// Contact/Links
|
|
151
|
+
email: 180,
|
|
152
|
+
phone: 120,
|
|
153
|
+
url: 160,
|
|
154
|
+
// Visual indicators
|
|
155
|
+
status: 90,
|
|
156
|
+
badge: 90,
|
|
157
|
+
boolean: 60,
|
|
158
|
+
rating: 80,
|
|
159
|
+
color: 60,
|
|
160
|
+
// Entity references
|
|
161
|
+
entity: 140,
|
|
162
|
+
user: 140,
|
|
163
|
+
// Special
|
|
164
|
+
image: 60,
|
|
165
|
+
file: 100,
|
|
166
|
+
json: 200
|
|
167
|
+
};
|
|
168
|
+
const COMPACT_COLUMN_WIDTHS = {
|
|
169
|
+
text: 120,
|
|
170
|
+
// With truncation
|
|
171
|
+
money: 60,
|
|
172
|
+
// $2.5k format
|
|
173
|
+
date: 55,
|
|
174
|
+
// "Dec 5" or "Tu"
|
|
175
|
+
datetime: 65,
|
|
176
|
+
// "5m ago"
|
|
177
|
+
email: 100,
|
|
178
|
+
// Truncated
|
|
179
|
+
phone: 80,
|
|
180
|
+
url: 80,
|
|
181
|
+
entity: 100,
|
|
182
|
+
user: 80,
|
|
183
|
+
json: 80
|
|
184
|
+
};
|
|
185
|
+
const COMPACT_FORMATTERS = {
|
|
186
|
+
money: "compactCurrency",
|
|
187
|
+
// $2,456.99 → $2.5k
|
|
188
|
+
date: "shortDate",
|
|
189
|
+
// 2024-01-15 → Dec 5
|
|
190
|
+
datetime: "relative",
|
|
191
|
+
// 2024-01-15T10:30 → 5m ago
|
|
192
|
+
text: "truncate",
|
|
193
|
+
// Long customer name → Long cust...
|
|
194
|
+
email: "truncate",
|
|
195
|
+
url: "domain",
|
|
196
|
+
// https://example.com/path → example.com
|
|
197
|
+
number: "compact"
|
|
198
|
+
// 1234567 → 1.2M
|
|
199
|
+
};
|
|
200
|
+
const COMPACT_LABELS = {
|
|
201
|
+
// Common field names → short versions
|
|
202
|
+
customer: "Cust",
|
|
203
|
+
description: "Desc",
|
|
204
|
+
quantity: "Qty",
|
|
205
|
+
amount: "Amt",
|
|
206
|
+
total: "Tot",
|
|
207
|
+
priority: "Pri",
|
|
208
|
+
status: "Stat",
|
|
209
|
+
created_at: "Created",
|
|
210
|
+
updated_at: "Updated",
|
|
211
|
+
email: "Email",
|
|
212
|
+
phone: "Ph",
|
|
213
|
+
category: "Cat",
|
|
214
|
+
// Time fields
|
|
215
|
+
time: "Time",
|
|
216
|
+
timeAgo: "Time",
|
|
217
|
+
timestamp: "Time",
|
|
218
|
+
// ID fields
|
|
219
|
+
order_id: "#",
|
|
220
|
+
id: "#",
|
|
221
|
+
transaction_id: "Txn"
|
|
222
|
+
};
|
|
223
|
+
const TABLE_BREAKPOINTS = {
|
|
224
|
+
/** Below this width (px), always use cards */
|
|
225
|
+
minForTable: 400,
|
|
226
|
+
/** Buffer (px) to add when calculating if columns fit */
|
|
227
|
+
widthBuffer: 50,
|
|
228
|
+
/** Minimum columns to show in compact mode */
|
|
229
|
+
minCompactColumns: 3,
|
|
230
|
+
/** Maximum columns in compact mode */
|
|
231
|
+
maxCompactColumns: 6
|
|
232
|
+
};
|
|
233
|
+
const IMPORTANCE_VISIBILITY = {
|
|
234
|
+
full: ["primary", "secondary", "tertiary", "critical", "high", "medium", "low", "minimal"],
|
|
235
|
+
compact: ["primary", "secondary", "critical", "high", "medium"],
|
|
236
|
+
cards: ["primary", "critical", "high"]
|
|
237
|
+
};
|
|
238
|
+
function getColumnWidth(type, mode = "full") {
|
|
239
|
+
if (mode === "compact" && type in COMPACT_COLUMN_WIDTHS) {
|
|
240
|
+
return COMPACT_COLUMN_WIDTHS[type];
|
|
241
|
+
}
|
|
242
|
+
return COLUMN_WIDTHS[type] ?? COLUMN_WIDTHS.text;
|
|
243
|
+
}
|
|
244
|
+
function calculateTableWidth(columns, mode = "full") {
|
|
245
|
+
return columns.reduce((sum, col) => sum + getColumnWidth(col.type, mode), 0);
|
|
246
|
+
}
|
|
247
|
+
function getCompactLabel(fieldName, originalLabel) {
|
|
248
|
+
const normalized = fieldName.toLowerCase();
|
|
249
|
+
return COMPACT_LABELS[normalized] ?? originalLabel;
|
|
250
|
+
}
|
|
251
|
+
function getCompactFormatter(type) {
|
|
252
|
+
return COMPACT_FORMATTERS[type];
|
|
253
|
+
}
|
|
254
|
+
function determineTableMode(containerWidth, columns) {
|
|
255
|
+
const { minForTable, widthBuffer } = TABLE_BREAKPOINTS;
|
|
256
|
+
if (containerWidth < minForTable) {
|
|
257
|
+
return "cards";
|
|
258
|
+
}
|
|
259
|
+
const fullWidth = calculateTableWidth(columns, "full");
|
|
260
|
+
const compactColumns = columns.filter(
|
|
261
|
+
(col) => IMPORTANCE_VISIBILITY.compact.includes(
|
|
262
|
+
col.importance ?? "medium"
|
|
263
|
+
)
|
|
264
|
+
);
|
|
265
|
+
const compactWidth = calculateTableWidth(compactColumns, "compact");
|
|
266
|
+
if (fullWidth + widthBuffer <= containerWidth) {
|
|
267
|
+
return "full";
|
|
268
|
+
}
|
|
269
|
+
if (compactWidth + widthBuffer <= containerWidth) {
|
|
270
|
+
return "compact";
|
|
271
|
+
}
|
|
272
|
+
return "cards";
|
|
273
|
+
}
|
|
139
274
|
const breakpoints = {
|
|
140
275
|
"2xs": 400,
|
|
141
276
|
xs: 500,
|
|
@@ -2009,6 +2144,498 @@ function renderField(value, fieldName, fieldType, breakpoint, item, customRender
|
|
|
2009
2144
|
function cn(...inputs) {
|
|
2010
2145
|
return twMerge(clsx(inputs));
|
|
2011
2146
|
}
|
|
2147
|
+
const IconBadge = ({
|
|
2148
|
+
children,
|
|
2149
|
+
icon,
|
|
2150
|
+
variant = "category",
|
|
2151
|
+
category = 1,
|
|
2152
|
+
status = "neutral",
|
|
2153
|
+
size = "md",
|
|
2154
|
+
interactive = false,
|
|
2155
|
+
onClick,
|
|
2156
|
+
className,
|
|
2157
|
+
tooltip
|
|
2158
|
+
}) => {
|
|
2159
|
+
const currentSize = useResponsiveValue(size);
|
|
2160
|
+
const sizeConfig = responsiveScales.components.iconBadge[currentSize];
|
|
2161
|
+
const sizeClasses2 = {
|
|
2162
|
+
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"}`,
|
|
2163
|
+
sm: "w-8 h-8 text-xs rounded-lg",
|
|
2164
|
+
md: "w-10 h-10 text-sm rounded-xl",
|
|
2165
|
+
lg: "w-12 h-12 text-base rounded-xl"
|
|
2166
|
+
};
|
|
2167
|
+
const baseClasses = cn(
|
|
2168
|
+
"inline-flex items-center justify-center font-bold shadow-md",
|
|
2169
|
+
sizeClasses2[currentSize],
|
|
2170
|
+
interactive && [
|
|
2171
|
+
"cursor-pointer",
|
|
2172
|
+
getAnimationClasses({
|
|
2173
|
+
...animationPresets.dataBadge,
|
|
2174
|
+
size: currentSize === "lg" ? "lg" : currentSize === "sm" || currentSize === "xs" ? "sm" : "md"
|
|
2175
|
+
})
|
|
2176
|
+
],
|
|
2177
|
+
className
|
|
2178
|
+
);
|
|
2179
|
+
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";
|
|
2180
|
+
const badge = /* @__PURE__ */ jsxs(
|
|
2181
|
+
"div",
|
|
2182
|
+
{
|
|
2183
|
+
className: cn(baseClasses, gradientClasses, "animate-fade-in"),
|
|
2184
|
+
onClick,
|
|
2185
|
+
role: interactive ? "button" : void 0,
|
|
2186
|
+
tabIndex: interactive ? 0 : void 0,
|
|
2187
|
+
onKeyDown: interactive ? (e) => {
|
|
2188
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
2189
|
+
e.preventDefault();
|
|
2190
|
+
onClick == null ? void 0 : onClick();
|
|
2191
|
+
}
|
|
2192
|
+
} : void 0,
|
|
2193
|
+
"data-component-name": "IconBadge",
|
|
2194
|
+
children: [
|
|
2195
|
+
icon && /* @__PURE__ */ jsx("span", { className: "text-primary-foreground drop-shadow", children: icon }),
|
|
2196
|
+
children && !icon && /* @__PURE__ */ jsx("span", { className: "text-primary-foreground font-bold", children })
|
|
2197
|
+
]
|
|
2198
|
+
}
|
|
2199
|
+
);
|
|
2200
|
+
if (tooltip) {
|
|
2201
|
+
return /* @__PURE__ */ jsx(Tooltip, { content: tooltip, position: "top", size: "sm", children: badge });
|
|
2202
|
+
}
|
|
2203
|
+
return badge;
|
|
2204
|
+
};
|
|
2205
|
+
const valueColorMap = {
|
|
2206
|
+
success: "text-green-600",
|
|
2207
|
+
error: "text-red-600",
|
|
2208
|
+
warning: "text-yellow-600",
|
|
2209
|
+
info: "text-blue-600",
|
|
2210
|
+
neutral: "text-muted-foreground",
|
|
2211
|
+
default: "text-foreground"
|
|
2212
|
+
};
|
|
2213
|
+
function ListCard({
|
|
2214
|
+
icon,
|
|
2215
|
+
title,
|
|
2216
|
+
subtitle,
|
|
2217
|
+
metadata,
|
|
2218
|
+
value,
|
|
2219
|
+
badge,
|
|
2220
|
+
onClick,
|
|
2221
|
+
className,
|
|
2222
|
+
children
|
|
2223
|
+
}) {
|
|
2224
|
+
return /* @__PURE__ */ jsxs(
|
|
2225
|
+
"div",
|
|
2226
|
+
{
|
|
2227
|
+
className: cn(
|
|
2228
|
+
"flex items-start gap-3 p-3 rounded-lg border border-border transition-colors",
|
|
2229
|
+
onClick && "hover:bg-muted/50 cursor-pointer",
|
|
2230
|
+
className
|
|
2231
|
+
),
|
|
2232
|
+
onClick,
|
|
2233
|
+
children: [
|
|
2234
|
+
icon && /* @__PURE__ */ jsx(
|
|
2235
|
+
IconBadge,
|
|
2236
|
+
{
|
|
2237
|
+
variant: icon.variant || "category",
|
|
2238
|
+
category: icon.variant === "category" ? icon.category || 1 : void 0,
|
|
2239
|
+
status: icon.variant === "status" ? icon.status || "neutral" : void 0,
|
|
2240
|
+
size: icon.size || "sm",
|
|
2241
|
+
icon: icon.icon,
|
|
2242
|
+
tooltip: icon.tooltip
|
|
2243
|
+
}
|
|
2244
|
+
),
|
|
2245
|
+
/* @__PURE__ */ jsxs("div", { className: "flex-1 min-w-0", children: [
|
|
2246
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between gap-2", children: [
|
|
2247
|
+
/* @__PURE__ */ jsxs("div", { className: "flex-1", children: [
|
|
2248
|
+
/* @__PURE__ */ jsx("h4", { className: "text-sm font-medium text-foreground truncate", children: title }),
|
|
2249
|
+
subtitle && /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground mt-0.5", children: subtitle }),
|
|
2250
|
+
metadata && metadata.length > 0 && /* @__PURE__ */ jsx("div", { className: "flex items-center gap-3 mt-1", children: metadata.map((item, index) => /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", children: item }, index)) })
|
|
2251
|
+
] }),
|
|
2252
|
+
(value || badge) && /* @__PURE__ */ jsxs("div", { className: "text-right", children: [
|
|
2253
|
+
value && /* @__PURE__ */ jsx(
|
|
2254
|
+
"p",
|
|
2255
|
+
{
|
|
2256
|
+
className: cn(
|
|
2257
|
+
"text-sm font-semibold",
|
|
2258
|
+
value.variant && valueColorMap[value.variant],
|
|
2259
|
+
value.className
|
|
2260
|
+
),
|
|
2261
|
+
children: value.text
|
|
2262
|
+
}
|
|
2263
|
+
),
|
|
2264
|
+
badge && /* @__PURE__ */ jsx(
|
|
2265
|
+
DataBadge,
|
|
2266
|
+
{
|
|
2267
|
+
variant: badge.variant,
|
|
2268
|
+
status: badge.variant === "status" ? badge.status : void 0,
|
|
2269
|
+
category: badge.variant === "category" ? badge.category : void 0,
|
|
2270
|
+
size: badge.size || "sm",
|
|
2271
|
+
icon: badge.icon,
|
|
2272
|
+
className: "mt-1",
|
|
2273
|
+
children: badge.text
|
|
2274
|
+
}
|
|
2275
|
+
)
|
|
2276
|
+
] })
|
|
2277
|
+
] }),
|
|
2278
|
+
children
|
|
2279
|
+
] })
|
|
2280
|
+
]
|
|
2281
|
+
}
|
|
2282
|
+
);
|
|
2283
|
+
}
|
|
2284
|
+
const STATUS_COLOR_MAP = {
|
|
2285
|
+
// Success states
|
|
2286
|
+
active: "success",
|
|
2287
|
+
completed: "success",
|
|
2288
|
+
approved: "success",
|
|
2289
|
+
paid: "success",
|
|
2290
|
+
delivered: "success",
|
|
2291
|
+
resolved: "success",
|
|
2292
|
+
closed: "success",
|
|
2293
|
+
// Warning states
|
|
2294
|
+
pending: "warning",
|
|
2295
|
+
processing: "warning",
|
|
2296
|
+
review: "warning",
|
|
2297
|
+
draft: "warning",
|
|
2298
|
+
waiting: "warning",
|
|
2299
|
+
// Error states
|
|
2300
|
+
failed: "error",
|
|
2301
|
+
rejected: "error",
|
|
2302
|
+
cancelled: "error",
|
|
2303
|
+
overdue: "error",
|
|
2304
|
+
blocked: "error",
|
|
2305
|
+
// Info states
|
|
2306
|
+
new: "info",
|
|
2307
|
+
open: "info",
|
|
2308
|
+
in_progress: "info",
|
|
2309
|
+
scheduled: "info",
|
|
2310
|
+
// Neutral (default)
|
|
2311
|
+
inactive: "neutral",
|
|
2312
|
+
archived: "neutral",
|
|
2313
|
+
unknown: "neutral"
|
|
2314
|
+
};
|
|
2315
|
+
function getStatusColor(value) {
|
|
2316
|
+
if (typeof value !== "string") return "neutral";
|
|
2317
|
+
const normalized = value.toLowerCase().replace(/[_-]/g, "_");
|
|
2318
|
+
return STATUS_COLOR_MAP[normalized] ?? "neutral";
|
|
2319
|
+
}
|
|
2320
|
+
const CATEGORY_MAP = {
|
|
2321
|
+
account: 1,
|
|
2322
|
+
customer: 1,
|
|
2323
|
+
client: 1,
|
|
2324
|
+
user: 2,
|
|
2325
|
+
contact: 2,
|
|
2326
|
+
person: 2,
|
|
2327
|
+
order: 3,
|
|
2328
|
+
sale: 3,
|
|
2329
|
+
transaction: 3,
|
|
2330
|
+
product: 4,
|
|
2331
|
+
item: 4,
|
|
2332
|
+
inventory: 4,
|
|
2333
|
+
task: 5,
|
|
2334
|
+
activity: 5,
|
|
2335
|
+
event: 5,
|
|
2336
|
+
file: 6,
|
|
2337
|
+
document: 6,
|
|
2338
|
+
report: 6,
|
|
2339
|
+
tag: 7,
|
|
2340
|
+
category: 7,
|
|
2341
|
+
label: 7,
|
|
2342
|
+
default: 8
|
|
2343
|
+
};
|
|
2344
|
+
function getCategoryForEntity(entityType) {
|
|
2345
|
+
if (!entityType) return 8;
|
|
2346
|
+
const normalized = entityType.toLowerCase();
|
|
2347
|
+
for (const [key, value] of Object.entries(CATEGORY_MAP)) {
|
|
2348
|
+
if (normalized.includes(key)) return value;
|
|
2349
|
+
}
|
|
2350
|
+
return 8;
|
|
2351
|
+
}
|
|
2352
|
+
function getIconForEntity(entityType) {
|
|
2353
|
+
if (!entityType) return /* @__PURE__ */ jsx(Circle, { className: "w-4 h-4" });
|
|
2354
|
+
const normalized = entityType.toLowerCase();
|
|
2355
|
+
if (normalized.includes("account") || normalized.includes("customer") || normalized.includes("client")) {
|
|
2356
|
+
return /* @__PURE__ */ jsx(Building2, { className: "w-4 h-4" });
|
|
2357
|
+
}
|
|
2358
|
+
if (normalized.includes("user") || normalized.includes("contact") || normalized.includes("person")) {
|
|
2359
|
+
return /* @__PURE__ */ jsx(User, { className: "w-4 h-4" });
|
|
2360
|
+
}
|
|
2361
|
+
if (normalized.includes("product") || normalized.includes("item")) {
|
|
2362
|
+
return /* @__PURE__ */ jsx(Package, { className: "w-4 h-4" });
|
|
2363
|
+
}
|
|
2364
|
+
if (normalized.includes("file") || normalized.includes("document")) {
|
|
2365
|
+
return /* @__PURE__ */ jsx(FileText, { className: "w-4 h-4" });
|
|
2366
|
+
}
|
|
2367
|
+
if (normalized.includes("tag") || normalized.includes("category")) {
|
|
2368
|
+
return /* @__PURE__ */ jsx(Tag, { className: "w-4 h-4" });
|
|
2369
|
+
}
|
|
2370
|
+
return /* @__PURE__ */ jsx(Circle, { className: "w-4 h-4" });
|
|
2371
|
+
}
|
|
2372
|
+
function normalizeImportance(importance) {
|
|
2373
|
+
switch (importance) {
|
|
2374
|
+
case "critical":
|
|
2375
|
+
case "high":
|
|
2376
|
+
case "primary":
|
|
2377
|
+
return "primary";
|
|
2378
|
+
case "medium":
|
|
2379
|
+
case "secondary":
|
|
2380
|
+
return "secondary";
|
|
2381
|
+
default:
|
|
2382
|
+
return "tertiary";
|
|
2383
|
+
}
|
|
2384
|
+
}
|
|
2385
|
+
function isPrimaryImportance(importance) {
|
|
2386
|
+
return normalizeImportance(importance) === "primary";
|
|
2387
|
+
}
|
|
2388
|
+
function formatValueForCard(value, type, format) {
|
|
2389
|
+
if (value === null || value === void 0) return "—";
|
|
2390
|
+
switch (type) {
|
|
2391
|
+
case "money": {
|
|
2392
|
+
const num = Number(value);
|
|
2393
|
+
const currency = (format == null ? void 0 : format.currency) ?? "USD";
|
|
2394
|
+
if (num >= 1e6) {
|
|
2395
|
+
return new Intl.NumberFormat("en-US", {
|
|
2396
|
+
style: "currency",
|
|
2397
|
+
currency,
|
|
2398
|
+
notation: "compact",
|
|
2399
|
+
maximumFractionDigits: 1
|
|
2400
|
+
}).format(num);
|
|
2401
|
+
}
|
|
2402
|
+
if (num >= 1e3) {
|
|
2403
|
+
return new Intl.NumberFormat("en-US", {
|
|
2404
|
+
style: "currency",
|
|
2405
|
+
currency,
|
|
2406
|
+
notation: "compact",
|
|
2407
|
+
maximumFractionDigits: 1
|
|
2408
|
+
}).format(num);
|
|
2409
|
+
}
|
|
2410
|
+
return new Intl.NumberFormat("en-US", {
|
|
2411
|
+
style: "currency",
|
|
2412
|
+
currency,
|
|
2413
|
+
maximumFractionDigits: 0
|
|
2414
|
+
}).format(num);
|
|
2415
|
+
}
|
|
2416
|
+
case "percent": {
|
|
2417
|
+
const num = Number(value);
|
|
2418
|
+
return `${num.toFixed(0)}%`;
|
|
2419
|
+
}
|
|
2420
|
+
case "number": {
|
|
2421
|
+
const num = Number(value);
|
|
2422
|
+
if (num >= 1e6) return `${(num / 1e6).toFixed(1)}M`;
|
|
2423
|
+
if (num >= 1e3) return `${(num / 1e3).toFixed(1)}K`;
|
|
2424
|
+
return String(num);
|
|
2425
|
+
}
|
|
2426
|
+
case "date":
|
|
2427
|
+
case "datetime": {
|
|
2428
|
+
const date = new Date(String(value));
|
|
2429
|
+
if (isNaN(date.getTime())) return String(value);
|
|
2430
|
+
return date.toLocaleDateString("en-US", {
|
|
2431
|
+
month: "short",
|
|
2432
|
+
day: "numeric"
|
|
2433
|
+
});
|
|
2434
|
+
}
|
|
2435
|
+
case "boolean":
|
|
2436
|
+
return value ? "Yes" : "No";
|
|
2437
|
+
default:
|
|
2438
|
+
return String(value);
|
|
2439
|
+
}
|
|
2440
|
+
}
|
|
2441
|
+
function autoDetectMapping(columns) {
|
|
2442
|
+
var _a, _b, _c, _d, _e, _f;
|
|
2443
|
+
const primaryCols = columns.filter((c) => isPrimaryImportance(c.importance));
|
|
2444
|
+
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);
|
|
2445
|
+
const valueField = (_d = primaryCols.find((c) => c.type === "money")) == null ? void 0 : _d.field;
|
|
2446
|
+
const statusField = (_e = primaryCols.find(
|
|
2447
|
+
(c) => c.type === "status" || c.type === "badge"
|
|
2448
|
+
)) == null ? void 0 : _e.field;
|
|
2449
|
+
const usedForMain = new Set([titleField, valueField, statusField].filter(Boolean));
|
|
2450
|
+
const remainingPrimary = primaryCols.filter((c) => !usedForMain.has(c.field));
|
|
2451
|
+
const subtitleField = (_f = remainingPrimary[0]) == null ? void 0 : _f.field;
|
|
2452
|
+
const usedFields = new Set(
|
|
2453
|
+
[titleField, valueField, statusField, subtitleField].filter(Boolean)
|
|
2454
|
+
);
|
|
2455
|
+
const metadataFields = primaryCols.filter((c) => !usedFields.has(c.field)).slice(0, 3).map((c) => c.field);
|
|
2456
|
+
return {
|
|
2457
|
+
titleField: titleField ?? "id",
|
|
2458
|
+
subtitleField,
|
|
2459
|
+
valueField,
|
|
2460
|
+
statusField,
|
|
2461
|
+
metadataFields,
|
|
2462
|
+
iconConfig: void 0
|
|
2463
|
+
};
|
|
2464
|
+
}
|
|
2465
|
+
function entityToListCardProps(item, columns, mapping, entityType) {
|
|
2466
|
+
const autoMapping = autoDetectMapping(columns);
|
|
2467
|
+
const effectiveMapping = { ...autoMapping, ...mapping };
|
|
2468
|
+
const {
|
|
2469
|
+
titleField,
|
|
2470
|
+
subtitleField,
|
|
2471
|
+
valueField,
|
|
2472
|
+
statusField,
|
|
2473
|
+
metadataFields,
|
|
2474
|
+
iconConfig
|
|
2475
|
+
} = effectiveMapping;
|
|
2476
|
+
const getColumn = (field) => field ? columns.find((c) => c.field === field) : void 0;
|
|
2477
|
+
const title = item[titleField] != null ? String(item[titleField]) : "—";
|
|
2478
|
+
const subtitle = subtitleField && item[subtitleField] != null ? String(item[subtitleField]) : void 0;
|
|
2479
|
+
let value;
|
|
2480
|
+
if (valueField && item[valueField] != null) {
|
|
2481
|
+
const valueCol = getColumn(valueField);
|
|
2482
|
+
const formatted = formatValueForCard(
|
|
2483
|
+
item[valueField],
|
|
2484
|
+
(valueCol == null ? void 0 : valueCol.type) ?? "text",
|
|
2485
|
+
valueCol == null ? void 0 : valueCol.format
|
|
2486
|
+
);
|
|
2487
|
+
value = {
|
|
2488
|
+
text: formatted,
|
|
2489
|
+
variant: "success"
|
|
2490
|
+
// Money typically green
|
|
2491
|
+
};
|
|
2492
|
+
}
|
|
2493
|
+
let badge;
|
|
2494
|
+
if (statusField && item[statusField] != null) {
|
|
2495
|
+
const statusValue = String(item[statusField]);
|
|
2496
|
+
badge = {
|
|
2497
|
+
text: statusValue,
|
|
2498
|
+
variant: "status",
|
|
2499
|
+
status: getStatusColor(statusValue),
|
|
2500
|
+
size: "sm"
|
|
2501
|
+
};
|
|
2502
|
+
}
|
|
2503
|
+
const metadata = metadataFields == null ? void 0 : metadataFields.map((field) => {
|
|
2504
|
+
const col = getColumn(field);
|
|
2505
|
+
if (!col || item[field] == null) return null;
|
|
2506
|
+
return formatValueForCard(item[field], col.type, col.format);
|
|
2507
|
+
}).filter((v) => v !== null);
|
|
2508
|
+
let icon;
|
|
2509
|
+
if (iconConfig) {
|
|
2510
|
+
const iconValue = iconConfig.field ? item[iconConfig.field] : void 0;
|
|
2511
|
+
if (iconConfig.variant === "status" && iconValue) {
|
|
2512
|
+
icon = {
|
|
2513
|
+
icon: iconConfig.icon ?? getIconForEntity(entityType),
|
|
2514
|
+
variant: "status",
|
|
2515
|
+
status: getStatusColor(iconValue),
|
|
2516
|
+
size: "sm"
|
|
2517
|
+
};
|
|
2518
|
+
} else {
|
|
2519
|
+
icon = {
|
|
2520
|
+
icon: iconConfig.icon ?? getIconForEntity(entityType),
|
|
2521
|
+
variant: "category",
|
|
2522
|
+
category: getCategoryForEntity(entityType),
|
|
2523
|
+
size: "sm"
|
|
2524
|
+
};
|
|
2525
|
+
}
|
|
2526
|
+
} else {
|
|
2527
|
+
icon = {
|
|
2528
|
+
icon: getIconForEntity(entityType),
|
|
2529
|
+
variant: "category",
|
|
2530
|
+
category: getCategoryForEntity(entityType),
|
|
2531
|
+
size: "sm"
|
|
2532
|
+
};
|
|
2533
|
+
}
|
|
2534
|
+
return {
|
|
2535
|
+
icon,
|
|
2536
|
+
title,
|
|
2537
|
+
subtitle,
|
|
2538
|
+
metadata,
|
|
2539
|
+
value,
|
|
2540
|
+
badge
|
|
2541
|
+
};
|
|
2542
|
+
}
|
|
2543
|
+
const HEADER_ABBREVIATIONS = {
|
|
2544
|
+
customer: "Cust",
|
|
2545
|
+
account: "Acct",
|
|
2546
|
+
amount: "Amt",
|
|
2547
|
+
quantity: "Qty",
|
|
2548
|
+
priority: "Pri",
|
|
2549
|
+
status: "Status",
|
|
2550
|
+
created: "Created",
|
|
2551
|
+
updated: "Updated",
|
|
2552
|
+
description: "Desc",
|
|
2553
|
+
total: "Total",
|
|
2554
|
+
items: "Items",
|
|
2555
|
+
number: "#",
|
|
2556
|
+
date: "Date",
|
|
2557
|
+
time: "Time"
|
|
2558
|
+
};
|
|
2559
|
+
function abbreviateHeader(label) {
|
|
2560
|
+
const lower = label.toLowerCase();
|
|
2561
|
+
for (const [key, abbrev] of Object.entries(HEADER_ABBREVIATIONS)) {
|
|
2562
|
+
if (lower.includes(key)) return abbrev;
|
|
2563
|
+
}
|
|
2564
|
+
if (label.length > 8) return label.slice(0, 6) + "…";
|
|
2565
|
+
return label;
|
|
2566
|
+
}
|
|
2567
|
+
function generateCompactColumns(columns, options = {}) {
|
|
2568
|
+
const {
|
|
2569
|
+
maxColumns = 5,
|
|
2570
|
+
abbreviateHeaders = true,
|
|
2571
|
+
requiredFields = [],
|
|
2572
|
+
excludeFields = []
|
|
2573
|
+
} = options;
|
|
2574
|
+
const excludeSet = new Set(excludeFields);
|
|
2575
|
+
const requiredSet = new Set(requiredFields);
|
|
2576
|
+
const filteredColumns = columns.filter((col) => {
|
|
2577
|
+
if (excludeSet.has(col.field)) return false;
|
|
2578
|
+
return true;
|
|
2579
|
+
});
|
|
2580
|
+
const required = filteredColumns.filter((c) => requiredSet.has(c.field));
|
|
2581
|
+
const primary = filteredColumns.filter(
|
|
2582
|
+
(c) => !requiredSet.has(c.field) && normalizeImportance(c.importance) === "primary"
|
|
2583
|
+
);
|
|
2584
|
+
const secondary = filteredColumns.filter(
|
|
2585
|
+
(c) => !requiredSet.has(c.field) && normalizeImportance(c.importance) === "secondary"
|
|
2586
|
+
);
|
|
2587
|
+
const selectedColumns = [...required, ...primary, ...secondary].slice(
|
|
2588
|
+
0,
|
|
2589
|
+
maxColumns
|
|
2590
|
+
);
|
|
2591
|
+
return selectedColumns.map((col) => ({
|
|
2592
|
+
key: col.field,
|
|
2593
|
+
header: abbreviateHeaders ? abbreviateHeader(col.label) : col.label,
|
|
2594
|
+
sortable: col.sortable,
|
|
2595
|
+
type: col.type,
|
|
2596
|
+
format: col.format,
|
|
2597
|
+
// Compact widths
|
|
2598
|
+
width: getCompactWidth(col.type)
|
|
2599
|
+
}));
|
|
2600
|
+
}
|
|
2601
|
+
function getCompactWidth(type) {
|
|
2602
|
+
switch (type) {
|
|
2603
|
+
case "money":
|
|
2604
|
+
return "70px";
|
|
2605
|
+
case "number":
|
|
2606
|
+
case "percent":
|
|
2607
|
+
return "50px";
|
|
2608
|
+
case "status":
|
|
2609
|
+
case "badge":
|
|
2610
|
+
return "80px";
|
|
2611
|
+
case "date":
|
|
2612
|
+
return "70px";
|
|
2613
|
+
case "datetime":
|
|
2614
|
+
return "90px";
|
|
2615
|
+
case "boolean":
|
|
2616
|
+
return "50px";
|
|
2617
|
+
default:
|
|
2618
|
+
return "120px";
|
|
2619
|
+
}
|
|
2620
|
+
}
|
|
2621
|
+
function createMobileCardRenderer(columns, mapping, entityType) {
|
|
2622
|
+
return ({ data, onItemClick }) => /* @__PURE__ */ jsx("div", { className: "space-y-2", children: data.map((item, index) => {
|
|
2623
|
+
const cardProps = entityToListCardProps(
|
|
2624
|
+
item,
|
|
2625
|
+
columns,
|
|
2626
|
+
mapping,
|
|
2627
|
+
entityType
|
|
2628
|
+
);
|
|
2629
|
+
return /* @__PURE__ */ jsx(
|
|
2630
|
+
ListCard,
|
|
2631
|
+
{
|
|
2632
|
+
...cardProps,
|
|
2633
|
+
onClick: onItemClick ? () => onItemClick(item) : void 0
|
|
2634
|
+
},
|
|
2635
|
+
item.id ?? index
|
|
2636
|
+
);
|
|
2637
|
+
}) });
|
|
2638
|
+
}
|
|
2012
2639
|
let globalAuthService = null;
|
|
2013
2640
|
function setGlobalAuthService(authService) {
|
|
2014
2641
|
globalAuthService = authService;
|
|
@@ -2174,10 +2801,10 @@ function useApiMutation(mutationFn, options) {
|
|
|
2174
2801
|
const queryClient = useQueryClient();
|
|
2175
2802
|
return useMutation({
|
|
2176
2803
|
mutationFn,
|
|
2177
|
-
onSuccess: (
|
|
2804
|
+
onSuccess: (...args) => {
|
|
2178
2805
|
var _a;
|
|
2179
|
-
queryClient.invalidateQueries();
|
|
2180
|
-
(_a = options == null ? void 0 : options.onSuccess) == null ? void 0 : _a.call(options,
|
|
2806
|
+
void queryClient.invalidateQueries({});
|
|
2807
|
+
(_a = options == null ? void 0 : options.onSuccess) == null ? void 0 : _a.call(options, ...args);
|
|
2181
2808
|
},
|
|
2182
2809
|
...options
|
|
2183
2810
|
});
|
|
@@ -2252,43 +2879,87 @@ function useFieldMetadata({
|
|
|
2252
2879
|
}
|
|
2253
2880
|
function useResponsiveTable(options = {}) {
|
|
2254
2881
|
const {
|
|
2882
|
+
columns,
|
|
2255
2883
|
initialView = "full",
|
|
2256
2884
|
autoSwitch = true,
|
|
2257
|
-
minWidthForCompact =
|
|
2885
|
+
minWidthForCompact = TABLE_BREAKPOINTS.minForTable,
|
|
2258
2886
|
debounceMs = 100,
|
|
2259
2887
|
onViewChange
|
|
2260
2888
|
} = options;
|
|
2261
2889
|
const [viewMode, setViewModeState] = useState(initialView);
|
|
2262
2890
|
const [isAutoSwitching, setIsAutoSwitching] = useState(autoSwitch);
|
|
2891
|
+
const [containerWidth, setContainerWidth] = useState(0);
|
|
2263
2892
|
const [overflowState, setOverflowState] = useState({
|
|
2264
2893
|
fullOverflows: false,
|
|
2265
2894
|
compactOverflows: false
|
|
2266
2895
|
});
|
|
2896
|
+
const containerRef = useRef(null);
|
|
2267
2897
|
const fullTableRef = useRef(null);
|
|
2268
2898
|
const compactTableRef = useRef(null);
|
|
2269
2899
|
const debounceTimerRef = useRef(null);
|
|
2270
2900
|
const isTransitioningRef = useRef(false);
|
|
2901
|
+
const compactColumns = useCallback(() => {
|
|
2902
|
+
if (!columns) return null;
|
|
2903
|
+
const validImportance = IMPORTANCE_VISIBILITY.compact;
|
|
2904
|
+
const filtered = columns.filter(
|
|
2905
|
+
(col) => validImportance.includes(col.importance ?? "medium")
|
|
2906
|
+
);
|
|
2907
|
+
const limited = filtered.slice(0, TABLE_BREAKPOINTS.maxCompactColumns);
|
|
2908
|
+
return limited.map((col) => ({
|
|
2909
|
+
...col,
|
|
2910
|
+
label: getCompactLabel(col.field, col.label)
|
|
2911
|
+
}));
|
|
2912
|
+
}, [columns])();
|
|
2913
|
+
const calculatedWidths = useCallback(() => {
|
|
2914
|
+
if (!columns) {
|
|
2915
|
+
return { full: 0, compact: 0, container: containerWidth };
|
|
2916
|
+
}
|
|
2917
|
+
const fullWidth = calculateTableWidth(
|
|
2918
|
+
columns.map((c) => ({ type: c.type })),
|
|
2919
|
+
"full"
|
|
2920
|
+
);
|
|
2921
|
+
const compactCols = compactColumns ?? [];
|
|
2922
|
+
const compactWidth = calculateTableWidth(
|
|
2923
|
+
compactCols.map((c) => ({ type: c.type })),
|
|
2924
|
+
"compact"
|
|
2925
|
+
);
|
|
2926
|
+
return {
|
|
2927
|
+
full: fullWidth,
|
|
2928
|
+
compact: compactWidth,
|
|
2929
|
+
container: containerWidth
|
|
2930
|
+
};
|
|
2931
|
+
}, [columns, compactColumns, containerWidth])();
|
|
2271
2932
|
const hasOverflow = useCallback((element) => {
|
|
2272
2933
|
if (!element) return false;
|
|
2273
2934
|
return element.scrollWidth > element.clientWidth + 2;
|
|
2274
2935
|
}, []);
|
|
2275
2936
|
const determineView = useCallback(() => {
|
|
2276
|
-
var _a, _b, _c, _d;
|
|
2277
|
-
|
|
2278
|
-
|
|
2937
|
+
var _a, _b, _c, _d, _e;
|
|
2938
|
+
if (columns && containerWidth > 0) {
|
|
2939
|
+
const { full, compact } = calculatedWidths;
|
|
2940
|
+
const buffer = TABLE_BREAKPOINTS.widthBuffer;
|
|
2941
|
+
if (containerWidth < minWidthForCompact) {
|
|
2942
|
+
return "cards";
|
|
2943
|
+
}
|
|
2944
|
+
if (full + buffer <= containerWidth) {
|
|
2945
|
+
return "full";
|
|
2946
|
+
}
|
|
2947
|
+
if (compact + buffer <= containerWidth) {
|
|
2948
|
+
return "compact";
|
|
2949
|
+
}
|
|
2950
|
+
return "cards";
|
|
2951
|
+
}
|
|
2952
|
+
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;
|
|
2953
|
+
if (width < minWidthForCompact) {
|
|
2279
2954
|
return "cards";
|
|
2280
2955
|
}
|
|
2281
2956
|
const fullOverflows = hasOverflow(fullTableRef.current);
|
|
2282
2957
|
const compactOverflows = hasOverflow(compactTableRef.current);
|
|
2283
2958
|
setOverflowState({ fullOverflows, compactOverflows });
|
|
2284
|
-
if (!fullOverflows)
|
|
2285
|
-
|
|
2286
|
-
}
|
|
2287
|
-
if (!compactOverflows) {
|
|
2288
|
-
return "compact";
|
|
2289
|
-
}
|
|
2959
|
+
if (!fullOverflows) return "full";
|
|
2960
|
+
if (!compactOverflows) return "compact";
|
|
2290
2961
|
return "cards";
|
|
2291
|
-
}, [
|
|
2962
|
+
}, [columns, containerWidth, calculatedWidths, minWidthForCompact, hasOverflow]);
|
|
2292
2963
|
const checkAndUpdate = useCallback(() => {
|
|
2293
2964
|
if (!isAutoSwitching || isTransitioningRef.current) return;
|
|
2294
2965
|
if (debounceTimerRef.current) {
|
|
@@ -2320,42 +2991,49 @@ function useResponsiveTable(options = {}) {
|
|
|
2320
2991
|
useEffect(() => {
|
|
2321
2992
|
var _a, _b;
|
|
2322
2993
|
if (!isAutoSwitching) return;
|
|
2323
|
-
const
|
|
2994
|
+
const updateContainerWidth = () => {
|
|
2995
|
+
var _a2;
|
|
2996
|
+
const ref = containerRef.current || ((_a2 = fullTableRef.current) == null ? void 0 : _a2.parentElement);
|
|
2997
|
+
if (ref) {
|
|
2998
|
+
setContainerWidth(ref.clientWidth);
|
|
2999
|
+
}
|
|
3000
|
+
};
|
|
3001
|
+
const initialTimer = setTimeout(updateContainerWidth, 50);
|
|
2324
3002
|
const resizeObserver = new ResizeObserver(() => {
|
|
3003
|
+
updateContainerWidth();
|
|
2325
3004
|
checkAndUpdate();
|
|
2326
3005
|
});
|
|
2327
|
-
|
|
2328
|
-
|
|
3006
|
+
const observeTarget = containerRef.current || ((_a = fullTableRef.current) == null ? void 0 : _a.parentElement) || ((_b = compactTableRef.current) == null ? void 0 : _b.parentElement);
|
|
3007
|
+
if (observeTarget) {
|
|
3008
|
+
resizeObserver.observe(observeTarget);
|
|
2329
3009
|
}
|
|
2330
|
-
if (
|
|
2331
|
-
resizeObserver.observe(
|
|
2332
|
-
|
|
2333
|
-
const parent = ((_a = fullTableRef.current) == null ? void 0 : _a.parentElement) || ((_b = compactTableRef.current) == null ? void 0 : _b.parentElement);
|
|
2334
|
-
if (parent) {
|
|
2335
|
-
resizeObserver.observe(parent);
|
|
3010
|
+
if (!columns) {
|
|
3011
|
+
if (fullTableRef.current) resizeObserver.observe(fullTableRef.current);
|
|
3012
|
+
if (compactTableRef.current) resizeObserver.observe(compactTableRef.current);
|
|
2336
3013
|
}
|
|
2337
3014
|
window.addEventListener("resize", checkAndUpdate);
|
|
2338
3015
|
return () => {
|
|
2339
|
-
clearTimeout(
|
|
2340
|
-
if (debounceTimerRef.current)
|
|
2341
|
-
clearTimeout(debounceTimerRef.current);
|
|
2342
|
-
}
|
|
3016
|
+
clearTimeout(initialTimer);
|
|
3017
|
+
if (debounceTimerRef.current) clearTimeout(debounceTimerRef.current);
|
|
2343
3018
|
resizeObserver.disconnect();
|
|
2344
3019
|
window.removeEventListener("resize", checkAndUpdate);
|
|
2345
3020
|
};
|
|
2346
|
-
}, [isAutoSwitching, checkAndUpdate]);
|
|
3021
|
+
}, [isAutoSwitching, columns, checkAndUpdate]);
|
|
2347
3022
|
useEffect(() => {
|
|
2348
3023
|
if (!isAutoSwitching) return;
|
|
2349
3024
|
const timer = setTimeout(checkAndUpdate, 100);
|
|
2350
3025
|
return () => clearTimeout(timer);
|
|
2351
|
-
}, [viewMode, isAutoSwitching, checkAndUpdate]);
|
|
3026
|
+
}, [viewMode, containerWidth, isAutoSwitching, checkAndUpdate]);
|
|
2352
3027
|
return {
|
|
2353
3028
|
viewMode,
|
|
2354
3029
|
setViewMode,
|
|
2355
3030
|
enableAutoSwitch,
|
|
2356
3031
|
isAutoSwitching,
|
|
3032
|
+
containerRef,
|
|
2357
3033
|
fullTableRef,
|
|
2358
3034
|
compactTableRef,
|
|
3035
|
+
compactColumns,
|
|
3036
|
+
calculatedWidths,
|
|
2359
3037
|
overflowState
|
|
2360
3038
|
};
|
|
2361
3039
|
}
|
|
@@ -2374,6 +3052,154 @@ function useOverflowDetection(ref) {
|
|
|
2374
3052
|
}, [ref]);
|
|
2375
3053
|
return hasOverflow;
|
|
2376
3054
|
}
|
|
3055
|
+
const IMPORTANCE_PRIORITY = {
|
|
3056
|
+
minimal: 0,
|
|
3057
|
+
low: 1,
|
|
3058
|
+
tertiary: 2,
|
|
3059
|
+
medium: 3,
|
|
3060
|
+
secondary: 4,
|
|
3061
|
+
high: 5,
|
|
3062
|
+
critical: 6,
|
|
3063
|
+
primary: 7
|
|
3064
|
+
};
|
|
3065
|
+
function getColumnModeWidth(col, mode) {
|
|
3066
|
+
if (mode === "hidden") return 0;
|
|
3067
|
+
return getColumnWidth(col.type, mode === "compact" ? "compact" : "full");
|
|
3068
|
+
}
|
|
3069
|
+
function calculateAdaptiveWidth(columns, modes) {
|
|
3070
|
+
return columns.reduce((sum, col) => sum + getColumnModeWidth(col, modes[col.field] ?? "full"), 0);
|
|
3071
|
+
}
|
|
3072
|
+
function calculateColumnModes(columns, containerWidth, protectedColumns, minColumnsVisible) {
|
|
3073
|
+
const buffer = TABLE_BREAKPOINTS.widthBuffer;
|
|
3074
|
+
const sortedByImportance = [...columns].sort((a, b) => {
|
|
3075
|
+
const priorityA = IMPORTANCE_PRIORITY[a.importance ?? "tertiary"];
|
|
3076
|
+
const priorityB = IMPORTANCE_PRIORITY[b.importance ?? "tertiary"];
|
|
3077
|
+
return priorityA - priorityB;
|
|
3078
|
+
});
|
|
3079
|
+
const modes = {};
|
|
3080
|
+
columns.forEach((col) => modes[col.field] = "full");
|
|
3081
|
+
let currentWidth = calculateAdaptiveWidth(columns, modes);
|
|
3082
|
+
if (currentWidth + buffer <= containerWidth) {
|
|
3083
|
+
return { modes, degradationLevel: 0 };
|
|
3084
|
+
}
|
|
3085
|
+
let degradationLevel = 1;
|
|
3086
|
+
for (const col of sortedByImportance) {
|
|
3087
|
+
if (protectedColumns.has(col.field)) continue;
|
|
3088
|
+
const priority = IMPORTANCE_PRIORITY[col.importance ?? "tertiary"];
|
|
3089
|
+
if (priority > 2) break;
|
|
3090
|
+
modes[col.field] = "compact";
|
|
3091
|
+
currentWidth = calculateAdaptiveWidth(columns, modes);
|
|
3092
|
+
if (currentWidth + buffer <= containerWidth) return { modes, degradationLevel };
|
|
3093
|
+
}
|
|
3094
|
+
degradationLevel = 2;
|
|
3095
|
+
for (const col of sortedByImportance) {
|
|
3096
|
+
if (protectedColumns.has(col.field)) continue;
|
|
3097
|
+
const priority = IMPORTANCE_PRIORITY[col.importance ?? "tertiary"];
|
|
3098
|
+
if (priority <= 2) continue;
|
|
3099
|
+
if (priority > 4) break;
|
|
3100
|
+
modes[col.field] = "compact";
|
|
3101
|
+
currentWidth = calculateAdaptiveWidth(columns, modes);
|
|
3102
|
+
if (currentWidth + buffer <= containerWidth) return { modes, degradationLevel };
|
|
3103
|
+
}
|
|
3104
|
+
degradationLevel = 3;
|
|
3105
|
+
let visibleCount = columns.length;
|
|
3106
|
+
for (const col of sortedByImportance) {
|
|
3107
|
+
const priority = IMPORTANCE_PRIORITY[col.importance ?? "tertiary"];
|
|
3108
|
+
if (priority > 2) break;
|
|
3109
|
+
if (visibleCount <= minColumnsVisible) break;
|
|
3110
|
+
modes[col.field] = "hidden";
|
|
3111
|
+
visibleCount--;
|
|
3112
|
+
currentWidth = calculateAdaptiveWidth(columns, modes);
|
|
3113
|
+
if (currentWidth + buffer <= containerWidth) return { modes, degradationLevel };
|
|
3114
|
+
}
|
|
3115
|
+
degradationLevel = 4;
|
|
3116
|
+
for (const col of sortedByImportance) {
|
|
3117
|
+
const priority = IMPORTANCE_PRIORITY[col.importance ?? "tertiary"];
|
|
3118
|
+
if (priority <= 2) continue;
|
|
3119
|
+
if (priority > 4) break;
|
|
3120
|
+
if (visibleCount <= minColumnsVisible) break;
|
|
3121
|
+
modes[col.field] = "hidden";
|
|
3122
|
+
visibleCount--;
|
|
3123
|
+
currentWidth = calculateAdaptiveWidth(columns, modes);
|
|
3124
|
+
if (currentWidth + buffer <= containerWidth) return { modes, degradationLevel };
|
|
3125
|
+
}
|
|
3126
|
+
degradationLevel = 5;
|
|
3127
|
+
for (const col of sortedByImportance) {
|
|
3128
|
+
if (modes[col.field] === "hidden") continue;
|
|
3129
|
+
modes[col.field] = "compact";
|
|
3130
|
+
currentWidth = calculateAdaptiveWidth(columns, modes);
|
|
3131
|
+
if (currentWidth + buffer <= containerWidth) return { modes, degradationLevel };
|
|
3132
|
+
}
|
|
3133
|
+
return { modes, degradationLevel: 6 };
|
|
3134
|
+
}
|
|
3135
|
+
function useAdaptiveTable(options) {
|
|
3136
|
+
const {
|
|
3137
|
+
columns,
|
|
3138
|
+
protectedColumns = [],
|
|
3139
|
+
minColumnsVisible = 2,
|
|
3140
|
+
minWidthForTable = TABLE_BREAKPOINTS.minForTable,
|
|
3141
|
+
debounceMs = 100,
|
|
3142
|
+
onModeChange
|
|
3143
|
+
} = options;
|
|
3144
|
+
const containerRef = useRef(null);
|
|
3145
|
+
const [containerWidth, setContainerWidth] = useState(0);
|
|
3146
|
+
const debounceTimerRef = useRef(null);
|
|
3147
|
+
const protectedSet = useMemo(() => new Set(protectedColumns), [protectedColumns]);
|
|
3148
|
+
const { modes: columnModes, degradationLevel } = useMemo(() => {
|
|
3149
|
+
if (containerWidth === 0) {
|
|
3150
|
+
const modes = {};
|
|
3151
|
+
columns.forEach((col) => modes[col.field] = "full");
|
|
3152
|
+
return { modes, degradationLevel: 0 };
|
|
3153
|
+
}
|
|
3154
|
+
return calculateColumnModes(columns, containerWidth, protectedSet, minColumnsVisible);
|
|
3155
|
+
}, [columns, containerWidth, protectedSet, minColumnsVisible]);
|
|
3156
|
+
const visibleColumns = useMemo(() => {
|
|
3157
|
+
return columns.filter((col) => columnModes[col.field] !== "hidden").map(
|
|
3158
|
+
(col) => columnModes[col.field] === "compact" ? { ...col, label: getCompactLabel(col.field, col.label) } : col
|
|
3159
|
+
);
|
|
3160
|
+
}, [columns, columnModes]);
|
|
3161
|
+
const calculatedWidth = useMemo(
|
|
3162
|
+
() => calculateAdaptiveWidth(columns, columnModes),
|
|
3163
|
+
[columns, columnModes]
|
|
3164
|
+
);
|
|
3165
|
+
const viewMode = useMemo(() => {
|
|
3166
|
+
if (containerWidth > 0 && containerWidth < minWidthForTable) return "cards";
|
|
3167
|
+
if (visibleColumns.length < minColumnsVisible) return "cards";
|
|
3168
|
+
return "table";
|
|
3169
|
+
}, [containerWidth, minWidthForTable, visibleColumns.length, minColumnsVisible]);
|
|
3170
|
+
useEffect(() => {
|
|
3171
|
+
const updateWidth = () => {
|
|
3172
|
+
if (containerRef.current) setContainerWidth(containerRef.current.clientWidth);
|
|
3173
|
+
};
|
|
3174
|
+
const initialTimer = setTimeout(updateWidth, 50);
|
|
3175
|
+
const resizeObserver = new ResizeObserver(() => {
|
|
3176
|
+
if (debounceTimerRef.current) clearTimeout(debounceTimerRef.current);
|
|
3177
|
+
debounceTimerRef.current = setTimeout(updateWidth, debounceMs);
|
|
3178
|
+
});
|
|
3179
|
+
if (containerRef.current) resizeObserver.observe(containerRef.current);
|
|
3180
|
+
return () => {
|
|
3181
|
+
clearTimeout(initialTimer);
|
|
3182
|
+
if (debounceTimerRef.current) clearTimeout(debounceTimerRef.current);
|
|
3183
|
+
resizeObserver.disconnect();
|
|
3184
|
+
};
|
|
3185
|
+
}, [debounceMs]);
|
|
3186
|
+
const prevModesRef = useRef(columnModes);
|
|
3187
|
+
useEffect(() => {
|
|
3188
|
+
if (onModeChange && columnModes !== prevModesRef.current) {
|
|
3189
|
+
onModeChange(columnModes);
|
|
3190
|
+
prevModesRef.current = columnModes;
|
|
3191
|
+
}
|
|
3192
|
+
}, [columnModes, onModeChange]);
|
|
3193
|
+
return {
|
|
3194
|
+
containerRef,
|
|
3195
|
+
columnModes,
|
|
3196
|
+
visibleColumns,
|
|
3197
|
+
viewMode,
|
|
3198
|
+
calculatedWidth,
|
|
3199
|
+
containerWidth,
|
|
3200
|
+
degradationLevel
|
|
3201
|
+
};
|
|
3202
|
+
}
|
|
2377
3203
|
function useEntityData(entity, options = {}) {
|
|
2378
3204
|
var _a, _b, _c;
|
|
2379
3205
|
const {
|
|
@@ -4256,8 +5082,9 @@ function normalizeColumn(col) {
|
|
|
4256
5082
|
return col;
|
|
4257
5083
|
}
|
|
4258
5084
|
function DataTable({
|
|
4259
|
-
data,
|
|
4260
|
-
columns,
|
|
5085
|
+
data: dataProp,
|
|
5086
|
+
columns: columnsProp,
|
|
5087
|
+
query,
|
|
4261
5088
|
searchPlaceholder = "Search...",
|
|
4262
5089
|
pageSize = 10,
|
|
4263
5090
|
showPagination = true,
|
|
@@ -4266,12 +5093,12 @@ function DataTable({
|
|
|
4266
5093
|
emptyMessage = "No data available",
|
|
4267
5094
|
className = "",
|
|
4268
5095
|
hover = false,
|
|
4269
|
-
isLoading = false,
|
|
5096
|
+
isLoading: isLoadingProp = false,
|
|
4270
5097
|
loadingItemCount = 5,
|
|
4271
5098
|
responsive = true,
|
|
4272
5099
|
renderMobileCard,
|
|
4273
5100
|
ui,
|
|
4274
|
-
error = null,
|
|
5101
|
+
error: errorProp = null,
|
|
4275
5102
|
errorTitle,
|
|
4276
5103
|
errorRetry,
|
|
4277
5104
|
selectable = false,
|
|
@@ -4286,6 +5113,10 @@ function DataTable({
|
|
|
4286
5113
|
const [currentPage, setCurrentPage] = useState(1);
|
|
4287
5114
|
const currentBreakpoint = useBreakpoint();
|
|
4288
5115
|
const isMobile = currentBreakpoint === "xs" || currentBreakpoint === "2xs" || currentBreakpoint === "sm";
|
|
5116
|
+
const data = dataProp ?? (query == null ? void 0 : query.data) ?? [];
|
|
5117
|
+
const columns = columnsProp ?? (query == null ? void 0 : query.columns) ?? [];
|
|
5118
|
+
const isLoading = isLoadingProp || (query == null ? void 0 : query.isLoading) || (query == null ? void 0 : query.isLoadingMetadata) || false;
|
|
5119
|
+
const error = errorProp ?? (query == null ? void 0 : query.error) ?? (query == null ? void 0 : query.metadataError) ?? null;
|
|
4289
5120
|
const normalizedColumns = useMemo(
|
|
4290
5121
|
() => columns.map((col) => normalizeColumn(col)),
|
|
4291
5122
|
[columns]
|
|
@@ -4672,64 +5503,6 @@ const TableHead = TableHead$1;
|
|
|
4672
5503
|
const TableHeader = TableHeader$1;
|
|
4673
5504
|
const TableRow = TableRow$1;
|
|
4674
5505
|
const TableFooter = TableFooter$1;
|
|
4675
|
-
const IconBadge = ({
|
|
4676
|
-
children,
|
|
4677
|
-
icon,
|
|
4678
|
-
variant = "category",
|
|
4679
|
-
category = 1,
|
|
4680
|
-
status = "neutral",
|
|
4681
|
-
size = "md",
|
|
4682
|
-
interactive = false,
|
|
4683
|
-
onClick,
|
|
4684
|
-
className,
|
|
4685
|
-
tooltip
|
|
4686
|
-
}) => {
|
|
4687
|
-
const currentSize = useResponsiveValue(size);
|
|
4688
|
-
const sizeConfig = responsiveScales.components.iconBadge[currentSize];
|
|
4689
|
-
const sizeClasses2 = {
|
|
4690
|
-
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"}`,
|
|
4691
|
-
sm: "w-8 h-8 text-xs rounded-lg",
|
|
4692
|
-
md: "w-10 h-10 text-sm rounded-xl",
|
|
4693
|
-
lg: "w-12 h-12 text-base rounded-xl"
|
|
4694
|
-
};
|
|
4695
|
-
const baseClasses = cn(
|
|
4696
|
-
"inline-flex items-center justify-center font-bold shadow-md",
|
|
4697
|
-
sizeClasses2[currentSize],
|
|
4698
|
-
interactive && [
|
|
4699
|
-
"cursor-pointer",
|
|
4700
|
-
getAnimationClasses({
|
|
4701
|
-
...animationPresets.dataBadge,
|
|
4702
|
-
size: currentSize === "lg" ? "lg" : currentSize === "sm" || currentSize === "xs" ? "sm" : "md"
|
|
4703
|
-
})
|
|
4704
|
-
],
|
|
4705
|
-
className
|
|
4706
|
-
);
|
|
4707
|
-
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";
|
|
4708
|
-
const badge = /* @__PURE__ */ jsxs(
|
|
4709
|
-
"div",
|
|
4710
|
-
{
|
|
4711
|
-
className: cn(baseClasses, gradientClasses, "animate-fade-in"),
|
|
4712
|
-
onClick,
|
|
4713
|
-
role: interactive ? "button" : void 0,
|
|
4714
|
-
tabIndex: interactive ? 0 : void 0,
|
|
4715
|
-
onKeyDown: interactive ? (e) => {
|
|
4716
|
-
if (e.key === "Enter" || e.key === " ") {
|
|
4717
|
-
e.preventDefault();
|
|
4718
|
-
onClick == null ? void 0 : onClick();
|
|
4719
|
-
}
|
|
4720
|
-
} : void 0,
|
|
4721
|
-
"data-component-name": "IconBadge",
|
|
4722
|
-
children: [
|
|
4723
|
-
icon && /* @__PURE__ */ jsx("span", { className: "text-primary-foreground drop-shadow", children: icon }),
|
|
4724
|
-
children && !icon && /* @__PURE__ */ jsx("span", { className: "text-primary-foreground font-bold", children })
|
|
4725
|
-
]
|
|
4726
|
-
}
|
|
4727
|
-
);
|
|
4728
|
-
if (tooltip) {
|
|
4729
|
-
return /* @__PURE__ */ jsx(Tooltip, { content: tooltip, position: "top", size: "sm", children: badge });
|
|
4730
|
-
}
|
|
4731
|
-
return badge;
|
|
4732
|
-
};
|
|
4733
5506
|
const Chart = ({
|
|
4734
5507
|
title,
|
|
4735
5508
|
subtitle,
|
|
@@ -5492,85 +6265,6 @@ const ProgressBar = ({
|
|
|
5492
6265
|
)
|
|
5493
6266
|
] });
|
|
5494
6267
|
};
|
|
5495
|
-
const valueColorMap = {
|
|
5496
|
-
success: "text-green-600",
|
|
5497
|
-
error: "text-red-600",
|
|
5498
|
-
warning: "text-yellow-600",
|
|
5499
|
-
info: "text-blue-600",
|
|
5500
|
-
neutral: "text-muted-foreground",
|
|
5501
|
-
default: "text-foreground"
|
|
5502
|
-
};
|
|
5503
|
-
function ListCard({
|
|
5504
|
-
icon,
|
|
5505
|
-
title,
|
|
5506
|
-
subtitle,
|
|
5507
|
-
metadata,
|
|
5508
|
-
value,
|
|
5509
|
-
badge,
|
|
5510
|
-
onClick,
|
|
5511
|
-
className,
|
|
5512
|
-
children
|
|
5513
|
-
}) {
|
|
5514
|
-
return /* @__PURE__ */ jsxs(
|
|
5515
|
-
"div",
|
|
5516
|
-
{
|
|
5517
|
-
className: cn(
|
|
5518
|
-
"flex items-start gap-3 p-3 rounded-lg border border-border transition-colors",
|
|
5519
|
-
onClick && "hover:bg-muted/50 cursor-pointer",
|
|
5520
|
-
className
|
|
5521
|
-
),
|
|
5522
|
-
onClick,
|
|
5523
|
-
children: [
|
|
5524
|
-
icon && /* @__PURE__ */ jsx(
|
|
5525
|
-
IconBadge,
|
|
5526
|
-
{
|
|
5527
|
-
variant: icon.variant || "category",
|
|
5528
|
-
category: icon.variant === "category" ? icon.category || 1 : void 0,
|
|
5529
|
-
status: icon.variant === "status" ? icon.status || "neutral" : void 0,
|
|
5530
|
-
size: icon.size || "sm",
|
|
5531
|
-
icon: icon.icon,
|
|
5532
|
-
tooltip: icon.tooltip
|
|
5533
|
-
}
|
|
5534
|
-
),
|
|
5535
|
-
/* @__PURE__ */ jsxs("div", { className: "flex-1 min-w-0", children: [
|
|
5536
|
-
/* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between gap-2", children: [
|
|
5537
|
-
/* @__PURE__ */ jsxs("div", { className: "flex-1", children: [
|
|
5538
|
-
/* @__PURE__ */ jsx("h4", { className: "text-sm font-medium text-foreground truncate", children: title }),
|
|
5539
|
-
subtitle && /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground mt-0.5", children: subtitle }),
|
|
5540
|
-
metadata && metadata.length > 0 && /* @__PURE__ */ jsx("div", { className: "flex items-center gap-3 mt-1", children: metadata.map((item, index) => /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", children: item }, index)) })
|
|
5541
|
-
] }),
|
|
5542
|
-
(value || badge) && /* @__PURE__ */ jsxs("div", { className: "text-right", children: [
|
|
5543
|
-
value && /* @__PURE__ */ jsx(
|
|
5544
|
-
"p",
|
|
5545
|
-
{
|
|
5546
|
-
className: cn(
|
|
5547
|
-
"text-sm font-semibold",
|
|
5548
|
-
value.variant && valueColorMap[value.variant],
|
|
5549
|
-
value.className
|
|
5550
|
-
),
|
|
5551
|
-
children: value.text
|
|
5552
|
-
}
|
|
5553
|
-
),
|
|
5554
|
-
badge && /* @__PURE__ */ jsx(
|
|
5555
|
-
DataBadge,
|
|
5556
|
-
{
|
|
5557
|
-
variant: badge.variant,
|
|
5558
|
-
status: badge.variant === "status" ? badge.status : void 0,
|
|
5559
|
-
category: badge.variant === "category" ? badge.category : void 0,
|
|
5560
|
-
size: badge.size || "sm",
|
|
5561
|
-
icon: badge.icon,
|
|
5562
|
-
className: "mt-1",
|
|
5563
|
-
children: badge.text
|
|
5564
|
-
}
|
|
5565
|
-
)
|
|
5566
|
-
] })
|
|
5567
|
-
] }),
|
|
5568
|
-
children
|
|
5569
|
-
] })
|
|
5570
|
-
]
|
|
5571
|
-
}
|
|
5572
|
-
);
|
|
5573
|
-
}
|
|
5574
6268
|
const TruncatedText = ({
|
|
5575
6269
|
text,
|
|
5576
6270
|
className,
|
|
@@ -8891,6 +9585,13 @@ const defaultShowcaseNavigation = [
|
|
|
8891
9585
|
path: "/admin/dashboard",
|
|
8892
9586
|
category: 2
|
|
8893
9587
|
},
|
|
9588
|
+
{
|
|
9589
|
+
value: "admin-dashboard-v2",
|
|
9590
|
+
label: "Admin Dashboard V2",
|
|
9591
|
+
icon: "Shield",
|
|
9592
|
+
path: "/admin/dashboard-v2",
|
|
9593
|
+
category: 2
|
|
9594
|
+
},
|
|
8894
9595
|
{
|
|
8895
9596
|
value: "admin-users",
|
|
8896
9597
|
label: "User Management",
|
|
@@ -9161,7 +9862,6 @@ const Sidebar = ({ className }) => {
|
|
|
9161
9862
|
);
|
|
9162
9863
|
};
|
|
9163
9864
|
const AppHeader = ({ className }) => {
|
|
9164
|
-
const isTrialMode = false;
|
|
9165
9865
|
return /* @__PURE__ */ jsx(
|
|
9166
9866
|
"header",
|
|
9167
9867
|
{
|
|
@@ -9174,7 +9874,7 @@ const AppHeader = ({ className }) => {
|
|
|
9174
9874
|
children: /* @__PURE__ */ jsx("div", { className: "mx-auto max-w-7xl px-4 sm:px-6 lg:px-8", children: /* @__PURE__ */ jsxs("div", { className: "flex h-16 items-center justify-between", children: [
|
|
9175
9875
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
|
|
9176
9876
|
/* @__PURE__ */ jsx("h1", { className: "text-xl font-bold text-foreground", children: "Frontend Template" }),
|
|
9177
|
-
|
|
9877
|
+
/* @__PURE__ */ jsx(DataBadge, { variant: "status", status: "info", display: "icon-text", children: "Trial Mode" })
|
|
9178
9878
|
] }),
|
|
9179
9879
|
/* @__PURE__ */ jsx("div", { className: "flex-1 max-w-2xl mx-8", children: /* @__PURE__ */ jsx(
|
|
9180
9880
|
GlobalSearch,
|
|
@@ -13958,18 +14658,41 @@ function createReactApp(config) {
|
|
|
13958
14658
|
enableRouting = true,
|
|
13959
14659
|
auth,
|
|
13960
14660
|
navigation,
|
|
13961
|
-
customProviders = []
|
|
14661
|
+
customProviders = [],
|
|
14662
|
+
persistQueryCache = false,
|
|
14663
|
+
queryCacheKey = "PATTERN_STACK_QUERY_CACHE"
|
|
13962
14664
|
} = appConfig;
|
|
13963
14665
|
const queryClient = new QueryClient({
|
|
13964
14666
|
defaultOptions: {
|
|
13965
14667
|
queries: {
|
|
13966
14668
|
retry: 1,
|
|
13967
14669
|
refetchOnWindowFocus: false,
|
|
13968
|
-
staleTime: 5 * 60 * 1e3
|
|
14670
|
+
staleTime: 5 * 60 * 1e3,
|
|
13969
14671
|
// 5 minutes
|
|
14672
|
+
// Keep data longer when persistence is enabled
|
|
14673
|
+
gcTime: persistQueryCache ? 1e3 * 60 * 60 * 24 : 1e3 * 60 * 5
|
|
13970
14674
|
}
|
|
13971
14675
|
}
|
|
13972
14676
|
});
|
|
14677
|
+
if (persistQueryCache && typeof window !== "undefined") {
|
|
14678
|
+
import("@tanstack/react-query-persist-client").then(({ persistQueryClient }) => {
|
|
14679
|
+
import("@tanstack/query-sync-storage-persister").then(({ createSyncStoragePersister }) => {
|
|
14680
|
+
const persister = createSyncStoragePersister({
|
|
14681
|
+
storage: window.localStorage,
|
|
14682
|
+
key: queryCacheKey
|
|
14683
|
+
});
|
|
14684
|
+
persistQueryClient({
|
|
14685
|
+
queryClient,
|
|
14686
|
+
persister,
|
|
14687
|
+
maxAge: 1e3 * 60 * 60 * 24
|
|
14688
|
+
// 24 hours
|
|
14689
|
+
});
|
|
14690
|
+
console.info("[app] Query cache persistence enabled");
|
|
14691
|
+
});
|
|
14692
|
+
}).catch((err) => {
|
|
14693
|
+
console.warn("[app] Query persistence not available:", err.message);
|
|
14694
|
+
});
|
|
14695
|
+
}
|
|
13973
14696
|
const routes = [];
|
|
13974
14697
|
const DefaultHome = () => /* @__PURE__ */ jsx(DashboardTemplate, { title, description, children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center justify-center min-h-[400px] text-center", children: [
|
|
13975
14698
|
/* @__PURE__ */ jsxs("h1", { className: "text-4xl font-bold text-foreground mb-4", children: [
|
|
@@ -13988,7 +14711,7 @@ function createReactApp(config) {
|
|
|
13988
14711
|
] }) });
|
|
13989
14712
|
const createProviderTree = (children) => {
|
|
13990
14713
|
let tree = children;
|
|
13991
|
-
customProviders.reverse().forEach((Provider) => {
|
|
14714
|
+
[...customProviders].reverse().forEach((Provider) => {
|
|
13992
14715
|
tree = /* @__PURE__ */ jsx(Provider, { children: tree }, Provider.name);
|
|
13993
14716
|
});
|
|
13994
14717
|
if (enableRouting) {
|
|
@@ -14031,10 +14754,10 @@ function createReactApp(config) {
|
|
|
14031
14754
|
}
|
|
14032
14755
|
return component;
|
|
14033
14756
|
};
|
|
14034
|
-
const AppContent = () => /* @__PURE__ */ jsx(Routes, { children: /* @__PURE__ */ jsxs(Route, { path: "/", element: /* @__PURE__ */ jsx(AppLayout, {}), children: [
|
|
14757
|
+
const AppContent = () => /* @__PURE__ */ jsx(Suspense, { fallback: /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center min-h-screen", children: "Loading..." }), children: /* @__PURE__ */ jsx(Routes, { children: /* @__PURE__ */ jsxs(Route, { path: "/", element: /* @__PURE__ */ jsx(AppLayout, {}), children: [
|
|
14035
14758
|
/* @__PURE__ */ jsx(Route, { index: true, element: wrapWithProtection("/", /* @__PURE__ */ jsx(DefaultHome, {})) }),
|
|
14036
14759
|
routes.map(({ path, component }, index) => /* @__PURE__ */ jsx(Route, { path, element: wrapWithProtection(path, component) }, index))
|
|
14037
|
-
] }) });
|
|
14760
|
+
] }) }) });
|
|
14038
14761
|
return createProviderTree(/* @__PURE__ */ jsx(AppContent, {}));
|
|
14039
14762
|
},
|
|
14040
14763
|
mount(elementId = "root") {
|
|
@@ -17230,6 +17953,10 @@ export {
|
|
|
17230
17953
|
Breadcrumb,
|
|
17231
17954
|
BulkSelectionBar,
|
|
17232
17955
|
Button,
|
|
17956
|
+
COLUMN_WIDTHS,
|
|
17957
|
+
COMPACT_COLUMN_WIDTHS,
|
|
17958
|
+
COMPACT_FORMATTERS,
|
|
17959
|
+
COMPACT_LABELS,
|
|
17233
17960
|
Card,
|
|
17234
17961
|
CardContent,
|
|
17235
17962
|
CardDescription,
|
|
@@ -17288,6 +18015,7 @@ export {
|
|
|
17288
18015
|
FormField,
|
|
17289
18016
|
FormGroup,
|
|
17290
18017
|
GlobalSearch,
|
|
18018
|
+
IMPORTANCE_VISIBILITY,
|
|
17291
18019
|
Icon,
|
|
17292
18020
|
IconBadge,
|
|
17293
18021
|
Input,
|
|
@@ -17343,6 +18071,7 @@ export {
|
|
|
17343
18071
|
StatCard,
|
|
17344
18072
|
StyleGuide,
|
|
17345
18073
|
Switch,
|
|
18074
|
+
TABLE_BREAKPOINTS,
|
|
17346
18075
|
Table,
|
|
17347
18076
|
TableBody,
|
|
17348
18077
|
TableCaption,
|
|
@@ -17365,19 +18094,27 @@ export {
|
|
|
17365
18094
|
animationPresets,
|
|
17366
18095
|
apiClient,
|
|
17367
18096
|
breakpoints,
|
|
18097
|
+
calculateTableWidth,
|
|
17368
18098
|
cn,
|
|
17369
18099
|
createAPIDataTemplate,
|
|
17370
18100
|
createApiClient,
|
|
18101
|
+
createMobileCardRenderer,
|
|
17371
18102
|
createReactApp,
|
|
17372
18103
|
createSimpleApp,
|
|
17373
18104
|
defaultFieldRenderers,
|
|
17374
18105
|
detectBulkOperationType,
|
|
17375
18106
|
detectUIConfig,
|
|
18107
|
+
determineTableMode,
|
|
18108
|
+
entityToListCardProps,
|
|
17376
18109
|
env,
|
|
17377
18110
|
formatNumberWithTooltip,
|
|
17378
18111
|
generateBulkOperationName,
|
|
18112
|
+
generateCompactColumns,
|
|
17379
18113
|
getAnimationClasses,
|
|
17380
18114
|
getChartHeight,
|
|
18115
|
+
getColumnWidth,
|
|
18116
|
+
getCompactFormatter,
|
|
18117
|
+
getCompactLabel,
|
|
17381
18118
|
getContainerHeightClass,
|
|
17382
18119
|
getCurrentBreakpoint,
|
|
17383
18120
|
getFieldType,
|
|
@@ -17396,6 +18133,7 @@ export {
|
|
|
17396
18133
|
responsiveScales,
|
|
17397
18134
|
setGlobalAuthService,
|
|
17398
18135
|
tooltipContent,
|
|
18136
|
+
useAdaptiveTable,
|
|
17399
18137
|
useApiMutation,
|
|
17400
18138
|
useApiQuery,
|
|
17401
18139
|
useAuth,
|