web: undo/redo, a clean preview, and a histogram that stays put

Four things the studio owed the visitor:
- UNDO/REDO in the header, so a look can be taken back and put back without
  reloading the photo; a fresh edit clears the redo trail.
- Opening a saved frame, or picking a look out of its history, now drops the
  stale preview buffer instead of leaving the previous render on the stage.
- The picked history look is marked in the accent, so it is plain which look
  the photo is wearing.
- The histogram is re-clamped against the photo box on resize, so opening a
  chip column no longer pushes the overlay past the edge of the canvas.

The 'NEW SAVES: FILM STRIP' chip goes: a save already lands in the strip.
This commit is contained in:
2026-09-18 15:47:08 +07:00
parent 78fe2b097b
commit abaa980f93
4 changed files with 167 additions and 39 deletions
+10 -1
View File
@@ -108,10 +108,19 @@ export function Histogram({ url, onClose }: { url: string; onClose: () => void }
setPos({ x: Math.max(8, b.width - box.getBoundingClientRect().width - 12), y: 12 });
}, [pos]);
// The photo's own box is what the frame is parked against, and it shrinks
// when a column opens beside the stage — not only when the window does. So
// the frame watches that box, not the window, and is pulled back inside it.
useEffect(() => {
const onResize = () => setPos((p) => (p ? clamp(p.x, p.y) : p));
window.addEventListener('resize', onResize);
return () => window.removeEventListener('resize', onResize);
const wrap = boxRef.current?.parentElement;
const ro = wrap ? new ResizeObserver(onResize) : null;
ro?.observe(wrap as Element);
return () => {
window.removeEventListener('resize', onResize);
ro?.disconnect();
};
}, [clamp]);
const start = (e: React.PointerEvent<HTMLDivElement>) => {