Calendar drag ghost: remove the thick snap line; inset the start/end times with card padding #612

Open
opened 2026-10-01 09:42:33 +00:00 by kayg · 9 comments
Owner

Owner report (2026-10-01, Calendar drag screenshots on 1af8ead26, from #536 snapping)

  1. "This is horrible visually to represent that it starts from there; just showing the time is enough?" While dragging or creating, a thick dark horizontal line marks the snap edge above the ghost. Remove it. The start and end times on the ghost are the feedback.
  2. "The times could sit further up/down/inward, basically with some padding, so it looks better." The 13:30 / 14:45 labels sit flush against the ghost's top-left and bottom-right corners. Inset them with the item card's own padding tokens (the same inset as an event card's text), vertically centred in a small pill if the ghost is short; never clipped by the radius.
  3. Snapping stays as built (#536); a snap may give a subtle haptic-like spring nudge on the ghost (the shared spring), but no lines.
    Test: e2e drag screenshots at 3×: no snap line; time labels inset by the card padding token (±0.5 px). Web gates.
## Owner report (2026-10-01, Calendar drag screenshots on 1af8ead26, from #536 snapping) 1. "This is horrible visually to represent that it starts from there; just showing the time is enough?" While dragging or creating, a thick dark horizontal line marks the snap edge above the ghost. Remove it. The start and end times on the ghost are the feedback. 2. "The times could sit further up/down/inward, basically with some padding, so it looks better." The 13:30 / 14:45 labels sit flush against the ghost's top-left and bottom-right corners. Inset them with the item card's own padding tokens (the same inset as an event card's text), vertically centred in a small pill if the ghost is short; never clipped by the radius. 3. Snapping stays as built (#536); a snap may give a subtle haptic-like spring nudge on the ghost (the shared spring), but no lines. **Test:** e2e drag screenshots at 3×: no snap line; time labels inset by the card padding token (±0.5 px). Web gates.
Author
Owner

Starting #612 on branch job/dragghost-612 at base SHA 5882b4340e7b6c1fa755567772484b19944cb1f0. I have read CLAUDE.md, CONTEXT.md, docs/DESIGN.md and the issue. I am tracing the drag ghost, card padding tokens and existing Calendar e2e/bench paths now.

Starting #612 on branch `job/dragghost-612` at base SHA `5882b4340e7b6c1fa755567772484b19944cb1f0`. I have read `CLAUDE.md`, `CONTEXT.md`, `docs/DESIGN.md` and the issue. I am tracing the drag ghost, card padding tokens and existing Calendar e2e/bench paths now.
Author
Owner

The first real-server drag e2e reached the 390 px screenshot pass, then failed in the existing empty-grid hit check: optional chaining returned undefined when elementFromPoint had no element, while the assertion expects null. I am normalizing the no-hit result to null; the empty-grid expectation stays the same.

The first real-server drag e2e reached the 390 px screenshot pass, then failed in the existing empty-grid hit check: optional chaining returned `undefined` when `elementFromPoint` had no element, while the assertion expects `null`. I am normalizing the no-hit result to `null`; the empty-grid expectation stays the same.
Author
Owner

The second real-server run passed the snap-label and no-line checks, then failed at the existing Task ArrowDown assertion: the focused page-wide 3× context returned 14:15 instead of the expected 13:52. I will keep interactions at the normal device scale and use a separate 3× context only for the requested screenshots; the keyboard expectation stays unchanged.

The second real-server run passed the snap-label and no-line checks, then failed at the existing Task ArrowDown assertion: the focused page-wide 3× context returned `14:15` instead of the expected `13:52`. I will keep interactions at the normal device scale and use a separate 3× context only for the requested screenshots; the keyboard expectation stays unchanged.
Author
Owner

The Task drag response carried 13:37–14:37, but the immediate ArrowDown request returned 14:15; the Calendar refresh after the write is asynchronous. The e2e helper did not wait for the refreshed plan before sending the next key. I am adding that render wait and keeping the 13:52 step expectation unchanged.

The Task drag response carried `13:37–14:37`, but the immediate ArrowDown request returned `14:15`; the Calendar refresh after the write is asynchronous. The e2e helper did not wait for the refreshed plan before sending the next key. I am adding that render wait and keeping the `13:52` step expectation unchanged.
Author
Owner

At 390 px in Week, the live e2e reported .tg-body.scrollTop at its 11 px maximum while the 17:30 drag point sat below the viewport, so no ghost rendered. The phone screenshot case now uses 10:30 inside the initial viewport; tablet and desktop keep the afternoon range.

At 390 px in Week, the live e2e reported `.tg-body.scrollTop` at its 11 px maximum while the 17:30 drag point sat below the viewport, so no ghost rendered. The phone screenshot case now uses 10:30 inside the initial viewport; tablet and desktop keep the afternoon range.
Author
Owner

Finding: the 390px day/week screenshots and 820px day screenshot passed, but the 820px week screenshot could not drag at 17:30. The week grid's .tg-body clamped scrollTop to 17px, leaving that point below the 900px viewport. I am keeping screenshot-only drags at 10:30 from the initial scroll position across widths; the drag behavior checks are unchanged.

Finding: the 390px day/week screenshots and 820px day screenshot passed, but the 820px week screenshot could not drag at 17:30. The week grid's `.tg-body` clamped `scrollTop` to 17px, leaving that point below the 900px viewport. I am keeping screenshot-only drags at 10:30 from the initial scroll position across widths; the drag behavior checks are unchanged.
Author
Owner

Finding: the 390px day/week screenshots and 820px day screenshot passed, but the 820px week screenshot could not drag at 17:30. The week grid's .tg-body clamped scrollTop to 17px, leaving that point below the 900px viewport. I am keeping screenshot-only drags at 10:30 from the initial scroll position across widths; the drag behavior checks are unchanged.

Finding: the 390px day/week screenshots and 820px day screenshot passed, but the 820px week screenshot could not drag at 17:30. The week grid's `.tg-body` clamped `scrollTop` to 17px, leaving that point below the 900px viewport. I am keeping screenshot-only drags at 10:30 from the initial scroll position across widths; the drag behavior checks are unchanged.
Author
Owner

Drag screenshot evidence (3×)

Snap ghost: snapped Log at desktop 3×

Day view:

Week view:

### Drag screenshot evidence (3×) Snap ghost: [snapped Log at desktop 3×](https://git.kayg.org/attachments/7f233901-6d90-4018-93aa-ced100dd93ab) Day view: - 390px: [light](https://git.kayg.org/attachments/f2694f72-dd7b-4558-bc8b-2cb439503c97), [dark](https://git.kayg.org/attachments/0229e320-1944-46cf-a94c-66e0c93ee617) - 820px: [light](https://git.kayg.org/attachments/a33e9ef3-d823-4c7f-9ccf-9ec13a822a09), [dark](https://git.kayg.org/attachments/d2a95471-7562-486f-80c9-d1fe0e8f601a) - 1440px: [light](https://git.kayg.org/attachments/9e6bcb5c-a2fa-470d-a388-a1c74d057938), [dark](https://git.kayg.org/attachments/45711a69-3f43-47e0-a022-f22da467d5aa) Week view: - 390px: [light](https://git.kayg.org/attachments/0835bfc9-629f-421b-a9be-b14653d7c6ec), [dark](https://git.kayg.org/attachments/2fb134d4-d61d-4d12-8d18-f66ec9b0c9a7) - 820px: [light](https://git.kayg.org/attachments/45d5358f-443a-4937-be62-75f46f053bd7), [dark](https://git.kayg.org/attachments/84f966ce-35d4-4847-a38c-68db38e9c1e1) - 1440px: [light](https://git.kayg.org/attachments/a7657bb9-7eba-4b31-9646-c2783ae1f13f), [dark](https://git.kayg.org/attachments/53599ab8-eafc-4fe0-8f9b-1373dcf53dee)
Author
Owner

Completed #612

Head SHA: bc08062b167e59ca7ac39426a96481b2664b2e75 (feature commit 179a67294). The branch includes the required merge of origin/dev.

Built

  • Removed the item-snap edge overlay and snapped Now-line glow. Snap targets still update the ghost times.
  • Inset long ghost times by the Calendar Event card padding tokens. Short ranges use a centered surface pill and reserve enough height for its padding.
  • Added real-server e2e assertions for no snap line and label geometry within 0.5 CSS px. Attached the 3× snapped ghost capture and the Day/Week light/dark matrix at 390, 820 and 1440 px in the screenshot comment above.

Files changed for #612:

  • packages/ui/src/components/calendar/GridColumn.svelte
  • packages/ui/src/components/calendar/TimeGrid.svelte
  • apps/web/e2e/calendar.mjs

Gate output (verbatim success lines)

E2E: calendar drag e2e: live labels and touch drag passed

svelte-check found 0 errors and 0 warnings

 Test Files  148 passed (148)
      Tests  1011 passed (1011)
   Start at  03:45:12
   Duration  81.28s (transform 50%, environment 19%, import 15%, tests 11%, setup 4%)

    Finished `dev` profile [unoptimized + debuginfo] target(s) in 2m 46s
    test result: ok. 39 passed; 0 failed; 2 ignored; 0 measured; 0 filtered out; finished in 1.13s
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 5m 43s
    test result: ok. 107 passed; 0 failed; 3 ignored; 0 measured; 0 filtered out; finished in 13.69s

MAIL_TLS_PROFILE {"first_100_ms":1147,"max_uid":12658,"messages":2000,"page_p50_ms":123.76664199999999,"page_p95_ms":191.481033,"process_vm_hwm_kib":24336,"provider":"local TLS Dovecot; one window per call","uid_windows":159,"wall_ms":22536}
test sync::tests::real_tls_provider_backfill ... ok
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 40 filtered out; finished in 23.57s

     Removed 15535 files, 7.9GiB total

cargo fmt --check exited 0 with no output. The production build completed with ✓ built in 1m 13s. The Vitest run also printed jsdom Window.scrollTo() and CSS-parser diagnostics; all tests passed.

Performance profile

Local bench/calendar-snap-536.mjs, compared with docs/perf/baseline.json (2026-09-30):

  • Average, 400 edges: p50/p95 1.52/3.79 µs, CPU 0.0136 s; baseline 4.36/13.27 µs, CPU 0.0176 s.
  • Worst, 10,000 edges: p50/p95 32.98/64.64 µs, CPU 0.0381 s; baseline 41.44/70.17 µs, CPU 0.0494 s.
  • Current RSS was 73,617,408–80,076,800 bytes; baseline was 21,917,696–35,512,320 bytes. Current load average was 17.60/15.47/17.56 before and 18.19/15.62/17.60 after.

Decisions and known gaps

  • The issue says a spring nudge may be used, so I left snapped labels as the feedback and added no extra nudge.
  • Screenshot-only drags use 10:30 at the initial scroll position. The Week grid clamps .tg-body scrolling to 11 px on phone and 17 px on tablet, so a 17:30 screenshot drag falls below the viewport. Interaction checks still cover the snap behavior.
  • The merged Mail TLS fixture needed write access to its generated Maildir on this rootless Podman host. The probe passed after a local permission adjustment; no fixture code was changed. I reported the setup finding on #613. The fixture and test keys were removed.

Cleanup completed: cargo clean ran and apps/web/build plus apps/web/.svelte-kit were removed. No screenshots were committed.

## Completed #612 Head SHA: `bc08062b167e59ca7ac39426a96481b2664b2e75` (feature commit `179a67294`). The branch includes the required merge of `origin/dev`. ### Built - Removed the item-snap edge overlay and snapped Now-line glow. Snap targets still update the ghost times. - Inset long ghost times by the Calendar Event card padding tokens. Short ranges use a centered surface pill and reserve enough height for its padding. - Added real-server e2e assertions for no snap line and label geometry within 0.5 CSS px. Attached the 3× snapped ghost capture and the Day/Week light/dark matrix at 390, 820 and 1440 px in the screenshot comment above. Files changed for #612: - `packages/ui/src/components/calendar/GridColumn.svelte` - `packages/ui/src/components/calendar/TimeGrid.svelte` - `apps/web/e2e/calendar.mjs` ### Gate output (verbatim success lines) ```text E2E: calendar drag e2e: live labels and touch drag passed svelte-check found 0 errors and 0 warnings Test Files 148 passed (148) Tests 1011 passed (1011) Start at 03:45:12 Duration 81.28s (transform 50%, environment 19%, import 15%, tests 11%, setup 4%) Finished `dev` profile [unoptimized + debuginfo] target(s) in 2m 46s test result: ok. 39 passed; 0 failed; 2 ignored; 0 measured; 0 filtered out; finished in 1.13s Finished `dev` profile [unoptimized + debuginfo] target(s) in 5m 43s test result: ok. 107 passed; 0 failed; 3 ignored; 0 measured; 0 filtered out; finished in 13.69s MAIL_TLS_PROFILE {"first_100_ms":1147,"max_uid":12658,"messages":2000,"page_p50_ms":123.76664199999999,"page_p95_ms":191.481033,"process_vm_hwm_kib":24336,"provider":"local TLS Dovecot; one window per call","uid_windows":159,"wall_ms":22536} test sync::tests::real_tls_provider_backfill ... ok test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 40 filtered out; finished in 23.57s Removed 15535 files, 7.9GiB total ``` `cargo fmt --check` exited 0 with no output. The production build completed with `✓ built in 1m 13s`. The Vitest run also printed jsdom `Window.scrollTo()` and CSS-parser diagnostics; all tests passed. ### Performance profile Local `bench/calendar-snap-536.mjs`, compared with `docs/perf/baseline.json` (2026-09-30): - Average, 400 edges: p50/p95 1.52/3.79 µs, CPU 0.0136 s; baseline 4.36/13.27 µs, CPU 0.0176 s. - Worst, 10,000 edges: p50/p95 32.98/64.64 µs, CPU 0.0381 s; baseline 41.44/70.17 µs, CPU 0.0494 s. - Current RSS was 73,617,408–80,076,800 bytes; baseline was 21,917,696–35,512,320 bytes. Current load average was 17.60/15.47/17.56 before and 18.19/15.62/17.60 after. ### Decisions and known gaps - The issue says a spring nudge may be used, so I left snapped labels as the feedback and added no extra nudge. - Screenshot-only drags use 10:30 at the initial scroll position. The Week grid clamps `.tg-body` scrolling to 11 px on phone and 17 px on tablet, so a 17:30 screenshot drag falls below the viewport. Interaction checks still cover the snap behavior. - The merged Mail TLS fixture needed write access to its generated Maildir on this rootless Podman host. The probe passed after a local permission adjustment; no fixture code was changed. I reported the setup finding on #613. The fixture and test keys were removed. Cleanup completed: `cargo clean` ran and `apps/web/build` plus `apps/web/.svelte-kit` were removed. No screenshots were committed.
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#612
No description provided.