- 반응형: 최소 폭 1350→1024px, max-[1350px]/max-[1180px] 2단계 축소 - 사이드바 350→310→280, 우측 메뉴 360→320→280, 채팅 거터 140/126→80/72→48/40 (헤더 패딩 동기) - 가격·할인율 입력 min-w 480→420→320, 가운데 버튼 패딩·최소폭 축소, 상품목록 버튼 1180px 미만 아이콘만 - 상품 이미지 220→200, 사이드바 정보 행 값 영역 고정 150px → flex-1 - 리드타임: formatLeadTime 헬퍼 신설 — 좌측 상품정보·협상 결과 요약 카드에 "일" 접미 표시 - 인디케이터: init 의 session_status 를 스토어에 적재, 협상중(IN_PROGRESS) 세션에서만 표시 - 사이드바 정보 영역 의미 없는 가로 스크롤 제거 (shrink 금지 컬럼 + overflow-x 자동 계산이 원인) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
75 lines
2.1 KiB
TypeScript
75 lines
2.1 KiB
TypeScript
import { type ReactNode } from 'react'
|
|
import { Logo } from '@/components'
|
|
import { cn } from '@/lib'
|
|
|
|
// 좌측 폭: list=반응형 비율 / chat=고정폭 단계 축소
|
|
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] max-[1350px]:w-[310px] max-[1180px]:w-[280px]',
|
|
} 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-[1024px] 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
|