76 lines
1.8 KiB
TypeScript
76 lines
1.8 KiB
TypeScript
"use client";
|
|
|
|
/**
|
|
* 그리드 표시 모드
|
|
*
|
|
* CSS Grid로 셀 배치 (엑셀형 분할/병합 결과 반영)
|
|
* 각 셀에 @container 적용하여 내부 아이템 반응형
|
|
*/
|
|
|
|
import React from "react";
|
|
import type { DashboardCell } from "../../types";
|
|
|
|
// ===== Props =====
|
|
|
|
export interface GridModeProps {
|
|
/** 셀 배치 정보 */
|
|
cells: DashboardCell[];
|
|
/** 열 수 */
|
|
columns: number;
|
|
/** 행 수 */
|
|
rows: number;
|
|
/** 아이템 간 간격 (px) */
|
|
gap?: number;
|
|
/** 셀의 아이템 렌더링. itemId가 null이면 빈 셀 */
|
|
renderItem: (itemId: string) => React.ReactNode;
|
|
}
|
|
|
|
// ===== 메인 컴포넌트 =====
|
|
|
|
export function GridModeComponent({
|
|
cells,
|
|
columns,
|
|
rows,
|
|
gap = 8,
|
|
renderItem,
|
|
}: GridModeProps) {
|
|
if (!cells.length) {
|
|
return (
|
|
<div className="flex h-full w-full items-center justify-center">
|
|
<span className="text-xs text-muted-foreground">셀 없음</span>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<div
|
|
className="h-full w-full"
|
|
style={{
|
|
display: "grid",
|
|
gridTemplateColumns: `repeat(${columns}, 1fr)`,
|
|
gridTemplateRows: `repeat(${rows}, 1fr)`,
|
|
gap: `${gap}px`,
|
|
}}
|
|
>
|
|
{cells.map((cell) => (
|
|
<div
|
|
key={cell.id}
|
|
className="@container min-h-0 min-w-0 overflow-hidden rounded-md border border-border/50 bg-card"
|
|
style={{
|
|
gridColumn: cell.gridColumn,
|
|
gridRow: cell.gridRow,
|
|
}}
|
|
>
|
|
{cell.itemId ? (
|
|
renderItem(cell.itemId)
|
|
) : (
|
|
<div className="flex h-full w-full items-center justify-center">
|
|
<span className="text-[10px] text-muted-foreground/50">빈 셀</span>
|
|
</div>
|
|
)}
|
|
</div>
|
|
))}
|
|
</div>
|
|
);
|
|
}
|