visualization functions seperated
This commit is contained in:
BIN
app/src/assets/orgTemp.png
Normal file
BIN
app/src/assets/orgTemp.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 25 KiB |
@@ -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>
|
||||
);
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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"} />
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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,
|
||||
|
||||
2
app/src/functions/generateUniqueId.ts
Normal file
2
app/src/functions/generateUniqueId.ts
Normal 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
0
app/src/hooks/temp.md
Normal file
0
app/src/modules/builder/temp.md
Normal file
0
app/src/modules/builder/temp.md
Normal file
0
app/src/modules/simulation/temp.md
Normal file
0
app/src/modules/simulation/temp.md
Normal file
55
app/src/modules/visualization/captureVisualization.ts
Normal file
55
app/src/modules/visualization/captureVisualization.ts
Normal 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");
|
||||
};
|
||||
36
app/src/modules/visualization/handleSaveTemplate.ts
Normal file
36
app/src/modules/visualization/handleSaveTemplate.ts
Normal 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);
|
||||
}
|
||||
};
|
||||
@@ -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
0
app/src/services/temp.md
Normal 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 {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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%;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user