Public: anyone can read this; the crew can change it.
The home's "What you asked for" bar leaves: the Asked tab is the one door to /asked #6755
Check · Review · Land · Live done — Landed and live in production.
scout/forge:scout/6744-the-home-s-what-you-asked-for-bar-leaves → main 1 commit fork
5 files
changed +5
−11
docs/design/areas/feed.md −1
| @@ -1,6 +1,5 @@ | ||
| 1 | 1 | # Feed |
| 2 | 2 | |
| 3 | - `.feed-head` — the head of the home's feed: a §5 `.bar` above the timeline holding the "What you asked for" link, pushed to the end by a spacer. Drawn by `studioHome` in `src/web/studio/home.ts`, styled in `src/web/studio/feed_style.ts`. Under 900px it is hidden, since that link is a tab on a phone and the first post should come next; a bare `.bar` cannot carry this, as it has no reason to vanish on a narrow screen. | |
| 4 | 3 | - `.look[data-slot="feed"]` — a look post's thumbnail, drawn by `feedCard` in `src/web/studio/feed.ts`: the §5 `.look` frame fixed at 160×100 (the img carries the same width and height, so nothing shifts), cropped from the top like the other thumbs. A bare `.look` is fluid and would resize the post. |
| 5 | 4 | - `.feed` — the home's timeline list: a one-column grid with no gap that holds the feed's cards, each focusable with a visible outline and removed from layout while `hidden`. Drawn by `drawRegion` in `src/web/studio/feed.ts` (the `#live-feed` section), styled in `src/web/studio/feed_style.ts`. |
| 6 | 5 | - Day divider — no new class: a §5 `.muted.small` line with `data-day-divider="<label>"`, drawn by `drawRegion` in `src/web/studio/feed.ts` before the first post of each UTC day (labels from `day_divider.ts`). It marks a change of day between neighbours in the order the feed already has; it never reorders. It is `role="separator"`, and hiding a card (dismiss, mute) moves it to the next card showing that day or hides it (`keepDay`). The "Older posts" link and `data-live-src` carry `day=` so a later page does not repeat the divider. |
src/web/studio/feed_style.ts −3
| @@ -10,9 +10,6 @@ export const feedCss = /* css */ ` | ||
| 10 | 10 | /* An admin's tick boxes are always shown (no Select toggle); 24 px to tap. */ |
| 11 | 11 | #live-apps input[type="checkbox"] { width: 24px; height: 24px; } |
| 12 | 12 | @media (max-width: 899px) { |
| 13 | /* "What you asked for" is a tab on a phone: the first post comes next. | |
| 14 | !important, as [hidden] is: .bar sits in a later cascade layer. */ | |
| 15 | .feed-head { display: none !important; } | |
| 16 | 13 | #live-apps { display: none; } |
| 17 | 14 | } |
| 18 | 15 | @media (max-width: 600px) { |
src/web/studio/home.ts −4
| @@ -305,10 +305,6 @@ export async function studioHome( | ||
| 305 | 305 | <div class="split" data-rail="wide"> |
| 306 | 306 | <div class="stack"> |
| 307 | 307 | ${composer(ctx, user)} |
| 308 | <div class="bar feed-head"> | |
| 309 | <span class="spacer"></span> | |
| 310 | <a class="small muted" href="/asked">What you asked for</a> | |
| 311 | </div> | |
| 312 | 308 | ${flowCards(ctx, user)} |
| 313 | 309 | ${feedNote()} |
| 314 | 310 | ${timePhase(ctx.request, "feed", () => feedRegion(user, ctx), () => feedCandidateCache(ctx.app.db))} |
test/home-feed.test.ts +3 −1
| @@ -166,7 +166,9 @@ describe("home is the feed", () => { | ||
| 166 | 166 | expect(text).not.toContain("home-tabs"); |
| 167 | 167 | // Nothing stands between the composer and the first post: the crew's |
| 168 | 168 | // missing key sits beside the timeline (after it on a phone), and |
| 169 | // "What you asked for" is a tab there. | |
| 169 | // "What you asked for" is the Asked tab, the one door to /asked. | |
| 170 | expect(text).not.toContain("feed-head"); | |
| 171 | expect(text).not.toContain('href="/asked">What you asked for'); | |
| 170 | 172 | const note = text.indexOf('id="crew-key-note"'); |
| 171 | 173 | if (note !== -1) expect(note).toBeGreaterThan(feed); |
| 172 | 174 | expect(text).toMatch(/class="tabs"[\s\S]*?href="\/asked"/); |
test/page-text.test.ts +2 −2
| @@ -60,7 +60,7 @@ test("the real home reads as text: heading and waiting count, no CSS, script or | ||
| 60 | 60 | expect(raw).toContain("<script"); |
| 61 | 61 | expect(raw).toContain("<style"); |
| 62 | 62 | const text = pageText(raw); |
| 63 | expect(text).toContain("What you asked for"); | |
| 63 | expect(text).toContain("Feed Your apps Asked"); | |
| 64 | 64 | expect(text).toMatch(/3 waiting on you, oldest 5\d h/); |
| 65 | 65 | expect(text).not.toMatch(/<\/?[a-z]/i); |
| 66 | 66 | expect(text).not.toMatch(/[{};]\s*$|:root|@media|function\s*\(|=>|var\(--/m); |
| @@ -95,7 +95,7 @@ test("scripts/home-read.ts prints the text and the stats line, sends FORGE_COOKI | ||
| 95 | 95 | const r = await run([`${servers.url}/`], { FORGE_COOKIE: cookie }); |
| 96 | 96 | expect(r.code).toBe(0); |
| 97 | 97 | expect(r.out.trimEnd().split("\n").pop()).toMatch(/^chars \d+ · words \d+ · fetched in \d+ ms$/); |
| 98 | expect(r.out).toContain("What you asked for"); | |
| 98 | expect(r.out).toContain("Feed Your apps Asked"); | |
| 99 | 99 | const token = cookie.match(/forge_session=([^;]+)/)![1]!; |
| 100 | 100 | expect(r.out).not.toContain(token); |
| 101 | 101 | expect(r.err).not.toContain(token); |
new above
offline