/* eslint-disable max-lines, max-statements */ import { BONUS_CHARACTER, BONUS_WORD } from '@scrabble-solver/constants'; import { useCallback, useMemo } from 'react'; import { renderToString } from 'react-dom/server'; import { Provider } from 'react-redux'; import { useAppLayout } from '@/app-layout'; import { useMediaQueries } from '@/hooks'; import { LOCALE_FEATURES } from '@/i18n'; import { Star } from '@/icons'; import { getTileSizes } from '@/lib'; import { BORDER_COLOR_LIGHT, BORDER_RADIUS, BORDER_WIDTH, COLOR_BACKGROUND, COLOR_BONUS_START } from '@/parameters'; import { selectConfig, selectLocale, selectShowCoordinates, store, useTypedSelector } from '@/state'; import { type Point } from '@/types'; import { getBonusColor } from '../lib'; const BORDER_RADIUS_XS = 3; const GRID_LINE_SIZE = 1; const HORIZONTAL_LINE = 'h'; const VERTICAL_LINE = 'v'; const BONUS = 'b'; const BONUS_WORD_2 = 'b2'; const BONUS_WORD_3 = 'b3'; const BONUS_WORD_4 = 'b4'; export const useBackgroundImage = () => { const { boardHeight, boardWidth, cellSize, coordinatesSize } = useAppLayout(); const locale = useTypedSelector(selectLocale); const { direction } = LOCALE_FEATURES[locale]; const showCoordinates = useTypedSelector(selectShowCoordinates); const { isLessThanXs } = useMediaQueries(); const borderRadius = isLessThanXs ? BORDER_RADIUS_XS : BORDER_RADIUS; const config = useTypedSelector(selectConfig); const center = useMemo( () => ({ x: Math.floor(config.boardWidth / 2), y: Math.floor(config.boardHeight / 2) }), [config.boardHeight, config.boardWidth], ); const viewBoxHeight = boardHeight; const viewBoxWidth = boardWidth; const bonusSize = cellSize * 0.8; const bonusOffset = cellSize * 0.1; const iconSize = cellSize * 0.4; const iconOffset = (cellSize - iconSize) / 2; const { tileFontSize } = getTileSizes(cellSize); const fontSize = tileFontSize * 0.6; const fontOffset = cellSize / 2; const characterBonuses = useMemo( () => config.bonuses.filter((bonus) => bonus.type === BONUS_CHARACTER), [config.bonuses], ); const word2Bonuses = useMemo( () => config.bonuses.filter((bonus) => bonus.type === BONUS_WORD && bonus.multiplier === 2), [config.bonuses], ); const word3Bonuses = useMemo( () => config.bonuses.filter((bonus) => bonus.type === BONUS_WORD && bonus.multiplier === 3), [config.bonuses], ); const word4Bonuses = useMemo( () => config.bonuses.filter((bonus) => bonus.type === BONUS_WORD && bonus.multiplier === 4), [config.bonuses], ); const getX = useCallback( (point: Point): number => (direction === 'ltr' ? coordinatesSize : 0) + point.x * (cellSize + BORDER_WIDTH), [coordinatesSize, cellSize, direction], ); const getY = useCallback( (point: Point): number => coordinatesSize + point.y * (cellSize + BORDER_WIDTH), [coordinatesSize, cellSize], ); const backgroundSvg = useMemo( () => renderToString( ×2 ×3 ×4 {showCoordinates === 'hidden' && ( )} {showCoordinates !== 'hidden' && ( <> )} {Array.from({ length: config.boardHeight - 1 }).map((_value, index) => ( ))} {Array.from({ length: config.boardWidth - 1 }).map((_value, index) => ( ))} {characterBonuses.map((bonus, index) => ( ))} {word2Bonuses.map((bonus, index) => ( ))} {word3Bonuses.map((bonus, index) => ( ))} {word4Bonuses.map((bonus, index) => ( ))} , ), [ bonusOffset, bonusSize, borderRadius, cellSize, center, characterBonuses, config.boardHeight, config.boardWidth, coordinatesSize, direction, fontOffset, fontSize, getX, getY, iconOffset, iconSize, showCoordinates, viewBoxHeight, viewBoxWidth, word2Bonuses, word3Bonuses, word4Bonuses, ], ); const dataUrl = useMemo(() => `data:image/svg+xml,${encodeURIComponent(backgroundSvg)}`, [backgroundSvg]); return dataUrl; };