Template
Bookwren
A block-style writing editor that feels like a modern docs tool: type '/' for headings, lists, quotes, code, images and to-dos, select text for formatting, and ask AI to continue or improve what you've written. It autosaves locally and optionally to a backend, making it a drop-in editor component or the core of a writing app.
Block-based rich-text editor with slash menu and AI autocomplete · 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
Readex Pro is a geometric sans with generous proportions that reads well at 16px/1.75 for long writing, and Google Sans Code keeps code blocks clean beside it.
- Readex ProHeadings: title 30px 700, H1 24px, H2 20px, H3 18px
- Readex ProBody: prose 16px/1.75 400, menu titles 14px 500, descriptions 12-13px
- Google Sans CodeFigures and code: code 14px
Patterns
- centred paper-like editor card on white
- slash command menu with icon tiles, titles and descriptions
- AI 'continue writing' as the first slash command
- inline ghost-text autocomplete
- floating bubble menu on text selection
- save status chip in the top-right corner
- drag handle beside blocks
- markdown shortcuts (#, -, >, ```)
States it is designed for
- Empty document: placeholder 'Type / for commands' on the first line
- Saving / saved / save failed (chip turns red with Retry)
- AI streaming with Stop; AI error (rate limited, provider down) inline in the AI panel
- Image uploading, upload failed (retry/remove), unsupported file type
- Offline: edits kept locally, chip says 'Offline, saved on this device'
- Very long documents stay responsive (lazy node views)
- Loading an existing doc: skeleton lines
Who it is for
- developers embedding a rich editor in their product
- writers and note-takers
- teams building docs or knowledge-base tools
Layout
- Page: white canvas; centred editor card max-width 1024px with 1px border, 8px radius and soft shadow on desktop; full-bleed on mobile
- Top-right of card: small grey 'Saved' / 'Unsaved' chip
- Editor body: 48px padding; first block a 30px bold title, then paragraphs and blocks
- Slash menu: floating 280px panel below the caret with a scrollable list; each item a 40px square icon tile, bold title and one-line description; active item highlighted
- Bubble menu: dark or white floating toolbar above selection (AI, text type, link, bold, italic, underline, strike, code, colour)
- Ghost completion text in muted colour after the caret while AI streams
- Mobile: card loses border and padding reduces to 20px; slash menu becomes a bottom sheet
Palette
Clean, focused and quietly smart. Monochrome chrome keeps attention on the writing; purple marks the AI features.
- page / editor surface
#ffffff - menu hover / chip fill
#f5f5f5 - primary text
#0a0a0a - muted text (descriptions, ghost text, chip)
#707070 - card border (decorative)
#e5e5e5 - icon tile / input border
#949494 - AI accent
#7c3aed - AI tint
#f5f3ff - link
#2563eb
Every checked pair, measured again
| Sample | Where | Ratio | Needs |
|---|---|---|---|
| Aa | body text on editor | 19.80:1 | 4.5:1 |
| Aa | menu title on hover fill | 18.16:1 | 4.5:1 |
| Aa | muted description on hover fill | 4.54:1 | 4.5:1 |
| Aa | AI accent text on white | 5.70:1 | 4.5:1 |
| Aa | AI accent on tint | 5.20:1 | 4.5:1 |
| Aa | link on white | 5.17:1 | 4.5:1 |
| icon tile border | 3.03: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
- Readex Pro 700, 30px title, 24px H1 blocks, 20px H2, 18px H3
- Body
- Readex Pro 400 16px/1.75 for prose; menu titles 14px 500, descriptions 12-13px; code in Google Sans Code 14px
Generous line-height for reading; the observed 'Saved' chip text was too light, use #707070.
Spacing and imagery
Comfortable reading measure (~70ch); 4px grid; menu items 8px padding; block gap 12px. Radius 8px card and menus, 6px icon tiles and chips. Shadows: card `0 1px 3px rgb(0 0 0 / 0.08)`, menus `0 8px 24px rgb(0 0 0 / 0.12)`.
Only user-inserted images (rounded 8px, with captions) and lucide icons in menu tiles; a sparkle icon for AI.
Components
- EditorCard
- SaveStatusChip
- SlashCommandMenu
- CommandItem (icon tile, title, description)
- BubbleMenu (formatting toolbar)
- AISelector (continue, improve, shorten, lengthen, fix grammar, custom prompt)
- GhostCompletion
- BlockDragHandle
- ImageUploadBlock
- TaskListBlock
- CodeBlock with language select
- LinkPopover
Interactions
- Type '/' to open the slash menu; filter by typing; Up/Down to move, Enter to insert, Escape to close
- '++' or the Continue writing command streams AI text as ghost text; Tab accepts, Escape discards
- Select text to open the bubble menu; AI actions show a result preview with Replace, Insert below, Discard
- Markdown shortcuts convert on type (# heading, - list, [] task, > quote, ``` code)
- Drag blocks by the handle; Alt+Up/Down moves the current block
- Paste or drop images to upload with a progress placeholder
- Autosave debounced 750ms; chip toggles Unsaved to Saving to Saved
Data
Document{id, owner_id, title, content (JSON), updated_at, created_at}Asset{id, document_id, owner_id, path, mime, size, created_at}AiUsage{id, user_id, action (continue|improve|shorten|lengthen|fix|custom), tokens, created_at}
Guardrails
Experience
- The slash menu shows icon, title and a one-line description for every command
- AI output always previews before replacing user text; never overwrite silently
- Always show save status; never lose text on refresh
- Keep the toolbar hidden until selection to preserve focus
- AI commands are grouped first and visually tagged with the accent colour
Accessibility
- Editor is a labelled textbox (aria-multiline) and blocks use semantic HTML (h1-h3, ul, ol, blockquote, pre)
- Slash menu is a listbox with aria-activedescendant; bubble menu is a toolbar with roving tabindex
- Ghost completion is announced ('Suggestion available, press Tab to accept')
- Muted descriptions and chip text use #707070 (4.54:1 on the hover fill)
- All shortcuts have menu equivalents; images require alt text on insert
Security
- Sanitise pasted HTML to an allow-listed schema; never render raw HTML from content
- AI route is server-side, authenticated and rate-limited per user; prompts capped in length
- RLS on documents and assets: owner-only select/insert/update/delete
- Uploads: validate mime and size (images only, <= 5 MB), store in a private bucket, serve via signed URLs
- Strip link protocols other than http, https and mailto
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 **Bookwren**, a block-style rich-text editor with a slash command menu, a selection toolbar and AI writing help (continue, improve, shorten, lengthen, fix grammar, custom prompt). It must work as an embeddable React component and as a small writing app with autosave and image uploads. ### Stack Next.js (App Router) + React + TypeScript. Tiptap (ProseMirror) with StarterKit, Placeholder, TaskList, Image, Link, CodeBlock, Highlight and a custom slash-command extension. Tailwind CSS, Radix (Popover, DropdownMenu), lucide-react and zod. A server route streams completions from a configurable LLM provider. Supabase provides Auth, Postgres (documents) and Storage (images). ### Pages & layout 1. **Editor (`/d/[id]`)**: a white page with a centred card (max 1024px, 1px border, 8px radius, soft shadow) and a "Saved" chip top-right. Inside, 48px padding, a 30px bold title line and then the content blocks. Typing `/` opens a floating menu of commands: Continue writing (AI, first), Text, Heading 1-3, To-do list, Bullet list, Numbered list, Quote, Code, Image and Divider. Each has a 40px icon tile, a title and a description. Selecting text opens a bubble toolbar (Ask AI, Turn into, Link, B, I, U, S, code, colour). 2. **Documents (`/`)**: a list of your docs with title, updated time and a New document button. 3. **Responsive**: on mobile the card becomes full-bleed with 20px padding, the slash menu becomes a bottom sheet and the bubble toolbar docks above the keyboard. ### Design system - Colors: `--bg: #ffffff`, `--hover: #f5f5f5`, `--fg: #0a0a0a`, `--muted: #707070`, `--border: #e5e5e5` (decorative), `--control: #949494`, `--ai: #7c3aed`, `--ai-tint: #f5f3ff`, `--link: #2563eb`. - Fonts: Readex Pro; title 700 at 30px; H1 24px, H2 20px, H3 18px; prose 400 at 16px/1.75; menu titles 500 at 14px; descriptions 13px; Google Sans Code 14px for code. - Spacing: 4px base; block gap 12px; menu item padding 8px; reading width about 70ch. - Radius: 8px card and menus; 6px tiles, chips and code blocks. - Shadows: card `0 1px 3px rgb(0 0 0 / 0.08)`; menus `0 8px 24px rgb(0 0 0 / 0.12)`. - Motion: menus fade and scale from 98% over 120ms; ghost text fades in; none under reduced motion. ### Components & interactions EditorCard, SaveStatusChip, SlashCommandMenu and CommandItem (type to filter; Up/Down, Enter and Escape), BubbleMenu, AISelector (actions listed above plus a free-text prompt; shows a preview with Replace, Insert below, Discard), GhostCompletion (typing `++` or choosing Continue writing streams ghost text; Tab accepts, Escape discards), BlockDragHandle (Alt+Up/Down), ImageUploadBlock (paste or drop, progress placeholder), TaskListBlock, CodeBlock (language select), LinkPopover. Markdown input rules convert as you type. Autosave debounces 750ms to local storage and the server. ### Data & state `documents(id, owner_id, title, content jsonb, updated_at, created_at)`, `assets(id, document_id, owner_id, path, mime, size, created_at)`, `ai_usage(id, user_id, action, tokens, created_at)`. The editor state is Tiptap JSON. Keep a local draft in IndexedDB (wrapped in try/catch) and reconcile on load by picking the newest `updated_at`. Seed one welcome document with invented example content. ### Accessibility The editor has `role="textbox"`, `aria-multiline="true"` and a label. Blocks render semantic elements. The slash menu is a listbox using `aria-activedescendant`; the bubble menu is a toolbar with roving tabindex and named buttons. Ghost suggestions are announced. Image insert prompts for alt text. The focus ring is 2px `--ai` on menus. Keyboard shortcuts are listed in a help dialog (`Ctrl+/`). Verified contrast: body text on editor: #0a0a0a on #ffffff = 19.8:1; menu title on hover fill: #0a0a0a on #f5f5f5 = 18.16:1; muted description on hover fill: #707070 on #f5f5f5 = 4.54:1; AI accent text on white: #7c3aed on #ffffff = 5.7:1; AI accent on tint: #7c3aed on #f5f3ff = 5.2:1; link on white: #2563eb on #ffffff = 5.17:1; icon tile border: #949494 on #ffffff = 3.03:1. ### Security Sanitise pasted HTML against the Tiptap schema and never render stored HTML directly. Links allow only http, https and mailto. The AI route requires a session, caps prompt length (4,000 characters of context), rate-limits per user (for example 30 requests per 10 minutes) and logs usage. Enable RLS on `documents`, `assets` and `ai_usage` with owner-only access (`owner_id = auth.uid()` / `user_id = auth.uid()`). Uploads accept image mime types up to 5 MB in a private bucket, served via short-lived signed URLs. Provider keys stay server-side. ### Performance & SEO Code-split the editor and load it client-side only. Lazy-load the AI selector and code highlighting. Keep ProseMirror transactions cheap and avoid re-rendering the whole card on each keystroke. Editor routes are `noindex`; a public read-only share view can be indexed with title and description. ### Guardrails - Original UI copy; example content invented. - No provider or editor-brand names in the interface. - AI never edits text without an explicit accept. - Acceptance criteria: - [ ] Slash menu inserts every block type by keyboard alone - [ ] Continue writing streams ghost text; Tab accepts and Escape discards - [ ] Refresh mid-edit loses nothing; the save chip reflects reality - [ ] Other users cannot read or modify your documents or images - [ ] Pasted script tags and javascript: links are stripped