Repository navigation
feat(admin): full-screen entry editor layout - #70
Merged
Merged
Conversation
Replaces the bordered-form-inside-shell entry editor with a dedicated
full-screen layout: sticky header + canvas + right rail. Modelled on
WP Gutenberg / Builder.io / Ghost — the editor *is* the page, not a
form embedded in one.
**Layout shape**
- New `_editor` route group, sibling to `_authenticated`. Same auth
gate (hoisted into `requireAuthenticatedSession` in `lib/session.ts`)
but no admin shell / left nav.
- Canvas: centered max-w-3xl, borderless h1-styled title input, Tiptap
content editor filling the rest.
- Right rail: shadcn `Sidebar side="right" collapsible="offcanvas"`.
Holds Permalink / Status / Excerpt cards plus every registered
plugin meta box.
**Entry URLs unchanged.** `_editor` is an underscore layout route, so
`/entries/$slug/new` and `/entries/$slug/$id` render under the new
layout without the browser URL moving.
**`box.location` no longer honoured.** Every meta box lands in the
right rail; `partitionBoxesByLocation` is gone. The manifest field
stays declared so existing plugins don't break — it's just ignored. A
follow-up commit turns the rail cards into collapsible accordion
sections and formalises the deprecation.
**Feature gating.** `PostEditorForm` now takes an `entryType.supports`
list (`"title" | "editor" | "slug" | "excerpt"`) and renders canvas +
rail pieces conditionally. `DEFAULT_ENTRY_SUPPORTS = ["title",
"editor", "slug"]` matches WP's default (plus `slug`, which is
load-bearing for routing). Entry types that omit `editor` get a
muted placeholder in the canvas and drive everything from the rail —
mirrors WP's Gutenberg fallback for `remove_post_type_support`.
**Ships**
- Accordion shadcn primitive added for the meta-box follow-up.
- Test IDs preserved for e2e; `post-editor-{new,edit}-heading` collapse
into `post-editor-headline` (the header caption). `meta-boxes-bottom`
is gone — everything lives in `meta-boxes-sidebar` now.
…e box.location
Follow-up to the full-screen editor layout. Turns the flat stack of
Cards in the document rail into a single `<Accordion type="multiple">`
where every section — built-in (Permalink / Status / Excerpt) and
plugin-registered meta boxes — reads as the same kind of collapsible
panel. Matches WP Gutenberg / Builder.io / Notion: one consistent
rail with one interaction pattern per section.
**Changes**
- `components/meta-box/meta-box.tsx` now exports two variants over a
shared `MetaBoxFieldsGrid` helper:
- `MetaBoxCard` (card shell — unchanged behaviour, still used by
term + user edit forms)
- `MetaBoxAccordionItem` (new — used inside the entry editor rail)
- Entry editor's built-in rail sections (Permalink, Status, Excerpt)
become `AccordionItem`s alongside plugin meta boxes. All open by
default (Gutenberg parity); user collapses what they don't want.
- `EntryMetaBoxOptions.location` and `EntryMetaBoxManifestEntry.location`
marked `@deprecated` with JSDoc. The admin editor no longer reads
the field; it remains declared so plugins that set it don't fail
manifest validation.
**Not touched**
- `MetaBoxFieldSpan`'s responsive object form (`base`/`sm`/`md`/`lg`)
stays declared. In the ~20rem rail the breakpoints never activate,
so only `base` effectively applies — but the full shape is still
useful on wider surfaces (settings pages keep the 12-col grid at
card width). Can be formally simplified in a later pass once real
usage informs the choice.
Three follow-ups to the previous two commits on this branch, all from running find-bugs / code-review / code-simplifier on the PR diff: **Bugs** 1. `SidebarTrigger` inside the editor form defaulted to `type="submit"` (shadcn's `Button` doesn't set a default, and its onClick handler runs before — not instead of — the native form action). Clicking the rail toggle on an edit screen with valid fields would fire a spurious `entry.update`. Pass `type="button"` at the call site. 2. Skeleton aside used `w-(--sidebar-width)`, but the `--sidebar-width` CSS variable is set by `SidebarProvider`, which only mounts once the form itself renders. Hardcode `w-64` (matches shadcn's `SIDEBAR_WIDTH = "16rem"`) so the skeleton doesn't reflow when the real rail takes over. **Design** 3. Move `ENTRIES_LIST_DEFAULT_SEARCH` from the list route's `-constants.ts` into a neutral `@/lib/entries.ts`. The editor routes now reach across layouts via a clean alias import instead of `../../../_authenticated/entries/$slug/-constants.js`. 4. Collapse the duplicated `entryType.supports ?? DEFAULT_ENTRY_SUPPORTS` at every `PostEditorForm` call-site: the fallback is applied internally, and `supports` is now optional on the component. **Simplification** 5. Extract `RailSection` — the three built-in rail sections (Permalink / Status / Excerpt) shared identical `AccordionItem` + `AccordionTrigger` + `AccordionContent` wrappers with the same className overrides. Net ~18 lines saved and each section's JSX reads as "just the field". 6. Comment the `<div>` wrapper inside `ContentField`'s `FormControl` — it looks pointless, but it's load-bearing: shadcn's FormControl clones its single direct child via Radix `Slot.Root` to merge `id`/`aria-*`, and `TiptapEditor` (a component) doesn't forward DOM attrs, so the div is the Slot target.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Replaces the bordered-form-in-shell entry editor with a full-screen canvas + right rail, modelled on WP Gutenberg / Builder.io / Ghost. The editor is the page — no admin shell, no left nav. Every registered meta box lives in the right rail as a collapsible accordion section alongside built-in panels (Permalink / Status / Excerpt).
Entry URLs are unchanged —
/entries/\$slug/newand/entries/\$slug/\$idstill resolve to the same browser path; only the outer layout route moves from_authenticatedto a new_editorsibling (TanStack Router underscore layouts don't contribute to the URL).Architecture
_editorroute group, sibling to_authenticated. Both call a sharedrequireAuthenticatedSessiongate, but_editordrops the shell (no left nav, noShellHeader).PostEditorFormowns the layout: sticky header (back · headline · Save · sidebar toggle) + scrollable centered canvas (borderless h1 title + Tiptap) + shadcnSidebar side="right" collapsible="offcanvas"for the rail.<Accordion type="multiple">— Permalink, Status, Excerpt, and plugin meta boxes all render asAccordionItems. All open by default (Gutenberg parity).Feature gating via
entryType.supportsPostEditorFormacceptssupports: readonly string[]. Canvas + rail pieces render conditionally:titleeditorslugexcerptDefault when
entryType.supportsis omitted:["title", "editor", "slug"](WP parity + slug, which is load-bearing for routing). Entry types that omiteditorget a muted placeholder in the canvas and drive everything from the rail — mirrors WP Gutenberg'sremove_post_type_support("editor")fallback.Meta-box changes
MetaBoxCardsplits into two variants over a sharedMetaBoxFieldsGrid:MetaBoxCard(card shell — still used by term + user edit forms) andMetaBoxAccordionItem(new — used by the editor rail).EntryMetaBoxOptions.locationandEntryMetaBoxManifestEntry.locationmarked@deprecated. The admin no longer reads it; kept on the wire so older plugins don't fail manifest validation.partitionBoxesByLocationdeleted — every box lands in the rail.Non-goals / follow-ups
MetaBoxFieldSpankeeps its responsive object form (base/sm/md/lg), but at the ~20rem rail width onlybaseeffectively applies. Can be simplified in a follow-up once we see real usage — other surfaces (settings pages) still benefit from the breakpoints.Test plan
pnpm typecheck— 15 packages cleanpnpm lint— only the pre-existing data-table warningpnpm formatpnpm test— 487 core + 86 admin unit tests greenpnpm test:e2e— all 50 admin Playwright scenarios green (meta-box test updated: both boxes now assert in the rail)pnpm knip/pnpm publint/pnpm attwCommits
box.location