Freeze a shared design system (DesignSystem/{Tokens,Typography,StatusStyle,
Primitives}.swift): indigo #7C8CFF accent (root .tint), semantic status colors,
2-4-8-12-16-20-24 spacing + sm8/md12/lg16 radii scale, SF Mono tabular numbers,
reduce-motion-gated animations, haptics, reusable StatusBadge/TelemetryChip/Card/
SectionHeader/DSButtonStyle/ContinueLastBanner. Every changed view consumes tokens
— no hardcoded colors/spacing.
Applied across all surfaces (visual only — zero behavior/logic change, all suites
green): session list rows + status system (shape+color, not color-alone) +
telemetry chips + thumbnail placeholders; terminal gate card (≥44pt approve/reject)
+ keybar + reconnect + quick-reply + digest + SwiftTerm accent theme; pairing hero
+ warning tiers + Projects cards + Timeline/Diff; nav chrome + iPad split placeholder
+ privacy shade + motion. Chinese gate copy. UX finding fixed: timeline class colors
now via DS.Palette (+timelineTool/timelineUser tokens).
Design review 8.5/10. Verified: iPhone 16 290 + iPad Pro 11 290 tests green;
packages + integration green; consistency audit ~clean; zero changes under
ios/Packages, src/, public/.
61 lines
2.2 KiB
Swift
61 lines
2.2 KiB
Swift
import SwiftUI
|
||
|
||
/// # Typography — the SF type ramp (FROZEN public surface)
|
||
///
|
||
/// All font choices come from `DS.Typography`. The ramp maps to Apple's
|
||
/// semantic text styles so everything scales with Dynamic Type (the a11y
|
||
/// audit's "keep it scalable" point). Numbers/dimensions/cost/`cols×rows`/
|
||
/// timestamps use `mono(_:)` — SF Mono with tabular figures — so columns line
|
||
/// up and digits don't jitter as values change (matches the existing
|
||
/// `TelemetryChips`/`Timeline` convention, now centralized).
|
||
extension DS {
|
||
enum Typography {
|
||
|
||
// ── Proportional ramp (Dynamic-Type scaling, semantic styles) ───────
|
||
|
||
/// Screen hero title.
|
||
static let largeTitle = Font.largeTitle
|
||
/// Section / prominent title.
|
||
static let title = Font.title2
|
||
/// Emphasis / card heading.
|
||
static let headline = Font.headline
|
||
/// Default body text.
|
||
static let body = Font.body
|
||
/// Slightly smaller body (secondary actions).
|
||
static let callout = Font.callout
|
||
/// Meta / caption text.
|
||
static let caption = Font.caption
|
||
|
||
// ── Monospaced (numbers, dimensions, timestamps) ────────────────────
|
||
|
||
/// SF Mono + tabular figures at the given text style (default `.body`).
|
||
/// Use for anything numeric that must align or not jump: `cols×rows`,
|
||
/// device/client counts, `$cost`, context %, relative timestamps.
|
||
static func mono(_ style: Font.TextStyle = .body) -> Font {
|
||
.system(style, design: .monospaced).monospacedDigit()
|
||
}
|
||
|
||
/// The canonical meta-number font: caption-sized mono + tabular.
|
||
static let metaMono = mono(.caption)
|
||
}
|
||
}
|
||
|
||
// MARK: - MetaText style
|
||
|
||
/// Secondary + monospaced-tabular styling for a row's numeric meta line
|
||
/// ("N 台设备在看 · 161×50"). Apply via `.dsMetaText()`.
|
||
struct MetaText: ViewModifier {
|
||
func body(content: Content) -> some View {
|
||
content
|
||
.font(DS.Typography.metaMono)
|
||
.foregroundStyle(DS.Palette.textSecondary)
|
||
}
|
||
}
|
||
|
||
extension View {
|
||
/// Style a meta/number line as secondary monospaced-tabular text.
|
||
func dsMetaText() -> some View {
|
||
modifier(MetaText())
|
||
}
|
||
}
|