feat(web): Favoriten-Widget — Symbol-Ersatzweg aus dem Browser, Sortierpfeile im Bearbeitungsmodus

- FavoriteIcon (favorites-widget.tsx): dreistufiger Ersatzweg proxy ->
  direct -> none; Buchstaben-Platzhalter liegt immer darunter. Direktbild
  nur bei http/https-URL (getDirectFaviconSrc), referrerPolicy
  no-referrer, kein Drittanbieter-Favicon-Dienst. key={iconUrl|url}
  setzt die Stufe bei Aenderung zurueck; kein style.display-Hack mehr
- handleMove + Sortierpfeile im Bearbeitungsmodus (nur bei nicht-inline-
  Bearbeitung): optimistische Neuberechnung, PUT /favorites/order ueber
  reorderFavorites; erster/letzter Eintrag deaktiviert; Fehler ->
  Neuladen mit Fehlermeldung
- favorites-api.ts: reorderFavorites(widgetId, ids)
- de.json/en.json: widgets.favorites.moveUpButton/moveDownButton
- 5 neue Widget-Tests (Ersatzbild-Kette, Nicht-http-URL, Pfeilzustand,
  Klick, Fehlerpfad); 11 bestehende unveraendert gruen; volle Web-Suite
  64 Dateien/429 Tests und type-check gruen

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-09-17 14:40:09 +02:00
parent 2a562d0b14
commit b18ac25ccc
5 changed files with 355 additions and 25 deletions
+21
View File
@@ -2,6 +2,7 @@
* Favorites API client functions.
* Mirrors the NestJS FavoritesController routes (08-03).
* All calls use credentials: 'include' for cookie-based auth.
* PUT /favorites/order (reorderFavorites) added 260917-jdd.
*/
const API_URL = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:3001';
@@ -69,6 +70,26 @@ export async function updateFavorite(
return res.json();
}
/**
* Persist the display order for a widget's favorites (260917-jdd).
* `ids` is the full id list in the desired order; the server responds with
* the favorites of this widget in the new order.
*/
export async function reorderFavorites(
widgetId: string,
ids: string[],
): Promise<FavoriteLink[]> {
const res = await fetch(`${API_URL}/favorites/order`, {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
credentials: 'include',
body: JSON.stringify({ widgetId, ids }),
});
if (!res.ok) throw new Error('Failed to reorder favorites');
return res.json();
}
/**
* Delete a favorite link by id.
*/