-
Notifications
You must be signed in to change notification settings - Fork 0
Design System
디자인 토큰, Typography, Glass Effect, 공용 컴포넌트, 렌더링 최적화. 토큰은
Core/DesignSystem(CoreDesignSystem), 컴포넌트는Core/UIComponents(CoreUIComponents)에 있습니다.
| 경로 | 내용 |
|---|---|
Colors/AppColor.swift · Color+Tokens.swift
|
컬러 토큰 (grey/indigo/orange/red/green/yellow 램프 + kakao/etc000) |
Layout/DefaultConstant.swift |
전역 레이아웃 상수 |
Layout/DefaultSpacing.swift |
4pt 기반 간격 스케일 |
Tokens/TypographyTokens.swift |
AppFont · AppFontWeight · .appFont()
|
Styles/ButtonStyles.swift |
Primary / Secondary / Destructive / Text 버튼 스타일 |
Modifiers/SymbolDrawOnModifier.swift |
SF Symbol draw-on 애니메이션 |
다크 모드: 앱은
UIUserInterfaceStyle = Light로 고정되어 있습니다. 컬러 자산에 다크 값이 남아 있지만 시안·시맨틱 별칭 토큰이 갖춰지기 전까지 프로덕션에서 쓰지 않습니다.
Asset 심볼 자동 생성 off: 자동 생성 extension은
internal접근이라 외부 모듈에서 못 씁니다.Color+Tokens.swift가public으로 직접 노출합니다.
| 상수 | 값 | 용도 |
|---|---|---|
defaultSafeHorizon |
16 | 좌우 기본 여백 |
defaultSafeTop |
20 | 상단 기본 여백 |
defaultSafeBottom |
56 | 하단 탭바 safe area |
defaultCornerRadius |
30 | 기본 모서리 반경 |
cornerRadius |
24 | 카드/아이콘 컨테이너 반경 |
concentricRadius |
40 |
ConcentricRectangle 최소 반경 (Edge.Corner.Style) |
minimumTouchTarget |
44 | 탭 가능 요소 최소 히트 영역 (HIG) |
iconSize / iconPadding
|
36 / 8 | 아이콘 컨테이너 |
defaultCapsuleSpacing |
28 | 캡슐형 요소 여백 |
defaultTextFieldPadding |
14 | 텍스트 필드 내부 패딩 |
defaultListPadding |
16 (all) | 리스트 행 인셋 |
defaultCardPadding |
24 / 16 | 카드 인셋 (수직/수평) |
animationTime / transitionScale
|
0.3s / 0.95 | 기본 전환 |
lineSpacing |
2.5 | 기본 줄 간격 |
간격은 DefaultSpacing.spacing4 ~ spacing384 (4·8·12·16·24·32·40·48·56·64·72·80·96·112·128·
144·160·192·208·224·240·256·288·320·384)를 사용합니다.
Pretendard 기반. .appFont(_:weight:color:) modifier는 줄간격까지 적용하고,
.font(.app(_:weight:))는 폰트만 적용합니다.
| Scale | Size | Line height | 용도 |
|---|---|---|---|
.largeTitle |
34 | 41.14 | 최상위 제목 |
.title1 |
28 | 33.88 | 주요 제목 |
.title2 |
22 | 27.94 | 섹션 제목 |
.title3 |
20 | 25.00 | 서브 섹션 |
.body |
17 | 23.46 | 본문 |
.callout |
16 | 20.96 | 카드 제목 |
.subheadline |
15 | 19.95 | 부제목 |
.footnote |
13 | 17.94 | 부가정보 |
.caption1 |
12 | 15.96 | 보조 레이블 |
.caption2 |
11 | 12.98 | 최소 텍스트 |
강조는 별도 스케일이 아니라 AppFontWeight 로 지정합니다.
| Weight | 폰트 |
|---|---|
.regular |
Pretendard-Regular |
.medium |
Pretendard-Medium |
.semibold |
Pretendard-SemiBold |
Text("공지사항")
.appFont(.title2, weight: .semibold, color: .grey900)각 스케일은 relativeTo: 로 시스템 TextStyle에 연결되어 있어 Dynamic Type을 따릅니다.
// ConcentricRectangle 사용 (디바이스별 일관성)
.clipShape(
ConcentricRectangle(
corners: .concentric(minimum: DefaultConstant.concentricRadius),
isUniform: true
)
)
.containerShape(.rect(corners: .concentric(minimum: DefaultConstant.concentricRadius)))| Variant | 용도 |
|---|---|
.regular |
일반 카드, 폼 |
.regular.interactive() |
탭 가능 요소 |
.clear |
미디어/색상 배경 위 |
.glassProminent (ButtonStyle) |
Primary 버튼 |
.glass (ButtonStyle) |
Secondary 버튼 |
프로젝트 자체 버튼 스타일도 있습니다: .primary · .secondary · .destructive · .text
(ButtonStyles.swift, 기본 높이 44 / 반경 8).
| 그룹 | 컴포넌트 |
|---|---|
| 입력 |
ArticleTextField(.title / .content), KeyboardToolbarModifier
|
| 버튼 |
MainButton(+Size/Environment/Modifiers), ChipButton(+Size/Style/Environment) |
| 뱃지 |
InfoBadge, AttendanceStatusBadge(AttendanceBadgeStatus) |
| 인증 |
LoginActionStack, SocialLoginLabel, AuthLogoBlock, LoginMethod
|
| 상태 |
LoadingView, RetryContentUnavailableView, Progress(+Size) |
| 섹션 |
SectionHeaderView, SectionRightImage
|
| 지도/장소 |
PlaceSelectView, MapPlacePickerView, MapPickerLocationProvider, POILongPressTip(TipKit) |
| 일정 |
DatePickerRow, TimePickerRow, DateTimeRow, InPersonToggle, AttendancePolicyTimeSection
|
| 이미지 |
RemoteImage(Kingfisher), CardIconImage, Image+*Assets 확장 |
| 레이아웃/효과 |
FlowLayout, CapsuleModifier, DefaultBackgroundModifier, RainbowBorderModifier, ShadowReuse, ChromaticLens / RefractiveCinematic
|
| 네비게이션 |
NavigationModifier, NavigationTitle, ToolBarCollection
|
-
GlassEffectContainer로 그룹화 필수 (오프스크린 렌더링 약 66% 감소) -
glassEffectID는 모핑 애니메이션 필요 시에만 사용 (CPU 부하) - 적용 불가: List, Table, 미디어 콘텐츠
- Container-Presenter 패턴: Container(상태/로직) + Presenter(UI + Equatable)
- 클로저는 Equatable 비교에서 제외
struct CardPresenter: View, Equatable {
let id: UUID
let name: String
var onTap: () -> Void
static func == (lhs: Self, rhs: Self) -> Bool {
lhs.id == rhs.id && lhs.name == rhs.name
}
}- List 우선 사용 (LazyVStack보다 뷰 재사용 효율적)
- ForEach 내 조건부 뷰 금지 (lazy loading 깨짐)
- List에서
.id()모디파이어 사용 금지
관련 문서: Architecture · Coding Conventions