feat(ui): relative message timestamps (LC-314) #334

Merged
longjacksonle merged 1 commit from feat/lc-314-relative-timestamps into main 2026-06-15 04:25:38 +02:00

Summary

Message and thread-reply times render as compact relative ("now", "2 minutes ago", "yesterday"), update live, and show the exact time on hover.

Changes

  • server/src/views/room.rs: MessageView::created_at_iso() (+ free to_iso_utc helper, unit-tested) converts the stored timestamp to a JS-safe RFC3339 UTC string; handles both SQLite YYYY-MM-DD HH:MM:SS and already-RFC3339 input.
  • room/message.html (system + normal rows) and room/thread_reply_inner.html: timestamp wrapped in <time data-lc-ts datetime=... title=<absolute>> (absolute stays as title + no-JS fallback text).
  • layout.html: formatter IIFE - Intl.RelativeTimeFormat (browser-localized; no new Fluent strings) for now/min/hour/day, absolute-date fallback past ~26 days; re-renders on htmx settle / OOB swap and every 30s.
  • server/tests/fixtures/lc77_*: regenerated for the additive <time> wrapper (verified additive-only).

Testing

  • just check, just fmt, just test, just test-saas all pass.
  • to_iso_utc unit tests (SQLite format + pass-through). LC-77 fixtures updated + passing.

Not operator-visible (no env/config/contract change).

## Summary Message and thread-reply times render as compact relative ("now", "2 minutes ago", "yesterday"), update live, and show the exact time on hover. ## Changes - `server/src/views/room.rs`: `MessageView::created_at_iso()` (+ free `to_iso_utc` helper, unit-tested) converts the stored timestamp to a JS-safe RFC3339 UTC string; handles both SQLite `YYYY-MM-DD HH:MM:SS` and already-RFC3339 input. - `room/message.html` (system + normal rows) and `room/thread_reply_inner.html`: timestamp wrapped in `<time data-lc-ts datetime=... title=<absolute>>` (absolute stays as title + no-JS fallback text). - `layout.html`: formatter IIFE - `Intl.RelativeTimeFormat` (browser-localized; no new Fluent strings) for now/min/hour/day, absolute-date fallback past ~26 days; re-renders on htmx settle / OOB swap and every 30s. - `server/tests/fixtures/lc77_*`: regenerated for the additive `<time>` wrapper (verified additive-only). ## Testing - `just check`, `just fmt`, `just test`, `just test-saas` all pass. - `to_iso_utc` unit tests (SQLite format + pass-through). LC-77 fixtures updated + passing. Not operator-visible (no env/config/contract change).
feat(ui): relative message timestamps (LC-314)
All checks were successful
check-secrets / TruffleHog (push) Successful in 4s
check-secrets / Nosey parker (push) Successful in 5s
check-secrets / Kingfisher (push) Successful in 5s
check-secrets / Kingfisher (pull_request) Successful in 5s
check-secrets / TruffleHog (pull_request) Successful in 6s
check-secrets / Nosey parker (pull_request) Successful in 5s
Create release / Create release from merged PR (pull_request) Has been skipped
Check / clippy + fmt + tests (pull_request) Successful in 3m49s
825a9d365d
Message and thread-reply times now read as compact relative ("now", "2 minutes ago", "yesterday"), update live, and show the exact time on hover.

`MessageView::created_at_iso()` emits a JS-safe RFC3339 UTC string for a new `<time data-lc-ts datetime=... title=<absolute>>` wrapper at the three chat-reading timestamp sites (message row, system row, thread reply). A small formatter in layout.html renders each `[data-lc-ts]` via `Intl.RelativeTimeFormat` (browser-localized, so no new Fluent strings), falling back to an absolute date past ~26 days, and re-renders on htmx settle / OOB swap and every 30s so "2m" ticks up and a live arrival formats immediately. The absolute time stays in the title and is the no-JS fallback text.

The LC-77 render fixtures were regenerated for the additive `<time>` wrapper (verified additive-only). `created_at_iso` handles both the SQLite "YYYY-MM-DD HH:MM:SS" UTC format and already-RFC3339 input.

#LC-314
#LC-315

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
longjacksonle deleted branch feat/lc-314-relative-timestamps 2026-06-15 04:25:38 +02:00
Sign in to join this conversation.
No reviewers
No labels
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
psa-systems/lets-chat!334
No description provided.