Enhance Simulations component to support adding and removing events from products; integrate new asset selection store for better state management. Fix import paths in Design component and related files to ensure correct module resolution. Update Tools component to correct import paths for template saving functionality. Refactor EditWidgetOption component to simplify option handling and remove unnecessary state management. Add new mechanics components for various asset types (Conveyor, Machine, Robotic Arm, Storage, Vehicle) as placeholders for future implementation. Implement Trigger and TriggerConnector components to manage right-click interactions and asset selection in the simulation environment. Enhance product store with new helper functions for event and action retrieval based on UUIDs. Introduce new selected event data and asset state management in the simulation store for improved event handling. Update simulation types to include new action types and improve type definitions for better type safety. Remove obsolete temp markdown file from triggers directory.
329 lines
9.9 KiB
TypeScript
329 lines
9.9 KiB
TypeScript
import { useState, useEffect, useRef } from "react";
|
|
import { useWidgetStore } from "../../../../../store/useWidgetStore";
|
|
import ChartComponent from "../../../sidebarLeft/visualization/widgets/ChartComponent";
|
|
import RegularDropDown from "../../../../ui/inputs/RegularDropDown";
|
|
import { WalletIcon } from "../../../../icons/3dChartIcons";
|
|
import SimpleCard from "../../../../../modules/visualization/widgets/floating/cards/SimpleCard";
|
|
|
|
interface Widget {
|
|
id: string;
|
|
type?: string;
|
|
panel: "top" | "bottom" | "left" | "right";
|
|
title?: string;
|
|
header?: string;
|
|
fontFamily?: string;
|
|
fontSize?: string;
|
|
fontWeight?: string;
|
|
className?: string;
|
|
data?: {
|
|
labels: string[];
|
|
datasets: {
|
|
data: number[];
|
|
backgroundColor: string;
|
|
borderColor: string;
|
|
borderWidth: number;
|
|
}[];
|
|
};
|
|
value?: string;
|
|
per?: string;
|
|
}
|
|
|
|
interface ChartElement {
|
|
tagName: string;
|
|
className: string;
|
|
textContent: string;
|
|
selector: string;
|
|
}
|
|
|
|
const Design = () => {
|
|
const [selectedFont, setSelectedFont] = useState("drop down");
|
|
const [selectedSize, setSelectedSize] = useState("drop down");
|
|
const [selectedWeight, setSelectedWeight] = useState("drop down");
|
|
const [elementColor, setElementColor] = useState("#6f42c1");
|
|
const [showColorPicker, setShowColorPicker] = useState(false);
|
|
const [chartElements, setChartElements] = useState<ChartElement[]>([]);
|
|
const [selectedElementToStyle, setSelectedElementToStyle] = useState<
|
|
string | null
|
|
>(null);
|
|
const [nameInput, setNameInput] = useState("");
|
|
const chartRef = useRef<HTMLDivElement>(null);
|
|
|
|
const { selectedChartId, setSelectedChartId, widgets, setWidgets } =
|
|
useWidgetStore();
|
|
|
|
// Initialize name input and extract elements when selectedChartId changes
|
|
useEffect(() => {
|
|
setNameInput(selectedChartId?.header || selectedChartId?.title || "");
|
|
|
|
if (!chartRef.current) return;
|
|
|
|
const timer = setTimeout(() => {
|
|
const chartContainer = chartRef.current;
|
|
if (!chartContainer) return;
|
|
|
|
const elements = Array.from(chartContainer.querySelectorAll("*"))
|
|
.filter((el) => {
|
|
const tagName = el.tagName.toLowerCase();
|
|
return !["script", "style", "meta", "link", "head"].includes(tagName);
|
|
})
|
|
.map((el, index) => {
|
|
const tagName = el.tagName.toLowerCase();
|
|
const className =
|
|
typeof el.className === "string" ? el.className : "";
|
|
const textContent = el.textContent?.trim() || "";
|
|
|
|
let selector = tagName;
|
|
|
|
if (className && typeof className === "string") {
|
|
const classList = className
|
|
.split(/\s+/)
|
|
.filter((c) => c.length > 0);
|
|
if (classList.length > 0) {
|
|
selector += "." + classList.join(".");
|
|
}
|
|
}
|
|
|
|
if (!className || className.trim() === "") {
|
|
const parent = el.parentElement;
|
|
if (parent) {
|
|
const siblings = Array.from(parent.children).filter(
|
|
(child) => child.tagName.toLowerCase() === tagName
|
|
);
|
|
const position = siblings.indexOf(el) + 1;
|
|
selector += `:nth-of-type(${position})`;
|
|
}
|
|
}
|
|
|
|
return {
|
|
tagName,
|
|
className,
|
|
textContent,
|
|
selector,
|
|
};
|
|
});
|
|
|
|
setChartElements(elements);
|
|
}, 300);
|
|
|
|
return () => clearTimeout(timer);
|
|
}, [selectedChartId]);
|
|
|
|
const applyStyles = () => {
|
|
if (!selectedElementToStyle || !chartRef.current) return;
|
|
|
|
const element = chartRef.current.querySelector(selectedElementToStyle);
|
|
if (!element) return;
|
|
|
|
const elementToStyle = element as HTMLElement;
|
|
|
|
if (selectedFont !== "drop down") {
|
|
elementToStyle.style.fontFamily = selectedFont;
|
|
}
|
|
if (selectedSize !== "drop down") {
|
|
elementToStyle.style.fontSize = selectedSize;
|
|
}
|
|
if (selectedWeight !== "drop down") {
|
|
elementToStyle.style.fontWeight = selectedWeight.toLowerCase();
|
|
}
|
|
if (elementColor) {
|
|
elementToStyle.style.color = elementColor;
|
|
}
|
|
};
|
|
|
|
useEffect(() => {
|
|
applyStyles();
|
|
}, [
|
|
selectedFont,
|
|
selectedSize,
|
|
selectedWeight,
|
|
elementColor,
|
|
selectedElementToStyle,
|
|
]);
|
|
|
|
const handleUpdateWidget = (updatedProperties: Partial<Widget>) => {
|
|
if (!selectedChartId) return;
|
|
|
|
const updatedChartId = {
|
|
...selectedChartId,
|
|
...updatedProperties,
|
|
};
|
|
setSelectedChartId(updatedChartId);
|
|
|
|
const updatedWidgets = widgets.map((widget) =>
|
|
widget.id === selectedChartId.id
|
|
? { ...widget, ...updatedProperties }
|
|
: widget
|
|
);
|
|
setWidgets(updatedWidgets);
|
|
};
|
|
|
|
const handleNameChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
|
const newName = e.target.value;
|
|
setNameInput(newName);
|
|
|
|
if (selectedChartId?.title) {
|
|
handleUpdateWidget({ title: newName });
|
|
} else if (selectedChartId?.header) {
|
|
handleUpdateWidget({ header: newName });
|
|
}
|
|
};
|
|
|
|
const defaultChartData = {
|
|
labels: ["January", "February", "March", "April", "May", "June", "July"],
|
|
datasets: [
|
|
{
|
|
data: [65, 59, 80, 81, 56, 55, 40],
|
|
backgroundColor: "#6f42c1",
|
|
borderColor: "#b392f0",
|
|
borderWidth: 1,
|
|
},
|
|
],
|
|
};
|
|
|
|
const elementOptions = chartElements.map((el) => {
|
|
let displayName = el.tagName;
|
|
if (el.className) displayName += `.${el.className}`;
|
|
if (el.textContent)
|
|
displayName += ` (${el.textContent.substring(0, 20)}${
|
|
el.textContent.length > 20 ? "..." : ""
|
|
})`;
|
|
return {
|
|
display: displayName,
|
|
value: el.selector,
|
|
};
|
|
});
|
|
|
|
return (
|
|
<div className="design">
|
|
<div className="selectedWidget">
|
|
{selectedChartId?.title || selectedChartId?.header || "Widget 1"}
|
|
</div>
|
|
|
|
<div className="reviewChart" ref={chartRef}>
|
|
{selectedChartId?.title ? (
|
|
<ChartComponent
|
|
type={selectedChartId.type || "bar"}
|
|
title={selectedChartId.title}
|
|
data={selectedChartId.data || defaultChartData}
|
|
/>
|
|
) : (
|
|
<SimpleCard
|
|
header={selectedChartId?.header || ""}
|
|
icon={WalletIcon}
|
|
value={selectedChartId?.value || ""}
|
|
per={selectedChartId?.per || ""}
|
|
/>
|
|
)}
|
|
</div>
|
|
|
|
<div className="optionsContainer">
|
|
<div className="option">
|
|
<span>Element to Style</span>
|
|
<RegularDropDown
|
|
header={selectedElementToStyle || "Select Element"}
|
|
options={
|
|
elementOptions.length > 0
|
|
? elementOptions.map((opt) => opt.display)
|
|
: ["No elements found"]
|
|
}
|
|
onSelect={(value) => {
|
|
const selected = elementOptions.find(
|
|
(opt) => opt.display === value
|
|
);
|
|
setSelectedElementToStyle(selected?.value || null);
|
|
}}
|
|
/>
|
|
</div>
|
|
|
|
<div className="option">
|
|
<span>Name</span>
|
|
<input
|
|
type="text"
|
|
value={nameInput}
|
|
onChange={handleNameChange}
|
|
placeholder="Enter name"
|
|
/>
|
|
</div>
|
|
|
|
{selectedChartId?.title && (
|
|
<div className="option">
|
|
<span>Chart Type</span>
|
|
<RegularDropDown
|
|
header={selectedChartId?.type || "Select Type"}
|
|
options={["bar", "line", "pie", "doughnut", "radar", "polarArea"]}
|
|
onSelect={(value) => {
|
|
handleUpdateWidget({ type: value });
|
|
}}
|
|
/>
|
|
</div>
|
|
)}
|
|
|
|
<div className="option">
|
|
<span>Font Family</span>
|
|
<RegularDropDown
|
|
header={selectedChartId?.fontFamily || "Select Font"}
|
|
options={["Arial", "Roboto", "Sans-serif"]}
|
|
onSelect={(value) => setSelectedFont(value)}
|
|
/>
|
|
</div>
|
|
|
|
<div className="option">
|
|
<span>Size</span>
|
|
<RegularDropDown
|
|
header={selectedChartId?.fontSize || "Select Size"}
|
|
options={["12px", "14px", "16px", "18px"]}
|
|
onSelect={(value) => setSelectedSize(value)}
|
|
/>
|
|
</div>
|
|
|
|
<div className="option">
|
|
<span>Weight</span>
|
|
<RegularDropDown
|
|
header={selectedChartId?.fontWeight || "Select Weight"}
|
|
options={["Light", "Regular", "Bold"]}
|
|
onSelect={(value) => setSelectedWeight(value)}
|
|
/>
|
|
</div>
|
|
|
|
<div className="option">
|
|
<div
|
|
className="header"
|
|
onClick={() => setShowColorPicker((prev) => !prev)}
|
|
>
|
|
<span>Element Color</span>
|
|
<div className="icon">▾</div>
|
|
</div>
|
|
|
|
{showColorPicker && (
|
|
<div className="colorDisplayer">
|
|
<input
|
|
type="color"
|
|
value={elementColor}
|
|
onChange={(e) => {
|
|
setElementColor(e.target.value);
|
|
if (selectedChartId?.data) {
|
|
handleUpdateWidget({
|
|
data: {
|
|
...selectedChartId.data,
|
|
datasets: [
|
|
{
|
|
...selectedChartId.data.datasets[0],
|
|
backgroundColor: e.target.value,
|
|
},
|
|
],
|
|
},
|
|
});
|
|
}
|
|
}}
|
|
/>
|
|
<span style={{ marginLeft: "10px" }}>{elementColor}</span>
|
|
</div>
|
|
)}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default Design;
|