feat: disclose coordinate provenance
This commit is contained in:
@@ -18,7 +18,7 @@ const precision = coordinatePrecisionLabel(item.coordinate_precision);
|
||||
<FishSilhouette name={item.fish}/>
|
||||
<div class="spot-meta"><span><FishingIcon name="pin" size={14}/> {item.x}:{item.y} · {precision}</span><span><FishingIcon name="clock" size={14}/> {ago(item.last_confirmed_at)}</span></div>
|
||||
<p class="data-note">{item.explanation}</p>
|
||||
<DataPassport sources={item.sources} observedAt={item.last_confirmed_at} periodLabel={periodLabel} confidence={item.confidence_score} sampleSize={item.catches} independentPlayers={item.unique_players} coordinatePrecision={item.coordinate_precision} sourceConflicts={item.source_conflicts} status={limited ? "insufficient" : "verified"}/>
|
||||
<DataPassport sources={item.sources} observedAt={item.last_confirmed_at} periodLabel={periodLabel} confidence={item.confidence_score} sampleSize={item.catches} independentPlayers={item.unique_players} coordinatePrecision={item.coordinate_precision} coordinateSources={item.coordinate_sources} sourceConflicts={item.source_conflicts} status={limited ? "insufficient" : "verified"}/>
|
||||
<div class="bait-line"><TackleGlyph name={item.best_bait}/><div><span>{limited ? "Нужно ещё подтверждений" : item.best_bait ? "Работает сейчас" : "Наживка не указана"}</span><strong>{item.best_bait ?? "не указана"}</strong></div></div>
|
||||
<span class="card-cta">Открыть точку <span aria-hidden="true">→</span></span>
|
||||
</div>
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
---
|
||||
import SourceBadge from "./SourceBadge.astro";
|
||||
import { ago, coordinatePrecisionLabel, freshnessStatus, passportDisplayStatus } from "../lib/api";
|
||||
type Props = { sources: string[]; sourceUrl?: string | null; observedAt?: string | null; periodLabel?: string | null; completeness?: number | null; confidence?: number | null; sampleSize?: number | null; independentPlayers?: number | null; coordinatePrecision?: "exact" | "approximate" | "area" | "missing" | null; sourceConflicts?: string[]; status?: "verified" | "unverified" | "incomplete" | "insufficient" | "blocked" };
|
||||
const { sources, sourceUrl, observedAt, periodLabel = null, completeness = null, confidence = null, sampleSize = null, independentPlayers = null, coordinatePrecision = null, sourceConflicts = [], status = "verified" } = Astro.props as Props;
|
||||
type Props = { sources: string[]; sourceUrl?: string | null; observedAt?: string | null; periodLabel?: string | null; completeness?: number | null; confidence?: number | null; sampleSize?: number | null; independentPlayers?: number | null; coordinatePrecision?: "exact" | "approximate" | "area" | "missing" | null; coordinateSources?: string[]; sourceConflicts?: string[]; status?: "verified" | "unverified" | "incomplete" | "insufficient" | "blocked" };
|
||||
const { sources, sourceUrl, observedAt, periodLabel = null, completeness = null, confidence = null, sampleSize = null, independentPlayers = null, coordinatePrecision = null, coordinateSources = [], sourceConflicts = [], status = "verified" } = Astro.props as Props;
|
||||
const freshness = freshnessStatus(observedAt);
|
||||
const displayStatus = passportDisplayStatus(status, freshness, sourceConflicts.length > 0);
|
||||
const statusLabels = { verified: "Учтено", unverified: "Ждёт проверки", incomplete: "Неполные данные", insufficient: "Недостаточно данных", blocked: "Источник ограничен", conflict: "Источники расходятся", stale: "Данные устарели" };
|
||||
@@ -12,6 +12,7 @@ const completenessLabel = completeness == null ? "Не рассчитана" : `
|
||||
<header><span>Паспорт данных</span><strong data-passport-status={displayStatus}>{statusLabels[displayStatus]}</strong></header>
|
||||
<div class="data-passport__sources">{sources.map(source => <SourceBadge source={source} href={sources.length === 1 ? sourceUrl : null}/>)}</div>
|
||||
{sourceConflicts.length > 0 && <p class="data-passport__conflict"><strong>Источники расходятся:</strong> {sourceConflicts.join(" · ")}</p>}
|
||||
{coordinateSources.length > 0 && <details class="data-passport__coordinate-sources"><summary>Источники координат</summary><div>{coordinateSources.map(source => <SourceBadge source={source}/>)}</div></details>}
|
||||
<dl><div><dt>Свежесть</dt><dd data-freshness={freshness}>{freshness === "stale" ? "Устарело" : freshness === "fresh" ? "Свежо" : "Не указана"}{observedAt && ` · ${ago(observedAt)}`}</dd></div>{periodLabel && <div><dt>Период</dt><dd>{periodLabel}</dd></div>}<div><dt>Полнота</dt><dd>{completenessLabel}</dd></div><div><dt>Доверие</dt><dd>{confidence == null ? "После проверки" : `${confidence}%`}</dd></div>{sampleSize != null && <div><dt>Наблюдения</dt><dd>{sampleSize}</dd></div>}{independentPlayers != null && <div><dt>Игроки</dt><dd>{independentPlayers}</dd></div>}{coordinatePrecision && <div><dt>Координаты</dt><dd>{coordinatePrecisionLabel(coordinatePrecision)}</dd></div>}</dl>
|
||||
{sampleSize != null && sampleSize < 3 && <p class="data-passport__minimum">Минимум для рекомендации: 3 наблюдения.</p>}
|
||||
</section>
|
||||
|
||||
@@ -50,7 +50,7 @@ const breadcrumbs = spot ? { "@context": "https://schema.org", "@type": "Breadcr
|
||||
<div class="section-heading"><h2>Последние уловы</h2></div>
|
||||
{catches.length ? <CatchList catches={catches}/> : <div class="state compact-state"><h2>Уловов пока нет</h2><p>Для этой точки нет одобренных наблюдений.</p></div>}
|
||||
</div>
|
||||
<aside><span class="eyebrow">Оценка за 24 часа</span>{activity && level ? <><h2>{activity.activity_score} / 100</h2><strong data-activity-level={level.short}>{level.description}</strong><p>{activity.explanation}</p><DataPassport sources={activity.sources} observedAt={activity.last_confirmed_at} confidence={activity.confidence_score} sampleSize={activity.catches} independentPlayers={activity.unique_players} coordinatePrecision={activity.coordinate_precision} sourceConflicts={activity.source_conflicts} status={activity.catches < 3 ? "insufficient" : "verified"}/></> : <p>За последние 24 часа данных для расчёта нет.</p>}<h3 class="detail-action-heading">Что взять</h3>{spot.top_baits.length ? <ol>{spot.top_baits.map(name => <li><span class="tackle-label"><TackleGlyph name={name} size={24}/><span>{name}</span></span></li>)}</ol> : <p>Недостаточно данных.</p>}<p class="note">Учитываются только одобренные наблюдения.</p></aside>
|
||||
<aside><span class="eyebrow">Оценка за 24 часа</span>{activity && level ? <><h2>{activity.activity_score} / 100</h2><strong data-activity-level={level.short}>{level.description}</strong><p>{activity.explanation}</p><DataPassport sources={activity.sources} observedAt={activity.last_confirmed_at} confidence={activity.confidence_score} sampleSize={activity.catches} independentPlayers={activity.unique_players} coordinatePrecision={activity.coordinate_precision} coordinateSources={activity.coordinate_sources} sourceConflicts={activity.source_conflicts} status={activity.catches < 3 ? "insufficient" : "verified"}/></> : <p>За последние 24 часа данных для расчёта нет.</p>}<h3 class="detail-action-heading">Что взять</h3>{spot.top_baits.length ? <ol>{spot.top_baits.map(name => <li><span class="tackle-label"><TackleGlyph name={name} size={24}/><span>{name}</span></span></li>)}</ol> : <p>Недостаточно данных.</p>}<p class="note">Учитываются только одобренные наблюдения.</p></aside>
|
||||
</section>
|
||||
</>}
|
||||
</Layout>
|
||||
|
||||
@@ -2,6 +2,6 @@
|
||||
.data-passport header{display:flex;align-items:center;justify-content:space-between;gap:12px;margin-bottom:11px}.data-passport header>span{font:italic 15px Georgia,serif}.data-passport header strong{padding:4px 8px;border-radius:999px;background:var(--success-soft);color:var(--success);font-size:9px;text-transform:uppercase;letter-spacing:.06em}.data-passport header strong[data-passport-status="unverified"]{background:var(--info-soft);color:var(--info)}.data-passport header strong[data-passport-status="incomplete"],.data-passport header strong[data-passport-status="insufficient"],.data-passport header strong[data-passport-status="blocked"],.data-passport header strong[data-passport-status="stale"]{background:var(--warning-soft);color:var(--warning)}
|
||||
.data-passport__sources{display:flex;flex-wrap:wrap;gap:5px;margin-bottom:12px}.data-passport dl{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:8px;margin:0}.data-passport dl div{padding-top:8px;border-top:1px solid var(--border-soft)}.data-passport dt{font-size:8px;text-transform:uppercase;letter-spacing:.08em;color:var(--text-subtle)}.data-passport dd{margin:3px 0 0;font:400 12px Georgia,serif;color:var(--deep)}
|
||||
.data-passport__minimum{margin:12px 0 0;color:var(--warning);font-size:11px;line-height:1.4}
|
||||
.data-passport__conflict{margin:12px 0 0;padding:9px 10px;border-left:3px solid var(--warning);background:var(--warning-soft);color:var(--warning);font-size:11px;line-height:1.4}.data-passport__conflict strong{font-weight:750}
|
||||
.data-passport__conflict{margin:12px 0 0;padding:9px 10px;border-left:3px solid var(--warning);background:var(--warning-soft);color:var(--warning);font-size:11px;line-height:1.4}.data-passport__conflict strong{font-weight:750}.data-passport__coordinate-sources{margin-top:12px;border-top:1px solid var(--border-soft);padding-top:10px}.data-passport__coordinate-sources summary{cursor:pointer;color:var(--text-secondary);font-size:10px;font-weight:750;text-transform:uppercase;letter-spacing:.06em}.data-passport__coordinate-sources>div{display:flex;flex-wrap:wrap;gap:5px;margin-top:8px}
|
||||
.detail-card .data-passport,.detail-grid aside .data-passport{border-color:#ffffff20;background:#ffffff08;color:#fff}.detail-card .data-passport dd,.detail-grid aside .data-passport dd{color:#fff}.detail-card .data-passport dl div,.detail-grid aside .data-passport dl div{border-color:#ffffff1c}.detail-card .data-passport dt,.detail-grid aside .data-passport dt{color:#a9b8b5}.signal-card .data-passport{position:relative;z-index:1;margin-top:15px;background:#fffdf7;border-color:#ddd3af}
|
||||
@media(max-width:720px){.data-passport dl{grid-template-columns:repeat(2,minmax(0,1fr))}}@media(max-width:420px){.data-passport dl{grid-template-columns:1fr}.data-passport dl div{display:flex;justify-content:space-between;gap:10px}}
|
||||
|
||||
Reference in New Issue
Block a user