feat: Add specialized tool cards for transcript-debug and glassmorphism bubbles

Add toolCards/ with rich visual cards for 10 tool types:
- AskUserQuestion, ExitPlanMode, EnterPlanMode
- Read, Write, Bash, Edit
- Grep, Glob
- Task/TaskCreate/TaskUpdate/TaskGet/TaskList (unified TaskCard)

Add MarkdownContent component and markdown/syntax highlight utils.
Make user/assistant bubbles transparent with backdrop blur.
This commit is contained in:
2026-02-19 02:45:53 -06:00
parent 159a38e3c2
commit 4ab1d03370
17 changed files with 2925 additions and 18 deletions

View File

@@ -0,0 +1,170 @@
<script setup lang="ts">
import { computed } from 'vue'
import type { ParsedToolCall } from '@/types/transcript-debug'
import ToolResultBlock from '../ToolResultBlock.vue'
const props = defineProps<{
call: ParsedToolCall
}>()
const pattern = computed(() => (props.call.input?.pattern as string) || '')
const path = computed(() => (props.call.input?.path as string) || '')
const isError = computed(() => props.call.result?.isError ?? false)
// Count files from result
const fileCount = computed(() => {
if (!props.call.result?.content) return null
const content = props.call.result.content.trim()
if (!content) return 0
return content.split('\n').filter(l => l.trim()).length
})
</script>
<template>
<div :class="['glob-card', { error: isError }]">
<div class="card-header">
<span class="card-icon">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z"/>
</svg>
</span>
<span class="card-label">Glob</span>
<span v-if="fileCount != null && !isError" class="match-count">{{ fileCount }} files</span>
<span v-if="isError" class="error-badge">error</span>
</div>
<div class="card-body">
<!-- Pattern -->
<div class="pattern-row">
<code class="pattern-text">{{ pattern }}</code>
</div>
<!-- Path scope -->
<div v-if="path" class="scope-row">
<span class="scope-badge">
<svg width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z"/>
</svg>
{{ path.replace(/\\/g, '/').split('/').slice(-3).join('/') }}
</span>
</div>
</div>
<!-- Result -->
<ToolResultBlock v-if="call.result" :result="call.result" />
</div>
</template>
<style scoped>
.glob-card {
border: 1px solid rgba(251, 191, 36, 0.25);
border-left: 3px solid #fbbf24;
border-radius: 8px;
overflow: hidden;
margin: 0.5rem 0;
background: var(--bg-primary);
}
.glob-card.error {
border-color: rgba(239, 68, 68, 0.25);
border-left-color: #ef4444;
}
.card-header {
display: flex;
align-items: center;
gap: 0.5rem;
padding: 0.45rem 0.75rem;
background: rgba(251, 191, 36, 0.06);
border-bottom: 1px solid rgba(251, 191, 36, 0.12);
}
.glob-card.error .card-header {
background: rgba(239, 68, 68, 0.06);
border-bottom-color: rgba(239, 68, 68, 0.12);
}
.card-icon {
display: flex;
align-items: center;
color: #fbbf24;
}
.glob-card.error .card-icon { color: #ef4444; }
.card-label {
font-size: 11px;
font-weight: 600;
color: #fbbf24;
text-transform: uppercase;
letter-spacing: 0.5px;
}
.glob-card.error .card-label { color: #ef4444; }
.match-count {
margin-left: auto;
font-size: 10px;
padding: 0.1rem 0.35rem;
border-radius: 4px;
background: rgba(34, 197, 94, 0.1);
color: #22c55e;
font-family: 'SF Mono', 'Fira Code', monospace;
font-weight: 500;
}
.error-badge {
font-size: 10px;
padding: 0.1rem 0.4rem;
border-radius: 4px;
background: rgba(239, 68, 68, 0.15);
color: #ef4444;
font-weight: 500;
}
.card-body {
padding: 0.5rem 0.75rem;
display: flex;
flex-direction: column;
gap: 0.35rem;
}
.pattern-row {
display: flex;
align-items: center;
}
.pattern-text {
font-size: 12px;
font-family: 'SF Mono', 'Fira Code', monospace;
color: #fbbf24;
background: rgba(251, 191, 36, 0.06);
padding: 0.2rem 0.5rem;
border-radius: 4px;
border: 1px solid rgba(251, 191, 36, 0.12);
word-break: break-all;
}
.scope-row {
display: flex;
align-items: center;
gap: 0.35rem;
}
.scope-badge {
display: inline-flex;
align-items: center;
gap: 0.2rem;
font-size: 10px;
padding: 0.1rem 0.35rem;
border-radius: 4px;
font-family: 'SF Mono', 'Fira Code', monospace;
background: rgba(6, 182, 212, 0.08);
color: #06b6d4;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
max-width: 280px;
}
</style>