Template
Rostane
An admin invites several people at once to an AI workspace by pasting emails and choosing a role. The drawer keeps the people-and-security settings visible behind it so admins stay oriented.
Invite-users drawer over team security settings · 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 600, 20px drawer title, 28px page title
- InterBody: Inter 400, 16px, line-height 1.5
Patterns
- right drawer form over settings page
- large multi-email textarea
- role pill select with helper line
- sticky drawer footer with Cancel and Send
- trial banner at top
- admin sidebar with grouped sections
- members/invitations tabs
States it is designed for
- empty: Send disabled
- validation: invalid emails listed with reasons
- sending
- partial success: some addresses already members, listed
- seat limit: warning with Subscription link
- permission-denied for non-admins: drawer never opens, button hidden
- server error with Retry
Who it is for
- workspace admins
- IT managers onboarding a department
Layout
- sidebar: tabs Chat / Spaces / Admin; groups Workspace (People & security, Settings, Analytics, Subscription), API (Keys, Programmatic usage), Builder tools (Providers, Secrets); footer trial meter
- main (dimmed): trial banner, People & security title, Domain verification card, Auto-join card, Members with search and Members/Invitations tabs and table
- right drawer (~40% width): title and close button, label, tall textarea, Role row with pill select and chevron, helper sentence, sticky footer with Cancel and Send invite
- below 768px the drawer is full-screen
Palette
Practical and plain; one big field, one choice, one button.
- bg
#ffffff - canvas
#f5f6f8 - text
#161a22 - muted
#5d6472 - border
#8d94a1 - role
#e3f7c9 - role-text
#2f5a0c - primary
#1e5bd8 - disabled
#c7ccd4 - banner
#fff4d6
Every checked pair, measured again
| Sample | Where | Ratio | Needs |
|---|---|---|---|
| Aa | body text | 17.43:1 | 4.5:1 |
| Aa | helper text | 5.95:1 | 4.5:1 |
| Aa | role pill text | 7.11:1 | 4.5:1 |
| Aa | Send button label | 5.93:1 | 4.5:1 |
| textarea border | 3.05:1 | 3:1 | |
| focus ring | 5.93:1 | 3:1 | |
| Aa | trial banner text | 15.90:1 | 4.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 600, 20px drawer title, 28px page title
- Body
- Inter 400, 16px, line-height 1.5
Field labels 16px 600; helper text 15px; table headers 13px 600.
Spacing and imagery
Density: Medium. Grid: 8px; drawer padding 16-24px. Container: drawer 40vw clamped 400-520px. Radius: 6px textarea and buttons, full pill for role. Shadows: Drawer left shadow; footer has a top border instead of a shadow.
Line icons only (people, globe, lock, key).
Components
- TrialBanner
- AdminSidebar
- MembersTable with tabs
- InviteDrawer
- EmailTextarea
- RoleSelect pill
- RoleHelperText
- DrawerFooter
Interactions
- Emails parsed live; count shown under the field ('3 valid, 1 invalid')
- Role select changes the helper sentence describing permissions
- Send disabled until ≥1 valid email; shows spinner while sending
- On success the drawer closes and the Invitations tab gains a count badge
- Esc or Cancel closes; unsaved text triggers a discard confirm
Data
Membership{workspace_id, user_id, role (admin|builder|member)}Invitation{id, workspace_id, email, role, status (pending|accepted|revoked|expired), sent_at}Workspace{id, name, seats, trial_ends_at}
Guardrails
Experience
- Accept comma and newline separators and trim whitespace
- Explain the selected role in one plain sentence
- Show a per-address result after sending
- Keep Cancel as a secondary text button left of Send
- Keep the trial banner dismissible per session
Accessibility
- Drawer is a dialog with labelled title and focus trap
- Textarea has a visible label and describes its separator rules
- Role select is keyboard operable and its helper text is aria-describedby
- Result list announced via aria-live=polite
- Disabled Send has aria-disabled and an explanation
Security
- Only admins can invite (RLS on invitations: insert where caller is admin)
- Server re-validates emails and dedupes against memberships
- Rate-limit to 100 invites/hour per workspace
- Log invitations to an audit table
- Invite tokens are single-use and expire
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 **Rostane**, the invite-users drawer on a workspace's people-and-security settings page. Admins paste many emails, pick a role and send; results show per address. Build the admin sidebar shell, the settings page behind a scrim and the drawer.
### 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 go out through a transactional email service from an Edge Function.
### Pages & layout
1. **Sidebar** with three top tabs and grouped admin links; trial usage meter in the footer.
2. **People & security page**: dismissible trial banner, title and description, domain verification card, auto-join card, members section with search and Members / Invitations tabs.
3. **Invite drawer**: title 'Invite people' with close X; label 'Email addresses (comma or new line)'; tall textarea; 'Role:' with a green pill select; helper sentence; sticky footer with Cancel and Send invite.
Responsive: full-screen drawer under 768px.
### Design system
- Colors: `--bg: #ffffff` (drawer), `--canvas: #f5f6f8` (page and sidebar), `--text: #161a22` (primary text), `--muted: #5d6472` (helper text), `--border: #8d94a1` (textarea border), `--role: #e3f7c9` (role pill fill), `--role-text: #2f5a0c` (role pill text), `--primary: #1e5bd8` (Send button), `--disabled: #c7ccd4` (disabled button fill), `--banner: #fff4d6` (trial banner).
- Fonts: Inter 600, 20px drawer title, 28px page title for headings; Inter 400, 16px, line-height 1.5 for body. Field labels 16px 600; helper text 15px; table headers 13px 600.
- Spacing: Medium. 8px; drawer padding 16-24px. Container: drawer 40vw clamped 400-520px.
- Radius: 6px textarea and buttons, full pill for role.
- Shadows: Drawer left shadow; footer has a top border instead of a shadow.
- Motion: Drawer slides 200ms; role pill opens a Radix Select; success collapses the drawer and flashes the Invitations tab count.
### Components & interactions
RoleSelect is a soft green pill with a chevron trigger. The drawer footer is sticky with a top border so buttons are always visible above long textarea content.
- Emails parsed live; count shown under the field ('3 valid, 1 invalid')
- Role select changes the helper sentence describing permissions
- Send disabled until ≥1 valid email; shows spinner while sending
- On success the drawer closes and the Invitations tab gains a count badge
- Esc or Cancel closes; unsaved text triggers a discard confirm
### Data & state
Seed one admin and two pending invitations. Parsing is a pure function unit-tested for separators and duplicates. Invitations list refetches after send.
Entities: `Membership{workspace_id, user_id, role (admin|builder|member)}`; `Invitation{id, workspace_id, email, role, status (pending|accepted|revoked|expired), sent_at}`; `Workspace{id, name, seats, trial_ends_at}`.
States to build and show in a dev-only state switcher:
- empty: Send disabled
- validation: invalid emails listed with reasons
- sending
- partial success: some addresses already members, listed
- seat limit: warning with Subscription link
- permission-denied for non-admins: drawer never opens, button hidden
- server error with Retry
### Accessibility
- Drawer is a dialog with labelled title and focus trap
- Textarea has a visible label and describes its separator rules
- Role select is keyboard operable and its helper text is aria-describedby
- Result list announced via aria-live=polite
- Disabled Send has aria-disabled and an explanation
Verified contrast: body text: #161a22 on #ffffff = 17.43:1; helper text: #5d6472 on #ffffff = 5.95:1; role pill text: #2f5a0c on #e3f7c9 = 7.11:1; Send button label: #ffffff on #1e5bd8 = 5.93:1; textarea border: #8d94a1 on #ffffff = 3.05:1; focus ring: #1e5bd8 on #ffffff = 5.93:1; trial banner text: #161a22 on #fff4d6 = 15.9:1.
### Security
- Only admins can invite (RLS on invitations: insert where caller is admin)
- Server re-validates emails and dedupes against memberships
- Rate-limit to 100 invites/hour per workspace
- Log invitations to an audit table
- Invite tokens are single-use and expire
RLS detail: `memberships` select for members of the same workspace, write for admins; `invitations` select/insert/update for admins; `audit_log` insert-only.
### Performance & SEO
Split the drawer into its own chunk; debounce parsing at 150ms for large pastes (500+ addresses).
### Guardrails
- Accept comma and newline separators and trim whitespace
- Explain the selected role in one plain sentence
- Show a per-address result after sending
- Keep Cancel as a secondary text button left of Send
- Keep the trial banner dismissible per session
- 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:
- Pasting mixed separators yields correct valid/invalid counts
- Send creates invitations with the chosen role
- Duplicates and existing members are reported
- Non-admins cannot invite (RLS verified)
- Drawer is fully keyboard-operable