Public: anyone can read this; the crew can change it.
Time in words: src/when.ts, and a countdown that does not move the page #39
Check · Review · Land · Live done — Landed and live in production.
`bun test` is green (39 pass) and the branch is pushed.
shipped production is serving it deploy 6ecafc0
Sign in to join this conversation.
new above
offline
bun testis green (39 pass) and the branch is pushed.Time is now said in one place.
static/when.jsholds the vocabulary — unitsd h m s, at most two, largest first, "just now" for the minute either side of now, "lapsed" the second a deadline arrives — as pure functions withnowhanded in:remaining,relative,absoluteandphrase.src/when.tsis that file with types on it plustimeTag, the escaped<time class="when" data-when="…" datetime="…" title="…">every page uses. The words live instatic/rather thansrc/on purpose: the browser needs exactly the same ones, since the server renders a countdown at paint and the page re-renders it a second later, and two implementations of relative time are two implementations that drift. One file, two runtimes;src/when.tsis the only import that crosses that way, and AGENTS.md now says so.static/live.jsticks every clock on the page from its owndatetimeattribute — one interval for the whole document however many clocks it has, cleared while the tab is hidden, no request of any kind — and sets the reader's local time in the hover text, the one thing the server cannot know. With JavaScript off the server's words are correct at paint and simply grow stale.static/app.cssgives the slot tabular numbers and a width inchwide enough for the longest phrase its kind can say, so a tick never reflows the row.Beyond the issue's list I deleted two private copies of the same idea rather than leaving them beside the new one:
src/page.tshad its ownago()usingtoLocaleDateStringon the server (a locale the server cannot know), andsrc/tty.tssliced an ISO string by hand. Both now call the module, so a note reads "20m ago" on the page and over ssh alike and the page's<time>actually ticks in the preview — the rendered wording changes, nothing else does. I did not add any page or route of its own: #11, #12, #14 and #16 are what this lands for. No dependency was added.To try it: open
/signed in, add a note, and watch its time — "just now" becomes "1m ago" a minute later with nothing fetched and nothing shifting; hover it for your local time;view-source:shows the UTC instant indatetime.src/when.test.tsis the table of inputs to expected strings, including 0s/59s/60s/90m/23h59m/24h/8d, a negative duration, a value that is not a time at all, and a check that nothing a caller passes is echoed into the markup.🤖 Generated with Claude Code
Closes #20