style(layout): logo stays anchored on collapse + squarer corners
Refines the prior sidebar styling commit (8e166512) after manual smoke:
- Brand logo + workspace avatar: rounded-xl -> rounded-lg (crisper
square per design review; both stay unified at the same radius).
- Logo no longer jumps on collapse. The previous code toggled
`justify-between` ⇄ `justify-center` on the header row, which
re-centred the logo against the parent's width — and the parent
width animates from 256px to 64px over 200ms, so the logo slid
from x≈112px (centred in the expanded rail) to x=16px (centred in
the collapsed rail). Visible jump.
Fix: the brand row is now ALWAYS `px-4` and left-aligned. The
logo's horizontal offset (16px from the rail's left edge) is
identical in expanded and collapsed states. Why this still looks
centred when the rail collapses:
rail_collapsed (64px) = logo (32px) + 2 × px-4 (2 × 16px)
With those numbers aligned, a stationary left-aligned logo IS
visually centred in the 64px-wide collapsed rail. The width
transition then "slides the rail closed around" the anchored
logo. Wordmark + Beta badge sit to the RIGHT of the logo and
v-if-disappear on collapse; their absence doesn't shift the logo
because they were never to its left.
- Toggle chevron placement:
- Expanded: collapse chevron (◀) inline at the right of the brand
row, pushed by `ms-auto` (NOT by justify-between forcing the
layout to recentre the logo).
- Collapsed: a SECOND row below the brand row holds a centred
expand chevron (▶) button. Replaces the prior tucked-chip that
overlapped the logo. No overlap, no overhang needed against the
aside's `overflow-hidden`.
- WorkspaceSwitcher trigger: same anchor-on-the-left treatment
applied. The `justify-center` switch on collapse is gone (it
caused an identical avatar slide). Wrapper padding `p-[10px]` ->
`p-2` so the avatar's left offset (wrapper 8 + trigger 8 = 16px)
matches the SidebarHeader logo (px-4 = 16px) — the brand square
and the workspace square are now vertically aligned in the
collapsed rail.
Desktop only. Mobile drawer chrome tracked separately as
MOBILE-SHELL-PARITY.
Tests adapted:
- WorkspaceSwitcher.spec.ts: trigger-rounded assertion bumped
rounded-xl -> rounded-lg; +1 spec locks "trigger never carries
justify-center" (avatar-anchored invariant).
- SidebarHeader.spec.ts: collapsed-behaviour spec rewritten — was
asserting `justify-center`, now asserts the row carries `px-4`
WITHOUT either justify-center OR justify-between (the actual
anchor contract); +1 spec confirms the expand chevron lives in a
SIBLING row of the brand mark (no overlap).
Suite delta: 561 -> 563 (+2). vue-tsc clean. Scoped ESLint clean
(0 errors, pre-existing warnings only).
Manual smoke pending Bert: collapse/expand slowly and watch the
logo — must NOT move horizontally. Confirm rounded-lg looks crisp
(not pebble-soft). Confirm expand chevron sits in its own row
below the logo, no overlap.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -194,12 +194,13 @@ describe('SidebarHeader', () => {
|
||||
expect(btn.attributes('aria-label')).toBe('Collapse sidebar')
|
||||
})
|
||||
|
||||
// P6-followup-styling: when collapsed, the brand-name (wordmark) is
|
||||
// hidden and the row centres the logo. The expand button is a
|
||||
// separate absolute-positioned sibling — its presence must not push
|
||||
// the logo off-centre. This spec locks the "logo stays centred"
|
||||
// contract by asserting the row's flex alignment + wordmark absence.
|
||||
it('collapsed: hides the Crewli wordmark and centres the row', async () => {
|
||||
// P6-styling-fix — the brand row is ALWAYS left-aligned with constant
|
||||
// px-4 padding (no justify-content switch on collapse). The logo's
|
||||
// horizontal position is therefore identical in expanded vs collapsed
|
||||
// states: 16px from the rail's left edge, which IS the visual centre
|
||||
// when the rail narrows to w-16 (64px = 32px logo + 2 × 16px padding).
|
||||
// This is what eliminates the previous slide-from-x=112 jump.
|
||||
it('collapsed: hides the Crewli wordmark, brand row keeps constant px-4 alignment', async () => {
|
||||
const wrapper = mountHeader()
|
||||
const shell = useShellUiStore()
|
||||
|
||||
@@ -210,9 +211,36 @@ describe('SidebarHeader', () => {
|
||||
expect(wrapper.find('.brand-name').exists()).toBe(false)
|
||||
expect(wrapper.text()).not.toContain('Crewli')
|
||||
|
||||
// The header row toggles to justify-center when collapsed.
|
||||
const row = wrapper.find('div')
|
||||
// No justify-center / justify-between toggling — those classes
|
||||
// caused the prior collapse-time slide. The brand row should NOT
|
||||
// carry either when collapsed.
|
||||
const brandRow = wrapper.find('.brand-mark').element.parentElement
|
||||
|
||||
expect(row.classes()).toContain('justify-center')
|
||||
expect(brandRow?.classList.contains('justify-center')).toBe(false)
|
||||
expect(brandRow?.classList.contains('justify-between')).toBe(false)
|
||||
expect(brandRow?.classList.contains('px-4')).toBe(true)
|
||||
})
|
||||
|
||||
it('collapsed: expand chevron is rendered in a row below the brand row (no overlap)', async () => {
|
||||
const wrapper = mountHeader()
|
||||
const shell = useShellUiStore()
|
||||
|
||||
shell.sidebarCollapsed = true
|
||||
|
||||
await wrapper.vm.$nextTick()
|
||||
|
||||
// Two buttons would mean both expand AND collapse chevrons render;
|
||||
// we want exactly one — the expand chevron, in its own row.
|
||||
const buttons = wrapper.findAll('button[aria-label]')
|
||||
|
||||
expect(buttons).toHaveLength(1)
|
||||
expect(buttons[0].attributes('aria-label')).toBe('Expand sidebar')
|
||||
|
||||
// The expand button is NOT a child of the brand row — it lives in a
|
||||
// sibling row below, so the brand row's logo cannot overlap it.
|
||||
const expandBtn = buttons[0].element
|
||||
const brandMark = wrapper.find('.brand-mark').element
|
||||
|
||||
expect(expandBtn.parentElement).not.toBe(brandMark.parentElement)
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user