updated data panel and added zones
This commit is contained in:
@@ -38,6 +38,34 @@
|
||||
height: 600px;
|
||||
background-color: rgb(235, 235, 235);
|
||||
margin: 0 30px;
|
||||
|
||||
.zoon-wrapper {
|
||||
display: flex;
|
||||
background-color: #E0DFFF80;
|
||||
position: absolute;
|
||||
bottom: 10px;
|
||||
left: 50%;
|
||||
transform: translate(-50%, 0);
|
||||
gap: 6px;
|
||||
padding: 4px;
|
||||
border-radius: 8px;
|
||||
max-width: 80%;
|
||||
overflow: auto;
|
||||
|
||||
&::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.zone {
|
||||
width: auto;
|
||||
background-color: #FCFDFD;
|
||||
border-radius: 6px;
|
||||
padding: 4px 8px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
// + button
|
||||
@@ -388,6 +416,10 @@
|
||||
flex-direction: column;
|
||||
gap: 5px;
|
||||
align-items: center;
|
||||
|
||||
.active {
|
||||
// background-color: red;
|
||||
}
|
||||
}
|
||||
|
||||
.icon {
|
||||
@@ -426,6 +458,7 @@
|
||||
.extra-buttons {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,59 +1,47 @@
|
||||
import React, { useState, useEffect, useRef } from 'react';
|
||||
import { DropDownIcon } from '../../../assets/images/svgExports';
|
||||
import React, { useState, useEffect } from "react";
|
||||
|
||||
interface DropdownProps {
|
||||
header: string;
|
||||
options: string[];
|
||||
onSelect: (option: string) => void; // Callback for option selection
|
||||
onSelect: (option: string) => void;
|
||||
}
|
||||
|
||||
const RegularDropDown: React.FC<DropdownProps> = ({ header, options, onSelect }) => {
|
||||
const RegularDropDown: React.FC<DropdownProps> = ({
|
||||
header,
|
||||
options,
|
||||
onSelect,
|
||||
}) => {
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
const [selectedOption, setSelectedOption] = useState<string | null>(null);
|
||||
|
||||
// Reference to the dropdown container
|
||||
const dropdownRef = useRef<HTMLDivElement | null>(null);
|
||||
// Reset selectedOption when the dropdown closes
|
||||
useEffect(() => {
|
||||
if (!isOpen) {
|
||||
setSelectedOption(null); // Clear local state when the dropdown closes
|
||||
}
|
||||
}, [isOpen]);
|
||||
|
||||
// Reset selectedOption when the header prop changes
|
||||
useEffect(() => {
|
||||
setSelectedOption(null); // Ensure the dropdown reflects the updated header
|
||||
}, [header]);
|
||||
|
||||
// Toggle dropdown visibility
|
||||
const toggleDropdown = () => {
|
||||
setIsOpen(prev => !prev);
|
||||
setIsOpen((prev) => !prev);
|
||||
};
|
||||
|
||||
// Handle option selection
|
||||
const handleOptionClick = (option: string) => {
|
||||
setSelectedOption(option);
|
||||
onSelect(option); // Call the onSelect function passed from the parent
|
||||
setIsOpen(false); // Close the dropdown after selection
|
||||
};
|
||||
|
||||
// Handle clicks outside the dropdown
|
||||
useEffect(() => {
|
||||
const handleOuterClick = (event: MouseEvent) => {
|
||||
if (
|
||||
dropdownRef.current &&
|
||||
!dropdownRef.current.contains(event.target as Node)
|
||||
) {
|
||||
setIsOpen(false); // Close the dropdown if clicked outside
|
||||
}
|
||||
};
|
||||
|
||||
// Attach the event listener
|
||||
document.addEventListener('mousedown', handleOuterClick);
|
||||
|
||||
// Cleanup the event listener on component unmount
|
||||
return () => {
|
||||
document.removeEventListener('mousedown', handleOuterClick);
|
||||
};
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className="regularDropdown-container" ref={dropdownRef}>
|
||||
<div className="regularDropdown-container">
|
||||
{/* Dropdown Header */}
|
||||
<div className="dropdown-header flex-sb" onClick={toggleDropdown}>
|
||||
<div className="key">{selectedOption || header}</div>
|
||||
<div className="icon">
|
||||
<DropDownIcon />
|
||||
</div>
|
||||
<div className="icon">▾</div>
|
||||
</div>
|
||||
|
||||
{/* Dropdown Options */}
|
||||
@@ -63,7 +51,7 @@ const RegularDropDown: React.FC<DropdownProps> = ({ header, options, onSelect })
|
||||
<div
|
||||
className="option"
|
||||
key={index}
|
||||
onClick={() => handleOptionClick(option)} // Handle option click
|
||||
onClick={() => handleOptionClick(option)}
|
||||
>
|
||||
{option}
|
||||
</div>
|
||||
@@ -74,4 +62,4 @@ const RegularDropDown: React.FC<DropdownProps> = ({ header, options, onSelect })
|
||||
);
|
||||
};
|
||||
|
||||
export default RegularDropDown;
|
||||
export default RegularDropDown;
|
||||
|
||||
@@ -21,7 +21,7 @@ const Data = () => {
|
||||
easing: "Connecter 1",
|
||||
children: [
|
||||
{ id: 1, easing: "Linear" },
|
||||
{ id: 2, easing: "Linear" },
|
||||
{ id: 2, easing: "Ease Out" },
|
||||
{ id: 3, easing: "Linear" },
|
||||
],
|
||||
},
|
||||
@@ -70,21 +70,26 @@ const Data = () => {
|
||||
});
|
||||
};
|
||||
|
||||
const removeChild = (childId: number) => {
|
||||
setGroups((groups) =>
|
||||
groups
|
||||
.map((group) => ({
|
||||
...group,
|
||||
children: group.children.filter((c) => c.id !== childId),
|
||||
}))
|
||||
.filter((group) => group.children.length > 0)
|
||||
const removeChild = (groupId: number, childId: number) => {
|
||||
setGroups((currentGroups) =>
|
||||
currentGroups.map((group) => {
|
||||
if (group.id === groupId) {
|
||||
return {
|
||||
...group,
|
||||
children: group.children.map((child) =>
|
||||
child.id === childId ? { ...child, easing: "Linear" } : child
|
||||
),
|
||||
};
|
||||
}
|
||||
return group;
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="dataSideBar">
|
||||
<div className="sideBarHeader">{selectedWidget}</div>
|
||||
{groups.map((group, groupIndex) => (
|
||||
{groups.map((group) => (
|
||||
<div key={group.id} className="selectedMain-container">
|
||||
<div className="selectedMain">
|
||||
<span className="bulletPoint">•</span>
|
||||
@@ -107,6 +112,7 @@ const Data = () => {
|
||||
{group.children.map((child) => (
|
||||
<div key={child.id} className="selectedMain child">
|
||||
<main>Input {child.id}</main>
|
||||
{/* Pass the current easing as the header */}
|
||||
<RegularDropDown
|
||||
header={child.easing}
|
||||
options={["Linear", "Ease In", "Ease Out", "Ease In-Out"]}
|
||||
@@ -124,7 +130,10 @@ const Data = () => {
|
||||
<div className="icon" onClick={() => handleLinkClick(child.id)}>
|
||||
<LinkIcon />
|
||||
</div>
|
||||
<div className="icon" onClick={() => removeChild(child.id)}>
|
||||
<div
|
||||
className="icon"
|
||||
onClick={() => removeChild(group.id, child.id)}
|
||||
>
|
||||
<RemoveIcon />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -49,17 +49,11 @@ const DraggableWidget = ({ widget }: { widget: any }) => {
|
||||
};
|
||||
|
||||
const handlePointerDown = () => {
|
||||
// Set selected chart when pointer down event occurs (i.e., when it's clicked, not dragged)
|
||||
if (!isDragging) {
|
||||
setSelectedChartId(widget); // Update selected chart in the store
|
||||
setSelectedChartId(widget);
|
||||
}
|
||||
};
|
||||
|
||||
// Log to see the selectedChartId updates
|
||||
useEffect(() => {
|
||||
console.log("selectedChartID: ", selectedChartId);
|
||||
}, [selectedChartId]);
|
||||
|
||||
return (
|
||||
<div
|
||||
key={widget.id}
|
||||
@@ -68,7 +62,7 @@ const DraggableWidget = ({ widget }: { widget: any }) => {
|
||||
{...attributes}
|
||||
{...listeners}
|
||||
style={style}
|
||||
onPointerDown={handlePointerDown} // Use onPointerDown instead of onPointerUp
|
||||
onPointerDown={handlePointerDown}
|
||||
>
|
||||
<ChartComponent
|
||||
type={widget.type}
|
||||
@@ -82,19 +76,28 @@ const DraggableWidget = ({ widget }: { widget: any }) => {
|
||||
};
|
||||
|
||||
const RealTimeVisualization = () => {
|
||||
const [zone, setZone] = useState([
|
||||
"Manufacturing unit",
|
||||
"Assembly unit",
|
||||
"Packing unit",
|
||||
"Warehouse",
|
||||
"Inventory",
|
||||
]);
|
||||
|
||||
const [activeSides, setActiveSides] = useState<Side[]>([]);
|
||||
const [panelOrder, setPanelOrder] = useState<Side[]>([]);
|
||||
const [selectedSide, setSelectedSide] = useState<Side | null>(null);
|
||||
const [lockedPanels, setLockedPanels] = useState<Side[]>([]);
|
||||
const [activeExtraButton, setActiveExtraButton] = useState<{
|
||||
[key in Side]?: string;
|
||||
}>({});
|
||||
const { draggedAsset, addWidget, widgets, setWidgets } = useWidgetStore();
|
||||
|
||||
// Sensors for drag-and-drop (Pointer and Keyboard)
|
||||
const sensors = useSensors(
|
||||
useSensor(PointerSensor),
|
||||
useSensor(KeyboardSensor)
|
||||
);
|
||||
|
||||
useEffect(() => {}, [widgets]);
|
||||
|
||||
const toggleSide = (side: Side) => {
|
||||
setActiveSides((prev) => {
|
||||
const newActive = prev.includes(side)
|
||||
@@ -102,17 +105,24 @@ const RealTimeVisualization = () => {
|
||||
: [...prev, side];
|
||||
setPanelOrder(newActive);
|
||||
|
||||
// Reset selectedSide if the panel is being closed
|
||||
if (prev.includes(side)) {
|
||||
setSelectedSide(null); // Hide extra buttons when the panel is closed
|
||||
setSelectedSide(null);
|
||||
} else {
|
||||
setSelectedSide(side); // Show extra buttons when the panel is opened
|
||||
setSelectedSide(side);
|
||||
}
|
||||
|
||||
return newActive;
|
||||
});
|
||||
};
|
||||
|
||||
const toggleLockPanel = (side: Side) => {
|
||||
setLockedPanels((prev) =>
|
||||
prev.includes(side)
|
||||
? prev.filter((panel) => panel !== side)
|
||||
: [...prev, side]
|
||||
);
|
||||
};
|
||||
|
||||
const getPanelStyle = (currentSide: Side) => {
|
||||
const currentIndex = panelOrder.indexOf(currentSide);
|
||||
const previousPanels = panelOrder.slice(0, currentIndex);
|
||||
@@ -159,9 +169,6 @@ const RealTimeVisualization = () => {
|
||||
}
|
||||
};
|
||||
|
||||
const leftHeader = useMemo(() => ["Overview", "Widgets", "Templates"], []);
|
||||
const rightHeader = useMemo(() => ["Data", "Design"], []);
|
||||
|
||||
const handleDragEnd = (event: any) => {
|
||||
const { active, over } = event;
|
||||
|
||||
@@ -171,14 +178,11 @@ const RealTimeVisualization = () => {
|
||||
const newPanel =
|
||||
widgets.find((widget) => widget.id === over.id)?.panel || active.panel;
|
||||
|
||||
// Ensure widgets are reordered within the same panel or moved to a new panel
|
||||
if (active.panel === newPanel) {
|
||||
// Reorder within the same panel
|
||||
const newIndex = widgets.findIndex((widget) => widget.id === over.id);
|
||||
const reorderedWidgets = arrayMove(widgets, oldIndex, newIndex);
|
||||
setWidgets(reorderedWidgets);
|
||||
} else {
|
||||
// Move to a different panel
|
||||
const updatedWidgets = widgets.map((widget) =>
|
||||
widget.id === active.id ? { ...widget, panel: newPanel } : widget
|
||||
);
|
||||
@@ -200,12 +204,19 @@ const RealTimeVisualization = () => {
|
||||
onDragEnd={handleDragEnd}
|
||||
>
|
||||
<div className="content-container realTime-viz flex">
|
||||
<SideBar header={leftHeader} defaultActive={"Widgets"} />
|
||||
<SideBar
|
||||
header={["Overview", "Widgets", "Templates"]}
|
||||
defaultActive={"Widgets"}
|
||||
/>
|
||||
|
||||
<div className="main-container relative">
|
||||
<div className="zoon-wrapper">
|
||||
{zone.map((zone, index) => (
|
||||
<div className="zone">{zone}</div>
|
||||
))}
|
||||
</div>
|
||||
{(["top", "right", "bottom", "left"] as Side[]).map((side) => (
|
||||
<div key={side} className={`side-button-container ${side}`}>
|
||||
{/* Side Button */}
|
||||
<button
|
||||
className={`side-button ${side}`}
|
||||
onClick={() => toggleSide(side)}
|
||||
@@ -214,23 +225,71 @@ const RealTimeVisualization = () => {
|
||||
+
|
||||
</button>
|
||||
|
||||
{/* Extra Buttons */}
|
||||
<div
|
||||
className="extra-buttons"
|
||||
style={{
|
||||
display: activeSides.includes(side) ? "flex" : "none", // Show if the panel is active
|
||||
display: activeSides.includes(side) ? "flex" : "none",
|
||||
}}
|
||||
>
|
||||
<div className="icon" title="Disable Sorting">
|
||||
<div
|
||||
className={`icon ${
|
||||
activeExtraButton[side] === "Disable Sorting"
|
||||
? "active"
|
||||
: ""
|
||||
}`}
|
||||
title="Disable Sorting"
|
||||
onClick={() =>
|
||||
setActiveExtraButton((prev) => ({
|
||||
...prev,
|
||||
[side]: "Disable Sorting",
|
||||
}))
|
||||
}
|
||||
>
|
||||
<DisableSorting />
|
||||
</div>
|
||||
<div className="icon" title="Hide Panel">
|
||||
<div
|
||||
className={`icon ${
|
||||
activeExtraButton[side] === "Hide Panel" ? "active" : ""
|
||||
}`}
|
||||
title="Hide Panel"
|
||||
onClick={() =>
|
||||
setActiveExtraButton((prev) => ({
|
||||
...prev,
|
||||
[side]: "Hide Panel",
|
||||
}))
|
||||
}
|
||||
>
|
||||
<EyeIcon />
|
||||
</div>
|
||||
<div className="icon" title="Clean Panel">
|
||||
<div
|
||||
className={`icon ${
|
||||
activeExtraButton[side] === "Clean Panel" ? "active" : ""
|
||||
}`}
|
||||
title="Clean Panel"
|
||||
onClick={() =>
|
||||
setActiveExtraButton((prev) => ({
|
||||
...prev,
|
||||
[side]: "Clean Panel",
|
||||
}))
|
||||
}
|
||||
>
|
||||
<CleanPannel />
|
||||
</div>
|
||||
<div className="icon" title="Lock Panel">
|
||||
<div
|
||||
className={`icon ${
|
||||
activeExtraButton[side] === "Lock Panel" ? "active" : ""
|
||||
}`}
|
||||
title={
|
||||
lockedPanels.includes(side) ? "Unlock Panel" : "Lock Panel"
|
||||
}
|
||||
onClick={() => {
|
||||
toggleLockPanel(side);
|
||||
setActiveExtraButton((prev) => ({
|
||||
...prev,
|
||||
[side]: "Lock Panel",
|
||||
}));
|
||||
}}
|
||||
>
|
||||
<LockIcon />
|
||||
</div>
|
||||
</div>
|
||||
@@ -245,7 +304,13 @@ const RealTimeVisualization = () => {
|
||||
onDrop={(e) => handleDrop(e, side)}
|
||||
onDragOver={(e) => e.preventDefault()}
|
||||
>
|
||||
<div className="panel-content">
|
||||
<div
|
||||
className="panel-content"
|
||||
style={{
|
||||
pointerEvents: lockedPanels.includes(side) ? "none" : "auto",
|
||||
opacity: lockedPanels.includes(side) ? "0.8" : "1",
|
||||
}}
|
||||
>
|
||||
<SortableContext
|
||||
items={widgets
|
||||
.filter((w) => w.panel === side)
|
||||
@@ -255,9 +320,7 @@ const RealTimeVisualization = () => {
|
||||
{widgets
|
||||
.filter((w) => w.panel === side)
|
||||
.map((widget) => (
|
||||
<>
|
||||
<DraggableWidget widget={widget} />
|
||||
</>
|
||||
<DraggableWidget widget={widget} key={widget.id} />
|
||||
))}
|
||||
</SortableContext>
|
||||
</div>
|
||||
@@ -265,7 +328,7 @@ const RealTimeVisualization = () => {
|
||||
))}
|
||||
</div>
|
||||
|
||||
<SideBar header={rightHeader} defaultActive={"Data"} />
|
||||
<SideBar header={["Data", "Design"]} defaultActive={"Data"} />
|
||||
</div>
|
||||
</DndContext>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user