refactor: unify dashboard/terminal selector into single strip, default to dashboard

Remove separate Chat/SE tab toggle. Dashboard is now a button in the
terminal strip alongside T1-T5. Chat only renders when a specific
terminal route is active (/transcript-debug/:n).
This commit is contained in:
2026-02-24 18:16:35 -06:00
parent 4cb0760c50
commit cfb58c3a9f

View File

@@ -4,7 +4,7 @@ import { useRoute, useRouter } from 'vue-router'
import { useTranscriptDebug } from '@/composables/transcript-debug'
import { useVoiceInput } from '@/composables/useVoiceInput'
import { useSessionState } from '@/stores/session-state'
import { ChatContainer, AquaticBackground, AgentBadge, NewSessionModal } from '@/components/transcript-debug'
import { ChatContainer, AquaticBackground, AgentBadge, NewSessionModal, SyncEnginePanel } from '@/components/transcript-debug'
import type { AgentName } from '@/types/transcript-debug'
import { isTauri, isMobileTauri, getTauriWindow } from '@/lib/tauri'
import { usePipWindow } from '@/composables/usePipWindow'
@@ -63,6 +63,9 @@ const showSelector = ref(false)
const showNewSessionModal = ref(false)
const isPipWindow = computed(() => route.query.pip === '1')
// Dashboard vs terminal view — driven by route
const isDashboard = computed(() => !route.params.terminalIndex)
// Readability overlay
const savedOverlay = localStorage.getItem('transcript-overlay-opacity')
const overlayOpacity = ref(savedOverlay !== null ? parseFloat(savedOverlay) : 0.55)
@@ -136,6 +139,10 @@ async function handleModalCreateNew(agent: AgentName, initialPrompt: string) {
}
}
function goToDashboard() {
router.push({ name: 'transcript-debug' })
}
function handleTerminalSwitch(sessionId: string) {
const idx = sessionState.terminalRegistry.findIndex(
e => e.transcriptSessionId === sessionId
@@ -219,6 +226,15 @@ onMounted(async () => {
await init()
await voice.init()
syncTerminalFromRoute()
// Signal to the parent window that this PiP page is ready to show
if (isTauri && route.query.pip === '1') {
try {
const { getCurrentWebviewWindow } = await import('@tauri-apps/api/webviewWindow')
const { emitTo } = await import('@tauri-apps/api/event')
await emitTo('main', 'pip:ready', getCurrentWebviewWindow().label)
} catch {}
}
})
onBeforeUnmount(() => {
@@ -252,13 +268,23 @@ onBeforeUnmount(() => {
<!-- Terminal selector strip (hidden in PiP) -->
<div v-if="!isPipWindow" class="terminal-strip">
<div class="strip-left">
<button
:class="['strip-terminal-btn', 'strip-dashboard-btn', { active: isDashboard }]"
@click="goToDashboard"
title="Dashboard"
>
<svg width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5">
<rect x="3" y="3" width="7" height="7" rx="1"/><rect x="14" y="3" width="7" height="7" rx="1"/>
<rect x="3" y="14" width="7" height="7" rx="1"/><rect x="14" y="14" width="7" height="7" rx="1"/>
</svg>
</button>
<button
v-for="(entry, idx) in sessionState.terminalRegistry"
:key="entry.transcriptSessionId"
:class="[
'strip-terminal-btn',
{
active: String(idx + 1) === route.params.terminalIndex || (!route.params.terminalIndex && entry.transcriptSessionId === activeTerminalSessionId),
active: String(idx + 1) === route.params.terminalIndex,
dead: !entry.alive
}
]"
@@ -360,6 +386,8 @@ onBeforeUnmount(() => {
</div>
</Transition>
<!-- Terminal chat (only when a specific terminal is selected) -->
<template v-if="!isDashboard">
<ChatContainer
ref="chatRef"
v-if="conversation"
@@ -410,6 +438,10 @@ onBeforeUnmount(() => {
<small v-if="!sessionState.terminalRegistry.length">No terminals registered</small>
<small v-else>Select a terminal above to begin</small>
</div>
</template>
<!-- Dashboard (default view) -->
<SyncEnginePanel v-if="isDashboard" />
</div>
<!-- New session modal -->
@@ -499,6 +531,16 @@ onBeforeUnmount(() => {
gap: 0.5rem;
}
.strip-dashboard-btn {
gap: 0;
}
.strip-dashboard-btn svg {
opacity: 0.7;
}
.strip-dashboard-btn.active svg {
opacity: 1;
}
.realtime-dot {
color: var(--text-muted);
opacity: 0.4;
@@ -641,6 +683,13 @@ onBeforeUnmount(() => {
ChatContainer glass-transparent overrides (mirrored from FloatingTranscriptDebug)
══════════════════════════════════════════════════════════════════════════════ */
.content-area :deep(.sync-engine-panel) {
position: relative;
z-index: 1;
flex: 1;
overflow-y: auto;
}
.content-area :deep(.chat-container) {
background: transparent !important;
border: none !important;