o2o-negosium-original/frontend/src/layouts/MainLayout.tsx

75 lines
2.0 KiB
TypeScript

import { type ReactNode } from 'react'
import { Logo } from '@/components'
import { cn } from '@/lib'
// 좌측 폭: list=반응형 비율 / chat=고정 350px
const SIDEBAR_WIDTH = {
list:
'w-[20%] max-w-[320px] ' +
'max-[1520px]:w-[23%] max-[1410px]:w-[25%] ' +
'max-[1180px]:w-[27%] max-[1024px]:w-[29%] max-[960px]:w-[33%]',
chat: 'w-[350px]',
} as const
const styles = {
root: 'flex w-full min-h-screen max-h-screen bg-background',
scrollX: 'flex w-full min-h-screen max-h-screen overflow-x-auto overflow-y-hidden',
scrollXInner: 'flex w-full min-h-screen max-h-screen min-w-[1350px] bg-background',
sidebar: 'flex flex-col h-screen pt-2 bg-background',
logoHeader:
'flex w-full h-[56px] pl-[32px] pr-[24px] py-[8px] items-center justify-between shrink-0',
main: 'flex flex-1 flex-col h-screen overflow-hidden pt-2 pr-2 pb-2 pl-0',
// 다크 헤더와 합쳐져 카드 형태
content: 'flex flex-1 flex-col min-h-0 w-full overflow-hidden rounded-b-[8px] bg-surface',
} as const
export type SidebarWidth = keyof typeof SIDEBAR_WIDTH
export interface MainLayoutProps {
sidebarWidth?: SidebarWidth
/** 루트 가로 스크롤 + 최소폭 (chat 전용) */
scrollX?: boolean
logoAction?: ReactNode
sidebar: ReactNode
header: ReactNode
children?: ReactNode
}
export function MainLayout({
sidebarWidth = 'list',
scrollX = false,
logoAction,
sidebar,
header,
children,
}: MainLayoutProps) {
const panes = (
<>
<aside className={cn(styles.sidebar, SIDEBAR_WIDTH[sidebarWidth])}>
<div className={styles.logoHeader}>
<Logo size="sm" />
{logoAction}
</div>
{sidebar}
</aside>
<main className={styles.main}>
{header}
<div className={styles.content}>{children}</div>
</main>
</>
)
if (!scrollX) {
return <div className={styles.root}>{panes}</div>
}
return (
<div className={styles.scrollX}>
<div className={styles.scrollXInner}>{panes}</div>
</div>
)
}
export default MainLayout