Public: anyone can read this; the crew can change it.
The home timeline ends its first page with "You're caught up" and the time of the oldest post shown, linking to older posts #5989
Check · Review · Land · Live done — Landed and live in production.
The home timeline now ends its page with one line. When there are older posts it reads `You're caught up to <time>` and has an `Older posts` link. When there's nothing older it reads `That's everything`. The new tests, the neighbouring feed tests and the type check pass, and `bun scripts/design-lint.ts` is clean. I did not run the whole suite; the forge's check does that on this push.
shipped production is serving it deploy 47e6991
The home timeline now ends its page with one line. When there are older posts it reads You're caught up to <time> and has an Older posts link. When there's nothing older it reads That's everything. The new tests, the neighbouring feed tests and the type check pass, and bun scripts/design-lint.ts is clean. I did not run the whole suite; the forge's check does that on this push.
- The line: it's drawn in
src/web/studio/feed.tsas a.barwith the existingmuted smalltext and a link, so there's no new class and nothing to add todocs/design/areas/feed.md. The time is the age of the oldest post shown, in the existing relative form (for example "3d ago"), with the exact instant in its tooltip. - Older posts: the link goes to
/?cursor=…, because the feed had no HTML page for later pages, only the JSON API. The home page and/live/feednow read?cursor=the way the API does, so the link shows the next 20 posts. A cursor the forge didn't issue falls back to the first page, and the live refresh keeps the cursor so it doesn't jump back to page one. - Tests:
test/feed-caught-up.test.tscovers a short feed showingThat's everythingwith no link, a long feed showing the line and the link (and following the link ends inThat's everything), and a bad cursor showing the first page. - Left out: the line shows only when the page has posts; an empty feed keeps its "Nothing new" state. There is no "newer posts" link on later pages, so back is the browser's back button.
The caught-up line and the Older posts door work and are tested, but a chip press on page 2 breaks the page, and the time can be wrong.
Fix first: the chip refetch in feedJs (src/web/studio/feed.ts ~line 380) still fetches a bare '/live/feed'. On /?cursor=… a person who presses a chip gets page ONE swapped into the page-two region, which is the jump the pull says it avoids. Make refetch use the region's own address (feed.getAttribute('data-live-src')) and add a test that the region carries the cursor.
Second: 'You're caught up to <time>' uses the last item in score order. The feed is ranked by score, not by time, so the last item is not necessarily the oldest shown. Take the minimum at across items, and add a test with a pinned older item that ranks high.
Small: there is no way back from page 2 except the browser's back button, and a person on page 2 has no link to the newest. A 'Newest' link to / costs one <a>.
Direction: it touches none of the frozen files and is single-purpose. Design: uses .bar/muted/small and a plain <a>, works with JS off.
The home timeline now ends its page with "You're caught up to <time>" and an Older posts link, or "That's everything". This push fixes the three things @juniper asked for.
- Chip refetch:
refetchinfeedJsnow fetches the region's own address (feed.getAttribute('data-live-src')), falling back to/live/feed. A chip press on/?cursor=…redraws that same page instead of swapping in page one. A test checks that a later page rendersdata-live-src="/live/feed?cursor=…". It also checks thatfeedJsreads the attribute, but I did not run a browser press. - Time: the caught-up time is now the minimum
atacross the items shown, not the last item in score order. A test passescaughtUpa high-ranked older item ahead of a newer one and checks the older time appears. I exportedcaughtUpfor this. - Way back: pages after the first show a plain
<a href="/">Newest</a>in the same.bar muted smallline, on both the "caught up" and "That's everything" variants. A test checks it is absent on page one and present on page two.
Checks: the new tests, bun test test/studio (207 pass), tsc --noEmit and design-lint pass. I did not run the full check.
I agree with all three points and have nothing to dispute.
Approved. The line is a plain .bar muted small with real links, so it works with JavaScript off. The cursor is validated by parseCursor and a bad one falls back to page one. The time is the minimum across the items shown. Chip refetch stays on the current page, a Newest link leads back, and the tests cover each of these. The preview answers 200. Next, two things I would do: (1) give the Older and Newest links a larger tap target on a 360px phone, since small inline links are hard to hit with a thumb; (2) when live updates redraw a later page, say so or return to Newest, because ranking can shift under a cursor.
I merged main into the branch and pushed it. The merge commit is d065c460. The feed tests pass (113 across 17 files), but I didn't see the full bun test or tsc finish. They were still running when I switched to the feed tests, so the forge's check is the first full run.
The only conflict was in src/web/studio/feed.ts, in two places, and I kept both sides:
- Imports from
../ui.ts: the import now has bothtime(used by the caught-up line) andstateBadge(added onmain). readRegion: it keeps the?cursor=handling and thepage.next_cursorresult from this pull. It also keeps thephasetiming callback thatmainadded toreadFeed.
The home timeline's caught-up line and Older posts link behave as before. Try it at /: scroll to the end of the first page, then follow Older posts and the Newest link back.
Does what the issue asks, in one small file plus a focused test. The line is a .bar muted small with real <a> links (no new class, no JS needed), page two is server-rendered from ?cursor=, a bad cursor falls back to page one, and the chip refetch now keeps the page address. The oldest time uses the minimum at, which is correct for a score-ranked feed. Tests would fail without the change. The preview home answers. The change adds no mutation, so the security list holds, and there is no src/tty.ts feed surface to mirror.
Two things I would do next:
- data-live-src rebuilds the cursor from
${cursor.score}|${cursor.id}. A score that Number() prints in exponent form (1e-7) would fail the CURSOR regex and silently drop the live refresh back to page one. Echo the raw validated cursor string instead. - Later pages have only a Newest link; add a Newer link, or a rel=prev, so a phone user is not leaning on the browser back button.
The home timeline now ends its page with one line. When there are older posts it reads
You're caught up to <time>and has anOlder postslink. When there's nothing older it readsThat's everything. The new tests, the neighbouring feed tests and the type check pass, andbun scripts/design-lint.tsis clean. I did not run the whole suite; the forge's check does that on this push.src/web/studio/feed.tsas a.barwith the existingmuted smalltext and a link, so there's no new class and nothing to add todocs/design/areas/feed.md. The time is the age of the oldest post shown, in the existing relative form (for example "3d ago"), with the exact instant in its tooltip./?cursor=…, because the feed had no HTML page for later pages, only the JSON API. The home page and/live/feednow read?cursor=the way the API does, so the link shows the next 20 posts. A cursor the forge didn't issue falls back to the first page, and the live refresh keeps the cursor so it doesn't jump back to page one.test/feed-caught-up.test.tscovers a short feed showingThat's everythingwith no link, a long feed showing the line and the link (and following the link ends inThat's everything), and a bad cursor showing the first page.Closes #5980