b2970e4c-45a2-423e-b84d-257.../Sources/ui/Theme.swift
徐翔宇 e5a72bcf42 v0.2.0: initial 看盘侠 — Fund & Gold plugin for MioIsland
Real-time OTC fund and gold tracker for the macOS notch. Three tabs:
- 持仓: live intraday estimates from 天天基金, hero card with
  total value / today P&L / cumulative P&L, per-row 当日 + 累计.
- 黄金: SHFE 沪金 realtime + daily K-line + 伦敦金 reference.
- 添加: search 26k+ public funds via 东方财富 suggest API.

No API keys, no Python, no servers. All data comes from public
endpoints (天天基金, 东方财富, 新浪财经).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 20:20:15 +08:00

89 lines
3.2 KiB
Swift

//
// Theme.swift
// plugin v0.2
//
// Single source of truth for the design's colour tokens. Keeps the
// per-view code from re-deriving the same hex values.
//
import SwiftUI
enum FundTheme {
// Lime accent same value as the design's `#d4ff3a`.
static let lime = Color(red: 0xD4/255, green: 0xFF/255, blue: 0x3A/255)
// Gold accent for the gold hero card and chart.
static let gold = Color(red: 0xFF/255, green: 0xC4/255, blue: 0x54/255)
// China convention: red = up, green = down.
static let upRed = Color(red: 0xFF/255, green: 0x5E/255, blue: 0x5E/255)
static let downGreen = Color(red: 0x2C/255, green: 0xD4/255, blue: 0x7E/255)
// Panel background pure black with a hint of warmth.
static let panelBg = Color(red: 0x05/255, green: 0x05/255, blue: 0x05/255)
// Subtle white overlays used everywhere.
static let overlay04 = Color.white.opacity(0.04)
static let overlay06 = Color.white.opacity(0.06)
static let overlay08 = Color.white.opacity(0.08)
static let overlay12 = Color.white.opacity(0.12)
static let overlay18 = Color.white.opacity(0.18)
// Foreground tints
static let fgPrimary = Color(red: 0xF4/255, green: 0xF4/255, blue: 0xF5/255)
static let fg85 = Color.white.opacity(0.85)
static let fg70 = Color.white.opacity(0.7)
static let fg55 = Color.white.opacity(0.55)
static let fg45 = Color.white.opacity(0.45)
static let fg40 = Color.white.opacity(0.4)
static let fg35 = Color.white.opacity(0.35)
}
// MARK: - Color helper
extension Color {
/// Pick red/green based on a signed value. `0` returns a neutral white.
/// Chinese convention: positive = red, negative = green.
static func upDown(_ value: Double) -> Color {
if value > 0.0001 { return FundTheme.upRed }
if value < -0.0001 { return FundTheme.downGreen }
return FundTheme.fg70
}
}
// MARK: - Number formatting
enum FundFormat {
/// "+0.53%" / "-1.20%" / "0.00%"
static func percent(_ value: Double, decimals: Int = 2) -> String {
let sign = value > 0 ? "+" : ""
return "\(sign)\(String(format: "%.\(decimals)f", value))%"
}
/// "+1,234.56" / "-1,234.56" / "0.00"
static func money(_ value: Double, decimals: Int = 2) -> String {
let sign = value > 0 ? "+" : ""
let formatter = NumberFormatter()
formatter.numberStyle = .decimal
formatter.minimumFractionDigits = decimals
formatter.maximumFractionDigits = decimals
let abs = formatter.string(from: NSNumber(value: Swift.abs(value))) ?? "0"
if value < 0 { return "-\(abs)" }
return "\(sign)\(abs)"
}
/// "1,234.56" no sign, used for ""-like displays.
static func unsignedMoney(_ value: Double, decimals: Int = 2) -> String {
let formatter = NumberFormatter()
formatter.numberStyle = .decimal
formatter.minimumFractionDigits = decimals
formatter.maximumFractionDigits = decimals
return formatter.string(from: NSNumber(value: value)) ?? "0"
}
/// "1.7669" fixed decimals for NAV display.
static func nav(_ value: Double, decimals: Int = 4) -> String {
String(format: "%.\(decimals)f", value)
}
}