feat: preview html

This commit is contained in:
Timothy Jaeryang Baek 2025-05-16 21:47:43 +04:00
parent 07b5e84221
commit 54dc24986f
8 changed files with 73 additions and 28 deletions

View File

@ -4,7 +4,7 @@
const i18n = getContext('i18n');
const dispatch = createEventDispatcher();
import { chatId, settings, showArtifacts, showControls } from '$lib/stores';
import { artifactCode, chatId, settings, showArtifacts, showControls } from '$lib/stores';
import XMark from '../icons/XMark.svelte';
import { copyToClipboard, createMessagesList } from '$lib/utils';
import ArrowsPointingOut from '../icons/ArrowsPointingOut.svelte';
@ -180,7 +180,14 @@
}
};
onMount(() => {});
onMount(() => {
artifactCode.subscribe((value) => {
if (contents) {
const codeIdx = contents.findIndex((content) => content.content.includes(value));
selectedContentIdx = codeIdx !== -1 ? codeIdx : 0;
}
});
});
</script>
<div class=" w-full h-full relative flex flex-col bg-gray-50 dark:bg-gray-850">

View File

@ -957,8 +957,6 @@
? (e.key === 'Enter' || e.keyCode === 13) && isCtrlPressed
: (e.key === 'Enter' || e.keyCode === 13) && !e.shiftKey;
console.log('Enter pressed:', enterPressed);
if (enterPressed) {
e.preventDefault();
}

View File

@ -17,6 +17,7 @@
import ChevronUp from '$lib/components/icons/ChevronUp.svelte';
import ChevronUpDown from '$lib/components/icons/ChevronUpDown.svelte';
import CommandLine from '$lib/components/icons/CommandLine.svelte';
import Cube from '$lib/components/icons/Cube.svelte';
const i18n = getContext('i18n');
@ -24,9 +25,11 @@
export let onSave = (e) => {};
export let onCode = (e) => {};
export let onPreview = (e) => {};
export let save = false;
export let run = true;
export let preview = false;
export let collapsed = false;
export let token;
@ -88,6 +91,10 @@
}, 1000);
};
const previewCode = () => {
onPreview(code);
};
const checkPythonCode = (str) => {
// Check if the string contains typical Python syntax characters
const pythonSyntax = [
@ -430,7 +437,7 @@
class="flex gap-1 items-center bg-none border-none bg-gray-50 hover:bg-gray-100 dark:bg-gray-850 dark:hover:bg-gray-800 transition rounded-md px-1.5 py-0.5"
on:click={collapseCodeBlock}
>
<div>
<div class=" -translate-y-[0.5px]">
<ChevronUpDown className="size-3" />
</div>
@ -439,6 +446,21 @@
</div>
</button>
{#if preview && ['html', 'svg'].includes(lang)}
<button
class="flex gap-1 items-center run-code-button bg-none border-none bg-gray-50 hover:bg-gray-100 dark:bg-gray-850 dark:hover:bg-gray-800 transition rounded-md px-1.5 py-0.5"
on:click={previewCode}
>
<div class=" -translate-y-[0.5px]">
<Cube className="size-3" />
</div>
<div>
{$i18n.t('Preview')}
</div>
</button>
{/if}
{#if ($config?.features?.enable_code_execution ?? true) && (lang.toLowerCase() === 'python' || lang.toLowerCase() === 'py' || (lang === '' && checkPythonCode(code)))}
{#if executing}
<div class="run-code-button bg-none border-none p-1 cursor-not-allowed">
@ -453,7 +475,7 @@
executePython(code);
}}
>
<div>
<div class=" -translate-y-[0.5px]">
<CommandLine className="size-3" />
</div>

View File

@ -1,10 +1,17 @@
<script>
import { onDestroy, onMount, tick, getContext, createEventDispatcher } from 'svelte';
import { onDestroy, onMount, tick, getContext } from 'svelte';
const i18n = getContext('i18n');
const dispatch = createEventDispatcher();
import Markdown from './Markdown.svelte';
import { chatId, mobile, settings, showArtifacts, showControls, showOverview } from '$lib/stores';
import {
artifactCode,
chatId,
mobile,
settings,
showArtifacts,
showControls,
showOverview
} from '$lib/stores';
import FloatingButtons from '../ContentRenderer/FloatingButtons.svelte';
import { createMessagesList } from '$lib/utils';
@ -15,8 +22,10 @@
export let sources = null;
export let save = false;
export let preview = false;
export let floatingButtons = true;
export let onUpdate = () => {};
export let onSourceClick = () => {};
export let onTaskClick = () => {};
@ -122,6 +131,7 @@
{content}
{model}
{save}
{preview}
sourceIds={(sources ?? []).reduce((acc, s) => {
let ids = [];
s.document.forEach((document, index) => {
@ -154,8 +164,12 @@
}, [])}
{onSourceClick}
{onTaskClick}
onUpdate={(value) => {
dispatch('update', value);
{onUpdate}
onPreview={async (value) => {
await artifactCode.set(value);
await showControls.set(true);
await showArtifacts.set(true);
await showOverview.set(false);
}}
onCode={(value) => {
const { lang, code } = value;

View File

@ -12,11 +12,13 @@
export let content;
export let model = null;
export let save = false;
export let preview = false;
export let sourceIds = [];
export let onUpdate = () => {};
export let onCode = () => {};
export let onPreview = () => {};
export let onSourceClick = () => {};
export let onTaskClick = () => {};
@ -40,5 +42,15 @@
</script>
{#key id}
<MarkdownTokens {tokens} {id} {save} {onTaskClick} {onSourceClick} {onUpdate} {onCode} />
<MarkdownTokens
{tokens}
{id}
{save}
{preview}
{onTaskClick}
{onSourceClick}
{onUpdate}
{onCode}
{onPreview}
/>
{/key}

View File

@ -29,9 +29,11 @@
export let attributes = {};
export let save = false;
export let preview = false;
export let onUpdate: Function = () => {};
export let onCode: Function = () => {};
export let onPreview: Function = () => {};
export let onTaskClick: Function = () => {};
export let onSourceClick: Function = () => {};
@ -95,7 +97,9 @@
code={token?.text ?? ''}
{attributes}
{save}
{preview}
{onCode}
{onPreview}
onSave={(value) => {
onUpdate({
raw: token.raw,

View File

@ -806,6 +806,7 @@
sources={message.sources}
floatingButtons={message?.done && !readOnly}
save={!readOnly}
preview={!readOnly}
{model}
onTaskClick={async (e) => {
console.log(e);
@ -840,28 +841,13 @@
onAddMessages={({ modelId, parentId, messages }) => {
addMessages({ modelId, parentId, messages });
}}
on:update={(e) => {
const { raw, oldContent, newContent } = e.detail;
onUpdate={({ raw, oldContent, newContent }) => {
history.messages[message.id].content = history.messages[
message.id
].content.replace(raw, raw.replace(oldContent, newContent));
updateChat();
}}
on:select={(e) => {
const { type, content } = e.detail;
if (type === 'explain') {
submitMessage(
message.id,
`Explain this section to me in more detail\n\n\`\`\`\n${content}\n\`\`\``
);
} else if (type === 'ask') {
const input = e.detail?.input ?? '';
submitMessage(message.id, `\`\`\`\n${content}\n\`\`\`\n${input}`);
}
}}
/>
{/if}

View File

@ -74,6 +74,8 @@ export const showOverview = writable(false);
export const showArtifacts = writable(false);
export const showCallOverlay = writable(false);
export const artifactCode = writable(null);
export const temporaryChatEnabled = writable(false);
export const scrollPaginationEnabled = writable(false);
export const currentChatPage = writable(1);