diff --git a/frontend/src/App.vue b/frontend/src/App.vue index e8d1bb7..eaa6ee9 100644 --- a/frontend/src/App.vue +++ b/frontend/src/App.vue @@ -6,6 +6,7 @@ import TorchButton from './components/TorchButton.vue' import FloatingTerminal from './components/FloatingTerminal.vue' import FloatingResponse from './components/FloatingResponse.vue' import FloatingVoice from './components/FloatingVoice.vue' +import FloatingTranscriptDebug from './components/FloatingTranscriptDebug.vue' import AgentBar from './components/AgentBar.vue' import PwaInstallBanner from './components/PwaInstallBanner.vue' import HooksApprovalModal from './components/HooksApprovalModal.vue' @@ -23,6 +24,7 @@ const route = useRoute() const router = useRouter() const showTerminal = ref(false) const showVoice = ref(false) +const showTranscriptDebug = ref(false) const showDebugConsole = ref(false) const toolbarVisible = ref(true) const forceWco = ref(false) @@ -450,7 +452,7 @@ watch(() => route.name, (newPage) => { 'session-start': showSessionStart, notification: showNotification, 'tool-flash': showToolFlash, - 'sheet-open': showTerminal || showVoice, + 'sheet-open': showTerminal || showVoice || showTranscriptDebug, 'keyboard-visible': keyboardVisible }" @click="showTerminal = !showTerminal" @@ -521,10 +523,22 @@ watch(() => route.name, (newPage) => { + + + + + + + route.name, (newPage) => { + + + @@ -1309,6 +1326,49 @@ watch(() => route.name, (newPage) => { 50% { box-shadow: 0 0 50px rgba(249, 115, 22, 0.9); } } +/* Transcript Debug FAB */ +.transcript-fab { + position: fixed; + bottom: 20px; + left: 80px; + width: 44px; + height: 44px; + border-radius: 4px; + background: rgba(15, 15, 20, 0.85); + color: #818cf8; + border: 1px solid rgba(99, 102, 241, 0.2); + cursor: pointer; + display: flex; + align-items: center; + justify-content: center; + box-shadow: 0 4px 16px rgba(0, 0, 0, 0.4); + transition: all 0.2s ease; + z-index: 9998; + -webkit-user-select: none; + user-select: none; + -webkit-touch-callout: none; + touch-action: manipulation; + backdrop-filter: blur(12px); +} + +.transcript-fab:hover { + transform: translateY(-2px); + border-color: rgba(99, 102, 241, 0.4); + box-shadow: 0 6px 20px rgba(0, 0, 0, 0.5), 0 0 12px rgba(99, 102, 241, 0.15); + color: #a5b4fc; +} + +.transcript-fab.active { + background: rgba(99, 102, 241, 0.15); + border-color: rgba(99, 102, 241, 0.4); + color: #c7d2fe; + box-shadow: 0 4px 16px rgba(0, 0, 0, 0.4), 0 0 8px rgba(99, 102, 241, 0.2); +} + +.transcript-fab.active:hover { + box-shadow: 0 6px 20px rgba(0, 0, 0, 0.5), 0 0 12px rgba(99, 102, 241, 0.3); +} + @media (max-width: 768px) { .terminal-fab { bottom: 80px; @@ -1340,28 +1400,39 @@ watch(() => route.name, (newPage) => { width: 44px; height: 44px; } + + .transcript-fab { + bottom: 80px; + left: 68px; + width: 40px; + height: 40px; + } } /* Mobile: FABs above bottom sheets */ @media (max-width: 1024px) and (pointer: coarse) { .terminal-fab, - .voice-fab { + .voice-fab, + .transcript-fab { z-index: 10001; transition: bottom 0.25s cubic-bezier(0.4, 0, 0.2, 1), transform 0.3s ease; } .terminal-fab.sheet-open, - .voice-fab.sheet-open { + .voice-fab.sheet-open, + .transcript-fab.sheet-open { bottom: calc(15vh + 100px); } .terminal-fab.keyboard-visible, - .voice-fab.keyboard-visible { + .voice-fab.keyboard-visible, + .transcript-fab.keyboard-visible { bottom: 35vh; } .terminal-fab.keyboard-visible.sheet-open, - .voice-fab.keyboard-visible.sheet-open { + .voice-fab.keyboard-visible.sheet-open, + .transcript-fab.keyboard-visible.sheet-open { bottom: 45vh; } } diff --git a/frontend/src/components/FloatingTranscriptDebug.vue b/frontend/src/components/FloatingTranscriptDebug.vue new file mode 100644 index 0000000..467cdb7 --- /dev/null +++ b/frontend/src/components/FloatingTranscriptDebug.vue @@ -0,0 +1,928 @@ + + + + + + + + + + + + + + + + + + + Transcript + + {{ selectedAgent }} + + + + + + + + + + + + + + + + + + + + + + + Agent + + + {{ a.label }} + + + + + Session + + Select session... + + {{ s.firstUserMessage ? (s.firstUserMessage.length > 50 ? s.firstUserMessage.slice(0, 50) + '...' : s.firstUserMessage) : s.id.slice(0, 8) + '...' }} + + + + + + + + + + {{ error }} + + + + + + + + + Select a session to begin + {{ sessions.length }} sessions available + + + + + + + + + + + +