feat: custom tool renderers

This commit is contained in:
Zoe
2026-09-25 19:46:00 -05:00
parent 3f81f96bda
commit bb5795e00d
18 changed files with 1294 additions and 65 deletions
@@ -0,0 +1,103 @@
<script setup lang="ts">
import { computed, ref, watch } from "vue";
import { useNuxtApp } from "#app";
const props = defineProps<{
code: string;
lang?: string;
}>();
const { $shiki } = useNuxtApp();
const html = ref("");
const targetLang = computed(() => props.lang || "json");
const lineNumberWidth = computed(() => {
const lines = props.code ? props.code.split("\n").length : 1;
return lines.toString().length;
});
watch(
[() => props.code, targetLang],
async ([newCode, newLang]) => {
if (!newCode) {
html.value = "";
return;
}
let resolvedLang = newLang;
try {
if ($shiki?.getLanguage) {
await $shiki.getLanguage(resolvedLang);
}
} catch {
resolvedLang = "text";
}
try {
if ($shiki?.codeToHtml) {
html.value = await $shiki.codeToHtml(newCode, {
lang: resolvedLang,
themes: {
dark: "vitesse-dark",
light: "vitesse-light",
},
});
} else {
html.value = "";
}
} catch {
html.value = "";
}
},
{ immediate: true },
);
</script>
<template>
<div
class="tool-code-container overflow-auto max-h-80 scrollbar-thin text-xs font-mono"
:style="`--line-number-width: ${lineNumberWidth}ch;`"
>
<div v-if="html" class="tool-code-highlight" v-html="html"></div>
<pre v-else class="tool-code-fallback m-0 p-3.5 text-[var(--text-secondary)] whitespace-pre-wrap break-words leading-relaxed">{{ code }}</pre>
</div>
</template>
<style scoped>
.tool-code-container {
background-color: var(--shiki-dark-bg, #121019);
}
:deep(.tool-code-highlight > pre) {
margin: 0;
padding: 0.875rem 1rem;
font-size: 0.75rem;
line-height: 1.625;
scrollbar-width: thin;
overflow-x: auto;
counter-reset: lines;
min-height: 100%;
box-sizing: border-box;
font-family: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
}
:deep(.tool-code-highlight > pre > code .line::before) {
counter-increment: lines;
content: counter(lines);
width: var(--line-number-width, 2ch);
margin-right: 1.25rem;
display: inline-block;
text-align: right;
color: rgba(255, 255, 255, 0.25);
user-select: none;
}
:deep(html.light .tool-code-container) {
background-color: #ffffff;
}
:deep(html.light .tool-code-highlight > pre > code .line::before) {
color: rgba(0, 0, 0, 0.25);
}
</style>