diff --git a/static/css/01-agent-chat.css b/static/css/01-agent-chat.css index 506d04e81..6a98cfd25 100644 --- a/static/css/01-agent-chat.css +++ b/static/css/01-agent-chat.css @@ -315,7 +315,7 @@ body.bg-pattern-ascii-fireflies { width: 240px; background: var(--sidebar-bg, var(--panel)); border-right: 1px solid var(--border); - transition: width 0.25s ease, opacity 0.2s ease, padding 0.25s ease; + transition: width 0.25s ease, opacity 0.2s ease, padding 0.25s ease, visibility 0.25s; display: flex; flex-direction: column; flex-shrink: 0; @@ -361,12 +361,23 @@ body.bg-pattern-ascii-fireflies { /* !important so it beats the inline width init.js restores from storage — otherwise the width never changes and only opacity animates, making the collapse look instant. With this, width animates from the inline value - down to 0 via the .sidebar width transition. */ + down to 0 via the .sidebar width transition. + display overrides the global .hidden utility, which would otherwise + remove the box before any transition can run. visibility (transitioned + on .sidebar) flips to hidden only once the collapse has finished, + taking the closed sidebar out of the tab order. */ + display: flex; width: 0 !important; padding: 0 !important; border: none; overflow: hidden; opacity: 0; + visibility: hidden; + pointer-events: none; + } + /* IDs so this also beats the mobile drawer's !important transition. */ + @media (prefers-reduced-motion: reduce) { + #sidebar, #icon-rail { transition: none !important; } } /* ===== Sidebar User Bar ===== */ .sidebar-user-bar { @@ -449,10 +460,6 @@ body.bg-pattern-ascii-fireflies { } - .sidebar.hidden .sidebar-user-bar { - display: none; - } - /* Sticky sidebar header — logo, never scrolls */ .sidebar-header { display: flex; @@ -673,6 +680,24 @@ body.bg-pattern-ascii-fireflies { margin-bottom: calc(-1 * var(--safe-bottom)); padding-bottom: calc(8px + var(--safe-bottom)); } + /* Tuck the rail under the sidebar (which paints above it) and slide it + out as the sidebar collapses, so the combined width eases instead of + jumping by the rail's 48px when the two swap. */ + .icon-rail, + .icon-rail.right-side { + margin-inline-end: -48px; + transition: margin-inline-end 0.25s ease, display 0.25s allow-discrete; + } + body.sidebar-collapsed:not(.hamburger-only) .icon-rail, + html.ody-sidebar-mini .icon-rail { + margin-inline-end: 0; + } + @starting-style { + body.sidebar-collapsed:not(.hamburger-only) .icon-rail, + html.ody-sidebar-mini .icon-rail { + margin-inline-end: -48px; + } + } } .icon-rail-divider { width: 24px; @@ -5116,7 +5141,7 @@ body.bg-pattern-ascii-fireflies { width: 80% !important; max-width: 340px; box-shadow: 4px 0 20px rgba(0,0,0,0.5); - transition: transform 0.25s ease, opacity 0.25s ease !important; + transition: transform 0.25s ease, opacity 0.25s ease, visibility 0.25s !important; opacity: 1 !important; overflow: visible !important; /* Force opaque background — Firefox mobile renders the @@ -5147,6 +5172,7 @@ body.bg-pattern-ascii-fireflies { } html.ody-sidebar-off .sidebar, html.ody-mobile-startup-sidebar-hidden .sidebar { + width: 80% !important; transform: translateX(-100%) !important; pointer-events: none !important; opacity: 0 !important; diff --git a/static/js/sidebar-layout.js b/static/js/sidebar-layout.js index 745c1e334..58fcb363a 100644 --- a/static/js/sidebar-layout.js +++ b/static/js/sidebar-layout.js @@ -170,6 +170,15 @@ export function initSidebarLayout(Storage, opts) { syncRailSide(); } + // Move the closed drawer to the other edge without transitioning its + // transform across the screen, so it then slides in from the edge it opens on. + function _setSidebarSideInstantly(sidebar, right) { + sidebar.style.setProperty('transition', 'none', 'important'); + sidebar.classList.toggle('right-side', right); + void sidebar.offsetWidth; + sidebar.style.removeProperty('transition'); + } + // Deliberate "open the sidebar" used by the mobile swipe gesture (wired at // module scope). It MUST set _userToggledSidebar so the auto-collapse // MutationObserver doesn't immediately re-hide it (the swipe was opening it, @@ -189,7 +198,7 @@ export function initSidebarLayout(Storage, opts) { if (side === 'left' || side === 'right') { const wantRight = side === 'right'; if (sidebar.classList.contains('right-side') !== wantRight) { - sidebar.classList.toggle('right-side', wantRight); + _setSidebarSideInstantly(sidebar, wantRight); // Swipe-selected sides are temporary on compact/mobile layouts. Do // not overwrite the user's desktop sidebar preference. if (window.innerWidth >= 768) { @@ -227,7 +236,7 @@ export function initSidebarLayout(Storage, opts) { // Mobile: the hamburger always opens the sidebar from the RIGHT. // (Not persisted — keeps the desktop side preference untouched.) if (!sidebar.classList.contains('right-side')) { - sidebar.classList.add('right-side'); + _setSidebarSideInstantly(sidebar, true); if (documentModule && documentModule.swapSide) { try { documentModule.swapSide(); } catch (_) {} } } // Opening sidebar — blur keyboard first, then open after layout settles @@ -312,7 +321,9 @@ export function initSidebarLayout(Storage, opts) { _wasAutoCollapsed = true; syncRailSide(); } else if (window.innerWidth >= AUTO_COLLAPSE_WIDTH && isHidden && _wasAutoCollapsed) { - // Only restore if chat won't be too narrow + // Only restore if chat won't be too narrow. Suppress the width + // transition so the reflow measures the sidebar at its full width. + sidebar.style.transition = 'none'; sidebar.classList.remove('hidden'); void document.body.offsetWidth; // reflow if (chatContainer && chatContainer.offsetWidth < MIN_CHAT_WIDTH) { @@ -320,6 +331,8 @@ export function initSidebarLayout(Storage, opts) { } else { _wasAutoCollapsed = false; } + void document.body.offsetWidth; + sidebar.style.transition = ''; syncRailSide(); } } diff --git a/tests/css_snapshot/baseline.json b/tests/css_snapshot/baseline.json index a144f9f53..550a438a2 100644 --- a/tests/css_snapshot/baseline.json +++ b/tests/css_snapshot/baseline.json @@ -1,5 +1,5 @@ { - "digest": "f7e60e4a567c46dc", + "digest": "5282a075729cc246", "elements": { "app-shell": { "app-loader": "f04ad5bf6312d53f", @@ -17,7 +17,7 @@ "export-dropdown-item": "d90f6f513d06a6f7", "export-dropdown-menu": "0793e06a6aae6a7a", "hamburger-btn": "34714f6eef3734d8", - "icon-rail": "e3f72205260a4a5f", + "icon-rail": "c800b4ef07f5f1f0", "icon-rail-btn": "54ffb10e056ebf44", "incognito-btn": "ee42bd3f6a32576b", "input-icon-btn": "3d1c773acd84a825", @@ -59,7 +59,7 @@ "settings-row": "de568724268cec6e", "settings-select": "a96e8430b0ec6668", "settings-sidebar-toggle": "6be9025ab24bc434", - "sidebar": "77ec42a646a8db66", + "sidebar": "0dbf510da61afa07", "sidebar-brand": "d3d7ef4b21514e80", "sidebar-new-chat": "567fae30048b7ff3", "sidebar-resize-handle": "6607b819ee45409d", @@ -488,7 +488,7 @@ ".hwfit-serve-topline .hwfit-serve-runtime-note": "15b3fef4e5ceaffc", ".hwfit-serve-topline .hwfit-serve-runtime-text": "57c6822b0d13147d", ".hwfit-spec-group .hwfit-spec-method": "5d1c329116272cf1", - ".icon-rail": "e3f72205260a4a5f", + ".icon-rail": "c800b4ef07f5f1f0", ".icon-rail-btn": "a5f207c3be15401e", ".incognito-btn": "9833a2e86fab6a94", ".incognito-indicator": "b3945c46844c7278", @@ -617,15 +617,15 @@ ".settings-sidebar.settings-sidebar-collapsed": "d9d8f25df95d9ad8", ".settings-sidebar.settings-sidebar-collapsed .settings-sidebar-content": "608e51170864586a", ".settings-system-logs-tab": "d0d90a13ff327ace", - ".sidebar": "77ec42a646a8db66", + ".sidebar": "0dbf510da61afa07", ".sidebar .section": "37fc733d59519a08", ".sidebar-brand-title": "2b20f75768b50346", ".sidebar-header": "0d58816ca65b7216", ".sidebar-inner": "ad5e28fedbfeb5db", ".sidebar-notif-dot": "2673e215d0cd84a6", ".sidebar-user-bar": "b77372dbdcb069ef", - ".sidebar.hidden": "0df301b638e2f93f", - ".sidebar.right-side": "2b6bcc7d59f7b6bd", + ".sidebar.hidden": "9021ec7e4e052131", + ".sidebar.right-side": "bb6ed4427d07657e", ".skill-card > .skill-card-header": "e2408e762818d2fb", ".skill-card-tags": "a327c85e053e6d3f", ".skill-card-textcol": "f1059ed37c120b60", @@ -686,56 +686,56 @@ }, "variants": { "app-shell": { - "desktop-dark-comfortable": "0c9123117135e362", - "desktop-dark-compact": "c694f5d5118ac0e2", - "desktop-dark-spacious": "90a67613e8cfdf5d", - "desktop-light-comfortable": "17727a9945ccc77b", - "desktop-light-compact": "2a887c30d231e357", - "desktop-light-spacious": "94b4666734b87625", - "laptop-dark-comfortable": "26d334b139b653f2", - "laptop-dark-compact": "fea30bad6824357d", - "laptop-dark-spacious": "4fdb28deaaaec870", - "laptop-light-comfortable": "c7fc986a7e70aac8", - "laptop-light-compact": "147645431229ddff", - "laptop-light-spacious": "d513c285d30c8289", - "phone-dark-comfortable": "551761344bec8d09", - "phone-dark-compact": "293d66518c3ec994", - "phone-dark-spacious": "551761344bec8d09", - "phone-light-comfortable": "cb41acd3f9af3578", - "phone-light-compact": "dbef6e9e373e9c10", - "phone-light-spacious": "cb41acd3f9af3578", - "tablet-dark-comfortable": "0f682621b4ead393", - "tablet-dark-compact": "e6f3fece5e716a2c", - "tablet-dark-spacious": "0f682621b4ead393", - "tablet-light-comfortable": "6e398df9ca69c58b", - "tablet-light-compact": "dca75981c8675bfa", - "tablet-light-spacious": "6e398df9ca69c58b" + "desktop-dark-comfortable": "a401d90436a5ca64", + "desktop-dark-compact": "207348542b2e4e0f", + "desktop-dark-spacious": "cf93e41d494c2fdc", + "desktop-light-comfortable": "e080e0286a12ad19", + "desktop-light-compact": "5ecb27fdc079e051", + "desktop-light-spacious": "97eeb23477e3ac77", + "laptop-dark-comfortable": "c3142729689b9c36", + "laptop-dark-compact": "2d0bd3f5e3075c14", + "laptop-dark-spacious": "4c9a7ddc3fa236e4", + "laptop-light-comfortable": "234d92df9bed6f4c", + "laptop-light-compact": "a619f09b8b9e33e5", + "laptop-light-spacious": "5dea4413f33a9002", + "phone-dark-comfortable": "86f8033e0a23b873", + "phone-dark-compact": "2df6fce436ebbaac", + "phone-dark-spacious": "86f8033e0a23b873", + "phone-light-comfortable": "0067d466b77774f5", + "phone-light-compact": "8c82bcc55dd57b63", + "phone-light-spacious": "0067d466b77774f5", + "tablet-dark-comfortable": "dfeed4c65fea98a1", + "tablet-dark-compact": "cbdb84a6edc362bf", + "tablet-dark-spacious": "dfeed4c65fea98a1", + "tablet-light-comfortable": "7399146b3d437f7f", + "tablet-light-compact": "be6bf69a5215b052", + "tablet-light-spacious": "7399146b3d437f7f" }, "bench": { - "desktop-dark-comfortable": "a9709cb47eec7544", - "desktop-dark-compact": "bfab96cb72fd6faf", - "desktop-dark-spacious": "25469178b443428a", - "desktop-light-comfortable": "2166794d643fae4c", - "desktop-light-compact": "81d8ab64407b1d9a", - "desktop-light-spacious": "d6d19f33476665af", - "laptop-dark-comfortable": "57169e64e1fb5324", - "laptop-dark-compact": "6ac903cd8a711bcf", - "laptop-dark-spacious": "a47535332e9c5de7", - "laptop-light-comfortable": "1e2b381de3556fac", - "laptop-light-compact": "6dbfb465121949c1", - "laptop-light-spacious": "1b8bfcd4bc4ed214", - "phone-dark-comfortable": "67ca3c78e6b9495a", - "phone-dark-compact": "ad6f3a9f5c8d81cd", - "phone-dark-spacious": "1e6f66e56519ba5d", - "phone-light-comfortable": "ef876073cc2dc45e", - "phone-light-compact": "2ef6f5dc7a646be9", - "phone-light-spacious": "b0d4cd9bd0361966", - "tablet-dark-comfortable": "58922240b216e786", - "tablet-dark-compact": "3991c22f99a394e0", - "tablet-dark-spacious": "9848c3b7debac974", - "tablet-light-comfortable": "12dfbad36172de20", - "tablet-light-compact": "80d4843e622f1353", - "tablet-light-spacious": "c420b8d46c991a44" + "desktop-dark-comfortable": "477394268d56dab4", + "desktop-dark-compact": "cdb2a994f2347d9a", + "desktop-dark-spacious": "44a0286474f509bc", + "desktop-light-comfortable": "b4991b72e1629a7e", + "desktop-light-compact": "4b31438b6cf29191", + "desktop-light-spacious": "6d2bb1699acb8ba1", + "laptop-dark-comfortable": "6b8df96c7323bd57", + "laptop-dark-compact": "9af052dd3ee47593", + "laptop-dark-spacious": "7d031596ee98a11f", + "laptop-light-comfortable": "352a8564ecebd3dd", + "laptop-light-compact": "c038f51edaf78a6b", + "laptop-light-spacious": "232cfb9c427a156d", + "phone-dark-comfortable": "1f66ccc3d46e3d59", + "phone-dark-compact": "14802a927af47d2a", + "phone-dark-spacious": "3b48b91c9f218777", + "phone-light-comfortable": "191dd9704ea10245", + "phone-light-compact": "2f659a85548fd8d6", + "phone-light-spacious": "ece925a707889ec4", + "tablet-dark-comfortable": "7075293d10d618b5", + "tablet-dark-compact": "792f8efb8de95a25", + "tablet-dark-spacious": "b7ec70ad523b5a2e", + "tablet-light-comfortable": "bdf9d78bf3cd5ced", + "tablet-light-compact": "990bb4d23e0fbac9", + "tablet-light-spacious": "53c5142d2fca6fc1" }, "login": { "desktop-dark-comfortable": "3cf4809db0f8e119",