mirror of
https://github.com/pewdiepie-archdaemon/odysseus.git
synced 2026-10-29 17:22:25 +01:00
Merge pull request #6840 from eesoymilk/fix/sidebar-toggle-animation
fix(sidebar): animate the sidebar toggle instead of snapping
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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,14 +321,20 @@ 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 and sync the mode classes (ody-sidebar-mini also forces
|
||||
// width 0) so the reflow measures the sidebar at its full width.
|
||||
sidebar.style.transition = 'none';
|
||||
sidebar.classList.remove('hidden');
|
||||
syncRailSide();
|
||||
void document.body.offsetWidth; // reflow
|
||||
if (chatContainer && chatContainer.offsetWidth < MIN_CHAT_WIDTH) {
|
||||
sidebar.classList.add('hidden');
|
||||
} else {
|
||||
_wasAutoCollapsed = false;
|
||||
}
|
||||
void document.body.offsetWidth;
|
||||
sidebar.style.transition = '';
|
||||
syncRailSide();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user