From 4219daba25026834c2a31095c7e328011e3857a1 Mon Sep 17 00:00:00 2001 From: Codex Agent Date: Sun, 18 Jan 2026 11:02:04 +0100 Subject: [PATCH] feat(admin-pwa): modernize dashboard KPI section with unified glass strip --- .../js/admin/i18n/locales/de/management.json | 3 +- .../js/admin/i18n/locales/en/management.json | 3 +- resources/js/admin/mobile/DashboardPage.tsx | 45 +++---- .../js/admin/mobile/components/Primitives.tsx | 115 +++++++++++++++--- 4 files changed, 124 insertions(+), 42 deletions(-) diff --git a/resources/js/admin/i18n/locales/de/management.json b/resources/js/admin/i18n/locales/de/management.json index f3f5ee7..9c99d49 100644 --- a/resources/js/admin/i18n/locales/de/management.json +++ b/resources/js/admin/i18n/locales/de/management.json @@ -203,7 +203,8 @@ "processing": "Verarbeite …", "select": "Auswählen", "close": "Schließen", - "reset": "Zurücksetzen" + "reset": "Zurücksetzen", + "actionNeeded": "Prüfen" }, "photos": { "moderation": { diff --git a/resources/js/admin/i18n/locales/en/management.json b/resources/js/admin/i18n/locales/en/management.json index 33c0f5f..b70f2b9 100644 --- a/resources/js/admin/i18n/locales/en/management.json +++ b/resources/js/admin/i18n/locales/en/management.json @@ -199,7 +199,8 @@ "processing": "Processing…", "select": "Select", "close": "Close", - "reset": "Reset" + "reset": "Reset", + "actionNeeded": "Review" }, "photos": { "moderation": { diff --git a/resources/js/admin/mobile/DashboardPage.tsx b/resources/js/admin/mobile/DashboardPage.tsx index 738b0d4..6f3ab95 100644 --- a/resources/js/admin/mobile/DashboardPage.tsx +++ b/resources/js/admin/mobile/DashboardPage.tsx @@ -20,6 +20,7 @@ import { buildLimitWarnings } from '../lib/limitWarnings'; import { withAlpha } from './components/colors'; import { useEventReadiness } from './hooks/useEventReadiness'; import { SetupChecklist } from './components/SetupChecklist'; +import { KpiStrip } from './components/Primitives'; // --- HELPERS --- @@ -386,27 +387,29 @@ function PulseStrip({ event, stats }: any) { const pendingCount = stats?.pending_photos ?? event?.pending_photo_count ?? 0; return ( - - - - - - 0 ? 'warning' : 'neutral'} /> - - ); -} - -function PulseItem({ icon: Icon, value, label, tone = 'neutral' }: any) { - const theme = useAdminTheme(); - const color = tone === 'warning' ? theme.warningText : theme.textStrong; - return ( - - - - {value} - {label} - - + + 0 ? t('management:common.actionNeeded', 'Review') : undefined, + color: pendingCount > 0 ? '#8B5CF6' : theme.textMuted + } + ]} /> + ); } diff --git a/resources/js/admin/mobile/components/Primitives.tsx b/resources/js/admin/mobile/components/Primitives.tsx index bb612dc..07f45a7 100644 --- a/resources/js/admin/mobile/components/Primitives.tsx +++ b/resources/js/admin/mobile/components/Primitives.tsx @@ -153,35 +153,42 @@ export function KpiTile({ label, value, note, + color, }: { icon: React.ComponentType<{ size?: number; color?: string }>; label: string; value: string | number; note?: string; + color?: string; }) { - const { accentSoft, primary, text } = useAdminTheme(); + const { surfaceMuted, textStrong, textMuted, primary, accentSoft } = useAdminTheme(); + const iconBg = color ? withAlpha(color, 0.12) : accentSoft; + const iconColor = color || primary; + return ( - - - - - - + + + + + + + + {value} + + {label} - - - {value} - + + {note ? ( - + {note} ) : null} @@ -189,6 +196,76 @@ export function KpiTile({ ); } +export function KpiStrip({ + items +}: { + items: Array<{ + icon: React.ComponentType<{ size?: number; color?: string }>; + label: string; + value: string | number; + color?: string; + note?: string; + }> +}) { + const { glassSurface, border, textStrong, textMuted, primary, accentSoft } = useAdminTheme(); + + return ( + + + {items.map((item, index) => { + const isLast = index === items.length - 1; + const iconColor = item.color || primary; + const iconBg = withAlpha(iconColor, 0.12); + + return ( + + + + + + + + + {item.value} + + + {item.label} + + + + {item.note && ( + + {item.note} + + )} + + + {!isLast && ( + + )} + + ); + })} + + + ); +} + export function SkeletonCard({ height = 80 }: { height?: number }) { return (