Files
portfolio/CLAUDE.md
T
2026-02-13 16:42:23 +00:00

15 KiB

CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

Project Overview

Interactive CV/portfolio for Andy Charlwood, presented as a GP clinical record system. The concept: what if a GP surgery's patient record system were redesigned by a luxury product studio? The structure and metaphor of a real clinical system (tiles as record sections, status indicators, medication-style skill entries, alerts) — but elevated with refined typography, considered motion, and a modern light aesthetic.

This is NOT a faithful NHS system clone. It's a showcase portfolio that evokes the feel of clinical software while being distinctly beautiful. The clinical metaphor is the creative conceit; the execution should feel premium and contemporary.

Built as a React SPA with TypeScript and Vite.

Reference design: References/GPSystemconcept.html — the visual and structural target for the dashboard.

Commands

  • npm run dev — Start dev server (localhost:5173)
  • npm run build — TypeScript compile + Vite production build
  • npm run typecheck — TypeScript type checking only (tsc --noEmit)
  • npm run lint — ESLint
  • npm run preview — Preview production build

No test framework is configured.

Architecture

Four-Phase UI Flow

App.tsx manages a Phase state ('boot''ecg''login''dashboard'). Each phase renders exclusively:

  1. BootSequence — Terminal typing animation (~4s), green-on-black aesthetic. Fira Code font, matrix-green palette. Locked — do not change.
  2. ECGAnimation — Canvas-based heartbeat animation with mask-based letter tracing. Background transitions from black to #1E293B. Locked — do not change.
  3. LoginScreen — Animated login card on dark background. Types credentials at a natural pace, then presents an interactive "Log In" button for the user to click. Login transitions to the dashboard.
  4. DashboardLayout — The main portfolio experience: TopBar + Sidebar + scrollable tile-based dashboard.

Dashboard Layout (Post-Login)

The dashboard uses a three-zone layout:

┌─────────────────────────────────────────────────────┐
│  TopBar (fixed, 48px) — brand, search, session      │
├──────────┬──────────────────────────────────────────┤
│          │                                          │
│ Sidebar  │  Card Grid (scrollable)                  │
│ (272px)  │  ┌─────────────────────────────────┐     │
│          │  │ Patient Summary (full width)     │     │
│ Person   │  ├────────────────┬────────────────┤     │
│ Header   │  │ Latest Results │ Repeat Meds    │     │
│          │  │ (KPIs)         │ (Core Skills)  │     │
│ Tags     │  ├────────────────┴────────────────┤     │
│          │  │ Last Consultation (full width)   │     │
│ Alerts   │  ├─────────────────────────────────┤     │
│          │  │ Career Activity (full width)     │     │
│          │  ├─────────────────────────────────┤     │
│          │  │ Education (full width)           │     │
│          │  ├─────────────────────────────────┤     │
│          │  │ Projects (full width)            │     │
│          │  └─────────────────────────────────┘     │
└──────────┴──────────────────────────────────────────┘

No view switching. The dashboard is a single scrollable page of tiles. Users scroll to see all sections. Detail drill-down happens by expanding tiles in-place (accordion pattern).

Key Patterns

  • Canvas ECG: ECGAnimation.tsx does imperative canvas drawing with requestAnimationFrame — flatline → 3 heartbeats (40px→60px→100px) → mask-based letter tracing → exit. Locked — do not change.
  • TopBar: TopBar.tsx — fixed at top, brand + search trigger + session info. Search bar triggers Command Palette on click/Ctrl+K.
  • Sidebar: Sidebar.tsx — light background, contains PersonHeader (avatar, name, title, status, details), Tags, and Alerts only. Skills, Projects, Education are in the main content tiles.
  • Card Grid: CSS Grid, 2 columns on desktop (gap 16px), 1 column on mobile. Tiles use a reusable Card component with consistent styling.
  • Tile Expansion: Career Activity items, Project items, and Skill items expand in-place with height-only animation (200ms, ease-out). Single-expand accordion — only one item open at a time.
  • KPI Flip Cards: Latest Results metrics flip on click to show explanation text. CSS perspective transform, 400ms.
  • Command Palette: Ctrl+K opens a Spotlight-style search overlay. Fuzzy search via fuse.js. Keyboard navigation (arrow keys, Enter, Escape).
  • Staggered entrance: TopBar slides down → Sidebar slides from left → Content fades in. Quick (200-300ms).
  • Expandable content: Height-only animation, 200ms ease-out. Content grows/shrinks — no opacity fade.
  • Responsive breakpoints: Desktop (full sidebar + 2-col grid), Tablet (collapsed/hidden sidebar + 1-col), Mobile (no sidebar, stacked tiles).

Path Aliases

@/ maps to ./src/ (configured in both vite.config.ts and tsconfig.json).

Type System

All data types live in src/types/index.ts and src/types/pmr.ts. Strict TypeScript — no any types. One component per file with typed props interfaces.

Design Direction: GP System Dashboard

The aesthetic direction is a modern GP system dashboard — the precision and information density of a medical records system, but with a light, contemporary, premium feel. Think: a healthcare SaaS product redesigned by a Swiss product studio.

Tone

  • Precise, not cold. Every element has a reason. Spacing is generous but intentional.
  • Light, not washed out. Warm sage background, clean white surfaces, deliberate color accents.
  • Technical, not sterile. Monospace data, status indicators, and coded entries create authentic texture.
  • Elegant, not decorative. No gratuitous ornament. Beauty comes from proportion, contrast, and type.

Typography

Typography is the primary vehicle for premium feel. Avoid generic system fonts.

  • UI / Body:
    • Elvaro Grotesque (primary, font-ui) — Modern grotesque sans-serif. 7 weights (300-900). Institutional credibility with premium feel. Slightly condensed proportions suit data-dense UI.
    • Blumir (alternative, font-ui-alt) — Geometric-humanist hybrid. Variable font (100-700). More refined/luxurious feel.
    • Both fonts sourced from Envato (licensed), stored in Fonts/. Do not use Inter, Roboto, DM Sans, or system defaults.
    • Font files: Elvaro Fonts/Elvaro Grotesque Sans Family/WOFF/TBJElvaro-*.woff2, Blumir Fonts/blumir-font-family/WOFF/Blumir-VF.woff2
  • Monospace / Data: Geist Mono for timestamps, session info, GPhC number, dates, coded entries. Creates "technical texture."
  • Terminal phase: Fira Code — locked, do not change.
  • Type scale: Tight. Headings 15-18px, body 12.5-14px, labels 10-12px. Precision over drama.
  • Weight hierarchy: Use weight (400/500/600/700) rather than size to establish hierarchy.

Color Palette

The palette anchors on teal as the primary accent, with a light sidebar + warm content background.

  • Teal #0D6E6E — Primary accent. Active states, links, avatar gradient, interactive elements. Hover: #0A8080. Light: rgba(10,128,128,0.08).
  • Background #F0F5F4 — Warm sage. The content area feels organic, not flat gray.
  • Sidebar #F7FAFA — Very light. Right border #D4E0DE separates from content.
  • TopBar #FFFFFF — White surface. Bottom border #D4E0DE.
  • Cards #FFFFFF — White with shadow-sm and border-light. Hover deepens to shadow-md.
  • Status colors: Success #059669, Amber #D97706, Alert #DC2626, Purple #7C3AED — each with light bg and border variants. Always paired with text labels.
  • Text: Primary #1A2B2A, Secondary #5B7A78, Tertiary #8DA8A5. Use full range for hierarchy.
  • Borders: Structural #D4E0DE, Cards/inner #E4EDEB.

Shadows & Depth

Three-tier shadow system for layered depth:

  • Cards (resting): 0 1px 2px rgba(26,43,42,0.05) — gentle, always present.
  • Cards (hover/interactive): 0 2px 8px rgba(26,43,42,0.08) — slightly lifted.
  • Overlays (command palette, modals): 0 8px 32px rgba(26,43,42,0.12) — clearly elevated.
  • Hover states: Shadow deepens + border color strengthens. Subtle, not dramatic.

Motion

Motion should feel considered and premium, never flashy:

  • Entrance animations: Dashboard materializes in sequence — TopBar slides down → Sidebar slides from left → Content fades in. Quick (200-300ms) with easing.
  • Login typing: 80ms/char for username, 60ms/dot for password. Natural, readable pace. After typing completes, "Log In" button becomes interactive — user clicks to proceed.
  • Login transition: On button click, card scales slightly and fades. Transition to dashboard layout.
  • Tile expansion: Height-only animation, 200ms ease-out. Content grows/shrinks — no opacity fade.
  • KPI flip: CSS perspective rotateY, 400ms ease-in-out. Click to flip, click to flip back.
  • Command palette: Scale 0.97→1.0 + translateY entrance, 200ms. Backdrop fade.
  • Hover states: Subtle, immediate. Border color shifts, shadow deepens. Think: OS-level responsiveness.
  • prefers-reduced-motion: All animations skip to final state. No exceptions.

Spatial Composition

  • Generous but structured. Cards have 20px padding. Tile grid has 16px gap. Sections breathe.
  • Clear visual hierarchy. Card headers: uppercase, small (12px), tracked-out, secondary color with colored dot indicator.
  • Two-column grid on desktop, single column on mobile. Full-width tiles span both columns.
  • Sidebar sections separated by thin divider titles (10px, uppercase, tertiary, with line extending right).

What Makes It Memorable

The distinctiveness comes from the clinical metaphor applied to a modern interface:

  • A light, professional sidebar with clinical-style person header and alert flags
  • Skills presented as "Repeat Medications" with frequency dosing (twice daily, when required)
  • KPI metrics that flip to reveal explanations, like interactive test results
  • Career history as a clinical timeline with color-coded entry types
  • The boot sequence → ECG → login flow is theatrical in a way that real clinical software never is
  • Command palette (Ctrl+K) for searching records, like a clinical search tool

Styling

Tailwind CSS with custom design tokens in tailwind.config.js:

  • Color tokens: PMR-prefixed tokens (pmr-accent, pmr-bg, pmr-surface, pmr-sidebar, pmr-text-primary, etc.)
  • Fonts: font-ui (Elvaro Grotesque), font-ui-alt (Blumir), font-geist (Geist Mono), font-mono (Fira Code for terminal)
  • Breakpoints: xs 480px, sm 640px, md 768px, lg 1024px, xl 1280px
  • Border radius: 8px default for cards/tiles (var(--radius)). 6px for inner elements (var(--radius-sm)). 12px exception for login card and command palette.
  • Shadows: shadow-sm, shadow-md, shadow-lg tokens matching three-tier system.
  • CSS custom properties in index.css for both boot/ECG phase tokens and dashboard phase tokens.
  • Inline styles only for dynamic values that Tailwind can't express.

Guardrails

  • Boot sequence: Text, colors, and timing must match References/concept.html exactly. Do not modify.
  • ECG animation: Timing, amplitudes, color transitions, and mask-based text reveal must match the concept reference. Do not modify.
  • Reference design: References/GPSystemconcept.html is the visual and structural target for the dashboard.
  • CV content: Sourced from References/CV_v4.md — roles, dates, and achievement numbers must be accurate.
  • Icons: Via lucide-react, not unicode symbols.
  • Accessibility: WCAG 2.1 AA compliance. Semantic HTML, ARIA attributes, keyboard navigation, prefers-reduced-motion support throughout. Status indicators always paired with text labels.
  • No generic aesthetics: Every design decision should feel intentional. If a component could appear in any random SaaS template, it needs more character.
  • Fonts: Elvaro Grotesque (primary) or Blumir (alt). Never Inter, Roboto, DM Sans, or system defaults. DM Sans appears in the concept HTML as a placeholder only.

Project Structure

src/
├── components/        # One component per file (PascalCase)
│   ├── tiles/         # Dashboard tile components (PatientSummaryTile, LatestResultsTile, etc.)
│   ├── views/         # Legacy PMR views (being replaced by tiles — may be referenced during transition)
│   ├── TopBar.tsx     # Fixed top bar (brand, search trigger, session)
│   ├── Sidebar.tsx    # Light sidebar (person header, tags, alerts)
│   ├── DashboardLayout.tsx  # Main layout (topbar + sidebar + card grid)
│   ├── Card.tsx       # Reusable card component with header
│   ├── CommandPalette.tsx   # Ctrl+K search overlay
│   └── ...            # Boot, ECG, Login (unchanged)
├── contexts/          # React contexts (AccessibilityContext)
├── data/              # Static data files
│   ├── patient.ts     # Person details
│   ├── consultations.ts  # Career roles (used in Last Consultation + Career Activity)
│   ├── medications.ts # Legacy skill data
│   ├── problems.ts    # Achievements
│   ├── investigations.ts  # Projects
│   ├── documents.ts   # Education entries
│   ├── profile.ts     # Personal statement
│   ├── tags.ts        # Sidebar tags
│   ├── alerts.ts      # Sidebar alert flags
│   ├── kpis.ts        # KPI metrics for Latest Results
│   └── skills.ts      # Skills with frequency/years (medication metaphor)
├── hooks/             # Custom hooks (camelCase, use* prefix)
├── lib/               # Utility functions (search.ts for fuse.js)
├── types/             # TypeScript interfaces (index.ts, pmr.ts)
├── App.tsx            # Phase manager (root component)
└── index.css          # Global styles + Tailwind directives
Ralph/                 # Implementation plan, guardrails, progress tracking
References/            # Source content (concept.html, GPSystemconcept.html, CV_v4.md)