pass theme as context

This commit is contained in:
Vinzenz Schroeter 2024-05-06 14:06:53 +02:00
parent ba56edf588
commit 8f497cae85
5 changed files with 37 additions and 41 deletions

View file

@ -8,20 +8,21 @@ import Scoreboard from './Scoreboard.tsx';
import Button from './components/Button.tsx'; import Button from './components/Button.tsx';
import MapChooser from './MapChooser.tsx'; import MapChooser from './MapChooser.tsx';
import './App.css'; import './App.css';
import {getRandomTheme, useStoredTheme} from './theme.ts'; import {ThemeContext, getRandomTheme, useStoredTheme} from './theme.ts';
import {useState} from 'react'; import {useState} from 'react';
export default function App() { export default function App() {
const [theme, setTheme] = useStoredTheme(); const [theme, setTheme] = useStoredTheme();
const [name, setName] = useState<string | null>(null); const [name, setName] = useState<string | null>(null);
return <Column className="flex-grow"> return <ThemeContext.Provider value={theme}>
<Column className="flex-grow">
<ClientScreen theme={theme} player={name}/> <ClientScreen player={name}/>
<Row> <Row>
<h1 className="flex-grow">CCCB-Tanks!</h1> <h1 className="flex-grow">CCCB-Tanks!</h1>
<MapChooser theme={theme}/> <MapChooser />
<Button text="☼ change colors" onClick={() => setTheme(_ => getRandomTheme())}/> <Button text="☼ change colors" onClick={() => setTheme(_ => getRandomTheme())}/>
<Button <Button
onClick={() => window.open('https://github.com/kaesaecracker/cccb-tanks-cs', '_blank')?.focus()} onClick={() => window.open('https://github.com/kaesaecracker/cccb-tanks-cs', '_blank')?.focus()}
@ -38,5 +39,6 @@ export default function App() {
<Scoreboard/> <Scoreboard/>
</Row> </Row>
</Column>; </Column>
</ThemeContext.Provider>;
} }

View file

@ -1,12 +1,10 @@
import {useEffect, useState} from 'react'; import {useEffect, useState} from 'react';
import {Theme} from './theme.ts';
import {makeApiUrl, useMyWebSocket} from './serverCalls.tsx'; import {makeApiUrl, useMyWebSocket} from './serverCalls.tsx';
import {ReadyState} from 'react-use-websocket'; import {ReadyState} from 'react-use-websocket';
import PixelGridCanvas from './components/PixelGridCanvas.tsx'; import PixelGridCanvas from './components/PixelGridCanvas.tsx';
export default function ClientScreen({theme, player}: { export default function ClientScreen({player}: {
theme: Theme,
player: string | null player: string | null
}) { }) {
const [shouldSendMessage, setShouldSendMessage] = useState(false); const [shouldSendMessage, setShouldSendMessage] = useState(false);
@ -40,5 +38,5 @@ export default function ClientScreen({theme, player}: {
return <></>; return <></>;
const pixels = new Uint8ClampedArray(lastMessage.data); const pixels = new Uint8ClampedArray(lastMessage.data);
return <PixelGridCanvas pixels={pixels} theme={theme}/>; return <PixelGridCanvas pixels={pixels}/>;
} }

View file

@ -4,7 +4,6 @@ import {makeApiUrl, MapInfo} from './serverCalls';
import Dialog from './components/Dialog.tsx'; import Dialog from './components/Dialog.tsx';
import PixelGridCanvas from './components/PixelGridCanvas.tsx'; import PixelGridCanvas from './components/PixelGridCanvas.tsx';
import Column from './components/Column.tsx'; import Column from './components/Column.tsx';
import {Theme} from './theme.ts';
import Button from './components/Button.tsx'; import Button from './components/Button.tsx';
import Row from './components/Row.tsx'; import Row from './components/Row.tsx';
import './MapChooser.css'; import './MapChooser.css';
@ -18,9 +17,8 @@ function base64ToArrayBuffer(base64: string) {
return bytes; return bytes;
} }
function MapPreview({mapName, theme, highlight, onClick}: { function MapPreview({mapName, highlight, onClick}: {
readonly mapName: string, readonly mapName: string,
readonly theme: Theme,
readonly highlight: boolean, readonly highlight: boolean,
readonly onClick: () => void readonly onClick: () => void
}) { }) {
@ -47,15 +45,14 @@ function MapPreview({mapName, theme, highlight, onClick}: {
className={'MapChooser-Preview' + (highlight ? ' MapChooser-Preview-Highlight' : '')} className={'MapChooser-Preview' + (highlight ? ' MapChooser-Preview-Highlight' : '')}
onClick={onClick} onClick={onClick}
> >
<PixelGridCanvas pixels={base64ToArrayBuffer(preview)} theme={theme}/> <PixelGridCanvas pixels={base64ToArrayBuffer(preview)}/>
<p>{name}</p> <p>{name}</p>
</Column>; </Column>;
} }
function MapChooserDialog({mapNames, theme, onClose, onConfirm}: { function MapChooserDialog({mapNames, onClose, onConfirm}: {
readonly mapNames: string[]; readonly mapNames: string[];
readonly theme: Theme;
readonly onConfirm: (mapName: string) => void; readonly onConfirm: (mapName: string) => void;
readonly onClose: () => void; readonly onClose: () => void;
}) { }) {
@ -66,22 +63,19 @@ function MapChooserDialog({mapNames, theme, onClose, onConfirm}: {
{mapNames.map(name => <MapPreview {mapNames.map(name => <MapPreview
key={name} key={name}
mapName={name} mapName={name}
theme={theme}
highlight={chosenMap == name} highlight={chosenMap == name}
onClick={() => setChosenMap(name)} onClick={() => setChosenMap(name)}
/>)} />)}
</Row> </Row>
<Row> <Row>
<div className='flex-grow'/> <div className="flex-grow"/>
<Button text="« cancel" onClick={onClose}/> <Button text="« cancel" onClick={onClose}/>
<Button text="√ confirm" disabled={!chosenMap} onClick={() => chosenMap && onConfirm(chosenMap)}/> <Button text="√ confirm" disabled={!chosenMap} onClick={() => chosenMap && onConfirm(chosenMap)}/>
</Row> </Row>
</Dialog>; </Dialog>;
} }
export default function MapChooser({theme}: { export default function MapChooser({}: {}) {
readonly theme: Theme;
}) {
const query = useQuery({ const query = useQuery({
queryKey: ['get-maps'], queryKey: ['get-maps'],
queryFn: async () => { queryFn: async () => {
@ -114,7 +108,6 @@ export default function MapChooser({theme}: {
{query.isSuccess && open && {query.isSuccess && open &&
<MapChooserDialog <MapChooserDialog
mapNames={query.data!} mapNames={query.data!}
theme={theme}
onClose={() => setOpen(false)} onClose={() => setOpen(false)}
onConfirm={name => { onConfirm={name => {
setOpen(false); setOpen(false);

View file

@ -1,5 +1,5 @@
import {hslToString, Theme} from '../theme.ts'; import {hslToString, ThemeContext} from '../theme.ts';
import {useEffect, useRef} from 'react'; import {useContext, useEffect, useRef} from 'react';
import './PixelGridCanvas.css'; import './PixelGridCanvas.css';
const pixelsPerRow = 352; const pixelsPerRow = 352;
@ -104,10 +104,10 @@ function drawPixelsToCanvas(
context.putImageData(imageData, 0, 0); context.putImageData(imageData, 0, 0);
} }
export default function PixelGridCanvas({pixels, theme}: { export default function PixelGridCanvas({pixels}: {
readonly pixels: Uint8ClampedArray; readonly pixels: Uint8ClampedArray;
readonly theme: Theme;
}) { }) {
const theme = useContext(ThemeContext);
const canvasRef = useRef<HTMLCanvasElement>(null); const canvasRef = useRef<HTMLCanvasElement>(null);
useEffect(() => { useEffect(() => {

View file

@ -1,4 +1,5 @@
import {useStoredObjectState} from "./useStoredState.ts"; import {useStoredObjectState} from './useStoredState.ts';
import {createContext} from 'react';
export type Theme = { export type Theme = {
primary: HSL; primary: HSL;
@ -88,3 +89,5 @@ export function useStoredTheme() {
save: applyTheme save: applyTheme
}); });
} }
export const ThemeContext = createContext<Theme>(getRandomTheme());