Skip to content

Phone UI: one-line header, locked viewport, one scroller per view - #28

Merged
utorque merged 1 commit into
mainfrom
claude/phone-ui-overhaul-6b9ho2
Jul 25, 2026
Merged

Phone UI: one-line header, locked viewport, one scroller per view#28
utorque merged 1 commit into
mainfrom
claude/phone-ui-overhaul-6b9ho2

Conversation

@utorque

Copy link
Copy Markdown
Owner

Second pass on the phone layer (≤640px). The PC UI is unchanged — verified by
pixel-diffing every destination at 641/700/768/900/1024/1440 before vs after,
back to back on the same data: 7 of 9 views byte-identical, the other two
differ by ≤46 sub-threshold pixels (max intensity delta 10/255) from text
antialiasing where a label gained a wrapper .

Layout model. Phones are now height-locked like desktop instead of scrolling
the page: html/body get height:100dvh; overflow:hidden, and

app-main = 100dvh − --ph-header-h (50px) − --ph-nav-h (54px + safe-area)

Each view then divides that budget with flexbox — a fixed toolbar row plus
exactly one child that scrolls itself. That is the fix for the double
scrollbars in the kanban, the note editor and the assistant: nothing nests a
scroller inside another scroller, and no view scrolls the page.
viewDisplayMode() is the JS half — Tasks/Notes/Calendar become display:flex on
phones only (desktop keeps block; only the assistant view was ever a flexbox),
re-applied on breakpoint flips by applyResponsiveViewDisplay().

  • Header: one row — brand, the quick-capture input inline, action icons right.
  • Toolbars: one row, icon-only actions. Every dropped label is wrapped in a
    .btn-label span in index.html (Board/Overview/Download/Share/Stop sharing/
    Files/Settings), so hiding it is one rule and desktop markup renders the
    same.
  • Kanban: the per-card "…" button is gone (markup, CSS and click branch);
    tapping a card opens the action sheet — status · freeze · Edit… — instead of
    jumping to the edit modal. Board/Overview sit inline with the space dropdown.
  • Overview: single scrolling child; stat cards 2×2; the "Show done" bar and its
    list ordered last with CSS order (desktop order untouched).
  • Note editor: the overlay is height-locked to the viewport and passes a
    definite height down to CodeMirror, so the note is exactly as tall as the
    space available and only the editor/preview scrolls. NotesView.refresh()
    re-measures on overlay open and on breakpoint flips.
  • Assistant: the iframe gets an exact pixel height (app-main − toolbar), which
    is the sizing information the embedded Chainlit UI was missing. Phone rules
    inside the iframe live in chat/public/simpler.css gated on
    html.simpler-phone, which simpler-bridge.js mirrors from the shell's
    body.is-mobile — deliberately not from the iframe's own width, which a
    narrowed desktop window can also make small. They hide the starters (the
    backend still ships them, so a wider viewport gets them back with no
    reload), wrap the composer's control row, and bottom-align the empty state.
    The workspace Files button and drawer are off on phones.
  • Calendar: the task sidebar and the calendar become two stacked panes each
    scrolling itself, so the calendar is always on screen; the legend's
    Ctrl/Shift+click hint is dropped (no modifier keys on a phone).

Verified with a Playwright pass at 320/360/393/430/640×short: no horizontal
overflow, no page scroll, note-editor overlay exactly the viewport height with
its action row inside it; plus the real flows — tap-card → sheet → status
change, space dropdown filtering, a chat round trip inside the iframe, and a
phone↔desktop↔phone breakpoint round trip. Backend suite green (363 tests, no
Python touched).

Pre-existing and left alone: the header still overflows horizontally between
641px and ~1030px (nav labels + capture + actions do not fit); confirmed
identical on the unmodified code.

Co-Authored-By: Claude Opus 5 noreply@anthropic.com
Claude-Session: https://claude.ai/code/session_012rpit72fJZVQSie3kAryhx

Second pass on the phone layer (≤640px). The PC UI is unchanged — verified by
pixel-diffing every destination at 641/700/768/900/1024/1440 before vs after,
back to back on the same data: 7 of 9 views byte-identical, the other two
differ by ≤46 sub-threshold pixels (max intensity delta 10/255) from text
antialiasing where a label gained a wrapper <span>.
Layout model. Phones are now height-locked like desktop instead of scrolling
the page: html/body get `height:100dvh; overflow:hidden`, and
app-main = 100dvh − --ph-header-h (50px) − --ph-nav-h (54px + safe-area)
Each view then divides that budget with flexbox — a fixed toolbar row plus
exactly one child that scrolls itself. That is the fix for the double
scrollbars in the kanban, the note editor and the assistant: nothing nests a
scroller inside another scroller, and no view scrolls the page.
viewDisplayMode() is the JS half — Tasks/Notes/Calendar become display:flex on
phones only (desktop keeps block; only the assistant view was ever a flexbox),
re-applied on breakpoint flips by applyResponsiveViewDisplay().
- Header: one row — brand, the quick-capture input inline, action icons right.
- Toolbars: one row, icon-only actions. Every dropped label is wrapped in a
.btn-label span in index.html (Board/Overview/Download/Share/Stop sharing/
Files/Settings), so hiding it is one rule and desktop markup renders the
same.
- Kanban: the per-card "…" button is gone (markup, CSS and click branch);
tapping a card opens the action sheet — status · freeze · Edit… — instead of
jumping to the edit modal. Board/Overview sit inline with the space dropdown.
- Overview: single scrolling child; stat cards 2×2; the "Show done" bar and its
list ordered last with CSS `order` (desktop order untouched).
- Note editor: the overlay is height-locked to the viewport and passes a
definite height down to CodeMirror, so the note is exactly as tall as the
space available and only the editor/preview scrolls. NotesView.refresh()
re-measures on overlay open and on breakpoint flips.
- Assistant: the iframe gets an exact pixel height (app-main − toolbar), which
is the sizing information the embedded Chainlit UI was missing. Phone rules
inside the iframe live in chat/public/simpler.css gated on
html.simpler-phone, which simpler-bridge.js mirrors from the shell's
body.is-mobile — deliberately not from the iframe's own width, which a
narrowed desktop window can also make small. They hide the starters (the
backend still ships them, so a wider viewport gets them back with no
reload), wrap the composer's control row, and bottom-align the empty state.
The workspace Files button and drawer are off on phones.
- Calendar: the task sidebar and the calendar become two stacked panes each
scrolling itself, so the calendar is always on screen; the legend's
Ctrl/Shift+click hint is dropped (no modifier keys on a phone).
Verified with a Playwright pass at 320/360/393/430/640×short: no horizontal
overflow, no page scroll, note-editor overlay exactly the viewport height with
its action row inside it; plus the real flows — tap-card → sheet → status
change, space dropdown filtering, a chat round trip inside the iframe, and a
phone↔desktop↔phone breakpoint round trip. Backend suite green (363 tests, no
Python touched).
Pre-existing and left alone: the header still overflows horizontally between
641px and ~1030px (nav labels + capture + actions do not fit); confirmed
identical on the unmodified code.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012rpit72fJZVQSie3kAryhx
@utorque
utorque merged commit c9a3dc8 into mainJul 25, 2026
2 checks passed
@utorque
utorque deleted the claude/phone-ui-overhaul-6b9ho2 branch July 25, 2026 10:48
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@utorque@claude