Inbox sidebar: contacts list (read-only) #7

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

Parent

#2

What to build

Authenticated users land on /, which renders a persistent sidebar listing their posta-server contacts (read-only) and a main pane with an empty-state hint. Sidebar shows each contact's avatar (initials fallback with deterministic color from the lifted palette accents), display name (fallback to peer host), and unread count badge derived from lastReadRowId versus inbox state. Contacts ordered by lastMessageAt descending. Uses the internal/posta typed client to call GET /api/v1/contacts.

Acceptance criteria

  • GET / (authenticated) renders the page with the sidebar populated from GET <user-server>/api/v1/contacts
  • Unauthenticated request to / redirects to /login
  • Avatar rendering: if peer has avatar URL, <img>; otherwise 2-letter initials in a circle, color deterministically picked from --forest|--sky|--terracotta|--gold|--moss by hash of peer URL
  • Display name falls back to URL host when posta-server returns empty name
  • Unread count badge: number shown when > 0; absent at 0; "99+" above 99
  • Empty contacts list shows "No conversations yet" hint
  • internal/posta client implements GetContacts(ctx, token, serverURL) with bearer auth
  • First-ever-login user with no contacts renders cleanly without errors

Blocked by

## Parent #2 ## What to build Authenticated users land on `/`, which renders a persistent sidebar listing their posta-server contacts (read-only) and a main pane with an empty-state hint. Sidebar shows each contact's avatar (initials fallback with deterministic color from the lifted palette accents), display name (fallback to peer host), and unread count badge derived from `lastReadRowId` versus inbox state. Contacts ordered by `lastMessageAt` descending. Uses the `internal/posta` typed client to call `GET /api/v1/contacts`. ## Acceptance criteria - [ ] GET `/` (authenticated) renders the page with the sidebar populated from `GET <user-server>/api/v1/contacts` - [ ] Unauthenticated request to `/` redirects to `/login` - [ ] Avatar rendering: if peer has avatar URL, `<img>`; otherwise 2-letter initials in a circle, color deterministically picked from `--forest|--sky|--terracotta|--gold|--moss` by hash of peer URL - [ ] Display name falls back to URL host when posta-server returns empty `name` - [ ] Unread count badge: number shown when > 0; absent at 0; "99+" above 99 - [ ] Empty contacts list shows "No conversations yet" hint - [ ] `internal/posta` client implements `GetContacts(ctx, token, serverURL)` with bearer auth - [ ] First-ever-login user with no contacts renders cleanly without errors ## Blocked by - #6
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#7
No description provided.