fix(library): strictly enforce single folder photo filtering unless subfolder option is enabled

This commit is contained in:
2026-10-08 17:37:06 +07:00
parent e39a53663e
commit 3d12635a62
+32 -10
View File
@@ -960,13 +960,33 @@ function Catalogue() {
go(`/app?lib=${encodeURIComponent(photo.id)}`);
}, [t]);
const rootName = node ? node.split('/')[0] : null;
const rootFolder = useMemo(() => {
if (!node) return folders[0] ?? null;
const normNode = (node || '').replace(/\\/g, '/');
return (
folders.find((f) => {
const normF = (f.name || '').replace(/\\/g, '/');
return normNode === normF || normNode.startsWith(`${normF}/`);
}) ?? folders[0] ?? null
);
}, [folders, node]);
const rootName = rootFolder ? rootFolder.name : null;
// A row's folder as the walk spells it: '' for the picked folder itself, the
// path under it for a subfolder, and nothing for a row belonging to another
// folder — that one is not a folder of this roll.
const relOf = (key: string): string | null =>
!rootName ? null : key === rootName ? '' : key.startsWith(`${rootName}/`) ? `${key.slice(rootName.length + 1)}/` : null;
const relOf = useCallback(
(key: string): string | null => {
if (!rootName) return null;
const normRoot = normPath(rootName);
const normKey = normPath(key);
if (normKey === normRoot) return '';
if (normKey.startsWith(`${normRoot}/`)) return `${normKey.slice(normRoot.length + 1)}/`;
return null;
},
[rootName]
);
// The tree: one row per picked folder, then one per subfolder, indented by its
// depth — the folders the walk has named, whether or not a frame has been read
@@ -1089,20 +1109,22 @@ function Catalogue() {
// it sits in, so the screen never opens on a node that is not drawn.
useEffect(() => {
if (!loaded || !node || nodes.some((n) => n.key === node)) return;
setNode(nodes.find((n) => n.key === node.split('/')[0])?.key ?? nodes[0]?.key ?? null);
}, [loaded, node, nodes]);
setNode(nodes.find((n) => n.key === rootName || n.key === normPath(rootName ?? ''))?.key ?? nodes[0]?.key ?? null);
}, [loaded, node, nodes, rootName]);
// What the open node draws: its own frames, and — when the reader has asked
// for the branch — the ones in every subfolder under it.
const shown = useMemo(() => {
if (!rootName) return photos;
const normRoot = rootName.replace(/\\/g, '/');
const normNode = (node ?? '').replace(/\\/g, '/');
const normRoot = normPath(rootName);
const normNode = normPath(node ?? '');
const dir = normNode === normRoot ? '' : normNode.slice(normRoot.length + 1);
const below = dir === '' ? (p: LibraryPhoto) => (p.dir ?? '').replace(/\\/g, '/') !== '' : (p: LibraryPhoto) => (p.dir ?? '').replace(/\\/g, '/').startsWith(`${dir}/`);
const below = dir === ''
? (p: LibraryPhoto) => normPath(p.dir ?? '') !== ''
: (p: LibraryPhoto) => normPath(p.dir ?? '').startsWith(`${dir}/`);
return photos.filter((p) => {
const pFolder = (p.folder ?? '').replace(/\\/g, '/');
const pDir = (p.dir ?? '').replace(/\\/g, '/');
const pFolder = normPath(p.folder ?? '');
const pDir = normPath(p.dir ?? '');
return pFolder === normRoot && (pDir === dir || (deep && below(p)));
});
}, [deep, node, photos, rootName]);