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
co-authored by Cursor
parent 39186cfe25
commit 87696a4774
31 changed files with 737 additions and 213 deletions
+49 -8
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
}
+54
View File
@@ -0,0 +1,54 @@
//
// AppFont.swift
// suixinkan
//
import UIKit
/// 应用字体层级,基于 8pt 网格与 SF Pro(System)。
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
}
}
@@ -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
}
}
+20
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
/// 周期筛选 pill(Statistics)。
static let pill: CGFloat = 18
}
+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
}
}
+33
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
}