redesign(ui): rebuild the plan-reminder form as a grouped-row panel - #2002
Merged
Conversation
The create/edit dialog packed nine fields into paired two-column FormLayouts under an eyebrow heading — dense, boxy, and unlike any other Maka surface. Rebuilt on the reference scheduled-task panel shape, expressed in Maka's own idiom: - a quiet kicker (新建提醒 / 编辑提醒) with the template menu and close beside it, then ONE display element: a large borderless title input (raw <input> wrapped in Astryx Field so the hidden label and detached error status stay accessible), then the bare description textarea; - the schedule and delivery fields become two labeled groups of label-left / control-right hairline rows (重复 / 时间 / Cron, then 方式 / 平台 / Chat ID) — the settings open-row idiom scoped to the dialog — with the run-at presets as a quiet ghost row under 时间; - the title's "required" error no longer scolds an untouched empty form: it appears after first input (the submit button was already the gate); - copy gains groupSchedule/groupDelivery + short row labels (时间 / 方式) so group and row labels stop repeating each other; the unused eyebrow style is retired. All form state, validation, and the submit single-flight/close-guard invariants are unchanged — presentation only. Verified: build, typecheck, check-dead-css, check-a11y/copy/console, product Storybook smoke (71 renders x 3 viewports), plus a rendered screenshot of the open dialog from the built Storybook.
Astro-Han
added a commit
that referenced
this pull request
Aug 3, 2026
#2002 rebuilt the dialog's title row as a bare <input autoFocus> inside a Field, replacing a TextInput with `hasAutoFocus`. Astryx's Dialog picks its initial focus target by querying `[data-autofocus]` after showModal(), and its own source documents why React's autoFocus cannot work here: it calls .focus() during commit, while the dialog is still invisible, so the focus silently fails. TextInput emits `data-autofocus`; the bare input did not, so opening 编辑提醒 left the caret on the close button instead of the title. Move the field onto the same seam. Caught by the E2E that asserts the title box is focused when the edit dialog opens.
Astro-Han
added a commit
that referenced
this pull request
Aug 3, 2026
…utofocus, harbor-cell deadline race) (#2001) * test(e2e): sample Mermaid toolbar geometry atomically `toolbar.top - figure.top` is structurally the figure's 1px top border: the Toolbar is the figure's first flex child, so zoom cannot move it. The assertion still read 2-3px of change in CI because it derived that offset from two independent boundingBox() round-trips, and the transcript is a bottom-pinned scroller that re-pins on every ResizeObserver update — the zoom-induced viewport reflow lands between the two samples and the scroll drift shows up as a phantom offset. Read both the toolbar offset and the viewport height inside one evaluate, so the pair is sampled in a single frame, and poll for the steady state instead of the frame right after the click: the zoomed layout settles over a rAF, a ResizeObserver pass, and the scroller's re-pin. The 1px tolerance is unchanged; only the sampling is fixed. Closes #2000 * fix(ui): restore autofocus on the plan-reminder title field #2002 rebuilt the dialog's title row as a bare <input autoFocus> inside a Field, replacing a TextInput with `hasAutoFocus`. Astryx's Dialog picks its initial focus target by querying `[data-autofocus]` after showModal(), and its own source documents why React's autoFocus cannot work here: it calls .focus() during commit, while the dialog is still invisible, so the focus silently fails. TextInput emits `data-autofocus`; the bare input did not, so opening 编辑提醒 left the caret on the close button instead of the title. Move the field onto the same seam. Caught by the E2E that asserts the title box is focused when the edit dialog opens. * test(headless): stop racing the deadline against harbor-cell setup The force-stop test asserts that the deadline stops an *active* isolated tool, but established that precondition by giving the cell 1000ms of wall clock to finish setup, create the session, and drive the first send before the timer fired. Lose that race on a loaded runner and the run is still cancelled by `benchmark.deadline` — settledByDeadline stays true — while the backend is never stopped, so `stopModes` is empty. That is the CI failure: actual [] vs expected ['immediate']. Reproduced by forcing the ordering with a 1ms deadline, which yields the same signature. Budget the setup at 3000ms instead of 1000ms and assert the precondition directly, so losing the race reports 'the isolated tool never started within the budget' rather than a bare deepEqual mismatch.
jackwener
added a commit
that referenced
this pull request
Aug 3, 2026
Adversarial review of #2002/#2004 (correctness + design lenses, every finding verified before fixing). Confirmed regressions, fixed: - Autofocus was broken: raw `autoFocus` fires at React commit, before showModal() makes the dialog visible, so focus silently landed on the first button. The title input now wears `data-autofocus`, the hook Astryx Dialog actually queries after opening (this is also what the plan-reminders e2e asserts). - The raw title input carried none of the a11y wiring TextInput used to provide — aria-required / aria-invalid / aria-describedby now point at Field's generated status id, and Field gets isRequired back, so the validation message is announced again. - The `::backdrop` override derived its color from --foreground, which inverts in dark mode (a whitening veil over a dark UI). It derives from --background now — light wash over light, dark scrim over dark — and the sheet gains a hairline inline-start border so dark mode separates by ring before shadow. - The form's own `overflow: auto` was a no-op inside LayoutContent's `overflow: clip`; tall variants (cron + bot delivery) clipped the Chat ID row and Create with no way to scroll. LayoutContent is the single scroll region now (isScrollable), between the pinned header and footer Layout slots. Design-review completions: - 时间 row: hand-typed `YYYY-MM-DDTHH:mm` TextInput → Astryx DateTimeInput (compact, 24h, 5-min stepping, full-row width); the sheet widens 440 → 480 so the date+time pair fits its min-content with proper insets. - The inset group cards gain a real fill (--muted) — a border on the same surface color read as a bare outlined rectangle, not an inset. - The borderless title gets a :focus-visible ring (it was the one control with no focus indicator); its placeholder moves to the platform text-secondary token (the hand mix was below 4.5:1). - Group labels step up to the label type role so the kicker/label ladder reads as two tiers; presets keep role="group"; the sheet slides in from the right (Astryx's center scale-pop detached a 100dvh element from three window edges mid-animation). - Dead copy keys pruned (eyebrow, cancel, field.delivery, templatesAriaLabel); two classNames that landed on the menu popover instead of the trigger removed. Verified: build, typecheck, check-dead-css, check-a11y/copy/console, plan-reminder unit tests (9/9), Storybook smoke (74 renders x 3 viewports), rendered screenshot of the open sheet re-checked.
jackwener
added a commit
that referenced
this pull request
Aug 3, 2026
* fix(ui): deep-review round over the plan-reminder sheet Adversarial review of #2002/#2004 (correctness + design lenses, every finding verified before fixing). Confirmed regressions, fixed: - Autofocus was broken: raw `autoFocus` fires at React commit, before showModal() makes the dialog visible, so focus silently landed on the first button. The title input now wears `data-autofocus`, the hook Astryx Dialog actually queries after opening (this is also what the plan-reminders e2e asserts). - The raw title input carried none of the a11y wiring TextInput used to provide — aria-required / aria-invalid / aria-describedby now point at Field's generated status id, and Field gets isRequired back, so the validation message is announced again. - The `::backdrop` override derived its color from --foreground, which inverts in dark mode (a whitening veil over a dark UI). It derives from --background now — light wash over light, dark scrim over dark — and the sheet gains a hairline inline-start border so dark mode separates by ring before shadow. - The form's own `overflow: auto` was a no-op inside LayoutContent's `overflow: clip`; tall variants (cron + bot delivery) clipped the Chat ID row and Create with no way to scroll. LayoutContent is the single scroll region now (isScrollable), between the pinned header and footer Layout slots. Design-review completions: - 时间 row: hand-typed `YYYY-MM-DDTHH:mm` TextInput → Astryx DateTimeInput (compact, 24h, 5-min stepping, full-row width); the sheet widens 440 → 480 so the date+time pair fits its min-content with proper insets. - The inset group cards gain a real fill (--muted) — a border on the same surface color read as a bare outlined rectangle, not an inset. - The borderless title gets a :focus-visible ring (it was the one control with no focus indicator); its placeholder moves to the platform text-secondary token (the hand mix was below 4.5:1). - Group labels step up to the label type role so the kicker/label ladder reads as two tiers; presets keep role="group"; the sheet slides in from the right (Astryx's center scale-pop detached a 100dvh element from three window edges mid-animation). - Dead copy keys pruned (eyebrow, cancel, field.delivery, templatesAriaLabel); two classNames that landed on the menu popover instead of the trigger removed. Verified: build, typecheck, check-dead-css, check-a11y/copy/console, plan-reminder unit tests (9/9), Storybook smoke (74 renders x 3 viewports), rendered screenshot of the open sheet re-checked. * redesign(ui): plan-reminder form becomes a true split-view panel WAWQAQ round 3: the sheet was pinned to the WINDOW edge while the page content is width-clamped, leaving a dead band between the list and the form — the reference has none: its create panel sits flush against the list pane, one divider between, non-modal. - The form drops the <dialog> overlay entirely. It is an in-page <aside> now: when open, .maka-plan-panel becomes a two-column grid (list keeps flowing in column one; the panel takes minmax(380px, 460px) flush right) with a single hairline seam. Non-modal role="dialog" + aria-labelledby keeps the accessible name the e2e locates; Escape closes through the same guarded path via an onKeyDown at the panel root; the title autofocuses from a mount effect (the component still remounts per form session). - The aside is position: sticky with its own pinned header/footer and the form as the single scroll region between them, so the list can scroll independently — matching the reference's split behavior. - The sheet-era CSS (window-pinned dialog, custom ::backdrop) is retired; the slide-in animation survives on the aside. Verified: build, typecheck, check-dead-css, check-a11y/copy/console, plan-reminder unit tests 9/9, Storybook smoke (74 renders x 3 viewports), rendered screenshot re-checked against the reference. * fix(ui): plan form panel hands focus back to its opener on close The Astryx Dialog used to capture the focused element at open and restore it on close; the split-view aside dropped that contract, so Escape from the edit panel left focus on <body> — caught by the e2e that expects the row's menu trigger to regain focus. The open effect now captures the opener (the panel has already re-focused the triggering row control by then) and its cleanup hands focus back when the panel closes. Verified locally: both plan-reminders e2e tests pass.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Rebuilds the 新建定时任务 create/edit dialog per the review feedback ("特别丑,完全重做"). Layout inspiration from the reference scheduled-task panels; expression entirely in Maka's own idiom on Astryx.
Before → After
Before: nine fields packed into paired two-column
FormLayouts under an eyebrow heading — dense, boxy, unlike any other Maka surface.After:
<input>wrapped in AstryxField, so the hidden label and detached error status stay fully accessible.groupSchedule/groupDelivery+ short row labels (时间 / 方式) so group and row labels stop repeating; the unused eyebrow style is retired.All form state, validation, and the submit single-flight / close-guard invariants are unchanged — presentation only.
Verification
build ✅ · typecheck ✅ · check-dead-css ✅ · check-a11y/copy/console ✅ · Storybook smoke 71 renders × 3 viewports ✅ · rendered screenshot of the open dialog verified from the built Storybook (posted in the work thread).
Follow-up (next PR): the list page (
plan-reminder-panel.tsx) — big title + search + segmented state filter + quiet rows, per the same references.