23 KiB
LNB (Pattern)
2026-10-10 추가 수정 요청 기준: 독립 Green LNB 펼친 2Depth 그룹 배경만 Black 8%. 글자·아이콘 opacity와 선택·Hover 보존. GNB 콘텐츠 LNB는 별도 밝은 배경 범위. 과거 검증 기록은 당시 결과이며 현재 검증은 추가 수정 보고서를 따릅니다.
2026-10-10 추가 확정: Storybook 왼쪽 목차의 펼친 2Depth 그룹 배경도 Black 8%로 적용합니다. 컴포넌트는 HM LNB CSS, 목차는 Storybook Manager CSS의 기존 펼친 그룹 selector가 각각 담당합니다. 배경 Alpha만 적용하며 글자·아이콘 opacity, Selected·Hover·Focus, 검색·필터·펼침·접힘은 유지합니다. Selected inset depth 등에 쓰는 별도 Black 20%는 그룹 배경이 아니므로 유지하며, 공통 Theme·Token을 변경하지 않습니다.
2026-10-07 확정: SINGLE NAVIGATION MODE. GNB / LNB / Dashboard는 함께 사용하지 않는다. AI 코드 생성·제안, 신규/기존 페이지, 프로토타입, Storybook, Production 전체에 적용한다. 공통 정책이 이전 조합 기록보다 우선한다.
현재 HM 구현의 기준 문서. 공통 원칙은 docs/guidelines/프로젝트-지침.md(§6.10, §6.11)를 따른다.
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로 사용 |
<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를 소비 화면이 가진다.
<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 단일 Sheet를 사용하며 독립 LNB Mobile Header/Menu를 추가하지 않는다. DASHBOARD ONLY 운영 화면에는 Sidebar가 없다(Dashboard 현재 계약).
HISTORICAL RECORD — 이전 GNB Sheet 혼합 안내
아래 안내는 이전 구성의 기록이며 현재 운영·신규 화면 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.
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 |
중첩 지역 메뉴 그룹 |
<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 8% + 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 8%, 선 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 자체 변수만 사용한다.
내부 스크롤과 숨김 알림 Usage
viewport 높이 shell에서 모바일 Header와 main을 세로 flex로 배분할 때 부모와 main의 min-height: 0, main의 flex: 1; overflow: auto를 확인한다. 위 콘텐츠 면의 position: relative는 main 안의 absolute 숨김 status가 BODY를 기준으로 배치되어 바깥 빈 스크롤을 만드는 것도 방지한다. 숨김 알림은 Toast가 아니며 요청 없이 시각 알림 기능을 추가하지 않는다.
/* 소비 레이아웃의 높이·스크롤만 구성한다. 기존 HM 면·간격은 유지한다. */
.content-stack { display: flex; flex-direction: column; min-height: 0; min-width: 0; }
.page-content { position: relative; flex: 1; min-height: 0; min-width: 0; overflow: auto; }
390/768/1280/1440px에서 초기·조회·초기화·완료 후 document.documentElement.scrollHeight/clientHeight, main의 같은 값, live region의 offsetParent·크기·문구를 기록한다. viewport 높이 shell이면 바깥 스크롤 없이 main 내부의 마지막 항목에 접근할 수 있어야 한다. 일반 문서 흐름 화면에는 viewport 높이를 강제하지 않는다. 완료 후 disabled 버튼 대신 유효한 focus 대상이 유지되는지도 확인한다. 전역 overflow:hidden은 해결책이 아니다.
7. Accessibility / 상호작용
<aside> + <nav aria-label>, 현재 aria-current="page", 그룹 trigger는 Radix aria-expanded/aria-controls. LNBProfile은 native button + 기본 accessible name "<name> <description> 사용자 메뉴"이며 description이 없으면 "<name> 사용자 메뉴"다. 명시적 aria-label/aria-labelledby를 소비자가 지정할 때도 화면에 보이는 이름·설명을 포함한다. 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, radius8 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, LNBWith GNB) 데스크톱 보이는 brand =gnb-brand1개, LNBBrand 없음, 1023·390 GNB 모바일 바 1개. LNB Only(DashboardLNB Only,LNB Standalone Desktop) 데스크톱lnb-brand1개·상단 바 0, 1023·390 Local 모바일 바 1개(gnb-brand1개). 서비스명 "프로젝트 대시보드"는 모든 경우 화면에 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