diff --git a/app/src/components/SimulationDashboard/components/block/BlockEditor.tsx b/app/src/components/SimulationDashboard/components/block/BlockEditor.tsx index 0626915..3d4e769 100644 --- a/app/src/components/SimulationDashboard/components/block/BlockEditor.tsx +++ b/app/src/components/SimulationDashboard/components/block/BlockEditor.tsx @@ -8,9 +8,11 @@ import { handleBlurAmountChange } from "../../functions/helpers/handleBlurAmount import InputRange from "../../../ui/inputs/InputRange"; import { DeleteIcon } from "../../../icons/ContextMenuIcons"; import InputWithDropDown from "../../../ui/inputs/InputWithDropDown"; -import { ResizeHeightIcon } from "../../../icons/ExportCommonIcons"; +import { ArrowIcon, ResizeHeightIcon } from "../../../icons/ExportCommonIcons"; import RenameInput from "../../../ui/inputs/RenameInput"; import { useVisualizationStore } from "../../../../store/visualization/useVisualizationStore"; +import { ResetIcon } from "../../../icons/SimulationIcons"; +import { Color } from "../../../ui/inputs/Color"; interface BlockEditorProps { blockEditorRef: RefObject; @@ -27,6 +29,9 @@ interface BlockEditorProps { const BlockEditor: React.FC = ({ blockEditorRef, currentBlock, selectedBlock, updateBlockStyle, updateBlockSize, updateBlockPositionType, updateBlockZIndex, handleRemoveBlock }) => { const [color, setColor] = useState("#000000"); + useEffect(() => { + setColor(rgbaToHex(getCurrentBlockStyleValue(currentBlock, "backgroundColor") || "#000000")); + }, [currentBlock]); // Use position from VisualizationStore const { editorPosition, setEditorPosition } = useVisualizationStore(); const panelRef = useRef(null); @@ -87,6 +92,8 @@ const BlockEditor: React.FC = ({ blockEditorRef, currentBlock, }; // Initialize position on mount + + // compute exact initial position once we have panel dimensions useEffect(() => { if (!editorPosition) { const { width } = getPanelDimensions(); @@ -277,55 +284,73 @@ const BlockEditor: React.FC = ({ blockEditorRef, currentBlock,
- updateBlockZIndex(selectedBlock, Number(newValue))} /> - - { - updateBlockStyle(selectedBlock, { - borderRadius: Number(newValue), - }); - }} - /> +
+ updateBlockZIndex(selectedBlock, Number(newValue))} + /> + + + +
+
+
Apperance
+ { + updateBlockStyle(selectedBlock, { + borderRadius: Number(newValue), + }); + }} + /> +
+
Background
-
-
Color
-
- setColor(e.target.value)} - onChange={(e) => { - handleBackgroundColorChange(currentBlock, selectedBlock, updateBlockStyle, e.target.value); - setColor(e.target.value); - }} - /> -
{ - e.preventDefault(); - handleBackgroundColorChange(currentBlock, selectedBlock, updateBlockStyle, color); - }} - > - { - setColor(e.target.value); - }} - onBlur={(e) => { - handleBackgroundColorChange(currentBlock, selectedBlock, updateBlockStyle, color); - }} - /> -
-
-
+ + { + setColor(value); + if (/^#?([0-9A-Fa-f]{3}|[0-9A-Fa-f]{6})$/.test(value)) { + handleBackgroundColorChange(currentBlock, selectedBlock, updateBlockStyle, value); + } + }} + onUpdate={(value) => { + handleBackgroundColorChange(currentBlock, selectedBlock, updateBlockStyle, value); + }} + /> + = ({
Background
-
-
Color
-
- { - updateElementStyle(selectedBlock, selectedElement, { - backgroundColor: hexToRgba(e.target.value), - }); - setColor(e.target.value); - }} - /> -
{ - e.preventDefault(); - updateElementStyle(selectedBlock, selectedElement, { - backgroundColor: color, - }); - }} - > - { - setColor(e.target.value); - }} - onBlur={(e) => { - updateElementStyle(selectedBlock, selectedElement, { - backgroundColor: color, - }); - }} - /> -
-
-
+ { + const currentBg = getCurrentElementStyleValue(currentElement, "backgroundColor") || "rgba(0,0,0,1)"; + const currentAlpha = getAlphaFromRgba(currentBg); + updateElementStyle(selectedBlock, selectedElement, { + backgroundColor: hexToRgba(value, currentAlpha), + }); + setColor(value); + }} + onUpdate={(value) => { + const currentBg = getCurrentElementStyleValue(currentElement, "backgroundColor") || "rgba(0,0,0,1)"; + const currentAlpha = getAlphaFromRgba(currentBg); + updateElementStyle(selectedBlock, selectedElement, { + backgroundColor: hexToRgba(value, currentAlpha), + }); + }} + /> + = ({ {selectType === "data" && (
{element?.type === "label-value" && ( -
- { - updateElementData(selectedBlock, selectedElement, { label: value }); - }} - /> -
- }], - }, - { - title: "Assets", - items: getAssetDropdownItems(), - }, - ]} - value={ - element.dataBinding?.dataSource - ? { - id: element.dataBinding.dataSource as string, - label: - getEventByModelUuid(selectedProduct.productUuid, element.dataBinding.dataSource as string)?.modelName ?? - (element.dataBinding.dataSource === "global" ? "Global" : ""), - icon: , - } - : null - } + <> +
+
Data Handling
+ { - updateElementData(selectedBlock, selectedElement, { dataSource: value.id }); + updateElementData(selectedBlock, selectedElement, { label: value }); }} - dropDownHeader={"RT-Data"} - eyedroper={true} /> -
+
+ }], + }, + { + title: "Assets", + items: getAssetDropdownItems(), + }, + ]} + value={ + element.dataBinding?.dataSource + ? { + id: element.dataBinding.dataSource as string, + label: + getEventByModelUuid(selectedProduct.productUuid, element.dataBinding.dataSource as string)?.modelName ?? + (element.dataBinding.dataSource === "global" ? "Global" : ""), + icon: , + } + : null + } + onChange={(value) => { + updateElementData(selectedBlock, selectedElement, { dataSource: value.id }); + }} + dropDownHeader={"RT-Data"} + eyedroper={true} + /> +
-
- section.items) - .find((item) => item.id === element.dataBinding?.dataValue)?.label ?? "", - icon: , - } - : null - } - onChange={(value) => { - updateElementData(selectedBlock, selectedElement, { dataValue: value.id, label: value.label }); - }} - dropDownHeader={"RT-Data-Value"} - /> +
+ section.items) + .find((item) => item.id === element.dataBinding?.dataValue)?.label ?? "", + icon: , + } + : null + } + onChange={(value) => { + updateElementData(selectedBlock, selectedElement, { dataValue: value.id, label: value.label }); + }} + dropDownHeader={"RT-Data-Value"} + /> +
-
+ )} {/* Data Mapping */} diff --git a/app/src/components/ui/inputs/Color.tsx b/app/src/components/ui/inputs/Color.tsx new file mode 100644 index 0000000..dbe3021 --- /dev/null +++ b/app/src/components/ui/inputs/Color.tsx @@ -0,0 +1,70 @@ +import React from "react"; + +interface ColorProps { + value: string; + onChange: (value: string) => void; + label?: string; + className?: string; + disabled?: boolean; + onBlur?: (e: React.FocusEvent) => void; + onFocus?: (e: React.FocusEvent) => void; + onUpdate?: (value: string) => void; +} + +export const Color: React.FC = ({ + value, + onChange, + label = "Color", + className = "", + disabled = false, + onBlur, + onFocus, + onUpdate, +}) => { + const handleTextChange = (e: React.ChangeEvent) => { + onChange(e.target.value); + }; + + const handleColorPickerChange = (e: React.ChangeEvent) => { + onChange(e.target.value); + }; + + const handleSubmit = (e?: React.FormEvent) => { + if (e) e.preventDefault(); + if (onUpdate) { + onUpdate(value); + } + }; + + const handleBlur = (e: React.FocusEvent) => { + handleSubmit(); + if (onBlur) onBlur(e); + }; + + return ( +
+ {label &&
{label}
} +
+ +
+ +
+
+
+ ); +}; diff --git a/app/src/styles/components/_input.scss b/app/src/styles/components/_input.scss index 7bd9f6f..cb64933 100644 --- a/app/src/styles/components/_input.scss +++ b/app/src/styles/components/_input.scss @@ -46,6 +46,7 @@ textarea { } input[type="number"] { + // Chrome, Safari, Edge, Opera &::-webkit-outer-spin-button, &::-webkit-inner-spin-button { @@ -225,25 +226,29 @@ input[type="number"] { position: relative; cursor: pointer; - .key{ + .key { text-overflow: none; } + .dropdown-header { height: 100%; display: flex; justify-content: space-between; cursor: pointer; border-radius: #{$border-radius-large}; - .key{ + + .key { width: calc(100% - 18px); overflow: hidden; text-overflow: ellipsis; } - } + } + .icon { height: auto; } } + .dropdown-options { position: absolute; width: 100%; @@ -787,3 +792,39 @@ input[type="number"] { } } } + + +.data-picker { + display: flex; + justify-content: space-between; + align-items: center; + + .label { + width: 50%; + white-space: nowrap; + } + + input[type="color"] { + width: 42px; + padding: 0; + background: transparent; + outline: none; + } + + .left { + width: 100%; + display: flex; + align-items: center; + gap: 6px; + + .colorValue { + width: 100%; + 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; + } + } +} \ No newline at end of file diff --git a/app/src/styles/components/simulationDashboard/_simulationDashBoard.scss b/app/src/styles/components/simulationDashboard/_simulationDashBoard.scss index 7161671..3812765 100644 --- a/app/src/styles/components/simulationDashboard/_simulationDashBoard.scss +++ b/app/src/styles/components/simulationDashboard/_simulationDashBoard.scss @@ -18,7 +18,7 @@ transition: none !important; } - * > { + *> { pointer-events: auto; } @@ -167,10 +167,10 @@ padding: 8px; user-select: none; border: 1px solid transparent; + outline: 1px solid transparent; &.edit-mode { transition: all 0.2s; - outline: 1px solid transparent; &:hover { outline-color: var(--border-color); @@ -285,7 +285,7 @@ gap: 11px; min-width: 280px; height: fit-content; - min-width: 320px; + max-width: 320px; min-height: 60vh; padding: 12px; @@ -460,39 +460,6 @@ padding: 0; } - .data-picker { - display: flex; - justify-content: space-between; - align-items: center; - - .label { - width: 50%; - white-space: nowrap; - } - - input[type="color"] { - width: 42px; - padding: 0; - background: transparent; - outline: none; - } - - .left { - width: 100%; - display: flex; - align-items: center; - gap: 6px; - - .colorValue { - width: 100%; - 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; - } - } - } - .design-section-footer { display: flex; flex-direction: column; @@ -1120,4 +1087,4 @@ } } } -} +} \ No newline at end of file diff --git a/app/src/utils/shortcutkeys/handleShortcutKeys.ts b/app/src/utils/shortcutkeys/handleShortcutKeys.ts index 7491008..fd5ac67 100644 --- a/app/src/utils/shortcutkeys/handleShortcutKeys.ts +++ b/app/src/utils/shortcutkeys/handleShortcutKeys.ts @@ -24,7 +24,7 @@ import { useSceneContext } from "../../modules/scene/sceneContext"; const KeyPressListener: React.FC = () => { const { comparisonScene, clearComparisonState } = useSimulationState(); const { activeModule, setActiveModule } = useModuleStore(); - const { assetStore, versionStore } = useSceneContext(); + const { assetStore, versionStore, simulationDashBoardStore } = useSceneContext(); const { selectedAssets } = assetStore(); const { setSubModule } = useSubModuleStore(); const { setActiveSubTool } = useActiveSubTool(); @@ -46,6 +46,7 @@ const KeyPressListener: React.FC = () => { const { setSelectedComment } = useSelectedComment(); const { setDfxUploaded } = useDfxUpload(); const isTextInput = (element: Element | null): boolean => element instanceof HTMLInputElement || element instanceof HTMLTextAreaElement || element?.getAttribute("contenteditable") === "true"; + const { setSelectedBlock, setSelectedElement } = simulationDashBoardStore(); const handleModuleSwitch = (keyCombination: string) => { const modules: Record = { @@ -189,6 +190,8 @@ const KeyPressListener: React.FC = () => { setIsRenameMode(false); setDfxUploaded([]); setSelectedComment(null); + setSelectedBlock(null); + setSelectedElement(null); } if (!keyCombination || ["F5", "F11", "F12"].includes(event.key) || keyCombination === "Ctrl+R") return;