Skip to content

Commit 76413da

Browse files
authored
Soften the dark theme and widen the issues column (#44)
Idle services and out-of-scope rows keep readable text instead of fading with opacity, and the issues column grows with the window.
1 parent a8016ff commit 76413da

2 files changed

Lines changed: 65 additions & 13 deletions

File tree

‎release_scope/_static/index.html‎

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -14,26 +14,29 @@
1414
</script>
1515
<style>
1616
:root {
17-
--bg: #ffffff; --fg: #1f2328; --muted: #656d76; --border: #d0d7de; --panel: #f6f8fa;
17+
--bg: #ffffff; --fg: #1f2328; --muted: #656d76; --faint: #6e7781; --border: #d0d7de; --panel: #f6f8fa;
1818
--accent: #0969da; --bad: #cf222e; --warn: #9a6700; --good: #1a7f37;
19+
--pill-bg: var(--accent); --pill-fg: var(--bg);
1920
color-scheme: light;
2021
}
2122
@media (prefers-color-scheme: dark) {
2223
:root:not([data-theme="light"]) {
23-
--bg: #0d1117; --fg: #e6edf3; --muted: #8d96a0; --border: #30363d; --panel: #161b22;
24-
--accent: #4493f8; --bad: #f85149; --warn: #d29922; --good: #3fb950;
24+
--bg: #22272e; --fg: #cdd5df; --muted: #a3adb8; --faint: #959fa9; --border: #444c56; --panel: #2d333b;
25+
--accent: #7cb9ff; --bad: #f8817a; --warn: #daaa3f; --good: #5fbf72;
26+
--pill-bg: color-mix(in srgb, var(--accent) 20%, transparent); --pill-fg: var(--accent);
2527
color-scheme: dark;
2628
}
2729
}
2830
:root[data-theme="dark"] {
29-
--bg: #0d1117; --fg: #e6edf3; --muted: #8d96a0; --border: #30363d; --panel: #161b22;
30-
--accent: #4493f8; --bad: #f85149; --warn: #d29922; --good: #3fb950;
31+
--bg: #22272e; --fg: #cdd5df; --muted: #a3adb8; --faint: #959fa9; --border: #444c56; --panel: #2d333b;
32+
--accent: #7cb9ff; --bad: #f8817a; --warn: #daaa3f; --good: #5fbf72;
33+
--pill-bg: color-mix(in srgb, var(--accent) 20%, transparent); --pill-fg: var(--accent);
3134
color-scheme: dark;
3235
}
3336
[x-cloak] { display: none !important; }
3437
* { box-sizing: border-box; }
3538
body { margin: 0; background: var(--bg); color: var(--fg); font: 14px/1.5 system-ui, sans-serif; }
36-
main { max-width: 1680px; margin: 0 auto; padding: 16px; }
39+
main { max-width: 2048px; margin: 0 auto; padding: 16px; }
3740
h1 { font-size: 24px; margin: 0 0 4px; }
3841
h2 { font-size: 18px; margin: 32px 0 8px; border-bottom: 1px solid var(--border); padding-bottom: 4px; }
3942
a { color: var(--accent); text-decoration: none; }
@@ -56,7 +59,7 @@
5659
.warn { color: var(--warn); }
5760
.message { white-space: pre-line; }
5861
.scroll { overflow-x: auto; }
59-
.layout { display: grid; grid-template-columns: minmax(0, 1fr) 420px; gap: 24px; align-items: start; }
62+
.layout { display: grid; grid-template-columns: minmax(0, 1fr) clamp(420px, 32vw, 640px); gap: 24px; align-items: start; }
6063
.layout > aside { position: sticky; top: 0; max-height: 100vh; overflow-y: auto; padding: 0 4px 16px; }
6164
.strip { display: none; writing-mode: vertical-rl; width: 40px; min-height: 240px; margin-top: 32px; padding: 12px 4px;
6265
border-color: var(--accent); color: var(--accent); font-weight: 600; }
@@ -72,7 +75,7 @@
7275
.tabs { display: flex; flex-wrap: wrap; gap: 4px; margin: 8px 0; }
7376
.outputs textarea { min-height: 160px; }
7477
.out-head { display: flex; justify-content: flex-end; gap: 8px; flex-wrap: wrap; }
75-
tr.out-of-scope td { opacity: 0.55; }
78+
tr.out-of-scope td, tr.out-of-scope .muted { color: var(--faint); }
7679
tr.shipped td { background: color-mix(in srgb, var(--accent) 12%, transparent); }
7780
.tag { white-space: nowrap; }
7881
.service { border: 1px solid var(--border); border-radius: 6px; margin: 6px 0; }
@@ -82,9 +85,9 @@
8285
.service.deployed { border-left: 4px solid var(--good); background: color-mix(in srgb, var(--good) 6%, transparent); }
8386
.service.deployed .name { color: var(--good); }
8487
.chip { display: inline-flex; align-items: center; gap: 4px; padding: 0 4px 0 10px; border-radius: 999px;
85-
background: var(--accent); color: var(--bg); font-weight: 600; }
88+
background: var(--pill-bg); color: var(--pill-fg); font-weight: 600; }
8689
.chip button { border: 0; border-radius: 999px; padding: 0 6px; background: transparent; color: inherit; }
87-
.chip button:hover { background: color-mix(in srgb, var(--bg) 25%, transparent); }
90+
.chip button:hover { background: color-mix(in srgb, currentColor 25%, transparent); }
8891
.service > summary::before { content: "▸"; color: var(--muted); }
8992
.service[open] > summary::before { content: "▾"; }
9093
.service .name { min-width: 200px; font-weight: 600; }
@@ -96,11 +99,12 @@
9699
.status-done { color: var(--good); background: color-mix(in srgb, var(--good) 12%, transparent); }
97100
button.picked { border-color: var(--accent); color: var(--accent); }
98101
.service.involved { border-color: var(--accent); }
99-
.service.idle { opacity: 0.45; }
102+
.service.idle:not(.deployed) { border-style: dashed; }
103+
.service.idle > summary, .service.idle > summary :is(.name, .muted, .warn, .bad) { color: var(--faint); }
100104
.service.unlisted { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; padding: 8px 12px; border-style: dashed; }
101105
.plan-line { flex-basis: 100%; display: flex; flex-wrap: wrap; gap: 4px 14px; align-items: center; padding-left: 14px; }
102106
.plan-line > span { display: inline-flex; flex-wrap: wrap; gap: 4px; align-items: center; }
103-
.key { padding: 0 8px; border: 1px solid var(--accent); border-radius: 999px; font-size: 12px; background: var(--accent); color: var(--bg); }
107+
.key { padding: 0 8px; border: 1px solid var(--accent); border-radius: 999px; font-size: 12px; background: var(--pill-bg); color: var(--pill-fg); }
104108
.key.rider { border-style: dashed; border-color: var(--warn); background: transparent; color: var(--warn); }
105109
.cell { padding: 0 6px; border-radius: 4px; font-size: 12px; white-space: nowrap; }
106110
.cell-tag { background: color-mix(in srgb, var(--accent) 14%, transparent); color: var(--accent); }
@@ -119,7 +123,7 @@
119123
align-items: center; height: 48px; padding: 4px 8px; border-bottom: 1px solid var(--border); cursor: pointer; }
120124
.issue-row:hover { background: color-mix(in srgb, var(--accent) 5%, transparent); }
121125
.issue-row.chosen { background: color-mix(in srgb, var(--accent) 10%, transparent); }
122-
.issue-row code { font-weight: 600; }
126+
.issue-row code { font-weight: 500; }
123127
.issue-row .summary { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
124128
.issue-row .reach { grid-column: 3 / -1; display: flex; gap: 4px; overflow: hidden; white-space: nowrap; }
125129
.rider-mark { padding: 0 6px; border: 1px dashed var(--warn); border-radius: 999px; color: var(--warn); font-size: 11px; white-space: nowrap; }

‎tests/test_browser.py‎

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,3 +236,51 @@ def test_demo_a_hand_pick_survives_when_the_issue_is_unticked(page: Page, demo_s
236236
expect(web.locator(".chip > span")).to_have_text("1.9.1")
237237
expect(page).to_have_url(re.compile(r"#shop/web=1\.9\.1$"))
238238
assert errors == []
239+
240+
241+
_SHOWN_COLOR_JS: typing.Final = """element => {
242+
let alpha = 1;
243+
for (let node = element; node; node = node.parentElement) alpha *= Number(getComputedStyle(node).opacity);
244+
return [getComputedStyle(element).color, getComputedStyle(document.body).backgroundColor, alpha];
245+
}"""
246+
247+
248+
def _luminance(color: str) -> float:
249+
channels: typing.Final = [int(value) / 255 for value in re.findall(r"\d+", color)[:3]]
250+
linear: typing.Final = [
251+
value / 12.92 if value <= 0.04045 else ((value + 0.055) / 1.055) ** 2.4 for value in channels
252+
]
253+
return 0.2126 * linear[0] + 0.7152 * linear[1] + 0.0722 * linear[2]
254+
255+
256+
def _contrast(element: Locator) -> float:
257+
color, background, alpha = element.evaluate(_SHOWN_COLOR_JS)
258+
text, ground = _luminance(color), _luminance(background)
259+
shown: typing.Final = alpha * text + (1 - alpha) * ground
260+
return (max(shown, ground) + 0.05) / (min(shown, ground) + 0.05)
261+
262+
263+
@pytest.mark.parametrize("scheme", ["light", "dark"])
264+
def test_demo_an_idle_service_keeps_readable_text(
265+
page: Page, demo_site: str, errors: list[str], scheme: typing.Literal["light", "dark"]
266+
) -> None:
267+
page.emulate_media(color_scheme=scheme)
268+
page.goto(demo_site)
269+
_issue(page, "SHOP-38").check()
270+
271+
worker: typing.Final = _demo_service(page, "shop/worker")
272+
expect(worker).to_have_class(re.compile(r"\bidle\b"))
273+
for text in worker.locator("summary span:visible").all():
274+
assert _contrast(text) >= 4.5, text.inner_text()
275+
assert errors == []
276+
277+
278+
def test_demo_the_side_column_grows_with_a_wide_window(page: Page, demo_site: str, errors: list[str]) -> None:
279+
page.set_viewport_size({"width": 1920, "height": 900})
280+
page.goto(demo_site)
281+
282+
box: typing.Final = page.locator(".layout > aside").bounding_box()
283+
284+
assert box is not None
285+
assert box["width"] == pytest.approx(1920 * 0.32, abs=1)
286+
assert errors == []

0 commit comments

Comments
 (0)