Connection lost. Reconnecting… attempt 1 of 8
Paused. Your work is held on the server.
Could not reconnect.
This session has expired on the server.
An unhandled error has occurred.
Sedna.UI
v0.17.0 · main

Timeline

tier 2 — classes

A record of things that happened, with when — an audit trail, a run history, a comment thread. It differs from .steps in being open-ended: if the reader can be “on” one of them, it is steps.

Timeline

Two spans per entry: .timeline-when and .timeline-what. data-kindgo, warn, danger, info — colours a marker for an entry that mattered.

  • 03:15 Approved and written to the warehouse
  • 02:58 Priority raised to P2 by the housekeeper
  • 02:41 Rerouted to EU-West
  • 01:12 First reply attempt failed — mailbox unavailable
  • 00:31 Order opened from an e-mail
<ul class="timeline" style="max-width:460px">
    <li data-kind="go">
        <span class="timeline-when">03:15</span>
        <span class="timeline-what">Approved and written to the warehouse</span>
    </li>
    <li data-kind="warn">
        <span class="timeline-when">02:58</span>
        <span class="timeline-what">Priority raised to P2 by the housekeeper</span>
    </li>
    <li data-kind="info">
        <span class="timeline-when">02:41</span>
        <span class="timeline-what">Rerouted to EU-West</span>
    </li>
    <li data-kind="danger">
        <span class="timeline-when">01:12</span>
        <span class="timeline-what">First reply attempt failed — mailbox unavailable</span>
    </li>
    <li>
        <span class="timeline-when">00:31</span>
        <span class="timeline-what">Order opened from an e-mail</span>
    </li>
</ul>

Icon markers

A .timeline-mark child replaces the dot, for a record where the marker is the information — a robot for “the agent worked it”, a lock for “it needs a person”. The gutter is set by the list, so one marked entry widens every row and the connector stays straight.

  • 03:15 Decided — the reply went out unchanged
  • 02:58 Held for a person: the mailbox is shared
  • 02:41 The agent drafted a reply and cited two articles
  • 00:31 Opened from an e-mail to the service desk
<ul class="timeline" style="max-width:460px">
    <li data-kind="go">
        <span class="timeline-mark"><i class="ri-check-line" aria-hidden="true"></i></span>
        <span class="timeline-when">03:15</span>
        <span class="timeline-what">Decided — the reply went out unchanged</span>
    </li>
    <li data-kind="warn">
        <span class="timeline-mark"><i class="ri-lock-line" aria-hidden="true"></i></span>
        <span class="timeline-when">02:58</span>
        <span class="timeline-what">Held for a person: the mailbox is shared</span>
    </li>
    <li>
        <span class="timeline-mark"><i class="ri-robot-2-line" aria-hidden="true"></i></span>
        <span class="timeline-when">02:41</span>
        <span class="timeline-what">The agent drafted a reply and cited two articles</span>
    </li>
    <li>
        <span class="timeline-mark"><i class="ri-mail-line" aria-hidden="true"></i></span>
        <span class="timeline-when">00:31</span>
        <span class="timeline-what">Opened from an e-mail to the service desk</span>
    </li>
</ul>

The entry still happening

data-state="current" marks the head of a live record — a job still running, a reply still being drafted.

  • now Drafting a reply against the two cited articles
  • 14:07 Matched to the “returns after 30 days” policy
  • 14:06 Order opened from an e-mail
<ul class="timeline" style="max-width:460px">
    <li data-state="current">
        <span class="timeline-when">now</span>
        <span class="timeline-what">Drafting a reply against the two cited articles</span>
    </li>
    <li data-kind="info">
        <span class="timeline-when">14:07</span>
        <span class="timeline-what">Matched to the &ldquo;returns after 30 days&rdquo; policy</span>
    </li>
    <li>
        <span class="timeline-when">14:06</span>
        <span class="timeline-what">Order opened from an e-mail</span>
    </li>
</ul>

Entries with a body

.timeline-body is the supporting block under the headline — the error a retry returned, the fields that changed, the chips for what it touched. A marker is opaque, and --timeline-surface reads --surface-here, so a timeline in a card, a modal or a drawer is right already; on a surface your app paints, set --timeline-surface on the list.

TCK-4182 — Mailbox quota exceeded on EXCH-02
  • 14:52 Automatic reply could not be delivered

    550 5.2.2 Mailbox full — quota 2048 MB exceeded

    Retried twice, ten minutes apart. Both attempts returned the same code.

  • 14:41 Held for a person
    The mailbox is shared, so nobody owns the reply. Assigned to the on-call queue rather than to a name.
  • 14:38 Classified and tagged
    Exchange Quota Contoso Logistics
<div class="card" style="max-width:520px">
    <div class="card-head">
        <strong>TCK-4182 — Mailbox quota exceeded on EXCH-02</strong>
    </div>
    <div class="card-body">
        <ul class="timeline">
            <li data-kind="danger">
                <span class="timeline-mark"><i class="ri-error-warning-line" aria-hidden="true"></i></span>
                <span class="timeline-when">14:52</span>
                <span class="timeline-what">Automatic reply could not be delivered</span>
                <div class="timeline-body">
                    <p><code>550 5.2.2 Mailbox full — quota 2048 MB exceeded</code></p>
                    <p>Retried twice, ten minutes apart. Both attempts returned the same code.</p>
                </div>
            </li>
            <li data-kind="warn">
                <span class="timeline-mark"><i class="ri-lock-line" aria-hidden="true"></i></span>
                <span class="timeline-when">14:41</span>
                <span class="timeline-what">Held for a person</span>
                <div class="timeline-body">
                    The mailbox is shared, so nobody owns the reply. Assigned to the on-call
                    queue rather than to a name.
                </div>
            </li>
            <li>
                <span class="timeline-mark"><i class="ri-price-tag-3-line" aria-hidden="true"></i></span>
                <span class="timeline-when">14:38</span>
                <span class="timeline-what">Classified and tagged</span>
                <div class="timeline-body">
                    <div class="chip-set">
                        <span class="chip">Exchange</span>
                        <span class="chip">Quota</span>
                        <span class="chip">Contoso Logistics</span>
                    </div>
                </div>
            </li>
        </ul>
    </div>
</div>

Timestamps in a gutter

.timeline--aside moves the “when” into a right-aligned column of its own — reach for it when the reader scans by time, because a column of times can be read down. The gutter is --timeline-aside; not for a narrow column, where the entry text then wraps to three words a line.

  • 08:12:04 Run finished — 1 340 rows written, 0 rejected
  • 08:11:58 Retried the ledger batch once after a lock timeout
  • 08:09:31 Loaded the incremental slice since yesterday 08:00
  • 08:09:30 Run started by the nightly schedule
<ul class="timeline timeline--aside" style="max-width:520px">
    <li data-kind="go">
        <span class="timeline-when">08:12:04</span>
        <span class="timeline-what">Run finished — 1 340 rows written, 0 rejected</span>
    </li>
    <li data-kind="warn">
        <span class="timeline-when">08:11:58</span>
        <span class="timeline-what">Retried the ledger batch once after a lock timeout</span>
    </li>
    <li>
        <span class="timeline-when">08:09:31</span>
        <span class="timeline-what">Loaded the incremental slice since yesterday 08:00</span>
    </li>
    <li>
        <span class="timeline-when">08:09:30</span>
        <span class="timeline-what">Run started by the nightly schedule</span>
    </li>
</ul>

Breaks and a foot

.timeline-group is a day, a release or a shift, and is an <li> in the same list rather than a heading between two, so the record stays one list. .timeline-more is the foot a record with no end needs; put a link or a .btn-ghost inside it, because the <li> is a row, not a control.

  • Today
  • 09:41 Closed by Priya Nair
  • 09:12 Assigned to Fulfilment
  • Yesterday
  • 18:03 Delivery attempt failed — no answer at the door
  • 11:27 Address corrected after a postcode mismatch
  • 37 earlier entries, back to 4 March
<ul class="timeline" style="max-width:480px">
    <li class="timeline-group">Today</li>
    <li data-kind="go">
        <span class="timeline-when">09:41</span>
        <span class="timeline-what">Closed by Priya Nair</span>
    </li>
    <li>
        <span class="timeline-when">09:12</span>
        <span class="timeline-what">Assigned to Fulfilment</span>
    </li>
    <li class="timeline-group">Yesterday</li>
    <li data-kind="danger">
        <span class="timeline-when">18:03</span>
        <span class="timeline-what">Delivery attempt failed — no answer at the door</span>
    </li>
    <li data-kind="warn">
        <span class="timeline-when">11:27</span>
        <span class="timeline-what">Address corrected after a postcode mismatch</span>
    </li>
    <li class="timeline-more">37 earlier entries, back to 4 March</li>
</ul>

Avatar markers

.timeline-mark--bare drops the tile's chrome and hands the avatar the marker's diameter, so the two cannot disagree about size. Do not put a data-kind on a bare entry — the fill is painted over by whatever is in the marker; .avatar--muted is the honest marker for an actor that is not a person.

  • PN Priya Nair · 10:04 The quota was raised to 8 GB, so this should not recur.
  • JW Jordan Weiss · 09:52 Archived everything older than two years and asked for a bigger quota.
    Freed 1.1 GB. That buys about a fortnight at the current rate, which is why the quota request is the actual fix.
  • Housekeeper · 09:31 Opened from an e-mail to the service desk.
<ul class="timeline" style="max-width:520px">
    <li>
        <span class="timeline-mark timeline-mark--bare"><span class="avatar">PN</span></span>
        <span class="timeline-when">Priya Nair · 10:04</span>
        <span class="timeline-what">The quota was raised to 8 GB, so this should not recur.</span>
    </li>
    <li>
        <span class="timeline-mark timeline-mark--bare"><span class="avatar">JW</span></span>
        <span class="timeline-when">Jordan Weiss · 09:52</span>
        <span class="timeline-what">Archived everything older than two years and asked for a bigger quota.</span>
        <div class="timeline-body">
            Freed 1.1 GB. That buys about a fortnight at the current rate, which is why the
            quota request is the actual fix.
        </div>
    </li>
    <li>
        <span class="timeline-mark timeline-mark--bare">
            <span class="avatar avatar--muted"><i class="ri-robot-2-line" aria-hidden="true"></i></span>
        </span>
        <span class="timeline-when">Housekeeper · 09:31</span>
        <span class="timeline-what">Opened from an e-mail to the service desk.</span>
    </li>
</ul>

Sizing it

Five variables size the component, and every offset is derived from them: --timeline-line (the connector's width), --timeline-dot and --timeline-marker (the two marker diameters), --timeline-lead (the height of the row a marker centres in) and --timeline-gap (the space under an entry). Keep a diameter odd against a 1px line, or the marker centres on a half pixel and the circle antialiases into a smudge.

  • 03:15:02 deploy.web — succeeded in 41s
  • 03:14:21 migrate.db — 3 migrations applied
  • 03:14:18 migrate.db — advisory lock held, waited 2.4s
  • 03:13:55 build.image — pushed sha-9f2c1ab
  • 03:12:40 pipeline started from main
<div style="max-width:460px; padding:16px; border-radius:6px; background:var(--surface-raised-2)">
    <ul class="timeline" style="--timeline-gap: 6px; --timeline-surface: var(--surface-raised-2)">
        <li data-kind="go">
            <span class="timeline-when">03:15:02</span>
            <span class="timeline-what">deploy.web — succeeded in 41s</span>
        </li>
        <li data-kind="go">
            <span class="timeline-when">03:14:21</span>
            <span class="timeline-what">migrate.db — 3 migrations applied</span>
        </li>
        <li data-kind="warn">
            <span class="timeline-when">03:14:18</span>
            <span class="timeline-what">migrate.db — advisory lock held, waited 2.4s</span>
        </li>
        <li data-kind="go">
            <span class="timeline-when">03:13:55</span>
            <span class="timeline-what">build.image — pushed sha-9f2c1ab</span>
        </li>
        <li>
            <span class="timeline-when">03:12:40</span>
            <span class="timeline-what">pipeline started from main</span>
        </li>
    </ul>
</div>