mirror of
https://github.com/samsonjs/vibetunnel.git
synced 2026-04-27 15:17:38 +00:00
add view transition for terminal open
This commit is contained in:
parent
8b64f2088d
commit
d8dae14bde
6 changed files with 132 additions and 3 deletions
|
|
@ -171,6 +171,71 @@ export class VibeTunnelApp extends LitElement {
|
||||||
this.showCreateModal = false;
|
this.showCreateModal = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async handleNavigateToSession(e: CustomEvent): Promise<void> {
|
||||||
|
const { sessionId } = e.detail;
|
||||||
|
|
||||||
|
// Check if View Transitions API is supported
|
||||||
|
if ('startViewTransition' in document && typeof document.startViewTransition === 'function') {
|
||||||
|
// Debug: Check what elements have view-transition-name before transition
|
||||||
|
console.log('Before transition - elements with view-transition-name:');
|
||||||
|
document.querySelectorAll('[style*="view-transition-name"]').forEach((el) => {
|
||||||
|
console.log('Element:', el, 'Style:', el.getAttribute('style'));
|
||||||
|
});
|
||||||
|
|
||||||
|
// Use View Transitions API for smooth animation
|
||||||
|
const transition = document.startViewTransition(async () => {
|
||||||
|
// Update state which will trigger a re-render
|
||||||
|
this.selectedSessionId = sessionId;
|
||||||
|
this.currentView = 'session';
|
||||||
|
this.updateUrl(sessionId);
|
||||||
|
|
||||||
|
// Wait for LitElement to complete its update
|
||||||
|
await this.updateComplete;
|
||||||
|
|
||||||
|
// Debug: Check what elements have view-transition-name after transition
|
||||||
|
console.log('After transition - elements with view-transition-name:');
|
||||||
|
document.querySelectorAll('[style*="view-transition-name"]').forEach((el) => {
|
||||||
|
console.log('Element:', el, 'Style:', el.getAttribute('style'));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Log if transition is ready
|
||||||
|
transition.ready
|
||||||
|
.then(() => {
|
||||||
|
console.log('View transition ready');
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
console.error('View transition failed:', err);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// Fallback for browsers without View Transitions support
|
||||||
|
this.selectedSessionId = sessionId;
|
||||||
|
this.currentView = 'session';
|
||||||
|
this.updateUrl(sessionId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private handleNavigateToList(): void {
|
||||||
|
// Check if View Transitions API is supported
|
||||||
|
if ('startViewTransition' in document && typeof document.startViewTransition === 'function') {
|
||||||
|
// Use View Transitions API for smooth animation
|
||||||
|
document.startViewTransition(() => {
|
||||||
|
// Update state which will trigger a re-render
|
||||||
|
this.selectedSessionId = null;
|
||||||
|
this.currentView = 'list';
|
||||||
|
this.updateUrl();
|
||||||
|
|
||||||
|
// Force update to ensure DOM changes happen within the transition
|
||||||
|
return this.updateComplete;
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// Fallback for browsers without View Transitions support
|
||||||
|
this.selectedSessionId = null;
|
||||||
|
this.currentView = 'list';
|
||||||
|
this.updateUrl();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private async handleKillAll() {
|
private async handleKillAll() {
|
||||||
// Find all session cards and trigger their kill buttons
|
// Find all session cards and trigger their kill buttons
|
||||||
const sessionCards = this.querySelectorAll<SessionCard>('session-card');
|
const sessionCards = this.querySelectorAll<SessionCard>('session-card');
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,15 @@ export class SessionList extends LitElement {
|
||||||
|
|
||||||
private handleSessionSelect(e: CustomEvent) {
|
private handleSessionSelect(e: CustomEvent) {
|
||||||
const session = e.detail as Session;
|
const session = e.detail as Session;
|
||||||
window.location.search = `?session=${session.id}`;
|
|
||||||
|
// Dispatch a custom event that the app can handle with view transitions
|
||||||
|
this.dispatchEvent(
|
||||||
|
new CustomEvent('navigate-to-session', {
|
||||||
|
detail: { sessionId: session.id },
|
||||||
|
bubbles: true,
|
||||||
|
composed: true,
|
||||||
|
})
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private handleSessionKilled(e: CustomEvent) {
|
private handleSessionKilled(e: CustomEvent) {
|
||||||
|
|
|
||||||
|
|
@ -446,7 +446,13 @@ export class SessionView extends LitElement {
|
||||||
}
|
}
|
||||||
|
|
||||||
private handleBack() {
|
private handleBack() {
|
||||||
window.location.search = '';
|
// Dispatch a custom event that the app can handle with view transitions
|
||||||
|
this.dispatchEvent(
|
||||||
|
new CustomEvent('navigate-to-list', {
|
||||||
|
bubbles: true,
|
||||||
|
composed: true,
|
||||||
|
})
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private handleSessionExit(e: Event) {
|
private handleSessionExit(e: Event) {
|
||||||
|
|
|
||||||
|
|
@ -1195,6 +1195,7 @@ export class Terminal extends LitElement {
|
||||||
class="terminal-container w-full h-full overflow-hidden"
|
class="terminal-container w-full h-full overflow-hidden"
|
||||||
tabindex="0"
|
tabindex="0"
|
||||||
contenteditable="false"
|
contenteditable="false"
|
||||||
|
style="view-transition-name: terminal-${this.sessionId}"
|
||||||
@paste=${this.handlePaste}
|
@paste=${this.handlePaste}
|
||||||
@click=${this.handleClick}
|
@click=${this.handleClick}
|
||||||
></div>
|
></div>
|
||||||
|
|
|
||||||
|
|
@ -191,7 +191,10 @@ export class VibeTerminalBuffer extends LitElement {
|
||||||
line-height: ${lineHeight}px;
|
line-height: ${lineHeight}px;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
<div class="relative w-full h-full overflow-hidden bg-black">
|
<div
|
||||||
|
class="relative w-full h-full overflow-hidden bg-black"
|
||||||
|
style="view-transition-name: terminal-${this.sessionId}"
|
||||||
|
>
|
||||||
${this.error
|
${this.error
|
||||||
? html`
|
? html`
|
||||||
<div class="absolute inset-0 flex items-center justify-center">
|
<div class="absolute inset-0 flex items-center justify-center">
|
||||||
|
|
|
||||||
|
|
@ -701,3 +701,49 @@ body {
|
||||||
color: #00ff88;
|
color: #00ff88;
|
||||||
box-shadow: 0 0 10px rgba(0, 255, 136, 0.3);
|
box-shadow: 0 0 10px rgba(0, 255, 136, 0.3);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* View Transitions */
|
||||||
|
@supports (view-transition-name: none) {
|
||||||
|
::view-transition {
|
||||||
|
/* Set the transition duration to 0.1s as requested */
|
||||||
|
--transition-duration: 100ms;
|
||||||
|
}
|
||||||
|
|
||||||
|
::view-transition-group(*) {
|
||||||
|
animation-duration: var(--transition-duration);
|
||||||
|
animation-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
::view-transition-old(*),
|
||||||
|
::view-transition-new(*) {
|
||||||
|
animation-duration: var(--transition-duration);
|
||||||
|
mix-blend-mode: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Specific styling for terminal transitions */
|
||||||
|
::view-transition-old(terminal-*) {
|
||||||
|
animation: view-transition-fade-out var(--transition-duration) cubic-bezier(0.4, 0, 0.2, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
::view-transition-new(terminal-*) {
|
||||||
|
animation: view-transition-fade-in var(--transition-duration) cubic-bezier(0.4, 0, 0.2, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes view-transition-fade-out {
|
||||||
|
from {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes view-transition-fade-in {
|
||||||
|
from {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue