From 670c9cc74c2db19f2274397e0afd2a034ed7983c Mon Sep 17 00:00:00 2001 From: A Charlwood Date: Fri, 13 Feb 2026 17:09:56 +0000 Subject: [PATCH] Tasks 5-6: Build Sidebar with PersonHeader, Tags, and Alerts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Created src/components/Sidebar.tsx: - PersonHeader section with 52px avatar, name, title, status badge with pulse animation - Details grid: GPhC No. (monospace), Education, Location, Phone (link), Email (link), Registered - Tags section with colored pill badges (teal/amber/green variants) - Alerts/Highlights section with severity-based styling (alert/amber) - Section title component with divider line - Custom scrollbar styling (4px, transparent track, border-colored thumb) - Added animations to src/index.css: - @keyframes pulse for status badge dot (opacity 1→0.4→1, 2s infinite) - .pmr-scrollbar custom scrollbar styles Data sources: patient.ts, tags.ts, alerts.ts Co-Authored-By: Claude Sonnet 4.5 --- src/components/Sidebar.tsx | 432 +++++++++++++++++++++++++++++++++++++ src/index.css | 33 +++ 2 files changed, 465 insertions(+) create mode 100644 src/components/Sidebar.tsx diff --git a/src/components/Sidebar.tsx b/src/components/Sidebar.tsx new file mode 100644 index 0000000..eb201cb --- /dev/null +++ b/src/components/Sidebar.tsx @@ -0,0 +1,432 @@ +import { AlertTriangle, AlertCircle } from 'lucide-react' +import { patient } from '@/data/patient' +import { tags } from '@/data/tags' +import { alerts } from '@/data/alerts' +import type { Tag, Alert } from '@/types/pmr' + +interface SectionTitleProps { + children: React.ReactNode +} + +function SectionTitle({ children }: SectionTitleProps) { + return ( +
+ {children} +
+
+ ) +} + +interface TagPillProps { + tag: Tag +} + +function TagPill({ tag }: TagPillProps) { + const styles: Record = { + teal: { + background: 'var(--accent-light)', + color: 'var(--accent)', + border: '1px solid var(--accent-border)', + }, + amber: { + background: 'var(--amber-light)', + color: 'var(--amber)', + border: '1px solid var(--amber-border)', + }, + green: { + background: 'var(--success-light)', + color: 'var(--success)', + border: '1px solid var(--success-border)', + }, + } + + return ( + + {tag.label} + + ) +} + +interface AlertFlagProps { + alert: Alert +} + +function AlertFlag({ alert }: AlertFlagProps) { + const Icon = alert.icon === 'AlertTriangle' ? AlertTriangle : AlertCircle + + const styles: Record = { + alert: { + background: 'var(--alert-light)', + color: 'var(--alert)', + border: '1px solid var(--alert-border)', + }, + amber: { + background: 'var(--amber-light)', + color: 'var(--amber)', + border: '1px solid var(--amber-border)', + }, + } + + return ( +
+
+ +
+ {alert.message} +
+ ) +} + +export default function Sidebar() { + return ( + + ) +} diff --git a/src/index.css b/src/index.css index 2c89741..f1f8b24 100644 --- a/src/index.css +++ b/src/index.css @@ -232,3 +232,36 @@ body { html { scroll-behavior: smooth; } + +/* Pulse animation for status badge dot */ +@keyframes pulse { + 0%, 100% { + opacity: 1; + } + 50% { + opacity: 0.4; + } +} + +/* Custom scrollbar for sidebar */ +.pmr-scrollbar { + scrollbar-width: thin; + scrollbar-color: var(--border) transparent; +} + +.pmr-scrollbar::-webkit-scrollbar { + width: 4px; +} + +.pmr-scrollbar::-webkit-scrollbar-track { + background: transparent; +} + +.pmr-scrollbar::-webkit-scrollbar-thumb { + background: var(--border); + border-radius: 2px; +} + +.pmr-scrollbar::-webkit-scrollbar-thumb:hover { + background: var(--text-tertiary); +}