ERP-node/frontend/lib/registry/pop-components/pop-card-list/PopCardListPreview.tsx

201 lines
5.8 KiB
TypeScript

"use client";
/**
* pop-card-list 디자인 모드 미리보기 컴포넌트 (V2)
*
* 디자이너 캔버스에서 표시되는 미리보기
* 이미지 참조 기반 카드 구조 반영
*/
import React from "react";
import { LayoutGrid, Package } from "lucide-react";
import type { PopCardListConfig } from "../types";
import {
CARD_LAYOUT_MODE_LABELS,
CARD_SIZE_LABELS,
DEFAULT_CARD_IMAGE,
} from "../types";
interface PopCardListPreviewProps {
config?: PopCardListConfig;
}
export function PopCardListPreviewComponent({
config,
}: PopCardListPreviewProps) {
const layoutMode = config?.layoutMode || "grid";
const cardSize = config?.cardSize || "medium";
const cardsPerRow = config?.cardsPerRow || 3;
const dataSource = config?.dataSource;
const template = config?.cardTemplate;
// 설정 상태 확인
const hasTable = !!dataSource?.tableName;
const hasHeader =
!!template?.header?.codeField || !!template?.header?.titleField;
const hasImage = template?.image?.enabled ?? true;
const fieldCount = template?.body?.fields?.length || 0;
// 샘플 카드 개수 (미리보기용)
const sampleCardCount =
layoutMode === "grid" ? Math.min(cardsPerRow, 3) : 2;
return (
<div className="flex h-full w-full flex-col bg-muted/30 p-3">
{/* 헤더 */}
<div className="mb-2 flex items-center justify-between">
<div className="flex items-center gap-2 text-muted-foreground">
<LayoutGrid className="h-4 w-4" />
<span className="text-xs font-medium"> </span>
</div>
{/* 설정 배지 */}
<div className="flex gap-1">
<span className="rounded bg-primary/10 px-1.5 py-0.5 text-[9px] text-primary">
{CARD_LAYOUT_MODE_LABELS[layoutMode]}
</span>
<span className="rounded bg-secondary px-1.5 py-0.5 text-[9px] text-secondary-foreground">
{CARD_SIZE_LABELS[cardSize]}
</span>
</div>
</div>
{/* 테이블 미선택 시 안내 */}
{!hasTable ? (
<div className="flex flex-1 items-center justify-center">
<div className="text-center">
<Package className="mx-auto mb-2 h-8 w-8 text-muted-foreground/50" />
<p className="text-xs text-muted-foreground">
</p>
</div>
</div>
) : (
<>
{/* 테이블 정보 */}
<div className="mb-2 text-center">
<span className="rounded bg-muted px-2 py-0.5 text-[10px] text-muted-foreground">
{dataSource.tableName}
</span>
</div>
{/* 카드 미리보기 */}
<div
className={`flex-1 flex gap-2 ${
layoutMode === "vertical"
? "flex-col"
: layoutMode === "horizontal"
? "flex-row overflow-x-auto"
: "flex-wrap justify-center content-start"
}`}
>
{Array.from({ length: sampleCardCount }).map((_, idx) => (
<PreviewCard
key={idx}
index={idx}
hasHeader={hasHeader}
hasImage={hasImage}
fieldCount={fieldCount}
cardSize={cardSize}
layoutMode={layoutMode}
/>
))}
</div>
{/* 필드 정보 */}
{fieldCount > 0 && (
<div className="mt-2 text-center">
<span className="text-[10px] text-muted-foreground">
{fieldCount}
</span>
</div>
)}
</>
)}
</div>
);
}
// ===== 미리보기 카드 컴포넌트 =====
function PreviewCard({
index,
hasHeader,
hasImage,
fieldCount,
cardSize,
layoutMode,
}: {
index: number;
hasHeader: boolean;
hasImage: boolean;
fieldCount: number;
cardSize: string;
layoutMode: string;
}) {
// 카드 크기
const sizeClass =
cardSize === "small"
? "min-h-[60px]"
: cardSize === "large"
? "min-h-[100px]"
: "min-h-[80px]";
const widthClass =
layoutMode === "vertical"
? "w-full"
: layoutMode === "horizontal"
? "min-w-[140px] flex-shrink-0"
: "w-[140px]";
return (
<div
className={`rounded-md border bg-card overflow-hidden ${sizeClass} ${widthClass}`}
>
{/* 헤더 */}
{hasHeader && (
<div className="border-b bg-muted/30 px-2 py-1">
<div className="flex items-center gap-1">
<span className="h-2 w-8 rounded bg-muted-foreground/20" />
<span className="h-2 w-12 rounded bg-muted-foreground/30" />
</div>
</div>
)}
{/* 본문 */}
<div className="flex p-2 gap-2">
{/* 이미지 */}
{hasImage && (
<div className="flex-shrink-0">
<div className="h-10 w-10 rounded border bg-muted/30 flex items-center justify-center">
<img
src={DEFAULT_CARD_IMAGE}
alt=""
className="h-6 w-6 opacity-50"
/>
</div>
</div>
)}
{/* 필드 목록 */}
<div className="flex-1 space-y-1">
{fieldCount > 0 ? (
Array.from({ length: Math.min(fieldCount, 3) }).map((_, i) => (
<div key={i} className="flex items-center gap-1">
<span className="h-1.5 w-6 rounded bg-muted-foreground/20" />
<span className="h-1.5 w-10 rounded bg-muted-foreground/30" />
</div>
))
) : (
<div className="flex h-full items-center justify-center">
<span className="text-[8px] text-muted-foreground">
</span>
</div>
)}
</div>
</div>
</div>
);
}