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

Every search input sizes by one base rule, and `.search` leaves the stylesheet #6568

Merged opened this

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

Merged

scout/forge:scout/4750-every-search-input-sizes-by-one-base-rul → main 5 commits fork

  • Merged. scout/4750-every-search-input-sizes-by-one-base-rul was merged into main as 6466898.

Review

Sign in to review this change.
11 files changed +30 −10
docs/design/areas/search.md −1
@@ -1,3 +1,2 @@
11 # Search box
22
3 - `.search` — the search field of a filter or search form: an `.input` that grows to fill its row between 180px and 320px wide. Written by `searchPage` in `src/web/pages/search.ts` (the `/search` form), and by the filter forms in `src/web/pages/browse.ts`, `src/web/pages/org.ts`, `src/web/pages/origin-repos.ts` and `src/web/studio/explore.ts`. Styled in `src/web/style/content.ts` as `.bar .search` only.
docs/design/areas/shell.md +1 −1
@@ -12,4 +12,4 @@ The chrome every page sits in: a skip link, the sticky top bar with the wordmark
1212 - `.shell-wide` — on `<main class="shell">` when a page passes `wide`: from 1200px the column drops its reading width and keeps a 24px gutter, for the one layout that gains from every pixel (a tree beside a file).
1313 - `.bare` — the `<main>` of a page that owns the whole window: no top bar, no footer, no width or padding. Written when the page passes `bare: true` (the board, `src/web/pages/board.ts`).
1414 - `.foot` — the `<footer>` under every non-bare page: the mark, the links, the reduced-motion note.
15 - `.bar` — a wrapping row of controls with an 8px gap, used across pages for a header's actions, a filter bar or a line of meta (for instance `src/web/pages/commits.ts`, `src/web/pages/repo.ts`, the board's header in `src/web/pages/board.ts`). A `.field` directly inside drops its bottom margin and the row aligns to the end, so a labelled input and its button share a baseline. `.search`, `.seg` and `.device-code` inside it are styled in `src/web/style/content.ts`.
15 - `.bar` — a wrapping row of controls with an 8px gap, used across pages for a header's actions, a filter bar or a line of meta (for instance `src/web/pages/commits.ts`, `src/web/pages/repo.ts`, the board's header in `src/web/pages/board.ts`). A `.field` directly inside drops its bottom margin and the row aligns to the end, so a labelled input and its button share a baseline. `.seg` and `.device-code` inside it are styled in `src/web/style/content.ts`.
src/web/pages/browse.ts +1 −1
@@ -174,7 +174,7 @@ function filterBar(
174174 ${when(query.label !== "", () => hidden("label", query.label))}
175175 ${when(query.author !== "", () => hidden("author", query.author))}
176176 <input
177 class="input search"
177 class="input"
178178 type="search"
179179 name="q"
180180 value="${query.q}"
src/web/pages/org.ts +1 −1
@@ -104,7 +104,7 @@ function repoSection(
104104 return html`<div class="bar mt mb">
105105 <form class="bar" method="get" action="/${owner.username}" role="search">
106106 <input
107 class="input search"
107 class="input"
108108 type="search"
109109 name="q"
110110 value="${query}"
src/web/pages/origin-repos.ts +1 −1
@@ -67,7 +67,7 @@ export async function originReposPage(ctx: Ctx): Promise<Response> {
6767
6868 const filter = html`<form class="bar mb" method="get" action="${base}">
6969 <input
70 class="input search"
70 class="input"
7171 type="search"
7272 name="q"
7373 value="${query}"
src/web/pages/search.ts +1 −1
@@ -364,7 +364,7 @@ export async function searchPage(ctx: Ctx): Promise<Response> {
364364 role="search"
365365 >
366366 <input
367 class="input search"
367 class="input"
368368 type="search"
369369 name="q"
370370 value="${a.query}"
src/web/studio/explore.ts +2 −1
@@ -146,7 +146,8 @@ export async function explorePage(ctx: Ctx): Promise<Response> {
146146 })}
147147 <form method="get" action="/explore" class="bar mb">
148148 <input
149 class="input mono search"
149 type="search"
150 class="input mono"
150151 name="q"
151152 value="${exploreLine(query)}"
152153 placeholder="kind:app sort:forks garden"
src/web/style/components.ts +1
@@ -105,6 +105,7 @@ select.input {
105105 background-repeat: no-repeat;
106106 }
107107 @media (pointer: coarse) { .input { min-height: 44px; } }
108 .bar .input[type=search] { min-width: 180px; flex: 1; max-width: 320px; }
108109
109110 /* One control for every boolean. A native checkbox tinted with accent-color
110111 is themed for free, keyboard-correct for free, and honest about what it is —
src/web/style/content.ts −1
@@ -153,7 +153,6 @@ a.origin-chip:hover { border-color: var(--border-strong); color: var(--fg); }
153153 /* A list's six words fit a phone without pushing the page sideways in a
154154 filter bar drawn with §5's .bar: a little less padding there, and a
155155 scroll inside the bar as the last resort. */
156 .bar .search { min-width: 180px; flex: 1; max-width: 320px; }
157156 .bar .seg { max-width: 100%; overflow-x: auto; scrollbar-width: none; }
158157 @media (max-width: 420px) { .bar .seg > a { padding: 0 8px; } }
159158
test/apps-archived.test.ts +3 −2
@@ -119,9 +119,10 @@ test("a signed-out viewer does not see a private archived app", async () => {
119119 expect((await get("/apps?archived=1")).body).toContain("/alice/secret");
120120 });
121121
122 test("the stylesheet sizes .search and .seg inside .bar, without needing .filters", async () => {
122 test("the stylesheet sizes search inputs and .seg inside .bar, without needing .filters", async () => {
123123 const { content } = await import("../src/web/style/content.ts");
124 expect(content).toMatch(/^\.bar \.search \{[^}]*min-width: 180px[^}]*max-width: 320px/m);
124 const { components } = await import("../src/web/style/components.ts");
125 expect(components).toMatch(/^\.bar \.input\[type=search\] \{[^}]*min-width: 180px[^}]*max-width: 320px/m);
125126 expect(content).toMatch(/^\.bar \.seg \{[^}]*overflow-x: auto/m);
126127 expect(content).toMatch(/\.bar \.seg > a \{ padding: 0 8px/);
127128 });
test/design-lint.test.ts +19
@@ -187,3 +187,22 @@ describe("docs/DESIGN.md", () => {
187187 expect(registeredClasses(text).length).toBeGreaterThan(0);
188188 });
189189 });
190
191 describe("search inputs (#4750)", () => {
192 test("no input carries class `search`; the bar sizes type=search once", () => {
193 const files = [
194 "src/web/pages/browse.ts",
195 "src/web/pages/origin-repos.ts",
196 "src/web/pages/search.ts",
197 "src/web/pages/org.ts",
198 "src/web/studio/explore.ts",
199 ];
200 for (const f of files) {
201 const src = readFileSync(f, "utf8");
202 expect(src).not.toMatch(/class="[^"]*\bsearch\b[^"]*"/);
203 expect(src).toContain('type="search"');
204 }
205 expect(readFileSync("src/web/style/content.ts", "utf8")).not.toContain(".bar .search");
206 expect(readFileSync("src/web/style/components.ts", "utf8")).toContain(".bar .input[type=search]");
207 });
208 });

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs