React-Frontend: Thread-Ansicht mit Antworten, Bearbeiten, Löschen

- EntryPage: Vorfahren, Fokus, Antworten mit unverändertem Markup
- Bearbeiten/Löschen für eigene Beiträge, Antwortformular mit
  Zwischenablage-Bild
- useMe(): eigenes Konto oder null (401 = nicht angemeldet)
- nach Änderungen Thread und Feeds invalidieren

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TiXsPUqw7oeomZ8wZrQW5q
This commit is contained in:
irrlicht
2026-09-26 23:34:31 +02:00
co-authored by Claude Opus 5.5
parent bd5c59bcad
commit b82c432bce
3 changed files with 200 additions and 2 deletions
+28
View File
@@ -0,0 +1,28 @@
import type { ClipboardEvent } from "react";
// pasteImage erlaubt Strg+V eines Bildes aus der Zwischenablage direkt im
// Formular: das Bild wandert in den File-Input (über DataTransfer, weil sich
// .files nicht direkt setzen lässt). Liegt kein Bild vor (Text o. Ä.), tun wir
// nichts und lassen den normalen Paste durchlaufen -> preventDefault nur, wenn
// wir wirklich ein Bild gegriffen haben. Gibt true zurück, wenn ein Bild
// übernommen wurde.
export function pasteImage(e: ClipboardEvent<HTMLFormElement>): boolean {
const item = [...(e.clipboardData?.items ?? [])].find(
(it) => it.kind === "file" && it.type.startsWith("image/"),
);
const original = item?.getAsFile();
if (!original) return false;
e.preventDefault();
// Browser benennen Clipboard-Bilder uneinheitlich ("grafik.png" o. Ä.) ->
// neu verpacken mit sprechendem Namen. Endung aus dem MIME-Typ, sonst png.
const ext = (original.type.split("/")[1] || "png").toLowerCase();
const file = new File([original], `zwischenablage.${ext}`, { type: original.type });
const input = e.currentTarget.querySelector<HTMLInputElement>("input[name='file']");
if (!input) return false;
const dt = new DataTransfer();
dt.items.add(file);
input.files = dt.files;
return true;
}