2024-09-12 19:20:46 +05:30
|
|
|
import { useRef, useState } from 'react'
|
2024-08-04 22:47:43 +05:30
|
|
|
|
2024-08-05 22:36:05 +05:30
|
|
|
import { LayoutFilled, ProductFilled, CloudUploadOutlined } from "@ant-design/icons"
|
2024-08-04 22:47:43 +05:30
|
|
|
|
2024-08-05 22:36:05 +05:30
|
|
|
import Sidebar from './sidebar/sidebar'
|
|
|
|
|
import WidgetsContainer from './sidebar/widgetsContainer'
|
|
|
|
|
import UploadsContainer from './sidebar/uploadsContainer'
|
2024-08-08 16:21:19 +05:30
|
|
|
import Canvas from './canvas/canvas'
|
2024-09-08 21:58:53 +05:30
|
|
|
import Header from './components/header'
|
2024-09-12 19:20:46 +05:30
|
|
|
import { DndContext, useSensors, useSensor, PointerSensor, closestCorners, DragOverlay, rectIntersection } from '@dnd-kit/core'
|
2024-09-11 19:06:04 +05:30
|
|
|
import { DraggableWidgetCard } from './components/cards'
|
2024-09-12 19:20:46 +05:30
|
|
|
import Widget from './canvas/widgets/base'
|
|
|
|
|
import { snapCenterToCursor } from '@dnd-kit/modifiers'
|
2024-09-11 19:06:04 +05:30
|
|
|
|
2024-08-04 12:08:30 +05:30
|
|
|
|
|
|
|
|
function App() {
|
2024-08-04 22:47:43 +05:30
|
|
|
|
2024-09-12 19:20:46 +05:30
|
|
|
/**
|
|
|
|
|
* @type {Canvas | null>}
|
|
|
|
|
*/
|
|
|
|
|
const canvasRef = useRef()
|
|
|
|
|
|
2024-08-05 22:36:05 +05:30
|
|
|
const [uploadedAssets, setUploadedAssets] = useState([]) // a global storage for assets, since redux can't store files(serialize files)
|
|
|
|
|
|
2024-09-12 19:20:46 +05:30
|
|
|
const [dropAnimation, setDropAnimation] = useState(null)
|
|
|
|
|
|
2024-09-11 19:06:04 +05:30
|
|
|
const [sidebarWidgets, setSidebarWidgets] = useState([])
|
|
|
|
|
const [canvasWidgets, setCanvasWidgets] = useState([]) // contains the reference to the widgets inside the canvas
|
|
|
|
|
|
|
|
|
|
const [activeSidebarWidget, setActiveSidebarWidget] = useState(null) // helps with the dnd overlay
|
|
|
|
|
|
|
|
|
|
const sensors = useSensors(
|
|
|
|
|
useSensor(PointerSensor)
|
|
|
|
|
)
|
2024-08-05 22:36:05 +05:30
|
|
|
|
2024-09-11 19:06:04 +05:30
|
|
|
const sidebarTabs = [
|
2024-08-04 22:47:43 +05:30
|
|
|
{
|
|
|
|
|
name: "Widgets",
|
|
|
|
|
icon: <LayoutFilled />,
|
2024-09-11 19:06:04 +05:30
|
|
|
content: <WidgetsContainer onWidgetsUpdate={(widgets) => setSidebarWidgets(widgets)}/>
|
2024-08-04 22:47:43 +05:30
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: "Extensions",
|
|
|
|
|
icon: <ProductFilled />,
|
|
|
|
|
content: <></>
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: "Uploads",
|
|
|
|
|
icon: <CloudUploadOutlined />,
|
2024-08-05 22:36:05 +05:30
|
|
|
content: <UploadsContainer assets={uploadedAssets}
|
|
|
|
|
onAssetUploadChange={(assets) => setUploadedAssets(assets)}/>
|
2024-08-04 22:47:43 +05:30
|
|
|
}
|
|
|
|
|
]
|
|
|
|
|
|
2024-09-11 19:06:04 +05:30
|
|
|
const handleDragStart = (event) => {
|
2024-09-12 19:20:46 +05:30
|
|
|
console.log("Drag start: ", event)
|
2024-09-11 19:06:04 +05:30
|
|
|
const draggedItem = sidebarWidgets.find((item) => item.name === event.active.id)
|
|
|
|
|
setActiveSidebarWidget(draggedItem)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const handleDragMove = (event) => {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const handleDragEnd = (event) => {
|
|
|
|
|
// add items to canvas from sidebar
|
|
|
|
|
|
2024-09-12 19:20:46 +05:30
|
|
|
const {active, over, delta, activatorEvent} = event
|
|
|
|
|
|
|
|
|
|
const widgetItem = active.data.current?.title
|
|
|
|
|
const activeItemElement = document.getElementById(`${active.id}`)
|
|
|
|
|
|
|
|
|
|
// console.log("ended: ", activatorEvent, "delta", delta, "drag ended: ", event, "active: ", active, "over: ", over)
|
|
|
|
|
console.log("over: ", active, over, activeItemElement)
|
|
|
|
|
if (over?.id !== "canvas-droppable" || !widgetItem) {
|
|
|
|
|
setDropAnimation({ duration: 250, easing: "ease" })
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
setDropAnimation(null)
|
|
|
|
|
|
2024-09-12 22:09:13 +05:30
|
|
|
// FIXME: drop offset is not correct
|
2024-09-12 19:20:46 +05:30
|
|
|
// Calculate the dragged item's bounding rectangle
|
|
|
|
|
// const itemRect = activeItemElement.getBoundingClientRect();
|
|
|
|
|
// const itemCenterX = itemRect.left + itemRect.width / 2
|
|
|
|
|
// const itemCenterY = itemRect.top + itemRect.height / 2
|
|
|
|
|
|
|
|
|
|
// // Calculate cursor position relative to the canvas
|
|
|
|
|
// const cursorX = activatorEvent.clientX
|
|
|
|
|
// const cursorY = activatorEvent.clientY
|
|
|
|
|
|
|
|
|
|
// // Calculate the offset from the center of the item to the cursor
|
|
|
|
|
// const offsetX = cursorX - itemCenterX
|
|
|
|
|
// const offsetY = cursorY - itemCenterY
|
|
|
|
|
|
|
|
|
|
const canvasContainerRect = canvasRef.current.getCanvasContainerBoundingRect()
|
|
|
|
|
const canvasTranslate = canvasRef.current.getCanvasTranslation()
|
|
|
|
|
const zoom = canvasRef.current.getZoom()
|
|
|
|
|
|
|
|
|
|
let finalPosition = {
|
|
|
|
|
x: (delta.x - canvasContainerRect.x - canvasTranslate.x) / zoom,
|
|
|
|
|
y: (delta.y - canvasContainerRect.y - canvasTranslate.y) / zoom,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// find the center of the active widget then set the final position
|
|
|
|
|
|
|
|
|
|
// finalPosition = {
|
|
|
|
|
// finalPosition
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// console.log("drop position: ", "delta: ", delta, "activator", canvasContainerRect, canvasTranslate,)
|
|
|
|
|
|
|
|
|
|
canvasRef.current.addWidget(Widget, ({id, widgetRef}) => {
|
|
|
|
|
widgetRef.current.setPos(finalPosition.x, finalPosition.y)
|
|
|
|
|
// widgetRef.current.setPos(10, 10)
|
|
|
|
|
})
|
|
|
|
|
|
2024-09-11 19:06:04 +05:30
|
|
|
setActiveSidebarWidget(null)
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
2024-09-12 19:20:46 +05:30
|
|
|
const handleWidgetAddedToCanvas = (widgets) => {
|
|
|
|
|
console.log("canvas ref: ", canvasRef)
|
|
|
|
|
setCanvasWidgets(widgets)
|
|
|
|
|
}
|
2024-09-11 19:06:04 +05:30
|
|
|
|
2024-08-04 12:08:30 +05:30
|
|
|
return (
|
2024-09-08 21:58:53 +05:30
|
|
|
<div className="tw-w-full tw-h-[100vh] tw-flex tw-flex-col tw-bg-primaryBg">
|
|
|
|
|
<Header className="tw-h-[6vh]"/>
|
2024-09-11 19:06:04 +05:30
|
|
|
|
2024-09-12 19:20:46 +05:30
|
|
|
<DndContext sensors={sensors}
|
|
|
|
|
modifiers={[snapCenterToCursor]}
|
|
|
|
|
collisionDetection={rectIntersection}
|
2024-09-11 19:06:04 +05:30
|
|
|
onDragStart={handleDragStart}
|
|
|
|
|
onDragMove={handleDragMove}
|
|
|
|
|
onDragEnd={handleDragEnd}
|
2024-09-12 19:20:46 +05:30
|
|
|
|
2024-09-11 19:06:04 +05:30
|
|
|
>
|
|
|
|
|
<div className="tw-w-full tw-h-[94vh] tw-flex">
|
|
|
|
|
<Sidebar tabs={sidebarTabs}/>
|
2024-09-12 19:20:46 +05:30
|
|
|
<Canvas ref={canvasRef} widgets={canvasWidgets} onWidgetAdded={handleWidgetAddedToCanvas}/>
|
2024-09-11 19:06:04 +05:30
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
{/* dragOverlay (dnd-kit) helps move items from one container to another */}
|
2024-09-12 19:20:46 +05:30
|
|
|
<DragOverlay dropAnimation={dropAnimation} >
|
2024-09-11 19:06:04 +05:30
|
|
|
{activeSidebarWidget ? (
|
|
|
|
|
<DraggableWidgetCard name={activeSidebarWidget.name}
|
|
|
|
|
img={activeSidebarWidget.img}
|
2024-09-12 19:20:46 +05:30
|
|
|
url={activeSidebarWidget.link}
|
2024-09-11 19:06:04 +05:30
|
|
|
/>
|
|
|
|
|
):
|
|
|
|
|
null}
|
|
|
|
|
</DragOverlay>
|
|
|
|
|
|
|
|
|
|
</DndContext>
|
2024-08-04 12:08:30 +05:30
|
|
|
</div>
|
2024-09-11 19:06:04 +05:30
|
|
|
)
|
2024-08-04 12:08:30 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export default App;
|