ui(duplicates): show grandparent + parent in path strip

When two duplicates live in folders with the same parent name (e.g.
matching '2023' subfolders under different archives), showing only
the parent gave both thumbnails the same label. Walk one level up:
the path strip now renders '…/<grandparent>/<parent>' so the user
can always tell two copies apart at a glance. Filename still
surfaces via the title tooltip.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Claudio
2026-05-11 00:49:02 +02:00
parent f290784bf3
commit f14ea69223

View File

@@ -515,20 +515,25 @@ function formatBytes(n: number): string {
} }
/** Short label for the bottom path strip on a duplicate thumbnail. /** Short label for the bottom path strip on a duplicate thumbnail.
* Goal: tell two copies-with-the-same-filename apart at a glance, so * Goal: tell two copies-with-the-same-filename apart at a glance.
* we want the parent folder name — that's almost always the * Shows the last two folders ("…/<grandparent>/<parent>") so the
* discriminator (different shoots, different years, different * discriminator is visible even when both copies live under the
* upload sources). When the parent folder is unhelpful (e.g. the * same parent name (e.g. matching `2023` subfolders under different
* filename is itself sitting at the root) we fall back to the file * archives). The leading "…/" is always present when there's any
* basename. Long folder names get text-overflow-ellipsis'd by the * truncated prefix; the enclosing strip's `truncate` handles any
* enclosing strip's `truncate`. */ * excess width. */
function duplicatePathLabel(filepath: string): string { function duplicatePathLabel(filepath: string): string {
if (!filepath) return '' if (!filepath) return ''
const parts = filepath.split('/').filter(Boolean) const parts = filepath.split('/').filter(Boolean)
if (parts.length === 0) return filepath if (parts.length === 0) return filepath
if (parts.length === 1) return parts[0] // Strip the filename (last segment); only the directory chain
// The second-to-last segment IS the parent directory. // discriminates between copies with matching basenames.
return parts[parts.length - 2] const folders = parts.slice(0, -1)
if (folders.length === 0) return parts[0]
if (folders.length === 1) return `…/${folders[0]}`
const parent = folders[folders.length - 1]
const grandparent = folders[folders.length - 2]
return `…/${grandparent}/${parent}`
} }
/** Adapt a DuplicateGroupMember (the slim API shape) to a Photo, which /** Adapt a DuplicateGroupMember (the slim API shape) to a Photo, which