From ab80d659581b097df18056cfdaf9c87ddae730bf Mon Sep 17 00:00:00 2001 From: Andy Charlwood Date: Mon, 16 Feb 2026 10:36:30 +0000 Subject: [PATCH] feat: compact latest results kpi section --- src/components/tiles/PatientSummaryTile.tsx | 150 ++++++++------------ src/index.css | 61 +++----- 2 files changed, 84 insertions(+), 127 deletions(-) diff --git a/src/components/tiles/PatientSummaryTile.tsx b/src/components/tiles/PatientSummaryTile.tsx index b26deb5..33b0526 100644 --- a/src/components/tiles/PatientSummaryTile.tsx +++ b/src/components/tiles/PatientSummaryTile.tsx @@ -1,4 +1,4 @@ -import React, { useEffect, useState } from 'react' +import React from 'react' import { FileText, ChevronRight } from 'lucide-react' import { CardHeader } from '../Card' import { ParentSection } from '../ParentSection' @@ -12,26 +12,20 @@ const colorMap: Record = { teal: '#0D6E6E', } -const KPI_COACHMARK_KEY = 'kpi-evidence-coachmark-dismissed-v1' - interface MetricCardProps { kpi: KPI - showCoachmark?: boolean - onOpen: () => void } -function MetricCard({ kpi, showCoachmark = false, onOpen }: MetricCardProps) { +function MetricCard({ kpi }: MetricCardProps) { const { openPanel } = useDetailPanel() const handleClick = () => { - onOpen() openPanel({ type: 'kpi', kpi }) } const handleKeyDown = (e: React.KeyboardEvent) => { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault() - onOpen() openPanel({ type: 'kpi', kpi }) } } @@ -39,7 +33,7 @@ function MetricCard({ kpi, showCoachmark = false, onOpen }: MetricCardProps) { const buttonStyles: React.CSSProperties = { width: '100%', textAlign: 'left', - padding: '20px', + padding: '16px 16px 14px', background: 'var(--surface)', border: '1px solid var(--border-light)', borderRadius: 'var(--radius-sm)', @@ -48,11 +42,11 @@ function MetricCard({ kpi, showCoachmark = false, onOpen }: MetricCardProps) { position: 'relative', display: 'flex', flexDirection: 'column', - gap: '2px', + gap: 0, } const valueStyles: React.CSSProperties = { - fontSize: '34px', + fontSize: '30px', fontWeight: 700, letterSpacing: '-0.02em', lineHeight: 1.2, @@ -60,85 +54,62 @@ function MetricCard({ kpi, showCoachmark = false, onOpen }: MetricCardProps) { } const labelStyles: React.CSSProperties = { - fontSize: '14px', + fontSize: '13px', fontWeight: 500, color: 'var(--text-primary)', marginTop: '4px', } const subStyles: React.CSSProperties = { - fontSize: '12px', + fontSize: '11px', color: 'var(--text-tertiary)', fontFamily: 'var(--font-geist-mono)', marginTop: '2px', } return ( -
- {showCoachmark && ( -
- Open any metric to see evidence -
- )} - -
+ + +
{kpi.value}
+
{kpi.label}
+
{kpi.sub}
+
+ Click to view evidence + +
+ ) } export function PatientSummaryTile() { - const [showCoachmark, setShowCoachmark] = useState(false) - - useEffect(() => { - if (typeof window === 'undefined') return - const hasDismissed = window.localStorage.getItem(KPI_COACHMARK_KEY) === '1' - if (!hasDismissed) { - setShowCoachmark(true) - } - }, []) - - const handleMetricOpen = () => { - if (!showCoachmark) return - setShowCoachmark(false) - window.localStorage.setItem(KPI_COACHMARK_KEY, '1') - } - const profileTextStyles: React.CSSProperties = { fontSize: '15px', lineHeight: '1.65', @@ -147,7 +118,8 @@ export function PatientSummaryTile() { const kpiGridStyles: React.CSSProperties = { display: 'grid', - gap: '16px', + gap: '10px', + gridTemplateColumns: '1fr', } return ( @@ -165,20 +137,22 @@ export function PatientSummaryTile() { {/* Latest Results subsection */}
- -

- Select a metric to inspect methodology, impact, and outcomes. -

-
- {kpis.map((kpi, index) => ( - +
+ +

+ Select a metric to inspect methodology, impact, and outcomes. +

+
+
+ {kpis.map((kpi) => ( + ))}
diff --git a/src/index.css b/src/index.css index 5218cf7..0a1a9ae 100644 --- a/src/index.css +++ b/src/index.css @@ -204,26 +204,6 @@ body { animation: fadeIn 200ms ease-out forwards; } -@keyframes kpiPulse { - 0%, 100% { - box-shadow: 0 0 0 0 rgba(10, 128, 128, 0.12); - } - 50% { - box-shadow: 0 0 0 8px rgba(10, 128, 128, 0); - } -} - -@keyframes coachmarkIn { - from { - opacity: 0; - transform: translateY(-4px); - } - to { - opacity: 1; - transform: translateY(0); - } -} - .scrollbar-hide { -ms-overflow-style: none; scrollbar-width: none; @@ -314,29 +294,32 @@ html { transform: translateY(0) scale(0.992); } -.metric-card-pulse { - animation: kpiPulse 1.8s ease-out infinite; +.latest-results-header { + display: flex; + flex-direction: column; + align-items: flex-start; + gap: 8px; } -.kpi-card-coachmark-target { - margin-top: 24px; +.latest-results-header > div { + margin-bottom: 0 !important; } -.kpi-coachmark { - position: absolute; - top: -28px; - left: 0; - z-index: 2; - padding: 4px 8px; - border-radius: 999px; - font-size: 11px; - font-weight: 600; - letter-spacing: 0.02em; - font-family: var(--font-geist-mono); - color: var(--accent); - background: rgba(10, 128, 128, 0.1); - border: 1px solid var(--accent-border); - animation: coachmarkIn 180ms ease-out; +.latest-results-grid { + margin-top: 12px; +} + +@media (min-width: 768px) { + .latest-results-header { + flex-direction: row; + align-items: center; + justify-content: space-between; + gap: 12px; + } + + .latest-results-grid { + grid-template-columns: repeat(4, minmax(0, 1fr)) !important; + } } /* Dashboard card grid responsive — mobile-first */