Add handling for buttons

This commit is contained in:
sschwei1 2022-10-24 19:24:16 +02:00
parent 4d3113dc99
commit 591ed62ccd
5 changed files with 122 additions and 16 deletions

View File

@ -9,6 +9,7 @@ export interface ButtonDefinition {
text: string|JSX.Element;
onClick: React.MouseEventHandler<HTMLButtonElement>;
cssProps: CSSProperties;
buttonProps?: React.ButtonHTMLAttributes<HTMLButtonElement>
}
const ButtonGroup = ({buttons, buttonStyleProps}: ButtonGroupProps) => {
@ -23,6 +24,7 @@ const ButtonGroup = ({buttons, buttonStyleProps}: ButtonGroupProps) => {
...buttonStyleProps,
...btn.cssProps
}}
{...(btn.buttonProps ?? {})}
>
<>{btn.text}</>
</button>

View File

@ -1,26 +1,54 @@
import {ButtonDefinition, ButtonGroup} from '../button';
import {AiOutlineClear, BsFillPlayFill, BsFillStopFill, CiSettings, TbArrowsRandom} from 'react-icons/all';
import React, {useMemo} from 'react';
import {
AiOutlineClear,
BsFillPlayFill,
BsFillStopFill,
CiSettings,
IoAdd,
IoRemove,
TbArrowsRandom
} from 'react-icons/all';
import React, {useCallback, useMemo} from 'react';
import {GameOptions, GameState} from './Game';
interface ControlPanelProps {
gameOptions: GameOptions;
handleStart: React.MouseEventHandler<HTMLButtonElement>;
handleStop: React.MouseEventHandler<HTMLButtonElement>;
handleRandomFill: React.MouseEventHandler<HTMLButtonElement>;
handleClear: React.MouseEventHandler<HTMLButtonElement>;
handleUpdateSpeed: (newVal: number) => void;
}
const ControlPanel = ({
gameOptions,
handleStart,
handleStop,
handleRandomFill,
handleClear
handleClear,
handleUpdateSpeed
}: ControlPanelProps) => {
const controlButtons: ButtonDefinition[] = useMemo(() => [
{text: <BsFillPlayFill />, onClick: handleStart, cssProps: {}},
{text: <BsFillStopFill />, onClick: handleStop, cssProps: {}},
{text: <BsFillPlayFill />, onClick: handleStart, cssProps: {}, buttonProps: {disabled: gameOptions.gameState === GameState.Running}},
{text: <BsFillStopFill />, onClick: handleStop, cssProps: {}, buttonProps: {disabled: gameOptions.gameState === GameState.Stopped}},
{text: <TbArrowsRandom />, onClick: handleRandomFill, cssProps: {}},
{text: <AiOutlineClear />, onClick: handleClear, cssProps: {}}
], [handleStart, handleStop, handleRandomFill, handleClear]);
], [handleStart, handleStop, handleRandomFill, handleClear, gameOptions]);
const handleSpeedChange = useCallback((event: React.ChangeEvent<HTMLInputElement>) => {
const value = event.target.value;
handleUpdateSpeed(Number(value));
}, [handleUpdateSpeed]);
const handleSpeedUp = useCallback((event: React.MouseEvent<HTMLButtonElement>) => {
const newVal = gameOptions.speed + 100;
handleUpdateSpeed(newVal);
}, [handleUpdateSpeed, gameOptions]);
const handleSpeedDown = useCallback((event: React.MouseEvent<HTMLButtonElement>) => {
const newVal = gameOptions.speed - 100;
handleUpdateSpeed(newVal);
}, [handleUpdateSpeed, gameOptions]);
return (
<div className='control-panel'>
@ -30,6 +58,16 @@ const ControlPanel = ({
width: '50px'
}}
/>
<div className='speed-selector'>
<button onClick={handleSpeedUp}><IoAdd /></button>
<input
value={gameOptions.speed}
onChange={handleSpeedChange}
/>
<button onClick={handleSpeedDown}><IoRemove /></button>
</div>
<button><CiSettings/></button>
</div>
);

View File

@ -8,30 +8,66 @@ interface GameProps {
}
interface GameOptions {
export enum GameState {
Stopped,
Running
}
export interface GameOptions {
gameState: GameState;
width: number;
height: number;
speed: number;
minSpeed: number;
}
const defaultGameOptions: GameOptions = {
gameState: GameState.Stopped,
width: 25,
height: 25
height: 25,
speed: 1000,
minSpeed: 100
}
const Game = ({}: GameProps) => {
const [gameOptions, setGameOptions] = useState<GameOptions>(defaultGameOptions);
const [cells, setCells] = useState<boolean[]>([]);
useEffect(() => {
const handleStart = useCallback(() => {
setGameOptions(prev => {
prev.gameState = GameState.Running;
return {...prev};
});
}, []);
const handleStop = useCallback(() => {
setGameOptions(prev => {
prev.gameState = GameState.Stopped;
return {...prev};
});
}, []);
const handleRandomFill = useCallback(() => {
const newCells: boolean[] = [];
const totalCells = gameOptions.width * gameOptions.height;
for(let i = 0; i < totalCells; i++) {
newCells.push(false);
newCells.push(Math.random() < 0.5);
}
setCells(newCells);
}, [gameOptions]);
}, []);
const handleClear = useCallback(() => {
const newCells: boolean[] = [];
const totalCells = gameOptions.width * gameOptions.height;
for(let i = 0; i < totalCells; i++) {
newCells.push(false);
}
setCells(newCells);
}, []);
const handleCellUpdate = useCallback((newVal: boolean, position: number) => {
setCells(prev => {
@ -40,13 +76,30 @@ const Game = ({}: GameProps) => {
});
}, []);
const handleUpdateSpeed = useCallback((newVal: number) => {
if(newVal < gameOptions.minSpeed) {
newVal = gameOptions.minSpeed;
}
setGameOptions(prev => {
prev.speed = newVal;
return {...prev};
})
}, [gameOptions]);
useEffect(() => {
handleClear();
}, [handleClear]);
return (
<div className='game-container'>
<ControlPanel
handleStart={() => {}}
handleStop={() => {}}
handleRandomFill={() => {}}
handleClear={() => {}}
gameOptions={gameOptions}
handleStart={handleStart}
handleStop={handleStop}
handleRandomFill={handleRandomFill}
handleClear={handleClear}
handleUpdateSpeed={handleUpdateSpeed}
/>
<CellContainer
cells={cells}

View File

@ -10,6 +10,18 @@
margin-bottom: 1rem;
}
.speed-selector {
display: flex;
input {
width: 60px;
text-align: center;
margin: 0;
padding: 0;
}
}
.cell-container {
flex-grow: 1;
display: grid;

View File

@ -26,6 +26,7 @@ button {
margin: 0;
font-size: 20px;
align-content: center;
height: 100%;
align-items: center;
justify-content: center;
}