Skip to content

Design System

JEONG edited this page Aug 24, 2026 · 2 revisions

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.swiftpublic으로 직접 노출합니다.

레이아웃 상수 (DefaultConstant)

상수 용도
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)를 사용합니다.

Typography (AppFont)

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을 따릅니다.

Shape 패턴 (권장)

// ConcentricRectangle 사용 (디바이스별 일관성)
.clipShape(
    ConcentricRectangle(
        corners: .concentric(minimum: DefaultConstant.concentricRadius),
        isUniform: true
    )
)
.containerShape(.rect(corners: .concentric(minimum: DefaultConstant.concentricRadius)))

Glass Effect 선택

Variant 용도
.regular 일반 카드, 폼
.regular.interactive() 탭 가능 요소
.clear 미디어/색상 배경 위
.glassProminent (ButtonStyle) Primary 버튼
.glass (ButtonStyle) Secondary 버튼

프로젝트 자체 버튼 스타일도 있습니다: .primary · .secondary · .destructive · .text (ButtonStyles.swift, 기본 높이 44 / 반경 8).

공용 UI 컴포넌트 (CoreUIComponents)

그룹 컴포넌트
입력 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

성능 최적화

Liquid Glass (iOS 26)

  • GlassEffectContainer로 그룹화 필수 (오프스크린 렌더링 약 66% 감소)
  • glassEffectID는 모핑 애니메이션 필요 시에만 사용 (CPU 부하)
  • 적용 불가: List, Table, 미디어 콘텐츠

View 렌더링

  • 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 / ForEach

  • List 우선 사용 (LazyVStack보다 뷰 재사용 효율적)
  • ForEach 내 조건부 뷰 금지 (lazy loading 깨짐)
  • List에서 .id() 모디파이어 사용 금지

관련 문서: Architecture · Coding Conventions

Clone this wiki locally