Skip to content

Admin UI: full-width header + Home stat tiles + a11y (on @plugpress/ui v0.6.0) #35

Description

@ifahimreza

Context

Saddle's admin UI was migrated to @plugpress/ui. v0.6.0 is now tagged/pushed and verified a clean, non-breaking bump for Saddle (all 34 imported symbols resolve; the flat Tabs/FilterTabs/Steps APIs and every pp-* class Saddle's SCSS targets survive; changes are additive — forwardRef/asChild/defaultChecked + a WCAG 2.2 AA pass).

This is a design-refresh bundled onto the v0.6.0 bump:

  1. Full-width header — make the header span the wp-admin content area edge-to-edge (like Waggle/Knovia) instead of sitting boxed inside the 1008px column.
  2. Home stat tiles — turn Home's ad-hoc counts into DS StatCard/StatGrid tiles.
  3. Accessibility — add SkipLink + #pp-main (pairs with the new header).

Decisions: header = full-bleed the existing two-row TopBar (NOT DS AppShell/AppNav) — keep the tone-colored status pill + Pause prominent and keep DS Tabs keyboard nav.

Key finding: Saddle already zeroes the wp-admin gutter (body.toplevel_page_saddle { #wpcontent { padding-inline-start: 0 } .wrap { margin: 0 } }). The only thing keeping the header boxed-in is .saddle-app { max-width: 1008px; margin: 0 auto } (style.scss ~96–97). Moving that constraint down to the content column makes the header full-width — no PHP breakout, no negative margins. (This is the structural difference between Saddle and Waggle: Waggle's app root has no max-width; the width lives on AppContent.)

Step 0 — Bump to v0.6.0

  • package.json pin → github:plugpressco/plugpress-ui#v0.6.0; force re-resolve the git-tag install; verify installed version is 0.6.0.
  • Rebuild; confirm externals unchanged in admin/build/index.asset.php and no google-fonts in built CSS. Non-breaking is pre-verified — no code changes expected from the bump alone.

Step 1 — Full-bleed header (CSS-led, one small JSX change each)

  • admin/src/components/TopBar.jsx — wrap the existing __row + Tabs in a centered .saddle-top__inner so the bar is full-bleed but its contents align with the body column. No behavior change (status pill, Pause, DS Tabs unchanged).
  • admin/src/App.jsx — move ForeignNotices + notices + .saddle-panel into a <div className="saddle-content" id="pp-main"> wrapper; TopBar stays outside it (full-bleed).
  • admin/src/style.scss:
    • .saddle-app (main view): remove max-width: 1008px; margin: 0 auto + horizontal/top padding.
    • .saddle-app--setup: add max-width: 620px; margin: 0 auto; padding: 28px 24px 72px (onboarding stays centered-narrow).
    • .saddle-top: full-bleed bar — background: var(--s-surface), border-bottom: 1px solid var(--s-border), horizontal padding, position: sticky; top: var(--wp-admin--admin-bar--height, 32px); z-index: 20.
    • .saddle-top__inner (new): max-width: 1008px; margin: 0 auto (centers header content to the body column).
    • .saddle-content (new): max-width: 1008px; margin: 0 auto; padding: 28px 24px 72px — where the 1008 column now lives.
    • Leave the existing body.toplevel_page_saddle gutter reset untouched.

Gotchas (handled by the above): sticky offset under the admin bar via --wp-admin--admin-bar--height (tracks the 32→46px change ≤782px); folded admin menu handled because #wpcontent's left edge is WP-controlled; no !important needed.

Step 2 — Home stat tiles (admin/src/components/Home.jsx)

Import StatCard, StatGrid. Insert a StatGrid between the Hero and the existing CardGrid, from data already in the component (tierlevelFor, clients, activity):

  • Connected appsvalue={clients.length}, plug/connect icon.
  • Access levelvalue={level.title}, tone = safe→success / active→warning.
  • Recent activityvalue={activity?.entries.length ?? 0}, sub = "logged changes"; blocked-count optional as a delta with deltaTone="danger".

Keep the existing "Recent activity" list card below. pp-stat/pp-stat-grid CSS ships in the DS bundle — no new SCSS.

Step 3 — Accessibility: SkipLink + #pp-main

  • admin/src/App.jsx: render <SkipLink /> as the first child of the main .pp-app view (before <TopBar>). Default href="#pp-main" targets the id="pp-main" on .saddle-content. DS .pp-skip-link CSS handles visually-hidden-until-focused. No SCSS.

Verification

  1. npm run build green; admin/build/index.asset.php still lists react/react-dom/wp-element/wp-i18n/wp-api-fetch; grep -c fonts.googleapis admin/build/*.css → 0.
  2. composer test still green (300).
  3. wp-playground smoke test (npx @wp-playground/cli server --auto-mount --login): header spans full content width, sticky under the admin bar, inner content aligned to the 1008px column; content + notices centered at 1008px; onboarding still 620px; Home renders 3 pp-stat tiles; Tab surfaces "Skip to content" → focus moves to #pp-main; status pill + Pause + DS Tabs behave as before.
  4. Keyboard-only + prefers-reduced-motion pass; folded admin menu — header still tracks the content edge.

Notes / deferred

  • Bundle onto the still-uncommitted UI-migration working tree (or commit migration first, then this) — decide at commit time.
  • Deferred (not this issue): DS AppShell/AppNav wholesale adoption; FeatureCard for the Permissions lanes; Brandmark/BrandProvider app-wide (React-only — does not replace the PHP menu-icon single-source assets/brand/mark.svg, keep that as source of truth); replacing the hand-rolled wizard with DS Wizard.
  • Update STATUS.md when implemented.

🤖 Filed from a Claude Code planning session.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions