GridLines.tsx 1.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849
  1. import { useMemo } from 'react';
  2. import { useCanvasStore, useSceneSelector } from '@/lib/store';
  3. import type { SlideContent } from '@/lib/types/stage';
  4. import type { SlideBackground } from '@/lib/types/slides';
  5. export function GridLines() {
  6. const gridLineSize = useCanvasStore.use.gridLineSize();
  7. const viewportRatio = useCanvasStore.use.viewportRatio();
  8. const viewportSize = useCanvasStore.use.viewportSize();
  9. const background = useSceneSelector<SlideContent, SlideBackground | undefined>(
  10. (content) => content.canvas.background,
  11. );
  12. // Calculate grid line color to avoid blending with background
  13. const gridColor = useMemo(() => {
  14. const bgColor = background?.color || '#fff';
  15. // Simplified version: choose black or white based on background brightness
  16. const isLight = bgColor === '#fff' || bgColor.startsWith('#f') || bgColor.startsWith('#e');
  17. const baseColor = isLight ? '0, 0, 0' : '255, 255, 255';
  18. return `rgba(${baseColor}, 0.5)`;
  19. }, [background]);
  20. // Grid path
  21. const path = useMemo(() => {
  22. const maxX = viewportSize;
  23. const maxY = viewportSize * viewportRatio;
  24. let p = '';
  25. for (let i = 0; i <= Math.floor(maxY / gridLineSize); i++) {
  26. p += `M0 ${i * gridLineSize} L${maxX} ${i * gridLineSize} `;
  27. }
  28. for (let i = 0; i <= Math.floor(maxX / gridLineSize); i++) {
  29. p += `M${i * gridLineSize} 0 L${i * gridLineSize} ${maxY} `;
  30. }
  31. return p;
  32. }, [viewportSize, viewportRatio, gridLineSize]);
  33. return (
  34. <svg
  35. className="grid-lines absolute inset-0 pointer-events-none z-40"
  36. width={viewportSize}
  37. height={viewportSize * viewportRatio}
  38. viewBox={`0 0 ${viewportSize} ${viewportSize * viewportRatio}`}
  39. >
  40. <path d={path} fill="none" stroke={gridColor} strokeWidth="1" strokeDasharray="5 5" />
  41. </svg>
  42. );
  43. }