Template
Marrowfield
An analytics page for the name-resolution service of a web infrastructure console. It answers 'who is asking for which records, and when?' by letting an operator pivot the same query volume by record name, type, response code, location or source network. It supports printing and exporting for incident reports.
DNS query analytics with dimension tabs and top-N breakdown · App screen: analytics · 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, 32px, tracking -0.02em for title; tile counts 24px 600 tabular
- InterBody: Inter 400, 16px/1.5; tabs 15px 500; tile labels 14px; axis 12px
Patterns
- console shell with collapsible sidebar
- dismissible info banner with cross-link
- report card with print and download actions
- add-filter chip builder
- time-range select with timezone suffix
- dimension tabs with overflow menu
- top-N value tiles with series colour dots
- multi-series time chart
- breakdown table under chart
States it is designed for
- loading skeletons for tiles and chart
- no queries in range (empty chart with suggestion to widen range)
- fewer than 5 values (tiles shrink, no gaps)
- very long record names wrap
- filters produce no results (clear filters CTA)
- export generating / ready / failed
- error with retry
- banner dismissed
Who it is for
- network and DNS administrators
- SRE and security analysts
- agency developers managing client domains
Layout
- Top bar and sidebar as in the console shell (DNS section expanded: Records, Analytics, Settings)
- Header: eyebrow 'DNS', title, subtitle naming the zone, outlined docs pill
- Info banner: blue tint, icon, bold line + description, right-aligned link
- Report card header: title with zone, Print and Download actions right
- Filter row: outlined 'Add filter' button, applied filter chips, time-range select (with timezone) right
- Query overview: section title with info icon; dimension tabs (Name, Type, Response code, Location, Source IP, Destination IP, ... overflow)
- Top-N tiles: 5 columns separated by hairlines, each dot + label (wraps) + big count
- Time-series chart: one line per top value, y-axis in thousands
- Breakdown table: value, queries, share, trend
- Below 900px tiles scroll horizontally with snap; tabs become a select
Palette
Operational, precise, calm. Colour appears only in data series and the one info banner.
- canvas
#fbfbfb - surface
#ffffff - text
#1d1d1f - muted
#595959 - border
#e0e3e8 - link
#0b57c2 - banner-bg
#eef4fc - series-1
#2f6fdf - series-2
#b26b00 - series-3
#1f8a4c - series-4
#d6336c - series-5
#9c36b5
Every checked pair, measured again
| Sample | Where | Ratio | Needs |
|---|---|---|---|
| Aa | body text on canvas | 16.26:1 | 4.5:1 |
| Aa | muted subtitle on card | 7.00:1 | 4.5:1 |
| Aa | banner link text | 6.01:1 | 4.5:1 |
| series 1 on card | 4.71:1 | 3:1 | |
| series 2 on card | 4.20:1 | 3:1 | |
| series 3 on card | 4.38:1 | 3:1 | |
| series 4 on card | 4.62:1 | 3:1 | |
| series 5 on card | 5.82:1 | 3:1 | |
| filter button border (link colour) on card | 6.65: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
- Inter 600, 32px, tracking -0.02em for title; tile counts 24px 600 tabular
- Body
- Inter 400, 16px/1.5; tabs 15px 500; tile labels 14px; axis 12px
Similar to the observed neo-grotesk; long hostnames wrap with overflow-wrap:anywhere.
Spacing and imagery
Medium density; 8px base; content max 1040px; report card padding 20px; tiles 16px padding with 1px dividers; radius 6px cards, full pill for docs link and filter button; no shadows.
Line chart with five distinct hues and matching dots; no illustration.
Components
- docs pill link
- info banner
- report card header actions
- add filter button and filter chips
- time range select
- dimension tabs with overflow
- top-N tile
- multi-line chart
- breakdown table
- download menu (CSV, JSON)
Interactions
- Clicking a tile or table row adds it as a filter (with undo toast)
- Tab change swaps the tiles, chart series and table in place with a 150ms fade
- Chart hover shows a vertical guide and a tooltip listing all series at that time
- Legend/tile dot click isolates a series
- Print opens a print stylesheet version; Download offers CSV or JSON
- Banner dismiss is remembered per user
Data
Zone{id, account_id, name}QueryBucket{zone_id, bucket_start, dimension (name|type|rcode|location|source_ip|dest_ip), value, count}SavedFilter{id, user_id, zone_id, field, operator (eq|neq|contains), value}Export{id, zone_id, format (csv|json), status, url, expires_at}
Guardrails
Experience
- Default to last 24 hours with timezone shown
- Let any visible value become a filter in one click
- Keep series colours identical between tiles, chart and table
- Wrap long hostnames rather than truncating them
- Show absolute counts and share together
- Make export formats and time range explicit in the file name
Accessibility
- Each series also has a distinct marker shape at points and a text label in tiles
- Chart has a data-table alternative (the breakdown table)
- Tabs are a real tablist; overflow items reachable via a menu button
- Filter chips have remove buttons named 'Remove filter type = A'
- Banner uses role=status and is dismissible by keyboard
- Numbers use tabular numerals and full values in aria-labels (1.9 million)
Security
- RLS: query buckets and exports scoped by account membership
- Exports generated server-side with signed, expiring download URLs
- Filter values validated (hostname or IP pattern) and parameterised in SQL
- Rate-limit export creation per user
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 **Marrowfield**, the DNS > Analytics page of a web infrastructure console. For one zone, the operator sees total query volume over a time range and pivots it by record name, type, response code, location, source IP or destination IP, with the top five values as tiles, a multi-line chart and a sortable breakdown table. Printing and exporting must be first-class. ### Stack React 18 + TypeScript + Vite, Tailwind CSS, shadcn/ui (Tabs, DropdownMenu, Popover, Select, Badge, Toast), lucide-react, Recharts (LineChart), TanStack Table for the breakdown, TanStack Query, date-fns with time zones. Supabase Auth, Postgres (bucketed counts table or materialised view) and an Edge Function for exports. ### Pages & layout 1. **Shell**: console top bar and sidebar (DNS expanded: Records, Analytics, Settings). 2. **/dns/analytics** (this screen): header 'Analytics' for zone 'larkspur-labs.net' (invented), docs pill; info banner suggesting a combined overview page; report card 'Queries for larkspur-labs.net' with Print and Download; filter row; 'Query overview' with dimension tabs; five tiles (e.g. www 1.9M, apex 40.2k, docs 1.04k, a long verification subdomain 180, mail policy record 120); chart; breakdown table. 3. Print view: single column, no sidebar, black text, series patterns. 4. Responsive: tiles scroll-snap horizontally below 900px; tabs collapse to a Select. ### Design system - Colors: `--canvas: #fbfbfb`, `--surface: #ffffff`, `--text: #1d1d1f`, `--muted: #595959`, `--border: #e0e3e8`, `--link: #0b57c2`, `--banner-bg: #eef4fc`, `--series-1: #2f6fdf`, `--series-2: #b26b00`, `--series-3: #1f8a4c`, `--series-4: #d6336c`, `--series-5: #9c36b5`. - Fonts: Inter (similar to observed). Title 32px/600; counts 24px/600 tabular; body 16px/1.5; axis ticks 12px. - Spacing: 8px base; card padding 20px; tile padding 16px. - Radius: 6px cards; pills full. - Shadows: none. - Motion: 150ms fades between dimensions; chart animation off under reduced motion. ### Components & interactions `InfoBanner` (dismissible), `ReportCard` (header actions), `FilterBuilder` (field Select, operator, value Input with pattern validation, chip list), `TimeRangeSelect` (presets + custom, timezone label), `DimensionTabs` (overflow DropdownMenu), `TopValueTile` (dot, label, count, click to filter), `SeriesChart` (tooltip, legend isolate), `BreakdownTable` (sortable, share bar, copy value button), `ExportMenu` (CSV / JSON, progress toast). ### Data & state `query_buckets(zone_id, bucket_start timestamptz, dimension, value, count)` with index on (zone_id, dimension, bucket_start). RPC `top_values(zone_id, dimension, from, to, filters jsonb, limit 5)` and `series(...)`. Filters and dimension in URL params. Mock 24h of 5-minute buckets with spiky traffic. ### Accessibility Series are distinguishable by colour, marker shape and label text. The breakdown table is the accessible equivalent of the chart. Tile click affordance is a real button. Counts read as full numbers. The print view uses patterns rather than colour for series. Verified contrast: body text on canvas: #1d1d1f on #fbfbfb = 16.26:1; muted subtitle on card: #595959 on #ffffff = 7.0:1; banner link text: #0b57c2 on #eef4fc = 6.01:1; series 1 on card: #2f6fdf on #ffffff = 4.71:1; series 2 on card: #b26b00 on #ffffff = 4.2:1; series 3 on card: #1f8a4c on #ffffff = 4.38:1; series 4 on card: #d6336c on #ffffff = 4.62:1; series 5 on card: #9c36b5 on #ffffff = 5.82:1; filter button border (link colour) on card: #0b57c2 on #ffffff = 6.65:1. ### Security RLS on `zones`, `query_buckets`, `exports` by account membership. Parameterise all filter values; validate hostnames and IPs with zod. Exports are created by an Edge Function that checks membership, writes to a private bucket and returns a signed URL valid for 10 minutes. Rate-limit exports to 10 per hour per user. ### Performance & SEO Downsample series server-side to at most 300 points. Lazy-load the chart. Cache top values per filter key. Console routes noindex. ### Guardrails - Invented zones and hostnames only - Keep colours consistent across tile, chart and table - Never truncate record names silently - Typed code, visible errors - Acceptance criteria: (1) switching dimension updates tiles, chart and table together; (2) clicking a tile adds a removable filter; (3) CSV export downloads with zone and range in the file name; (4) RLS blocks other accounts; (5) layout works at 390px.