fix(dashboard): pin --vv-offset-top to resize/focus, ignore pan scrolls

iOS fires visualViewport scroll events at 60fps during a pan with the
keyboard up. Routing those through React state and into the .chat-thread
translateY(--vv-offset-top) transform amplified the pan into a visible
judder + ~300px shift + body background exposure.

useMobileKeyboard now uses two listeners: a full update (resize +
focusin/focusout) that re-snapshots all metrics including offsetTop, and
a scroll-only update that updates only height/keyboardOpen. offsetTop
is therefore frozen between keyboard open/close events — the transform
correctly compensates for iOS's initial visualViewport shift on focus
without following pan-time movement.

Restores the translateY anchor (so the thread isn't off-screen on
first focus) while keeping the swipe-jitter fix.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
gsxdsm
2026-05-06 20:58:04 -07:00
parent d5858b44b9
commit 4708e453ae
20 changed files with 803 additions and 42 deletions

View File

@@ -471,6 +471,12 @@ Implemented in `agent-heartbeat.ts`:
- Canonical replication/write-coordination contract: [`docs/shared-mesh-protocol.md`](./shared-mesh-protocol.md)
- Defines protocol versioning, write classes, quorum/ack semantics, lease epochs/fencing, offline queue/replay, reconciliation outcomes, restart recovery hooks, and degraded-read staleness metadata.
- Existing `/api/mesh/sync` and settings-sync payloads remain the active exchange primitives while follow-on runtime tasks implement full v1 coordinator/quorum behavior.
- Distributed task-ID allocation (`packages/core/src/distributed-task-id.ts`) is the first mesh-aware coordinated write primitive.
- Durable state lives in SQLite tables `distributed_task_id_state` (prefix sequence + authoritative committed count) and `distributed_task_id_reservations` (reservation lifecycle rows).
- Reserve/commit/abort execute under a process-local lock and a single SQLite transaction. Lazy reservation expiry cleanup runs inside those same transactions.
- Default reservation TTL is `15 * 60 * 1000` ms (15 minutes). Expired/aborted reservations are **burned IDs** and are never reissued.
- `committedClusterTaskCount` from allocator state is the only authoritative cluster-wide committed-task count. Local task-row counts and ID suffix math are not authoritative.
- Mesh allocator write routes (`/api/mesh/task-ids/reserve|commit|abort`) return `503` when the coordinator node is unreachable; they never fall back to local-only cluster ID issuance.
- Process lifecycle ownership:
- `fn serve` / `fn dashboard` start a single process-level `PeerExchangeService` and stop it during shutdown.
- `CentralCore.startDiscovery()` is invoked from CLI startup only after HTTP bind completes so discovery advertises the actual listening port.