import { games } from '@scrabble-solver/configs'; import { Game, Locale } from '@scrabble-solver/types'; import fs from 'fs'; import Document, { Head, Html, Main, NextScript } from 'next/document'; import path from 'path'; import { type ReactElement } from 'react'; import { LOCALE_FEATURES } from '@/i18n/constants'; import { CONFIG_PENDING_CLASS } from '@/parameters'; const GAME_DIMENSIONS = Object.fromEntries( Object.values(games).map(({ boardHeight, boardWidth, game, rackSize }) => [ game, [boardWidth, boardHeight, rackSize], ]), ); const LOCALE_DIRECTIONS = Object.fromEntries( Object.entries(LOCALE_FEATURES).map(([locale, { direction }]) => [locale, direction]), ); /** * The SSR HTML is always an English Scrabble board. This runs before first paint * so a returning user's persisted board dimensions and text direction apply without a flash. * The board itself cannot be reshaped pre-hydration, so it is hidden (CONFIG_PENDING_CLASS, * see global.scss) until hydration applies the persisted config. */ const preHydrationScript = `(function () { try { var settings = JSON.parse(localStorage.getItem('scrabble-solver.settings')); if (!settings) { return; } var dimensions = ${JSON.stringify(GAME_DIMENSIONS)}[settings.game]; var direction = ${JSON.stringify(LOCALE_DIRECTIONS)}[settings.locale]; var root = document.documentElement; if (dimensions) { root.style.setProperty('--board-cols', dimensions[0]); root.style.setProperty('--board-rows', dimensions[1]); root.style.setProperty('--rack-size', dimensions[2]); if (settings.game !== ${JSON.stringify(Game.Scrabble)}) { root.classList.add(${JSON.stringify(CONFIG_PENDING_CLASS)}); } } if (direction) { root.dir = direction; root.lang = settings.locale; } } catch (error) {} })()`; export default class MyDocument extends Document { render(): ReactElement { return ( {/* eslint-disable-next-line react/no-danger */}