Open a board's cards in an inspector beside it, from 1100px #241

Merged
Grandiras merged 3 commits from ui-v2-inspector into main 2026-10-03 01:01:06 +00:00
Owner

The UI language v2 inspector, signed off by the owner. On a board from 1100px, a card opens in a panel docked on the right instead of a centred dialog.

What changes

  • CardModal Dockable (the board page's dialog) gets .modal-backdrop-dockable. From 1100px, app.css turns the backdrop into a 400px panel at the right edge:
    • there is no scrim;
    • the board and its title bar make room (--inspector-w) and stay live;
    • the panel slides in, unless reduced motion is set.
  • Clicking another card opens it in the same panel. Its tile is ringed (.card-open, passed down via ColumnView.OpenCardId), and only at that width, because under a phone's sheet the ring change would animate the board.
  • Editing is unchanged: Save, Cancel and the two-step Delete. Switching cards drops unsaved edits, as a click outside the dialog did. Saving as you leave a field is a separate, unapproved behaviour.
  • aria-modal follows the width (js/inspector.js), since a docked panel isn't modal.
  • Only the board docks. The calendar keeps the centred dialog. Below 1100px, and on phones, nothing changes.
  • docs/ui.md gains On a board, from 1100px: the inspector. There is a changelog line in both locales.

Checked

  • tools/verify.sh passes (584).
  • I opened, switched and closed cards on the running app at 1440 (docked, aria-modal=false, ring follows, Escape closes) and at 1024 (a modal again), in light and dark.
  • e2e on an isolated stack: 157/158 at the first commit. The one failure was the ring animating under the phone sheet, a real bug that is fixed here. A full re-run on the head is in progress.
  • New spec: from 1100px a card opens in an inspector beside the board, which stays live.

🤖 Generated with Claude Code

The UI language v2 **inspector**, signed off by the owner. On a board from 1100px, a card opens in a panel docked on the right instead of a centred dialog. **What changes** - `CardModal Dockable` (the board page's dialog) gets `.modal-backdrop-dockable`. From 1100px, `app.css` turns the backdrop into a 400px panel at the right edge: - there is no scrim; - the board and its title bar make room (`--inspector-w`) and stay live; - the panel slides in, unless reduced motion is set. - **Clicking another card opens it in the same panel.** Its tile is ringed (`.card-open`, passed down via `ColumnView.OpenCardId`), and only at that width, because under a phone's sheet the ring change would animate the board. - **Editing is unchanged:** Save, Cancel and the two-step Delete. Switching cards drops unsaved edits, as a click outside the dialog did. Saving as you leave a field is a separate, unapproved behaviour. - **`aria-modal` follows the width** (`js/inspector.js`), since a docked panel isn't modal. - **Only the board docks.** The calendar keeps the centred dialog. Below 1100px, and on phones, nothing changes. - `docs/ui.md` gains *On a board, from 1100px: the inspector*. There is a changelog line in both locales. **Checked** - `tools/verify.sh` passes (584). - I opened, switched and closed cards on the running app at 1440 (docked, `aria-modal=false`, ring follows, Escape closes) and at 1024 (a modal again), in light and dark. - e2e on an isolated stack: 157/158 at the first commit. The one failure was the ring animating under the phone sheet, a real bug that is fixed here. A full re-run on the head is in progress. - New spec: *from 1100px a card opens in an inspector beside the board, which stays live*. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
The v2 language's inspector, signed off by the owner. On a board from 1100px
the card dialog docks on the right: no scrim, the board and its title bar make
room and stay live, and clicking another card opens it in the same panel, its
tile ringed. Editing is unchanged (Save, Cancel, the two-step Delete): a
switch drops unsaved edits as a click outside the dialog did. js/inspector.js
keeps aria-modal true to the width, since docked the dialog is not modal.
The calendar keeps the centred dialog and phones the sheet.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Ring the open card only beside the docked inspector, and pin the inspector
All checks were successful
CI / build (pull_request) Successful in 42s
3afd15f084
The ring was set at every width, so on a phone opening a card animated a
board card's box-shadow under the sheet, the repaint mobile.spec.js forbids.
It now lives in the 1100px block with the docking.

board.spec.js gains the inspector: docked at 1280 with aria-modal false, a
second card opening in the same panel with the ring following, Escape
closing it, and at 1024 the modal dialog with its scrim again.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Collaborator

🤖 Reviewing this PR — the review will link the full session transcript.

📜 Live transcript — updating every ~5 minutes while the review runs.

🤖 Reviewing this PR — the review will link the full session transcript. <!-- opencode-run:review --> 📜 [Live transcript](https://git.grandiras.net/Grandiras/opencode-bot/src/branch/opencode-logs/transcripts/Grandiras/Ponente/pr-241/run-2026-10-03T00-54-27-289Z.md) — updating every ~5 minutes while the review runs.
Collaborator

🤖 Reviewing this PR — follow along in the action run; the reply will link the full session transcript.

📜 Live transcript — updating every ~5 minutes while the task runs.

🤖 Reviewing this PR — follow along in [the action run](https://git.grandiras.net/Grandiras/claude-bot/actions/runs/673); the reply will link the full session transcript. <!-- claude-run:pr_review --> 📜 [Live transcript](https://git.grandiras.net/Grandiras/claude-bot/src/branch/claude-logs/transcripts/Grandiras/Ponente/pr-241/run-673.md) — updating every ~5 minutes while the task runs.
claude-reviewer approved these changes 2026-10-03 00:54:56 +00:00
Dismissed
claude-reviewer left a comment

✅ Verdict: approve — no blocking issues found.

The inspector is a small, well-scoped change. The Dockable flag, the CSS-only docking at 1100px, and aria-modal following the width through js/inspector.js all hang together. Disposal is correct: LocalizedComponentBase documents the pattern of async-only teardown calling base.Dispose(), and DisposeAsync does that and tolerates a disconnected circuit. OnParametersSet re-initialises per card id, which matches the "unsaved edits go on switch" claim. Docs, changelog in both locales, and an e2e spec are all included.

Minor nits, none blocking:

  • CardModal.razor ends with a stray trailing blank line.
  • The _dock import and watch happen only on first render. That is fine because the dialog element persists across card switches.
  • The PR notes a full e2e re-run on the head is still in progress. Confirm it is green before merging.

🧠 claude-sonnet-5-5 · ⏱ 0m 12s · 3 turns · tokens: 17.2k in / 1.2k out (+40.3k cache-read)
📜 Full session transcript

✅ **Verdict: approve** — no blocking issues found. The inspector is a small, well-scoped change. The Dockable flag, the CSS-only docking at 1100px, and `aria-modal` following the width through `js/inspector.js` all hang together. Disposal is correct: `LocalizedComponentBase` documents the pattern of async-only teardown calling `base.Dispose()`, and `DisposeAsync` does that and tolerates a disconnected circuit. `OnParametersSet` re-initialises per card id, which matches the "unsaved edits go on switch" claim. Docs, changelog in both locales, and an e2e spec are all included. Minor nits, none blocking: - `CardModal.razor` ends with a stray trailing blank line. - The `_dock` import and `watch` happen only on first render. That is fine because the dialog element persists across card switches. - The PR notes a full e2e re-run on the head is still in progress. Confirm it is green before merging. --- 🧠 claude-sonnet-5-5 · ⏱ 0m 12s · 3 turns · tokens: 17.2k in / 1.2k out (+40.3k cache-read) 📜 [Full session transcript](https://git.grandiras.net/Grandiras/claude-bot/src/branch/claude-logs/transcripts/Grandiras/Ponente/pr-241/run-673.md) <!-- claude-verdict:approve --> <!-- claude-reviewed-head:3afd15f0847ba005c6fd104cb5f96fa5b7cd2268 -->
opencode-reviewer approved these changes 2026-10-03 00:57:37 +00:00
Dismissed
opencode-reviewer left a comment

✅ Verdict: approve — no blocking issues found.

Good to merge. The inspector is a clean, contained change: the docked mode is scoped to Dockable (board only), the scrim removal is exactly ::before (the layer that carries it), and Escape works docked for the same reason modal-escape.js already handles — the panel keeps .modal-backdrop and stays focused, so the delegated handler finds it.

Checked against the code:

  • DisposeAsync follows the documented pattern in LocalizedComponentBase (async-only teardown calling base.Dispose()), and the catch list covers the realistic interop failures on teardown.
  • Card switching reuses the component instance and resets fields in the guarded OnParametersSet, so "unsaved edits go, as a click outside dropped them" is accurate; the watch/_dialog binding survives because Blazor preserves the dialog element across those re-renders.
  • The JS-set aria-modal="false" is not clobbered by Blazor re-renders — the attribute is a constant in markup, so the diff never re-patches it — and a fresh instance re-runs watch, so close/reopen at a different width is correct (the new e2e covers exactly that).
  • The animation: none + re-enable ordering resolves correctly under prefers-reduced-motion: reduce (no motion, as documented).

Minor, non-blocking:

  • catch (JSException) { } around the module import means a failed load leaves aria-modal="true" while docked — reasonable graceful degradation, but a one-line comment (or a debug log) would make the silent swallow deliberate-looking rather than accidental.
  • inspector.js's module-scoped watched assumes one dockable dialog at a time; watch does call unwatch() first, so it's safe today — worth a comment if a second dockable page ever appears.
  • A trailing blank line was added at the end of CardModal.razor.

⏱ 3m 10s · 15 steps · $0.0268 · tokens: 84.3k in / 1.3k out (+235.5k cache-read) · Go: 5h 2% · wk 8% · mo 87%
📜 Full session transcript

✅ **Verdict: approve** — no blocking issues found. Good to merge. The inspector is a clean, contained change: the docked mode is scoped to `Dockable` (board only), the scrim removal is exactly `::before` (the layer that carries it), and Escape works docked for the same reason `modal-escape.js` already handles — the panel keeps `.modal-backdrop` and stays focused, so the delegated handler finds it. Checked against the code: - `DisposeAsync` follows the documented pattern in `LocalizedComponentBase` (async-only teardown calling `base.Dispose()`), and the catch list covers the realistic interop failures on teardown. - Card switching reuses the component instance and resets fields in the guarded `OnParametersSet`, so "unsaved edits go, as a click outside dropped them" is accurate; the `watch`/`_dialog` binding survives because Blazor preserves the dialog element across those re-renders. - The JS-set `aria-modal="false"` is not clobbered by Blazor re-renders — the attribute is a constant in markup, so the diff never re-patches it — and a fresh instance re-runs `watch`, so close/reopen at a different width is correct (the new e2e covers exactly that). - The `animation: none` + re-enable ordering resolves correctly under `prefers-reduced-motion: reduce` (no motion, as documented). Minor, non-blocking: - `catch (JSException) { }` around the module import means a failed load leaves `aria-modal="true"` while docked — reasonable graceful degradation, but a one-line comment (or a debug log) would make the silent swallow deliberate-looking rather than accidental. - `inspector.js`'s module-scoped `watched` assumes one dockable dialog at a time; `watch` does call `unwatch()` first, so it's safe today — worth a comment if a second dockable page ever appears. - A trailing blank line was added at the end of `CardModal.razor`. --- ⏱ 3m 10s · 15 steps · $0.0268 · tokens: 84.3k in / 1.3k out (+235.5k cache-read) · Go: 5h 2% · wk 8% · mo 87% 📜 [Full session transcript](https://git.grandiras.net/Grandiras/opencode-bot/src/branch/opencode-logs/transcripts/Grandiras/Ponente/pr-241/run-2026-10-03T00-54-27-289Z.md) <!-- opencode-reviewed-head:3afd15f0847ba005c6fd104cb5f96fa5b7cd2268 --> <!-- opencode-verdict:approve -->
Say why a failed inspector module is swallowed, and drop a stray blank line
All checks were successful
CI / build (pull_request) Successful in 42s
58c67ce0d6
Both reviews' nits.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Collaborator

🤖 Reviewing this PR — the review will link the full session transcript.

📜 Live transcript — updating every ~5 minutes while the review runs.

🤖 Reviewing this PR — the review will link the full session transcript. <!-- opencode-run:review --> 📜 [Live transcript](https://git.grandiras.net/Grandiras/opencode-bot/src/branch/opencode-logs/transcripts/Grandiras/Ponente/pr-241/run-2026-10-03T00-59-41-585Z.md) — updating every ~5 minutes while the review runs.
Collaborator

🤖 Reviewing this PR — follow along in the action run; the reply will link the full session transcript.

📜 Live transcript — updating every ~5 minutes while the task runs.

🤖 Reviewing this PR — follow along in [the action run](https://git.grandiras.net/Grandiras/claude-bot/actions/runs/674); the reply will link the full session transcript. <!-- claude-run:pr_review --> 📜 [Live transcript](https://git.grandiras.net/Grandiras/claude-bot/src/branch/claude-logs/transcripts/Grandiras/Ponente/pr-241/run-674.md) — updating every ~5 minutes while the task runs.
claude-reviewer left a comment

✅ Verdict: approve — no blocking issues found.

The nits from my last pass are fixed, and I found nothing new that blocks merging.

  • Stray blank line: the trailing blank line in CardModal.razor is gone.
  • Swallowed module failure: the catch (JSException) in OnAfterRenderAsync now has a comment saying why. If the module is missing, aria-modal stays true, which is the safe fallback.
  • Ring scope: .card-open is now styled only inside the min-width: 1100px query. That fixes the bug where the ring animated under the phone sheet.
  • Docking: the docking CSS, aria-modal following the width, the watch/unwatch single-slot logic in inspector.js, and async disposal in CardModal all look right. The new e2e spec covers docking, switching cards, Escape, and the 1024px modal fallback.
  • Docs and changelog: docs/ui.md and the changelog (both locales) are updated.

Before merging, confirm that the full e2e re-run on the head commit is green. The PR description says it was still in progress.


🧠 claude-sonnet-5-5 · ⏱ 0m 8s · 2 turns · tokens: 16.5k in / 1.0k out (+12.2k cache-read)
📜 Full session transcript

✅ **Verdict: approve** — no blocking issues found. The nits from my last pass are fixed, and I found nothing new that blocks merging. - **Stray blank line:** the trailing blank line in `CardModal.razor` is gone. - **Swallowed module failure:** the `catch (JSException)` in `OnAfterRenderAsync` now has a comment saying why. If the module is missing, `aria-modal` stays `true`, which is the safe fallback. - **Ring scope:** `.card-open` is now styled only inside the `min-width: 1100px` query. That fixes the bug where the ring animated under the phone sheet. - **Docking:** the docking CSS, `aria-modal` following the width, the `watch`/`unwatch` single-slot logic in `inspector.js`, and async disposal in `CardModal` all look right. The new e2e spec covers docking, switching cards, Escape, and the 1024px modal fallback. - **Docs and changelog:** `docs/ui.md` and the changelog (both locales) are updated. Before merging, confirm that the full e2e re-run on the head commit is green. The PR description says it was still in progress. --- 🧠 claude-sonnet-5-5 · ⏱ 0m 8s · 2 turns · tokens: 16.5k in / 1.0k out (+12.2k cache-read) 📜 [Full session transcript](https://git.grandiras.net/Grandiras/claude-bot/src/branch/claude-logs/transcripts/Grandiras/Ponente/pr-241/run-674.md) <!-- claude-verdict:approve --> <!-- claude-reviewed-head:58c67ce0d6e819fd062f879c07f255035f8e0c07 -->
opencode-reviewer left a comment

✅ Verdict: approve — no blocking issues found.

Good to merge. Re-review of the head: both minor notes from my last pass are addressed — the catch (JSException) { } around the module import now explains itself (aria-modal stays true as a stricter claim, never a wrong non-modal announcement), inspector.js documents its one-slot watched assumption, and the stray trailing blank line in CardModal.razor is gone. No new issues in the added commits; the ring-scoping fix under the phone sheet (.card-open inside the 1100px media query) is correctly placed. Disposal, card-switch re-initialisation, Escape handling, and the 1024px fallback in the e2e spec all check out as before. One open item from the PR description: the full e2e re-run on the head was still in progress at posting — confirm it is green before merging.


⏱ 0m 53s · 5 steps · $0.0060 · tokens: 29.4k in / 666 out (+23.6k cache-read) · Go: 5h 2% · wk 8% · mo 87%
📜 Full session transcript

✅ **Verdict: approve** — no blocking issues found. Good to merge. Re-review of the head: both minor notes from my last pass are addressed — the `catch (JSException) { }` around the module import now explains itself (aria-modal stays true as a stricter claim, never a wrong non-modal announcement), `inspector.js` documents its one-slot `watched` assumption, and the stray trailing blank line in `CardModal.razor` is gone. No new issues in the added commits; the ring-scoping fix under the phone sheet (`.card-open` inside the 1100px media query) is correctly placed. Disposal, card-switch re-initialisation, Escape handling, and the 1024px fallback in the e2e spec all check out as before. One open item from the PR description: the full e2e re-run on the head was still in progress at posting — confirm it is green before merging. --- ⏱ 0m 53s · 5 steps · $0.0060 · tokens: 29.4k in / 666 out (+23.6k cache-read) · Go: 5h 2% · wk 8% · mo 87% 📜 [Full session transcript](https://git.grandiras.net/Grandiras/opencode-bot/src/branch/opencode-logs/transcripts/Grandiras/Ponente/pr-241/run-2026-10-03T00-59-41-585Z.md) <!-- opencode-reviewed-head:58c67ce0d6e819fd062f879c07f255035f8e0c07 --> <!-- opencode-verdict:approve -->
Grandiras deleted branch ui-v2-inspector 2026-10-03 01:01:06 +00:00
Sign in to join this conversation.
No labels
No milestone
No project
No assignees
5 participants
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
Grandiras/Ponente!241
No description provided.