Tree page (/) gains every navigation dimension m asked for:
- Debounced search input matching title/slug/aliases/content_md/paths
case-insensitively (?q=…)
- Tag chip row (?tag=a,b — AND within tags, as before)
- Management chip row with ?mgmt=mai,self,external,unmanaged
(OR within management; "unmanaged" is the synthetic empty-array case)
- Status chip row with ?status=active,done,archived (default = active;
archived rows only surface when the separate show-archived toggle is on)
- Has-link chip row ?has=caldav-list,gitea-repo
- Each chip carries the count it would yield if toggled — honest user
cue, computed via per-dimension recomputation in pure Go (cheap at
m's scale)
- URL is the source of truth — every filter goes through the query
string, so any view is bookmarkable; HTMX swaps the tree-section in
place with hx-push-url=true on every chip click and on search keyup
- Empty-state copy with a clear-all link
Implementation:
- web/tree_filter.go new: TreeFilter struct + ParseTreeFilter +
QueryString/URL + Toggle* helpers + Matches + applyTreeFilter
(replacement for buildForest) + computeChipCounts.
- web/tree_filter_test.go: parse defaults + every dimension's match +
URL round-trip + ancestor-keep semantics + chip counting.
- Linkages: linkKindsByItem on Server fans across the two has-link
ref_types in one pass and feeds the filter.
- tree.tmpl reduced to a one-liner that calls tree-section; new
tree_section partial powers both the initial page render and HTMX
fragment swaps (matches the pattern from phases 2.a/b/d).
docs/design.md §4: tree-filter contract — URL keys, AND/OR rules,
count semantics, archived ergonomics.