Add support for blank characters
This commit is contained in:
parent
c61b2e3f75
commit
cd8a4b73a9
2 changed files with 91 additions and 16 deletions
|
@ -1,6 +1,6 @@
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
import {GameWasm, Letter as LetterData, MyResult, PlayedTile, PlayerAndScore, Tray, WordResult} from "word_grid";
|
import {GameWasm, Letter as LetterData, MyResult, PlayedTile, PlayerAndScore, Tray, WordResult} from "word_grid";
|
||||||
import {JSX, useEffect, useMemo, useReducer, useState} from "react";
|
import {ChangeEvent, JSX, useEffect, useMemo, useReducer, useState} from "react";
|
||||||
|
|
||||||
export enum LocationType {
|
export enum LocationType {
|
||||||
GRID,
|
GRID,
|
||||||
|
@ -75,8 +75,9 @@ function matchCoordinate(playerLetters: PlayableLetterData[], coords: Coordinate
|
||||||
enum TileDispatchActionType {
|
enum TileDispatchActionType {
|
||||||
MOVE,
|
MOVE,
|
||||||
RETRIEVE,
|
RETRIEVE,
|
||||||
|
SET_BLANK,
|
||||||
}
|
}
|
||||||
type TileDispatchAction = {action: TileDispatchActionType, start?: CoordinateData, end?: CoordinateData};
|
type TileDispatchAction = {action: TileDispatchActionType, start?: CoordinateData, end?: CoordinateData, newBlankValue?: string, blankIndex?: number};
|
||||||
type TileDispatch = React.Dispatch<TileDispatchAction>;
|
type TileDispatch = React.Dispatch<TileDispatchAction>;
|
||||||
|
|
||||||
function addLogInfo(existingLog: React.JSX.Element[], newItem: React.JSX.Element) {
|
function addLogInfo(existingLog: React.JSX.Element[], newItem: React.JSX.Element) {
|
||||||
|
@ -124,6 +125,15 @@ export function Game(props: {wasm: GameWasm}) {
|
||||||
|
|
||||||
setConfirmedScorePoints(-1);
|
setConfirmedScorePoints(-1);
|
||||||
|
|
||||||
|
return playerLetters.slice();
|
||||||
|
} if (update.action === TileDispatchActionType.SET_BLANK) {
|
||||||
|
const blankLetter = playerLetters[update.blankIndex];
|
||||||
|
if(blankLetter.text !== update.newBlankValue) {
|
||||||
|
blankLetter.text = update.newBlankValue;
|
||||||
|
if (blankLetter.location == LocationType.GRID) {
|
||||||
|
setConfirmedScorePoints(-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
return playerLetters.slice();
|
return playerLetters.slice();
|
||||||
} else {
|
} else {
|
||||||
console.error("Unknown tray update");
|
console.error("Unknown tray update");
|
||||||
|
@ -221,7 +231,7 @@ export function Game(props: {wasm: GameWasm}) {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
export function TileSlot(props: { tile: React.JSX.Element | undefined, location: CoordinateData, dispatch: TileDispatch }): React.JSX.Element {
|
export function TileSlot(props: { tile?: React.JSX.Element | undefined, location: CoordinateData, dispatch: TileDispatch }): React.JSX.Element {
|
||||||
let isDraggable = props.tile !== undefined;
|
let isDraggable = props.tile !== undefined;
|
||||||
|
|
||||||
function onDragStart(e: React.DragEvent<HTMLDivElement>) {
|
function onDragStart(e: React.DragEvent<HTMLDivElement>) {
|
||||||
|
@ -252,11 +262,51 @@ export function TileSlot(props: { tile: React.JSX.Element | undefined, location:
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function Letter(props: { data: LetterData }): React.JSX.Element {
|
export function Letter(props: { data: LetterData, letterUpdater?: (value: string) => void }): React.JSX.Element {
|
||||||
|
|
||||||
|
function modifyThisLetter(value:string){
|
||||||
|
props.letterUpdater(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function onBlankInput(e: ChangeEvent<HTMLInputElement>){
|
||||||
|
let value = e.target.value.toUpperCase();
|
||||||
|
if(value.length > 1){
|
||||||
|
value = value[value.length - 1];
|
||||||
|
} else if(value.length == 0){
|
||||||
|
modifyThisLetter(value);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now check that it's a letter
|
||||||
|
let is_letter = value.match("[A-Z]") != null;
|
||||||
|
if(is_letter){
|
||||||
|
modifyThisLetter(value);
|
||||||
|
} else {
|
||||||
|
// Cancel and do nothing
|
||||||
|
e.preventDefault();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if(props.data.is_blank && props.data.ephemeral) {
|
||||||
return <div className="letter">
|
return <div className="letter">
|
||||||
<div className="text">{props.data.text}</div>
|
<input className="blank-input" type="text" onChange={onBlankInput} value={props.data.text} />
|
||||||
<div className="letter-points">{props.data.points}</div>
|
<div className="letter-points">{props.data.points}</div>
|
||||||
</div>
|
</div>
|
||||||
|
} else {
|
||||||
|
let className = "text";
|
||||||
|
if (props.data.is_blank) { // not ephemeral
|
||||||
|
className += " prev-blank";
|
||||||
|
}
|
||||||
|
return <div className="letter">
|
||||||
|
<div className={className}>{props.data.text}</div>
|
||||||
|
<div className="letter-points">{props.data.points}</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -266,24 +316,28 @@ export function TileTray(props: { letters: Array<PlayableLetterData>, trayLength
|
||||||
for (let i=0; i<props.trayLength; i++) {
|
for (let i=0; i<props.trayLength; i++) {
|
||||||
elements.push(
|
elements.push(
|
||||||
<TileSlot
|
<TileSlot
|
||||||
tile={undefined}
|
|
||||||
key={"empty" + i}
|
key={"empty" + i}
|
||||||
location={{location: LocationType.TRAY, index: i}}
|
location={{location: LocationType.TRAY, index: i}}
|
||||||
dispatch={props.dispatch} />
|
dispatch={props.dispatch} />
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (let letter of props.letters) {
|
props.letters.forEach((letter, i) => {
|
||||||
if (letter.location === LocationType.TRAY) {
|
if (letter.location === LocationType.TRAY) {
|
||||||
elements[letter.index] =
|
elements[letter.index] =
|
||||||
<TileSlot
|
<TileSlot
|
||||||
tile={<Letter data={letter} />}
|
tile={<Letter
|
||||||
|
data={letter}
|
||||||
|
letterUpdater={(value) => {
|
||||||
|
props.dispatch({action: TileDispatchActionType.SET_BLANK, blankIndex: i, newBlankValue: value})
|
||||||
|
}}
|
||||||
|
/>}
|
||||||
key={"letter" + letter.index}
|
key={"letter" + letter.index}
|
||||||
location={{location: LocationType.TRAY, index: letter.index}}
|
location={{location: LocationType.TRAY, index: letter.index}}
|
||||||
dispatch={props.dispatch} />
|
dispatch={props.dispatch} />
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="tray">
|
<div className="tray">
|
||||||
|
@ -309,7 +363,6 @@ function Grid(props: {
|
||||||
tileElement = <>
|
tileElement = <>
|
||||||
<span>{text}</span>
|
<span>{text}</span>
|
||||||
<TileSlot
|
<TileSlot
|
||||||
tile={undefined}
|
|
||||||
location={{location: LocationType.GRID, index: i}}
|
location={{location: LocationType.GRID, index: i}}
|
||||||
dispatch={props.dispatch} /></>;
|
dispatch={props.dispatch} /></>;
|
||||||
}
|
}
|
||||||
|
@ -320,7 +373,7 @@ function Grid(props: {
|
||||||
</div>;
|
</div>;
|
||||||
});
|
});
|
||||||
|
|
||||||
for (let letter of props.playerLetters) {
|
props.playerLetters.forEach((letter, i) => {
|
||||||
if (letter.location === LocationType.GRID) {
|
if (letter.location === LocationType.GRID) {
|
||||||
const ct = props.cellTypes[letter.index];
|
const ct = props.cellTypes[letter.index];
|
||||||
const {className, text} = cell_type_to_details(ct);
|
const {className, text} = cell_type_to_details(ct);
|
||||||
|
@ -328,14 +381,19 @@ function Grid(props: {
|
||||||
elements[letter.index] =
|
elements[letter.index] =
|
||||||
<div key={"letter" + letter.index} className={"grid-spot " + className}>
|
<div key={"letter" + letter.index} className={"grid-spot " + className}>
|
||||||
<TileSlot
|
<TileSlot
|
||||||
tile={<Letter data={letter} />}
|
tile={<Letter
|
||||||
|
data={letter}
|
||||||
|
letterUpdater={(value) => {
|
||||||
|
props.dispatch({action: TileDispatchActionType.SET_BLANK, blankIndex: i, newBlankValue: value});
|
||||||
|
}}
|
||||||
|
/>}
|
||||||
location={{location: LocationType.GRID, index: letter.index}}
|
location={{location: LocationType.GRID, index: letter.index}}
|
||||||
dispatch={props.dispatch} />
|
dispatch={props.dispatch} />
|
||||||
</div>;
|
</div>;
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
|
|
||||||
return <div className="board-grid">
|
return <div className="board-grid">
|
||||||
{elements}
|
{elements}
|
||||||
|
|
|
@ -105,6 +105,23 @@
|
||||||
padding-right: 5px;
|
padding-right: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
input {
|
||||||
|
position: absolute;
|
||||||
|
width: 100%;
|
||||||
|
top: 5px;
|
||||||
|
text-align: center;
|
||||||
|
font-size: @tile-font-size;
|
||||||
|
background: none;
|
||||||
|
border: none;
|
||||||
|
padding: 0;
|
||||||
|
font-style: italic;
|
||||||
|
left: 0; /* Fixes a weird display bug where the input is shifted to the right when the tile is on the grid */
|
||||||
|
}
|
||||||
|
|
||||||
|
.prev-blank {
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.board-log {
|
.board-log {
|
||||||
|
|
Loading…
Reference in a new issue