From f9fe57c72cbe4f466c451a513b0ba4527815a7b5 Mon Sep 17 00:00:00 2001 From: Jerald-Golden-B Date: Mon, 22 Dec 2025 11:17:31 +0530 Subject: [PATCH] feat: Add new UI input components for color, detailed dropdown, and data source selection, alongside foundational simulation dashboard components and styles. --- .../components/element/ElementData.tsx | 4 +- app/src/components/ui/inputs/Color.tsx | 260 ++++++++++-------- .../ui/inputs/DataDetailedDropdown.tsx | 2 +- .../ui/inputs/DataSourceSelector.tsx | 2 +- app/src/services/visulization/temp.md | 0 .../_simulationDashBoard.scss | 29 +- 6 files changed, 169 insertions(+), 128 deletions(-) delete mode 100644 app/src/services/visulization/temp.md diff --git a/app/src/components/SimulationDashboard/components/element/ElementData.tsx b/app/src/components/SimulationDashboard/components/element/ElementData.tsx index cf4c95b..2715faa 100644 --- a/app/src/components/SimulationDashboard/components/element/ElementData.tsx +++ b/app/src/components/SimulationDashboard/components/element/ElementData.tsx @@ -229,7 +229,7 @@ const ElementData: React.FC = ({ {singleValueFields.length < totalValueOptions && (
-
+
Add Field
@@ -292,7 +292,7 @@ const ElementData: React.FC = ({ {multipleSourceFields.length < totalAssetOptions && (
-
+
Add Field
diff --git a/app/src/components/ui/inputs/Color.tsx b/app/src/components/ui/inputs/Color.tsx index 37d556d..d293022 100644 --- a/app/src/components/ui/inputs/Color.tsx +++ b/app/src/components/ui/inputs/Color.tsx @@ -1,4 +1,5 @@ import React, { useState, useRef, useEffect } from "react"; +import { createPortal } from "react-dom"; import { HexColorPicker } from "react-colorful"; import { useOuterClick } from "../../../utils/useOuterClick"; @@ -17,33 +18,22 @@ const hexToRgb = (hex: string) => { const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex); return result ? { - r: parseInt(result[1], 16), - g: parseInt(result[2], 16), - b: parseInt(result[3], 16), - } + r: parseInt(result[1], 16), + g: parseInt(result[2], 16), + b: parseInt(result[3], 16), + } : { r: 0, g: 0, b: 0 }; }; const rgbToHex = (r: number, g: number, b: number) => { - return ( - "#" + - ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1).toUpperCase() - ); + return "#" + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1).toUpperCase(); }; -export const Color: React.FC = ({ - value, - onChange, - label = "Color", - className = "", - disabled = false, - onBlur, - onFocus, - onUpdate, -}) => { +export const Color: React.FC = ({ value, onChange, label = "Color", className = "", disabled = false, onBlur, onFocus, onUpdate }) => { const [isOpen, setIsOpen] = useState(false); const popoverRef = useRef(null); const containerRef = useRef(null); + const [coords, setCoords] = useState<{ top: number; left: number }>({ top: 0, left: 0 }); const [localValue, setLocalValue] = useState(value); // Sync local value when prop changes @@ -73,11 +63,42 @@ export const Color: React.FC = ({ if (onUpdate) onUpdate(localValue); }; - useOuterClick( - () => setIsOpen(false), - ["color-picker-popover", "color-trigger"], - isOpen - ); + // Calculate position before opening or when needed + const updatePosition = () => { + if (containerRef.current) { + const rect = containerRef.current.getBoundingClientRect(); + setCoords({ + top: rect.top + window.scrollY - 8, + left: rect.left + window.scrollX, + }); + } + }; + + const toggleOpen = () => { + if (disabled) return; + if (!isOpen) { + updatePosition(); + setIsOpen(true); + } else { + setIsOpen(false); + } + }; + + useOuterClick(() => setIsOpen(false), ["color-picker-popover", "color-trigger"], isOpen); + + // Update position on window resize/scroll if open + useEffect(() => { + if (isOpen) { + const handleResize = () => updatePosition(); + window.addEventListener("resize", handleResize); + window.addEventListener("scroll", handleResize, true); + + return () => { + window.removeEventListener("resize", handleResize); + window.removeEventListener("scroll", handleResize, true); + }; + } + }, [isOpen]); const rgb = hexToRgb(localValue); @@ -87,7 +108,7 @@ export const Color: React.FC = ({
!disabled && setIsOpen(!isOpen)} + onClick={toggleOpen} style={{ backgroundColor: localValue, width: "52px", @@ -98,36 +119,30 @@ export const Color: React.FC = ({ position: "relative", }} /> - handleChange(e.target.value)} - onBlur={handleBlur} - onFocus={onFocus} - disabled={disabled} - /> + handleChange(e.target.value)} onBlur={handleBlur} onFocus={onFocus} disabled={disabled} />
- {isOpen && ( -
- - + -
- {/* Eyedropper placeholder icon */} -
- - - -
- -
- -
- {/* Small hex input representation usually goes here, but we have separated RGB below */} -
-
- - {/* RGB Inputs */} -
- {["r", "g", "b"].map((key) => ( -
- handleRgbChange(key as "r" | "g" | "b", e.target.value)} - style={{ - width: "100%", - backgroundColor: "#333", - border: "1px solid #444", - borderRadius: "4px", - color: "#eee", - textAlign: "center", - fontSize: "12px", - padding: "4px 0", - appearance: "textfield", - }} - /> - - {key} - +
+ {/* Eyedropper placeholder icon */} +
+ + +
- ))} -
-
- )} + +
+ +
+ {/* Small hex input representation usually goes here, but we have separated RGB below */} +
+
+ + {/* RGB Inputs */} +
+ {["r", "g", "b"].map((key) => ( +
+ handleRgbChange(key as "r" | "g" | "b", e.target.value)} + style={{ + width: "100%", + backgroundColor: "#333", + border: "1px solid #444", + borderRadius: "4px", + color: "#eee", + textAlign: "center", + fontSize: "12px", + padding: "4px 0", + appearance: "textfield", + }} + /> + + {key} + +
+ ))} +
+
, + document.body + )}
); }; diff --git a/app/src/components/ui/inputs/DataDetailedDropdown.tsx b/app/src/components/ui/inputs/DataDetailedDropdown.tsx index c9556c9..19d26ae 100644 --- a/app/src/components/ui/inputs/DataDetailedDropdown.tsx +++ b/app/src/components/ui/inputs/DataDetailedDropdown.tsx @@ -111,7 +111,7 @@ const DataDetailedDropdown: React.FC = ({ title, plac
{eyedroper && ( -
+
)} diff --git a/app/src/components/ui/inputs/DataSourceSelector.tsx b/app/src/components/ui/inputs/DataSourceSelector.tsx index af53bd4..290c3fb 100644 --- a/app/src/components/ui/inputs/DataSourceSelector.tsx +++ b/app/src/components/ui/inputs/DataSourceSelector.tsx @@ -40,7 +40,7 @@ const DataSourceSelector: React.FC = ({ label = "Data S {showEyeDropper && ( -
+
)} diff --git a/app/src/services/visulization/temp.md b/app/src/services/visulization/temp.md deleted file mode 100644 index e69de29..0000000 diff --git a/app/src/styles/components/simulationDashboard/_simulationDashBoard.scss b/app/src/styles/components/simulationDashboard/_simulationDashBoard.scss index b260159..c7d1264 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; } @@ -640,7 +640,8 @@ border-radius: 25px; .heading { - text-align: center; + padding: 4px 6px 8px; + font-weight: 500; } .fields-wrapper { @@ -661,6 +662,7 @@ .datas__label { flex: 0.8; + min-width: 96px; } .datas__class { @@ -668,12 +670,20 @@ align-items: center; gap: 4px; - .icon { + .add-icon, + .delete { display: flex; - padding: 5px 4px; + height: 24px; + width: 24px; + align-items: center; + justify-content: center; border-radius: 6px; cursor: pointer; + &:hover { + background: var(--background-color-input); + } + &.active { background: var(--background-color-button); } @@ -681,9 +691,17 @@ .delete { cursor: pointer; + &:hover { + background: var(--log-error-background-color); + path { + stroke: var(--log-error-text-color); + } + } } .regularDropdown-container { + max-width: 106px; + width: 106px; .icon { padding: 0; } @@ -709,7 +727,6 @@ } } - .appearance { .design-datas-wrapper { display: grid; @@ -1088,4 +1105,4 @@ } } } -} \ No newline at end of file +}