Bugfixes (Dark Mode, Dropdown-Kontrast, IP-Suche), Lesezeichen-Ausbau (Farbe, Beschreibung, Favicon), Zuletzt-besucht, Spaeter-lesen, kombinierter Import-Export, Scanner-Reconciliation, Admin-Ueberarbeitung

This commit is contained in:
2026-07-20 07:52:38 +02:00
parent dc91a9aba9
commit 96cf29fef4
37 changed files with 1988 additions and 494 deletions

View File

@@ -0,0 +1,24 @@
import { useQuery } from "@tanstack/react-query";
export interface ReadLaterItem {
id: string;
url: string;
displayName: string;
favicon: string | null;
savedAt: string;
}
async function fetchReadLater(): Promise<ReadLaterItem[]> {
const res = await fetch("/api/read-later");
if (!res.ok) {
throw new Error(`Später-lesen-Liste konnte nicht geladen werden (HTTP ${res.status})`);
}
return res.json();
}
export function useReadLater() {
return useQuery({
queryKey: ["read-later"],
queryFn: fetchReadLater,
});
}

View File

@@ -0,0 +1,29 @@
import { useQuery } from "@tanstack/react-query";
import type { Bookmark, Service } from "@launchpad/shared";
export type RecentVisitItem =
| (Service & { kind: "service" })
| (Bookmark & { kind: "bookmark" });
async function fetchRecentVisits(): Promise<RecentVisitItem[]> {
const res = await fetch("/api/recent-visits");
if (!res.ok) {
throw new Error(`Zuletzt besucht konnte nicht geladen werden (HTTP ${res.status})`);
}
return res.json();
}
export function useRecentVisits() {
return useQuery({
queryKey: ["recent-visits"],
queryFn: fetchRecentVisits,
});
}
export async function recordVisit(itemType: "service" | "bookmark", itemId: string): Promise<void> {
await fetch("/api/recent-visits", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ itemType, itemId }),
});
}

View File

@@ -0,0 +1,20 @@
import { useQuery } from "@tanstack/react-query";
export interface AppSettings {
recentVisitsLimit: number;
}
async function fetchSettings(): Promise<AppSettings> {
const res = await fetch("/api/settings");
if (!res.ok) {
throw new Error(`Einstellungen konnten nicht geladen werden (HTTP ${res.status})`);
}
return res.json();
}
export function useSettings() {
return useQuery({
queryKey: ["settings"],
queryFn: fetchSettings,
});
}