@pattern-stack/frontend-patterns 0.0.4 → 0.0.6

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.
Files changed (86) hide show
  1. package/dist/atoms/composed/SalesPanel/SalesPanel.d.ts +19 -0
  2. package/dist/atoms/composed/SalesPanel/SalesPanel.d.ts.map +1 -0
  3. package/dist/atoms/composed/SalesPanel/index.d.ts +2 -0
  4. package/dist/atoms/composed/SalesPanel/index.d.ts.map +1 -0
  5. package/dist/atoms/composed/SalesPanel/mockSalesData.d.ts +63 -0
  6. package/dist/atoms/composed/SalesPanel/mockSalesData.d.ts.map +1 -0
  7. package/dist/atoms/composed/index.d.ts +1 -0
  8. package/dist/atoms/composed/index.d.ts.map +1 -1
  9. package/dist/atoms/types/entity-config.d.ts +117 -0
  10. package/dist/atoms/types/entity-config.d.ts.map +1 -0
  11. package/dist/atoms/types/index.d.ts +2 -0
  12. package/dist/atoms/types/index.d.ts.map +1 -1
  13. package/dist/atoms/types/navigation.d.ts +30 -0
  14. package/dist/atoms/types/navigation.d.ts.map +1 -0
  15. package/dist/atoms/ui/ErrorBoundary.d.ts +1 -1
  16. package/dist/atoms/ui/button.d.ts +1 -1
  17. package/dist/atoms/utils/icon-resolver.d.ts +72 -0
  18. package/dist/atoms/utils/icon-resolver.d.ts.map +1 -0
  19. package/dist/atoms/utils/metric-engine.d.ts +30 -0
  20. package/dist/atoms/utils/metric-engine.d.ts.map +1 -0
  21. package/dist/atoms/utils/utils.d.ts +2 -0
  22. package/dist/atoms/utils/utils.d.ts.map +1 -1
  23. package/dist/features/auth/components/ProtectedRoute.d.ts +1 -1
  24. package/dist/frontend-patterns.css +1 -1
  25. package/dist/index.es.js +402 -14
  26. package/dist/index.es.js.map +1 -1
  27. package/dist/index.js +402 -14
  28. package/dist/index.js.map +1 -1
  29. package/dist/molecules/layout/DashboardWithSidePanel/DashboardWithSidePanel.d.ts +16 -0
  30. package/dist/molecules/layout/DashboardWithSidePanel/DashboardWithSidePanel.d.ts.map +1 -0
  31. package/dist/molecules/layout/DashboardWithSidePanel/index.d.ts +2 -0
  32. package/dist/molecules/layout/DashboardWithSidePanel/index.d.ts.map +1 -0
  33. package/dist/molecules/layout/NavigationContext.d.ts +15 -0
  34. package/dist/molecules/layout/NavigationContext.d.ts.map +1 -0
  35. package/dist/molecules/layout/Sidebar.d.ts.map +1 -1
  36. package/dist/molecules/layout/SidebarButton/SidebarButton.d.ts +2 -0
  37. package/dist/molecules/layout/SidebarButton/SidebarButton.d.ts.map +1 -1
  38. package/dist/molecules/layout/index.d.ts +3 -0
  39. package/dist/molecules/layout/index.d.ts.map +1 -1
  40. package/dist/templates/factory.d.ts +2 -1
  41. package/dist/templates/factory.d.ts.map +1 -1
  42. package/dist/templates/index.d.ts.map +1 -1
  43. package/package.json +7 -3
  44. package/src/App.tsx +11 -1
  45. package/src/__tests__/atoms/composed/databadge.test.tsx +106 -0
  46. package/src/__tests__/atoms/composed/statcard.test.tsx +133 -0
  47. package/src/__tests__/atoms/utils/icon-resolver.test.tsx +140 -0
  48. package/src/atoms/composed/SalesPanel/SalesPanel.tsx +116 -0
  49. package/src/atoms/composed/SalesPanel/index.ts +1 -0
  50. package/src/atoms/composed/SalesPanel/mockSalesData.ts +151 -0
  51. package/src/atoms/composed/index.ts +1 -0
  52. package/src/atoms/types/entity-config.ts +127 -0
  53. package/src/atoms/types/index.ts +3 -1
  54. package/src/atoms/types/navigation.ts +43 -0
  55. package/src/atoms/utils/icon-resolver.tsx +54 -0
  56. package/src/atoms/utils/metric-engine.ts +236 -0
  57. package/src/atoms/utils/utils.ts +4 -2
  58. package/src/molecules/layout/DashboardWithSidePanel/DashboardWithSidePanel.tsx +42 -0
  59. package/src/molecules/layout/DashboardWithSidePanel/index.ts +1 -0
  60. package/src/molecules/layout/NavigationContext.tsx +63 -0
  61. package/src/molecules/layout/Sidebar.tsx +10 -23
  62. package/src/molecules/layout/SidebarButton/SidebarButton.tsx +32 -10
  63. package/src/molecules/layout/index.ts +4 -1
  64. package/src/organisms/entity/CategoryBreakdownPanel.tsx +427 -0
  65. package/src/organisms/entity/EntityListPanel.tsx +339 -0
  66. package/src/organisms/entity/MetricsOverviewPanel.tsx +236 -0
  67. package/src/organisms/entity/TrendAnalysisPanel.tsx +337 -0
  68. package/src/organisms/entity/index.ts +4 -0
  69. package/src/organisms/index.ts +5 -1
  70. package/src/pages/AdminShowcase/AdminDashboardShowcase.tsx +77 -75
  71. package/src/pages/AdminShowcase/SalesPerformanceDashboard.tsx +158 -0
  72. package/src/pages/AdminShowcase/index.tsx +2 -1
  73. package/src/pages/EntityShowcase/EntityManagementShowcase.tsx +137 -0
  74. package/src/pages/EntityShowcase/EntityPerformanceShowcase.tsx +117 -0
  75. package/src/pages/EntityShowcase/index.ts +2 -0
  76. package/src/pages/EntityTemplateExample.tsx +229 -0
  77. package/src/pages/TestEntityTemplate.tsx +40 -0
  78. package/src/pages/index.ts +2 -1
  79. package/src/templates/entity/EntityManagementTemplate.tsx +430 -0
  80. package/src/templates/entity/EntityPerformanceDashboardTemplate.tsx +277 -0
  81. package/src/templates/entity/configs/financial-config.ts +141 -0
  82. package/src/templates/entity/configs/index.ts +1 -0
  83. package/src/templates/entity/index.ts +3 -0
  84. package/src/templates/factory.tsx +14 -7
  85. package/src/templates/financial/FinancialDashboardTemplate.tsx +326 -0
  86. package/src/templates/index.ts +4 -0
package/dist/index.js CHANGED
@@ -7,19 +7,18 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
7
7
  const clsx = require("clsx");
8
8
  const tailwindMerge = require("tailwind-merge");
9
9
  const React = require("react");
10
+ const jsxRuntime = require("react/jsx-runtime");
11
+ const lucideReact = require("lucide-react");
10
12
  const classVarianceAuthority = require("class-variance-authority");
11
13
  const axios = require("axios");
12
14
  const reactQuery = require("@tanstack/react-query");
13
- const jsxRuntime = require("react/jsx-runtime");
14
15
  const reactSlot = require("@radix-ui/react-slot");
15
16
  const LabelPrimitive = require("@radix-ui/react-label");
16
17
  const AvatarPrimitive = require("@radix-ui/react-avatar");
17
18
  const DropdownMenuPrimitive = require("@radix-ui/react-dropdown-menu");
18
- const lucideReact = require("lucide-react");
19
19
  const reactDom = require("react-dom");
20
20
  const reactRouterDom = require("react-router-dom");
21
21
  const client = require("react-dom/client");
22
- require("@tanstack/react-query-devtools");
23
22
  function _interopNamespaceDefault(e) {
24
23
  const n = Object.create(null, { [Symbol.toStringTag]: { value: "Module" } });
25
24
  if (e) {
@@ -265,6 +264,240 @@ const tooltipContent = {
265
264
  profile: "Profile",
266
265
  account: "Account settings"
267
266
  };
267
+ class MetricCalculationEngine {
268
+ static calculateMetric(config, data, previousData) {
269
+ const currentValue = this.aggregateValue(config, data);
270
+ const previousValue = previousData ? this.aggregateValue(config, previousData) : void 0;
271
+ const trend = this.calculateTrend(currentValue, previousValue);
272
+ const formattedValue = this.formatValue(currentValue, config.format, config.type);
273
+ const target = typeof config.target === "function" ? config.target(data) : config.target;
274
+ return {
275
+ current: currentValue,
276
+ previous: previousValue,
277
+ trend,
278
+ target,
279
+ formattedValue
280
+ };
281
+ }
282
+ static aggregateValue(config, data) {
283
+ if (!data.length) return 0;
284
+ const values = data.map((item) => {
285
+ const value = this.extractValue(item, config.key);
286
+ return typeof value === "number" ? value : 0;
287
+ }).filter((value) => !isNaN(value));
288
+ if (!values.length) return 0;
289
+ switch (config.aggregation || "sum") {
290
+ case "sum":
291
+ return values.reduce((sum, value) => sum + value, 0);
292
+ case "avg":
293
+ return values.reduce((sum, value) => sum + value, 0) / values.length;
294
+ case "count":
295
+ return values.length;
296
+ case "min":
297
+ return Math.min(...values);
298
+ case "max":
299
+ return Math.max(...values);
300
+ default:
301
+ return values.reduce((sum, value) => sum + value, 0);
302
+ }
303
+ }
304
+ static extractValue(item, key) {
305
+ return key.split(".").reduce((obj, k) => obj == null ? void 0 : obj[k], item);
306
+ }
307
+ static calculateTrend(current, previous) {
308
+ if (previous === void 0 || previous === 0) return "neutral";
309
+ const change = (current - previous) / Math.abs(previous) * 100;
310
+ if (change > 1) return "up";
311
+ if (change < -1) return "down";
312
+ return "neutral";
313
+ }
314
+ static formatValue(value, format, type) {
315
+ let formatted = value;
316
+ if ((format == null ? void 0 : format.decimals) !== void 0) {
317
+ formatted = Number(value.toFixed(format.decimals));
318
+ }
319
+ let result = formatted.toString();
320
+ if ((format == null ? void 0 : format.thousands) !== false && Math.abs(formatted) >= 1e3) {
321
+ result = formatted.toLocaleString();
322
+ }
323
+ switch (type) {
324
+ case "currency":
325
+ result = new Intl.NumberFormat("en-US", {
326
+ style: "currency",
327
+ currency: "USD",
328
+ minimumFractionDigits: (format == null ? void 0 : format.decimals) ?? 2,
329
+ maximumFractionDigits: (format == null ? void 0 : format.decimals) ?? 2
330
+ }).format(formatted);
331
+ break;
332
+ case "percentage":
333
+ result = `${formatted.toFixed((format == null ? void 0 : format.decimals) ?? 1)}%`;
334
+ break;
335
+ case "duration":
336
+ result = this.formatDuration(formatted);
337
+ break;
338
+ case "ratio":
339
+ result = `${formatted.toFixed((format == null ? void 0 : format.decimals) ?? 2)}:1`;
340
+ break;
341
+ default:
342
+ if (format == null ? void 0 : format.prefix) result = format.prefix + result;
343
+ if (format == null ? void 0 : format.suffix) result = result + format.suffix;
344
+ }
345
+ return result;
346
+ }
347
+ static formatDuration(minutes) {
348
+ const hours = Math.floor(minutes / 60);
349
+ const mins = Math.floor(minutes % 60);
350
+ if (hours > 0) {
351
+ return `${hours}h ${mins}m`;
352
+ }
353
+ return `${mins}m`;
354
+ }
355
+ static calculateTrendData(config, data, dateField = "date", periods = 12) {
356
+ const groupedData = this.groupByPeriod(data, dateField);
357
+ const sortedDates = Object.keys(groupedData).sort();
358
+ return sortedDates.slice(-periods).map((date) => ({
359
+ date,
360
+ value: this.aggregateValue(config, groupedData[date]),
361
+ label: this.formatDateLabel(date)
362
+ }));
363
+ }
364
+ static groupByPeriod(data, dateField) {
365
+ return data.reduce((groups, item) => {
366
+ const date = this.extractValue(item, dateField);
367
+ if (!date) return groups;
368
+ const period = new Date(date).toISOString().split("T")[0];
369
+ if (!groups[period]) groups[period] = [];
370
+ groups[period].push(item);
371
+ return groups;
372
+ }, {});
373
+ }
374
+ static formatDateLabel(dateString) {
375
+ const date = new Date(dateString);
376
+ return date.toLocaleDateString("en-US", {
377
+ month: "short",
378
+ day: "numeric"
379
+ });
380
+ }
381
+ static calculateCategoryBreakdown(data, categoryField, valueField, maxCategories = 8) {
382
+ const groups = data.reduce((acc, item) => {
383
+ const category = String(this.extractValue(item, categoryField) || "Unknown");
384
+ const value = this.extractValue(item, valueField) || 0;
385
+ if (!acc[category]) acc[category] = 0;
386
+ acc[category] += typeof value === "number" ? value : 0;
387
+ return acc;
388
+ }, {});
389
+ const total = Object.values(groups).reduce((sum, value) => sum + value, 0);
390
+ let categories = Object.entries(groups).map(([category, value]) => ({
391
+ category,
392
+ value,
393
+ percentage: total > 0 ? value / total * 100 : 0
394
+ })).sort((a, b) => b.value - a.value);
395
+ if (categories.length > maxCategories) {
396
+ const topCategories = categories.slice(0, maxCategories - 1);
397
+ const otherValue = categories.slice(maxCategories - 1).reduce((sum, cat) => sum + cat.value, 0);
398
+ topCategories.push({
399
+ category: "Other",
400
+ value: otherValue,
401
+ percentage: total > 0 ? otherValue / total * 100 : 0
402
+ });
403
+ categories = topCategories;
404
+ }
405
+ return categories;
406
+ }
407
+ static detectInsights(metrics, thresholds = {}) {
408
+ const insights = [];
409
+ for (const [key, metric] of Object.entries(metrics)) {
410
+ const threshold = thresholds[key];
411
+ if (metric.target && metric.current < metric.target * 0.8) {
412
+ insights.push({
413
+ type: "negative",
414
+ message: `${key} is significantly below target`,
415
+ value: metric.current
416
+ });
417
+ }
418
+ if (metric.trend === "up" && metric.previous && metric.current > metric.previous * 1.2) {
419
+ insights.push({
420
+ type: "positive",
421
+ message: `${key} showing strong growth`,
422
+ value: metric.current
423
+ });
424
+ }
425
+ if (threshold && metric.current >= threshold.critical) {
426
+ insights.push({
427
+ type: "negative",
428
+ message: `${key} has reached critical threshold`,
429
+ value: metric.current
430
+ });
431
+ }
432
+ }
433
+ return insights.slice(0, 5);
434
+ }
435
+ }
436
+ const iconMap = {
437
+ Palette: lucideReact.Palette,
438
+ Menu: lucideReact.Menu,
439
+ X: lucideReact.X,
440
+ Shield: lucideReact.Shield,
441
+ Users: lucideReact.Users,
442
+ BarChart3: lucideReact.BarChart3,
443
+ Database: lucideReact.Database,
444
+ TrendingUp: lucideReact.TrendingUp,
445
+ Layout: lucideReact.Layout,
446
+ Home: lucideReact.Home,
447
+ Settings: lucideReact.Settings,
448
+ Bell: lucideReact.Bell,
449
+ Search: lucideReact.Search,
450
+ Plus: lucideReact.Plus,
451
+ Edit: lucideReact.Edit,
452
+ Trash2: lucideReact.Trash2,
453
+ Eye: lucideReact.Eye,
454
+ Download: lucideReact.Download,
455
+ Upload: lucideReact.Upload,
456
+ Share: lucideReact.Share,
457
+ Lock: lucideReact.Lock,
458
+ Unlock: lucideReact.Unlock,
459
+ Mail: lucideReact.Mail,
460
+ Phone: lucideReact.Phone,
461
+ Calendar: lucideReact.Calendar,
462
+ Clock: lucideReact.Clock,
463
+ MapPin: lucideReact.MapPin,
464
+ Star: lucideReact.Star,
465
+ Heart: lucideReact.Heart,
466
+ Bookmark: lucideReact.Bookmark,
467
+ Tag: lucideReact.Tag,
468
+ Flag: lucideReact.Flag,
469
+ File: lucideReact.File,
470
+ Folder: lucideReact.Folder,
471
+ Image: lucideReact.Image,
472
+ Video: lucideReact.Video,
473
+ Music: lucideReact.Music,
474
+ ChevronRight: lucideReact.ChevronRight,
475
+ ChevronDown: lucideReact.ChevronDown,
476
+ ChevronLeft: lucideReact.ChevronLeft,
477
+ ChevronUp: lucideReact.ChevronUp,
478
+ ArrowRight: lucideReact.ArrowRight,
479
+ ArrowLeft: lucideReact.ArrowLeft,
480
+ ArrowUp: lucideReact.ArrowUp,
481
+ ArrowDown: lucideReact.ArrowDown,
482
+ Check: lucideReact.Check,
483
+ AlertCircle: lucideReact.AlertCircle,
484
+ Info: lucideReact.Info,
485
+ HelpCircle: lucideReact.HelpCircle
486
+ };
487
+ const Icon = ({ name, className = "w-5 h-5", size, ...props }) => {
488
+ const IconComponent = iconMap[name];
489
+ if (!IconComponent) {
490
+ console.warn(`Icon "${name}" not found. Using default Menu icon.`);
491
+ return /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Menu, { className, size, ...props });
492
+ }
493
+ return /* @__PURE__ */ jsxRuntime.jsx(IconComponent, { className, size, ...props });
494
+ };
495
+ const getIcon = (name) => {
496
+ return iconMap[name] || lucideReact.Menu;
497
+ };
498
+ const isValidIcon = (name) => {
499
+ return name in iconMap;
500
+ };
268
501
  function cn(...inputs) {
269
502
  return tailwindMerge.twMerge(clsx.clsx(inputs));
270
503
  }
@@ -1286,6 +1519,83 @@ const DataBadge = ({
1286
1519
  }
1287
1520
  return badge;
1288
1521
  };
1522
+ const getStageStatus = (stage) => {
1523
+ switch (stage) {
1524
+ case "Closed Won":
1525
+ return "success";
1526
+ case "Negotiation":
1527
+ return "warning";
1528
+ case "Proposal Sent":
1529
+ return "info";
1530
+ case "Qualified":
1531
+ return "info";
1532
+ case "Discovery":
1533
+ return "neutral";
1534
+ default:
1535
+ return "neutral";
1536
+ }
1537
+ };
1538
+ const SalesPanel = ({
1539
+ sales,
1540
+ onSaleClick,
1541
+ onClose
1542
+ }) => {
1543
+ const topDeals = sales.slice(0, 5);
1544
+ const totalValue = sales.reduce((sum, sale) => sum + sale.amount, 0);
1545
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "fixed right-0 top-16 h-[calc(100vh-4rem)] w-72 bg-background border-l border-border shadow-lg flex flex-col z-30", children: [
1546
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-3 border-b border-border", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between", children: [
1547
+ /* @__PURE__ */ jsxRuntime.jsxs("h3", { className: "font-medium flex items-center gap-2", children: [
1548
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Target, { className: "w-4 h-4" }),
1549
+ "Pipeline"
1550
+ ] }),
1551
+ onClose && /* @__PURE__ */ jsxRuntime.jsx(Button, { variant: "ghost", size: "sm", onClick: onClose, children: "×" })
1552
+ ] }) }),
1553
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-3 border-b border-border", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
1554
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex justify-between", children: [
1555
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-muted-foreground", children: "Total Value" }),
1556
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "font-semibold text-green-600", children: [
1557
+ "$",
1558
+ totalValue.toLocaleString()
1559
+ ] })
1560
+ ] }),
1561
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex justify-between", children: [
1562
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-muted-foreground", children: "Active Deals" }),
1563
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-semibold", children: sales.length })
1564
+ ] })
1565
+ ] }) }),
1566
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 overflow-auto p-3", children: [
1567
+ /* @__PURE__ */ jsxRuntime.jsx("h4", { className: "text-sm font-medium mb-3", children: "Recent Opportunities" }),
1568
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-2", children: topDeals.map((sale) => /* @__PURE__ */ jsxRuntime.jsxs(
1569
+ "div",
1570
+ {
1571
+ className: "p-2 border border-border rounded-md hover:bg-muted/50 cursor-pointer transition-colors",
1572
+ onClick: () => onSaleClick == null ? void 0 : onSaleClick(sale),
1573
+ children: [
1574
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex justify-between items-start mb-1", children: [
1575
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 min-w-0", children: [
1576
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-medium truncate", children: sale.customer }),
1577
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground truncate", children: sale.product })
1578
+ ] }),
1579
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-right ml-2", children: /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "text-sm font-semibold text-green-600", children: [
1580
+ "$",
1581
+ sale.amount.toLocaleString()
1582
+ ] }) })
1583
+ ] }),
1584
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex justify-between items-center", children: [
1585
+ /* @__PURE__ */ jsxRuntime.jsx(DataBadge, { variant: "status", status: getStageStatus(sale.stage), children: sale.stage }),
1586
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-muted-foreground", children: sale.salesperson })
1587
+ ] })
1588
+ ]
1589
+ },
1590
+ sale.id
1591
+ )) })
1592
+ ] }),
1593
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-3 border-t border-border", children: /* @__PURE__ */ jsxRuntime.jsxs(Button, { variant: "outline", size: "sm", className: "w-full", children: [
1594
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ExternalLink, { className: "w-4 h-4 mr-2" }),
1595
+ "View All Deals"
1596
+ ] }) })
1597
+ ] });
1598
+ };
1289
1599
  const StatCard = ({
1290
1600
  title,
1291
1601
  value,
@@ -5550,6 +5860,42 @@ const useSidebar = () => {
5550
5860
  }
5551
5861
  return context;
5552
5862
  };
5863
+ const NavigationContext = React.createContext(void 0);
5864
+ const defaultShowcaseNavigation = [
5865
+ { value: "showcase", label: "Showcase", icon: "Palette", path: "/showcase", category: 5 },
5866
+ { value: "admin-dashboard", label: "Admin Dashboard", icon: "Shield", path: "/admin/dashboard", category: 2 },
5867
+ { value: "admin-users", label: "User Management", icon: "Users", path: "/admin/users", category: 3 },
5868
+ { value: "admin-sales", label: "Sales Dashboard", icon: "TrendingUp", path: "/admin/sales", category: 4 },
5869
+ { value: "entity-performance", label: "Performance Dashboard", icon: "BarChart3", path: "/entity/performance", category: 6 },
5870
+ { value: "entity-management", label: "Entity Management", icon: "Database", path: "/entity/management", category: 7 },
5871
+ { value: "entity-template", label: "Template Example", icon: "Layout", path: "/entity/template-example", category: 1 }
5872
+ ];
5873
+ const NavigationProvider = ({ children, initialNavigation }) => {
5874
+ const [navigation, setNavigation] = React.useState(
5875
+ initialNavigation || {
5876
+ items: defaultShowcaseNavigation,
5877
+ showDefaultNavigation: true,
5878
+ defaultExpanded: true
5879
+ }
5880
+ );
5881
+ return /* @__PURE__ */ jsxRuntime.jsx(NavigationContext.Provider, { value: { navigation, setNavigation }, children });
5882
+ };
5883
+ const useNavigation = () => {
5884
+ const context = React.useContext(NavigationContext);
5885
+ if (context === void 0) {
5886
+ throw new Error("useNavigation must be used within a NavigationProvider");
5887
+ }
5888
+ return context;
5889
+ };
5890
+ const getNavigationItems = (config) => {
5891
+ if (config.items.length > 0) {
5892
+ return config.items;
5893
+ }
5894
+ if (config.showDefaultNavigation !== false) {
5895
+ return defaultShowcaseNavigation;
5896
+ }
5897
+ return [];
5898
+ };
5553
5899
  const SidebarButton = ({
5554
5900
  icon,
5555
5901
  label,
@@ -5557,13 +5903,16 @@ const SidebarButton = ({
5557
5903
  category = 1,
5558
5904
  expanded = false,
5559
5905
  onClick,
5560
- className
5906
+ className,
5907
+ badge,
5908
+ disabled = false
5561
5909
  }) => {
5562
5910
  return /* @__PURE__ */ jsxRuntime.jsxs(
5563
5911
  Button,
5564
5912
  {
5565
5913
  variant: active ? "secondary" : "ghost",
5566
5914
  onClick,
5915
+ disabled,
5567
5916
  tooltip: !expanded ? label : void 0,
5568
5917
  className: cn(
5569
5918
  "relative w-full justify-start gap-3 h-12",
@@ -5597,12 +5946,19 @@ const SidebarButton = ({
5597
5946
  "text-sm font-medium flex-1 text-left",
5598
5947
  active ? `text-category-${category}` : "text-foreground"
5599
5948
  ), children: label }),
5600
- active && /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn(
5949
+ badge ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: cn(
5950
+ "px-2 py-0.5 text-xs font-medium rounded-full flex-shrink-0",
5951
+ "bg-primary/10 text-primary"
5952
+ ), children: badge }) : active && /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn(
5601
5953
  "w-2 h-2 rounded-full flex-shrink-0",
5602
5954
  `bg-category-${category}`
5603
5955
  ) })
5604
5956
  ] }),
5605
- !expanded && active && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute -top-1 -right-1", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn(
5957
+ !expanded && (badge || active) && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute -top-1 -right-1", children: badge ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: cn(
5958
+ "px-1.5 py-0.5 text-xs font-bold rounded-full",
5959
+ "bg-primary text-primary-foreground",
5960
+ "ring-2 ring-background"
5961
+ ), children: badge }) : active && /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn(
5606
5962
  "w-2.5 h-2.5 rounded-full",
5607
5963
  `bg-category-${category}`,
5608
5964
  "ring-2 ring-background"
@@ -5613,14 +5969,11 @@ const SidebarButton = ({
5613
5969
  };
5614
5970
  const Sidebar = ({ className }) => {
5615
5971
  const { isExpanded, toggleSidebar } = useSidebar();
5972
+ const { navigation } = useNavigation();
5616
5973
  const location = reactRouterDom.useLocation();
5617
5974
  const navigate = reactRouterDom.useNavigate();
5618
5975
  const [searchParams] = reactRouterDom.useSearchParams();
5619
- const items = [
5620
- { value: "showcase", label: "Showcase", icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Palette, { className: "w-5 h-5" }), path: "/showcase", category: 5 },
5621
- { value: "admin-dashboard", label: "Admin Dashboard", icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Shield, { className: "w-5 h-5" }), path: "/admin/dashboard", category: 2 },
5622
- { value: "admin-users", label: "User Management", icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Users, { className: "w-5 h-5" }), path: "/admin/users", category: 3 }
5623
- ];
5976
+ const items = getNavigationItems(navigation);
5624
5977
  const handleNavigation = (path) => {
5625
5978
  if (path.includes("?")) {
5626
5979
  const [basePath, query] = path.split("?");
@@ -5676,12 +6029,14 @@ const Sidebar = ({ className }) => {
5676
6029
  return /* @__PURE__ */ jsxRuntime.jsx(
5677
6030
  SidebarButton,
5678
6031
  {
5679
- icon: item.icon,
6032
+ icon: /* @__PURE__ */ jsxRuntime.jsx(Icon, { name: item.icon, className: "w-5 h-5" }),
5680
6033
  label: item.label,
5681
6034
  active: isActive,
5682
6035
  category: item.category,
5683
6036
  expanded: isExpanded,
5684
- onClick: () => handleNavigation(item.path)
6037
+ onClick: () => handleNavigation(item.path),
6038
+ badge: item.badge,
6039
+ disabled: item.disabled
5685
6040
  },
5686
6041
  item.value
5687
6042
  );
@@ -5747,6 +6102,28 @@ const AppLayout = () => {
5747
6102
  )
5748
6103
  ] });
5749
6104
  };
6105
+ const DashboardWithSidePanel = ({
6106
+ children,
6107
+ sidePanel,
6108
+ showSidePanel = false,
6109
+ sidePanelWidth = 72,
6110
+ className
6111
+ }) => {
6112
+ const marginClass = `pr-${sidePanelWidth}`;
6113
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("relative h-full", className), children: [
6114
+ /* @__PURE__ */ jsxRuntime.jsx(
6115
+ "div",
6116
+ {
6117
+ className: cn(
6118
+ "transition-all duration-300",
6119
+ showSidePanel ? marginClass : ""
6120
+ ),
6121
+ children
6122
+ }
6123
+ ),
6124
+ showSidePanel && sidePanel
6125
+ ] });
6126
+ };
5750
6127
  const SectionHeader = ({
5751
6128
  title,
5752
6129
  description,
@@ -7769,6 +8146,7 @@ function createReactApp(config) {
7769
8146
  enableQuery = true,
7770
8147
  enableRouting = true,
7771
8148
  auth,
8149
+ navigation,
7772
8150
  customProviders = []
7773
8151
  } = appConfig;
7774
8152
  const queryClient = new reactQuery.QueryClient({
@@ -7803,7 +8181,7 @@ function createReactApp(config) {
7803
8181
  tree = /* @__PURE__ */ jsxRuntime.jsx(Provider, { children: tree }, Provider.name);
7804
8182
  });
7805
8183
  if (enableRouting) {
7806
- tree = /* @__PURE__ */ jsxRuntime.jsx(SidebarProvider, { children: tree });
8184
+ tree = /* @__PURE__ */ jsxRuntime.jsx(NavigationProvider, { initialNavigation: navigation, children: /* @__PURE__ */ jsxRuntime.jsx(SidebarProvider, { children: tree }) });
7807
8185
  }
7808
8186
  if (enableAuth) {
7809
8187
  tree = /* @__PURE__ */ jsxRuntime.jsx(AuthProvider, { config: auth, children: tree });
@@ -10069,6 +10447,7 @@ exports.DarkModeToggle = DarkModeToggle;
10069
10447
  exports.DashboardCard = DashboardCard;
10070
10448
  exports.DashboardGrid = DashboardGrid;
10071
10449
  exports.DashboardTemplate = DashboardTemplate;
10450
+ exports.DashboardWithSidePanel = DashboardWithSidePanel;
10072
10451
  exports.DataBadge = DataBadge;
10073
10452
  exports.DataDetailTemplate = DataDetailTemplate;
10074
10453
  exports.DataTable = DataTable;
@@ -10096,14 +10475,17 @@ exports.FileUpload = FileUpload;
10096
10475
  exports.FormField = FormField;
10097
10476
  exports.FormGroup = FormGroup;
10098
10477
  exports.GlobalSearch = GlobalSearch;
10478
+ exports.Icon = Icon;
10099
10479
  exports.IconBadge = IconBadge;
10100
10480
  exports.Input = Input;
10101
10481
  exports.Label = Label;
10102
10482
  exports.Loading = Loading;
10103
10483
  exports.LoginForm = LoginForm;
10104
10484
  exports.LogoutButton = LogoutButton;
10485
+ exports.MetricCalculationEngine = MetricCalculationEngine;
10105
10486
  exports.Modal = Modal;
10106
10487
  exports.NavMenu = NavMenu;
10488
+ exports.NavigationProvider = NavigationProvider;
10107
10489
  exports.PageTemplate = PageTemplate;
10108
10490
  exports.Pagination = Pagination;
10109
10491
  exports.PaletteSwitcher = PaletteSwitcher;
@@ -10111,6 +10493,7 @@ exports.ProgressBar = ProgressBar;
10111
10493
  exports.ProtectedRoute = ProtectedRoute;
10112
10494
  exports.RESPONSIVE_CHART_HEIGHTS = RESPONSIVE_CHART_HEIGHTS;
10113
10495
  exports.ROUTES = ROUTES;
10496
+ exports.SalesPanel = SalesPanel;
10114
10497
  exports.SearchInput = SearchInput;
10115
10498
  exports.SectionHeader = SectionHeader;
10116
10499
  exports.Select = Select;
@@ -10119,6 +10502,7 @@ exports.SelectItem = SelectItem;
10119
10502
  exports.SelectTrigger = SelectTrigger;
10120
10503
  exports.SelectValue = SelectValue;
10121
10504
  exports.ShowcaseSection = ShowcaseSection;
10505
+ exports.Sidebar = Sidebar;
10122
10506
  exports.SidebarButton = SidebarButton;
10123
10507
  exports.SidebarProvider = SidebarProvider;
10124
10508
  exports.Skeleton = Skeleton;
@@ -10154,7 +10538,10 @@ exports.formatNumberWithTooltip = formatNumberWithTooltip;
10154
10538
  exports.getAnimationClasses = getAnimationClasses;
10155
10539
  exports.getChartHeight = getChartHeight;
10156
10540
  exports.getContainerHeightClass = getContainerHeightClass;
10541
+ exports.getIcon = getIcon;
10542
+ exports.getNavigationItems = getNavigationItems;
10157
10543
  exports.interactionVariants = interactionVariants;
10544
+ exports.isValidIcon = isValidIcon;
10158
10545
  exports.legacyPatterns = legacyPatterns;
10159
10546
  exports.setGlobalAuthService = setGlobalAuthService;
10160
10547
  exports.tooltipContent = tooltipContent;
@@ -10164,6 +10551,7 @@ exports.useAuth = useAuth;
10164
10551
  exports.useCreateExample = useCreateExample;
10165
10552
  exports.useDeleteExample = useDeleteExample;
10166
10553
  exports.useGetExample = useGetExample;
10554
+ exports.useNavigation = useNavigation;
10167
10555
  exports.usePermissions = usePermissions;
10168
10556
  exports.useSidebar = useSidebar;
10169
10557
  exports.useTextOverflow = useTextOverflow;