diff --git a/src/lib/components/chat/ArtifactViewer.svelte b/src/lib/components/chat/ArtifactViewer.svelte index 3cd408d..2d0f8a8 100644 --- a/src/lib/components/chat/ArtifactViewer.svelte +++ b/src/lib/components/chat/ArtifactViewer.svelte @@ -2,7 +2,6 @@ import { Dialog } from 'bits-ui'; import { Badge } from '$lib/components/ui/badge/index.js'; import { toast } from '$lib/stores/toast'; - import { onMount } from 'svelte'; import type { Artifact } from '$lib/types'; let { @@ -18,19 +17,24 @@ let editorInstance: any = null; $effect(() => { - if (open && artifact && artifact.type === 'code' && editorContainer && !editorInstance) { + if (open && artifact && (artifact.type === 'code' || artifact.type === 'diff') && editorContainer && !editorInstance) { loadMonaco(); } + // Cleanup on close + if (!open && editorInstance) { + editorInstance.dispose(); + editorInstance = null; + } }); async function loadMonaco() { try { const monaco = await import('monaco-editor'); monacoReady = true; - if (editorContainer) { + if (editorContainer && artifact) { editorInstance = monaco.editor.create(editorContainer, { - value: artifact?.content || '', - language: mapLang(artifact?.language || ''), + value: artifact.content, + language: artifact.type === 'diff' ? 'diff' : mapLang(artifact.language), readOnly: true, theme: document.documentElement.classList.contains('dark') ? 'vs-dark' : 'vs', minimap: { enabled: false }, @@ -53,8 +57,7 @@ go: 'go', rs: 'rust', java: 'java', cpp: 'cpp', c: 'c', html: 'html', css: 'css', scss: 'scss', json: 'json', yaml: 'yaml', yml: 'yaml', md: 'markdown', sh: 'shell', - bash: 'shell', sql: 'sql', xml: 'xml', svelte: 'html', - svg: 'xml' + bash: 'shell', sql: 'sql', xml: 'xml', svelte: 'html', svg: 'xml' }; return map[lang] || lang || 'plaintext'; } @@ -94,12 +97,8 @@ {artifact.language || artifact.type}
- - + +
{/if} + {:else if artifact.type === 'mermaid'} +
+
{artifact.content}
+
{:else}
{artifact.content}
diff --git a/src/lib/components/chat/ChatMessage.svelte b/src/lib/components/chat/ChatMessage.svelte index d54e6c5..63081a2 100644 --- a/src/lib/components/chat/ChatMessage.svelte +++ b/src/lib/components/chat/ChatMessage.svelte @@ -4,18 +4,24 @@ import hljs from 'highlight.js'; import { toast } from '$lib/stores/toast'; import { onMount } from 'svelte'; + import type { Artifact } from '$lib/types'; let { content = '', role = 'assistant' as 'user' | 'assistant', - status = 'complete' as 'sending' | 'streaming' | 'complete' | 'error' + status = 'complete' as 'sending' | 'streaming' | 'complete' | 'error', + artifacts = [] as Artifact[], + onArtifactClick }: { content?: string; role?: 'user' | 'assistant'; status?: 'sending' | 'streaming' | 'complete' | 'error'; + artifacts?: Artifact[]; + onArtifactClick?: (artifact: Artifact) => void; } = $props(); let ready = $state(false); + let copiedId = $state(null); onMount(() => { marked.setOptions({ @@ -40,10 +46,15 @@ } }); - function copyCode(code: string, e: Event) { - e.stopPropagation(); + function copyCode(code: string, id: string) { navigator.clipboard.writeText(code); + copiedId = id; toast('Copied to clipboard'); + setTimeout(() => { copiedId = null; }, 2000); + } + + function handleArtifactClick(a: Artifact) { + onArtifactClick?.(a); } @@ -60,9 +71,9 @@ )}> {#if !content && status === 'streaming'}
- - - + + +
{:else if content}
@@ -70,13 +81,48 @@
{#if status === 'streaming'} - + {/if} {/if} {#if status === 'error'}
Error generating response
{/if} + + + {#if artifacts && artifacts.length > 0} +
+ {#each artifacts as a (a.id)} + + {/each} +
+ {/if}
{#if role === 'user'} @@ -99,23 +145,6 @@ margin: 0.5rem 0; position: relative; } - :global(.prose pre:hover .copy-btn) { - opacity: 1; - } - :global(.copy-btn) { - position: absolute; - top: 0.5rem; - right: 0.5rem; - opacity: 0; - transition: opacity 0.15s; - padding: 0.25rem 0.5rem; - font-size: 0.7rem; - border-radius: 0.25rem; - background: hsl(var(--color-muted)); - color: hsl(var(--color-muted-foreground)); - border: 1px solid hsl(var(--color-border)); - cursor: pointer; - } :global(.prose code) { font-size: 0.8rem; padding: 0.1rem 0.3rem; diff --git a/src/lib/components/chat/Sidebar.svelte b/src/lib/components/chat/Sidebar.svelte index 97fefd1..c221cf6 100644 --- a/src/lib/components/chat/Sidebar.svelte +++ b/src/lib/components/chat/Sidebar.svelte @@ -1,9 +1,10 @@