enhancement: toolbar now has accordion/collapsible
This commit is contained in:
@@ -1,6 +1,9 @@
|
||||
import { memo, useEffect, useState } from "react"
|
||||
|
||||
import { Checkbox, ColorPicker, Input, InputNumber, Select } from "antd"
|
||||
import {
|
||||
Checkbox, ColorPicker, Input,
|
||||
InputNumber, Select, Collapse
|
||||
} from "antd"
|
||||
|
||||
import { capitalize } from "../utils/common"
|
||||
import Tools from "./constants/tools.js"
|
||||
@@ -128,7 +131,83 @@ const CanvasToolBar = memo(({ isOpen, widgetType, attrs = {} }) => {
|
||||
}
|
||||
|
||||
|
||||
const renderWidgets = (obj, parentKey = "") => {
|
||||
const renderTool = (keyName, val) => {
|
||||
|
||||
return (
|
||||
<>
|
||||
{val.tool === Tools.INPUT && (
|
||||
<Input
|
||||
{...val.toolProps}
|
||||
value={val.value}
|
||||
onChange={(e) => handleChange(e.target.value, val.onChange)}
|
||||
/>
|
||||
)}
|
||||
|
||||
{val.tool === Tools.NUMBER_INPUT && (
|
||||
<InputNumber
|
||||
{...val.toolProps}
|
||||
value={val.value || 0}
|
||||
size="small"
|
||||
onChange={(value) => handleChange(value, val.onChange)}
|
||||
/>
|
||||
)}
|
||||
|
||||
{val.tool === Tools.COLOR_PICKER && (
|
||||
<ColorPicker
|
||||
// defaultValue={val.value || "#fff"}
|
||||
value={val.value || "#fff"}
|
||||
disabledAlpha
|
||||
arrow={false}
|
||||
size="middle"
|
||||
showText
|
||||
format="hex"
|
||||
placement="bottomRight"
|
||||
className="tw-w-fit !tw-min-w-[110px]"
|
||||
onChange={(value) => handleChange(value.toHexString(), val.onChange)}
|
||||
/>
|
||||
)}
|
||||
|
||||
{val.tool === Tools.SELECT_DROPDOWN && (
|
||||
<Select
|
||||
options={val.options}
|
||||
showSearch
|
||||
value={val.value || ""}
|
||||
placeholder={`${val.label}`}
|
||||
onChange={(value) => handleChange(value, val.onChange)}
|
||||
/>
|
||||
)}
|
||||
|
||||
{val.tool === Tools.CHECK_BUTTON && (
|
||||
<Checkbox
|
||||
checked={val.value}
|
||||
defaultChecked={val.value}
|
||||
onChange={(e) => handleChange(e.target.checked, val.onChange)}
|
||||
>{val.label}</Checkbox>
|
||||
)}
|
||||
|
||||
{val.tool === Tools.INPUT_RADIO_LIST && (
|
||||
<DynamicRadioInputList
|
||||
defaultInputs={val.value.inputs}
|
||||
defaultSelected={val.value.selectedRadio}
|
||||
onChange={({ inputs, selectedRadio }) => handleChange({ inputs, selectedRadio }, val.onChange)}
|
||||
/>
|
||||
)}
|
||||
|
||||
{
|
||||
val.tool === Tools.LAYOUT_MANAGER && (
|
||||
renderLayoutManager(val)
|
||||
)
|
||||
}
|
||||
|
||||
</>
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
|
||||
const renderToolbar = (obj, parentKey = "", toolCount=0) => {
|
||||
const keys = []
|
||||
|
||||
return Object.entries(obj).map(([key, val], i) => {
|
||||
const keyName = parentKey ? `${parentKey}.${key}` : key
|
||||
|
||||
@@ -136,81 +215,34 @@ const CanvasToolBar = memo(({ isOpen, widgetType, attrs = {} }) => {
|
||||
const isFirstLevel = parentKey === ""
|
||||
|
||||
const outerLabelClass = isFirstLevel
|
||||
? "tw-text-base tw-text-blue-700 tw-font-medium"
|
||||
: "tw-text-base"
|
||||
? "tw-text-sm tw-text-black tw-font-medium"
|
||||
: "tw-text-sm"
|
||||
|
||||
// Render tool widgets
|
||||
if (typeof val === "object" && val.tool) {
|
||||
return (
|
||||
<div key={keyName} className="tw-flex tw-flex-col tw-gap-2">
|
||||
<div className={`${isFirstLevel ? outerLabelClass : "tw-text-sm"}`}>{val.label}</div>
|
||||
|
||||
if (isFirstLevel && keys.length < 3) keys.push(keyName)
|
||||
|
||||
if (isFirstLevel){
|
||||
|
||||
{val.tool === Tools.INPUT && (
|
||||
<Input
|
||||
{...val.toolProps}
|
||||
value={val.value}
|
||||
onChange={(e) => handleChange(e.target.value, val.onChange)}
|
||||
/>
|
||||
)}
|
||||
return (
|
||||
<Collapse key={keyName} ghost defaultActiveKey={keys}>
|
||||
<Collapse.Panel header={val.label} key={keyName}>
|
||||
{renderTool(keyName, val)}
|
||||
</Collapse.Panel>
|
||||
</Collapse>
|
||||
)
|
||||
|
||||
{val.tool === Tools.NUMBER_INPUT && (
|
||||
<InputNumber
|
||||
{...val.toolProps}
|
||||
value={val.value || 0}
|
||||
size="small"
|
||||
onChange={(value) => handleChange(value, val.onChange)}
|
||||
/>
|
||||
)}
|
||||
}
|
||||
|
||||
{val.tool === Tools.COLOR_PICKER && (
|
||||
<ColorPicker
|
||||
// defaultValue={val.value || "#fff"}
|
||||
value={val.value || "#fff"}
|
||||
disabledAlpha
|
||||
arrow={false}
|
||||
size="middle"
|
||||
showText
|
||||
format="hex"
|
||||
placement="bottomRight"
|
||||
className="tw-w-fit !tw-min-w-[110px]"
|
||||
onChange={(value) => handleChange(value.toHexString(), val.onChange)}
|
||||
/>
|
||||
)}
|
||||
|
||||
{val.tool === Tools.SELECT_DROPDOWN && (
|
||||
<Select
|
||||
options={val.options}
|
||||
showSearch
|
||||
value={val.value || ""}
|
||||
placeholder={`${val.label}`}
|
||||
onChange={(value) => handleChange(value, val.onChange)}
|
||||
/>
|
||||
)}
|
||||
|
||||
{val.tool === Tools.CHECK_BUTTON && (
|
||||
<Checkbox
|
||||
checked={val.value}
|
||||
defaultChecked={val.value}
|
||||
onChange={(e) => handleChange(e.target.checked, val.onChange)}
|
||||
>{val.label}</Checkbox>
|
||||
)}
|
||||
|
||||
{val.tool === Tools.INPUT_RADIO_LIST && (
|
||||
<DynamicRadioInputList
|
||||
defaultInputs={val.value.inputs}
|
||||
defaultSelected={val.value.selectedRadio}
|
||||
onChange={({inputs, selectedRadio}) => handleChange({inputs, selectedRadio}, val.onChange)}
|
||||
/>
|
||||
)}
|
||||
|
||||
{
|
||||
val.tool === Tools.LAYOUT_MANAGER && (
|
||||
renderLayoutManager(val)
|
||||
)
|
||||
}
|
||||
|
||||
</div>
|
||||
);
|
||||
else
|
||||
return (
|
||||
<div key={keyName} className="tw-flex tw-flex-col tw-gap-2">
|
||||
<div className={`${isFirstLevel ? outerLabelClass : "tw-text-sm"}`}>{val.label}</div>
|
||||
{renderTool(keyName, val)}
|
||||
</div>
|
||||
|
||||
)
|
||||
}
|
||||
|
||||
// Handle nested objects and horizontal display for inner elements
|
||||
@@ -219,13 +251,29 @@ const CanvasToolBar = memo(({ isOpen, widgetType, attrs = {} }) => {
|
||||
? "tw-flex tw-flex-row tw-flex-wrap tw-content-start tw-gap-4"
|
||||
: "tw-flex tw-flex-col tw-gap-2"
|
||||
|
||||
return (
|
||||
<div key={keyName} className="tw-flex tw-flex-col tw-gap-2">
|
||||
{/* Outer label highlighted in blue for first-level */}
|
||||
<div className={outerLabelClass}>{val.label}</div>
|
||||
<div className={`${containerClass} tw-px-2`}>{renderWidgets(val, keyName)}</div>
|
||||
</div>
|
||||
)
|
||||
if (isFirstLevel && keys.length < 3) keys.push(keyName)
|
||||
|
||||
if (isFirstLevel){
|
||||
return (
|
||||
<Collapse key={keyName} ghost defaultActiveKey={keys}>
|
||||
<Collapse.Panel header={val.label} key={keyName}>
|
||||
<div className={`${containerClass} tw-px-2`}>
|
||||
{renderToolbar(val, keyName, toolCount+1)}
|
||||
</div>
|
||||
</Collapse.Panel>
|
||||
</Collapse>
|
||||
)
|
||||
}else{
|
||||
return (
|
||||
<div key={keyName} className="tw-flex tw-flex-col tw-gap-2">
|
||||
{/* Outer label highlighted in blue for first-level */}
|
||||
<div className={outerLabelClass}>{val.label}</div>
|
||||
<div className={`${containerClass} tw-px-2`}>
|
||||
{renderToolbar(val, keyName, toolCount+1)}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
return null
|
||||
@@ -235,15 +283,17 @@ const CanvasToolBar = memo(({ isOpen, widgetType, attrs = {} }) => {
|
||||
return (
|
||||
<div
|
||||
className={`tw-absolute tw-top-20 tw-right-5 tw-bg-white ${toolbarOpen ? "tw-w-[280px]" : "tw-w-0"
|
||||
} tw-px-4 tw-p-2 tw-h-[600px] tw-rounded-md tw-z-[1000] tw-shadow-lg
|
||||
} tw-px-3 tw-p-2 tw-h-[600px] tw-rounded-md tw-z-[1000] tw-shadow-lg
|
||||
tw-transition-transform tw-duration-75 tw-overflow-x-hidden
|
||||
tw-flex tw-flex-col tw-gap-2 tw-overflow-y-auto`}
|
||||
>
|
||||
<h3 className="tw-text-xl tw-text-center">
|
||||
<h3 className="tw-text-lg tw-text-center">
|
||||
{capitalize(`${widgetType || ""}`).replace(/_/g, " ")}
|
||||
</h3>
|
||||
|
||||
<div className="tw-flex tw-flex-col tw-gap-4">{renderWidgets(toolbarAttrs || {})}</div>
|
||||
<div className="tw-flex tw-flex-col tw-gap-2">
|
||||
{renderToolbar(toolbarAttrs || {})}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ import WidgetDraggable from "./widgetDragDrop"
|
||||
import WidgetContainer from "../constants/containers"
|
||||
import { DragContext } from "../../components/draggable/draggableContext"
|
||||
|
||||
|
||||
// FIXME: make it possible to have fit-width and height
|
||||
|
||||
const ATTRS_KEYS = ['value', 'label', 'tool', 'onChange', 'toolProps'] // these are attrs keywords, don't use these keywords as keys while defining the attrs property
|
||||
|
||||
@@ -138,12 +138,12 @@ class Widget extends React.Component {
|
||||
this.setLayout(value)
|
||||
}
|
||||
},
|
||||
events: {
|
||||
event1: {
|
||||
tool: Tools.EVENT_HANDLER,
|
||||
value: ""
|
||||
}
|
||||
}
|
||||
// events: {
|
||||
// event1: {
|
||||
// tool: Tools.EVENT_HANDLER,
|
||||
// value: ""
|
||||
// }
|
||||
// }
|
||||
},
|
||||
}
|
||||
|
||||
@@ -617,15 +617,11 @@ class Widget extends React.Component {
|
||||
|
||||
const {attrs, parentLayout, ...restData} = data
|
||||
|
||||
// for (let [key, value] of Object.entries(attrs | {}))
|
||||
// this.setAttrValue(key, value)
|
||||
|
||||
// delete data.attrs
|
||||
|
||||
let layoutUpdates = {
|
||||
parentLayout: parentLayout
|
||||
}
|
||||
// FIXME: Need to load the data properly
|
||||
|
||||
if (parentLayout === Layouts.FLEX || parentLayout === Layouts.GRID){
|
||||
|
||||
layoutUpdates = {
|
||||
@@ -640,8 +636,6 @@ class Widget extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
console.log("loaded layout: ", layoutUpdates)
|
||||
|
||||
const newData = {
|
||||
...restData,
|
||||
layoutUpdates
|
||||
|
||||
@@ -28,6 +28,7 @@ export class CheckBox extends Widget{
|
||||
attrs: {
|
||||
...newAttrs,
|
||||
styling: {
|
||||
label: "Styling",
|
||||
foregroundColor: {
|
||||
label: "Foreground Color",
|
||||
tool: Tools.COLOR_PICKER, // the tool to display, can be either HTML ELement or a constant string
|
||||
@@ -128,6 +129,7 @@ export class RadioButton extends Widget{
|
||||
attrs: {
|
||||
...newAttrs,
|
||||
styling: {
|
||||
label: "styling",
|
||||
foregroundColor: {
|
||||
label: "Foreground Color",
|
||||
tool: Tools.COLOR_PICKER, // the tool to display, can be either HTML ELement or a constant string
|
||||
|
||||
@@ -28,6 +28,7 @@ class OptionMenu extends Widget{
|
||||
attrs: {
|
||||
...newAttrs,
|
||||
styling: {
|
||||
label: "styling",
|
||||
foregroundColor: {
|
||||
label: "Foreground Color",
|
||||
tool: Tools.COLOR_PICKER, // the tool to display, can be either HTML ELement or a constant string
|
||||
|
||||
Reference in New Issue
Block a user