Skip to main content
vibld

Template

Ribbonet

A deliberately sparse settings page for a privacy-friendly web analytics tool, where the project owner adds collaborators by typing one email into a field with an inline Invite button. Everything fits in one card so managing a small team takes seconds.

Minimal project team settings with inline invite · App screen: invite team · 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 500, 26px page title
  • InterBody: Inter 400, 16px, line-height 1.5

Patterns

  • centred page title with subtitle
  • icon text nav beside a single card
  • inline input with embedded invite button
  • owner row with avatar and email
  • floating bottom pill toolbar
  • project switcher next to logo

States it is designed for

  • only owner: owner row plus hint 'Invite someone to share this dashboard'
  • invalid email inline error
  • sending: button spinner
  • already a member notice
  • invite limit on free plan with upgrade link
  • error with Retry
  • non-owner view: field hidden, read-only list

Who it is for

  • indie makers and small teams tracking site traffic
  • freelancers sharing analytics with clients

Layout

  1. top bar: round logo mark, project switcher with chevron, account glyph on the right
  2. centred heading 'Settings' with subtitle
  3. two columns: narrow icon nav (General, Usage, Team, Security) and a ~340px card
  4. card: title, description, email field with inline Invite button, 'Owner' label and owner row, then Members and Pending lists
  5. floating dark pill toolbar bottom-centre showing a live counter and a settings button
  6. below 720px the nav becomes a horizontal segmented row above the card

Palette

Minimal, friendly, almost empty; the product respects your time.

  • bg#ffffff
  • field#f3f3f4
  • text#1b1b1f
  • muted#66666e
  • border#8a8a93
  • toolbar#15151c
  • live#a78bfa
  • accent#5b3fd1

Every checked pair, measured again

SampleWhereRatioNeeds
Aabody text17.17:14.5:1
Aamuted text5.69:14.5:1
Aaplaceholder on field5.13:14.5:1
Aatoolbar text18.17:14.5:1
live glyph on toolbar6.68:13:1
input border3.42:13:1
Aafocus ring / link6.83:14.5: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 500, 26px page title
Body
Inter 400, 16px, line-height 1.5

Nav items 15px with 16px icons; card title 17px 500; no uppercase anywhere.

Spacing and imagery

Density: Very airy. Grid: 8px; card padding 12-16px. Container: page max 560px centred; nav 170px + card 340px. Radius: 10px card, 8px input, 6px inline button, full pill toolbar. Shadows: Card 0 1px 3px rgba(0,0,0,0.06); toolbar 0 8px 24px rgba(0,0,0,0.25).

Small outline icons; avatars are monogram circles or uploaded images.

Components

  • TopBar with ProjectSwitcher
  • SettingsNav
  • TeamCard
  • InlineInviteField
  • MemberRow (avatar, name, email, role menu)
  • PendingInviteRow (Resend, Revoke)
  • FloatingToolbar
  • Toast

Interactions

  • Enter in the field submits; Invite button enabled only for a valid email
  • Member row hover reveals a role menu (Viewer, Admin, Remove)
  • Pending rows show 'Invited 2d ago' with Resend and Revoke
  • Toolbar counter updates via polling every 15s

Data

  • Project{id, name, owner_id, plan (free|paid)}
  • ProjectMember{project_id, user_id, role (owner|admin|viewer)}
  • ProjectInvite{id, project_id, email, role, status (pending|accepted|revoked), created_at}

Guardrails

Experience

  • Keep the whole team flow inside one card
  • Default new invites to Viewer
  • Show the owner first and label it clearly
  • Never hide the Invite button inside a menu
  • Keep the toolbar from covering content: add bottom padding equal to its height

Accessibility

  • Email input has a visible or programmatic label, not just placeholder
  • Invite button text stays 'Invite' (not icon-only)
  • Role menu uses Radix DropdownMenu with keyboard support
  • Toast is announced politely
  • Toolbar buttons have accessible names

Security

  • Only owner/admin can invite (RLS)
  • Validate and normalise emails server-side
  • Rate-limit invites per project
  • Revoked invite tokens are invalid immediately

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 **Ribbonet**, the team section of a lightweight analytics tool's project settings. The owner types an email into one field and presses Invite; members and pending invites appear below. Build the top bar, the centred settings layout with its four-item nav, the team card and the floating toolbar.

### Stack
React 18 + TypeScript + Vite, Tailwind CSS, shadcn/ui on Radix primitives and lucide-react icons. TanStack Query for server state, react-hook-form + zod for every form, date-fns for relative times. Supabase for Auth, Postgres with row-level security and Edge Functions for anything that needs a secret.

### Pages & layout
1. **Top bar**: round logo mark, project switcher, account glyph.
2. **Settings**: centred title and subtitle; left nav with General, Usage, Team (active), Security.
3. **Team card**: title, description, grey email field with inline Invite button, Owner label and owner row (logo avatar, name, email right-aligned), Members and Pending lists.
4. **Floating toolbar** bottom-centre with live counter and settings button.

### Design system
- Colors: `--bg: #ffffff` (page and card), `--field: #f3f3f4` (input fill), `--text: #1b1b1f` (primary text), `--muted: #66666e` (subtitle and descriptions), `--border: #8a8a93` (card outline and input focus-free border), `--toolbar: #15151c` (floating pill), `--live: #a78bfa` (live counter glyph on dark), `--accent: #5b3fd1` (focus ring and links).
- Fonts: Inter 500, 26px page title for headings; Inter 400, 16px, line-height 1.5 for body. Nav items 15px with 16px icons; card title 17px 500; no uppercase anywhere.
- Spacing: Very airy. 8px; card padding 12-16px. Container: page max 560px centred; nav 170px + card 340px.
- Radius: 10px card, 8px input, 6px inline button, full pill toolbar.
- Shadows: Card 0 1px 3px rgba(0,0,0,0.06); toolbar 0 8px 24px rgba(0,0,0,0.25).
- Motion: Invite button shows a check morph on success (200ms); new member row fades in; toolbar counter ticks without layout shift.

### Components & interactions
InlineInviteField is a filled rounded input with a small bordered button docked inside its right edge. MemberRow aligns name left and email right on desktop, stacking under 480px.

- Enter in the field submits; Invite button enabled only for a valid email
- Member row hover reveals a role menu (Viewer, Admin, Remove)
- Pending rows show 'Invited 2d ago' with Resend and Revoke
- Toolbar counter updates via polling every 15s

### Data & state
Seed an owner with an example.com address, one viewer and one pending invite. TanStack Query caches members; the toolbar counter uses its own polling query.

Entities: `Project{id, name, owner_id, plan (free|paid)}`; `ProjectMember{project_id, user_id, role (owner|admin|viewer)}`; `ProjectInvite{id, project_id, email, role, status (pending|accepted|revoked), created_at}`.

States to build and show in a dev-only state switcher:
- only owner: owner row plus hint 'Invite someone to share this dashboard'
- invalid email inline error
- sending: button spinner
- already a member notice
- invite limit on free plan with upgrade link
- error with Retry
- non-owner view: field hidden, read-only list

### Accessibility
- Email input has a visible or programmatic label, not just placeholder
- Invite button text stays 'Invite' (not icon-only)
- Role menu uses Radix DropdownMenu with keyboard support
- Toast is announced politely
- Toolbar buttons have accessible names
Verified contrast: body text: #1b1b1f on #ffffff = 17.17:1; muted text: #66666e on #ffffff = 5.69:1; placeholder on field: #66666e on #f3f3f4 = 5.13:1; toolbar text: #ffffff on #15151c = 18.17:1; live glyph on toolbar: #a78bfa on #15151c = 6.68:1; input border: #8a8a93 on #ffffff = 3.42:1; focus ring / link: #5b3fd1 on #ffffff = 6.83:1.

### Security
- Only owner/admin can invite (RLS)
- Validate and normalise emails server-side
- Rate-limit invites per project
- Revoked invite tokens are invalid immediately
RLS detail: `project_members` select for members, insert/update/delete for owner/admin; `project_invites` owner/admin only; viewers can read the member list but not emails of pending invites.

### Performance & SEO
Tiny page: aim for <80KB JS. Private route, noindex.

### Guardrails
- Keep the whole team flow inside one card
- Default new invites to Viewer
- Show the owner first and label it clearly
- Never hide the Invite button inside a menu
- Keep the toolbar from covering content: add bottom padding equal to its height
- Write fresh, generic copy and invented sample data; no real brands, logos, product names or people.
- Keep components small and typed (no `any`); surface every error visibly with a way to recover.

Acceptance criteria:
- Inviting adds a pending row
- Role changes persist
- Non-owners cannot invite
- Toolbar never overlaps the last row
- Keyboard works end to end

Open the builderAll templatesThis palette on its own