diff --git a/docker/frontend/src/App.tsx b/docker/frontend/src/App.tsx index 2638d9f..3088d27 100644 --- a/docker/frontend/src/App.tsx +++ b/docker/frontend/src/App.tsx @@ -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(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(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.