@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.
- package/dist/admin/components/DataTable.js +5 -5
- package/dist/admin/components/DataTable.js.map +1 -1
- package/dist/admin/components/MetricCard.js +40 -37
- package/dist/admin/components/MetricCard.js.map +1 -1
- package/dist/admin/components/PageLayout.js +28 -22
- package/dist/admin/components/PageLayout.js.map +1 -1
- package/dist/admin/components/ui.js +45 -38
- package/dist/admin/components/ui.js.map +1 -1
- package/dist/admin/pages/AuditLogsPage.js +2 -0
- package/dist/admin/pages/AuditLogsPage.js.map +1 -1
- package/dist/admin/pages/BillingPage.js +51 -43
- package/dist/admin/pages/BillingPage.js.map +1 -1
- package/dist/admin/pages/CommunicationsPage.js +3 -0
- package/dist/admin/pages/CommunicationsPage.js.map +1 -1
- package/dist/admin/pages/ContentPagesPage.js +2 -0
- package/dist/admin/pages/ContentPagesPage.js.map +1 -1
- package/dist/admin/pages/DashboardPage.js +7 -4
- package/dist/admin/pages/DashboardPage.js.map +1 -1
- package/dist/admin/pages/FeatureFlagsPage.js +2 -0
- package/dist/admin/pages/FeatureFlagsPage.js.map +1 -1
- package/dist/admin/pages/OrganizationsListPage.js +2 -0
- package/dist/admin/pages/OrganizationsListPage.js.map +1 -1
- package/dist/admin/pages/ProductsPage.js +3 -0
- package/dist/admin/pages/ProductsPage.js.map +1 -1
- package/dist/admin/pages/ReferralsPage.js +4 -0
- package/dist/admin/pages/ReferralsPage.js.map +1 -1
- package/dist/admin/pages/RolesPermissionsPage.js +3 -0
- package/dist/admin/pages/RolesPermissionsPage.js.map +1 -1
- package/dist/admin/pages/SREPage.js +4 -0
- package/dist/admin/pages/SREPage.js.map +1 -1
- package/dist/admin/pages/SandboxSettingsPage.js +1 -0
- package/dist/admin/pages/SandboxSettingsPage.js.map +1 -1
- package/dist/admin/pages/SettingsPage.js +139 -127
- package/dist/admin/pages/SettingsPage.js.map +1 -1
- package/dist/admin/pages/SyncFailuresPage.js +3 -0
- package/dist/admin/pages/SyncFailuresPage.js.map +1 -1
- package/dist/admin/pages/TenantsListPage.js +2 -0
- package/dist/admin/pages/TenantsListPage.js.map +1 -1
- package/dist/admin/pages/UsersListPage.js +2 -0
- package/dist/admin/pages/UsersListPage.js.map +1 -1
- package/dist/admin/pages/WaitlistPage.js +2 -0
- package/dist/admin/pages/WaitlistPage.js.map +1 -1
- package/dist/admin/pages/WorkflowsPage.js +3 -0
- package/dist/admin/pages/WorkflowsPage.js.map +1 -1
- package/dist/admin/pages/WorkspacesListPage.js +1 -0
- package/dist/admin/pages/WorkspacesListPage.js.map +1 -1
- 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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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,
|
|
3
|
-
import { formatChange as
|
|
4
|
-
import { Minus as
|
|
5
|
-
import { Link as
|
|
6
|
-
import { jsx as
|
|
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
|
|
9
|
-
let
|
|
10
|
-
|
|
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-
|
|
14
|
-
}[
|
|
15
|
-
children: [/* @__PURE__ */
|
|
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__ */
|
|
20
|
+
children: [/* @__PURE__ */ u("span", {
|
|
18
21
|
className: "text-sm font-medium text-text-secondary",
|
|
19
|
-
children:
|
|
20
|
-
}),
|
|
22
|
+
children: p
|
|
23
|
+
}), y && /* @__PURE__ */ u("div", {
|
|
21
24
|
className: "text-text-secondary",
|
|
22
|
-
children:
|
|
25
|
+
children: y
|
|
23
26
|
})]
|
|
24
|
-
}),
|
|
27
|
+
}), C ? /* @__PURE__ */ d("div", {
|
|
25
28
|
className: "space-y-2",
|
|
26
|
-
children: [/* @__PURE__ */
|
|
27
|
-
}) : /* @__PURE__ */
|
|
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__ */
|
|
30
|
-
className: "text-3xl font-bold text-text-primary",
|
|
31
|
-
children:
|
|
32
|
-
}),
|
|
33
|
-
variant:
|
|
34
|
-
className: "flex items-center gap-1",
|
|
35
|
-
children: [/* @__PURE__ */
|
|
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
|
-
}),
|
|
40
|
+
}), b && /* @__PURE__ */ u("p", {
|
|
38
41
|
className: "mt-1 text-xs text-text-secondary",
|
|
39
|
-
children:
|
|
40
|
-
})] })
|
|
42
|
+
children: b
|
|
43
|
+
})] })]
|
|
41
44
|
});
|
|
42
|
-
return
|
|
43
|
-
to:
|
|
44
|
-
className: "block",
|
|
45
|
-
children:
|
|
46
|
-
}) :
|
|
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
|
|
49
|
-
return /* @__PURE__ */
|
|
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 {
|
|
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 {
|
|
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 {
|
|
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
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
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:
|
|
30
|
+
children: l
|
|
25
31
|
})]
|
|
26
32
|
});
|
|
27
33
|
}
|
|
28
34
|
//#endregion
|
|
29
|
-
export {
|
|
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({
|
|
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
|
|
6
|
+
var a = t(({ className: t, children: r, ...i }, a) => /* @__PURE__ */ n("div", {
|
|
6
7
|
ref: a,
|
|
7
|
-
className: e("rounded-
|
|
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
|
-
|
|
12
|
-
var
|
|
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
|
-
|
|
19
|
-
var
|
|
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
|
-
|
|
26
|
-
var
|
|
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
|
-
|
|
33
|
-
var
|
|
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
|
-
|
|
40
|
-
var
|
|
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
|
-
|
|
47
|
-
var
|
|
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
|
-
},
|
|
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",
|
|
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
|
-
|
|
61
|
-
var
|
|
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
|
-
},
|
|
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
|
-
},
|
|
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",
|
|
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
|
-
|
|
80
|
-
var
|
|
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
|
-
|
|
87
|
-
var
|
|
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
|
-
|
|
93
|
-
var
|
|
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
|
-
|
|
99
|
-
var
|
|
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
|
-
},
|
|
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",
|
|
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
|
-
|
|
117
|
-
function
|
|
118
|
-
return /* @__PURE__ */
|
|
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
|
-
|
|
136
|
+
a && /* @__PURE__ */ n("p", {
|
|
130
137
|
className: "mb-4 max-w-sm text-sm text-text-secondary",
|
|
131
|
-
children:
|
|
138
|
+
children: a
|
|
132
139
|
}),
|
|
133
|
-
|
|
140
|
+
o
|
|
134
141
|
]
|
|
135
142
|
});
|
|
136
143
|
}
|
|
137
144
|
//#endregion
|
|
138
|
-
export {
|
|
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"
|