import { useLayoutEffect, useRef, useState } from 'react'; /** * Zooms the desktop board to fill the whole window. The board is a canvas of * fixed height (`designHeight`) whose width is computed to span the viewport, * and the scale is driven by height — so everything (cards, circles, text, * header) grows and shrinks together while the felt always uses the full width. * * Returns the container ref (the viewport), the `scale` for `transform`, and * `contentWidth` — the pre-scale canvas width (`viewportWidth / scale`) so that * after scaling it exactly fills the viewport width. * * `deps` should change when the layout swaps (mobile↔desktop) so the observer * re-attaches to the freshly rendered element. */ export function useFitScale(deps: unknown[] = [], designHeight = 860, maxScale = 2.6) { const containerRef = useRef(null); const [box, setBox] = useState({ scale: 1, contentWidth: 1280 }); useLayoutEffect(() => { const el = containerRef.current; if (!el) return; const measure = () => { const availW = el.clientWidth; const availH = el.clientHeight; if (!availW || !availH) return; const scale = Math.min(maxScale, availH / designHeight); const contentWidth = availW / scale; setBox((prev) => Math.abs(prev.scale - scale) > 0.004 || Math.abs(prev.contentWidth - contentWidth) > 1 ? { scale, contentWidth } : prev, ); }; measure(); const ro = new ResizeObserver(measure); ro.observe(el); return () => ro.disconnect(); // eslint-disable-next-line react-hooks/exhaustive-deps }, deps); return { containerRef, scale: box.scale, contentWidth: box.contentWidth }; }