updated data panel and added zones
This commit is contained in:
@@ -38,6 +38,34 @@
|
|||||||
height: 600px;
|
height: 600px;
|
||||||
background-color: rgb(235, 235, 235);
|
background-color: rgb(235, 235, 235);
|
||||||
margin: 0 30px;
|
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
|
// + button
|
||||||
@@ -388,6 +416,10 @@
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 5px;
|
gap: 5px;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
||||||
|
.active {
|
||||||
|
// background-color: red;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.icon {
|
.icon {
|
||||||
@@ -426,6 +458,7 @@
|
|||||||
.extra-buttons {
|
.extra-buttons {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,59 +1,47 @@
|
|||||||
import React, { useState, useEffect, useRef } from 'react';
|
import React, { useState, useEffect } from "react";
|
||||||
import { DropDownIcon } from '../../../assets/images/svgExports';
|
|
||||||
|
|
||||||
interface DropdownProps {
|
interface DropdownProps {
|
||||||
header: string;
|
header: string;
|
||||||
options: 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 [isOpen, setIsOpen] = useState(false);
|
||||||
const [selectedOption, setSelectedOption] = useState<string | null>(null);
|
const [selectedOption, setSelectedOption] = useState<string | null>(null);
|
||||||
|
|
||||||
// Reference to the dropdown container
|
// Reset selectedOption when the dropdown closes
|
||||||
const dropdownRef = useRef<HTMLDivElement | null>(null);
|
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 = () => {
|
const toggleDropdown = () => {
|
||||||
setIsOpen(prev => !prev);
|
setIsOpen((prev) => !prev);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Handle option selection
|
|
||||||
const handleOptionClick = (option: string) => {
|
const handleOptionClick = (option: string) => {
|
||||||
setSelectedOption(option);
|
setSelectedOption(option);
|
||||||
onSelect(option); // Call the onSelect function passed from the parent
|
onSelect(option); // Call the onSelect function passed from the parent
|
||||||
setIsOpen(false); // Close the dropdown after selection
|
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 (
|
return (
|
||||||
<div className="regularDropdown-container" ref={dropdownRef}>
|
<div className="regularDropdown-container">
|
||||||
{/* Dropdown Header */}
|
{/* Dropdown Header */}
|
||||||
<div className="dropdown-header flex-sb" onClick={toggleDropdown}>
|
<div className="dropdown-header flex-sb" onClick={toggleDropdown}>
|
||||||
<div className="key">{selectedOption || header}</div>
|
<div className="key">{selectedOption || header}</div>
|
||||||
<div className="icon">
|
<div className="icon">▾</div>
|
||||||
<DropDownIcon />
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Dropdown Options */}
|
{/* Dropdown Options */}
|
||||||
@@ -63,7 +51,7 @@ const RegularDropDown: React.FC<DropdownProps> = ({ header, options, onSelect })
|
|||||||
<div
|
<div
|
||||||
className="option"
|
className="option"
|
||||||
key={index}
|
key={index}
|
||||||
onClick={() => handleOptionClick(option)} // Handle option click
|
onClick={() => handleOptionClick(option)}
|
||||||
>
|
>
|
||||||
{option}
|
{option}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ const Data = () => {
|
|||||||
easing: "Connecter 1",
|
easing: "Connecter 1",
|
||||||
children: [
|
children: [
|
||||||
{ id: 1, easing: "Linear" },
|
{ id: 1, easing: "Linear" },
|
||||||
{ id: 2, easing: "Linear" },
|
{ id: 2, easing: "Ease Out" },
|
||||||
{ id: 3, easing: "Linear" },
|
{ id: 3, easing: "Linear" },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
@@ -70,21 +70,26 @@ const Data = () => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const removeChild = (childId: number) => {
|
const removeChild = (groupId: number, childId: number) => {
|
||||||
setGroups((groups) =>
|
setGroups((currentGroups) =>
|
||||||
groups
|
currentGroups.map((group) => {
|
||||||
.map((group) => ({
|
if (group.id === groupId) {
|
||||||
...group,
|
return {
|
||||||
children: group.children.filter((c) => c.id !== childId),
|
...group,
|
||||||
}))
|
children: group.children.map((child) =>
|
||||||
.filter((group) => group.children.length > 0)
|
child.id === childId ? { ...child, easing: "Linear" } : child
|
||||||
|
),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return group;
|
||||||
|
})
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="dataSideBar">
|
<div className="dataSideBar">
|
||||||
<div className="sideBarHeader">{selectedWidget}</div>
|
<div className="sideBarHeader">{selectedWidget}</div>
|
||||||
{groups.map((group, groupIndex) => (
|
{groups.map((group) => (
|
||||||
<div key={group.id} className="selectedMain-container">
|
<div key={group.id} className="selectedMain-container">
|
||||||
<div className="selectedMain">
|
<div className="selectedMain">
|
||||||
<span className="bulletPoint">•</span>
|
<span className="bulletPoint">•</span>
|
||||||
@@ -107,6 +112,7 @@ const Data = () => {
|
|||||||
{group.children.map((child) => (
|
{group.children.map((child) => (
|
||||||
<div key={child.id} className="selectedMain child">
|
<div key={child.id} className="selectedMain child">
|
||||||
<main>Input {child.id}</main>
|
<main>Input {child.id}</main>
|
||||||
|
{/* Pass the current easing as the header */}
|
||||||
<RegularDropDown
|
<RegularDropDown
|
||||||
header={child.easing}
|
header={child.easing}
|
||||||
options={["Linear", "Ease In", "Ease Out", "Ease In-Out"]}
|
options={["Linear", "Ease In", "Ease Out", "Ease In-Out"]}
|
||||||
@@ -124,7 +130,10 @@ const Data = () => {
|
|||||||
<div className="icon" onClick={() => handleLinkClick(child.id)}>
|
<div className="icon" onClick={() => handleLinkClick(child.id)}>
|
||||||
<LinkIcon />
|
<LinkIcon />
|
||||||
</div>
|
</div>
|
||||||
<div className="icon" onClick={() => removeChild(child.id)}>
|
<div
|
||||||
|
className="icon"
|
||||||
|
onClick={() => removeChild(group.id, child.id)}
|
||||||
|
>
|
||||||
<RemoveIcon />
|
<RemoveIcon />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -49,17 +49,11 @@ const DraggableWidget = ({ widget }: { widget: any }) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handlePointerDown = () => {
|
const handlePointerDown = () => {
|
||||||
// Set selected chart when pointer down event occurs (i.e., when it's clicked, not dragged)
|
|
||||||
if (!isDragging) {
|
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 (
|
return (
|
||||||
<div
|
<div
|
||||||
key={widget.id}
|
key={widget.id}
|
||||||
@@ -68,7 +62,7 @@ const DraggableWidget = ({ widget }: { widget: any }) => {
|
|||||||
{...attributes}
|
{...attributes}
|
||||||
{...listeners}
|
{...listeners}
|
||||||
style={style}
|
style={style}
|
||||||
onPointerDown={handlePointerDown} // Use onPointerDown instead of onPointerUp
|
onPointerDown={handlePointerDown}
|
||||||
>
|
>
|
||||||
<ChartComponent
|
<ChartComponent
|
||||||
type={widget.type}
|
type={widget.type}
|
||||||
@@ -82,19 +76,28 @@ const DraggableWidget = ({ widget }: { widget: any }) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const RealTimeVisualization = () => {
|
const RealTimeVisualization = () => {
|
||||||
|
const [zone, setZone] = useState([
|
||||||
|
"Manufacturing unit",
|
||||||
|
"Assembly unit",
|
||||||
|
"Packing unit",
|
||||||
|
"Warehouse",
|
||||||
|
"Inventory",
|
||||||
|
]);
|
||||||
|
|
||||||
const [activeSides, setActiveSides] = useState<Side[]>([]);
|
const [activeSides, setActiveSides] = useState<Side[]>([]);
|
||||||
const [panelOrder, setPanelOrder] = useState<Side[]>([]);
|
const [panelOrder, setPanelOrder] = useState<Side[]>([]);
|
||||||
const [selectedSide, setSelectedSide] = useState<Side | null>(null);
|
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();
|
const { draggedAsset, addWidget, widgets, setWidgets } = useWidgetStore();
|
||||||
|
|
||||||
// Sensors for drag-and-drop (Pointer and Keyboard)
|
|
||||||
const sensors = useSensors(
|
const sensors = useSensors(
|
||||||
useSensor(PointerSensor),
|
useSensor(PointerSensor),
|
||||||
useSensor(KeyboardSensor)
|
useSensor(KeyboardSensor)
|
||||||
);
|
);
|
||||||
|
|
||||||
useEffect(() => {}, [widgets]);
|
|
||||||
|
|
||||||
const toggleSide = (side: Side) => {
|
const toggleSide = (side: Side) => {
|
||||||
setActiveSides((prev) => {
|
setActiveSides((prev) => {
|
||||||
const newActive = prev.includes(side)
|
const newActive = prev.includes(side)
|
||||||
@@ -102,17 +105,24 @@ const RealTimeVisualization = () => {
|
|||||||
: [...prev, side];
|
: [...prev, side];
|
||||||
setPanelOrder(newActive);
|
setPanelOrder(newActive);
|
||||||
|
|
||||||
// Reset selectedSide if the panel is being closed
|
|
||||||
if (prev.includes(side)) {
|
if (prev.includes(side)) {
|
||||||
setSelectedSide(null); // Hide extra buttons when the panel is closed
|
setSelectedSide(null);
|
||||||
} else {
|
} else {
|
||||||
setSelectedSide(side); // Show extra buttons when the panel is opened
|
setSelectedSide(side);
|
||||||
}
|
}
|
||||||
|
|
||||||
return newActive;
|
return newActive;
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const toggleLockPanel = (side: Side) => {
|
||||||
|
setLockedPanels((prev) =>
|
||||||
|
prev.includes(side)
|
||||||
|
? prev.filter((panel) => panel !== side)
|
||||||
|
: [...prev, side]
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
const getPanelStyle = (currentSide: Side) => {
|
const getPanelStyle = (currentSide: Side) => {
|
||||||
const currentIndex = panelOrder.indexOf(currentSide);
|
const currentIndex = panelOrder.indexOf(currentSide);
|
||||||
const previousPanels = panelOrder.slice(0, currentIndex);
|
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 handleDragEnd = (event: any) => {
|
||||||
const { active, over } = event;
|
const { active, over } = event;
|
||||||
|
|
||||||
@@ -171,14 +178,11 @@ const RealTimeVisualization = () => {
|
|||||||
const newPanel =
|
const newPanel =
|
||||||
widgets.find((widget) => widget.id === over.id)?.panel || active.panel;
|
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) {
|
if (active.panel === newPanel) {
|
||||||
// Reorder within the same panel
|
|
||||||
const newIndex = widgets.findIndex((widget) => widget.id === over.id);
|
const newIndex = widgets.findIndex((widget) => widget.id === over.id);
|
||||||
const reorderedWidgets = arrayMove(widgets, oldIndex, newIndex);
|
const reorderedWidgets = arrayMove(widgets, oldIndex, newIndex);
|
||||||
setWidgets(reorderedWidgets);
|
setWidgets(reorderedWidgets);
|
||||||
} else {
|
} else {
|
||||||
// Move to a different panel
|
|
||||||
const updatedWidgets = widgets.map((widget) =>
|
const updatedWidgets = widgets.map((widget) =>
|
||||||
widget.id === active.id ? { ...widget, panel: newPanel } : widget
|
widget.id === active.id ? { ...widget, panel: newPanel } : widget
|
||||||
);
|
);
|
||||||
@@ -200,12 +204,19 @@ const RealTimeVisualization = () => {
|
|||||||
onDragEnd={handleDragEnd}
|
onDragEnd={handleDragEnd}
|
||||||
>
|
>
|
||||||
<div className="content-container realTime-viz flex">
|
<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="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) => (
|
{(["top", "right", "bottom", "left"] as Side[]).map((side) => (
|
||||||
<div key={side} className={`side-button-container ${side}`}>
|
<div key={side} className={`side-button-container ${side}`}>
|
||||||
{/* Side Button */}
|
|
||||||
<button
|
<button
|
||||||
className={`side-button ${side}`}
|
className={`side-button ${side}`}
|
||||||
onClick={() => toggleSide(side)}
|
onClick={() => toggleSide(side)}
|
||||||
@@ -214,23 +225,71 @@ const RealTimeVisualization = () => {
|
|||||||
+
|
+
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
{/* Extra Buttons */}
|
|
||||||
<div
|
<div
|
||||||
className="extra-buttons"
|
className="extra-buttons"
|
||||||
style={{
|
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 />
|
<DisableSorting />
|
||||||
</div>
|
</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 />
|
<EyeIcon />
|
||||||
</div>
|
</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 />
|
<CleanPannel />
|
||||||
</div>
|
</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 />
|
<LockIcon />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -245,7 +304,13 @@ const RealTimeVisualization = () => {
|
|||||||
onDrop={(e) => handleDrop(e, side)}
|
onDrop={(e) => handleDrop(e, side)}
|
||||||
onDragOver={(e) => e.preventDefault()}
|
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
|
<SortableContext
|
||||||
items={widgets
|
items={widgets
|
||||||
.filter((w) => w.panel === side)
|
.filter((w) => w.panel === side)
|
||||||
@@ -255,9 +320,7 @@ const RealTimeVisualization = () => {
|
|||||||
{widgets
|
{widgets
|
||||||
.filter((w) => w.panel === side)
|
.filter((w) => w.panel === side)
|
||||||
.map((widget) => (
|
.map((widget) => (
|
||||||
<>
|
<DraggableWidget widget={widget} key={widget.id} />
|
||||||
<DraggableWidget widget={widget} />
|
|
||||||
</>
|
|
||||||
))}
|
))}
|
||||||
</SortableContext>
|
</SortableContext>
|
||||||
</div>
|
</div>
|
||||||
@@ -265,7 +328,7 @@ const RealTimeVisualization = () => {
|
|||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<SideBar header={rightHeader} defaultActive={"Data"} />
|
<SideBar header={["Data", "Design"]} defaultActive={"Data"} />
|
||||||
</div>
|
</div>
|
||||||
</DndContext>
|
</DndContext>
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user