Template
Ostrel
A developer console page for a logo-image API. Users type any domain to preview the returned logo instantly, copy the ready-made image URL or embed tag, manage the public client ID and its domain restrictions, and watch monthly usage against quota.
Logo lookup API product page with snippet and usage · App screen: dashboard · 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 500 28px h1, -0.02em
- InterBody: Inter 400 16px / 1.5
Patterns
- product dashboard for a single API
- domain input bar with parameters button
- live preview tile
- copyable URL and embed snippets
- masked public key with reveal and copy
- warning line for missing restriction
- usage meter card with last refresh
States it is designed for
- preview loading shimmer
- logo not found (fallback monogram tile + note)
- invalid domain
- rate-limited preview
- no restrictions warning / restricted state with chip count
- usage near quota (amber) and over quota (red, upgrade CTA)
- usage fetch error with retry
Who it is for
- front-end developers adding company logos to apps
- product teams enriching CRM or directory data
Layout
- Console sidebar (same as other console pages) with product section and workspace section; credits counter top-right
- Centered column (max 440px): h1, two-line description with docs link
- Domain bar card: favicon + domain input + Parameters button (opens size/format/theme options)
- Preview card: large checkerboard-free grey tile with centered logo; below it two snippet rows (link icon + URL, code icon + img tag) each with copy button
- Public client ID card: key icon, title, Domain restrictions button; masked ID with reveal and copy; red warning line when unrestricted
- Usage card: title, last refresh indicator; rows Used this month, Remaining / quota with large numbers
- Mobile: sidebar drawer; snippet rows scroll horizontally inside their box
Palette
Crisp, utilitarian and instant - the page is a playground, docs and settings in one column.
- app bg
#f7f7f7 - surface
#ffffff - inset
#f2f2f2 - text
#1a1a1a - muted text
#6b6b6b - primary blue
#006ede - on primary
#ffffff - code accent
#7c3aed - warning red
#d92d20 - border
#e4e4e4 - focus ring
#0072e6
Every checked pair, measured again
| Sample | Where | Ratio | Needs |
|---|---|---|---|
| Aa | body text on white | 17.40:1 | 4.5:1 |
| Aa | muted text on inset | 4.76:1 | 4.5:1 |
| Aa | Upgrade label on blue | 4.90:1 | 4.5:1 |
| Aa | highlighted parameter in snippet on inset | 5.09:1 | 4.5:1 |
| Aa | warning text on white | 4.83:1 | 4.5:1 |
| focus ring on app bg | 4.31:1 | 3:1 | |
| Aa | docs link on app bg | 4.57: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
- Inter 500 28px h1, -0.02em
- Body
- Inter 400 16px / 1.5
JetBrains Mono 15px for URLs, IDs and snippets with syntax-tinted parameters; usage numbers 28px tabular.
Spacing and imagery
Comfortable; 4px base, 16px between cards, 16px card padding, 8px inset rows; radius 12px cards, 8px inset rows; soft shadow 0 1px 2px rgba(0,0,0,.04).
The returned logo is the only image; icons are 16px outline.
Components
- ConsoleSidebar
- CreditsCounter
- DomainInputBar
- ParametersPopover (size, format, theme, fallback)
- LogoPreviewTile
- SnippetRow with CopyButton
- PublicClientIdCard (masked, reveal, copy)
- DomainRestrictionsDialog
- UsageCard with RefreshIndicator
Interactions
- Typing a domain debounces 400ms and updates preview and snippets; invalid domains show inline error
- Parameters popover changes query params in snippets with highlighted diff
- Copy buttons swap to a check and announce 'Copied'
- Reveal toggles the masked ID for 30s then re-masks
- Domain restrictions dialog adds allowed referrer domains as chips; saving removes the warning
- Usage auto-refreshes every 60s and on focus
Data
PublicClient{id, workspace_id, client_id, allowed_domains[], created_at}UsageMonth{workspace_id, month, used, quota}LogoRequest{params: size, format (png|svg|webp), theme (light|dark), fallback (monogram|404)}
Guardrails
Experience
- Let users try the API before reading docs
- Make copy one click for each snippet format
- Warn plainly when the key is unrestricted, with a direct fix button
- Show quota as used and remaining, not just a bar
- Keep the page to one scannable column
Accessibility
- Preview image alt is 'Logo preview for <domain>'
- Snippet rows are readonly inputs with labels so they can be selected and read
- Masked ID has a visually hidden 'masked' note; reveal button has aria-pressed
- Warning uses an icon plus text
- Usage numbers include units in their accessible names
Security
- Public client IDs are not secrets but must be restrictable by referrer domain; enforce on the edge
- Secret API keys never appear on this page
- Validate domain input (hostname only) to prevent SSRF-style misuse of the preview
- Rate-limit preview requests per session
- RLS by workspace on clients and usage
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 **Ostrel**, the product page for a logo-image API inside a developer console: domain preview, copyable snippets, public client ID with domain restrictions, and a usage card. Use fictional domains and invented logos (monograms) for mock data.
### Stack
Use React 18, TypeScript, Vite, Tailwind CSS, shadcn/ui, Radix, lucide-react, TanStack Query, react-hook-form, zod, Supabase. Use Supabase for Auth, Postgres (row-level security on every table) and Storage where noted; keep only the anon key in the browser and run privileged work in Edge Functions.
### Pages & layout
1. **/logo-lookup**: this page.
2. Shared console shell pages (overview, API keys, usage) as stubs.
Regions, in order:
- Console sidebar (same as other console pages) with product section and workspace section; credits counter top-right
- Centered column (max 440px): h1, two-line description with docs link
- Domain bar card: favicon + domain input + Parameters button (opens size/format/theme options)
- Preview card: large checkerboard-free grey tile with centered logo; below it two snippet rows (link icon + URL, code icon + img tag) each with copy button
- Public client ID card: key icon, title, Domain restrictions button; masked ID with reveal and copy; red warning line when unrestricted
- Usage card: title, last refresh indicator; rows Used this month, Remaining / quota with large numbers
- Mobile: sidebar drawer; snippet rows scroll horizontally inside their box
### Design system
- Colors: `--app-bg: #f7f7f7` (app bg), `--surface: #ffffff` (surface), `--inset: #f2f2f2` (inset), `--text: #1a1a1a` (text), `--muted-text: #6b6b6b` (muted text), `--primary-blue: #006ede` (primary blue), `--on-primary: #ffffff` (on primary), `--code-accent: #7c3aed` (code accent), `--warning-red: #d92d20` (warning red), `--border: #e4e4e4` (border), `--focus-ring: #0072e6` (focus ring).
- Fonts: Inter 500 28px h1, -0.02em for headings; Inter 400 16px / 1.5 for body. JetBrains Mono 15px for URLs, IDs and snippets with syntax-tinted parameters; usage numbers 28px tabular.
- Spacing, radius and shadows: Comfortable; 4px base, 16px between cards, 16px card padding, 8px inset rows; radius 12px cards, 8px inset rows; soft shadow 0 1px 2px rgba(0,0,0,.04).
- Motion: 150-200 ms ease-out for hover, focus and overlay transitions; overlays fade and scale from 98% to 100%; everything collapses to an instant change under prefers-reduced-motion.
- Mood: Crisp, utilitarian and instant - the page is a playground, docs and settings in one column. Imagery: The returned logo is the only image; icons are 16px outline.
### Components & interactions
Build these components: ConsoleSidebar; CreditsCounter; DomainInputBar; ParametersPopover (size, format, theme, fallback); LogoPreviewTile; SnippetRow with CopyButton; PublicClientIdCard (masked, reveal, copy); DomainRestrictionsDialog; UsageCard with RefreshIndicator.
- Typing a domain debounces 400ms and updates preview and snippets; invalid domains show inline error
- Parameters popover changes query params in snippets with highlighted diff
- Copy buttons swap to a check and announce 'Copied'
- Reveal toggles the masked ID for 30s then re-masks
- Domain restrictions dialog adds allowed referrer domains as chips; saving removes the warning
- Usage auto-refreshes every 60s and on focus
### Data & state
Model: `PublicClient{id, workspace_id, client_id, allowed_domains[], created_at}`; `UsageMonth{workspace_id, month, used, quota}`; `LogoRequest{params: size, format (png|svg|webp), theme (light|dark), fallback (monogram|404)}`.
Preview calls the public image endpoint with the workspace's client ID. Snippets are built from a single `buildLogoUrl(params)` function. Usage comes from a daily-aggregated table.
States to implement and demo:
- preview loading shimmer
- logo not found (fallback monogram tile + note)
- invalid domain
- rate-limited preview
- no restrictions warning / restricted state with chip count
- usage near quota (amber) and over quota (red, upgrade CTA)
- usage fetch error with retry
### Accessibility
- Preview image alt is 'Logo preview for <domain>'
- Snippet rows are readonly inputs with labels so they can be selected and read
- Masked ID has a visually hidden 'masked' note; reveal button has aria-pressed
- Warning uses an icon plus text
- Usage numbers include units in their accessible names
- Body text is 16px with line-height 1.5 (15px only inside dense tables), nothing renders below 12px, weights of 300 or lighter appear only at 24px and above, and uppercase is limited to short labels with at least 0.05em tracking.
Verified contrast: body text on white: #1a1a1a on #ffffff = 17.40:1; muted text on inset: #6b6b6b on #f2f2f2 = 4.76:1; Upgrade label on blue: #ffffff on #006ede = 4.90:1; highlighted parameter in snippet on inset: #7c3aed on #f2f2f2 = 5.09:1; warning text on white: #d92d20 on #ffffff = 4.83:1; focus ring on app bg: #0072e6 on #f7f7f7 = 4.31:1; docs link on app bg: #006ede on #f7f7f7 = 4.57:1.
### Security
- Public client IDs are not secrets but must be restrictable by referrer domain; enforce on the edge
- Secret API keys never appear on this page
- Validate domain input (hostname only) to prevent SSRF-style misuse of the preview
- Rate-limit preview requests per session
- RLS by workspace on clients and usage
RLS: `public_clients` - members select, admins update `allowed_domains`; `usage_months` - members select; writes via service role only.
### Performance & SEO
Cache previews by domain+params; use the image CDN with immutable caching. Noindex console.
### Guardrails
- Let users try the API before reading docs
- Make copy one click for each snippet format
- Warn plainly when the key is unrestricted, with a direct fix button
- Show quota as used and remaining, not just a bar
- Keep the page to one scannable column
- Use the product name Ostrel and fresh, generic copy throughout; all people, companies, amounts and IDs are invented, and no third-party brand, logo or wordmark appears.
- Keep components small and typed (no `any`), and surface every failure visibly instead of swallowing it.
Acceptance criteria:
- [ ] Preview and snippets update from one source of truth
- [ ] Domain restrictions remove the warning
- [ ] Usage states (normal, near, over) render
- [ ] Copy works with feedback
- [ ] 390px layout works