# Ditto 상단 바 · 바텀시트 디자인 시스템 1.1

2026-10-02 · 첨부 7개 사례 + 현재 로컬 SwiftUI 앱 구조를 기준으로 정리. 스크린샷은 시각 참고이며 원본 pt 측정값이 아니다. 아래 값은 기존 DDS 토큰을 바탕으로 확립한 규격이다.

[유형별 시각 가이드](../design/site/navigation-sheets.html) · 정본: `design/tokens/tokens.json → component.navigationChrome`.

## 핵심 결정

상단 바는 **버튼 수 → 버튼 위치 → 중앙 콘텐츠** 순서로 선택한다. 이동·편집 같은 화면 역할은 별도 모양이 아니라 사용 규칙이다. 사용자 요청에 따라 기존 Root/Detail/Editor 분류를 이 구조로 대체한다. 시트는 작업 성격과 종료 방식으로 구분한다.

검토 범위는 로컬 앱 코드, 첨부 사례, 피그마 페이지 목록과 관련 화면 일부다. 피그마 전 페이지·전 화면 시각 감사 완료를 의미하지 않는다.

상태바는 OS 소유이며 56pt 상단 바에 포함하지 않는다. 바텀시트에 가짜 상태바나 별도 GNB를 중복 배치하지 않는다. 뒤로는 이전 단계, 닫기는 현재 모달 종료, 취소는 미저장 작업 폐기 절차다.

## 현재 구조에서 확인한 원인

- `DSNavBar`: 56pt지만 뒤로가기 터치 영역이 40pt이고 제목이 버튼과 겹칠 수 있는 ZStack 구조.
- `FriendsTab.navBar`: 45pt, 36pt 버튼, 별도 로고 overlay. 보관함은 다시 56pt.
- `AddSheet`: 52pt 헤더, `InviteSheet`: 50pt 헤더. 둘 다 30pt 닫기 버튼.
- `ProfileEditSheet`: 모달 종료를 뒤로가기 화살표로 표시. 그래버는 있지만 드래그 동작은 없음. 스크린샷과 달리 현재 코드의 완료는 하단 CTA.
- `UnfriendSheet`: 독립 19pt 제목과 회색 본문 배경이 공통 시트의 흰색 표면을 덮음.
- `BottomSheet`, 전용 VStack 모달, 시스템 `.sheet`가 공존한다. 단일 외형 강제 대신 같은 헤더·토큰·종료 계약을 공유한다.
- 현재 `HomeTab`은 별도 로고 GNB 없이 대표/라이프 탭으로 시작한다. 첨부 홈 로고형 GNB는 유효한 구성 규격으로 남기되 임의로 새 탐색 액션을 추가하지 않는다.

## 상단 바: 버튼 수 3단계 · 배치 4유형

| 버튼 수 | 유형 | 좌측 | 중앙 | 우측 |
|---|---|---|---|---|
| 0 | N0 · None | 비움 | 제목 / 로고 | 비움 |
| 1 | N1-L · Leading | 버튼 1개 | 제목 / 로고 | 비움 |
| 1 | N1-R · Trailing | 비움 | 제목 / 로고 | 버튼 1개 |
| 2 | N2 · Both | 버튼 1개 | 제목 / 로고 | 버튼 1개 |

### 사용 예시

- **N0:** 보관함처럼 헤더에서 수행할 액션이 없는 화면. 현재 보관함에 적용.
- **N1-L:** 설정의 뒤로가기, 하단 완료가 있는 편집 화면의 취소. 온보딩의 로고 + 뒤로도 같은 구조.
- **N1-R:** 시트의 제목 + 닫기, 최상위의 로고 + 알림. 현재 친구 화면의 왼쪽 오브제는 장식이므로 버튼은 오른쪽 1개다.
- **N2:** 상세의 뒤로 + 더보기, 편집의 취소 + 완료, 홈의 초대 + 알림. 세 경우 모두 같은 구조이고 액션 종류만 다르다.

### 조합 규칙

1. 버튼 수는 **실제로 누를 수 있는 컨트롤**만 센다. 제목·로고·배지·그래버·장식은 제외한다. 비활성 버튼은 자리를 유지하므로 개수에 포함한다.
2. 중앙 콘텐츠는 Title 또는 Logo. 독립 속성이므로 로고 전용 상단 바를 따로 만들지 않는다. 로고 자체에는 액션을 추가하지 않는다.
3. 좌측에는 이전 단계/취소, 우측에는 닫기/저장/맥락 액션을 둔다. 최상위의 좌측 초대 등은 허용하되 아이콘 이름과 결과를 명확히 한다.
4. 종료 액션 중복 금지: 취소 + 닫기, 뒤로 + 닫기를 기본 조합으로 제공하지 않는다. 편집 하위 단계에서는 뒤로와 저장 여부를 흐름에 맞춰 별도로 검토한다.
5. 저장은 상단 완료 또는 하단 완료 중 **한 곳**에만 둔다. 하단 CTA를 추가하면 헤더는 N2 → N1-L로 바뀐다.
6. 기본형은 한쪽 최대 1개, 전체 최대 2개 버튼. 우측 2개 몰아두기와 3개 이상은 기본형에서 제외한다. 추가 액션은 더보기 메뉴로 묶는다.
7. 버튼 유무와 관계없이 양쪽 64pt 슬롯을 유지한다. 빈 슬롯은 터치/접근성 대상이 아니며 가짜 비활성 버튼으로 채우지 않는다.
8. 버튼 상태는 기본/비활성/실행 중. 실행 중에는 위치와 폭을 유지하고 중복 실행을 막는다. 앱 저장 처리와 연결된 로딩 상태는 별도 검증 대상.

### 컴포넌트와 피그마 속성 계약

- 네이티브: `DDSTopBar(leadingAction:trailingAction:center:)`. 선택된 액션으로 `DDSChromeArrangement`와 버튼 수를 자동 계산한다. 기본형과 실제 버튼 수가 다르게 저장되지 않는다.
- 기존 `DSNavBar`는 N1-L / N2, `DSSheetHeader`는 N1-R의 호환 래퍼다. 장식이 있는 기존 친구 화면은 낮은 수준의 `DDSChromeBar`를 사용한다.
- 피그마 예정 구성: `Ditto/Navigation/TopBar`의 `Arrangement=None|Leading|Trailing|Both` 4개 변형. `Center=Title|Logo`는 중앙 하위 컴포넌트의 교체 속성, `Title`은 텍스트 속성. 좌/우 Action은 교체 속성으로 두고 아이콘 종류별 변형을 늘리지 않는다.
- 아이콘/텍스트/닫기 표면과 기본/비활성 상태는 Action 하위 컴포넌트가 소유한다. 표준 icon 20pt, close glyph 16pt, close surface 32pt, touch 44pt.
- 위 속성 계약은 로컬 DS에 반영했다. 피그마 실제 컴포넌트 생성·수정은 아직 미적용이다.

로고만 있는 온보딩 단계는 브랜드 문맥의 예외: 실제 이전 단계가 있을 때만 뒤로를 제공한다. 비활성처럼 보이는 연회색 뒤로 아이콘은 쓰지 않는다. 활성 아이콘은 `textStrong`, 진짜 비활성만 `textDisabled`.

## 시트 3유형

| 유형 | 그래버 | 헤더 | 높이/본문 | 종료 |
|---|---|---|---|---|
| Browse · 선택/조회 | 드래그 지원 시 1개 | 중앙 제목 + 우측 닫기 | 콘텐츠 높이; 긴 목록은 large·본문 스크롤 | 닫기·배경 탭·헤더 드래그 |
| Editor · 편집 | 없음 | 좌측 취소 + 중앙 제목 | 키보드/내용에 따라 확장; 본문 스크롤, 완료 고정 | 변경 없으면 종료; 변경 있으면 버리기 확인 |
| Confirmation · 확인 | 드래그 지원 시 1개 | 중앙 제목 + 우측 닫기 | 내용 높이; 긴 내용/큰 글씨는 스크롤 | 모든 비확정 종료는 취소. 파괴적 CTA만 실행 |

시트 프레임이 필요할 때 위 유형을 사용한다. 단순한 친구 끊기는 확인창을 우선 권장하며, 대상 비교나 추가 선택이 필요한 확인에만 Confirmation 시트를 사용한다. 현재 친구 끊기 앱 구현은 이전 시트를 유지하고 있다. 파괴적 버튼은 기존 `DButton(destructive: true)` 의미색을 따른다. 일반 완료에 Ditto 전용 젤리 버튼을 사용하지 않는다.

## 먼저 표현 방식을 고른다

| 작업 | 우선 형식 | 적용 후보 |
|---|---|---|
| 문맥을 유지하는 짧은 조회·선택 | 바텀시트 | 위젯 종류 선택, 댓글, 미니 프로필, 단일 사유 신고 |
| 여러 입력·키보드·하위 단계 | 전체 화면 편집 | 프로필 수정, 그룹 만들기 |
| 캔버스 조작 | 전체 화면 캔버스 | 스티커 보드 |
| 장기 조회·여러 기능 묶음 | 일반 화면 | 친구 초대 현황·보상·근처 친구 |
| 짧은 실행/취소 결정 | 확인창 | 친구 끊기, 미저장 변경 폐기 |
| 맥락 설명 | 인라인 도움말 | 주파수, 프로필 열람권 |
| 적은 수의 즉시 실행 옵션 | 직접 버튼 / 메뉴 | 폴라로이드 카메라·앨범 |
| 외부로 전달 | 시스템 공유창 | 초대 링크 공유 |

이 표는 디자인 시스템의 선택 기준이다. 네이티브 전체 화면 전환 작업을 수행했다는 뜻은 아니다. [화면별 근거와 이관 우선순위](Ditto_Presentation_Audit_2026-10-02.md)를 함께 본다.

## 공통 치수와 상태

- 상단 바/시트 제목 행: 최소 56pt. Pretendard 17 / Semibold 600, 기존 `titleSm` 기반. 큰 글씨에서는 높이가 증가하고 제목 줄바꿈 허용.
- 좌우 콘텐츠 여백 16pt. 좌우 슬롯 각각 64pt로 제목의 실제 중앙을 보장. 긴 액션은 메뉴나 하단으로 이동; 제목을 액션 위에 겹치지 않는다.
- 모든 아이콘 버튼 터치 영역 최소 44×44pt. 기본 아이콘 20pt. 닫기는 16pt 아이콘 + 32pt 중립 원형 + 44pt 터치 영역.
- 시트 상단 R24, `layerModal` 표면. 회색 카드가 필요하면 본문 내부 그룹에만 사용. 헤더와 본문 사이 강제 배경 전환 없음.
- 그래버 40×5pt, 위 10 / 아래 12pt. 접근성 트리에서는 장식으로 제외. 시스템 시트에는 시스템 그래버만 사용.
- 콘텐츠/푸터 좌우 16pt. 하단 16pt + OS safe area. CTA는 기존 일반 버튼 R12/60pt 기준; 저장 중 재실행 차단, 실패 시 입력 유지가 목표 계약.
- 닫기/뒤로/취소에는 접근성 이름 제공. 모달 진입 시 제목으로 포커스, 종료 시 진입 버튼으로 복원하는 것이 목표 계약. VoiceOver·큰 글씨·키보드·작은 화면 실기 검증 필요.
- 시트 모션 `Motion.sheet`, 복귀 `Motion.settle`. Reduce Motion에서는 페이드/즉시 전환 적용을 검증한다. 별도 스프링 추가 금지.
- 스크롤과 드래그를 구분: 닫기 드래그는 헤더에서 시작. 컨트롤·본문 스크롤로 시트를 닫지 않는다.

## 공유한 7개 사례의 처리

| 사례 | 결정 |
|---|---|
| 1 위젯 추가 큰 X | 5번과 같은 Browse 헤더. 큰 X 제거, 공통 32/44pt 닫기 사용 |
| 2 프로필 수정 | 하단 완료 유지 시 N1-L 취소. 상단 완료 선택 시 N2 취소+완료. 전체 화면 편집을 권장 |
| 3 로고 + 뒤로 | N1-L + Logo. 온보딩 브랜드 문맥에 사용, 일반 상세는 Title |
| 4 초대 + 로고 + 알림 | N2 + Logo. 공통 56pt/44pt; 로고 22pt. 초대 그래픽은 기존 자산 유지 |
| 5 위젯 추가 | Browse 대표 패턴으로 채택, 공통 헤더 치수 적용 |
| 6 친구 초대 | 5번과 동일한 Browse 헤더. 본문만 기능별 변화 |
| 7 친구 끊기 | 확인창 전환 권장. 현재 시트를 유지하는 동안 헤더는 N1-R, 공통 표면 적용 |

## 코드 적용과 후속 범위

이번 적용: `DDSChromeBar`, `DDSChromeTitle`, `DDSCloseButton`, `DSSheetHeader`; 기존 `DSNavBar` 소비 화면; 친구 Root와 보관함; 위젯 추가·친구 초대·프로필 수정·친구 끊기. 프로필 취소는 이름·링크·컬러·사진 변경을 비교해 폐기 확인. 토큰 및 문서 미리보기 등록.

남은 이관: 친구 플래터/그룹/게시글의 독립 상세 헤더, 댓글·요청·신고·위젯 상세 등 기타 시트, 전체 모달 VoiceOver 포커스, 네이티브 detent·safe area·Reduce Motion 통합. 기존 동작을 보존하며 각 화면 수정 때 공통 컴포넌트로 이관한다. 시스템 시트에 커스텀 그래버를 추가하지 않는다.

이 문서는 전체 앱 이관·Figma 라이브러리 갱신·배포 완료를 뜻하지 않는다. 웹 미리보기는 새 규격의 시각 설명이며 실제 앱 캡처가 아니다.

## 이번 검증 결과

최종 iOS Simulator 대상 Debug 빌드 성공. 웹 가이드는 1440px 라이트 및 375px 다크/큰 제목에서 확인했으며 이미지·폰트 누락, JavaScript 오류, 가로 넘침 없음. 웹 시트 Escape 종료와 포커스 복귀 확인. 네이티브 기기 화면·VoiceOver·키보드·미저장 변경 취소 플로우는 실기 검증 전이다. 캡처와 기록: `output/ditto-navigation-sheets-2026-10-02/`.

### 1.1 재검증

버튼 수별 API 적용 후 Simulator Debug 빌드 성공. 웹 예시의 버튼 수는 0/1/1/2/2/2로 확인했다. 320·375·402·1440px 다크/큰 제목에서 가로 넘침과 제목 중앙 이탈 없음, 버튼 터치 영역 44px 이상. 피그마 원본은 수정하지 않았으며 계정 선택과 폰트 가용성 문제가 남아 있다.

### 피그마 파운데이션 반영

`halo0901@yonsei.ac.kr` 계정으로 Ditto/Navigation/Layout 의미 토큰 15개와 누락 원시 치수 4개를 추가했다. 기존 간격 토큰은 별칭으로 재사용했다. 레이아웃 컬렉션 ID: `VariableCollectionId:1255:2762`. 텍스트 포함 컴포넌트·실제 화면 갱신은 Pretendard 로딩 실패로 미완료다. 위 검증 절의 미반영 기록은 이 작업 이전 상태다.
