Template
Rowport
The processing step of a customer-data CSV import in a messaging automation tool. After upload, field mapping and review, the user waits on a centred 'Uploading…' state with a clear way to cancel.
CSV import uploading step with stepper · App screen: loading · 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 page title and 18px status
- InterBody: Inter 400, 16px, line-height 1.5
Patterns
- dark top bar with trial countdown and upgrade
- icon rail plus labelled sidebar
- breadcrumb with file name
- three-step stepper with checks
- centred uploading message with spinner
- danger outlined cancel
- version footer
States it is designed for
- uploading
- processing rows with count
- done summary
- failed with downloadable error report
- cancelled
- partially imported
- file too large / wrong type (earlier step)
- trial limit reached mid-import
Who it is for
- lifecycle marketers importing contact lists
- growth ops teams
Layout
- top bar (dark green): workspace switcher, test-mode badge, trial days left, Upgrade button, help, notifications, settings, profile
- icon rail (~30px) plus sidebar (~130px) with product sections and a Data & integrations group expanded
- breadcrumb: Imports / file name / Uploading
- title 'Import CSV' with Cancel import (danger outline) right
- stepper: Upload, Map fields, Review -- all checked
- centre: heading 'Uploading…', spinner, one-line message
- footer: version string left, credit line right
- below 900px sidebar collapses; stepper labels shorten
Palette
Dependable and operational; a long job is shown calmly with an exit.
- bg
#ffffff - topbar
#0d2a1f - upgrade
#dcf7c5 - upgrade-text
#0d2a1f - text
#1c1f24 - muted
#5f6570 - step-done
#2f8a4f - danger
#d32f2f - sidebar
#f6f7f8 - active
#e9ecef
Every checked pair, measured again
| Sample | Where | Ratio | Needs |
|---|---|---|---|
| Aa | body text | 16.52:1 | 4.5:1 |
| Aa | muted message | 5.86:1 | 4.5:1 |
| Aa | top bar text | 15.35:1 | 4.5:1 |
| Aa | Upgrade label | 13.27:1 | 4.5:1 |
| Aa | cancel text and border | 4.98:1 | 4.5:1 |
| stepper check | 4.31:1 | 3:1 | |
| Aa | active nav text | 13.94: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.
- background
- card
- muted
- primary
- secondary
- accent
- destructive
Type scale
- Display
- Inter 600, 20px page title and 18px status
- Body
- Inter 400, 16px, line-height 1.5
Sidebar 15px; breadcrumb 14px muted; version footer 13px.
Spacing and imagery
Density: Medium. Grid: 8px; page padding 16px. Container: fluid main. Radius: 6px buttons, 8px active nav. Shadows: none; top bar provides contrast.
Line icons; a small animated brand-neutral spinner.
Components
- TopBar with TrialCountdown and UpgradeButton
- IconRail
- Sidebar with collapsible groups
- Breadcrumbs
- ImportStepper
- UploadProgress (heading, spinner, message, optional %)
- CancelImportButton with confirm
- VersionFooter
Interactions
- Cancel import asks for confirmation and aborts the job
- Progress polls every 2s; when rows processed are known show 'n of m rows'
- On completion show a summary (created, updated, skipped with reasons) and 'View people'
- Leaving the page keeps the job running with a banner elsewhere
Data
ImportJob{id, workspace_id, file_name, status (uploading|processing|done|failed|cancelled), rows_total, rows_done, created, updated, skipped, error_report_url}FieldMapping{import_id, column, attribute, type (text|number|date|bool)}Person{id, workspace_id, email, attributes jsonb}
Guardrails
Experience
- Keep Cancel import visible throughout
- Show row counts once known instead of an indeterminate spinner
- Summarise results with reasons for skipped rows
- Let users navigate away safely
- Keep the stepper visible so users know where they are
Accessibility
- Status heading and count in a live region
- Stepper is an ordered list with aria-current on the current step
- Spinner has role=progressbar (indeterminate) and a label
- Cancel confirm is a labelled alertdialog
- Completed step labels still meet 4.5:1
Security
- Accept only .csv under 50MB; sniff content type server-side
- Store uploads in a private bucket with signed URLs
- Validate each row with zod on the server; neutralise formula-injection prefixes in exports
- RLS: import_jobs and people scoped to workspace members
- Audit who imported what
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 **Rowport**, the processing step of a CSV contact import. After mapping and review, the user sees 'Uploading…' with a spinner and count, a stepper showing all prior steps done, and a clear Cancel import. Build the app shell, the full three-step import with this step emphasised, and the summary.
### 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. Parse CSV headers in the browser with a lightweight CSV parser for mapping, then upload the file to Supabase Storage; an Edge Function or worker processes rows in chunks.
### Pages & layout
1. **Shell**: dark top bar (workspace switcher, test-mode badge, 'n days left in trial', Upgrade, help, bell, settings, profile); icon rail; sidebar with groups and Data & integrations expanded.
2. **Import flow**: breadcrumb, title, Cancel import; stepper (Upload CSV, Map fields, Review).
3. **Uploading state**: centred heading, spinner, message ('We're processing your file. This shouldn't take long.'), optional row count.
4. **Summary**: created/updated/skipped counts and error report link.
### Design system
- Colors: `--bg: #ffffff` (page), `--topbar: #0d2a1f` (top bar), `--upgrade: #dcf7c5` (Upgrade button), `--upgrade-text: #0d2a1f` (Upgrade label), `--text: #1c1f24` (primary text), `--muted: #5f6570` (messages), `--step-done: #2f8a4f` (stepper checks), `--danger: #d32f2f` (Cancel import), `--sidebar: #f6f7f8` (sidebar), `--active: #e9ecef` (active nav item).
- Fonts: Inter 600, 20px page title and 18px status for headings; Inter 400, 16px, line-height 1.5 for body. Sidebar 15px; breadcrumb 14px muted; version footer 13px.
- Spacing: Medium. 8px; page padding 16px. Container: fluid main.
- Radius: 6px buttons, 8px active nav.
- Shadows: none; top bar provides contrast.
- Motion: Spinner rotates 1s linear (reduced motion: pulsing dot); step checks draw in on completion; success transitions to the result summary.
### Components & interactions
ImportStepper shows circled checks and muted labels for completed steps. UploadProgress switches from indeterminate spinner to determinate bar once rows_total is known.
- Cancel import asks for confirmation and aborts the job
- Progress polls every 2s; when rows processed are known show 'n of m rows'
- On completion show a summary (created, updated, skipped with reasons) and 'View people'
- Leaving the page keeps the job running with a banner elsewhere
### Data & state
Mock a 4,800-row file processing in chunks of 400 every second, with 12 skipped rows. TanStack Query polls the job.
Entities: `ImportJob{id, workspace_id, file_name, status (uploading|processing|done|failed|cancelled), rows_total, rows_done, created, updated, skipped, error_report_url}`; `FieldMapping{import_id, column, attribute, type (text|number|date|bool)}`; `Person{id, workspace_id, email, attributes jsonb}`.
States to build and show in a dev-only state switcher:
- uploading
- processing rows with count
- done summary
- failed with downloadable error report
- cancelled
- partially imported
- file too large / wrong type (earlier step)
- trial limit reached mid-import
### Accessibility
- Status heading and count in a live region
- Stepper is an ordered list with aria-current on the current step
- Spinner has role=progressbar (indeterminate) and a label
- Cancel confirm is a labelled alertdialog
- Completed step labels still meet 4.5:1
Verified contrast: body text: #1c1f24 on #ffffff = 16.52:1; muted message: #5f6570 on #ffffff = 5.86:1; top bar text: #ffffff on #0d2a1f = 15.35:1; Upgrade label: #0d2a1f on #dcf7c5 = 13.27:1; cancel text and border: #d32f2f on #ffffff = 4.98:1; stepper check: #2f8a4f on #ffffff = 4.31:1; active nav text: #1c1f24 on #e9ecef = 13.94:1.
### Security
- Accept only .csv under 50MB; sniff content type server-side
- Store uploads in a private bucket with signed URLs
- Validate each row with zod on the server; neutralise formula-injection prefixes in exports
- RLS: import_jobs and people scoped to workspace members
- Audit who imported what
RLS detail: `import_jobs` select/insert for workspace members with editor role, update by service role; `people` select for members, write for editors and the service role; storage bucket policies limit paths to the workspace id.
### Performance & SEO
Parse only the first 50 rows client-side for preview; stream the upload; stop polling on terminal states.
### Guardrails
- Keep Cancel import visible throughout
- Show row counts once known instead of an indeterminate spinner
- Summarise results with reasons for skipped rows
- Let users navigate away safely
- Keep the stepper visible so users know where they are
- 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:
- Cancel aborts and shows cancelled state
- Counts progress and summary is correct
- Invalid files are rejected earlier with reasons
- Private storage with signed URLs
- Stepper and status are screen-reader friendly