import { useLayoutEffect, useRef, useState, type ReactNode } from 'react'
import { useSkin } from '../skin'
/**
* The thing the game is happening inside.
*
* Both skins get a frame, and the frames are not the same object: 1973 is a
* Teletype, so it is a sheet of fanfold paper coming out of a machine, with
* the sprocket holes down both edges and a platen at the top. The remaster is
* a cave, so it is a lit chamber with rock around it. Everything inside is
* laid out identically -- only the box changes.
*/
export function Frame({ children, footer }: { children: ReactNode; footer?: ReactNode }) {
const { skin } = useSkin()
return (
{skin === 'teletype' && }
{children}
{skin === 'teletype' ? (
<>
>
) : (
<>
>
)}
{footer}
)
}
/**
* A sheet of paper does not scroll and a cave mouth does not either. If the
* page comes out taller than the frame, shrink it rather than clipping it.
* Lifted from the lemonade stand, where the argument was about televisions.
*/
export function Fit({ children }: { children: ReactNode }) {
const box = useRef(null)
const [scale, setScale] = useState(1)
useLayoutEffect(() => {
const measure = () => {
const el = box.current
const page = el?.firstElementChild as HTMLElement | null
if (!el || !page) return
// offsetHeight is the laid-out size and ignores the transform, so
// measuring here cannot feed back into itself.
const h = page.offsetHeight
const avail = el.clientHeight
setScale(h > 0 && avail > 0 ? Math.min(1, avail / h) : 1)
}
measure()
const ro = new ResizeObserver(measure)
if (box.current) ro.observe(box.current)
if (box.current?.firstElementChild) ro.observe(box.current.firstElementChild)
return () => ro.disconnect()
})
return (