2024-09-13 16:03:58 +05:30
|
|
|
import { useEffect, useState } from "react"
|
2024-09-13 19:24:03 +05:30
|
|
|
|
2024-09-14 16:03:26 +05:30
|
|
|
import { ColorPicker, Input, InputNumber, Select } from "antd"
|
2024-09-13 19:24:03 +05:30
|
|
|
|
2024-09-13 16:03:58 +05:30
|
|
|
import { capitalize } from "../utils/common"
|
2024-09-13 22:05:38 +05:30
|
|
|
import Tools from "./constants/tools.js"
|
2024-09-13 16:03:58 +05:30
|
|
|
|
|
|
|
|
|
2024-09-13 19:24:03 +05:30
|
|
|
/**
|
|
|
|
|
*
|
|
|
|
|
* @param {boolean} isOpen
|
|
|
|
|
* @param {import("./widgets/base.js").Widget} activeWidget
|
|
|
|
|
* @param {React.Dispatch<React.SetStateAction<import("./widgets/base.js").Widget>>} setActiveWidget
|
|
|
|
|
* @returns
|
|
|
|
|
*/
|
|
|
|
|
function CanvasToolBar({isOpen, activeWidget, setActiveWidget}){
|
2024-09-13 16:03:58 +05:30
|
|
|
|
|
|
|
|
const [toolbarOpen, setToolbarOpen] = useState(isOpen)
|
|
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
setToolbarOpen(isOpen)
|
|
|
|
|
}, [isOpen])
|
|
|
|
|
|
|
|
|
|
|
2024-09-13 19:24:03 +05:30
|
|
|
const handleWidgetNameChange = (e) => {
|
2024-09-14 16:03:26 +05:30
|
|
|
activeWidget?.setWidgetName(e.target.value) // Update widget's internal state
|
2024-09-13 19:24:03 +05:30
|
|
|
const updatedWidget = { ...activeWidget } // Create a shallow copy of the widget
|
|
|
|
|
setActiveWidget(updatedWidget) // Update the state with the modified widget
|
|
|
|
|
}
|
|
|
|
|
|
2024-09-14 16:03:26 +05:30
|
|
|
const handleChange = (attrPath, value, callback) => {
|
|
|
|
|
// console.log("Value: ", attrPath, value)
|
|
|
|
|
activeWidget?.setAttrValue(attrPath, value) // Update widget's internal state
|
|
|
|
|
const updatedWidget = { ...activeWidget }
|
|
|
|
|
|
|
|
|
|
if (callback){
|
|
|
|
|
callback(value)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
setActiveWidget(updatedWidget)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const renderWidgets = (obj, parentKey = "") => {
|
|
|
|
|
return Object.entries(obj).map(([key, val], i) => {
|
|
|
|
|
// console.log("parent key: ", parentKey)
|
|
|
|
|
// Build a unique identifier for keys that handle nested structures
|
|
|
|
|
const keyName = parentKey ? `${parentKey}.${key}` : key
|
|
|
|
|
|
|
|
|
|
// Check if the current value is an object and has a "tool" property
|
|
|
|
|
if (typeof val === "object" && val.tool) {
|
|
|
|
|
// Render widgets based on the tool type
|
|
|
|
|
return (
|
|
|
|
|
<div key={keyName} className="tw-flex tw-flex-col tw-gap-2">
|
|
|
|
|
{
|
|
|
|
|
parentKey ?
|
|
|
|
|
<div className={`tw-text-sm tw-font-medium `}>{val.label}</div>
|
|
|
|
|
:
|
|
|
|
|
<div className="tw-text-lg tw-text-blue-700">{capitalize(key)}</div>
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
val.tool === Tools.NUMBER_INPUT && (
|
|
|
|
|
<InputNumber
|
|
|
|
|
defaultValue={val.value || 0}
|
|
|
|
|
size="small"
|
|
|
|
|
onChange={(value) => handleChange(keyName, value, val.onChange)}
|
|
|
|
|
/>
|
|
|
|
|
)}
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
val.tool === Tools.COLOR_PICKER && (
|
|
|
|
|
<ColorPicker
|
|
|
|
|
defaultValue={val.value || "#fff"}
|
|
|
|
|
disabledAlpha
|
|
|
|
|
arrow={false}
|
|
|
|
|
size="middle"
|
|
|
|
|
showText
|
|
|
|
|
format="hex"
|
|
|
|
|
placement="bottomRight"
|
|
|
|
|
className="tw-w-fit !tw-min-w-[100px]"
|
|
|
|
|
onChange={(value) => handleChange(keyName, value.toHexString(), val.onChange)}
|
|
|
|
|
/>
|
|
|
|
|
)}
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
val.tool === Tools.SELECT_DROPDOWN && (
|
|
|
|
|
<Select
|
|
|
|
|
options={val.options}
|
|
|
|
|
showSearch
|
|
|
|
|
value={val.value || ""}
|
|
|
|
|
placeholder={`${val.label}`}
|
|
|
|
|
onChange={(value) => handleChange(keyName, value, val.onChange)}
|
|
|
|
|
/>
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
{/* Add more widget types here as needed */}
|
|
|
|
|
</div>
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// If the value is another nested object, recursively call renderWidgets
|
|
|
|
|
if (typeof val === "object") {
|
|
|
|
|
return (
|
|
|
|
|
<div key={keyName} className="tw-flex tw-flex-col tw-gap-2">
|
|
|
|
|
<div className="tw-text-lg tw-text-blue-700">{capitalize(key)}</div>
|
|
|
|
|
{renderWidgets(val, keyName)}
|
|
|
|
|
</div>
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return null // Skip rendering for non-object types
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
2024-09-13 16:03:58 +05:30
|
|
|
return (
|
|
|
|
|
<div className={`tw-absolute tw-top-20 tw-right-5 tw-bg-white ${toolbarOpen ? "tw-w-[320px]": "tw-w-0"}
|
|
|
|
|
tw-px-4 tw-p-2 tw-h-[600px] tw-rounded-md tw-z-20 tw-shadow-lg
|
|
|
|
|
tw-transition-transform tw-duration-75
|
2024-09-14 16:03:26 +05:30
|
|
|
tw-flex tw-flex-col tw-overflow-y-auto
|
2024-09-13 16:03:58 +05:30
|
|
|
`}
|
|
|
|
|
>
|
|
|
|
|
|
2024-09-14 16:03:26 +05:30
|
|
|
<h3 className="tw-text-xl tw-text-center">
|
2024-09-13 19:24:03 +05:30
|
|
|
{capitalize(`${activeWidget?.getWidgetType() || ""}`)}
|
2024-09-13 16:03:58 +05:30
|
|
|
</h3>
|
|
|
|
|
|
2024-09-13 19:24:03 +05:30
|
|
|
<div>
|
|
|
|
|
<Input placeholder="widget name"
|
|
|
|
|
value={activeWidget?.getWidgetName() || ""}
|
|
|
|
|
onChange={handleWidgetNameChange}
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
2024-09-13 22:05:38 +05:30
|
|
|
<hr />
|
|
|
|
|
<div className="tw-flex tw-flex-col tw-gap-4">
|
2024-09-14 16:03:26 +05:30
|
|
|
{renderWidgets(activeWidget?.state?.attrs || {})}
|
2024-09-13 22:05:38 +05:30
|
|
|
</div>
|
2024-09-13 19:24:03 +05:30
|
|
|
|
2024-09-13 16:03:58 +05:30
|
|
|
</div>
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
export default CanvasToolBar
|