Spaces:
Sleeping
Sleeping
stylized markdown think
Browse files- src/lib/components/chat/Message.svelte +1 -1
- src/lib/components/chat/markdown/Code.svelte +19 -3
- src/lib/components/chat/markdown/Codespan.svelte +1 -1
- src/lib/components/chat/markdown/Heading.svelte +4 -4
- src/lib/components/chat/markdown/List.svelte +2 -2
- src/lib/components/chat/markdown/Paragraph.svelte +1 -1
- src/lib/components/chat/markdown/Think.svelte +37 -4
- src/lib/components/chat/markdown/think/Blockquote.svelte +8 -0
- src/lib/components/chat/markdown/think/Code.svelte +55 -0
- src/lib/components/chat/markdown/think/Codespan.svelte +8 -0
- src/lib/components/chat/markdown/think/Heading.svelte +23 -0
- src/lib/components/chat/markdown/think/Hr.svelte +1 -0
- src/lib/components/chat/markdown/think/Link.svelte +18 -0
- src/lib/components/chat/markdown/think/List.svelte +20 -0
- src/lib/components/chat/markdown/think/ListItem.svelte +6 -0
- src/lib/components/chat/markdown/think/Paragraph.svelte +6 -0
src/lib/components/chat/Message.svelte
CHANGED
|
@@ -38,7 +38,7 @@
|
|
| 38 |
{:else}
|
| 39 |
{#if message.reasoning}
|
| 40 |
<Think
|
| 41 |
-
isThinking={!message.content
|
| 42 |
content={message.reasoning as string}
|
| 43 |
/>
|
| 44 |
{/if}
|
|
|
|
| 38 |
{:else}
|
| 39 |
{#if message.reasoning}
|
| 40 |
<Think
|
| 41 |
+
isThinking={!!message.content && (message.content as string)?.trim() !== ''}
|
| 42 |
content={message.reasoning as string}
|
| 43 |
/>
|
| 44 |
{/if}
|
src/lib/components/chat/markdown/Code.svelte
CHANGED
|
@@ -2,7 +2,9 @@
|
|
| 2 |
import Button from '$lib/components/ui/button/button.svelte';
|
| 3 |
import { Check, Copy } from '@lucide/svelte';
|
| 4 |
import { HighlightAuto } from 'svelte-highlight';
|
| 5 |
-
import '
|
|
|
|
|
|
|
| 6 |
|
| 7 |
let {
|
| 8 |
lang,
|
|
@@ -17,16 +19,30 @@
|
|
| 17 |
copiedCode = true;
|
| 18 |
setTimeout(() => (copiedCode = false), 2000);
|
| 19 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 20 |
</script>
|
| 21 |
|
| 22 |
<div class="overflow-hidden {className}">
|
| 23 |
{#if lang}
|
| 24 |
-
<div
|
|
|
|
|
|
|
| 25 |
<span class="font-mono text-[11px] text-muted-foreground">{lang}</span>
|
| 26 |
</div>
|
| 27 |
{/if}
|
| 28 |
<div class="group relative">
|
| 29 |
-
<HighlightAuto code={text} class="font-mono text-[
|
| 30 |
<Button
|
| 31 |
variant="outline"
|
| 32 |
class="absolute top-2 right-2 opacity-0 group-hover:opacity-100"
|
|
|
|
| 2 |
import Button from '$lib/components/ui/button/button.svelte';
|
| 3 |
import { Check, Copy } from '@lucide/svelte';
|
| 4 |
import { HighlightAuto } from 'svelte-highlight';
|
| 5 |
+
import { mode } from 'mode-watcher';
|
| 6 |
+
import githubDarkUrl from 'svelte-highlight/styles/github-dark.css?url';
|
| 7 |
+
import githubUrl from 'svelte-highlight/styles/github.css?url';
|
| 8 |
|
| 9 |
let {
|
| 10 |
lang,
|
|
|
|
| 19 |
copiedCode = true;
|
| 20 |
setTimeout(() => (copiedCode = false), 2000);
|
| 21 |
}
|
| 22 |
+
|
| 23 |
+
$effect(() => {
|
| 24 |
+
const themeUrl = mode.current === 'dark' ? githubDarkUrl : githubUrl;
|
| 25 |
+
let link = document.getElementById('highlight-theme') as HTMLLinkElement | null;
|
| 26 |
+
if (!link) {
|
| 27 |
+
link = document.createElement('link');
|
| 28 |
+
link.id = 'highlight-theme';
|
| 29 |
+
link.rel = 'stylesheet';
|
| 30 |
+
document.head.appendChild(link);
|
| 31 |
+
}
|
| 32 |
+
link.href = themeUrl;
|
| 33 |
+
});
|
| 34 |
</script>
|
| 35 |
|
| 36 |
<div class="overflow-hidden {className}">
|
| 37 |
{#if lang}
|
| 38 |
+
<div
|
| 39 |
+
class="flex items-center justify-between border-b border-border/60 bg-muted px-3 py-1.5 dark:bg-accent/30"
|
| 40 |
+
>
|
| 41 |
<span class="font-mono text-[11px] text-muted-foreground">{lang}</span>
|
| 42 |
</div>
|
| 43 |
{/if}
|
| 44 |
<div class="group relative">
|
| 45 |
+
<HighlightAuto code={text} class="font-mono text-[11px] leading-relaxed" />
|
| 46 |
<Button
|
| 47 |
variant="outline"
|
| 48 |
class="absolute top-2 right-2 opacity-0 group-hover:opacity-100"
|
src/lib/components/chat/markdown/Codespan.svelte
CHANGED
|
@@ -3,6 +3,6 @@
|
|
| 3 |
</script>
|
| 4 |
|
| 5 |
<code
|
| 6 |
-
class="rounded-md border border-border/40 bg-
|
| 7 |
>{raw.replace(/`/g, '')}</code
|
| 8 |
>
|
|
|
|
| 3 |
</script>
|
| 4 |
|
| 5 |
<code
|
| 6 |
+
class="rounded-md border border-border/40 bg-accent-foreground/5 px-1.5 py-0.5 font-mono text-[11px] text-foreground/85"
|
| 7 |
>{raw.replace(/`/g, '')}</code
|
| 8 |
>
|
src/lib/components/chat/markdown/Heading.svelte
CHANGED
|
@@ -5,19 +5,19 @@
|
|
| 5 |
</script>
|
| 6 |
|
| 7 |
{#if depth === 1}
|
| 8 |
-
<h1 class="mt-4 mb-2 text-
|
| 9 |
{@render children?.()}
|
| 10 |
</h1>
|
| 11 |
{:else if depth === 2}
|
| 12 |
-
<h2 class="mt-3.5 mb-2 text-
|
| 13 |
{@render children?.()}
|
| 14 |
</h2>
|
| 15 |
{:else if depth === 3}
|
| 16 |
-
<h3 class="mt-3 mb-1.5 text-
|
| 17 |
{@render children?.()}
|
| 18 |
</h3>
|
| 19 |
{:else}
|
| 20 |
-
<h4 class="mt-2.5 mb-1 text-
|
| 21 |
{@render children?.()}
|
| 22 |
</h4>
|
| 23 |
{/if}
|
|
|
|
| 5 |
</script>
|
| 6 |
|
| 7 |
{#if depth === 1}
|
| 8 |
+
<h1 class="mt-4 mb-2 text-base font-semibold text-foreground first:mt-0">
|
| 9 |
{@render children?.()}
|
| 10 |
</h1>
|
| 11 |
{:else if depth === 2}
|
| 12 |
+
<h2 class="mt-3.5 mb-2 text-base font-semibold text-foreground first:mt-0">
|
| 13 |
{@render children?.()}
|
| 14 |
</h2>
|
| 15 |
{:else if depth === 3}
|
| 16 |
+
<h3 class="mt-3 mb-1.5 text-sm font-semibold text-foreground first:mt-0">
|
| 17 |
{@render children?.()}
|
| 18 |
</h3>
|
| 19 |
{:else}
|
| 20 |
+
<h4 class="mt-2.5 mb-1 text-sm font-semibold text-foreground first:mt-0">
|
| 21 |
{@render children?.()}
|
| 22 |
</h4>
|
| 23 |
{/if}
|
src/lib/components/chat/markdown/List.svelte
CHANGED
|
@@ -6,14 +6,14 @@
|
|
| 6 |
|
| 7 |
{#if ordered}
|
| 8 |
<ol
|
| 9 |
-
class="my-2 list-outside list-decimal space-y-1 pl-5 text-
|
| 10 |
{start}
|
| 11 |
>
|
| 12 |
{@render children?.()}
|
| 13 |
</ol>
|
| 14 |
{:else}
|
| 15 |
<ul
|
| 16 |
-
class="my-2 list-outside list-disc space-y-1 pl-5 text-
|
| 17 |
>
|
| 18 |
{@render children?.()}
|
| 19 |
</ul>
|
|
|
|
| 6 |
|
| 7 |
{#if ordered}
|
| 8 |
<ol
|
| 9 |
+
class="my-2 list-outside list-decimal space-y-1 pl-5 text-xs text-foreground/90 marker:text-muted-foreground"
|
| 10 |
{start}
|
| 11 |
>
|
| 12 |
{@render children?.()}
|
| 13 |
</ol>
|
| 14 |
{:else}
|
| 15 |
<ul
|
| 16 |
+
class="my-2 list-outside list-disc space-y-1 pl-5 text-xs text-foreground/90 marker:text-muted-foreground"
|
| 17 |
>
|
| 18 |
{@render children?.()}
|
| 19 |
</ul>
|
src/lib/components/chat/markdown/Paragraph.svelte
CHANGED
|
@@ -3,4 +3,4 @@
|
|
| 3 |
let { children }: { children?: Snippet } = $props();
|
| 4 |
</script>
|
| 5 |
|
| 6 |
-
<p class="mb-3 text-
|
|
|
|
| 3 |
let { children }: { children?: Snippet } = $props();
|
| 4 |
</script>
|
| 5 |
|
| 6 |
+
<p class="mb-3 text-xs leading-relaxed text-foreground/90 last:mb-0">{@render children?.()}</p>
|
src/lib/components/chat/markdown/Think.svelte
CHANGED
|
@@ -1,8 +1,20 @@
|
|
| 1 |
<script lang="ts">
|
| 2 |
import { slide } from 'svelte/transition';
|
| 3 |
import { Brain, ChevronDown } from '@lucide/svelte';
|
|
|
|
| 4 |
|
| 5 |
import Spinner from '$lib/components/loading/Spinner.svelte';
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 6 |
let { isThinking, content }: { isThinking?: boolean; content?: string } = $props();
|
| 7 |
|
| 8 |
let isCollapsed = $state.raw<boolean>(false);
|
|
@@ -10,15 +22,36 @@
|
|
| 10 |
function toggleCollapse() {
|
| 11 |
isCollapsed = !isCollapsed;
|
| 12 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 13 |
</script>
|
| 14 |
|
| 15 |
-
<div
|
|
|
|
|
|
|
| 16 |
<button
|
| 17 |
-
class="flex w-full cursor-pointer items-center gap-2.5 p-3 text-left transition-colors hover:bg-accent/80"
|
| 18 |
onclick={toggleCollapse}
|
| 19 |
>
|
| 20 |
<div
|
| 21 |
-
class="flex size-7 min-h-7 min-w-7 items-center justify-center rounded-lg bg-linear-to-br from-primary/20 to-primary/5
|
|
|
|
| 22 |
>
|
| 23 |
<Brain class="size-3.5 text-muted-foreground" />
|
| 24 |
</div>
|
|
@@ -37,7 +70,7 @@
|
|
| 37 |
{#if !isCollapsed}
|
| 38 |
<div transition:slide={{ duration: 200 }}>
|
| 39 |
<div class="border-t border-border/60 px-4 py-3">
|
| 40 |
-
<
|
| 41 |
</div>
|
| 42 |
</div>
|
| 43 |
{/if}
|
|
|
|
| 1 |
<script lang="ts">
|
| 2 |
import { slide } from 'svelte/transition';
|
| 3 |
import { Brain, ChevronDown } from '@lucide/svelte';
|
| 4 |
+
import SvelteMarkdown from 'svelte-markdown';
|
| 5 |
|
| 6 |
import Spinner from '$lib/components/loading/Spinner.svelte';
|
| 7 |
+
|
| 8 |
+
import Paragraph from './Paragraph.svelte';
|
| 9 |
+
import Heading from './Heading.svelte';
|
| 10 |
+
import Code from './Code.svelte';
|
| 11 |
+
import Codespan from './Codespan.svelte';
|
| 12 |
+
import Blockquote from './Blockquote.svelte';
|
| 13 |
+
import List from './List.svelte';
|
| 14 |
+
import ListItem from './ListItem.svelte';
|
| 15 |
+
import Link from './Link.svelte';
|
| 16 |
+
import Hr from './Hr.svelte';
|
| 17 |
+
|
| 18 |
let { isThinking, content }: { isThinking?: boolean; content?: string } = $props();
|
| 19 |
|
| 20 |
let isCollapsed = $state.raw<boolean>(false);
|
|
|
|
| 22 |
function toggleCollapse() {
|
| 23 |
isCollapsed = !isCollapsed;
|
| 24 |
}
|
| 25 |
+
|
| 26 |
+
const renderers = {
|
| 27 |
+
paragraph: Paragraph,
|
| 28 |
+
heading: Heading,
|
| 29 |
+
code: Code,
|
| 30 |
+
codespan: Codespan,
|
| 31 |
+
blockquote: Blockquote,
|
| 32 |
+
list: List,
|
| 33 |
+
listitem: ListItem,
|
| 34 |
+
link: Link,
|
| 35 |
+
hr: Hr
|
| 36 |
+
};
|
| 37 |
+
|
| 38 |
+
$effect(() => {
|
| 39 |
+
if (!isThinking) {
|
| 40 |
+
isCollapsed = true;
|
| 41 |
+
}
|
| 42 |
+
});
|
| 43 |
</script>
|
| 44 |
|
| 45 |
+
<div
|
| 46 |
+
class="mb-4 overflow-hidden rounded-xl border border-border bg-accent text-xs dark:bg-accent/30"
|
| 47 |
+
>
|
| 48 |
<button
|
| 49 |
+
class="flex w-full cursor-pointer items-center gap-2.5 p-3 text-left transition-colors hover:bg-accent/80 dark:hover:bg-accent/30"
|
| 50 |
onclick={toggleCollapse}
|
| 51 |
>
|
| 52 |
<div
|
| 53 |
+
class="flex size-7 min-h-7 min-w-7 items-center justify-center rounded-lg bg-linear-to-br from-primary/20 to-primary/5 {isThinking &&
|
| 54 |
+
'animate-pulse'}"
|
| 55 |
>
|
| 56 |
<Brain class="size-3.5 text-muted-foreground" />
|
| 57 |
</div>
|
|
|
|
| 70 |
{#if !isCollapsed}
|
| 71 |
<div transition:slide={{ duration: 200 }}>
|
| 72 |
<div class="border-t border-border/60 px-4 py-3">
|
| 73 |
+
<SvelteMarkdown source={content?.trimStart()} renderers={renderers as any} />
|
| 74 |
</div>
|
| 75 |
</div>
|
| 76 |
{/if}
|
src/lib/components/chat/markdown/think/Blockquote.svelte
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<script lang="ts">
|
| 2 |
+
import type { Snippet } from 'svelte';
|
| 3 |
+
let { children }: { children?: Snippet } = $props();
|
| 4 |
+
</script>
|
| 5 |
+
|
| 6 |
+
<blockquote class="my-2 border-l-2 border-muted-foreground/25 pl-2.5 text-muted-foreground/80 italic">
|
| 7 |
+
{@render children?.()}
|
| 8 |
+
</blockquote>
|
src/lib/components/chat/markdown/think/Code.svelte
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<script lang="ts">
|
| 2 |
+
import Button from '$lib/components/ui/button/button.svelte';
|
| 3 |
+
import { Check, Copy } from '@lucide/svelte';
|
| 4 |
+
import { HighlightAuto } from 'svelte-highlight';
|
| 5 |
+
import { mode } from 'mode-watcher';
|
| 6 |
+
import githubDarkUrl from 'svelte-highlight/styles/github-dark.css?url';
|
| 7 |
+
import githubUrl from 'svelte-highlight/styles/github.css?url';
|
| 8 |
+
|
| 9 |
+
let { lang, text }: { lang?: string; text: string } = $props();
|
| 10 |
+
|
| 11 |
+
let copiedCode = $state(false);
|
| 12 |
+
|
| 13 |
+
async function copy(text: string) {
|
| 14 |
+
await navigator.clipboard.writeText(text);
|
| 15 |
+
copiedCode = true;
|
| 16 |
+
setTimeout(() => (copiedCode = false), 2000);
|
| 17 |
+
}
|
| 18 |
+
|
| 19 |
+
$effect(() => {
|
| 20 |
+
const themeUrl = mode.current === 'dark' ? githubDarkUrl : githubUrl;
|
| 21 |
+
let link = document.getElementById('highlight-theme') as HTMLLinkElement | null;
|
| 22 |
+
if (!link) {
|
| 23 |
+
link = document.createElement('link');
|
| 24 |
+
link.id = 'highlight-theme';
|
| 25 |
+
link.rel = 'stylesheet';
|
| 26 |
+
document.head.appendChild(link);
|
| 27 |
+
}
|
| 28 |
+
link.href = themeUrl;
|
| 29 |
+
});
|
| 30 |
+
</script>
|
| 31 |
+
|
| 32 |
+
<div class="my-2 overflow-hidden rounded-md border border-border/50 bg-muted/40">
|
| 33 |
+
{#if lang}
|
| 34 |
+
<div
|
| 35 |
+
class="flex items-center justify-between border-b border-border/50 bg-muted/60 px-2.5 py-1 dark:bg-accent/20"
|
| 36 |
+
>
|
| 37 |
+
<span class="font-mono text-[10px] text-muted-foreground">{lang}</span>
|
| 38 |
+
</div>
|
| 39 |
+
{/if}
|
| 40 |
+
<div class="group relative">
|
| 41 |
+
<HighlightAuto code={text} class="font-mono text-[11px] leading-relaxed" />
|
| 42 |
+
<Button
|
| 43 |
+
variant="outline"
|
| 44 |
+
class="absolute top-1.5 right-1.5 opacity-0 group-hover:opacity-100"
|
| 45 |
+
size="icon-xs"
|
| 46 |
+
onclick={() => copy(text)}
|
| 47 |
+
>
|
| 48 |
+
{#if copiedCode}
|
| 49 |
+
<Check class="size-3 text-green-500" />
|
| 50 |
+
{:else}
|
| 51 |
+
<Copy class="size-3" />
|
| 52 |
+
{/if}
|
| 53 |
+
</Button>
|
| 54 |
+
</div>
|
| 55 |
+
</div>
|
src/lib/components/chat/markdown/think/Codespan.svelte
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<script lang="ts">
|
| 2 |
+
let { raw }: { raw: string } = $props();
|
| 3 |
+
</script>
|
| 4 |
+
|
| 5 |
+
<code
|
| 6 |
+
class="rounded border border-border/30 bg-muted px-1 py-px font-mono text-[10px] text-foreground/80"
|
| 7 |
+
>{raw.replace(/`/g, '')}</code
|
| 8 |
+
>
|
src/lib/components/chat/markdown/think/Heading.svelte
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<script lang="ts">
|
| 2 |
+
import type { Snippet } from 'svelte';
|
| 3 |
+
let { depth, children }: { depth: number; raw?: string; text?: string; children?: Snippet } =
|
| 4 |
+
$props();
|
| 5 |
+
</script>
|
| 6 |
+
|
| 7 |
+
{#if depth === 1}
|
| 8 |
+
<h1 class="mt-3 mb-1.5 text-sm font-semibold text-foreground first:mt-0">
|
| 9 |
+
{@render children?.()}
|
| 10 |
+
</h1>
|
| 11 |
+
{:else if depth === 2}
|
| 12 |
+
<h2 class="mt-2.5 mb-1 text-[13px] font-semibold text-foreground first:mt-0">
|
| 13 |
+
{@render children?.()}
|
| 14 |
+
</h2>
|
| 15 |
+
{:else if depth === 3}
|
| 16 |
+
<h3 class="mt-2 mb-1 text-xs font-semibold text-foreground first:mt-0">
|
| 17 |
+
{@render children?.()}
|
| 18 |
+
</h3>
|
| 19 |
+
{:else}
|
| 20 |
+
<h4 class="mt-1.5 mb-0.5 text-[11px] font-semibold text-foreground first:mt-0">
|
| 21 |
+
{@render children?.()}
|
| 22 |
+
</h4>
|
| 23 |
+
{/if}
|
src/lib/components/chat/markdown/think/Hr.svelte
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
<hr class="my-2.5 border-t border-border/40" />
|
src/lib/components/chat/markdown/think/Link.svelte
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<script lang="ts">
|
| 2 |
+
import type { Snippet } from 'svelte';
|
| 3 |
+
let {
|
| 4 |
+
href = '',
|
| 5 |
+
title,
|
| 6 |
+
children
|
| 7 |
+
}: { href?: string; title?: string; children?: Snippet } = $props();
|
| 8 |
+
</script>
|
| 9 |
+
|
| 10 |
+
<a
|
| 11 |
+
{href}
|
| 12 |
+
{title}
|
| 13 |
+
target="_blank"
|
| 14 |
+
rel="noopener noreferrer"
|
| 15 |
+
class="text-primary/80 underline decoration-primary/30 underline-offset-2 transition-colors hover:text-primary hover:decoration-primary"
|
| 16 |
+
>
|
| 17 |
+
{@render children?.()}
|
| 18 |
+
</a>
|
src/lib/components/chat/markdown/think/List.svelte
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<script lang="ts">
|
| 2 |
+
import type { Snippet } from 'svelte';
|
| 3 |
+
let { ordered, start, children }: { ordered: boolean; start?: number; children?: Snippet } =
|
| 4 |
+
$props();
|
| 5 |
+
</script>
|
| 6 |
+
|
| 7 |
+
{#if ordered}
|
| 8 |
+
<ol
|
| 9 |
+
class="my-1.5 list-outside list-decimal space-y-0.5 pl-4 text-foreground/75 marker:text-muted-foreground"
|
| 10 |
+
{start}
|
| 11 |
+
>
|
| 12 |
+
{@render children?.()}
|
| 13 |
+
</ol>
|
| 14 |
+
{:else}
|
| 15 |
+
<ul
|
| 16 |
+
class="my-1.5 list-outside list-disc space-y-0.5 pl-4 text-foreground/75 marker:text-muted-foreground"
|
| 17 |
+
>
|
| 18 |
+
{@render children?.()}
|
| 19 |
+
</ul>
|
| 20 |
+
{/if}
|
src/lib/components/chat/markdown/think/ListItem.svelte
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<script lang="ts">
|
| 2 |
+
import type { Snippet } from 'svelte';
|
| 3 |
+
let { children }: { children?: Snippet } = $props();
|
| 4 |
+
</script>
|
| 5 |
+
|
| 6 |
+
<li class="leading-relaxed">{@render children?.()}</li>
|
src/lib/components/chat/markdown/think/Paragraph.svelte
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<script lang="ts">
|
| 2 |
+
import type { Snippet } from 'svelte';
|
| 3 |
+
let { children }: { children?: Snippet } = $props();
|
| 4 |
+
</script>
|
| 5 |
+
|
| 6 |
+
<p class="mb-2 leading-relaxed text-foreground/75 last:mb-0">{@render children?.()}</p>
|