style(layout): re-add placeholder workspace sub line + unify avatar across states
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 <button>, letting
user-agent button rendering diverge subtly from the expanded <span>
avatar. The collapsed render now wraps the EXACT SAME avatar span
markup (same classes, gradient, .ws-logo-square inset-shadow) in a
bare transparent p-0 button — the 32px square is byte-identical
across states; only the surrounding context differs.
Fix B — sub line re-added to WorkspaceDisplay (cleanly typed as
`sub: string`, sourced from a SUB_PLACEHOLDER const with a TODO
pointing at the deferred backend). Rendered light-grey
(text-[var(--p-text-muted-color)], matching the in-component muted
text) at text-[11.5px] in the trigger and text-[12.5px] in dropdown
rows, mirroring the pre-P4 sizes. Collapsed renders no sub.
Specs: reversed the P4/P5 no-sub locks to sub-present assertions
(trigger sub present + honest-placeholder/not-role; dropdown sub on
every row + no role leak; collapsed-no-sub via `.meta .sub`).
Updated the collapsed-bare-avatar spec for the new span-in-button
structure (.ws-logo moved from button to inner span).
Suite delta: 566 → 569 (+3). vue-tsc clean. Scoped ESLint clean
(0 errors). No backend, no fabricated data.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -57,9 +57,24 @@ interface WorkspaceDisplay {
|
||||
id: string
|
||||
initials: string
|
||||
name: string
|
||||
/**
|
||||
* Light-grey second line under the name. Plan 2.5 P6-styling-switcher-sub
|
||||
* re-adds the two-line layout (reverses AD-2.5-W1 option A) after visual
|
||||
* review against the crewli-starter SoT. The value is a neutral
|
||||
* PLACEHOLDER — the real org type + metrics (e.g. "Festival · 12 days ·
|
||||
* 14 stages") require the organisations.type enum + a metrics endpoint,
|
||||
* which stay deferred under WORKSPACE-DROPDOWN-SUB-CONTENT. The org
|
||||
* object exposes no field that reads well as a subtitle today (only
|
||||
* id/name/slug/role; role is an access identifier, not a description),
|
||||
* so a static neutral string is used rather than fabricated metrics.
|
||||
*/
|
||||
sub: string
|
||||
gradient: [string, string]
|
||||
}
|
||||
|
||||
// TODO: replace with org type + metrics when WORKSPACE-DROPDOWN-SUB-CONTENT backend lands
|
||||
const SUB_PLACEHOLDER = 'Organisatie'
|
||||
|
||||
function buildDisplay(org: Organisation): WorkspaceDisplay {
|
||||
const words = org.name.trim().split(/\s+/)
|
||||
|
||||
@@ -72,6 +87,7 @@ function buildDisplay(org: Organisation): WorkspaceDisplay {
|
||||
id: org.id,
|
||||
initials,
|
||||
name: org.name,
|
||||
sub: SUB_PLACEHOLDER,
|
||||
gradient: computeOrgGradient(org.id),
|
||||
}
|
||||
}
|
||||
@@ -159,22 +175,28 @@ function inviteUser(): void {
|
||||
:class="collapsed ? 'h-[56px] flex items-center px-4' : 'px-4 py-2'"
|
||||
>
|
||||
<!--
|
||||
Collapsed: bare 32px rounded-lg button positioned at the same
|
||||
`px-4` left offset as the brand logo. No trigger container, no
|
||||
hover bg wider than the avatar — true mirror of the logo above.
|
||||
The `.ws-logo .ws-logo-square` classes carry the scoped
|
||||
inset-shadow (RFC §7.4) so the visual treatment matches the
|
||||
avatar in the expanded trigger.
|
||||
Collapsed: a bare click target (transparent, p-0, no box) wrapping
|
||||
the EXACT SAME avatar span markup the expanded trigger uses, so the
|
||||
32px square is byte-identical across states (same classes, same
|
||||
gradient, same `.ws-logo-square` inset-shadow). P6-styling-switcher-sub
|
||||
Fix A: previously the collapsed avatar styling lived directly on the
|
||||
<button>, which let user-agent button rendering diverge subtly from
|
||||
the expanded <span> avatar. Extracting the shared span removes that
|
||||
drift. The wrapping button only adds the click target + focus ring.
|
||||
-->
|
||||
<button
|
||||
v-if="collapsed && current"
|
||||
class="ws-logo ws-logo-square w-8 h-8 flex-shrink-0 rounded-lg inline-flex items-center justify-center text-white font-bold text-[12px] border-0 cursor-pointer focus-visible:outline focus-visible:outline-2 focus-visible:outline-[var(--p-primary-color)] focus-visible:outline-offset-2"
|
||||
:style="{ background: `linear-gradient(135deg, ${current.gradient[0]}, ${current.gradient[1]})` }"
|
||||
class="flex-shrink-0 border-0 bg-transparent p-0 cursor-pointer rounded-lg inline-flex focus-visible:outline focus-visible:outline-2 focus-visible:outline-[var(--p-primary-color)] focus-visible:outline-offset-2"
|
||||
:aria-label="`Workspace: ${current.name}`"
|
||||
aria-haspopup="true"
|
||||
@click="toggle"
|
||||
>
|
||||
{{ current.initials }}
|
||||
<span
|
||||
class="ws-logo ws-logo-square w-8 h-8 flex-shrink-0 rounded-lg inline-flex items-center justify-center text-white font-bold text-[12px]"
|
||||
:style="{ background: `linear-gradient(135deg, ${current.gradient[0]}, ${current.gradient[1]})` }"
|
||||
>
|
||||
{{ current.initials }}
|
||||
</span>
|
||||
</button>
|
||||
|
||||
<!--
|
||||
@@ -199,7 +221,7 @@ function inviteUser(): void {
|
||||
{{ current.initials }}
|
||||
</span>
|
||||
|
||||
<!-- Meta: name (AD-2.5-W1 / P4: no sub). -->
|
||||
<!-- Meta: name + placeholder sub line (P6-styling-switcher-sub). -->
|
||||
<span
|
||||
v-if="current"
|
||||
class="meta flex flex-1 min-w-0 flex-col text-left leading-[1.2]"
|
||||
@@ -207,6 +229,9 @@ function inviteUser(): void {
|
||||
<span class="name truncate text-[13.5px] font-semibold text-[var(--p-text-color)]">
|
||||
{{ current.name }}
|
||||
</span>
|
||||
<span class="sub truncate text-[11.5px] text-[var(--p-text-muted-color)]">
|
||||
{{ current.sub }}
|
||||
</span>
|
||||
</span>
|
||||
|
||||
<Icon
|
||||
@@ -251,12 +276,13 @@ function inviteUser(): void {
|
||||
>{{ ws.initials }}</span>
|
||||
|
||||
<!--
|
||||
Name only. AD-2.5-W1 option A: no .sub line on dropdown items
|
||||
until WORKSPACE-DROPDOWN-SUB-CONTENT RFC lands with backend
|
||||
(organisations.type enum + metrics endpoint).
|
||||
Name + placeholder sub line (P6-styling-switcher-sub reverses
|
||||
AD-2.5-W1 option A). Real org type + metrics still deferred
|
||||
under WORKSPACE-DROPDOWN-SUB-CONTENT.
|
||||
-->
|
||||
<span>
|
||||
<div class="name text-[14px] font-semibold text-[var(--p-text-color)]">{{ ws.name }}</div>
|
||||
<span class="min-w-0">
|
||||
<div class="name truncate text-[14px] font-semibold text-[var(--p-text-color)]">{{ ws.name }}</div>
|
||||
<div class="sub mt-[2px] truncate text-[12.5px] text-[var(--p-text-muted-color)]">{{ ws.sub }}</div>
|
||||
</span>
|
||||
|
||||
<!-- Check mark for active org -->
|
||||
|
||||
Reference in New Issue
Block a user