Initial commit: KisaniCal iOS app
Task management, Eisenhower matrix, workout logging with persistence, and calendar with 6 view modes (Month, List, Year, Week, 3 Day, Day). Custom floating tab bar, dynamic calendar icon, and workout data seeded.
This commit is contained in:
123
KisaniCal/Theme/DesignTokens.swift
Normal file
123
KisaniCal/Theme/DesignTokens.swift
Normal file
@@ -0,0 +1,123 @@
|
||||
import SwiftUI
|
||||
|
||||
// MARK: - Accent & Semantic Colors
|
||||
struct AppColors {
|
||||
|
||||
// Fixed accent palette
|
||||
static let accent = Color(r: 232, g: 98, b: 42)
|
||||
static let green = Color(r: 62, g: 207, b: 142)
|
||||
static let blue = Color(r: 77, g: 157, b: 224)
|
||||
static let yellow = Color(r: 232, g: 184, b: 42)
|
||||
static let red = Color(r: 232, g: 66, b: 66)
|
||||
|
||||
static let accentSoft = Color(UIColor { $0.userInterfaceStyle == .dark
|
||||
? UIColor(r: 52, g: 28, b: 14) // dark: deep warm orange
|
||||
: UIColor(r: 252, g: 238, b: 228) })// light: warm peach wash
|
||||
static let accentGhost = accent.opacity(0.05)
|
||||
static let greenSoft = Color(UIColor { $0.userInterfaceStyle == .dark
|
||||
? UIColor(r: 14, g: 40, b: 28)
|
||||
: UIColor(r: 220, g: 248, b: 236) })
|
||||
static let blueSoft = Color(UIColor { $0.userInterfaceStyle == .dark
|
||||
? UIColor(r: 14, g: 30, b: 50)
|
||||
: UIColor(r: 222, g: 237, b: 252) })
|
||||
static let yellowSoft = Color(UIColor { $0.userInterfaceStyle == .dark
|
||||
? UIColor(r: 44, g: 34, b: 10)
|
||||
: UIColor(r: 252, g: 243, b: 215) })
|
||||
static let redSoft = Color(UIColor { $0.userInterfaceStyle == .dark
|
||||
? UIColor(r: 50, g: 14, b: 14)
|
||||
: UIColor(r: 252, g: 224, b: 224) })
|
||||
|
||||
// Adaptive surfaces
|
||||
static func background(_ cs: ColorScheme) -> Color {
|
||||
cs == .dark ? Color(r: 9, g: 9, b: 9)
|
||||
: Color(r: 245, g: 243, b: 240)
|
||||
}
|
||||
static func surface(_ cs: ColorScheme) -> Color {
|
||||
cs == .dark ? Color(r: 19, g: 19, b: 19)
|
||||
: Color(r: 255, g: 253, b: 250) // warm white, not clinical pure white
|
||||
}
|
||||
static func surface2(_ cs: ColorScheme) -> Color {
|
||||
cs == .dark ? Color(r: 26, g: 26, b: 26)
|
||||
: Color(r: 240, g: 237, b: 232)
|
||||
}
|
||||
static func surface3(_ cs: ColorScheme) -> Color {
|
||||
cs == .dark ? Color(r: 34, g: 34, b: 34)
|
||||
: Color(r: 232, g: 228, b: 222)
|
||||
}
|
||||
static func text(_ cs: ColorScheme) -> Color {
|
||||
cs == .dark ? Color(r: 240, g: 237, b: 232)
|
||||
: Color(r: 26, g: 23, b: 20)
|
||||
}
|
||||
static func text2(_ cs: ColorScheme) -> Color {
|
||||
text(cs).opacity(cs == .dark ? 0.44 : 0.50)
|
||||
}
|
||||
static func text3(_ cs: ColorScheme) -> Color {
|
||||
text(cs).opacity(cs == .dark ? 0.24 : 0.34)
|
||||
}
|
||||
static func border(_ cs: ColorScheme) -> Color {
|
||||
cs == .dark ? Color.white.opacity(0.07)
|
||||
: Color.black.opacity(0.09)
|
||||
}
|
||||
static func borderHi(_ cs: ColorScheme) -> Color {
|
||||
cs == .dark ? Color.white.opacity(0.13)
|
||||
: Color.black.opacity(0.17)
|
||||
}
|
||||
static func phoneSheetBg(_ cs: ColorScheme) -> Color {
|
||||
cs == .dark ? Color(r: 18, g: 18, b: 18)
|
||||
: Color.white
|
||||
}
|
||||
}
|
||||
|
||||
private extension Color {
|
||||
init(r: Double, g: Double, b: Double) {
|
||||
self.init(.sRGB, red: r / 255, green: g / 255, blue: b / 255)
|
||||
}
|
||||
}
|
||||
|
||||
private extension UIColor {
|
||||
convenience init(r: Int, g: Int, b: Int) {
|
||||
self.init(red: CGFloat(r) / 255, green: CGFloat(g) / 255, blue: CGFloat(b) / 255, alpha: 1)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Typography
|
||||
struct AppFonts {
|
||||
static func sans(_ size: CGFloat, weight: Font.Weight = .regular) -> Font {
|
||||
.system(size: size, weight: weight, design: .default)
|
||||
}
|
||||
static func mono(_ size: CGFloat, weight: Font.Weight = .regular) -> Font {
|
||||
.system(size: size, weight: weight, design: .monospaced)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Motion Tokens
|
||||
enum KisaniSpring {
|
||||
/// General entrance — slight overshoot, feels alive (≈ 320ms settle)
|
||||
static let entrance = Animation.spring(response: 0.38, dampingFraction: 0.72)
|
||||
/// Exit — snappier, ~20% shorter settle than entrance
|
||||
static let exit = Animation.spring(response: 0.28, dampingFraction: 0.88)
|
||||
/// Micro-interactions — button presses, toggles, chips (< 150ms feel)
|
||||
static let micro = Animation.spring(response: 0.22, dampingFraction: 0.70)
|
||||
/// Snappy — section expands, panel slides (≈ 250ms settle)
|
||||
static let snappy = Animation.spring(response: 0.32, dampingFraction: 0.78)
|
||||
/// Bouncy — checkmarks, completion states — noticeable overshoot
|
||||
static let bounce = Animation.spring(response: 0.28, dampingFraction: 0.52)
|
||||
}
|
||||
|
||||
// MARK: - Corner Radii
|
||||
enum AppRadius {
|
||||
static let large: CGFloat = 16
|
||||
static let medium: CGFloat = 13
|
||||
static let small: CGFloat = 10
|
||||
static let pill: CGFloat = 20
|
||||
}
|
||||
|
||||
// MARK: - Icon color helpers
|
||||
extension Int {
|
||||
var iconColor: Color {
|
||||
[AppColors.accent, AppColors.blue, AppColors.green, AppColors.yellow][self % 4]
|
||||
}
|
||||
var iconBg: Color {
|
||||
[AppColors.accentSoft, AppColors.blueSoft, AppColors.greenSoft, AppColors.yellowSoft][self % 4]
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user