fix: lifecycle ribbon always visible at bottom, slides up on hover/focus

This commit is contained in:
2026-02-24 11:19:50 -06:00
parent 3112c53d86
commit 6fabf37196

View File

@@ -7,6 +7,7 @@ import { useSessionState } from '@/stores/session-state'
import { ChatContainer, AquaticBackground, AgentBadge, NewSessionModal } from '@/components/transcript-debug' import { ChatContainer, AquaticBackground, AgentBadge, NewSessionModal } from '@/components/transcript-debug'
import type { AgentName } from '@/types/transcript-debug' import type { AgentName } from '@/types/transcript-debug'
import { isTauri, isMobileTauri, getTauriWindow } from '@/lib/tauri' import { isTauri, isMobileTauri, getTauriWindow } from '@/lib/tauri'
import { usePipWindow } from '@/composables/usePipWindow'
const route = useRoute() const route = useRoute()
const router = useRouter() const router = useRouter()
@@ -163,7 +164,12 @@ watch(() => sessionState.terminalRegistry.length, () => {
}) })
const isAndroid = isMobileTauri() const isAndroid = isMobileTauri()
const pipOpen = ref(false) const { openPip, closePip, isPipOpen } = usePipWindow()
const currentTerminalIndex = computed(() => {
return parseInt(route.params.terminalIndex as string) || 1
})
const pipOpen = computed(() => isPipOpen(currentTerminalIndex.value))
async function closePipWindow() { async function closePipWindow() {
try { try {
@@ -197,47 +203,16 @@ async function enterPip() {
return return
} }
// Desktop Tauri: toggle pip window // Desktop Tauri: toggle pip window using shared composable
if (!isTauri) return if (!isTauri) return
const idx = currentTerminalIndex.value
if (pipOpen.value) { if (pipOpen.value) {
try { await closePip(idx)
const { WebviewWindow } = await import('@tauri-apps/api/webviewWindow')
const existing = await WebviewWindow.getByLabel('pip-terminal')
if (existing) await existing.close()
} catch {}
pipOpen.value = false
return return
} }
try { await openPip(idx)
const { WebviewWindow } = await import('@tauri-apps/api/webviewWindow')
// Build the URL for the pip window — same transcript page with terminal index
const terminalIdx = route.params.terminalIndex || '1'
const pipUrl = `/transcript-debug/${terminalIdx}?pip=1`
const pip = new WebviewWindow('pip-terminal', {
url: pipUrl,
title: 'Agent UI',
width: 380,
height: 620,
x: window.screen.width - 400,
y: 60,
alwaysOnTop: false,
decorations: false,
resizable: true,
focus: true,
})
pipOpen.value = true
pip.onCloseRequested(() => {
pipOpen.value = false
})
} catch (e) {
console.warn('Failed to open PiP window:', e)
pipOpen.value = false
}
} }
onMounted(async () => { onMounted(async () => {
@@ -755,18 +730,21 @@ onBeforeUnmount(() => {
backdrop-filter: blur(8px) !important; backdrop-filter: blur(8px) !important;
-webkit-backdrop-filter: blur(8px) !important; -webkit-backdrop-filter: blur(8px) !important;
border-top: 1px solid rgba(255, 255, 255, 0.06) !important; border-top: 1px solid rgba(255, 255, 255, 0.06) !important;
/* Auto-hide: fade out when idle */ /* Idle: slide down but keep lifecycle ribbon visible at bottom */
opacity: 0; transform: translateY(calc(100% - 26px));
transform: translateY(100%); transition: transform 0.3s ease;
transition: opacity 0.3s ease, transform 0.3s ease;
pointer-events: none; pointer-events: none;
} }
/* Lifecycle ribbon always interactive even when idle */
.content-area :deep(.lifecycle-ribbon) {
pointer-events: auto !important;
}
/* Show on hover anywhere in the content area or when input is focused */ /* Show on hover anywhere in the content area or when input is focused */
.content-area:hover :deep(.bottom-overlay), .content-area:hover :deep(.bottom-overlay),
.content-area:has(:focus-within) :deep(.bottom-overlay), .content-area:has(:focus-within) :deep(.bottom-overlay),
.content-area :deep(.bottom-overlay:focus-within) { .content-area :deep(.bottom-overlay:focus-within) {
opacity: 1;
transform: translateY(0); transform: translateY(0);
pointer-events: auto; pointer-events: auto;
} }
@@ -819,7 +797,6 @@ onBeforeUnmount(() => {
/* Lifecycle ribbon */ /* Lifecycle ribbon */
.content-area :deep(.lifecycle-ribbon) { .content-area :deep(.lifecycle-ribbon) {
background: transparent !important; background: transparent !important;
pointer-events: none !important;
} }
/* Input container */ /* Input container */