# Reference: Tasks 16-18 — Interactions ## Task 16: Tile Expansion System ### Overview Three tiles have expandable items: CareerActivity (roles), Projects, and CoreSkills. Clicking an item expands it in-place to reveal detail, like expanding a clinical record entry. ### Expansion Pattern (consistent across all tiles) **Animation:** - Framer Motion `AnimatePresence` + `motion.div` - Height-only animation: 200ms, ease-out - **No opacity fade on content** (guardrail) - `overflow: hidden` on the animated container ```typescript {isExpanded && ( {/* expanded content */} )} ``` **Behavior:** - Single-expand accordion: only one item expanded at a time within each tile - Click expanded item again to collapse - Click different item: collapses current, expands new - State: `expandedItemId: string | null` in each tile component **Keyboard:** - Enter/Space: toggle expand/collapse - Escape: collapse current item - `aria-expanded` on each clickable item **Visual:** - Expanded content has slightly different background (`var(--bg)` or subtle border-left) - Colored left border on expanded panel (accent color for roles, amber for projects, teal for skills) - Content padding: 12-16px ### CareerActivity Expansion (roles) When a role-type activity item is expanded: - Show full role details from corresponding consultation entry - Structure: role title, organization, date range - Achievement bullets (examination array from consultation) - Coded entries if available - Match expanded content to `consultations` data by mapping activity item to consultation ### Projects Expansion When a project item is expanded: - Show from investigation data: - Methodology - Tech stack (as tags or inline list) - Results (bulleted) - External URL link if available ("View Results" button) ### CoreSkills Expansion When a skill item is expanded: - Show "prescribing history" — a timeline of skill development - Source: Can use the existing `medications` data which has `prescribingHistory` entries - Format: vertical timeline with year markers and descriptions - Timeline dots: accent color, 6px, with connecting line - Year: mono font, 12px, semibold - Description: 12px, regular --- ## Task 17: KPI Flip Cards ### Overview In the LatestResults tile, each metric card can be clicked to "flip" and reveal an explanation of that KPI. ### Flip Animation **CSS Perspective approach:** ```css .metric-card { perspective: 1000px; cursor: pointer; } .metric-card-inner { transition: transform 0.4s ease-in-out; transform-style: preserve-3d; position: relative; } .metric-card-inner.flipped { transform: rotateY(180deg); } .metric-card-front, .metric-card-back { backface-visibility: hidden; position: absolute; inset: 0; } .metric-card-back { transform: rotateY(180deg); } ``` Or use Framer Motion `animate={{ rotateY: isFlipped ? 180 : 0 }}` with `perspective` on parent. **Behavior:** - Click to flip front → back - Click again to flip back → front - Only one card flipped at a time (clicking another card flips the current one back) - State: `flippedCardId: string | null` in LatestResultsTile **Front face:** Current metric display (value + label + sub) — same as Task 10. **Back face:** - `background: var(--accent-light)` (subtle teal tint) - `padding: 14px` - Text: 12px, text-secondary, `line-height: 1.5` - The explanation text from KPI data's `explanation` field **Reduced motion:** - No 3D flip animation - Instant content swap (front → back) - Could use a simple crossfade or just replace content immediately **Keyboard:** - Enter/Space to flip - Each metric card should be `tabIndex={0}` with appropriate `aria-label` **KPI Explanations** (from `src/data/kpis.ts`): - £220M: Budget management with forecasting models - £14.6M: Efficiency programme through data analysis - 9+ Years: NHS service progression since 2016 - 12: Cross-functional team leadership --- ## Task 18: Command Palette ### File: `src/components/CommandPalette.tsx` ### Trigger - **Ctrl+K** (global `keydown` listener on `document`) - **Click** on TopBar search bar (or focus on search input) - The TopBar search input does NOT do inline search — it opens the palette ### Overlay - `position: fixed`, `inset: 0` - `background: rgba(26,43,42,0.45)` - `backdrop-filter: blur(4px)` - `z-index: 1000` - Fade in: `opacity: 0 → 1`, `visibility: hidden → visible`, 200ms transition - Click overlay (outside modal) to close ### Palette Modal - `width: 580px`, `max-height: 520px` - `background: var(--surface)` (#FFFFFF) - `border-radius: 12px` - `box-shadow: 0 20px 60px rgba(26,43,42,0.2), 0 0 0 1px rgba(26,43,42,0.08)` - `overflow: hidden` - Entrance: `transform: scale(0.97) translateY(-8px)` → `scale(1) translateY(0)`, 200ms cubic-bezier ### Search Input - Flex row: search icon (18px, accent) + input + "ESC" hint badge - `padding: 14px 18px`, `border-bottom: 1px solid var(--border-light)` - Input: 15px, font-body, placeholder "Search records, experience, skills..." - ESC badge: mono 10px, tertiary, bg var(--bg), border, padding 2px 7px, radius 4px ### Results Area - `overflow-y: auto`, `padding: 8px`, `flex: 1` - Custom scrollbar (4px) ### Result Sections Section label: 10px, 600 weight, uppercase, `letter-spacing: 0.08em`, text-tertiary, `padding: 8px 10px 5px` ### Result Items - `display: flex`, `align-items: center`, `gap: 10px` - `padding: 9px 10px`, `border-radius: var(--radius-sm)` (6px) - `cursor: pointer`, `transition: background 0.1s` - 13px, text-primary - Hover/selected: `background: var(--accent-light)` - Selected also gets: `outline: 1.5px solid var(--accent-border)` **Item structure:** - Icon container: 28px square, 6px radius, colored bg per section - Experience: teal - Core Skills: green - Active Projects: amber - Achievements: amber - Education: purple - Quick Actions: teal - Text: title (500 weight) + subtitle (11px, tertiary, truncated) - Optional badge: 10px, mono, tertiary ### Fuzzy Search Adapt existing `src/lib/search.ts` (fuse.js integration): - Rebuild search index to include new data (skills from skills.ts, KPIs, etc.) - `threshold: 0.3`, weighted keys (title: 2, content: 1) - `minMatchCharLength: 2` - Group results by section - Highlight matching text in titles using `` with accent-light background ### Keyboard Navigation - **Arrow Down/Up**: move selection through results - **Enter**: select highlighted result (navigate to section or trigger action) - **Escape**: close palette - `selectedIndex` state tracks which result is highlighted - Auto-scroll highlighted result into view ### Quick Actions Section | Title | Subtitle | Action | |-------|----------|--------| | Download CV | Export as PDF | Trigger download | | Send Email | andy@charlwood.xyz | `mailto:` link | | View LinkedIn | Professional profile | External link | | View Projects | GitHub & portfolio | External link | ### Footer - `display: flex`, `gap: 12px` - `padding: 10px 18px`, `border-top: 1px solid var(--border-light)` - 11px, text-tertiary - Keyboard hints: `↑ ↓ Navigate`, `Enter Select`, `Esc Close` - Each key in `` styled element ### Reduced Motion - No scale/translate entrance animation - Instant show/hide (opacity only, or immediate) ### State Management ```typescript const [isOpen, setIsOpen] = useState(false) const [query, setQuery] = useState('') const [selectedIndex, setSelectedIndex] = useState(-1) ``` Render the palette at the DashboardLayout level so it overlays everything.