50 lines
1.8 KiB
TypeScript
50 lines
1.8 KiB
TypeScript
import { useMemo } from 'react';
|
|
import { useCanvasStore, useSceneSelector } from '@/lib/store';
|
|
import type { SlideContent } from '@/lib/types/stage';
|
|
import type { SlideBackground } from '@openmaic/dsl';
|
|
|
|
export function GridLines() {
|
|
const gridLineSize = useCanvasStore.use.gridLineSize();
|
|
const viewportRatio = useCanvasStore.use.viewportRatio();
|
|
const viewportSize = useCanvasStore.use.viewportSize();
|
|
|
|
const background = useSceneSelector<SlideContent, SlideBackground | undefined>(
|
|
(content) => content.canvas.background,
|
|
);
|
|
|
|
// Calculate grid line color to avoid blending with background
|
|
const gridColor = useMemo(() => {
|
|
const bgColor = background?.color || '#fff';
|
|
// Simplified version: choose black or white based on background brightness
|
|
const isLight = bgColor === '#fff' || bgColor.startsWith('#f') || bgColor.startsWith('#e');
|
|
const baseColor = isLight ? '0, 0, 0' : '255, 255, 255';
|
|
return `rgba(${baseColor}, 0.5)`;
|
|
}, [background]);
|
|
|
|
// Grid path
|
|
const path = useMemo(() => {
|
|
const maxX = viewportSize;
|
|
const maxY = viewportSize * viewportRatio;
|
|
|
|
let p = '';
|
|
for (let i = 0; i <= Math.floor(maxY / gridLineSize); i++) {
|
|
p += `M0 ${i * gridLineSize} L${maxX} ${i * gridLineSize} `;
|
|
}
|
|
for (let i = 0; i <= Math.floor(maxX / gridLineSize); i++) {
|
|
p += `M${i * gridLineSize} 0 L${i * gridLineSize} ${maxY} `;
|
|
}
|
|
return p;
|
|
}, [viewportSize, viewportRatio, gridLineSize]);
|
|
|
|
return (
|
|
<svg
|
|
className="grid-lines absolute inset-0 pointer-events-none z-40"
|
|
width={viewportSize}
|
|
height={viewportSize * viewportRatio}
|
|
viewBox={`0 0 ${viewportSize} ${viewportSize * viewportRatio}`}
|
|
>
|
|
<path d={path} fill="none" stroke={gridColor} strokeWidth="1" strokeDasharray="5 5" />
|
|
</svg>
|
|
);
|
|
}
|