web: the mixer hangs a panel on the colour it read, and STRAIGHTEN becomes a scale on the photo
This commit is contained in:
@@ -14,6 +14,9 @@ export interface ChipDef {
|
||||
amberValue?: boolean;
|
||||
pro?: boolean;
|
||||
disabled?: boolean;
|
||||
// CSS colour drawn as a dot on the chip's leading edge — the HSL mixer's band
|
||||
// chips name a colour, so they show it too.
|
||||
color?: string;
|
||||
// Present when the chip itself can be dragged somewhere: the payload the drop
|
||||
// target reads back (the recipe's id, for the FAVORITED rail button).
|
||||
drag?: string;
|
||||
@@ -62,6 +65,7 @@ export function ChipRow({ chips }: { chips: ChipDef[] }) {
|
||||
}
|
||||
onClick={chip.onClick}
|
||||
>
|
||||
{chip.color ? <span className="chip-dot" data-color={chip.color} style={{ background: chip.color }} /> : null}
|
||||
{chip.label}
|
||||
{chip.value ? <span className="val">{chip.value}</span> : null}
|
||||
{chip.pro ? <span className="pro">PRO</span> : null}
|
||||
@@ -123,3 +127,57 @@ export function SliderRow({ slider }: { slider: SliderDef }) {
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// The same ruler without its own column: one knob of the mixer's inline panel,
|
||||
// where HUE/SAT/LUM sit side by side under the colour they are moving. Wheel
|
||||
// steps it, double-click puts it back to 0.
|
||||
export function MiniSlider({
|
||||
label,
|
||||
value,
|
||||
onChange,
|
||||
onReset,
|
||||
}: {
|
||||
label: string;
|
||||
value: number;
|
||||
onChange: (value: number) => void;
|
||||
onReset: () => void;
|
||||
}) {
|
||||
const ref = useRef<HTMLDivElement>(null);
|
||||
const live = useRef({ value, onChange });
|
||||
live.current = { value, onChange };
|
||||
useEffect(() => {
|
||||
const el = ref.current;
|
||||
if (!el) return;
|
||||
const onWheel = (e: WheelEvent) => {
|
||||
// The panel lives on the stage, whose own wheel zooms the photo: the
|
||||
// knob takes the notch and keeps it.
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
const s = live.current;
|
||||
const next = Math.max(-10, Math.min(10, s.value + (e.deltaY < 0 ? 1 : -1)));
|
||||
if (next !== s.value) s.onChange(next);
|
||||
};
|
||||
el.addEventListener('wheel', onWheel, { passive: false });
|
||||
return () => el.removeEventListener('wheel', onWheel);
|
||||
}, []);
|
||||
return (
|
||||
<div className="mini-slider" ref={ref} data-key={`hsl-knob-${label}`}>
|
||||
<div className="mini-head">
|
||||
<span>{label}</span>
|
||||
<b className={value !== 0 ? 'amber' : ''} data-key={`hsl-knob-${label}-value`}>
|
||||
{value > 0 ? `+${value}` : String(value)}
|
||||
</b>
|
||||
</div>
|
||||
<input
|
||||
type="range"
|
||||
min={-10}
|
||||
max={10}
|
||||
step={1}
|
||||
value={value}
|
||||
aria-label={label}
|
||||
onChange={(e) => onChange(Number(e.target.value))}
|
||||
onDoubleClick={onReset}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user