239 lines
20 KiB
Markdown
239 lines
20 KiB
Markdown
# LNB (Pattern)
|
||
|
||
> **2026-10-07 확정: SINGLE NAVIGATION MODE.** GNB / LNB / Dashboard는 함께 사용하지 않는다. AI 코드 생성·제안, 신규/기존 페이지, 프로토타입, Storybook, Production 전체에 적용한다. [공통 정책](../guidelines/navigation-single-mode.md)이 이전 조합 기록보다 우선한다.
|
||
|
||
현재 HM 구현의 기준 문서. 공통 원칙은 `docs/guidelines/프로젝트-지침.md`(§6.10, §6.11)를 따른다.
|
||
|
||
```text
|
||
Layout visual reference: 외부 ui_viz Reference (ZIP 미포함) (Patterns/LNB, Variant A Sidebar)
|
||
Implementation: current @hm-design/ui primitives / patterns (HM Collapsible + plain elements)
|
||
```
|
||
|
||
## 1. 상태
|
||
|
||
| 항목 | 내용 |
|
||
|---|---|
|
||
| 구현 상태 | 구현 완료 (2026-10-03), 3뎁스 추가 (2026-10-06) |
|
||
| 기반 | HM Collapsible + 일반 요소 (새 dependency 없음) |
|
||
| 대표 Story | `Patterns/Layout/LNB` → `LNB` (verification: Third Level, Third Level Long Labels, Default, Selected, Expanded, Selected Child, Collapsed With Selection, With Logo, Long Labels, Scroll, Third Level Scroll, VERIFICATION ONLY · GNB + LNB, LNB Standalone Desktop, LNB Standalone Mobile, LNB Standalone Mobile Menu Open) |
|
||
| 보류 | §11 |
|
||
|
||
## 2. 목적 / 역할
|
||
|
||
LNB Mode 페이지의 독립 Navigation 체계. Desktop 열과 LNB Mobile Header는 같은 메뉴·선택 상태의 Responsive 표현이다. GNB 또는 Dashboard와 조합하지 않는다.
|
||
|
||
## 3. 구성 요소와 API
|
||
|
||
| export | 역할 |
|
||
|---|---|
|
||
| `LNB` | `<aside>` 열. 폭 `--hm-lnb-width` |
|
||
| `LNBBrand` | 선택적. LNB Mode의 서비스 브랜드를 담당한다(§3c). 세로형(로고 위·서비스명 아래, 같은 시작선). 로고는 `img`/`svg`가 있을 때만. `<span>`에 `<small>` eyebrow + `<strong>` 이름 |
|
||
| `LNBNav` | 메뉴 영역 `<nav>`(`aria-label` 지정). 길면 이 영역만 스크롤 |
|
||
| `LNBItem` | 링크(`<a>`, `asChild`). `active` → `aria-current="page"`. 앞의 `svg` 자식 = 아이콘(lucide) |
|
||
| `LNBGroup` | 2뎁스 그룹: HM `Collapsible`(`open`/`defaultOpen`/`onOpenChange`), `label`, `current`(하위 현재 → 이름·화살표 노랑). 그룹 안에 `LNBGroup`을 중첩하면 3뎁스(§3a) |
|
||
| `LNBProfile` | 하단 사용자 메뉴 trigger `<button>`: Avatar(children, default size) + 이름·역할 글자. `DropdownMenuTrigger asChild`로 사용 |
|
||
|
||
```tsx
|
||
<LNB>
|
||
{/* LNB Mode의 서비스 브랜드 */}
|
||
<LNBBrand><span><small>한맥 업무 시스템</small><strong>프로젝트 대시보드</strong></span></LNBBrand>
|
||
<LNBNav aria-label="서비스 메뉴">
|
||
<LNBItem href="#a" active><LayoutGridIcon />메뉴 1</LNBItem>
|
||
<LNBGroup label="메뉴 2" current><LNBItem href="#b" active>메뉴 2-1</LNBItem></LNBGroup>
|
||
</LNBNav>
|
||
<DropdownMenu>
|
||
<DropdownMenuTrigger asChild>
|
||
<LNBProfile name="김한맥" description="프로젝트 관리자"><Avatar>…</Avatar></LNBProfile>
|
||
</DropdownMenuTrigger>
|
||
<DropdownMenuContent align="start" className="min-w-(--radix-dropdown-menu-trigger-width)">
|
||
<DropdownMenuLabel>김한맥</DropdownMenuLabel>
|
||
<DropdownMenuItem>프로필 설정</DropdownMenuItem>
|
||
<DropdownMenuSeparator />
|
||
<DropdownMenuItem variant="destructive">로그아웃</DropdownMenuItem>
|
||
</DropdownMenuContent>
|
||
</DropdownMenu>
|
||
</LNB>
|
||
```
|
||
|
||
Collapsible의 trigger/content는 `asChild`로 자체 `button`/`div`를 써서 Collapsible의 기본 text-trigger 스타일을 쓰지 않는다(Radix `aria-expanded`/`aria-controls`/Enter/Space는 그대로).
|
||
|
||
## 3a. 3뎁스 (2026-10-06)
|
||
|
||
현재 interaction은 2Depth에서 들여쓴 링크 면, 3Depth에서 connector 끝부터 시작하는 링크 면에 한정한다. 3Depth connector는 상태와 무관하게 Green Tint 40%이며 장식 행은 pointer interaction을 소유하지 않는다. 아래 비교표는 도입 시점 기록이며 최신 Mapping은 §5를 따른다.
|
||
|
||
기준: 3Depth 도입 당시의 디자이너 공유 자료(외부 Reference, ZIP 미포함). 현재 구현 기준과 사용법은 이 문서, `packages/ui/src/patterns/lnb/`와 `src/patterns/lnb.stories.tsx`의 대표 Story를 따른다. ui-viz에는 3뎁스가 없다.
|
||
|
||
사용: 기존 `LNBGroup`을 그룹 안에 중첩한다. 새 컴포넌트·`depth` prop·state 없음. 실제 선택 링크 = `active`, 그 경로의 모든 그룹 = `current`(소비자 경로 상태에서 계산). 닫힌 그룹은 내용을 unmount하므로, 바깥 그룹을 접었다 펼 때 안쪽 그룹 열림을 유지하려면 각 그룹 `open`/`onOpenChange`를 소비 화면이 가진다.
|
||
|
||
```tsx
|
||
<LNBGroup label="프로젝트 관리" current open={open.projects} onOpenChange={…}>
|
||
<LNBGroup label="디자인 관리" current open={open.design} onOpenChange={…}>
|
||
<LNBItem href="#tokens" active>컬러 토큰</LNBItem>
|
||
<LNBItem href="#components">컴포넌트 스타일</LNBItem>
|
||
</LNBGroup>
|
||
<LNBItem href="#tasks">업무 목록</LNBItem>
|
||
</LNBGroup>
|
||
```
|
||
|
||
| 항목 | 명세 | 구현 | 분류 |
|
||
|---|---|---|---|
|
||
| 글자 | 1·2뎁스 18/28/700, 3뎁스 18/24/500, 선택 700 | 같음 | MATCHED |
|
||
| 3뎁스 행 | 최소 48, 상하 12, 링크 padding-left 88(2뎁스 68 + 20) | 같음 (1·2뎁스 56 유지) | MATCHED |
|
||
| 3뎁스 글자 장식 | 외곽선·그림자 없음 | 같음 | MATCHED |
|
||
| 긴 이름 | 줄바꿈, 행 높이 증가 | 48 / 72 / 96 (1·2·3줄), ellipsis 없음, 가로 overflow 0 | MATCHED |
|
||
| 선택 | Beige + `--hm-sem-action-primary`, 오른쪽 곡선 | 기존 current 규칙 그대로(폭 +1, 위·아래 오목 곡선) | MATCHED |
|
||
| 상위 경로 | 1·2뎁스 노랑, 접혀도 유지 | `current` → `--hm-yellow-accent` | MATCHED |
|
||
| 연결선 | 3뎁스만, 1px, 세로선 x 68, 가로 12, 글자까지 8, 행 세로 중앙, 마지막 행 중앙에서 끝 | 행마다 background 2겹(세로 `1px × 100%`, 마지막 행 `1px × 50%`, 가로 `12 × 1` at `calc(50% - 0.5px)`). DOM·tab stop·aria 없음 | MATCHED / IMPLEMENTATION_CHANGE(명세의 "배경 레이어" 방식) |
|
||
| 연결선 색 | 기본·hover `--hm-green-tint` 40%, 선택 `--hm-green-light-2` 40% | 같음. 선택 색은 선택된 행의 선에만 적용(나머지 행은 기본색) | MATCHED |
|
||
| 접힘 | 하위 메뉴·연결선 함께 숨김 | Radix가 내용을 unmount → 선도 같이 사라짐 | MATCHED |
|
||
| 중첩 그룹 | 배경·테두리·padding 중복, 폭 감소, 오른쪽 틈 금지 | 안쪽 그룹은 면·선·padding-bottom 없음, 폭 100%(바깥 그룹과 같은 252), 선택 항목 오른쪽 273(1px 겹침) | MATCHED |
|
||
| 안쪽 그룹 이름 위치 | 명세 수치 없음, 이미지상 2뎁스 글자와 같은 시작선 | trigger padding-left = 68 − 화살표 18 − gap 12 = 38 → 글자 x 68 | INTENTIONAL_CHANGE(이미지 기준) |
|
||
|
||
모바일(<1024): LNB ONLY는 Desktop 열을 숨기고 같은 메뉴를 독립 `LNBMobileHeader / LNBMobileMenu`로 표시한다(§3b). GNB ONLY 내부 Sidebar는 [GNB §15](gnb.md#15-gnb-only-sidebar-composition-2026-10-08)의 GNB 단일 Sheet를 사용하며 독립 LNB Mobile Header/Menu를 추가하지 않는다. DASHBOARD ONLY 운영 화면에는 Sidebar가 없다([Dashboard 현재 계약](dashboard-layout.md#1-현재-계약)).
|
||
|
||
<details>
|
||
<summary>HISTORICAL RECORD — 이전 GNB Sheet 혼합 안내</summary>
|
||
|
||
아래 안내는 이전 구성의 기록이며 현재 운영·신규 화면 Reference가 아니다.
|
||
|
||
모바일(<1024): LNB는 그대로 숨긴다(icon-only collapsed 없음, 새 breakpoint 없음). 같은 지역 메뉴 트리를 GNB 모바일 Sheet에 중첩 `GNBMobileGroup`으로 조합한다(`Patterns/Layout/Dashboard Layout` → `Third Level`, `gnb.md` §8). Sheet는 GNB의 시각 언어(14px 링크, Beige current)를 쓰고 LNB의 gradient·곡선·연결선은 가져가지 않는다. 화면에 GNB가 없을 때의 모바일 탐색은 §3b.
|
||
|
||
</details>
|
||
|
||
## 3b. LNB Mobile Header (2026-10-07)
|
||
|
||
| viewport | Desktop LNB | LNB Mobile Header |
|
||
|---|---|---|
|
||
| ≥1024px | VISIBLE | HIDDEN |
|
||
| ≤1023px | HIDDEN | VISIBLE |
|
||
|
||
모바일 Header와 Sheet는 LNB의 Responsive 표현이며 GNB가 아니다. 기존 GNB 모바일 부품 조합을 LNB 전용 공개 API로 대체했다. HM Sheet가 focus trap, Escape, focus 복귀를 맡고 링크 선택 시 router가 preventDefault를 사용해도 Sheet를 닫는다.
|
||
|
||
| export | 역할 |
|
||
|---|---|
|
||
| `LNBMobileHeader` | 모바일 전용 Header, 높이 56px / padding 16px. ≥1024px에서 자체 숨김 |
|
||
| `LNBMobileBrand` | 서비스명 및 선택적 로고, 링크 또는 `asChild` |
|
||
| `LNBMobileMenu` | 햄버거 + Sheet. `title`, `side`, `open/defaultOpen/onOpenChange` |
|
||
| `LNBMobileLink` | Sheet 링크, `active`, `asChild`, 선택 시 닫기 |
|
||
| `LNBMobileGroup` | 중첩 지역 메뉴 그룹 |
|
||
|
||
```tsx
|
||
<div className="grid grid-cols-1 lg:grid-cols-[var(--hm-lnb-width)_minmax(0,1fr)]">
|
||
<LNB>
|
||
<LNBBrand>…</LNBBrand>
|
||
<LNBNav aria-label="서비스 메뉴">{desktopMenu(tree)}</LNBNav>
|
||
<LNBProfile name={profile.name}>…</LNBProfile>
|
||
</LNB>
|
||
<div>
|
||
<LNBMobileHeader>
|
||
<LNBMobileMenu title="서비스 메뉴">
|
||
{mobileMenu(tree)}
|
||
<LNBProfile name={profile.name}>…</LNBProfile>
|
||
</LNBMobileMenu>
|
||
<LNBMobileBrand href="/">서비스명</LNBMobileBrand>
|
||
</LNBMobileHeader>
|
||
<main>…</main>
|
||
</div>
|
||
</div>
|
||
```
|
||
|
||
Desktop/Mobile은 메뉴 트리, 현재 위치, 그룹 상태, Profile 데이터 원본을 공유한다. 모바일 Sheet 링크는 44px 높이, 14/20/500(current 700)을 유지한다. 중첩 그룹은 12px 들여쓴다. Header/Sheet 스타일은 `--hm-lnb-mobile-*`와 공통 Semantic을 사용하며 GNB/Dashboard 변수에 의존하지 않는다.
|
||
|
||
## 3c. 브랜드·프로필 소유
|
||
|
||
LNB Mode가 Desktop Brand/Profile과 Mobile Header/Sheet Profile을 담당한다. 다른 Navigation에 소유권을 넘기지 않는다. `LNBBrand`는 선택적이며 생략하면 빈 자리 없이 메뉴가 올라간다. 공통 LNB 메뉴 스크롤·geometry는 그대로 유지한다.
|
||
|
||
기존 `WithGNB` Story는 `verification` 태그 및 화면과 이름에 **VERIFICATION ONLY**를 표시한 기술 검증 전용이다. 운영·신규 페이지·AI 생성 예제로 사용하지 않는다.
|
||
|
||
## 4. ui-viz 비교 (원본: `dashboard-composition.md` §6, `dashboard-variant-specimens.css/jsx`)
|
||
|
||
| 항목 | ui-viz | 최종 HM | 분류 |
|
||
|---|---|---|---|
|
||
| 폭 | track 272, visual 290(오른쪽 18 bleed) | 열 272(`--hm-lnb-width`), 뒤로 18(`--hm-lnb-join`) 같은 색 연장 | MATCHED (연장은 `::after`) |
|
||
| 배경 | 90° 5-stop `#123328/#205241/#266651/#249473/#266651` 0/30/50/90/100%, 트랙 폭, 트랙 밖 `#266651` | 같음 (`--hm-green-*`) | MATCHED |
|
||
| 상단 | 위 28, 브랜드 padding 0 10 22, 메뉴 위 20 | 위 28, 브랜드 inset 30(=20+10), 아래 22, 메뉴 위 20 | MATCHED |
|
||
| 브랜드 | 로고 조건부, 위 로고·아래 서비스명, eyebrow 11/700, 이름 17 | 같음 | MATCHED |
|
||
| 항목 | 18/28/700, 최소 56, padding 14 12 14 18, White, 아이콘 20 opacity .5, 글자 테두리 1.5px + 그림자 `1px 2px 1px` | 같음 | MATCHED |
|
||
| hover | Black 10%, 콘텐츠 경계까지, 시작 쪽 radius 4 | 같음 | MATCHED |
|
||
| current | Beige + `#123328`, 왼쪽 radius 8, 오른쪽 20+1 연장, 위·아래 18 오목 곡선, 안쪽 깊이 그림자(마지막 25% fade), 글자 효과 없음 | 같음. 깊이는 span 대신 background gradient 3겹으로 근사 | MATCHED / IMPLEMENTATION_CHANGE |
|
||
| nested(2뎁스) | 상위 = disclosure 버튼, 화살표 접힘 → 펼침 90°, 펼친 그룹 Black 20% + 1px `#266651` 선 + 왼쪽 radius 8, 하위 padding-left 68, 하단 8, 하위 선택 시 상위 노랑 `#FFC600` | 같음. HM Collapsible(Radix) 사용 | MATCHED / IMPLEMENTATION_CHANGE |
|
||
| divider | Brand/Profile 구분선 없음, 그룹 구분선은 그룹이 둘 이상일 때만(현재 없음) | 없음 | MATCHED |
|
||
| profile | 이름 16 + 역할 12, avatar 없음, 아래 22 | 위치·글자 같음 + Avatar 32px(gap 12, 세로 중앙) | INTENTIONAL_CHANGE |
|
||
| 외곽 brand 테두리(`.sidebar::after`) | D-093 예시에 없음, FOLLOW_UP | 그리지 않음 | FOLLOW_UP |
|
||
| collapsed(열 자체 접힘) | ui-viz에 없음 | 만들지 않음 (`--hm-lnb-collapsed-width` 없음). ui-viz의 "Collapsed"는 그룹 접힘이다 | — |
|
||
| mobile | ui-viz에 없음 | 열 숨김, `--hm-lnb-width: 0px`. LNB Mobile Header + LNB Sheet로 같은 목적지 표시(§3b) | INTENTIONAL_CHANGE |
|
||
| 스크롤 | ui-viz는 `overflow:hidden`(넘치면 잘림) | 메뉴 영역만 세로 스크롤(brand/profile 고정) | INTENTIONAL_CHANGE |
|
||
| 아이콘 | 4종 자체 SVG | lucide 아이콘을 소비자가 자식으로 둠(새 icon system 없음) | IMPLEMENTATION_CHANGE |
|
||
|
||
## 5. Token / CSS Variables
|
||
|
||
`packages/ui/src/theme/lnb.css`의 `--hm-lnb-*`.
|
||
|
||
| Token | 값 |
|
||
|---|---|
|
||
| `--hm-lnb-width` | 272px (1023px 이하에서 0px) |
|
||
| `--hm-lnb-join` | 18px. 콘텐츠 둥근 모서리·bleed |
|
||
| `--hm-lnb-background` / `-background-end` | 5-stop gradient / `#266651` |
|
||
| item | min-height 56, 18/28/700, gap 12, 아이콘 20, 글자 테두리 1.5px |
|
||
| current | `--hm-sem-bg-content` + `--hm-sem-action-primary`, radius 8 0 0 8 |
|
||
| group | open face Black 20%, 선 1px `--hm-sem-palette-green-light-2`, 하위 padding-start 68, current 글자 `--hm-sem-palette-yellow-accent` |
|
||
| `--hm-lnb-third-*` | min-height 48, padding-block 12, text padding-start 88(메뉴 행 기준), line-height 24, weight 500 / current 700, connector x `= --hm-lnb-subitem-padding-start`(68)·length 12·width 1, 모든 상태에서 `--hm-sem-palette-green-tint` 40%. 실제 link는 connector 끝부터 시작 |
|
||
|
||
새 Primitive: `--hm-yellow-accent: #ffc600`(`primitives.css`). ui-viz `color.action.accent-on-green`이며 HM 팔레트에 없어 추가했다. 그 외 새 Semantic은 없다.
|
||
|
||
## 6. LNB Mode 콘텐츠 연결
|
||
|
||
- 열 옆 콘텐츠 면: `position: relative`, DOM상 뒤, 왼쪽 모서리 `border-radius: var(--hm-lnb-join) 0 0 var(--hm-lnb-join)`, grid 첫 열 = `var(--hm-lnb-width)`. 열의 초록은 콘텐츠 뒤로 `--hm-lnb-join`만큼 이어진다.
|
||
- current 항목은 열 오른쪽 가장자리를 넘어 콘텐츠와 1px 겹쳐 이음새 없이 이어진다(열은 overflow를 자르지 않는다).
|
||
- 높이는 소비자가 정한다(열은 `min-height: 100%`).
|
||
- GNB 또는 Dashboard와 조합하지 않는다. 콘텐츠 계산은 LNB 자체 변수만 사용한다.
|
||
|
||
## 7. Accessibility / 상호작용
|
||
|
||
`<aside>` + `<nav aria-label>`, 현재 `aria-current="page"`, 그룹 trigger는 Radix `aria-expanded`/`aria-controls`. `LNBProfile`은 native button + 기본 accessible name `"<name> 사용자 메뉴"`이며 Avatar·이름·역할의 inner content 폭에 interaction을 한정한다(`fit-content` + 안쪽 hit padding). 이 버튼에 pointer cursor와 LNB focus-visible outline을 쓴다. `DropdownMenuTrigger asChild`로 합성하면 Enter/Space 열기, Arrow 이동, Escape 닫기와 trigger focus 복귀는 Radix가 담당한다. 접힌 그룹의 하위는 DOM에서 빠져 focus되지 않는다. 아이콘은 장식(`aria-hidden`, 소비자가 지정).
|
||
|
||
## 8. 검증 (2026-10-03, Storybook)
|
||
|
||
> HISTORICAL_RECORD: 아래 날짜별 geometry·상태 측정은 당시 기록이다. 현재 링크 interaction 범위·connector 색은 §3a/§5, Profile interaction은 §7을 따른다.
|
||
|
||
- 1280: current 항목 x 20→273, 높이 56, 18/28/700, Beige `#F5F0E5`/`#123328`, radius `8 0 0 8`, 그룹·하위 x 20→272. 하위 선택 시 상위 `rgb(255,198,0)`, 접힌 채여도 유지. 긴 이름은 줄바꿈(112px), 스크롤 영역은 메뉴만 스크롤하고 profile은 아래 22px 고정. 그룹 trigger Enter로 펼침.
|
||
- 1000px: 열 `display:none`, 가로 overflow 없음. 390px은 GNB 모바일 메뉴로 대체.
|
||
- `npm run typecheck`, `npm run build` 통과. 기존 primitive Story 변화 없음.
|
||
|
||
- 3뎁스(2026-10-06, Storybook): 위 §3a 수치를 computed style로 확인(1280 열 272, 3뎁스 x 20 → 272/선택 273, 그룹 2개 모두 x 20·폭 252, 안쪽 그룹 배경 투명·`::before` 없음). 키보드: Enter로 바깥 그룹 접힘(노랑 유지, 3뎁스·선 사라짐), Space로 다시 펼침(안쪽 그룹 열림 유지), Tab → 안쪽 그룹 Enter로 접힘. trigger는 `button` + `aria-expanded`/`aria-controls`, 선택 링크 `aria-current="page"`, focus-visible 흰 outline. 기존 Selected Child 수치 변화 없음(2뎁스 68/56/700, 그룹 하단 8, 선 1px).
|
||
|
||
- 스크롤 소유(2026-10-06, Storybook): 열 = flex column, brand·profile `flex: none`, `LNBNav`만 `flex: 1 1 auto; min-height: 0; overflow-y: auto`(열 overflow 없음, 높이는 Story shell / Dashboard Layout이 결정). 메뉴 위 20을 nav margin 2 + padding 18에서 nav padding 20(`--hm-lnb-nav-padding-top`)으로 옮겨 스크롤 영역이 brand 바로 아래에서 시작(첫 항목 y 그대로). 측정: Scroll(460) nav 93.7→370 = brand bottom → profile top, client 276 / scroll 830, 최하단 마지막 항목 bottom 351.7(= nav bottom − 18); Third Level Scroll(460) client 276 / scroll 990, 3뎁스 선택 행·곡선·연결선 함께 스크롤; Dashboard Third Level 1280·1024×600 nav 163.7→510, client 346 / scroll 526, 최하단 491.7. 1023px 열 `display:none`, 가로 overflow 없음.
|
||
|
||
- 왼쪽 scrollbar(2026-10-06, Storybook): 오른쪽 native scrollbar(263→273)가 content box를 10px 줄여 스크롤 시 메뉴 면 262·선택 263·곡선 262로 콘텐츠와 떨어졌다. `LNBNav`에 `direction: rtl`(native scrollbar만 왼쪽), 직계 자식 `direction: ltr` + `margin-left: calc(100% + inset-start − width − 1px)`(= −scrollbar 폭, 없으면 0) + `width: auto`(stretch)로 scrollbar가 왼쪽 inset 20 안(0→10)에 들어가고 행은 x 20→272(선택 273) 유지. 스크롤 없음/있음 모두 메뉴 면 272·선택 273·곡선 272·join 272, 아이콘 38·글자 70·chevron 38·2뎁스 글자 88·3뎁스 글자 108·connector 88. LNB Scroll·Third Level Scroll, Dashboard Third Level 1280·1024×600 같은 값. Tab/Enter/Space, `aria-expanded`, `aria-current`, focus-visible 유지.
|
||
|
||
- Brand ownership(2026-10-06, Storybook, 높이 700, 1280·1024·1023·390): GNB + LNB(Dashboard `Dashboard Layout`·`Third Level`, LNB `With GNB`) 데스크톱 보이는 brand = `gnb-brand` 1개, LNBBrand 없음, 1023·390 GNB 모바일 바 1개. LNB Only(Dashboard `LNB Only`, `LNB Standalone Desktop`) 데스크톱 `lnb-brand` 1개·상단 바 0, 1023·390 Local 모바일 바 1개(`gnb-brand` 1개). 서비스명 "프로젝트 대시보드"는 모든 경우 화면에 1개, 가로 overflow 0. 메뉴 geometry(GNB + LNB, 1280): Brand 제거 전 nav top 163.7(GNB 70 + 열 padding 28 + Brand 65.7) → 후 98, 첫 항목 118(= 98 + 20), nav bottom = profile top 610(높이 700) 그대로. Dashboard Third Level 1280×600: nav 98→510, client 346 → 412 / scroll 526, 최하단 마지막 항목 492(= nav bottom − 18), profile top 510 고정. 3뎁스 행 48·padding 88·500(current 700, Beige, x 20→273), 상위 그룹 노랑, 행 x 20→272, 곡선 18 — 이전 값과 같음.
|
||
|
||
## 9. 변경하지 않은 것
|
||
|
||
2026-10-07 단일 모드 검증: 1280·1232·1024·1023·960·959·390·320px에서 LNB Mode에 GNB/Dashboard가 없고 Desktop 열과 Mobile Header 중 하나만 보임을 확인했다. 390px Sheet Escape·포커스 복귀·preventDefault 링크 닫기, 1024px에서 Sheet 숨김, Desktop/Mobile 선택 상태 공유 통과.
|
||
|
||
Collapsible, Navigation Menu 등 기존 primitive 코드·theme CSS는 수정하지 않았다. `primitives.css`에 `--hm-yellow-accent` 한 줄만 추가했다.
|
||
|
||
## 10. 남은 차이
|
||
|
||
| 항목 | 분류 |
|
||
|---|---|
|
||
| 외곽 brand 테두리, 그룹 구분선(그룹이 둘 이상일 때) | FOLLOW_UP / MISSING (ui-viz도 미확정·현재 사용 안 함) |
|
||
| 로고 asset(테스트 이미지만), 크기·간격 D-070 | MISSING |
|
||
| 선택 시 하위 그룹 자동 펼침 | 서비스별 TBD(ui-viz도 TBD) |
|
||
| 하위 hover/selected 시작 위치 | 현재 2Depth는 들여쓴 링크 면, 3Depth는 connector 끝부터 시작하는 링크 면 사용(§3a) |
|
||
| 실기기, 1024~1280 사이 시각 | 미확인 |
|
||
| 4뎁스 이상 | 명세 없음. 3뎁스 규칙만 정의(더 깊이 중첩하면 3뎁스 모양이 반복된다) |
|
||
| 선택 경로 전체 연결선을 선택색으로 칠할지 | 현재 모든 connector는 Green Tint 40%를 유지한다(§3a/§5). 선택은 Beige 면 + Primary 글자 + 700 weight로 표현하며, 경로 전체 선의 선택색은 별도 결정 전까지 적용하지 않는다 |
|
||
| LNB 모바일 Sheet 그룹 접기·상위 current 표시 | 현재 링크 목록 방식. Desktop 18px / Mobile 14px 유지 |
|
||
| LNB Mobile Header 공개 API | 구현 완료. GNB/Dashboard 의존성 없음 |
|
||
|
||
## 11. 관련 파일
|
||
|
||
```
|
||
packages/ui/src/patterns/lnb/{lnb.tsx,lnb-mobile.tsx,index.ts}
|
||
packages/ui/src/theme/lnb.css
|
||
packages/ui/src/theme/primitives.css (--hm-yellow-accent)
|
||
src/patterns/lnb.stories.tsx
|
||
```
|