Files
board-viewer/.tasks/board-viewer-html-render.md
vitya cab4a8b92d task(html-render): close → 🟢, unblock cron-deploy
closes board-viewer-html-render

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-22 14:49:42 +03:00

4.6 KiB
Raw Permalink Blame History

board-viewer-html-render

Goal

Рендер 5-колоночного kanban-board из нормализованной структуры (продукт board-viewer-gitea-reader). Статический HTML + минимальный клиент-сайд JS для фильтра / drawer / refresh-таймера. Без write-side, без realtime.

TDD-mode: обязательно по follow tdd-criteria. Снапшот-тесты на HTML-output из фиксированных reader-фикстур. Не модифицировать assert'ы без [test-modify: ...] маркера. Визуальная отделка (CSS) — под carve-out «visual CSS», но логика рендера (распределение по колонкам, age-расчёт, drawer-привязка) — TDD.

Key files

  • src/render.tsrenderBoard(), formatAge(), partitionByStatus() (pure)
  • src/cli.ts — entry: load config → readBoard → renderBoard → dist/index.html + copy static/
  • static/board.css — raw CSS, system font, light/dark, ~190 LOC
  • static/board.js — ESM module: filter, drawer (lazy-fetch + marked@14 from esm.sh), toggle-archived, toggle-grouping (full rerender into per-project columns)
  • tests/render.test.ts — 17 tests on render logic (no snapshots — semantic property assertions, more robust to harmless markup tweaks)

Acceptance criteria

  • 5 колонок по статусам: open / 🔴 in-progress / 🟡 paused / 🔵 blocked / 🟢 done. Названия колонок — emoji + слово.
  • Карточка:
    • title (truncate на 80 chars в default-view),
    • project badge (e.g. books, board-viewer),
    • owner (если есть) — pill,
    • age — относительное (3d, 2w, 5mo) от last_commit_iso,
    • last-commit-marker — короткий hash или дата.
  • Группировка по проекту — toggle вверху: «по статусам» (5 колонок × проекты внутри) vs «по проектам» (per-project колонки × статусы внутри).
  • Поиск/фильтр — клиент-сайд input: substring по slug, title, project; multi-select по статусам.
  • Per-card drawer — клик по карточке → side panel с full markdown из per-task <slug>.md (lazy-fetch из raw_url). Markdown рендерится клиент-сайд (e.g. marked для TS, markdown-it для Py-side-rendered).
  • Refresh-таймер видно в header: «refreshed Xm ago, next in Ym» (data attribute из generation timestamp).
  • Output: один index.html файл + sidecar static/. Открывается локально без сервера для smoke-test.
  • Tests: snapshot-тесты на 3 reader-фикстуры (пустая доска / 1-2 таски / N≥10 тасок). Snapshots checked-in.

Decisions log

  • 2026-05-22: task создан промоушеном; зависит от board-viewer-gitea-reader контракта.
  • 2026-05-22: emoji-set acceptance выравнен под reader контракт (🔴🟡🔵🟢).
  • 2026-05-22: client-side marked@14 via esm.sh — lazy-load на первое открытие drawer'а.
  • 2026-05-22: raw CSS, no framework — соответствует «whitespace + типографика» intent task notes.
  • 2026-05-22: done >14 дней архивируются (hidden by default, toggle «show archived»).
  • 2026-05-22: snapshot tests заменены 17 semantic-property тестами — устойчивее к косметическим изменениям markup'а.

Open questions

  • Markdown-renderer → client-side marked via esm.sh (lazy на drawer).
  • CSS → raw, no framework.
  • Done archive → >14d hidden, toggle for show.

Completed steps

  • formatAge (m/h/d/w/mo/y, calendar-month arithmetic) — pure, TDD
  • partitionByStatus — canonical 5-col order
  • renderBoard — HTML with escaped fields, JSON embed XSS-safe (\uXXXX escapes)
  • static/board.css — raw, light/dark
  • static/board.js — filter, drawer, archived/grouping toggles, refresh-info
  • src/cli.ts — wires config+reader+render+fs
  • 17 render tests + smoke-verified e2e (78 records, 4 repos, browser-tested both toggle modes)

Notes

Стиль: минимализм без аватарок/гифок/анимаций. Это инструмент глядеть на доску, не дашборд для презентации. Whitespace + типографика.