# Issue triage inbox

> A cream issue triage list: issues are assigned or closed as duplicates, the rest move up and the untriaged count drops from 9 to 6.

- Category: Developer tools
- Version: 1.0
- Source: https://ownlyplans.com/bhaskar/issue-triage-inbox/

## Overview

An issue inbox with five cards. The first gets an ASSIGNED tag and slides away, a duplicate gets a red CLOSED tag and leaves, the others slide up and the Untriaged counter counts down. Topic inspired by OpenDesign's public dashboard prompt list; this prompt and design are written from scratch.

## Tech stack

- CSS
- Dashboard
- HTML

## Build steps

### 1. Paste the prompt

One prompt builds the whole inbox.

Prompt:

```text
Make a single-file HTML issue triage inbox, 1280x720, warm cream background #f6f3ee, ink #221d16. System fonts, no libraries.
Header: H1 "Issue triage", a muted "Needs a decision" and a right aligned counter "Untriaged" with a big number that counts down 9, 8, 7, 6 (CSS @property integer animation with steps).
Five absolutely positioned white cards (90px tall, 16px radius, soft shadow), each with a coloured priority dot, bold title, meta line (issue number, opener, age) and pills on the right (P1 red, P2 amber, P3 blue, Bug purple, Feature/Docs blue): Checkout fails on Safari 17, Add CSV export to reports, Duplicate of #1990 - login loop, Docs typo on pricing page, Dark mode flicker on load.
Motion (8 second loop): cards rise in. Card 1 gets a green ASSIGNED tag, slides 28px right then 90px and fades; cards below move up one slot. Card 3 gets a red CLOSED - DUPLICATE tag and leaves the same way. Counter steps down in sync. Reset at the end.
Respect prefers-reduced-motion. Return only the complete HTML.
```

### 2. Check the assign move

The first card should get a green tag and slide away.

### 3. Check the duplicate

The duplicate card should get a red tag and leave.

**Done when:** You can see it working in the browser.

### 4. Make it real

Replace sample issues with your tracker data.

## Assets

### prompt.md — The full prompt.

~~~~
# Issue triage inbox

Copy this prompt into Claude, Cursor or Lovable.

```text
Make a single-file HTML issue triage inbox, 1280x720, warm cream background #f6f3ee, ink #221d16. System fonts, no libraries.
Header: H1 "Issue triage", a muted "Needs a decision" and a right aligned counter "Untriaged" with a big number that counts down 9, 8, 7, 6 (CSS @property integer animation with steps).
Five absolutely positioned white cards (90px tall, 16px radius, soft shadow), each with a coloured priority dot, bold title, meta line (issue number, opener, age) and pills on the right (P1 red, P2 amber, P3 blue, Bug purple, Feature/Docs blue): Checkout fails on Safari 17, Add CSV export to reports, Duplicate of #1990 - login loop, Docs typo on pricing page, Dark mode flicker on load.
Motion (8 second loop): cards rise in. Card 1 gets a green ASSIGNED tag, slides 28px right then 90px and fades; cards below move up one slot. Card 3 gets a red CLOSED - DUPLICATE tag and leaves the same way. Counter steps down in sync. Reset at the end.
Respect prefers-reduced-motion. Return only the complete HTML.
```
~~~~

### index.html.md — Complete code of the result in the video.

~~~~
# index.html

The finished result as one file. Save it as index.html and open it.

```html
<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>Issue triage inbox</title><style>*{box-sizing:border-box;margin:0;padding:0}
html,body{width:1280px;height:720px;overflow:hidden}
body{font-family:ui-sans-serif,system-ui,-apple-system,"Segoe UI",Roboto,sans-serif;-webkit-font-smoothing:antialiased}
@property --n{syntax:'<integer>';inherits:false;initial-value:0}
.stage{position:absolute;inset:0;animation:cyc 8s linear infinite both}
@keyframes cyc{0%{opacity:0}4%{opacity:1}94%{opacity:1}100%{opacity:0}}
body:not(.go) *,body:not(.go) *::before,body:not(.go) *::after{animation-play-state:paused!important}
.cnt::after{content:counter(n)}.cnt{counter-reset:n var(--n)}
@media (prefers-reduced-motion:reduce){*{animation:none!important}}


body{background:#f6f3ee;color:#221d16}
.hd{position:absolute;left:44px;right:44px;top:30px;display:flex;align-items:center;gap:14px}
.hd h1{font-size:28px;letter-spacing:-.03em}.hd span{color:#8c8272;font-size:14px}
.c{margin-left:auto;font-size:14px;color:#8c8272}.c b{font-size:30px;color:#221d16;letter-spacing:-.03em;margin-left:6px}
.cn{animation:cn 8s infinite both}@keyframes cn{0%,30%{--n:9}40%,52%{--n:8}60%,72%{--n:7}82%,100%{--n:6}}
.is{position:absolute;left:44px;right:44px;height:90px;background:#fff;border-radius:16px;padding:16px 22px;box-shadow:0 12px 26px -22px #5c4a1d;display:flex;align-items:center;gap:18px}
.is i{width:12px;height:12px;border-radius:50%}.is h3{font-size:17px}.is p{font-size:13px;color:#8c8272;margin-top:4px}
.is .pl{margin-left:auto;display:flex;gap:8px;align-items:center}
.lb{font-size:12px;font-weight:700;padding:5px 11px;border-radius:99px}
.p1{background:#ffe0dc;color:#b42318}.p2{background:#ffefc7;color:#8a5a00}.p3{background:#e1eaff;color:#2a4dc4}.bg{background:#e8e1ff;color:#5b34c2}
.i1{top:100px;animation:a 8s infinite both}.i2{top:204px;animation:b 8s infinite both}.i3{top:308px;animation:c 8s infinite both}.i4{top:412px;animation:d 8s infinite both}.i5{top:516px}
@keyframes a{0%,6%{opacity:0;transform:translateY(14px)}12%,28%{opacity:1;transform:none}38%{opacity:1;transform:translateX(28px)}46%,100%{opacity:0;transform:translateX(90px)}}
@keyframes b{0%,8%{opacity:0;transform:translateY(14px)}14%,40%{opacity:1;transform:none}52%,100%{opacity:1;transform:translateY(-104px)}}
@keyframes c{0%,10%{opacity:0;transform:translateY(14px)}16%,52%{opacity:1;transform:none}60%{opacity:1;transform:translate(28px,-104px)}68%,100%{opacity:0;transform:translate(90px,-104px)}}
@keyframes d{0%,12%{opacity:0;transform:translateY(14px)}18%,64%{opacity:1;transform:none}76%,100%{opacity:1;transform:translateY(-208px)}}
.i5{animation:e 8s infinite both}@keyframes e{0%,14%{opacity:0;transform:translateY(14px)}20%,76%{opacity:1;transform:none}88%,100%{opacity:1;transform:translateY(-208px)}}
.tag{position:absolute;right:140px;font-size:12px;font-weight:800;letter-spacing:.06em;color:#fff;padding:6px 12px;border-radius:9px;opacity:0}
.t1{top:128px;background:#16a34a;animation:t1 8s infinite both}.t2{top:336px;background:#b42318;animation:t2 8s infinite both}
@keyframes t1{0%,26%{opacity:0}30%,40%{opacity:1}44%,100%{opacity:0}}@keyframes t2{0%,50%{opacity:0}54%,62%{opacity:1}66%,100%{opacity:0}}
.ls{position:absolute;left:44px;bottom:26px;font-size:13px;color:#8c8272}
</style></head><body><div class="stage"><div class="hd"><h1>Issue triage</h1><span>Needs a decision</span><div class="c">Untriaged<b><span class="cnt cn"></span></b></div></div><div class="is i1"><i style="background:#ef4444"></i><div><h3>Checkout fails on Safari 17</h3><p>#2041 - opened by Dana - 2 h ago</p></div><div class="pl"><span class="lb p1">P1</span><span class="lb bg">Bug</span></div></div><div class="is i2"><i style="background:#f59e0b"></i><div><h3>Add CSV export to reports</h3><p>#2038 - opened by Marco - 5 h ago</p></div><div class="pl"><span class="lb p3">P3</span><span class="lb p3">Feature</span></div></div><div class="is i3"><i style="background:#f59e0b"></i><div><h3>Duplicate of #1990 - login loop</h3><p>#2036 - opened by Lena - 1 d ago</p></div><div class="pl"><span class="lb p2">P2</span><span class="lb bg">Bug</span></div></div><div class="is i4"><i style="background:#3b82f6"></i><div><h3>Docs typo on pricing page</h3><p>#2033 - opened by Tom - 1 d ago</p></div><div class="pl"><span class="lb p3">P3</span><span class="lb p3">Docs</span></div></div><div class="is i5"><i style="background:#f59e0b"></i><div><h3>Dark mode flicker on load</h3><p>#2031 - opened by Priya - 2 d ago</p></div><div class="pl"><span class="lb p2">P2</span><span class="lb bg">Bug</span></div></div><div class="tag t1">ASSIGNED</div><div class="tag t2">CLOSED - DUPLICATE</div><div class="ls">Swipe-style triage: assign, label or close each issue</div></div><script>window.start=function(){document.body.classList.add("go")};if(!/[?&]rec/.test(location.search))start();</script></body></html>
```
~~~~


## Build instructions by tool

### Claude Code

Open a terminal in an empty folder, run `claude`, then paste the prompt.

```text
Build the "Issue triage inbox" app from the OwnlyPlans blueprint at https://ownlyplans.com/bhaskar/issue-triage-inbox/.
Stack: CSS, Dashboard, HTML.
Follow the plan's steps in order: Paste the prompt → Check the assign move → Check the duplicate → Make it real.
Download the full plan (Markdown) from the link above and keep it in the project root as PLAN.md.
Ask me before adding anything not in the plan. (Prepared for Claude Code.)
```

### Cursor

Open an empty folder in Cursor, start an Agent chat, then paste the prompt.

```text
Build the "Issue triage inbox" app from the OwnlyPlans blueprint at https://ownlyplans.com/bhaskar/issue-triage-inbox/.
Stack: CSS, Dashboard, HTML.
Follow the plan's steps in order: Paste the prompt → Check the assign move → Check the duplicate → Make it real.
Download the full plan (Markdown) from the link above and keep it in the project root as PLAN.md.
Ask me before adding anything not in the plan. (Prepared for Cursor.)
```

### Lovable

Start a new Lovable project and paste the prompt as your first message.

```text
Build the "Issue triage inbox" app from the OwnlyPlans blueprint at https://ownlyplans.com/bhaskar/issue-triage-inbox/.
Stack: CSS, Dashboard, HTML.
Follow the plan's steps in order: Paste the prompt → Check the assign move → Check the duplicate → Make it real.
Download the full plan (Markdown) from the link above and keep it in the project root as PLAN.md.
Ask me before adding anything not in the plan. (Prepared for Lovable.)
```

## Definition of done

- Every build step is complete and the app runs locally.
- The main user flow works end to end.
- Share your build on OwnlyPlans with a demo link, build time and tool.
