Template
Rendalo
A developer platform's members settings page where owners invite collaborators to an application and choose between Owner and Member access using descriptive radio cards. An empty Invitations section shows what happens next.
Invite-members modal with role cards · 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, 22px modal title, 26px page titles
- InterBody: Inter 400, 16px, line-height 1.5
Patterns
- centred modal over members page
- radio cards for role with check badge
- multi-email textarea
- top tabs (Overview, Billing, Configure)
- balance and top-up in header
- command-K search
- empty invitations state with icon
States it is designed for
- empty invitations: icon, 'No invitations yet', one line
- loading members: skeleton rows
- invalid email error
- owner-only: members see Invite disabled with tooltip
- sending
- success toast
- error with Retry
- expired invitation badge with Resend
Who it is for
- developers administering an API application
- startup engineering leads
Layout
- top bar: workspace and service switchers left, balance readout and Top up button right, avatar
- tabs row: Overview, Billing, Configure (active); search with ⌘K hint on the right
- left settings nav: App (General, Members), Security (Keys), Billing (Spending limit, Notifications)
- main: Members title and description with Invite button; members table card with pagination; Invitations section with empty state
- modal ~310px wide: title, description, email textarea, Role label, two radio cards side by side, Cancel and dark primary button
- below 640px role cards stack vertically
Palette
Crisp, neutral developer console; structure through borders not colour.
- bg
#ffffff - canvas
#f7f7f8 - text
#18181b - muted
#62626b - border
#8b8b94 - selected
#3558d4 - button
#18181b - scrim
#71717a
Every checked pair, measured again
| Sample | Where | Ratio | Needs |
|---|---|---|---|
| Aa | body text | 17.72:1 | 4.5:1 |
| Aa | muted description | 6.04:1 | 4.5:1 |
| Aa | muted on page | 5.64:1 | 4.5:1 |
| Aa | dark button label | 17.72:1 | 4.5:1 |
| selected role border | 6.00:1 | 3:1 | |
| input border | 3.38:1 | 3:1 | |
| focus ring | 6.00:1 | 3: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, 22px modal title, 26px page titles
- Body
- Inter 400, 16px, line-height 1.5
Role card title 15px 600, description 15px muted. Balance uses tabular numerals.
Spacing and imagery
Density: Compact developer console. Grid: 4px base; card padding 12px; modal padding 16px. Container: main max 560px. Radius: 8px cards and modal, 6px buttons. Shadows: Modal 0 16px 40px rgba(0,0,0,0.18); cards flat with border.
Line icons; a small envelope icon for the empty invitations state.
Components
- TopBar with switchers and BalanceTopUp
- TabsNav
- SettingsNav
- MembersTable with pagination
- InviteModal
- RoleRadioCards
- EmptyState
- CommandSearch
Interactions
- Role cards behave as a radio group; arrow keys move selection, check badge appears on the selected card
- Send invitations disabled until valid emails; spinner while sending
- Invitations section updates with rows (email, role, sent, Revoke)
- ⌘K opens command search over settings pages
- Revoke asks for confirmation
Data
App{id, name, owner_id}AppMember{app_id, user_id, role (owner|member), joined_at}AppInvitation{id, app_id, email, role, status (pending|accepted|revoked|expired), created_at}
Guardrails
Experience
- Describe each role's access in one sentence inside its card
- Default the selection to Member, the least-privileged role
- Keep Cancel as text and the primary as the only filled button
- Show invitations immediately after sending with Revoke/Resend
- Warn before promoting someone to Owner
Accessibility
- Role cards use role=radiogroup with labelled radios; selection not by colour alone (check icon + border)
- Modal title is the dialog label; focus returns to Invite button on close
- Table uses th scope and caption
- Command search is a combobox with listbox semantics
- Focus rings 2px blue offset 2px
Security
- Only owners may invite or change roles (RLS)
- Default to least privilege (Member)
- Server-side email validation and dedupe
- Rate-limit invitations
- Audit log role changes and revocations
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 **Rendalo**, the members settings page of a developer API console with an invite modal that uses role cards. Owners add teammates by email as Owner or Member. Build the console shell, the page with its empty invitations state and the modal.
### 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. Invite emails via a transactional email service.
### Pages & layout
1. **Top bar**: workspace switcher and 'All services' switcher, balance (e.g. €0.00) with a dark Top up button, avatar.
2. **Tabs**: Overview, Billing, Configure; search with ⌘K.
3. **Settings nav** with App, Security and Billing groups.
4. **Members page**: title, description, Invite members button; table card (Member, Added) with count and Previous/Next; Invitations section with empty state.
5. **Invite modal**: title, description, 'Email addresses' textarea, 'Role' with Owner and Member radio cards, Cancel and 'Send invitations'.
### Design system
- Colors: `--bg: #ffffff` (cards and modal), `--canvas: #f7f7f8` (page), `--text: #18181b` (primary text), `--muted: #62626b` (descriptions), `--border: #8b8b94` (input and card borders), `--selected: #3558d4` (selected role border and check), `--button: #18181b` (primary dark button), `--scrim: #71717a` (overlay at 50%).
- Fonts: Inter 500, 22px modal title, 26px page titles for headings; Inter 400, 16px, line-height 1.5 for body. Role card title 15px 600, description 15px muted. Balance uses tabular numerals.
- Spacing: Compact developer console. 4px base; card padding 12px; modal padding 16px. Container: main max 560px.
- Radius: 8px cards and modal, 6px buttons.
- Shadows: Modal 0 16px 40px rgba(0,0,0,0.18); cards flat with border.
- Motion: Modal scales from 0.98 and fades over 150ms; selected card border animates colour.
### Components & interactions
RoleRadioCards: two equal cards with bold role name and a three-line description; the selected one gets a 1.5px blue border and a filled check badge in its top-right corner.
- Role cards behave as a radio group; arrow keys move selection, check badge appears on the selected card
- Send invitations disabled until valid emails; spinner while sending
- Invitations section updates with rows (email, role, sent, Revoke)
- ⌘K opens command search over settings pages
- Revoke asks for confirmation
### Data & state
Seed one owner (invented) and no invitations to show the empty state; toggle a seeded variant with two invitations. TanStack Query for members and invitations; modal form in react-hook-form.
Entities: `App{id, name, owner_id}`; `AppMember{app_id, user_id, role (owner|member), joined_at}`; `AppInvitation{id, app_id, email, role, status (pending|accepted|revoked|expired), created_at}`.
States to build and show in a dev-only state switcher:
- empty invitations: icon, 'No invitations yet', one line
- loading members: skeleton rows
- invalid email error
- owner-only: members see Invite disabled with tooltip
- sending
- success toast
- error with Retry
- expired invitation badge with Resend
### Accessibility
- Role cards use role=radiogroup with labelled radios; selection not by colour alone (check icon + border)
- Modal title is the dialog label; focus returns to Invite button on close
- Table uses th scope and caption
- Command search is a combobox with listbox semantics
- Focus rings 2px blue offset 2px
Verified contrast: body text: #18181b on #ffffff = 17.72:1; muted description: #62626b on #ffffff = 6.04:1; muted on page: #62626b on #f7f7f8 = 5.64:1; dark button label: #ffffff on #18181b = 17.72:1; selected role border: #3558d4 on #ffffff = 6.0:1; input border: #8b8b94 on #ffffff = 3.38:1; focus ring: #3558d4 on #ffffff = 6.0:1.
### Security
- Only owners may invite or change roles (RLS)
- Default to least privilege (Member)
- Server-side email validation and dedupe
- Rate-limit invitations
- Audit log role changes and revocations
RLS detail: `app_members` select for members of the app, insert/update/delete for owners; `app_invitations` all actions for owners, select own by email for invitees through an Edge Function.
### Performance & SEO
Keep the modal in the main chunk (it's small); paginate members server-side at 20 per page.
### Guardrails
- Describe each role's access in one sentence inside its card
- Default the selection to Member, the least-privileged role
- Keep Cancel as text and the primary as the only filled button
- Show invitations immediately after sending with Revoke/Resend
- Warn before promoting someone to Owner
- 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:
- Member is preselected
- Invites appear in the Invitations list with Revoke
- Owners-only enforced by RLS
- Role cards work with arrow keys
- Empty state shows when there are no invitations