Separate zoom and pan from settings

This commit is contained in:
1ilit 2024-03-09 20:35:04 +02:00
parent 610e2fa5c5
commit f3eb6d7c04
4 changed files with 197 additions and 178 deletions

View File

@ -10,6 +10,7 @@ import {
TableContext, TableContext,
UndoRedoContext, UndoRedoContext,
SelectContext, SelectContext,
TransformContext,
} from "../pages/Editor"; } from "../pages/Editor";
import Note from "./Note"; import Note from "./Note";
import { Toast } from "@douyinfe/semi-ui"; import { Toast } from "@douyinfe/semi-ui";
@ -19,8 +20,9 @@ export default function Canvas() {
useContext(TableContext); useContext(TableContext);
const { areas, updateArea } = useContext(AreaContext); const { areas, updateArea } = useContext(AreaContext);
const { notes, updateNote } = useContext(NoteContext); const { notes, updateNote } = useContext(NoteContext);
const { settings, setSettings } = useContext(SettingsContext); const { settings } = useContext(SettingsContext);
const { setUndoStack, setRedoStack } = useContext(UndoRedoContext); const { setUndoStack, setRedoStack } = useContext(UndoRedoContext);
const { transform, setTransform } = useContext(TransformContext);
const { selectedElement, setSelectedElement } = useContext(SelectContext); const { selectedElement, setSelectedElement } = useContext(SelectContext);
const [dragging, setDragging] = useState({ const [dragging, setDragging] = useState({
element: ObjectType.NONE, element: ObjectType.NONE,
@ -69,8 +71,8 @@ export default function Canvas() {
if (type === ObjectType.TABLE) { if (type === ObjectType.TABLE) {
const table = tables.find((t) => t.id === id); const table = tables.find((t) => t.id === id);
setOffset({ setOffset({
x: clientX / settings.zoom - table.x, x: clientX / transform.zoom - table.x,
y: clientY / settings.zoom - table.y, y: clientY / transform.zoom - table.y,
}); });
setDragging({ setDragging({
element: ObjectType.TABLE, element: ObjectType.TABLE,
@ -81,8 +83,8 @@ export default function Canvas() {
} else if (type === ObjectType.AREA) { } else if (type === ObjectType.AREA) {
const area = areas.find((t) => t.id === id); const area = areas.find((t) => t.id === id);
setOffset({ setOffset({
x: clientX / settings.zoom - area.x, x: clientX / transform.zoom - area.x,
y: clientY / settings.zoom - area.y, y: clientY / transform.zoom - area.y,
}); });
setDragging({ setDragging({
element: ObjectType.AREA, element: ObjectType.AREA,
@ -93,8 +95,8 @@ export default function Canvas() {
} else if (type === ObjectType.NOTE) { } else if (type === ObjectType.NOTE) {
const note = notes.find((t) => t.id === id); const note = notes.find((t) => t.id === id);
setOffset({ setOffset({
x: clientX / settings.zoom - note.x, x: clientX / transform.zoom - note.x,
y: clientY / settings.zoom - note.y, y: clientY / transform.zoom - note.y,
}); });
setDragging({ setDragging({
element: ObjectType.NOTE, element: ObjectType.NOTE,
@ -119,8 +121,8 @@ export default function Canvas() {
setLine({ setLine({
...line, ...line,
endX: (e.clientX - offsetX - settings.pan?.x) / settings.zoom, endX: (e.clientX - offsetX - transform.pan?.x) / transform.zoom,
endY: (e.clientY - offsetY - settings.pan?.y) / settings.zoom, endY: (e.clientY - offsetY - transform.pan?.y) / transform.zoom,
}); });
} else if ( } else if (
panning.state && panning.state &&
@ -132,26 +134,26 @@ export default function Canvas() {
} }
const dx = e.clientX - panOffset.x; const dx = e.clientX - panOffset.x;
const dy = e.clientY - panOffset.y; const dy = e.clientY - panOffset.y;
setSettings((prev) => ({ setTransform((prev) => ({
...prev, ...prev,
pan: { x: prev.pan?.x + dx, y: prev.pan?.y + dy }, pan: { x: prev.pan?.x + dx, y: prev.pan?.y + dy },
})); }));
setPanOffset({ x: e.clientX, y: e.clientY }); setPanOffset({ x: e.clientX, y: e.clientY });
} else if (dragging.element === ObjectType.TABLE && dragging.id >= 0) { } else if (dragging.element === ObjectType.TABLE && dragging.id >= 0) {
const dx = e.clientX / settings.zoom - offset.x; const dx = e.clientX / transform.zoom - offset.x;
const dy = e.clientY / settings.zoom - offset.y; const dy = e.clientY / transform.zoom - offset.y;
updateTable(dragging.id, { x: dx, y: dy }, true); updateTable(dragging.id, { x: dx, y: dy }, true);
} else if ( } else if (
dragging.element === ObjectType.AREA && dragging.element === ObjectType.AREA &&
dragging.id >= 0 && dragging.id >= 0 &&
areaResize.id === -1 areaResize.id === -1
) { ) {
const dx = e.clientX / settings.zoom - offset.x; const dx = e.clientX / transform.zoom - offset.x;
const dy = e.clientY / settings.zoom - offset.y; const dy = e.clientY / transform.zoom - offset.y;
updateArea(dragging.id, { x: dx, y: dy }); updateArea(dragging.id, { x: dx, y: dy });
} else if (dragging.element === ObjectType.NOTE && dragging.id >= 0) { } else if (dragging.element === ObjectType.NOTE && dragging.id >= 0) {
const dx = e.clientX / settings.zoom - offset.x; const dx = e.clientX / transform.zoom - offset.x;
const dy = e.clientY / settings.zoom - offset.y; const dy = e.clientY / transform.zoom - offset.y;
updateNote(dragging.id, { x: dx, y: dy }); updateNote(dragging.id, { x: dx, y: dy });
} else if (areaResize.id !== -1) { } else if (areaResize.id !== -1) {
if (areaResize.dir === "none") return; if (areaResize.dir === "none") return;
@ -160,8 +162,8 @@ export default function Canvas() {
let newY = initCoords.y; let newY = initCoords.y;
let newWidth = initCoords.width; let newWidth = initCoords.width;
let newHeight = initCoords.height; let newHeight = initCoords.height;
const mouseX = e.clientX / settings.zoom; const mouseX = e.clientX / transform.zoom;
const mouseY = e.clientY / settings.zoom; const mouseY = e.clientY / transform.zoom;
setPanning({ state: false, x: 0, y: 0 }); setPanning({ state: false, x: 0, y: 0 });
if (areaResize.dir === "br") { if (areaResize.dir === "br") {
newWidth = initCoords.width + (mouseX - initCoords.mouseX); newWidth = initCoords.width + (mouseX - initCoords.mouseX);
@ -191,7 +193,7 @@ export default function Canvas() {
}; };
const handleMouseDown = (e) => { const handleMouseDown = (e) => {
setPanning({ state: true, ...settings.pan }); setPanning({ state: true, ...transform.pan });
setPanOffset({ x: e.clientX, y: e.clientY }); setPanOffset({ x: e.clientX, y: e.clientY });
setCursor("grabbing"); setCursor("grabbing");
}; };
@ -228,7 +230,7 @@ export default function Canvas() {
}; };
const didPan = () => const didPan = () =>
!(settings.pan?.x === panning.x && settings.pan?.y === panning.y); !(transform.pan?.x === panning.x && transform.pan?.y === panning.y);
const getMoveInfo = () => { const getMoveInfo = () => {
switch (dragging.element) { switch (dragging.element) {
@ -280,8 +282,8 @@ export default function Canvas() {
{ {
action: Action.PAN, action: Action.PAN,
undo: { x: panning.x, y: panning.y }, undo: { x: panning.x, y: panning.y },
redo: settings.pan, redo: transform.pan,
message: `Move diagram to (${settings.pan?.x}, ${settings.pan?.y})`, message: `Move diagram to (${transform.pan?.x}, ${transform.pan?.y})`,
}, },
]); ]);
setRedoStack([]); setRedoStack([]);
@ -359,7 +361,7 @@ export default function Canvas() {
const handleMouseWheel = (e) => { const handleMouseWheel = (e) => {
e.preventDefault(); e.preventDefault();
setSettings((prev) => ({ setTransform((prev) => ({
...prev, ...prev,
zoom: e.deltaY <= 0 ? prev.zoom * 1.05 : prev.zoom / 1.05, zoom: e.deltaY <= 0 ? prev.zoom * 1.05 : prev.zoom / 1.05,
})); }));
@ -422,7 +424,7 @@ export default function Canvas() {
)} )}
<g <g
style={{ style={{
transform: `translate(${settings.pan?.x}px, ${settings.pan?.y}px) scale(${settings.zoom})`, transform: `translate(${transform.pan?.x}px, ${transform.pan?.y}px) scale(${transform.zoom})`,
transformOrigin: "top left", transformOrigin: "top left",
}} }}
id="diagram" id="diagram"
@ -437,7 +439,7 @@ export default function Canvas() {
setResize={setAreaResize} setResize={setAreaResize}
initCoords={initCoords} initCoords={initCoords}
setInitCoords={setInitCoords} setInitCoords={setInitCoords}
zoom={settings.zoom} zoom={transform.zoom}
></Area> ></Area>
))} ))}
{relationships.map((e, i) => ( {relationships.map((e, i) => (

View File

@ -51,6 +51,7 @@ import {
import { import {
AreaContext, AreaContext,
NoteContext, NoteContext,
TransformContext,
SelectContext, SelectContext,
SettingsContext, SettingsContext,
StateContext, StateContext,
@ -122,7 +123,7 @@ export default function ControlPanel({
}); });
const [data, setData] = useState(null); const [data, setData] = useState(null);
const { state, setState } = useContext(StateContext); const { state, setState } = useContext(StateContext);
const {layout, setLayout} = useLayout(); const { layout, setLayout } = useLayout();
const { settings, setSettings } = useContext(SettingsContext); const { settings, setSettings } = useContext(SettingsContext);
const { const {
relationships, relationships,
@ -146,6 +147,7 @@ export default function ControlPanel({
useContext(UndoRedoContext); useContext(UndoRedoContext);
const { selectedElement, setSelectedElement } = useContext(SelectContext); const { selectedElement, setSelectedElement } = useContext(SelectContext);
const { tab, setTab } = useContext(TabContext); const { tab, setTab } = useContext(TabContext);
const { transform, setTransform } = useContext(TransformContext);
const invertLayout = (component) => const invertLayout = (component) =>
setLayout((prev) => ({ ...prev, [component]: !prev[component] })); setLayout((prev) => ({ ...prev, [component]: !prev[component] }));
@ -334,7 +336,7 @@ export default function ControlPanel({
} }
setRedoStack((prev) => [...prev, a]); setRedoStack((prev) => [...prev, a]);
} else if (a.action === Action.PAN) { } else if (a.action === Action.PAN) {
setSettings((prev) => ({ setTransform((prev) => ({
...prev, ...prev,
pan: a.undo, pan: a.undo,
})); }));
@ -515,7 +517,7 @@ export default function ControlPanel({
} }
setUndoStack((prev) => [...prev, a]); setUndoStack((prev) => [...prev, a]);
} else if (a.action === Action.PAN) { } else if (a.action === Action.PAN) {
setSettings((prev) => ({ setTransform((prev) => ({
...prev, ...prev,
pan: a.redo, pan: a.redo,
})); }));
@ -527,9 +529,9 @@ export default function ControlPanel({
const viewGrid = () => const viewGrid = () =>
setSettings((prev) => ({ ...prev, showGrid: !prev.showGrid })); setSettings((prev) => ({ ...prev, showGrid: !prev.showGrid }));
const zoomIn = () => const zoomIn = () =>
setSettings((prev) => ({ ...prev, zoom: prev.zoom * 1.2 })); setTransform((prev) => ({ ...prev, zoom: prev.zoom * 1.2 }));
const zoomOut = () => const zoomOut = () =>
setSettings((prev) => ({ ...prev, zoom: prev.zoom / 1.2 })); setTransform((prev) => ({ ...prev, zoom: prev.zoom / 1.2 }));
const viewStrictMode = () => { const viewStrictMode = () => {
setSettings((prev) => ({ ...prev, strictMode: !prev.strictMode })); setSettings((prev) => ({ ...prev, strictMode: !prev.strictMode }));
Toast.success(`Stict mode is ${settings.strictMode ? "on" : "off"}.`); Toast.success(`Stict mode is ${settings.strictMode ? "on" : "off"}.`);
@ -557,7 +559,7 @@ export default function ControlPanel({
}); });
}; };
const resetView = () => const resetView = () =>
setSettings((prev) => ({ ...prev, zoom: 1, pan: { x: 0, y: 0 } })); setTransform((prev) => ({ ...prev, zoom: 1, pan: { x: 0, y: 0 } }));
const fitWindow = () => { const fitWindow = () => {
const diagram = document.getElementById("diagram").getBoundingClientRect(); const diagram = document.getElementById("diagram").getBoundingClientRect();
const canvas = document.getElementById("canvas").getBoundingClientRect(); const canvas = document.getElementById("canvas").getBoundingClientRect();
@ -572,7 +574,7 @@ export default function ControlPanel({
const translateX = canvas.left; const translateX = canvas.left;
const translateY = canvas.top; const translateY = canvas.top;
setSettings((prev) => ({ setTransform((prev) => ({
...prev, ...prev,
zoom: scale - 0.01, zoom: scale - 0.01,
pan: { x: translateX, y: translateY }, pan: { x: translateX, y: translateY },
@ -756,6 +758,10 @@ export default function ControlPanel({
setRelationships(diagram.references); setRelationships(diagram.references);
setAreas(diagram.areas); setAreas(diagram.areas);
setNotes(diagram.notes); setNotes(diagram.notes);
setTransform({
pan: diagram.pan,
zoom: diagram.zoom,
});
setUndoStack([]); setUndoStack([]);
setRedoStack([]); setRedoStack([]);
window.name = `d ${diagram.id}`; window.name = `d ${diagram.id}`;
@ -1609,7 +1615,7 @@ export default function ControlPanel({
} }
case MODAL.IMPORT: case MODAL.IMPORT:
if (error.type !== STATUS.ERROR) { if (error.type !== STATUS.ERROR) {
setSettings((prev) => ({ ...prev, pan: { x: 0, y: 0 } })); setTransform((prev) => ({ ...prev, pan: { x: 0, y: 0 } }));
overwriteDiagram(); overwriteDiagram();
setData(null); setData(null);
setVisible(MODAL.NONE); setVisible(MODAL.NONE);
@ -2125,7 +2131,7 @@ export default function ControlPanel({
<Dropdown.Item <Dropdown.Item
key={i} key={i}
onClick={() => { onClick={() => {
setSettings((prev) => ({ ...prev, zoom: e })); setTransform((prev) => ({ ...prev, zoom: e }));
}} }}
> >
{Math.floor(e * 100)}% {Math.floor(e * 100)}%
@ -2139,7 +2145,7 @@ export default function ControlPanel({
placeholder="Zoom" placeholder="Zoom"
suffix={<div className="p-1">%</div>} suffix={<div className="p-1">%</div>}
onChange={(v) => onChange={(v) =>
setSettings((prev) => ({ setTransform((prev) => ({
...prev, ...prev,
zoom: parseFloat(v) * 0.01, zoom: parseFloat(v) * 0.01,
})) }))
@ -2151,7 +2157,9 @@ export default function ControlPanel({
trigger="click" trigger="click"
> >
<div className="py-1 px-2 hover-2 rounded flex items-center justify-center"> <div className="py-1 px-2 hover-2 rounded flex items-center justify-center">
<div className="w-[40px]">{Math.floor(settings.zoom * 100)}%</div> <div className="w-[40px]">
{Math.floor(transform.zoom * 100)}%
</div>
<div> <div>
<IconCaretdown /> <IconCaretdown />
</div> </div>
@ -2161,7 +2169,7 @@ export default function ControlPanel({
<button <button
className="py-1 px-2 hover-2 rounded text-lg" className="py-1 px-2 hover-2 rounded text-lg"
onClick={() => onClick={() =>
setSettings((prev) => ({ ...prev, zoom: prev.zoom * 1.2 })) setTransform((prev) => ({ ...prev, zoom: prev.zoom * 1.2 }))
} }
> >
<i className="fa-solid fa-magnifying-glass-plus"></i> <i className="fa-solid fa-magnifying-glass-plus"></i>
@ -2171,7 +2179,7 @@ export default function ControlPanel({
<button <button
className="py-1 px-2 hover-2 rounded text-lg" className="py-1 px-2 hover-2 rounded text-lg"
onClick={() => onClick={() =>
setSettings((prev) => ({ ...prev, zoom: prev.zoom / 1.2 })) setTransform((prev) => ({ ...prev, zoom: prev.zoom / 1.2 }))
} }
> >
<i className="fa-solid fa-magnifying-glass-minus"></i> <i className="fa-solid fa-magnifying-glass-minus"></i>

View File

@ -1,6 +1,6 @@
import { createContext, useState } from "react"; import { createContext, useState } from "react";
export const LayoutContext = createContext(); export const LayoutContext = createContext(null);
export default function LayoutContextProvider({ children }) { export default function LayoutContextProvider({ children }) {
const [layout, setLayout] = useState({ const [layout, setLayout] = useState({

View File

@ -28,6 +28,7 @@ export const TaskContext = createContext();
export const MessageContext = createContext(); export const MessageContext = createContext();
export const BotMessageContext = createContext(); export const BotMessageContext = createContext();
export const TypeContext = createContext(); export const TypeContext = createContext();
export const TransformContext = createContext();
export default function Editor() { export default function Editor() {
return ( return (
@ -54,14 +55,16 @@ function WorkSpace() {
const [settings, setSettings] = useState({ const [settings, setSettings] = useState({
strictMode: false, strictMode: false,
showFieldSummary: true, showFieldSummary: true,
zoom: 1,
pan: { x: 0, y: 0 },
showGrid: true, showGrid: true,
mode: "light", mode: "light",
autosave: true, autosave: true,
panning: true, panning: true,
showCardinality: true, showCardinality: true,
}); });
const [transform, setTransform] = useState({
zoom: 1,
pan: { x: 0, y: 0 },
});
const [tasks, setTasks] = useState([]); const [tasks, setTasks] = useState([]);
const [undoStack, setUndoStack] = useState([]); const [undoStack, setUndoStack] = useState([]);
const [redoStack, setRedoStack] = useState([]); const [redoStack, setRedoStack] = useState([]);
@ -485,7 +488,7 @@ function WorkSpace() {
types?.length, types?.length,
relationships?.length, relationships?.length,
tasks?.length, tasks?.length,
settings.zoom, transform.zoom,
title, title,
]); ]);
@ -509,8 +512,8 @@ function WorkSpace() {
notes: notes, notes: notes,
areas: areas, areas: areas,
todos: tasks, todos: tasks,
pan: settings.pan, pan: transform.pan,
zoom: settings.zoom, zoom: transform.zoom,
}) })
.then((id) => { .then((id) => {
setId(id); setId(id);
@ -529,8 +532,8 @@ function WorkSpace() {
notes: notes, notes: notes,
areas: areas, areas: areas,
todos: tasks, todos: tasks,
pan: settings.pan, pan: transform.pan,
zoom: settings.zoom, zoom: transform.zoom,
}) })
.then(() => { .then(() => {
setState(State.SAVED); setState(State.SAVED);
@ -547,8 +550,8 @@ function WorkSpace() {
notes: notes, notes: notes,
subjectAreas: areas, subjectAreas: areas,
todos: tasks, todos: tasks,
pan: settings.pan, pan: transform.pan,
zoom: settings.zoom, zoom: transform.zoom,
}) })
.then(() => { .then(() => {
setState(State.SAVED); setState(State.SAVED);
@ -569,8 +572,8 @@ function WorkSpace() {
id, id,
state, state,
tasks, tasks,
settings.zoom, transform.zoom,
settings.pan, transform.pan,
] ]
); );
useEffect(() => { useEffect(() => {
@ -597,7 +600,7 @@ function WorkSpace() {
setAreas(d.areas); setAreas(d.areas);
setTypes(d.types); setTypes(d.types);
setTasks(d.todos); setTasks(d.todos);
setSettings((prev) => ({ ...prev, pan: d.pan, zoom: d.zoom })); setTransform({ pan: d.pan, zoom: d.zoom });
window.name = `d ${d.id}`; window.name = `d ${d.id}`;
} else { } else {
window.name = ""; window.name = "";
@ -621,11 +624,10 @@ function WorkSpace() {
setAreas(diagram.areas); setAreas(diagram.areas);
setNotes(diagram.notes); setNotes(diagram.notes);
setTasks(diagram.todos); setTasks(diagram.todos);
setSettings((prev) => ({ setTransform({
...prev,
pan: diagram.pan, pan: diagram.pan,
zoom: diagram.zoom, zoom: diagram.zoom,
})); });
setUndoStack([]); setUndoStack([]);
setRedoStack([]); setRedoStack([]);
window.name = `d ${diagram.id}`; window.name = `d ${diagram.id}`;
@ -651,11 +653,10 @@ function WorkSpace() {
setAreas(diagram.subjectAreas); setAreas(diagram.subjectAreas);
setTasks(diagram.tasks); setTasks(diagram.tasks);
setNotes(diagram.notes); setNotes(diagram.notes);
setSettings((prev) => ({ setTransform({
...prev,
pan: { x: 0, y: 0 },
zoom: 1, zoom: 1,
})); pan: { x: 0, y: 0 },
});
setUndoStack([]); setUndoStack([]);
setRedoStack([]); setRedoStack([]);
} }
@ -708,134 +709,142 @@ function WorkSpace() {
return ( return (
<StateContext.Provider value={{ state, setState }}> <StateContext.Provider value={{ state, setState }}>
<TableContext.Provider <TransformContext.Provider value={{ transform, setTransform }}>
value={{ <TableContext.Provider
tables, value={{
setTables, tables,
addTable, setTables,
updateTable, addTable,
updateField, updateTable,
deleteTable, updateField,
relationships, deleteTable,
setRelationships, relationships,
addRelationship, setRelationships,
deleteRelationship, addRelationship,
}} deleteRelationship,
> }}
<AreaContext.Provider
value={{ areas, setAreas, updateArea, addArea, deleteArea }}
> >
<NoteContext.Provider <AreaContext.Provider
value={{ notes, setNotes, updateNote, addNote, deleteNote }} value={{ areas, setAreas, updateArea, addArea, deleteArea }}
> >
<TabContext.Provider value={{ tab, setTab }}> <NoteContext.Provider
<SettingsContext.Provider value={{ settings, setSettings }}> value={{ notes, setNotes, updateNote, addNote, deleteNote }}
<UndoRedoContext.Provider >
value={{ undoStack, redoStack, setUndoStack, setRedoStack }} <TabContext.Provider value={{ tab, setTab }}>
> <SettingsContext.Provider value={{ settings, setSettings }}>
<SelectContext.Provider <UndoRedoContext.Provider
value={{ selectedElement, setSelectedElement }} value={{ undoStack, redoStack, setUndoStack, setRedoStack }}
> >
<TaskContext.Provider <SelectContext.Provider
value={{ tasks, setTasks, updateTask }} value={{ selectedElement, setSelectedElement }}
> >
<TypeContext.Provider <TaskContext.Provider
value={{ value={{ tasks, setTasks, updateTask }}
types,
setTypes,
addType,
updateType,
deleteType,
}}
> >
<div className="h-[100vh] flex flex-col overflow-hidden theme"> <TypeContext.Provider
<ControlPanel value={{
diagramId={id} types,
setDiagramId={setId} setTypes,
title={title} addType,
setTitle={setTitle} updateType,
lastSaved={lastSaved} deleteType,
setLastSaved={setLastSaved} }}
/> >
<div <div className="h-[100vh] flex flex-col overflow-hidden theme">
className="flex h-full overflow-y-auto" <ControlPanel
onMouseUp={() => setResize(false)} diagramId={id}
onMouseMove={dragHandler} setDiagramId={setId}
> title={title}
{layout.sidebar && ( setTitle={setTitle}
<SidePanel lastSaved={lastSaved}
resize={resize} setLastSaved={setLastSaved}
setResize={setResize} />
width={width} <div
/> className="flex h-full overflow-y-auto"
)} onMouseUp={() => setResize(false)}
<div className="relative w-full h-full overflow-hidden"> onMouseMove={dragHandler}
<Canvas state={state} setState={setState} /> >
{!( {layout.sidebar && (
layout.sidebar || <SidePanel
layout.toolbar || resize={resize}
layout.header setResize={setResize}
) && ( width={width}
<div className="fixed right-5 bottom-4 flex gap-2"> />
<div className="popover-theme flex rounded-lg items-center">
<button
className="px-3 py-2"
onClick={() =>
setSettings((prev) => ({
...prev,
zoom: prev.zoom / 1.2,
}))
}
>
<i className="bi bi-dash-lg"></i>
</button>
<Divider align="center" layout="vertical" />
<div className="px-3 py-2">
{parseInt(settings.zoom * 100)}%
</div>
<Divider align="center" layout="vertical" />
<button
className="px-3 py-2"
onClick={() =>
setSettings((prev) => ({
...prev,
zoom: prev.zoom * 1.2,
}))
}
>
<i className="bi bi-plus-lg"></i>
</button>
</div>
<Tooltip content="Exit">
<button
className="px-3 py-2 rounded-lg popover-theme"
onClick={() => {
setLayout((prev) => ({
...prev,
sidebar: true,
toolbar: true,
header: true,
}));
exitFullscreen();
}}
>
<i className="bi bi-fullscreen-exit"></i>
</button>
</Tooltip>
</div>
)} )}
<div className="relative w-full h-full overflow-hidden">
<Canvas state={state} setState={setState} />
{!(
layout.sidebar ||
layout.toolbar ||
layout.header
) && (
<div className="fixed right-5 bottom-4 flex gap-2">
<div className="popover-theme flex rounded-lg items-center">
<button
className="px-3 py-2"
onClick={() =>
setTransform((prev) => ({
...prev,
zoom: prev.zoom / 1.2,
}))
}
>
<i className="bi bi-dash-lg"></i>
</button>
<Divider
align="center"
layout="vertical"
/>
<div className="px-3 py-2">
{parseInt(transform.zoom * 100)}%
</div>
<Divider
align="center"
layout="vertical"
/>
<button
className="px-3 py-2"
onClick={() =>
setTransform((prev) => ({
...prev,
zoom: prev.zoom * 1.2,
}))
}
>
<i className="bi bi-plus-lg"></i>
</button>
</div>
<Tooltip content="Exit">
<button
className="px-3 py-2 rounded-lg popover-theme"
onClick={() => {
setLayout((prev) => ({
...prev,
sidebar: true,
toolbar: true,
header: true,
}));
exitFullscreen();
}}
>
<i className="bi bi-fullscreen-exit"></i>
</button>
</Tooltip>
</div>
)}
</div>
</div> </div>
</div> </div>
</div> </TypeContext.Provider>
</TypeContext.Provider> </TaskContext.Provider>
</TaskContext.Provider> </SelectContext.Provider>
</SelectContext.Provider> </UndoRedoContext.Provider>
</UndoRedoContext.Provider> </SettingsContext.Provider>
</SettingsContext.Provider> </TabContext.Provider>
</TabContext.Provider> </NoteContext.Provider>
</NoteContext.Provider> </AreaContext.Provider>
</AreaContext.Provider> </TableContext.Provider>
</TableContext.Provider> </TransformContext.Provider>
</StateContext.Provider> </StateContext.Provider>
); );
} }