CLAUDE.md v2.0 — 기획서(v1.0)를 폐기하고 실제 구현 기준의 현행 명세로 전면 재작성: 프로젝트 구조·빌드/검증 루틴·도메인 모델(CloudKit 규칙)·집계/판정 규칙·데이터 계층 (LocalPrefs/DataChange)·화면별 상세·내보내기·프리미엄/StoreKit·위젯 6종·워치·시리· DEBUG 런치 인자·작업 컨벤션까지 새 세션이 이 문서만으로 파악 가능하게 정리. 동작 보존 범위의 안전 수정 3건: - Color.hexString: 와이드 컬러(P3) 성분을 0...1로 클램프 — 음수/1 초과 값이 %02X를 거치며 자릿수 깨진 hex가 태그·목표 색으로 저장되던 잠재 버그 방지 - 일기 타임테이블 필터: 선택 즉시 명시적 save — 캘린더 일정 선택 경로와 동일하게 영속을 보장 (autosave 의존 제거) - 통계 평균 "%.1f회"가 String(format:)이라 영어·일본어에서도 '회'로 노출되던 것을 Format.countAverage로 지역화 (en "times" / ja "回", 카탈로그 동기화 포함) Debug·Store(Release) 스킴 빌드 검증 완료. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013yKDMhuF39GVYy3FMcGHh7
61 lines
2.3 KiB
Swift
61 lines
2.3 KiB
Swift
//
|
|
// Theme.swift
|
|
// Haru_Danim
|
|
//
|
|
// 컬러 팔레트 (CLAUDE.md §5.2)
|
|
//
|
|
|
|
import SwiftUI
|
|
import UIKit
|
|
|
|
extension Color {
|
|
/// "#RRGGBB" 형식의 hex 문자열로 생성
|
|
init(hex: String) {
|
|
let cleaned = hex.trimmingCharacters(in: CharacterSet.alphanumerics.inverted)
|
|
var value: UInt64 = 0
|
|
Scanner(string: cleaned).scanHexInt64(&value)
|
|
let r = Double((value >> 16) & 0xFF) / 255
|
|
let g = Double((value >> 8) & 0xFF) / 255
|
|
let b = Double(value & 0xFF) / 255
|
|
self.init(red: r, green: g, blue: b)
|
|
}
|
|
|
|
/// 라이트/다크 모드에 따라 달라지는 동적 색
|
|
init(light: Color, dark: Color) {
|
|
self.init(uiColor: UIColor { traits in
|
|
traits.userInterfaceStyle == .dark ? UIColor(dark) : UIColor(light)
|
|
})
|
|
}
|
|
|
|
/// "#RRGGBB" hex 문자열로 변환.
|
|
/// 와이드 컬러(P3)에서 getRed 성분이 0...1 밖으로 나올 수 있어 클램프한다 —
|
|
/// 음수/1 초과 값이 %02X 포맷을 거치면 자릿수가 깨진 hex("#FFFFFFE6…")가 저장된다.
|
|
var hexString: String {
|
|
let ui = UIColor(self)
|
|
var r: CGFloat = 0, g: CGFloat = 0, b: CGFloat = 0, a: CGFloat = 0
|
|
ui.getRed(&r, green: &g, blue: &b, alpha: &a)
|
|
func component(_ value: CGFloat) -> Int {
|
|
Int(round(min(max(value, 0), 1) * 255))
|
|
}
|
|
return String(format: "#%02X%02X%02X", component(r), component(g), component(b))
|
|
}
|
|
}
|
|
|
|
enum AppTheme {
|
|
/// Primary Green: 라이트 딥 모스 그린 / 다크 세이지 민트
|
|
static let green = Color(light: Color(hex: "#2F6B4F"), dark: Color(hex: "#7FBF9E"))
|
|
/// Accent Yellow: 라이트 머스터드 골드 / 다크 소프트 앰버
|
|
static let yellow = Color(light: Color(hex: "#D9A621"), dark: Color(hex: "#E8C558"))
|
|
/// Background: 라이트 웜 화이트 / 다크 그린 틴트 블랙
|
|
static let background = Color(light: Color(hex: "#FAFAF6"), dark: Color(hex: "#111512"))
|
|
/// 카드 등 한 단계 떠 있는 표면
|
|
static let surface = Color(light: .white, dark: Color(hex: "#1B211D"))
|
|
|
|
/// 꼬리표 색 프리셋 (라이트/다크 공용으로 무난한 톤)
|
|
static let tagPresets: [String] = [
|
|
"#2F6B4F", "#D9A621", "#4A7A9D", "#9D5B4A",
|
|
"#7A5C9D", "#4F8A8B", "#C06C84", "#6B705C",
|
|
"#B5651D", "#3D5A80", "#8D6B94", "#588157",
|
|
]
|
|
}
|