web: gate the newest film sims and the HSL mixer behind PRO
The last three PHOTO STYLE looks (B&W HIGH CONTRAST, LC STREETLIFE CLASSIC and LC STREETLIFE VIVID) and the whole mixer now belong to the account, the way PRO frames and the geotag already do: the chip wears the PRO badge, a guest who picks it is shown the way in, and the look stays off. The HSL tab keeps its place in the rail but offers the one PRO chip while locked, so the tab itself is not a dead end; a look that arrives without the chips — an imported .recipe, or a photo saved before the gate — is still caught where the gate bites, at export. STRAIGHTEN's scale turns with the wheel, one degree a notch, because the ruler is where the angle is being judged and reaching for a slider elsewhere loses the thread. The listener is native and stops the notch before the stage sees it, so the photo does not zoom under the pointer. The scale gives up its opaque card, its blur and its shadow: the frame it is levelling has to stay readable through it, so legibility comes from a text shadow on the heading and a drop shadow on the graduations instead.
This commit is contained in:
@@ -1,10 +1,14 @@
|
||||
import { useRef } from 'react';
|
||||
import { useEffect, useRef } from 'react';
|
||||
|
||||
// FRAME > ROTATE > STRAIGHTEN's ruler is not one of the chip row's stacked
|
||||
// knobs: it is a graduated scale lying across the foot of the photo, so the
|
||||
// angle is read off the picture it is levelling. Dragging anywhere on the scale
|
||||
// turns the photo by whole degrees; leaving the tool (another tab or button)
|
||||
// keeps the angle and takes the scale away — see App's dismiss effect.
|
||||
// turns the photo by whole degrees, and the wheel does the same one degree a
|
||||
// notch while the pointer is on the ruler — the photo underneath stays visible
|
||||
// through it (see `.straighten-ruler` in styles/app.css), because the whole
|
||||
// point of the scale is to be read against the frame it is levelling. Leaving
|
||||
// the tool (another tab or button) keeps the angle and takes the scale away —
|
||||
// see App's dismiss effect.
|
||||
const RANGE = 180; // degrees either side of 0, the whole circle across the width
|
||||
const TICK = 5; // minor tick spacing
|
||||
const MAJOR = 45; // labelled tick spacing
|
||||
@@ -19,7 +23,27 @@ export function StraightenRuler({
|
||||
onReset: () => void;
|
||||
}) {
|
||||
const scaleRef = useRef<HTMLDivElement>(null);
|
||||
const rootRef = useRef<HTMLDivElement>(null);
|
||||
const dragging = useRef(false);
|
||||
const live = useRef({ value, onChange });
|
||||
live.current = { value, onChange };
|
||||
|
||||
// The wheel belongs to the ruler while the pointer is on it: one notch is one
|
||||
// degree. The listener is native because React's is passive, and the notch
|
||||
// must not reach the stage — whose own wheel zooms the photo under it.
|
||||
useEffect(() => {
|
||||
const el = rootRef.current;
|
||||
if (!el) return;
|
||||
const onWheel = (e: WheelEvent) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
const s = live.current;
|
||||
const next = Math.max(-RANGE, Math.min(RANGE, 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);
|
||||
}, []);
|
||||
|
||||
// A pixel of travel is well under a degree at any sane width, so the reading
|
||||
// snaps to whole degrees however far the pointer has been dragged.
|
||||
@@ -35,7 +59,7 @@ export function StraightenRuler({
|
||||
const pctOf = (d: number) => ((d + RANGE) / (2 * RANGE)) * 100;
|
||||
|
||||
return (
|
||||
<div className="straighten-ruler" data-key="straighten-ruler" onPointerDown={(e) => e.stopPropagation()}>
|
||||
<div ref={rootRef} className="straighten-ruler" data-key="straighten-ruler" onPointerDown={(e) => e.stopPropagation()}>
|
||||
<div className="straighten-head">
|
||||
<span className="straighten-label">STRAIGHTEN</span>
|
||||
<b className={value !== 0 ? 'amber' : ''} data-key="straighten-value">
|
||||
|
||||
Reference in New Issue
Block a user