docs: add brutalist app-wide design spec
Design for extending Brutalist style from home-screen-only to app-wide: - StyleProvider protocol for shape/typography language - Adaptive view routers for each major screen - Brutalist variants for TripDetail, MyTrips, Schedule, Settings - Colors still controlled by user's selected Theme Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
183
docs/plans/2026-01-16-brutalist-app-wide-design.md
Normal file
183
docs/plans/2026-01-16-brutalist-app-wide-design.md
Normal file
@@ -0,0 +1,183 @@
|
||||
# Brutalist App-Wide Design
|
||||
|
||||
## Overview
|
||||
|
||||
Extend the Brutalist design style from home-screen-only to work app-wide. Brutalist is a **shape/typography language** that layers on top of the user's chosen **color theme** (Teal, Orbit, Clutch, etc.).
|
||||
|
||||
**Scope:** Classic + Brutalist styles only. Other 22 styles fall back to Classic for non-home screens.
|
||||
|
||||
## Design Language
|
||||
|
||||
### What Brutalist Controls (Shape Language)
|
||||
|
||||
| Property | Classic | Brutalist |
|
||||
|----------|---------|-----------|
|
||||
| Typography | System default | Monospaced |
|
||||
| Text case | Mixed case | UPPERCASE |
|
||||
| Letter tracking | 0 | 2-4 |
|
||||
| Corner radius | 8-16px | 0px |
|
||||
| Borders | None | 1-2px solid |
|
||||
| Shadows | Soft | None or harsh |
|
||||
| Gradients | Yes | No (flat colors) |
|
||||
| Dividers | Subtle lines | Perforated ticket-stub |
|
||||
| Labels | Plain text | Bracketed `[ SECTION ]` |
|
||||
|
||||
### What Theme Still Controls (Color Palette)
|
||||
|
||||
- `Theme.warmOrange` → accent color
|
||||
- `Theme.routeGold` → secondary accent
|
||||
- `Theme.textPrimary/Secondary/Muted` → text colors
|
||||
- `Theme.cardBackground` → surfaces
|
||||
- `Theme.darkBackground1/lightBackground1` → flat backgrounds (Brutalist override)
|
||||
|
||||
## Architecture
|
||||
|
||||
### Pattern: Adaptive View Routers
|
||||
|
||||
Each major screen has an "Adaptive" wrapper that routes to style-specific variants:
|
||||
|
||||
```swift
|
||||
struct AdaptiveTripDetailView: View {
|
||||
let trip: Trip
|
||||
|
||||
var body: some View {
|
||||
switch DesignStyleManager.shared.currentStyle {
|
||||
case .brutalist:
|
||||
TripDetailView_Brutalist(trip: trip)
|
||||
default:
|
||||
TripDetailView_Classic(trip: trip)
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### File Structure
|
||||
|
||||
```
|
||||
SportsTime/Core/Design/
|
||||
├── StyleProvider.swift (protocol + implementations)
|
||||
|
||||
SportsTime/Features/Trip/Views/
|
||||
├── AdaptiveTripDetailView.swift (router)
|
||||
└── Variants/
|
||||
├── Classic/TripDetailView_Classic.swift
|
||||
└── Brutalist/TripDetailView_Brutalist.swift
|
||||
|
||||
SportsTime/Features/MyTrips/Views/
|
||||
├── AdaptiveMyTripsView.swift (router)
|
||||
└── Variants/
|
||||
├── Classic/MyTripsView_Classic.swift
|
||||
└── Brutalist/MyTripsView_Brutalist.swift
|
||||
|
||||
SportsTime/Features/Schedule/Views/
|
||||
├── AdaptiveScheduleView.swift (router)
|
||||
└── Variants/
|
||||
├── Classic/ScheduleView_Classic.swift
|
||||
└── Brutalist/ScheduleView_Brutalist.swift
|
||||
|
||||
SportsTime/Features/Settings/Views/
|
||||
├── AdaptiveSettingsView.swift (router)
|
||||
└── Variants/
|
||||
├── Classic/SettingsView_Classic.swift
|
||||
└── Brutalist/SettingsView_Brutalist.swift
|
||||
```
|
||||
|
||||
## StyleProvider Protocol
|
||||
|
||||
Lightweight protocol for shared component styling within variants:
|
||||
|
||||
```swift
|
||||
protocol StyleProvider {
|
||||
// Shape
|
||||
var cornerRadius: CGFloat { get }
|
||||
var borderWidth: CGFloat { get }
|
||||
|
||||
// Typography
|
||||
var fontDesign: Font.Design { get }
|
||||
var usesUppercase: Bool { get }
|
||||
var headerTracking: CGFloat { get }
|
||||
|
||||
// Effects
|
||||
var usesGradientBackgrounds: Bool { get }
|
||||
var usesSoftShadows: Bool { get }
|
||||
|
||||
// Helpers
|
||||
func flatBackground(_ colorScheme: ColorScheme) -> Color
|
||||
}
|
||||
|
||||
struct ClassicStyle: StyleProvider {
|
||||
let cornerRadius: CGFloat = 12
|
||||
let borderWidth: CGFloat = 0
|
||||
let fontDesign: Font.Design = .default
|
||||
let usesUppercase = false
|
||||
let headerTracking: CGFloat = 0
|
||||
let usesGradientBackgrounds = true
|
||||
let usesSoftShadows = true
|
||||
}
|
||||
|
||||
struct BrutalistStyle: StyleProvider {
|
||||
let cornerRadius: CGFloat = 0
|
||||
let borderWidth: CGFloat = 1
|
||||
let fontDesign: Font.Design = .monospaced
|
||||
let usesUppercase = true
|
||||
let headerTracking: CGFloat = 2
|
||||
let usesGradientBackgrounds = false
|
||||
let usesSoftShadows = false
|
||||
}
|
||||
```
|
||||
|
||||
## Screen Designs
|
||||
|
||||
### TripDetailView_Brutalist
|
||||
|
||||
**Header:**
|
||||
- Date range: Monospaced, uppercase, wide tracking
|
||||
- Route: `DETROIT → MILWAUKEE → SALT LAKE` (arrows, no dots)
|
||||
- Sport badges: Bordered rectangles, monospace text
|
||||
|
||||
**Stats row:**
|
||||
- Bordered boxes: `[ 7 DAYS ]` `[ 3 CITIES ]` `[ 4 GAMES ]`
|
||||
- Monospaced numbers, uppercase labels
|
||||
|
||||
**Score card:**
|
||||
- Sharp rectangle, 2px border
|
||||
- Score grade uses `Theme.warmOrange`
|
||||
- No glow effects
|
||||
|
||||
**Itinerary:**
|
||||
- Day headers: `DAY 1` large monospace
|
||||
- Perforated dividers between days
|
||||
- Game rows: Bordered boxes, monospace teams
|
||||
- Travel: `[ TRAVEL ] DETROIT → MILWAUKEE • 327 MI • 5H 27M`
|
||||
- Timeline: Solid line, square dots
|
||||
|
||||
### MyTripsView_Brutalist
|
||||
|
||||
- Section headers: `[ PLANNED ]` `[ COMPLETED ]`
|
||||
- Trip rows: Bordered, monospace city names
|
||||
- Status badges: Sharp rectangles
|
||||
|
||||
### ScheduleView_Brutalist
|
||||
|
||||
- Date picker: Sharp buttons, monospace dates
|
||||
- Game list: Bordered rows, monospace matchups
|
||||
- Filters: Bracketed labels `[ NBA ]` `[ NHL ]`
|
||||
|
||||
### SettingsView_Brutalist
|
||||
|
||||
- Section headers: `[ APPEARANCE ]` `[ ACCOUNT ]`
|
||||
- Row items: Bordered, monospace labels
|
||||
- Toggles: Sharp rectangles
|
||||
|
||||
## Implementation Order
|
||||
|
||||
1. `StyleProvider.swift` - Protocol + Classic/Brutalist implementations
|
||||
2. `TripDetailView_Brutalist.swift` + `AdaptiveTripDetailView.swift`
|
||||
3. `MyTripsView_Brutalist.swift` + `AdaptiveMyTripsView.swift`
|
||||
4. `ScheduleView_Brutalist.swift` + `AdaptiveScheduleView.swift`
|
||||
5. `SettingsView_Brutalist.swift` + `AdaptiveSettingsView.swift`
|
||||
|
||||
## Files to Modify
|
||||
|
||||
- `UIDesignStyle.swift` - Add `styleProvider` computed property
|
||||
- All callers of TripDetailView, MyTripsView, etc. - Switch to Adaptive versions
|
||||
Reference in New Issue
Block a user