diff --git a/apps/app/src/components/ui/theme.css b/apps/app/src/components/ui/theme.css index b6f39ed6ea..e5f0b0611b 100644 --- a/apps/app/src/components/ui/theme.css +++ b/apps/app/src/components/ui/theme.css @@ -191,6 +191,10 @@ min-height: var(--bb-sidebar-sticky-tier-height); z-index: var(--bb-sidebar-sticky-tier-z-index); isolation: isolate; + /* Native vibrancy can make a sidebar paint translucent. The image keeps + opaque themes unchanged. The shield below blurs rows beneath a + translucent tier instead of letting them collide with its label. */ + background-image: linear-gradient(var(--sidebar), var(--sidebar)); } [data-sidebar-sticky-stack] [data-sidebar-sticky-tier]::before, @@ -202,11 +206,14 @@ z-index: -1; pointer-events: none; background-color: var(--sidebar); + background-image: linear-gradient(var(--sidebar), var(--sidebar)); + backdrop-filter: blur(16px); } [data-sidebar-sticky-stack] [data-sidebar-sticky-tier]::before { - bottom: 100%; - height: var(--bb-sidebar-sticky-tier-shield-top-height, 0); + top: calc(-1 * var(--bb-sidebar-sticky-tier-shield-top-height, 0)); + bottom: auto; + height: calc(100% + var(--bb-sidebar-sticky-tier-shield-top-height, 0)); } [data-sidebar-sticky-stack] [data-sidebar-sticky-tier]::after { diff --git a/apps/app/src/components/ui/theme.test.ts b/apps/app/src/components/ui/theme.test.ts index a571adbf3c..bd3d9e489c 100644 --- a/apps/app/src/components/ui/theme.test.ts +++ b/apps/app/src/components/ui/theme.test.ts @@ -133,6 +133,29 @@ function contrastRatio(foreground: OklchColor, background: OklchColor): number { } describe("theme.css neutral ramp", () => { + it("prevents rows from reading through every sticky sidebar tier", () => { + const rule = css.match( + /\[data-sidebar-sticky-stack\] \[data-sidebar-sticky-tier\]\s*\{([^}]*)\}/s, + )?.[1]; + + expect(rule).toContain( + "background-image: linear-gradient(var(--sidebar), var(--sidebar));", + ); + expect(rule).not.toContain("backdrop-filter"); + + const shieldRule = css.match( + /\[data-sidebar-sticky-stack\] \[data-sidebar-sticky-tier\]::before,\s*\[data-sidebar-sticky-stack\] \[data-sidebar-sticky-tier\]::after\s*\{([^}]*)\}/s, + )?.[1]; + expect(shieldRule).toContain("backdrop-filter: blur(16px);"); + + const topShieldRule = css.match( + /\[data-sidebar-sticky-stack\] \[data-sidebar-sticky-tier\]::before\s*\{([^}]*)\}/s, + )?.[1]; + expect(topShieldRule).toContain( + "100% + var(--bb-sidebar-sticky-tier-shield-top-height, 0)", + ); + }); + it("backs selected sticky sidebar rows with an opaque sidebar layer", () => { const rule = css.match( /\[data-sidebar-sticky-tier\]\.bb-sidebar-selected-row\s*\{([^}]*)\}/s,