Build Dockerized MVP scaffold and records importer

This commit is contained in:
ik
2026-09-02 20:29:02 +07:00
parent a6f91a1329
commit d3a45248ef
39 changed files with 6638 additions and 13 deletions
+31
View File
@@ -0,0 +1,31 @@
---
import Layout from "../layouts/Layout.astro";
import ActivityCard from "../components/ActivityCard.astro";
import { api, type Activity, type DictionaryItem } from "../lib/api";
const params = Astro.url.searchParams;
const hours = params.get("hours") ?? "24";
const waterbody = params.get("waterbody") ?? "";
const fish = params.get("fish") ?? "";
const sort = params.get("sort") ?? "activity";
let items: Activity[] = [], fishes: DictionaryItem[] = [], waterbodies: DictionaryItem[] = [];
let unavailable = false;
try {
[items, fishes, waterbodies] = await Promise.all([
api<Activity[]>(`/api/v1/activity?hours=${hours}&waterbody=${waterbody}&fish=${fish}&sort=${sort}`),
api<DictionaryItem[]>("/api/v1/fishes"), api<DictionaryItem[]>("/api/v1/waterbodies")
]);
} catch { unavailable = true; }
---
<Layout title="Что клюёт сейчас — RF4 Spotter">
<section class="hero"><div><span class="eyebrow">Сводка активности</span><h1>Что клюёт<br/><em>прямо сейчас</em></h1></div><p>Свежие подтверждения, рабочие приманки и честная оценка надёжности данных.</p></section>
<form class="filters" method="get">
<label>Водоём<select name="waterbody"><option value="">Все водоёмы</option>{waterbodies.map(x => <option value={x.slug} selected={waterbody === x.slug}>{x.name_ru}</option>)}</select></label>
<label>Рыба<select name="fish"><option value="">Любая рыба</option>{fishes.map(x => <option value={x.slug} selected={fish === x.slug}>{x.name_ru}</option>)}</select></label>
<label>Период<select name="hours"><option value="6" selected={hours === "6"}>6 часов</option><option value="12" selected={hours === "12"}>12 часов</option><option value="24" selected={hours === "24"}>24 часа</option><option value="72" selected={hours === "72"}>72 часа</option></select></label>
<label>Сначала<select name="sort"><option value="activity" selected={sort === "activity"}>Активные</option><option value="confidence" selected={sort === "confidence"}>Надёжные</option><option value="freshness" selected={sort === "freshness"}>Свежие</option></select></label>
<button>Показать</button>
</form>
<div class="section-heading"><h2>Активные точки</h2><span>{items.length} комбинации</span></div>
{unavailable ? <div class="state"><h2>Источник временно недоступен</h2><p>Не показываем устаревшие догадки. Попробуйте обновить страницу позже.</p></div> : items.length ? <div class="grid">{items.map(item => <ActivityCard item={item} />)}</div> : <div class="state"><h2>За этот период данных нет</h2><p>Измените фильтры или выберите более длинный период.</p></div>}
</Layout>