Editor and roles
The admin is at /admin/. Accounts and sessions are the site’s own (src/lib/auth, with Better
Auth), in its database.
profiles.role is one of:
| Role | Access |
|---|---|
editor |
Content, templates, media, forms and Compose |
admin |
Everything editors have, plus site settings, redirects and users |
viewer |
No access |
Admin-only pages are listed in ADMIN_ONLY (src/middleware.ts); settings writes are admin-only in
the site’s policies (src/lib/db/policies.ts). Admins manage users at /admin/users/: roles and invitations, with Resend invitation for anyone invited who hasn’t set a password yet, and Delete (not your own account; what they made stays).
Editors set their password at /admin/set-password/, where invitations (7 days) and password links
(Forgot password on the sign-in page; an hour) land; setting it signs them in and signs the account
out everywhere else. After 10 wrong passwords for an address (or 30 from one visitor) in 15 minutes,
sign-in asks them to wait; password links go out at most 3 an hour per address.
Admin colors and logo
Section titled “Admin colors and logo”Settings > Admin sets the admin’s colors for everyone who signs in: accent, text, menu bar and
background (settings.site.admin_theme, src/lib/admin-theme.ts), and a logo for the menu bar. The
logo replaces the site name there, or sits beside it with Show the site name beside it (on phones
only the logo shows); it is shown up to 32px tall, so pick one that reads on the menu bar’s color. The
settings API stores its media id and makes its URL from the media row. Colors and logo change on the
screen as they are picked; Save keeps them. The admin’s styles use only role tokens (--color-admin-* in
src/styles/tailwind.css, as Tailwind colors such as text-admin-muted and bg-admin-accent), and
every admin page writes the saved colors over them (AdminTheme.astro), with the shades made from
them: a darker accent, a soft background, and the menu bar’s text, dark on a light bar. Puck’s own
blue scale is made from the accent (src/styles/admin.css). The accent and text carry white text, so
the screen warns when white on them would be hard to read. The admin uses the system font. Admin
colors and logo are part of the site settings, so a settings sync copies them (sync Files too, or
the logo’s image is missing on the other copy).
The page editor
Section titled “The page editor”src/puck/Editor.tsx renders blocks through the same string renderer as the site, inside Puck
(BlockView.tsx parses the HTML to React; slots become the block’s inner wrapper element). What you
see while editing is the site’s own markup.
The left rail has Blocks (and Patterns), Outline and an accessibility check. Blocks
with types are offered only on those entry types. A Compose panel docks beside the canvas
(Compose).
Link picker
Section titled “Link picker”Rich text toolbars (Link: page blocks and emails) and link fields (Find: Button, Image, Hero, any
field of type url in a type’s or a site block’s fields, Settings > Menu’s links, a linked pattern’s links)
open the link picker (src/puck/LinkPicker.tsx) instead of a browser prompt:
- Typing searches entries of types with pages by title (drafts marked; the latest edited when empty) and links to their address.
- An address typed in is used as is (
typedAddress,src/lib/link-address.ts): web addresses (a bare domain getshttps://), email addresses (mailto:), phone numbers (tel:), paths, anchors and merge tags. - Media library links any file.
- In rich text, Open in a new tab (ticked for other sites) adds
target="_blank" rel="noopener"; with nothing selected the entry’s title or file’s name becomes the linked words; with the cursor in a link it edits that link, with Remove link. Emails get full addresses for the site’s own pages.
Copy and paste styles
Section titled “Copy and paste styles”Every block’s settings end with Copy styles and Paste styles (src/puck/StyleCopy.tsx,
src/lib/content/style-copy.ts). The copy is kept in the browser (localStorage), so it pastes into
another page, template, part or pattern.
- Any block takes the shared style settings (
SHARED_STYLE:style,width,className,formStyle). - A block of the same type also takes its look settings (
LOOK: alignment, gap, overlay, height, size, columns, display…). - Each setting the copy covers is set to its value or cleared; content is never copied. The paste is an ordinary, undoable edit.
- Blocks inside a linked pattern, and the linked pattern itself, don’t offer it: their styles are the pattern’s.
Saving and publishing
Section titled “Saving and publishing”- Save draft keeps changes to a published page aside (
entry_drafts) while the live page stays unchanged. Unpublished pages save in place as drafts. - Publish / Publish changes makes them live.
- Discard changes and Unpublish are in the header (
PUT /api/admin/entries/:idwithaction). - Preview opens
/admin/preview/<id>/with the editor’s current state (POST) or the saved draft (GET), rendered like the site with a preview bar and noindex. - If someone else saved the page (or template) since you opened it, your save is refused and the editor asks whether to save over their version; cancel and reload to see theirs first.
- Autosave: a page’s content and settings save as a draft 3 seconds after the last edit (at most 30 seconds after the first unsaved one), as Save draft does, so a published page’s live version stays as it is. Autosaves don’t clear the page cache, and a placeholder address stays one until a manual save. If someone else saved meanwhile, autosave stops and the next manual save asks. Templates and layout mode don’t autosave: their changes apply to every page using them.
- Leaving with unsaved changes: a link out of the editor (such as ← back to the list) asks Save your changes?: save (as Save draft, or Save & apply for templates and layout mode) and go, leave without saving, or stay. Reloading, closing the tab or the browser’s Back get the browser’s own prompt. Templates and layout mode show “Unsaved changes” in the header too.
- Revisions (left rail): the page’s saved versions, to preview or restore. Each manual save
(Save draft, Publish, Unpublish) is a checkpoint; autosaves between them keep one version per
ten minutes of editing (
src/lib/admin/revisions.ts). Checkpoints only hides the autosaves. Restore loads a version into the editor (Undo takes it back) with its page settings: in content mode its content and the template’s other content areas, then autosaved as a draft; in layout mode the template as that version saved it (versions saved with another template are preview only), kept with Save & apply, which changes every page using the template.
A published entry whose address changes gets a redirect from the old one automatically.
Accessibility check
Section titled “Accessibility check”A11yPanel.tsx lists problems on the page. Those a person has to judge (warnings, and text over an
image, whose contrast can’t be measured) can be marked as checked with a note. The marks live in the
document’s root props (a11y), save on their own as they are made (PUT /api/admin/a11y; not an
unsaved edit), and lapse when the text or image they were about changes.
Settings > Accessibility can make publishing wait for the check: Publish and Publish changes, on an entry of any type with a page, first run it afresh. If anything is left open (a problem not fixed, or a warning not marked as checked), the publish is held and a dialog offers Show the problems (the A11y panel) or Publish anyway with an optional reason. A publish made anyway keeps a note in Revisions with that version: what was left open, and why. Bulk Publish in the content list skips entries with a page while this is on, since the check runs in the editor. Templates’ Save & apply isn’t held.
Editor bar on the site
Section titled “Editor bar on the site”Pages are cached at the CDN, so the editor bar signed-in editors see on the public site is added in
the browser (public/assets/js/editor-bar.js, /api/admin/me).