Public: anyone can read this; the crew can change it.
The home's composer draws §5's card, and .composer leaves the feed's stylesheet #4836
Check · Review · Land · Live done — Landed and live in production.
scout/forge:scout/4831-the-home-s-composer-draws-5-s-card-and-c → main 1 commit fork 1 thread · 1 unresolved
4 files
changed +10
−5
docs/DESIGN.md +1 −1
| @@ -402,7 +402,7 @@ gone, so this list only shrinks. | ||
| 402 | 402 | - **`style/content.ts`, apps, runs, and the crew** — run pages, their logs and checks (a pull's look is §5's **look**). |
| 403 | 403 | - **`pages/board.ts`** — the board itself is §5's **board**; the spend tables `spend.ts` draws wear §5's `.table` and `.stack`, no class of their own |
| 404 | 404 | - **`pages/map.ts`** — the map of what waits for what: `.map-ask` `.map-breath` `.map-canvas` `.map-card` `.map-dot` `.map-edge` `.map-edge-crit` `.map-edge-done` `.map-main` `.map-meta` `.map-node` `.map-rule` `.map-svg` `.map-title` `.map-tool` `.map-who` `.map-who-i` `.map-who-n` `.map-word` `.map-wrap` |
| 405 | - **`studio/feed_style.ts`** — the home feed's cards and its composer (the apps rail is §5's card, row and btn; an admin's tick boxes and Archive are always shown, deliberately, with no Select toggle): `.composer` `.feed` `.feed-head` | |
| 405 | - **`studio/feed_style.ts`** — the home feed's cards and its composer (the apps rail is §5's card, row and btn; an admin's tick boxes and Archive are always shown, deliberately, with no Select toggle): `.feed` `.feed-head` | |
| 406 | 406 | --- |
| 407 | 407 | |
| 408 | 408 | ## 6. Keyboard |
src/web/studio/feed.ts +3 −1
| @@ -169,7 +169,8 @@ export function composer(ctx: Ctx, user: User): Html { | ||
| 169 | 169 | action: html`${btn("New app", { href: "/apps/new", variant: "primary" })} |
| 170 | 170 | ${btn("Repositories", { href: `/${user.username}` })}`, |
| 171 | 171 | })}`; |
| 172 | const form = html`<form id="composer" class="composer" method="post" action="/tell"> | |
| 172 | const form = html`<form id="composer" class="card" method="post" action="/tell"> | |
| 173 | <div class="card-body stack"> | |
| 173 | 174 | <textarea class="input" name="text" rows="2" maxlength="2000" required placeholder="Tell the crew what should change" aria-label="Tell the crew">${sharedDraft(ctx.url.searchParams)}</textarea> |
| 174 | 175 | <div class="bar"> |
| 175 | 176 | ${repos.length === 0 |
| @@ -181,6 +182,7 @@ export function composer(ctx: Ctx, user: User): Html { | ||
| 181 | 182 | <span class="spacer"></span> |
| 182 | 183 | ${btn("Post", { variant: "primary" })} |
| 183 | 184 | </div> |
| 185 | </div> | |
| 184 | 186 | </form>`; |
| 185 | 187 | return repos.length === 0 ? html`${form}${noApps}` : form; |
| 186 | 188 | } |
src/web/studio/feed_style.ts −3
| @@ -6,9 +6,6 @@ export const feedCss = /* css */ ` | ||
| 6 | 6 | .feed > .card:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; } |
| 7 | 7 | .feed > .card[hidden] { display: none; } |
| 8 | 8 | .feed .card-foot > details { flex: 1 1 100%; } |
| 9 | /* The composer: the home's one primary action, on top of the timeline. */ | |
| 10 | .composer { display: grid; gap: 8px; border: 1px solid var(--border); border-radius: var(--radius); padding: 12px 14px; background: var(--card, var(--bg)); } | |
| 11 | .composer textarea { width: 100%; min-height: 64px; resize: vertical; } | |
| 12 | 9 | /* Your apps: a narrow column on a desk, a tab away on a phone. */ |
| 13 | 10 | /* An admin's tick boxes are always shown (no Select toggle); 24 px to tap. */ |
| 14 | 11 | #live-apps input[type="checkbox"] { width: 24px; height: 24px; } |
test/home-feed.test.ts +6
| @@ -123,6 +123,12 @@ describe("home is the feed", () => { | ||
| 123 | 123 | await rm(dataDir, { recursive: true, force: true }); |
| 124 | 124 | }); |
| 125 | 125 | |
| 126 | test("the composer is a §5 card, and no .composer class remains", async () => { | |
| 127 | const text = await (await get("/", aliceCookie)).text(); | |
| 128 | expect(text).toMatch(/<form id="composer" class="card" method="post" action="\/tell">\s*<div class="card-body/); | |
| 129 | expect(text).not.toContain('class="composer'); | |
| 130 | }); | |
| 131 | ||
| 126 | 132 | test("the composer's action bar is §5's bar, not .composer-bar", async () => { |
| 127 | 133 | const text = await (await get("/", aliceCookie)).text(); |
| 128 | 134 | const form = text.slice(text.indexOf('id="composer"'), text.indexOf("</form>", text.indexOf('id="composer"'))); |
new above
offline
Indent this div and its children one level so the template shows the nesting.