Polish mobile browser affordances

Keep the File Browser path and search affordances on compact mobile rows, with create buttons sharing the search row and the Up control sharing the path row. Give the Web Browser mobile toolbar a full-width address row by moving navigation controls above it, and add regression/DOX coverage for the layout contracts.

Alessandro committed Jun 23, 2026 at 14:01 UTC 0028473ec98c9e0334c399e9fcb6720ed80d60b4
6 files changed +59 -7
plugins/_browser/AGENTS.md
+1
@@ -19,6 +19,7 @@
19 - Preserve Playwright lifecycle cleanup and WebSocket viewer compatibility across regular host browsers and Electron WebContentsView embedding.
20 - Keep the WebUI Browser inside its own modal/canvas affordance; do not replace it with page-level navigation.
21 - Default the visible WebUI Browser to live CDP screencast for responsiveness. Keep lightweight CDP/DOM state snapshots as the fallback transport.
22 +- Keep narrow WebUI Browser controls usable by placing navigation buttons above a full-width address bar.
23 - Prefer DOM/CDP browser actions with refs, selectors, frame-chain refs, and screenshots over viewport coordinate input. Coordinates remain a visual fallback.
24 - Do not hardcode user-specific browser paths or secrets.
25
plugins/_browser/webui/browser-panel.html
+17
@@ -1278,6 +1278,23 @@
1278 }
1279
1280 @container (max-width: 460px) {
1281 + .browser-toolbar {
1282 + grid-template-columns: minmax(0, 1fr);
1283 + grid-template-areas:
1284 + "nav"
1285 + "address";
1286 + align-items: stretch;
1287 + gap: 7px;
1288 + }
1289 +
1290 + .browser-navigation {
1291 + justify-content: flex-start;
1292 + }
1293 +
1294 + .browser-address-form {
1295 + width: 100%;
1296 + }
1297 +
1298 .browser-meta-top {
1299 grid-template-columns: minmax(0, 1fr);
1300 }
tests/test_browser_agent_regressions.py
+11
@@ -1354,6 +1354,17 @@ def test_browser_panel_exposes_agent_friendly_address_input():
1354 assert 'class="browser-address" aria-label="Browser address" name="browser_address"' in panel
1355
1356
1357 +def test_browser_panel_gives_address_bar_full_mobile_row():
1358 + panel = (
1359 + PROJECT_ROOT / "plugins" / "_browser" / "webui" / "browser-panel.html"
1360 + ).read_text(encoding="utf-8")
1361 +
1362 + assert "@container (max-width: 460px)" in panel
1363 + assert ".browser-toolbar {\n grid-template-columns: minmax(0, 1fr);" in panel
1364 + assert ' "nav"\n "address";' in panel
1365 + assert ".browser-address-form {\n width: 100%;" in panel
1366 +
1367 +
1368 def test_browser_runtime_requires_current_content_helper_for_modifier_clicks():
1369 runtime = (
1370 PROJECT_ROOT / "plugins" / "_browser" / "helpers" / "runtime.py"
tests/test_file_browser_navigation.py
+4
@@ -74,6 +74,10 @@ def test_file_browser_compact_controls_and_narrow_layout_contract() -> None:
74 assert ".btn-new-item" in html
75 assert "width: 2.8rem;" in html
76 assert "height: 2.8rem;" in html
77 + assert ".path-navigator {\n align-items: center;\n flex-direction: row;" in html
78 + assert ".file-browser-toolbar {\n align-items: center;\n flex-direction: row;" in html
79 + assert ".file-search-shell {\n flex: 1 1 auto;\n min-width: 0;\n width: auto;" in html
80 + assert ".path-navigator .nav-button-label {\n display: none;" in html
81
82 assert "container: file-browser / inline-size;" in html
83 assert "@container file-browser (max-width: 620px)" in html
webui/components/modals/file-browser/AGENTS.md
+1
@@ -19,6 +19,7 @@
19 - Empty mounted startup states must self-heal to the `$WORK_DIR` default instead of rendering a blank path and empty list.
20 - Keep the file list readable in narrow canvas/modal containers by hiding the Modified date column before sacrificing the Name or Size columns.
21 - Keep New file and New folder controls icon-only across canvas and modal modes while preserving accessible labels.
22 +- Keep narrow mobile controls compact: Up shares the path row, and New file/New folder share the search row.
23 - Preserve surface actions that route supported files to Browser, Desktop, or Editor.
24
25 ## Work Guidance
webui/components/modals/file-browser/file-browser.html
+25 -7
@@ -754,7 +754,7 @@
754 gap: 0.5em;
755 }
756 .new-item-buttons button {
757 - margin-left: 0.5em;
757 + margin-left: 0;
758 }
759
760 .file-status-bar {
@@ -902,20 +902,31 @@
902 /* Responsive Design */
903 @media (max-width: 768px) {
904 .path-navigator {
905 - align-items: stretch;
906 - flex-direction: column;
905 + align-items: center;
906 + flex-direction: row;
907 gap: 0.5rem;
908 }
909 .path-navigator .back-button {
910 - align-self: flex-start;
910 + align-self: stretch;
911 }
912 .file-browser-toolbar {
913 - align-items: stretch;
914 - flex-direction: column;
913 + align-items: center;
914 + flex-direction: row;
915 + gap: 0.5rem;
916 }
917 .file-search-shell {
918 + flex: 1 1 auto;
919 min-width: 0;
918 - width: 100%;
920 + width: auto;
921 + }
922 + .new-item-buttons {
923 + flex: 0 0 auto;
924 + gap: 0.4rem;
925 + }
926 + .btn-new-item {
927 + width: 2.5rem;
928 + min-width: 2.5rem;
929 + height: 2.5rem;
930 }
931 .file-header {
932 grid-template-columns: 2.25rem minmax(0, 1fr) minmax(5rem, 0.52fr) 7.5rem;
@@ -929,6 +940,13 @@
940 }
941 }
942 @media (max-width: 540px) {
943 + .path-navigator .back-button {
944 + min-width: 2.45rem;
945 + padding-inline: 0.5rem;
946 + }
947 + .path-navigator .nav-button-label {
948 + display: none;
949 + }
950 .file-header,
951 .file-item {
952 grid-template-columns: 2.25rem minmax(0, 1fr) minmax(4.25rem, max-content) 5.25rem;