Thread view: bubbles, 2-min clusters, date dividers (read-only) #8

Open
opened 2026-05-14 23:17:16 +02:00 by arne · 0 comments
Owner

Parent

#2

What to build

Clicking a sidebar contact navigates to /c/<url-encoded-peer>, which renders the message thread. Bubble layout — outbound right, inbound left. Consecutive messages from the same sender within 2 minutes cluster (single avatar + timestamp on the first; tight spacing thereafter). Date dividers between calendar days (browser-local timezone). Main pane swaps via hx-push-url; sidebar stays mounted. Server distinguishes full vs partial render via the HX-Request header — direct visit and refresh return the full page; in-app navigation returns only the thread fragment.

Acceptance criteria

  • Sidebar contact links use hx-get="/c/<peer>" hx-target="#main" hx-push-url="true"
  • Direct visit / refresh of /c/<peer> returns the full page (layout chrome + thread)
  • htmx navigation returns only the thread fragment (HX-Request header detected)
  • Outbound messages right-aligned with accent color; inbound left-aligned with neutral
  • 2-minute clustering: consecutive same-sender messages within 2 min collapse into one cluster with single avatar (inbound) and timestamp on the first
  • Date dividers ("Today", "Yesterday", "May 12") between days, computed in the browser's local timezone via <time datetime="…"> + small JS formatter
  • Each message has id="msg-<rowId>" for future anchor scrolling
  • Newlines in text bodies preserved with white-space: pre-wrap
  • Initial load returns the 50 most-recent messages (newest first)
  • Older history loadable via ?before=<rowId> cursor passed through to posta-server
  • internal/posta client implements GetMessages(ctx, token, serverURL, peer, cursor)
  • Visiting a peer not yet in contacts renders an empty thread without error

Blocked by

## Parent #2 ## What to build Clicking a sidebar contact navigates to `/c/<url-encoded-peer>`, which renders the message thread. Bubble layout — outbound right, inbound left. Consecutive messages from the same sender within 2 minutes cluster (single avatar + timestamp on the first; tight spacing thereafter). Date dividers between calendar days (browser-local timezone). Main pane swaps via `hx-push-url`; sidebar stays mounted. Server distinguishes full vs partial render via the `HX-Request` header — direct visit and refresh return the full page; in-app navigation returns only the thread fragment. ## Acceptance criteria - [ ] Sidebar contact links use `hx-get="/c/<peer>" hx-target="#main" hx-push-url="true"` - [ ] Direct visit / refresh of `/c/<peer>` returns the full page (layout chrome + thread) - [ ] htmx navigation returns only the thread fragment (`HX-Request` header detected) - [ ] Outbound messages right-aligned with accent color; inbound left-aligned with neutral - [ ] 2-minute clustering: consecutive same-sender messages within 2 min collapse into one cluster with single avatar (inbound) and timestamp on the first - [ ] Date dividers ("Today", "Yesterday", "May 12") between days, computed in the browser's local timezone via `<time datetime="…">` + small JS formatter - [ ] Each message has `id="msg-<rowId>"` for future anchor scrolling - [ ] Newlines in text bodies preserved with `white-space: pre-wrap` - [ ] Initial load returns the 50 most-recent messages (newest first) - [ ] Older history loadable via `?before=<rowId>` cursor passed through to posta-server - [ ] `internal/posta` client implements `GetMessages(ctx, token, serverURL, peer, cursor)` - [ ] Visiting a peer not yet in contacts renders an empty thread without error ## Blocked by - #7
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
posta/chat#8
No description provided.