92 lines
2.8 KiB
TypeScript
92 lines
2.8 KiB
TypeScript
"use client";
|
|
|
|
import React, { useCallback } from "react";
|
|
import { useBuilderState, useCurrentViewBlocks } from "./hooks/useBuilderState";
|
|
import BuilderBlock from "./BuilderBlock";
|
|
import type { ComponentType } from "@/types/invyone-component";
|
|
|
|
export default function BuilderCanvas() {
|
|
const blocks = useCurrentViewBlocks();
|
|
const addBlock = useBuilderState((s) => s.addBlock);
|
|
const selectBlock = useBuilderState((s) => s.selectBlock);
|
|
const currentView = useBuilderState((s) => s.currentView);
|
|
|
|
const handleDrop = useCallback(
|
|
(e: React.DragEvent) => {
|
|
e.preventDefault();
|
|
const type = e.dataTransfer.getData("component-type") as ComponentType;
|
|
if (!type) return;
|
|
const rect = e.currentTarget.getBoundingClientRect();
|
|
const x = Math.round(e.clientX - rect.left);
|
|
const y = Math.round(e.clientY - rect.top);
|
|
addBlock(type, { x, y, w: 0, h: 0 });
|
|
},
|
|
[addBlock]
|
|
);
|
|
|
|
const handleDragOver = useCallback((e: React.DragEvent) => {
|
|
e.preventDefault();
|
|
e.dataTransfer.dropEffect = "copy";
|
|
}, []);
|
|
|
|
const handleCanvasClick = useCallback(
|
|
(e: React.MouseEvent) => {
|
|
if ((e.target as HTMLElement).closest(".dev-block")) return;
|
|
selectBlock(null);
|
|
},
|
|
[selectBlock]
|
|
);
|
|
|
|
// 팝업 뷰 (등록/수정)
|
|
if (currentView !== "list") {
|
|
return (
|
|
<div className="dev-canvas" onClick={handleCanvasClick}>
|
|
<div className="dev-popup-overlay">
|
|
<div className="dev-popup-frame">
|
|
<div
|
|
className="dev-canvas-inner"
|
|
onDrop={handleDrop}
|
|
onDragOver={handleDragOver}
|
|
>
|
|
{blocks.length === 0 && (
|
|
<div className="dev-empty">
|
|
<div className="dev-empty-icon">📝</div>
|
|
<div className="dev-empty-text">
|
|
{currentView === "create" ? "등록" : "수정"} 팝업에 컴포넌트를 배치하세요
|
|
</div>
|
|
</div>
|
|
)}
|
|
{blocks.map((block) => (
|
|
<BuilderBlock key={block.id} block={block} />
|
|
))}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<div
|
|
className="dev-canvas"
|
|
onClick={handleCanvasClick}
|
|
onDrop={handleDrop}
|
|
onDragOver={handleDragOver}
|
|
>
|
|
<div className="dev-canvas-inner">
|
|
{blocks.length === 0 && (
|
|
<div className="dev-empty">
|
|
<div className="dev-empty-icon">🎨</div>
|
|
<div className="dev-empty-text">
|
|
팔레트에서 컴포넌트를 드래그하거나 클릭하여 추가하세요
|
|
</div>
|
|
</div>
|
|
)}
|
|
{blocks.map((block) => (
|
|
<BuilderBlock key={block.id} block={block} />
|
|
))}
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|