enhancement: toolbar now has accordion/collapsible

This commit is contained in:
paul
2024-09-24 23:27:52 +05:30
parent 00277205f5
commit 492115bb4c
4 changed files with 142 additions and 95 deletions

View File

@@ -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>
)

View File

@@ -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

View File

@@ -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

View File

@@ -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