visualization functions seperated

This commit is contained in:
2025-03-20 09:36:10 +05:30
parent 299b3ed381
commit b9fa37cef8
21 changed files with 564 additions and 701 deletions

BIN
app/src/assets/orgTemp.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

View File

@@ -378,8 +378,8 @@ export function UndoIcon() {
xmlns="http://www.w3.org/2000/svg"
>
<path
fill-rule="evenodd"
clip-rule="evenodd"
fillRule="evenodd"
clipRule="evenodd"
d="M3.76516 1.73483C3.91161 1.88128 3.91161 2.11872 3.76516 2.26516L2.90533 3.125H7.5C9.0878 3.125 10.375 4.41218 10.375 6C10.375 7.5878 9.0878 8.875 7.5 8.875H4C3.79289 8.875 3.625 8.7071 3.625 8.5C3.625 8.2929 3.79289 8.125 4 8.125H7.5C8.6736 8.125 9.625 7.1736 9.625 6C9.625 4.82639 8.6736 3.875 7.5 3.875H2.90533L3.76516 4.73483C3.91161 4.88128 3.91161 5.1187 3.76516 5.26515C3.61872 5.4116 3.38128 5.4116 3.23483 5.26515L1.73483 3.76516C1.58839 3.61872 1.58839 3.38128 1.73483 3.23483L3.23483 1.73483C3.38128 1.58839 3.61872 1.58839 3.76516 1.73483Z"
fill="var(--text-color)"
/>
@@ -397,8 +397,8 @@ export function RedoIcon() {
xmlns="http://www.w3.org/2000/svg"
>
<path
fill-rule="evenodd"
clip-rule="evenodd"
fillRule="evenodd"
clipRule="evenodd"
d="M8.23484 1.73483C8.08839 1.88128 8.08839 2.11872 8.23484 2.26516L9.09467 3.125H4.5C2.9122 3.125 1.625 4.41218 1.625 6C1.625 7.5878 2.9122 8.875 4.5 8.875H8C8.20711 8.875 8.375 8.7071 8.375 8.5C8.375 8.2929 8.20711 8.125 8 8.125H4.5C3.3264 8.125 2.375 7.1736 2.375 6C2.375 4.82639 3.3264 3.875 4.5 3.875H9.09467L8.23484 4.73483C8.08839 4.88128 8.08839 5.1187 8.23484 5.26515C8.38128 5.4116 8.61872 5.4116 8.76517 5.26515L10.2652 3.76516C10.4116 3.61872 10.4116 3.38128 10.2652 3.23483L8.76517 1.73483C8.61872 1.58839 8.38128 1.58839 8.23484 1.73483Z"
fill="var(--text-color)"
/>
@@ -436,7 +436,7 @@ export function RemoveIcon() {
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path d="M3 6.5H9" stroke="var(--text-color)" stroke-linecap="round" />
<path d="M3 6.5H9" stroke="var(--text-color)" strokeLinecap="round" />
</svg>
);
}
@@ -458,8 +458,8 @@ export function InfoIcon() {
d="M6.00006 10.3175C8.45219 10.3175 10.4401 8.32963 10.4401 5.8775C10.4401 3.42536 8.45219 1.4375 6.00006 1.4375C3.54792 1.4375 1.56006 3.42536 1.56006 5.8775C1.56006 8.32963 3.54792 10.3175 6.00006 10.3175Z"
stroke="var(--text-color)"
stroke-width="0.72"
stroke-linecap="round"
stroke-linejoin="round"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
);

View File

@@ -113,7 +113,7 @@ export function CartIcon({ isActive }: { isActive: boolean }) {
<path
d="M1.33337 2L1.50998 2.05887C2.39001 2.35221 2.83002 2.49888 3.08169 2.84807C3.33337 3.19725 3.33337 3.66106 3.33337 4.58869V6.33333C3.33337 8.21893 3.33337 9.16173 3.91916 9.74753C4.50495 10.3333 5.44775 10.3333 7.33337 10.3333H8.66671M12.6667 10.3333H11.3334"
stroke={isActive ? "var(--primary-color)" : "var(--text-color)"}
stroke-linecap="round"
strokeLinecap="round"
/>
<path
d="M5.00005 12C5.55233 12 6.00005 12.4477 6.00005 13C6.00005 13.5523 5.55233 14 5.00005 14C4.44776 14 4.00005 13.5523 4.00005 13C4.00005 12.4477 4.44776 12 5.00005 12Z"
@@ -126,7 +126,7 @@ export function CartIcon({ isActive }: { isActive: boolean }) {
<path
d="M3.33337 4H5.33337M3.66671 8.66667H10.6812C11.3208 8.66667 11.6406 8.66667 11.8911 8.50153C12.1416 8.33633 12.2676 8.0424 12.5195 7.45453L12.8052 6.78787C13.3449 5.52863 13.6148 4.89902 13.3184 4.44951C13.0219 4 12.337 4 10.967 4H8.00004"
stroke={isActive ? "var(--primary-color)" : "var(--text-color)"}
stroke-linecap="round"
strokeLinecap="round"
/>
</svg>
);

View File

@@ -605,7 +605,7 @@ export function PenIcon({ isActive }: { isActive: boolean }) {
stroke={
isActive ? "var(--highlight-accent-color)" : "var(--text-color)"
}
stroke-linecap="round"
strokeLinecap="round"
/>
</svg>
);
@@ -631,7 +631,7 @@ export function SaveTemplateIcon({ isActive }: { isActive: boolean }) {
stroke={
isActive ? "var(--highlight-accent-color)" : "var(--text-color)"
}
stroke-linecap="round"
strokeLinecap="round"
/>
</svg>
);

View File

@@ -7,40 +7,40 @@ export function CleanPannel() {
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<g clip-path="url(#clip0_1782_1158)">
<path d="M12 0H0V12H12V0Z" fill="white" fill-opacity="0.01" />
<g clipPath="url(#clip0_1782_1158)">
<path d="M12 0H0V12H12V0Z" fill="white" fillOpacity="0.01" />
<path
fill-rule="evenodd"
clip-rule="evenodd"
fillRule="evenodd"
clipRule="evenodd"
d="M5 1.47852H7V3.47853H10.75V5.47853H1.25V3.47853H5V1.47852Z"
stroke="#2B3344"
stroke-linecap="round"
stroke-linejoin="round"
strokeLinecap="round"
strokeLinejoin="round"
/>
<path d="M2 10H10V5.5H2V10Z" stroke="#2B3344" stroke-linejoin="round" />
<path d="M2 10H10V5.5H2V10Z" stroke="#2B3344" strokeLinejoin="round" />
<path
d="M4 9.97439V8.47852"
stroke="#2B3344"
stroke-linecap="round"
stroke-linejoin="round"
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
d="M6 9.97461V8.47461"
stroke="#2B3344"
stroke-linecap="round"
stroke-linejoin="round"
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
d="M8 9.97439V8.47852"
stroke="#2B3344"
stroke-linecap="round"
stroke-linejoin="round"
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
d="M3 10H9"
stroke="#2B3344"
stroke-linecap="round"
stroke-linejoin="round"
strokeLinecap="round"
strokeLinejoin="round"
/>
</g>
<defs>
@@ -98,65 +98,3 @@ export function LockIcon() {
</svg>
);
}
export function PlayIcon() {
return (
<svg
width="28"
height="28"
viewBox="0 0 28 28"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M19.9111 12.5144C21.363 13.3799 21.363 15.6201 19.9111 16.4856L11.1451 21.7109C9.73403 22.552 8 21.4572 8 19.7253V9.27468C8 7.54276 9.73403 6.44801 11.145 7.28911L19.9111 12.5144Z"
stroke="#1C274C"
/>
</svg>
);
}
export function CommentIcon() {
return (
<svg
width="28"
height="28"
viewBox="0 0 28 28"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M8.15482 20.3118L7.30127 21.1654H8.50838H14H14.0004C15.6584 21.1641 17.2646 20.5879 18.5455 19.5352C19.8263 18.4824 20.7025 17.0181 21.0248 15.3917C21.3471 13.7654 21.0955 12.0776 20.3129 10.6159C19.5303 9.15428 18.2651 8.00918 16.7329 7.37572C15.2007 6.74227 13.4963 6.65966 11.91 7.14196C10.3238 7.62427 8.95377 8.64165 8.0335 10.0208C7.11322 11.3999 6.69958 13.0554 6.86306 14.7053L6.86513 14.7262L6.86895 14.7469C7.0346 15.6431 7.22308 16.3535 7.53795 17.0282C7.85334 17.704 8.28373 18.3189 8.90409 19.0412L8.91809 19.0575L8.93343 19.0725C8.99514 19.133 9.03091 19.215 9.03333 19.3012C9.03257 19.3438 9.02367 19.3858 9.0071 19.425L9.46767 19.6196L9.0071 19.425C8.98993 19.4656 8.96488 19.5024 8.93338 19.5333L8.93336 19.5333L8.92982 19.5368L8.15482 20.3118Z"
stroke="#2B3344"
/>
<path
d="M10.6665 12.332H17.3332"
stroke="#2B3344"
stroke-linecap="round"
/>
<path
d="M10.6665 15.668H17.3332"
stroke="#2B3344"
stroke-linecap="round"
/>
</svg>
);
}
export function SaveTeemplateIcon() {
return (
<svg
width="28"
height="28"
viewBox="0 0 28 28"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M21.5 17.4104V13.2492C21.5 9.67539 21.5 7.88847 20.4017 6.77822C19.3033 5.66797 17.5355 5.66797 14 5.66797C10.4645 5.66797 8.6967 5.66797 7.59835 6.77822C6.5 7.88847 6.5 9.67539 6.5 13.2492V17.4104C6.5 19.9909 6.5 21.2811 7.11176 21.8449C7.40351 22.1138 7.77179 22.2827 8.1641 22.3276C8.98668 22.4217 9.94727 21.5721 11.8685 19.8728C12.7177 19.1217 13.1423 18.7461 13.6336 18.6472C13.8755 18.5985 14.1245 18.5985 14.3664 18.6472C14.8577 18.7461 15.2823 19.1217 16.1315 19.8728C18.0527 21.5721 19.0133 22.4217 19.8359 22.3276C20.2282 22.2827 20.5965 22.1138 20.8882 21.8449C21.5 21.2811 21.5 19.9909 21.5 17.4104Z"
stroke="#2B3344"
/>
<path d="M16.5 9H11.5" stroke="#2B3344" stroke-linecap="round" />
</svg>
);
}

View File

@@ -10,14 +10,14 @@ export function AnalysisIcon({ isActive }: { isActive: boolean }) {
<path
d="M17.5002 12.4987L15.1418 10.1404M10.8335 14.1654H5.8335M7.50016 10.832H5.8335M10.8335 8.33203C10.8335 8.82648 10.9801 9.30983 11.2548 9.72096C11.5295 10.1321 11.92 10.4525 12.3768 10.6417C12.8336 10.8309 13.3363 10.8805 13.8212 10.784C14.3062 10.6875 14.7516 10.4494 15.1013 10.0998C15.4509 9.75017 15.689 9.30471 15.7855 8.81976C15.8819 8.3348 15.8324 7.83214 15.6432 7.37532C15.454 6.91851 15.1335 6.52806 14.7224 6.25336C14.3113 5.97865 13.8279 5.83203 13.3335 5.83203C12.6705 5.83203 12.0346 6.09542 11.5657 6.56426C11.0969 7.03311 10.8335 7.66899 10.8335 8.33203Z"
stroke={isActive ? "var(--primary-color)" : "var(--text-color)"}
stroke-linecap="round"
stroke-linejoin="round"
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
d="M14.1667 14.1667V16.6667C14.1667 16.8877 14.0789 17.0996 13.9226 17.2559C13.7663 17.4122 13.5543 17.5 13.3333 17.5H3.33333C3.11232 17.5 2.90036 17.4122 2.74408 17.2559C2.5878 17.0996 2.5 16.8877 2.5 16.6667V3.33333C2.5 3.11232 2.5878 2.90036 2.74408 2.74408C2.90036 2.5878 3.11232 2.5 3.33333 2.5H13.3333"
stroke={isActive ? "var(--primary-color)" : "var(--text-color)"}
stroke-linecap="round"
stroke-linejoin="round"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
);

View File

@@ -1,5 +1,6 @@
import React from "react";
import { AppDockIcon } from "../../icons/HeaderIcons";
import orgImg from "../../../assets/orgTemp.png"
const Header: React.FC = () => {
const guestUsers = [
@@ -38,7 +39,7 @@ const Header: React.FC = () => {
V
</div>
<div className="user-organization">
<img src="" alt="" />
<img src={orgImg} alt="" />
</div>
</div>
</div>

View File

@@ -13,6 +13,10 @@ import {
} from "../icons/ExportToolsIcons";
import { ArrowIcon, TickIcon } from "../icons/ExportCommonIcons";
import useModuleStore from "../../store/useModuleStore";
import { handleSaveTemplate } from "../../modules/visualization/handleSaveTemplate";
import { usePlayButtonStore } from "../../store/usePlayButtonStore";
import useTemplateStore from "../../store/useTemplateStore";
import { useSelectedZoneStore } from "../../store/useZoneStore";
const Tools: React.FC = () => {
const [activeTool, setActiveTool] = useState("cursor");
@@ -23,6 +27,9 @@ const Tools: React.FC = () => {
const [openDrop, setOpenDrop] = useState(false);
const { activeModule } = useModuleStore();
const { isPlaying, setIsPlaying } = usePlayButtonStore();
const { addTemplate } = useTemplateStore();
const { selectedZone } = useSelectedZoneStore();
// Reset activeTool whenever activeModule changes
useEffect(() => {
@@ -187,7 +194,10 @@ const Tools: React.FC = () => {
<>
<div className="split"></div>
<div className="draw-tools">
<div className={`tool-button`}>
<div
className={`tool-button`}
onClick={() => handleSaveTemplate({ addTemplate, selectedZone })}
>
<SaveTemplateIcon isActive={false} />
</div>
</div>
@@ -207,6 +217,7 @@ const Tools: React.FC = () => {
className={`tool-button ${activeTool === "play" ? "active" : ""}`}
onClick={() => {
setActiveTool("play");
setIsPlaying(!isPlaying);
}}
>
<PlayIcon isActive={activeTool === "play"} />

View File

@@ -1,5 +1,9 @@
import React from "react";
import { CleanPannel, EyeIcon, LockIcon } from "../../icons/RealTimeVisulationIcons";
import {
CleanPannel,
EyeIcon,
LockIcon,
} from "../../icons/RealTimeVisulationIcons";
// Define the type for `Side`
type Side = "top" | "bottom" | "left" | "right";
@@ -137,47 +141,42 @@ const AddButtons: React.FC<ButtonsProps> = ({
</button>
{/* Extra Buttons */}
<div
className="extra-Bs"
style={{
display: selectedZone.activeSides.includes(side)
? "flex"
: "none",
}}
>
{/* Hide Panel */}
<div
className="icon"
title="Hide Panel"
onClick={() => toggleVisibility(side)}
>
<EyeIcon />
</div>
{selectedZone.activeSides.includes(side) && (
<div className="extra-Bs">
{/* Hide Panel */}
<div
className="icon"
title="Hide Panel"
onClick={() => toggleVisibility(side)}
>
<EyeIcon />
</div>
{/* Clean Panel */}
<div
className="icon"
title="Clean Panel"
onClick={() => cleanPanel(side)}
>
<CleanPannel />
</div>
{/* Clean Panel */}
<div
className="icon"
title="Clean Panel"
onClick={() => cleanPanel(side)}
>
<CleanPannel />
</div>
{/* Lock/Unlock Panel */}
<div
className={`icon ${
selectedZone.lockedPanels.includes(side) ? "active" : ""
}`}
title={
selectedZone.lockedPanels.includes(side)
? "Unlock Panel"
: "Lock Panel"
}
onClick={() => toggleLockPanel(side)}
>
<LockIcon />
{/* Lock/Unlock Panel */}
<div
className={`icon ${
selectedZone.lockedPanels.includes(side) ? "active" : ""
}`}
title={
selectedZone.lockedPanels.includes(side)
? "Unlock Panel"
: "Lock Panel"
}
onClick={() => toggleLockPanel(side)}
>
<LockIcon />
</div>
</div>
</div>
)}
</div>
))}
</div>

View File

@@ -2,12 +2,6 @@ import React, { useEffect, useState, useRef } from "react";
import { usePlayButtonStore } from "../../../store/usePlayButtonStore";
import Panel from "./Panel";
import AddButtons from "./AddButtons";
import {
CommentIcon,
PlayIcon,
SaveTeemplateIcon,
} from "../../icons/RealTimeVisulationIcons";
import useTemplateStore from "../../../store/useTemplateStore";
import { useSelectedZoneStore } from "../../../store/useZoneStore";
type Side = "top" | "bottom" | "left" | "right";
@@ -62,82 +56,9 @@ const RealTimeVisulization: React.FC = () => {
},
});
const { isPlaying, setIsPlaying } = usePlayButtonStore();
const { addTemplate } = useTemplateStore();
const { isPlaying } = usePlayButtonStore();
const { selectedZone, setSelectedZone } = useSelectedZoneStore();
const generateUniqueId = (): string =>
`${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
const captureVisualization = async (): Promise<string | null> => {
const container = containerRef.current;
if (!container) return null;
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
if (!ctx) return null;
const rect = container.getBoundingClientRect();
canvas.width = rect.width;
canvas.height = rect.height;
// Draw background
ctx.fillStyle = getComputedStyle(container).backgroundColor;
ctx.fillRect(0, 0, canvas.width, canvas.height);
// Capture all canvas elements
const canvases = container.querySelectorAll('canvas');
canvases.forEach(childCanvas => {
const childRect = childCanvas.getBoundingClientRect();
const x = childRect.left - rect.left;
const y = childRect.top - rect.top;
ctx.drawImage(childCanvas, x, y, childRect.width, childRect.height);
});
// Capture SVG elements
const svgs = container.querySelectorAll('svg');
for (const svg of Array.from(svgs)) {
const svgString = new XMLSerializer().serializeToString(svg);
const svgBlob = new Blob([svgString], { type: 'image/svg+xml' });
const url = URL.createObjectURL(svgBlob);
try {
const img = await new Promise<HTMLImageElement>((resolve, reject) => {
const image = new Image();
image.onload = () => resolve(image);
image.onerror = reject;
image.src = url;
});
const svgRect = svg.getBoundingClientRect();
ctx.drawImage(
img,
svgRect.left - rect.left,
svgRect.top - rect.top,
svgRect.width,
svgRect.height
);
} finally {
URL.revokeObjectURL(url);
}
}
return canvas.toDataURL('image/png');
};
const handleSaveTemplate = async () => {
const snapshot = await captureVisualization();
const template = {
id: generateUniqueId(),
name: `Template ${Date.now()}`,
panelOrder: selectedZone.panelOrder,
widgets: selectedZone.widgets,
snapshot,
};
addTemplate(template);
};
useEffect(() => {
setZonesData((prev) => ({
...prev,
@@ -148,38 +69,25 @@ const RealTimeVisulization: React.FC = () => {
return (
<div
ref={containerRef}
id="real-time-vis-canvas"
className="realTime-viz canvas"
style={{
height: isPlaying ? "100vh" : "600px",
width: isPlaying ? "100%" : "55%",
left: isPlaying ? "50%" : "48%",
height: isPlaying ? "100vh" : "",
width: isPlaying ? "100%" : "",
left: isPlaying ? "50%" : "",
}}
>
<div className="realTimeViz-tools">
<div
className="icon save"
title="Save Template"
onClick={handleSaveTemplate}
>
<SaveTeemplateIcon />
</div>
<div className="icon comment" title="Comment">
<CommentIcon />
</div>
<div
className="play icon"
title="Play"
onClick={() => setIsPlaying(!isPlaying)}
>
<PlayIcon />
</div>
</div>
<div className={`zoon-wrapper ${selectedZone.activeSides.includes("bottom") && "bottom"}`}>
<div
className={`zoon-wrapper ${
selectedZone.activeSides.includes("bottom") && "bottom"
}`}
>
{Object.keys(zonesData).map((zoneName, index) => (
<div
key={index}
className={`zone ${selectedZone.zoneName === zoneName ? "active" : ""}`}
className={`zone ${
selectedZone.zoneName === zoneName ? "active" : ""
}`}
onClick={() => {
setSelectedZone({
zoneName,

View File

@@ -0,0 +1,2 @@
export const generateUniqueId = (): string =>
`${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;

0
app/src/hooks/temp.md Normal file
View File

View File

View File

View File

@@ -0,0 +1,55 @@
export const captureVisualization = async (): Promise<string | null> => {
const container = document.getElementById("real-time-vis-canvas");
if (!container) return null;
const canvas = document.createElement("canvas");
const ctx = canvas.getContext("2d");
if (!ctx) return null;
const rect = container.getBoundingClientRect();
canvas.width = rect.width;
canvas.height = rect.height;
// Draw background
ctx.fillStyle = getComputedStyle(container).backgroundColor;
ctx.fillRect(0, 0, canvas.width, canvas.height);
// Capture all canvas elements
const canvases = container.querySelectorAll("canvas");
canvases.forEach((childCanvas) => {
const childRect = childCanvas.getBoundingClientRect();
const x = childRect.left - rect.left;
const y = childRect.top - rect.top;
ctx.drawImage(childCanvas, x, y, childRect.width, childRect.height);
});
// Capture SVG elements
const svgs = container.querySelectorAll("svg");
for (const svg of Array.from(svgs)) {
const svgString = new XMLSerializer().serializeToString(svg);
const svgBlob = new Blob([svgString], { type: "image/svg+xml" });
const url = URL.createObjectURL(svgBlob);
try {
const img = await new Promise<HTMLImageElement>((resolve, reject) => {
const image = new Image();
image.onload = () => resolve(image);
image.onerror = reject;
image.src = url;
});
const svgRect = svg.getBoundingClientRect();
ctx.drawImage(
img,
svgRect.left - rect.left,
svgRect.top - rect.top,
svgRect.width,
svgRect.height
);
} finally {
URL.revokeObjectURL(url);
}
}
return canvas.toDataURL("image/png");
};

View File

@@ -0,0 +1,36 @@
import { Template } from "../../store/useTemplateStore";
import { captureVisualization } from "./captureVisualization";
type HandleSaveTemplateProps = {
addTemplate: (template: Template) => void;
selectedZone: {
panelOrder: string[]; // Adjust the type based on actual data structure
widgets: any[]; // Replace `any` with the actual widget type
};
};
// Generate a unique ID (placeholder function)
const generateUniqueId = (): string => {
return Math.random().toString(36).substring(2, 15);
};
// Refactored function
export const handleSaveTemplate = async ({
addTemplate,
selectedZone,
}: HandleSaveTemplateProps): Promise<void> => {
try {
const snapshot = await captureVisualization();
const template: Template = {
id: generateUniqueId(),
name: `Template ${Date.now()}`,
panelOrder: selectedZone.panelOrder,
widgets: selectedZone.widgets,
snapshot,
};
console.log('template: ', template);
addTemplate(template);
} catch (error) {
console.error('Failed to save template:', error);
}
};

View File

@@ -4,6 +4,7 @@ import SideBarLeft from "../components/layout/sidebarLeft/SideBarLeft";
import SideBarRight from "../components/layout/sidebarRight/SideBarRight";
import useModuleStore from "../store/useModuleStore";
import RealTimeVisulization from "../components/ui/componets/RealTimeVisulization";
import Tools from "../components/ui/Tools";
const Project: React.FC = () => {
const { activeModule } = useModuleStore();
@@ -14,6 +15,7 @@ const Project: React.FC = () => {
<SideBarLeft />
<SideBarRight />
{activeModule === "visualization" && <RealTimeVisulization />}
<Tools />
</div>
);
};

0
app/src/services/temp.md Normal file
View File

View File

@@ -1,21 +1,21 @@
import { create } from "zustand";
type Side = "top" | "bottom" | "left" | "right";
// type Side = "top" | "bottom" | "left" | "right";
interface Widget {
export interface Widget {
id: string;
type: string;
title: string;
panel: Side;
panel: string;
data: any;
}
interface Template {
export interface Template {
id: string;
name: string;
panelOrder: Side[];
panelOrder: string[];
widgets: Widget[];
snapshot?: string; // Add an optional image property (base64)
snapshot?: string | null; // Add an optional image property (base64)
}
interface TemplateStore {

View File

@@ -84,9 +84,9 @@
.chart {
min-height: 170px;
background: var(--background-primary, #FCFDFD);
border: 1.23px solid var(--Grays-Gray-5, #E5E5EA);
box-shadow: 0px 4.91px 4.91px 0px #0000001C;
background: var(--background-primary, #fcfdfd);
border: 1.23px solid var(--Grays-Gray-5, #e5e5ea);
box-shadow: 0px 4.91px 4.91px 0px #0000001c;
border-radius: $border-radius-medium;
padding: 12px 6px;
}
@@ -107,7 +107,7 @@
.stock {
padding: 13px 5px;
background-color: #E0DFFF80;
background-color: #e0dfff80;
border-radius: 6.33px;
display: flex;
justify-content: space-between;
@@ -129,16 +129,11 @@
font-size: 12px;
}
}
}
}
}
}
}
}
.outline-container {
@@ -230,14 +225,18 @@
.user-profile-container {
display: flex;
.user-organnization {
.user-organization {
height: 100%;
max-width: 52px;
border-radius: 20px;
overflow: hidden;
margin-left: 2px;
img {
height: 100%;
width: 100%;
object-fit: cover;
vertical-align: top;
}
}
}
@@ -430,9 +429,7 @@
width: 24px;
height: 26px;
border-radius: 3.2px;
}
}
}
@@ -441,7 +438,6 @@
}
}
}
}
}
}
@@ -527,39 +523,6 @@
}
}
/* Base styles */
.multi-level-dropdown {
position: relative;

View File

@@ -1,464 +1,412 @@
@use '../abstracts/variables.scss' as *;
@use "../abstracts/variables.scss" as *;
// Main Container
.realTime-viz {
background-color: var(--background-color);
border-radius: 20px;
box-shadow: 0px 4px 8px rgba(60, 60, 67, 0.1019607843);
width: 55%;
height: 600px;
position: absolute;
top: 50%;
left: 48%;
transform: translate(-50%, -50%);
background-color: var(--background-color);
border-radius: 20px;
box-shadow: 0px 4px 8px rgba(60, 60, 67, 0.1019607843);
width: calc(100% - (320px + 270px + 80px));
height: 600px;
position: absolute;
top: 50%;
left: calc(270px + 40px);
transform: translate(0, -50%);
.icon {
display: flex;
align-items: center;
position: relative;
}
.icons-container {
.icon {
display: flex;
align-items: center;
position: relative;
&:first-child {
&::after {
content: "";
display: block;
width: 1px;
height: 18px;
background-color: #000;
margin-top: 10px;
position: absolute;
right: -10px;
top: -4px;
}
&:first-child {
&::after {
display: none;
}
}
}
}
.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;
}
.icons-container {
.icon {
&:first-child {
&::after {
display: none;
}
}
}
.zone {
width: auto;
background-color: #fcfdfd;
border-radius: 6px;
padding: 4px 8px;
white-space: nowrap;
font-size: $small;
}
.realTimeViz-tools {
position: fixed;
bottom: -150px;
left: 50%;
transform: translateX(-50%);
box-shadow: 0px 4px 8px 0px rgba(60, 60, 67, 0.1);
background: $background-color;
display: flex;
gap: 12px;
border-radius: 12px;
z-index: 1000;
transition: bottom 0.3s ease;
padding: 8px;
.icons-container {
padding-left: 8px;
display: flex;
align-items: center;
gap: 10px;
}
.active {
background-color: var(--accent-color);
color: var(--background-color);
// color: #FCFDFD !important;
}
}
.zoon-wrapper.bottom {
bottom: 210px;
}
.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;
font-size: $small;
}
.active {
background-color: var(--accent-color);
color: var(--background-color);
// color: #FCFDFD !important;
}
}
.zoon-wrapper.bottom {
bottom: 210px;
}
@media (max-width: 1024px) {
width: 80%; // Increase width to take more space on smaller screens
height: 500px; // Reduce height to fit smaller screens
left: 50%; // Center horizontally
.main-container {
margin: 0 15px; // Reduce margin for better spacing
}
.zoon-wrapper {
bottom: 5px; // Adjust position for smaller screens
&.bottom {
bottom: 150px; // Adjust for bottom placement
}
}
}
@media (max-width: 768px) {
width: 90%; // Take even more width on very small screens
height: 400px; // Further reduce height
top: 45%; // Adjust vertical position slightly upward
.panel {
&.top-panel,
&.bottom-panel {
.panel-content {
flex-direction: column; // Stack panels vertically on small screens
.chart-container {
width: 100%; // Make charts full width
height: 150px; // Reduce chart height
}
}
}
}
}
@media (max-width: 480px) {
width: 95%; // Take almost full width on very small devices
height: 350px; // Further reduce height
top: 40%; // Move slightly higher for better visibility
.side-button-container {
flex-direction: row !important; // Force buttons into a row
gap: 4px; // Reduce spacing between buttons
&.top,
&.bottom {
left: 50%; // Center horizontally
transform: translateX(-50%);
}
}
}
.content-container {
display: flex;
height: 100vh;
transition: all 0.3s ease;
}
@media (max-width: 1024px) {
width: 80%; // Increase width to take more space on smaller screens
height: 500px; // Reduce height to fit smaller screens
left: 50%; // Center horizontally
.main-container {
position: relative;
flex: 1;
height: 600px;
background-color: rgb(235, 235, 235);
margin: 0 30px;
transition: height 0.3s ease, margin 0.3s ease;
.zoon-wrapper {
display: flex;
background-color: rgba(224, 223, 255, 0.5);
position: absolute;
bottom: 10px;
left: 50%;
transform: translate(-50%, 0);
gap: 6px;
padding: 4px;
border-radius: 8px;
max-width: 80%;
overflow: auto;
transition: transform 0.3s ease;
&::-webkit-scrollbar {
display: none;
}
.zone {
width: auto;
background-color: $background-color;
border-radius: 6px;
padding: 4px 8px;
white-space: nowrap;
cursor: pointer;
transition: background-color 0.3s ease;
&.active {
background-color: var(--primary-color);
color: var(--accent-color);
}
}
&.bottom {
bottom: 210px;
}
}
margin: 0 15px; // Reduce margin for better spacing
}
.zoon-wrapper {
bottom: 5px; // Adjust position for smaller screens
&.bottom {
bottom: 150px; // Adjust for bottom placement
}
}
}
@media (max-width: 768px) {
width: 90%; // Take even more width on very small screens
height: 400px; // Further reduce height
top: 45%; // Adjust vertical position slightly upward
.panel {
position: absolute;
background: white;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
transition: all 0.3s ease;
border-radius: 6px;
overflow: visible !important;
&.top-panel,
&.bottom-panel {
.panel-content {
position: relative;
height: 100%;
padding: 10px;
overflow: auto;
display: flex;
flex-direction: column;
gap: 10px;
flex-direction: column; // Stack panels vertically on small screens
&::-webkit-scrollbar {
display: none;
}
.chart-container {
width: 100%;
height: 200px;
max-height: 100%;
border: 1px dotted #a9a9a9;
border-radius: 8px;
box-shadow: 0px 2px 6px 0px rgba(60, 60, 67, 0.1);
padding: 6px 0;
background-color: white;
}
.close-btn {
position: absolute;
top: 5px;
right: 5px;
background: none;
border: none;
cursor: pointer;
color: var(--primary-color);
}
}
&.top-panel,
&.bottom-panel {
left: 0;
right: 0;
.panel-content {
display: flex;
flex-direction: row;
.chart-container {
height: 100%;
width: 230px;
}
}
}
&.top-panel {
top: 0;
}
&.bottom-panel {
bottom: 0;
}
&.left-panel {
left: 0;
top: 0;
bottom: 0;
.chart-container {
width: 100%;
height: 200px;
}
}
&.right-panel {
right: 0;
top: 0;
bottom: 0;
.chart-container {
width: 100%; // Make charts full width
height: 150px; // Reduce chart height
}
}
}
}
}
@media (max-width: 480px) {
width: 95%; // Take almost full width on very small devices
height: 350px; // Further reduce height
top: 40%; // Move slightly higher for better visibility
.side-button-container {
flex-direction: row !important; // Force buttons into a row
gap: 4px; // Reduce spacing between buttons
&.top,
&.bottom {
left: 50%; // Center horizontally
transform: translateX(-50%);
}
}
}
.content-container {
display: flex;
height: 100vh;
transition: all 0.3s ease;
}
.main-container {
position: relative;
flex: 1;
height: 600px;
background-color: rgb(235, 235, 235);
margin: 0 30px;
transition: height 0.3s ease, margin 0.3s ease;
.zoon-wrapper {
display: flex;
background-color: rgba(224, 223, 255, 0.5);
position: absolute;
bottom: 10px;
left: 50%;
transform: translate(-50%, 0);
gap: 6px;
padding: 4px;
border-radius: 8px;
max-width: 80%;
overflow: auto;
transition: transform 0.3s ease;
&::-webkit-scrollbar {
display: none;
}
.zone {
width: auto;
background-color: $background-color;
border-radius: 6px;
padding: 4px 8px;
white-space: nowrap;
cursor: pointer;
transition: background-color 0.3s ease;
&.active {
background-color: var(--primary-color);
color: var(--accent-color);
}
}
&.bottom {
bottom: 210px;
}
}
}
.panel {
position: absolute;
background: white;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
transition: all 0.3s ease;
border-radius: 6px;
overflow: visible !important;
.panel-content {
position: relative;
height: 100%;
padding: 10px;
overflow: auto;
display: flex;
flex-direction: column;
gap: 10px;
&::-webkit-scrollbar {
display: none;
}
.chart-container {
width: 100%;
height: 200px;
max-height: 100%;
border: 1px dotted #a9a9a9;
border-radius: 8px;
box-shadow: 0px 2px 6px 0px rgba(60, 60, 67, 0.1);
padding: 6px 0;
background-color: white;
}
.close-btn {
position: absolute;
top: 5px;
right: 5px;
background: none;
border: none;
cursor: pointer;
color: var(--primary-color);
}
}
&.top-panel,
&.bottom-panel {
left: 0;
right: 0;
.panel-content {
display: flex;
flex-direction: row;
.chart-container {
height: 100%;
width: 230px;
}
}
}
&.top-panel {
top: 0;
}
&.bottom-panel {
bottom: 0;
}
&.left-panel {
left: 0;
top: 0;
bottom: 0;
.chart-container {
width: 100%;
height: 200px;
}
}
&.right-panel {
right: 0;
top: 0;
bottom: 0;
}
}
}
// Side Buttons
.side-button-container {
position: absolute;
position: absolute;
display: flex;
background-color: $background-color;
padding: 5px;
border-radius: 8px;
transition: transform 0.3s ease;
.extra-Bs {
display: flex;
background-color: $background-color;
padding: 5px;
border-radius: 8px;
transition: transform 0.3s ease;
align-items: center;
gap: 12px;
.extra-Bs {
display: flex;
align-items: center;
gap: 12px;
.icon {
display: flex;
}
&:hover {
cursor: pointer;
}
.icon {
display: flex;
}
.side-button {
cursor: pointer;
transition: background-color 0.3s ease;
width: 18px;
height: 18px;
display: flex;
justify-content: center;
// align-items: center;
background-color: var(--accent-color);
border: none;
color: var(--background-color);
border-radius: 4px;
&:hover {
// background-color: var(--primary-color);
// color: var(--accent-color);
}
&:hover {
cursor: pointer;
}
}
&.top {
top: -30px;
left: 50%;
transform: translateX(-50%);
flex-direction: row;
gap: 6px;
}
.side-button {
cursor: pointer;
transition: background-color 0.3s ease;
width: 18px;
height: 18px;
display: flex;
justify-content: center;
// align-items: center;
background-color: var(--accent-color);
border: none;
color: var(--background-color);
border-radius: 4px;
}
&.right {
right: -30px;
top: 50%;
transform: translateY(-50%);
flex-direction: column;
gap: 6px;
}
&.top {
top: -30px;
left: 50%;
transform: translateX(-50%);
flex-direction: row;
gap: 6px;
}
&.bottom {
bottom: -30px;
left: 50%;
transform: translateX(-50%);
flex-direction: row;
gap: 6px;
}
&.right {
right: -30px;
top: 50%;
transform: translateY(-50%);
flex-direction: column;
gap: 6px;
}
&.left {
left: -30px;
top: 50%;
transform: translateY(-50%);
flex-direction: column;
gap: 6px;
}
&.bottom {
bottom: -30px;
left: 50%;
transform: translateX(-50%);
flex-direction: row;
gap: 6px;
}
&.left {
left: -30px;
top: 50%;
transform: translateY(-50%);
flex-direction: column;
gap: 6px;
}
}
.right.side-button-container {
.extra-Bs {
flex-direction: column;
}
.extra-Bs {
flex-direction: column;
}
}
.left.side-button-container {
.extra-Bs {
flex-direction: column;
}
.extra-Bs {
flex-direction: column;
}
}
// Theme Container
.theme-container {
width: 250px;
padding: 12px;
box-shadow: 1px -3px 4px 0px rgba(0, 0, 0, 0.11);
border-radius: 8px;
background-color: white;
position: absolute;
top: 20px;
right: -100%;
transform: translate(-0%, 0);
width: 250px;
padding: 12px;
box-shadow: 1px -3px 4px 0px rgba(0, 0, 0, 0.11);
border-radius: 8px;
background-color: white;
position: absolute;
top: 20px;
right: -100%;
transform: translate(-0%, 0);
h2 {
font-size: 12px;
margin-bottom: 8px;
color: #2B3344;
}
h2 {
font-size: 12px;
margin-bottom: 8px;
color: #2b3344;
}
.theme-preset-wrapper {
display: flex;
gap: 5px;
flex-wrap: wrap;
.theme-preset-wrapper {
display: flex;
gap: 5px;
flex-wrap: wrap;
.theme-preset {
display: flex;
gap: 2px;
margin-bottom: 10px;
border: 1px solid $border-color;
padding: 5px 10px;
border-radius: 4px;
transition: border 0.3s ease;
.theme-preset {
display: flex;
gap: 2px;
margin-bottom: 10px;
border: 1px solid $border-color;
padding: 5px 10px;
border-radius: 4px;
transition: border 0.3s ease;
&.active {
border: 1px solid var(--primary-color);
&.active {
border: 1px solid var(--primary-color);
&::after {
content: '';
position: absolute;
top: 1px;
left: 1px;
width: 10px;
height: 10px;
background-color: var(--primary-color);
border-radius: 50%;
}
}
&::after {
content: "";
position: absolute;
top: 1px;
left: 1px;
width: 10px;
height: 10px;
background-color: var(--primary-color);
border-radius: 50%;
}
}
}
}
.custom-color {
display: flex;
justify-content: space-between;
.custom-color {
display: flex;
justify-content: space-between;
.color-displayer {
display: flex;
gap: 5px;
align-items: center;
border: 1px solid var(--accent-color);
border-radius: 4px;
padding: 0 5px;
.color-displayer {
display: flex;
gap: 5px;
align-items: center;
border: 1px solid var(--accent-color);
border-radius: 4px;
padding: 0 5px;
input {
border: none;
outline: none;
border-radius: 50%;
}
}
input {
border: none;
outline: none;
border-radius: 50%;
}
}
}
}