A file list's icon cell had the class icon, which the stylesheet gives the svg icon: inline-block, 16px square. The cell stopped being a table cell, so a hovered row painted a small block behind the icon and another behind the name, offset from each other. The cell is file-icon now, the icon rule names svg.icon, and the hover background goes on the row, not on each cell. A row's own link stays ink on hover, underlined, rather than turning blue.
- commit
- 7d3519b8032a2663d1f4400b4d53b1fb21ae13cb
- parent
- d08b3dad5c639d304c379802410a9e62fbcaefb8
- author
- cat <admin@dev.site>
- ci
- ✓ passed in 80s, signed by cat
- kind
- fix risk score 1.6 of 3, Jev's estimate
- review
- #16 Panels with a head strip for content, and an even row hover
ci attestation
forge-attestation 1 type ci commit 7d3519b8032a2663d1f4400b4d53b1fb21ae13cb tree 7bf3e5f75c9d0bfbd6f0c66e8d524fd52fb9af59 script .forge/ci aa9f4eac26627c6559e68cd4b5e5e76afb8e65e8 result pass exit 0 started 2026-10-19T03:54:52Z duration 80s runner (not shown here; refs/notes/ci has it) system Darwin 25.5.0 arm64 env host log sha256:a436c8d6a04a0586d9de0b7bcaa292ca0029d14f1c6fbff549d095b82560b305 264 lines |pushed wip/i18n |0665eba running .forge/ci: greet.sh: say what it is | | sh: /bin/sh | | ok greet |0665eba pass in 0s, signed |pushed main |remote: review #4: /dami/greet/reviews/4/ |pushed wip/i18n |9b61cbd running .forge/ci: wave at the world | | sh: /bin/sh | | FAIL greet : got 'hello, world o/', want 'hello, world' |9b61cbd fail in 0s, signed |forge: 1 commit(s) did not pass |remote: review #6: /dami/greet/reviews/6/ |pushed ana/wave |3afc1fc running .forge/ci: update the test for the wave | | sh: /bin/sh | | ok greet |3afc1fc pass in 0s, signed |remote: review #6: /dami/greet/reviews/6/ |pushed ana/wave |warning: You appear to have cloned an empty repository. |site home: deployed 2085958 -> /sites/ana/dotfiles/home/ |created ana/notes |remote: review #1: /ana/notes/reviews/1/ |pushed ana/todo |landing #1 A todo list: ana/todo -> main |7943121 running .forge/ci: web, server and Python versions of greet | | sh: /bin/sh | | ok greet |7943121 pass in 0s, signed |pushed main |3d9e89a running .forge/ci: messages: notes for the later regions | | sh: /bin/sh | | ok greet |3d9e89a pass in 0s, signed |remote: review #7: /dami/greet/reviews/7/ |pushed dami/regions |created dami/forge |warning: You appear to have cloned an empty repository. |site guide: mkdir -p guide/fonts && cp site/assets/fonts/*.woff2 guide/fonts/ |site guide: deployed c4cc6a2 -> /sites/dami/forge/guide/ |(node:46931) ExperimentalWarning: stripTypeScriptTypes is an experimental feature and might change at any time |(Use `node --trace-warnings ...` to show where the warning was created) |built ana/dotfiles in 0s -> /var/folders/b4/mv8w4c8j0zj0_mldppxdbdw00000gn/T/forge-ci.NKoClD/wt/demo/root/.forge/www |(node:47059) ExperimentalWarning: stripTypeScriptTypes is an experimental feature and might change at any time |(Use `node --trace-warnings ...` to show where the warning was created) |built ana/notes in 1s -> /var/folders/b4/mv8w4c8j0zj0_mldppxdbdw00000gn/T/forge-ci.NKoClD/wt/demo/root/.forge/www |(node:47202) ExperimentalWarning: stripTypeScriptTypes is an experimental feature and might change at any time |(Use `node --trace-warnings ...` to show where the warning was created) |built dami/forge in 0s -> /var/folders/b4/mv8w4c8j0zj0_mldppxdbdw00000gn/T/forge-ci.NKoClD/wt/demo/root/.forge/www |(node:47335) ExperimentalWarning: stripTypeScriptTypes is an experimental feature and might change at any time |(Use `node --trace-warnings ...` to show where the warning was created) |built dami/greet in 2s -> /var/folders/b4/mv8w4c8j0zj0_mldppxdbdw00000gn/T/forge-ci.NKoClD/wt/demo/root/.forge/www |(node:48001) ExperimentalWarning: stripTypeScriptTypes is an experimental feature and might change at any time |(Use `node --trace-warnings ...` to show where the warning was created) |built - in 0s -> /var/folders/b4/mv8w4c8j0zj0_mldppxdbdw00000gn/T/forge-ci.NKoClD/wt/demo/root/.forge/www |234 of 234 pages render the same without 11ty |guide: 8 files, links ok |ok
Signature: good, cat
| M | site/ | 4 | ++-- |
| M | site/ | 22 | ++++++++++------------ |
| A | test/ | 23 | +++++++++++++++++++++++ |
@@ -129,9 +129,9 @@
129129 {% macro files(entries, parentHref) %}130130 <table class="list files nav">131131 <tbody>132-{% if parentHref %}<tr><td class="icon">{{ ui.icon('up') }}</td><td class="main"><a href="{{ parentHref }}" data-key="u">..</a></td><td></td></tr>{% endif %}132+{% if parentHref %}<tr><td class="file-icon">{{ ui.icon('up') }}</td><td class="main"><a href="{{ parentHref }}" data-key="u">..</a></td><td></td></tr>{% endif %}133133 {% for e in entries %}134-<tr><td class="icon">{{ ui.icon('folder' if e.type == 'tree' else ('link' if e.type == 'commit' else 'file')) }}</td><td class="main">{% if e.href %}<a href="{{ e.href }}">{{ e.name }}</a>{% else %}{{ e.name }} <span class="desc">@ {{ e.oid | short }}</span>{% endif %}</td><td class="num size">{{ e.size | size if e.type == 'blob' else '' }}</td></tr>134+<tr><td class="file-icon">{{ ui.icon('folder' if e.type == 'tree' else ('link' if e.type == 'commit' else 'file')) }}</td><td class="main">{% if e.href %}<a href="{{ e.href }}">{{ e.name }}</a>{% else %}{{ e.name }} <span class="desc">@ {{ e.oid | short }}</span>{% endif %}</td><td class="num size">{{ e.size | size if e.type == 'blob' else '' }}</td></tr>135135 {% endfor %}136136 </tbody>137137 </table>@@ -178,7 +178,7 @@ h3 { font-size: var(--text-md); margin: var(--space-6) 0 var(--space-2); }
178178 .wrap { max-width: 1280px; margin: 0 auto; padding: 0 var(--space-4); }179179 kbd { border: var(--hairline) solid var(--border-strong); padding: 0 var(--space-1); color: var(--muted); background: var(--raised); }180180 hr { border: 0; border-top: var(--hairline) solid var(--border); margin: var(--space-6) 0; }181-.icon { display: inline-block; width: 16px; height: 16px; flex: none; vertical-align: -3px; }181+svg.icon { display: inline-block; width: 16px; height: 16px; flex: none; vertical-align: -3px; }182182 183183 /* header: on the page, over a rule that the current tab's bar sits on */184184 header.site { border-bottom: var(--hairline) solid var(--border); }@@ -282,11 +282,13 @@ table.list td.date time { font-size: inherit; }
282282 table.list .nowrap, table.list .date, table.list .sha, table.list td.mono { white-space: nowrap; }283283 table.list td.mono { font-size: var(--text-sm); }284284 table.list td.main { width: 100%; overflow-wrap: anywhere; }285-/* A row's own link (a subject, a file, a branch) is in ink; other links stay blue. */286-table.list td.main > a:first-of-type, .files td.main a { color: var(--fg); font-weight: var(--fw-medium); }287-table.list td.main > a:first-of-type:hover, .files td.main a:hover { color: var(--deep); }288-table.list tbody tr:hover td, table.list tbody tr:focus-within td, table.list tbody tr.sel td { background: var(--hover); }289-table.list tbody tr.sel td:first-child { box-shadow: inset 2px 0 0 var(--accent); }285+/* A row's own link (a subject, a file, a branch) is in ink, and stays ink286+ on hover; other links are blue. */287+table.list td.main > a:first-of-type { color: var(--fg); font-weight: var(--fw-medium); }288+table.list td.main > a:first-of-type:hover { color: var(--fg); }289+/* Hover tints the row, never a cell or a link, so it is one even block. */290+table.list tbody tr:hover, table.list tbody tr:focus-within, table.list tbody tr.sel { background: var(--hover); }291+table.list tbody tr.sel > td:first-child { box-shadow: inset 2px 0 0 var(--accent); }290292 /* A box holds a list or prose under a heading row; only a file viewer291293 (.viewer) is a bordered region. */292294 .box + .box { margin-top: var(--space-6); }@@ -297,8 +299,7 @@ table.list tbody tr.sel td:first-child { box-shadow: inset 2px 0 0 var(--accent)
297299 .box.viewer > .box-head { padding: var(--space-1) var(--space-3); align-items: center; }298300 .box.viewer > table.list tr:last-child td { border-bottom: 0; }299301 .files td { padding-top: var(--space-1); padding-bottom: var(--space-1); }300-.files td.icon { width: 1.75em; color: var(--muted); padding-right: 0; }301-.files td.icon .icon { vertical-align: -3px; }302+.files td.file-icon { width: 1.75em; color: var(--muted); padding-right: 0; }302303 .files td.size { color: var(--muted); }303304 .empty { color: var(--muted); padding: var(--space-6); text-align: center; }304305 @@ -307,11 +308,8 @@ table.list tbody tr.sel td:first-child { box-shadow: inset 2px 0 0 var(--accent)
307308 table.list.stack tr { display: flex; flex-wrap: wrap; gap: var(--space-half) var(--space-3); padding: var(--space-2); border-bottom: var(--hairline) solid var(--border); }308309 table.list.stack td { border: 0; padding: 0; font-size: var(--text-sm); color: var(--muted); }309310 table.list.stack td.main { flex: 0 0 100%; font-size: var(--text-md); color: var(--fg); }310- /* a stacked row is one block: paint the row, not each cell, so the gaps between cells don't show */311- table.list.stack tbody tr:hover, table.list.stack tbody tr:focus-within, table.list.stack tbody tr.sel { background: var(--hover); }312- table.list.stack tbody tr td { background: none; }313311 table.list.stack tbody tr.sel { box-shadow: inset 2px 0 0 var(--accent); }314- table.list.stack tbody tr.sel td:first-child { box-shadow: none; }312+ table.list.stack tbody tr.sel > td:first-child { box-shadow: none; }315313 table.list.stack .hide-sm { display: none; }316314 table.list.stack td { order: 2; }317315 table.list.stack td.main { order: 0; }@@ -0,0 +1,23 @@
1+# A hovered row is one even tint: the hover background is on the row, never2+# on a table cell, and no cell borrows the icon's class (a td.icon took the3+# svg's inline-block size and painted its own small block). The forge's4+# CSS has no hover rule that tints a td or th, and no built page has an5+# element other than an svg with the class icon.6+. "$(dirname "$0")/../lib.sh"7+css=$T_HOME/site8+if grep -rnE ':(hover|focus-within)[^{,]*[ >](td|th)([.:[][^{,]*)?[{,][^}]*background' "$css" --include=*.css --include=*.njk; then9+ fail "a hover rule tints a cell, not its row"10+fi11+has "$css/assets/style.css" '^table\.list tbody tr:hover, table\.list tbody tr:focus-within, table\.list tbody tr\.sel \{ background: var\(--hover\); \}'12+has "$css/assets/style.css" '^svg\.icon \{'13+user dami14+repo dami/greet15+clone dami dami/greet "$T/w/g"16+at "$T/w/g" commit "first"17+at "$T/w/g" commit "docs" docs/a.md18+push_as dami "$T/w/g" origin main19+build20+for f in "$FORGE_WWW/dami/greet/index.html" "$FORGE_WWW/dami/greet/tree/main/docs/index.html"; do21+ has "$f" 'class="file-icon"'22+ if grep -oE '<[a-z][a-z0-9]* class="([^"]* )?icon( [^"]*)?"' "$f" | grep -v '^<svg '; then fail "$f: a non-svg element has the class icon"; fi23+done