Skip to main content
vibld

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

  1. App shell dimmed behind a 40% scrim: grouped left sidebar and API keys table
  2. Right-side sheet (~480px, full height, rounded left corners) with title, muted subtitle and close X
  3. Warning callout with left rule and alert icon
  4. Labelled monospace read-only field containing the key, square copy button to its right
  5. Empty space, then a footer strip with a dark Done button right-aligned
  6. 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

SampleWhereRatioNeeds
Aabody text on sheet17.72:14.5:1
Aamuted subtitle6.42:14.5:1
AaDone label on dark button17.72:14.5:1
Aamuted on footer strip6.00:14.5:1
field border3.42:13:1
focus ring5.17:13:1
warning rule/icon5.02:13:1
success check icon5.02: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, 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

Open the builderAll templatesThis palette on its own