D·Camp UI

AppLayout

Dark Mode

앱 전체 페이지를 감싸는 레이아웃 컴포넌트입니다. Sidebar(좌측 고정) + Header(상단 고정) + SubHeader(선택) + Content(스크롤) 구조로, 사이드바 확장/축소에 따라 콘텐츠 영역이 자동 조정됩니다.

import { AppLayout } from "@/shared/ui/common"
사용 컴포넌트:Sidebar,MainHeader

구조

┌──────────────────────────────────────────────────┐
│ AppLayout  (h-screen, flex)                      │
├────────────┬─────────────────────────────────────┤
│            │  header (MainHeader, 84px, 고정)     │
│  sidebar   ├─────────────────────────────────────┤
│  (Sidebar) │  subHeader? (TabBar 등, 고정)        │
│  212/80px  ├─────────────────────────────────────┤
│  고정      │  main (children, 스크롤)             │
│            │  px-7 py-8 기본 패딩                 │
│            │                                     │
└────────────┴─────────────────────────────────────┘

사이드바 토글 연동

토글 버튼 위치: 사이드바 접기/펼치기 버튼은MainHeader에 위치합니다. Sidebar 컴포넌트에는 버튼이 없습니다.

상태 소유권: collapsed 상태는 AppLayout을 사용하는 page 컴포넌트가 소유합니다. AppLayout 자체는 sidebar / header를 ReactNode 슬롯으로 받는 구조라 내부에서 상태를 직접 중계하지 않습니다.

연결 방법: page에서 하나의 collapsed state를 만들고,Sidebar에는 collapsed를,MainHeader에는 collapsed + onToggleCollapse를 각각 전달합니다.

인터랙티브 데모

디캠프 주식회사투자 담당자

콘텐츠 블록 A

이 영역만 스크롤됩니다. 사이드바와 헤더는 고정됩니다.

콘텐츠 블록 B

콘텐츠 블록 C

tsx
// collapsed 상태를 page에서 소유하고 Sidebar/MainHeader 양쪽에 주입합니다.
// AppLayout은 ReactNode 슬롯 구조이므로 상태를 직접 중계하지 않습니다.
const [collapsed, setCollapsed] = useState(false);

<AppLayout
  sidebar={
    <Sidebar
      items={navItems}
      collapsed={collapsed}
      user={{ userName: "홍길동", spaceName: "디캠프 주식회사" }}
    />
  }
  header={
    <MainHeader
      title="대시보드"
      backHref="/dashboard"
      collapsed={collapsed}
      onToggleCollapse={() => setCollapsed((p) => !p)}
      actions={
        <>
          <MainHeaderIconButton icon={Search} label="검색" />
          <MainHeaderIconButton icon={Settings} label="설정" />
        </>
      }
      profile={profile}
    />
  }
>
  {/* 콘텐츠 — 이 영역만 스크롤됩니다 */}
  <PageContent />
</AppLayout>

사이드바 확장 vs 축소

사이드바 확장 시 212px, 축소 시 80px. 콘텐츠 영역은 flex-1로 나머지 공간을 자동으로 채웁니다.

Expanded (212px)

Collapsed (80px)

SubHeader 슬롯

헤더 아래에 TabBar 등의 서브 네비게이션을 고정 배치할 수 있습니다. subHeader는 콘텐츠와 함께 스크롤되지 않습니다.

tsx
// subHeader 슬롯에 TabBar 등을 배치하면 헤더 아래에 고정됩니다
<AppLayout
  sidebar={<Sidebar items={navItems} collapsed={false} />}
  header={<MainHeader title="펀드 상세" backHref="#" />}
  subHeader={
    <TabBar
      items={tabItems}
      value={tabValue}
      onChange={setTabValue}
    />
  }
>
  <PageContent />
</AppLayout>

Props

AppLayout

PropTypeRequiredDefault설명
sidebarReactNode좌측 사이드바 영역. Sidebar 컴포넌트를 전달합니다.
headerReactNode상단 헤더 영역. MainHeader 컴포넌트를 전달합니다.
subHeaderReactNode헤더 바로 아래 고정되는 서브헤더 영역. TabBar 등에 사용합니다.
childrenReactNode메인 콘텐츠 영역. 이 영역만 스크롤됩니다.
contentClassNamestring콘텐츠 래퍼에 적용할 추가 클래스. 기본 패딩(px-7 py-8)을 커스터마이즈할 때 사용합니다.
classNamestring루트 요소에 적용할 추가 클래스.