import { motion, useReducedMotion } from 'framer-motion' import { useLayoutEffect, useRef } from 'react' import { useLocation } from 'react-router-dom' import nikumaru from '@/assets/fonts/nikumaru.otf' import { formatUIString } from '@/components/LocalisedText' import PrefetchLink from '@/components/PrefetchLink' import MainArea from '@/components/layout/MainArea' import { Button } from '@/components/ui/button' import PageHead from '@/components/common/PageHead' import { switchLocalePath } from '@/lib/locales' import { useClientBehaviourSettings } from '@/lib/useClientBehaviourSettings' import { useLocaleNavigate } from '@/lib/useLocale' import { useUITranslation } from '@/lib/useUITranslation' const GekanatorUnavailablePage = () => { const location = useLocation () const navigate = useLocaleNavigate () const behaviourSettings = useClientBehaviourSettings () const prefersReducedMotion = useReducedMotion () const shakeMascot = (behaviourSettings.animation ?? 'normal') === 'normal' && !prefersReducedMotion const { message, label } = useUITranslation ('gekanator') const title = message ('unavailable.title') const imageAlt = message ('unavailable.imageAlt') const headingRef = useRef (null) useLayoutEffect (() => { const heading = headingRef.current const context = document.createElement ('canvas').getContext ('2d') if (heading == null || context == null) return const fitTitle = () => { heading.style.fontSize = '' heading.style.maxWidth = '' const style = window.getComputedStyle (heading) const minimum = Number.parseFloat (style.fontSize) context.font = `${style.fontWeight} ${minimum}px ${style.fontFamily}` const width = context.measureText (formatUIString (title.text, title.language)).width if (width > 0) { const available = heading.clientWidth const fitted = minimum * Math.max (0, available - 1) / width const fontSize = Math.max (minimum, fitted) heading.style.fontSize = `${fontSize}px` let lower = available / 2 let upper = available // Keep the one-line font size and find a width that allows two lines. for (let step = 0; step < 12; ++step) { const candidate = (lower + upper) / 2 heading.style.maxWidth = `${candidate}px` if (heading.scrollHeight <= fontSize * 1.25 * 2 + 1 && heading.scrollWidth <= heading.clientWidth) upper = candidate else lower = candidate } heading.style.maxWidth = `${Math.ceil (upper)}px` } } let disposed = false const resizeObserver = new ResizeObserver (fitTitle) resizeObserver.observe (heading) window.addEventListener ('resize', fitTitle) document.fonts.addEventListener ('loadingdone', fitTitle) void document.fonts.ready.then (() => { if (!disposed) fitTitle () }) fitTitle () return () => { disposed = true resizeObserver.disconnect () window.removeEventListener ('resize', fitTitle) document.fonts.removeEventListener ('loadingdone', fitTitle) } }, [title.text, title.language]) const goBack = () => { // The router index excludes unrelated external history and is zero on direct entry. const index: unknown = window.history.state?.idx if (typeof index === 'number' && index > 0) navigate (-1) else navigate ('/posts', { replace: true }) } return (

{label ('unavailable.title')}

) } export default GekanatorUnavailablePage