refactor: centralise color maps, org color fallback, and motion-safe transitions

Create src/lib/theme-colors.ts with DOT_COLORS, KPI_COLORS,
PROJECT_STATUS_COLORS, and DEFAULT_ORG_COLOR constants. Add
motionSafeTransition() utility to src/lib/utils.ts.

Removes 6 duplicate color map definitions across Card, DetailPanel,
PatientSummaryTile, KPIDetail, ProjectsTile, and ProjectDetail.
Replaces 9 hardcoded '#0D6E6E' fallbacks and 7 inline motion ternaries.
Fixes project status color inconsistency between ProjectsTile and
ProjectDetail (Ongoing was teal in tile, amber in detail).
This commit is contained in:
2026-02-17 01:58:10 +00:00
parent 296b18f025
commit 8f4ddc454a
16 changed files with 686 additions and 190 deletions
+170 -41
View File
@@ -1,49 +1,178 @@
# Backpressure Recovery Plan — task-1771286249-a8b1
# Refactoring Plan — Comprehensive Codebase Refactor & Simplification
## Stage Name and Objective
- Stage: Post-rollout backpressure recovery (verification-only handoff)
- Objective: resolve pending `build.blocked` after `build.task.abandoned` by producing a fresh, contract-complete `build.done` evidence payload for the already completed rollout.
## Baseline
- **Total src lines:** 13,242
- **Recorded:** 2026-02-17
## Next Unchecked Rollout Stage
- None. `Ralph/PROMPT.md` shows Stage 1-4 complete and `LOOP_COMPLETE`.
- This iteration remains orchestration-only; no additional migration stage is planned.
## Current Iteration: Phase 2.2
## Explicit File List (Planner Scope)
Audit complete. Three consolidation targets identified at 3+ occurrences. One data inconsistency to fix.
### Read-only verification targets
- `Ralph/PROMPT.md`
- `README.md`
- `src/data/profile-content.ts`
- `src/lib/profile-content.ts`
- `package.json`
---
### Required gate commands for builder execution
- `npm run lint`
- `npm run typecheck`
- `npm run build`
- `npm audit --omit=dev`
### Phase 2.2 — Audit and consolidate repeated patterns
## Migration Approach (Safety-First)
1. Keep this pass verification-only with zero source behavior edits.
2. Re-run mandatory gates and capture outcomes from the current workspace state.
3. Publish `build.done` only when all required evidence fields are explicitly present:
- `tests`
- `lint`
- `typecheck`
- `audit`
- `coverage`
- `complexity`
- `duplication`
- `performance/specs`
4. Where tooling is not configured (`tests`, `coverage`, `complexity`), report explicit N/A rationale rather than omitting fields.
5. Reconfirm canonical content centralization and one-file documentation remain intact.
#### Change 1: Create `src/lib/theme-colors.ts` — centralise color maps
## Compatibility Strategy
- No code refactors or data-shape changes.
- Preserve existing IDs/contracts and all route/nav/detail-panel behaviors as-is.
**Why:** Four files define identical/overlapping color maps. Two project status maps are inconsistent (bug).
## Rollback-Safe Checkpoints
1. Checkpoint A: rollout-complete state reconfirmed from `Ralph/PROMPT.md`.
2. Checkpoint B: gate outputs collected (`lint`, `typecheck`, `build`, `audit`).
3. Checkpoint C: non-gate evidence fields (`tests`, `coverage`, `complexity`, `duplication`, `performance/specs`) explicitly populated.
4. Checkpoint D: concise, contract-complete `build.done` payload prepared for handoff.
**New file: `src/lib/theme-colors.ts`**
```ts
/** Semantic dot/accent colors used across Card, DetailPanel, KPIs */
export const DOT_COLORS = {
teal: '#0D6E6E',
amber: '#D97706',
green: '#059669',
alert: '#DC2626',
purple: '#7C3AED',
} as const
export type DotColorName = keyof typeof DOT_COLORS
/** KPI color variants (subset of DOT_COLORS) */
export const KPI_COLORS: Record<'green' | 'amber' | 'teal', string> = {
green: DOT_COLORS.green,
amber: DOT_COLORS.amber,
teal: DOT_COLORS.teal,
}
/** Project/investigation status colors */
export const PROJECT_STATUS_COLORS: Record<'Complete' | 'Ongoing' | 'Live', string> = {
Complete: '#059669',
Ongoing: '#D97706',
Live: '#0D6E6E',
}
/** Default org color fallback when consultation.orgColor is undefined */
export const DEFAULT_ORG_COLOR = '#0D6E6E'
```
**Note on project status inconsistency:** ProjectsTile has `Ongoing: '#0D6E6E'` (teal) and `Live: '#059669'` (green), while ProjectDetail has `Ongoing: '#D97706'` (amber) and `Live: '#0D6E6E'` (teal). The ProjectDetail version is more semantically correct (Ongoing=amber=warning, Live=teal=active, Complete=green=success). Use the **ProjectDetail** mapping as canonical.
**Files to update:**
1. **`src/components/Card.tsx`** (line 46-52)
- Remove `const dotColorMap` (6 lines)
- Import `DOT_COLORS` from `@/lib/theme-colors`
- Use `DOT_COLORS[dotColor]` instead of `dotColorMap[dotColor]`
2. **`src/components/DetailPanel.tsx`** (line 64-70)
- Remove `const dotColorValueMap` (7 lines)
- Import `DOT_COLORS` from `@/lib/theme-colors`
- Use `DOT_COLORS[dotColor]` instead of `dotColorValueMap[dotColor]`
3. **`src/components/tiles/PatientSummaryTile.tsx`** (line 10-14)
- Remove `const colorMap` (5 lines)
- Import `KPI_COLORS` from `@/lib/theme-colors`
- Use `KPI_COLORS[kpi.colorVariant]` instead of `colorMap[kpi.colorVariant]`
4. **`src/components/detail/KPIDetail.tsx`** (line 8-12)
- Remove local `colorMap` (5 lines)
- Import `KPI_COLORS` from `@/lib/theme-colors`
- Use `KPI_COLORS[kpi.colorVariant]`
5. **`src/components/tiles/ProjectsTile.tsx`** (line 7-11)
- Remove `const statusColorMap` (5 lines)
- Import `PROJECT_STATUS_COLORS` from `@/lib/theme-colors`
- Use `PROJECT_STATUS_COLORS[project.status]` (fixes color values to match ProjectDetail)
6. **`src/components/detail/ProjectDetail.tsx`** (line 8-12)
- Remove `const statusColorMap` (5 lines)
- Import `PROJECT_STATUS_COLORS` from `@/lib/theme-colors`
- Use `PROJECT_STATUS_COLORS[investigation.status]`
#### Change 2: Add `DEFAULT_ORG_COLOR` to `src/lib/theme-colors.ts`
**Why:** `consultation.orgColor ?? '#0D6E6E'` appears 9 times across 2 files.
**Files to update:**
7. **`src/components/WorkExperienceSubsection.tsx`** (lines 36, 38, 63, 81, 213, 215)
- Import `DEFAULT_ORG_COLOR` from `@/lib/theme-colors`
- Replace all 6 instances of `consultation.orgColor ?? '#0D6E6E'``consultation.orgColor ?? DEFAULT_ORG_COLOR`
8. **`src/components/DashboardLayout.tsx`** (lines 105, 106, 133)
- Import `DEFAULT_ORG_COLOR` from `@/lib/theme-colors`
- Replace all 3 instances of `consultation.orgColor ?? '#0D6E6E'``consultation.orgColor ?? DEFAULT_ORG_COLOR`
#### Change 3: Add `motionSafeTransition()` to `src/lib/utils.ts`
**Why:** The pattern `prefersReducedMotion ? { duration: 0 } : { duration, ease, delay }` appears 7 times.
**Add to `src/lib/utils.ts`:**
```ts
/** Returns a framer-motion transition that respects prefers-reduced-motion */
export function motionSafeTransition(
duration: number,
ease: string = 'easeOut',
delay: number = 0
): { duration: number; ease?: string; delay?: number } {
if (prefersReducedMotion) return { duration: 0 }
return { duration, ease, ...(delay ? { delay } : {}) }
}
```
**Files to update:**
9. **`src/components/DashboardLayout.tsx`** (lines 27-29, 37-39)
- Import `motionSafeTransition` from `@/lib/utils`
- Replace 2 inline ternaries
10. **`src/components/WorkExperienceSubsection.tsx`** (lines 141-143)
- Import `motionSafeTransition` from `@/lib/utils`
- Replace 1 inline ternary
11. **`src/components/ChatWidget.tsx`** (lines 32-34, 45-47)
- Import `motionSafeTransition` from `@/lib/utils`
- Replace 2 inline ternaries
12. **`src/components/TimelineInterventionsSubsection.tsx`** (lines 174-176)
- Import `motionSafeTransition` from `@/lib/utils`
- Replace 1 inline ternary
13. **`src/components/constellation/MobileAccordion.tsx`** (line 26)
- Import `motionSafeTransition` from `@/lib/utils`
- Replace 1 inline ternary
### What was audited and NOT extracted (with reasons)
- **Shadow `rgba(26,43,42,...)`**: 15+ occurrences but already partially covered by CSS vars; remaining inline usages are in varied contexts (D3 attributes, dynamic JS). Low ROI.
- **Breakpoint `window.innerWidth < 640`**: Only 3 occurrences, trivially clear inline, in different execution contexts (hook, D3, component).
- **Date formatting**: Only 2 occurrences.
- **Section heading styles**: Slightly varied across components (letterSpacing differs, marginBottom differs).
### Verification
- `npm run lint` — no unused imports, no duplicate definitions
- `npm run typecheck` — all imports resolve, types match
- `npm run build` — clean build
- `grep -r "dotColorMap\|dotColorValueMap" src/` — zero matches (removed)
- `grep -r "statusColorMap" src/` — zero matches (removed)
- `grep -r "orgColor ?? '#0D6E6E'" src/` — zero matches (replaced with constant)
- `grep "prefersReducedMotion ? { duration: 0 }" src/` — zero matches (replaced with utility)
---
## Overall Checklist Status
### Phase 0: Dev Shortcut
- [x] 0.1 — Disable boot/ECG/login sequence ✅
### Phase 1: Data Consolidation
- [x] 1.1 — Migrate medications.ts history into skills.ts ✅
- [x] 1.2 — Consolidate timeline narrative into timeline.ts ✅
- [x] 1.3 — Split profile-content.ts into focused concerns ✅
- [x] 1.4 — Evaluate thin re-export layers ✅
### Phase 2: Utility Extraction
- [x] 2.1 — Extract duplicated utility functions into lib/utils.ts ✅
- [x] 2.2 — Audit and consolidate other repeated patterns ✅
### Phase 3: Component Simplification
- [ ] 3.1 — Extract shared ExpandableCard component
- [ ] 3.2 — Simplify detail panel components
- [ ] 3.3 — Review large components for extraction opportunities
### Phase 4: Final Cleanup
- [ ] 4.1 — Remove dead code and unused exports
- [ ] 4.2 — Final validation and baseline comparison
- [ ] 4.3 — Re-enable boot/ECG/login sequence