feat(home): SvelteKit snapshot für echte State-Preservation beim Back
All checks were successful
Build & Publish Docker Image / build-and-push (push) Successful in 1m16s
All checks were successful
Build & Publish Docker Image / build-and-push (push) Successful in 1m16s
Vorher (Commit 1055a67): Query in URL gespiegelt, Back triggerte einen
frischen Request — zwar schnell, aber Scroll-Position + Ergebnisreihen-
folge nicht garantiert konstant.
Jetzt: SvelteKit's snapshot-API speichert query + hits + webHits +
searchedFor + webError in der History-Entry. Beim Zurück-Navigieren aus
/preview oder /recipes/[id] stellt restore() den exakten UI-Zustand
wieder her — ohne Fetch. Scroll-Position wird von SvelteKit ohnehin auto-
restored.
Der Debounce-Effekt hat jetzt einen skipNextSearch-Flag, der beim
Restore true gesetzt wird, damit das Setzen von query keinen neuen
Search-Request auslöst. Erstmaliges Tippen nach dem Restore arbeitet
wieder ganz normal mit Debounce.
Die URL-Synchronisation (?q=…) bleibt bestehen — für Bookmarks und
Share-Links. Snapshot überlagert den URL-Load in der Ordnung:
restore → onMount sieht query bereits korrekt gesetzt → kein Double-Work.
This commit is contained in:
@@ -2,6 +2,7 @@
|
|||||||
import { onMount } from 'svelte';
|
import { onMount } from 'svelte';
|
||||||
import { page } from '$app/stores';
|
import { page } from '$app/stores';
|
||||||
import { CookingPot, Globe, X } from 'lucide-svelte';
|
import { CookingPot, Globe, X } from 'lucide-svelte';
|
||||||
|
import type { Snapshot } from './$types';
|
||||||
import type { SearchHit } from '$lib/server/recipes/search-local';
|
import type { SearchHit } from '$lib/server/recipes/search-local';
|
||||||
import type { WebHit } from '$lib/server/search/searxng';
|
import type { WebHit } from '$lib/server/search/searxng';
|
||||||
import { randomQuote } from '$lib/quotes';
|
import { randomQuote } from '$lib/quotes';
|
||||||
@@ -18,6 +19,27 @@
|
|||||||
let webSearching = $state(false);
|
let webSearching = $state(false);
|
||||||
let webError = $state<string | null>(null);
|
let webError = $state<string | null>(null);
|
||||||
let searchedFor = $state<string | null>(null);
|
let searchedFor = $state<string | null>(null);
|
||||||
|
let skipNextSearch = false;
|
||||||
|
|
||||||
|
type SearchSnapshot = {
|
||||||
|
query: string;
|
||||||
|
hits: SearchHit[];
|
||||||
|
webHits: WebHit[];
|
||||||
|
searchedFor: string | null;
|
||||||
|
webError: string | null;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const snapshot: Snapshot<SearchSnapshot> = {
|
||||||
|
capture: () => ({ query, hits, webHits, searchedFor, webError }),
|
||||||
|
restore: (v) => {
|
||||||
|
query = v.query;
|
||||||
|
hits = v.hits;
|
||||||
|
webHits = v.webHits;
|
||||||
|
searchedFor = v.searchedFor;
|
||||||
|
webError = v.webError;
|
||||||
|
skipNextSearch = true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
async function loadRecent() {
|
async function loadRecent() {
|
||||||
const res = await fetch('/api/recipes/search');
|
const res = await fetch('/api/recipes/search');
|
||||||
@@ -100,6 +122,12 @@
|
|||||||
$effect(() => {
|
$effect(() => {
|
||||||
const q = query.trim();
|
const q = query.trim();
|
||||||
if (debounceTimer) clearTimeout(debounceTimer);
|
if (debounceTimer) clearTimeout(debounceTimer);
|
||||||
|
if (skipNextSearch) {
|
||||||
|
// Snapshot-Restore hat hits/webHits/searchedFor wiederhergestellt —
|
||||||
|
// nicht erneut fetchen.
|
||||||
|
skipNextSearch = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (q.length <= 3) {
|
if (q.length <= 3) {
|
||||||
hits = [];
|
hits = [];
|
||||||
webHits = [];
|
webHits = [];
|
||||||
|
|||||||
Reference in New Issue
Block a user