Files
hermes/mobile/ios-app/Core/DesignSystem/Theme.swift
T
2026-04-09 15:51:03 +02:00

135 lines
5.0 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 warning: Bool = false
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(warning ? HermesTheme.warning : HermesTheme.accent)
}
.padding(.horizontal, 14)
.padding(.vertical, 12)
.background((warning ? HermesTheme.warning : HermesTheme.accent).opacity(0.16))
.clipShape(RoundedRectangle(cornerRadius: HermesTheme.insetRadius, style: .continuous))
}
}