feat(library): RESET SETTING puts a frame back to the tile it came in with

This commit is contained in:
2026-10-11 12:00:22 +07:00
parent 791e7d093c
commit de5d42e272
4 changed files with 84 additions and 0 deletions
+46
View File
@@ -36,6 +36,7 @@ import {
remoteUrl,
removeFolder,
renameFolder,
resetEdit,
scanAsked,
scanBusy,
scanQueue,
@@ -1277,6 +1278,23 @@ function Catalogue({ admin }: { admin: boolean }) {
go(`/app?lib=${encodeURIComponent(photo.id)}`);
}, [t]);
// Put a frame back: the recipe goes, the graded tile goes with it, and the frame
// is drawn again from the negative. Everything this screen holds a copy of goes
// too — the URL it is painting and the mark that says the frame was ever touched
// — which is what makes the wall draw the tile it is about to be handed.
const resetSetting = useCallback(async (photo: LibraryPhoto) => {
const blob = await resetEdit(photo).catch(() => null);
dropThumbUrl(photo.id);
if (blob) cacheObjectUrl(photo.id, blob);
setEdited((prev) => {
if (!prev.has(photo.id)) return prev;
const next = new Set(prev);
next.delete(photo.id);
return next;
});
setTilesAt((n) => n + 1);
}, []);
const rootFolder = useMemo(() => {
if (!node) return folders[0] ?? null;
const normNode = normPath(node);
@@ -3163,6 +3181,24 @@ function Catalogue({ admin }: { admin: boolean }) {
</div>
) : null}
{/* The frame's own look, taken back: what the studio filed for it and the
tile it drew from it, so the shelf shows the picture the frame came in
with — the tile as it was first drawn, and the preview the file's own
develop gives. */}
<button
type="button"
className="lib-menu-item"
data-key="lib-photo-reset"
onClick={() => {
const photo = photoMenu.photo;
setPhotoMenu(null);
void resetSetting(photo);
}}
>
<span className="lib-menu-icon" aria-hidden="true">↺</span>
{t('lib.reset')}
</button>
<button
type="button"
className="lib-menu-item"
@@ -3378,6 +3414,16 @@ function cacheObjectUrl(id: string, blob: Blob): string {
return url;
}
// A tile the shelf is to draw again from the negative — the studio's grading taken
// back — is dropped here, the URL with it: the row is keyed on the tile the store
// holds, and a copy kept would answer every read after with the graded one.
function dropThumbUrl(id: string): void {
const held = globalThumbUrls.get(id);
if (!held) return;
URL.revokeObjectURL(held.url);
globalThumbUrls.delete(id);
}
function useThumbUrls(photos: LibraryPhoto[], also?: LibraryPhoto | null, stamp?: number): Record<string, string> {
const list = useMemo(() => (also && !photos.some((p) => p.id === also.id) ? [...photos, also] : photos), [photos, also]);