XI Conversation

Star on GitHubFeedback
XI ConversationNative HTMLot-marker

Marker

A quiet line in a conversation: a status, where a day begins, where you left off, or how long it went quiet.

Report an issue with Marker

Example

HaldenRound twoThree people

Yesterday

Ada joined the thread

The harbour mark is ready for a look.

Three hours later

Looking now. Can we see it at stamp size?

Today

Here it is at stamp size.

New

And one in a single colour, for the ferry office.

Edited at 09:52

Status

Edited at 09:52

Status, dot

Ada joined the thread

Divider

Today

Rule
Rule, standing
OursYours
Standing, with a word

Today

Ribbon

New

Ribbon, right to left

جديد

Lapse, a minute

A minute later

Lapse, an hour

An hour later

Lapse, a day

The next day

Lapse, right to left

في اليوم التالي

Lapse, a week

A week later

Install

Run it in a project that has the shadcn CLI set up. It brings the 0nlyType base along.

npx shadcn@latest add https://thedirectors.agency/ui/r/marker.json

Usage

This example also uses Button.

npx shadcn@latest add https://thedirectors.agency/ui/r/button.json
marker-example.tsx
"use client"import * as React from "react"import { Button } from "@/components/ui/button"import { Marker } from "@/components/ui/marker"/** A line of the conversation the markers sit in, set as the thread sets theirs and yours. */function Said({ you, children }: { you?: boolean; children: React.ReactNode }) {return (<p className={you ? "ot-yours justify-self-end" : undefined} style={{ margin: 0, fontSize: "var(--ot-p)", color: "var(--ot-ink)" }}>{children}</p>)}export default function Example() {const [played, setPlayed] = React.useState(0)const arriving = played > 0return (<div className="grid max-w-[36rem] justify-items-stretch gap-(--ot-space-5)"><div key={played} className="grid justify-items-stretch gap-(--ot-space-5)"><div className="flex gap-(--ot-space-4)" style={{ fontSize: "var(--ot-pp)", color: "var(--ot-graphite)" }}><span>Halden</span><Marker variant="divider" orientation="vertical" arriving={arriving} /><span>Round two</span><Marker variant="divider" orientation="vertical" arriving={arriving} /><span>Three people</span></div><Marker variant="divider" arriving={arriving} /><Marker variant="divider" arriving={arriving}>Yesterday</Marker><Marker dot>Ada joined the thread</Marker><Said>The harbour mark is ready for a look.</Said><Marker variant="lapse" minutes={180} arriving={arriving}>Three hours later</Marker><Said you>Looking now. Can we see it at stamp size?</Said><Marker variant="divider" arriving={arriving}>Today</Marker><Said>Here it is at stamp size.</Said><Marker variant="ribbon" arriving={arriving}>New</Marker><Said>And one in a single colour, for the ferry office.</Said><Marker>Edited at 09:52</Marker></div><Button variant="quiet" className="justify-self-start" onClick={() => setPlayed((n) => n + 1)}>Draw them again</Button></div>)}const wide = { width: "18rem", maxWidth: "100%" }

Contract

  • Underneath: native.
  • Anatomy: <p class="ot-marker"> for a status (with .ot-marker-dot), or data-variant="divider | ribbon | lapse". A lapse carries --lapse (0–1, from minutes). A divider may carry data-orientation="vertical". data-arriving plays it.
  • A quiet line in the flow. A divider draws its rules outward from the word, as if the word pushed them apart; the word stands on them, as "Less is more." sets its rules on the baselines.
  • Rule: a divider with no word is a plain rule (role="separator"): the two rules meet, one unbroken hairline, and arriving it still draws outward from its middle. Vertical (orientation="vertical", divider only): the rule stands up between two things in a row, as tall as the row, as "Less is more." rules its columns. The marker turns on its side (writing-mode: vertical-rl), so a word reads down it like a book's spine, the rules running above and below it and drawing outward from it.
  • Ribbon: where you left off, after the ribbon sewn into a book to keep your place. One accent line (--ot-stroke) runs from the inline start to the word at the end ("New"), in the accent, because it marks where you are. Arriving, it draws from where you started reading. It is the one accent in a thread; forced colours draw it in Highlight.
  • Lapse: a pause in the conversation, given as silence (Principle 1, literally). No rule at all: the room above and below the words and the space between their letters both grow with how long it went quiet, on a log scale from a minute (a breath) to a week (the widest). The words stay centred however far they're tracked. A joined script (Arabic, Persian, Urdu, by lang) is never tracked apart; its word spaces widen instead. Arriving, the silence opens and the letters spread.

Props

Props of Marker
PropTypeDefaultWhat it does
variant"status" | "divider" | "ribbon" | "lapse""status"divider: where a day begins, the word standing on the rule it pushed apart. ribbon: where you left off, one accent line across the page with its word at the end, like the ribbon in a book. lapse: a pause, given as silence: no rule, only room around the words and space between their letters, more the longer it was. A divider with no word is a plain rule (role separator), one unbroken hairline.
orientation"horizontal" | "vertical""horizontal"Divider only. vertical stands the rule up between two things in a row, as tall as the row (put it in a flex or grid row). A word, if any, turns on its side and reads down it like a book's spine, the rules running above and below it.
dotbooleanfalseA small dot before a status.
minutesnumber0Lapse only: how long the pause was. The room grows on a log scale, from a breath at a minute to the widest at a week.
arrivingbooleanfalsePlays the arrival when it mounts: a divider's rules draw outward, a ribbon draws from where you started reading, a lapse opens.

Craft

Where its move comes from

Where its move comes from
ComponentReferenceMove
Marker"Less is more." rulesRules pushed apart by the word, which stands on them
Ribbon markerThe ribbon in a book; one accent for where you areOne accent line across the page where you left off
Lapse markerPrinciple 1; "Renaissance." spread labelsThe pause given as room and tracking, longer silence, more of both
Rule marker"Less is more." rules its rows and columnsA wordless rule, lying or standing; a word stood up reads down it like a spine

How it moves

How it moves
ComponentArticulationWhat moves
MarkerSpreadThe rules draw outward from the word, or from the middle of a wordless rule (up and down when it stands)
Ribbon markerDrawnThe accent line draws from the start to the word
Lapse markerOpeningThe silence opens around the words and their letters spread