179 lines
4.9 KiB
TypeScript
179 lines
4.9 KiB
TypeScript
"use client";
|
|
|
|
import React from "react";
|
|
import { cn } from "@/lib/utils";
|
|
import {
|
|
Card,
|
|
CardContent,
|
|
CardDescription,
|
|
CardHeader,
|
|
CardTitle,
|
|
} from "@/components/ui/card";
|
|
|
|
export interface SectionCardProps {
|
|
component?: {
|
|
id: string;
|
|
componentConfig?: {
|
|
title?: string;
|
|
description?: string;
|
|
showHeader?: boolean;
|
|
headerPosition?: "top" | "left";
|
|
padding?: "none" | "sm" | "md" | "lg";
|
|
backgroundColor?: "default" | "muted" | "transparent";
|
|
borderStyle?: "solid" | "dashed" | "none";
|
|
collapsible?: boolean;
|
|
defaultOpen?: boolean;
|
|
};
|
|
style?: React.CSSProperties;
|
|
};
|
|
children?: React.ReactNode;
|
|
className?: string;
|
|
onClick?: (e?: React.MouseEvent) => void;
|
|
isSelected?: boolean;
|
|
isDesignMode?: boolean;
|
|
}
|
|
|
|
/**
|
|
* Section Card 컴포넌트
|
|
* 제목과 테두리가 있는 명확한 그룹화 컨테이너
|
|
*/
|
|
export function SectionCardComponent({
|
|
component,
|
|
children,
|
|
className,
|
|
onClick,
|
|
isSelected = false,
|
|
isDesignMode = false,
|
|
}: SectionCardProps) {
|
|
const config = component?.componentConfig || {};
|
|
const [isOpen, setIsOpen] = React.useState(config.defaultOpen !== false);
|
|
|
|
// 🔄 실시간 업데이트를 위해 config에서 직접 읽기
|
|
const title = config.title || "";
|
|
const description = config.description || "";
|
|
const showHeader = config.showHeader !== false; // 기본값: true
|
|
const padding = config.padding || "md";
|
|
const backgroundColor = config.backgroundColor || "default";
|
|
const borderStyle = config.borderStyle || "solid";
|
|
const collapsible = config.collapsible || false;
|
|
|
|
// 🎯 디버깅: config 값 확인
|
|
React.useEffect(() => {
|
|
console.log("✅ Section Card Config:", {
|
|
title,
|
|
description,
|
|
showHeader,
|
|
fullConfig: config,
|
|
});
|
|
}, [config.title, config.description, config.showHeader]);
|
|
|
|
// 패딩 매핑
|
|
const paddingMap = {
|
|
none: "p-0",
|
|
sm: "p-3",
|
|
md: "p-6",
|
|
lg: "p-8",
|
|
};
|
|
|
|
// 배경색 매핑
|
|
const backgroundColorMap = {
|
|
default: "bg-card",
|
|
muted: "bg-muted/30",
|
|
transparent: "bg-transparent",
|
|
};
|
|
|
|
// 테두리 스타일 매핑
|
|
const borderStyleMap = {
|
|
solid: "border-solid",
|
|
dashed: "border-dashed",
|
|
none: "border-none",
|
|
};
|
|
|
|
const handleToggle = () => {
|
|
if (collapsible) {
|
|
setIsOpen(!isOpen);
|
|
}
|
|
};
|
|
|
|
return (
|
|
<Card
|
|
className={cn(
|
|
"transition-all",
|
|
backgroundColorMap[backgroundColor],
|
|
borderStyleMap[borderStyle],
|
|
borderStyle === "none" && "shadow-none",
|
|
isDesignMode && isSelected && "ring-2 ring-primary ring-offset-2",
|
|
isDesignMode && !children && "min-h-[150px]",
|
|
className
|
|
)}
|
|
style={component?.style}
|
|
onClick={onClick}
|
|
>
|
|
{/* 헤더 */}
|
|
{showHeader && (title || description || isDesignMode) && (
|
|
<CardHeader
|
|
className={cn(
|
|
"cursor-pointer",
|
|
collapsible && "hover:bg-accent/50 transition-colors"
|
|
)}
|
|
onClick={handleToggle}
|
|
>
|
|
<div className="flex items-center justify-between">
|
|
<div className="flex-1">
|
|
{(title || isDesignMode) && (
|
|
<CardTitle className="text-xl font-semibold">
|
|
{title || (isDesignMode ? "섹션 제목" : "")}
|
|
</CardTitle>
|
|
)}
|
|
{(description || isDesignMode) && (
|
|
<CardDescription className="text-sm text-muted-foreground mt-1.5">
|
|
{description || (isDesignMode ? "섹션 설명 (선택사항)" : "")}
|
|
</CardDescription>
|
|
)}
|
|
</div>
|
|
{collapsible && (
|
|
<div className={cn(
|
|
"ml-4 transition-transform",
|
|
isOpen ? "rotate-180" : "rotate-0"
|
|
)}>
|
|
<svg
|
|
xmlns="http://www.w3.org/2000/svg"
|
|
width="20"
|
|
height="20"
|
|
viewBox="0 0 24 24"
|
|
fill="none"
|
|
stroke="currentColor"
|
|
strokeWidth="2"
|
|
strokeLinecap="round"
|
|
strokeLinejoin="round"
|
|
>
|
|
<path d="m6 9 6 6 6-6" />
|
|
</svg>
|
|
</div>
|
|
)}
|
|
</div>
|
|
</CardHeader>
|
|
)}
|
|
|
|
{/* 컨텐츠 */}
|
|
{(!collapsible || isOpen) && (
|
|
<CardContent className={cn(paddingMap[padding])}>
|
|
{/* 디자인 모드에서 빈 상태 안내 */}
|
|
{isDesignMode && !children && (
|
|
<div className="flex items-center justify-center py-12 text-muted-foreground text-sm">
|
|
<div className="text-center">
|
|
<div className="mb-2">🃏 Section Card</div>
|
|
<div className="text-xs">컴포넌트를 이곳에 배치하세요</div>
|
|
</div>
|
|
</div>
|
|
)}
|
|
|
|
{/* 자식 컴포넌트들 */}
|
|
{children}
|
|
</CardContent>
|
|
)}
|
|
</Card>
|
|
);
|
|
}
|
|
|