Template
Rinwell
An account settings page listing the third-party apps an AI assistant can read from. Connected apps sit at the top with Configure and overflow actions; available apps follow with a single Connect button, and a final button lets advanced users register a custom connection.
Connected-apps list in account settings · App screen: integrations · 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 Serif 4Headings: Source Serif 4 500, 28px settings title (similar to the observed transitional serif)
- InterBody: Inter 400, 16px body, line-height 1.5; 15px row subtitles in 400
Patterns
- narrow icon rail with settings text nav
- connected-then-available list ordering
- row with logo tile, name, subtitle and trailing action
- secondary Configure plus overflow menu for connected items
- de-emphasised names for unconnected items
- header-level Browse button
- add custom item button at list end
- warm paper background
States it is designed for
- loading: six skeleton rows
- no connections yet: list shows only available apps plus a short hint above
- connecting: button shows spinner and 'Connecting…'
- popup blocked: inline message with 'Open in new tab' fallback
- expired token: connected row shows a warning line 'Needs reconnect' and a Reconnect button
- error testing custom connection: inline field error with the failing status
- admin-disabled app: row shows 'Managed by your admin' and no action
Who it is for
- individual users of an AI assistant
- team members connecting work tools
- power users adding custom tool servers
Layout
- far-left icon rail (~28px wide) with sidebar toggle, new, search, library icons, download and avatar at the bottom
- settings title (serif, 28px) above a two-column body
- left text nav (~130px): General, Account, Privacy, Billing, Usage, Capabilities, Connections (active), Developer
- right column (~560px): section title with description and 'Browse connections' button, list of connection rows, 'Add custom connection' button
- below 768px the text nav becomes a horizontal scrollable tab row under the title and rows keep actions on the right
Palette
Quiet, bookish, trustworthy; a warm paper tone and a serif title make a technical list feel calm.
- bg
#faf9f5 - surface
#ffffff - selected
#efeee9 - text
#1f1e1b - muted
#6e6c66 - border
#d6d4cc - control-border
#8f8d86 - accent
#b6562e - danger
#b3261e
Every checked pair, measured again
| Sample | Where | Ratio | Needs |
|---|---|---|---|
| Aa | body text | 15.82:1 | 4.5:1 |
| Aa | muted / unconnected names | 4.98:1 | 4.5:1 |
| Aa | button label | 16.67:1 | 4.5:1 |
| Aa | active nav text | 14.35:1 | 4.5:1 |
| Aa | link / accent text | 4.57:1 | 4.5:1 |
| focus ring | 4.57:1 | 3:1 | |
| control border | 3.15:1 | 3:1 | |
| Aa | disconnect text in menu | 6.54: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
- Source Serif 4 500, 28px settings title (similar to the observed transitional serif)
- Body
- Inter 400, 16px body, line-height 1.5; 15px row subtitles in 400
Section titles 17px Inter 600. No uppercase. Buttons 14px 500 but never below 14px.
Spacing and imagery
Density: Airy; generous vertical rhythm. Grid: 8px base; rows 46px tall with 12px gaps. Container: content column max 560px, offset 80px from the rail. Radius: 8px buttons and nav pill, 10px logo tiles. Shadows: Buttons have a 1px border and a hairline 0 1px 1px shadow; menus a soft 0 8px 24px shadow.
Each row has a 28px rounded tile with a monochrome or two-tone app glyph (use generic lucide icons: file, mail, calendar, git-branch, pen-tool, globe); no illustrations.
Components
- IconRail
- SettingsNav
- SectionHeader with Browse button
- ConnectionRow (logo tile, name, optional capability subtitle, action)
- ConfigureDialog (permission scopes, account, disconnect)
- OverflowMenu
- BrowseConnectionsDialog (search, category chips, grid)
- AddCustomConnectionDialog (name, server URL, auth type)
- Toast
Interactions
- Connect starts an OAuth popup; on success the row moves to the connected group with a success toast
- Configure opens a dialog listing scopes with checkboxes and a Disconnect button in danger text
- Overflow menu: Reconnect, View permissions, Disconnect
- Browse opens a searchable directory dialog with category filter chips
- Add custom connection validates an https URL and tests it before saving
- Rows are keyboard-reachable; Enter on a row focuses its primary action
Data
Connector{id, slug, display_name, category (files|mail|calendar|code|design|web), capabilities[]}Connection{id, user_id, connector_id, status (connected|expired|revoked), scopes[], account_label, connected_at}CustomConnection{id, user_id, name, url, auth_type (none|oauth|token), created_at}
Guardrails
Experience
- Sort connected items first, then available ones alphabetically
- Use 'Configure' for connected items and 'Connect' for available ones; never both
- Unconnected names use the muted colour but must still pass 4.5:1
- Explain in one sentence what connecting allows, above the list
- Disconnect always asks for confirmation and states what data access ends
Accessibility
- Each action button's accessible name includes the app name (e.g. 'Connect calendar')
- List is a ul with li rows; status like 'Needs reconnect' is text, not colour
- OAuth popup launch announces 'Opening sign-in window' via aria-live
- Dialogs trap focus and return it to the triggering button
- Focus ring 2px accent with offset on all buttons
Security
- OAuth tokens are stored server-side only, encrypted, and never returned to the client
- Custom connection URLs must be https and are validated with zod; block private IP ranges server-side
- Request the least scopes needed and show them before consent
- RLS: users can only read and change their own connections
- Rate-limit connection tests to 5 per minute 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 **Rinwell**, the connections page in an AI assistant's settings. Users see which of their work apps the assistant can read from, connect new ones in one click, configure scopes for connected ones and add a custom connection by URL. Build the page with a thin icon rail and the settings text nav as shell, using six invented connectors.
### 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.
### Pages & layout
1. **Shell**: 28px icon rail on the far left (panel toggle, new, search, library, apps; download and avatar pinned bottom).
2. **Settings layout**: serif 'Settings' title, left text nav with eight items and a pill highlight on the active one.
3. **Connections section**: title, one-line description, 'Browse connections' outlined button right; connected rows (logo tile, name, optional 'Interactive' subtitle, Configure + overflow) then available rows (muted name, Connect); 'Add custom connection' outlined button after the list.
4. **Dialogs**: Browse directory, Configure, Add custom connection, Disconnect confirmation.
Responsive: nav becomes horizontal tabs under 768px; list rows keep a 44px minimum touch target.
### Design system
- Colors: `--bg: #faf9f5` (warm paper page), `--surface: #ffffff` (buttons and logo tiles), `--selected: #efeee9` (active nav pill), `--text: #1f1e1b` (primary text), `--muted: #6e6c66` (descriptions and unconnected names), `--border: #d6d4cc` (button outlines, decorative), `--control-border: #8f8d86` (input and button borders that must be visible), `--accent: #b6562e` (focus ring and links), `--danger: #b3261e` (disconnect text).
- Fonts: Source Serif 4 500, 28px settings title (similar to the observed transitional serif) for headings; Inter 400, 16px body, line-height 1.5; 15px row subtitles in 400 for body. Section titles 17px Inter 600. No uppercase. Buttons 14px 500 but never below 14px.
- Spacing: Airy; generous vertical rhythm. 8px base; rows 46px tall with 12px gaps. Container: content column max 560px, offset 80px from the rail.
- Radius: 8px buttons and nav pill, 10px logo tiles.
- Shadows: Buttons have a 1px border and a hairline 0 1px 1px shadow; menus a soft 0 8px 24px shadow.
- Motion: 120ms background fades on hover; Connect button shows an inline spinner; newly connected row slides up into the connected group over 200ms (disabled under reduced motion).
### Components & interactions
ConnectionRow is a flex row: 28px logo tile, text block (name 16px, optional subtitle 15px muted), then actions right-aligned. Connected rows show an outlined 'Configure' button and a square overflow button; available rows show a single outlined 'Connect' button. Buttons are white on the paper background with a visible border.
- Connect starts an OAuth popup; on success the row moves to the connected group with a success toast
- Configure opens a dialog listing scopes with checkboxes and a Disconnect button in danger text
- Overflow menu: Reconnect, View permissions, Disconnect
- Browse opens a searchable directory dialog with category filter chips
- Add custom connection validates an https URL and tests it before saving
- Rows are keyboard-reachable; Enter on a row focuses its primary action
### Data & state
Seed six connectors: a design canvas and a site builder (connected), plus file storage, mail, calendar and code hosting (available). TanStack Query caches the list; after OAuth completes, invalidate and move the row. Keep dialog state local; the Browse filter lives in the URL.
Entities: `Connector{id, slug, display_name, category (files|mail|calendar|code|design|web), capabilities[]}`; `Connection{id, user_id, connector_id, status (connected|expired|revoked), scopes[], account_label, connected_at}`; `CustomConnection{id, user_id, name, url, auth_type (none|oauth|token), created_at}`.
States to build and show in a dev-only state switcher:
- loading: six skeleton rows
- no connections yet: list shows only available apps plus a short hint above
- connecting: button shows spinner and 'Connecting…'
- popup blocked: inline message with 'Open in new tab' fallback
- expired token: connected row shows a warning line 'Needs reconnect' and a Reconnect button
- error testing custom connection: inline field error with the failing status
- admin-disabled app: row shows 'Managed by your admin' and no action
### Accessibility
- Each action button's accessible name includes the app name (e.g. 'Connect calendar')
- List is a ul with li rows; status like 'Needs reconnect' is text, not colour
- OAuth popup launch announces 'Opening sign-in window' via aria-live
- Dialogs trap focus and return it to the triggering button
- Focus ring 2px accent with offset on all buttons
Verified contrast: body text: #1f1e1b on #faf9f5 = 15.82:1; muted / unconnected names: #6e6c66 on #faf9f5 = 4.98:1; button label: #1f1e1b on #ffffff = 16.67:1; active nav text: #1f1e1b on #efeee9 = 14.35:1; link / accent text: #b6562e on #faf9f5 = 4.57:1; focus ring: #b6562e on #faf9f5 = 4.57:1; control border: #8f8d86 on #faf9f5 = 3.15:1; disconnect text in menu: #b3261e on #ffffff = 6.54:1.
### Security
- OAuth tokens are stored server-side only, encrypted, and never returned to the client
- Custom connection URLs must be https and are validated with zod; block private IP ranges server-side
- Request the least scopes needed and show them before consent
- RLS: users can only read and change their own connections
- Rate-limit connection tests to 5 per minute per user
RLS detail: `connections` and `custom_connections` allow select/insert/update/delete where `user_id = auth.uid()`; `connectors` is read-only for authenticated users. Token columns live in a separate table with no client select policy.
### Performance & SEO
Load connector logos as inline SVG sprites; prefetch the Configure dialog data on hover. Private route: noindex. Keep list render under 16ms for 50 connectors.
### Guardrails
- Sort connected items first, then available ones alphabetically
- Use 'Configure' for connected items and 'Connect' for available ones; never both
- Unconnected names use the muted colour but must still pass 4.5:1
- Explain in one sentence what connecting allows, above the list
- Disconnect always asks for confirmation and states what data access ends
- 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:
- Connecting an app moves it into the connected group and persists after reload
- Disconnect requires confirmation and removes stored tokens
- Custom connection rejects non-https and private-network URLs
- Expired connections show a reconnect path
- All rows and actions are operable by keyboard with visible focus