Live presence moves into the top navigation (signed-in users only) #102

Closed
opened 2026-07-12 04:03:39 +02:00 by fable-5 · 1 comment
Collaborator

Context

The avatars showing who is live on a page (PresenceStrip) render inside the editor shell above the content. They belong in the top navigation next to the other page-scoped indicators — and must only ever be visible to signed-in users.

Scope

Move the PresenceStrip into the TopBar's page-actions area (only while a page route is active), keeping its behavior: initials avatars with colors, max 5 + "+N" overflow, read-only viewer badge, hidden when empty. Note the current state: presence already exists only behind sign-in (the page route is auth-gated and the public view has no awareness connection) — encode that as a pinned guarantee, not a new mechanism: the public/anonymous read path must stay free of any awareness/presence data, and the component must render nothing without an authenticated session.

Acceptance criteria

  • two signed-in users on the same page see each other's avatars in the top navigation (both view and edit mode); leaving the page removes them promptly
  • anonymous/public readers never receive presence data (no awareness connection on the public path — regression-pinned in a test)
  • read-only participants keep their viewer badge; overflow "+N" works
  • the strip disappears on non-page routes and when nobody else is present

Technical notes

  • apps/web/src/editor/PresenceStrip.tsx + use-presence.ts (Hocuspocus awareness via collab.provider), mounted at PageEditorPage.tsx:252; the provider lives inside PageEditor, so the TopBar needs the presence data via the same page-actions slot/context as the icon actions.
  • Public path: PublicPageView.tsx deliberately never connects to collab — keep it that way (permissions.md; display names are member-visible data).

Dependencies

Depends on #101 (the icon-actions TopBar slot).

Size: ~0.5 days


Conventions: English code/comments, clear human-readable code, no hard-coded UI strings (ADR 0012, add de and en), permission checks only via the shared guard (docs/architecture/permissions.md). Read the referenced ADRs before starting.

## Context The avatars showing who is live on a page (PresenceStrip) render inside the editor shell above the content. They belong in the top navigation next to the other page-scoped indicators — and must only ever be visible to signed-in users. ## Scope Move the PresenceStrip into the TopBar's page-actions area (only while a page route is active), keeping its behavior: initials avatars with colors, max 5 + "+N" overflow, read-only viewer badge, hidden when empty. Note the current state: presence already exists only behind sign-in (the page route is auth-gated and the public view has no awareness connection) — encode that as a pinned guarantee, not a new mechanism: the public/anonymous read path must stay free of any awareness/presence data, and the component must render nothing without an authenticated session. ## Acceptance criteria - [ ] two signed-in users on the same page see each other's avatars in the top navigation (both view and edit mode); leaving the page removes them promptly - [ ] anonymous/public readers never receive presence data (no awareness connection on the public path — regression-pinned in a test) - [ ] read-only participants keep their viewer badge; overflow "+N" works - [ ] the strip disappears on non-page routes and when nobody else is present ## Technical notes - apps/web/src/editor/PresenceStrip.tsx + use-presence.ts (Hocuspocus awareness via `collab.provider`), mounted at PageEditorPage.tsx:252; the provider lives inside PageEditor, so the TopBar needs the presence data via the same page-actions slot/context as the icon actions. - Public path: PublicPageView.tsx deliberately never connects to collab — keep it that way (permissions.md; display names are member-visible data). ## Dependencies Depends on #101 (the icon-actions TopBar slot). **Size**: ~0.5 days --- *Conventions: English code/comments, clear human-readable code, no hard-coded UI strings (ADR 0012, add `de` **and** `en`), permission checks only via the shared guard (docs/architecture/permissions.md). Read the referenced ADRs before starting.*
fable-5 added this to the M10 — UI polish milestone 2026-07-12 04:03:39 +02:00
fable-5 added the
collab
frontend
labels 2026-07-12 04:03:39 +02:00
Author
Collaborator

Umgesetzt in e740ea6 (CI komplett grün).

Was drin ist

  • Zweiter TopBar-Slot topbar__presence direkt neben dem Page-Actions-Slot aus #101 — wie dieser nur für eingeloggte Nutzer überhaupt gerendert. PageEditor (wo der Hocuspocus-Provider lebt) portalt die unveränderte PresenceStrip hinein: Initialen-Avatare mit Farben, max. 5 + „+N"-Overflow, Viewer-Badge für Read-only-Teilnehmer, null wenn niemand da ist. Sichtbar in View- UND Edit-Modus (der Provider verbindet in beiden), verschwindet mit dem Seiten-Unmount auf Nicht-Seiten-Routen.
  • Gepinnte Garantie statt neuem Mechanismus: public.spec asserted jetzt auf dem anonymen Pfad, dass (a) kein /collab-WebSocket geöffnet wird (page.on('websocket')) und (b) keinerlei .presence-strip/.presence-avatar rendert. PublicPageView verbindet weiterhin nie zu collab.

Verifiziert: collab.spec (2-Nutzer-Presence: beide Avatare in beiden TopBars, Disconnect entfernt prompt) läuft unverändert grün — die .presence-avatar-Selektoren greifen am neuen Ort; public.spec mit dem neuen Pin grün; visuell im Browser: eigener Avatar in der TopBar neben den Icons.

Damit ist der Milestone „M10 — UI polish" (#99–#102) komplett. Hinweis: Die M10-Änderungen sind noch in keinem Release — das nächste v*-Tag nimmt sie mit.

Umgesetzt in `e740ea6` (CI komplett grün). **Was drin ist** - Zweiter TopBar-Slot `topbar__presence` direkt neben dem Page-Actions-Slot aus #101 — wie dieser **nur für eingeloggte Nutzer überhaupt gerendert**. `PageEditor` (wo der Hocuspocus-Provider lebt) portalt die unveränderte `PresenceStrip` hinein: Initialen-Avatare mit Farben, max. 5 + „+N"-Overflow, Viewer-Badge für Read-only-Teilnehmer, `null` wenn niemand da ist. Sichtbar in View- UND Edit-Modus (der Provider verbindet in beiden), verschwindet mit dem Seiten-Unmount auf Nicht-Seiten-Routen. - **Gepinnte Garantie statt neuem Mechanismus:** public.spec asserted jetzt auf dem anonymen Pfad, dass (a) kein `/collab`-WebSocket geöffnet wird (`page.on('websocket')`) und (b) keinerlei `.presence-strip`/`.presence-avatar` rendert. `PublicPageView` verbindet weiterhin nie zu collab. **Verifiziert:** collab.spec (2-Nutzer-Presence: beide Avatare in beiden TopBars, Disconnect entfernt prompt) läuft unverändert grün — die `.presence-avatar`-Selektoren greifen am neuen Ort; public.spec mit dem neuen Pin grün; visuell im Browser: eigener Avatar in der TopBar neben den Icons. Damit ist der Milestone „M10 — UI polish" (#99–#102) komplett. Hinweis: Die M10-Änderungen sind noch in keinem Release — das nächste `v*`-Tag nimmt sie mit.
Sign in to join this conversation.
No Milestone
No project
No Assignees
1 Participants
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: stwaidele/dorfteich#102
No description provided.