From b790e48bc4c07f57a6e94dd7e7aa1ba761d0d038 Mon Sep 17 00:00:00 2001 From: Joel Therrien Date: Mon, 21 Aug 2023 19:42:22 -0700 Subject: [PATCH] Add UI for tile exchange --- ui/package-lock.json | 3 +- ui/src/Modal.tsx | 4 +- ui/src/elements.tsx | 120 +++++++++++++++++++++++++++++++++++++++++-- ui/src/style.less | 27 ++++++++++ ui/src/utils.ts | 6 +++ 5 files changed, 154 insertions(+), 6 deletions(-) create mode 100644 ui/src/utils.ts diff --git a/ui/package-lock.json b/ui/package-lock.json index 25d4050..2ee7479 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -19,7 +19,8 @@ }, "../pkg": { "name": "word_grid", - "version": "0.1.0" + "version": "0.1.0", + "license": "AGPL-3" }, "node_modules/@babel/code-frame": { "version": "7.22.5", diff --git a/ui/src/Modal.tsx b/ui/src/Modal.tsx index 041a13e..d043788 100644 --- a/ui/src/Modal.tsx +++ b/ui/src/Modal.tsx @@ -2,7 +2,7 @@ import {useEffect, useRef} from "react"; export function Modal(props: { isOpen: boolean; - setClosed: () => void; + setOpen: (isOpen: boolean) => void; children: any; }){ @@ -27,7 +27,7 @@ export function Modal(props: { // we manually trigger a close anyway because the children can get updated before the dialog gets closed otherwise // @ts-ignore ref.current.close(); - props.setClosed(); + props.setOpen(false); }}>✕
diff --git a/ui/src/elements.tsx b/ui/src/elements.tsx index e34672c..1db9dd2 100644 --- a/ui/src/elements.tsx +++ b/ui/src/elements.tsx @@ -1,6 +1,8 @@ import * as React from "react"; import {GameWasm, Letter as LetterData, MyResult, PlayedTile, PlayerAndScore, Tray, WordResult} from "word_grid"; import {ChangeEvent, JSX, useEffect, useMemo, useReducer, useRef, useState} from "react"; +import {Modal} from "./Modal"; +import {addNTimes} from "./utils"; export interface Settings { trayLength: number; @@ -181,8 +183,6 @@ export function Game(props: {wasm: GameWasm, settings: Settings}) { } const [playerLetters, trayDispatch] = useReducer(movePlayableLetters, []); - - const [logInfo, logDispatch] = useReducer(addLogInfo, []); const [turnCount, setTurnCount] = useState(1); @@ -202,6 +202,7 @@ export function Game(props: {wasm: GameWasm, settings: Settings}) { const logDivRef = useRef(null); + const [isTileExchangeOpen, setIsTileExchangeOpen] = useState(false); useEffect(() => { // Effect is to keep the log window scrolled down @@ -214,6 +215,7 @@ export function Game(props: {wasm: GameWasm, settings: Settings}) { return <> +
@@ -273,6 +275,7 @@ export function Game(props: {wasm: GameWasm, settings: Settings}) { }}>{confirmedScorePoints > -1 ? `Score ${confirmedScorePoints} points ✅` : "Check"} + ; @@ -465,4 +468,115 @@ function Scores(props: {playerScores: Array}){ return
{elements}
-} \ No newline at end of file +} + +function TileExchangeModal(props: {playerLetters: PlayableLetterData[], isOpen: boolean, setOpen: (isOpen: boolean) => void}) { + + function clearExchangeTiles() { + const array: boolean[] = []; + addNTimes(array, false, props.playerLetters.length); + return array; + } + + const [tilesToExchange, setTilesToExchange] = useState(clearExchangeTiles); + + let tilesExchangedSelected = 0; + for (let i of tilesToExchange) { + if(i) { + tilesExchangedSelected++; + } + } + + return { + setTilesToExchange(clearExchangeTiles()); + props.setOpen(isOpen); + }}> +
+
+ Click on each tile you'd like to exchange. You currently have {tilesExchangedSelected} tiles selected. +
+
+ + +
+ + +
+ + +
+
+
; + +} + +function TilesExchangedTray(props: { + tray: Array, + trayLength: number, + selectedArray: Array, + setSelectedArray: (x: Array) => void, +}){ + + const divContent = []; + for(let i = 0; i { + props.selectedArray[i] = !props.selectedArray[i]; + props.setSelectedArray(props.selectedArray.slice()); + } + + if(tileData != null){ + divContent.push( + + ); + } else{ + divContent.push(); + } + } + + return
+ {divContent} +
; + +} + +function DummyExchangeTile(props: { + letter: LetterData, + isSelected: boolean, + onClick: () => void, +}){ + + let textClassName = "text"; + if(props.letter.is_blank) { + textClassName += " prev-blank"; + } + + let letterClassName = "letter"; + if(props.isSelected){ + letterClassName += ' selected-tile'; + } + + + return
+
{props.letter.text}
+
{props.letter.points}
+
; +} diff --git a/ui/src/style.less b/ui/src/style.less index a205905..b5d837f 100644 --- a/ui/src/style.less +++ b/ui/src/style.less @@ -188,4 +188,31 @@ dialog { } } + .tile-exchange-dialog { + + .selection-buttons { + display: flex; + justify-content: space-around; + + button { + width: 40%; + } + } + + .finish-buttons { + .selection-buttons(); + } + + .tray-container { + display: flex; + justify-content: center; + margin: 20px; + } + + .selected-tile { + bottom: 10px; + } + + } + } \ No newline at end of file diff --git a/ui/src/utils.ts b/ui/src/utils.ts new file mode 100644 index 0000000..bc070f3 --- /dev/null +++ b/ui/src/utils.ts @@ -0,0 +1,6 @@ + +export function addNTimes(array: T[], toAdd: T, times: number) { + for (let i=0; i