Fix 1-2 second animation delay when reopening session sidebar

- Remove animate-fade-in class from compact mode session list items
- Prevent sessions-showing/hiding animation classes when in session detail view
- Disable View Transitions API for navigating back from session detail view
- Add body.in-session-view class to disable all animations in session view
- Remove transition-all duration-200 from compact session list items
- Disable grid transitions when in session view

This eliminates all staggered animations and transitions that were causing
the perceived 1-2 second delay when toggling the sidebar in session detail view.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Peter Steinberger 2025-07-08 00:29:41 +01:00
parent 35e523f051
commit d7a8b565d2
3 changed files with 72 additions and 85 deletions

View file

@ -127,6 +127,15 @@ export class VibeTunnelApp extends LitElement {
if (changedProperties.has('sessions') || changedProperties.has('currentView')) {
this.requestUpdate();
}
// Add/remove body class based on current view to control animations
if (changedProperties.has('currentView')) {
if (this.currentView === 'session') {
document.body.classList.add('in-session-view');
} else {
document.body.classList.remove('in-session-view');
}
}
}
disconnectedCallback() {
@ -557,8 +566,21 @@ export class VibeTunnelApp extends LitElement {
logger.log('handleHideExitedChange', {
currentHideExited: this.hideExited,
newHideExited: e.detail,
currentView: this.currentView,
});
// Skip animations entirely when in session detail view
const isInSessionDetailView = this.currentView === 'session';
if (isInSessionDetailView) {
// Just update state without any animations
this.hideExited = e.detail;
this.saveHideExitedState(this.hideExited);
await this.updateComplete;
logger.log('Skipped animations in session detail view');
return;
}
// Don't use View Transitions for hide/show exited toggle
// as it causes the entire UI to fade. Use CSS animations instead.
const wasHidingExited = this.hideExited;
@ -729,88 +751,33 @@ export class VibeTunnelApp extends LitElement {
mediaStateIsMobile: this.mediaState.isMobile,
});
// Check if View Transitions API is supported - DISABLED for session navigation
// if ('startViewTransition' in document && typeof document.startViewTransition === 'function') {
if (false) {
// Debug: Check what elements have view-transition-name before transition
logger.debug('before transition - elements with view-transition-name:');
document.querySelectorAll('[style*="view-transition-name"]').forEach((el) => {
logger.debug('element:', el, 'style:', el.getAttribute('style'));
});
// View Transitions disabled for session navigation to prevent animations
// Direct state update for instant navigation
this.selectedSessionId = sessionId;
this.sessionLoadingState = 'idle'; // Reset loading state for new session
this.currentView = 'session';
this.updateUrl(sessionId);
// Use View Transitions API for smooth animation
const transition = document.startViewTransition(async () => {
// Update state which will trigger a re-render
this.selectedSessionId = sessionId;
this.sessionLoadingState = 'idle'; // Reset loading state for new session
this.currentView = 'session';
this.updateUrl(sessionId);
// Update page title with session name
const session = this.sessions.find((s) => s.id === sessionId);
if (session) {
const sessionName = session.name || session.command.join(' ');
console.log('[App] Setting title from view transition:', sessionName);
document.title = `${sessionName} - VibeTunnel`;
} else {
console.log('[App] No session found for view transition:', sessionId);
}
// Collapse sidebar on mobile after selecting a session
if (this.mediaState.isMobile) {
this.sidebarCollapsed = true;
this.saveSidebarState(true);
}
// Wait for LitElement to complete its update
await this.updateComplete;
// Trigger terminal resize after session switch to ensure proper dimensions
triggerTerminalResize(sessionId, this);
// Debug: Check what elements have view-transition-name after transition
logger.debug('after transition - elements with view-transition-name:');
document.querySelectorAll('[style*="view-transition-name"]').forEach((el) => {
logger.debug('element:', el, 'style:', el.getAttribute('style'));
});
});
// Log if transition is ready
transition.ready
.then(() => {
logger.debug('view transition ready');
})
.catch((err) => {
logger.error('view transition failed:', err);
});
// Update page title with session name
const session = this.sessions.find((s) => s.id === sessionId);
if (session) {
const sessionName = session.name || session.command.join(' ');
console.log('[App] Setting title:', sessionName);
document.title = `${sessionName} - VibeTunnel`;
} else {
// Fallback for browsers without View Transitions support
this.selectedSessionId = sessionId;
this.sessionLoadingState = 'idle'; // Reset loading state for new session
this.currentView = 'session';
this.updateUrl(sessionId);
// Update page title with session name
const session = this.sessions.find((s) => s.id === sessionId);
if (session) {
const sessionName = session.name || session.command.join(' ');
console.log('[App] Setting title from fallback:', sessionName);
document.title = `${sessionName} - VibeTunnel`;
} else {
console.log('[App] No session found for fallback:', sessionId);
}
// Collapse sidebar on mobile after selecting a session
if (this.mediaState.isMobile) {
this.sidebarCollapsed = true;
this.saveSidebarState(true);
}
// Trigger terminal resize after session switch to ensure proper dimensions
this.updateComplete.then(() => {
triggerTerminalResize(sessionId, this);
});
console.log('[App] No session found:', sessionId);
}
// Collapse sidebar on mobile after selecting a session
if (this.mediaState.isMobile) {
this.sidebarCollapsed = true;
this.saveSidebarState(true);
}
// Trigger terminal resize after session switch to ensure proper dimensions
this.updateComplete.then(() => {
triggerTerminalResize(sessionId, this);
});
}
private handleNavigateToList(): void {
@ -821,8 +788,16 @@ export class VibeTunnelApp extends LitElement {
const sessionCount = this.sessions.length;
document.title = `VibeTunnel - ${sessionCount} Session${sessionCount !== 1 ? 's' : ''}`;
// Check if View Transitions API is supported
if ('startViewTransition' in document && typeof document.startViewTransition === 'function') {
// Disable View Transitions when navigating from session detail view
// to prevent animations when sidebar is involved
const skipViewTransition = this.currentView === 'session';
// Check if View Transitions API is supported and should be used
if (
!skipViewTransition &&
'startViewTransition' in document &&
typeof document.startViewTransition === 'function'
) {
// Use View Transitions API for smooth animation
document.startViewTransition(() => {
// Update state which will trigger a re-render
@ -834,7 +809,7 @@ export class VibeTunnelApp extends LitElement {
return this.updateComplete;
});
} else {
// Fallback for browsers without View Transitions support
// Fallback for browsers without View Transitions support or when skipping
this.selectedSessionId = null;
this.currentView = 'list';
this.updateUrl();

View file

@ -354,7 +354,7 @@ export class SessionList extends LitElement {
? html`
<!-- Enhanced compact list item for sidebar -->
<div
class="group flex items-center gap-3 p-3 rounded-lg cursor-pointer transition-all duration-200 animate-fade-in ${
class="group flex items-center gap-3 p-3 rounded-lg cursor-pointer ${
session.id === this.selectedSessionId
? 'bg-dark-bg-elevated border border-accent-primary shadow-card-hover'
: 'bg-dark-bg-secondary border border-dark-border hover:bg-dark-bg-tertiary hover:border-dark-border-light hover:shadow-card'
@ -558,7 +558,7 @@ export class SessionList extends LitElement {
? html`
<!-- Enhanced compact list item for sidebar -->
<div
class="group flex items-center gap-3 p-3 rounded-lg cursor-pointer transition-all duration-200 animate-fade-in ${
class="group flex items-center gap-3 p-3 rounded-lg cursor-pointer ${
session.id === this.selectedSessionId
? 'bg-dark-bg-elevated border border-accent-primary shadow-card-hover'
: 'bg-dark-bg-secondary border border-dark-border hover:bg-dark-bg-tertiary hover:border-dark-border-light hover:shadow-card opacity-75'

View file

@ -219,9 +219,14 @@
grid-auto-rows: 400px;
gap: 1.25rem;
padding: 0.5rem 0.75rem;
/* Enable smooth grid transitions */
/* Enable smooth grid transitions - disabled in session view */
transition: grid-template-columns 0.3s ease-out;
}
/* Disable grid transitions in session view */
body.in-session-view .session-flex-responsive {
transition: none !important;
}
.session-flex-responsive > * {
height: 100%;
@ -529,6 +534,13 @@ body.sessions-showing .session-flex-responsive > session-card {
animation: sessionFlow 0.2s ease-out backwards;
}
/* Disable ALL animations when in session view */
body.in-session-view .session-flex-responsive > session-card,
body.in-session-view .space-y-2 > div {
animation: none !important;
animation-delay: 0s !important;
}
/* Stagger animation when showing exited sessions */
body.sessions-showing .session-flex-responsive > session-card:nth-child(1) {
animation-delay: 0s;