Skip to main content
vibld

Template

Pebbleroom

The unified inbox of an all-in-one team workspace (chat, tasks, docs). It collects notifications from threads and channels, grouped by conversation, and opens the selected thread on the right with messages, reactions and a composer so people can catch up and reply in one place.

Dark-mode team workspace inbox with grouped threads · App screen: inbox · Small tools and apps · full-stack app (auth + DB)

A mock-up of the screen, drawn from its layout, palette and typefaces. A build follows the full prompt below.

Start from this screenRead the build prompt

Typefaces

The catalog's own faces. A screen composed into a template is drawn in that template's typefaces.

  • InterHeadings: Inter 600, 18px column titles
  • InterBody: Inter 400 16px/1.5 messages; 15px list rows

Patterns

  • dark UI with layered navy surfaces
  • vertical icon rail
  • notification inbox grouped by thread
  • nested activity rows under each group
  • thread view with day-separator pills
  • emoji reactions with counts and add-reaction
  • rich composer toolbar
  • top workspace tab strip

States it is designed for

  • unread groups (bold title + dot)
  • all caught up (empty inbox message)
  • loading older messages (top spinner)
  • message sending / failed (retry icon)
  • edited message label
  • attachment uploading
  • offline banner and queued messages
  • long messages collapsed with 'show more'
  • non-Latin text rendering (full Unicode support)

Who it is for

  • software teams
  • remote startups
  • open-source maintainers

Layout

  1. top strip: workspace tabs with add, right search, call, clock, settings
  2. icon rail (~48px): logo, menu, inbox (active), chat, calendar, docs, contacts, tasks, more; bottom settings, help, avatar
  3. inbox column (~380px): title, filter and overflow; groups with icon, type label, title; nested rows (avatar, name, excerpt, age); selected group highlighted
  4. thread pane: header (close, thread icon + title, 'Thread' pill, add, star count, reaction summary, panel toggle, overflow), scroll of messages with centred day pills, composer card at bottom with toolbar and send
  5. right mini rail for calendar/favourites
  6. mobile: inbox list full screen; thread opens as a pushed view

Palette

Focused, nocturnal, developer-friendly; layered indigo darks with soft pastel accents.

  • app background#141420
  • column surface#1b1a28
  • raised / selected#26253a
  • primary text#e8e8f0
  • secondary text#a2a2b8
  • link / version text#7fb0ff
  • day pill fill#2c2b3d
  • thread tag fill#4a2a3a
  • thread tag text#f3c1d0
  • reaction chip#23222f
  • border#2e2d40
  • send / accent#8aa6ff

Every checked pair, measured again

SampleWhereRatioNeeds
Aabody text14.07:14.5:1
Aamuted text6.85:14.5:1
Aatext on selected group12.24:14.5:1
Aamuted on selected group5.96:14.5:1
Aalink text8.31:14.5:1
Aaday pill text5.52:14.5:1
Aathread tag text7.93:14.5:1
send icon7.33:13:1

As vibld’s tokens

The palette on the fifteen colour tokens vibld styles a project with, each text colour on the fill it is read on. Marked tokens are solved from the palette, because no swatch held that role at 4.5:1.

  • background
  • card
  • muted
  • primary
  • secondary
  • accent
  • destructive *

Type scale

Display
Inter 600, 18px column titles
Body
Inter 400 16px/1.5 messages; 15px list rows

Names 15px 600; timestamps 13px muted tabular; group type label 14px 600; no light weights on dark.

Spacing and imagery

Dense: list rows 32px, groups 12px padding with 4px row gaps; messages 12px vertical rhythm with 40px avatars; composer 12px radius.

Round photo avatars; tiny coloured square icons for channel/blog sources; emoji reactions; no illustrations.

Components

  • WorkspaceTabs
  • IconRail
  • InboxColumn (GroupCard, ActivityRow)
  • ThreadHeader (ThreadPill, StarCount, ReactionSummary)
  • DaySeparator
  • MessageItem (avatar, name, time, body, ReactionBar)
  • ReactionChip + AddReactionButton
  • Composer (attach, video, emoji, mention, poll, send)

Interactions

  • selecting a group opens its thread and marks rows read
  • hover a message to show quick reactions, reply-in-thread and more
  • click a reaction to toggle yours; long-press on touch
  • @ in the composer opens a mention picker; : opens emoji search
  • Enter sends, Shift+Enter newline; Up edits last message
  • day pills stick to the top while scrolling

Data

  • InboxItem{id, user_id, thread_id, kind (message|mention|reaction|added), actor_id, excerpt, read_at, created_at}
  • Thread{id, channel_id, title, kind (thread|blog|channel)}
  • Message{id, thread_id, author_id, body_md, edited_at, created_at}
  • Reaction{message_id, user_id, emoji}
  • Attachment{id, message_id, file_path, name, size}

Guardrails

Experience

  • Group notifications by thread so one busy thread doesn't bury others.
  • Show a short excerpt and relative age on every row; absolute time on hover.
  • Keep reactions compact and show counts; highlight ones you added.
  • Use day separators so long threads stay navigable.
  • Make it obvious which group is open with a raised surface, not only a border.

Accessibility

  • All text pairs on dark surfaces meet 4.5:1; muted text is never below #a2a2b8 on these panels.
  • The thread is a feed (role=feed) with articles per message and accessible timestamps.
  • Reaction chips are toggle buttons with 'emoji, count, you reacted' names.
  • Icon rail items have labels (tooltip + aria-label) and aria-current.
  • Composer toolbar buttons are labelled and reachable by Tab; Escape closes pickers.

Security

  • RLS: inbox items visible only to their user; messages and reactions to channel members.
  • Render message markdown with a safe renderer (no raw HTML); sanitise links (rel=noopener, no javascript: URLs).
  • Scan attachment types and serve via signed URLs.
  • Rate-limit posting and reactions per user.

Build prompt

The baseline every prompt in the catalog assumes, then this design’s own ten sections, from goal to guardrails.

The baseline
### How to use these prompts
Paste an entry's build prompt into your coding agent as the first message. Each prompt names its own stack, tokens and acceptance criteria; the rules below apply to all of them and can be prepended once per project.

### Engineering baseline
- TypeScript strict mode, no `any`, small typed components, feature folders, and one source of truth for design tokens (CSS variables consumed by Tailwind).
- Validate every input with a shared zod schema on the client and again on the server or edge function. Never trust client-side checks alone.
- Show loading, empty and error states for every async view. Surface errors in plain language with a retry, and log details to the console in development only.
- Keep secrets out of the bundle. Only publishable keys (for example a Supabase anon key) belong in client code; service-role keys, API keys and webhooks live in server or edge-function environment variables.

### Data and auth baseline (full-stack entries)
- Enable Row Level Security on every table before inserting data. Default-deny, then add owner-scoped policies (`auth.uid() = user_id`) and explicit role checks for admin views.
- Store roles in a separate table checked by a security-definer function, never in a user-editable profile field.
- Upload files to private storage buckets with size and MIME limits, and serve them through signed URLs.
- Rate-limit public endpoints (forms, auth, AI calls) and add a honeypot field or captcha to anonymous forms.
- Take payments through a hosted checkout and verify webhooks by signature. Never handle raw card data.

### Accessibility and UX baseline
- Target WCAG 2.2 AA: 4.5:1 contrast for normal text and 3:1 for large text, input borders, focus rings and meaningful icons or chart lines. Every palette in this catalog lists its verified pairs; re-check with a contrast tool after any colour change.
- Keep body text at 16px or larger with 1.5 line height, nothing below 12px, no light weights under 24px, and uppercase only for short labels.
- Give every interactive element a visible focus ring, full keyboard support, semantic landmarks, labelled form fields, and alt text on meaningful images.
- Respect `prefers-reduced-motion` for every animation. Give drag-and-drop and carousels keyboard and button alternatives.
- Build mobile-first and test at 375px, 768px and 1280px.

### Content guardrails
- Use original copy, fictional sample data and placeholder or licensed imagery. Do not reuse another product's name, logo, screenshots or marketing text.
- Label demo testimonials and metrics as samples. Collect the minimum personal data the feature needs.

### SaaS screen baseline
- Design every screen for its full set of states: first-run empty, loading skeleton, partial data, error with retry, permission-denied, and success feedback. Each entry lists the states its screen needs.
- Keep destructive actions (delete, revoke, downgrade, remove member) behind a confirmation that names the object, and prefer undo over a second dialog where the action is reversible.
- Enforce authorisation on the server for every action a screen exposes. Hiding a button is not access control; check the role again in the API or RLS policy.
- Never show secrets (API keys, tokens) in full after creation. Show them once, then mask them, and offer rotate and revoke.
- Keep the app shell (navigation, workspace switcher, account menu) consistent across screens, and preserve filters, sort and scroll position when the user navigates back.
### Goal
Build **Pebbleroom**, the dark-mode inbox of a team workspace. The inbox groups notifications by thread; selecting a group opens the thread with day separators, reactions and a composer so a person can catch up and reply without leaving the page.

### Stack
React 18 + TypeScript + Vite, Tailwind CSS, shadcn/ui (Tooltip, Popover, Command, ScrollArea), lucide-react, TanStack Query, Tiptap for the composer, date-fns. Supabase Auth, Postgres and a realtime service for new messages and reactions.

### Pages & layout
1. **Workspace shell**: tab strip, icon rail.
2. **/inbox/:threadId?**: inbox column + thread pane.
3. Pickers: mention, emoji, attachment.
4. Mobile: stacked navigation.

### Design system
- Colors: `--bg: #141420` (app background), `--panel: #1b1a28` (column surface), `--raised: #26253a` (raised / selected), `--fg: #e8e8f0` (primary text), `--muted: #a2a2b8` (secondary text), `--link: #7fb0ff` (link / version text), `--pill: #2c2b3d` (day pill fill), `--tag-bg: #4a2a3a` (thread tag fill), `--tag-fg: #f3c1d0` (thread tag text), `--reaction: #23222f` (reaction chip), `--border: #2e2d40` (border), `--accent: #8aa6ff` (send / accent).
- Fonts: Inter 600, 18px column titles for headings; Inter 400 16px/1.5 messages; 15px list rows for body. Names 15px 600; timestamps 13px muted tabular; group type label 14px 600; no light weights on dark.
- Spacing: Dense: list rows 32px, groups 12px padding with 4px row gaps; messages 12px vertical rhythm with 40px avatars; composer 12px radius.
- Radius: 8px groups and composer, full pills for day separators, tags and reactions.
- Shadows: none; depth by surface lightness only.
- Motion: 120ms hover reveal of message actions; new messages fade in 150ms; reduced motion disables.

### Components & interactions
WorkspaceTabs, IconRail, InboxColumn, GroupCard, ActivityRow, ThreadHeader, ThreadPill, DaySeparator, MessageItem, ReactionBar, ReactionChip, AddReactionButton, Composer, MentionPicker, EmojiPicker.

Interactions: selecting a group opens its thread and marks rows read; hover a message to show quick reactions, reply-in-thread and more; click a reaction to toggle yours; long-press on touch; @ in the composer opens a mention picker; : opens emoji search; Enter sends, Shift+Enter newline; Up edits last message; day pills stick to the top while scrolling.

States to build: unread groups (bold title + dot); all caught up (empty inbox message); loading older messages (top spinner); message sending / failed (retry icon); edited message label; attachment uploading; offline banner and queued messages; long messages collapsed with 'show more'; non-Latin text rendering (full Unicode support).

### Data & state
Inbox items are grouped by `thread_id` client-side and sorted by latest. Opening a thread marks its items read. Messages paginate backward 50 at a time. Seed four threads (release notes, code discussion, a dev blog feed, random) with invented people and version-number messages.

Model: `InboxItem{id, user_id, thread_id, kind (message|mention|reaction|added), actor_id, excerpt, read_at, created_at}`; `Thread{id, channel_id, title, kind (thread|blog|channel)}`; `Message{id, thread_id, author_id, body_md, edited_at, created_at}`; `Reaction{message_id, user_id, emoji}`; `Attachment{id, message_id, file_path, name, size}`.

### Accessibility
All text pairs on dark surfaces meet 4.5:1; muted text is never below #a2a2b8 on these panels. The thread is a feed (role=feed) with articles per message and accessible timestamps. Reaction chips are toggle buttons with 'emoji, count, you reacted' names. Icon rail items have labels (tooltip + aria-label) and aria-current. Composer toolbar buttons are labelled and reachable by Tab; Escape closes pickers.
Verified contrast: body text: #e8e8f0 on #1b1a28 = 14.07:1; muted text: #a2a2b8 on #1b1a28 = 6.85:1; text on selected group: #e8e8f0 on #26253a = 12.24:1; muted on selected group: #a2a2b8 on #26253a = 5.96:1; link text: #7fb0ff on #141420 = 8.31:1; day pill text: #a2a2b8 on #2c2b3d = 5.52:1; thread tag text: #f3c1d0 on #4a2a3a = 7.93:1; send icon: #8aa6ff on #1b1a28 = 7.33:1.

### Security
RLS: inbox items visible only to their user; messages and reactions to channel members. Render message markdown with a safe renderer (no raw HTML); sanitise links (rel=noopener, no javascript: URLs). Scan attachment types and serve via signed URLs. Rate-limit posting and reactions per user. RLS per table: `inbox_items` select/update where `user_id = auth.uid()`; `threads`, `messages`, `reactions`, `attachments` select for members of the channel; insert messages/reactions as self; update/delete own messages only.

### Performance & SEO
Virtualise messages and inbox rows; lazy-load emoji data; keep the composer editor mounted once. App routes noindex.

### Guardrails
- Group notifications by thread so one busy thread doesn't bury others.
- Show a short excerpt and relative age on every row; absolute time on hover.
- Keep reactions compact and show counts; highlight ones you added.
- Use day separators so long threads stay navigable.
- Make it obvious which group is open with a raised surface, not only a border.
- Write all copy fresh; use invented people, companies and numbers only. No real brands, logos, wordmarks or third-party product names anywhere in the UI or seed data.
- Do not trace or copy any existing product's layout assets, icons or illustrations; draw generic ones.
- Acceptance criteria:
  - [ ] Inbox groups rows by thread with unread state
  - [ ] Selecting a group opens the thread and marks it read
  - [ ] Reactions toggle with counts
  - [ ] Composer sends with Enter and supports mentions
  - [ ] All dark-surface text pairs pass the verified ratios

Open the builderAll templatesThis palette on its own