Skip to content

refactor(ui): tabs spacing/alignment + PageHeader split (CorePageHeaderTabs)#4190

Merged
PierreBrisorgueil merged 7 commits into
masterfrom
refactor/tabs-spacing-alignment
May 21, 2026
Merged

refactor(ui): tabs spacing/alignment + PageHeader split (CorePageHeaderTabs)#4190
PierreBrisorgueil merged 7 commits into
masterfrom
refactor/tabs-spacing-alignment

Conversation

@PierreBrisorgueil
Copy link
Copy Markdown
Collaborator

@PierreBrisorgueil PierreBrisorgueil commented May 21, 2026

Summary

Three layered fixes to the chrome convention that #4187/#4188 established:

  1. Tabs horizontal alignmentCoreSurfaceTabBar now applies mx-4 on its inner <v-tabs>, so the tab strip aligns with the section title icon (same x-offset as corePageHeader).
  2. Vertical gap below tabs — tabbed-layout containers (user.view.vue, admin.layout.vue, organization.detail.component.vue) get class="pb-0" to collapse the dead space between the tab underline and the routed child's top edge. ~40px → ~24px.
  3. PageHeader split into two primitivesPageHeader is now content-sized (drop the canonical 56px min/max-height) and loses the dead #tabs slot path. A new CorePageHeaderTabs bundles PageHeader + CoreSurfaceTabBar and re-enforces the 56px title↔breadcrumb rhythm via scoped :deep(). The 3 tabbed callsites migrate to the new primitive.

Plus an empty-state regression fix on tasks.view.vue (the populated v-row had no v-if guard, so it took ~16-24px of vertical space and pushed the "No tasks yet" card down).

Files

  • core.surfaceTabBar.component.vue<v-tabs class="mx-4">
  • core.pageHeader.component.vue — content-sized, no #tabs slot
  • core.pageHeaderTabs.component.vuenew, bundles PageHeader + SurfaceTabBar
  • user.view.vue — migrate to CorePageHeaderTabs
  • admin.layout.vue — migrate to CorePageHeaderTabs with :hide-tabs in breadcrumb mode
  • organization.detail.component.vue — migrate to CorePageHeaderTabs
  • tasks.view.vue — empty-state row spacing harmonized with /task + v-if guard on populated row
  • Tests updated across all 6 touched files + new test file for CorePageHeaderTabs
  • MIGRATIONS.md — new entry documenting the refactor for downstream projects

Tests

  • Full suite (after this branch): 1913/1913 pass.
  • New core.pageHeaderTabs.component.unit.tests.js: 8/8 pass (composition, breadcrumb forward, hideTabs gating, CASL).
  • Existing PageHeader tests: drop assertions on the removed #tabs slot + the no-longer-enforced 56px CSS rule.
  • The 3 tabbed-layout tests now stub CorePageHeaderTabs instead of PageHeader + CoreSurfaceTabBar separately.

Test plan

  • Lint clean on all touched files
  • Unit tests green
  • Visual smoke on /users/profile, /users/organizations/:id/general, /admin/users, /admin/users/:id (breadcrumb mode), /tasks (empty + populated), /task — verify horizontal alignment + tightened gap below tabs + empty-state aligns with /task

Summary by CodeRabbit

  • New Features

    • Introduced a new consolidated header component that bundles page headers with tab navigation for improved alignment and spacing.
  • Bug Fixes

    • Fixed empty-state regression in task list display.
  • Refactor

    • Page header sizing now flexible instead of fixed height.
    • Updated header/tab layout logic across multiple modules.
    • Improved tab bar spacing and alignment throughout the application.

Review Change Stack

…low tabs

- CoreSurfaceTabBar: add `mx-4` to `<v-tabs>` so the tab strip aligns
  horizontally with PageHeader's title icon (both now use the same 16px
  inset inside `v-container fluid`).
- user.view.vue + admin.layout.vue: add `pb-0` on the parent
  `<v-container fluid>` to collapse ~16px of dead space between the tab
  underline and the routed child's top edge. Child views own their own
  top padding via their own `<v-container fluid>` + `pa-2` row.

Visual impact (Account, Org detail, Admin surfaces):
- Tabs now align with the section title icon instead of being 16px to the left
- Vertical gap below tabs drops from ~40px to ~24px
Extends the tabs-spacing-alignment fix to organization.detail.component.vue
which had the same `<v-container fluid>` parent pattern as user.view.vue
and admin.layout.vue. Brings /users/organizations/:id/* into visual
parity with /users/profile and /admin/* surfaces.
Splits the chrome primitive into two specialised components so each page
gets the spacing it actually needs:

- `PageHeader` (existing, simplified): content-sized header for list views
  and simple pages (Tasks, Scraps, etc.). Drops the 56px min/max-height
  enforcement and removes the dead `#tabs` slot path (unused since the
  CoreSurfaceTabBar sibling refactor in #4187/#4188).
- `CorePageHeaderTabs` (new): bundles a PageHeader + CoreSurfaceTabBar and
  enforces the 56px height externally via a scoped `:deep()` rule. Used on
  tabbed surfaces (Account, Organization detail, Admin) where the title↔
  breadcrumb rhythm matters across route transitions.

The new primitive accepts `tabs`, `can`, `basePath`, and `hideTabs` for the
tab bar, plus passthrough of icon/title/subtitle/avatar/actions/breadcrumb
slots and props to the inner PageHeader.

Migrates 3 callsites:
- user.view.vue (Account)
- admin.layout.vue (with hideTabs in breadcrumb mode)
- organization.detail.component.vue

Visual impact: pages without tabs (e.g. /tasks) no longer pay the 56px
chrome tax; tabbed surfaces preserve the route-transition rhythm.
The empty-state v-row was missing `pa-2 mt-0` (so Vuetify's default v-row
margin applied) and the card carried `ma-6` (24px all-sides margin),
which together added ~36px of dead space above the "No tasks yet" card
compared to the populated state. Drop `ma-6` and apply the same
`pa-2 mt-0` row classes as the populated branch — empty state now sits
flush with where task cards would render.
Drop `align="start" justify="center"` on the v-row and align card padding
(pa-8 → pa-6) so the empty-state card sits at the exact same top/left as
the form card on /task. Keeps `text-center` for icon + label centering
inside the card.
The populated state's v-row had no v-if guard, so when the task list was
empty it still rendered (just without children) — taking ~16-24px of
vertical space (pa-2 + default v-row margins) on top of the empty-state
row below. Empty-state card now sits at the same top position as the
populated cards (and /task form card).
…refactor

Adds a new migration entry above the previous chrome convergence entry
covering the changes in this batch:
- PageHeader is content-sized (56px enforcement removed)
- #tabs slot on PageHeader dropped (dead since #4187)
- mx-4 on v-tabs inside CoreSurfaceTabBar (horizontal alignment with title)
- New CorePageHeaderTabs primitive that bundles PageHeader + SurfaceTabBar
  and re-enforces the 56px rhythm for tabbed surfaces
- pb-0 on the tabbed-layout container to collapse the gap below tabs
- Empty-state v-row regression pattern (guard the populated row with v-if)

Downstream impact: minimal — only projects with custom tabbed layouts need
to migrate to CorePageHeaderTabs; default consumers get the new convention
via /update-stack automatically.
Copilot AI review requested due to automatic review settings May 21, 2026 14:38
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 21, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: c1fd447e-fbe9-40c4-9f2e-4f76b9faf9ad

📥 Commits

Reviewing files that changed from the base of the PR and between 1e5fdf1 and 1a9d486.

📒 Files selected for processing (13)
  • MIGRATIONS.md
  • src/modules/admin/tests/admin.layout.unit.tests.js
  • src/modules/admin/views/admin.layout.vue
  • src/modules/core/components/core.pageHeader.component.vue
  • src/modules/core/components/core.pageHeaderTabs.component.vue
  • src/modules/core/components/core.surfaceTabBar.component.vue
  • src/modules/core/components/tests/core.pageHeaderTabs.component.unit.tests.js
  • src/modules/core/tests/core.pageHeader.component.unit.tests.js
  • src/modules/organizations/components/organization.detail.component.vue
  • src/modules/organizations/tests/organizations.detail.layout.unit.tests.js
  • src/modules/tasks/views/tasks.view.vue
  • src/modules/users/tests/user.view.unit.tests.js
  • src/modules/users/views/user.view.vue

Walkthrough

This PR introduces CorePageHeaderTabs, a new component that unifies PageHeader and CoreSurfaceTabBar with fixed 56px height enforcement. PageHeader loses its #tabs slot and height rule; CoreSurfaceTabBar gains horizontal margin. The component is wired into admin, organizations, and users layouts. Tests are updated across four modules; incidental empty-state rendering is fixed in tasks view.

Changes

PageHeader split + CorePageHeaderTabs refactor

Layer / File(s) Summary
Core component refactoring: PageHeader and CorePageHeaderTabs
src/modules/core/components/core.pageHeader.component.vue, src/modules/core/components/core.pageHeaderTabs.component.vue, src/modules/core/tests/core.pageHeader.component.unit.tests.js, src/modules/core/components/tests/core.pageHeaderTabs.component.unit.tests.js
PageHeader template removes the #tabs slot conditional and PageHeader style removes fixed 56px height enforcement. New CorePageHeaderTabs component composes PageHeader + CoreSurfaceTabBar, conditionally renders tab bar based on hideTabs and tabs length, enforces 56px height via :deep(.core-page-header) rule. Unit tests added for CorePageHeaderTabs (composition, slot forwarding, CASL gating); PageHeader tests updated to verify root layout classes instead of height invariant.
CoreSurfaceTabBar horizontal margin
src/modules/core/components/core.surfaceTabBar.component.vue
Root v-tabs element gains mx-4 CSS class for horizontal margin alignment.
Admin layout: PageHeader + tabs → CorePageHeaderTabs
src/modules/admin/views/admin.layout.vue, src/modules/admin/tests/admin.layout.unit.tests.js
Admin layout template consolidates PageHeader + CoreSurfaceTabBar into CorePageHeaderTabs with breadcrumb slot and hideTabs logic driven by currentBreadcrumb. Component registration updated to CorePageHeaderTabs. Tests update stubs to provide CorePageHeaderTabs stub, rewrite assertions to verify tab merging from config.admin.tabs, basePath="/admin", can predicate, breadcrumb-mode hideTabs=true, and router-view rendering outside container.
Organizations detail: PageHeader + tabs → CorePageHeaderTabs
src/modules/organizations/components/organization.detail.component.vue, src/modules/organizations/tests/organizations.detail.layout.unit.tests.js
Organization detail template replaces split PageHeader + CoreSurfaceTabBar with CorePageHeaderTabs inside v-container with pb-0. Component registration updated. Tests update stubs to provide CorePageHeaderTabs stub, rewrite header-chrome presence assertion, update prop assertions to verify CorePageHeaderTabs receives resolved basePath, config.organizations.tabs, and can predicate; router-view regression test updated to use new stub marker.
Users layout: PageHeader + tabs → CorePageHeaderTabs
src/modules/users/views/user.view.vue, src/modules/users/tests/user.view.unit.tests.js
User view template consolidates PageHeader + CoreSurfaceTabBar into CorePageHeaderTabs preserving actions slot and tab wiring. Script imports and component registration updated to CorePageHeaderTabs. Tests update shared stubs to provide CorePageHeaderTabs stub, rewrite layout assertion, update prop wiring tests to verify config.users.tabs, '/users' basePath, and can predicate.
Incidental empty-state fix: Tasks view
src/modules/tasks/views/tasks.view.vue
Tasks view template now conditionally renders task list when tasks exists and has items; otherwise renders "No tasks yet" empty-state card with theme-driven flat/rounded styling.
Migration documentation
MIGRATIONS.md
New top-of-file entry documents PageHeader split (content-sized, #tabs slot removed), CorePageHeaderTabs primitive introduction, layout conventions for tabbed vs non-tabbed pages, breadcrumb mode guidance via hide-tabs, empty-state v-if guard pattern, and stack test updates to locate CorePageHeaderTabs by name.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • pierreb-devkit/Vue#4185: Both PRs update the Users "account" page header/tab chrome, with the main PR consolidating the layout into the new CorePageHeaderTabs component.
  • pierreb-devkit/Vue#4188: Both PRs refactor the admin "header chrome" area in admin.layout.vue from PageHeader/CoreSurfaceTabBar patterns to the new unified CorePageHeaderTabs component.
  • pierreb-devkit/Vue#3781: Main PR builds on and supersedes the feat(pageHeader): add tabs slot... change from PR #3781 by removing the #tabs slot and introducing the new CorePageHeaderTabs wrapper.

Suggested labels

Tests

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and specifically summarizes the main change: a refactor of tabs spacing/alignment and the introduction of CorePageHeaderTabs component that splits PageHeader functionality.
Description check ✅ Passed The description covers most required sections: summary with three main changes, files affected, tests status, and test plan. However, it lacks explicit checkboxes completion status for lint/build and some risk/validation details from the template.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch refactor/tabs-spacing-alignment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@codecov
Copy link
Copy Markdown

codecov Bot commented May 21, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 99.56%. Comparing base (1e5fdf1) to head (1a9d486).
⚠️ Report is 1 commits behind head on master.

Additional details and impacted files
@@           Coverage Diff           @@
##           master    #4190   +/-   ##
=======================================
  Coverage   99.56%   99.56%           
=======================================
  Files          31       31           
  Lines        1140     1140           
  Branches      329      329           
=======================================
  Hits         1135     1135           
  Misses          5        5           

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@PierreBrisorgueil PierreBrisorgueil merged commit 45bf131 into master May 21, 2026
7 of 8 checks passed
@PierreBrisorgueil PierreBrisorgueil review requested due to automatic review settings May 21, 2026 15:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant