@burdenoff/microfe-admin 2026.624.1 → 2026.625.1

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 (47) hide show
  1. package/dist/admin/components/DataTable.js +5 -5
  2. package/dist/admin/components/DataTable.js.map +1 -1
  3. package/dist/admin/components/MetricCard.js +40 -37
  4. package/dist/admin/components/MetricCard.js.map +1 -1
  5. package/dist/admin/components/PageLayout.js +28 -22
  6. package/dist/admin/components/PageLayout.js.map +1 -1
  7. package/dist/admin/components/ui.js +45 -38
  8. package/dist/admin/components/ui.js.map +1 -1
  9. package/dist/admin/pages/AuditLogsPage.js +2 -0
  10. package/dist/admin/pages/AuditLogsPage.js.map +1 -1
  11. package/dist/admin/pages/BillingPage.js +51 -43
  12. package/dist/admin/pages/BillingPage.js.map +1 -1
  13. package/dist/admin/pages/CommunicationsPage.js +3 -0
  14. package/dist/admin/pages/CommunicationsPage.js.map +1 -1
  15. package/dist/admin/pages/ContentPagesPage.js +2 -0
  16. package/dist/admin/pages/ContentPagesPage.js.map +1 -1
  17. package/dist/admin/pages/DashboardPage.js +7 -4
  18. package/dist/admin/pages/DashboardPage.js.map +1 -1
  19. package/dist/admin/pages/FeatureFlagsPage.js +2 -0
  20. package/dist/admin/pages/FeatureFlagsPage.js.map +1 -1
  21. package/dist/admin/pages/OrganizationsListPage.js +2 -0
  22. package/dist/admin/pages/OrganizationsListPage.js.map +1 -1
  23. package/dist/admin/pages/ProductsPage.js +3 -0
  24. package/dist/admin/pages/ProductsPage.js.map +1 -1
  25. package/dist/admin/pages/ReferralsPage.js +4 -0
  26. package/dist/admin/pages/ReferralsPage.js.map +1 -1
  27. package/dist/admin/pages/RolesPermissionsPage.js +3 -0
  28. package/dist/admin/pages/RolesPermissionsPage.js.map +1 -1
  29. package/dist/admin/pages/SREPage.js +4 -0
  30. package/dist/admin/pages/SREPage.js.map +1 -1
  31. package/dist/admin/pages/SandboxSettingsPage.js +1 -0
  32. package/dist/admin/pages/SandboxSettingsPage.js.map +1 -1
  33. package/dist/admin/pages/SettingsPage.js +139 -127
  34. package/dist/admin/pages/SettingsPage.js.map +1 -1
  35. package/dist/admin/pages/SyncFailuresPage.js +3 -0
  36. package/dist/admin/pages/SyncFailuresPage.js.map +1 -1
  37. package/dist/admin/pages/TenantsListPage.js +2 -0
  38. package/dist/admin/pages/TenantsListPage.js.map +1 -1
  39. package/dist/admin/pages/UsersListPage.js +2 -0
  40. package/dist/admin/pages/UsersListPage.js.map +1 -1
  41. package/dist/admin/pages/WaitlistPage.js +2 -0
  42. package/dist/admin/pages/WaitlistPage.js.map +1 -1
  43. package/dist/admin/pages/WorkflowsPage.js +3 -0
  44. package/dist/admin/pages/WorkflowsPage.js.map +1 -1
  45. package/dist/admin/pages/WorkspacesListPage.js +1 -0
  46. package/dist/admin/pages/WorkspacesListPage.js.map +1 -1
  47. package/package.json +2 -2
@@ -14,13 +14,13 @@ function l({ columns: t, data: r, keyExtractor: i, loading: a, skeletonRows: o =
14
14
  right: "text-right"
15
15
  };
16
16
  return /* @__PURE__ */ s("div", {
17
- className: e("overflow-hidden rounded-lg border border-border-subtle", m),
17
+ className: e("overflow-hidden rounded-card border border-border-seam", m),
18
18
  children: /* @__PURE__ */ s("div", {
19
19
  className: "overflow-x-auto",
20
20
  children: /* @__PURE__ */ c("table", {
21
21
  className: "w-full border-collapse",
22
22
  children: [/* @__PURE__ */ s("thead", { children: /* @__PURE__ */ s("tr", {
23
- className: "border-b border-border-subtle bg-bg-sunken/50",
23
+ className: "border-b border-border-seam bg-bg-sunken/40",
24
24
  children: t.map((t) => /* @__PURE__ */ s("th", {
25
25
  className: e("px-4 py-3 text-sm font-medium text-text-secondary", g[t.align || "left"], t.sortable && "cursor-pointer select-none hover:text-text-primary", t.width),
26
26
  style: t.width ? { width: t.width } : void 0,
@@ -34,10 +34,10 @@ function l({ columns: t, data: r, keyExtractor: i, loading: a, skeletonRows: o =
34
34
  })
35
35
  }, t.key))
36
36
  }) }), /* @__PURE__ */ s("tbody", { children: a ? Array.from({ length: o }).map((e, r) => /* @__PURE__ */ s("tr", {
37
- className: "border-b border-border-subtle last:border-0",
37
+ className: "border-b border-border-seam last:border-0",
38
38
  children: t.map((e) => /* @__PURE__ */ s("td", {
39
39
  className: "px-4 py-3",
40
- children: /* @__PURE__ */ s(n, { className: "h-5 w-full" })
40
+ children: /* @__PURE__ */ s(n, { className: "h-5 w-full motion-safe:animate-vc-shimmer" })
41
41
  }, e.key))
42
42
  }, r)) : r.length === 0 ? /* @__PURE__ */ s("tr", { children: /* @__PURE__ */ s("td", {
43
43
  colSpan: t.length,
@@ -47,7 +47,7 @@ function l({ columns: t, data: r, keyExtractor: i, loading: a, skeletonRows: o =
47
47
  children: "No data available"
48
48
  })
49
49
  }) }) : r.map((n, r) => /* @__PURE__ */ s("tr", {
50
- className: e("border-b border-border-subtle last:border-0 transition-colors", u && "cursor-pointer hover:bg-bg-sunken/50"),
50
+ className: e("border-b border-border-seam last:border-0 transition-colors", u && "cursor-pointer hover:bg-bg-sunken/40"),
51
51
  onClick: () => u?.(n),
52
52
  children: t.map((t) => /* @__PURE__ */ s("td", {
53
53
  className: e("px-4 py-3 text-sm", g[t.align || "left"]),
@@ -1 +1 @@
1
- {"version":3,"file":"DataTable.js","names":[],"sources":["../../../src/admin/components/DataTable.tsx"],"sourcesContent":["import type { ReactNode } from 'react';\nimport { ChevronLeft, ChevronRight, ChevronsLeft, ChevronsRight } from 'lucide-react';\nimport { Button, Skeleton } from './ui';\nimport { cn } from '../utils/cn';\n\ninterface Column<T> {\n /** Column key (used for accessing data) */\n key: string;\n /** Column header */\n header: string;\n /** Custom render function */\n render?: (item: T, index: number) => ReactNode;\n /** Column width */\n width?: string;\n /** Align content */\n align?: 'left' | 'center' | 'right';\n /** Sortable */\n sortable?: boolean;\n}\n\ninterface DataTableProps<T> {\n /** Column definitions */\n columns: Column<T>[];\n /** Data to display */\n data: T[];\n /** Key extractor for rows */\n keyExtractor: (item: T) => string;\n /** Loading state */\n loading?: boolean;\n /** Number of skeleton rows when loading */\n skeletonRows?: number;\n /** Empty state content */\n emptyState?: ReactNode;\n /** On row click handler */\n onRowClick?: (item: T) => void;\n /** Current sort column */\n sortBy?: string;\n /** Sort direction */\n sortOrder?: 'asc' | 'desc';\n /** On sort change */\n onSort?: (column: string, order: 'asc' | 'desc') => void;\n /** Additional class name */\n className?: string;\n}\n\n/**\n * Reusable data table component\n */\nexport function DataTable<T>({\n columns,\n data,\n keyExtractor,\n loading,\n skeletonRows = 5,\n emptyState,\n onRowClick,\n sortBy,\n sortOrder,\n onSort,\n className,\n}: DataTableProps<T>) {\n const handleSort = (column: Column<T>) => {\n if (!column.sortable || !onSort) return;\n const newOrder = sortBy === column.key && sortOrder === 'asc' ? 'desc' : 'asc';\n onSort(column.key, newOrder);\n };\n\n const alignClasses = {\n left: 'text-left',\n center: 'text-center',\n right: 'text-right',\n };\n\n return (\n <div className={cn('overflow-hidden rounded-lg border border-border-subtle', className)}>\n <div className=\"overflow-x-auto\">\n <table className=\"w-full border-collapse\">\n <thead>\n <tr className=\"border-b border-border-subtle bg-bg-sunken/50\">\n {columns.map((column) => (\n <th\n key={column.key}\n className={cn(\n 'px-4 py-3 text-sm font-medium text-text-secondary',\n alignClasses[column.align || 'left'],\n column.sortable && 'cursor-pointer select-none hover:text-text-primary',\n column.width\n )}\n style={column.width ? { width: column.width } : undefined}\n onClick={() => handleSort(column)}\n >\n <div className=\"flex items-center gap-2\">\n {column.header}\n {column.sortable && sortBy === column.key && (\n <span className=\"text-xs\">{sortOrder === 'asc' ? '↑' : '↓'}</span>\n )}\n </div>\n </th>\n ))}\n </tr>\n </thead>\n <tbody>\n {loading ? (\n Array.from({ length: skeletonRows }).map((_, rowIndex) => (\n <tr key={rowIndex} className=\"border-b border-border-subtle last:border-0\">\n {columns.map((column) => (\n <td key={column.key} className=\"px-4 py-3\">\n <Skeleton className=\"h-5 w-full\" />\n </td>\n ))}\n </tr>\n ))\n ) : data.length === 0 ? (\n <tr>\n <td colSpan={columns.length} className=\"px-4 py-8\">\n {emptyState || (\n <div className=\"text-center text-sm text-text-secondary\">\n No data available\n </div>\n )}\n </td>\n </tr>\n ) : (\n data.map((item, index) => (\n <tr\n key={keyExtractor(item)}\n className={cn(\n 'border-b border-border-subtle last:border-0 transition-colors',\n onRowClick && 'cursor-pointer hover:bg-bg-sunken/50'\n )}\n onClick={() => onRowClick?.(item)}\n >\n {columns.map((column) => (\n <td\n key={column.key}\n className={cn('px-4 py-3 text-sm', alignClasses[column.align || 'left'])}\n >\n {column.render\n ? column.render(item, index)\n : String((item as Record<string, unknown>)[column.key] ?? '')}\n </td>\n ))}\n </tr>\n ))\n )}\n </tbody>\n </table>\n </div>\n </div>\n );\n}\n\ninterface PaginationProps {\n /** Current page (1-indexed) */\n page: number;\n /** Total pages */\n totalPages: number;\n /** Total items */\n totalItems: number;\n /** Items per page */\n pageSize: number;\n /** On page change */\n onPageChange: (page: number) => void;\n /** Additional class name */\n className?: string;\n}\n\n/**\n * Pagination controls\n */\nexport function Pagination({\n page,\n totalPages,\n totalItems,\n pageSize,\n onPageChange,\n className,\n}: PaginationProps) {\n const startItem = (page - 1) * pageSize + 1;\n const endItem = Math.min(page * pageSize, totalItems);\n\n return (\n <div className={cn('flex items-center justify-between px-4 py-3', className)}>\n <div className=\"text-sm text-text-secondary\">\n Showing {startItem} to {endItem} of {totalItems} results\n </div>\n <div className=\"flex items-center gap-1\">\n <Button\n variant=\"outline\"\n size=\"icon\"\n onClick={() => onPageChange(1)}\n disabled={page === 1}\n aria-label=\"First page\"\n >\n <ChevronsLeft className=\"h-4 w-4\" />\n </Button>\n <Button\n variant=\"outline\"\n size=\"icon\"\n onClick={() => onPageChange(page - 1)}\n disabled={page === 1}\n aria-label=\"Previous page\"\n >\n <ChevronLeft className=\"h-4 w-4\" />\n </Button>\n <span className=\"px-3 text-sm\">\n Page {page} of {totalPages}\n </span>\n <Button\n variant=\"outline\"\n size=\"icon\"\n onClick={() => onPageChange(page + 1)}\n disabled={page === totalPages}\n aria-label=\"Next page\"\n >\n <ChevronRight className=\"h-4 w-4\" />\n </Button>\n <Button\n variant=\"outline\"\n size=\"icon\"\n onClick={() => onPageChange(totalPages)}\n disabled={page === totalPages}\n aria-label=\"Last page\"\n >\n <ChevronsRight className=\"h-4 w-4\" />\n </Button>\n </div>\n </div>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"DataTable.js","names":[],"sources":["../../../src/admin/components/DataTable.tsx"],"sourcesContent":["import type { ReactNode } from 'react';\nimport { ChevronLeft, ChevronRight, ChevronsLeft, ChevronsRight } from 'lucide-react';\nimport { Button, Skeleton } from './ui';\nimport { cn } from '../utils/cn';\n\ninterface Column<T> {\n /** Column key (used for accessing data) */\n key: string;\n /** Column header */\n header: string;\n /** Custom render function */\n render?: (item: T, index: number) => ReactNode;\n /** Column width */\n width?: string;\n /** Align content */\n align?: 'left' | 'center' | 'right';\n /** Sortable */\n sortable?: boolean;\n}\n\ninterface DataTableProps<T> {\n /** Column definitions */\n columns: Column<T>[];\n /** Data to display */\n data: T[];\n /** Key extractor for rows */\n keyExtractor: (item: T) => string;\n /** Loading state */\n loading?: boolean;\n /** Number of skeleton rows when loading */\n skeletonRows?: number;\n /** Empty state content */\n emptyState?: ReactNode;\n /** On row click handler */\n onRowClick?: (item: T) => void;\n /** Current sort column */\n sortBy?: string;\n /** Sort direction */\n sortOrder?: 'asc' | 'desc';\n /** On sort change */\n onSort?: (column: string, order: 'asc' | 'desc') => void;\n /** Additional class name */\n className?: string;\n}\n\n/**\n * Reusable data table component\n */\nexport function DataTable<T>({\n columns,\n data,\n keyExtractor,\n loading,\n skeletonRows = 5,\n emptyState,\n onRowClick,\n sortBy,\n sortOrder,\n onSort,\n className,\n}: DataTableProps<T>) {\n const handleSort = (column: Column<T>) => {\n if (!column.sortable || !onSort) return;\n const newOrder = sortBy === column.key && sortOrder === 'asc' ? 'desc' : 'asc';\n onSort(column.key, newOrder);\n };\n\n const alignClasses = {\n left: 'text-left',\n center: 'text-center',\n right: 'text-right',\n };\n\n return (\n <div className={cn('overflow-hidden rounded-card border border-border-seam', className)}>\n <div className=\"overflow-x-auto\">\n <table className=\"w-full border-collapse\">\n <thead>\n <tr className=\"border-b border-border-seam bg-bg-sunken/40\">\n {columns.map((column) => (\n <th\n key={column.key}\n className={cn(\n 'px-4 py-3 text-sm font-medium text-text-secondary',\n alignClasses[column.align || 'left'],\n column.sortable && 'cursor-pointer select-none hover:text-text-primary',\n column.width\n )}\n style={column.width ? { width: column.width } : undefined}\n onClick={() => handleSort(column)}\n >\n <div className=\"flex items-center gap-2\">\n {column.header}\n {column.sortable && sortBy === column.key && (\n <span className=\"text-xs\">{sortOrder === 'asc' ? '↑' : '↓'}</span>\n )}\n </div>\n </th>\n ))}\n </tr>\n </thead>\n <tbody>\n {loading ? (\n Array.from({ length: skeletonRows }).map((_, rowIndex) => (\n <tr key={rowIndex} className=\"border-b border-border-seam last:border-0\">\n {columns.map((column) => (\n <td key={column.key} className=\"px-4 py-3\">\n <Skeleton className=\"h-5 w-full motion-safe:animate-vc-shimmer\" />\n </td>\n ))}\n </tr>\n ))\n ) : data.length === 0 ? (\n <tr>\n <td colSpan={columns.length} className=\"px-4 py-8\">\n {emptyState || (\n <div className=\"text-center text-sm text-text-secondary\">\n No data available\n </div>\n )}\n </td>\n </tr>\n ) : (\n data.map((item, index) => (\n <tr\n key={keyExtractor(item)}\n className={cn(\n 'border-b border-border-seam last:border-0 transition-colors',\n onRowClick && 'cursor-pointer hover:bg-bg-sunken/40'\n )}\n onClick={() => onRowClick?.(item)}\n >\n {columns.map((column) => (\n <td\n key={column.key}\n className={cn('px-4 py-3 text-sm', alignClasses[column.align || 'left'])}\n >\n {column.render\n ? column.render(item, index)\n : String((item as Record<string, unknown>)[column.key] ?? '')}\n </td>\n ))}\n </tr>\n ))\n )}\n </tbody>\n </table>\n </div>\n </div>\n );\n}\n\ninterface PaginationProps {\n /** Current page (1-indexed) */\n page: number;\n /** Total pages */\n totalPages: number;\n /** Total items */\n totalItems: number;\n /** Items per page */\n pageSize: number;\n /** On page change */\n onPageChange: (page: number) => void;\n /** Additional class name */\n className?: string;\n}\n\n/**\n * Pagination controls\n */\nexport function Pagination({\n page,\n totalPages,\n totalItems,\n pageSize,\n onPageChange,\n className,\n}: PaginationProps) {\n const startItem = (page - 1) * pageSize + 1;\n const endItem = Math.min(page * pageSize, totalItems);\n\n return (\n <div className={cn('flex items-center justify-between px-4 py-3', className)}>\n <div className=\"text-sm text-text-secondary\">\n Showing {startItem} to {endItem} of {totalItems} results\n </div>\n <div className=\"flex items-center gap-1\">\n <Button\n variant=\"outline\"\n size=\"icon\"\n onClick={() => onPageChange(1)}\n disabled={page === 1}\n aria-label=\"First page\"\n >\n <ChevronsLeft className=\"h-4 w-4\" />\n </Button>\n <Button\n variant=\"outline\"\n size=\"icon\"\n onClick={() => onPageChange(page - 1)}\n disabled={page === 1}\n aria-label=\"Previous page\"\n >\n <ChevronLeft className=\"h-4 w-4\" />\n </Button>\n <span className=\"px-3 text-sm\">\n Page {page} of {totalPages}\n </span>\n <Button\n variant=\"outline\"\n size=\"icon\"\n onClick={() => onPageChange(page + 1)}\n disabled={page === totalPages}\n aria-label=\"Next page\"\n >\n <ChevronRight className=\"h-4 w-4\" />\n </Button>\n <Button\n variant=\"outline\"\n size=\"icon\"\n onClick={() => onPageChange(totalPages)}\n disabled={page === totalPages}\n aria-label=\"Last page\"\n >\n <ChevronsRight className=\"h-4 w-4\" />\n </Button>\n </div>\n </div>\n );\n}\n"],"mappings":"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"}
@@ -1,57 +1,60 @@
1
1
  import { cn as e } from "../utils/cn.js";
2
- import { Badge as t, Card as n, CardContent as r, CardHeader as i, CardTitle as a, Skeleton as o } from "./ui.js";
3
- import { formatChange as s, formatCurrency as c, formatNumber as l } from "../utils/formatters.js";
4
- import { Minus as u, TrendingDown as d, TrendingUp as f } from "lucide-react";
5
- import { Link as p } from "react-router-dom";
6
- import { jsx as m, jsxs as h } from "react/jsx-runtime";
2
+ import { Badge as t, Skeleton as n } from "./ui.js";
3
+ import { formatChange as r, formatCurrency as i, formatNumber as a } from "../utils/formatters.js";
4
+ import { Minus as o, TrendingDown as s, TrendingUp as c } from "lucide-react";
5
+ import { Link as l } from "react-router-dom";
6
+ import { jsx as u, jsxs as d } from "react/jsx-runtime";
7
+ import { GlassCard as f } from "@burdenoff/fe-libs/ui";
7
8
  //#region src/admin/components/MetricCard.tsx
8
- function g({ title: g, value: _, change: v, changeType: y = "number", trend: b, changeIsPositive: x, icon: S, subtitle: C, linkTo: w, priority: T, loading: E, className: D }) {
9
- let O = x ?? b === "up", k = typeof _ == "number" ? y === "currency" ? c(_) : l(_) : _, A = v === void 0 ? null : s(v, y === "percentage"), j = b === "up" ? f : b === "down" ? d : u, M = /* @__PURE__ */ h(n, {
10
- className: e("transition-shadow hover:shadow-md", T && {
9
+ function p({ title: p, value: m, change: h, changeType: g = "number", trend: _, changeIsPositive: v, icon: y, subtitle: b, linkTo: x, priority: S, loading: C, hero: w = !1, className: T }) {
10
+ let E = v ?? _ === "up", D = typeof m == "number" ? g === "currency" ? i(m) : a(m) : m, O = h === void 0 ? null : r(h, g === "percentage"), k = _ === "up" ? c : _ === "down" ? s : o, A = /* @__PURE__ */ d(f, {
11
+ treatment: w ? "glass" : "metric",
12
+ glow: w,
13
+ className: e("h-full p-6", S && {
11
14
  normal: "",
12
- high: "border-l-4 border-l-warning",
13
- critical: "border-l-4 border-l-destructive"
14
- }[T], D),
15
- children: [/* @__PURE__ */ h(i, {
15
+ high: "border-l-4 border-l-status-warning-border",
16
+ critical: "border-l-4 border-l-status-error-border"
17
+ }[S], T),
18
+ children: [/* @__PURE__ */ d("div", {
16
19
  className: "flex flex-row items-center justify-between pb-2",
17
- children: [/* @__PURE__ */ m(a, {
20
+ children: [/* @__PURE__ */ u("span", {
18
21
  className: "text-sm font-medium text-text-secondary",
19
- children: g
20
- }), S && /* @__PURE__ */ m("div", {
22
+ children: p
23
+ }), y && /* @__PURE__ */ u("div", {
21
24
  className: "text-text-secondary",
22
- children: S
25
+ children: y
23
26
  })]
24
- }), /* @__PURE__ */ m(r, { children: E ? /* @__PURE__ */ h("div", {
27
+ }), C ? /* @__PURE__ */ d("div", {
25
28
  className: "space-y-2",
26
- children: [/* @__PURE__ */ m(o, { className: "h-8 w-24" }), /* @__PURE__ */ m(o, { className: "h-4 w-16" })]
27
- }) : /* @__PURE__ */ h("div", { children: [/* @__PURE__ */ h("div", {
29
+ children: [/* @__PURE__ */ u(n, { className: "h-8 w-24" }), /* @__PURE__ */ u(n, { className: "h-4 w-16" })]
30
+ }) : /* @__PURE__ */ d("div", { children: [/* @__PURE__ */ d("div", {
28
31
  className: "flex items-baseline justify-between",
29
- children: [/* @__PURE__ */ m("div", {
30
- className: "text-3xl font-bold text-text-primary",
31
- children: k
32
- }), A !== null && /* @__PURE__ */ h(t, {
33
- variant: O ? "success" : "destructive",
34
- className: "flex items-center gap-1",
35
- children: [/* @__PURE__ */ m(j, { className: "h-3 w-3" }), A]
32
+ children: [/* @__PURE__ */ u("div", {
33
+ className: "text-3xl font-bold tabular-nums text-text-primary",
34
+ children: D
35
+ }), O !== null && /* @__PURE__ */ d(t, {
36
+ variant: E ? "success" : "destructive",
37
+ className: "flex items-center gap-1 tabular-nums",
38
+ children: [/* @__PURE__ */ u(k, { className: "h-3 w-3" }), O]
36
39
  })]
37
- }), C && /* @__PURE__ */ m("p", {
40
+ }), b && /* @__PURE__ */ u("p", {
38
41
  className: "mt-1 text-xs text-text-secondary",
39
- children: C
40
- })] }) })]
42
+ children: b
43
+ })] })]
41
44
  });
42
- return w ? /* @__PURE__ */ m(p, {
43
- to: w,
44
- className: "block",
45
- children: M
46
- }) : M;
45
+ return x ? /* @__PURE__ */ u(l, {
46
+ to: x,
47
+ className: "block rounded-card focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-focus-ring)] focus-visible:ring-offset-2",
48
+ children: A
49
+ }) : A;
47
50
  }
48
- function _({ children: t, className: n }) {
49
- return /* @__PURE__ */ m("div", {
51
+ function m({ children: t, className: n }) {
52
+ return /* @__PURE__ */ u("div", {
50
53
  className: e("grid gap-4", "grid-cols-1 sm:grid-cols-2 xl:grid-cols-4", n),
51
54
  children: t
52
55
  });
53
56
  }
54
57
  //#endregion
55
- export { g as MetricCard, _ as MetricsGrid };
58
+ export { p as MetricCard, m as MetricsGrid };
56
59
 
57
60
  //# sourceMappingURL=MetricCard.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"MetricCard.js","names":[],"sources":["../../../src/admin/components/MetricCard.tsx"],"sourcesContent":["import type { ReactNode } from 'react';\nimport { Link } from 'react-router-dom';\nimport { TrendingUp, TrendingDown, Minus } from 'lucide-react';\nimport { Card, CardHeader, CardTitle, CardContent, Badge, Skeleton } from './ui';\nimport { cn } from '../utils/cn';\nimport { formatNumber, formatCurrency, formatChange } from '../utils/formatters';\n\nexport interface MetricCardProps {\n /** Card title */\n title: string;\n /** Metric value (number or formatted string) */\n value: number | string;\n /** Change from previous period */\n change?: number;\n /** Type of change display */\n changeType?: 'number' | 'percentage' | 'currency';\n /** Trend direction */\n trend?: 'up' | 'down' | 'neutral';\n /** Whether change is positive or negative for styling */\n changeIsPositive?: boolean;\n /** Icon to display */\n icon?: ReactNode;\n /** Subtitle text */\n subtitle?: string;\n /** Link to navigate to on click */\n linkTo?: string;\n /** Priority indicator */\n priority?: 'normal' | 'high' | 'critical';\n /** Loading state */\n loading?: boolean;\n /** Additional class name */\n className?: string;\n}\n\n/**\n * Metric card component for dashboard\n */\nexport function MetricCard({\n title,\n value,\n change,\n changeType = 'number',\n trend,\n changeIsPositive,\n icon,\n subtitle,\n linkTo,\n priority,\n loading,\n className,\n}: MetricCardProps) {\n // Determine if change is positive based on trend or explicit prop\n const isPositive = changeIsPositive ?? trend === 'up';\n\n // Format the value\n const formattedValue =\n typeof value === 'number'\n ? changeType === 'currency'\n ? formatCurrency(value)\n : formatNumber(value)\n : value;\n\n // Format the change\n const formattedChange =\n change !== undefined ? formatChange(change, changeType === 'percentage') : null;\n\n // Get trend icon\n const TrendIcon = trend === 'up' ? TrendingUp : trend === 'down' ? TrendingDown : Minus;\n\n // Priority border classes\n const priorityClasses = {\n normal: '',\n high: 'border-l-4 border-l-warning',\n critical: 'border-l-4 border-l-destructive',\n };\n\n const cardContent = (\n <Card\n className={cn(\n 'transition-shadow hover:shadow-md',\n priority && priorityClasses[priority],\n className\n )}\n >\n <CardHeader className=\"flex flex-row items-center justify-between pb-2\">\n <CardTitle className=\"text-sm font-medium text-text-secondary\">{title}</CardTitle>\n {icon && <div className=\"text-text-secondary\">{icon}</div>}\n </CardHeader>\n <CardContent>\n {loading ? (\n <div className=\"space-y-2\">\n <Skeleton className=\"h-8 w-24\" />\n <Skeleton className=\"h-4 w-16\" />\n </div>\n ) : (\n <div>\n <div className=\"flex items-baseline justify-between\">\n <div className=\"text-3xl font-bold text-text-primary\">{formattedValue}</div>\n {formattedChange !== null && (\n <Badge\n variant={isPositive ? 'success' : 'destructive'}\n className=\"flex items-center gap-1\"\n >\n <TrendIcon className=\"h-3 w-3\" />\n {formattedChange}\n </Badge>\n )}\n </div>\n {subtitle && <p className=\"mt-1 text-xs text-text-secondary\">{subtitle}</p>}\n </div>\n )}\n </CardContent>\n </Card>\n );\n\n if (linkTo) {\n return (\n <Link to={linkTo} className=\"block\">\n {cardContent}\n </Link>\n );\n }\n\n return cardContent;\n}\n\n/**\n * Grid container for metric cards\n */\nexport function MetricsGrid({ children, className }: { children: ReactNode; className?: string }) {\n return (\n <div className={cn('grid gap-4', 'grid-cols-1 sm:grid-cols-2 xl:grid-cols-4', className)}>\n {children}\n </div>\n );\n}\n"],"mappings":";;;;;;;AAqCA,SAAgB,EAAW,EACzB,UACA,UACA,WACA,gBAAa,UACb,UACA,qBACA,SACA,aACA,WACA,aACA,YACA,gBACkB;CAElB,IAAM,IAAa,KAAoB,MAAU,MAG3C,IACJ,OAAO,KAAU,WACb,MAAe,aACb,EAAe,EAAM,GACrB,EAAa,EAAM,GACrB,GAGA,IACJ,MAAW,KAAA,IAAgE,OAApD,EAAa,GAAQ,MAAe,aAAa,EAGpE,IAAY,MAAU,OAAO,IAAa,MAAU,SAAS,IAAe,GAS5E,IACJ,kBAAC,GAAD;EACE,WAAW,EACT,qCACA,KAVkB;GACtB,QAAQ;GACR,MAAM;GACN,UAAU;GACX,CAMiC,IAC5B,EACD;YALH,CAOE,kBAAC,GAAD;GAAY,WAAU;aAAtB,CACE,kBAAC,GAAD;IAAW,WAAU;cAA2C;IAAkB,CAAA,EACjF,KAAQ,kBAAC,OAAD;IAAK,WAAU;cAAuB;IAAW,CAAA,CAC/C;MACb,kBAAC,GAAD,EAAA,UACG,IACC,kBAAC,OAAD;GAAK,WAAU;aAAf,CACE,kBAAC,GAAD,EAAU,WAAU,YAAa,CAAA,EACjC,kBAAC,GAAD,EAAU,WAAU,YAAa,CAAA,CAC7B;OAEN,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,OAAD;GAAK,WAAU;aAAf,CACE,kBAAC,OAAD;IAAK,WAAU;cAAwC;IAAqB,CAAA,EAC3E,MAAoB,QACnB,kBAAC,GAAD;IACE,SAAS,IAAa,YAAY;IAClC,WAAU;cAFZ,CAIE,kBAAC,GAAD,EAAW,WAAU,WAAY,CAAA,EAChC,EACK;MAEN;MACL,KAAY,kBAAC,KAAD;GAAG,WAAU;aAAoC;GAAa,CAAA,CACvE,EAAA,CAAA,EAEI,CAAA,CACT;;AAWT,QARI,IAEA,kBAAC,GAAD;EAAM,IAAI;EAAQ,WAAU;YACzB;EACI,CAAA,GAIJ;;AAMT,SAAgB,EAAY,EAAE,aAAU,gBAA0D;AAChG,QACE,kBAAC,OAAD;EAAK,WAAW,EAAG,cAAc,6CAA6C,EAAU;EACrF;EACG,CAAA"}
1
+ {"version":3,"file":"MetricCard.js","names":[],"sources":["../../../src/admin/components/MetricCard.tsx"],"sourcesContent":["import type { ReactNode } from 'react';\nimport { Link } from 'react-router-dom';\nimport { TrendingUp, TrendingDown, Minus } from 'lucide-react';\nimport { GlassCard } from '@burdenoff/fe-libs/ui';\nimport { Badge, Skeleton } from './ui';\nimport { cn } from '../utils/cn';\nimport { formatNumber, formatCurrency, formatChange } from '../utils/formatters';\n\nexport interface MetricCardProps {\n /** Card title */\n title: string;\n /** Metric value (number or formatted string) */\n value: number | string;\n /** Change from previous period */\n change?: number;\n /** Type of change display */\n changeType?: 'number' | 'percentage' | 'currency';\n /** Trend direction */\n trend?: 'up' | 'down' | 'neutral';\n /** Whether change is positive or negative for styling */\n changeIsPositive?: boolean;\n /** Icon to display */\n icon?: ReactNode;\n /** Subtitle text */\n subtitle?: string;\n /** Link to navigate to on click */\n linkTo?: string;\n /** Priority indicator */\n priority?: 'normal' | 'high' | 'critical';\n /** Loading state */\n loading?: boolean;\n /**\n * Hero metric — uses the glass treatment with an accent glow (Boff UI 2.0).\n * Reserve for the single most important metric per group.\n */\n hero?: boolean;\n /** Additional class name */\n className?: string;\n}\n\n/**\n * Metric card component for dashboard\n */\nexport function MetricCard({\n title,\n value,\n change,\n changeType = 'number',\n trend,\n changeIsPositive,\n icon,\n subtitle,\n linkTo,\n priority,\n loading,\n hero = false,\n className,\n}: MetricCardProps) {\n // Determine if change is positive based on trend or explicit prop\n const isPositive = changeIsPositive ?? trend === 'up';\n\n // Format the value\n const formattedValue =\n typeof value === 'number'\n ? changeType === 'currency'\n ? formatCurrency(value)\n : formatNumber(value)\n : value;\n\n // Format the change\n const formattedChange =\n change !== undefined ? formatChange(change, changeType === 'percentage') : null;\n\n // Get trend icon\n const TrendIcon = trend === 'up' ? TrendingUp : trend === 'down' ? TrendingDown : Minus;\n\n // Priority accent (left rail) — semantic tokens only.\n const priorityClasses = {\n normal: '',\n high: 'border-l-4 border-l-status-warning-border',\n critical: 'border-l-4 border-l-status-error-border',\n };\n\n const cardContent = (\n <GlassCard\n treatment={hero ? 'glass' : 'metric'}\n glow={hero}\n className={cn('h-full p-6', priority && priorityClasses[priority], className)}\n >\n <div className=\"flex flex-row items-center justify-between pb-2\">\n <span className=\"text-sm font-medium text-text-secondary\">{title}</span>\n {icon && <div className=\"text-text-secondary\">{icon}</div>}\n </div>\n {loading ? (\n <div className=\"space-y-2\">\n <Skeleton className=\"h-8 w-24\" />\n <Skeleton className=\"h-4 w-16\" />\n </div>\n ) : (\n <div>\n <div className=\"flex items-baseline justify-between\">\n <div className=\"text-3xl font-bold tabular-nums text-text-primary\">\n {formattedValue}\n </div>\n {formattedChange !== null && (\n <Badge\n variant={isPositive ? 'success' : 'destructive'}\n className=\"flex items-center gap-1 tabular-nums\"\n >\n <TrendIcon className=\"h-3 w-3\" />\n {formattedChange}\n </Badge>\n )}\n </div>\n {subtitle && <p className=\"mt-1 text-xs text-text-secondary\">{subtitle}</p>}\n </div>\n )}\n </GlassCard>\n );\n\n if (linkTo) {\n return (\n <Link\n to={linkTo}\n className=\"block rounded-card focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-focus-ring)] focus-visible:ring-offset-2\"\n >\n {cardContent}\n </Link>\n );\n }\n\n return cardContent;\n}\n\n/**\n * Grid container for metric cards\n */\nexport function MetricsGrid({ children, className }: { children: ReactNode; className?: string }) {\n return (\n <div className={cn('grid gap-4', 'grid-cols-1 sm:grid-cols-2 xl:grid-cols-4', className)}>\n {children}\n </div>\n );\n}\n"],"mappings":";;;;;;;;AA2CA,SAAgB,EAAW,EACzB,UACA,UACA,WACA,gBAAa,UACb,UACA,qBACA,SACA,aACA,WACA,aACA,YACA,UAAO,IACP,gBACkB;CAElB,IAAM,IAAa,KAAoB,MAAU,MAG3C,IACJ,OAAO,KAAU,WACb,MAAe,aACb,EAAe,EAAM,GACrB,EAAa,EAAM,GACrB,GAGA,IACJ,MAAW,KAAA,IAAgE,OAApD,EAAa,GAAQ,MAAe,aAAa,EAGpE,IAAY,MAAU,OAAO,IAAa,MAAU,SAAS,IAAe,GAS5E,IACJ,kBAAC,GAAD;EACE,WAAW,IAAO,UAAU;EAC5B,MAAM;EACN,WAAW,EAAG,cAAc,KAVR;GACtB,QAAQ;GACR,MAAM;GACN,UAAU;GACX,CAM2D,IAAW,EAAU;YAH/E,CAKE,kBAAC,OAAD;GAAK,WAAU;aAAf,CACE,kBAAC,QAAD;IAAM,WAAU;cAA2C;IAAa,CAAA,EACvE,KAAQ,kBAAC,OAAD;IAAK,WAAU;cAAuB;IAAW,CAAA,CACtD;MACL,IACC,kBAAC,OAAD;GAAK,WAAU;aAAf,CACE,kBAAC,GAAD,EAAU,WAAU,YAAa,CAAA,EACjC,kBAAC,GAAD,EAAU,WAAU,YAAa,CAAA,CAC7B;OAEN,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,OAAD;GAAK,WAAU;aAAf,CACE,kBAAC,OAAD;IAAK,WAAU;cACZ;IACG,CAAA,EACL,MAAoB,QACnB,kBAAC,GAAD;IACE,SAAS,IAAa,YAAY;IAClC,WAAU;cAFZ,CAIE,kBAAC,GAAD,EAAW,WAAU,WAAY,CAAA,EAChC,EACK;MAEN;MACL,KAAY,kBAAC,KAAD;GAAG,WAAU;aAAoC;GAAa,CAAA,CACvE,EAAA,CAAA,CAEE;;AAcd,QAXI,IAEA,kBAAC,GAAD;EACE,IAAI;EACJ,WAAU;YAET;EACI,CAAA,GAIJ;;AAMT,SAAgB,EAAY,EAAE,aAAU,gBAA0D;AAChG,QACE,kBAAC,OAAD;EAAK,WAAW,EAAG,cAAc,6CAA6C,EAAU;EACrF;EACG,CAAA"}
@@ -1,31 +1,37 @@
1
1
  import { cn as e } from "../utils/cn.js";
2
- import { jsx as t, jsxs as n } from "react/jsx-runtime";
2
+ import { Fragment as t, jsx as n, jsxs as r } from "react/jsx-runtime";
3
+ import { AuroraBackground as i, GradientText as a } from "@burdenoff/fe-libs/ui";
3
4
  //#region src/admin/components/PageLayout.tsx
4
- function r({ title: r, description: i, actions: a, children: o, className: s }) {
5
- return /* @__PURE__ */ n("div", {
6
- className: e("flex h-full flex-col", s),
7
- children: [/* @__PURE__ */ n("header", {
8
- className: "flex flex-col gap-4 border-b border-border-subtle bg-bg-surface px-6 py-4 sm:flex-row sm:items-center sm:justify-between",
9
- children: [/* @__PURE__ */ n("div", {
10
- className: "min-w-0 flex-1",
11
- children: [/* @__PURE__ */ t("h1", {
12
- className: "text-2xl font-bold tracking-tight text-text-primary sm:text-3xl",
13
- children: r
14
- }), i && /* @__PURE__ */ t("p", {
15
- className: "mt-1 text-sm text-text-secondary sm:text-base",
16
- children: i
17
- })]
18
- }), a && /* @__PURE__ */ t("div", {
19
- className: "flex flex-shrink-0 flex-wrap items-center gap-2",
20
- children: a
21
- })]
22
- }), /* @__PURE__ */ t("div", {
5
+ function o({ title: o, description: s, actions: c, children: l, className: u, gradientWord: d, aurora: f = !1 }) {
6
+ let p = o, m = null;
7
+ return d && o.endsWith(d) && o.length > d.length ? (p = o.slice(0, o.length - d.length), m = d) : d && o === d && (p = "", m = d), /* @__PURE__ */ r("div", {
8
+ className: e("flex h-full flex-col", u),
9
+ children: [/* @__PURE__ */ r("header", {
10
+ className: e("relative flex flex-col gap-4 border-b border-border-seam bg-bg-surface px-6 py-4 sm:flex-row sm:items-center sm:justify-between", f && "overflow-hidden"),
11
+ children: [
12
+ f && /* @__PURE__ */ n(i, { intensity: "subtle" }),
13
+ /* @__PURE__ */ r("div", {
14
+ className: "min-w-0 flex-1",
15
+ children: [/* @__PURE__ */ n("h1", {
16
+ className: "text-2xl font-bold tracking-tight text-text-primary sm:text-3xl",
17
+ children: m === null ? o : /* @__PURE__ */ r(t, { children: [p, /* @__PURE__ */ n(a, { children: m })] })
18
+ }), s && /* @__PURE__ */ n("p", {
19
+ className: "mt-1 text-sm text-text-secondary sm:text-base",
20
+ children: s
21
+ })]
22
+ }),
23
+ c && /* @__PURE__ */ n("div", {
24
+ className: "flex flex-shrink-0 flex-wrap items-center gap-2",
25
+ children: c
26
+ })
27
+ ]
28
+ }), /* @__PURE__ */ n("div", {
23
29
  className: "flex-1 overflow-auto p-6",
24
- children: o
30
+ children: l
25
31
  })]
26
32
  });
27
33
  }
28
34
  //#endregion
29
- export { r as PageLayout };
35
+ export { o as PageLayout };
30
36
 
31
37
  //# sourceMappingURL=PageLayout.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"PageLayout.js","names":[],"sources":["../../../src/admin/components/PageLayout.tsx"],"sourcesContent":["import type { ReactNode } from 'react';\nimport { cn } from '../utils/cn';\n\ninterface PageLayoutProps {\n /** Page title */\n title: string;\n /** Optional description */\n description?: string;\n /** Actions to display in the header (buttons, etc.) */\n actions?: ReactNode;\n /** Page content */\n children: ReactNode;\n /** Additional class names */\n className?: string;\n}\n\n/**\n * Standard page layout component with title, description, and content area\n */\nexport function PageLayout({ title, description, actions, children, className }: PageLayoutProps) {\n return (\n <div className={cn('flex h-full flex-col', className)}>\n {/* Page Header */}\n <header className=\"flex flex-col gap-4 border-b border-border-subtle bg-bg-surface px-6 py-4 sm:flex-row sm:items-center sm:justify-between\">\n <div className=\"min-w-0 flex-1\">\n <h1 className=\"text-2xl font-bold tracking-tight text-text-primary sm:text-3xl\">{title}</h1>\n {description && (\n <p className=\"mt-1 text-sm text-text-secondary sm:text-base\">{description}</p>\n )}\n </div>\n {actions && (\n <div className=\"flex flex-shrink-0 flex-wrap items-center gap-2\">{actions}</div>\n )}\n </header>\n\n {/* Page Content — must not use a <main> landmark here because the\n host shell (AppShellLayout) already renders one; nesting <main>\n elements is invalid HTML and an a11y violation. */}\n <div className=\"flex-1 overflow-auto p-6\">{children}</div>\n </div>\n );\n}\n\ninterface PageSectionProps {\n /** Section title */\n title?: string;\n /** Optional description */\n description?: string;\n /** Section content */\n children: ReactNode;\n /** Additional class names */\n className?: string;\n}\n\n/**\n * Section within a page\n */\nexport function PageSection({ title, description, children, className }: PageSectionProps) {\n return (\n <section className={cn('space-y-4', className)}>\n {(title || description) && (\n <div>\n {title && <h2 className=\"text-lg font-semibold text-text-primary\">{title}</h2>}\n {description && <p className=\"text-sm text-text-secondary\">{description}</p>}\n </div>\n )}\n {children}\n </section>\n );\n}\n"],"mappings":";;;AAmBA,SAAgB,EAAW,EAAE,UAAO,gBAAa,YAAS,aAAU,gBAA8B;AAChG,QACE,kBAAC,OAAD;EAAK,WAAW,EAAG,wBAAwB,EAAU;YAArD,CAEE,kBAAC,UAAD;GAAQ,WAAU;aAAlB,CACE,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,MAAD;KAAI,WAAU;eAAmE;KAAW,CAAA,EAC3F,KACC,kBAAC,KAAD;KAAG,WAAU;eAAiD;KAAgB,CAAA,CAE5E;OACL,KACC,kBAAC,OAAD;IAAK,WAAU;cAAmD;IAAc,CAAA,CAE3E;MAKT,kBAAC,OAAD;GAAK,WAAU;GAA4B;GAAe,CAAA,CACtD"}
1
+ {"version":3,"file":"PageLayout.js","names":[],"sources":["../../../src/admin/components/PageLayout.tsx"],"sourcesContent":["import type { ReactNode } from 'react';\nimport { AuroraBackground, GradientText } from '@burdenoff/fe-libs/ui';\nimport { cn } from '../utils/cn';\n\ninterface PageLayoutProps {\n /** Page title */\n title: string;\n /** Optional description */\n description?: string;\n /** Actions to display in the header (buttons, etc.) */\n actions?: ReactNode;\n /** Page content */\n children: ReactNode;\n /** Additional class names */\n className?: string;\n /**\n * When set, the trailing words of the title are clipped with a brand\n * gradient (Boff UI 2.0 hero treatment). The leading text stays solid.\n * Provide the exact substring that appears at the end of `title`.\n */\n gradientWord?: string;\n /**\n * Render the living aurora backdrop behind the page header (Boff UI 2.0).\n * Use at most ONE per MFE — set on the primary/landing page header only.\n */\n aurora?: boolean;\n}\n\n/**\n * Standard page layout component with title, description, and content area\n */\nexport function PageLayout({\n title,\n description,\n actions,\n children,\n className,\n gradientWord,\n aurora = false,\n}: PageLayoutProps) {\n // Split the title so only the trailing key noun is gradient-clipped (ONE per page).\n let leading = title;\n let gradient: string | null = null;\n if (gradientWord && title.endsWith(gradientWord) && title.length > gradientWord.length) {\n leading = title.slice(0, title.length - gradientWord.length);\n gradient = gradientWord;\n } else if (gradientWord && title === gradientWord) {\n leading = '';\n gradient = gradientWord;\n }\n\n return (\n <div className={cn('flex h-full flex-col', className)}>\n {/* Page Header */}\n <header\n className={cn(\n 'relative flex flex-col gap-4 border-b border-border-seam bg-bg-surface px-6 py-4 sm:flex-row sm:items-center sm:justify-between',\n aurora && 'overflow-hidden'\n )}\n >\n {aurora && <AuroraBackground intensity=\"subtle\" />}\n <div className=\"min-w-0 flex-1\">\n <h1 className=\"text-2xl font-bold tracking-tight text-text-primary sm:text-3xl\">\n {gradient !== null ? (\n <>\n {leading}\n <GradientText>{gradient}</GradientText>\n </>\n ) : (\n title\n )}\n </h1>\n {description && (\n <p className=\"mt-1 text-sm text-text-secondary sm:text-base\">{description}</p>\n )}\n </div>\n {actions && (\n <div className=\"flex flex-shrink-0 flex-wrap items-center gap-2\">{actions}</div>\n )}\n </header>\n\n {/* Page Content — must not use a <main> landmark here because the\n host shell (AppShellLayout) already renders one; nesting <main>\n elements is invalid HTML and an a11y violation. */}\n <div className=\"flex-1 overflow-auto p-6\">{children}</div>\n </div>\n );\n}\n\ninterface PageSectionProps {\n /** Section title */\n title?: string;\n /** Optional description */\n description?: string;\n /** Section content */\n children: ReactNode;\n /** Additional class names */\n className?: string;\n}\n\n/**\n * Section within a page\n */\nexport function PageSection({ title, description, children, className }: PageSectionProps) {\n return (\n <section className={cn('space-y-4', className)}>\n {(title || description) && (\n <div>\n {title && <h2 className=\"text-lg font-semibold text-text-primary\">{title}</h2>}\n {description && <p className=\"text-sm text-text-secondary\">{description}</p>}\n </div>\n )}\n {children}\n </section>\n );\n}\n"],"mappings":";;;;AA+BA,SAAgB,EAAW,EACzB,UACA,gBACA,YACA,aACA,cACA,iBACA,YAAS,MACS;CAElB,IAAI,IAAU,GACV,IAA0B;AAS9B,QARI,KAAgB,EAAM,SAAS,EAAa,IAAI,EAAM,SAAS,EAAa,UAC9E,IAAU,EAAM,MAAM,GAAG,EAAM,SAAS,EAAa,OAAO,EAC5D,IAAW,KACF,KAAgB,MAAU,MACnC,IAAU,IACV,IAAW,IAIX,kBAAC,OAAD;EAAK,WAAW,EAAG,wBAAwB,EAAU;YAArD,CAEE,kBAAC,UAAD;GACE,WAAW,EACT,mIACA,KAAU,kBACX;aAJH;IAMG,KAAU,kBAAC,GAAD,EAAkB,WAAU,UAAW,CAAA;IAClD,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,MAAD;MAAI,WAAU;gBACX,MAAa,OAMZ,IALA,kBAAA,GAAA,EAAA,UAAA,CACG,GACD,kBAAC,GAAD,EAAA,UAAe,GAAwB,CAAA,CACtC,EAAA,CAAA;MAIF,CAAA,EACJ,KACC,kBAAC,KAAD;MAAG,WAAU;gBAAiD;MAAgB,CAAA,CAE5E;;IACL,KACC,kBAAC,OAAD;KAAK,WAAU;eAAmD;KAAc,CAAA;IAE3E;MAKT,kBAAC,OAAD;GAAK,WAAU;GAA4B;GAAe,CAAA,CACtD"}
@@ -1,108 +1,109 @@
1
1
  import { cn as e } from "../utils/cn.js";
2
2
  import { forwardRef as t } from "react";
3
3
  import { jsx as n, jsxs as r } from "react/jsx-runtime";
4
+ import { IllustratedEmptyState as i } from "@burdenoff/fe-libs/ui";
4
5
  //#region src/admin/components/ui.tsx
5
- var i = t(({ className: t, children: r, ...i }, a) => /* @__PURE__ */ n("div", {
6
+ var a = t(({ className: t, children: r, ...i }, a) => /* @__PURE__ */ n("div", {
6
7
  ref: a,
7
- className: e("rounded-lg border border-border-subtle bg-bg-surface text-text-primary shadow-sm", t),
8
+ className: e("rounded-card border border-border-seam bg-bg-surface text-text-primary shadow-elevation-1 transition-[box-shadow,border-color] duration-200 hover:border-border-strong", t),
8
9
  ...i,
9
10
  children: r
10
11
  }));
11
- i.displayName = "Card";
12
- var a = t(({ className: t, children: r, ...i }, a) => /* @__PURE__ */ n("div", {
12
+ a.displayName = "Card";
13
+ var o = t(({ className: t, children: r, ...i }, a) => /* @__PURE__ */ n("div", {
13
14
  ref: a,
14
15
  className: e("flex flex-col space-y-1.5 p-6", t),
15
16
  ...i,
16
17
  children: r
17
18
  }));
18
- a.displayName = "CardHeader";
19
- var o = t(({ className: t, children: r, ...i }, a) => /* @__PURE__ */ n("h3", {
19
+ o.displayName = "CardHeader";
20
+ var s = t(({ className: t, children: r, ...i }, a) => /* @__PURE__ */ n("h3", {
20
21
  ref: a,
21
22
  className: e("text-2xl font-semibold leading-none tracking-tight", t),
22
23
  ...i,
23
24
  children: r
24
25
  }));
25
- o.displayName = "CardTitle";
26
- var s = t(({ className: t, children: r, ...i }, a) => /* @__PURE__ */ n("p", {
26
+ s.displayName = "CardTitle";
27
+ var c = t(({ className: t, children: r, ...i }, a) => /* @__PURE__ */ n("p", {
27
28
  ref: a,
28
29
  className: e("text-sm text-text-secondary", t),
29
30
  ...i,
30
31
  children: r
31
32
  }));
32
- s.displayName = "CardDescription";
33
- var c = t(({ className: t, children: r, ...i }, a) => /* @__PURE__ */ n("div", {
33
+ c.displayName = "CardDescription";
34
+ var l = t(({ className: t, children: r, ...i }, a) => /* @__PURE__ */ n("div", {
34
35
  ref: a,
35
36
  className: e("p-6 pt-0", t),
36
37
  ...i,
37
38
  children: r
38
39
  }));
39
- c.displayName = "CardContent";
40
- var l = t(({ className: t, children: r, ...i }, a) => /* @__PURE__ */ n("div", {
40
+ l.displayName = "CardContent";
41
+ var u = t(({ className: t, children: r, ...i }, a) => /* @__PURE__ */ n("div", {
41
42
  ref: a,
42
43
  className: e("flex items-center p-6 pt-0", t),
43
44
  ...i,
44
45
  children: r
45
46
  }));
46
- l.displayName = "CardFooter";
47
- var u = {
47
+ u.displayName = "CardFooter";
48
+ var d = {
48
49
  default: "bg-action-primary-bg text-action-primary-text",
49
50
  secondary: "bg-secondary text-secondary-foreground",
50
51
  success: "bg-success/10 text-success border-success/20",
51
52
  warning: "bg-warning/10 text-warning border-warning/20",
52
53
  destructive: "bg-status-error-bg/10 text-status-error-text border-status-error-border/20",
53
54
  outline: "border-border-subtle bg-transparent text-text-primary"
54
- }, d = t(({ className: t, variant: r = "default", children: i, ...a }, o) => /* @__PURE__ */ n("span", {
55
+ }, f = t(({ className: t, variant: r = "default", children: i, ...a }, o) => /* @__PURE__ */ n("span", {
55
56
  ref: o,
56
- className: e("inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors", u[r], t),
57
+ className: e("inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors", d[r], t),
57
58
  ...a,
58
59
  children: i
59
60
  }));
60
- d.displayName = "Badge";
61
- var f = {
61
+ f.displayName = "Badge";
62
+ var p = {
62
63
  default: "bg-action-primary-bg text-action-primary-text hover:bg-action-primary-bg/90",
63
64
  secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80",
64
65
  outline: "border border-border-default bg-bg-surface hover:bg-accent hover:text-text-primary",
65
66
  ghost: "hover:bg-accent hover:text-text-primary",
66
67
  destructive: "bg-status-error-bg text-status-error-text hover:bg-status-error-bg/90",
67
68
  link: "text-primary underline-offset-4 hover:underline"
68
- }, p = {
69
+ }, m = {
69
70
  default: "h-10 px-4 py-2",
70
71
  sm: "h-9 rounded-md px-3",
71
72
  lg: "h-11 rounded-md px-8",
72
73
  icon: "h-10 w-10"
73
- }, m = t(({ className: t, variant: r = "default", size: i = "default", children: a, ...o }, s) => /* @__PURE__ */ n("button", {
74
+ }, h = t(({ className: t, variant: r = "default", size: i = "default", children: a, ...o }, s) => /* @__PURE__ */ n("button", {
74
75
  ref: s,
75
- className: e("inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors", "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-focus-ring)] focus-visible:ring-offset-2", "disabled:pointer-events-none disabled:opacity-50", f[r], p[i], t),
76
+ className: e("inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors", "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-focus-ring)] focus-visible:ring-offset-2", "disabled:pointer-events-none disabled:opacity-50", p[r], m[i], t),
76
77
  ...o,
77
78
  children: a
78
79
  }));
79
- m.displayName = "Button";
80
- var h = t(({ className: t, type: r, ...i }, a) => /* @__PURE__ */ n("input", {
80
+ h.displayName = "Button";
81
+ var g = t(({ className: t, type: r, ...i }, a) => /* @__PURE__ */ n("input", {
81
82
  type: r,
82
83
  className: e("flex h-10 w-full rounded-md border border-border-default bg-bg-surface px-3 py-2 text-sm ring-offset-background", "file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-text-primary", "placeholder:text-text-secondary", "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-focus-ring)] focus-visible:ring-offset-2", "disabled:cursor-not-allowed disabled:opacity-50", t),
83
84
  ref: a,
84
85
  ...i
85
86
  }));
86
- h.displayName = "Input";
87
- var g = t(({ className: t, ...r }, i) => /* @__PURE__ */ n("div", {
87
+ g.displayName = "Input";
88
+ var _ = t(({ className: t, ...r }, i) => /* @__PURE__ */ n("div", {
88
89
  ref: i,
89
90
  className: e("animate-pulse rounded-md bg-bg-sunken", t),
90
91
  ...r
91
92
  }));
92
- g.displayName = "Skeleton";
93
- var _ = t(({ className: t, orientation: r = "horizontal", ...i }, a) => /* @__PURE__ */ n("div", {
93
+ _.displayName = "Skeleton";
94
+ var v = t(({ className: t, orientation: r = "horizontal", ...i }, a) => /* @__PURE__ */ n("div", {
94
95
  ref: a,
95
96
  className: e("shrink-0 bg-border", r === "horizontal" ? "h-[1px] w-full" : "h-full w-[1px]", t),
96
97
  ...i
97
98
  }));
98
- _.displayName = "Separator";
99
- var v = {
99
+ v.displayName = "Separator";
100
+ var y = {
100
101
  sm: "h-8 w-8 text-xs",
101
102
  default: "h-10 w-10 text-sm",
102
103
  lg: "h-12 w-12 text-base"
103
- }, y = t(({ className: t, src: r, alt: i, fallback: a, size: o = "default", ...s }, c) => /* @__PURE__ */ n("div", {
104
+ }, b = t(({ className: t, src: r, alt: i, fallback: a, size: o = "default", ...s }, c) => /* @__PURE__ */ n("div", {
104
105
  ref: c,
105
- className: e("relative flex shrink-0 overflow-hidden rounded-full bg-bg-sunken", v[o], t),
106
+ className: e("relative flex shrink-0 overflow-hidden rounded-full bg-bg-sunken", y[o], t),
106
107
  ...s,
107
108
  children: r ? /* @__PURE__ */ n("img", {
108
109
  src: r,
@@ -113,9 +114,15 @@ var v = {
113
114
  children: a
114
115
  })
115
116
  }));
116
- y.displayName = "Avatar";
117
- function b({ icon: e, title: t, description: i, action: a }) {
118
- return /* @__PURE__ */ r("div", {
117
+ b.displayName = "Avatar";
118
+ function x({ icon: e, title: t, description: a, action: o, illustration: s }) {
119
+ return s ? /* @__PURE__ */ n(i, {
120
+ illustration: s,
121
+ title: t,
122
+ description: a,
123
+ action: o,
124
+ className: "py-12"
125
+ }) : /* @__PURE__ */ r("div", {
119
126
  className: "flex flex-col items-center justify-center py-12 text-center",
120
127
  children: [
121
128
  e && /* @__PURE__ */ n("div", {
@@ -126,15 +133,15 @@ function b({ icon: e, title: t, description: i, action: a }) {
126
133
  className: "mb-2 text-lg font-semibold",
127
134
  children: t
128
135
  }),
129
- i && /* @__PURE__ */ n("p", {
136
+ a && /* @__PURE__ */ n("p", {
130
137
  className: "mb-4 max-w-sm text-sm text-text-secondary",
131
- children: i
138
+ children: a
132
139
  }),
133
- a
140
+ o
134
141
  ]
135
142
  });
136
143
  }
137
144
  //#endregion
138
- export { y as Avatar, d as Badge, m as Button, i as Card, c as CardContent, s as CardDescription, l as CardFooter, a as CardHeader, o as CardTitle, b as EmptyState, h as Input, _ as Separator, g as Skeleton };
145
+ export { b as Avatar, f as Badge, h as Button, a as Card, l as CardContent, c as CardDescription, u as CardFooter, o as CardHeader, s as CardTitle, x as EmptyState, g as Input, v as Separator, _ as Skeleton };
139
146
 
140
147
  //# sourceMappingURL=ui.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ui.js","names":[],"sources":["../../../src/admin/components/ui.tsx"],"sourcesContent":["/**\n * Shared UI Components for Admin Console\n * Using semantic tokens for consistent theming\n */\n\nimport type { ReactNode, HTMLAttributes, ButtonHTMLAttributes } from 'react';\nimport { forwardRef } from 'react';\nimport { cn } from '../utils/cn';\n\n// ============================================================================\n// Card Components\n// ============================================================================\n\ninterface CardProps extends HTMLAttributes<HTMLDivElement> {\n children: ReactNode;\n}\n\nexport const Card = forwardRef<HTMLDivElement, CardProps>(\n ({ className, children, ...props }, ref) => (\n <div\n ref={ref}\n className={cn(\n 'rounded-lg border border-border-subtle bg-bg-surface text-text-primary shadow-sm',\n className\n )}\n {...props}\n >\n {children}\n </div>\n )\n);\nCard.displayName = 'Card';\n\nexport const CardHeader = forwardRef<HTMLDivElement, CardProps>(\n ({ className, children, ...props }, ref) => (\n <div ref={ref} className={cn('flex flex-col space-y-1.5 p-6', className)} {...props}>\n {children}\n </div>\n )\n);\nCardHeader.displayName = 'CardHeader';\n\nexport const CardTitle = forwardRef<HTMLHeadingElement, HTMLAttributes<HTMLHeadingElement>>(\n ({ className, children, ...props }, ref) => (\n <h3\n ref={ref}\n className={cn('text-2xl font-semibold leading-none tracking-tight', className)}\n {...props}\n >\n {children}\n </h3>\n )\n);\nCardTitle.displayName = 'CardTitle';\n\nexport const CardDescription = forwardRef<\n HTMLParagraphElement,\n HTMLAttributes<HTMLParagraphElement>\n>(({ className, children, ...props }, ref) => (\n <p ref={ref} className={cn('text-sm text-text-secondary', className)} {...props}>\n {children}\n </p>\n));\nCardDescription.displayName = 'CardDescription';\n\nexport const CardContent = forwardRef<HTMLDivElement, CardProps>(\n ({ className, children, ...props }, ref) => (\n <div ref={ref} className={cn('p-6 pt-0', className)} {...props}>\n {children}\n </div>\n )\n);\nCardContent.displayName = 'CardContent';\n\nexport const CardFooter = forwardRef<HTMLDivElement, CardProps>(\n ({ className, children, ...props }, ref) => (\n <div ref={ref} className={cn('flex items-center p-6 pt-0', className)} {...props}>\n {children}\n </div>\n )\n);\nCardFooter.displayName = 'CardFooter';\n\n// ============================================================================\n// Badge Component\n// ============================================================================\n\ninterface BadgeProps extends HTMLAttributes<HTMLSpanElement> {\n variant?: 'default' | 'secondary' | 'success' | 'warning' | 'destructive' | 'outline';\n}\n\nconst badgeVariants = {\n default: 'bg-action-primary-bg text-action-primary-text',\n secondary: 'bg-secondary text-secondary-foreground',\n success: 'bg-success/10 text-success border-success/20',\n warning: 'bg-warning/10 text-warning border-warning/20',\n destructive: 'bg-status-error-bg/10 text-status-error-text border-status-error-border/20',\n outline: 'border-border-subtle bg-transparent text-text-primary',\n};\n\nexport const Badge = forwardRef<HTMLSpanElement, BadgeProps>(\n ({ className, variant = 'default', children, ...props }, ref) => (\n <span\n ref={ref}\n className={cn(\n 'inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors',\n badgeVariants[variant],\n className\n )}\n {...props}\n >\n {children}\n </span>\n )\n);\nBadge.displayName = 'Badge';\n\n// ============================================================================\n// Button Component\n// ============================================================================\n\ninterface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {\n variant?: 'default' | 'secondary' | 'outline' | 'ghost' | 'destructive' | 'link';\n size?: 'default' | 'sm' | 'lg' | 'icon';\n}\n\nconst buttonVariants = {\n default: 'bg-action-primary-bg text-action-primary-text hover:bg-action-primary-bg/90',\n secondary: 'bg-secondary text-secondary-foreground hover:bg-secondary/80',\n outline: 'border border-border-default bg-bg-surface hover:bg-accent hover:text-text-primary',\n ghost: 'hover:bg-accent hover:text-text-primary',\n destructive: 'bg-status-error-bg text-status-error-text hover:bg-status-error-bg/90',\n link: 'text-primary underline-offset-4 hover:underline',\n};\n\nconst buttonSizes = {\n default: 'h-10 px-4 py-2',\n sm: 'h-9 rounded-md px-3',\n lg: 'h-11 rounded-md px-8',\n icon: 'h-10 w-10',\n};\n\nexport const Button = forwardRef<HTMLButtonElement, ButtonProps>(\n ({ className, variant = 'default', size = 'default', children, ...props }, ref) => (\n <button\n ref={ref}\n className={cn(\n 'inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors',\n 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-focus-ring)] focus-visible:ring-offset-2',\n 'disabled:pointer-events-none disabled:opacity-50',\n buttonVariants[variant],\n buttonSizes[size],\n className\n )}\n {...props}\n >\n {children}\n </button>\n )\n);\nButton.displayName = 'Button';\n\n// ============================================================================\n// Input Component\n// ============================================================================\n\ntype InputProps = React.InputHTMLAttributes<HTMLInputElement>;\n\nexport const Input = forwardRef<HTMLInputElement, InputProps>(\n ({ className, type, ...props }, ref) => (\n <input\n type={type}\n className={cn(\n 'flex h-10 w-full rounded-md border border-border-default bg-bg-surface px-3 py-2 text-sm ring-offset-background',\n 'file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-text-primary',\n 'placeholder:text-text-secondary',\n 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-focus-ring)] focus-visible:ring-offset-2',\n 'disabled:cursor-not-allowed disabled:opacity-50',\n className\n )}\n ref={ref}\n {...props}\n />\n )\n);\nInput.displayName = 'Input';\n\n// ============================================================================\n// Skeleton Component\n// ============================================================================\n\ntype SkeletonProps = HTMLAttributes<HTMLDivElement>;\n\nexport const Skeleton = forwardRef<HTMLDivElement, SkeletonProps>(\n ({ className, ...props }, ref) => (\n <div ref={ref} className={cn('animate-pulse rounded-md bg-bg-sunken', className)} {...props} />\n )\n);\nSkeleton.displayName = 'Skeleton';\n\n// ============================================================================\n// Separator Component\n// ============================================================================\n\ninterface SeparatorProps extends HTMLAttributes<HTMLDivElement> {\n orientation?: 'horizontal' | 'vertical';\n}\n\nexport const Separator = forwardRef<HTMLDivElement, SeparatorProps>(\n ({ className, orientation = 'horizontal', ...props }, ref) => (\n <div\n ref={ref}\n className={cn(\n 'shrink-0 bg-border',\n orientation === 'horizontal' ? 'h-[1px] w-full' : 'h-full w-[1px]',\n className\n )}\n {...props}\n />\n )\n);\nSeparator.displayName = 'Separator';\n\n// ============================================================================\n// Avatar Component\n// ============================================================================\n\ninterface AvatarProps extends HTMLAttributes<HTMLDivElement> {\n src?: string;\n alt?: string;\n fallback: string;\n size?: 'sm' | 'default' | 'lg';\n}\n\nconst avatarSizes = {\n sm: 'h-8 w-8 text-xs',\n default: 'h-10 w-10 text-sm',\n lg: 'h-12 w-12 text-base',\n};\n\nexport const Avatar = forwardRef<HTMLDivElement, AvatarProps>(\n ({ className, src, alt, fallback, size = 'default', ...props }, ref) => (\n <div\n ref={ref}\n className={cn(\n 'relative flex shrink-0 overflow-hidden rounded-full bg-bg-sunken',\n avatarSizes[size],\n className\n )}\n {...props}\n >\n {src ? (\n <img src={src} alt={alt} className=\"aspect-square h-full w-full object-cover\" />\n ) : (\n <span className=\"flex h-full w-full items-center justify-center font-medium text-text-secondary\">\n {fallback}\n </span>\n )}\n </div>\n )\n);\nAvatar.displayName = 'Avatar';\n\n// ============================================================================\n// Empty State Component\n// ============================================================================\n\ninterface EmptyStateProps {\n icon?: ReactNode;\n title: string;\n description?: string;\n action?: ReactNode;\n}\n\nexport function EmptyState({ icon, title, description, action }: EmptyStateProps) {\n return (\n <div className=\"flex flex-col items-center justify-center py-12 text-center\">\n {icon && <div className=\"mb-4 rounded-full bg-bg-sunken p-4 text-text-secondary\">{icon}</div>}\n <h3 className=\"mb-2 text-lg font-semibold\">{title}</h3>\n {description && <p className=\"mb-4 max-w-sm text-sm text-text-secondary\">{description}</p>}\n {action}\n </div>\n );\n}\n\n// ============================================================================\n// Loading Spinner Component\n// ============================================================================\n\ninterface SpinnerProps extends HTMLAttributes<HTMLDivElement> {\n size?: 'sm' | 'default' | 'lg';\n}\n\nconst spinnerSizes = {\n sm: 'h-4 w-4',\n default: 'h-6 w-6',\n lg: 'h-8 w-8',\n};\n\nexport function Spinner({ className, size = 'default', ...props }: SpinnerProps) {\n return (\n <div\n className={cn(\n 'animate-spin rounded-full border-2 border-current border-t-transparent text-primary',\n spinnerSizes[size],\n className\n )}\n {...props}\n />\n );\n}\n\n// ============================================================================\n// Page Loading Fallback\n// ============================================================================\n\ninterface PageLoadingFallbackProps {\n message?: string;\n}\n\nexport function PageLoadingFallback({ message = 'Loading...' }: PageLoadingFallbackProps) {\n return (\n <div className=\"flex h-full min-h-[400px] flex-col items-center justify-center gap-4\">\n <Spinner size=\"lg\" />\n <p className=\"text-sm text-text-secondary\">{message}</p>\n </div>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"ui.js","names":[],"sources":["../../../src/admin/components/ui.tsx"],"sourcesContent":["/**\n * Shared UI Components for Admin Console\n * Using semantic tokens for consistent theming\n */\n\nimport type { ReactNode, HTMLAttributes, ButtonHTMLAttributes } from 'react';\nimport { forwardRef } from 'react';\nimport { IllustratedEmptyState } from '@burdenoff/fe-libs/ui';\nimport { cn } from '../utils/cn';\n\n// ============================================================================\n// Card Components\n// ============================================================================\n\ninterface CardProps extends HTMLAttributes<HTMLDivElement> {\n children: ReactNode;\n}\n\nexport const Card = forwardRef<HTMLDivElement, CardProps>(\n ({ className, children, ...props }, ref) => (\n <div\n ref={ref}\n className={cn(\n 'rounded-card border border-border-seam bg-bg-surface text-text-primary shadow-elevation-1 transition-[box-shadow,border-color] duration-200 hover:border-border-strong',\n className\n )}\n {...props}\n >\n {children}\n </div>\n )\n);\nCard.displayName = 'Card';\n\nexport const CardHeader = forwardRef<HTMLDivElement, CardProps>(\n ({ className, children, ...props }, ref) => (\n <div ref={ref} className={cn('flex flex-col space-y-1.5 p-6', className)} {...props}>\n {children}\n </div>\n )\n);\nCardHeader.displayName = 'CardHeader';\n\nexport const CardTitle = forwardRef<HTMLHeadingElement, HTMLAttributes<HTMLHeadingElement>>(\n ({ className, children, ...props }, ref) => (\n <h3\n ref={ref}\n className={cn('text-2xl font-semibold leading-none tracking-tight', className)}\n {...props}\n >\n {children}\n </h3>\n )\n);\nCardTitle.displayName = 'CardTitle';\n\nexport const CardDescription = forwardRef<\n HTMLParagraphElement,\n HTMLAttributes<HTMLParagraphElement>\n>(({ className, children, ...props }, ref) => (\n <p ref={ref} className={cn('text-sm text-text-secondary', className)} {...props}>\n {children}\n </p>\n));\nCardDescription.displayName = 'CardDescription';\n\nexport const CardContent = forwardRef<HTMLDivElement, CardProps>(\n ({ className, children, ...props }, ref) => (\n <div ref={ref} className={cn('p-6 pt-0', className)} {...props}>\n {children}\n </div>\n )\n);\nCardContent.displayName = 'CardContent';\n\nexport const CardFooter = forwardRef<HTMLDivElement, CardProps>(\n ({ className, children, ...props }, ref) => (\n <div ref={ref} className={cn('flex items-center p-6 pt-0', className)} {...props}>\n {children}\n </div>\n )\n);\nCardFooter.displayName = 'CardFooter';\n\n// ============================================================================\n// Badge Component\n// ============================================================================\n\ninterface BadgeProps extends HTMLAttributes<HTMLSpanElement> {\n variant?: 'default' | 'secondary' | 'success' | 'warning' | 'destructive' | 'outline';\n}\n\nconst badgeVariants = {\n default: 'bg-action-primary-bg text-action-primary-text',\n secondary: 'bg-secondary text-secondary-foreground',\n success: 'bg-success/10 text-success border-success/20',\n warning: 'bg-warning/10 text-warning border-warning/20',\n destructive: 'bg-status-error-bg/10 text-status-error-text border-status-error-border/20',\n outline: 'border-border-subtle bg-transparent text-text-primary',\n};\n\nexport const Badge = forwardRef<HTMLSpanElement, BadgeProps>(\n ({ className, variant = 'default', children, ...props }, ref) => (\n <span\n ref={ref}\n className={cn(\n 'inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors',\n badgeVariants[variant],\n className\n )}\n {...props}\n >\n {children}\n </span>\n )\n);\nBadge.displayName = 'Badge';\n\n// ============================================================================\n// Button Component\n// ============================================================================\n\ninterface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {\n variant?: 'default' | 'secondary' | 'outline' | 'ghost' | 'destructive' | 'link';\n size?: 'default' | 'sm' | 'lg' | 'icon';\n}\n\nconst buttonVariants = {\n default: 'bg-action-primary-bg text-action-primary-text hover:bg-action-primary-bg/90',\n secondary: 'bg-secondary text-secondary-foreground hover:bg-secondary/80',\n outline: 'border border-border-default bg-bg-surface hover:bg-accent hover:text-text-primary',\n ghost: 'hover:bg-accent hover:text-text-primary',\n destructive: 'bg-status-error-bg text-status-error-text hover:bg-status-error-bg/90',\n link: 'text-primary underline-offset-4 hover:underline',\n};\n\nconst buttonSizes = {\n default: 'h-10 px-4 py-2',\n sm: 'h-9 rounded-md px-3',\n lg: 'h-11 rounded-md px-8',\n icon: 'h-10 w-10',\n};\n\nexport const Button = forwardRef<HTMLButtonElement, ButtonProps>(\n ({ className, variant = 'default', size = 'default', children, ...props }, ref) => (\n <button\n ref={ref}\n className={cn(\n 'inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors',\n 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-focus-ring)] focus-visible:ring-offset-2',\n 'disabled:pointer-events-none disabled:opacity-50',\n buttonVariants[variant],\n buttonSizes[size],\n className\n )}\n {...props}\n >\n {children}\n </button>\n )\n);\nButton.displayName = 'Button';\n\n// ============================================================================\n// Input Component\n// ============================================================================\n\ntype InputProps = React.InputHTMLAttributes<HTMLInputElement>;\n\nexport const Input = forwardRef<HTMLInputElement, InputProps>(\n ({ className, type, ...props }, ref) => (\n <input\n type={type}\n className={cn(\n 'flex h-10 w-full rounded-md border border-border-default bg-bg-surface px-3 py-2 text-sm ring-offset-background',\n 'file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-text-primary',\n 'placeholder:text-text-secondary',\n 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-focus-ring)] focus-visible:ring-offset-2',\n 'disabled:cursor-not-allowed disabled:opacity-50',\n className\n )}\n ref={ref}\n {...props}\n />\n )\n);\nInput.displayName = 'Input';\n\n// ============================================================================\n// Skeleton Component\n// ============================================================================\n\ntype SkeletonProps = HTMLAttributes<HTMLDivElement>;\n\nexport const Skeleton = forwardRef<HTMLDivElement, SkeletonProps>(\n ({ className, ...props }, ref) => (\n <div ref={ref} className={cn('animate-pulse rounded-md bg-bg-sunken', className)} {...props} />\n )\n);\nSkeleton.displayName = 'Skeleton';\n\n// ============================================================================\n// Separator Component\n// ============================================================================\n\ninterface SeparatorProps extends HTMLAttributes<HTMLDivElement> {\n orientation?: 'horizontal' | 'vertical';\n}\n\nexport const Separator = forwardRef<HTMLDivElement, SeparatorProps>(\n ({ className, orientation = 'horizontal', ...props }, ref) => (\n <div\n ref={ref}\n className={cn(\n 'shrink-0 bg-border',\n orientation === 'horizontal' ? 'h-[1px] w-full' : 'h-full w-[1px]',\n className\n )}\n {...props}\n />\n )\n);\nSeparator.displayName = 'Separator';\n\n// ============================================================================\n// Avatar Component\n// ============================================================================\n\ninterface AvatarProps extends HTMLAttributes<HTMLDivElement> {\n src?: string;\n alt?: string;\n fallback: string;\n size?: 'sm' | 'default' | 'lg';\n}\n\nconst avatarSizes = {\n sm: 'h-8 w-8 text-xs',\n default: 'h-10 w-10 text-sm',\n lg: 'h-12 w-12 text-base',\n};\n\nexport const Avatar = forwardRef<HTMLDivElement, AvatarProps>(\n ({ className, src, alt, fallback, size = 'default', ...props }, ref) => (\n <div\n ref={ref}\n className={cn(\n 'relative flex shrink-0 overflow-hidden rounded-full bg-bg-sunken',\n avatarSizes[size],\n className\n )}\n {...props}\n >\n {src ? (\n <img src={src} alt={alt} className=\"aspect-square h-full w-full object-cover\" />\n ) : (\n <span className=\"flex h-full w-full items-center justify-center font-medium text-text-secondary\">\n {fallback}\n </span>\n )}\n </div>\n )\n);\nAvatar.displayName = 'Avatar';\n\n// ============================================================================\n// Empty State Component\n// ============================================================================\n\ninterface EmptyStateProps {\n icon?: ReactNode;\n title: string;\n description?: string;\n action?: ReactNode;\n /**\n * On-brand illustration name (Boff UI 2.0). When provided, renders the\n * IllustratedEmptyState (host serves /illustrations/<name>.webp). Standard\n * names: empty-data, empty-search, empty-files, empty-people,\n * empty-notifications, onboarding, empty-generic. Falls back to the icon\n * variant when omitted.\n */\n illustration?: string;\n}\n\nexport function EmptyState({ icon, title, description, action, illustration }: EmptyStateProps) {\n if (illustration) {\n return (\n <IllustratedEmptyState\n illustration={illustration}\n title={title}\n description={description}\n action={action}\n className=\"py-12\"\n />\n );\n }\n return (\n <div className=\"flex flex-col items-center justify-center py-12 text-center\">\n {icon && <div className=\"mb-4 rounded-full bg-bg-sunken p-4 text-text-secondary\">{icon}</div>}\n <h3 className=\"mb-2 text-lg font-semibold\">{title}</h3>\n {description && <p className=\"mb-4 max-w-sm text-sm text-text-secondary\">{description}</p>}\n {action}\n </div>\n );\n}\n\n// ============================================================================\n// Loading Spinner Component\n// ============================================================================\n\ninterface SpinnerProps extends HTMLAttributes<HTMLDivElement> {\n size?: 'sm' | 'default' | 'lg';\n}\n\nconst spinnerSizes = {\n sm: 'h-4 w-4',\n default: 'h-6 w-6',\n lg: 'h-8 w-8',\n};\n\nexport function Spinner({ className, size = 'default', ...props }: SpinnerProps) {\n return (\n <div\n className={cn(\n 'animate-spin rounded-full border-2 border-current border-t-transparent text-primary',\n spinnerSizes[size],\n className\n )}\n {...props}\n />\n );\n}\n\n// ============================================================================\n// Page Loading Fallback\n// ============================================================================\n\ninterface PageLoadingFallbackProps {\n message?: string;\n}\n\nexport function PageLoadingFallback({ message = 'Loading...' }: PageLoadingFallbackProps) {\n return (\n <div className=\"flex h-full min-h-[400px] flex-col items-center justify-center gap-4\">\n <Spinner size=\"lg\" />\n <p className=\"text-sm text-text-secondary\">{message}</p>\n </div>\n );\n}\n"],"mappings":"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"}
@@ -83,6 +83,7 @@ function T() {
83
83
  denyMessage: "You don't have permission to view audit logs.",
84
84
  children: /* @__PURE__ */ y(r, {
85
85
  title: "Audit Logs",
86
+ gradientWord: "Logs",
86
87
  description: `Security and compliance audit trail${N ? ` · ${N} total` : ""}`,
87
88
  actions: /* @__PURE__ */ y(x, {
88
89
  label: "Export CSV",
@@ -201,6 +202,7 @@ function T() {
201
202
  keyExtractor: (e) => e.id,
202
203
  loading: k,
203
204
  emptyState: /* @__PURE__ */ y(t, {
205
+ illustration: "empty-files",
204
206
  icon: /* @__PURE__ */ y(p, { className: "h-8 w-8" }),
205
207
  title: "No audit logs found",
206
208
  description: "Audit events will appear here when actions are performed"