feat(ui): compact Color Wheels & Match panel with MiniSlider rulers and 4-column color bands

This commit is contained in:
2026-10-16 08:56:49 +07:00
parent a841c7f5a0
commit 7a3b81b6ea
3 changed files with 139 additions and 78 deletions
+112 -77
View File
@@ -4028,7 +4028,7 @@ export function Workspace() {
<div>
<span className="dev-box-title" style={{ marginBottom: '6px', display: 'block' }}>COLOR BANDS</span>
<ChipRow
grid
grid4
chips={HSL_BANDS.map((b) => {
const band = recipe.adjustments.hslBands?.[b.id];
const moved = !!band && (band[0] !== 0 || band[1] !== 0 || band[2] !== 0);
@@ -4050,7 +4050,7 @@ export function Workspace() {
{hslBand && (
<div className="dev-subgroup" style={{ marginTop: '4px' }}>
<div className="dev-subgroup-title" style={{ display: 'flex', justifyContent: 'space-between' }}>
<div className="dev-subgroup-title" style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
<span>BAND: {HSL_BANDS.find((b) => b.id === hslBand)?.label}</span>
{(recipe.adjustments.hslBands?.[hslBand]?.[0] || recipe.adjustments.hslBands?.[hslBand]?.[1] || recipe.adjustments.hslBands?.[hslBand]?.[2]) ? (
<button
@@ -4082,39 +4082,45 @@ export function Workspace() {
};
return (
<>
<div className="dev-row">
<span className="dev-row-label">Hue</span>
<input
type="range"
min={-30}
max={30}
value={bandVals[0]}
onChange={(e) => updateBand(0, Number(e.target.value))}
/>
<span className="dev-row-value">{bandVals[0] > 0 ? `+${bandVals[0]}` : bandVals[0]}</span>
</div>
<div className="dev-row">
<span className="dev-row-label">Saturation</span>
<input
type="range"
min={-100}
max={100}
value={bandVals[1]}
onChange={(e) => updateBand(1, Number(e.target.value))}
/>
<span className="dev-row-value">{bandVals[1] > 0 ? `+${bandVals[1]}` : bandVals[1]}</span>
</div>
<div className="dev-row">
<span className="dev-row-label">Luminance</span>
<input
type="range"
min={-100}
max={100}
value={bandVals[2]}
onChange={(e) => updateBand(2, Number(e.target.value))}
/>
<span className="dev-row-value">{bandVals[2] > 0 ? `+${bandVals[2]}` : bandVals[2]}</span>
</div>
<MiniSlider
label="Hue"
value={bandVals[0]}
min={-10}
max={10}
step={1}
defaultValue={0}
format={(v) => v.toFixed(1)}
prefix={`dev-hsl-${hslBand}`}
dataKey={`dev-hsl-${hslBand}-hue`}
onChange={(v) => updateBand(0, v)}
onReset={() => updateBand(0, 0)}
/>
<MiniSlider
label="Saturation"
value={bandVals[1]}
min={-10}
max={10}
step={1}
defaultValue={0}
format={(v) => v.toFixed(1)}
prefix={`dev-hsl-${hslBand}`}
dataKey={`dev-hsl-${hslBand}-sat`}
onChange={(v) => updateBand(1, v)}
onReset={() => updateBand(1, 0)}
/>
<MiniSlider
label="Luminance"
value={bandVals[2]}
min={-10}
max={10}
step={1}
defaultValue={0}
format={(v) => v.toFixed(1)}
prefix={`dev-hsl-${hslBand}`}
dataKey={`dev-hsl-${hslBand}-lum`}
onChange={(v) => updateBand(2, v)}
onReset={() => updateBand(2, 0)}
/>
</>
);
})()}
@@ -4122,49 +4128,78 @@ export function Workspace() {
)}
<div className="dev-subgroup" style={{ marginTop: '4px' }}>
<div className="dev-subgroup-title">IMAGE MASTER</div>
<div className="dev-row">
<span className="dev-row-label">Hue</span>
<input
type="range"
min={-180}
max={180}
value={recipe.adjustments.hslHue ?? 0}
onChange={(e) => {
remember();
setAdjustment({ hslHue: Number(e.target.value) });
}}
/>
<span className="dev-row-value">{(recipe.adjustments.hslHue ?? 0) > 0 ? `+${recipe.adjustments.hslHue}` : recipe.adjustments.hslHue ?? 0}</span>
</div>
<div className="dev-row">
<span className="dev-row-label">Saturation</span>
<input
type="range"
min={-100}
max={100}
value={recipe.adjustments.hslSat ?? 0}
onChange={(e) => {
remember();
setAdjustment({ hslSat: Number(e.target.value) });
}}
/>
<span className="dev-row-value">{(recipe.adjustments.hslSat ?? 0) > 0 ? `+${recipe.adjustments.hslSat}` : recipe.adjustments.hslSat ?? 0}</span>
</div>
<div className="dev-row">
<span className="dev-row-label">Luminance</span>
<input
type="range"
min={-100}
max={100}
value={recipe.adjustments.hslLum ?? 0}
onChange={(e) => {
remember();
setAdjustment({ hslLum: Number(e.target.value) });
}}
/>
<span className="dev-row-value">{(recipe.adjustments.hslLum ?? 0) > 0 ? `+${recipe.adjustments.hslLum}` : recipe.adjustments.hslLum ?? 0}</span>
<div className="dev-subgroup-title" style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
<span>IMAGE MASTER</span>
{((recipe.adjustments.hslHue ?? 0) !== 0 || (recipe.adjustments.hslSat ?? 0) !== 0 || (recipe.adjustments.hslLum ?? 0) !== 0) ? (
<button
type="button"
style={{ background: 'none', border: 'none', color: 'var(--accent)', cursor: 'pointer', fontSize: '10px' }}
onClick={() => {
remember();
setAdjustment({ hslHue: 0, hslSat: 0, hslLum: 0 });
}}
>
RESET
</button>
) : null}
</div>
<MiniSlider
label="Hue"
value={recipe.adjustments.hslHue ?? 0}
min={-10}
max={10}
step={1}
defaultValue={0}
format={(v) => v.toFixed(1)}
prefix="dev-hsl-master"
dataKey="dev-hsl-master-hue"
onChange={(v) => {
remember();
setAdjustment({ hslHue: v });
}}
onReset={() => {
remember();
setAdjustment({ hslHue: 0 });
}}
/>
<MiniSlider
label="Saturation"
value={recipe.adjustments.hslSat ?? 0}
min={-10}
max={10}
step={1}
defaultValue={0}
format={(v) => v.toFixed(1)}
prefix="dev-hsl-master"
dataKey="dev-hsl-master-sat"
onChange={(v) => {
remember();
setAdjustment({ hslSat: v });
}}
onReset={() => {
remember();
setAdjustment({ hslSat: 0 });
}}
/>
<MiniSlider
label="Luminance"
value={recipe.adjustments.hslLum ?? 0}
min={-10}
max={10}
step={1}
defaultValue={0}
format={(v) => v.toFixed(1)}
prefix="dev-hsl-master"
dataKey="dev-hsl-master-lum"
onChange={(v) => {
remember();
setAdjustment({ hslLum: v });
}}
onReset={() => {
remember();
setAdjustment({ hslLum: 0 });
}}
/>
</div>
</div>
),