134 lines
4.9 KiB
Swift
134 lines
4.9 KiB
Swift
import SwiftUI
|
|
|
|
enum HermesTheme {
|
|
static let background = Color(red: 0.04, green: 0.05, blue: 0.08)
|
|
static let surface = Color(red: 0.11, green: 0.12, blue: 0.16)
|
|
static let surfaceElevated = Color(red: 0.16, green: 0.17, blue: 0.22)
|
|
static let accent = Color(red: 0.88, green: 0.75, blue: 0.36)
|
|
static let accentSoft = Color(red: 0.88, green: 0.75, blue: 0.36).opacity(0.16)
|
|
static let positive = Color(red: 0.34, green: 0.78, blue: 0.52)
|
|
static let warning = Color(red: 0.95, green: 0.70, blue: 0.30)
|
|
static let textPrimary = Color.white
|
|
static let textSecondary = Color.white.opacity(0.72)
|
|
static let textTertiary = Color.white.opacity(0.48)
|
|
static let cornerRadius: CGFloat = 24
|
|
static let insetRadius: CGFloat = 18
|
|
static let screenPadding: CGFloat = 20
|
|
static let sectionSpacing: CGFloat = 16
|
|
static let contentPadding: CGFloat = 20
|
|
}
|
|
|
|
struct HermesCardModifier: ViewModifier {
|
|
var elevated: Bool = false
|
|
|
|
func body(content: Content) -> some View {
|
|
content
|
|
.padding(HermesTheme.contentPadding)
|
|
.background(
|
|
RoundedRectangle(cornerRadius: HermesTheme.cornerRadius, style: .continuous)
|
|
.fill(elevated ? HermesTheme.surfaceElevated : HermesTheme.surface)
|
|
)
|
|
.overlay(
|
|
RoundedRectangle(cornerRadius: HermesTheme.cornerRadius, style: .continuous)
|
|
.stroke(HermesTheme.accent.opacity(elevated ? 0.22 : 0.08), lineWidth: 1)
|
|
)
|
|
.shadow(color: .black.opacity(elevated ? 0.34 : 0.22), radius: elevated ? 24 : 12, x: 0, y: elevated ? 12 : 6)
|
|
}
|
|
}
|
|
|
|
extension View {
|
|
func hermesCard(elevated: Bool = false) -> some View {
|
|
modifier(HermesCardModifier(elevated: elevated))
|
|
}
|
|
}
|
|
|
|
struct HermesPrimaryButtonStyle: ButtonStyle {
|
|
func makeBody(configuration: Configuration) -> some View {
|
|
configuration.label
|
|
.font(.headline.weight(.semibold))
|
|
.foregroundStyle(HermesTheme.background)
|
|
.frame(maxWidth: .infinity, minHeight: 52)
|
|
.padding(.horizontal, 18)
|
|
.background(HermesTheme.accent)
|
|
.clipShape(RoundedRectangle(cornerRadius: 16, style: .continuous))
|
|
.opacity(configuration.isPressed ? 0.88 : 1)
|
|
.scaleEffect(configuration.isPressed ? 0.98 : 1)
|
|
}
|
|
}
|
|
|
|
struct HermesSecondaryButtonStyle: ButtonStyle {
|
|
func makeBody(configuration: Configuration) -> some View {
|
|
configuration.label
|
|
.font(.headline.weight(.semibold))
|
|
.foregroundStyle(HermesTheme.textPrimary)
|
|
.frame(maxWidth: .infinity, minHeight: 52)
|
|
.padding(.horizontal, 18)
|
|
.background(HermesTheme.surfaceElevated)
|
|
.overlay(
|
|
RoundedRectangle(cornerRadius: 16, style: .continuous)
|
|
.stroke(HermesTheme.accent.opacity(0.18), lineWidth: 1)
|
|
)
|
|
.clipShape(RoundedRectangle(cornerRadius: 16, style: .continuous))
|
|
.opacity(configuration.isPressed ? 0.88 : 1)
|
|
.scaleEffect(configuration.isPressed ? 0.98 : 1)
|
|
}
|
|
}
|
|
|
|
struct HermesSectionHeader: View {
|
|
let title: String
|
|
let subtitle: String
|
|
|
|
var body: some View {
|
|
VStack(alignment: .leading, spacing: 8) {
|
|
Text(title)
|
|
.font(.title2.weight(.bold))
|
|
.foregroundStyle(HermesTheme.textPrimary)
|
|
Text(subtitle)
|
|
.font(.callout)
|
|
.foregroundStyle(HermesTheme.textSecondary)
|
|
.fixedSize(horizontal: false, vertical: true)
|
|
}
|
|
}
|
|
}
|
|
|
|
struct HermesMetricPill: View {
|
|
let label: String
|
|
let value: String
|
|
|
|
var body: some View {
|
|
VStack(alignment: .leading, spacing: 2) {
|
|
Text(label)
|
|
.font(.caption.weight(.semibold))
|
|
.foregroundStyle(HermesTheme.textTertiary)
|
|
Text(value)
|
|
.font(.headline.weight(.semibold))
|
|
.foregroundStyle(HermesTheme.textPrimary)
|
|
}
|
|
.frame(maxWidth: .infinity, alignment: .leading)
|
|
.padding(.horizontal, 14)
|
|
.padding(.vertical, 12)
|
|
.background(HermesTheme.surfaceElevated)
|
|
.clipShape(RoundedRectangle(cornerRadius: HermesTheme.insetRadius, style: .continuous))
|
|
}
|
|
}
|
|
|
|
struct HermesCountdownBadge: View {
|
|
let label: String
|
|
let value: String
|
|
|
|
var body: some View {
|
|
VStack(alignment: .leading, spacing: 4) {
|
|
Text(label)
|
|
.font(.caption.weight(.semibold))
|
|
.foregroundStyle(HermesTheme.textTertiary)
|
|
Text(value)
|
|
.font(.title3.weight(.bold))
|
|
.foregroundStyle(HermesTheme.accent)
|
|
}
|
|
.padding(.horizontal, 14)
|
|
.padding(.vertical, 12)
|
|
.background(HermesTheme.accentSoft)
|
|
.clipShape(RoundedRectangle(cornerRadius: HermesTheme.insetRadius, style: .continuous))
|
|
}
|
|
}
|