fix(kanban): respect mobile safe areas in task detail drawer (#35378)

* fix(file-tools): handle UTF-8 BOM in read_file / write_file / patch

Some Windows editors prepend an invisible UTF-8 BOM (U+FEFF) to text
files. We had no awareness of it, so: read_file surfaced a phantom
U+FEFF as the first character; patch matches against the true first
line could miss; and a write/patch round-trip silently stripped the
marker, changing the file's byte signature.

Now:
- read_file / read_file_raw strip a single leading BOM so the model
  never sees it (only on the first chunk — the marker lives at byte 0).
- patch_replace strips the BOM before fuzzy-matching (so an exact
  first-line match works) and its post-write verification compares
  BOM-stripped content.
- write_file restores the BOM when the original file had one and the
  new content doesn't, mirroring the existing line-ending preservation
  (detect on disk via a cheap `head -c 3` probe or reuse pre_content,
  re-prepend across the edit). Guards against double-BOM.

Mid-content U+FEFF is left alone (it's data there, not a file marker).

Tests: TestBomHandling (real LocalEnvironment) — read-strips, raw-read
strips, write preserves, no-BOM-when-original-had-none, no-double-BOM,
patch round-trip preserves, patch matches first line through a BOM,
plus helper unit tests. 208 file-tool tests green.

* fix(kanban): respect mobile safe areas in task detail drawer

The task detail drawer is a body-level z-60 fixed overlay using
height:100vh starting at the viewport top. On mobile this puts the
drawer header behind the dashboard's fixed top bar (min-h-14, z-40)
and lets the bottom comment input sit under the browser's collapsing
nav bar.

- drawer: 100vh -> 100dvh (+ max-height:100dvh), 100vh kept as fallback
- head: padding-top honors env(safe-area-inset-top); mobile (<1024px,
  matching the lg breakpoint where the fixed bar shows) clears the
  3.5rem header
- comment-row + body: bottom padding extended with
  env(safe-area-inset-bottom) so the bottom-most element clears the
  mobile browser chrome

Mirrors the host shell idiom (100dvh + env(safe-area-inset-bottom) in
web/), and web/index.html already sets viewport-fit=cover so the insets
resolve. max()/calc() fallbacks leave desktop unchanged.

Closes #35324
This commit is contained in:
Teknium
2026-05-30 07:13:26 -07:00
committed by GitHub
parent ea6eaabd8f
commit 10dec7c6dc

View File

@ -334,6 +334,11 @@
.hermes-kanban-drawer {
width: min(var(--hermes-kanban-drawer-width, 640px), 92vw);
height: 100vh;
/* Dynamic viewport unit excludes the mobile browser's collapsing chrome
(URL/nav bars) so the drawer's bottom row stays reachable. Falls back to
100vh on browsers without dvh support. */
height: 100dvh;
max-height: 100dvh;
background: var(--color-card);
border-left: 1px solid var(--color-border);
display: flex;
@ -352,10 +357,23 @@
align-items: center;
justify-content: space-between;
padding: 0.6rem 0.8rem;
/* Honor the top safe-area inset (notch) so the task id / close button are
not clipped on mobile. */
padding-top: max(0.6rem, env(safe-area-inset-top));
border-bottom: 1px solid var(--color-border);
font-family: var(--font-mono, ui-monospace, monospace);
}
/* On mobile the dashboard shell renders a fixed top bar (min-h-14, hidden at
the lg breakpoint). The drawer is a body-level z-60 overlay starting at the
viewport top, so its header would sit behind that bar. Push the header down
by the bar height (3.5rem) plus the top safe-area inset. */
@media (max-width: 1023px) {
.hermes-kanban-drawer-head {
padding-top: calc(3.5rem + env(safe-area-inset-top));
}
}
.hermes-kanban-drawer-close {
appearance: none;
background: transparent;
@ -372,6 +390,10 @@
flex: 1;
overflow-y: auto;
padding: 0.9rem;
/* When no comment row is rendered (loading / error states), the scrolling
body is the bottom-most element — extend its bottom padding past the
mobile browser chrome so the last content stays readable. */
padding-bottom: max(0.9rem, calc(0.9rem + env(safe-area-inset-bottom)));
display: flex;
flex-direction: column;
gap: 0.85rem;
@ -530,6 +552,9 @@
display: flex;
gap: 0.4rem;
padding: 0.55rem 0.75rem;
/* Keep the comment input clear of the mobile browser nav bar / home
indicator by extending the bottom padding with the safe-area inset. */
padding-bottom: max(0.55rem, calc(0.55rem + env(safe-area-inset-bottom)));
border-top: 1px solid var(--color-border);
background: color-mix(in srgb, var(--color-card) 90%, transparent);
}