web: an FX chip that flips the photo to monochrome

It is a switch, not a look: it swaps the base filter for the mono stock and
swaps right back to the one the photo was wearing — name and sim included. The
adjustments are never touched, so a knob moved while it is on survives the trip
back, and the swap rides the undo stack like any other edit.
This commit is contained in:
2026-09-18 16:16:28 +07:00
parent d7d7be2c6b
commit 4d0d44170f
+24 -1
View File
@@ -256,6 +256,9 @@ export function Workspace() {
// Which look of the open frame's own history is standing on the stage, if one
// was picked from its column; a fresh edit or another frame clears it.
const [histPick, setHistPick] = useState<number | null>(null);
// FX's MONOCHROME switch remembers what the photo was wearing, so flipping it
// back returns that filter — and its sim name — instead of guessing PROVIA.
const monoPrev = useRef<{ baseFilter: Recipe['baseFilter']; simId: string | null; name: string } | null>(null);
const lookRef = useRef<Look | null>(null);
lookRef.current = { recipe, simId, frameId, crop, cropRect, cropApplied, rotation, markOn, markText, markStyle, useGeotag, gpsStyle };
// Twenty looks is enough to walk, but the oldest entry is the floor — the look
@@ -1331,6 +1334,23 @@ export function Workspace() {
// looks it carried before its last saves and its landing-strip consent.
const openPhoto = myPhotos.find((p) => p.id === openPhotoId);
// FX's MONOCHROME switch is not a look of its own: it swaps the base filter
// for the mono stock and swaps right back. Adjustments are never touched, so
// a knob moved while the switch is on survives the trip back.
const monoOn = recipe.baseFilter === 'monochrome';
const toggleMono = () => {
remember();
if (monoOn) {
const back = monoPrev.current ?? { baseFilter: 'provia' as Recipe['baseFilter'], simId: 'sim-provia', name: 'PROVIPES' };
setRecipe((prev) => ({ ...prev, baseFilter: back.baseFilter, name: back.name, isCustom: true }));
setSimId(back.simId);
} else {
monoPrev.current = { baseFilter: recipe.baseFilter, simId, name: recipe.name };
setRecipe((prev) => ({ ...prev, baseFilter: 'monochrome', name: 'MONOCHROME', isCustom: true }));
setSimId(null);
}
};
// The main chip row of the active tab, exactly the phone's per-tab sets.
const chips: ChipDef[] = (() => {
switch (tab) {
@@ -1401,7 +1421,10 @@ export function Workspace() {
groupChip('cxb'),
];
case 'fx':
return paramChips(PARAM_DEFS.filters);
return [
{ key: 'mono', label: 'MONOCHROME', active: monoOn, onClick: toggleMono },
...paramChips(PARAM_DEFS.filters),
];
case 'frame':
// WATERMARK is a chip like the rest: its own sub-panel opens as the next
// column (see the wm column in the render), so the frame chips stay put.