Template
Olvanta
Inside a sales CRM's settings, admins build a lead-capture form: pick layout and CRM-mapped fields from a palette, arrange them on a canvas that previews the live form, then publish and share. Submissions create leads and contacts automatically.
Lead-capture form builder with field palette · App screen: add edit · 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.
- Source Sans 3Headings: Source Sans 3 600 24px title, 18px section heads
- Source Sans 3Body: Source Sans 3 400 16px / 1.5
Patterns
- three-pane builder (settings nav, canvas, field palette)
- dark primary app sidebar
- draft status badge beside title
- builder/settings/share tabs
- template field tiles grid
- live preview including thank-you state
- sticky header with publish button
States it is designed for
- new empty form (canvas shows drop hint)
- draft with fields
- field validation in inspector (duplicate mapping)
- publishing / published / unpublished changes badge
- save failed banner with retry
- preview on mobile width toggle
- form with 0 submissions vs n submissions
- permission denied for non-admins
Who it is for
- sales ops admins
- marketers at small sales teams
Layout
- Dark left app sidebar (~155px): user block, highlighted AI card with chat and voice links, main nav (inbox, opportunities, leads, contacts, activities, workflows, conversations, reports), saved views
- Top bar: search field, phone menu, help
- Settings nav (~150px): grouped sections (general, organization, customization, communication) with Forms highlighted
- Header: back to Forms, title + DRAFT badge, tabs (Builder, Settings, Share), Publish button and overflow
- Canvas (centre, grey): form card with fields (name, email, phone with country code, address, consent checkbox, submit) and below it the thank-you screen preview
- Right palette (~185px): tabs Fields / Design; Layout tiles (heading, paragraph); 'Choose from a template' 2-column tile grid of CRM-mapped fields
- Below 1200px the settings nav collapses to a dropdown; below 900px the palette becomes a bottom sheet opened by an Add field button
Palette
Professional and productive; dark rail anchors navigation while the builder stays bright.
- app sidebar
#0f0f0f - on sidebar
#f2f2f2 - muted on sidebar
#a3a3a3 - canvas
#f6f6f6 - surface
#ffffff - text
#1f2937 - muted text
#6a717f - primary blue
#1f6fe5 - on primary
#ffffff - field icon green
#15803d - draft badge bg
#fdf3c4 - draft badge text
#7a5a00
Every checked pair, measured again
| Sample | Where | Ratio | Needs |
|---|---|---|---|
| Aa | sidebar text | 17.12:1 | 4.5:1 |
| Aa | muted sidebar label | 7.60:1 | 4.5:1 |
| Aa | body text on white | 14.68:1 | 4.5:1 |
| Aa | muted text on canvas | 4.54:1 | 4.5:1 |
| Aa | Publish label on blue | 4.70:1 | 4.5:1 |
| Aa | draft badge | 5.71:1 | 4.5:1 |
| field icon on white tile | 5.02:1 | 3:1 | |
| input border on white | 4.90: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
- Source Sans 3 600 24px title, 18px section heads
- Body
- Source Sans 3 400 16px / 1.5
Similar to the observed grotesk; nav group labels uppercase 12px 600 with 0.06em tracking; field tile labels 15px in dense tiles, nothing below 12px.
Spacing and imagery
Dense-comfortable; 4px base, 16px canvas padding, 12px tile gap; radius 6px inputs, 8px tiles and cards; tiles have 1px border and hover shadow 0 2px 8px rgba(0,0,0,.06).
Green circular field-type icons on tiles; country flag emoji in the phone input; no photos.
Components
- AppSidebar (dark)
- SettingsNav
- BuilderHeader with StatusBadge and Tabs
- FormCanvas with SortableField
- FieldInspector (label, placeholder, required, CRM mapping)
- FieldPaletteTile
- ThankYouPreview
- PublishButton
- ShareTab (link, embed snippet, QR)
Interactions
- Drag tiles from the palette onto the canvas (dnd-kit) with a blue insertion line; click a tile to append
- Drag handles reorder fields; keyboard reorder with space to lift and arrows to move
- Selecting a field opens its settings in the palette pane (Fields tab switches to an inspector)
- Publish validates (at least email or phone), switches badge to LIVE and shows a toast with the share link
- Design tab changes button colour and corner radius live on canvas
- Unsaved changes auto-save every 2s with a 'Saved' indicator
Data
Form{id, org_id, name, status (draft|live), fields[], design{button_color, radius}, thank_you{title, body}, published_at}FormField{id, type (heading|paragraph|text|email|phone|address|checkbox|consent), label, placeholder, required, maps_to (contact.name|contact.email|contact.phone|company.name|company.website|none)}Submission{id, form_id, payload, lead_id, created_at}
Guardrails
Experience
- Canvas mirrors the real form including the thank-you state
- Show which CRM field each form field fills
- Keep draft/live status next to the title
- Allow click-to-add as well as drag
- Warn before publishing a form without consent text
Accessibility
- Every drag action has a keyboard alternative and live announcements ('Email moved to position 2')
- Palette tiles are buttons with names 'Add Contact email field'
- Public form has proper labels, autocomplete tokens and error summary
- Consent checkbox text is the label, not a separate paragraph
- Dark sidebar and light canvas both keep visible focus rings
Security
- Public form submissions: validate against published schema, rate-limit per IP and form, and add a honeypot field
- Only admins may edit or publish forms
- Sanitize thank-you rich text before rendering
- Store consent text version with each submission
- Embed snippet uses an iframe with a restricted origin list
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 **Olvanta**, a lead-capture form builder inside a CRM's settings with a dark app sidebar, settings nav, live canvas and field palette. Seed one draft form for a fictional company and support build, design, publish and share.
### Stack
Use React 18, TypeScript, Vite, Tailwind CSS, shadcn/ui, Radix, lucide-react, TanStack Query, react-hook-form, zod, Supabase, dnd-kit. Use Supabase for Auth, Postgres (row-level security on every table) and Storage where noted; keep only the anon key in the browser and run privileged work in Edge Functions.
### Pages & layout
1. **/settings/forms**: list of forms with status and submissions.
2. **/settings/forms/:id**: builder (Builder, Settings, Share tabs).
3. **/f/:slug**: the public hosted form and its thank-you page.
Regions, in order:
- Dark left app sidebar (~155px): user block, highlighted AI card with chat and voice links, main nav (inbox, opportunities, leads, contacts, activities, workflows, conversations, reports), saved views
- Top bar: search field, phone menu, help
- Settings nav (~150px): grouped sections (general, organization, customization, communication) with Forms highlighted
- Header: back to Forms, title + DRAFT badge, tabs (Builder, Settings, Share), Publish button and overflow
- Canvas (centre, grey): form card with fields (name, email, phone with country code, address, consent checkbox, submit) and below it the thank-you screen preview
- Right palette (~185px): tabs Fields / Design; Layout tiles (heading, paragraph); 'Choose from a template' 2-column tile grid of CRM-mapped fields
- Below 1200px the settings nav collapses to a dropdown; below 900px the palette becomes a bottom sheet opened by an Add field button
### Design system
- Colors: `--app-sidebar: #0f0f0f` (app sidebar), `--on-sidebar: #f2f2f2` (on sidebar), `--muted-on-sidebar: #a3a3a3` (muted on sidebar), `--canvas: #f6f6f6` (canvas), `--surface: #ffffff` (surface), `--text: #1f2937` (text), `--muted-text: #6a717f` (muted text), `--primary-blue: #1f6fe5` (primary blue), `--on-primary: #ffffff` (on primary), `--field-icon-green: #15803d` (field icon green), `--draft-badge-bg: #fdf3c4` (draft badge bg), `--draft-badge-text: #7a5a00` (draft badge text).
- Fonts: Source Sans 3 600 24px title, 18px section heads for headings; Source Sans 3 400 16px / 1.5 for body. Similar to the observed grotesk; nav group labels uppercase 12px 600 with 0.06em tracking; field tile labels 15px in dense tiles, nothing below 12px.
- Spacing, radius and shadows: Dense-comfortable; 4px base, 16px canvas padding, 12px tile gap; radius 6px inputs, 8px tiles and cards; tiles have 1px border and hover shadow 0 2px 8px rgba(0,0,0,.06).
- Motion: 150-200 ms ease-out for hover, focus and overlay transitions; overlays fade and scale from 98% to 100%; everything collapses to an instant change under prefers-reduced-motion.
- Mood: Professional and productive; dark rail anchors navigation while the builder stays bright. Imagery: Green circular field-type icons on tiles; country flag emoji in the phone input; no photos.
### Components & interactions
Build these components: AppSidebar (dark); SettingsNav; BuilderHeader with StatusBadge and Tabs; FormCanvas with SortableField; FieldInspector (label, placeholder, required, CRM mapping); FieldPaletteTile; ThankYouPreview; PublishButton; ShareTab (link, embed snippet, QR).
- Drag tiles from the palette onto the canvas (dnd-kit) with a blue insertion line; click a tile to append
- Drag handles reorder fields; keyboard reorder with space to lift and arrows to move
- Selecting a field opens its settings in the palette pane (Fields tab switches to an inspector)
- Publish validates (at least email or phone), switches badge to LIVE and shows a toast with the share link
- Design tab changes button colour and corner radius live on canvas
- Unsaved changes auto-save every 2s with a 'Saved' indicator
### Data & state
Model: `Form{id, org_id, name, status (draft|live), fields[], design{button_color, radius}, thank_you{title, body}, published_at}`; `FormField{id, type (heading|paragraph|text|email|phone|address|checkbox|consent), label, placeholder, required, maps_to (contact.name|contact.email|contact.phone|company.name|company.website|none)}`; `Submission{id, form_id, payload, lead_id, created_at}`.
Fields are stored as ordered JSON on the form; submissions go through an Edge Function that validates against the published field set and creates contact/lead rows. Use optimistic updates for reorder.
States to implement and demo:
- new empty form (canvas shows drop hint)
- draft with fields
- field validation in inspector (duplicate mapping)
- publishing / published / unpublished changes badge
- save failed banner with retry
- preview on mobile width toggle
- form with 0 submissions vs n submissions
- permission denied for non-admins
### Accessibility
- Every drag action has a keyboard alternative and live announcements ('Email moved to position 2')
- Palette tiles are buttons with names 'Add Contact email field'
- Public form has proper labels, autocomplete tokens and error summary
- Consent checkbox text is the label, not a separate paragraph
- Dark sidebar and light canvas both keep visible focus rings
- Body text is 16px with line-height 1.5 (15px only inside dense tables), nothing renders below 12px, weights of 300 or lighter appear only at 24px and above, and uppercase is limited to short labels with at least 0.05em tracking.
Verified contrast: sidebar text: #f2f2f2 on #0f0f0f = 17.12:1; muted sidebar label: #a3a3a3 on #0f0f0f = 7.60:1; body text on white: #1f2937 on #ffffff = 14.68:1; muted text on canvas: #6a717f on #f6f6f6 = 4.54:1; Publish label on blue: #ffffff on #1f6fe5 = 4.70:1; draft badge: #7a5a00 on #fdf3c4 = 5.71:1; field icon on white tile: #15803d on #ffffff = 5.02:1; input border on white: #6a717f on #ffffff = 4.90:1.
### Security
- Public form submissions: validate against published schema, rate-limit per IP and form, and add a honeypot field
- Only admins may edit or publish forms
- Sanitize thank-you rich text before rendering
- Store consent text version with each submission
- Embed snippet uses an iframe with a restricted origin list
RLS: `forms` - org members select, admins insert/update/delete; `submissions` - org members select, inserts only via the Edge Function (service role); public route reads a published-form view exposing only live forms.
### Performance & SEO
Lazy-load dnd-kit and the builder chunk. The public form is a small, server-rendered page with a title and description, indexable only if the admin opts in.
### Guardrails
- Canvas mirrors the real form including the thank-you state
- Show which CRM field each form field fills
- Keep draft/live status next to the title
- Allow click-to-add as well as drag
- Warn before publishing a form without consent text
- Use the product name Olvanta and fresh, generic copy throughout; all people, companies, amounts and IDs are invented, and no third-party brand, logo or wordmark appears.
- Keep components small and typed (no `any`), and surface every failure visibly instead of swallowing it.
Acceptance criteria:
- [ ] Fields can be added, reordered and configured by mouse and keyboard
- [ ] Publish creates a working public form that writes leads
- [ ] Draft badge reflects unpublished changes
- [ ] Palette usable as a sheet at 390px
- [ ] Contrast pairs pass