Toggle Sidebar B
AppearanceLight & dark mode D

Chat Transcript

The small parts every transcript repeats: the day a run of messages belongs to, the clock beside a turn, a human's message with its links made clickable, pictures that open in the lightbox, files that can only be named, and a turn that never reached the server. Assemble them inside message-scroller, message and bubble.

Day divider and timestamp

`startsNewDay(previous, current)` says when to draw the divider, `dayLabelOf` says what it reads: Today, Yesterday, or the date. `ChatTimestamp` is the clock beside a turn, and it never fades: an action you go looking for can hide until hover, context you read cannot.

Replay preview
Booth 12 has no power outlet.

10:51 AM

On it, an electrician is on the way.

11:51 AM

Sorted, thank you.

11:51 AM

Glad to hear it. Anything else?

11:50 AM

Text with links

A human's message is text, not markdown. `ChatText` splits it into segments and builds an element for each URL, so whatever someone typed stays text and nothing they wrote is parsed as markup. Trailing punctuation stays with the sentence.

Replay preview
Please check https://example.com/booth/12, then reply "ok". Markup like <b>this</b> stays text.

Pictures and file chips

Pictures are shown, not named: `ChatPictures` opens each one in the lightbox. Anything that cannot be drawn - a document, or an image whose bytes are gone - goes through `ChatFileChips`.

Replay preview
floor-plan.pdf
expired-screenshot.png
Here is the booth and the plan.

Failed turn

A turn that never reached the server keeps the reader's own words where they wrote them, says what went wrong, and offers Retry and Discard. The host owns the message and decides what retrying means.

Replay preview
Can we get one more chair?
Message failed to send.

Unread dot

For a launcher whose panel is shut while something arrived. A dot rather than a count: on a small round button a number needs a size the style guide does not allow for a value, and the next action is the same either way.

Replay preview
Click to toggle the mark.

API Reference

ChatDayDivider

PropTypeDefaultDescription
labelstringUsually dayLabelOf(iso).

ChatTimestamp

PropTypeDefaultDescription
atstringISO timestamp; renders formatMessageTime(at).

ChatText

PropTypeDefaultDescription
textstringPlain text. URLs become links, everything else stays text.

ChatPictures

PropTypeDefaultDescription
items{ url: string; name?: string | null }[]Images with a URL. Renders nothing for an empty list.

ChatFileChips

PropTypeDefaultDescription
items{ name?: string | null; kind: "image" | "document" }[]Files to name rather than draw.

ChatFailedTurn

PropTypeDefaultDescription
errorstringWhat went wrong, in the reader's words.
disabledbooleanfalseWhile another turn is in flight.
SlotDescription
retryEvent: send the same thing again.
discardEvent: give up on the turn.

Helpers

PropTypeDefaultDescription
formatMessageTime(iso)string"10:02", or "" when the date does not parse.
dayLabelOf(iso)string"Today", "Yesterday", or the date.
startsNewDay(previousIso, currentIso)booleanTrue for the first message and whenever the calendar date changes.
linkSegments(text){ text, href? }[]The split ChatText renders.