From 29efd0e9702ed3ba59ef4fca8fe6f7f2a356c30f Mon Sep 17 00:00:00 2001 From: Codeman maintainer Date: Mon, 10 Aug 2026 11:15:47 +0200 Subject: [PATCH] fix(readmymind): style the modal footer, point the empty-result copy at the steer note The footer buttons shipped with class="btn btn-secondary/primary", but no .btn or .btn-secondary rule exists in this codebase, so all four rendered as unstyled UA buttons. Moved them to the btn-toolbar convention every other modal footer uses, with a scoped flex-row footer rule (btn-toolbar is display:flex, block-level) mirroring the runSummaryModal footer. Send's accent needs a (0,4,0) re-assert: the skin block's bare .btn-toolbar rule is (0,2,1) under html:not([data-skin="og"]) and beats .btn-toolbar.btn-primary (0,2,0), the same specificity trap CLAUDE.md documents for mobile.css. Scoped to this modal; the repo-wide greying of btn-primary on non-OG skins is pre-existing and left as a design call. The empty-result copy now points at the steer note sitting right below it ("Add a steer note and Rethink to try again"), zh-CN updated. Verified with the steer E2E (still green) plus desktop, phone (390px), and error-phase screenshots; static guards extended to pin the footer convention and the accent re-assert. Co-Authored-By: Claude Fable 5 --- docs/readmymind-plan.md | 2 +- src/web/public/i18n.js | 3 ++- src/web/public/index.html | 13 ++++++++----- src/web/public/mobile.css | 9 ++++----- src/web/public/styles.css | 26 ++++++++++++++++++++++++++ test/readmymind-phone-key.test.ts | 16 ++++++++++++++++ 6 files changed, 57 insertions(+), 12 deletions(-) diff --git a/docs/readmymind-plan.md b/docs/readmymind-plan.md index 5d664f88..6b251a52 100644 --- a/docs/readmymind-plan.md +++ b/docs/readmymind-plan.md @@ -124,7 +124,7 @@ Agent use cases this unlocks: a lead session records intentions as the user stat 1. **Intent store + capture + intent endpoints + skill docs.** Immediately useful to agents even before any UI exists. 2. **Context assembler + predictor + predict endpoint + desktop button/modal.** The feature as pitched. The assembler ships with all collectors it can serve from day one (transcript, intent, git, run-summary, siblings); the approvals collector activates when PR #245 lands. -3. **Phone accessory key, rethink steering, alternates row.** Part 1 (shipped): the alternates row (tappable, swap into the field without losing edits; Rethink rejects the whole shown set), the phone 🧠 keyboard-accessory key (both bar templates, `rmm-enabled` marker class on the bar), and a phone-sized modal (small dialog, not full-screen). Part 2 (shipped): rethink steering, the free-text steer note under the suggestions, sent as `steer`, visible whenever Rethink is live (ready and empty-result phases), cleared on each open. +3. **Phone accessory key, rethink steering, alternates row.** Part 1 (shipped): the alternates row (tappable, swap into the field without losing edits; Rethink rejects the whole shown set), the phone 🧠 keyboard-accessory key (both bar templates, `rmm-enabled` marker class on the bar), and a phone-sized modal (small dialog, not full-screen). Part 2 (shipped): rethink steering, the free-text steer note under the suggestions, sent as `steer`, visible whenever Rethink is live (ready and empty-result phases), cleared on each open; the empty-result copy points at the note, and the footer buttons moved to the styled `btn-toolbar` convention (the bare `btn btn-*` classes they shipped with match no CSS in this codebase and rendered as unstyled UA buttons). 4. Explicitly later: proactive predict-on-idle (ghost suggestion chip), auto-compaction of `recentPrompts` into `goals` via a cheap model, codex/gemini capture, cross-case "global" intent. ## Open questions diff --git a/src/web/public/i18n.js b/src/web/public/i18n.js index 47e681f4..db9c6a27 100644 --- a/src/web/public/i18n.js +++ b/src/web/public/i18n.js @@ -255,7 +255,8 @@ 'Read My Mind: predict your next prompt': '读心术:预测您的下一条提示', 'Predict my next prompt': '预测我的下一条提示', 'Reading your mind…': '正在读取您的想法…', - 'No suggestion this time. Rethink to try again.': '这次没有建议。点击「重想」再试一次。', + 'No suggestion this time. Add a steer note and Rethink to try again.': + '这次没有建议。可添加引导备注后点击「重想」再试一次。', Rethink: '重想', Insert: '插入', "Put the text on the session's composer without submitting it": '将文本放入会话输入框但不提交', diff --git a/src/web/public/index.html b/src/web/public/index.html index 85038bd8..0704c847 100644 --- a/src/web/public/index.html +++ b/src/web/public/index.html @@ -2894,7 +2894,7 @@
- + diff --git a/src/web/public/mobile.css b/src/web/public/mobile.css index 1ff443a4..981c3e98 100644 --- a/src/web/public/mobile.css +++ b/src/web/public/mobile.css @@ -1336,15 +1336,14 @@ html.mobile-init .file-browser-panel { width: calc(100% - 2rem); } /* Four footer buttons on a narrow phone: let them wrap instead of clipping, - and give buttons + alternate rows finger-sized targets. */ + and give buttons + alternate rows finger-sized targets. The flex row + itself comes from the base rule in styles.css. */ .readmymind-modal .modal-footer { - display: flex; flex-wrap: wrap; - justify-content: flex-end; - gap: 0.5rem; } - .readmymind-modal .modal-footer .btn { + .readmymind-modal .modal-footer .btn-toolbar { flex: 1 1 auto; + justify-content: center; min-height: 38px; } .readmymind-alt { diff --git a/src/web/public/styles.css b/src/web/public/styles.css index 9d56bcc4..de29e37e 100644 --- a/src/web/public/styles.css +++ b/src/web/public/styles.css @@ -10927,6 +10927,32 @@ kbd { .readmymind-steer-input::placeholder { color: var(--text-dim); } +/* Footer row: the buttons are btn-toolbar (display: flex, block-level), so + without this rule the four of them stack vertically. Mirrors the + runSummaryModal footer; the ≤430px block in mobile.css adds wrapping. */ +.readmymind-modal .modal-footer { + display: flex; + justify-content: flex-end; + gap: 0.5rem; + padding: 0.75rem 1rem; + border-top: 1px solid rgba(255, 255, 255, 0.06); +} +/* Send keeps the primary accent: the skin block's bare .btn-toolbar rule is + (0,2,1) under html:not([data-skin="og"]) and outranks the base + .btn-toolbar.btn-primary (0,2,0) — the specificity trap CLAUDE.md documents + for mobile.css — so the accent is re-asserted here at (0,4,0). Scoped to + this modal on purpose; un-greying every btn-primary on the new skins is a + design call, not this feature's. */ +.readmymind-modal .modal-footer .btn-toolbar.btn-primary { + background: var(--accent); + border-color: var(--accent); + color: #fff; +} +.readmymind-modal .modal-footer .btn-toolbar.btn-primary:hover { + background: var(--accent-hover); + border-color: var(--accent-hover); + color: #fff; +} /* Keyboard-accessory 🧠 key: the phone surface for the same opt-in setting (the header 🧠 button stays phone-hidden in mobile.css). The key ships in diff --git a/test/readmymind-phone-key.test.ts b/test/readmymind-phone-key.test.ts index dc31e2a2..c3f938e5 100644 --- a/test/readmymind-phone-key.test.ts +++ b/test/readmymind-phone-key.test.ts @@ -89,4 +89,20 @@ describe('read my mind phone key + alternates (static guards)', () => { // A fresh open resets the note along with the rethink memory. expect(ui).toMatch(/steer\.value = ''/); }); + + it('styles the footer with btn-toolbar (bare "btn btn-*" matches no CSS in this codebase)', () => { + const modal = html.slice(html.indexOf('id="readMyMindModal"'), html.indexOf('id="approvalsDrawer"')); + // The unstyled classes the footer originally shipped with must not return. + expect(modal).not.toMatch(/class="btn /); + expect(modal.match(/class="btn-toolbar/g)?.length).toBe(4); + expect(modal).toMatch(/class="btn-toolbar btn-primary"[^>]*sendReadMyMind\(true\)/); + // btn-toolbar is display:flex (block-level): without the desktop footer + // row rule the four buttons would stack vertically. + expect(styles).toMatch(/\.readmymind-modal \.modal-footer \{[^}]*display: flex/); + // The skin block's bare .btn-toolbar (0,2,1) greys out .btn-primary + // (0,2,0), so Send's accent must be re-asserted at higher specificity. + expect(styles).toMatch(/\.readmymind-modal \.modal-footer \.btn-toolbar\.btn-primary \{[^}]*var\(--accent\)/); + // The phone block sizes the same class for finger targets. + expect(phoneBlock).toMatch(/\.readmymind-modal \.modal-footer \.btn-toolbar/); + }); });