Template
Bluequill
An analytics dashboard for a customer-support team that shows ticket volume, resolution, first-reply time, conversions by region, tickets by channel and satisfaction at a glance. It is a starter for any metrics-heavy admin: sidebar shell, KPI strip, chart cards and theme switching are all ready.
Support-desk analytics dashboard with light/dark themes · App · Small tools and apps · full-stack app (auth + DB)
A mock-up of the homepage, drawn from this design’s layout, palette and typefaces. A build follows the full prompt below.
Add app screens
Pick up to 6 screens, such as a dashboard, settings or an empty state. Each is built in this design’s own palette and typefaces, with its states and guardrails.
Start from this templateRead the build prompt
Typefaces
Gabarito is kept as named: a rounded geometric sans with tabular numerals that makes saturated blue charts feel bright and orderly, and no other template uses it.
- GabaritoHeadings: page title 24px 600, KPI numbers 20px 600 tabular, card titles 16px 500
- GabaritoBody: body 14-16px 400, captions and axis labels 12px
Patterns
- persistent left sidebar with profile switcher on top
- KPI stat strip with delta chips
- date-range picker in card header
- stacked bar chart with side legend of totals
- bubble/circle-packing chart for category share
- semi-circle gauge with centre total
- sentiment breakdown with icon, percentage and progress bars
- hairline-divided card grid (no card shadows)
- system/light/dark theme toggle with 'auto' badge
- collapsible sidebar to icon rail on mobile
States it is designed for
- Loading: skeleton blocks for KPIs and chart areas
- Empty range: 'No tickets in this period' inside each card
- API error per card with retry button (other cards keep working)
- Zero or negative deltas: neutral grey chip
- Very large numbers abbreviated (24.2k) with full value in tooltip
- Dark mode variants for all chart colours
Who it is for
- support team leads
- operations managers
- developers building internal analytics dashboards
Layout
- Left sidebar (240px, pale slate): avatar + name + role switcher at top, nav items (Dashboard, Tickets), footer credit area
- Top bar in main: page title left, theme toggle button right with a tiny 'auto' badge
- KPI strip: four stats in a row separated by whitespace: label, big number, delta chip (green up / red down), 'vs last month' caption
- Row 2: wide card (2/3) with title, date-range picker and stacked bar chart plus a left legend showing two averages; narrow card (1/3) with total conversions, a four-region legend and a bubble chart
- Row 3: two half cards: tickets by channel (semi-circle gauge with centred total and five-item legend) and satisfaction (responses count plus positive/neutral/negative rows with icon, percent and bar)
- Cards separated by 1px hairlines rather than gaps/shadows
- Tablet: row 2 stacks; mobile: sidebar collapses to a slide-over opened from an edge tab, KPIs in 2x2, charts full width
Palette
Bright, data-forward and orderly. Saturated blues on white make numbers pop without clutter.
- canvas (light)
#ffffff - sidebar / subtle fill
#f1f5f9 - primary text
#020817 - muted text
#617087 - chart primary blue
#0040ff - chart cyan
#009fd2 - chart orange
#f76906 - positive delta text
#17843f - negative delta text
#de1313 - hairline / input border
#7d96b4 - dark canvas
#020817 - dark card / sidebar
#0f172a
Every checked pair, measured again
| Sample | Where | Ratio | Needs |
|---|---|---|---|
| Aa | body text on white | 20.01:1 | 4.5:1 |
| Aa | muted caption on sidebar | 4.59:1 | 4.5:1 |
| Aa | positive delta on green tint | 4.55:1 | 4.5:1 |
| Aa | negative delta on red tint | 4.56:1 | 4.5:1 |
| primary bar on white | 6.61:1 | 3:1 | |
| cyan bar on white | 3.05:1 | 3:1 | |
| orange series on white | 3.01:1 | 3:1 | |
| input / picker border on white | 3.05:1 | 3:1 | |
| Aa | dark mode text | 19.12:1 | 4.5:1 |
| Aa | dark mode muted on card | 6.96: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. 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
- Gabarito 500-600 (observed), 24px page title, 20px KPI numbers, 16px card titles
- Body
- Gabarito 400 14-16px; captions 12px minimum (delta chip labels, axis ticks)
Rounded geometric sans with tabular numerals for KPIs. Keep axis labels 12px and muted.
Spacing and imagery
Medium-dense; 4px grid; card padding 24px; KPI strip 24px vertical padding; hairline borders only. Radius 6px on buttons, pickers and chips; bars have 4px top radius. No shadows.
Charts only: stacked bars, bubbles, gauge, progress bars; small line icons before card titles; gradient avatar circle.
Components
- SidebarProfileSwitcher
- NavItem (active pill)
- ThemeToggle (system/light/dark)
- KpiStat with DeltaChip
- DateRangePicker
- StackedBarChart with LegendTotals
- BubbleChart
- GaugeChart
- SentimentRow (icon, label, percent, progress)
- ChartCard shell
- TicketsTable (second page)
Interactions
- Hovering a bar shows a tooltip with both series and the date
- Date range picker updates all charts; presets (7d, 30d, quarter)
- Theme toggle cycles system, light, dark and persists
- Legend items toggle series visibility
- Sidebar collapses to icons on medium screens; slide-over on mobile with backdrop
- Chart entrance animation 400ms, disabled under reduced motion
Data
Ticket{id, channel (email|chat|form|messenger|phone), status (open|pending|solved), created_at, first_reply_at, solved_at, region, satisfaction (positive|neutral|negative|null)}DailyTicketStats{date, created, resolved}RegionConversion{region, sales}KpiSnapshot{metric, value, previous, delta_pct}
Guardrails
Experience
- Every KPI shows its comparison period in words next to the delta
- One date range controls the whole page; show it in the page header on mobile
- Limit each chart to five series; group the rest as 'Other'
- Charts start at zero on the value axis
- Delta colour logic respects metric direction (fewer unsolved tickets is good)
Accessibility
- Delta chips pair colour with an arrow icon and sign; fixed text colours #17843f and #de1313 pass 4.5:1 on their tints
- Chart hues (#0040ff, #009fd2, #f76906) all exceed 3:1 on white; lighter cyan and orange from the source were raised
- Each chart has an accessible summary and a 'View data' table toggle
- Theme toggle is a button with a text label announcing the current mode
- Sidebar muted text uses #617087 to pass on the pale sidebar
Security
- RLS on tickets: agents see rows in their workspace only (workspace_id in user's memberships)
- Aggregations run in SQL views or RPCs scoped by workspace; never ship raw ticket bodies to the dashboard
- Role-based access: viewers read, admins manage workspace settings
- Date-range parameters validated with zod and capped at 1 year
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 **Bluequill**, an analytics dashboard for a customer-support team. On one screen a lead sees tickets created, unsolved and resolved, first-reply time, a daily created-versus-resolved chart, conversions by region, tickets by channel and customer satisfaction. It also works as a reusable shell for any metrics admin, with light and dark themes. ### Stack Next.js (App Router) + React + TypeScript, Tailwind CSS, shadcn/ui (Radix), lucide-react, Recharts for bars, gauge (a radial bar) and bubble chart (scatter with a size scale, or a circle-packing helper), TanStack Query, date-fns, zod. Supabase for Auth and Postgres, with SQL views for aggregates. ### Pages & layout 1. **Dashboard**: a 240px pale sidebar (avatar with gradient, name, role and a switcher chevron; nav Dashboard and Tickets; footer area). Main area: header with "Dashboard" and a theme toggle showing a small "auto" badge in system mode. A KPI strip of four stats (label, big number, delta chip, "vs last month"). Row 2: a wide card with a stacked bar chart of created versus resolved per day, a left legend showing the two averages and a date-range picker in the header, next to a narrow card with total conversions, a four-region legend and bubbles sized by value. Row 3: tickets by channel (semi-circle gauge, total in the centre, five-item legend) and satisfaction (responses count, then positive, neutral and negative rows with icon, percent and progress bar). Cards are divided by 1px hairlines, not shadows. 2. **Tickets**: a TanStack Table with status and channel filters, search and pagination. 3. **Responsive**: at 1024px and below, row 2 stacks. Below 768px the sidebar becomes a slide-over opened from an edge tab, KPIs sit in a 2x2 grid and charts go full width. ### Design system - Light colors: `--bg: #ffffff`, `--subtle: #f1f5f9`, `--fg: #020817`, `--muted: #617087`, `--border: #7d96b4` for inputs and pickers (dividers may use a lighter decorative hairline), `--chart-1: #0040ff`, `--chart-2: #009fd2`, `--chart-3: #f76906`, `--up: #17843f` on `#f0fdf4`, `--down: #de1313` on `#fef2f2`. - Dark colors: `--bg: #020817`, `--card: #0f172a`, `--fg: #f8fafc`, `--muted: #94a3b8`; chart-1 lightens to `#3b6bff` for dark. - Fonts: Gabarito. Title 600 at 24px; KPI numbers 600 at 20px with tabular numerals; card titles 500 at 16px; body 400 at 14-16px; axis and captions 12px minimum. - Spacing: 4px base; card padding 24px; KPI gap 32px. - Radius: 6px controls and chips; bars 4px top corners; avatar full. - Shadows: none; hairlines only. - Motion: 400ms chart entrance, 150ms hovers; none under reduced motion. ### Components & interactions SidebarProfileSwitcher, NavItem (active = subtle fill), ThemeToggle (system, light, dark, stored in localStorage inside try/catch), KpiStat, DeltaChip (arrow + sign + colour; direction-aware), DateRangePicker (presets 7d, 30d, 90d, custom), ChartCard (title icon, actions slot, loading, empty and error slots), StackedBarChart, LegendTotals, BubbleChart, GaugeChart, SentimentRow, TicketsTable. Tooltips on every mark; legend clicks toggle series; the date range drives every query via the URL (`?from&to`). ### Data & state `workspaces(id, name)`, `memberships(user_id, workspace_id, role enum viewer|admin)`, `tickets(id, workspace_id, channel, status, region, created_at, first_reply_at, solved_at, satisfaction)`. Views: `daily_ticket_stats`, `kpi_snapshot(range)`, `region_conversions`, `channel_counts`, `satisfaction_summary`. Seed 3,000 invented tickets over 90 days across four fictional regions (for example North Vale, Eastport, Riverside, Hillcrest). TanStack Query caches per range. ### Accessibility KPIs are a description list. Each chart has an `aria-label` summary and a "View data" toggle that shows a table. Delta chips never rely on colour alone. Legend toggles are buttons with `aria-pressed`. Keyboard focus reaches bars via a focusable data table alternative. Visible 2px focus ring in `--chart-1`. Every text pair is checked in both themes. Verified contrast: body text on white: #020817 on #ffffff = 20.01:1; muted caption on sidebar: #617087 on #f1f5f9 = 4.59:1; positive delta on green tint: #17843f on #f0fdf4 = 4.55:1; negative delta on red tint: #de1313 on #fef2f2 = 4.56:1; primary bar on white: #0040ff on #ffffff = 6.61:1; cyan bar on white: #009fd2 on #ffffff = 3.05:1; orange series on white: #f76906 on #ffffff = 3.01:1; input / picker border on white: #7d96b4 on #ffffff = 3.05:1; dark mode text: #f8fafc on #020817 = 19.12:1; dark mode muted on card: #94a3b8 on #0f172a = 6.96:1. ### Security Enable RLS on `tickets`, `memberships` and `workspaces`: select only where `workspace_id` is in the caller's memberships; only admins may update workspace settings; nobody may delete tickets from the client. Views are `security_invoker` so RLS applies. Validate range params with zod (max 365 days). No ticket bodies or customer emails reach the dashboard. ### Performance & SEO Server-render the shell and KPI strip, and stream chart cards with Suspense. Lazy-load chart code. Memoise series transforms. Dashboard routes are `noindex`. Target an interaction-to-next-paint under 200ms on a mid-range laptop. ### Guardrails - All numbers, regions and names are invented; avoid real city names. - No vendor chart branding or "powered by" badges. - Keep chart palettes identical across cards so colours mean the same thing. - Acceptance criteria: - [ ] Changing the date range updates every card and the URL - [ ] Loading, empty and error states render per card - [ ] Both themes pass all recorded contrast pairs - [ ] Users in another workspace see none of these tickets - [ ] Mobile layout has no horizontal scroll at 360px