feat: search waterbody catalog

This commit is contained in:
ik
2026-09-21 20:09:11 +07:00
parent 1c4065a26c
commit 4c4849ad2c
+7 -3
View File
@@ -6,14 +6,17 @@ import WaterbodyMark from "../../components/WaterbodyMark.astro";
import Pagination from "../../components/Pagination.astro";
import { api, type DictionaryItem } from "../../lib/api";
const params = Astro.url.searchParams;
const search = params.get("q")?.trim() ?? "";
const pageLimit = 48;
const requestedOffset = Number(params.get("offset") ?? 0);
let offset = Number.isInteger(requestedOffset) && requestedOffset >= 0 ? requestedOffset : 0;
let waters: DictionaryItem[] = [], allWaters: DictionaryItem[] = [], unavailable = false;
try {
allWaters = await api<DictionaryItem[]>("/api/v1/waterbodies?limit=500");
if (allWaters.length > 0 && offset >= allWaters.length) offset = Math.floor((allWaters.length - 1) / pageLimit) * pageLimit;
waters = allWaters.slice(offset, offset + pageLimit);
const matchingWaters = search ? allWaters.filter(item => item.name_ru.toLocaleLowerCase("ru-RU").includes(search.toLocaleLowerCase("ru-RU"))) : allWaters;
if (matchingWaters.length > 0 && offset >= matchingWaters.length) offset = Math.floor((matchingWaters.length - 1) / pageLimit) * pageLimit;
waters = matchingWaters.slice(offset, offset + pageLimit);
allWaters = matchingWaters;
} catch { unavailable = true; }
if (unavailable) {
Astro.response.status = 503;
@@ -23,6 +26,7 @@ if (unavailable) {
---
<Layout title="Все водоёмы Russian Fishing 4 — RF4 Spotter" description="Каталог водоёмов RF4 со свежими точками, рыбами, приманками и прозрачными источниками данных." noindex={unavailable} errorPage={unavailable}>
<PageHero eyebrow="Карта водоёмов RF4" title="Водоёмы" description="Откройте водоём, чтобы увидеть активные виды рыб и последние подтверждённые точки." variant="water" count={allWaters.length} />
{unavailable ? <StatePanel tone="unavailable" title="Каталог временно недоступен" description="Не показываем непроверенный список. Попробуйте обновить страницу позже." /> : <nav class="catalog-grid catalog-grid--waters content-grid" aria-label="Водоёмы">{waters.map((water,index) => <a href={`/waterbodies/${water.slug}`}><span>Водоём · {String(offset + index + 1).padStart(2,"0")}</span><strong>{water.name_ru}</strong><i>Открыть <b>→</b></i><WaterbodyMark identity={water.slug}/></a>)}</nav>}
<form class="record-filters content-grid" method="get" aria-label="Поиск водоёма"><label>Поиск по названию<input name="q" value={search} maxlength="100" placeholder="Например, Вьюнок" /></label><button data-action="primary">Найти</button>{search && <a data-action="quiet" href="/waterbodies">Сбросить</a>}</form>
{unavailable ? <StatePanel tone="unavailable" title="Каталог временно недоступен" description="Не показываем непроверенный список. Попробуйте обновить страницу позже." /> : waters.length ? <nav class="catalog-grid catalog-grid--waters content-grid" aria-label="Водоёмы">{waters.map((water,index) => <a href={`/waterbodies/${water.slug}`}><span>Водоём · {String(offset + index + 1).padStart(2,"0")}</span><strong>{water.name_ru}</strong><i>Открыть <b>→</b></i><WaterbodyMark identity={water.slug}/></a>)}</nav> : <StatePanel title="Ничего не найдено" description="Попробуйте изменить запрос или открыть полный каталог водоёмов." />}
{!unavailable && <Pagination path="/waterbodies" params={params} total={allWaters.length} limit={pageLimit} offset={offset} itemLabel="водоёмов" />}
</Layout>