Introduce unified design tokens and migrate Home, Orders, and Statistics UI.

Establish AppColor/AppFont/AppSpacing/AppRadius theming, shared components, and design-system docs so pilot screens align with Android while keeping iOS-native spacing and touch targets.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-07-06 17:58:18 +08:00
parent 39186cfe25
commit 87696a4774
31 changed files with 737 additions and 213 deletions

View File

@ -5,15 +5,56 @@
import UIKit
/// Android `theme/Color.kt`
/// Android `theme/Color.kt` `ScenicQueueTokens`
enum AppColor {
static let primary = UIColor(red: 0 / 255, green: 115 / 255, blue: 255 / 255, alpha: 1)
static let text333 = UIColor(red: 51 / 255, green: 51 / 255, blue: 51 / 255, alpha: 1)
static let text666 = UIColor(red: 102 / 255, green: 102 / 255, blue: 102 / 255, alpha: 1)
static let agreementLink = UIColor(red: 32 / 255, green: 139 / 255, blue: 255 / 255, alpha: 1)
static let inputBackground = UIColor(red: 244 / 255, green: 244 / 255, blue: 244 / 255, alpha: 1)
static let secondaryButtonBackground = UIColor(red: 239 / 255, green: 246 / 255, blue: 255 / 255, alpha: 1)
static let buttonDisabled = UIColor(red: 192 / 255, green: 192 / 255, blue: 192 / 255, alpha: 1)
// MARK: - Brand
static let primary = UIColor(hex: 0x0073FF)
static let primaryBanner = UIColor(hex: 0x1677FF)
static let primaryLight = UIColor(hex: 0xEFF6FF)
// MARK: - Background
static let pageBackground = UIColor(hex: 0xF5F5F5)
static let pageBackgroundSoft = UIColor(hex: 0xF7FAFF)
static let cardBackground = UIColor.white
static let inputBackground = UIColor(hex: 0xF4F4F4)
// MARK: - Border
static let border = UIColor(hex: 0xEEEEEE)
static let cardOutline = UIColor(hex: 0xE9ECEF)
// MARK: - Text
static let textPrimary = UIColor(hex: 0x333333)
static let textSecondary = UIColor(hex: 0x666666)
static let textTertiary = UIColor(hex: 0x999999)
static let textTabInactive = UIColor(hex: 0x7D8DA3)
// MARK: - Semantic
static let success = UIColor(hex: 0x10B981)
static let successBackground = UIColor(hex: 0xF0FDF4)
static let warning = UIColor(hex: 0xFF7B00)
static let warningBackground = UIColor(hex: 0xFFF0E2)
static let danger = UIColor(hex: 0xEF4444)
static let dangerBackground = UIColor(hex: 0xFFE7E7)
static let info = UIColor(hex: 0x0073FF)
static let infoBackground = UIColor(hex: 0xE8F4FF)
static let online = UIColor(hex: 0x22C55E)
// MARK: - Overlay
static let overlayScrim = UIColor.black.withAlphaComponent(0.2)
// MARK: - Legacy aliases
static let text333 = textPrimary
static let text666 = textSecondary
static let agreementLink = UIColor(hex: 0x208BFF)
static let secondaryButtonBackground = primaryLight
static let buttonDisabled = UIColor(hex: 0xC0C0C0)
static let placeholder = UIColor.gray
}

View File

@ -0,0 +1,54 @@
//
// AppFont.swift
// suixinkan
//
import UIKit
/// 8pt SF ProSystem
enum AppFont {
case caption
case captionMedium
case body
case bodyMedium
case subtitle
case title
case metric
case display
/// UIFont
var uiFont: UIFont {
switch self {
case .caption:
return .systemFont(ofSize: 12, weight: .regular)
case .captionMedium:
return .systemFont(ofSize: 12, weight: .medium)
case .body:
return .systemFont(ofSize: 14, weight: .regular)
case .bodyMedium:
return .systemFont(ofSize: 14, weight: .medium)
case .subtitle:
return .systemFont(ofSize: 16, weight: .medium)
case .title:
return .systemFont(ofSize: 16, weight: .bold)
case .metric:
return .systemFont(ofSize: 18, weight: .bold)
case .display:
return .systemFont(ofSize: 28, weight: .semibold)
}
}
/// UILabel
func apply(to label: UILabel) {
label.font = uiFont
}
}
extension UIFont {
/// `AppFont`
static func app(_ style: AppFont) -> UIFont {
style.uiFont
}
}

View File

@ -0,0 +1,28 @@
//
// AppNavigationBarAppearance.swift
// suixinkan
//
import UIKit
/// UINavigationBar
enum AppNavigationBarAppearance {
/// shadow
static func applyGlobalAppearance() {
let appearance = UINavigationBarAppearance()
appearance.configureWithOpaqueBackground()
appearance.backgroundColor = AppColor.cardBackground
appearance.shadowColor = .clear
appearance.titleTextAttributes = [
.foregroundColor: AppColor.textPrimary,
.font: UIFont.app(.title),
]
let navigationBar = UINavigationBar.appearance()
navigationBar.standardAppearance = appearance
navigationBar.scrollEdgeAppearance = appearance
navigationBar.compactAppearance = appearance
navigationBar.tintColor = AppColor.primary
}
}

View File

@ -0,0 +1,20 @@
//
// AppRadius.swift
// suixinkan
//
import CoreGraphics
/// Android ScenicQueueTokens
enum AppRadius {
static let xs: CGFloat = 4
static let sm: CGFloat = 8
static let md: CGFloat = 10
static let lg: CGFloat = 12
static let xl: CGFloat = 16
static let sheetTop: CGFloat = 14
/// pillStatistics
static let pill: CGFloat = 18
}

View File

@ -0,0 +1,18 @@
//
// AppShadow.swift
// suixinkan
//
import UIKit
///
enum AppShadow {
/// layer
static func applyCardShadow(to layer: CALayer) {
layer.shadowColor = UIColor.black.cgColor
layer.shadowOpacity = 0.08
layer.shadowOffset = CGSize(width: 0, height: 4)
layer.shadowRadius = 12
}
}

View File

@ -0,0 +1,33 @@
//
// AppSpacing.swift
// suixinkan
//
import CoreGraphics
/// 8pt
enum AppSpacing {
static let xxs: CGFloat = 4
static let xs: CGFloat = 8
static let sm: CGFloat = 12
static let md: CGFloat = 16
static let lg: CGFloat = 24
static let xl: CGFloat = 32
static let xxl: CGFloat = 48
///
static let screenHorizontalInset: CGFloat = md
/// Apple HIG
static let minTouchTarget: CGFloat = 44
/// Header
static let homeHeaderHeight: CGFloat = 52
///
static let buttonHeight: CGFloat = 46
///
static let formRowHeight: CGFloat = 52
}