// Basic 레이아웃 헤더 — 시안: 통합관리자페이지 디자인시스템(KE9UILWhB8qTBe14uXUn4F) // header (7028:7614 · 컴포넌트 7001:10471) // // 시안에서 디자인시스템 컴포넌트로 정의된 조각은 아이콘 4종과 badge-dot뿐이다. 로고 영역· // 아이콘 버튼·프로필 pill은 header 안의 로컬 프레임이라 @fox로 승격하지 않고 여기서 조립한다. // 색·간격·radius·타이포는 전부 @fox 토큰을 거친다. @use "@fox/styles/abstracts" as fox; .header { // 시안 높이 64는 테두리를 포함한 값이다(Figma stroke는 안쪽에 그린다). box-sizing: border-box; display: flex; flex-shrink: 0; align-items: center; justify-content: space-between; // 시안 64px. Figma가 변수로 export하지 않는다. block-size: 6.4rem; padding-inline: fox.padding(8); border-block-end: fox.border(1) solid fox.color(border-neutral-subtler); background: fox.color(surface-neutral-default); } // ── 로고 ──────────────────────────────────────────────────────────────────── // 시안: 관리자페이지(QsFVFFUKGH68xAPVkF3SJ9) logo 5199:9639 — 정사각 심볼 + 2색 글자. .logo { display: flex; align-items: center; gap: fox.gap(3); } .logoMark { display: block; // 시안 28.12×28. 가로세로를 둘 다 적어야 ``의 width/height 속성에서 나오는 1:1 // 기본 비율에 눌리지 않는다. Figma가 변수로 export하지 않는 값이다. inline-size: 2.812rem; block-size: 2.8rem; } .title { font-family: fox.font-family(title); // 시안 24px / letter-spacing -0.6px(= -0.025em). Figma가 변수로 export하지 않는다. font-size: 2.4rem; font-weight: fox.font-weight(bold); line-height: 1.5; letter-spacing: -0.025em; white-space: nowrap; } // 제품명은 진하게, 역할(ADMIN)은 흐리게 — 시안이 두 색을 나눠 쓴다. .titleStrong { color: fox.color(font-neutral-strong); font-weight: fox.font-weight(bold); } .titleSub { color: fox.color(font-neutral-subtler); font-weight: fox.font-weight(medium); } // ── 우측 기능 영역 ────────────────────────────────────────────────────────── .fnc { display: flex; align-items: center; justify-content: flex-end; gap: fox.gap(5); } .btnGroup { // 알림 패널이 이 묶음 기준으로 떠야 해서 위치 기준을 만든다(프로필과 같은 처리). position: relative; display: flex; align-items: center; gap: fox.gap(2); } // ── 알림 패널 ─────────────────────────────────────────────────────────────── // 뜨는 모양은 프로필 메뉴와 같게 두고 폭·높이만 목록에 맞춘다. .notifications { position: absolute; inset-block-start: calc(100% + #{fox.gap(2)}); inset-inline-end: 0; z-index: 1; // 시안에 알림 패널이 없어 폭은 목록이 읽히는 선에서 잡았다(사용자 확정 전 잠정값). inline-size: 32rem; max-block-size: 40rem; overflow-y: auto; @include fox.scroll; padding-block: fox.padding(2); border: fox.border(1) solid fox.color(border-neutral-default); border-radius: fox.form(radius-md); background: fox.color(surface-neutral-default); box-shadow: fox.shadow(location1) fox.shadow(location1) fox.shadow(blur1) 0 fox.primitive(alpha-black10); } .notificationList { margin: 0; padding: 0; list-style: none; } .notification { display: flex; flex-direction: column; gap: fox.gap(1); padding-block: fox.padding(3); padding-inline: fox.padding(4); } // 안 읽은 알림은 왼쪽에 표시선을 둔다 — 점을 따로 그리면 글자 시작 위치가 줄마다 어긋난다. .notificationUnread { box-shadow: inset #{fox.border(2)} 0 0 0 fox.color(border-theme-primary); background: fox.color(surface-theme-primary); } .notificationTitle { color: fox.color(font-neutral-strong); font-family: fox.font-family(body); font-size: fox.font-size(label-md); font-weight: fox.font-weight(medium); line-height: 1.4; letter-spacing: -0.025em; } .notificationLink { color: inherit; text-decoration: none; cursor: pointer; &:hover { background: fox.color(action-default-hover); } &.notificationUnread:hover { background: fox.color(action-primary-pressed); } &:focus-visible { outline: fox.border(2) solid fox.color(border-theme-primary); outline-offset: calc(-1 * #{fox.border(2)}); } } .notificationContent { display: -webkit-box; overflow: hidden; color: fox.color(font-neutral-subtle); font-family: fox.font-family(body); font-size: fox.font-size(body-sm); line-height: 1.5; letter-spacing: -0.025em; word-break: break-word; -webkit-box-orient: vertical; -webkit-line-clamp: 2; } .notificationEmpty { margin: 0; padding-block: fox.padding(5); padding-inline: fox.padding(4); color: fox.color(font-neutral-subtle); font-family: fox.font-family(body); font-size: fox.font-size(body-sm); line-height: 1.5; letter-spacing: -0.025em; text-align: center; } // ── 프로필 ────────────────────────────────────────────────────────────────── // 메뉴가 이 버튼 기준으로 떠야 해서 위치 기준을 만든다. .profile { position: relative; } .profileButton { display: flex; align-items: center; gap: fox.gap(2); padding-block: fox.padding(3); padding-inline: fox.padding(4); border: none; border-radius: fox.radius(max); // 시안 높이 44 = 상하 여백 8 + 아바타 28. Figma stroke가 안쪽이라 테두리가 높이를 늘리지 // 않는다 — `border`를 쓰면 46이 되므로 레이아웃에 관여하지 않는 inset 그림자로 같은 선을 // 그린다. box-shadow: inset 0 0 0 fox.border(1) fox.color(border-neutral-subtle); background: fox.color(action-default); cursor: pointer; } .avatar { display: inline-flex; flex-shrink: 0; align-items: center; justify-content: center; // 시안 28px 원형 + 내부 20px. Figma가 변수로 export하지 않는다. inline-size: 2.8rem; block-size: 2.8rem; border-radius: fox.radius(max); background: fox.theme(primary-10); color: fox.color(icon-neutral-default); } // 시안은 이 자리에 프로필 사진을 넣지만 관리자 사진을 받는 경로가 없어 사람 아이콘으로 채운다. .avatar > svg { inline-size: 2rem; block-size: 2rem; } .profileName { color: fox.color(font-neutral-subtle); font-family: fox.font-family(body); font-size: fox.font-size(label-md); font-weight: fox.font-weight(medium); line-height: 1; letter-spacing: -0.025em; white-space: nowrap; } .caret { display: inline-flex; flex-shrink: 0; inline-size: fox.icon(3); font-size: fox.icon(3); block-size: fox.icon(3); color: fox.color(icon-neutral-default); } .caret > svg { inline-size: 100%; block-size: 100%; } // ── 프로필 메뉴 ───────────────────────────────────────────────────────────── // ⚠️ 시안에 없는 부분이다. 시안의 pill은 CaretDown만 있고 열린 모습이 그려져 있지 않아, // 판때기는 FoxSelectOption(떠 있는 목록)이 쓰는 것과 같은 토큰 조합으로 맞췄다. .menu { position: absolute; inset-block-start: calc(100% + #{fox.gap(2)}); inset-inline-end: 0; z-index: 1; min-inline-size: 100%; padding-block: fox.padding(2); border: fox.border(1) solid fox.color(border-neutral-default); border-radius: fox.form(radius-md); background: fox.color(surface-neutral-default); // 그림자 색은 FoxSelectOption과 같은 값을 쓴다 — 시안이 테마 토큰이 아니라 원시값에 // 물려 놓아서 다크 모드에서도 검은 그림자다. box-shadow: fox.shadow(location1) fox.shadow(location1) fox.shadow(blur1) 0 fox.primitive(alpha-black10); } .menuItem { display: flex; inline-size: 100%; align-items: center; padding-block: fox.padding(3); padding-inline: fox.padding(4); border: none; background: none; color: fox.color(font-neutral-default); font-family: fox.font-family(body); font-size: fox.font-size(label-md); font-weight: fox.font-weight(regular); line-height: 1; letter-spacing: -0.025em; white-space: nowrap; cursor: pointer; &:hover { background: fox.color(action-default-hover); } }