feat: implement ElementEditor and BlockEditor components, and a visualization store for editor state management.
This commit is contained in:
@@ -1,14 +1,19 @@
|
||||
import { create } from "zustand";
|
||||
import { immer } from "zustand/middleware/immer";
|
||||
|
||||
/**
|
||||
* Panel position stored as percentages (0-100) of viewport dimensions
|
||||
* This ensures panels stay within bounds when screen size changes
|
||||
*/
|
||||
interface PanelPosition {
|
||||
x: number;
|
||||
y: number;
|
||||
xPercent: number; // 0-100, percentage from left edge
|
||||
yPercent: number; // 0-100, percentage from top edge
|
||||
}
|
||||
|
||||
interface VisualizationState {
|
||||
editorPosition: PanelPosition | null;
|
||||
setEditorPosition: (position: PanelPosition) => void;
|
||||
resetEditorPosition: () => void;
|
||||
}
|
||||
|
||||
export const useVisualizationStore = create<VisualizationState>()(
|
||||
@@ -18,5 +23,63 @@ export const useVisualizationStore = create<VisualizationState>()(
|
||||
set((state) => {
|
||||
state.editorPosition = position;
|
||||
}),
|
||||
resetEditorPosition: () =>
|
||||
set((state) => {
|
||||
state.editorPosition = null;
|
||||
}),
|
||||
}))
|
||||
);
|
||||
|
||||
/**
|
||||
* Utility functions to convert between pixels and percentages
|
||||
*/
|
||||
export const positionUtils = {
|
||||
/**
|
||||
* Convert pixel position to percentage position
|
||||
*/
|
||||
pixelsToPercent: (pixelX: number, pixelY: number, panelWidth: number, panelHeight: number): PanelPosition => {
|
||||
const viewportWidth = window.innerWidth;
|
||||
const viewportHeight = window.innerHeight;
|
||||
|
||||
// Calculate percentage, ensuring panel stays within bounds
|
||||
const maxXPercent = ((viewportWidth - panelWidth) / viewportWidth) * 100;
|
||||
const maxYPercent = ((viewportHeight - panelHeight) / viewportHeight) * 100;
|
||||
|
||||
const xPercent = Math.max(0, Math.min((pixelX / viewportWidth) * 100, maxXPercent));
|
||||
const yPercent = Math.max(0, Math.min((pixelY / viewportHeight) * 100, maxYPercent));
|
||||
|
||||
return { xPercent, yPercent };
|
||||
},
|
||||
|
||||
/**
|
||||
* Convert percentage position to pixel position
|
||||
*/
|
||||
percentToPixels: (position: PanelPosition, panelWidth: number, panelHeight: number): { x: number; y: number } => {
|
||||
const viewportWidth = window.innerWidth;
|
||||
const viewportHeight = window.innerHeight;
|
||||
|
||||
// Calculate pixel position
|
||||
let x = (position.xPercent / 100) * viewportWidth;
|
||||
let y = (position.yPercent / 100) * viewportHeight;
|
||||
|
||||
// Ensure panel stays within bounds
|
||||
const maxX = viewportWidth - panelWidth - 8;
|
||||
const maxY = viewportHeight - panelHeight - 8;
|
||||
|
||||
x = Math.max(0, Math.min(x, maxX));
|
||||
y = Math.max(0, Math.min(y, maxY));
|
||||
|
||||
return { x, y };
|
||||
},
|
||||
|
||||
/**
|
||||
* Get default position (top-right corner with some margin)
|
||||
*/
|
||||
getDefaultPosition: (panelWidth: number): PanelPosition => {
|
||||
const viewportWidth = window.innerWidth;
|
||||
const defaultX = Math.max(0, viewportWidth - panelWidth - 40);
|
||||
const defaultY = 80;
|
||||
|
||||
return positionUtils.pixelsToPercent(defaultX, defaultY, panelWidth, 300);
|
||||
},
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user