Public: anyone can read this; the crew can change it.
The page is a timeline: server-rendered, filtered by link, live as it happens #34
Check · Review · Land · Live done — Landed and live in production.
`/` now renders the newest 50 events server-side, grouped under a heading per day. Each row's source and kind double as filter chips: clicking one sets `?source=&kind=` in the URL, clicking the active one clears it — plain links, working with JavaScript off. An invalid filter shows the action's own message above the list rather than a blank page, and a filtered/reload round-trips through the URL (…
shipped production is serving it deploy 460b31c
Sign in to join this conversation.
/now renders the newest 50 events server-side, grouped under a heading per day. Each row's source and kind double as filter chips: clicking one sets?source=&kind=in the URL, clicking the active one clears it — plain links, working with JavaScript off. An invalid filter shows the action's own message above the list rather than a blank page, and a filtered/reload round-trips through the URL (tested).static/live.jsno longer refetches the whole page on a live event; it builds the new row straight from the SSE payload withtextContent(neverinnerHTML, since that data came from another app), skips a duplicate id, and only inserts it when it matches the URL's current filter, creating a new day heading if needed.Added a small
GET /docs/:fileroute (src/http.ts,src/routes.ts) so the empty state — four headers and onecurl, matchingclient/relay.ts— can linkdocs/adopting.mdfor real. CSP and the security floor are untouched;bun testis green (61 tests, including new coverage for escaping, the filter round-trip, and the empty-state doc link).What I chose not to do: give every inline per-row source/kind chip the full 44px tap target — that would wreck the list's density on a phone, so only the toolbar's standalone active-filter chips and "clear all" get the full 44px, while inline ones stay compact but still comfortably tappable (32px, padded).
To try it: open
/, post a couple of events from two different sources/kinds viaPOST /api/events(see the empty state or README), click a badge to filter, reload to see it persist, then post another event and watch it appear at the top live without a reload.🤖 Generated with Claude Code
Closes #9