Compare commits
5
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
aed541c70c | ||
|
|
54a1e6c042 | ||
|
|
d8b0c08aaa | ||
|
|
99c1498810 | ||
|
|
7567ac9191 |
@@ -93,7 +93,7 @@ FastAPI ─ PostgreSQL 17
|
||||
|
||||
Production CSP ограничивает browser-запросы текущим доменом и отдельным files-доменом для изображений, запрещает plugins, frames, inline handlers и attributes, eval, wildcard и HTTP. Page scripts и scoped styles принудительно выпускаются отдельными same-origin `_astro`-ассетами; единственное временное inline-исключение остаётся для динамического JSON-LD и описано в [CSP inventory](docs/csp-inventory.md).
|
||||
|
||||
Тема по умолчанию следует системному `prefers-color-scheme`, а переключатель в header позволяет выбрать системную, светлую или тёмную палитру. Выбор сохраняется в cookie и применяется Astro при SSR без localStorage-only flash и ослабления CSP. Базовые поверхности, каталог, навигационная леска, паспорта данных и состояния загрузки уже используют семантические light/dark-токены; ограничения дальнейшей миграции описаны в [dark-theme.md](docs/dark-theme.md).
|
||||
Тема по умолчанию следует системному `prefers-color-scheme`, а переключатель в header позволяет выбрать системную, светлую или тёмную палитру. Выбор сохраняется в cookie и применяется Astro при SSR без localStorage-only flash и ослабления CSP; browser chrome синхронизируется парными `theme-color`. Публичные и административные поверхности, формы, таблицы, provenance/status-плашки и фирменная SVG/CSS-графика используют семантические light/dark-токены и базовый forced-colors layer; ограничения и оставшаяся визуальная приёмка описаны в [dark-theme.md](docs/dark-theme.md).
|
||||
|
||||
Gitea Actions workflow `.gitea/workflows/ci.yml` на каждый push и pull request проверяет Python, миграции на чистой PostgreSQL, Astro build и полный Compose/Playwright-сценарий. При падении E2E сохраняются логи контейнеров и Playwright-артефакты.
|
||||
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
"start_url": "/",
|
||||
"scope": "/",
|
||||
"display": "standalone",
|
||||
"background_color": "#f2f5ee",
|
||||
"theme_color": "#082226",
|
||||
"background_color": "#071719",
|
||||
"theme_color": "#071719",
|
||||
"icons": [
|
||||
{ "src": "/icon-192.png", "sizes": "192x192", "type": "image/png", "purpose": "any" },
|
||||
{ "src": "/icon-512.png", "sizes": "512x512", "type": "image/png", "purpose": "any" },
|
||||
|
||||
@@ -14,5 +14,5 @@ const { catches } = Astro.props as { catches: Catch[] };
|
||||
})}
|
||||
</div>
|
||||
<style>
|
||||
time{margin-top:7px;color:#496357;font-size:10px;font-weight:750}
|
||||
time{margin-top:7px;color:var(--text-secondary);font-size:10px;font-weight:750}
|
||||
</style>
|
||||
|
||||
@@ -31,6 +31,6 @@ const groups = [...signals.reduce((map, signal) => {
|
||||
})}</div>
|
||||
</section>
|
||||
<style>
|
||||
.repeat-note{position:relative;z-index:1;margin:-8px 0 10px!important;padding:6px 9px;border-left:2px solid #6b8d74;color:#496357!important;font-size:10px!important}
|
||||
.repeat-note{position:relative;z-index:1;margin:-8px 0 10px!important;padding:6px 9px;border-left:2px solid var(--border-strong);color:var(--text-secondary)!important;font-size:10px!important}
|
||||
.signal-card__top .source-strip{margin:0}
|
||||
</style>
|
||||
|
||||
@@ -52,7 +52,8 @@ const jsonLd = JSON.stringify({
|
||||
<link rel="icon" href="/favicon-32.png" sizes="32x32" type="image/png" />
|
||||
<link rel="apple-touch-icon" href="/apple-touch-icon.png" />
|
||||
<link rel="manifest" href="/site.webmanifest" />
|
||||
<meta name="theme-color" content="#082226" />
|
||||
<meta name="theme-color" content="#f2f5ee" media={theme === "system" ? "(prefers-color-scheme: light)" : theme === "light" ? "all" : "not all"} data-theme-color="light" />
|
||||
<meta name="theme-color" content="#071719" media={theme === "system" ? "(prefers-color-scheme: dark)" : theme === "dark" ? "all" : "not all"} data-theme-color="dark" />
|
||||
<meta property="og:locale" content="ru_RU" />
|
||||
<meta property="og:type" content="website" />
|
||||
<meta property="og:site_name" content="RF4 Spotter" />
|
||||
@@ -94,6 +95,7 @@ const jsonLd = JSON.stringify({
|
||||
<script>
|
||||
const root = document.documentElement;
|
||||
const themeButtons = document.querySelectorAll<HTMLButtonElement>("[data-theme-option]");
|
||||
const themeColors = document.querySelectorAll<HTMLMetaElement>("[data-theme-color]");
|
||||
const allowedThemes = new Set(["system", "light", "dark"]);
|
||||
|
||||
const applyTheme = (value: string) => {
|
||||
@@ -103,6 +105,10 @@ const jsonLd = JSON.stringify({
|
||||
themeButtons.forEach((button) => {
|
||||
button.setAttribute("aria-pressed", String(button.dataset.themeOption === theme));
|
||||
});
|
||||
themeColors.forEach((meta) => {
|
||||
const color = meta.dataset.themeColor;
|
||||
meta.media = theme === "system" ? `(prefers-color-scheme: ${color})` : color === theme ? "all" : "not all";
|
||||
});
|
||||
const secure = location.protocol === "https:" ? "; Secure" : "";
|
||||
document.cookie = `rf4-theme=${theme}; Max-Age=31536000; Path=/; SameSite=Lax${secure}`;
|
||||
};
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
.activity-timeline{width:min(1180px,calc(100% - 64px));margin:20px auto 0;padding:25px 28px;border-radius:14px;background:#fff;border:1px solid #d9e1da}.activity-timeline header{display:flex;align-items:end;justify-content:space-between;gap:20px}.activity-timeline h2{font:400 29px Georgia,serif;margin:5px 0 0}.activity-timeline header p{margin:0;color:#71817e;font-size:10px}
|
||||
.timeline-chart{height:145px;display:grid;grid-template-columns:repeat(6,1fr);gap:8px;margin-top:18px;padding-top:8px;border-bottom:1px solid #a9bbb1;background:repeating-linear-gradient(to top,transparent 0,transparent 35px,#dce5de 36px)}.timeline-slot{position:relative;display:grid;grid-template-rows:1fr auto;place-items:center}.timeline-line{position:relative;align-self:end;width:2px;height:var(--meter-level);min-height:10px;background:#3f7779}.timeline-line i{position:absolute;left:0;top:0;width:12px;height:18px;margin:-4px 0 0 -5px;border-radius:7px 7px 9px 9px;background:linear-gradient(#ff785a 0 35%,var(--lime) 35%);box-shadow:0 0 0 4px #c9f45b18}.timeline-slot strong{position:absolute;top:2px;font:400 14px Georgia,serif;color:#365c5e}.timeline-slot small{position:absolute;bottom:-20px;color:#71817e;font-size:8px;white-space:nowrap}.activity-timeline+*{margin-top:42px}
|
||||
.activity-timeline{width:min(1180px,calc(100% - 64px));margin:20px auto 0;padding:25px 28px;border-radius:14px;background:var(--surface);border:1px solid var(--border-soft)}.activity-timeline header{display:flex;align-items:end;justify-content:space-between;gap:20px}.activity-timeline h2{font:400 29px Georgia,serif;margin:5px 0 0}.activity-timeline header p{margin:0;color:var(--text-muted);font-size:10px}
|
||||
.timeline-chart{height:145px;display:grid;grid-template-columns:repeat(6,1fr);gap:8px;margin-top:18px;padding-top:8px;border-bottom:1px solid var(--border);background:repeating-linear-gradient(to top,transparent 0,transparent 35px,var(--graphic-grid) 36px)}.timeline-slot{position:relative;display:grid;grid-template-rows:1fr auto;place-items:center}.timeline-line{position:relative;align-self:end;width:2px;height:var(--meter-level);min-height:10px;background:var(--graphic-line)}.timeline-line i{position:absolute;left:0;top:0;width:12px;height:18px;margin:-4px 0 0 -5px;border-radius:7px 7px 9px 9px;background:linear-gradient(#ff785a 0 35%,var(--lime) 35%);box-shadow:0 0 0 4px color-mix(in srgb,var(--lime) 12%,transparent)}.timeline-slot strong{position:absolute;top:2px;font:400 14px Georgia,serif;color:var(--text)}.timeline-slot small{position:absolute;bottom:-20px;color:var(--text-muted);font-size:8px;white-space:nowrap}.activity-timeline+*{margin-top:42px}
|
||||
@media(max-width:720px){.activity-timeline{width:calc(100% - 28px);padding:20px 15px}.activity-timeline header{display:block}.activity-timeline header p{margin-top:6px}.timeline-slot small{font-size:7px}}
|
||||
|
||||
@@ -1 +1 @@
|
||||
.coordinate-radar{position:relative;flex:0 0 180px;width:180px;height:180px;display:grid;place-items:center;color:var(--lime)}.coordinate-radar svg{position:absolute;inset:0;width:100%;height:100%;fill:none;stroke:#ffffff20;stroke-width:1}.coordinate-radar .radar-sweep{fill:#c9f45b0d;stroke:#c9f45b38}.coordinate-radar .radar-mark{fill:var(--lime);stroke:none}.coordinate-radar .radar-pulse{stroke:var(--lime);stroke-width:2;opacity:.55}.coordinate-radar strong{position:relative;display:grid;grid-template-columns:auto auto 1px auto auto;align-items:baseline;gap:4px;padding:7px 10px;border-radius:7px;background:#082226d9;font:400 20px Georgia,serif}.coordinate-radar strong small{font:700 8px Inter,sans-serif;color:#9eb0ad}.coordinate-radar strong i{width:1px;height:14px;background:#ffffff35}.radar-north{position:absolute;top:3px;font-size:8px;letter-spacing:.15em}.radar-caption{position:absolute;bottom:1px;color:#91a5a1;font-size:8px;text-transform:uppercase;letter-spacing:.12em}@media(max-width:720px){.coordinate-radar{display:none}}
|
||||
.coordinate-radar{position:relative;flex:0 0 180px;width:180px;height:180px;display:grid;place-items:center;color:var(--lime)}.coordinate-radar svg{position:absolute;inset:0;width:100%;height:100%;fill:none;stroke:color-mix(in srgb,var(--text-on-dark) 13%,transparent);stroke-width:1}.coordinate-radar .radar-sweep{fill:color-mix(in srgb,var(--lime) 5%,transparent);stroke:color-mix(in srgb,var(--lime) 22%,transparent)}.coordinate-radar .radar-mark{fill:var(--lime);stroke:none}.coordinate-radar .radar-pulse{stroke:var(--lime);stroke-width:2;opacity:.55}.coordinate-radar strong{position:relative;display:grid;grid-template-columns:auto auto 1px auto auto;align-items:baseline;gap:4px;padding:7px 10px;border-radius:7px;background:color-mix(in srgb,var(--deep) 85%,transparent);font:400 20px Georgia,serif}.coordinate-radar strong small{font:700 8px Inter,sans-serif;color:color-mix(in srgb,var(--text-on-dark) 65%,transparent)}.coordinate-radar strong i{width:1px;height:14px;background:color-mix(in srgb,var(--text-on-dark) 22%,transparent)}.radar-north{position:absolute;top:3px;font-size:8px;letter-spacing:.15em}.radar-caption{position:absolute;bottom:1px;color:color-mix(in srgb,var(--text-on-dark) 60%,transparent);font-size:8px;text-transform:uppercase;letter-spacing:.12em}@media(max-width:720px){.coordinate-radar{display:none}}
|
||||
|
||||
@@ -1 +1 @@
|
||||
.fish-silhouette{fill:currentColor;color:#315f63;pointer-events:none}.fish-silhouette .fish-eye{fill:var(--paper)}.fish-silhouette .fish-detail{fill:none;stroke:currentColor;stroke-width:1.8;stroke-linecap:round}.spot-main{position:relative}.spot-main>.fish-silhouette{position:absolute;right:2px;top:38px;opacity:.075}.catalog-grid>a{position:relative;overflow:hidden}.catalog-grid>a>.fish-silhouette{position:absolute;right:20px;bottom:12px;opacity:.12;transform:rotate(-4deg);transition:opacity var(--motion-base) var(--ease-out),transform var(--motion-base) var(--ease-out)}.catalog-grid>a:hover>.fish-silhouette{opacity:.2;transform:rotate(-2deg) translateX(-2px)}@media(max-width:720px){.spot-main>.fish-silhouette{width:68px;right:0;opacity:.055}}
|
||||
.fish-silhouette{fill:currentColor;color:var(--decorative-water);pointer-events:none}.fish-silhouette .fish-eye{fill:var(--paper)}.fish-silhouette .fish-detail{fill:none;stroke:currentColor;stroke-width:1.8;stroke-linecap:round}.spot-main{position:relative}.spot-main>.fish-silhouette{position:absolute;right:2px;top:38px;opacity:.075}.catalog-grid>a{position:relative;overflow:hidden}.catalog-grid>a>.fish-silhouette{position:absolute;right:20px;bottom:12px;opacity:.12;transform:rotate(-4deg);transition:opacity var(--motion-base) var(--ease-out),transform var(--motion-base) var(--ease-out)}.catalog-grid>a:hover>.fish-silhouette{opacity:.2;transform:rotate(-2deg) translateX(-2px)}@media(max-width:720px){.spot-main>.fish-silhouette{width:68px;right:0;opacity:.055}}
|
||||
|
||||
@@ -1 +1 @@
|
||||
.tackle-glyph{--tackle-accent:#dd8b42;flex:none;color:var(--tackle-accent);stroke:currentColor;stroke-width:1.7;stroke-linecap:round;stroke-linejoin:round}.tackle-glyph[data-tone="1"]{--tackle-accent:#759d35}.tackle-glyph[data-tone="2"]{--tackle-accent:#3f8588}.tackle-glyph[data-tone="3"]{--tackle-accent:#9a6a9d}.tackle-glyph[data-tone="4"]{--tackle-accent:#bd6250}.tackle-glyph__fill{fill:color-mix(in srgb,currentColor 78%,var(--surface));stroke:currentColor}.tackle-glyph__stroke{stroke-width:3}.tackle-label{display:inline-flex;align-items:center;gap:8px;min-width:0}.tackle-label>span{min-width:0}.best-lure .tackle-glyph{color:var(--lime)}.bait-line>.tackle-glyph{width:25px;height:25px}.catch-list .tackle-label{margin-top:3px;color:var(--text-muted);font-size:12px}.detail-grid aside li .tackle-label{width:100%}
|
||||
.tackle-glyph{--tackle-accent:var(--tackle-orange);flex:none;color:var(--tackle-accent);stroke:currentColor;stroke-width:1.7;stroke-linecap:round;stroke-linejoin:round}.tackle-glyph[data-tone="1"]{--tackle-accent:var(--tackle-green)}.tackle-glyph[data-tone="2"]{--tackle-accent:var(--tackle-teal)}.tackle-glyph[data-tone="3"]{--tackle-accent:var(--tackle-violet)}.tackle-glyph[data-tone="4"]{--tackle-accent:var(--tackle-red)}.tackle-glyph__fill{fill:color-mix(in srgb,currentColor 78%,var(--surface));stroke:currentColor}.tackle-glyph__stroke{stroke-width:3}.tackle-label{display:inline-flex;align-items:center;gap:8px;min-width:0}.tackle-label>span{min-width:0}.best-lure .tackle-glyph{color:var(--lime)}.bait-line>.tackle-glyph{width:25px;height:25px}.catch-list .tackle-label{margin-top:3px;color:var(--text-muted);font-size:12px}.detail-grid aside li .tackle-label{width:100%}
|
||||
|
||||
@@ -35,6 +35,22 @@
|
||||
--decorative-water: light-dark(#315f63, #72a9ad);
|
||||
--skeleton: light-dark(#e7ede7, #1c3537);
|
||||
--skeleton-strong: light-dark(#d8e2d8, #294548);
|
||||
--status-healthy: light-dark(#5f8c26, #a8d85e);
|
||||
--status-warning: light-dark(#9a741d, #e8c768);
|
||||
--status-changed: light-dark(#a44236, #ff9587);
|
||||
--source-official: light-dark(#815713, #e3b65b);
|
||||
--source-rf4db: light-dark(#286581, #74bee3);
|
||||
--source-rf4stat: light-dark(#60499a, #b7a2ed);
|
||||
--source-rf4map: light-dark(#2f704f, #79c79e);
|
||||
--source-rf4posts: light-dark(#984a33, #ee9a7e);
|
||||
--source-players: light-dark(#526b1c, #add066);
|
||||
--graphic-line: light-dark(#3f7779, #79b5b8);
|
||||
--graphic-grid: light-dark(#dce5de, #294244);
|
||||
--tackle-orange: light-dark(#b96b27, #f0a55f);
|
||||
--tackle-green: light-dark(#648b2b, #a8cf62);
|
||||
--tackle-teal: light-dark(#34777a, #78bec1);
|
||||
--tackle-violet: light-dark(#845787, #c795ca);
|
||||
--tackle-red: light-dark(#a95041, #ed8e7c);
|
||||
}
|
||||
|
||||
:root[data-theme="light"] { color-scheme: light; }
|
||||
@@ -84,7 +100,13 @@
|
||||
.signal-card dt { color: light-dark(#776f56, #b9ae82); }
|
||||
.signal-card .missing-note { background: light-dark(#efe5bd, #453c20); color: light-dark(#6b550f, #f0d889); }
|
||||
.signal-card .data-passport { background: light-dark(#fffdf7, #172628); border-color: light-dark(#ddd3af, #59605a); }
|
||||
.source-chip { background: color-mix(in srgb, var(--chip) 24%, var(--surface-elevated)); }
|
||||
.source-chip { background: color-mix(in srgb, var(--chip) 24%, var(--surface-elevated)); box-shadow: 0 5px 14px var(--shadow-color); }
|
||||
.source-chip[data-source="rf4-official"] { --chip: var(--source-official); }
|
||||
.source-chip[data-source="rf4db"] { --chip: var(--source-rf4db); }
|
||||
.source-chip[data-source^="rf4stat"] { --chip: var(--source-rf4stat); }
|
||||
.source-chip[data-source="rf4map"] { --chip: var(--source-rf4map); }
|
||||
.source-chip[data-source="rf4posts-spot"] { --chip: var(--source-rf4posts); }
|
||||
.source-chip[data-source="players"] { --chip: var(--source-players); }
|
||||
.notice.success { background: var(--success-soft); color: var(--success); }
|
||||
.notice.warning, .data-quality { background: var(--warning-soft); color: var(--warning); }
|
||||
.notice.error { background: var(--danger-soft); color: var(--danger); }
|
||||
@@ -120,6 +142,46 @@
|
||||
.state::before { border-color: var(--border-strong); }
|
||||
.state::after { border-color: var(--decorative-water); box-shadow: 0 -7px 0 -6px var(--decorative-water),0 7px 0 -6px var(--decorative-water); }
|
||||
.data-passport header strong[data-passport-status="unverified"] { background: var(--info-soft); color: var(--info); }
|
||||
|
||||
.record-table, .report-form, .moderation-card { background: var(--surface-elevated); border-color: var(--border-subtle); box-shadow: 0 30px 80px var(--shadow-color); }
|
||||
.record-row, .optional-fields, .moderation-summary dl div, .moderation-actions { border-color: var(--border-subtle); }
|
||||
.record-head, .no-proof { background: var(--surface-raised); }
|
||||
.record-head span, .record-row > span, .record-row > time, .report-form label,
|
||||
.field-help, .privacy, .moderation-summary > p, .moderation-summary dt,
|
||||
.moderation-actions label { color: var(--text-secondary); }
|
||||
.report-form input, .report-form textarea, .report-form select,
|
||||
.moderation-actions textarea { background: var(--surface-control); color: var(--text-primary); border-color: var(--border-strong); }
|
||||
.report-form input:focus, .report-form textarea:focus, .report-form select:focus { border-color: var(--focus); box-shadow: 0 0 0 3px color-mix(in srgb,var(--focus) 28%,transparent); }
|
||||
.report-form input:user-invalid, .report-form select:user-invalid { border-color: var(--danger); }
|
||||
.moderation-summary blockquote { background: var(--surface-raised); color: var(--text-secondary); }
|
||||
|
||||
.data-legend { border-color: var(--border-strong); }
|
||||
.data-legend__intro p, .legend-sources > div > span, .legend-quality span { color: var(--text-secondary); }
|
||||
.legend-sources > div { border-color: var(--border-subtle); }
|
||||
.legend-quality > div { background: var(--surface-elevated); }
|
||||
.legend-quality i { background: var(--success-soft); color: var(--success); }
|
||||
.legend-quality i[data-quality="unverified"] { background: var(--info-soft); color: var(--info); }
|
||||
.legend-quality i[data-quality="incomplete"] { background: var(--warning-soft); color: var(--warning); }
|
||||
.health-state i { background: var(--status-warning); }
|
||||
.source-health-grid [data-status="healthy"] .health-state i { background: var(--status-healthy); }
|
||||
.source-health-grid [data-status="source_changed"] .health-state i { background: var(--status-changed); }
|
||||
.activity-timeline header p { color: var(--text-secondary); }
|
||||
.timeline-line { background: var(--graphic-line); }
|
||||
.timeline-line i { box-shadow: 0 0 0 4px color-mix(in srgb,var(--lime) 12%,transparent); }
|
||||
.coordinate-radar svg { stroke: color-mix(in srgb,var(--text-on-dark) 13%,transparent); }
|
||||
.coordinate-radar .radar-sweep { fill: color-mix(in srgb,var(--lime) 5%,transparent); stroke: color-mix(in srgb,var(--lime) 22%,transparent); }
|
||||
.admin-dashboard-grid > section, .admin-kpis > a, .admin-kpis > article,
|
||||
.source-health-grid article { background: var(--surface-elevated); border-color: var(--border-subtle); }
|
||||
.admin-history li small, .source-health-grid p, .health-state { color: var(--text-secondary); }
|
||||
@media print {
|
||||
:root { color-scheme: light; }
|
||||
}
|
||||
|
||||
@media (forced-colors: active) {
|
||||
.theme-switcher, .theme-switcher button, .spot-card, .record-table,
|
||||
.report-form, .moderation-card, .catalog-grid > a, .data-passport,
|
||||
.source-chip, .notice, .state { border: 1px solid CanvasText; }
|
||||
.theme-switcher button[aria-pressed="true"] { background: Highlight; color: HighlightText; }
|
||||
.source-chip i, .health-state i, .quality-chip i, .activity-pill i { forced-color-adjust: none; }
|
||||
.fish-silhouette, .waterbody-mark, .tackle-glyph, .coordinate-radar { color: CanvasText; }
|
||||
}
|
||||
|
||||
@@ -287,9 +287,19 @@
|
||||
"source_pages": [
|
||||
"https://rf4map.ru/fishes"
|
||||
],
|
||||
"status": "queued",
|
||||
"status": "approved",
|
||||
"first_seen_at": "2026-09-12T14:59:53.013377+00:00",
|
||||
"last_seen_at": "2026-09-12T14:59:53.013377+00:00"
|
||||
"last_seen_at": "2026-09-12T14:59:53.013377+00:00",
|
||||
"sha256": "143929ed5f4dc4ffbd585f009073d0cc107e1f0e2c77b0e3d81d92b2d3aff842",
|
||||
"local_path": "files/14/143929ed5f4dc4ffbd585f009073d0cc107e1f0e2c77b0e3d81d92b2d3aff842.png",
|
||||
"content_type": "image/png",
|
||||
"bytes": 2266,
|
||||
"width": 48,
|
||||
"height": 48,
|
||||
"fetched_at": "2026-09-13T09:11:46.504621+00:00",
|
||||
"entity_key": "rf4map-bait-101",
|
||||
"reviewed_at": "2026-09-13T09:12:06.537034+00:00",
|
||||
"review_note": "Visual review: Hijacker slim 7SP-003 minnow lure with orange flank and hooks; transparent PNG; RF4MAP catalog provenance"
|
||||
},
|
||||
{
|
||||
"source_page": "https://rf4map.ru/fishes",
|
||||
@@ -5029,7 +5039,7 @@
|
||||
"entity_type": "reference",
|
||||
"label": "Zig-Rig Guide Unterschiedliche Wetterbedingungen führen zu Veränderungen der Wassertemperatur. Bei niedrigen Temperaturen können Karpfen in die sonnenerwärmten Oberflächenschichten des Gewässers aufsteigen. In solchen Fällen können Zig-Rig Montagen die besten Ergebnisse erzielen. Beim Zig-Rig wird a",
|
||||
"external_id": null,
|
||||
"status": "stored",
|
||||
"status": "approved",
|
||||
"first_seen_at": "2026-09-12T08:50:41.276898+00:00",
|
||||
"last_seen_at": "2026-09-12T08:50:41.276898+00:00",
|
||||
"sha256": "48b4e4f2cdca2d65bc17feee61a36a9eaf979ea6a83756f3805750d99dd6388e",
|
||||
@@ -5041,7 +5051,10 @@
|
||||
"fetched_at": "2026-09-12T14:24:59.865233+00:00",
|
||||
"source_pages": [
|
||||
"https://rf4game.de/userguide/"
|
||||
]
|
||||
],
|
||||
"entity_key": "rf4game-de-zig-rig-depth-diagram",
|
||||
"reviewed_at": "2026-09-13T09:07:24.362599+00:00",
|
||||
"review_note": "Visual review: Zig-Rig depth placement diagram in a lake cross-section; official RF4 German user guide provenance"
|
||||
},
|
||||
{
|
||||
"source_page": "https://rf4game.de/userguide/",
|
||||
@@ -5256,12 +5269,14 @@
|
||||
"entity_type": "reference",
|
||||
"label": "RATSCHLÄGE Wurfweite und Wurfgenauigkeit Wurfweite hängt ab von: Geschicklichkeit des Spielers Fähigkeiten dieser Angelrutenart Fähigkeiten, diese Rollenart zu verwenden Länge der Angelrute Grad der Trunkenheit Beeinflussung durch den Wind Als allererstes geben Sie acht auf Ihre Fähigkeiten für dies",
|
||||
"external_id": null,
|
||||
"status": "queued",
|
||||
"status": "invalid",
|
||||
"first_seen_at": "2026-09-12T08:50:41.276898+00:00",
|
||||
"last_seen_at": "2026-09-12T08:50:41.276898+00:00",
|
||||
"source_pages": [
|
||||
"https://rf4game.de/userguide/"
|
||||
]
|
||||
],
|
||||
"last_attempt_at": "2026-09-13T09:06:54.770934+00:00",
|
||||
"last_error": "expected image, got text/html"
|
||||
},
|
||||
{
|
||||
"source_page": "https://rf4game.de/userguide/",
|
||||
|
||||
+2
-2
@@ -44,8 +44,8 @@
|
||||
- [x] **D02 · Системный режим без вспышки.** Первый визит следует `prefers-color-scheme` полностью через CSS: серверный HTML сразу совместим с системной темой, состояние не хранится, inline bootstrap не добавлен и CSP не ослаблена. Явное переопределение появится только вместе с D03–D04.
|
||||
- [x] **D03 · Переключатель темы.** В header добавлен доступный трёхпозиционный выбор «Системная / Светлая / Тёмная»; на узких экранах он сохраняет три понятные иконки и доступные названия. Кнопки работают с клавиатуры, имеют видимый focus и синхронизируют `aria-pressed`.
|
||||
- [x] **D04 · Сохранение и SSR-согласование.** Выбор хранится год в allowlist-cookie `rf4-theme` с `SameSite=Lax` и `Secure` на HTTPS; Astro SSR выставляет `data-theme` до отрисовки, а системный режим оставляет выбор браузеру. Собранный Astro client script переключает тему без inline-кода, localStorage и ослабления CSP.
|
||||
- [ ] **D05 · Темизация компонентов и графики.** На семантические light/dark-токены уже переведены базовые поверхности, header, каталог, breadcrumb-леска, ссылки сущностей, паспорта данных, pagination, empty/loading-состояния и часть декоративной графики. Следующий пакет: таблицы и формы, provenance/quality badges, admin-панель, радар, timeline, силуэты и глифы; затем проверить фотографии, прозрачные PNG, screenshots, тени, градиенты и forced-colors. Источники и статусы не должны различаться только цветом.
|
||||
- [ ] **D06 · Метаданные браузера и CSP.** Добавить парные `theme-color` для light/dark media queries, проверить manifest/PWA chrome и отсутствие новых inline script/style/attributes. Сохранить `inlinedScripts: []`, `style-src 'self'`, `style-src-attr 'none'` и не возвращать `unsafe-inline` ради инициализации темы.
|
||||
- [ ] **D05 · Темизация компонентов и графики.** На семантические light/dark-токены переведены базовые и admin-поверхности, header, каталог, breadcrumb-леска, ссылки сущностей, таблицы, формы, moderation-карточки, provenance/quality/status badges, паспорта данных, pagination, empty/loading-состояния, радар, timeline, силуэты и глифы; добавлен базовый forced-colors layer. Осталась визуальная проверка фотографий, прозрачных PNG, screenshots, теней и градиентов в обеих темах. Источники и статусы сохраняют текстовые подписи и не различаются только цветом.
|
||||
- [x] **D06 · Метаданные браузера и CSP.** Добавлены парные `theme-color` для системной light/dark схемы; явный cookie-выбор согласуется с SSR и мгновенно переключает активный meta-тег. PWA manifest использует устойчивый тёмный brand chrome и splash background. Production build сохраняет `inlinedScripts: []`; новые inline script/style/attributes не появились, ослабление CSP не потребовалось.
|
||||
- [ ] **D07 · Визуальная и accessibility-приёмка.** Проверить light/dark/system на 320/390/768/1280 px для главной, каталогов, detail, records, report, status и всех admin-экранов; покрыть normal/hover/focus/disabled/error/loading/empty и длинные данные. Для обеих тем обеспечить WCAG AA, отсутствие горизонтального scroll и CLS, корректную печать, reduced motion и переключение без потери введённых данных; сохранить эталонные screenshots и краткий отчёт.
|
||||
|
||||
- [ ] **Q01 · Документы источников — реестр готов, нужны первичные подтверждения.** Создан единый production-gate с атрибуцией, общим лимитом 30 минут, хранением и процедурой отзыва для RF4DB, RF4-STAT, RF4MAP, RF4 Posts и официального RF4. До открытой публикации приложить устойчивые ссылки/копии первичных разрешений, контакты, даты и отдельно подтвердить право на изображения; пустое поле блокирует соответствующий источник.
|
||||
|
||||
@@ -12,6 +12,8 @@
|
||||
|
||||
По умолчанию сайт следует `prefers-color-scheme` через CSS. Переключатель в header позволяет явно выбрать системную, светлую или тёмную тему; выбранное значение хранится в allowlist-cookie `rf4-theme` (`SameSite=Lax`, год, `Secure` на HTTPS). Astro читает cookie на сервере и сразу выставляет `data-theme="light|dark"`; для системного режима атрибут отсутствует. Client script собирается Astro во внешний asset, поэтому inline-код, localStorage и ослабление CSP не требуются.
|
||||
|
||||
Цвет browser chrome задаётся двумя `theme-color` meta-тегами с media query в системном режиме. При явном выборе Astro активирует нужный meta-тег на SSR, а переключатель синхронизирует его без перезагрузки. Manifest использует тёмный фирменный цвет как стабильный fallback для splash screen и установленного PWA.
|
||||
|
||||
## Дальнейшая миграция
|
||||
|
||||
Файл `theme.css` временно содержит точечные dark overrides для основных публичных и административных поверхностей. На этапе D05 жёсткие цвета последовательно заменяются семантическими токенами в исходных component styles; source/status различия сохраняют текст или форму и никогда не полагаются только на оттенок.
|
||||
|
||||
Reference in New Issue
Block a user