Redesign CVMIS system 2

This commit is contained in:
2026-02-13 16:42:45 +00:00
parent 000df670a3
commit e13a073a6f
26 changed files with 24405 additions and 0 deletions
+248
View File
@@ -0,0 +1,248 @@
# 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
<AnimatePresence initial={false}>
{isExpanded && (
<motion.div
initial={{ height: 0 }}
animate={{ height: 'auto' }}
exit={{ height: 0 }}
transition={prefersReducedMotion ? { duration: 0 } : { duration: 0.2, ease: 'easeOut' }}
style={{ overflow: 'hidden' }}
>
{/* expanded content */}
</motion.div>
)}
</AnimatePresence>
```
**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 `<mark>` 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 `<kbd>` 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.