From 10dec7c6dc3e1e051a2a3c8a6e60eac2532449b3 Mon Sep 17 00:00:00 2001 From: Teknium <127238744+teknium1@users.noreply.github.com> Date: Sat, 30 May 2026 07:13:26 -0700 Subject: [PATCH] fix(kanban): respect mobile safe areas in task detail drawer (#35378) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 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 --- plugins/kanban/dashboard/dist/style.css | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/plugins/kanban/dashboard/dist/style.css b/plugins/kanban/dashboard/dist/style.css index 9aa780e62..841890c51 100644 --- a/plugins/kanban/dashboard/dist/style.css +++ b/plugins/kanban/dashboard/dist/style.css @@ -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); }