Skip to main content
vibld

Template

Vantrell

A contacts list screen in a CRM that a team assembled with a no-code app builder. The builder chrome (workspace sidebar, tabs, Edit/Publish) frames the running app, whose Contacts tab lists people with role, company and open deal count.

CRM contacts list inside a no-code app builder · App screen: table · 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 700, 28px H1
  • InterBody: Inter 400/500, 16px names (500), 14px meta line; line-height 1.5

Patterns

  • app-within-app frame
  • top tab navigation inside card
  • search bar full width
  • avatar list rows with meta line
  • count pill per row
  • chevron row affordance
  • recents list in sidebar
  • upgrade promo card in sidebar

States it is designed for

  • Loading skeleton rows
  • Empty workspace ('Add your first contact')
  • No search results with clear-search button
  • Error loading with retry
  • Long names/companies truncate with tooltip
  • Missing avatar falls back to initials
  • Read-only viewer (no New contact button)

Who it is for

  • Small sales teams running a self-built CRM
  • Operations people assembling internal tools
  • Builders previewing an app before publishing

Layout

  1. Builder sidebar (240px, light grey): workspace switcher, Home/Projects/App store links, Recents list, promo card at bottom
  2. Builder top bar: back/forward, app tab with close, grid icon; right: sync, overflow, Edit, Publish (bright cyan pill)
  3. App frame (white rounded card): app logo + name left, tab nav centre (Dashboard, Deals, Contacts active, Companies)
  4. Contacts header: H1 left, dark 'New contact' button right
  5. Full-width grey search field, then '38 contacts' count
  6. Bordered list: avatar, name, 'Title · Company' meta, deal count pill, chevron
  7. Mobile: builder chrome hidden; app tabs become a bottom bar; rows stay

Palette

friendly, tidy, approachable. A CRM that feels hand-built but polished.

  • builder background#f5f5f4
  • app surface#ffffff
  • primary text#1c1917
  • muted text#5f5f5f
  • row border#8f8f8f
  • search fill#f0f0ef
  • dark button#1c1917
  • publish pill#5ee0e8
  • publish label#0c2a2c
  • focus ring#0e7c86
  • count pill fill#ededed

Every checked pair, measured again

SampleWhereRatioNeeds
Aabody text on app17.49:14.5:1
Aamuted meta on app6.39:14.5:1
Aamuted sidebar text5.85:14.5:1
Aaplaceholder on search fill5.60:14.5:1
Aadark button label17.49:14.5:1
Aapublish label on cyan9.62:14.5:1
row border3.23:13:1
focus ring4.95:13:1
Aacount pill text14.94:14.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 700, 28px H1
Body
Inter 400/500, 16px names (500), 14px meta line; line-height 1.5

Neutral grotesk similar to observed; meta line 14px muted with middle-dot separator.

Spacing and imagery

Comfortable list: 64px rows, 16px horizontal padding, 40px avatars; app card radius 12px; search 40px tall radius 8px; builder sidebar radius 12px on promo card.

Circular headshot avatars (use illustrated or initials avatars in mocks); line icons in builder chrome.

Components

  • Builder sidebar with recents
  • Upgrade promo card
  • Builder top bar with Edit and Publish
  • App header with logo and tab nav
  • New contact button
  • Search input
  • Result count
  • Contact row (avatar, name, meta, deal pill, chevron)
  • Contact detail drawer
  • New contact form dialog

Interactions

  • Search filters by name, title or company as you type (debounced 150ms)
  • Row hover tints background; click or Enter opens detail drawer
  • Tabs switch app screens; active tab has grey pill
  • New contact opens a dialog; new row appears at top with brief highlight
  • Keyboard: / focuses search, arrow keys move between rows

Data

  • Contact{id, app_id, full_name, title, company_id, avatar_url, email, phone, owner_id, created_at}
  • Company{id, app_id, name, sector_label}
  • Deal{id, contact_id, company_id, stage (lead|qualified|proposal|won|lost), value}

Guardrails

Experience

  • Show count above the list so users know search scope
  • Put the most useful facts (title and company) in the meta line
  • Make the whole row the click target
  • Keep builder chrome visually quieter than the app itself
  • Surface deal counts as neutral pills, not colours

Accessibility

  • List is a semantic ul of links with name + meta as accessible name
  • Search has a visible label (can be visually hidden) and announces result count
  • Avatars have empty alt; initials fallback aria-hidden
  • Publish label on cyan passes 4.5:1
  • Focus ring 2px teal visible on white and grey

Security

  • RLS: contacts/companies/deals scoped to app workspace members; viewers read-only
  • Validate contact fields (email, phone) with zod client and server
  • Avatar uploads: image types only, 2MB cap, private bucket with signed URLs
  • Audit contact deletes; soft-delete with 30-day restore

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 **Vantrell**, the Contacts screen of a small CRM assembled inside a no-code app builder. The builder chrome frames a running app whose Contacts tab lists 38 people with title, company and deal count, supports instant search, and opens a detail drawer.

### 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.

### Pages & layout
1. **Builder sidebar** (240px, `--chrome`): workspace switcher, search and collapse icons; Home, Projects, App store; 'Recent' list with app names and small type labels; bottom promo card 'Keep building' with a dark Upgrade button; help icon.
2. **Builder top bar**: back/forward, app tab with close, apps grid; right: refresh, overflow, Edit (grey pill), Publish (`--publish` pill).
3. **App frame** (white, radius 12px): app logo + name; centred tabs Dashboard, Deals, Contacts (active grey pill), Companies.
4. **Contacts**: H1 + 'New contact'; search; '38 contacts'; list rows with avatar, name, 'Title · Company', '1 deal' pill and chevron.
5. **Detail drawer** (right 420px): avatar, name, title, company link, email, phone, deals list, Edit.
6. Mobile: builder chrome hidden; app tabs become a bottom bar.

### Design system
- Colors: `--chrome: #f5f5f4` (builder background), `--bg: #ffffff` (app surface), `--fg: #1c1917` (primary text), `--muted: #5f5f5f` (muted text), `--border: #8f8f8f` (row border), `--field: #f0f0ef` (search fill), `--primary: #1c1917` (dark button), `--publish: #5ee0e8` (publish pill), `--on-publish: #0c2a2c` (publish label), `--ring: #0e7c86` (focus ring), `--pill: #ededed` (count pill fill).
- Fonts: Inter 400/500/700; H1 28px 700; row name 16px 500; meta 14px; body line-height 1.5.
- Spacing: 4px base; rows 64px; app padding 24px.
- Radius: app frame 12px, buttons 8px, pills 6px, avatars full.
- Shadows: app frame `0 1px 2px rgb(0 0 0 / 0.05)`; drawer `-8px 0 24px rgb(0 0 0 / 0.1)`.
- Motion: 120ms row hover; drawer slide 200ms; new-row highlight fades over 2s.

### Components & interactions
`BuilderSidebar`, `PromoCard`, `BuilderTopBar`, `AppFrame`, `AppTabs` (Radix Tabs as nav links), `SearchInput` ('/' shortcut), `ResultCount` (aria-live), `ContactRow`, `CountPill`, `ContactDrawer`, `ContactFormDialog` (react-hook-form + zod), `AvatarWithFallback`.

### Data & state
`contacts(id, workspace_id, full_name, title, company_id, avatar_path, email, phone, owner_id, created_at, deleted_at)`, `companies(id, workspace_id, name)`, `deals(id, workspace_id, contact_id, stage, value)`, `members(workspace_id, user_id, role enum builder|editor|viewer)`. Deal counts via a view. Search is client-side for <500 rows, server `ilike` beyond. Seed 38 invented contacts across invented companies.

### Accessibility
List of links with 'Name, Title at Company, 1 deal'. Search labelled, result count announced politely. Arrow keys move focus between rows. Drawer is a Radix Dialog with focus return. Initials avatars aria-hidden.
Verified contrast: body text on app: #1c1917 on #ffffff = 17.49:1; muted meta on app: #5f5f5f on #ffffff = 6.39:1; muted sidebar text: #5f5f5f on #f5f5f4 = 5.85:1; placeholder on search fill: #5f5f5f on #f0f0ef = 5.60:1; dark button label: #ffffff on #1c1917 = 17.49:1; publish label on cyan: #0c2a2c on #5ee0e8 = 9.62:1; row border: #8f8f8f on #ffffff = 3.23:1; focus ring: #0e7c86 on #ffffff = 4.95:1; count pill text: #1c1917 on #ededed = 14.94:1.

### Security
RLS per table: select for workspace members; insert/update for builder and editor roles; viewers read-only; deletes set `deleted_at` (editors) and hard delete only by builders after 30 days. Validate email/phone with zod on client and in a Postgres check or function. Avatars in a private bucket with signed URLs. Audit deletes.

### Performance & SEO
Virtualise the list above 200 rows. Avatars 80px WebP lazy-loaded. Prefetch the drawer data on row hover. App routes `noindex`.

### Guardrails
- Invent all people and companies; use illustrated or initials avatars.
- Keep builder brand neutral; no real platform names.
- Don't colour-code deal counts.

Acceptance criteria:
- [ ] Search narrows the list and updates the count
- [ ] Row click opens the drawer; Esc returns focus
- [ ] Viewer role sees no New contact button and RLS blocks writes
- [ ] Empty and no-results states render
- [ ] Contrast pairs pass

Open the builderAll templatesThis palette on its own