Finish the card inspector and the phone card sheet to the v2 draft #251
No reviewers
Labels
No labels
No milestone
No project
No assignees
5 participants
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
Grandiras/Ponente!251
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "ui-v2-inspector"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Finishes the card dialog to the UI language v2 draft (Figma Desktop · Board + Inspector, Components · Inspector, Phone · Card sheet · Medium / Large), light and dark.
What changed
The inspector (
CardModal,CommentList)aria-labelledby); "Edit card / View card" are gone.field-sizing, a hand resize where unsupported).LocaleService.FormatDueWhen, en + de, red once past), on the same UTC day the card pill uses.LocaleService.FormatAgo, exact stamp in the tooltip), the latest three with "Show N earlier", Edit/Delete on hover (always on touch), and the composer closing the group as in Parts.role="status"Saved. Save-on-leave and Undo are unchanged; a new card keeps Cancel + Create in a footer.The phone card sheet (
js/card-dialog.js, which replacesjs/inspector.jsand still ownsaria-modal)data-detent: medium (top at 35.5% of the screen, board dimmed above) and large (screen less a 12px strip). Existing cards open at medium, new ones at large.translateonly (compositor); the grabber and bar drag it, and at medium the whole sheet does (its body doesn't scroll there): a scroll, a wheel or a text field taking focus opens it to large. Release settles on the height nearest a 200ms projection; a throw from large stops at medium; past medium it closes through × after blurring the field (so it saves). Uploads block closing, as × does. Reduced motion changes height at once.--keyboard-inset).Judgement calls
ShareButton's, which other screens share..assignee-avataris shared with the cards on the board.Verified
tools/verify.sh(build + unit, 599 passing). NewRelativeTimeTestspin the due helper and comment times in both locales.board,mobileandpermissionsspecs re-run green (36) after a last padding tweak. Specs updated for the new structure (.card-delete, × instead of Done, Write before editing a description, 380px), andmobile.spec.jsdrives the sheet's heights with CDP touches: medium on open with the comment box below the screen, dragged to large (box pinned on its foot), back to medium, a scroll opening it, a drag off closing it.🤖 Generated with Claude Code
🤖 Reviewing this PR — the review will link the full session transcript.
📜 Live transcript — updating every ~5 minutes while the review runs.
🤖 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.
✅ Verdict: approve — no blocking issues found.
I found no blocking problems. I read the diff and spot-checked a few things in the repo. I didn't run the build or the e2e specs.
card-dialog.js): the detent maths, the 6px slop and the throw-from-large-stops-at-medium rule are consistent with the CSS. The upload guard also holds, since×is disabled and the drag falls back to medium.card.BoardColumn?.Nameis safe. The calendar already readscard.BoardColumn?.BoardId, so the navigation property is loaded..detail-panelor.card-details..detail-panel-assigneesis kept, and its.prop-rowparent isposition: relative.RelativeTimeTestscover both locales.Two minor points, neither blocking:
FormatAgosays "yesterday" for anything between 24h and 48h old. At 1am, a comment from 47h ago reads "yesterday" although it was two calendar days back. Comparing calendar days would be more accurate. The test pins the current behaviour at 30h.FormatAgochange in a long-open dialog won't refresh until a re-render. That seems acceptable.🧠 claude-sonnet-5-5 · ⏱ 0m 22s · 3 turns · tokens: 67.7k in / 2.3k out (+90.0k cache-read)
📜 Full session transcript
💬 Verdict: comment — the reviewer did not submit a structured review; the raw output follows.
(empty)
⏱ 30m 3s · 25 steps · $0.1067 · tokens: 384.0k in / 1.1k out (+890.8k cache-read) · Go: 5h 1% · wk 11% · mo 88%
📜 Full session transcript
🤖 Reviewing this PR — the review will link the full session transcript.
📜 Live transcript — updating every ~5 minutes while the review runs.
🤖 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.
✅ Verdict: approve — no blocking issues found.
I read the diff again and didn't run the build or the e2e specs. I found no blocking problems.
My earlier minor point is fixed.
FormatAgonow compares calendar days once a comment is more than a day old, so 47 hours ago reads "2 days ago" rather than "yesterday".RelativeTimeTestspins this, along with the 30h "yesterday" and 9-day date cases, in both locales.The long-open-dialog staleness I noted before remains. I'm leaving it as acceptable.
🧠 claude-sonnet-5-5 · ⏱ 0m 7s · 2 turns · tokens: 66.3k in / 451 out (+12.2k cache-read)
📜 Full session transcript
✅ Verdict: approve — no blocking issues found.
Re-review: no blockers. The two notes from the earlier pass are resolved —
FormatAgonow counts calendar days (47h ago reads "2 days ago", pinned byRelativeTimeTests), and the relative times in a long-open dialog are acceptable as is.What I checked this pass:
card-dialog.js↔ app.css): the detent maths is consistent. Medium's visual top works out to0.355 × innerHeightexactly astops()computes it, and theMath.max(large, …)guard handles short screens. Thenow < r.mediumthrow-from-large-stops-at-medium rule, the >80ms dead-finger check,pointercancel, the upload guard via the disabled ×, and the reduced-motion instant path (still.matches → go(), and the 600ms timeout covers thetransition: nonecase) all hold up. The newmobile.spec.jsCDP drag drives exactly these paths.close?.click()fires Blazor's handler even though the button isdisplay: noneon a phone, and blurring before it lets thechangesave land first, as documented.card.BoardColumn?.Nameis loaded (the calendar already relied onBoardColumn?.BoardId), andBoardPage.ColumnNameOf's drag-follow lookup falls back toBoardColumnId.CommentService, so_comments.Skip(Earlier)is the latest three;_showAllresets only when the card changes. The keyboard inset is produced by the existingsearch-interop.jswatcher (the nav header's SearchBox mounts it), so--keyboard-insethas a producer at the foot of the card sheet.inspector.js,modal.edit,modal.view,comments.empty,.card-detailsor the broad.detail-panelselector (.detail-panel-assigneesis kept deliberately); the removed.modal-savedblock is replaced by the.card-noteCarry and the:not(:empty)::beforeseparator; the share glyph class.share-buttonmatches the CSS you target.Minor, not blocking:
.card-modal:has(.comment-form)hardcodes--sheet-composer-h: 128px; if the pinned form ever grows (error line shown, longer wrap), the body's bottom pad lags it.FormatAgo-rendered stamp only refreshes when the dialog re-renders; acceptable in a dialog this short-lived.⏱ 6m 37s · 73 steps · $0.1723 · tokens: 122.0k in / 4.7k out (+4242.6k cache-read) · Go: 5h 3% · wk 11% · mo 88%
📜 Full session transcript
@ -11,1 +9,3 @@@if (!IsNew && !string.IsNullOrEmpty(BoardKey))@* data-detent is the phone sheet's first height; card-dialog.js owns it from then on. *@<div class="modal card-modal" role="dialog" aria-modal="true" aria-labelledby="card-modal-title"data-detent="@(IsNew ? "large" : "medium")" @onclick:stopPropagation="true" @ref="_dialog">The sheet height survives opening another card:
data-detentis only written by Blazor when its rendered value changes, and for an existing card that value is constantlymedium— after JS has moved it tolarge, a subsequent re-render (or opening a different card in the same component instance) carries no diff entry for the attribute, so the next card opens at the previous height rather than the documented "existing cards open at medium". Same component instance, same DOM node. Only affects the second-and-later opens; worth either re-pinning the detent client-side inwatch()or dropping the claim from the docs.On the sheet-height note in
CardModal.razor: that case can't arise. The heights exist only below 600px, and there another card can't be opened while the sheet is up. Tapping the dimmed board above a medium sheet closes the dialog, soCardModalis disposed. The next card then gets a new instance and a new DOM node, which open at medium. Switching cards in place, with the same instance, happens only in the docked inspector from 1100px, where there are no sheet heights. So I've left the code and the docs as they are.9abe07dadds the changelog line, folded into the existing card-panel bullet so the list stays at 7.🤖 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.
✅ Verdict: approve — no blocking issues found.
I re-read the new commit against the diff and didn't run the build or the e2e specs. I found no blocking problems.
My earlier minor point is resolved.
FormatAgonow compares calendar days once a comment is more than a day old, so 47 hours ago reads "2 days ago".RelativeTimeTestspins this, along with the 30h "yesterday" and 9-day date cases, in both locales. The docs and the changelog were updated in the same PR.The one point I'm leaving is non-blocking: relative times in a long-open dialog don't refresh until the next re-render.
🧠 claude-sonnet-5-5 · ⏱ 0m 3s · 2 turns · tokens: 68.2k in / 288 out (+12.2k cache-read)
📜 Full session transcript
🤖 Reviewing this PR — the review will link the full session transcript.
📜 Live transcript — updating every ~5 minutes while the review runs.
✅ Verdict: approve — no blocking issues found.
Re-review of the new commits: no blockers. The prior threads are all resolved or moot.
What I checked this pass:
data-detent(from the previous pass): still mechanically true —watch()fires only onfirstRenderand Blazor doesn't rewrite an unchanged attribute — but I've re-verified it cannot produce a wrong resting height in practice, because on a phone the fullscreen backdrop blocks opening another card into the same dialog node, and the docked inspector never enters the sheet branch. Downgraded to a non-blocking remark oncard-dialog.js; no change requested.FormatAgonow counts calendar days (47h → "2 days ago", 30h → "yesterday"), matching the earlier notes, andRelativeTimeTestspins both locales' cases.0.355 × innerHeightmatches the CSS, theMath.max(large, …)clamp, the >80ms dead-finger rule, the upload guard via the disabled ×, the reduced-motion instant path (plus the 600ms fallback), andpointercancelall hold.changesave precedes the close, matching the updated docs.FormatDueWhenweekday indexing (Monday=0) and UTCTodayare consistent withCardView's pill, and the tests pin Tuesday 2026-09-22 correctly.card-dialog.js,modal.autosave, removedmodal.edit/modal.view,comments.earlier,.card-delete, 380px inspector).Nothing blocking. Good to merge.
⏱ 11m 46s · 10 steps · $0.0479 · tokens: 246.3k in / 1.5k out (+225.8k cache-read) · Go: 5h 4% · wk 12% · mo 88%
📜 Full session transcript
@ -0,0 +49,4 @@const body = dialog.querySelector('.modal-body');const close = dialog.querySelector('.modal-close');const at = () => dialog.dataset.detent;const expand = () => { if (phone.matches && at() === 'medium') dialog.dataset.detent = 'large'; };Keeping my earlier note here for the author's benefit, downgraded to non-blocking on closer look:
watch()runs once (OnAfterRenderAsyncguarded byfirstRender), and Blazor only rewritesdata-detenton a diff, so after JS moves the open sheet tolargea same-instance re-render (e.g. a save orCommentsChanged) won't re-pin it. In practice this can't strand a card at the wrong height as I first suspected: on a phone the fullscreen backdrop blocks board taps, the dialog can only be swapped card-to-card on the docked inspector (wherecard-dialog.jsnever touches the detent), and any re-render lands while the sheet is already as the user left it. Left as-is is fine; pinning the detent inwatch()would only matter if a phone path ever opens a second card into the same node.9abe07df3ff56cc2e3c8🤖 Reviewing this PR — the review will link the full session transcript.
📜 Live transcript — updating every ~5 minutes while the review runs.
🤖 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.
✅ Verdict: approve — no blocking issues found.
I found no blocking problems. No commits have landed since my last pass. I re-read the diff and didn't run the build or e2e specs.
My earlier
FormatAgopoint is resolved: 47 hours ago now reads "2 days ago", andRelativeTimeTestspins it in both locales.One non-blocking note remains. Relative times in a long-open dialog won't refresh until the next re-render.
🧠 claude-sonnet-5-5 · ⏱ 0m 8s · 3 turns · tokens: 81.0k in / 339 out (+80.7k cache-read)
📜 Full session transcript
✅ Verdict: approve — no blocking issues found.
Re-review
No blockers — good to merge. All three of my prior notes are answered in
ui.md:card-dialog.js:122focusinfilter — the missingcomment-edittextarea:ui.md6945–6952 answers it exactly as I guessed. The edit box lives in the already-large card sheet, out of the medium sheet's reach (its body doesn't scroll there), so the keyboard can't cover it on the lower half — and on the phone, editing can already only be initiated from acomment-actionbutton on a card row.comment-action, not from the reduced surface. The mobile spec pins the composer path (comment pinned to the sheet's foot, above the keyboard via--keyboard-inset), which is the one that matters; leaving the edit-box case as-is is reasonable.focusinopening the sheet when it's mid-drag — the pointer initiatives the move, and afocusinlanding mid-drag would stop and rotate the sheet to large while the finger is still down. Answered with a small but real guard:card-dialog.js:121checksat() === 'medium'before assigning large, so a mid-drag sheet (never at medium once dragged) only pivots once the finger settles past the medium threshold, consistent with the same guard already gatingexpand()elsewhere..calendar-daynesting with--sheet-composer-h— the comment box is.card-modal's child (not the body's), so it isn't carried by the scrolling body and the pad is reserved out of the group flow; that's a reasonable refinement of what I flagged.What I checked this pass:
BoardPalette.ColorOf(int)exists (BoardPalette.cs:27) and is fit for the crumb's--board-color.--font-monoexists asJetBrains Mono, ui-monospace, monospace(app.css:28) — the diff's trailing font stack change tracks an already-defined variable.modal.done/modal.close/comments.earlierall exist in both the en and de dictionaries.--keyboard-insethas a real producer insearch-interop.js(setProperty/removeProperty), as the PR description claims;app.cssalready consumes it for the search sheet, so the card sheet's pinned composer is on solid ground.Nothing blocking. Approve.
⏱ 0m 33s · 7 steps · $0.0186 · tokens: 56.3k in / 956 out (+273.3k cache-read) · Go: 5h 0% · wk 12% · mo 88%
📜 Full session transcript