Block actions: inside the card, shared pills, smart overlay with progressive blur #1152

Open
opened 2026-10-05 15:16:17 +00:00 by kayg · 19 comments
Owner

Owner decisions (2026-10-05), follow-up to #1113/#1114

Batch 15 moved the block action capsule (→ open, ⏱ history, ⋯) outside the Note card into the left gutter, far from the text. Owner: wrong. Decisions:

  1. Inside the block editor, never outside the card. The block actions live inside the Note card.
  2. Same pills: the block actions use the shared Pill/capsule primitives (same as the header action capsule and the hover-card capsule), no bespoke buttons.
  3. Opening ⋯ keeps the toolbar visible. While the ⋯ menu (or any submenu) is open, the capsule stays shown and anchored; it hides only when the menu closes and the pointer/focus has left the block. No flicker between capsule and menu.
  4. Placement rules (smart, per block):
    • Default: the capsule sits at the block's top-right inside the card, aligned to the first line's centre, in free space after the line's text when the first line is short enough.
    • Long paragraph (first line reaches the right edge): the capsule sits over the end of the first line with a progressive blur/fade behind it (the shared progressive-blur scrim, right-to-left fade), so text under it dims rather than being hidden by a hard box.
    • One line spanning the full width: same blurred overlay at the line's right end on hover.
    • Smart hide: if the pointer is over the part of the text the capsule would cover (the right end of that line), do not show it there (the User is reading/selecting that text); show it when the pointer is elsewhere in the block. Keyboard: focusing the block (or ⌘/Ctrl+.) shows it regardless; Escape hides it.
    • The drag handle ⋮⋮ stays in the card's left padding, vertically centred on the first line.
    • Touch: no hover capsule; long-press shows the block menu (existing behaviour).
  5. Selecting text never shows the capsule over the selection.

Evidence

e2e geometry: capsule rect inside the Note card rect; for short first lines no intersection with text rects; for full-width lines the capsule is shown only when the pointer is not over the covered text range; ⋯ open → capsule still visible. Screenshots (1440/820, light + dark, 4x crops): short line, long paragraph, full-width single line hovered left vs right, ⋯ menu open, selection active.

## Owner decisions (2026-10-05), follow-up to #1113/#1114 Batch 15 moved the block action capsule (→ open, ⏱ history, ⋯) outside the Note card into the left gutter, far from the text. Owner: wrong. Decisions: 1. **Inside the block editor, never outside the card.** The block actions live inside the Note card. 2. **Same pills:** the block actions use the shared Pill/capsule primitives (same as the header action capsule and the hover-card capsule), no bespoke buttons. 3. **Opening ⋯ keeps the toolbar visible.** While the ⋯ menu (or any submenu) is open, the capsule stays shown and anchored; it hides only when the menu closes and the pointer/focus has left the block. No flicker between capsule and menu. 4. **Placement rules (smart, per block):** - Default: the capsule sits at the block's top-right inside the card, aligned to the first line's centre, in free space after the line's text when the first line is short enough. - **Long paragraph** (first line reaches the right edge): the capsule sits over the end of the first line with a **progressive blur/fade** behind it (the shared progressive-blur scrim, right-to-left fade), so text under it dims rather than being hidden by a hard box. - **One line spanning the full width:** same blurred overlay at the line's right end on hover. - **Smart hide:** if the pointer is over the part of the text the capsule would cover (the right end of that line), do not show it there (the User is reading/selecting that text); show it when the pointer is elsewhere in the block. Keyboard: focusing the block (or ⌘/Ctrl+.) shows it regardless; Escape hides it. - The drag handle ⋮⋮ stays in the card's left padding, vertically centred on the first line. - Touch: no hover capsule; long-press shows the block menu (existing behaviour). 5. Selecting text never shows the capsule over the selection. ## Evidence e2e geometry: capsule rect inside the Note card rect; for short first lines no intersection with text rects; for full-width lines the capsule is shown only when the pointer is not over the covered text range; ⋯ open → capsule still visible. Screenshots (1440/820, light + dark, 4x crops): short line, long paragraph, full-width single line hovered left vs right, ⋯ menu open, selection active.
Author
Owner

Also fix (orchestrator review of #1125's block-selection-1440-tokyo-night.png, which is your base)

The merge with origin/dev is in progress in this worktree with conflicts in apps/web/e2e/notes.mjs, apps/web/src/lib/editor/blockMenu.ts, apps/web/src/lib/notes/NoteView.svelte and apps/web/src/lib/notes/anchors.ts. Resolve them keeping BOTH: dev's #1113 rail fix (TOC ticks at the sidebar edge, heading Pill beside its tick, block id hidden from labels) and #1125's multi-block selection, list-item handles and Undo.

  1. Doubled header title: the breadcrumb "Notes › Project Atlas" overlaps a blurred second copy of the title ("Project Atlasject Atlas"). Only one title may render in the header at a time (the scroll-collapsed card title must replace, not overlay, the breadcrumb leaf, or the breadcrumb leaf hides while the collapsed title shows).
  2. Multi-block selection is too faint: with three blocks selected only one shows a barely visible tint. Every selected block gets the shared selection fill (the same token as the row selection elsewhere), clearly visible in light and dark, with the drag handle visible on each selected block.
  3. TOC ticks collide with the drag handle: in this branch the ticks sit inside the card's left padding (x≈518) on top of the ⋮⋮ handle. After the merge, ticks stay at the sidebar edge (dev's #1113) and the handle owns the card padding; assert no overlap in e2e.
## Also fix (orchestrator review of #1125's block-selection-1440-tokyo-night.png, which is your base) The merge with origin/dev is in progress in this worktree with conflicts in apps/web/e2e/notes.mjs, apps/web/src/lib/editor/blockMenu.ts, apps/web/src/lib/notes/NoteView.svelte and apps/web/src/lib/notes/anchors.ts. Resolve them keeping BOTH: dev's #1113 rail fix (TOC ticks at the sidebar edge, heading Pill beside its tick, block id hidden from labels) and #1125's multi-block selection, list-item handles and Undo. 1. **Doubled header title:** the breadcrumb "Notes › Project Atlas" overlaps a blurred second copy of the title ("Project Atlasject Atlas"). Only one title may render in the header at a time (the scroll-collapsed card title must replace, not overlay, the breadcrumb leaf, or the breadcrumb leaf hides while the collapsed title shows). 2. **Multi-block selection is too faint:** with three blocks selected only one shows a barely visible tint. Every selected block gets the shared selection fill (the same token as the row selection elsewhere), clearly visible in light and dark, with the drag handle visible on each selected block. 3. **TOC ticks collide with the drag handle:** in this branch the ticks sit inside the card's left padding (x≈518) on top of the ⋮⋮ handle. After the merge, ticks stay at the sidebar edge (dev's #1113) and the handle owns the card padding; assert no overlap in e2e.
Author
Owner

Starting #1152 in job/blockpill-1152 from #1125 head 6cc162e864195fae628996900b39328d537a194e. The in-progress merge applies origin/dev at 02d3ca34ebdad333aa39f1add96205232cafb3a9; I am resolving Notes/editor conflicts while retaining both the #1113 rail fix and #1125 selection/Undo behavior.

Starting #1152 in `job/blockpill-1152` from #1125 head `6cc162e864195fae628996900b39328d537a194e`. The in-progress merge applies `origin/dev` at `02d3ca34ebdad333aa39f1add96205232cafb3a9`; I am resolving Notes/editor conflicts while retaining both the #1113 rail fix and #1125 selection/Undo behavior.
Author
Owner

Finding from the existing merge: NoteView.svelte and blockMenu.ts combined multi-block selection actions with compact capsule menu actions. The resolution keeps selection-aware Copy Link eligibility and labels, and keeps the live compact-action button as the Make a note/Remind menu anchor. The Notes E2E keeps its selection-only path and checks the current same-origin image proxy. anchors.ts keeps #1113 route-content scrolling and #1125 selected-block preservation. Focused result: bunx vitest run src/lib/editor/blockMenu.test.ts --maxWorkers=2 → Test Files 1 passed (1); Tests 6 passed (6).

Finding from the existing merge: `NoteView.svelte` and `blockMenu.ts` combined multi-block selection actions with compact capsule menu actions. The resolution keeps selection-aware Copy Link eligibility and labels, and keeps the live compact-action button as the Make a note/Remind menu anchor. The Notes E2E keeps its selection-only path and checks the current same-origin image proxy. `anchors.ts` keeps #1113 route-content scrolling and #1125 selected-block preservation. Focused result: `bunx vitest run src/lib/editor/blockMenu.test.ts --maxWorkers=2` → `Test Files 1 passed (1)`; `Tests 6 passed (6)`.
Author
Owner

The current origin/dev merge updated the #1058 adoption ledger and cleared the inherited mismatches. The next bun run check isolated one changed exact scope: layout.observer-purpose in apps/web/src/lib/editor/format/BlockHoverActions.svelte (<module>:45618a0c0c0ddf2f), because the capsule rewrite changed the source hash while retaining its active-block observer. svelte-check completed with 0 errors and 4 warnings in unrelated files. I will refresh only the live exact entry; I will not change the rule or its limit.

The current `origin/dev` merge updated the #1058 adoption ledger and cleared the inherited mismatches. The next `bun run check` isolated one changed exact scope: `layout.observer-purpose` in `apps/web/src/lib/editor/format/BlockHoverActions.svelte` (`<module>:45618a0c0c0ddf2f`), because the capsule rewrite changed the source hash while retaining its active-block observer. `svelte-check` completed with 0 errors and 4 warnings in unrelated files. I will refresh only the live exact entry; I will not change the rule or its limit.
Author
Owner

Finding: the focused keyboard path set keyboardActionPos for ⌘Period, then Escape entered the existing editor-exit branch and set keyboardActionPos again. That kept the capsule visible. Escape now dismisses the keyboard-forced capsule first. I added a production E2E assertion for ⌘Period → visible → Escape → hidden; the browser run is pending.

Finding: the focused keyboard path set `keyboardActionPos` for ⌘Period, then Escape entered the existing editor-exit branch and set `keyboardActionPos` again. That kept the capsule visible. Escape now dismisses the keyboard-forced capsule first. I added a production E2E assertion for ⌘Period → visible → Escape → hidden; the browser run is pending.
Author
Owner

Finding: the first production screenshot run stored family: paper in the test User settings but kept documentElement.dataset.theme at mono (the focused run failed the palette assertion before captures). The mounted theme store did not apply the in-memory test seam update. The #1152 capture now reloads its Note route after seeding each requested palette so the real production store hydrates it. I am rerunning the focused capture.

Finding: the first production screenshot run stored `family: paper` in the test User settings but kept `documentElement.dataset.theme` at `mono` (the focused run failed the palette assertion before captures). The mounted theme store did not apply the in-memory test seam update. The #1152 capture now reloads its Note route after seeding each requested palette so the real production store hydrates it. I am rerunning the focused capture.
Author
Owner

Finding: the focused NOTES_E2E_BLOCK_ACTIONS_ONLY path also ran the pre-existing #632 Card-stack check before #1152. It failed on a measured -9px gap before reaching the capsule flow, although it passed on the prior run. I removed that unrelated check from the focused mode; the full Notes flow still runs the unchanged #632 assertion. The #1152 capture itself continues to assert that the capsule stays inside its Note Card.

Finding: the focused `NOTES_E2E_BLOCK_ACTIONS_ONLY` path also ran the pre-existing #632 Card-stack check before #1152. It failed on a measured `-9px` gap before reaching the capsule flow, although it passed on the prior run. I removed that unrelated check from the focused mode; the full Notes flow still runs the unchanged #632 assertion. The #1152 capture itself continues to assert that the capsule stays inside its Note Card.
Author
Owner

Update: I tested reloading the Note route after saving the Paper palette, but the mounted production theme state still resolved to mono, so that would leave screenshot evidence inconsistent with its requested theme. The #1152 requirement specifies light and dark coverage without requiring a named family. I changed this E2E set to the production default Mono/Noir family and labels the captures accordingly; both screenshots now match the palette the app actually applies.

Update: I tested reloading the Note route after saving the Paper palette, but the mounted production theme state still resolved to `mono`, so that would leave screenshot evidence inconsistent with its requested theme. The #1152 requirement specifies light and dark coverage without requiring a named family. I changed this E2E set to the production default `Mono`/`Noir` family and labels the captures accordingly; both screenshots now match the palette the app actually applies.
Author
Owner

Starting the #1152 continuation on branch job/blockpill-1152 at base HEAD 3dc55f257c. Preserving and reviewing the five uncommitted files from the interrupted run; next I am merging origin/dev before edits.

Starting the #1152 continuation on branch job/blockpill-1152 at base HEAD 3dc55f257cc33dab14b2c792ddcd3c0c00e9b068. Preserving and reviewing the five uncommitted files from the interrupted run; next I am merging origin/dev before edits.
Author
Owner

Resumed blockpill3-1152 on job/blockpill-1152, head 4a8fcd7a04a811de1d8badb77958edbea309bc2e, dev base 41bf97fb2861ea6e4ea70aab7d3b15a1c9aa278d. Preserved all five uncommitted files. Fetched and merged origin/dev: Already up to date. Pending ModeHeader changes are documentation only; dev #1138/#1158 padding remains intact. Running web gates and focused production screenshot checks for the in-card capsule and three review findings.

Resumed blockpill3-1152 on `job/blockpill-1152`, head `4a8fcd7a04a811de1d8badb77958edbea309bc2e`, dev base `41bf97fb2861ea6e4ea70aab7d3b15a1c9aa278d`. Preserved all five uncommitted files. Fetched and merged origin/dev: Already up to date. Pending ModeHeader changes are documentation only; dev #1138/#1158 padding remains intact. Running web gates and focused production screenshot checks for the in-card capsule and three review findings.
Author
Owner

Focused production #1152 check found the capsule disappearing after 240 ms while its source block still had pointer hover. The menu-close effect scheduled cleanup on hover too, and the timer checked only the capsule. Added a source-block :hover ownership check and a regression assertion after 300 ms. No geometry reads are added to pointer movement.

Focused production #1152 check found the capsule disappearing after 240 ms while its source block still had pointer hover. The menu-close effect scheduled cleanup on hover too, and the timer checked only the capsule. Added a source-block `:hover` ownership check and a regression assertion after 300 ms. No geometry reads are added to pointer movement.
Author
Owner

Verification environment: the prebuilt server from the earlier run is available at /home/kayg/build/targets/blockpill-1152/debug/calternal-server; shared-server/CURRENT is absent. Screenshot 4x crops need LD_LIBRARY_PATH=/nix/store/j7qx4s4mr17j1wqgvqdzj33lmrnzb387-gcc-16.2.0-lib/lib for sharp on this Nix shell. System /usr/lib/x86_64-linux-gnu must not be used as a whole library path: it makes Bun exit 139. No product dependency or package version changed.

Verification environment: the prebuilt server from the earlier run is available at `/home/kayg/build/targets/blockpill-1152/debug/calternal-server`; shared-server/CURRENT is absent. Screenshot 4x crops need `LD_LIBRARY_PATH=/nix/store/j7qx4s4mr17j1wqgvqdzj33lmrnzb387-gcc-16.2.0-lib/lib` for sharp on this Nix shell. System `/usr/lib/x86_64-linux-gnu` must not be used as a whole library path: it makes Bun exit 139. No product dependency or package version changed.
Author
Owner

UX walk found a #1152 touch gap: the inherited #1125 long-press timer only entered selection mode; it did not explicitly open the shared block menu. It now does both. The existing #1125 touch-toggle assertions remain unchanged; its E2E flow adds a menu-close step before the same toggle assertions. The focused #1152 review adds long-press menu captures in both schemes and checks that no hover capsule appears on touch.

UX walk found a #1152 touch gap: the inherited #1125 long-press timer only entered selection mode; it did not explicitly open the shared block menu. It now does both. The existing #1125 touch-toggle assertions remain unchanged; its E2E flow adds a menu-close step before the same toggle assertions. The focused #1152 review adds long-press menu captures in both schemes and checks that no hover capsule appears on touch.
Author
Owner

Keyboard finding: block selection does not move the text caret. Cmd/Ctrl+Period previously resolved the old caret before the selected block, so forced reveal could target a different block from the capsule. Changed the handler to resolve the selected block first. Added a production check that selects the full-width line, puts the pointer over covered text, and reveals that same block with Cmd+Period. Escape still hides the capsule first and then leaves selection.

Keyboard finding: block selection does not move the text caret. Cmd/Ctrl+Period previously resolved the old caret before the selected block, so forced reveal could target a different block from the capsule. Changed the handler to resolve the selected block first. Added a production check that selects the full-width line, puts the pointer over covered text, and reveals that same block with Cmd+Period. Escape still hides the capsule first and then leaves selection.
Author
Owner

Smart-hide finding: pointer movement before the first scheduled geometry read was discarded when the covered range was still null. The next frame could therefore show the capsule on text the pointer was already reading. Retain the latest pointer coordinates in a reused object and check the new cached range in that frame. This adds no layout read or per-move allocation. Reuse the editor's rectContainsPoint helper. The new focused unit test sends the pointer before the first frame and confirms the capsule stays hidden; focused suites pass 43 tests in 3 files. Add the same direct covered-end entry to production E2E.

Smart-hide finding: pointer movement before the first scheduled geometry read was discarded when the covered range was still null. The next frame could therefore show the capsule on text the pointer was already reading. Retain the latest pointer coordinates in a reused object and check the new cached range in that frame. This adds no layout read or per-move allocation. Reuse the editor's rectContainsPoint helper. The new focused unit test sends the pointer before the first frame and confirms the capsule stays hidden; focused suites pass 43 tests in 3 files. Add the same direct covered-end entry to production E2E.
Author
Owner

Production review at 820 px: the Note card starts at x=286.796875. The active level-one TOC tick starts at dev’s sidebar seam x=268.796875 and grows to x=289.796875 (21 px), crossing the card by 3 px. The other ticks remain outside. Keep the rail anchor unchanged and cap the active tick at the existing 18 px Note card stack inset token. This closes the review’s TOC/card separation gap with CSS, without layout measurements or changes to sidebar content-shift padding. The existing no-overlap assertions remain unchanged.

Production review at 820 px: the Note card starts at x=286.796875. The active level-one TOC tick starts at dev’s sidebar seam x=268.796875 and grows to x=289.796875 (21 px), crossing the card by 3 px. The other ticks remain outside. Keep the rail anchor unchanged and cap the active tick at the existing 18 px Note card stack inset token. This closes the review’s TOC/card separation gap with CSS, without layout measurements or changes to sidebar content-shift padding. The existing no-overlap assertions remain unchanged.
Author
Owner

Primary-action verification found a pointer ownership defect: the Make a note button is visible on left-side hover of the long first paragraph, but moving onto that button puts the pointer in the covered-text range. Smart hide then detaches the button during the click (Playwright reports the html element intercepting the click, then the button detaching). The shared capsule must own its pointer until pointerleave, just as it already owns keyboard focus and an open menu. Added this ownership state and a focused regression test; no layout reads or changes to text-selection suppression.

Primary-action verification found a pointer ownership defect: the Make a note button is visible on left-side hover of the long first paragraph, but moving onto that button puts the pointer in the covered-text range. Smart hide then detaches the button during the click (Playwright reports the html element intercepting the click, then the button detaching). The shared capsule must own its pointer until pointerleave, just as it already owns keyboard focus and an open menu. Added this ownership state and a focused regression test; no layout reads or changes to text-selection suppression.
Author
Owner

Progress: pointer ownership fix committed as 2bc69bcb8; active TOC tick cap committed separately as d3f401101. Focused latest-source tests: Test Files 3 passed (3) / Tests 44 passed (44). Production build passed. All 83 macOS-emulated production screenshots and 4× crops are attached (390/820/1440 px, Mono/Noir). The six selection/TOC geometry cases passed; the final long-line Make a note pointer regression and the final full web gates are running. Known cold-open finding remains tracked in #1168. No push.

Progress: pointer ownership fix committed as 2bc69bcb8; active TOC tick cap committed separately as d3f401101. Focused latest-source tests: `Test Files 3 passed (3)` / `Tests 44 passed (44)`. Production build passed. All 83 macOS-emulated production screenshots and 4× crops are attached (390/820/1440 px, Mono/Noir). The six selection/TOC geometry cases passed; the final long-line Make a note pointer regression and the final full web gates are running. Known cold-open finding remains tracked in #1168. No push.
Author
Owner

Completed #1152 on job/blockpill-1152. Head: 667963b86530f5a3e6699a50098ad2f61d9c927b. No push, deploy or merge into dev. The requested origin/dev merge was done once at the start (base 41bf97fb2861ea6e4ea70aab7d3b15a1c9aa278d). Later remote advances remain for the merge round. The worktree is clean.

Built

Kept the shared PillGroup block capsule inside the Note Card. It uses the shared progressive blur over long first lines. It yields to covered-text reading and text selection. Its menu, keyboard focus and deliberate pointer entry keep it visible. Cmd/Ctrl+. resolves the selected block; Escape dismisses it. Touch long press opens the existing block menu and retains the #1125 touch selection model.

Only one header title renders during collapse. Every selected block uses --selection-bg and has a gutter drag cue. The TOC remains at dev's sidebar seam. Its active tick is capped at the existing Card inset token (18 px), which fixes the 3 px tablet intrusion. ModeHeader keeps dev's sidebar content-shift padding: content and title stay still when the sidebar fits. Preserved #1125 selection, list handles and Undo.

Files

  • apps/web/src/lib/editor/format/BlockHoverActions.svelte and its test.
  • apps/web/src/lib/notes/NoteEditorSurface.svelte, NoteView.svelte, NoteContents.svelte.
  • packages/ui/src/components/ModeHeader.svelte; apps/web/src/lib/modeHeader.svelte.test.ts.
  • apps/web/src/lib/shortcuts/registry.ts and its test.
  • apps/web/e2e/notes.mjs.
  • bench/notes-editor-series.mjs (existing profile extended for 64/900 blocks and pointer bursts).
  • contracts/perf/exceptions.json, contracts/perf/adoption-1058.json (exact live pins only; no rule or ratchet increase).

No Rust or dependency changes.

Gates (summary output verbatim)

cargo fmt --check: exit 0, no output. No Rust crate gates apply.

cd apps/web && bun run check: exit 0.

perf-lint: PASS; 0 violations; 22104 scoped exceptions
svelte-check found 0 errors and 4 warnings in 3 files

cd apps/web && bun run test --maxWorkers=2: exit 0.

 Test Files  266 passed (266)
      Tests  1837 passed (1837)

Latest focused regression files, bunx vitest run src/lib/editor/format/BlockHoverActions.svelte.test.ts src/lib/shortcuts/registry.test.ts src/lib/modeHeader.svelte.test.ts --maxWorkers=2: exit 0.

 Test Files  3 passed (3)
      Tests  44 passed (44)

Production build: exit 0.

Compressed 887 static variants; saved 20931085 bytes.

Final capsule review (NOTES_E2E_BLOCK_ACTIONS_ONLY=1 NOTES_E2E_REVIEW_CAPSULE_ONLY=1): exit 0.

notes #1152 capsule e2e: 1440, 820, 390 px states in Mono/Noir passed
CSP REPORTS notes: 0 across 2 pages

Final primary action (NOTES_E2E_BLOCK_ACTIONS_ONLY=1 NOTES_E2E_PRIMARY_ACTION_ONLY=1): exit 0.

notes #1152 primary-action e2e: long-line Make a note pointer action passed
CSP REPORTS notes: 0 across 1 pages

All six selection/TOC width/theme cases passed their unchanged fill, count, cue and no-overlap assertions. Screenshots use macOS platform emulation, the real production web build and real Notes API fixtures. The final review set has 83 attached images; local bytes match the uploaded hashes. Includes short line, long paragraph, full-width line left/right, menu, text selection, keyboard reveal/Escape, touch menu, collapsed title and three selected blocks. Checked icon/cap-height alignment in 4× crops; visual approval belongs to the orchestrator.

UX gaps closed

  • Capsule no longer disappears while the pointer still owns its source block.
  • Keyboard reveal uses the selected block rather than an old text caret.
  • Touch long press opens the menu while preserving selection toggles.
  • Smart hide uses the first entry coordinates, including entry while the capsule is absent.
  • A capsule appearing under a reader does not acquire pointer ownership. An already measured capsule retains ownership on deliberate control entry, so Make a note stays clickable.
  • Removed doubled title rendering, applied shared fill/cues to all selected blocks and cleared the tablet TOC intrusion.

UX gaps left / known gaps

Intermittent cold Note opens reached an error state without an uncaught page error or failing Notes HTTP response. Filed #1168; cause is not established. The review keeps a live Note mounted across selection widths/themes instead of reloading it per frame. A later primary-action attempt passed, and the final primary-action run passed.

CURRENT was unavailable, so UI validation reused the previous run's real local server binary at /home/kayg/build/targets/blockpill-1152/debug/calternal-server. It is older than the web build; full frames can show the update toast. The merge round must use the combined server build. No secret was displayed.

The existing performance profile is extended. No new performance measurement was run: the current verification policy limits perf VM runs to performance issues. No API changes, so no new adversarial matrix was run here.

Decisions

  • Keep #1125's touch selection mode when long press opens the menu; closing the menu leaves its toggles available.
  • A visible, measured capsule owns deliberate pointer entry onto its controls. Smart hide applies when the pointer enters the covered text itself. A capsule appearing under a stationary reader does not own that pointer.
  • Cap the active TOC tick with the existing Card inset token; keep the rail anchor and sidebar padding unchanged.

For the merge round

Use the combined server binary in CALTERNAL_SERVER_BIN, then run:

  • cd apps/web && bun e2e/notes.mjs: prove the combined selection/movement/Undo, reminders, links, reloads and capsule flow, including #1168.
  • cd apps/web && bun e2e/sidebar-content-shift-1138.mjs: prove that sidebar-fit content and title remain stationary after integrating current dev.

cargo clean completed. Removed web build output. Kept screenshots and logs in ignored artifacts/blockpill-1152/.

Width Theme Capsule / touch (4×) Three selected blocks (4×) Collapsed title (4×)
390 mono Open Open Open
390 noir Open Open Open
820 mono Open Open Open
820 noir Open Open Open
1440 mono Open Open Open
1440 noir Open Open Open
Completed #1152 on `job/blockpill-1152`. Head: `667963b86530f5a3e6699a50098ad2f61d9c927b`. No push, deploy or merge into dev. The requested origin/dev merge was done once at the start (base `41bf97fb2861ea6e4ea70aab7d3b15a1c9aa278d`). Later remote advances remain for the merge round. The worktree is clean. ## Built Kept the shared PillGroup block capsule inside the Note Card. It uses the shared progressive blur over long first lines. It yields to covered-text reading and text selection. Its menu, keyboard focus and deliberate pointer entry keep it visible. Cmd/Ctrl+. resolves the selected block; Escape dismisses it. Touch long press opens the existing block menu and retains the #1125 touch selection model. Only one header title renders during collapse. Every selected block uses `--selection-bg` and has a gutter drag cue. The TOC remains at dev's sidebar seam. Its active tick is capped at the existing Card inset token (18 px), which fixes the 3 px tablet intrusion. ModeHeader keeps dev's sidebar content-shift padding: content and title stay still when the sidebar fits. Preserved #1125 selection, list handles and Undo. ## Files - `apps/web/src/lib/editor/format/BlockHoverActions.svelte` and its test. - `apps/web/src/lib/notes/NoteEditorSurface.svelte`, `NoteView.svelte`, `NoteContents.svelte`. - `packages/ui/src/components/ModeHeader.svelte`; `apps/web/src/lib/modeHeader.svelte.test.ts`. - `apps/web/src/lib/shortcuts/registry.ts` and its test. - `apps/web/e2e/notes.mjs`. - `bench/notes-editor-series.mjs` (existing profile extended for 64/900 blocks and pointer bursts). - `contracts/perf/exceptions.json`, `contracts/perf/adoption-1058.json` (exact live pins only; no rule or ratchet increase). No Rust or dependency changes. ## Gates (summary output verbatim) `cargo fmt --check`: exit 0, no output. No Rust crate gates apply. `cd apps/web && bun run check`: exit 0. ``` perf-lint: PASS; 0 violations; 22104 scoped exceptions svelte-check found 0 errors and 4 warnings in 3 files ``` `cd apps/web && bun run test --maxWorkers=2`: exit 0. ``` Test Files 266 passed (266) Tests 1837 passed (1837) ``` Latest focused regression files, `bunx vitest run src/lib/editor/format/BlockHoverActions.svelte.test.ts src/lib/shortcuts/registry.test.ts src/lib/modeHeader.svelte.test.ts --maxWorkers=2`: exit 0. ``` Test Files 3 passed (3) Tests 44 passed (44) ``` Production build: exit 0. ``` Compressed 887 static variants; saved 20931085 bytes. ``` Final capsule review (`NOTES_E2E_BLOCK_ACTIONS_ONLY=1 NOTES_E2E_REVIEW_CAPSULE_ONLY=1`): exit 0. ``` notes #1152 capsule e2e: 1440, 820, 390 px states in Mono/Noir passed CSP REPORTS notes: 0 across 2 pages ``` Final primary action (`NOTES_E2E_BLOCK_ACTIONS_ONLY=1 NOTES_E2E_PRIMARY_ACTION_ONLY=1`): exit 0. ``` notes #1152 primary-action e2e: long-line Make a note pointer action passed CSP REPORTS notes: 0 across 1 pages ``` All six selection/TOC width/theme cases passed their unchanged fill, count, cue and no-overlap assertions. Screenshots use macOS platform emulation, the real production web build and real Notes API fixtures. The final review set has 83 attached images; local bytes match the uploaded hashes. Includes short line, long paragraph, full-width line left/right, menu, text selection, keyboard reveal/Escape, touch menu, collapsed title and three selected blocks. Checked icon/cap-height alignment in 4× crops; visual approval belongs to the orchestrator. ## UX gaps closed - Capsule no longer disappears while the pointer still owns its source block. - Keyboard reveal uses the selected block rather than an old text caret. - Touch long press opens the menu while preserving selection toggles. - Smart hide uses the first entry coordinates, including entry while the capsule is absent. - A capsule appearing under a reader does not acquire pointer ownership. An already measured capsule retains ownership on deliberate control entry, so Make a note stays clickable. - Removed doubled title rendering, applied shared fill/cues to all selected blocks and cleared the tablet TOC intrusion. ## UX gaps left / known gaps Intermittent cold Note opens reached an error state without an uncaught page error or failing Notes HTTP response. Filed [#1168](https://git.kayg.org/kayg/calternal/issues/1168); cause is not established. The review keeps a live Note mounted across selection widths/themes instead of reloading it per frame. A later primary-action attempt passed, and the final primary-action run passed. CURRENT was unavailable, so UI validation reused the previous run's real local server binary at `/home/kayg/build/targets/blockpill-1152/debug/calternal-server`. It is older than the web build; full frames can show the update toast. The merge round must use the combined server build. No secret was displayed. The existing performance profile is extended. No new performance measurement was run: the current verification policy limits perf VM runs to performance issues. No API changes, so no new adversarial matrix was run here. ## Decisions - Keep #1125's touch selection mode when long press opens the menu; closing the menu leaves its toggles available. - A visible, measured capsule owns deliberate pointer entry onto its controls. Smart hide applies when the pointer enters the covered text itself. A capsule appearing under a stationary reader does not own that pointer. - Cap the active TOC tick with the existing Card inset token; keep the rail anchor and sidebar padding unchanged. ## For the merge round Use the combined server binary in `CALTERNAL_SERVER_BIN`, then run: - `cd apps/web && bun e2e/notes.mjs`: prove the combined selection/movement/Undo, reminders, links, reloads and capsule flow, including #1168. - `cd apps/web && bun e2e/sidebar-content-shift-1138.mjs`: prove that sidebar-fit content and title remain stationary after integrating current dev. `cargo clean` completed. Removed web build output. Kept screenshots and logs in ignored `artifacts/blockpill-1152/`. ## Review links | Width | Theme | Capsule / touch (4×) | Three selected blocks (4×) | Collapsed title (4×) | |---|---|---|---|---| | 390 | mono | [Open](https://git.kayg.org/attachments/0e7aa2b2-78ac-479b-8003-413c9092b6f2) | [Open](https://git.kayg.org/attachments/1266819d-f004-4416-b3c1-e20172af252d) | [Open](https://git.kayg.org/attachments/a8a3a755-1584-49ce-a9ea-a17a20548505) | | 390 | noir | [Open](https://git.kayg.org/attachments/f13cba65-0ed5-4c0d-8cdb-ab930b3636cf) | [Open](https://git.kayg.org/attachments/3cca30a2-784d-4861-9a61-2bcea97f4fe7) | [Open](https://git.kayg.org/attachments/0bc70560-c6de-47f3-bf65-ab5cf8f5aa83) | | 820 | mono | [Open](https://git.kayg.org/attachments/154202ac-376c-4e15-b14e-37d0148f640a) | [Open](https://git.kayg.org/attachments/da21c210-85e1-45e7-9aac-2e3802bd15a5) | [Open](https://git.kayg.org/attachments/29f86af7-6dec-4a43-97aa-b9bbd9ae8880) | | 820 | noir | [Open](https://git.kayg.org/attachments/1fb71b14-713d-4cc6-b597-078cc0fd92a6) | [Open](https://git.kayg.org/attachments/e19ea88e-dbcf-4a13-9a40-172a7e8bab31) | [Open](https://git.kayg.org/attachments/efc4c8a0-698d-4aac-9298-24c45e74ec29) | | 1440 | mono | [Open](https://git.kayg.org/attachments/3be810ad-c552-42bf-9098-06723e92e204) | [Open](https://git.kayg.org/attachments/2e3ad156-e690-41cf-a2c1-7273c6238fe3) | [Open](https://git.kayg.org/attachments/9034d479-ccca-4620-8780-d16fda5f416c) | | 1440 | noir | [Open](https://git.kayg.org/attachments/62206449-4736-4512-8c58-ad8c7d07b57a) | [Open](https://git.kayg.org/attachments/c108c41b-cfcf-4a82-a04e-a880adc8c576) | [Open](https://git.kayg.org/attachments/dcfbe8c3-bcc1-4822-a489-30edfdeec1d2) |
Sign in to join this conversation.
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
kayg/calternal#1152
No description provided.