完成Mixer功能的设计。

This commit is contained in:
徐涛 2025-01-07 13:51:32 +08:00
parent 251e86b0b4
commit a94626c192
3 changed files with 115 additions and 0 deletions

View File

@ -5,6 +5,7 @@ import { Harmonies } from './pages/Harmonies';
import { Home } from './pages/Home';
import { LightenDarken } from './pages/LightenDarken';
import { MainLayout } from './pages/MainLayout';
import { Mixer } from './pages/Mixer';
import { NewScheme } from './pages/NewScheme';
import { SchemeDetail } from './pages/SchemeDetail';
import { SchemeNotFound } from './pages/SchemeNotFound';
@ -33,6 +34,7 @@ const routes = createBrowserRouter([
{ path: 'tones', element: <Tones /> },
{ path: 'tints-shades', element: <TintsShades /> },
{ path: 'lighten-darken', element: <LightenDarken /> },
{ path: 'mixer', element: <Mixer /> },
],
},
]);

View File

@ -0,0 +1,34 @@
@layer pages {
.mixer_workspace {
flex-direction: column;
}
.mixer_content {
width: 100%;
display: flex;
flex-direction: row;
justify-content: space-around;
align-items: flex-start;
gap: var(--spacing-m);
.mixer_column {
display: flex;
flex-direction: column;
gap: var(--spacing-s);
font-size: var(--font-size-s);
.color_value_mode {
display: flex;
flex-direction: row;
align-items: center;
gap: var(--spacing-s);
font-size: var(--font-size-s);
}
.colors_booth {
display: flex;
flex-direction: row;
justify-content: center;
align-items: stretch;
gap: var(--spacing-xs);
min-height: 12em;
}
}
}
}

79
src/pages/Mixer.tsx Normal file
View File

@ -0,0 +1,79 @@
import cx from 'clsx';
import { useMemo, useState } from 'react';
import { useColorFunction } from '../ColorFunctionContext';
import { ColorPicker } from '../components/ColorPicker';
import { FlexColorStand } from '../components/FlexColorStand';
import { HSegmentedControl } from '../components/HSegmentedControl';
import { LabeledPicker } from '../components/LabeledPicker';
import { ScrollArea } from '../components/ScrollArea';
import styles from './Mixer.module.css';
export function Mixer() {
const { colorFn } = useColorFunction();
const [basicColor, setBasicColor] = useState('000000');
const [mixColor, setMixColor] = useState('000000');
const [mixRatio, setMixRatio] = useState(0);
const [mode, setMode] = useState<'hex' | 'rgb' | 'hsl' | 'lab' | 'oklch'>('hex');
const mixedColor = useMemo(() => {
try {
if (!colorFn) {
return '000000';
}
const mixed = colorFn.mix(basicColor, mixColor, mixRatio / 100);
return mixed;
} catch (e) {
console.error('[Mix Color]', e);
}
return '000000';
}, [basicColor, mixColor, mixRatio]);
return (
<div className={cx('workspace', styles.mixer_workspace)}>
<header>
<h3>Color Mixer</h3>
<p>Make a new color by mixing two colors.</p>
</header>
<ScrollArea enableY>
<div className={styles.mixer_content}>
<div className={styles.mixer_column}>
<h5>Basic Color</h5>
<ColorPicker color={basicColor} onSelect={setBasicColor} />
</div>
<div className={styles.mixer_column}>
<h5>Mix Color</h5>
<ColorPicker color={mixColor} onSelect={setMixColor} />
<LabeledPicker
title="Mix Ratio"
value={mixRatio}
onChange={setMixRatio}
min={0}
max={100}
step={1}
unit="%"
/>
</div>
<div className={styles.mixer_column}>
<h5>Mix Result</h5>
<div className={styles.colors_booth}>
<FlexColorStand color={mixedColor} valueMode={mode} />
</div>
<div className={styles.color_value_mode}>
<label>Copy color value in</label>
<HSegmentedControl
options={[
{ label: 'HEX', value: 'hex' },
{ label: 'RGB', value: 'rgb' },
{ label: 'HSL', value: 'hsl' },
{ label: 'LAB', value: 'lab' },
{ label: 'OKLCH', value: 'oklch' },
]}
value={mode}
onChange={setMode}
/>
</div>
</div>
</div>
</ScrollArea>
</div>
);
}