From 2fd3c9ea6621e904e87e1cfb47556b6f26e1e4ae Mon Sep 17 00:00:00 2001 From: "bert.hausmans" Date: Thu, 21 May 2026 07:43:14 +0200 Subject: [PATCH] style(layout): re-add placeholder workspace sub line + unify avatar across states MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reverses AD-2.5-W1 option A (no-sub) after visual review against the crewli-starter SoT — the two-line layout reads better. Adds a light-grey placeholder sub line under the workspace name (expanded trigger + dropdown items); collapsed stays bare-avatar-only. No backend: the placeholder is a neutral static string ('Organisatie'), real org type + metrics still deferred under WORKSPACE-DROPDOWN-SUB-CONTENT. The org object exposes no field that reads well as a subtitle today (id/name/slug/role only; role is an access identifier, not a description), so a neutral string is used rather than fabricated metrics or the role string P4 originally removed. Fix A — avatar unified across collapsed/expanded. The collapsed avatar styling previously lived directly on the + {{ current.name }} + + {{ current.sub }} + {{ ws.initials }} - -
{{ ws.name }}
+ +
{{ ws.name }}
+
{{ ws.sub }}
diff --git a/apps/app/src/components-v2/layout/__tests__/WorkspaceSwitcher.spec.ts b/apps/app/src/components-v2/layout/__tests__/WorkspaceSwitcher.spec.ts index d72695a8..84c7f549 100644 --- a/apps/app/src/components-v2/layout/__tests__/WorkspaceSwitcher.spec.ts +++ b/apps/app/src/components-v2/layout/__tests__/WorkspaceSwitcher.spec.ts @@ -2,8 +2,10 @@ * WorkspaceSwitcher.spec.ts * * Locks two slices of contract: - * 1. AD-2.5-W1 + AD-2.5-W1 option A: NO sub line on trigger OR on any - * dropdown row. + * 1. Sub line (P6-styling-switcher-sub reverses AD-2.5-W1 option A): + * a placeholder sub line renders under the name in the expanded + * trigger AND on each dropdown row; the collapsed trigger stays + * bare-avatar-only (no sub). * 2. Plan 2.5 P5 Fix 5: dropdown panel structure per crewli-starter — * header (title + manage link), list (one .opt per org, .is-current * + .check-mark on active), footer (two buttons). @@ -71,14 +73,36 @@ describe('WorkspaceSwitcher', () => { }) // ------------------------------------------------------------------------- - // AD-2.5-W1 — no sub on trigger + // P6-styling-switcher-sub — placeholder sub line (reverses option A) // ------------------------------------------------------------------------- - it('does not render a sub line on the trigger (AD-2.5-W1)', () => { - const wrapper = mountSwitcher({ orgs: [orgA] }) + it('renders a placeholder sub line under the name in the expanded trigger', () => { + const wrapper = mountSwitcher({ orgs: [orgA], collapsed: false }) - expect(wrapper.text()).not.toContain(orgA.role) - expect(wrapper.html()).not.toMatch(/workspace-sub|ws-sub|meta-sub/) + const sub = wrapper.find('.meta .sub') + + expect(sub.exists()).toBe(true) + expect(sub.text().length).toBeGreaterThan(0) + }) + + it('the trigger sub is a neutral placeholder, NOT the org role', () => { + const wrapper = mountSwitcher({ orgs: [orgA], collapsed: false }) + + // The placeholder must not leak the access-control role string — + // that was the original AD-2.5-W1 concern; the reversal restores the + // line but with honest placeholder content, not org.role. + expect(wrapper.find('.meta .sub').text()).not.toContain(orgA.role) + }) + + it('does not render a sub line in the collapsed trigger (bare avatar only)', () => { + const wrapper = mountSwitcher({ orgs: [orgA], collapsed: true }) + + // The trigger sub lives inside `.meta`, which only the expanded + // trigger renders. The dropdown's `.opt .sub` rows render inline + // (Popover stubbed) regardless of collapse state, so assert against + // the trigger-scoped `.meta .sub` rather than a bare `.sub`. + expect(wrapper.find('.meta').exists()).toBe(false) + expect(wrapper.find('.meta .sub').exists()).toBe(false) }) it('renders the workspace name on the trigger', () => { @@ -105,15 +129,17 @@ describe('WorkspaceSwitcher', () => { expect(wrapper.find('.trigger').classes()).not.toContain('justify-center') }) - it('collapsed renders a bare avatar button (no .trigger container, just .ws-logo)', () => { + it('collapsed renders a bare avatar button (no .trigger container, no .meta)', () => { const wrapper = mountSwitcher({ collapsed: true }) // The padded trigger container with name/chevron is gone — no .trigger, - // no .meta. The avatar IS the button (.ws-logo + .ws-logo-square on the - // bare