Skip to content

fix(admin): use the shared page header on list pages - #4437

Closed
khoinguyenpham04 wants to merge 2 commits into
noah/admin-router-link-buttonfrom
noah/admin-page-header
Closed

khoinguyenpham04 wants to merge 2 commits into
noah/admin-router-link-buttonfrom
noah/admin-page-header

Conversation

@khoinguyenpham04

@khoinguyenpham04 khoinguyenpham04 commented Oct 27, 2026 •

Copy link
Copy Markdown
Collaborator

What does this PR do?

Each list page in the admin built its own header, so the header changed from page to page:

  • The title, description, divider and buttons sat in slightly different places.
  • The main action was a primary button on Redirects, Sections and Bylines, and an outlined button everywhere else.
  • Posts used underline tabs, while Comments and Redirects used segmented tabs.
  • On phones, the Categories header buttons ran off the side of the screen.

This PR makes the existing PageHeader the header for every list page.

  • PageHeader itself:
    • tabs is now optional.
    • Actions wrap under the title on narrow screens instead of overflowing. On phones, a header with a description puts its actions on the next line.
    • Every tab gets the same 14px label, fills the track on phones, and lines up with the first row of tools.
    • Tools now start right after the tabs on every page, where Comments, Redirects and Calendar used to push them to the far end.
  • Main action: each page's main action uses variant="primary", and other actions use secondary.
  • Search and filters: these move into the header's tools row, as on Comments and Redirects.
  • Content list filters:
    • "Clear filters" is now a compact × button with an accessible name and a tooltip.
    • The × keeps its place in the row while hidden, so it doesn't re-wrap the row or move the table when it appears.
    • I measured the position of the table before and after setting the status filter at every 10px from 1000 to 1440px wide, and every 20px from 360 to 1000px. It doesn't move at any width. On main it moves 34px at 1050–1140px, and on phones the text button adds a row.
    • Filters that show the chosen value (author, byline and date range) still change width with it, so at some window widths they can re-wrap the row.
    • I tried a labelled button in the reserved slot, but at 1280px and on phones it left "Date range" alone on an extra row.
  • Categories and Tags: both now show the same header: "Add to posts", then the primary "Add …", then a ⋯ menu with "New taxonomy" and "Delete taxonomy". Before, Categories showed "New Taxonomy" as a separate button.

Pages changed: Dashboard, Posts and Pages, Users, Bylines, Byline schema, Menus, Categories, Tags, Sections, Widgets and Content Types. Comments, Redirects and Calendar already used PageHeader and pick up its tab, alignment and wrapping changes. Calendar still passes the tab classes that PageHeader now adds; that cleanup is left for after #4151, which changes the same file.

Out of scope:

  • Strings: no strings change.
  • Detail pages: the menu editor, section editor, content type editor and settings pages keep their own headers.
  • Other list pages: Media, Relations, Plugins and Import also keep theirs, because they need back buttons or breadcrumbs that PageHeader doesn't support yet.

Stacked on #4436, which makes the primary "Add New" and "New Content Type" links render correctly.

Type of change

  • Bug fix
  • Feature (requires an accepted feature plan or RFC)
  • Refactor (no behavior change)
  • Translation
  • Documentation
  • Performance improvement
  • Tests
  • Chore (dependencies, CI, tooling)

Your connection to this change

  • I use EmDash and ran into the problem this PR addresses
  • I maintain a tool, dependency, or service that EmDash uses, and this change concerns that integration
  • A Maintainer approved this specific change before I opened the PR

Checklist

  • I have read CONTRIBUTING.md
  • pnpm typecheck passes
  • pnpm lint passes
  • pnpm test passes (or targeted tests for my change)
  • pnpm format has been run
  • I have added/updated tests for my changes (if applicable)
  • User-visible strings in the admin UI are wrapped for translation (if applicable). Do not include messages.po changes except in translation PRs — a workflow extracts catalogs on merge to main.
  • I have added and reviewed the user-facing changeset (if this PR changes a published package)
  • New features link to their merged design PR: https://github.com/emdash-cms/emdash/pull/...
  • I have included screenshots below if this PR changes the UI

Not applicable:

  • Design PR: this is a bug fix.
  • Tests: the existing component tests find the headers by role.
    • The taxonomy sidebar test now opens "New taxonomy" from the ⋯ menu.
    • The BulkTagDialog test's router Link mock now forwards className and style like the real one. Before, the primary "Add New" button's overlay covered the page in that test.
    • New layout tests check that setting the status filter never moves the table, at every width from 360 to 1500px (this fails on main at 32 widths), and that "Clear filters" stays out of the accessibility tree until a filter is active.
  • Visual baselines: the dashboard, content list and menus baselines change.

AI assistance disclosure

  • This PR includes AI-generated code or text — model/tool: Claude Opus 5.5

Screenshots / test output

Before After
Posts list before the change: underline All/Trash tabs, an outlined Add New button and filters on their own row Posts list after the change: segmented tabs with the filters beside them and a primary Add New button
Users list before the change: no divider and an outlined Invite User button Users list after the change: the shared header with a divider, the search and role filter in the header and a primary Invite User button
Categories before the change: New Taxonomy, Add Category and Add to posts as outlined buttons and a borderless more-actions button Categories after the change: Add to posts, a primary Add Category button and a more-actions menu that holds New taxonomy
Menus before the change: an outlined Create Menu button Menus after the change: the shared header with a primary Create Menu button
Content Types before the change: no divider and outlined Relations and New Content Type buttons Content Types after the change: the shared header with a divider, a secondary Relations link and a primary New Content Type link
Dashboard before the change: the title and quick actions without a divider Dashboard after the change: the shared header with a divider under the title and quick actions
More list pages
Before After
Posts Trash tab before the change: underline tabs above the trash table Posts Trash tab after the change: segmented tabs in the shared header
Tags before the change: secondary Add tag and Add to posts buttons and the search below the header Tags after the change: Add to posts, a primary Add tag button and the search in the header
Bylines before the change: a header without a divider and the toolbar below it Bylines after the change: the shared header with the search and type filter in it
Byline schema before the change: an outlined New field button Byline schema after the change: the shared header with a primary New field button
Sections before the change: a hand-built header with the search below the title Sections after the change: the shared header with the same layout
Widgets before the change: an outlined Add Widget Area button and no divider Widgets after the change: the shared header with a divider and a primary Add Widget Area button
Comments before the change: the shared header before this change Comments after the change: the same header, with tabs that fill the track on phones
Redirects before the change: the shared header before this change Redirects after the change: the same header
Calendar before the change: the shared header before this change Calendar after the change: the same header
Phone (390px)
Before After
Phone Posts list before the change: underline tabs and small filters Phone Posts list after the change: full-width segmented tabs and filters two per row
Phone Categories before the change: header buttons running off the right edge Phone Categories after the change: Add to posts, Add Category and the more-actions button on one row
Phone Sections before the change: the description beside the button Phone Sections after the change: the description on its own line and the button below it
Phone Users list before the change: the toolbar below the header Phone Users list after the change: the shared header with the search and role filter
Phone Bylines before the change: the toolbar below the header Phone Bylines after the change: the shared header with the search and type filter
Phone Comments before the change: the status tabs Phone Comments after the change: the same status tabs
Arabic
Before After
Arabic Posts list before the change: underline tabs and outlined Add New Arabic Posts list after the change: segmented tabs and a primary Add New, mirrored for right-to-left
Arabic Categories before the change: outlined actions Arabic Categories after the change: the shared actions mirrored for right-to-left
Arabic Menus before the change: an outlined Create Menu button Arabic Menus after the change: a primary Create Menu button mirrored for right-to-left
Design review scores

Three reviewer models scored main against this branch, using the same screenshots and rubric: typography, hierarchy, spacing, color, iconography, consistency, clarity and phone. Each round's findings were fixed before the next round. The scores cover this PR together with the toolbar height PR stacked on top of it.

Reviewer Round 1 (main → branch) Round 2 (main → branch) Round 3 (main → branch)
Claude Opus 5.5 6.2 → 7.0 6.2 → 7.2 6.2 → 7.3
Claude Fable 5.1 6.0 → 6.9 6.0 → 7.3 —
Claude Sonnet 5.5 5.8 → 7.1 5.8 → 7.3 —

Round 3 was a confirmation pass after the round-2 fixes. It found no new regressions and nothing left that must be fixed.

Consistency rose the most, from about 5.3 to 7.4.

The full admin suite passes: 259 files and 3,751 tests. One editor toolbar test in PortableTextEditor.test.tsx, which this PR doesn't touch, failed once and passed on a rerun.

Dashboard, content lists, Users, Bylines, Byline schema, Menus,
Categories, Tags, Sections, Widgets and Content Types each built their
own header, so titles, descriptions, dividers and buttons sat in
different places and the main action was primary on some pages only.

PageHeader now takes optional tabs, wraps its actions under the title on
narrow screens, gives every tab the same size and starts its tools right
after the tabs. Each list page renders it with its search and filters as
tools and its main action as the primary button. Categories and Tags
share one set of actions, with "New taxonomy" in the overflow menu.

On content lists, "Clear filters" keeps its place in the filter row
while hidden, so setting a filter no longer re-wraps the row and moves
the table.
@changeset-bot

changeset-bot Bot commented Oct 27, 2026 •

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 2057521

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 12 packages
Name Type
@emdash-cms/admin Patch
emdash Patch
@emdash-cms/cloudflare Patch
@emdash-cms/plugin-test Patch
@emdash-cms/sandbox-workerd Patch
@emdash-cms/auth Patch
@emdash-cms/blocks Patch
create-emdash Patch
@emdash-cms/gutenberg-to-portable-text Patch
@emdash-cms/x402 Patch
@emdash-cms/auth-atproto Patch
@emdash-cms/plugin-embeds Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Oct 27, 2026 •

Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Updated (UTC)
✅ Deployment successful!
View logs
docs c95b2a9 Oct 27 2026, 03:13 PM

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Oct 27, 2026 •

Copy link
Copy Markdown

🚀 Deploying Preview to Cloudflare 🚀

Preview URL: https://noah-admin-page-header.try.emdashcms.com, https://noah-admin-page-header-emdash-playground.emdash-cms.workers.dev (commit 2057521)

This URL reflects your latest Preview deployment

Preview Deployments by commit

Status Deployment URL Commit Updated (UTC) See this deployment's details
  • Build: Success ✅
  • Deployment: Success ✅

View logs ↗
https://e6e42e84.try.emdashcms.com, https://e6e42e84-emdash-playground.emdash-cms.workers.dev 2057521 2026-10-27T15:51:03.772Z Visit the dashboard ↗
  • Build: Success ✅
  • Deployment: Success ✅

View logs ↗
https://c67be3e1.try.emdashcms.com, https://c67be3e1-emdash-playground.emdash-cms.workers.dev c95b2a9 2026-10-27T15:15:47.844Z Visit the dashboard ↗

@pkg-pr-new

pkg-pr-new Bot commented Oct 27, 2026 •

Copy link
Copy Markdown

Open in StackBlitz

@emdash-cms/admin

npm i https://pkg.pr.new/emdash-cms/emdash/@emdash-cms/admin@4437

@emdash-cms/auth

npm i https://pkg.pr.new/emdash-cms/emdash/@emdash-cms/auth@4437

@emdash-cms/auth-atproto

npm i https://pkg.pr.new/emdash-cms/emdash/@emdash-cms/auth-atproto@4437

@emdash-cms/blocks

npm i https://pkg.pr.new/emdash-cms/emdash/@emdash-cms/blocks@4437

@emdash-cms/cloudflare

npm i https://pkg.pr.new/emdash-cms/emdash/@emdash-cms/cloudflare@4437

@emdash-cms/contentful-to-portable-text

npm i https://pkg.pr.new/emdash-cms/emdash/@emdash-cms/contentful-to-portable-text@4437

emdash

npm i https://pkg.pr.new/emdash-cms/emdash@4437

create-emdash

npm i https://pkg.pr.new/emdash-cms/emdash/create-emdash@4437

@emdash-cms/gutenberg-to-portable-text

npm i https://pkg.pr.new/emdash-cms/emdash/@emdash-cms/gutenberg-to-portable-text@4437

@emdash-cms/plugin-cli

npm i https://pkg.pr.new/emdash-cms/emdash/@emdash-cms/plugin-cli@4437

@emdash-cms/plugin-test

npm i https://pkg.pr.new/emdash-cms/emdash/@emdash-cms/plugin-test@4437

@emdash-cms/plugin-types

npm i https://pkg.pr.new/emdash-cms/emdash/@emdash-cms/plugin-types@4437

@emdash-cms/registry-client

npm i https://pkg.pr.new/emdash-cms/emdash/@emdash-cms/registry-client@4437

@emdash-cms/registry-lexicons

npm i https://pkg.pr.new/emdash-cms/emdash/@emdash-cms/registry-lexicons@4437

@emdash-cms/registry-loader

npm i https://pkg.pr.new/emdash-cms/emdash/@emdash-cms/registry-loader@4437

@emdash-cms/registry-moderation

npm i https://pkg.pr.new/emdash-cms/emdash/@emdash-cms/registry-moderation@4437

@emdash-cms/registry-verification

npm i https://pkg.pr.new/emdash-cms/emdash/@emdash-cms/registry-verification@4437

upgrade-emdash

npm i https://pkg.pr.new/emdash-cms/emdash/upgrade-emdash@4437

@emdash-cms/sandbox-workerd

npm i https://pkg.pr.new/emdash-cms/emdash/@emdash-cms/sandbox-workerd@4437

@emdash-cms/x402

npm i https://pkg.pr.new/emdash-cms/emdash/@emdash-cms/x402@4437

@emdash-cms/plugin-ai-moderation

npm i https://pkg.pr.new/emdash-cms/emdash/@emdash-cms/plugin-ai-moderation@4437

@emdash-cms/plugin-ai-search

npm i https://pkg.pr.new/emdash-cms/emdash/@emdash-cms/plugin-ai-search@4437

@emdash-cms/plugin-atproto

npm i https://pkg.pr.new/emdash-cms/emdash/@emdash-cms/plugin-atproto@4437

@emdash-cms/plugin-audit-log

npm i https://pkg.pr.new/emdash-cms/emdash/@emdash-cms/plugin-audit-log@4437

@emdash-cms/plugin-color

npm i https://pkg.pr.new/emdash-cms/emdash/@emdash-cms/plugin-color@4437

@emdash-cms/plugin-embeds

npm i https://pkg.pr.new/emdash-cms/emdash/@emdash-cms/plugin-embeds@4437

@emdash-cms/plugin-field-kit

npm i https://pkg.pr.new/emdash-cms/emdash/@emdash-cms/plugin-field-kit@4437

@emdash-cms/plugin-forms

npm i https://pkg.pr.new/emdash-cms/emdash/@emdash-cms/plugin-forms@4437

@emdash-cms/plugin-webhook-notifier

npm i https://pkg.pr.new/emdash-cms/emdash/@emdash-cms/plugin-webhook-notifier@4437

commit: 2057521

@github-actions

github-actions Bot commented Oct 27, 2026 •

Copy link
Copy Markdown
Contributor

Visual regression: 14 screens changed

These admin screens render differently on this PR. Confirm every change below is intended before accepting.

Screen Image Compare
content-list-byline-filter-ltr expected · actual
content-list-byline-filter-rtl expected · actual
content-list-date-field-filter-ltr expected · actual
content-list-date-field-filter-rtl expected · actual
content-list-date-range-filter-ltr expected · actual
content-list-date-range-filter-rtl expected · actual
content-list-ltr expected · actual
content-list-rtl expected · actual
content-list-status-filter-ltr expected · actual
content-list-status-filter-rtl expected · actual
dashboard-ltr expected · actual
dashboard-rtl expected · actual
menus-ltr expected · actual
menus-rtl expected · actual

Maintainers: if every change above is intended, comment /accept-baselines
to commit the regenerated Linux baselines to this PR.

Measured head: 2057521d4b08705b54d327f24cf0c4c4f62b590c. /accept-baselines accepts the snapshots for this commit.

github-actions Bot pushed a commit that referenced this pull request Oct 27, 2026
github-actions Bot pushed a commit that referenced this pull request Oct 27, 2026
@khoinguyenpham04
khoinguyenpham04 removed this pull request from stack #4439 October 27, 2026 16:20
@khoinguyenpham04
khoinguyenpham04 deleted the noah/admin-page-header branch October 27, 2026 16:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant