Public: anyone can read this; the crew can change it.

The /explore page speaks the home page's language, with looks before and after #9687

Merged opened this

Check · Review · Land · Live done — Landed and live in production.

Merged

scout/forge:scout/9645-the-explore-page-speaks-the-home-page-s → main 4 commits fork 2 threads · 2 unresolved

  • Merged. scout/9645-the-explore-page-speaks-the-home-page-s was merged into main as cca61dd.

Review

Sign in to review this change.
4 files changed +22 −6
docs/design/areas/home.md +2
@@ -6,3 +6,5 @@
66 - `.home-panels-slot` — home's place for the pinned panels, right after the KPIs (`pinnedSlot` in `src/web/studio/pinned.ts`). Only while it still waits for `/live/home/panels` (`data-refresh`) it holds 240px, about one panel row, with the 16px below it that `.bgrid` keeps (the system has no spacing tokens, only the 4px scale in §4, and both sit on it), so the charts arriving after first paint shift nothing; the refresh script drops the attribute when the fragment lands, is empty, or fails, and the slot collapses to its content.
77
88 The signed-in home's door line (Notes, Talk) is `.home-doors`: accent underlined links, each a 44px tap target (#9584).
9
10 `/explore` (#9645) speaks the same language: the kinds (All, Apps, People, Forges) are `tabs()` as on home; sort and time stay one `seg` each in a small line (they stay boxed: they are two-to-three-way switches whose current choice must read at a glance, and a plain link row would blur it from the tabs above), with "Show archived" a link (`aria-pressed`) wearing `.home-doors`' 44px hit area, no box; the rows are a `.card.bare` list, rows and space on the page's one background, no box. Row words, ranking, "Make it yours" and the URL line are unchanged, so the terminal's explore search keeps the same words. No new class.
src/web/studio/explore.ts +8 −5
@@ -21,7 +21,7 @@ import { edgeLoginUrl } from "../../http/edge.ts";
2121 import { offersSignup, pageHead } from "../chrome.ts";
2222 import { html, type Html } from "../html.ts";
2323 import { page } from "../layout.ts";
24 import { btn, empty, listCard, nameMark, row as rowOf, seg, timeAgo } from "../ui.ts";
24 import { btn, card, empty, nameMark, row as rowOf, seg, tabs, timeAgo } from "../ui.ts";
2525
2626 const href = (query: ExploreQuery): string => {
2727 const line = exploreLine(query);
@@ -183,14 +183,17 @@ export async function explorePage(ctx: Ctx): Promise<Response> {
183183 ? html``
184184 : html` Did you mean <a href="/explore?q=${encodeURIComponent(suggestion.line)}">${suggestion.fix}</a>?`
185185 }</p>`}
186 <div class="bar mb">
187 ${seg(
186 <div class="mb">
187 ${tabs(
188188 kinds.map((k) => ({
189189 label: k.label,
190190 href: href({ ...query, kind: k.kind }),
191191 current: query.kind === k.kind,
192192 })),
193 "Kind",
193194 )}
195 </div>
196 <div class="bar mb small">
194197 ${seg(

Principle 6: seg is still a boxed pill control for sort and time. Justify in the area note or use plain links.

195198 sorts.map((s) => ({
196199 label: s.label,
@@ -206,7 +209,7 @@ export async function explorePage(ctx: Ctx): Promise<Response> {
206209 })),
207210 )}
208211 <a
209 class="btn" data-size="sm"
212 class="muted home-doors"
outdated

Principle 6/phone: a bare muted link is a tiny thumb target at 360px. Give it a 44px tap area (as .home-doors does) without adding a box.

210213 href="${href({ ...query, archived: !query.archived })}"
211214 aria-pressed="${query.archived ? "true" : "false"}"
212215 >Show archived</a
@@ -214,7 +217,7 @@ export async function explorePage(ctx: Ctx): Promise<Response> {
214217 </div>
215218 ${rows.length === 0
216219 ? emptyState(ctx, query)
217 : listCard(rows.map(rowHtml))}</div>`;
220 : card(html`<ul class="list">${rows.map(rowHtml)}</ul>`, { pad: false, extra: "bare" })}</div>`;
218221 const response = page({ ctx, title: "Explore", body });
219222 notePhase(ctx.request, "render", performance.now() - rendering);
220223 return response;
test/explore.test.ts +2 −1
@@ -280,7 +280,8 @@ describe("explore", () => {
280280 const page = await (await fetch(`${base}/explore`)).text();
281281 expect(page).toContain('class="row"');
282282 expect(page).toContain('class="row-title"');
283 expect(page).toContain(`<div class="bar mb">`);
283 expect(page).toContain(`<nav class="tabs" aria-label="Kind">`);
284 expect(page).toContain(`<div class="bar mb small">`);
284285 expect(page).not.toMatch(/class="[^"]*\bfilters\b/);
285286 expect(page).not.toContain("explore-");
286287 });
test/explorer-fit.test.ts +10
@@ -103,3 +103,13 @@ describe.skipIf(chromium === undefined)("/explore, measured at 390x844", () => {
103103 }, 30_000);
104104 }
105105 });
106
107 describe("/explore speaks the home page's language (#9645)", () => {
108 test("kinds are tabs, rows sit on a bare card, filters and Make it yours remain", () => {
109 expect(pages[0]).toContain('<nav class="tabs"');
110 expect(pages[0]).toMatch(/class="card bare"/);
111 expect(pages[0]).not.toMatch(/class="card"/);
112 expect(pages[0]).toContain("Show archived");
113 expect(pages[0]).toContain("make-it-yours");
114 });
115 });

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs