website refactor

This commit is contained in:
2026-01-19 00:35:55 +01:00
parent c78b17eb58
commit b0431637b7
3 changed files with 79 additions and 2 deletions
+36 -2
View File
@@ -144,9 +144,11 @@ Additional strict rules:
- View Models SHOULD compose Displays.
- ViewData Builders SHOULD use Displays for all formatting.
- **Templates and Components MUST NOT use Displays directly.** They must receive already-formatted primitive outputs (strings, numbers) via their props.
Reason: This keeps the rendering layer "dumb" and ensures that the `ViewData` remains the single source of truth for what is displayed on the screen.
- Displays MUST NOT be serialized or passed across boundaries.
- They must not appear in server-to-client DTOs.
- Templates should receive primitive display outputs, not Display instances.
---
@@ -165,6 +167,38 @@ Additionally:
---
## Common Candidates (Found in Components)
The following patterns were identified in `apps/website/components` and SHOULD be migrated to Display Objects:
### 1. Date & Time
- **Month/Year:** `new Date().toLocaleDateString('en-US', { month: 'short', year: 'numeric' })` → `DateDisplay.formatMonthYear()`
- **Time only:** `new Date().toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })` → `DateDisplay.formatTime()`
- **Full Date:** `new Date().toLocaleDateString()` → `DateDisplay.formatShort()` (ensure UTC)
- **Relative Time:** `timeAgo(timestamp)` logic → `RelativeTimeDisplay.format(timestamp, now)`
### 2. Currency & Prices
- **Price with Symbol:** `$` + `amount.toFixed(2)` → `CurrencyDisplay.format(amount, 'USD')`
- **Compact Price:** `$` + `amount.toLocaleString()` → `CurrencyDisplay.formatCompact(amount)`
### 3. Numbers & Stats
- **Ratings:** `Math.round(rating).toLocaleString()` → `RatingDisplay.format(rating)`
- **Percentages:** `(val * 100).toFixed(1) + '%'` → `PercentDisplay.format(val)`
- **Consistency:** `${stats.consistency}%` → `ConsistencyDisplay.format(stats.consistency)`
- **Average Finish:** `avgFinish.toFixed(1)` → `FinishDisplay.format(avgFinish)`
- **Durations:** `duration.toFixed(2) + 'ms'` or `minutes:seconds` → `DurationDisplay.format(ms)`
- **Memory:** `(bytes / 1024 / 1024).toFixed(1) + 'MB'` → `MemoryDisplay.format(bytes)`
### 4. Status & Labels
- **Race Status:** Mapping `scheduled | running | completed` to labels → `RaceStatusDisplay`
- **Protest Status:** Mapping `pending | under_review | resolved` to labels → `ProtestStatusDisplay`
- **Action Status:** Mapping `PENDING | COMPLETED | FAILED` to labels → `ActionStatusDisplay`
### 5. Pluralization
- **Member Count:** `${count} ${count === 1 ? 'member' : 'members'}` → `MemberDisplay.formatCount(count)`
---
## Summary
- Displays encapsulate **how something looks** (the single source of truth for formatting logic).