add range sliders

This commit is contained in:
Vinzenz Schroeter 2024-05-07 14:08:21 +02:00
parent 59459019fc
commit e854f77bdc
4 changed files with 90 additions and 45 deletions

View file

@ -0,0 +1,6 @@
.HslEditor-Inputs {
display: grid;
column-gap: var(--padding-normal);
grid-template-columns: auto auto auto;
grid-template-rows: auto;
}

View file

@ -2,40 +2,37 @@ import Button from './components/Button.tsx';
import {getRandomTheme, HSL, hslToString, useHslTheme} from './theme.tsx'; import {getRandomTheme, HSL, hslToString, useHslTheme} from './theme.tsx';
import Dialog from './components/Dialog.tsx'; import Dialog from './components/Dialog.tsx';
import {useState} from 'react'; import {useState} from 'react';
import {NumberInput} from './components/Input.tsx'; import {NumberInput, RangeInput} from './components/Input.tsx';
import Row from './components/Row.tsx'; import Row from './components/Row.tsx';
import Column from './components/Column.tsx'; import Column from './components/Column.tsx';
import './ThemeChooser.css';
function HslEditor({name, value, setValue}: { function HslEditor({name, value, setValue}: {
name: string; name: string;
value: HSL; value: HSL;
setValue: (value: HSL) => void 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> return <Column>
<Row> <Row>
<div className="" style={{background: hslToString(value), border: '1px solid white', aspectRatio: '1'}}/> <div className="" style={{background: hslToString(value), border: '1px solid white', aspectRatio: '1'}}/>
<p>{name}</p> <p>{name}</p>
</Row> </Row>
<div style={{ <div className='HslEditor-Inputs'>
display: 'grid',
columnGap: 'var(--padding-normal)',
gridTemplateColumns: 'auto auto',
gridTemplateRows: 'auto'
}}>
<p>Hue</p> <p>Hue</p>
<NumberInput value={Math.round(value.h)} placeholder="Hue" onChange={event => { <NumberInput value={Math.round(value.h)} onChange={setH}/>
setValue({...value, h: parseInt(event.target.value)}); <RangeInput value={Math.round(value.h)} min={0} max={360} onChange={setH}/>
}}/>
<p>Saturation</p> <p>Saturation</p>
<NumberInput value={Math.round(value.s)} placeholder="Saturation" onChange={event => { <NumberInput value={Math.round(value.s)} onChange={setS}/>
setValue({...value, s: parseInt(event.target.value)}); <RangeInput value={Math.round(value.s)} min={0} max={100} onChange={setS}/>
}}/>
<p>Lightness</p> <p>Lightness</p>
<NumberInput value={Math.round(value.l)} placeholder="Lightness" onChange={event => { <NumberInput value={Math.round(value.l)} onChange={setL}/>
setValue({...value, l: parseInt(event.target.value)}); <RangeInput value={Math.round(value.l)} min={0} max={100} onChange={setL}/>
}}/>
</div> </div>
</Column>; </Column>;
} }
@ -45,25 +42,30 @@ function ThemeChooserDialog({onClose}: {
}) { }) {
const {hslTheme, setHslTheme} = useHslTheme(); const {hslTheme, setHslTheme} = useHslTheme();
return <Dialog title="Theme editor" onClose={onClose}> return <Dialog title="Theme editor" onClose={onClose}>
<Button <Row>
text="surprise me" <Button
onClick={() => setHslTheme(_ => getRandomTheme())}/> text="surprise me"
<HslEditor className='flex-grow'
name="background" onClick={() => setHslTheme(_ => getRandomTheme())}/>
value={hslTheme.background} </Row>
setValue={value => setHslTheme(old => ({...old, background: value}))}/> <Column className='overflow-scroll'>
<HslEditor <HslEditor
name="primary" name="background"
value={hslTheme.primary} value={hslTheme.background}
setValue={value => setHslTheme(old => ({...old, primary: value}))}/> setValue={value => setHslTheme(old => ({...old, background: value}))}/>
<HslEditor <HslEditor
name="secondary" name="primary"
value={hslTheme.secondary} value={hslTheme.primary}
setValue={value => setHslTheme(old => ({...old, secondary: value}))}/> setValue={value => setHslTheme(old => ({...old, primary: value}))}/>
<HslEditor <HslEditor
name="background" name="secondary"
value={hslTheme.tertiary} value={hslTheme.secondary}
setValue={value => setHslTheme(old => ({...old, tertiary: value}))}/> setValue={value => setHslTheme(old => ({...old, secondary: value}))}/>
<HslEditor
name="tertiary"
value={hslTheme.tertiary}
setValue={value => setHslTheme(old => ({...old, tertiary: value}))}/>
</Column>
</Dialog>; </Dialog>;
} }

View file

@ -1,3 +1,9 @@
.Input { .Input {
background-color: var(--color-background);
color: var(--color-text);
padding: var(--padding-normal); padding: var(--padding-normal);
} }
.RangeInput {
appearance: auto;
}

View file

@ -1,7 +1,7 @@
import {ChangeEventHandler} from "react"; import {ChangeEventHandler} from 'react';
import './Input.css'; import './Input.css';
export function TextInput( {onChange, className, value, placeholder, onEnter }: { export function TextInput({onChange, className, value, placeholder, onEnter}: {
onChange?: ChangeEventHandler<HTMLInputElement> | undefined; onChange?: ChangeEventHandler<HTMLInputElement> | undefined;
className?: string; className?: string;
value: string; value: string;
@ -10,7 +10,7 @@ export function TextInput( {onChange, className, value, placeholder, onEnter }:
}) { }) {
return <input return <input
type="text" type="text"
className={'Input ' + (className?? '')} className={'Input ' + (className ?? '')}
value={value} value={value}
placeholder={placeholder} placeholder={placeholder}
onChange={onChange} onChange={onChange}
@ -21,8 +21,8 @@ export function TextInput( {onChange, className, value, placeholder, onEnter }:
/>; />;
} }
export function NumberInput( {onChange, className, value, placeholder, onEnter }: { export function NumberInput({onChange, className, value, placeholder, onEnter}: {
onChange?: ChangeEventHandler<HTMLInputElement> | undefined; onChange?: (value: number) => void;
className?: string; className?: string;
value: number; value: number;
placeholder?: string; placeholder?: string;
@ -30,16 +30,47 @@ export function NumberInput( {onChange, className, value, placeholder, onEnter }
}) { }) {
return <input return <input
type="number" type="number"
className={'Input ' + (className?? '')} className={'Input ' + (className ?? '')}
value={value} value={value}
placeholder={placeholder} placeholder={placeholder}
onChange={onChange} onChange={event => {
if (!onChange)
return;
onChange(parseFloat(event.target.value));
}}
onKeyUp={event => { onKeyUp={event => {
if (onEnter && event.key === 'Enter') if (!onEnter || event.key !== 'Enter')
onEnter(); 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();
}} }}
/>; />;
} }