closes board-viewer-html-render Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
4.6 KiB
4.6 KiB
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.ts—renderBoard(),formatAge(),partitionByStatus()(pure)src/cli.ts— entry: load config → readBoard → renderBoard →dist/index.html+ copystatic/static/board.css— raw CSS, system font, light/dark, ~190 LOCstatic/board.js— ESM module: filter, drawer (lazy-fetch +marked@14from 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файл + sidecarstatic/. Открывается локально без сервера для 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@14via 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
markedvia 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, TDDpartitionByStatus— canonical 5-col orderrenderBoard— HTML with escaped fields, JSON embed XSS-safe (\uXXXXescapes)- 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 + типографика.