feat: Modular aquatic background system and shared CodeBlock component

Add aquaticBackground/ module with OceanScene (unified gradient, light rays,
sea floor, corals, seaweed, decorations), plus independent overlay layers
(BubbleStream, FishSchool, JellyfishDrift, EventOverlay, EdgeFade). Includes
event scheduling engine with 4 frequency tiers (minutes/hours/days/months)
and 20 random events with localStorage persistence.

Add shared CodeBlock component with copy-to-clipboard button, terminal-matched
monospace font (Consolas), and proper line-height/letter-spacing. Refactor
EditCard, WriteCard, TaskCard, and ToolResultBlock to use CodeBlock. Fix
markdown code block alignment to match terminal rendering.
This commit is contained in:
2026-02-19 17:15:36 -06:00
parent 3adfd189e1
commit eb69c0b2cf
21 changed files with 1707 additions and 257 deletions

View File

@@ -1,43 +1,36 @@
<script setup lang="ts">
import { computed } from 'vue'
import type { ParsedToolResult } from '@/types/transcript-debug'
import { highlightCode } from '@/utils/markdown'
import CodeBlock from './CodeBlock.vue'
const props = defineProps<{
result: ParsedToolResult
}>()
const highlightedContent = computed(() => {
const content = props.result.content
const trimmed = content.trim()
const content = computed(() => props.result.content)
const lang = computed(() => {
const trimmed = content.value.trim()
if ((trimmed.startsWith('{') && trimmed.endsWith('}')) ||
(trimmed.startsWith('[') && trimmed.endsWith(']'))) {
try {
const parsed = JSON.parse(trimmed)
return highlightCode(JSON.stringify(parsed, null, 2), 'json')
JSON.parse(trimmed)
return 'json'
} catch { /* not valid JSON */ }
}
return highlightCode(content)
return ''
})
const displayCode = computed(() => {
if (lang.value === 'json') {
try {
return JSON.stringify(JSON.parse(content.value.trim()), null, 2)
} catch { /* fallback */ }
}
return content.value
})
</script>
<template>
<pre class="result-content" v-html="highlightedContent"></pre>
<CodeBlock :code="displayCode" :lang="lang" max-height="300px" />
</template>
<style scoped>
.result-content {
margin: 0;
padding: 0.35rem 0.6rem;
font-size: 11px;
line-height: 1.45;
color: var(--text-secondary);
white-space: pre-wrap;
word-break: break-all;
max-height: 300px;
overflow-y: auto;
background: transparent;
border-top: 1px solid rgba(255, 255, 255, 0.04);
font-family: 'SF Mono', 'Fira Code', monospace;
}
</style>