feat(search): Enter bleibt auf Seite + robustere Thumbnail-Erkennung
All checks were successful
Build & Publish Docker Image / build-and-push (push) Successful in 55s
All checks were successful
Build & Publish Docker Image / build-and-push (push) Successful in 55s
Startseite:
- Enter/Return löst die Suche jetzt sofort aus (cancelt den Debounce),
navigiert aber NICHT mehr auf /search. Der Anwender bleibt auf der
gleichen Seite mit Inline-Ergebnissen.
Thumbnail-Enrichment (searxng.ts):
- Regex-basierte og:image-Extraktion durch linkedom-parseHTML ersetzt.
- Neue Fallback-Kette (in dieser Reihenfolge):
1. <meta property/name = og:image | og:image:url | og:image:secure_url
| twitter:image | twitter:image:src>
2. <link rel="image_src" href="...">
3. JSON-LD image (auch tief in @graph; "image" als String, Array,
Objekt-mit-url)
4. Erstes <img> in article/main/.entry-content/.post-content/figure
- Relative URLs werden gegen die Seiten-URL zu absoluten aufgelöst
(z.B. /uploads/foo.jpg → http://host/uploads/foo.jpg).
- maxBytes von 256 KB auf 512 KB angehoben, damit JSON-LD-lastige
Recipe-Seiten nicht mitten im Script abgeschnitten werden.
Tests (97/97):
- Neu: JSON-LD-Image-Fallback-Test.
- Neu: Content-<img>-Fallback-Test mit relativer URL, die zur
absoluten aufgelöst wird.
This commit is contained in:
@@ -1,6 +1,5 @@
|
||||
<script lang="ts">
|
||||
import { onMount } from 'svelte';
|
||||
import { goto } from '$app/navigation';
|
||||
import type { SearchHit } from '$lib/server/recipes/search-local';
|
||||
import type { WebHit } from '$lib/server/search/searxng';
|
||||
import { randomQuote } from '$lib/quotes';
|
||||
@@ -24,6 +23,34 @@
|
||||
|
||||
let debounceTimer: ReturnType<typeof setTimeout> | null = null;
|
||||
|
||||
async function runSearch(q: string) {
|
||||
try {
|
||||
const res = await fetch(`/api/recipes/search?q=${encodeURIComponent(q)}`);
|
||||
const body = await res.json();
|
||||
if (query.trim() !== q) return;
|
||||
hits = body.hits;
|
||||
searchedFor = q;
|
||||
if (body.hits.length === 0) {
|
||||
webSearching = true;
|
||||
try {
|
||||
const wres = await fetch(`/api/recipes/search/web?q=${encodeURIComponent(q)}`);
|
||||
if (query.trim() !== q) return;
|
||||
if (!wres.ok) {
|
||||
const err = await wres.json().catch(() => ({}));
|
||||
webError = err.message ?? `HTTP ${wres.status}`;
|
||||
} else {
|
||||
const wbody = await wres.json();
|
||||
webHits = wbody.hits;
|
||||
}
|
||||
} finally {
|
||||
if (query.trim() === q) webSearching = false;
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
if (query.trim() === q) searching = false;
|
||||
}
|
||||
}
|
||||
|
||||
$effect(() => {
|
||||
const q = query.trim();
|
||||
if (debounceTimer) clearTimeout(debounceTimer);
|
||||
@@ -40,40 +67,18 @@
|
||||
webHits = [];
|
||||
webSearching = false;
|
||||
webError = null;
|
||||
debounceTimer = setTimeout(async () => {
|
||||
try {
|
||||
const res = await fetch(`/api/recipes/search?q=${encodeURIComponent(q)}`);
|
||||
const body = await res.json();
|
||||
if (query.trim() !== q) return;
|
||||
hits = body.hits;
|
||||
searchedFor = q;
|
||||
if (body.hits.length === 0) {
|
||||
webSearching = true;
|
||||
try {
|
||||
const wres = await fetch(`/api/recipes/search/web?q=${encodeURIComponent(q)}`);
|
||||
if (query.trim() !== q) return;
|
||||
if (!wres.ok) {
|
||||
const err = await wres.json().catch(() => ({}));
|
||||
webError = err.message ?? `HTTP ${wres.status}`;
|
||||
} else {
|
||||
const wbody = await wres.json();
|
||||
webHits = wbody.hits;
|
||||
}
|
||||
} finally {
|
||||
if (query.trim() === q) webSearching = false;
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
if (query.trim() === q) searching = false;
|
||||
}
|
||||
debounceTimer = setTimeout(() => {
|
||||
void runSearch(q);
|
||||
}, 300);
|
||||
});
|
||||
|
||||
function submit(e: SubmitEvent) {
|
||||
e.preventDefault();
|
||||
const q = query.trim();
|
||||
if (!q) return;
|
||||
void goto(`/search?q=${encodeURIComponent(q)}`);
|
||||
if (q.length <= 3) return;
|
||||
if (debounceTimer) clearTimeout(debounceTimer);
|
||||
searching = true;
|
||||
void runSearch(q);
|
||||
}
|
||||
|
||||
const activeSearch = $derived(query.trim().length > 3);
|
||||
|
||||
Reference in New Issue
Block a user