fix(thumbnails): Fassung in der Adresse, Sofortanzeige, kein Flackern

Gleicher Dateiname erzeugt keine neue Datei, sondern eine neue Fassung -
gleiche ID, gleiche Vorschaubild-Adresse. Die darf einen Tag im Browser
liegen, also zeigte die Kachel nach dem erneuten Hochladen bis zu 24
Stunden das alte Bild. Das erklaert, warum eine Drehung erst nach
mehreren Versuchen "ankam". Die Adresse traegt jetzt ?v=<Fassung>.

Vorschaubilder entstehen im Hintergrund; die Kachel fragt jetzt bis zu
fuenfmal nach, statt bis zum naechsten Neuladen ihr Ersatzsymbol zu
zeigen. Nur bei Bildern juenger als zwei Minuten - sonst fragte jede
dauerhaft fehlgeschlagene Datei bei jedem Oeffnen erneut. Gemessen: 608
ms bis zur Anzeige, ohne Neuladen.

Das Anheben der Kachel beim Ueberfahren ist raus: Steht der Zeiger auf
der Unterkante, rutscht sie unter ihm weg, mouseleave, sie faellt
zurueck, mouseenter - im Kreis, sichtbar als Flackern.

Dazu liest die EXIF-Auswertung jetzt 256 statt 64 KB und gibt bei einem
abgeschnittenen Block nicht mehr auf: Die Drehung steht vorn, das
eingebettete Vorschaubild dahinter.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
marcandClaude Opus 5 committed 2026-08-25 14:29:09 +02:00
1 parent 5b3658640e
commit 5ea66ea884
9 files changed
+145 -20

No files matched your search

+1 -1
View File
@@ -150,7 +150,7 @@ export default function TagsPage({ tagId, correspondentId, onOpenFolder }: Props
einer Liste reicht die kleine Fassung; die großen Cover
gehören zu den Kacheln. */}
{f.has_thumbnail ? (
<img src={filesApi.thumbnail(f.id)} alt="" draggable={false} style={{
<img src={filesApi.thumbnail(f.id, f.updated_at)} alt="" draggable={false} style={{
width: 22, height: 22, borderRadius: 4, objectFit: 'cover', flexShrink: 0,
}} />
) : (
+1 -1
View File
@@ -107,7 +107,7 @@ export default function TrashPage({ onUserChanged }: Props) {
{file.has_thumbnail ? (
<img
draggable={false}
src={filesApi.thumbnail(file.id)}
src={filesApi.thumbnail(file.id, file.version)}
alt=""
style={{ width: '100%', height: '100%', objectFit: 'cover' }}
onError={e => { e.currentTarget.style.display = 'none' }}