diff --git a/.gitignore b/.gitignore index 626e25d..7ad82ec 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,4 @@ server/recordings/*.webm .claude-*/plugins/ .claude-*/plans/ .claude-*/file-history/ +.claude-*/tasks/ diff --git a/frontend/src/components/FloatingTranscriptDebug.vue b/frontend/src/components/FloatingTranscriptDebug.vue index 467cdb7..c931494 100644 --- a/frontend/src/components/FloatingTranscriptDebug.vue +++ b/frontend/src/components/FloatingTranscriptDebug.vue @@ -665,9 +665,77 @@ onBeforeUnmount(() => { display: flex; flex-direction: column; position: relative; - /* Pixel art galaxy: spiral arms, stars, nebula in bottom-right corner */ + isolation: isolate; + /* Pixel art animated ocean floor */ background: - url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='120' height='120' viewBox='0 0 120 120' shape-rendering='crispEdges'%3E%3C!-- galaxy core --%3E%3Crect x='56' y='56' width='4' height='4' fill='%23fef3c7' opacity='0.35'/%3E%3Crect x='60' y='56' width='4' height='4' fill='%23fde68a' opacity='0.3'/%3E%3Crect x='56' y='60' width='4' height='4' fill='%23fde68a' opacity='0.28'/%3E%3Crect x='60' y='60' width='4' height='4' fill='%23fef9c3' opacity='0.4'/%3E%3Crect x='52' y='56' width='4' height='4' fill='%23c4b5fd' opacity='0.2'/%3E%3Crect x='64' y='56' width='4' height='4' fill='%23a78bfa' opacity='0.18'/%3E%3Crect x='56' y='52' width='4' height='4' fill='%23818cf8' opacity='0.2'/%3E%3Crect x='60' y='64' width='4' height='4' fill='%23c4b5fd' opacity='0.18'/%3E%3C!-- spiral arm top-right --%3E%3Crect x='68' y='48' width='4' height='4' fill='%236366f1' opacity='0.18'/%3E%3Crect x='72' y='44' width='4' height='4' fill='%23818cf8' opacity='0.14'/%3E%3Crect x='76' y='40' width='4' height='4' fill='%236366f1' opacity='0.12'/%3E%3Crect x='80' y='38' width='4' height='2' fill='%23818cf8' opacity='0.1'/%3E%3Crect x='84' y='36' width='4' height='2' fill='%236366f1' opacity='0.08'/%3E%3Crect x='88' y='36' width='2' height='2' fill='%23a78bfa' opacity='0.06'/%3E%3C!-- spiral arm bottom-left --%3E%3Crect x='48' y='68' width='4' height='4' fill='%23818cf8' opacity='0.16'/%3E%3Crect x='44' y='72' width='4' height='4' fill='%236366f1' opacity='0.14'/%3E%3Crect x='40' y='76' width='4' height='4' fill='%23818cf8' opacity='0.12'/%3E%3Crect x='36' y='78' width='4' height='2' fill='%236366f1' opacity='0.1'/%3E%3Crect x='32' y='80' width='4' height='2' fill='%23a78bfa' opacity='0.07'/%3E%3C!-- spiral arm top-left --%3E%3Crect x='48' y='48' width='4' height='4' fill='%23c084fc' opacity='0.15'/%3E%3Crect x='44' y='44' width='4' height='4' fill='%23a855f7' opacity='0.12'/%3E%3Crect x='40' y='40' width='4' height='4' fill='%23c084fc' opacity='0.1'/%3E%3Crect x='36' y='38' width='4' height='2' fill='%23a855f7' opacity='0.08'/%3E%3C!-- spiral arm bottom-right --%3E%3Crect x='68' y='68' width='4' height='4' fill='%23a855f7' opacity='0.14'/%3E%3Crect x='72' y='72' width='4' height='4' fill='%23c084fc' opacity='0.12'/%3E%3Crect x='76' y='76' width='4' height='4' fill='%23a855f7' opacity='0.1'/%3E%3Crect x='80' y='78' width='4' height='2' fill='%23c084fc' opacity='0.07'/%3E%3C!-- nebula clouds --%3E%3Crect x='50' y='40' width='8' height='2' fill='%23f0abfc' opacity='0.07'/%3E%3Crect x='66' y='62' width='6' height='2' fill='%2367e8f9' opacity='0.06'/%3E%3Crect x='42' y='64' width='6' height='2' fill='%23f0abfc' opacity='0.05'/%3E%3Crect x='64' y='44' width='4' height='2' fill='%2367e8f9' opacity='0.06'/%3E%3C!-- scattered stars --%3E%3Crect x='20' y='18' width='2' height='2' fill='white' opacity='0.2'/%3E%3Crect x='95' y='22' width='2' height='2' fill='white' opacity='0.15'/%3E%3Crect x='14' y='90' width='2' height='2' fill='white' opacity='0.12'/%3E%3Crect x='100' y='88' width='2' height='2' fill='white' opacity='0.18'/%3E%3Crect x='30' y='105' width='2' height='2' fill='%23c4b5fd' opacity='0.1'/%3E%3Crect x='108' y='14' width='2' height='2' fill='%23fde68a' opacity='0.12'/%3E%3Crect x='10' y='50' width='2' height='2' fill='white' opacity='0.1'/%3E%3Crect x='110' y='60' width='2' height='2' fill='%2367e8f9' opacity='0.12'/%3E%3Crect x='70' y='20' width='2' height='2' fill='white' opacity='0.08'/%3E%3Crect x='50' y='100' width='2' height='2' fill='white' opacity='0.1'/%3E%3Crect x='85' y='105' width='2' height='2' fill='%23fde68a' opacity='0.08'/%3E%3Crect x='25' y='30' width='2' height='2' fill='%23c4b5fd' opacity='0.08'/%3E%3C/svg%3E") no-repeat center center / 100% 100%; + /* Subtle light rays from surface */ + repeating-linear-gradient( + -25deg, + transparent 0px, + transparent 60px, + rgba(103, 232, 249, 0.018) 60px, + rgba(103, 232, 249, 0.018) 63px, + transparent 63px, + transparent 180px + ), + /* Water depth gradient */ + linear-gradient( + 180deg, + rgba(0, 8, 28, 0.96) 0%, + rgba(0, 18, 48, 0.94) 20%, + rgba(0, 30, 60, 0.92) 40%, + rgba(2, 45, 72, 0.88) 60%, + rgba(5, 55, 70, 0.85) 75%, + rgba(12, 58, 58, 0.82) 88%, + rgba(30, 55, 40, 0.78) 100% + ), + /* Pixel art sea floor: sand, seaweed, coral, rocks, starfish, shell */ + url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='240' height='120' viewBox='0 0 240 120' shape-rendering='crispEdges'%3E%3Crect x='0' y='88' width='240' height='32' fill='%23c2a060' opacity='0.6'/%3E%3Crect x='0' y='86' width='240' height='4' fill='%23d4b878' opacity='0.5'/%3E%3Crect x='10' y='92' width='20' height='2' fill='%23a89048' opacity='0.3'/%3E%3Crect x='50' y='96' width='16' height='2' fill='%23b8a060' opacity='0.25'/%3E%3Crect x='90' y='94' width='24' height='2' fill='%23a89048' opacity='0.3'/%3E%3Crect x='140' y='98' width='20' height='2' fill='%23b8a060' opacity='0.25'/%3E%3Crect x='190' y='92' width='18' height='2' fill='%23a89048' opacity='0.28'/%3E%3Crect x='15' y='80' width='12' height='8' fill='%23475569' opacity='0.55'/%3E%3Crect x='17' y='78' width='8' height='4' fill='%2364748b' opacity='0.45'/%3E%3Crect x='19' y='76' width='4' height='4' fill='%23718096' opacity='0.35'/%3E%3Crect x='45' y='48' width='2' height='40' fill='%2316a34a' opacity='0.55'/%3E%3Crect x='47' y='44' width='2' height='12' fill='%2322c55e' opacity='0.5'/%3E%3Crect x='43' y='52' width='2' height='8' fill='%2315803d' opacity='0.45'/%3E%3Crect x='49' y='40' width='2' height='8' fill='%2322c55e' opacity='0.4'/%3E%3Crect x='41' y='56' width='2' height='6' fill='%2316a34a' opacity='0.35'/%3E%3Crect x='75' y='72' width='2' height='16' fill='%23f87171' opacity='0.5'/%3E%3Crect x='73' y='68' width='2' height='8' fill='%23fb7185' opacity='0.45'/%3E%3Crect x='77' y='70' width='2' height='6' fill='%23f472b6' opacity='0.4'/%3E%3Crect x='71' y='66' width='2' height='4' fill='%23f87171' opacity='0.35'/%3E%3Crect x='79' y='68' width='2' height='4' fill='%23fb7185' opacity='0.35'/%3E%3Crect x='69' y='68' width='2' height='2' fill='%23f472b6' opacity='0.3'/%3E%3Crect x='81' y='70' width='2' height='2' fill='%23f87171' opacity='0.3'/%3E%3Crect x='105' y='62' width='2' height='26' fill='%2322c55e' opacity='0.5'/%3E%3Crect x='107' y='58' width='2' height='10' fill='%2316a34a' opacity='0.45'/%3E%3Crect x='103' y='66' width='2' height='6' fill='%2315803d' opacity='0.4'/%3E%3Crect x='125' y='86' width='2' height='8' fill='%23f97316' opacity='0.5'/%3E%3Crect x='121' y='88' width='10' height='2' fill='%23f97316' opacity='0.5'/%3E%3Crect x='123' y='84' width='2' height='2' fill='%23fb923c' opacity='0.4'/%3E%3Crect x='129' y='84' width='2' height='2' fill='%23fb923c' opacity='0.4'/%3E%3Crect x='121' y='92' width='2' height='2' fill='%23fb923c' opacity='0.4'/%3E%3Crect x='131' y='92' width='2' height='2' fill='%23fb923c' opacity='0.4'/%3E%3Crect x='150' y='50' width='2' height='38' fill='%2316a34a' opacity='0.5'/%3E%3Crect x='152' y='46' width='2' height='10' fill='%2322c55e' opacity='0.45'/%3E%3Crect x='148' y='54' width='2' height='8' fill='%2315803d' opacity='0.4'/%3E%3Crect x='154' y='42' width='2' height='8' fill='%2322c55e' opacity='0.35'/%3E%3Crect x='180' y='76' width='2' height='12' fill='%23818cf8' opacity='0.45'/%3E%3Crect x='178' y='72' width='2' height='6' fill='%23a78bfa' opacity='0.4'/%3E%3Crect x='182' y='74' width='2' height='4' fill='%23c084fc' opacity='0.35'/%3E%3Crect x='176' y='74' width='2' height='2' fill='%23818cf8' opacity='0.3'/%3E%3Crect x='184' y='76' width='2' height='2' fill='%23a78bfa' opacity='0.3'/%3E%3Crect x='210' y='86' width='6' height='4' fill='%23fef3c7' opacity='0.4'/%3E%3Crect x='212' y='84' width='4' height='2' fill='%23fde68a' opacity='0.35'/%3E%3Crect x='214' y='82' width='2' height='2' fill='%23fef3c7' opacity='0.3'/%3E%3Crect x='220' y='82' width='10' height='6' fill='%23475569' opacity='0.5'/%3E%3Crect x='222' y='80' width='6' height='4' fill='%2364748b' opacity='0.4'/%3E%3Crect x='35' y='90' width='2' height='2' fill='%2364748b' opacity='0.3'/%3E%3Crect x='60' y='92' width='2' height='2' fill='%2364748b' opacity='0.25'/%3E%3Crect x='95' y='90' width='2' height='2' fill='%23475569' opacity='0.3'/%3E%3Crect x='160' y='92' width='2' height='2' fill='%2364748b' opacity='0.25'/%3E%3Crect x='200' y='90' width='2' height='2' fill='%23475569' opacity='0.28'/%3E%3C/svg%3E") repeat-x bottom center / 240px 120px; +} + +/* Animated bubbles rising through the water */ +.content::before { + content: ''; + position: absolute; + inset: 0; + pointer-events: none; + z-index: -1; + background: + /* Bubble layer 1 - larger, slower */ + url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='80' height='200' viewBox='0 0 80 200' shape-rendering='crispEdges'%3E%3Crect x='20' y='30' width='4' height='4' fill='%2367e8f9' opacity='0.22'/%3E%3Crect x='60' y='90' width='4' height='4' fill='%2367e8f9' opacity='0.18'/%3E%3Crect x='35' y='150' width='4' height='4' fill='%2367e8f9' opacity='0.24'/%3E%3Crect x='50' y='20' width='2' height='2' fill='white' opacity='0.16'/%3E%3Crect x='10' y='70' width='2' height='2' fill='white' opacity='0.13'/%3E%3Crect x='70' y='130' width='2' height='2' fill='white' opacity='0.16'/%3E%3Crect x='25' y='180' width='2' height='2' fill='white' opacity='0.13'/%3E%3Crect x='40' y='50' width='2' height='2' fill='%2367e8f9' opacity='0.1'/%3E%3Crect x='5' y='110' width='2' height='2' fill='%2367e8f9' opacity='0.09'/%3E%3Crect x='55' y='170' width='2' height='2' fill='white' opacity='0.11'/%3E%3C/svg%3E") repeat / 80px 200px, + /* Bubble layer 2 - smaller, different rhythm */ + url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='100' height='280' viewBox='0 0 100 280' shape-rendering='crispEdges'%3E%3Crect x='30' y='40' width='4' height='4' fill='%2367e8f9' opacity='0.16'/%3E%3Crect x='75' y='110' width='2' height='2' fill='white' opacity='0.13'/%3E%3Crect x='15' y='180' width='4' height='4' fill='%2367e8f9' opacity='0.2'/%3E%3Crect x='55' y='240' width='2' height='2' fill='white' opacity='0.11'/%3E%3Crect x='85' y='60' width='2' height='2' fill='%2367e8f9' opacity='0.1'/%3E%3Crect x='45' y='150' width='2' height='2' fill='white' opacity='0.13'/%3E%3Crect x='10' y='260' width='2' height='2' fill='%2367e8f9' opacity='0.09'/%3E%3Crect x='65' y='20' width='2' height='2' fill='white' opacity='0.11'/%3E%3C/svg%3E") repeat / 100px 280px; + animation: sea-bubbles 14s linear infinite, water-sway 8s ease-in-out infinite alternate; +} + +/* Animated pixel art fish swimming across */ +.content::after { + content: ''; + position: absolute; + inset: 0; + pointer-events: none; + z-index: -1; + background: + /* Fish 1: orange tropical fish (right-facing, swims left→right) */ + url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='10' viewBox='0 0 16 10' shape-rendering='crispEdges'%3E%3Crect x='0' y='1' width='2' height='2' fill='%23f97316' opacity='0.6'/%3E%3Crect x='0' y='7' width='2' height='2' fill='%23f97316' opacity='0.6'/%3E%3Crect x='2' y='2' width='2' height='6' fill='%23fb923c' opacity='0.6'/%3E%3Crect x='4' y='1' width='8' height='8' fill='%23f97316' opacity='0.55'/%3E%3Crect x='7' y='1' width='2' height='8' fill='%23fef3c7' opacity='0.4'/%3E%3Crect x='5' y='0' width='4' height='1' fill='%23fb923c' opacity='0.4'/%3E%3Crect x='5' y='9' width='4' height='1' fill='%23fb923c' opacity='0.4'/%3E%3Crect x='10' y='3' width='2' height='2' fill='%23000' opacity='0.5'/%3E%3Crect x='11' y='3' width='1' height='1' fill='white' opacity='0.4'/%3E%3Crect x='12' y='5' width='2' height='1' fill='%23000' opacity='0.3'/%3E%3C/svg%3E") no-repeat / 32px 20px, + /* Fish 2: blue fish (left-facing, swims right→left) */ + url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8' shape-rendering='crispEdges'%3E%3Crect x='10' y='1' width='2' height='2' fill='%236366f1' opacity='0.5'/%3E%3Crect x='10' y='5' width='2' height='2' fill='%236366f1' opacity='0.5'/%3E%3Crect x='8' y='2' width='2' height='4' fill='%23818cf8' opacity='0.5'/%3E%3Crect x='2' y='1' width='6' height='6' fill='%236366f1' opacity='0.45'/%3E%3Crect x='2' y='2' width='2' height='2' fill='%23000' opacity='0.4'/%3E%3Crect x='2' y='2' width='1' height='1' fill='white' opacity='0.3'/%3E%3Crect x='4' y='0' width='3' height='1' fill='%23818cf8' opacity='0.35'/%3E%3C/svg%3E") no-repeat / 24px 16px; + animation: fish-swim 20s linear infinite; +} + +@keyframes sea-bubbles { + from { background-position: 0 0, 40px 0; } + to { background-position: 0 -200px, 0 -280px; } +} + +@keyframes water-sway { + from { transform: translateX(-3px); } + to { transform: translateX(3px); } +} + +@keyframes fish-swim { + 0% { background-position: -40px 25%, calc(100% + 30px) 55%; } + 100% { background-position: calc(100% + 40px) 30%, -30px 50%; } } /* Override ChatContainer backgrounds for black transparency */ diff --git a/frontend/src/components/transcript-debug/AssistantMessageBubble.vue b/frontend/src/components/transcript-debug/AssistantMessageBubble.vue index 195d356..276f157 100644 --- a/frontend/src/components/transcript-debug/AssistantMessageBubble.vue +++ b/frontend/src/components/transcript-debug/AssistantMessageBubble.vue @@ -103,12 +103,9 @@ function formatTokens(n?: number): string { diff --git a/frontend/src/components/transcript-debug/toolCards/BashCard.vue b/frontend/src/components/transcript-debug/toolCards/BashCard.vue index 6fa3f80..eb769f4 100644 --- a/frontend/src/components/transcript-debug/toolCards/BashCard.vue +++ b/frontend/src/components/transcript-debug/toolCards/BashCard.vue @@ -17,8 +17,7 @@ const isError = computed(() => props.call.result?.isError ?? false) const highlightedCommand = computed(() => highlightCode(command.value, 'bash')) -const cmdExpanded = ref(false) -const resultExpanded = ref(false) +const expanded = ref(false) const cmdPreview = computed(() => { const c = command.value.replace(/\n/g, ' ').trim() @@ -28,7 +27,7 @@ const cmdPreview = computed(() => { @@ -88,7 +73,9 @@ const cmdPreview = computed(() => { padding: 0.3rem 0.6rem; background: transparent; min-height: 28px; + cursor: pointer; } +.card-header:hover { background: rgba(245, 158, 11, 0.04); } .card-icon { display: flex; align-items: center; color: rgba(245, 158, 11, 0.6); flex-shrink: 0; } .bash-card.error .card-icon { color: rgba(239, 68, 68, 0.6); } diff --git a/frontend/src/components/transcript-debug/toolCards/EditCard.vue b/frontend/src/components/transcript-debug/toolCards/EditCard.vue index e7dfffe..bd190bc 100644 --- a/frontend/src/components/transcript-debug/toolCards/EditCard.vue +++ b/frontend/src/components/transcript-debug/toolCards/EditCard.vue @@ -27,8 +27,7 @@ const ext = computed(() => { const isError = computed(() => props.call.result?.isError ?? false) -const diffExpanded = ref(false) -const resultExpanded = ref(false) +const expanded = ref(false) const highlightedOld = computed(() => highlightCode(oldString.value, ext.value || undefined)) const highlightedNew = computed(() => highlightCode(newString.value, ext.value || undefined)) @@ -39,7 +38,7 @@ const newLineCount = computed(() => newString.value.split('\n').length) @@ -105,8 +92,11 @@ const newLineCount = computed(() => newString.value.split('\n').length) padding: 0.3rem 0.6rem; background: transparent; min-height: 28px; + cursor: pointer; } +.card-header:hover { background: rgba(99, 102, 241, 0.04); } + .card-icon { display: flex; align-items: center; color: rgba(99, 102, 241, 0.6); flex-shrink: 0; } .edit-card.error .card-icon { color: rgba(239, 68, 68, 0.6); } @@ -147,26 +137,6 @@ const newLineCount = computed(() => newString.value.split('\n').length) .diff-added { color: rgba(34, 197, 94, 0.7); } .error-badge { color: rgba(239, 68, 68, 0.7); } -.header-spacer { flex: 1; } - -.toggle-btn { - display: flex; - align-items: center; - justify-content: center; - width: 20px; - height: 20px; - border: none; - border-radius: 4px; - background: transparent; - color: var(--text-muted); - cursor: pointer; - flex-shrink: 0; - opacity: 0.5; - transition: all 0.15s; -} -.toggle-btn:hover { opacity: 0.8; } -.toggle-btn.active { opacity: 1; color: rgba(99, 102, 241, 0.8); } - /* Diff */ .diff-content { border-top: 1px solid rgba(255, 255, 255, 0.04); } diff --git a/frontend/src/components/transcript-debug/toolCards/GlobCard.vue b/frontend/src/components/transcript-debug/toolCards/GlobCard.vue index d4d3263..0138a70 100644 --- a/frontend/src/components/transcript-debug/toolCards/GlobCard.vue +++ b/frontend/src/components/transcript-debug/toolCards/GlobCard.vue @@ -19,7 +19,7 @@ const fileCount = computed(() => { return content.split('\n').filter(l => l.trim()).length }) -const resultExpanded = ref(false) +const expanded = ref(false) const shortPath = computed(() => { if (!path.value) return '' @@ -29,7 +29,7 @@ const shortPath = computed(() => { @@ -74,7 +65,9 @@ const shortPath = computed(() => { padding: 0.3rem 0.6rem; background: transparent; min-height: 28px; + cursor: pointer; } +.card-header:hover { background: rgba(251, 191, 36, 0.04); } .card-icon { display: flex; align-items: center; color: rgba(251, 191, 36, 0.6); flex-shrink: 0; } .glob-card.error .card-icon { color: rgba(239, 68, 68, 0.6); } diff --git a/frontend/src/components/transcript-debug/toolCards/GrepCard.vue b/frontend/src/components/transcript-debug/toolCards/GrepCard.vue index e58dd96..b1096bb 100644 --- a/frontend/src/components/transcript-debug/toolCards/GrepCard.vue +++ b/frontend/src/components/transcript-debug/toolCards/GrepCard.vue @@ -42,8 +42,7 @@ const flags = computed(() => { return f }) -const detailsExpanded = ref(false) -const resultExpanded = ref(false) +const expanded = ref(false) const shortPath = computed(() => { if (!path.value) return '' @@ -53,7 +52,7 @@ const shortPath = computed(() => { @@ -113,7 +98,9 @@ const shortPath = computed(() => { padding: 0.3rem 0.6rem; background: transparent; min-height: 28px; + cursor: pointer; } +.card-header:hover { background: rgba(236, 72, 153, 0.04); } .card-icon { display: flex; align-items: center; color: rgba(236, 72, 153, 0.6); flex-shrink: 0; } .grep-card.error .card-icon { color: rgba(239, 68, 68, 0.6); } diff --git a/frontend/src/components/transcript-debug/toolCards/ReadCard.vue b/frontend/src/components/transcript-debug/toolCards/ReadCard.vue index d70d2f2..46d8aff 100644 --- a/frontend/src/components/transcript-debug/toolCards/ReadCard.vue +++ b/frontend/src/components/transcript-debug/toolCards/ReadCard.vue @@ -26,12 +26,12 @@ const ext = computed(() => { return dot >= 0 ? name.slice(dot + 1).toLowerCase() : '' }) -const resultExpanded = ref(false) +const expanded = ref(false) @@ -79,7 +70,9 @@ const resultExpanded = ref(false) padding: 0.3rem 0.6rem; background: transparent; min-height: 28px; + cursor: pointer; } +.card-header:hover { background: rgba(6, 182, 212, 0.04); } .card-icon { display: flex; align-items: center; color: rgba(6, 182, 212, 0.6); flex-shrink: 0; } .read-card.error .card-icon { color: rgba(239, 68, 68, 0.6); } diff --git a/frontend/src/components/transcript-debug/toolCards/TaskCard.vue b/frontend/src/components/transcript-debug/toolCards/TaskCard.vue index cd2ed66..f2d8f0a 100644 --- a/frontend/src/components/transcript-debug/toolCards/TaskCard.vue +++ b/frontend/src/components/transcript-debug/toolCards/TaskCard.vue @@ -21,10 +21,7 @@ const subagentType = computed(() => (props.call.input?.subagent_type as string) const model = computed(() => (props.call.input?.model as string) || '') const runInBackground = computed(() => props.call.input?.run_in_background as boolean | undefined) -// Toggles -const showPrompt = ref(false) -const showResult = ref(false) -const showDesc = ref(false) +const expanded = ref(false) // ---- Extract main topics from result ---- interface TopicItem { @@ -124,9 +121,9 @@ const cardColor = computed(() => { } }) -const hasDesc = computed(() => description.value.length > 0) -const hasPrompt = computed(() => prompt.value.length > 0) -const hasResult = computed(() => !!props.call.result) +const hasExpandable = computed(() => + description.value.length > 0 || prompt.value.length > 0 || !!props.call.result +) // Brief for body (only when no topics to show) const descBrief = computed(() => { @@ -143,7 +140,7 @@ const hasBody = computed(() => @@ -245,7 +221,9 @@ const hasBody = computed(() => padding: 0.3rem 0.6rem; background: transparent; min-height: 28px; + cursor: pointer; } +.card-header:hover { background: color-mix(in srgb, var(--card-color) 4%, transparent); } .card-icon { display: flex; align-items: center; color: color-mix(in srgb, var(--card-color) 60%, transparent); flex-shrink: 0; } .task-card.error .card-icon { color: rgba(239, 68, 68, 0.6); } diff --git a/frontend/src/components/transcript-debug/toolCards/WriteCard.vue b/frontend/src/components/transcript-debug/toolCards/WriteCard.vue index 4fc3cd5..188ba1f 100644 --- a/frontend/src/components/transcript-debug/toolCards/WriteCard.vue +++ b/frontend/src/components/transcript-debug/toolCards/WriteCard.vue @@ -25,8 +25,7 @@ const ext = computed(() => { const isError = computed(() => props.call.result?.isError ?? false) -const contentExpanded = ref(false) -const resultExpanded = ref(false) +const expanded = ref(false) const highlightedContent = computed(() => highlightCode(content.value, ext.value || undefined)) @@ -35,7 +34,7 @@ const lineCount = computed(() => content.value.split('\n').length) @@ -93,7 +78,9 @@ const lineCount = computed(() => content.value.split('\n').length) padding: 0.3rem 0.6rem; background: transparent; min-height: 28px; + cursor: pointer; } +.card-header:hover { background: rgba(34, 197, 94, 0.04); } .card-icon { display: flex; align-items: center; color: rgba(34, 197, 94, 0.6); flex-shrink: 0; } .write-card.error .card-icon { color: rgba(239, 68, 68, 0.6); }