add range sliders
This commit is contained in:
		
							parent
							
								
									59459019fc
								
							
						
					
					
						commit
						e854f77bdc
					
				
					 4 changed files with 90 additions and 45 deletions
				
			
		
							
								
								
									
										6
									
								
								tank-frontend/src/ThemeChooser.css
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								tank-frontend/src/ThemeChooser.css
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,6 @@ | |||
| .HslEditor-Inputs { | ||||
|     display: grid; | ||||
|     column-gap: var(--padding-normal); | ||||
|     grid-template-columns: auto auto auto; | ||||
|     grid-template-rows: auto; | ||||
| } | ||||
|  | @ -2,40 +2,37 @@ 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} from './components/Input.tsx'; | ||||
| import {NumberInput, RangeInput} from './components/Input.tsx'; | ||||
| import Row from './components/Row.tsx'; | ||||
| import Column from './components/Column.tsx'; | ||||
| import './ThemeChooser.css'; | ||||
| 
 | ||||
| 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}); | ||||
| 
 | ||||
|     return <Column> | ||||
|         <Row> | ||||
|             <div className="" style={{background: hslToString(value), border: '1px solid white', aspectRatio: '1'}}/> | ||||
|             <p>{name}</p> | ||||
|         </Row> | ||||
|         <div style={{ | ||||
|             display: 'grid', | ||||
|             columnGap: 'var(--padding-normal)', | ||||
|             gridTemplateColumns: 'auto auto', | ||||
|             gridTemplateRows: 'auto' | ||||
|         }}> | ||||
|         <div className='HslEditor-Inputs'> | ||||
|             <p>Hue</p> | ||||
|             <NumberInput value={Math.round(value.h)} placeholder="Hue" onChange={event => { | ||||
|                 setValue({...value, h: parseInt(event.target.value)}); | ||||
|             }}/> | ||||
|             <NumberInput value={Math.round(value.h)} onChange={setH}/> | ||||
|             <RangeInput value={Math.round(value.h)} min={0} max={360} onChange={setH}/> | ||||
| 
 | ||||
|             <p>Saturation</p> | ||||
|             <NumberInput value={Math.round(value.s)} placeholder="Saturation" onChange={event => { | ||||
|                 setValue({...value, s: parseInt(event.target.value)}); | ||||
|             }}/> | ||||
|             <NumberInput value={Math.round(value.s)} onChange={setS}/> | ||||
|             <RangeInput value={Math.round(value.s)} min={0} max={100} onChange={setS}/> | ||||
| 
 | ||||
|             <p>Lightness</p> | ||||
|             <NumberInput value={Math.round(value.l)} placeholder="Lightness" onChange={event => { | ||||
|                 setValue({...value, l: parseInt(event.target.value)}); | ||||
|             }}/> | ||||
|             <NumberInput value={Math.round(value.l)} onChange={setL}/> | ||||
|             <RangeInput value={Math.round(value.l)} min={0} max={100} onChange={setL}/> | ||||
|         </div> | ||||
|     </Column>; | ||||
| } | ||||
|  | @ -45,25 +42,30 @@ function ThemeChooserDialog({onClose}: { | |||
| }) { | ||||
|     const {hslTheme, setHslTheme} = useHslTheme(); | ||||
|     return <Dialog title="Theme editor" onClose={onClose}> | ||||
|         <Button | ||||
|             text="surprise me" | ||||
|             onClick={() => setHslTheme(_ => getRandomTheme())}/> | ||||
|         <HslEditor | ||||
|             name="background" | ||||
|             value={hslTheme.background} | ||||
|             setValue={value => setHslTheme(old => ({...old, background: value}))}/> | ||||
|         <HslEditor | ||||
|             name="primary" | ||||
|             value={hslTheme.primary} | ||||
|             setValue={value => setHslTheme(old => ({...old, primary: value}))}/> | ||||
|         <HslEditor | ||||
|             name="secondary" | ||||
|             value={hslTheme.secondary} | ||||
|             setValue={value => setHslTheme(old => ({...old, secondary: value}))}/> | ||||
|         <HslEditor | ||||
|             name="background" | ||||
|             value={hslTheme.tertiary} | ||||
|             setValue={value => setHslTheme(old => ({...old, tertiary: value}))}/> | ||||
|         <Row> | ||||
|             <Button | ||||
|                 text="surprise me" | ||||
|                 className='flex-grow' | ||||
|                 onClick={() => setHslTheme(_ => getRandomTheme())}/> | ||||
|         </Row> | ||||
|         <Column className='overflow-scroll'> | ||||
|             <HslEditor | ||||
|                 name="background" | ||||
|                 value={hslTheme.background} | ||||
|                 setValue={value => setHslTheme(old => ({...old, background: value}))}/> | ||||
|             <HslEditor | ||||
|                 name="primary" | ||||
|                 value={hslTheme.primary} | ||||
|                 setValue={value => setHslTheme(old => ({...old, primary: value}))}/> | ||||
|             <HslEditor | ||||
|                 name="secondary" | ||||
|                 value={hslTheme.secondary} | ||||
|                 setValue={value => setHslTheme(old => ({...old, secondary: value}))}/> | ||||
|             <HslEditor | ||||
|                 name="tertiary" | ||||
|                 value={hslTheme.tertiary} | ||||
|                 setValue={value => setHslTheme(old => ({...old, tertiary: value}))}/> | ||||
|         </Column> | ||||
|     </Dialog>; | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -1,3 +1,9 @@ | |||
| .Input { | ||||
|     background-color: var(--color-background); | ||||
|     color: var(--color-text); | ||||
|     padding: var(--padding-normal); | ||||
| } | ||||
| 
 | ||||
| .RangeInput { | ||||
|     appearance: auto; | ||||
| } | ||||
|  |  | |||
|  | @ -1,7 +1,7 @@ | |||
| import {ChangeEventHandler} from "react"; | ||||
| import {ChangeEventHandler} from 'react'; | ||||
| import './Input.css'; | ||||
| 
 | ||||
| export function TextInput( {onChange, className, value, placeholder, onEnter }: { | ||||
| export function TextInput({onChange, className, value, placeholder, onEnter}: { | ||||
|     onChange?: ChangeEventHandler<HTMLInputElement> | undefined; | ||||
|     className?: string; | ||||
|     value: string; | ||||
|  | @ -10,7 +10,7 @@ export function TextInput( {onChange, className, value, placeholder, onEnter }: | |||
| }) { | ||||
|     return <input | ||||
|         type="text" | ||||
|         className={'Input ' + (className?? '')} | ||||
|         className={'Input ' + (className ?? '')} | ||||
|         value={value} | ||||
|         placeholder={placeholder} | ||||
|         onChange={onChange} | ||||
|  | @ -21,8 +21,8 @@ export function TextInput( {onChange, className, value, placeholder, onEnter }: | |||
|     />; | ||||
| } | ||||
| 
 | ||||
| export function NumberInput( {onChange, className, value, placeholder, onEnter }: { | ||||
|     onChange?: ChangeEventHandler<HTMLInputElement> | undefined; | ||||
| export function NumberInput({onChange, className, value, placeholder, onEnter}: { | ||||
|     onChange?: (value: number) => void; | ||||
|     className?: string; | ||||
|     value: number; | ||||
|     placeholder?: string; | ||||
|  | @ -30,16 +30,47 @@ export function NumberInput( {onChange, className, value, placeholder, onEnter } | |||
| }) { | ||||
|     return <input | ||||
|         type="number" | ||||
|         className={'Input ' + (className?? '')} | ||||
|         className={'Input ' + (className ?? '')} | ||||
|         value={value} | ||||
|         placeholder={placeholder} | ||||
|         onChange={onChange} | ||||
|         onChange={event => { | ||||
|             if (!onChange) | ||||
|                 return; | ||||
|             onChange(parseFloat(event.target.value)); | ||||
|         }} | ||||
|         onKeyUp={event => { | ||||
|             if (onEnter && event.key === 'Enter') | ||||
|                 onEnter(); | ||||
|             if (!onEnter || event.key !== 'Enter') | ||||
|                 return; | ||||
|             onEnter(); | ||||
|         }} | ||||
|     />; | ||||
| } | ||||
| 
 | ||||
| export function RangeInput({onChange, className, value, placeholder, onEnter, min, max}: { | ||||
|     onChange?: (value: number) => void; | ||||
|     className?: string; | ||||
|     value: number; | ||||
|     min: number; | ||||
|     max: number; | ||||
|     placeholder?: string; | ||||
|     onEnter?: () => void; | ||||
| }) { | ||||
|     return <input | ||||
|         type="range" | ||||
|         className={'Input RangeInput ' + (className ?? '')} | ||||
|         value={value} min={min} max={max} | ||||
|         placeholder={placeholder} | ||||
|         onChange={event => { | ||||
|             if (!onChange) | ||||
|                 return; | ||||
|             onChange(parseFloat(event.target.value)); | ||||
|         }} | ||||
|         onKeyUp={event => { | ||||
|             if (!onEnter || event.key !== 'Enter') | ||||
|                 return; | ||||
|             onEnter(); | ||||
|         }} | ||||
|     />; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Vinzenz Schroeter
						Vinzenz Schroeter