diff --git a/src/components/game/variant-header.tsx b/src/components/game/variant-header.tsx index 85cb3c5..a45068d 100644 --- a/src/components/game/variant-header.tsx +++ b/src/components/game/variant-header.tsx @@ -1,37 +1,47 @@ -import { useBoardSubset } from "@/lib/hooks"; +import { groupByValue } from "@/lib/game"; +import { useBoardSubset, useSessionSubset } from "@/lib/hooks"; import { cva } from "class-variance-authority"; +import { useMemo } from "react"; -const variantHeader = cva("flex gap-2 text-sm text-main font-bold", { +const variantHeader = cva("flex gap-2 text-sm font-bold", { variants: { orientation: { horizontal: "", vertical: "flex-col items-center", }, + result: { + correct: "text-lime-400", + almost: "text-amber-300", + inProgress: "text-main", + }, }, }); type Props = { + orientation: "horizontal" | "vertical"; + index: number; variant: number; }; -type RowProps = { - row: number; -} & Props; +export function VariantHeader({ orientation, index, variant }: Props) { + const dir = orientation === "horizontal" ? "row" : "col"; + const boardRow = useBoardSubset(dir, index); + const boardHints = groupByValue(boardRow, variant); + const sessionRow = useSessionSubset(dir, index); + const sessionHints = groupByValue(sessionRow, variant); + // TODO This re-renders way too much because of the selectAtom -type ColProps = { - col: number; -} & Props; + const result = + sessionRow.toString() === boardRow.toString() + ? "correct" + : sessionHints.toString() === boardHints.toString() && + sessionRow.filter((i) => i > -1).length === boardRow.length + ? "almost" + : "inProgress"; -export function VariantHeader({ variant, ...props }: RowProps | ColProps) { - const orientation = "row" in props ? "horizontal" : "vertical"; - const block = useBoardSubset( - "row" in props ? "row" : "col", - "row" in props ? props.row : props.col, - variant, - ); return ( -
- {block.map((count, i) => ( +
+ {boardHints.map((count, i) => (

{count}

))}
diff --git a/src/components/game/variant-hints.tsx b/src/components/game/variant-hints.tsx index 27c3e99..d5e7f36 100644 --- a/src/components/game/variant-hints.tsx +++ b/src/components/game/variant-hints.tsx @@ -22,21 +22,10 @@ interface Props { blocks: number[][]; } -function headerProps(orientation: T) { - return (index: number) => { - return { - [orientation]: index, - } as Record; - }; -} - export function VariantHints({ variant, position, blocks }: Props) { const orientation = ["top", "bottom"].includes(position) ? "horizontal" : "vertical"; - const propsFactory = headerProps( - orientation === "horizontal" ? "col" : "row", - ); return (
{blocks.map((_, i) => ( @@ -49,7 +38,14 @@ export function VariantHints({ variant, position, blocks }: Props) { position === "top" ? "justify-end" : "", ].join(" ")} > - +
))}
diff --git a/src/lib/hooks.ts b/src/lib/hooks.ts index 611618d..7094fae 100644 --- a/src/lib/hooks.ts +++ b/src/lib/hooks.ts @@ -1,22 +1,22 @@ import { useAtom, useAtomValue } from "jotai"; import { useMemo } from "react"; import { - _boardAtom, boardAtom, boardMatrixAtom, gameResultAtom, - getGuessAtomAt, - getVariantAtomAt, heightAtom, preferencesAtom, + selectBoardSubset, + selectGuessAt, + selectSessionSubset, + selectVariantAt, sessionMatrixAtom, variantsAtom, widthAtom, } from "./state"; -import { groupByValue, groupIntoCols, groupIntoRows } from "./game"; export function useGuessAt(index: number) { - const atomCell = useMemo(() => getGuessAtomAt(index), [index]); + const atomCell = useMemo(() => selectGuessAt(index), [index]); const [cell] = useAtom(atomCell); return cell; } @@ -26,7 +26,7 @@ export function useVariants() { } export function useVariantAt(index: number) { - const variantAtom = useMemo(() => getVariantAtomAt(index), [index]); + const variantAtom = useMemo(() => selectVariantAt(index), [index]); return useAtomValue(variantAtom); } @@ -52,19 +52,14 @@ export function useGameResult() { return useAtomValue(gameResultAtom); } -export function useBoardSubset( - orientation: "row" | "col", - index: number, - variant: number, -) { - const [width] = useBoardDimensions(); - const board = useBoard(); +export function useBoardSubset(dir: "row" | "col", index: number) { + const subset = useMemo(() => selectBoardSubset(dir, index), [dir, index]); + return useAtomValue(subset); +} - if (orientation === "row") { - return groupByValue(groupIntoRows(board, width)[index]!, variant); - } else { - return groupByValue(groupIntoCols(board, width)[index]!, variant); - } +export function useSessionSubset(dir: "row" | "col", index: number) { + const subset = useMemo(() => selectSessionSubset(dir, index), [dir, index]); + return useAtomValue(subset); } export function usePreferences() { diff --git a/src/lib/state.ts b/src/lib/state.ts index 2da68d0..8f5f73a 100644 --- a/src/lib/state.ts +++ b/src/lib/state.ts @@ -103,7 +103,45 @@ export const preferencesAtom = atom( }, ); -export const getGuessAtomAt = (index: number) => +export const selectBoardSubset = (dir: "row" | "col", index: number) => + selectAtom(boardMatrixAtom, (board) => { + if (dir === "row") { + const row = board[index]; + if (typeof row === "undefined") { + throw new Error(`No board ${dir} at index ${index}`); + } + return row; + } else { + return board.map((row) => { + const col = row[index]; + if (typeof col === "undefined") { + throw new Error(`No board ${dir} at index ${index}`); + } + return col; + }); + } + }); + +export const selectSessionSubset = (dir: "row" | "col", index: number) => + selectAtom(sessionMatrixAtom, (session) => { + if (dir === "row") { + const row = session[index]; + if (typeof row === "undefined") { + throw new Error(`No session ${dir} at index ${index}`); + } + return row; + } else { + return session.map((row) => { + const col = row[index]; + if (typeof col === "undefined") { + throw new Error(`No session ${dir} at index ${index}`); + } + return col; + }); + } + }); + +export const selectGuessAt = (index: number) => selectAtom(sessionAtom, (cells) => { const cellAtom = cells[index]; if (typeof cellAtom === "undefined") { @@ -112,7 +150,7 @@ export const getGuessAtomAt = (index: number) => return cellAtom; }); -export function getVariantAtomAt(index: number) { +export function selectVariantAt(index: number) { return selectAtom(variantsAtom, (variants) => { const variant = variants[index]; if (typeof variant === "undefined") {