Groo Design

Side Panel

화면 옆(왼쪽 · 오른쪽)에서 미끄러져 나오는 모달 패널. 지금 쓰는 곳은 HR 폰(768 미만)의 주 메뉴 서랍 하나다 — ☰ 를 누르면 왼쪽에서 나와 Side Navigation 의 항목을 보인다. 오른쪽 패널(1280 이상의 보조 작업)은 쓰는 곳이 아직 없다. 아래에서 올라오는 모달은 Bottom Sheet, 가운데 대화상자는 Dialog 다. 이동 부품(하단 탭 바 · 사이드바 · 상단 바 · Tabs)과 고르는 표는 DESIGN.md Layout 의 "이동 부품 고르기" 한 곳이다.

구조는 당근 SEED Side Panel(Apache-2.0)을 따른다 — "화면의 측면에서 슬라이드되어 나타나며, 현재 맥락을 유지한 채 상세 정보를 확인하거나 부수적인 작업을 수행하는 레이아웃 컴포넌트" 로, 딤 · 패널 · 머리(제목 · 설명 · 닫기) · 본문 · 바닥, 크기 480 · 720 · 960 · 768 미만 80%, 높이 전체, 모서리 · 그림자 · 선 없음. 값은 groo 토큰이고, SEED 와 다른 자리는 맨 아래 "SEED 와 다른 점" 에 적었다(2026-10-04 사용자 결정). 옛 Sheet 스펙(shadcn — 네 방향 · 75% · 384 · 그림자 · 선)을 대신한다 — 아래는 Bottom Sheet 가 맡고, 위에서 내려오는 패널은 걷었다.

수치 원본은 side-panel.yaml이다. 수치 표 자리([표: …])와 그림 자리([그림: …])는 사이트가 그 파일로 그린다 — GitHub 에서는 그 파일 · 그림 코드로 가는 링크로 보인다.

9:41
휴가 현황
남은 연차11.5일
휴가 내역
연연차2026-09-21, 1일승인
반반차(오후)2026-09-04, 0.5일승인
연연차2026-08-18, 2일승인
병병가2026-07-31, 1일승인
연연차2026-07-10, 1일반려
그루 이음
근무
관리
desk.groo.app
그루 담다
워크스페이스
기록
설정
알림 설정
알림을 받을 때를 골라요.
카드 결제 예정
예산을 넘었을 때
일정 알림
더치페이 요청
증권 연결이 끊겼을 때
공지사항
주간 리포트
월간 리포트
새 기능 소식
로그인 알림
9:41
휴가 현황
남은 연차11.5일
휴가 내역
연연차2026-09-21, 1일승인
반반차(오후)2026-09-04, 0.5일승인
연연차2026-08-18, 2일승인
병병가2026-07-31, 1일승인
연연차2026-07-10, 1일반려
그루 이음
근무
관리
desk.groo.app
그루 담다
워크스페이스
기록
설정
알림 설정
알림을 받을 때를 골라요.
카드 결제 예정
예산을 넘었을 때
일정 알림
더치페이 요청
증권 연결이 끊겼을 때
공지사항
주간 리포트
월간 리포트
새 기능 소식
로그인 알림
HR 폰 주 메뉴 서랍 · 1280 오른쪽 패널 — 라이트 · 다크

직접 골라 보기

방향(왼쪽 주 메뉴 · 오른쪽 패널) · 크기 · 설명 · 본문 길이 · 바닥 버튼을 고르면 스펙대로 그린 패널과 그 코드가 바뀐다. 실제로 열고, 끌어 닫고, 본문을 스크롤할 수 있다.

휴가 현황
연차2026-09-21
반차(오후)2026-09-04
연차2026-08-18
병가2026-07-31
☰ 를 누르면 왼쪽에서 열린다 — 딤 · Esc · 왼쪽으로 끌기(손가락 · 펜)로 닫힌다. 항목을 누르면 이동하고 닫힌다.
방향
왼쪽 서랍은 크기와 상관없이 화면 폭의 80% 다.
본문
모드
import { SidePanel, SidePanelBody, SidePanelContent } from "@/components/ui/side-panel"
import { SideNavigationContent, SideNavigationGroup, SideNavigationItem, SideNavigationSubItem } from "@/components/ui/side-navigation"

<SidePanel open={menuOpen} onOpenChange={setMenuOpen}>
  <SidePanelContent side="left" title="그루 이음" id="main-menu">
    <SidePanelBody scrollFog className="px-x4">
      {/* 사이드바와 같은 항목 — 지금 묶음은 저절로 펼쳐지고, 항목을 누르면 이동하고 닫힌다 */}
      <SideNavigationContent onNavigate={() => setMenuOpen(false)}>…</SideNavigationContent>
    </SidePanelBody>
  </SidePanelContent>
</SidePanel>

Anatomy

설정
알림 설정
알림을 받을 때를 골라요.
카드 결제 예정
예산을 넘었을 때
일정 알림
더치페이 요청
증권 연결이 끊겼을 때
공지사항
ⓐ Overlay — 딤ⓑ Container — 높이 전체 · 모서리 없음ⓒ Headerⓓ Bodyⓔ Footer
패널은 딤 · 패널 · 머리(제목 · 설명 · 닫기) · 본문 · 바닥으로, 높이 전체 · 모서리 없음
부위설명
ⓐ Overlay딤 — 패널 뒤 화면 전체. 입력 폼이 아니면 누르면 닫힌다.
ⓑ Container패널 — 왼쪽 또는 오른쪽 끝, 높이 전체. 모서리 · 그림자 · 선 없이 딤과 면 색으로 뜬다.
ⓒ Header머리 — 제목(늘 있다) · 설명(있을 때만) · 닫기 버튼.
ⓓ Body본문 — 넘치면 이 안에서만 스크롤한다. 스크롤되면 머리 아래 1px 선.
ⓔ Footer바닥 — 버튼, 오른쪽 정렬(오른쪽 패널).

부위

부위설명
overlay딤 — 패널 뒤 화면 전체. 입력 폼이 아니면 누르면 닫힌다
root패널 — 화면 높이 전체, 왼쪽 또는 오른쪽 끝에 붙는다. 모서리 · 그림자 · 선 없음
header머리 — 제목 · 설명 · 닫기
title제목 — 늘 있다(패널의 이름)
description설명 — 덧붙일 말이 있을 때만
closeButton닫기 — 투명 상자 52 · 아이콘 22. 이름 "닫기"
divider머리 아래 선 — 본문이 스크롤됐을 때만
body본문 — 넘치면 이 안에서만 스크롤(머리 · 바닥은 고정)
fog끝 흐림 — Scroll Fog(scroll-fog.yaml 의 overlayBody). 넘칠 수 있는 본문에만 걸고, 걸면 늘 켜져 있다
footer바닥 — 버튼, 오른쪽 정렬(오른쪽 패널)
focusRing키보드 포커스 링(웹)

Properties

방향

방향쓰는 곳폭
left768 미만의 주 메뉴 서랍 — 지금 HR 폰 하나화면 폭의 80%
right1280 이상의 보조 작업 — 쓰는 곳 없음크기(480 · 720 · 960)

왼쪽은 내비게이션(SEED — "모바일 사이드바, 글로벌 내비게이션 메뉴"), 오른쪽은 상세 조회 · 설정 같은 보조 작업이다. 아래에서 올라오는 패널은 Bottom Sheet 이고, 위에서 내려오는 패널은 두지 않는다.

9:41
휴가 현황
남은 연차11.5일
휴가 내역
연연차2026-09-21, 1일승인
반반차(오후)2026-09-04, 0.5일승인
연연차2026-08-18, 2일승인
병병가2026-07-31, 1일승인
연연차2026-07-10, 1일반려
그루 이음
근무
관리
왼쪽 — 화면 폭의 80%(HR 폰 주 메뉴)
desk.groo.app
그루 담다
워크스페이스
기록
설정
알림 설정
알림을 받을 때를 골라요.
카드 결제 예정
예산을 넘었을 때
일정 알림
더치페이 요청
증권 연결이 끊겼을 때
공지사항
주간 리포트
월간 리포트
새 기능 소식
로그인 알림
오른쪽 — 1280 이상의 보조 작업, medium 720
방향 — 왼쪽 주 메뉴 80% · 오른쪽 720

방향

side너비자리title 글자body 좌우 여백설명
left화면 폭의 80% — 768 미만에서만 쓴다 — 딤이 오른쪽 20% 에 남는다. 크기(480 · 720 · 960)는 오른쪽 패널만 쓴다왼쪽 끝 — 왼쪽으로 끌면 닫힌다text-t8 22px / 30px — 서비스 이름("그루 이음") — 주 메뉴 서랍의 제목spacing-x4 16px — 주 메뉴 — Side Navigation 의 항목(좌우 8)이 들어와 아이콘이 제목과 같은 24 에서 선다왼쪽 — 768 미만의 주 메뉴 서랍(지금 HR 폰)
right (기본)—오른쪽 끝 — 1280 이상 — 미만에서는 같은 내용을 Bottom Sheet 로——오른쪽 — 1280 이상의 보조 작업(쓰는 곳 없음)

크기

오른쪽 패널의 폭이다 — small 480(단순한 상세) · medium 720 (기본)(두 줄 폼 · 목록과 상세 나란히) · large 960(복잡한 설정). 어느 크기든 화면의 80% 를 넘지 않아 딤이 늘 20% 남는다. 높이는 화면 전체다.

desk.groo.app
그루 담다
워크스페이스
기록
설정
알림 설정
카드 결제 예정
예산을 넘었을 때
일정 알림
더치페이 요청
증권 연결이 끊겼을 때
공지사항
주간 리포트
월간 리포트
새 기능 소식
로그인 알림
small 480 — 화면의 80% 를 넘지 않는다
desk.groo.app
그루 담다
워크스페이스
기록
설정
알림 설정
카드 결제 예정
예산을 넘었을 때
일정 알림
더치페이 요청
증권 연결이 끊겼을 때
공지사항
주간 리포트
월간 리포트
새 기능 소식
로그인 알림
medium 720 (기본) — 화면의 80% 를 넘지 않는다
desk.groo.app
그루 담다
워크스페이스
기록
설정
알림 설정
카드 결제 예정
예산을 넘었을 때
일정 알림
더치페이 요청
증권 연결이 끊겼을 때
공지사항
주간 리포트
월간 리포트
새 기능 소식
로그인 알림
large 960 — 화면의 80% 를 넘지 않는다
크기 — 480 · 720 · 960, 1280 화면에서

크기

size너비설명
small480px480 — 단순한 상세 조회
medium (기본)720px720 — 기본. 두 줄 폼 · 목록과 상세 나란히
large960px960 — 복잡한 설정 · 편집 도구

머리 · 본문 · 바닥

머리는 위 24 · 좌우 24 · 아래 16 · 최소 70, 제목 22 / 30 · 700 · 설명 16 / 22(fg-neutral-muted) · 사이 6 이다. 닫기 버튼은 투명 상자 52 · 아이콘 22(fg-neutral-subtle)이고 아이콘이 위 28 · 오른쪽 24 에 놓인다 — Dialog 의 닫기와 같다. 본문은 좌우 24 이고 넘치면 본문만 스크롤된다 — 위로 스크롤하면 머리 아래 1px 선이 생긴다. 바닥은 위 16 · 좌우 24 · 아래 24 에 Button small 36 을 오른쪽으로 모은다. 머리 위에는 위 안전 영역을, 패널 맨 아래에는 아래 안전 영역을 더한다(바닥이 없어도).

알림 설정
알림을 받을 때를 골라요.
카드 결제 예정
예산을 넘었을 때
일정 알림
더치페이 요청
증권 연결이 끊겼을 때
공지사항
주간 리포트
월간 리포트
머리 위 24 · 좌우 24 · 아래 16, 제목 22 / 30 · 700 · 설명 16 / 22 · 사이 6. 닫기 상자 52 · 아이콘 22(위 28 · 오른쪽 24). 본문 좌우 24, 바닥 위 16 · 아래 24 · 버튼 사이 8
알림 설정
알림을 받을 때를 골라요.
카드 결제 예정
예산을 넘었을 때
일정 알림
더치페이 요청
증권 연결이 끊겼을 때
공지사항
주간 리포트
월간 리포트
본문을 위로 스크롤하면 머리 아래 1px 선(점선 자리)
머리 · 본문 · 바닥의 여백, 스크롤하면 머리 아래 선

공통

부위속성값비고
overlay배경overlay-dim-light rgba(0, 0, 0, 0.50) · 다크 overlay-dim-dark rgba(0, 0, 0, 0.65)groo 딤(v102) — SEED 0.455 는 들이지 않았다
overlayz-index100z-modal — specs/z-index.md L2
root높이화면 높이 전체dvh — 방향과 상관없이(SEED)
root최대 너비80%딤이 늘 20% 남는다(SEED 코드). 768 미만이면 크기와 상관없이 화면 폭의 80%
root모서리0px평평 — 모서리 · 그림자 · 선 없이 딤과 면 색으로 뜬다(SEED)
root배경color-bg-layer-floating #FFFFFF · 다크 #2D3346
root그림자none
root아래 여백아래 안전 영역패널 내용의 맨 아래 — 바닥이 없어도(SEED). 붙은 쪽 안전 영역(가로 노치)은 폭에 더한다
rootz-index101z-modal-content — specs/z-index.md L2
header위 여백spacing-x6 24px위 안전 영역을 더한다
header좌우 여백spacing-x6 24px
header아래 여백spacing-x4 16px
header최소 높이70px제목 한 줄 + 위아래 — 닫기 버튼 상자가 들어간다
header간격spacing-x1_5 6px제목 ↔ 설명. 닫기 버튼이 있으면 오른쪽 52(24 + 아이콘 22 + 6)
title글자text-t8 22px / 30px
title굵기700
title글자·아이콘color-fg-neutral #1A1F2E · 다크 #F5F6FA
description글자text-t5 16px / 22px
description굵기400
description글자·아이콘color-fg-neutral-muted #535866 · 다크 #B7BDCC
closeButton크기52px투명 상자 — 보이는 건 아이콘 22(Dialog 의 닫기와 같다)
closeButton모서리radius-r3 12px
closeButton아이콘 크기22pxlucide x
closeButton색color-fg-neutral-subtle #62697A · 다크 #A2A8B7
closeButton위 거리28px아이콘이 패널 위에서 28 · 오른쪽 24 — 상자는 위 13 · 오른쪽 9. 제목 첫 줄 가운데와 맞는다
closeButton오른쪽 거리spacing-x6 24px
closeButton터치 영역52 × 52
closeButton전환 대상background-color, scale
closeButton전환 시간motion-duration-color-transition 150ms
closeButton전환 곡선motion-ease-easing cubic-bezier(0.35, 0, 0.35, 1)
divider높이1px
divider배경color-stroke-neutral-subtle #EDEFF3 · 다크 #353B4D머리 아래 — 본문이 위 끝에서 떨어지면 나타난다(SEED). SEED stroke.neutral-muted 의 불투명 짝
divider전환 시간motion-duration-color-transition 150ms
divider전환 곡선motion-ease-easing cubic-bezier(0.35, 0, 0.35, 1)
body좌우 여백spacing-x6 24px
body아래 여백spacing-x6 24px바닥이 없을 때만 — 바닥이 있으면 0
body세로 넘침auto
footer위 여백spacing-x4 16px
footer좌우 여백spacing-x6 24px
footer아래 여백spacing-x6 24px
footer간격spacing-x2 8px
footer가로 맞춤flex-end오른쪽 정렬 — [취소] [저장](Dialog 와 같다)
footer버튼 크기small 36Button small — 1280 이상의 오른쪽 패널

본문 끝 흐림

넘칠 수 있는 본문(주 메뉴 · 목록 · 긴 폼)은 Scroll Fog 를 건다(scrollFog) — 위 20 · 아래 80 이 늘 흐리고 본문 안에 그만큼 여백을 둔다. 시트 · 대화상자와 같은 규칙이다(SEED Side Panel 의 늘 켜진 아래 48 대신). 칸 두셋처럼 늘 들어맞는 본문에는 걸지 않는다.

본문 끝 흐림

scrollFogbody 위 여백body 아래 여백body 스크롤 여유fog 크기fog 마스크설명
off (기본)—————기본 — 늘 들어맞는 본문
on20px — 머리 아래 16 은 그대로 두고 본문 안에 더한다80px — 바닥이 있어도 — 끝까지 내려도 마지막 줄이 흐림 아래 남지 않는다위 20px · 아래 80px — 키보드로 옮긴 칸이 흐림 아래 멈추지 않게위 20px · 아래 80px — 본문 상자의 위 · 아래 끝gradient-fade-mask — Scroll Fog overlayBody(scroll-fog.yaml) — 늘 켜져 있다. SEED Side Panel 의 아래 48 대신넘칠 수 있는 본문(주 메뉴 · 목록 · 긴 폼) — 위 20 · 아래 80 이 늘 흐리다

State

상태모습
enabled열림 — 딤 위 패널
scrolled본문이 위로 스크롤됨 — 머리 아래 1px stroke-neutral-subtle
pressed닫기 버튼 — bg-layer-floating-pressed + 2px 거리 축소
focused키보드 포커스에만 링 2px · 띄움 2px

상태

상태closeButton 배경closeButton 배율divider 배경divider 불투명도링 두께링 간격링 색
enabled 열림——color-stroke-neutral-subtle #EDEFF3 · 다크 #353B4D — 머리 아래 — 본문이 위 끝에서 떨어지면 나타난다(SEED). SEED stroke.neutral-muted 의 불투명 짝————
scrolled 본문이 위로 스크롤됨 — 머리 아래 선——color-stroke-neutral-subtle #EDEFF3 · 다크 #353B4D — 머리 아래 — 본문이 위 끝에서 떨어지면 나타난다(SEED). SEED stroke.neutral-muted 의 불투명 짝1 — 본문을 위로 스크롤하면 나타난다———
pressed 닫기 버튼 누름 — 바탕 + 2px 거리 축소color-bg-layer-floating-pressed #F7F8FD · 다크 #353B4D — SEED bg.transparent-pressed 의 떠 있는 표면 짝(v102)2px 거리 축소 — 기준 52 → 0.962 — 모션 줄이기면 하지 않는다color-stroke-neutral-subtle #EDEFF3 · 다크 #353B4D — 머리 아래 — 본문이 위 끝에서 떨어지면 나타난다(SEED). SEED stroke.neutral-muted 의 불투명 짝————
focused 웹 — 키보드 포커스에만 링——color-stroke-neutral-subtle #EDEFF3 · 다크 #353B4D — 머리 아래 — 본문이 위 끝에서 떨어지면 나타난다(SEED). SEED stroke.neutral-muted 의 불투명 짝—2px2pxcolor-stroke-focus-ring #1A1F2E · 다크 #F5F6FA

모션

전환시간곡선대상비고
열림 — 패널motion-duration-d6 300msmotion-ease-enter-expressive cubic-bezier(0.03, 0.4, 0.1, 1)translateX ∓100% → 0붙은 쪽에서 미끄러져 들어온다(SEED). 모션 줄이기면 150ms 서서히 나타남(v104)
열림 — 딤motion-duration-d6 300msmotion-ease-enter cubic-bezier(0, 0, 0.15, 1)opacity 0 → 1
닫힘 — 패널motion-duration-d6 300msmotion-ease-exit-expressive cubic-bezier(0.35, 0, 0.95, 0.55)translateX → ∓100%끌다 놓아 되돌아갈 때도 같은 시간
닫힘 — 딤motion-duration-d6 300msmotion-ease-exit cubic-bezier(0.35, 0, 1, 1)opacity → 0
머리 아래 선motion-duration-color-transition 150msmotion-ease-easing cubic-bezier(0.35, 0, 0.35, 1)box-shadow
누름 — 닫기 버튼motion-duration-pressed-scale 150msmotion-ease-pressed-scale cubic-bezier(0, 0, 0.15, 1)scale

Guidelines

쓰는 자리

이런 일768 미만768 ~ 12791280 이상
주 메뉴Desk 하단 탭 바 · HR Side Panel(왼쪽)Side Navigation(접힘)Side Navigation(펼침)
지금 화면을 떠나지 않는 보조 작업(상세 · 설정)Bottom SheetBottom SheetDialog — 옆에 둘 까닭이 있으면 Side Panel(오른쪽)
아래에서 올라오는 모달Bottom SheetBottom Sheet—

오른쪽 패널은 1280 이상에서만이다 — 1280 미만에서는 같은 내용을 Bottom Sheet 로 띄운다. 1280 은 Dialog 의 Responsive Dialog · Input Button 과 같은 경계다 — 768 ~ 1279 에서 오른쪽 패널을 두면 그 안의 고르기 칸은 시트로, 같은 내용의 폼은 시트로 열려 표면이 엇갈려 겹친다. 새 경계를 두지 않는다(2026-10-02 사용자 결정 1280 을 옮겼다 — 2026-10-22 사용자 결정 11B, https://claude.ai/artifact/YRPbWzhgD4EDdKsVioU8Zj). 옆에 둘 까닭은 본문을 보면서 함께 다룰 때(목록을 보며 한 줄의 상세)다 — 그렇지 않으면 Dialog 다. 지금은 오른쪽 패널을 쓰는 곳이 없다. 다른 표면과 견준 "상황 → 고를 것" 표는 DESIGN.md Components 의 "시트 · 대화상자 · 확인창 · 팝오버" 한 벌이다(3C).

9:41
휴가 현황
남은 연차11.5일
휴가 내역
연연차2026-09-21, 1일승인
반반차(오후)2026-09-04, 0.5일승인
연연차2026-08-18, 2일승인
병병가2026-07-31, 1일승인
연연차2026-07-10, 1일반려
그루 이음
근무
관리
이렇게 — 768 미만 — 왼쪽 패널은 주 메뉴(HR 폰)
9:41
설정
카드 결제 예정
예산을 넘었을 때
알림 설정
카드 결제 예정
예산을 넘었을 때
일정 알림
더치페이 요청
이렇게 — 1280 미만 — 같은 보조 작업은 Bottom Sheet
desk.groo.app
그루 담다
워크스페이스
기록
설정
알림 설정
알림을 받을 때를 골라요.
카드 결제 예정
예산을 넘었을 때
일정 알림
더치페이 요청
증권 연결이 끊겼을 때
공지사항
주간 리포트
월간 리포트
새 기능 소식
로그인 알림
이렇게 — 1280 이상 — 옆에 둘 까닭이 있으면 오른쪽 패널(목록을 보며 한 줄의 상세)
쓰는 자리 — 폰 주 메뉴 · 1280 이상 오른쪽 패널 · 1280 미만은 시트

주 메뉴 서랍(HR 폰)

HR 웹 768 미만의 Top Navigation ☰ 가 연다.

  • 왼쪽 · 화면 폭의 80% · 제목은 서비스 이름("그루 이음").
  • 본문은 Side Navigation 의 묶음 · 항목을 펼친 모양 그대로 담는다 — 본문 좌우 16 에 항목(좌우 8)이 들어와 아이콘이 제목과 같은 24 에 선다. 넘칠 수 있어 scrollFog 를 건다.
  • 지금 화면의 묶음은 펼쳐진 채 열리고 지금 항목이 보인다.
  • 항목을 누르면 이동하고 서랍이 닫힌다 — 다음 화면의 초점 · 스크롤은 Top Navigation 의 "화면을 옮길 때".
  • 바닥에는 계정(Side Navigation 의 바닥과 같은 것)을 둔다.
  • 창이 768 이상으로 넓어지면 닫힌다 — 사이드바가 그 자리를 맡는다.
9:41
휴가 현황
남은 연차11.5일
휴가 내역
연연차2026-09-21, 1일승인
반반차(오후)2026-09-04, 0.5일승인
연연차2026-08-18, 2일승인
병병가2026-07-31, 1일승인
연연차2026-07-10, 1일반려
그루 이음
근무
관리
이렇게 — 지금 묶음(휴가)이 펼쳐진 채 열린다 — 지금 항목이 보인다
9:41
휴가 신청
남은 연차11.5일
휴가 내역
연연차2026-09-21, 1일승인
반반차(오후)2026-09-04, 0.5일승인
연연차2026-08-18, 2일승인
병병가2026-07-31, 1일승인
연연차2026-07-10, 1일반려
이렇게 — 휴가 신청을 누르면 이동하고 닫힌다 — 다음 화면의 제목에 초점
9:41
휴가 현황
남은 연차11.5일
휴가 내역
연연차2026-09-21, 1일승인
반반차(오후)2026-09-04, 0.5일승인
연연차2026-08-18, 2일승인
병병가2026-07-31, 1일승인
연연차2026-07-10, 1일반려
그루 이음
근무
관리
이렇게 하지 않는다 — 지금 묶음이 접힌 채 연다 — 어디에 있는지 다시 찾아야 한다
9:41
휴가 신청
남은 연차11.5일
휴가 내역
연연차2026-09-21, 1일승인
반반차(오후)2026-09-04, 0.5일승인
연연차2026-08-18, 2일승인
병병가2026-07-31, 1일승인
연연차2026-07-10, 1일반려
그루 이음
근무
관리
이렇게 하지 않는다 — 이동한 뒤에도 서랍이 열려 있다
HR 주 메뉴 서랍 — 휴가 묶음이 펼쳐진 채, 항목을 누르면 닫힘

입력 폼은 실수로 닫히지 않게

오른쪽 패널에 입력 폼을 띄우면 Dialog 와 같다 — 바깥(딤)을 눌러도, 끌어도 닫히지 않고, 바닥 [취소] · Esc 로 닫으며, 바뀐 값이 있으면 닫기 전에 "작성한 내용이 사라져요" 를 묻는다. 입력 폼에는 머리 닫기 버튼을 두지 않는다(닫기와 취소는 하나만). 조회 · 주 메뉴는 머리 닫기 · 딤 누르기 · Esc · 끌기로 닫힌다.

9:41
휴가 현황
남은 연차11.5일
휴가 내역
연연차2026-09-21, 1일승인
반반차(오후)2026-09-04, 0.5일승인
연연차2026-08-18, 2일승인
병병가2026-07-31, 1일승인
연연차2026-07-10, 1일반려
그루 이음
근무
관리
이렇게 — 주 메뉴 — 딤(오른쪽 20%)을 누르면 닫힌다
9:41
휴가 현황
남은 연차11.5일
휴가 내역
연연차2026-09-21, 1일승인
반반차(오후)2026-09-04, 0.5일승인
연연차2026-08-18, 2일승인
병병가2026-07-31, 1일승인
연연차2026-07-10, 1일반려
그루 이음
근무
관리
이렇게 — 주 메뉴 — 손가락으로 왼쪽으로 끌면 닫힌다(빠르게 0.4px/ms 넘게 · 폭의 25% 이상). 마우스로는 끌지 않는다
desk.groo.app
그루 담다
워크스페이스
기록
설정
알림 설정
알림을 받을 때를 골라요.
카드 결제 예정
예산을 넘었을 때
일정 알림
더치페이 요청
증권 연결이 끊겼을 때
공지사항
주간 리포트
월간 리포트
새 기능 소식
로그인 알림
이렇게 — 입력 폼 — 딤 · 끌기로 닫히지 않는다. 머리 닫기 없이 바닥 [취소] · Esc
닫기 — 주 메뉴는 딤 · 끌기로 닫힘 · 폼은 바닥 취소

평평하게

패널은 화면 높이 전체에 붙고 모서리 · 그림자 · 테두리가 없다 — 딤과 면 색(bg-layer-floating)으로 뜬다. 패널 위에 또 패널을 겹치지 않는다 — 그 안에서는 Popover · Select 목록 · 확인창(Alert Dialog)만 뜬다(SEED 고도 — Side Panel 은 Level 2, Dialog 는 Level 3).

글

제목은 무엇을 하는 패널인지 — 주 메뉴 서랍은 서비스 이름. 설명은 덧붙일 말이 있을 때만 한 문장(해요체 · 마침표). 바닥 버튼은 동작 이름("저장") — "확인" 으로 뭉뚱그리지 않는다.

코드

레시피 recipes/shadcn/components/ui/side-panel.tsx 를 쓴다(Radix Dialog 위 — 끌어 닫기 · 뒤로 가기 닫기는 레시피가 더한다). 아래 미리보기는 스펙 값으로 그린 모습이다.

  • SidePanel — open · onOpenChange · form(바깥 누르기 · 끌기로 닫지 않는다) · dirty(닫기 전에 묻는다).
  • SidePanelTrigger — asChild.
  • SidePanelContent — 패널. side("left" · "right" 기본) · size("small" · "medium" 기본 · "large" — 오른쪽만) · title(필수) · description · showCloseButton(기본 true, form 이면 그리지 않는다).
  • SidePanelBody — 본문. scrollFog(위 20 · 아래 80).
  • SidePanelFooter — 바닥 버튼, 오른쪽 정렬.

1280 미만에서 오른쪽 패널을 Bottom Sheet 로 바꾸는 부품은 오른쪽 패널을 쓸 자리가 생길 때 Responsive Dialog 처럼 더한다.

주 메뉴 서랍 — HR 폰

휴가 현황
그루 이음
근무
HR 주 메뉴 — 서비스 이름 · 지금 묶음 펼침
import { SidePanel, SidePanelBody, SidePanelContent } from "@/components/ui/side-panel"
import { SideNavigationContent, SideNavigationGroup, SideNavigationItem, SideNavigationSubItem } from "@/components/ui/side-navigation"

<SidePanel open={menuOpen} onOpenChange={setMenuOpen}>
  <SidePanelContent side="left" title="그루 이음" id="main-menu">
    <SidePanelBody scrollFog className="px-x4">
      {/* 사이드바와 같은 항목 — 지금 묶음은 저절로 펼쳐지고, 항목을 누르면 이동하고 닫힌다 */}
      <SideNavigationContent onNavigate={() => setMenuOpen(false)}>
        <SideNavigationGroup label="근무">
          <SideNavigationItem href="/calendar" icon={<CalendarDays />} label="캘린더" current={path === "/calendar"} />
          <SideNavigationItem icon={<Plane />} label="휴가">
            <SideNavigationSubItem href="/vacation/history" label="휴가 현황" current={path === "/vacation/history"} />
            <SideNavigationSubItem href="/vacation/application" label="휴가 신청" current={path === "/vacation/application"} />
          </SideNavigationItem>
        </SideNavigationGroup>
      </SideNavigationContent>
    </SidePanelBody>
  </SidePanelContent>
</SidePanel>

오른쪽 패널 — 1280 이상(쓰는 곳 없음)

<SidePanel open={open} onOpenChange={setOpen} form dirty={isDirty}>
  <SidePanelContent side="right" size="medium" title="알림 설정">
    <SidePanelBody>…</SidePanelBody>
    <SidePanelFooter>
      <Button variant="neutralWeak" size="small" onClick={() => setOpen(false)}>취소</Button>
      <Button size="small" onClick={save}>저장</Button>
    </SidePanelFooter>
  </SidePanelContent>
</SidePanel>

Behavior

인터랙션동작
열기붙은 쪽에서 300ms 로 미끄러져 들어온다. 처음 초점은 패널에 간다
닫기 버튼 · Esc닫는다. 입력 폼에 바뀐 값이 있으면 먼저 묻는다
뒤로 가기(기기 · 브라우저)1280 미만에서만 닫는다 — 열 때 기록을 하나 쌓고 뒤로 가기가 그것을 걷는다(Dialog · Bottom Sheet 와 같은 규칙). 1280 이상의 오른쪽 패널은 기록을 쌓지 않아 뒤로 가기가 화면을 옮긴다
바깥(딤) 누르기주 메뉴 · 조회는 닫는다. 입력 폼은 무시한다
붙은 쪽으로 끌기(손가락 · 펜)놓을 때 빠르게(0.4px/ms 넘게) 끌었거나 폭의 25% 이상 밀었으면 닫고, 아니면 제자리로(Bottom Sheet 와 같은 기준). 마우스로는 끌지 않는다 — 글 고르기와 겹친다. 입력 폼은 끌리지 않는다
주 메뉴의 항목 누르기이동하고 닫는다
창이 768 이상으로 넓어짐(주 메뉴)닫는다 — 사이드바가 맡는다
본문 스크롤본문만 — 위로 스크롤되면 머리 아래 선. 끝 흐림(scrollFog)은 걸었으면 늘 그대로
닫힌 뒤300ms 로 나가고, 초점은 연 자리(☰ · 트리거)로 돌아간다
열린 동안뒤 화면을 보조 기술에서 숨기고 스크롤을 잠근다. 초점은 패널 안을 돈다

Accessibility

기준검증
WCAG 1.4.3 Color contrast(글자 ≥ 4.5:1)제목 fg-neutral 떠 있는 표면(bg-layer-floating) 위 16.41 · 다크 11.62, 설명 fg-neutral-muted 7.11 · 6.67, 주 메뉴 항목 이름 7.11 · 6.67 · 지금 항목 15.20 · 10.32 ✓
WCAG 1.4.11 Non-text contrast(≥ 3:1)닫기 아이콘 fg-neutral-subtle 5.50 · 5.27 ✓, 주 메뉴 아이콘 같은 값 ✓. 키보드 포커스 링 Desk 8.38 · 5.28 · HR 8.17 · 5.26 ✓
WCAG 2.4.3 Focus order열면 패널로, 닫으면 연 자리로 초점이 간다. 열린 동안 초점이 뒤 화면으로 나가지 않는다 ✓
WCAG 2.5.1 Pointer Gestures끌기 말고도 딤 누르기 · 닫기 · Esc · 뒤로 가기로 닫힌다 ✓
WCAG 2.5.8 Target Size — Minimum(AA ≥ 24×24)닫기 52 · 주 메뉴 항목 44 · 바닥 버튼 36 ✓
WCAG 2.5.5 Target Size — Enhanced(AAA ≥ 44×44)닫기 52 ✓ · 항목 44 ✓ · 바닥 버튼은 누르는 영역을 44 까지(Button) ✓
ARIArole="dialog" + aria-modal="true", 제목 aria-labelledby(제목 h2) · 설명 aria-describedby(있을 때만), 닫기 버튼 이름 "닫기". 주 메뉴 서랍 안의 목록은 <nav aria-label="주 메뉴">(Side Navigation 의 내용)

Do / Don't

✅ Do

  • 왼쪽은 768 미만의 주 메뉴, 오른쪽은 1280 이상의 보조 작업 — 1280 미만은 Bottom Sheet.
  • 평평하게 — 높이 전체 · 모서리 · 그림자 · 선 없음.
  • 주 메뉴는 지금 묶음을 펼친 채 열고, 이동하면 닫는다.
  • 입력 폼은 바깥 · 끌기로 닫지 않고, 바뀐 값이 있으면 묻는다.

❌ Don't

  • 아래 · 위에서 나오는 패널(아래는 Bottom Sheet).
  • 1280 미만에서 오른쪽 패널.
  • 이동한 뒤에도 열려 있는 서랍 · 지금 묶음이 접힌 채 여는 서랍.
  • 패널 위에 패널 · 그림자 · 둥근 모서리.
  • 영어 이름("Sidebar" · "Close").

Specification

side-panel.yaml 의 규칙을 하나도 빼지 않고 조건마다 그린다 — 웹이 Side Panel 을 만들 때 이 값을 그대로 쓴다. 조건이 없는 Base 가 모든 조합에 걸리고, 뒤의 규칙이 앞의 같은 값을 덮는다. 상태는 enabled 에서 바뀌는 값만 적었다.

Base

부위상태속성값
overlayenabled배경backgroundoverlay-dim-lightrgba(0, 0, 0, 0.50)다크 overlay-dim-darkrgba(0, 0, 0, 0.65)groo 딤(v102) — SEED 0.455 는 들이지 않았다
z-indexzIndex100z-modal — specs/z-index.md L2
rootenabled높이height화면 높이 전체dvh — 방향과 상관없이(SEED)
최대 너비maxWidth80%딤이 늘 20% 남는다(SEED 코드). 768 미만이면 크기와 상관없이 화면 폭의 80%
아래 여백paddingBottom아래 안전 영역패널 내용의 맨 아래 — 바닥이 없어도(SEED). 붙은 쪽 안전 영역(가로 노치)은 폭에 더한다
모서리radius0px평평 — 모서리 · 그림자 · 선 없이 딤과 면 색으로 뜬다(SEED)
배경backgroundbg-layer-floating#FFFFFF다크 #2D3346
그림자shadownone
z-indexzIndex101z-modal-content — specs/z-index.md L2
headerenabled최소 높이minHeight70px제목 한 줄 + 위아래 — 닫기 버튼 상자가 들어간다
좌우 여백paddingXspacing-x624px
위 여백paddingTopspacing-x624px위 안전 영역을 더한다
아래 여백paddingBottomspacing-x416px
간격gapspacing-x1_56px제목 ↔ 설명. 닫기 버튼이 있으면 오른쪽 52(24 + 아이콘 22 + 6)
titleenabled글자·아이콘foregroundfg-neutral#1A1F2E다크 #F5F6FA
글자typographytext-t822px / 30px
굵기fontWeight700
descriptionenabled글자·아이콘foregroundfg-neutral-muted#535866다크 #B7BDCC
글자typographytext-t516px / 22px
굵기fontWeight400
closeButtonenabled크기size52px투명 상자 — 보이는 건 아이콘 22(Dialog 의 닫기와 같다)
아이콘 크기iconSize22pxlucide x
모서리radiusradius-r312px
색colorfg-neutral-subtle#62697A다크 #A2A8B7
터치 영역touchTarget52 × 52
전환 대상transitionPropertybackground-color, scale
전환 시간transitionDurationmotion-duration-color-transition150ms
전환 곡선transitionEasingmotion-ease-easingcubic-bezier(0.35, 0, 0.35, 1)
위 거리top28px아이콘이 패널 위에서 28 · 오른쪽 24 — 상자는 위 13 · 오른쪽 9. 제목 첫 줄 가운데와 맞는다
오른쪽 거리rightspacing-x624px
dividerenabled높이height1px
배경backgroundstroke-neutral-subtle#EDEFF3다크 #353B4D머리 아래 — 본문이 위 끝에서 떨어지면 나타난다(SEED). SEED stroke.neutral-muted 의 불투명 짝
전환 시간transitionDurationmotion-duration-color-transition150ms
전환 곡선transitionEasingmotion-ease-easingcubic-bezier(0.35, 0, 0.35, 1)
bodyenabled좌우 여백paddingXspacing-x624px
아래 여백paddingBottomspacing-x624px바닥이 없을 때만 — 바닥이 있으면 0
세로 넘침overflowYauto
footerenabled버튼 크기buttonSizesmall 36Button small — 1280 이상의 오른쪽 패널
좌우 여백paddingXspacing-x624px
위 여백paddingTopspacing-x416px
아래 여백paddingBottomspacing-x624px
간격gapspacing-x28px
가로 맞춤justifyContentflex-end오른쪽 정렬 — [취소] [저장](Dialog 와 같다)
dividerscrolled불투명도opacity1본문을 위로 스크롤하면 나타난다
closeButtonpressed배경backgroundbg-layer-floating-pressed#F7F8FD다크 #353B4DSEED bg.transparent-pressed 의 떠 있는 표면 짝(v102)
배율scale2px 거리 축소기준 52 → 0.962 — 모션 줄이기면 하지 않는다
focusRingfocused링 두께width2px
링 색colorstroke-focus-ringDesk#0147AD다크 #7AA9F6HR#075B3C다크 #2ABE84
링 간격offset2px

side=right

부위상태속성값
rootenabled자리position오른쪽 끝1280 이상 — 미만에서는 같은 내용을 Bottom Sheet 로

size=small

부위상태속성값
rootenabled너비width480px

size=medium

부위상태속성값
rootenabled너비width720px

size=large

부위상태속성값
rootenabled너비width960px

side=left

부위상태속성값
rootenabled너비width화면 폭의 80%768 미만에서만 쓴다 — 딤이 오른쪽 20% 에 남는다. 크기(480 · 720 · 960)는 오른쪽 패널만 쓴다
자리position왼쪽 끝왼쪽으로 끌면 닫힌다
titleenabled글자typographytext-t822px / 30px서비스 이름("그루 이음") — 주 메뉴 서랍의 제목
bodyenabled좌우 여백paddingXspacing-x416px주 메뉴 — Side Navigation 의 항목(좌우 8)이 들어와 아이콘이 제목과 같은 24 에서 선다

scrollFog=on

부위상태속성값
bodyenabled위 여백paddingTop20px머리 아래 16 은 그대로 두고 본문 안에 더한다
아래 여백paddingBottom80px바닥이 있어도 — 끝까지 내려도 마지막 줄이 흐림 아래 남지 않는다
스크롤 여유scrollPadding위 20px · 아래 80px키보드로 옮긴 칸이 흐림 아래 멈추지 않게
fogenabled크기size위 20px · 아래 80px본문 상자의 위 · 아래 끝
마스크maskgradient-fade-masklinear-gradient(#00000000 0%, #00000003 8%, #00000005 16%, #0000000d 22%, #00000014 29%, #00000021 35%, #0000002e 41%, #00000040 47%, #00000052 53%, #00000066 59%, #0000007a 65%, #00000094 71%, #000000ab 78%, #000000c7 84%, #000000e3 92%, #000000ff 100%)Scroll Fog overlayBody(scroll-fog.yaml) — 늘 켜져 있다. SEED Side Panel 의 아래 48 대신

SEED 와 다른 점

  • 딤은 groo 0.50 · 다크 0.65(v102) — SEED 0.455.
  • 본문 끝 흐림은 Scroll Fog(2026-10-03) — 넘칠 수 있는 본문에 늘 켜진 위 20 · 아래 80. SEED Side Panel 은 본문 아래 48 을 늘 흐린다.
  • 반투명 색을 불투명 짝으로(v102) — 머리 아래 선 stroke-neutral-subtle, 닫기 버튼 누름 bg-layer-floating-pressed.
  • 1280 미만의 오른쪽 패널은 Bottom Sheet — SEED Responsive Side Panel 은 md(768)에서 바꾼다. groo 는 Responsive Dialog · Input Button 과 같은 1280 이다.
  • 기본 크기는 medium 720 — SEED React · CSS 와 같다(rootage JSON 기본은 small).
  • 가로 화면의 노치 — SEED 문서는 "패널 너비에 safe-area-inset을 더합니다", 코드는 폭 안에서 뺀다. groo 는 문서를 따른다(내용 폭이 줄지 않게).
  • 입력 폼은 바깥 · 끌기로 닫지 않는다 — Dialog · Bottom Sheet 와 같은 groo 규칙(2026-10-02). SEED 는 모든 패널이 바깥 누르기 · 가로 끌기(25%)로 닫힌다.
  • 모션 줄이기면 150ms 서서히 나타남(v104) — SEED 는 300ms 미끄러짐 그대로.
  • Persistent(비모달) 패널은 보류 — SEED 는 Backdrop 없이 배경과 함께 다루는 Persistent Type 을 둔다(md 미만은 Modal). groo 는 지금 쓸 자리가 없어 두지 않았고, 생기면 그때 정한다 — 데스크톱 필터 · 목록 옆 상세(dialog.md "앱 적용 때 정할 자리")가 후보다(2026-10-22 사용자 결정 11B — https://claude.ai/artifact/YRPbWzhgD4EDdKsVioU8Zj).
  • z-index 는 specs/z-index.md 의 L2(딤 z-modal 100 · 패널 z-modal-content 101).

Migration notes

2026-10-22 — 이동 부품 표 링크

머리말에 DESIGN.md Layout 의 "이동 부품 고르기" 링크를 더했다(6B — https://claude.ai/artifact/Mag1tEv51MdQHdy1o8hY3L). 값 변경 없음.

2026-10-22 — 1280 의 까닭 · Persistent 는 보류

"쓰는 자리" 표 아래에 1280 의 까닭(Responsive Dialog · Input Button 과 같은 경계 — 768 ~ 1279 에서 표면이 엇갈리지 않게)을 적었다. "Persistent 는 두지 않는다" 는 묻지 않고 들어간 문장이라 "지금은 쓸 자리가 없다 — 생기면 그때 정한다" 로 바꿨다(사용자 결정 11B — https://claude.ai/artifact/YRPbWzhgD4EDdKsVioU8Zj). 값 변경 없음.

2026-10-04 — SEED Side Panel 로 새로 둔다(옛 Sheet 를 대신)

사용자가 화면 틀 · 이동 비교 페이지의 "따라오는 것" 으로 정했다 — Sheet 를 Side Panel 로: 왼쪽 · 오른쪽만(아래는 Bottom Sheet, 위는 걷음), 480 · 720 · 960 · 768 미만 80%, 평평(모서리 · 그림자 없음), 머리 24 · 제목 22 / 30 · 닫기 상자 52 · 아이콘 22. 지금 쓰는 곳은 HR 폰 메뉴 서랍(왼쪽) 하나 — 이동하면 닫고, 지금 묶음을 펼친 채 연다. 2026-10-02 Bottom Sheet 의 "오른쪽에서 나오는 패널은 Side Panel 차례에 정한다" 가 이것이다. 옛 Sheet(shadcn — 네 방향 · 폭 75% · 최대 384 · shadow-xl · 가장자리 1px 선 · 제목 18 / 600 · 닫기 28)는 걷었다 — 옛 스펙은 sheet.history/v-pre-seed-nav.*.

제품은 앱 적용 단계에서 옮긴다(2026-10-04 조사).

  • HR 폰 메뉴 서랍 — shadcn Sheet 왼쪽 288(80%) · #FAFAFA. 이름이 "Sidebar" · 설명 "Displays the mobile sidebar."(영어), 열면 지금 화면의 묶음도 접혀 있고(treeView.tsx:263-265 — 펼침 초기값은 첫 마운트에만), 잎을 눌러 이동해도 서랍이 열린 채 남는다(SidebarContent.tsx:101-108 · shared/ui/shadcn/sidebar.tsx:198-201, F12). Side Panel(왼쪽) + Side Navigation 항목으로.
  • Desk 웹 — 모바일 사이드바 시트는 닿지 않는 코드다(768 미만은 하단 탭 바 — F27). 옆 패널을 쓰는 화면이 없다.
  • HR 나눔 패널 4(회사 · 부서 · 역할 · 사용자 — Resizable 25 / 75, CompanyContent.tsx:116-140 외)은 화면 안의 나눔이지 Side Panel 이 아니다 — Resizable(2026-10-10 — 목록 20 ~ 40%).
  • 앱 적용 때 정할 자리 — HR 전체 화면 Dialog 3(페이지 · 시트 · 오른쪽 Side Panel — dialog.md), 데스크톱 필터(Dialog · Popover · 오른쪽 Side Panel).

이 페이지