From 0f768b6e20a2947cba799c71476bed065bbebf9f Mon Sep 17 00:00:00 2001 From: 4gray <4gray@users.noreply.github.com> Date: Tue, 29 Sep 2026 17:30:04 +0200 Subject: [PATCH] fix(dashboard): extend rail edge fades to the track clipping edge (#1731) --- .changes/dashboard-rail-edge-fade.md | 6 +++++ docs/architecture/workspace-dashboard.md | 4 ++++ .../lib/rails/dashboard-rail.component.scss | 22 ++++++++++++------- 3 files changed, 24 insertions(+), 8 deletions(-) create mode 100644 .changes/dashboard-rail-edge-fade.md diff --git a/.changes/dashboard-rail-edge-fade.md b/.changes/dashboard-rail-edge-fade.md new file mode 100644 index 000000000..f2cf900ba --- /dev/null +++ b/.changes/dashboard-rail-edge-fade.md @@ -0,0 +1,6 @@ +--- +type: fix +area: dashboard +--- + +Dashboard rails no longer show a thin strip of the partly visible card past the soft edge fade, and the focus outline of the first or last card in a rail is no longer cut off. diff --git a/docs/architecture/workspace-dashboard.md b/docs/architecture/workspace-dashboard.md index 352f8cb79..9ee6a4444 100644 --- a/docs/architecture/workspace-dashboard.md +++ b/docs/architecture/workspace-dashboard.md @@ -143,6 +143,10 @@ hooks: `dashboard-hero`, `dashboard-hero-slide` (`data-hero-kind`), optional `aspectRatio` (default `'2 / 3'`), optional `testId`. 2. Behavior: horizontal flex track with `scroll-snap-type: x mandatory`. 3. Chevron buttons fade in on hover (desktop only via `@media (hover: none)`). + Edge fades follow the chevrons' visibility. The track bleeds + `--rail-bleed` past the viewport on every side so card focus rings and + hover lift are not clipped; the fades are offset by the same variable so + they reach the track's clipping edge and no card strip shows beyond them. 4. Cards are keyboard-focusable router links; `scroll-snap-align: start` means arrow-key nav lands on card boundaries. 5. Image handling: `loading="lazy"`, `decoding="async"`, fallback icon tile diff --git a/libs/workspace/dashboard/feature/src/lib/rails/dashboard-rail.component.scss b/libs/workspace/dashboard/feature/src/lib/rails/dashboard-rail.component.scss index 4717177d3..485e34ced 100644 --- a/libs/workspace/dashboard/feature/src/lib/rails/dashboard-rail.component.scss +++ b/libs/workspace/dashboard/feature/src/lib/rails/dashboard-rail.component.scss @@ -3,6 +3,11 @@ --rail-card-width: var(--cover-rail-width, 172px); --rail-gap: var(--cover-gap, 14px); --rail-radius: 12px; + // How far the scrolling track bleeds past the viewport on every side: + // room for a card's focus ring (2px outline + 3px offset) plus its 2px + // hover lift, so neither is clipped. The track clips partially visible + // cards at this outer edge, so the edge fades extend by the same amount. + --rail-bleed: 8px; } .rail { @@ -81,13 +86,14 @@ // Soft edge gradients hint at horizontal scroll without any interaction. // Anchored to the viewport so they appear/disappear in sync with the - // chevrons' `.rail__chev--visible` state. + // chevrons' `.rail__chev--visible` state, but offset by the track bleed + // so each fade ends exactly where the track clips the partial card. &::before, &::after { content: ''; position: absolute; - top: 0; - bottom: 0; + top: calc(-1 * var(--rail-bleed)); + bottom: calc(-1 * var(--rail-bleed)); width: 32px; pointer-events: none; z-index: 1; @@ -96,7 +102,7 @@ } &::before { - left: 0; + left: calc(-1 * var(--rail-bleed)); background: linear-gradient( to right, var(--app-content-bg, #161a22) 0%, @@ -105,7 +111,7 @@ } &::after { - right: 0; + right: calc(-1 * var(--rail-bleed)); background: linear-gradient( to left, var(--app-content-bg, #161a22) 0%, @@ -135,10 +141,10 @@ overflow-x: auto; overflow-y: hidden; scroll-snap-type: x mandatory; - scroll-padding-inline-start: 4px; + scroll-padding-inline-start: var(--rail-bleed); scrollbar-width: none; - padding: 4px; - margin: -4px; + padding: var(--rail-bleed); + margin: calc(-1 * var(--rail-bleed)); &::-webkit-scrollbar { display: none;