Design Lounge
Install

Nº 452 of 520

Thread to issue board

A dark intake section: a chat thread floats over a faded kanban board; sending an @mention makes a bot file two issues that drop into Todo, linked back to the reply.

Preview

Open full size
1280 × 800 · 22.6 KB · 281 lines

Use it

Free to use · credit appreciated

1 Once, in your project

npx skills add SusanAcharya/Design-Lounge

2 Then ask

Using the Design Lounge skill, build "Thread to issue board" (piece features-thread-to-issue-board) in my stack. Match its brief; restyle it onto my product's theme.

No skill? Paste the brief instead. It carries the numbers, tokens and behaviour.

Brief

209 lines

Build brief for a coding agent. Rebuild this piece in the reader’s stack. If they haven’t said which stack, ask once, then default to semantic HTML + CSS + a little vanilla JS. Match the numbers below; don’t “improve” them.

What it is

Studied from linear.app: the “Intake” feature band, where a chat thread panel overlaps a dimmed, edge-faded issue board, so the page shows conversation turning into work. This version is for an invented issue tracker, Tracewell, in cool graphite with a single mint accent. It is fully live: press Send on the prefilled “@Tracewell file these and assign to me”, a bot reads the thread, and two issues slide into the Todo column behind the panel, with chips in the reply that light up their cards. The detail worth copying is the two-layer scene: a crisp foreground UI over a background UI that is masked away at its right and bottom edges, so it reads as “the product, continuing beyond the frame”.

Reference behaviour

  1. First frame: a 46px two-line heading “Intake that / files itself” on the left; on the right an 18px lede with a bold first sentence and a “How intake works →” link.
  2. Below, the scene: a board with four 252px columns (Backlog 12, Todo 7, In progress 3, In review 2) starting 260px from the left, masked to transparent from 62% → 98% across and 58% → 96% down, at 90% opacity.
  3. A 392px thread panel floats at the left over the Backlog column with a deep shadow. Header ”# Thread #mobile-feedback”. Three messages from Maya Okafor, Dev Patel and Lu Chen sit at the bottom of the panel (chat order, bottom-aligned).
  4. The composer shows a draft: a mint “@Tracewell” mention pill, then “file these and assign to me”. The mint Send button pulses a soft ring every 2.2s, so the viewer knows where to press.
  5. Pressing Send: the pulse stops, the button disables, the draft becomes a grey placeholder “Message #mobile-feedback”, and “You 10:46” appears with the same text (rises 8px, 400ms).
  6. After 500ms a Tracewell message appears with a shimmering “Reading 3 messages…” (gradient text sweep, 1.2s loop).
  7. After 1100ms the shimmer is replaced by “Filed 2 issues in Mobile, assigned to you, labelled Bug.” and two chips: “TRW-412 Offline banner persists after reconnect” and “TRW-413 Upload retry is inert until relaunch”.
  8. For each chip, a card is inserted at the top of Todo: the slot opens from 0 to its height (grid-rows 0fr → 1fr, 450ms) while the card drops 10px and scales from 0.97 (600ms) with a mint border and 3px mint ring. Cards arrive 320ms apart. The Todo count goes 7 → 8 → 9 and turns mint.
  9. 1.6s later the new cards settle to normal borders, the count returns to grey, and a “Reset demo” button fades into the thread header.
  10. Hovering or focusing a chip outlines its card on the board in mint; clicking flashes it for 900ms.
  11. The thread keeps at most four messages; older ones drop off the top.
  12. Reset restores the original messages, Todo cards, count and draft, re-enables Send and moves focus to it.
  13. With reduced motion, delays shrink to 120ms, nothing slides or shimmers, and the outcome is identical.

Structure

┌──────────────────────────────────── 1280 × 800 ─────────────────────────────────────┐
│  Intake that                         Mention Tracewell in any thread. It reads the   │ head: 2 cols, gap 48
│  files itself       46/1.04          conversation, splits it into issues, …          │ lede 18px, max 470
│                                      How intake works →                              │
│                                                                                       │ 40px
│  ┌ # Thread #mobile-feedback ─────┐  ○ Todo 7         ◑ In progress 3   ◕ In review  │ board top +28px
│  │                                │┐ ┌─────────────┐  ┌─────────────┐  ┌─────────┄┄  │
│  │                                ││ │ TRW-401  MO │  │ TRW-389  SL │  │ TRW-380 ┄┄  │ cards 252 wide
│  │ MO Maya Okafor 10:42           ││ │ Paginate …  │  │ Cache …     │  │ Remove ┄┄   │
│  │ The offline banner never …     ││ └─────────────┘  └─────────────┘  └─────────┄┄  │
│  │ DP Dev Patel 10:44             ││ ┌─────────────┐  ┌─────────────┐                 │
│  │ LC Lu Chen 10:45               ││ │ TRW-398 …   │  │ TRW-386 …   │     ← mask fades │
│  │ ┌────────────────────────────┐ ││ └─────────────┘  └─────────────┘       right and  │
│  │ │ @Tracewell file these and …│ ││ ┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄                         bottom    │
│  │ │ ⊕ ☺ @              [Send →]│ ││                                                  │
│  └─┴────────────────────────────┴─┘│  (Backlog column hidden behind the thread)       │
│   thread 392px, left 40, bottom 28  │                                                  │
└───────────────────────────────────────────────────────────────────────────────────────┘
  • section[aria-labelledby] (flex column, min-height: 100%) → .head grid (h2, lede p, link) → .scene (position: relative; flex: 1; overflow: hidden).
  • .board is role="region" labelled “Mobile team board”: a four-column grid of .col, each a header row plus article.issue cards. Todo’s cards live in #todo so new ones can be prepended.
  • .thread is role="region" labelled “Thread in studio-feedback”: header, ol.msgs (live region), and a form.composer with the draft div, decorative tool icons and a submit button.
  • New cards are wrapped in a .slot whose grid rows animate from 0fr to 1fr, so the column below slides down rather than jumping.

Tokens

:root {
  --bg: #0D0F12;        /* page */
  --panel: #15181D;     /* thread */
  --raised: #1B1F25;    /* composer, chips, reset */
  --card: #171A1F;      /* board cards */
  --line: #262B33;      /* borders */
  --line-2: #1F242B;    /* inner rules */
  --text: #EEF0F3;
  --text-2: #A3ABB7;    /* body copy, lede */
  --text-3: #6C7480;    /* times, ids, counts */
  --mint: #5BE3B0;      /* the only accent: send, mention, bot, new items */
  --mint-ink: #0B2A1F;  /* text on mint */
  --mint-tint: rgba(91,227,176,.12);

  /* label dots: semantic, 7px only */
  --bug: #EF6F6C; --design: #6FA8FF; --backend: #E6B450;
  --perf: #8BD3E6; --feature: #B79CFF; --android: #A4D96C;

  --sans: "Onest", system-ui, sans-serif;
  --mono: "Fragment Mono", ui-monospace, monospace;

  --r-card: 8px; --r-panel: 12px; --r-ctl: 7px;
  --shadow-panel: 0 30px 60px -20px rgba(0,0,0,.7), 0 0 0 1px rgba(0,0,0,.4);
  --ease: cubic-bezier(0.2, 0.7, 0.2, 1);
  --expo: cubic-bezier(0.16, 1, 0.3, 1);
}

Typography

RoleFamilySize / lineWeightTrackingColour
HeadingOnest46px / 1.04500-0.035em--text
LedeOnest18px / 1.45400, lead 5000--text-2, lead --text
Column headerOnest13px5000--text; count Fragment Mono 12px --text-3
Card idFragment Mono12px4000--text-3
Card titleOnest13px5000--text, one line, ellipsis
Label chipOnest11px4000--text-2
Message nameOnest13px6000--text; time 12px --text-3
Message bodyOnest13.5px / 1.454000--text-2
SendOnest13px6000--mint-ink on --mint

Motion

ThingTriggerPropertyFrom → toDuration / delayEasingReduced motion
Send pulseidlebox-shadow ring0 → 8px, fade2.2s loopstandardnone
Your messagesendopacity, translateY0, 8px → 1, 0400msexponone
Bot thinking+500msgradient position100% → −100%1.2s loop, 1.1s totallinearplain grey text
Slot openeach issuegrid-template-rows0fr → 1fr450ms, 320ms apartexpoinstant
New cardeach issueopacity, translateY, scale0, −10px, .97 → 1, 0, 1600msexpoinstant
New card ringeach issueborder, box-shadowmint → lineholds 1.6s, 200ms outstandardinstant
Counteach issuecolour--text-3 → --mint → back300msstandardinstant
Chip linkhover / focuscard border, ringline → mint200msstandardinstant
Reset buttondoneopacity0 → 1200msstandardinstant

The shimmer’s linear timing is fine: it is a texture, not a move.

States

  • Send: idle mint with pulse; hover brightness 1.08; active scale 0.97; disabled --line fill, --text-3 text, no pulse.
  • Draft: filled (mention pill + text) or empty placeholder in --text-3.
  • Composer: focus-within raises its border to #3A414C.
  • Bot message: thinking (shimmer) → done (sentence + chips).
  • Card: rest --line border; new (mint border + ring); linked (mint, forced while a chip is hovered or focused).
  • Count: grey; bumped mint while new cards are arriving.
  • Reset: hidden and not clickable until the run ends.
  • Focus-visible everywhere: 2px mint outline, offset 2px, radius 6px.

Accessibility

  • ol.msgs is aria-live="polite" with aria-relevant="additions", so “You…”, “Reading 3 messages…” and the filed summary are announced as they arrive.
  • The Send button’s accessible name includes the draft text: “Send: @Tracewell file these and assign to me”.
  • Each filed chip is a real button; focusing it highlights the matching card, giving keyboard users the same link that hover gives.
  • Avatars and tool icons are aria-hidden; names are in text.
  • Tab order: “How intake works”, Reset (when shown), Send, then the chips once they exist.
  • Reset returns focus to Send so a keyboard user can run it again immediately.
  • Contrast: --text-2 on --panel ≈ 7.5:1; --text-3 ≈ 3.9:1, used only for 11–12px mono metadata; --mint-ink on --mint ≈ 10:1.
  • The board is decorative context but stays in the accessibility tree as a labelled region, so its counts can be read.

Responsive rules

  • ≥ 1280: as drawn.
  • < 980: heading row stacks (gap 16px), heading 38px, thread 340px wide, board starts at 220px.
  • < 640: section padding 36px 16px; heading 32px; lede 16px; the thread becomes a full-width 470px block in flow, and the board sits under it at 490px down with four 240px columns that clip inside the scene (no page scroll sideways).
  • The scene always has overflow: hidden; the board’s right edge is faded by the mask, never by the window edge.
  • At 375 nothing overflows horizontally.

Acceptance checklist

Always

  • Two layers: a crisp foreground thread over a background board masked to transparent at its right and bottom edges.
  • Sending the @mention produces your message, a thinking state, and a bot summary with one chip per filed issue.
  • Each filed issue appears at the top of the correct column with a slot-open animation; the column count updates.
  • Hovering or focusing a chip highlights its card; the link works by keyboard.
  • One accent colour for everything the agent touches; label colours appear only as 7px dots.
  • Messages are announced via a polite live region.
  • A reset restores the exact first frame and refocuses Send.
  • Reduced motion gives the same result with no slides or shimmer.
  • No horizontal overflow at 375px.

This demo

  • Brand Tracewell; heading “Intake that files itself”.
  • Thread #mobile-feedback with Maya Okafor 10:42, Dev Patel 10:44, Lu Chen 10:45.
  • Board columns Backlog 12, Todo 7, In progress 3, In review 2.
  • Filed issues TRW-412 “Offline banner persists after reconnect” (Bug, Android) and TRW-413 “Upload retry is inert until relaunch” (Bug, Uploads); Todo becomes 9.
  • Accent #5BE3B0 on #0D0F12.

Implementation notes

1. Fade the background UI with two intersected masks. One gradient fades to the right, one fades down; intersecting them gives the soft corner. WebKit needs the prefixed property with source-in.

.board {
  opacity: .9;
  -webkit-mask-image: linear-gradient(90deg,#000 62%,transparent 98%), linear-gradient(180deg,#000 58%,transparent 96%);
  -webkit-mask-composite: source-in;
  mask-image: linear-gradient(90deg,#000 62%,transparent 98%), linear-gradient(180deg,#000 58%,transparent 96%);
  mask-composite: intersect;
}

2. Insert without a jump. Wrap each new card in a slot that animates grid-template-rows from 0fr to 1fr; the inner wrapper needs overflow: hidden; min-height: 0. Add the open class two frames after inserting, or the browser skips the transition.

.slot { display: grid; grid-template-rows: 0fr; transition: grid-template-rows .45s var(--expo); }
.slot.open { grid-template-rows: 1fr; }
.slot > div { overflow: hidden; min-height: 0; }
todo.prepend(node);
requestAnimationFrame(() => requestAnimationFrame(() => node.classList.add('open')));

3. Script the sequence with awaits. A tiny wait(ms) that shortens under reduced motion keeps the choreography readable and guarantees the same end state. Guard against double sends with a running flag and the disabled button.

Common mistakes:

  • Letting chip text wrap the issue id onto two lines; give the id flex: none and the message column minmax(0, 1fr) so the title ellipsizes.
  • Dimming the board with a dark overlay instead of a mask; it looks like a modal backdrop.
  • Faking the board as a screenshot. The new cards must enter the real column.
  • Animating the cards in but leaving the count unchanged.
  • An accent for every label. Label colours stay tiny; the agent owns the accent.
  • Positioning the scene so the board bleeds past the viewport and creates a horizontal scrollbar.

Details

Palette
Type
Onest · Fragment Mono
Motion
Rich motion
Build
Multi-step
Designed bySusan AcharyaKathmandu

Studied

Linear

Show the product doing the work. Fade it at the edges and keep one colour for what matters.

All sources