import/export theme
This commit is contained in:
		
							parent
							
								
									e854f77bdc
								
							
						
					
					
						commit
						d4d2b6397c
					
				
					 5 changed files with 56 additions and 17 deletions
				
			
		|  | @ -34,7 +34,7 @@ export default function JoinForm({onDone}: { | |||
|         <TextInput | ||||
|             value={name} | ||||
|             placeholder="player name" | ||||
|             onChange={e => setName(e.target.value)} | ||||
|             onChange={n => setName(n)} | ||||
|             onEnter={confirm} | ||||
|         /> | ||||
|         <Button | ||||
|  |  | |||
|  | @ -7,6 +7,7 @@ import Column from './components/Column.tsx'; | |||
| import Button from './components/Button.tsx'; | ||||
| import Row from './components/Row.tsx'; | ||||
| import './MapChooser.css'; | ||||
| import Spacer from './components/Spacer.tsx'; | ||||
| 
 | ||||
| function base64ToArrayBuffer(base64: string) { | ||||
|     const binaryString = atob(base64); | ||||
|  | @ -57,7 +58,7 @@ function MapChooserDialog({mapNames, onClose, onConfirm}: { | |||
|     readonly onClose: () => void; | ||||
| }) { | ||||
|     const [chosenMap, setChosenMap] = useState<string>(); | ||||
|     return <Dialog title='Choose a map' onClose={onClose}> | ||||
|     return <Dialog title="Choose a map" onClose={onClose}> | ||||
|         <Row className="MapChooser-Row overflow-scroll"> | ||||
|             {mapNames.map(name => <MapPreview | ||||
|                 key={name} | ||||
|  | @ -67,7 +68,7 @@ function MapChooserDialog({mapNames, onClose, onConfirm}: { | |||
|             />)} | ||||
|         </Row> | ||||
|         <Row> | ||||
|             <div className="flex-grow"/> | ||||
|             <Spacer/> | ||||
|             <Button text="« cancel" onClick={onClose}/> | ||||
|             <Button text="√ confirm" disabled={!chosenMap} onClick={() => chosenMap && onConfirm(chosenMap)}/> | ||||
|         </Row> | ||||
|  |  | |||
|  | @ -1,27 +1,28 @@ | |||
| import Button from './components/Button.tsx'; | ||||
| import {getRandomTheme, HSL, hslToString, useHslTheme} from './theme.tsx'; | ||||
| import Dialog from './components/Dialog.tsx'; | ||||
| import {useState} from 'react'; | ||||
| import {NumberInput, RangeInput} from './components/Input.tsx'; | ||||
| import {useMemo, useState} from 'react'; | ||||
| import {NumberInput, RangeInput, TextInput} from './components/Input.tsx'; | ||||
| import Row from './components/Row.tsx'; | ||||
| import Column from './components/Column.tsx'; | ||||
| import './ThemeChooser.css'; | ||||
| import Spacer from './components/Spacer.tsx'; | ||||
| 
 | ||||
| function HslEditor({name, value, setValue}: { | ||||
|     name: string; | ||||
|     value: HSL; | ||||
|     setValue: (value: HSL) => void | ||||
| }) { | ||||
|     const setH = (h: number) =>  setValue({...value, h}); | ||||
|     const setS = (s: number) =>  setValue({...value, s}); | ||||
|     const setL = (l: number) =>  setValue({...value, l}); | ||||
|     const setH = (h: number) => setValue({...value, h}); | ||||
|     const setS = (s: number) => setValue({...value, s}); | ||||
|     const setL = (l: number) => setValue({...value, l}); | ||||
| 
 | ||||
|     return <Column> | ||||
|         <Row> | ||||
|             <div className="" style={{background: hslToString(value), border: '1px solid white', aspectRatio: '1'}}/> | ||||
|             <p>{name}</p> | ||||
|         </Row> | ||||
|         <div className='HslEditor-Inputs'> | ||||
|         <div className="HslEditor-Inputs"> | ||||
|             <p>Hue</p> | ||||
|             <NumberInput value={Math.round(value.h)} onChange={setH}/> | ||||
|             <RangeInput value={Math.round(value.h)} min={0} max={360} onChange={setH}/> | ||||
|  | @ -41,14 +42,43 @@ function ThemeChooserDialog({onClose}: { | |||
|     onClose: () => void; | ||||
| }) { | ||||
|     const {hslTheme, setHslTheme} = useHslTheme(); | ||||
|     const [themeString, setThemeString] = useState<string>(JSON.stringify(hslTheme)); | ||||
|     const [errorMsg, setErrorMsg] = useState<string>(); | ||||
| 
 | ||||
|     useMemo(() => { | ||||
|         setThemeString(JSON.stringify(hslTheme)); | ||||
|     }, [hslTheme]); | ||||
| 
 | ||||
|     return <Dialog title="Theme editor" onClose={onClose}> | ||||
|         <Row> | ||||
|             <Button | ||||
|                 text="surprise me" | ||||
|                 className='flex-grow' | ||||
|                 text="? randomize" | ||||
|                 onClick={() => setHslTheme(_ => getRandomTheme())}/> | ||||
|             <Spacer/> | ||||
|         </Row> | ||||
|         <Column className='overflow-scroll'> | ||||
|         <Row> | ||||
|             <TextInput | ||||
|                 value={themeString} | ||||
|                 onChange={setThemeString} | ||||
|                 className="flex-grow"/> | ||||
|             <Button text="» import" onClick={() => { | ||||
|                 try { | ||||
|                     const theme = JSON.parse(themeString); | ||||
|                     setHslTheme(old => ({...old, theme})); | ||||
|                 } catch (e: any) { | ||||
|                     setErrorMsg(e.message); | ||||
|                 } | ||||
|             }}/> | ||||
|             {errorMsg && | ||||
|                 <Dialog | ||||
|                     title="Error" | ||||
|                     onClose={() => setErrorMsg(undefined)} | ||||
|                 > | ||||
|                     <p>{errorMsg}</p> | ||||
|                 </Dialog> | ||||
|             } | ||||
|         </Row> | ||||
|         <Column className="overflow-scroll"> | ||||
|             <HslEditor | ||||
|                 name="background" | ||||
|                 value={hslTheme.background} | ||||
|  |  | |||
|  | @ -1,8 +1,7 @@ | |||
| import {ChangeEventHandler} from 'react'; | ||||
| import './Input.css'; | ||||
| 
 | ||||
| export function TextInput({onChange, className, value, placeholder, onEnter}: { | ||||
|     onChange?: ChangeEventHandler<HTMLInputElement> | undefined; | ||||
|     onChange?: (value: string) => void; | ||||
|     className?: string; | ||||
|     value: string; | ||||
|     placeholder?: string; | ||||
|  | @ -13,10 +12,15 @@ export function TextInput({onChange, className, value, placeholder, onEnter}: { | |||
|         className={'Input ' + (className ?? '')} | ||||
|         value={value} | ||||
|         placeholder={placeholder} | ||||
|         onChange={onChange} | ||||
|         onChange={event => { | ||||
|             if (!onChange) | ||||
|                 return; | ||||
|             onChange(event.target.value); | ||||
|         }} | ||||
|         onKeyUp={event => { | ||||
|             if (onEnter && event.key === 'Enter') | ||||
|                 onEnter(); | ||||
|             if (!onEnter || event.key !== 'Enter') | ||||
|                 return; | ||||
|             onEnter(); | ||||
|         }} | ||||
|     />; | ||||
| } | ||||
|  |  | |||
							
								
								
									
										4
									
								
								tank-frontend/src/components/Spacer.tsx
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								tank-frontend/src/components/Spacer.tsx
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,4 @@ | |||
| 
 | ||||
| export default function Spacer() { | ||||
|     return <div className='flex-grow' />; | ||||
| } | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Vinzenz Schroeter
						Vinzenz Schroeter