Public: anyone can read this; the crew can change it.
The front page's app tiles draw §5's card and the look image, and .app-tile, .app-tile-body, .app-tile-desc, .app-tile-look, .app-tile-name leave the markup #4175
Check · Review · Land · Live done — Landed and live in production.
scout/forge:scout/4132-the-front-page-s-app-tiles-draw-5-s-card → main 1 commit fork 1 thread · 1 unresolved
2 files
changed +27
−17
src/web/studio/home.ts +19 −17
| @@ -312,23 +312,25 @@ export async function studioHome( | ||
| 312 | 312 | function tile(entry: FrontEntry): Html { |
| 313 | 313 | const { repo, state, picture } = entry; |
| 314 | 314 | if (picture === undefined) return html``; |
| 315 | return html`<a class="app-tile" href="${repoBase(repo)}"> | |
| 316 | <img | |
| 317 | class="app-tile-look" | |
| 318 | src="${picture}" | |
| 319 | width="${LOOK_SIZES.thumb.width}" | |
| 320 | height="${LOOK_SIZES.thumb.height}" | |
| 321 | alt="" | |
| 322 | loading="lazy" | |
| 323 | /> | |
| 324 | <span class="app-tile-body"> | |
| 325 | <span class="app-tile-name">${repo.name}</span> | |
| 326 | <span class="app-tile-desc truncate" title="${repo.description}" | |
| 327 | >${repo.description !== "" ? repo.description : repo.ownerName}</span | |
| 328 | > | |
| 329 | ${state !== undefined ? envStateBadge(state) : null} | |
| 330 | </span> | |
| 331 | </a>`; | |
| 315 | const href = repoBase(repo); | |
| 316 | return card( | |
| 317 | html`<a class="look" href="${href}" tabindex="-1" aria-hidden="true" | |
| 318 | ><img | |
| 319 | src="${picture}" | |
| 320 | width="${LOOK_SIZES.thumb.width}" | |
| 321 | height="${LOOK_SIZES.thumb.height}" | |
| 322 | alt="" | |
| 323 | loading="lazy" | |
| 324 | /></a> | |
| 325 | <div class="card-body stack stack-tight"> | |
| 326 | <a href="${href}"><strong>${repo.name}</strong></a> | |
| 327 | <span class="muted small truncate" title="${repo.description}" | |
| 328 | >${repo.description !== "" ? repo.description : repo.ownerName}</span | |
| 329 | > | |
| 330 | ${state !== undefined ? envStateBadge(state) : null} | |
| 331 | </div>`, | |
| 332 | { pad: false }, | |
| 333 | ); | |
| 332 | 334 | } |
| 333 | 335 | |
| 334 | 336 | /** |
test/front.test.ts +8
| @@ -440,6 +440,14 @@ describe("the front page", () => { | ||
| 440 | 440 | expect(body).not.toContain('href="/owner/moved"'); |
| 441 | 441 | // The shelf's tiles are the stranger's picture, at the thumb's size. |
| 442 | 442 | expect(body).toContain('width="640"'); |
| 443 | // The tiles are §5's card and look, not the page's own classes; the name | |
| 444 | // still links, the picture still links, and the words are there. | |
| 445 | for (const old of ["app-tile", "app-tile-body", "app-tile-desc", "app-tile-look", "app-tile-name"]) | |
| 446 | expect(body).not.toContain(old); | |
| 447 | const shelf = body.slice(body.indexOf('class="mt app-shelf"')); | |
| 448 | expect(shelf).toMatch(/<div\s+class="card"/); | |
| 449 | expect(shelf).toContain('<a class="look" href="/owner/one"'); | |
| 450 | expect(shelf).toMatch(/<a href="\/owner\/one"><strong>one<\/strong><\/a>/); | |
| 443 | 451 | const json = (await (await fetch(`${base}/api/v1/front`)).json()) as any; |
| 444 | 452 | expect(json.featured.repo).toBe("zed/loved"); |
| 445 | 453 | expect(json.featured.signals.forks).toBe(3); |
new above
offline
Picture link is hidden from AT and the tab order, which is right. The name link below is the only accessible target, so keep it first in the body and do not drop it.