Template
Pailvault
The storage tab of an account's repositories settings on a model-and-dataset hub. When nothing is stored yet it shows a blurred, greyed preview of what the usage breakdown will look like with a small 'nothing stored yet' chip on top, so users understand the feature before they need it.
Storage usage tab with blurred ghost-preview empty state · App screen: empty state · 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, 20px
- Source Sans 3Body: Source Sans 3 400 16px/1.5
Patterns
- account settings sidebar with long flat list
- Overview / Storage tab pair
- blurred ghost preview behind empty label
- donut chart plus category list
- isometric usage chart
- NEW badge on a nav item
States it is designed for
- empty (ghost preview + chip)
- populated
- near quota (amber banner with manage link)
- over quota (red banner, uploads blocked)
- loading (skeleton donut and bars)
- error with retry
- private-only usage
Who it is for
- ML practitioners managing quotas
- team admins watching storage spend
Layout
- global top bar (logo, search, product nav, avatar)
- left settings column (~240px): account card (avatar, name, handle chip) then a flat list of ~20 settings links, active 'Repositories' with grey fill
- main: section title, tab row (Overview, Storage active with underline), docs link right
- Storage tab: left a donut chart and a four-row category list (models, datasets, apps, buckets), right an isometric stacked bar chart, all blurred and desaturated when empty
- centre chip over the blur: 'No storage used yet'
- populated: same layout in full colour with values and a public/private toggle
- mobile: settings list becomes a select; chart pair stacks
Palette
Informative and honest; the ghost preview teases without pretending there is data.
- page background
#ffffff - sidebar active fill
#f3f4f6 - primary text
#111827 - secondary text
#5f6672 - tab underline / focus
#1f2937 - chart models
#2f6fdf - chart datasets
#c2410c - chart apps
#7c3aed - chart buckets
#0f766e - ghost preview grey
#c2c3c6 - NEW badge text
#2d5bd7
Every checked pair, measured again
| Sample | Where | Ratio | Needs |
|---|---|---|---|
| Aa | body text | 17.74:1 | 4.5:1 |
| Aa | muted text | 5.78:1 | 4.5:1 |
| Aa | nav text on active fill | 16.12:1 | 4.5:1 |
| Aa | NEW badge text | 5.85:1 | 4.5:1 |
| chart: models | 4.71:1 | 3:1 | |
| chart: datasets | 5.18:1 | 3:1 | |
| chart: apps | 5.70:1 | 3:1 | |
| chart: buckets | 5.47:1 | 3:1 | |
| focus / tab underline | 14.68: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, 20px
- Body
- Source Sans 3 400 16px/1.5
Handle chip in JetBrains Mono 12px; badge 12px uppercase 600, 0.06em tracking; chart numbers tabular.
Spacing and imagery
Comfortable: settings list rows 36px; main padding 24px; chart area min-height 320px; chip 12px radius with shadow 0 2px 8px rgba(0,0,0,0.08).
Charts only: donut, isometric 3D-looking bars drawn with simple SVG polygons. When empty they are blurred (8px) and greyscale at 40% opacity.
Components
- SettingsSidebar
- AccountCard
- Tabs
- StorageDonut
- CategoryList
- IsometricBars
- GhostOverlay with EmptyChip
- VisibilityToggle (all/public/private)
Interactions
- tab switch updates the URL (?tab=storage)
- hovering a donut segment highlights its list row and bar
- visibility toggle filters the numbers
- the ghost preview is non-interactive and not focusable
- docs link opens the quota guide
Data
StorageUsage{account_id, category (models|datasets|apps|buckets), visibility (public|private), bytes, updated_at}Quota{account_id, limit_bytes, plan}
Guardrails
Experience
- Make the empty chip the only crisp element over the blurred preview.
- Use the exact same layout for empty and populated so nothing jumps on first upload.
- Show absolute sizes with units (MB/GB) and percent of quota together.
- Pair each chart colour with a text label and value in the list.
- Warn at 80% and block at 100% with a clear next step.
Accessibility
- Ghost preview is aria-hidden; the chip text is the accessible content for the empty state.
- Donut and bars have a visually hidden table with the same numbers.
- Tabs follow the ARIA tabs pattern with arrow keys.
- Chart colours each reach 3:1 against white and are never the only cue.
- The settings list is a nav with aria-current.
Security
- RLS: usage and quota rows readable only by the account owner or org admins.
- Usage is computed by a server job; clients cannot write usage rows.
- Do not expose other accounts' sizes through search or public profile endpoints.
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 **Pailvault**, the storage usage tab inside account settings for a hub that hosts models, datasets, apps and file buckets. It shows used storage by category and visibility; when nothing is stored, it shows a blurred ghost of the same charts with a single 'No storage used yet' chip.
### Stack
React 18 + TypeScript + Vite, Tailwind CSS, shadcn/ui (Tabs, ToggleGroup, Alert), lucide-react, Recharts for the donut, hand-drawn SVG for the isometric bars, TanStack Query. Supabase Auth and Postgres with a scheduled function that recomputes usage.
### Pages & layout
1. **Settings shell**: top bar, account card, flat settings nav.
2. **/settings/repositories?tab=overview|storage**: this screen.
3. Responsive: nav becomes a select <768px; charts stack.
### Design system
- Colors: `--bg: #ffffff` (page background), `--nav-active: #f3f4f6` (sidebar active fill), `--fg: #111827` (primary text), `--muted: #5f6672` (secondary text), `--accent: #1f2937` (tab underline / focus), `--c-models: #2f6fdf` (chart models), `--c-datasets: #c2410c` (chart datasets), `--c-apps: #7c3aed` (chart apps), `--c-buckets: #0f766e` (chart buckets), `--ghost: #c2c3c6` (ghost preview grey), `--badge: #2d5bd7` (NEW badge text).
- Fonts: Source Sans 3 600, 20px for headings; Source Sans 3 400 16px/1.5 for body. Handle chip in JetBrains Mono 12px; badge 12px uppercase 600, 0.06em tracking; chart numbers tabular.
- Spacing: Comfortable: settings list rows 36px; main padding 24px; chart area min-height 320px; chip 12px radius with shadow 0 2px 8px rgba(0,0,0,0.08).
- Radius: 8px nav fill, 12px chip and cards.
- Shadows: empty chip only.
- Ghost treatment: filter blur(8px) grayscale(1) opacity(.4) on the chart container.
- Motion: 200ms segment highlight; donut draws in 400ms once, skipped under reduced motion.
### Components & interactions
SettingsSidebar, AccountCard, Tabs, StorageDonut, CategoryList, IsometricBars, GhostOverlay, EmptyChip, VisibilityToggle, QuotaBanner.
Interactions: tab switch updates the URL (?tab=storage); hovering a donut segment highlights its list row and bar; visibility toggle filters the numbers; the ghost preview is non-interactive and not focusable; docs link opens the quota guide.
States to build: empty (ghost preview + chip); populated; near quota (amber banner with manage link); over quota (red banner, uploads blocked); loading (skeleton donut and bars); error with retry; private-only usage.
### Data & state
Query `storage_usage` grouped by category and visibility; compute totals and quota percent client-side. Empty = total bytes 0. Seed two accounts: one empty, one with 3.2 GB across four categories.
Model: `StorageUsage{account_id, category (models|datasets|apps|buckets), visibility (public|private), bytes, updated_at}`; `Quota{account_id, limit_bytes, plan}`.
### Accessibility
Ghost preview is aria-hidden; the chip text is the accessible content for the empty state. Donut and bars have a visually hidden table with the same numbers. Tabs follow the ARIA tabs pattern with arrow keys. Chart colours each reach 3:1 against white and are never the only cue. The settings list is a nav with aria-current.
Verified contrast: body text: #111827 on #ffffff = 17.74:1; muted text: #5f6672 on #ffffff = 5.78:1; nav text on active fill: #111827 on #f3f4f6 = 16.12:1; NEW badge text: #2d5bd7 on #ffffff = 5.85:1; chart: models: #2f6fdf on #ffffff = 4.71:1; chart: datasets: #c2410c on #ffffff = 5.18:1; chart: apps: #7c3aed on #ffffff = 5.7:1; chart: buckets: #0f766e on #ffffff = 5.47:1; focus / tab underline: #1f2937 on #ffffff = 14.68:1.
### Security
RLS: usage and quota rows readable only by the account owner or org admins. Usage is computed by a server job; clients cannot write usage rows. Do not expose other accounts' sizes through search or public profile endpoints. RLS per table: `storage_usage` select where `account_id` is the user's account or an org they administer; no client insert/update; `quotas` select same rule, update only by service role.
### Performance & SEO
Lazy-load Recharts only for the storage tab. Settings routes noindex.
### Guardrails
- Make the empty chip the only crisp element over the blurred preview.
- Use the exact same layout for empty and populated so nothing jumps on first upload.
- Show absolute sizes with units (MB/GB) and percent of quota together.
- Pair each chart colour with a text label and value in the list.
- Warn at 80% and block at 100% with a clear next step.
- Write all copy fresh; use invented people, companies and numbers only. No real brands, logos, wordmarks or third-party product names anywhere in the UI or seed data.
- Do not trace or copy any existing product's layout assets, icons or illustrations; draw generic ones.
- Acceptance criteria:
- [ ] Empty account shows the blurred preview and chip
- [ ] Populated account shows matching numbers in charts and list
- [ ] Visibility toggle filters values
- [ ] Near/over quota banners appear at 80%/100%
- [ ] Screen readers get the data table