feat(ui): standardize LNB sizing and active depth effect
- Adopt the official LNB desktop spec as package defaults: 240px column, 14px menu text, 48px 1-depth rows and 42px 2/3-depth rows, with new item/subitem padding-block and profile min-height tokens. - Match --hm-lnb-current-depth to the Storybook Manager selected item: sampled soft inset falloff (left/top/bottom) and a fade over the last quarter, keeping the concave corners and content join. - Drop the size overrides from the LNB Story CSS and update the LNB, GNB and Dashboard docs, AI guides and the theme verification baseline.
This commit is contained in:
1 parent
89f265ae2f
commit
e42b67c53a
9 files changed
+95
-75
No files matched your search
@@ -31,6 +31,7 @@
|
||||
- 요청이 모드를 말하지 않으면 화면 목적(서비스 상단 메뉴 = GNB, 계층 업무 메뉴 = LNB, 운영 현황 = DASHBOARD)으로 고르고 **선택 근거를 보고**합니다. 임의로 Sidebar를 추가하지 않습니다.
|
||||
- 혼합 요청(GNB + LNB 등)은 정책 충돌로 안내하고 하나를 고르게 합니다. Drawer·Hamburger 등 대체 메뉴를 추측해 만들지 않습니다.
|
||||
- Breadcrumb·FilterBar·사용자 Dropdown은 Navigation 모드가 아닙니다.
|
||||
- **LNB 크기의 기준은 패키지 토큰입니다.** `@hm-design/ui`의 `--hm-lnb-*`가 정의한 값(Desktop 열 240px, 메뉴 14/28/700, 1뎁스 행 48px, 2·3뎁스 행 42px, Profile 48px, 모바일 Header 56px·링크 44px)을 그대로 씁니다. Storybook 화면에서 눈으로 잰 값이나 과거 예제의 272px·18px·56px를 새로 정하지 않고, `--hm-lnb-width` 등을 소비 CSS에서 다시 정의하지 않습니다. 레이아웃 열은 `var(--hm-lnb-width)`로 읽습니다.
|
||||
|
||||
```tsx
|
||||
// LNB ONLY 골격
|
||||
|
||||
@@ -68,6 +68,7 @@ Brown·Orange 계열 팔레트(`--hm-sem-palette-brown-*`, `--hm-sem-palette-ora
|
||||
| Select Trigger 높이 | medium 34 · large 44(기본) | — |
|
||||
| Control radius | 4px | `--hm-radius-control-md` → `--hm-radius-button`, `--hm-radius-input`, `--hm-radius-select`, `--hm-radius-container` |
|
||||
| Card | border 1px, padding 24px, radius 4px, 그림자 없음 | `--hm-card-*` |
|
||||
| LNB(Desktop) | 열 240px, 메뉴 14/28/700, 1뎁스 행 48 · 2·3뎁스 행 42, Profile 48, 콘텐츠 접점 18. 모바일 Header 56 · 링크 44 | `--hm-lnb-width`, `--hm-lnb-item-*`, `--hm-lnb-subitem-*`, `--hm-lnb-third-*`, `--hm-lnb-profile-min-height`, `--hm-lnb-join` |
|
||||
| Dialog | radius 8px, padding 24px, Header 아래 16px, Footer 위 16px, 버튼 간격 8px, 그림자 `0 0 12px` 검정 20% | `--hm-dialog-*` |
|
||||
|
||||
## 5. 상태
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
Black 10% to the same edge; an open group is a Black 8% face with a 1px green line. Spacing values are pattern-local. */
|
||||
:root, [data-hm-theme] {
|
||||
/* Exposed for the layout: grid column width and the surface that continues behind the content's rounded corners. */
|
||||
--hm-lnb-width: 272px;
|
||||
--hm-lnb-width: 240px;
|
||||
--hm-lnb-join: 18px;
|
||||
--hm-lnb-background: linear-gradient(90deg, var(--hm-sem-action-primary) 0%, var(--hm-sem-palette-green-light-1) 30%, var(--hm-sem-palette-green-light-2) 50%, var(--hm-sem-palette-green-light-3) 90%, var(--hm-sem-palette-green-light-2) 100%);
|
||||
--hm-lnb-background-end: var(--hm-sem-palette-green-light-2);
|
||||
@@ -29,10 +29,12 @@
|
||||
--hm-lnb-brand-name-size: 17px;
|
||||
--hm-lnb-brand-text-gap: 5px;
|
||||
|
||||
--hm-lnb-item-min-height: 56px;
|
||||
--hm-lnb-item-min-height: 48px;
|
||||
/* 1-depth row: 28px line + 2 x 10px = 48px. */
|
||||
--hm-lnb-item-padding-block: 10px;
|
||||
--hm-lnb-item-padding-start: 18px;
|
||||
--hm-lnb-item-gap: 12px;
|
||||
--hm-lnb-item-font-size: 18px;
|
||||
--hm-lnb-item-font-size: 14px;
|
||||
--hm-lnb-item-line-height: 28px;
|
||||
--hm-lnb-item-font-weight: 700;
|
||||
--hm-lnb-item-radius: 4px 0 0 4px;
|
||||
@@ -46,11 +48,38 @@
|
||||
--hm-lnb-current-background: var(--hm-sem-bg-content);
|
||||
--hm-lnb-current-text: var(--hm-sem-action-primary);
|
||||
--hm-lnb-current-radius: 8px 0 0 8px;
|
||||
/* Inset depth of the current face: left edge, top, bottom; the last quarter fades so the content side stays open. */
|
||||
/* Inset depth of the current face (left, top, bottom), matched to the Storybook Manager's selected item: inset box-shadows
|
||||
6px 0 8px -5px Black 30%, 0 3px 5px -3px Black 20% and 0 -2px 4px -3px Black 20%, faded out over the last quarter. A background
|
||||
cannot hold a box-shadow and ::before / ::after already draw the concave corners, so the blurred falloff is sampled as gradient
|
||||
stops (left 10px, top 5px, bottom 4px), and the first layer repaints the face color from 75% to 100% so the depth fades toward
|
||||
the content side. */
|
||||
--hm-lnb-current-depth:
|
||||
linear-gradient(to right, color-mix(in srgb, var(--hm-sem-palette-black) 30%, transparent), transparent 6px) 0 0 / 75% 100% no-repeat,
|
||||
linear-gradient(to bottom, color-mix(in srgb, var(--hm-sem-palette-black) 20%, transparent), transparent 3px) 0 0 / 75% 100% no-repeat,
|
||||
linear-gradient(to top, color-mix(in srgb, var(--hm-sem-palette-black) 20%, transparent), transparent 3px) 0 0 / 75% 100% no-repeat;
|
||||
linear-gradient(to right, transparent, var(--hm-lnb-current-background)) 100% 0 / 25% 100% no-repeat,
|
||||
linear-gradient(to right,
|
||||
color-mix(in srgb, var(--hm-sem-palette-black) 20%, transparent) 0,
|
||||
color-mix(in srgb, var(--hm-sem-palette-black) 15.7%, transparent) 1px,
|
||||
color-mix(in srgb, var(--hm-sem-palette-black) 12.2%, transparent) 2px,
|
||||
color-mix(in srgb, var(--hm-sem-palette-black) 9.5%, transparent) 3px,
|
||||
color-mix(in srgb, var(--hm-sem-palette-black) 7.1%, transparent) 4px,
|
||||
color-mix(in srgb, var(--hm-sem-palette-black) 5%, transparent) 5px,
|
||||
color-mix(in srgb, var(--hm-sem-palette-black) 3.3%, transparent) 6px,
|
||||
color-mix(in srgb, var(--hm-sem-palette-black) 2.2%, transparent) 7px,
|
||||
color-mix(in srgb, var(--hm-sem-palette-black) 1.4%, transparent) 8px,
|
||||
color-mix(in srgb, var(--hm-sem-palette-black) 0.8%, transparent) 9px,
|
||||
transparent 10px),
|
||||
linear-gradient(to bottom,
|
||||
color-mix(in srgb, var(--hm-sem-palette-black) 12%, transparent) 0,
|
||||
color-mix(in srgb, var(--hm-sem-palette-black) 8.5%, transparent) 1px,
|
||||
color-mix(in srgb, var(--hm-sem-palette-black) 5%, transparent) 2px,
|
||||
color-mix(in srgb, var(--hm-sem-palette-black) 2.3%, transparent) 3px,
|
||||
color-mix(in srgb, var(--hm-sem-palette-black) 0.8%, transparent) 4px,
|
||||
transparent 5px),
|
||||
linear-gradient(to top,
|
||||
color-mix(in srgb, var(--hm-sem-palette-black) 9%, transparent) 0,
|
||||
color-mix(in srgb, var(--hm-sem-palette-black) 5.1%, transparent) 1px,
|
||||
color-mix(in srgb, var(--hm-sem-palette-black) 2.4%, transparent) 2px,
|
||||
color-mix(in srgb, var(--hm-sem-palette-black) 0.7%, transparent) 3px,
|
||||
transparent 4px);
|
||||
|
||||
--hm-lnb-group-open-background: color-mix(in srgb, var(--hm-sem-palette-black) 8%, transparent);
|
||||
--hm-lnb-group-open-line: 1px solid var(--hm-sem-palette-green-light-2);
|
||||
@@ -58,14 +87,17 @@
|
||||
--hm-lnb-group-current-text: var(--hm-sem-palette-yellow-accent);
|
||||
--hm-lnb-group-arrow-size: 18px;
|
||||
--hm-lnb-subitem-padding-start: 68px;
|
||||
/* 2-depth row (links directly in a group, nested group triggers): 28px line + 2 x 7px = 42px. */
|
||||
--hm-lnb-subitem-min-height: 42px;
|
||||
--hm-lnb-subitem-padding-block: 7px;
|
||||
/* Align the 2-depth link surface with the 1-depth group text; retain its existing text inset. */
|
||||
--hm-lnb-subitem-surface-inset: calc(var(--hm-lnb-item-padding-start) + var(--hm-lnb-group-arrow-size) + var(--hm-lnb-item-gap));
|
||||
--hm-lnb-group-padding-bottom: 8px;
|
||||
|
||||
/* 3-depth: the items of an `LNBGroup` nested in a group. Same 18px; the hierarchy is the extra 20px indent and the connector
|
||||
(a vertical line at the 2-depth text start, a 12px branch to each row's middle, 8px to the text; it ends at the last row). */
|
||||
--hm-lnb-third-min-height: 48px;
|
||||
--hm-lnb-third-padding-block: 12px;
|
||||
/* 3-depth: the items of an `LNBGroup` nested in a group. Same font size as the other depths; the hierarchy is the extra 20px indent and the connector
|
||||
(a vertical line at the 2-depth text start, a 12px branch to each row's middle, 8px to the text; it ends at the last row). 42px = 24px line + 9px padding x2. */
|
||||
--hm-lnb-third-min-height: 42px;
|
||||
--hm-lnb-third-padding-block: 9px;
|
||||
--hm-lnb-third-padding-start: 88px;
|
||||
--hm-lnb-third-line-height: 24px;
|
||||
--hm-lnb-third-font-weight: 500;
|
||||
@@ -79,6 +111,7 @@
|
||||
--hm-lnb-profile-padding-x: 30px;
|
||||
--hm-lnb-profile-padding-top: 22px;
|
||||
--hm-lnb-profile-gap: 12px;
|
||||
--hm-lnb-profile-min-height: 48px;
|
||||
--hm-lnb-profile-name-size: 16px;
|
||||
--hm-lnb-profile-description-size: 12px;
|
||||
}
|
||||
@@ -150,7 +183,7 @@
|
||||
max-width: calc(100% - 2 * (var(--hm-lnb-profile-padding-x) - 8px));
|
||||
margin-top: auto;
|
||||
margin-inline: calc(var(--hm-lnb-profile-padding-x) - 8px);
|
||||
min-height: var(--hm-lnb-third-min-height);
|
||||
min-height: var(--hm-lnb-profile-min-height);
|
||||
padding: 0 8px;
|
||||
border: 0;
|
||||
background: transparent;
|
||||
@@ -211,7 +244,7 @@
|
||||
gap: var(--hm-lnb-item-gap);
|
||||
width: calc(100% - 1px);
|
||||
min-height: var(--hm-lnb-item-min-height);
|
||||
padding: 14px calc(var(--hm-lnb-inset-end) + 12px) 14px var(--hm-lnb-item-padding-start);
|
||||
padding: var(--hm-lnb-item-padding-block) calc(var(--hm-lnb-inset-end) + 12px) var(--hm-lnb-item-padding-block) var(--hm-lnb-item-padding-start);
|
||||
border: 0;
|
||||
border-radius: var(--hm-lnb-item-radius);
|
||||
background: transparent;
|
||||
@@ -329,6 +362,13 @@
|
||||
[data-slot="lnb-group-content"] [data-slot="lnb-item"]:not([aria-current="page"]):hover {
|
||||
border-radius: var(--hm-lnb-item-radius);
|
||||
}
|
||||
/* 2-depth rows (links directly in a group, nested group triggers): 42px = 28px line + 2 x 7px. */
|
||||
[data-slot="lnb-group-content"] > [data-slot="lnb-item"],
|
||||
[data-slot="lnb-group-content"] [data-slot="lnb-group-trigger"] {
|
||||
min-height: var(--hm-lnb-subitem-min-height);
|
||||
padding-top: var(--hm-lnb-subitem-padding-block);
|
||||
padding-bottom: var(--hm-lnb-subitem-padding-block);
|
||||
}
|
||||
[data-slot="lnb-group-content"] [data-slot="lnb-item"][aria-current="page"] {
|
||||
width: calc(100% + 1px);
|
||||
margin-right: -1px;
|
||||
|
||||
Reference in new issue
Block a user