mirror of
https://github.com/samsonjs/vibetunnel.git
synced 2026-04-06 11:25:52 +00:00
- Adds Arc-style persistent sidebar navigation with resizable vertical tabs - Implements comprehensive mobile responsiveness with slide animations and hamburger menu - Creates utility modules for responsive design, constants, and terminal management - Refactors header components into specialized classes for better separation of concerns - Implements ResizeObserver-based responsive design system for efficient viewport tracking - Fixes mobile scrolling issues and eliminates layout shift bugs - Improves session card consistency and status indicator positioning - Adds proper terminal resize events when switching between sessions - Enhances sidebar UX with compact headers, uniform borders, and smooth transitions - Centralizes UI constants and breakpoints for maintainable responsive design - Resolves TypeScript errors with web-push dependency reinstallation 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
94 lines
2.8 KiB
TypeScript
94 lines
2.8 KiB
TypeScript
/**
|
|
* Base functionality for header components
|
|
*/
|
|
import { LitElement } from 'lit';
|
|
import { property, state } from 'lit/decorators.js';
|
|
import type { Session } from './session-list.js';
|
|
import { TIMING } from '../utils/constants.js';
|
|
|
|
export abstract class HeaderBase extends LitElement {
|
|
createRenderRoot() {
|
|
return this;
|
|
}
|
|
|
|
@property({ type: Array }) sessions: Session[] = [];
|
|
@property({ type: Boolean }) hideExited = true;
|
|
@property({ type: String }) currentUser: string | null = null;
|
|
@property({ type: String }) authMethod: string | null = null;
|
|
@state() protected killingAll = false;
|
|
@state() protected showUserMenu = false;
|
|
|
|
protected get runningSessions(): Session[] {
|
|
return this.sessions.filter((session) => session.status === 'running');
|
|
}
|
|
|
|
protected get exitedSessions(): Session[] {
|
|
return this.sessions.filter((session) => session.status === 'exited');
|
|
}
|
|
|
|
protected handleCreateSession(e: MouseEvent) {
|
|
// Capture button position for view transition
|
|
const button = e.currentTarget as HTMLButtonElement;
|
|
const rect = button.getBoundingClientRect();
|
|
|
|
// Store position in CSS custom properties for the transition
|
|
document.documentElement.style.setProperty('--vt-button-x', `${rect.left + rect.width / 2}px`);
|
|
document.documentElement.style.setProperty('--vt-button-y', `${rect.top + rect.height / 2}px`);
|
|
document.documentElement.style.setProperty('--vt-button-width', `${rect.width}px`);
|
|
document.documentElement.style.setProperty('--vt-button-height', `${rect.height}px`);
|
|
|
|
this.dispatchEvent(new CustomEvent('create-session'));
|
|
}
|
|
|
|
protected handleKillAll() {
|
|
if (this.killingAll) return;
|
|
|
|
this.killingAll = true;
|
|
this.requestUpdate();
|
|
|
|
this.dispatchEvent(new CustomEvent('kill-all-sessions'));
|
|
|
|
// Reset after a delay to prevent multiple clicks
|
|
window.setTimeout(() => {
|
|
this.killingAll = false;
|
|
}, TIMING.KILL_ALL_BUTTON_DISABLE_DURATION);
|
|
}
|
|
|
|
protected handleCleanExited() {
|
|
this.dispatchEvent(new CustomEvent('clean-exited-sessions'));
|
|
}
|
|
|
|
protected handleHideExitedToggle() {
|
|
this.dispatchEvent(
|
|
new CustomEvent('hide-exited-change', {
|
|
detail: !this.hideExited,
|
|
})
|
|
);
|
|
}
|
|
|
|
protected handleLogout() {
|
|
this.showUserMenu = false;
|
|
this.dispatchEvent(new CustomEvent('logout'));
|
|
}
|
|
|
|
protected toggleUserMenu() {
|
|
this.showUserMenu = !this.showUserMenu;
|
|
}
|
|
|
|
protected handleClickOutside = (e: Event) => {
|
|
const target = e.target as HTMLElement;
|
|
if (!target.closest('.user-menu-container')) {
|
|
this.showUserMenu = false;
|
|
}
|
|
};
|
|
|
|
connectedCallback() {
|
|
super.connectedCallback();
|
|
document.addEventListener('click', this.handleClickOutside);
|
|
}
|
|
|
|
disconnectedCallback() {
|
|
super.disconnectedCallback();
|
|
document.removeEventListener('click', this.handleClickOutside);
|
|
}
|
|
}
|