# Community moderation queue

> A dark moderation queue: one report is removed, another approved, the rest move up and the open count drops from 12 to 10.

- Category: Developer tools
- Version: 1.0
- Source: https://ownlyplans.com/bhaskar/community-moderation-queue/

## Overview

Three flagged posts with highlighted words. Remove is pressed on the first (red REMOVED stamp, card leaves), Approve on the second (green stamp, card leaves) and the Open reports 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

The AI builds the three report cards and the counter.

Prompt:

```text
Make a single-file HTML community moderation queue, 1280x720, near-black blue background #14181f, cards #1c222c with 1px #2a3240 border and 18px radius, text #e6ebf5. System fonts, no libraries.
Header: H1 "Moderation queue" and a right aligned big number with the label "Open reports" that counts down 12, 11, 10 (CSS @property integer).
Three absolutely positioned report cards (158px tall). Each shows username, age, a red reason pill (Spam, Harassment, Off topic), the post text with offending words highlighted in a red tinted mark, and three buttons: Approve (dark green), Remove (dark red) and Ban user (grey).
Motion (8 second loop): cards rise in. On card 1 the Remove button presses, a red REMOVED stamp appears top right, the card slides right and fades; the other cards move up one slot and the counter drops to 11. Then card 2 gets Approve pressed, a green APPROVED stamp, slides away, card 3 moves up, counter drops to 10. Reset at the end.
Respect prefers-reduced-motion. Return only the complete HTML.
```

### 2. Check the remove

The first card should get a red stamp and leave.

### 3. Check the approve

The second card should get a green stamp and leave.

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

### 4. Make it real

Connect the buttons to your moderation actions.

## Assets

### prompt.md — The full prompt.

~~~~
# Community moderation queue

Copy this prompt into Claude, Cursor or Lovable.

```text
Make a single-file HTML community moderation queue, 1280x720, near-black blue background #14181f, cards #1c222c with 1px #2a3240 border and 18px radius, text #e6ebf5. System fonts, no libraries.
Header: H1 "Moderation queue" and a right aligned big number with the label "Open reports" that counts down 12, 11, 10 (CSS @property integer).
Three absolutely positioned report cards (158px tall). Each shows username, age, a red reason pill (Spam, Harassment, Off topic), the post text with offending words highlighted in a red tinted mark, and three buttons: Approve (dark green), Remove (dark red) and Ban user (grey).
Motion (8 second loop): cards rise in. On card 1 the Remove button presses, a red REMOVED stamp appears top right, the card slides right and fades; the other cards move up one slot and the counter drops to 11. Then card 2 gets Approve pressed, a green APPROVED stamp, slides away, card 3 moves up, counter drops to 10. 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>Community moderation queue</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:#14181f;color:#e6ebf5}
.w{position:absolute;left:48px;right:48px;top:30px}
.hd{display:flex;align-items:center}h1{font-size:28px;letter-spacing:-.03em}.hd .q{margin-left:auto;text-align:right}.q small{display:block;font-size:11px;letter-spacing:.1em;text-transform:uppercase;color:#8d9ab3}.q b{font-size:40px}
.q1{animation:q 8s infinite both}@keyframes q{0%,42%{--n:12}46%,66%{--n:11}70%,100%{--n:10}}
.list{position:relative;margin-top:22px;height:520px}
.it{position:absolute;left:0;right:0;height:158px;background:#1c222c;border:1px solid #2a3240;border-radius:18px;padding:18px 22px;opacity:0;animation:in 8s infinite both}
@keyframes in{0%,4%{opacity:0;transform:translateY(14px)}12%,100%{opacity:1;transform:none}}
.it:nth-child(1){top:0}.it:nth-child(2){top:176px;animation:in 8s .1s infinite both,u2 8s infinite both}.it:nth-child(3){top:352px;animation:in 8s .2s infinite both,u3 8s infinite both}
.it:nth-child(1){animation:in 8s infinite both,x1 8s infinite both}
@keyframes x1{0%,40%{transform:none}52%,100%{transform:translateX(120px);opacity:0}}
.it:nth-child(1){animation:in 8s infinite both,x1 8s infinite both}
.m{display:flex;gap:10px;align-items:center;font-size:12px;color:#8d9ab3}.m b{color:#e6ebf5;font-size:14px}.fl{background:#3a2024;color:#ff8a8a;border-radius:99px;padding:3px 10px;font-weight:700}
.tx{margin:12px 0;font-size:15px;line-height:1.5;color:#cdd6e6}.tx mark{background:#5a2a2a;color:#ffb4b4;border-radius:4px;padding:0 3px}
.bt{display:flex;gap:10px}.bt span{padding:9px 18px;border-radius:11px;font-weight:700;font-size:14px;background:#262e3b}
.bt .ap{background:#14532d;color:#86efac}.bt .rm{background:#7f1d1d;color:#fecaca}
.stamp{position:absolute;right:26px;top:20px;font-weight:800;font-size:13px;letter-spacing:.08em;padding:6px 12px;border-radius:9px;opacity:0}
.s1{background:#7f1d1d;color:#fecaca;animation:s1 8s infinite both}.s2{background:#14532d;color:#86efac;animation:s2 8s infinite both}
@keyframes s1{0%,34%{opacity:0}40%,100%{opacity:1}}@keyframes s2{0%,64%{opacity:0}70%,100%{opacity:1}}
.it:nth-child(1) .rm{animation:pr 8s infinite both}@keyframes pr{0%,30%{transform:none}34%{transform:scale(.9)}38%,100%{transform:none}}
.it:nth-child(2) .ap{animation:pa 8s infinite both}@keyframes pa{0%,60%{transform:none}64%{transform:scale(.9)}68%,100%{transform:none}}
@keyframes u2{0%,40%{top:176px}52%,100%{top:0}}
@keyframes u3{0%,40%{top:352px}52%,100%{top:176px}}
.it:nth-child(2){animation:in 8s .1s infinite both,u2 8s infinite both,x2 8s infinite both}
@keyframes x2{0%,64%{transform:none}76%,100%{transform:translateX(120px);opacity:0}}
.it:nth-child(1){animation:in 8s infinite both,x1 8s infinite both}</style></head><body><div class="stage"><div class="w"><div class="hd"><h1>Moderation queue</h1><div class="q"><small>Open reports</small><b class="cnt q1"></b></div></div><div class="list"><div class="it"><div class="stamp s1">REMOVED</div><div class="m"><b>mark_d</b><span>2m ago</span><span class="fl">Spam</span></div><div class="tx">Get rich fast!! click <mark>bit.ly/free-money</mark> and <mark>DM me</mark> for the secret</div><div class="bt"><span class="ap">Approve</span><span class="rm">Remove</span><span>Ban user</span></div></div><div class="it"><div class="stamp s2">APPROVED</div><div class="m"><b>lena.k</b><span>6m ago</span><span class="fl">Harassment</span></div><div class="tx">You clearly have no idea what you are doing, <mark>just quit</mark>. Everyone here knows it.</div><div class="bt"><span class="ap">Approve</span><span class="rm">Remove</span><span>Ban user</span></div></div><div class="it"><div class="m"><b>o_ramirez</b><span>9m ago</span><span class="fl">Off topic</span></div><div class="tx">Anyone selling used bikes in the area? Selling mine, message for photos.</div><div class="bt"><span class="ap">Approve</span><span class="rm">Remove</span><span>Ban user</span></div></div></div></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 "Community moderation queue" app from the OwnlyPlans blueprint at https://ownlyplans.com/bhaskar/community-moderation-queue/.
Stack: CSS, Dashboard, HTML.
Follow the plan's steps in order: Paste the prompt → Check the remove → Check the approve → 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 "Community moderation queue" app from the OwnlyPlans blueprint at https://ownlyplans.com/bhaskar/community-moderation-queue/.
Stack: CSS, Dashboard, HTML.
Follow the plan's steps in order: Paste the prompt → Check the remove → Check the approve → 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 "Community moderation queue" app from the OwnlyPlans blueprint at https://ownlyplans.com/bhaskar/community-moderation-queue/.
Stack: CSS, Dashboard, HTML.
Follow the plan's steps in order: Paste the prompt → Check the remove → Check the approve → 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.
