From 0a4af12dc027b98f2e55dd072388b3a9acfdddd4 Mon Sep 17 00:00:00 2001 From: IK Date: Mon, 21 Sep 2026 20:54:41 +0700 Subject: [PATCH] feat: label low resolution media fallback --- apps/web/src/components/EntityMedia.astro | 3 ++- apps/web/src/styles/media-catalog.css | 1 + docs/ROADMAP.md | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/apps/web/src/components/EntityMedia.astro b/apps/web/src/components/EntityMedia.astro index a1be6ca..5befe78 100644 --- a/apps/web/src/components/EntityMedia.astro +++ b/apps/web/src/components/EntityMedia.astro @@ -3,6 +3,7 @@ import SourceBadge from "./SourceBadge.astro"; import type { MediaAsset } from "../lib/api"; import { mediaRoleLabel } from "../lib/media"; const { asset, compact = false, sourceLink = false } = Astro.props as { asset: MediaAsset; compact?: boolean; sourceLink?: boolean }; +const isLowResolution = Math.min(asset.width, asset.height) < 256; ---
@@ -12,5 +13,5 @@ const { asset, compact = false, sourceLink = false } = Astro.props as { asset: M })} {asset.label -
{asset.label ?? "Справочный материал"}{asset.media_role && {mediaRoleLabel(asset.media_role)}}
+
{asset.label ?? "Справочный материал"}{asset.media_role && {mediaRoleLabel(asset.media_role)}}{isLowResolution && Низкое разрешение · {asset.width}×{asset.height}}
diff --git a/apps/web/src/styles/media-catalog.css b/apps/web/src/styles/media-catalog.css index 9fd7dae..7f603b0 100644 --- a/apps/web/src/styles/media-catalog.css +++ b/apps/web/src/styles/media-catalog.css @@ -6,3 +6,4 @@ .media-role-filter{display:flex;align-items:end;gap:10px;margin:0 0 22px;padding:14px 16px;border:1px solid var(--border-soft);border-radius:12px;background:var(--surface-soft)}.media-role-filter label{display:grid;gap:6px;color:var(--text-muted);font-size:11px;font-weight:750;text-transform:uppercase;letter-spacing:.08em}.media-role-filter select{min-width:220px;height:40px;padding:0 10px;border:1px solid var(--border);border-radius:8px;background:var(--surface);color:var(--text)}.media-role-filter a{padding:11px 4px;color:var(--text-muted);font-size:12px}@media(max-width:720px){.media-role-filter{align-items:stretch;flex-wrap:wrap}.media-role-filter label{flex:1 1 100%}.media-role-filter select{width:100%}} @media (min-width:721px) and (max-width:1050px){.media-library__grid{grid-template-columns:repeat(3,minmax(0,1fr))}} +.entity-media__quality{color:var(--warning);font-weight:700} diff --git a/docs/ROADMAP.md b/docs/ROADMAP.md index 6ee5738..3df9498 100644 --- a/docs/ROADMAP.md +++ b/docs/ROADMAP.md @@ -45,7 +45,7 @@ - [x] **B22 · Сравнение вариантов разных источников.** Offline-команда `--compare-quality-upgrades` сопоставила сохранённые кандидаты с опубликованными fallback по `duplicate_of` и проверила dimensions, размер файла, MIME, прозрачность и aspect ratio. Все 226 кандидатов прошли технические пороги и offline contact-sheet review; источник RF4DB/RF4MAP/официальный RF4 не получал автоматического приоритета. После публикации в manifest не осталось `upgrade_stored`, поэтому текущий повторный запуск команды корректно сообщает `compared: 0`. - [x] **B23 · Безопасное продвижение и provenance.** Связи `supersedes`/`replaced_by`, отдельное решение review, атомарное переключение публичного `entity_key` и явный CLI rollback сохраняют обе исходные ссылки и возможность отката. Публичная карточка показывает источник выбранного изображения, а manifest сохраняет проверенные варианты. Старый Git-файл не удаляется при включении нового. - [x] **B24 · Производные размеры.** После выбора оригиналов генерируются детерминированные WebP/AVIF thumbnails для каталога и отдельный крупный вариант для detail, хэши производных фиксируются в manifest и отдаются через каталог. Маленькие карточки больше не обязаны загружать 1024×1024 оригинал. -- [ ] **B25 · Визуальная приёмка media.** Contact sheets для всех 226 замен собраны и просмотрены offline: явных ложных соответствий, обрезки и искажённых пропорций не обнаружено; одно отличие подписи (`Ерш-носарь`/`Ёрш-носарь`) орфографическое. In-app Chromium проверил 12 комбинаций `/media` (320/390/768/1280 px × light/dark/system): горизонтального overflow нет, у 253 изображений есть `alt`, broken loaded images — `0`, переключение темы корректно меняет `data-theme`; automated media acceptance теперь отдельно проверяет loaded assets и разделы `waterbody/tackle/reference`, keyboard/focus и print-regression проходят, standalone axe — `12/12` маршрутов. Launcher `scripts/capture-visual-matrix.mjs` синхронизирован с regression matrix и захватывает `252` PNG; полный capture текущего прохода завершён без document overflow, representative manual review зафиксирован в `docs/ux-reference-review-2026-09-21.md`. Gate: нет битых файлов, искажённых пропорций, ложных соответствий, обрезанного объекта и изображений ниже 256 px без явной пометки «низкое разрешение». +- [x] **B25 · Визуальная приёмка media.** Contact sheets для всех 226 замен собраны и просмотрены offline: явных ложных соответствий, обрезки и искажённых пропорций не обнаружено; одно отличие подписи (`Ерш-носарь`/`Ёрш-носарь`) орфографическое. In-app Chromium проверил 12 комбинаций `/media` (320/390/768/1280 px × light/dark/system): горизонтального overflow нет, у 253 изображений есть `alt`, broken loaded images — `0`, переключение темы корректно меняет `data-theme`; automated media acceptance теперь отдельно проверяет loaded assets и разделы `waterbody/tackle/reference`, keyboard/focus и print-regression проходят, standalone axe — `12/12` маршрутов. Launcher `scripts/capture-visual-matrix.mjs` синхронизирован с regression matrix и захватывает `252` PNG; полный capture текущего прохода завершён без document overflow, representative manual review зафиксирован в `docs/ux-reference-review-2026-09-21.md`. Единственный опубликованный fallback ниже 256 px теперь явно помечается в UI как «Низкое разрешение · 48×48» и сохраняется с объяснением отсутствия проверенной крупной версии. Gate: нет битых файлов, искажённых пропорций, ложных соответствий или обрезанного объекта; низкое разрешение явно обозначено. ### Каталог водоёмов, карты и координаты