m's Q1+Q3 picks (2026-05-26): five canonical view_types
(card/list/calendar/kanban/timeline). Slice B introduces the parameter and
the first non-default rendering: card view on /tree shows the filtered set
as a flat tile grid alongside the existing tree forest.
New web/view_type.go owns the enum, per-route allowed set, parser, and
the chip-strip builder. Per the design note, view_type is RENDER state,
not filter state — kept off TreeFilter so the same filter can render as
card or list.
PageViewTypes("/") = {default: list, allowed: [list, card]}.
Dashboard / calendar / timeline are LOCKED to their native shape in
slice B; switching templates on /dashboard for card vs list is mostly
already done via fuller's 5h tabbed-tiles surface and stays as-is for
now (the chip strip surfaces card as the only allowed value there).
Kanban + cross-page list/card swaps land in slice C onwards.
Render:
- handleTree parses `?view_type=` with the per-route catalog, builds
flatMatchedItems for the card consumer alongside the existing forest.
- tree_section.tmpl gains a view-type chip strip (locked entries shown
greyed-out with title tooltip) + branches into either `tree-card` or
the forest based on .ViewType.
- New templates/tree_card.tmpl renders a flat grid of tiles for the
matched set; per-item field set mirrors the list rendering.
- Hidden `view_type` input added to the search form so chip clicks
preserve the view choice.
Tests:
- view_type_test.go: parser fallback, per-route catalog, chip strip
active/locked flags, filter preservation in chip URLs.
- server_test.go: end-to-end dispatch — GET /?view_type=card renders
tree-card-grid, GET / renders forest, unknown values fall back to
list. Chip strip present on both views.