feat: introduce BlockEditor for interactive block style, size, and position management within the simulation dashboard.

This commit is contained in:
2025-12-20 13:18:41 +05:30
parent 7646bfa07b
commit da85c33266
3 changed files with 108 additions and 56 deletions

View File

@@ -272,7 +272,7 @@ const BlockEditor: React.FC<BlockEditorProps> = ({
/>
<InputWithDropDown
label="Corner Radius"
label="Border Radius"
min={0}
value={String(
parseInt(getCurrentBlockStyleValue(currentBlock, "borderRadius")) ||

View File

@@ -1,4 +1,4 @@
import React, { RefObject, useState } from "react";
import React, { RefObject, useEffect, useState } from "react";
import DataSourceSelector from "../../../ui/inputs/DataSourceSelector";
import RenameInput from "../../../ui/inputs/RenameInput";
import {
@@ -78,6 +78,13 @@ const ElementDesign: React.FC<ElementDesignProps> = ({
setShowSwapUI,
}) => {
const [color, setColor] = useState("#000000");
useEffect(() => {
setColor(
rgbaToHex(getCurrentElementStyleValue(currentElement, "backgroundColor") || "#000000")
);
}, [currentElement]);
return (
<div style={{ display: "flex", flexDirection: "column", gap: 6 }} ref={elementEditorRef}>
{element?.type === "graph" && (
@@ -176,8 +183,8 @@ const ElementDesign: React.FC<ElementDesignProps> = ({
<div className="section">
<div
className={`icon ${getCurrentElementStyleValue(currentElement, "textAlign") === "right"
? "active"
: ""
? "active"
: ""
}`}
onClick={() =>
updateElementStyle(selectedBlock, selectedElement, {
@@ -189,9 +196,9 @@ const ElementDesign: React.FC<ElementDesignProps> = ({
</div>
<div
className={`icon ${getCurrentElementStyleValue(currentElement, "textAlign") ===
"justify"
? "active"
: ""
"justify"
? "active"
: ""
}`}
onClick={() =>
updateElementStyle(selectedBlock, selectedElement, {
@@ -203,8 +210,8 @@ const ElementDesign: React.FC<ElementDesignProps> = ({
</div>
<div
className={`icon ${getCurrentElementStyleValue(currentElement, "textAlign") === "left"
? "active"
: ""
? "active"
: ""
}`}
onClick={() =>
updateElementStyle(selectedBlock, selectedElement, {
@@ -218,8 +225,8 @@ const ElementDesign: React.FC<ElementDesignProps> = ({
<div className="section">
<div
className={`icon ${((currentElement.style.flexDirection as string) || "row") === "row"
? "active"
: ""
? "active"
: ""
}`}
onClick={() =>
updateElementStyle(selectedBlock, selectedElement, {
@@ -231,9 +238,9 @@ const ElementDesign: React.FC<ElementDesignProps> = ({
</div>
<div
className={`icon ${((currentElement.style.flexDirection as string) || "row") ===
"column"
? "active"
: ""
"column"
? "active"
: ""
}`}
onClick={() =>
updateElementStyle(selectedBlock, selectedElement, {
@@ -245,9 +252,9 @@ const ElementDesign: React.FC<ElementDesignProps> = ({
</div>
<div
className={`icon ${((currentElement.style.flexDirection as string) || "row") ===
"row-reverse"
? "active"
: ""
"row-reverse"
? "active"
: ""
}`}
onClick={() =>
updateElementStyle(selectedBlock, selectedElement, {
@@ -259,9 +266,9 @@ const ElementDesign: React.FC<ElementDesignProps> = ({
</div>
<div
className={`icon ${((currentElement.style.flexDirection as string) || "row") ===
"column-reverse"
? "active"
: ""
"column-reverse"
? "active"
: ""
}`}
onClick={() =>
updateElementStyle(selectedBlock, selectedElement, {
@@ -274,27 +281,52 @@ const ElementDesign: React.FC<ElementDesignProps> = ({
</div>
</div>
<div className="design-section-footer">
<InputWithDropDown
label="Layer"
value={String(currentElement.zIndex || 1)}
placeholder={"Layer"}
onChange={(newValue: string) => updateElementZIndex(selectedBlock, selectedElement, Number(newValue))}
/>
<InputRange
label={"Radius"}
min={0}
max={8}
value={
parseInt(
getCurrentElementStyleValue(currentElement, "borderRadius") || ""
) || 8
}
onChange={(newValue: number) => {
updateElementStyle(selectedBlock, selectedElement, {
borderRadius: Number(newValue),
});
}}
/>
<div className="layer-system">
<InputWithDropDown
label="Layer"
value={String(currentElement.zIndex || 1)}
placeholder={"Layer"}
onChange={(newValue: string) =>
updateElementZIndex(
selectedBlock,
selectedElement,
Number(newValue)
)
}
/>
<button
className="increase-z"
onClick={() => {
updateElementZIndex(
selectedBlock,
selectedElement,
Number(currentElement.zIndex ? currentElement.zIndex + 1 : 1)
);
}}
>
<ArrowIcon />
</button>
<button
className="decrease-z"
onClick={() => {
updateElementZIndex(
selectedBlock,
selectedElement,
Number(currentElement.zIndex ? currentElement.zIndex - 1 : 1)
);
}}
>
<ArrowIcon />
</button>
<button
className="reset"
onClick={() => {
updateElementZIndex(selectedBlock, selectedElement, Number(1));
}}
>
<ResetIcon />
</button>
</div>
</div>
</div>
@@ -361,9 +393,6 @@ const ElementDesign: React.FC<ElementDesignProps> = ({
<div className="left">
<input
type="color"
defaultValue={rgbaToHex(
getCurrentElementStyleValue(currentElement, "backgroundColor")
)}
value={color}
onChange={(e) => {
updateElementStyle(selectedBlock, selectedElement, {
@@ -399,12 +428,13 @@ const ElementDesign: React.FC<ElementDesignProps> = ({
<InputRange
label={"Opacity"}
min={0}
max={100}
value={Math.round(getAlphaFromRgba(getCurrentElementStyleValue(currentElement, "backgroundColor") || "rgba(0,0,0,1)") * 100)}
max={1}
step={0.1}
value={getAlphaFromRgba(getCurrentElementStyleValue(currentElement, "backgroundColor") || "rgba(0,0,0,1)")}
onChange={(value: number) => {
const currentBg = getCurrentElementStyleValue(currentElement, "backgroundColor") || "rgba(0,0,0,1)";
const currentHex = rgbaToHex(currentBg);
const newBg = hexToRgba(currentHex, Number(value) / 100);
const newBg = hexToRgba(currentHex, Number(value));
updateElementStyle(selectedBlock, selectedElement, { backgroundColor: newBg });
}}
/>
@@ -417,6 +447,21 @@ const ElementDesign: React.FC<ElementDesignProps> = ({
updateElementStyle(selectedBlock, selectedElement, { backdropFilter: `blur(${Number(value)}px)` });
}}
/>
<InputRange
label={"Border Radius"}
min={0}
max={8}
value={
parseInt(
getCurrentElementStyleValue(currentElement, "borderRadius") || ""
) || 8
}
onChange={(newValue: number) => {
updateElementStyle(selectedBlock, selectedElement, {
borderRadius: Number(newValue),
});
}}
/>
</div>
</div>
);

View File

@@ -12,7 +12,7 @@
left: 0;
pointer-events: none;
* > {
*> {
pointer-events: auto;
}
@@ -88,6 +88,7 @@
&.edit-mode {
cursor: pointer;
&:hover {
outline: 1px solid var(--border-color-accent);
}
@@ -185,6 +186,7 @@
&.edit-mode {
transition: all 0.2s;
outline: 1px solid transparent;
&:hover {
outline-color: var(--border-color);
transform: translateY(-2px);
@@ -200,6 +202,7 @@
&.selected {
outline: 2px solid var(--border-color-accent) !important;
background-color: rgba(98, 0, 255, 0.089);
&:hover {
transform: translateY(0);
}
@@ -365,7 +368,6 @@
.value-field-container {
padding: 0;
margin: 0;
// padding: 6px 0px;
}
.select-type {
@@ -498,11 +500,9 @@
.colorValue {
width: 100%;
background: linear-gradient(
90.85deg,
rgba(240, 228, 255, 0.3) 3.6%,
rgba(211, 174, 253, 0.3) 96.04%
);
background: linear-gradient(90.85deg,
rgba(240, 228, 255, 0.3) 3.6%,
rgba(211, 174, 253, 0.3) 96.04%);
text-align: center;
padding: 4px 0;
border-radius: 100px;
@@ -514,10 +514,12 @@
display: flex;
flex-direction: column;
gap: 7px;
.layer-system {
display: flex;
align-items: center;
gap: 3px;
.increase-z,
.decrease-z,
.reset {
@@ -530,13 +532,16 @@
justify-content: center;
cursor: pointer;
transition: background 0.2s;
&:hover {
background: var(--background-color-accent);
}
svg {
pointer-events: none;
}
}
.increase-z {
svg {
rotate: 180deg;
@@ -556,7 +561,7 @@
gap: 0px;
.label {
min-width: 82px;
min-width: 92px;
}
.input-container {
@@ -568,6 +573,7 @@
margin: 0;
width: 136px;
}
input[type="number"] {
margin: 0;
width: 48px;
@@ -760,6 +766,7 @@
position: fixed;
top: 80px;
right: 40px;
.appearance {
.design-datas-wrapper {
display: grid;
@@ -1125,4 +1132,4 @@
}
}
}
}
}