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:
+120
-56
@@ -1,79 +1,143 @@
|
||||
# Task: Centralize All Portfolio Descriptive Text Into One Editable Source
|
||||
# Task: Comprehensive Codebase Refactor & Simplification
|
||||
|
||||
Refactor the app so all core descriptive/profile copy is managed from a single source file and consumed everywhere relevant (education, experience, patient summary, skills, timeline/constellation text, and related detail/search/chat surfaces).
|
||||
Refactor the portfolio codebase to eliminate duplication, consolidate data sources, extract shared utilities, and simplify components — while preserving identical runtime behaviour and visual output.
|
||||
|
||||
This is a staged rollout, not a big-bang rewrite. Implement one stage at a time with passing quality gates before moving on.
|
||||
## Guiding Principle
|
||||
|
||||
## Requirements
|
||||
**Single Source of Truth**: Every piece of information should live in exactly one place. Derived data is fine (for code-splitting/performance), but the canonical definition must not be duplicated.
|
||||
|
||||
- Create one canonical content module (single file) for descriptive profile text.
|
||||
- Migrate all major consumer surfaces to this single source, including at minimum:
|
||||
- patient summary and sidebar profile details
|
||||
- work experience and education content
|
||||
- skills descriptive text and related summaries
|
||||
- timeline/constellation narrative fields that are shown to users
|
||||
- text used by search/chat context where it duplicates profile copy
|
||||
- Eliminate unnecessary duplication; where duplicate sources exist, consolidate to one source of truth.
|
||||
- Preserve existing UI behavior and interactions (navigation, panel opening, highlighting, timeline, constellation links).
|
||||
- Keep migration incremental and safe using staged checkpoints.
|
||||
## Refactoring Checklist
|
||||
|
||||
## Rollout Stages
|
||||
Work through these IN ORDER. Each item is a self-contained refactoring that leaves the codebase in a passing state (lint + typecheck + build).
|
||||
|
||||
### Stage 1: Inventory + Canonical Schema
|
||||
### Phase 0: Dev Shortcut
|
||||
|
||||
- Audit where descriptive text currently lives (`src/data/*`, component literals, search/chat context builders).
|
||||
- Define the canonical content schema and create the single editable file.
|
||||
- Add typed access helpers if needed so downstream consumers can migrate safely.
|
||||
- Keep compatibility exports/adapters for non-migrated consumers.
|
||||
- [x] **0.1 — Disable boot/ECG/login sequence for faster visual review**
|
||||
- In `src/App.tsx` line 48, change `useState<Phase>('boot')` to `useState<Phase>('pmr')`
|
||||
- This skips straight to the dashboard, saving ~10s per visual inspection
|
||||
- Do NOT remove the BootSequence/ECGAnimation/LoginScreen components or imports — just bypass them
|
||||
- Verify: `npm run build` passes, app loads directly to dashboard at localhost:5173
|
||||
|
||||
### Stage 2: Core UI Migration
|
||||
### Phase 1: Data Consolidation
|
||||
|
||||
- Migrate patient summary, sidebar profile text, experience, education, and skills surfaces.
|
||||
- Ensure components read from canonical content instead of local duplicate strings.
|
||||
- Keep existing IDs/keys where needed to avoid UI regressions.
|
||||
- [x] **1.1 — Migrate medications.ts history into skills.ts, then delete medications.ts**
|
||||
- `src/data/medications.ts` has ZERO imports anywhere (dead code) but contains `prescribingHistory[]` arrays with rich skill progression data
|
||||
- Merge the `prescribingHistory` data into corresponding entries in `src/data/skills.ts` (add a `prescribingHistory` field to SkillMedication type)
|
||||
- Update `src/types/pmr.ts` if needed for the new field
|
||||
- Delete `src/data/medications.ts`
|
||||
- Verify: no broken imports, build passes
|
||||
|
||||
### Stage 3: Secondary Consumer Migration
|
||||
- [x] **1.2 — Consolidate timeline narrative into timeline.ts**
|
||||
- `src/data/profile-content.ts` contains a `timelineNarrative` section (~320 lines) that is pulled into `timeline.ts` via `getTimelineNarrativeEntry()`
|
||||
- Inline the narrative content directly into the `TimelineEntity` objects in `timeline.ts`
|
||||
- Remove the `timelineNarrative` section from `profile-content.ts`
|
||||
- Remove `getTimelineNarrativeEntry()` from `src/lib/profile-content.ts` and all call sites
|
||||
- Verify: timeline entities still have all their description/details/outcomes/codedEntries data
|
||||
|
||||
- Migrate timeline/constellation narrative fields and detail-panel supporting content.
|
||||
- Migrate search/chat context text generation to derive from canonical content wherever feasible.
|
||||
- Remove hardcoded fallback narratives that duplicate canonical text.
|
||||
- [x] **1.3 — Split profile-content.ts into focused concerns**
|
||||
- After 1.2, `profile-content.ts` should be smaller. Split remaining content:
|
||||
- LLM system prompt → inline into `src/lib/llm.ts` or a dedicated `src/data/llm-prompt.ts`
|
||||
- Education narrative → merge into `src/data/documents.ts` or `educationExtras.ts`
|
||||
- Profile summary/achievements → keep in `profile-content.ts` only if genuinely unique
|
||||
- Goal: `profile-content.ts` either deleted or contains only truly unique content with zero duplication
|
||||
- Update `src/lib/profile-content.ts` accessor functions and all consumers
|
||||
- Update `src/types/profile-content.ts` types to match
|
||||
|
||||
### Stage 4: Cleanup + Hardening
|
||||
- [x] **1.4 — Evaluate thin re-export layers**
|
||||
- `src/data/constellation.ts` (9 lines) re-exports from `timeline.ts`
|
||||
- `src/data/tags.ts` (10 lines) derives from `timeline.ts`
|
||||
- For each: inline at call sites if few consumers, or keep if many consumers benefit
|
||||
- If kept, add a brief comment explaining why the indirection exists
|
||||
- If removed, update all import paths
|
||||
|
||||
- Remove obsolete duplicate fields/files once all consumers are migrated.
|
||||
- Tighten type definitions around canonical content access.
|
||||
- Add/update concise documentation describing how to edit content in one place.
|
||||
- Validate that future content edits require changes in only one file for shared text.
|
||||
### Phase 2: Utility Extraction
|
||||
|
||||
- [x] **2.1 — Extract duplicated utility functions into lib/utils.ts**
|
||||
- `hexToRgba()` is defined locally in at least: `DashboardLayout.tsx`, `TimelineInterventionsSubsection.tsx`, `WorkExperienceSubsection.tsx`
|
||||
- `prefersReducedMotion` media query is repeated across 8+ files
|
||||
- Extract both to `src/lib/utils.ts` (currently only 8 lines with `cn()`)
|
||||
- Replace all local definitions with imports from `@/lib/utils`
|
||||
- Verify: no duplicate function definitions remain, search codebase to confirm
|
||||
|
||||
- [x] **2.2 — Audit and consolidate other repeated patterns**
|
||||
- Search for other duplicated helper functions, constants, or inline logic across components
|
||||
- Extract anything used in 3+ places into shared modules
|
||||
- Common candidates: date formatting, color manipulation, responsive breakpoint checks, animation config objects
|
||||
|
||||
### Phase 3: Component Simplification
|
||||
|
||||
- [ ] **3.1 — Extract shared ExpandableCard component**
|
||||
- `WorkExperienceSubsection.tsx` (306 lines), `TimelineInterventionsSubsection.tsx` (346 lines), and `RepeatMedicationsSubsection.tsx` (294 lines) all implement expand/collapse card patterns with similar styling and interaction logic
|
||||
- Extract the shared pattern into `src/components/ExpandableCard.tsx`
|
||||
- The shared component handles: expand/collapse toggle, animation, consistent styling
|
||||
- Each subsection keeps its unique content rendering via children/render props
|
||||
- Goal: measurable line reduction across the three files
|
||||
|
||||
- [ ] **3.2 — Simplify detail panel components**
|
||||
- 6 detail panel components share structural patterns: `SkillDetail`, `SkillsAllDetail`, `ConsultationDetail`, `EducationDetail`, `ProjectDetail`, `KPIDetail`
|
||||
- Extract shared layout into a base component: container, header, close button, scroll behaviour, enter/exit animation
|
||||
- Each detail component keeps its unique content but reuses the shared shell
|
||||
- Look at `src/components/detail/` directory
|
||||
|
||||
- [ ] **3.3 — Review large components for extraction opportunities**
|
||||
- Components over 400 lines: ECGAnimation (686), ChatWidget (648), Sidebar (572), DashboardLayout (503), BootSequence (497), CommandPalette (456), LoginScreen (449)
|
||||
- For each: identify self-contained sections that can become sub-components
|
||||
- Only extract where it genuinely reduces complexity — not arbitrary line-count reduction
|
||||
- Prioritise sections with their own state/effects that don't need parent state
|
||||
|
||||
### Phase 4: Final Cleanup
|
||||
|
||||
- [ ] **4.1 — Remove dead code and unused exports**
|
||||
- After all refactoring, scan for: unused imports, unused exports, unused types, orphaned files
|
||||
- ESLint should catch most — run `npm run lint` and fix everything
|
||||
- Manually check for files that are no longer imported anywhere
|
||||
|
||||
- [ ] **4.2 — Final validation and baseline comparison**
|
||||
- `npm run lint` passes with zero warnings
|
||||
- `npm run typecheck` passes with zero errors
|
||||
- `npm run build` succeeds
|
||||
- Compare total line count against baseline (recorded at start)
|
||||
- Record the reduction in this file
|
||||
|
||||
- [ ] **4.3 — Re-enable boot/ECG/login sequence**
|
||||
- In `src/App.tsx`, change `useState<Phase>('pmr')` back to `useState<Phase>('boot')`
|
||||
- Verify: `npm run build` passes
|
||||
- Do a final Playwright visual check to confirm the full boot → ECG → login → dashboard flow works
|
||||
- Commit: `fix: re-enable boot sequence after refactor`
|
||||
|
||||
## Success Criteria
|
||||
|
||||
All of the following must be true:
|
||||
- [x] `npm run lint` passes
|
||||
- [x] `npm run typecheck` passes
|
||||
- [x] `npm run build` passes
|
||||
- [x] A single canonical content file exists and is the primary source for descriptive/profile text
|
||||
- [x] Education, experience, patient summary, and skills copy are sourced from canonical content
|
||||
- [x] Timeline/constellation user-facing narrative text is sourced from canonical content where applicable
|
||||
- [x] Search/chat context no longer maintains avoidable duplicate profile copy
|
||||
- [x] Obsolete duplicate text sources are removed or reduced to thin compatibility adapters
|
||||
- [x] Documentation explains the one-file content editing workflow
|
||||
ALL of the following must be true:
|
||||
- [ ] Every checklist item above is complete (or explicitly escalated with reason)
|
||||
- [ ] `npm run lint && npm run typecheck && npm run build` passes cleanly
|
||||
- [ ] No data is defined in more than one place (single source of truth)
|
||||
- [ ] `src/data/medications.ts` is deleted (history migrated to skills.ts)
|
||||
- [ ] `hexToRgba()` exists in exactly one location
|
||||
- [ ] `prefersReducedMotion` query is centralised
|
||||
- [ ] Shared component patterns are extracted (ExpandableCard, detail panel base)
|
||||
- [ ] Total codebase line count is measurably reduced
|
||||
- [ ] Zero runtime behaviour changes — identical visual output
|
||||
|
||||
## Constraints
|
||||
|
||||
- Stack: TypeScript + React + Vite.
|
||||
- Preserve current route/scroll/nav interactions and detail panel behaviors.
|
||||
- Prefer minimal, reversible refactors at each stage.
|
||||
- Do not introduce unrelated feature work.
|
||||
- Keep naming consistent with existing project conventions.
|
||||
- TypeScript strict mode must be maintained
|
||||
- Preserve all existing path aliases (`@/*`)
|
||||
- Follow existing naming conventions (PascalCase components, kebab-case utils)
|
||||
- Conventional commit messages for each logical change (`refactor: ...`)
|
||||
- Do not modify the app's phases or lifecycle (boot → ECG → login → dashboard) — except the temporary Phase 0 bypass which is reverted in 4.3
|
||||
- Do not change any Tailwind classes or visual styling
|
||||
- Do not add new dependencies
|
||||
- Do not remove the CLAUDE.md file
|
||||
|
||||
## Baseline
|
||||
|
||||
Record line count before starting. Run at first iteration:
|
||||
```bash
|
||||
find src -name '*.ts' -o -name '*.tsx' | xargs wc -l
|
||||
```
|
||||
Store result in .ralph/plan.md for comparison at end.
|
||||
|
||||
## Status
|
||||
|
||||
Track progress here. Mark items complete as you go.
|
||||
When all success criteria are met, print LOOP_COMPLETE.
|
||||
|
||||
- [x] Stage 1 complete: Inventory + Canonical schema
|
||||
- [x] Stage 2 complete: Core UI migration
|
||||
- [x] Stage 3 complete: Secondary consumer migration
|
||||
- [x] Stage 4 complete: Cleanup + hardening
|
||||
|
||||
LOOP_COMPLETE
|
||||
When ALL success criteria are met, print LOOP_COMPLETE.
|
||||
|
||||
Reference in New Issue
Block a user