Template
Tenrick
A success state after creating an API key in a developer platform: a side sheet slides in over the keys table and shows the full secret exactly once, with a copy button and a clear warning. It closes the loop between 'create' and 'stored safely'.
API key reveal sheet (shown once) · App screen: success · 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 sheet title
- InterBody: Inter 400, 16px/1.5; subtitle 14px muted
Patterns
- right-side sheet over dimmed app
- one-time secret reveal
- copy-to-clipboard field
- warning callout
- sheet footer with single primary action
- persistent left sidebar with grouped nav
States it is designed for
- Creating (skeleton in sheet)
- Revealed (default)
- Copied
- Clipboard blocked: show 'Select and copy manually' hint
- Closing without copying: confirm dialog
- Creation failed with retry
- Row highlight after close
- Revoked key row state in table
Who it is for
- Developers integrating via CLI or SDK
- Platform engineers rotating credentials
- Workspace admins issuing keys for services
Layout
- App shell dimmed behind a 40% scrim: grouped left sidebar and API keys table
- Right-side sheet (~480px, full height, rounded left corners) with title, muted subtitle and close X
- Warning callout with left rule and alert icon
- Labelled monospace read-only field containing the key, square copy button to its right
- Empty space, then a footer strip with a dark Done button right-aligned
- Mobile: sheet becomes a full-screen dialog; copy button stays inline
Palette
sober, careful, developer-grade. The screen slows the user down just enough to save the secret.
- sheet surface
#ffffff - footer strip
#f7f7f7 - scrim over app
#a8a8a8 - primary text
#18181b - muted text
#5e5e66 - field border
#8a8a93 - dark button
#18181b - warning rule/icon
#b45309 - success toast accent
#15803d - focus ring
#2563eb
Every checked pair, measured again
| Sample | Where | Ratio | Needs |
|---|---|---|---|
| Aa | body text on sheet | 17.72:1 | 4.5:1 |
| Aa | muted subtitle | 6.42:1 | 4.5:1 |
| Aa | Done label on dark button | 17.72:1 | 4.5:1 |
| Aa | muted on footer strip | 6.00:1 | 4.5:1 |
| field border | 3.42:1 | 3:1 | |
| focus ring | 5.17:1 | 3:1 | |
| warning rule/icon | 5.02:1 | 3:1 | |
| success check icon | 5.02: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 600, 20px sheet title
- Body
- Inter 400, 16px/1.5; subtitle 14px muted
Secrets in JetBrains Mono 14px with tabular, unambiguous glyphs; similar to the observed grotesk + mono pairing.
Spacing and imagery
Sheet padding 24px; 16px between blocks; field 40px tall radius 8px; sheet radius 12px on the leading edge; footer 64px; scrim with slight blur.
Only line icons (alert triangle, copy, close); no illustration.
Components
- Sheet/drawer with header and footer
- Warning callout
- Read-only mono secret field
- Copy button with copied feedback
- Done button
- Keys table behind (name, masked key, scopes, created, last used, expires, status, delete)
- Sidebar with grouped sections
Interactions
- Sheet slides in from the right (220ms) and traps focus; Esc and X ask for confirmation if the key hasn't been copied
- Copy button swaps icon to a check and announces 'Copied' for 2s
- Clicking the secret selects it fully
- Done closes the sheet and highlights the new row in the table for 3s
- After close the key is only ever shown masked
Data
ApiKey{id, org_id, name, prefix, hash, scopes[], created_by, created_at, last_used_at, expires_at, status (active|revoked|expired)}AuditEvent{id, org_id, actor_id, action (key.created|key.revoked), target_id, at}
Guardrails
Experience
- State plainly that the key is shown only once
- Make copy one click and confirm it visibly
- Warn before closing if the user never copied
- Mask keys everywhere else (prefix + ellipsis)
- Highlight the new row after closing so users see where it went
- Keep the footer action single and unambiguous
Accessibility
- Sheet is a Radix Dialog with aria-labelledby/-describedby; focus starts on the copy button
- Copied state announced via live region, not colour alone
- Secret field has a visible label and is readable by screen readers on demand only
- Warning callout uses an icon plus text, with role=note
- Scrim does not carry text; all text sits on white
Security
- Generate keys server-side (Edge Function) with a CSPRNG; store only a salted hash and the display prefix
- Return the plaintext once in the create response; never log it
- RLS: api_keys select limited to org members, insert/revoke only for admin role; hash column excluded from client selects via a view
- Audit every create and revoke
- Rate-limit key creation per org
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 **Tenrick**'s API key reveal: the moment after a developer creates an organisation API key. A sheet slides over the keys table, shows the full secret exactly once, makes copying trivial and makes the 'you won't see this again' rule impossible to miss. ### Stack React 18 + TypeScript + Vite, Tailwind CSS, shadcn/ui (Radix primitives) and lucide-react icons. TanStack Query for server state, react-hook-form + zod for forms, date-fns for dates. Supabase for Auth, Postgres and Row Level Security. A Supabase Edge Function creates keys and returns the plaintext once. TanStack Table for the keys list. ### Pages & layout 1. **App shell**: 240px left sidebar with workspace switcher at top and grouped nav (Build, Agents, Workflow, Developer) with the active item as a dark pill; bottom: docs link and theme switcher. Top bar with org breadcrumb. 2. **/settings/api-keys**: H1, muted description, 'Create API key' dark button top-right; table with Name, Key (masked `tk_live_ab12...` in a mono chip), Scopes chip, Created, Last used, Expires chip, Status chip, delete icon button. 3. **Reveal sheet** (right, 480px): title 'API key created', subtitle 'Copy it now. It will not be shown again.'; warning callout with a 2px `--warn` left rule; label 'Your API key'; mono read-only input + square copy button; footer strip (`--footer`) with Done. 4. Mobile: sheet becomes full-screen; table becomes stacked cards. ### Design system - Colors: `--bg: #ffffff` (sheet surface), `--footer: #f7f7f7` (footer strip), `--scrim: #a8a8a8` (scrim over app), `--fg: #18181b` (primary text), `--muted: #5e5e66` (muted text), `--input-border: #8a8a93` (field border), `--primary: #18181b` (dark button), `--warn: #b45309` (warning rule/icon), `--success: #15803d` (success toast accent), `--ring: #2563eb` (focus ring). - Fonts: Inter 400/500/600; title 20px 600; body 16px/1.5; table 15px; JetBrains Mono 14px for keys. - Spacing: 4px base; sheet padding 24px; table rows 48px. - Radius: sheet 12px (leading corners), inputs/buttons 8px, chips 6px. - Shadows: sheet `-8px 0 32px rgb(0 0 0 / 0.12)`; scrim `rgb(0 0 0 / 0.35)` with 2px blur. - Motion: 220ms ease-out slide; copy icon crossfade 120ms; reduced motion uses fade only. ### Components & interactions `AppSidebar`, `KeysTable` (sortable Created/Last used, row delete with confirm), `CreateKeyDialog` (name, scopes multiselect, expiry select), `RevealSheet` (Radix Dialog), `SecretField` (select-all on click), `CopyButton` (navigator.clipboard with fallback hint), `CloseGuard` (confirm 'Close without copying?'), `RowHighlight` (3s tinted background after close), `Toast`. ### Data & state `api_keys(id, org_id, name, prefix, key_hash, scopes text[], created_by, created_at, last_used_at, expires_at, status enum active|revoked|expired)`, `audit_events(id, org_id, actor_id, action, target_id, at)`. The plaintext secret lives only in component memory for the sheet's lifetime; clear it on unmount. Mock: two existing keys, one never used, one revoked. ### Accessibility Focus trapped in the sheet, starts on Copy, returns to the Create button on close. 'Copied to clipboard' announced politely. Warning uses icon + text. Keyboard: Esc triggers the close guard; Enter on Done closes. Status chips carry text, never colour alone. Verified contrast: body text on sheet: #18181b on #ffffff = 17.72:1; muted subtitle: #5e5e66 on #ffffff = 6.42:1; Done label on dark button: #ffffff on #18181b = 17.72:1; muted on footer strip: #5e5e66 on #f7f7f7 = 6.00:1; field border: #8a8a93 on #ffffff = 3.42:1; focus ring: #2563eb on #ffffff = 5.17:1; warning rule/icon: #b45309 on #ffffff = 5.02:1; success check icon: #15803d on #ffffff = 5.02:1. ### Security Keys generated with a CSPRNG in the Edge Function, stored as salted SHA-256 hash plus 8-char prefix; plaintext returned once over HTTPS and never logged. RLS: `api_keys` select for org members via a view without `key_hash`; insert/update(revoke) only for `role in (owner, admin)`; no delete (revoke instead). `audit_events` insert via function only, select for admins. Rate-limit creation to 20/hour per org. Service-role key stays server-side. ### Performance & SEO Lazy-load the sheet and create dialog. Keys table paginated server-side at 50 rows. App routes `noindex`. ### Guardrails - Use an invented key prefix and sample key names. - Never render a plaintext key after the sheet closes. - No real vendor names in scopes or docs links. Acceptance criteria: - [ ] Plaintext visible once, masked afterwards - [ ] Copy works and is announced - [ ] Closing without copying asks to confirm - [ ] Non-admins cannot create or revoke (RLS) - [ ] Create and revoke write audit events