111 lines
7.4 KiB
Markdown
111 lines
7.4 KiB
Markdown
# Page Header (Pattern)
|
||
|
||
현재 HM 구현의 기준 문서. 공통 원칙은 [프로젝트 지침](../guidelines/프로젝트-지침.md), [Button 규칙](../components/button.md), [단일 Navigation 정책](../guidelines/navigation-single-mode.md)을 따른다.
|
||
|
||
```text
|
||
Layout visual reference: 외부 ui_viz Reference (ZIP 미포함) (dashboard-composition.md §8 Page Heading)
|
||
Implementation: HM Breadcrumb / Button / Dropdown Menu composed as children
|
||
```
|
||
|
||
## 1. 상태
|
||
|
||
| 항목 | 내용 |
|
||
|---|---|
|
||
| 구현 상태 | 구현 완료 (2026-10-03) |
|
||
| 대표 Story | [Patterns/Layout/Page Header → Page Header](../../src/patterns/page-header.stories.tsx) (`patterns-layout-page-header--all`) |
|
||
| Dashboard 사용 예 | [Patterns/Layout/Dashboard → Dashboard](../../src/patterns/dashboard-layout.stories.tsx). 기존 대표 Story와 Dashboard 내부 조합 유지 |
|
||
| 분리 이유 | 모든 화면이 Breadcrumb + h1 + 액션을 반복하고, 하단 20px이 Layout contract |
|
||
|
||
## 2. 구성 / API
|
||
|
||
| export | 역할 |
|
||
|---|---|
|
||
| `PageHeader` | 행(flex, space-between, 하단 정렬, 줄바꿈) |
|
||
| `PageHeaderContent` | 시작 쪽 세로 묶음 |
|
||
| `PageHeaderTitle` | `h1`(화면의 유일한 h1) |
|
||
| `PageHeaderDescription` | 설명/메타 `p` |
|
||
| `PageHeaderActions` | 끝 쪽 액션 행(Button, Dropdown Menu) |
|
||
|
||
```tsx
|
||
import {
|
||
Breadcrumb, BreadcrumbItem, BreadcrumbLink, BreadcrumbList,
|
||
BreadcrumbPage, BreadcrumbSeparator, Button,
|
||
PageHeader, PageHeaderActions, PageHeaderContent,
|
||
PageHeaderDescription, PageHeaderTitle,
|
||
} from "@hm-design/ui"
|
||
|
||
<PageHeader>
|
||
<PageHeaderContent>
|
||
<Breadcrumb>
|
||
<BreadcrumbList>
|
||
<BreadcrumbItem><BreadcrumbLink href="#home">홈</BreadcrumbLink></BreadcrumbItem>
|
||
<BreadcrumbSeparator />
|
||
<BreadcrumbItem><BreadcrumbLink href="#projects">프로젝트</BreadcrumbLink></BreadcrumbItem>
|
||
<BreadcrumbSeparator />
|
||
<BreadcrumbItem><BreadcrumbPage>업무 현황</BreadcrumbPage></BreadcrumbItem>
|
||
</BreadcrumbList>
|
||
</Breadcrumb>
|
||
<PageHeaderTitle>업무 현황</PageHeaderTitle>
|
||
<PageHeaderDescription>프로젝트별 업무 진행 상황을 확인하고 조회합니다.</PageHeaderDescription>
|
||
</PageHeaderContent>
|
||
<PageHeaderActions>
|
||
<Button type="button" variant="primary" appearance="brand" size="default">신규 등록</Button>
|
||
</PageHeaderActions>
|
||
</PageHeader>
|
||
```
|
||
|
||
Breadcrumb와 액션 API는 정의하지 않는다(composition). 구분선은 없다(ui-viz에 없음).
|
||
|
||
대표 예제는 지원되는 `primary × brand`, `size="default"`(Medium 34px) Action 1개를 사용한다. 화면당 Brand는 최대 1개이며 `appearance`를 명시한다. 복수 Action의 PageHeader 전용 세트 규칙은 아직 확정하지 않았으므로 기존 Dashboard fixture를 공통 세트 규칙으로 일반화하지 않는다. 보조 Action이 필요하면 [Button의 사용 위치·세트 규칙과 허용 조합](../components/button.md)을 확인하고, 불명확한 조합은 사용자 결정 후 적용한다.
|
||
|
||
Story의 Breadcrumb hash 링크와 등록 버튼은 조합 예제다. 실제 화면은 해당 Runtime의 라우팅과 등록 처리 callback을 연결한다. React 소비 화면은 entry에서 `@hm-design/ui/theme.css`를 로드한다. Storybook은 기존 전역 Theme 연결을 재사용한다.
|
||
|
||
## 3. Token (`packages/ui/src/theme/page-header.css`)
|
||
|
||
| Token | 값 | ui-viz |
|
||
|---|---|---|
|
||
| `--hm-page-header-gap` | 24px | MATCHED (gap 24) |
|
||
| `--hm-page-header-margin-bottom` | 20px | MATCHED (D-043, 첫 카드까지 20) |
|
||
| `--hm-page-header-breadcrumb-gap` | 10px | MATCHED |
|
||
| title | 28/36/700, 아래→설명 8px | MATCHED (`h2` → `h1`은 INTENTIONAL_CHANGE) |
|
||
| description | 14/20, `--hm-sem-fg-secondary` | MATCHED (색은 ui-viz 임시값 대신 Semantic) |
|
||
| actions gap | 8px | 정의 없음(Button 간격) |
|
||
|
||
Breadcrumb는 HM Breadcrumb 그대로(14px, 링크). ui-viz는 12px 정적 텍스트였다(INTENTIONAL_CHANGE).
|
||
|
||
## 4. Responsive / Accessibility
|
||
|
||
`PageHeaderContent`는 `flex: 1 1 320px; min-width: 0`, 액션은 줄바꿈 후 오른쪽 정렬(390px에서 제목 아래 줄). 긴 제목은 `overflow-wrap: anywhere`. 화면당 `h1`은 하나만 둔다. wrapper에 role을 두지 않는다.
|
||
|
||
PageHeader는 콘텐츠의 제목 영역이며 Navigation Mode를 정의하지 않는다. 독립 대표 Story는 Navigation을 추가하지 않은 조합 예제다. 실제 페이지는 `GNB | LNB | DASHBOARD` 중 하나만 선택하고 반응형에서도 유지한다. Dashboard에서는 Dashboard 내부 Header/Menu/Sidebar와 합성하며 외부 GNB/LNB를 함께 넣지 않는다.
|
||
|
||
Dashboard Compact 최소 폭 960px(Sidebar 포함 1232px)과 내부 가로 스크롤은 Dashboard Layout 계약이다. PageHeader 단독 사용처에 이 최소 폭을 자동 적용하지 않는다. PageHeader 자체에는 고정 최소 폭이나 별도 breakpoint가 없으며 기존 flex wrapping과 Theme 규격을 유지한다. 외부 콘텐츠 padding은 소비 Layout이 소유한다.
|
||
|
||
## 5. 검증 / 관련 파일
|
||
|
||
### 현재 대표 Reference
|
||
|
||
- [독립 대표 Story 소스](../../src/patterns/page-header.stories.tsx): Breadcrumb + Title + Description + Actions. 운영 조합에 별도 Story CSS나 Dashboard 최소 폭을 추가하지 않는다.
|
||
- Storybook 경로: `Patterns/Layout/Page Header → Page Header`, ID: `patterns-layout-page-header--all`.
|
||
- 기존 Dashboard 대표 Story는 Dashboard 전체 Layout의 Reference로 유지한다. Verification Story는 운영 Reference로 사용하지 않는다.
|
||
|
||
### 2026-10-08 독립 대표 Story 검증
|
||
|
||
- 기존 6024 Storybook에서 독립 메뉴와 대표 Story 렌더링 확인. 1440×900 / 390×844에서 네 구성 요소가 표시되고 문서·body의 가로 넘침 없음. 모바일 Action은 아래 줄 오른쪽으로 배치된다.
|
||
- Computed style: Title 28/36/700, Breadcrumb 14/20, Description 14/20와 Secondary 전경, PageHeader gap 24px·하단 margin 20px·Actions gap 8px 유지. 기존 Noto Sans KR와 Theme Semantic 연결 확인.
|
||
- `primary × brand`, `size="default"` 버튼 1개·높이 34px 확인. Breadcrumb 링크 → Action의 Tab 순서와 focus-visible 링 유지. 콘텐츠의 보이는 `h1`은 1개다.
|
||
- 기존 Dashboard 대표 Story 정상 렌더. Header 48px·Variant C Typography·상태 필터 유지, 이슈 5건 조회 및 전체 47건 복원 확인. 390px에서 Dashboard 최소 폭 960px과 내부 가로 스크롤 유지.
|
||
- PageHeader / Dashboard Console 오류·경고 없음. Storybook 관리자에는 기존 `PopoverProvider ariaLabel`의 Storybook 11 예정 변경 경고 1건이 있다.
|
||
- 새 Story만 대상으로 한 최소 TypeScript 검사와 변경 파일 diff check 통과. 앱 범위 검사는 다른 작업의 Controlled Props와 패키지 선언 불일치 오류 6건으로 실패했으며 해당 파일은 수정하지 않았다. 전체 Component 회귀·build는 이번 범위에서 수행하지 않았다.
|
||
|
||
### 과거 검증 기록 (기존 문서)
|
||
|
||
당시 Dashboard Layout Story(1280, 390, 긴 제목)에서 page-header 상단이 Main padding 34 아래, 하단 20px 뒤에 첫 콘텐츠인 것을 확인했다. 이는 당시 Dashboard 조합의 검증 기록이며, 현재 Dashboard 최소 폭·내부 가로 스크롤 정책이나 모든 PageHeader 소비 화면의 padding 규격을 대신하지 않는다.
|
||
|
||
```
|
||
packages/ui/src/patterns/page-header/{page-header.tsx,index.ts}
|
||
packages/ui/src/theme/page-header.css
|
||
src/patterns/page-header.stories.tsx
|
||
src/patterns/dashboard-layout.stories.tsx
|
||
```
|