color-q/src/pages/Palette.tsx
2025-02-10 14:28:34 +08:00

126 lines
4.4 KiB
TypeScript

import cx from 'clsx';
import { useAtom } from 'jotai';
import { useEffect, useMemo, useState } from 'react';
import { ColorPicker } from '../components/ColorPicker';
import { HSegmentedControl } from '../components/HSegmentedControl';
import { Labeled } from '../components/Labeled';
import { LabeledPicker } from '../components/LabeledPicker';
import { ScrollArea } from '../components/ScrollArea';
import { Switch } from '../components/Switch';
import { PaletteColors } from '../page-components/auto-palette/PaletteColors';
import { currentPickedColor } from '../stores/colors';
import styles from './Palette.module.css';
type ColorModes = 'hex' | 'rgb' | 'hsl' | 'lab' | 'oklch';
export function AutomaticPalette() {
const [selectedColor, setSelectedColor] = useAtom(currentPickedColor);
const [useReferenceColor, setUseReferenceColor] = useState(false);
const [swatchAmount, setSwatchAmount] = useState(5);
const maxBias = useMemo(
() => (swatchAmount > 3 ? Math.floor(swatchAmount / 2) - 1 : 0),
[swatchAmount],
);
const [referenceBias, setReferenceBias] = useState(0);
const [minLightness, setMinLightness] = useState(10);
const [maxLightness, setMaxLightness] = useState(90);
const [mode, setMode] = useState<ColorModes>('hex');
useEffect(() => {
if (useReferenceColor) {
setReferenceBias(0);
}
}, [swatchAmount, useReferenceColor]);
return (
<div className={cx('workspace', styles.palette_workspace)}>
<header>
<h3>Automatic Palette</h3>
<p>
Automatically generate a color palette suitable for UI color matching according to the
given color algorithm.
</p>
</header>
<ScrollArea enableY>
<section className={styles.palette_section}>
<aside className={styles.function_side}>
<div>
<h5>Reference Color</h5>
<ColorPicker color={selectedColor} onSelect={(color) => setSelectedColor(color)} />
</div>
<div>
<h5>Palette Setting</h5>
<Labeled label="Use Reference Color" inline>
<Switch checked={useReferenceColor} onChange={setUseReferenceColor} />
</Labeled>
<LabeledPicker
title="Swatch Amount"
min={3}
max={12}
step={1}
value={swatchAmount}
onChange={(value) => setSwatchAmount(value)}
/>
<LabeledPicker
title="Reference Bias"
min={-maxBias}
max={maxBias}
step={1}
value={referenceBias}
onChange={setReferenceBias}
disabled={!useReferenceColor || maxBias < 2}
/>
<LabeledPicker
title="Min Lightness"
min={0}
max={100}
step={1}
value={minLightness}
onChange={setMinLightness}
unit="%"
/>
<LabeledPicker
title="Max Lightness"
min={0}
max={100}
step={1}
value={maxLightness}
onChange={setMaxLightness}
unit="%"
/>
</div>
</aside>
<div className={styles.palette_content}>
<h5>Generated Palette</h5>
<div className={styles.colors_booth}>
<PaletteColors
color={selectedColor}
swatchAmount={swatchAmount}
min={minLightness / 100}
max={maxLightness / 100}
useReference={useReferenceColor}
referenceBias={referenceBias}
copyMode={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={(v) => setMode(v as ColorModes)}
/>
</div>
</div>
</section>
</ScrollArea>
</div>
);
}