// Basic 레이아웃 사이드바 — 시안: 통합관리자페이지 디자인시스템(KE9UILWhB8qTBe14uXUn4F) // snb-area 3041:11860 // // 시안에서 디자인시스템 컴포넌트로 정의된 건 btn-ico(FoxIconButton)와 아이콘들뿐이고, 1·2·3depth // 항목은 @fox에 없어 사이드바 전용으로 짰다(사용자 확정). 색·간격·radius·타이포는 전부 @fox // 토큰을 거치므로 없는 이름을 쓰면 빌드가 실패한다. @use "@fox/styles/abstracts" as fox; // 여기 그리는 모든 조각은 테두리·안쪽 여백을 폭에 포함해 센다. 시안이 그 기준으로 그려져 // 있는데(Figma stroke는 안쪽) 앱에 전역 리셋이 없어 기본값이 `content-box`다 — 그대로 두면 // `inline-size: 100%`에 패딩이 더해져 항목이 부모보다 넓어진다. .sidebar, .sidebar *, .sidebar *::before, .sidebar *::after { box-sizing: border-box; } .sidebar { box-sizing: border-box; display: flex; flex-direction: column; flex-shrink: 0; // 시안 240px. Figma가 변수로 export하지 않는다. inline-size: 24rem; padding: fox.padding(5); // 시안 240은 구분선을 포함한 값이라 `border`로 그리면 안쪽 폭이 216에서 215로 줄어든다. // 레이아웃에 관여하지 않는 inset 그림자로 같은 선을 그린다(헤더 프로필 pill과 같은 처리). box-shadow: inset calc(-1 * #{fox.border(1)}) 0 0 0 fox.color(border-neutral-subtler); // 시안은 회색에서 시작해 70% 지점부터 옅은 파랑으로 넘어간다. background: linear-gradient( to bottom, fox.color(surface-neutral-gray) 70%, fox.color(surface-theme-primary) ); overflow-y: auto; } // ── 상단: 검색 + 사이드바 토글 ─────────────────────────────────────────────── .top { display: flex; align-items: center; gap: fox.gap(2); padding-block-end: fox.spacing(bottom-md); } .search { flex: 1 0 0; min-inline-size: 0; } // FoxInput의 기본 테두리는 input-border(진한 회색)인데 시안 검색창은 border-neutral-subtler다. // 크기·radius·안쪽 여백은 md가 이미 시안과 같아 색만 덮는다. 명시도가 같아 로드 순서에 // 좌우되지 않도록 `:global()`을 겹쳐 이기게 한다. .search :global(.fox-input__box) { border-color: fox.color(border-neutral-subtler); } // ── 섹션 ──────────────────────────────────────────────────────────────────── .section { display: flex; flex-direction: column; align-items: flex-start; padding-block-end: fox.spacing(bottom-md); } // 즐겨찾기만 아래 구분선이 있고 위 여백이 없다. .sectionFavorites { padding-block-end: fox.spacing(bottom-sm); border-block-end: fox.border(1) solid fox.color(border-neutral-subtle); } .sectionNav { padding-block-start: fox.spacing(top-sm); } .sectionTitle { inline-size: 100%; margin: 0; padding-block-end: fox.spacing(bottom-sm); color: fox.color(font-neutral-subtler); font-family: fox.font-family(title); font-size: fox.font-size(heading-2xsm); font-weight: fox.font-weight(bold); line-height: 1.4; letter-spacing: -0.025em; } .list { display: flex; inline-size: 100%; flex-direction: column; align-items: flex-start; margin: 0; padding: 0; list-style: none; } // ── 즐겨찾기 항목 ─────────────────────────────────────────────────────────── .favorite { display: flex; inline-size: 100%; align-items: center; gap: fox.gap(2); padding-block: fox.padding(1); padding-inline: fox.padding(2); color: fox.color(font-neutral-subtle); font-family: fox.font-family(body); // 시안 13px. heading/2xsm과 값이 같지만 이쪽은 본문 계열이라 리터럴로 둔다. font-size: 1.3rem; line-height: 1.5; letter-spacing: -0.025em; text-decoration: none; } // ── 1depth ────────────────────────────────────────────────────────────────── .item { inline-size: 100%; } .itemButton { display: flex; inline-size: 100%; align-items: center; gap: fox.gap(2); padding-block: fox.padding(4); padding-inline: fox.padding(3); border: none; border-radius: fox.radius(3); background: fox.color(action-secondary); color: fox.color(font-neutral-subtle); font-family: fox.font-family(title); // 시안 14px. font-size: 1.4rem; font-weight: fox.font-weight(bold); line-height: 1.4; letter-spacing: -0.025em; text-align: start; text-decoration: none; cursor: pointer; // 시안이 배경 위에 곱하기로 얹는다 — 그라데이션 위에서 색이 겹쳐 보이게 한다. mix-blend-mode: multiply; } .itemButtonActive { background: fox.color(action-secondary-active); color: fox.color(font-neutral-strong-inverse); // 활성 항목은 배경을 그대로 덮는다. mix-blend-mode: normal; } .itemIcon { display: inline-flex; flex-shrink: 0; inline-size: fox.icon(4); block-size: fox.icon(4); } .itemIcon > svg { inline-size: 100%; block-size: 100%; } .itemLabel { flex: 1 0 0; min-inline-size: 0; } // ── 2depth ────────────────────────────────────────────────────────────────── .childGroup { display: flex; inline-size: 100%; flex-direction: column; align-items: flex-start; margin: fox.gap(2) 0 0; padding: fox.padding(3); border-radius: fox.radius(3); // 시안의 2depth-list가 200인데 `border`로 그리면 216에서 테두리 2px을 더 빼 198이 된다. // 사이드바 바깥 구분선과 같은 이유로 inset 그림자를 쓴다(Figma stroke는 안쪽이다). box-shadow: inset 0 0 0 fox.border(1) fox.color(border-neutral-subtler); background: fox.color(surface-neutral-default); list-style: none; } .child { inline-size: 100%; } .childRow { display: flex; inline-size: 100%; align-items: center; gap: fox.gap(2); padding-block: fox.padding(2); padding-inline: fox.padding(3); border: none; border-radius: fox.radius(3); background: fox.color(action-secondary); color: fox.color(font-neutral-default); font-family: fox.font-family(title); font-size: 1.4rem; font-weight: fox.font-weight(bold); line-height: 1.4; letter-spacing: -0.025em; text-align: start; text-decoration: none; cursor: pointer; } .childRowActive { color: fox.color(font-theme-secondary); } // 시안은 별·캐럿 자리를 항상 잡아 두고 필요 없을 때 투명하게만 만든다 — 라벨 시작 위치가 // 항목마다 흔들리지 않게 하기 위해서다. .childMark { display: inline-flex; flex-shrink: 0; inline-size: fox.icon(2); block-size: fox.icon(2); } .childMark > svg { inline-size: 100%; block-size: 100%; } .childMarkHidden { opacity: 0; } .childLabel { flex: 1 0 0; min-inline-size: 0; } // ── 3depth ────────────────────────────────────────────────────────────────── .leafGroup { display: flex; inline-size: 100%; flex-direction: column; align-items: flex-start; margin: 0; padding-block: fox.padding(2); padding-inline-start: fox.padding(7); padding-inline-end: fox.padding(2); border-radius: fox.radius(3); list-style: none; } .leaf { display: flex; inline-size: 100%; align-items: center; gap: fox.gap(2); padding-block: fox.padding(1); padding-inline: fox.padding(2); color: fox.color(font-neutral-subtle); font-family: fox.font-family(body); font-size: 1.3rem; line-height: 1.5; letter-spacing: -0.025em; text-decoration: none; } .leafActive { color: fox.color(font-theme-secondary); }