화면관리 삭제기능구현
This commit is contained in:
@@ -6,6 +6,8 @@ import {
|
||||
WebType,
|
||||
WidgetComponent,
|
||||
FileComponent,
|
||||
AreaComponent,
|
||||
AreaLayoutType,
|
||||
DateTypeConfig,
|
||||
NumberTypeConfig,
|
||||
SelectTypeConfig,
|
||||
@@ -50,6 +52,15 @@ import {
|
||||
Edit,
|
||||
Trash2,
|
||||
Upload,
|
||||
Square,
|
||||
CreditCard,
|
||||
Layout,
|
||||
Grid3x3,
|
||||
Columns,
|
||||
Rows,
|
||||
SidebarOpen,
|
||||
Folder,
|
||||
ChevronUp,
|
||||
} from "lucide-react";
|
||||
|
||||
interface RealtimePreviewProps {
|
||||
@@ -62,6 +73,159 @@ interface RealtimePreviewProps {
|
||||
children?: React.ReactNode; // 그룹 내 자식 컴포넌트들
|
||||
}
|
||||
|
||||
// 영역 레이아웃에 따른 아이콘 반환
|
||||
const getAreaIcon = (layoutType: AreaLayoutType) => {
|
||||
switch (layoutType) {
|
||||
case "box":
|
||||
return <Square className="h-6 w-6 text-blue-600" />;
|
||||
case "card":
|
||||
return <CreditCard className="h-6 w-6 text-blue-600" />;
|
||||
case "panel":
|
||||
return <Layout className="h-6 w-6 text-blue-600" />;
|
||||
case "section":
|
||||
return <Layout className="h-6 w-6 text-blue-600" />;
|
||||
case "grid":
|
||||
return <Grid3x3 className="h-6 w-6 text-blue-600" />;
|
||||
case "flex-row":
|
||||
return <Columns className="h-6 w-6 text-blue-600" />;
|
||||
case "flex-column":
|
||||
return <Rows className="h-6 w-6 text-blue-600" />;
|
||||
case "sidebar":
|
||||
return <SidebarOpen className="h-6 w-6 text-blue-600" />;
|
||||
case "header-content":
|
||||
return <Layout className="h-6 w-6 text-blue-600" />;
|
||||
case "tabs":
|
||||
return <Folder className="h-6 w-6 text-blue-600" />;
|
||||
case "accordion":
|
||||
return <ChevronUp className="h-6 w-6 text-blue-600" />;
|
||||
default:
|
||||
return <Square className="h-6 w-6 text-blue-600" />;
|
||||
}
|
||||
};
|
||||
|
||||
// 영역 컴포넌트 렌더링
|
||||
const renderArea = (component: AreaComponent, children?: React.ReactNode) => {
|
||||
const { layoutType, title, description, layoutConfig, areaStyle } = component;
|
||||
|
||||
// 기본 스타일
|
||||
const baseStyle: React.CSSProperties = {
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
position: "relative",
|
||||
backgroundColor: areaStyle?.backgroundColor || "#ffffff",
|
||||
border: areaStyle?.borderWidth
|
||||
? `${areaStyle.borderWidth}px ${areaStyle.borderStyle || "solid"} ${areaStyle.borderColor || "#e5e7eb"}`
|
||||
: "1px solid #e5e7eb",
|
||||
borderRadius: `${areaStyle?.borderRadius || 8}px`,
|
||||
padding: `${areaStyle?.padding || 16}px`,
|
||||
margin: `${areaStyle?.margin || 0}px`,
|
||||
...(areaStyle?.shadow &&
|
||||
areaStyle.shadow !== "none" && {
|
||||
boxShadow:
|
||||
{
|
||||
sm: "0 1px 2px 0 rgba(0, 0, 0, 0.05)",
|
||||
md: "0 4px 6px -1px rgba(0, 0, 0, 0.1)",
|
||||
lg: "0 10px 15px -3px rgba(0, 0, 0, 0.1)",
|
||||
xl: "0 20px 25px -5px rgba(0, 0, 0, 0.1)",
|
||||
}[areaStyle.shadow] || "0 4px 6px -1px rgba(0, 0, 0, 0.1)",
|
||||
}),
|
||||
};
|
||||
|
||||
// 레이아웃별 컨테이너 스타일
|
||||
const getLayoutStyle = (): React.CSSProperties => {
|
||||
switch (layoutType) {
|
||||
case "grid":
|
||||
return {
|
||||
display: "grid",
|
||||
gridTemplateColumns: `repeat(${layoutConfig?.gridColumns || 3}, 1fr)`,
|
||||
gridTemplateRows: layoutConfig?.gridRows ? `repeat(${layoutConfig.gridRows}, 1fr)` : "auto",
|
||||
gap: `${layoutConfig?.gridGap || 16}px`,
|
||||
};
|
||||
|
||||
case "flex-row":
|
||||
return {
|
||||
display: "flex",
|
||||
flexDirection: "row",
|
||||
justifyContent: layoutConfig?.justifyContent || "flex-start",
|
||||
alignItems: layoutConfig?.alignItems || "stretch",
|
||||
gap: `${layoutConfig?.gap || 16}px`,
|
||||
flexWrap: layoutConfig?.flexWrap || "nowrap",
|
||||
};
|
||||
|
||||
case "flex-column":
|
||||
return {
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
justifyContent: layoutConfig?.justifyContent || "flex-start",
|
||||
alignItems: layoutConfig?.alignItems || "stretch",
|
||||
gap: `${layoutConfig?.gap || 16}px`,
|
||||
};
|
||||
|
||||
case "sidebar":
|
||||
return {
|
||||
display: "flex",
|
||||
flexDirection: layoutConfig?.sidebarPosition === "right" ? "row-reverse" : "row",
|
||||
};
|
||||
|
||||
default:
|
||||
return {};
|
||||
}
|
||||
};
|
||||
|
||||
// 헤더 렌더링 (panel, section 타입용)
|
||||
const renderHeader = () => {
|
||||
if (!title || (layoutType !== "panel" && layoutType !== "section")) return null;
|
||||
|
||||
const headerStyle: React.CSSProperties = {
|
||||
backgroundColor: areaStyle?.headerBackgroundColor || "#f3f4f6",
|
||||
color: areaStyle?.headerTextColor || "#374151",
|
||||
height: `${areaStyle?.headerHeight || 48}px`,
|
||||
padding: `${areaStyle?.headerPadding || 16}px`,
|
||||
borderBottom: layoutType === "panel" ? "1px solid #e5e7eb" : "none",
|
||||
borderTopLeftRadius: `${areaStyle?.borderRadius || 8}px`,
|
||||
borderTopRightRadius: `${areaStyle?.borderRadius || 8}px`,
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
fontWeight: "600",
|
||||
fontSize: "14px",
|
||||
};
|
||||
|
||||
return (
|
||||
<div style={headerStyle}>
|
||||
{title}
|
||||
{description && <span style={{ marginLeft: "8px", fontSize: "12px", opacity: 0.7 }}>{description}</span>}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
// 컨텐츠 영역 스타일
|
||||
const contentStyle: React.CSSProperties = {
|
||||
...getLayoutStyle(),
|
||||
flex: 1,
|
||||
minHeight: 0,
|
||||
};
|
||||
|
||||
// 자식 컴포넌트가 없을 때 표시할 플레이스홀더
|
||||
const renderPlaceholder = () => (
|
||||
<div className="pointer-events-none flex h-full flex-col items-center justify-center p-4">
|
||||
<div className="flex flex-col items-center space-y-2">
|
||||
{getAreaIcon(layoutType)}
|
||||
<div className="text-center">
|
||||
<div className="text-sm font-medium text-gray-700">{title || `${layoutType} 영역`}</div>
|
||||
<div className="text-xs text-gray-500">{description || "컴포넌트를 이 영역에 드래그하세요"}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
return (
|
||||
<div style={baseStyle}>
|
||||
{renderHeader()}
|
||||
<div style={contentStyle}>{children && React.Children.count(children) > 0 ? children : renderPlaceholder()}</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
// 웹 타입에 따른 위젯 렌더링
|
||||
const renderWidget = (component: ComponentData) => {
|
||||
// 위젯 컴포넌트가 아닌 경우 빈 div 반환
|
||||
@@ -1193,6 +1357,17 @@ export const RealtimePreview: React.FC<RealtimePreviewProps> = ({
|
||||
</div>
|
||||
)}
|
||||
|
||||
{type === "area" && (
|
||||
<div
|
||||
className="relative h-full w-full"
|
||||
data-area-container="true"
|
||||
data-component-id={component.id}
|
||||
data-layout-type={(component as AreaComponent).layoutType}
|
||||
>
|
||||
{renderArea(component as AreaComponent, children)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{false &&
|
||||
(() => {
|
||||
const dataTableComponent = component as any; // DataTableComponent 타입
|
||||
|
||||
Reference in New Issue
Block a user