refac
This commit is contained in:
1 parent
315566064a
commit
4a1064cefd
4 files changed
+157
-42
No files matched your search
@@ -15,6 +15,57 @@
|
|||||||
import FloatingButtons from '../ContentRenderer/FloatingButtons.svelte';
|
import FloatingButtons from '../ContentRenderer/FloatingButtons.svelte';
|
||||||
import { createMessagesList } from '$lib/utils';
|
import { createMessagesList } from '$lib/utils';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extracts all top-level <details>...</details> blocks from content,
|
||||||
|
* handling nested <details> via depth tracking.
|
||||||
|
* Returns { detailsContent, plainContent }.
|
||||||
|
*/
|
||||||
|
const extractDetailsBlocks = (text) => {
|
||||||
|
const blocks = [];
|
||||||
|
let remaining = text;
|
||||||
|
let result = '';
|
||||||
|
const openTag = '<details';
|
||||||
|
const closeTag = '</details>';
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
const start = remaining.indexOf(openTag);
|
||||||
|
if (start === -1) {
|
||||||
|
result += remaining;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
result += remaining.slice(0, start);
|
||||||
|
|
||||||
|
// Find matching closing tag with depth tracking
|
||||||
|
let depth = 1;
|
||||||
|
let idx = start + openTag.length;
|
||||||
|
while (depth > 0 && idx < remaining.length) {
|
||||||
|
if (remaining.startsWith(openTag, idx)) {
|
||||||
|
depth++;
|
||||||
|
} else if (remaining.startsWith(closeTag, idx)) {
|
||||||
|
depth--;
|
||||||
|
}
|
||||||
|
if (depth > 0) idx++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (depth === 0) {
|
||||||
|
const end = idx + closeTag.length;
|
||||||
|
blocks.push(remaining.slice(start, end));
|
||||||
|
remaining = remaining.slice(end);
|
||||||
|
} else {
|
||||||
|
// Unmatched opening tag, treat as plain text
|
||||||
|
result += remaining.slice(start);
|
||||||
|
remaining = '';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
detailsContent: blocks.join('\n'),
|
||||||
|
plainContent: result.trim()
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
export let id;
|
export let id;
|
||||||
export let content;
|
export let content;
|
||||||
|
|
||||||
@@ -174,43 +225,59 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div bind:this={contentContainerElement}>
|
<div bind:this={contentContainerElement}>
|
||||||
<Markdown
|
{#if $settings?.renderMarkdownInAssistantMessages ?? true}
|
||||||
{id}
|
<Markdown
|
||||||
content={model?.info?.meta?.capabilities?.citations == false
|
{id}
|
||||||
? content.replace(/\s*(\[(?:\d+(?:#[^,\]\s]+)?(?:,\s*\d+(?:#[^,\]\s]+)?)*)\])+/g, '')
|
content={model?.info?.meta?.capabilities?.citations == false
|
||||||
: content}
|
? content.replace(/\s*(\[(?:\d+(?:#[^,\]\s]+)?(?:,\s*\d+(?:#[^,\]\s]+)?)*)\])+/g, '')
|
||||||
{model}
|
: content}
|
||||||
{save}
|
{model}
|
||||||
{preview}
|
{save}
|
||||||
{done}
|
{preview}
|
||||||
{editCodeBlock}
|
{done}
|
||||||
{topPadding}
|
{editCodeBlock}
|
||||||
{sourceIds}
|
{topPadding}
|
||||||
{onSourceClick}
|
{sourceIds}
|
||||||
{onTaskClick}
|
{onSourceClick}
|
||||||
{onSave}
|
{onTaskClick}
|
||||||
onUpdate={async (token) => {
|
{onSave}
|
||||||
const { lang, text: code } = token;
|
onUpdate={async (token) => {
|
||||||
|
const { lang, text: code } = token;
|
||||||
|
|
||||||
if (
|
if (
|
||||||
($settings?.detectArtifacts ?? true) &&
|
($settings?.detectArtifacts ?? true) &&
|
||||||
(['html', 'svg'].includes(lang) || (lang === 'xml' && code.includes('svg'))) &&
|
(['html', 'svg'].includes(lang) || (lang === 'xml' && code.includes('svg'))) &&
|
||||||
!$mobile &&
|
!$mobile &&
|
||||||
$chatId
|
$chatId
|
||||||
) {
|
) {
|
||||||
await tick();
|
await tick();
|
||||||
showArtifacts.set(true);
|
showArtifacts.set(true);
|
||||||
showControls.set(true);
|
showControls.set(true);
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
onPreview={async (value) => {
|
onPreview={async (value) => {
|
||||||
console.log('Preview', value);
|
console.log('Preview', value);
|
||||||
await artifactCode.set(value);
|
await artifactCode.set(value);
|
||||||
await showControls.set(true);
|
await showControls.set(true);
|
||||||
await showArtifacts.set(true);
|
await showArtifacts.set(true);
|
||||||
await showEmbeds.set(false);
|
await showEmbeds.set(false);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
{:else}
|
||||||
|
{@const extracted = extractDetailsBlocks(content)}
|
||||||
|
|
||||||
|
{#if extracted.detailsContent}
|
||||||
|
<!-- Render structural blocks (tool calls, reasoning, etc.) through Markdown -->
|
||||||
|
<Markdown
|
||||||
|
{id}
|
||||||
|
content={extracted.detailsContent}
|
||||||
|
{done}
|
||||||
|
/>
|
||||||
|
{/if}
|
||||||
|
{#if extracted.plainContent}
|
||||||
|
<div class="whitespace-pre-wrap">{extracted.plainContent}</div>
|
||||||
|
{/if}
|
||||||
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{#if floatingButtons}
|
{#if floatingButtons}
|
||||||
|
|||||||
@@ -376,12 +376,16 @@
|
|||||||
: ' w-full'}"
|
: ' w-full'}"
|
||||||
>
|
>
|
||||||
{#if message.content}
|
{#if message.content}
|
||||||
<Markdown
|
{#if $settings?.renderMarkdownInUserMessages ?? true}
|
||||||
id={`${chatId}-${message.id}`}
|
<Markdown
|
||||||
content={message.content}
|
id={`${chatId}-${message.id}`}
|
||||||
{editCodeBlock}
|
content={message.content}
|
||||||
{topPadding}
|
{editCodeBlock}
|
||||||
/>
|
{topPadding}
|
||||||
|
/>
|
||||||
|
{:else}
|
||||||
|
<div class="whitespace-pre-wrap" dir={$settings?.chatDirection ?? 'auto'}>{message.content}</div>
|
||||||
|
{/if}
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -69,6 +69,8 @@
|
|||||||
let temporaryChatByDefault = false;
|
let temporaryChatByDefault = false;
|
||||||
let chatFadeStreamingText = true;
|
let chatFadeStreamingText = true;
|
||||||
let collapseCodeBlocks = false;
|
let collapseCodeBlocks = false;
|
||||||
|
let renderMarkdownInUserMessages = true;
|
||||||
|
let renderMarkdownInAssistantMessages = true;
|
||||||
let expandDetails = false;
|
let expandDetails = false;
|
||||||
let renderMarkdownInPreviews = true;
|
let renderMarkdownInPreviews = true;
|
||||||
let showChatTitleInTab = true;
|
let showChatTitleInTab = true;
|
||||||
@@ -232,6 +234,8 @@
|
|||||||
copyFormatted = $settings?.copyFormatted ?? false;
|
copyFormatted = $settings?.copyFormatted ?? false;
|
||||||
|
|
||||||
collapseCodeBlocks = $settings?.collapseCodeBlocks ?? false;
|
collapseCodeBlocks = $settings?.collapseCodeBlocks ?? false;
|
||||||
|
renderMarkdownInUserMessages = $settings?.renderMarkdownInUserMessages ?? true;
|
||||||
|
renderMarkdownInAssistantMessages = $settings?.renderMarkdownInAssistantMessages ?? true;
|
||||||
expandDetails = $settings?.expandDetails ?? false;
|
expandDetails = $settings?.expandDetails ?? false;
|
||||||
renderMarkdownInPreviews = $settings?.renderMarkdownInPreviews ?? true;
|
renderMarkdownInPreviews = $settings?.renderMarkdownInPreviews ?? true;
|
||||||
|
|
||||||
@@ -776,6 +780,44 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<div class=" py-0.5 flex w-full justify-between">
|
||||||
|
<div id="render-markdown-user-label" class=" self-center text-xs">
|
||||||
|
{$i18n.t('Render Markdown in User Messages')}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex items-center gap-2 p-1">
|
||||||
|
<Switch
|
||||||
|
ariaLabelledbyId="render-markdown-user-label"
|
||||||
|
tooltip={true}
|
||||||
|
bind:state={renderMarkdownInUserMessages}
|
||||||
|
on:change={() => {
|
||||||
|
saveSettings({ renderMarkdownInUserMessages });
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<div class=" py-0.5 flex w-full justify-between">
|
||||||
|
<div id="render-markdown-assistant-label" class=" self-center text-xs">
|
||||||
|
{$i18n.t('Render Markdown in Assistant Messages')}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex items-center gap-2 p-1">
|
||||||
|
<Switch
|
||||||
|
ariaLabelledbyId="render-markdown-assistant-label"
|
||||||
|
tooltip={true}
|
||||||
|
bind:state={renderMarkdownInAssistantMessages}
|
||||||
|
on:change={() => {
|
||||||
|
saveSettings({ renderMarkdownInAssistantMessages });
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<div class=" py-0.5 flex w-full justify-between">
|
<div class=" py-0.5 flex w-full justify-between">
|
||||||
<div id="auto-generation-label" class=" self-center text-xs">
|
<div id="auto-generation-label" class=" self-center text-xs">
|
||||||
|
|||||||
@@ -1697,6 +1697,8 @@
|
|||||||
"Remove Model": "",
|
"Remove Model": "",
|
||||||
"Rename": "",
|
"Rename": "",
|
||||||
"Renamed to {{name}}": "",
|
"Renamed to {{name}}": "",
|
||||||
|
"Render Markdown in Assistant Messages": "",
|
||||||
|
"Render Markdown in User Messages": "",
|
||||||
"Render Markdown in Previews": "",
|
"Render Markdown in Previews": "",
|
||||||
"Reorder Models": "",
|
"Reorder Models": "",
|
||||||
"Repeats": "",
|
"Repeats": "",
|
||||||
|
|||||||
Reference in new issue
Block a user