feat: add iOS support and harden receipt scanning
This commit is contained in:
93
app/ios/ScanReceipts/Design/ZenithTypography.swift
Normal file
93
app/ios/ScanReceipts/Design/ZenithTypography.swift
Normal file
@@ -0,0 +1,93 @@
|
||||
import SwiftUI
|
||||
|
||||
/// The web app's three-font type system (see `DESIGN (1).md` → Typography,
|
||||
/// and `tailwind.config.ts`'s `fontFamily`), ported with the SAME font
|
||||
/// files: `Resources/Fonts/*.ttf` are the real Hanken Grotesk / Inter /
|
||||
/// JetBrains Mono variable fonts (downloaded from the canonical
|
||||
/// google/fonts repository — the same open-source files the web app loads
|
||||
/// from Google Fonts' CDN), registered via `UIAppFonts` in `project.yml`.
|
||||
///
|
||||
/// PostScript names below were read directly out of each font file's `name`
|
||||
/// table (not guessed) — see the font files themselves if these ever need
|
||||
/// re-verifying after a font update.
|
||||
///
|
||||
/// - Hanken Grotesk → headlines, set tight (negative tracking) at large
|
||||
/// sizes for the "locked, architectural" feel the design system asks for.
|
||||
/// - Inter → body copy.
|
||||
/// - JetBrains Mono → labels, captions, technical/numeric data. `labelCaps`
|
||||
/// is additionally uppercased with wide tracking — apply
|
||||
/// `.zenithLabelCapsStyle()`, not just the bare font, or the case/tracking
|
||||
/// won't happen (SwiftUI doesn't derive that from the font itself).
|
||||
enum ZenithFont {
|
||||
static let display = "HankenGrotesk-Regular"
|
||||
static let body = "Inter-Regular"
|
||||
static let mono = "JetBrainsMono-Regular"
|
||||
}
|
||||
|
||||
extension Font {
|
||||
/// Rarely needed on iPhone (72pt) — kept for completeness / a future
|
||||
/// iPad or marketing surface.
|
||||
static var zenithDisplayLg: Font { .custom(ZenithFont.display, size: 72).weight(.bold) }
|
||||
|
||||
/// Screen/section titles. Sized at the web system's "headline-lg-mobile"
|
||||
/// (32/40) rather than the 48pt desktop size, since this app is
|
||||
/// iPhone-only (see project.yml's TARGETED_DEVICE_FAMILY).
|
||||
static var zenithHeadlineLg: Font { .custom(ZenithFont.display, size: 32).weight(.semibold) }
|
||||
|
||||
/// Card/sub-section titles.
|
||||
static var zenithHeadlineMd: Font { .custom(ZenithFont.display, size: 24).weight(.medium) }
|
||||
|
||||
static var zenithBodyLg: Font { .custom(ZenithFont.body, size: 18) }
|
||||
/// Default body/UI text size.
|
||||
static var zenithBodyMd: Font { .custom(ZenithFont.body, size: 16) }
|
||||
static var zenithBodySm: Font { .custom(ZenithFont.body, size: 14) }
|
||||
|
||||
/// Field labels, eyebrows, section headers — use with
|
||||
/// `.zenithLabelCapsStyle()` for the uppercase + tracking, not bare.
|
||||
static var zenithLabelCaps: Font { .custom(ZenithFont.mono, size: 12).weight(.medium) }
|
||||
/// Chips, technical/tabular data (amounts, dates, IDs).
|
||||
static var zenithLabelMd: Font { .custom(ZenithFont.mono, size: 14) }
|
||||
static var zenithLabelSm: Font { .custom(ZenithFont.mono, size: 12) }
|
||||
}
|
||||
|
||||
/// Complete text styles (font + tracking + default color) for each type
|
||||
/// role. Tracking values are the design system's em values
|
||||
/// (`DESIGN (1).md` → Typography) converted to points AT EACH ROLE'S OWN
|
||||
/// size — `SwiftUI.tracking(_:)` takes absolute points, not em, so these
|
||||
/// can't be a single generic modifier parameterized only by a ratio.
|
||||
/// Prefer these over composing `.font(.zenith...)` by hand.
|
||||
extension View {
|
||||
/// Screen/section titles (32pt, -0.02em ⇒ -0.64pt tracking).
|
||||
func zenithHeadlineLgStyle(color: Color = .zenithText) -> some View {
|
||||
font(.zenithHeadlineLg).tracking(-0.64).foregroundStyle(color)
|
||||
}
|
||||
|
||||
/// Card/sub-section titles (24pt, -0.01em ⇒ -0.24pt tracking).
|
||||
func zenithHeadlineMdStyle(color: Color = .zenithText) -> some View {
|
||||
font(.zenithHeadlineMd).tracking(-0.24).foregroundStyle(color)
|
||||
}
|
||||
|
||||
/// Default body text (16pt, 0 tracking).
|
||||
func zenithBodyStyle(color: Color = .zenithText) -> some View {
|
||||
font(.zenithBodyMd).foregroundStyle(color)
|
||||
}
|
||||
|
||||
func zenithBodySmStyle(color: Color = .zenithMuted) -> some View {
|
||||
font(.zenithBodySm).foregroundStyle(color)
|
||||
}
|
||||
|
||||
/// `label-caps` role: JetBrains Mono, uppercase, wide tracking
|
||||
/// (12pt, 0.1em ⇒ 1.2pt). This is the style used above every
|
||||
/// `ZenithTextField` and for chip/badge/eyebrow text.
|
||||
func zenithLabelCapsStyle(color: Color = .zenithSubtle) -> some View {
|
||||
font(.zenithLabelCaps)
|
||||
.textCase(.uppercase)
|
||||
.tracking(1.2)
|
||||
.foregroundStyle(color)
|
||||
}
|
||||
|
||||
/// Technical/tabular data — amounts, dates, IDs (14pt, 0 tracking).
|
||||
func zenithLabelMdStyle(color: Color = .zenithText) -> some View {
|
||||
font(.zenithLabelMd).foregroundStyle(color)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user