177 lines
4.6 KiB
TypeScript
177 lines
4.6 KiB
TypeScript
|
|
"use client";
|
||
|
|
|
||
|
|
/**
|
||
|
|
* pop-string-list 디자이너 미리보기
|
||
|
|
*
|
||
|
|
* 디자인 모드에서 캔버스에 표시되는 간략한 미리보기.
|
||
|
|
* 실제 데이터는 가져오지 않고 더미 데이터로 레이아웃만 시각화.
|
||
|
|
*/
|
||
|
|
|
||
|
|
import type { PopStringListConfig } from "./types";
|
||
|
|
|
||
|
|
interface PopStringListPreviewProps {
|
||
|
|
config?: PopStringListConfig;
|
||
|
|
}
|
||
|
|
|
||
|
|
export function PopStringListPreviewComponent({
|
||
|
|
config,
|
||
|
|
}: PopStringListPreviewProps) {
|
||
|
|
const displayMode = config?.displayMode || "list";
|
||
|
|
const header = config?.header;
|
||
|
|
const tableName = config?.dataSource?.tableName;
|
||
|
|
const listColumns = config?.listColumns || [];
|
||
|
|
const cardGrid = config?.cardGrid;
|
||
|
|
|
||
|
|
// 테이블 미선택
|
||
|
|
if (!tableName) {
|
||
|
|
return (
|
||
|
|
<div className="flex h-full w-full items-center justify-center p-2">
|
||
|
|
<span className="text-[10px] text-muted-foreground">
|
||
|
|
테이블을 선택하세요
|
||
|
|
</span>
|
||
|
|
</div>
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
return (
|
||
|
|
<div className="flex h-full w-full flex-col overflow-hidden">
|
||
|
|
{/* 헤더 */}
|
||
|
|
{header?.enabled && (
|
||
|
|
<div className="shrink-0 border-b px-2 py-1">
|
||
|
|
<span className="text-[10px] font-medium">
|
||
|
|
{header.label || "리스트 목록"}
|
||
|
|
</span>
|
||
|
|
</div>
|
||
|
|
)}
|
||
|
|
|
||
|
|
{/* 모드별 미리보기 */}
|
||
|
|
<div className="flex-1 overflow-hidden p-1">
|
||
|
|
{displayMode === "list" ? (
|
||
|
|
<ListPreview columns={listColumns} />
|
||
|
|
) : (
|
||
|
|
<CardPreview cardGrid={cardGrid} />
|
||
|
|
)}
|
||
|
|
</div>
|
||
|
|
|
||
|
|
{/* 모드 라벨 */}
|
||
|
|
<div className="shrink-0 border-t px-2 py-0.5">
|
||
|
|
<span className="text-[8px] text-muted-foreground">
|
||
|
|
{displayMode === "list" ? "리스트" : "카드"} | {tableName}
|
||
|
|
</span>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
// ===== 리스트 미리보기 =====
|
||
|
|
|
||
|
|
function ListPreview({
|
||
|
|
columns,
|
||
|
|
}: {
|
||
|
|
columns: PopStringListConfig["listColumns"];
|
||
|
|
}) {
|
||
|
|
const cols = columns || [];
|
||
|
|
|
||
|
|
if (cols.length === 0) {
|
||
|
|
return (
|
||
|
|
<div className="flex h-full items-center justify-center">
|
||
|
|
<span className="text-[8px] text-muted-foreground">컬럼 미설정</span>
|
||
|
|
</div>
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
const gridCols = cols.map((c) => c.width || "1fr").join(" ");
|
||
|
|
const dummyRows = 3;
|
||
|
|
|
||
|
|
return (
|
||
|
|
<div className="w-full">
|
||
|
|
{/* 헤더 */}
|
||
|
|
<div
|
||
|
|
className="border-b bg-muted/50"
|
||
|
|
style={{ display: "grid", gridTemplateColumns: gridCols }}
|
||
|
|
>
|
||
|
|
{cols.map((col) => (
|
||
|
|
<div
|
||
|
|
key={col.columnName}
|
||
|
|
className="px-1 py-0.5 text-[8px] font-medium text-muted-foreground truncate"
|
||
|
|
>
|
||
|
|
{col.label}
|
||
|
|
</div>
|
||
|
|
))}
|
||
|
|
</div>
|
||
|
|
{/* 더미 행 */}
|
||
|
|
{Array.from({ length: dummyRows }).map((_, i) => (
|
||
|
|
<div
|
||
|
|
key={i}
|
||
|
|
className="border-b last:border-b-0"
|
||
|
|
style={{ display: "grid", gridTemplateColumns: gridCols }}
|
||
|
|
>
|
||
|
|
{cols.map((col) => (
|
||
|
|
<div
|
||
|
|
key={col.columnName}
|
||
|
|
className="px-1 py-0.5"
|
||
|
|
>
|
||
|
|
<div className="h-2 w-3/4 rounded bg-muted animate-pulse" />
|
||
|
|
</div>
|
||
|
|
))}
|
||
|
|
</div>
|
||
|
|
))}
|
||
|
|
</div>
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
// ===== 카드 미리보기 =====
|
||
|
|
|
||
|
|
function CardPreview({
|
||
|
|
cardGrid,
|
||
|
|
}: {
|
||
|
|
cardGrid: PopStringListConfig["cardGrid"];
|
||
|
|
}) {
|
||
|
|
if (!cardGrid || cardGrid.cells.length === 0) {
|
||
|
|
return (
|
||
|
|
<div className="flex h-full items-center justify-center">
|
||
|
|
<span className="text-[8px] text-muted-foreground">
|
||
|
|
카드 레이아웃 미설정
|
||
|
|
</span>
|
||
|
|
</div>
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
// 더미 카드 2장
|
||
|
|
return (
|
||
|
|
<div className="space-y-1">
|
||
|
|
{[0, 1].map((i) => (
|
||
|
|
<div
|
||
|
|
key={i}
|
||
|
|
className="rounded border"
|
||
|
|
style={{
|
||
|
|
display: "grid",
|
||
|
|
gridTemplateColumns: cardGrid.colWidths.join(" "),
|
||
|
|
gridTemplateRows:
|
||
|
|
cardGrid.rowHeights?.join(" ") ||
|
||
|
|
`repeat(${cardGrid.rows}, 1fr)`,
|
||
|
|
gap: `${cardGrid.gap}px`,
|
||
|
|
minHeight: "24px",
|
||
|
|
}}
|
||
|
|
>
|
||
|
|
{cardGrid.cells.map((cell) => (
|
||
|
|
<div
|
||
|
|
key={cell.id}
|
||
|
|
className="flex items-center justify-center"
|
||
|
|
style={{
|
||
|
|
gridColumn: `${cell.col} / span ${cell.colSpan}`,
|
||
|
|
gridRow: `${cell.row} / span ${cell.rowSpan}`,
|
||
|
|
border: cardGrid.showBorder
|
||
|
|
? "1px dashed hsl(var(--border))"
|
||
|
|
: "none",
|
||
|
|
}}
|
||
|
|
>
|
||
|
|
<div className="h-2 w-3/4 rounded bg-muted animate-pulse" />
|
||
|
|
</div>
|
||
|
|
))}
|
||
|
|
</div>
|
||
|
|
))}
|
||
|
|
</div>
|
||
|
|
);
|
||
|
|
}
|