A tab bar's edge fade that stays hidden until something is off the edge

The local-attached covers were as wide as the scroll shadows and solid for
only 40% of that, so most of each shadow showed at rest -- invisible on Moria,
a grey sliver at both ends of every tab bar on Shire. The covers are now twice
the shadow's width and solid across all of it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-09-28 06:53:45 +00:00
co-authored by Claude Opus 5.5
parent db22962164
commit dfd8418d95
4 changed files with 39 additions and 4 deletions
+9
View File
@@ -16,6 +16,15 @@ for 1.0.0 have something to be assembled from.
## Unreleased ## Unreleased
## 1.8.5
- **No more grey slivers at the ends of the tab bars.** Tab bars fade at an edge
to show there are more tabs to scroll to. The fade was only partly hidden
when there was nothing to scroll, so a shadow always showed at both ends. It
was invisible on the dark theme and a grey sliver on Shire, on Administration
→ Prompts, Settings and every other tabbed page. The fade now appears only
on the side where tabs are actually hidden.
## 1.8.4 ## 1.8.4
Two things that kept showing up after they should have gone away. Two things that kept showing up after they should have gone away.
+1 -1
View File
@@ -1,3 +1,3 @@
"""LLeMbas - a Middle-earth themed web UI for OpenAI-compatible LLM endpoints.""" """LLeMbas - a Middle-earth themed web UI for OpenAI-compatible LLM endpoints."""
__version__ = "1.8.4" __version__ = "1.8.5"
+11 -3
View File
@@ -167,16 +167,24 @@ a.tabs__tab { text-decoration: none; }
pinned to the scrollport with `background-attachment: local`, which is the old pinned to the scrollport with `background-attachment: local`, which is the old
trick and works everywhere -- the `local` layers scroll with the content and trick and works everywhere -- the `local` layers scroll with the content and
cover the `scroll` ones exactly when there is nothing more to see. cover the `scroll` ones exactly when there is nothing more to see.
⚠ "Cover" has to mean all of it. The covers used to be as wide as the
shadows and solid for only 40% of that width, so the other 60% of every
shadow always showed through, with nothing to scroll to. On Moria that is
near-black on near-black and nobody saw it. On Shire it was a grey sliver at
both ends of every tab bar. Each cover is now twice the shadow's width and
solid across the first half, which is the whole shadow. It fades only past
the shadow's end, so once content is scrolled the shadow shows as before.
*/ */
.tabs__bar { .tabs__bar {
background-image: background-image:
linear-gradient(to right, var(--bg) 40%, transparent), linear-gradient(to right, var(--bg) 50%, transparent),
linear-gradient(to left, var(--bg) 40%, transparent), linear-gradient(to left, var(--bg) 50%, transparent),
linear-gradient(to right, var(--scrim), transparent 1.5rem), linear-gradient(to right, var(--scrim), transparent 1.5rem),
linear-gradient(to left, var(--scrim), transparent 1.5rem); linear-gradient(to left, var(--scrim), transparent 1.5rem);
background-position: left center, right center, left center, right center; background-position: left center, right center, left center, right center;
background-repeat: no-repeat; background-repeat: no-repeat;
background-size: 1.5rem 100%; background-size: 3rem 100%, 3rem 100%, 1.5rem 100%, 1.5rem 100%;
background-attachment: local, local, scroll, scroll; background-attachment: local, local, scroll, scroll;
/* A tab is a destination, so a flick should land on one rather than between /* A tab is a destination, so a flick should land on one rather than between
two. */ two. */
+18
View File
@@ -201,6 +201,24 @@ def test_a_tab_switch_moves_only_the_container_that_scrolls():
assert "outer.scrollTop" in handler assert "outer.scrollTop" in handler
def test_the_tab_bar_edge_fade_is_covered_when_nothing_overflows():
"""The covers were as wide as the shadows and solid for only 40% of that,
so 60% of each shadow showed through with nothing to scroll to. On Shire
that was a grey sliver at both ends of every tab bar. A cover has to be
solid across the whole shadow. Measured in headless Chromium on
/admin/prompts and /settings in both themes before and after.
"""
admin = (ROOT / "web/static/css/admin.css").read_text(encoding="utf-8")
start = admin.index("background-attachment: local, local, scroll, scroll")
block = admin[admin.rindex(".tabs__bar {", 0, start) : start]
cover = re.search(r"linear-gradient\(to right, var\(--bg\) (\d+)%, transparent\)", block)
shadow = re.search(r"var\(--scrim\), transparent ([\d.]+)rem", block)
sizes = re.search(r"background-size: ([\d.]+)rem 100%, [\d.]+rem 100%, ([\d.]+)rem 100%", block)
assert cover and shadow and sizes, "the edge-fade rule changed shape; re-check it by eye"
solid = float(sizes.group(1)) * int(cover.group(1)) / 100
assert solid >= float(shadow.group(1)) == float(sizes.group(2))
def test_the_two_ends_of_the_shell_stay_level(): def test_the_two_ends_of_the_shell_stay_level():
"""The sidebar footer and the composer sit either side of the same vertical """The sidebar footer and the composer sit either side of the same vertical
edge and are both content-sized, so without a common floor they end at edge and are both content-sized, so without a common floor they end at