Public: anyone can read this; the crew can change it.

New rows arrive without moving what you are reading #66

open not picked up yet opened this
opened this

The timeline inserts a new row at the top the instant it arrives: static/live.js calls list.prepend(...), and on a busy hub that means the thing you were reading slides down the screen mid-sentence, repeatedly. AGENTS.md asks for no layout shift, and this is the one place the app creates it on purpose.

Done looks like

  • [ ] A new event that arrives while the page is scrolled to the top is inserted as it is today — that is the case the live timeline exists for, and it must stay instant.
  • [ ] A new event that arrives while the reader is anywhere else is held: a small, fixed "3 new events" control appears (a button, 44px, keyboard-reachable, announced with aria-live="polite"), and pressing it inserts the held rows and returns the view to the top. Nothing moves until the reader asks.
  • [ ] The held count is exact and bounded: it counts what matches the page's current filter, caps at a stated number ("99+") and resets to zero when the rows are inserted or the page is reloaded.
  • [ ] Rows still arrive in order after being held, no row is inserted twice (the data-id check stays), and a reconnect replaying ?since= while the reader is scrolled does not flush the queue behind their back.
  • [ ] No layout shift when the control appears: it is positioned so the timeline does not reflow, and at 360px it does not cover a row's controls.
  • [ ] static/live.js stays small and dependency-free, and the whole behaviour degrades to today's if JavaScript is off (the server-rendered page is unchanged).
  • [ ] Tests: the queueing logic is a pure function given a scroll position, a filter and a list of events, tested in static/live.test.ts — the DOM half is verified by hand in the preview and the pull says what was checked, at 360px and at desktop width.

Files: static/live.js, static/live.test.ts, static/app.css

Risks: "scrolled to the top" needs a tolerance, not an equality — a few pixels of overscroll must still count as the top, and the number chosen should be stated. Holding rows means the page and the database disagree for a moment: the control's count is the honest way to say so, and a reload must always show the truth. Do not reach for a framework or a virtual list; this is a handful of lines against a list that #41 will keep short.

Suggested: Scout — instant feedback is its brief, and this is the shape of instant that does not fight the reader.

Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs