summaryrefslogtreecommitdiffhomepage
path: root/src/features/chat/ui
diff options
context:
space:
mode:
Diffstat (limited to 'src/features/chat/ui')
-rw-r--r--src/features/chat/ui/ChatView.svelte32
-rw-r--r--src/features/chat/ui/Composer.svelte6
-rw-r--r--src/features/chat/ui/ModelSelector.svelte22
3 files changed, 42 insertions, 18 deletions
diff --git a/src/features/chat/ui/ChatView.svelte b/src/features/chat/ui/ChatView.svelte
index ce66798..cb6069b 100644
--- a/src/features/chat/ui/ChatView.svelte
+++ b/src/features/chat/ui/ChatView.svelte
@@ -4,14 +4,16 @@
let { chunks }: { chunks: readonly RenderedChunk[] } = $props();
</script>
-<div class="chat-transcript" role="log" aria-live="polite">
+<div class="flex flex-col gap-2 p-4" role="log" aria-live="polite">
{#each chunks as rendered, i (rendered.seq != null ? `c${rendered.seq}` : `p${i}`)}
- <article
- class="message message--{rendered.role}"
- class:message--provisional={rendered.provisional}
- >
- <header class="message__role">{rendered.role}</header>
- <div class="message__content">
+ <div class="chat {rendered.role === 'user' ? 'chat-start' : 'chat-end'}">
+ <div class="chat-header text-xs opacity-70">{rendered.role}</div>
+ <div
+ class="chat-bubble"
+ class:chat-bubble-primary={rendered.role === "user"}
+ class:chat-bubble-secondary={rendered.role === "assistant"}
+ class:opacity-50={rendered.provisional}
+ >
{#if rendered.chunk.type === "text"}
<p>{rendered.chunk.text}</p>
{:else if rendered.chunk.type === "thinking"}
@@ -20,26 +22,26 @@
<p>{rendered.chunk.text}</p>
</details>
{:else if rendered.chunk.type === "tool-call"}
- <div class="tool-call">
+ <div class="text-sm">
<strong>{rendered.chunk.toolName}</strong>
- <pre>{JSON.stringify(rendered.chunk.input, null, 2)}</pre>
+ <pre class="text-xs mt-1">{JSON.stringify(rendered.chunk.input, null, 2)}</pre>
</div>
{:else if rendered.chunk.type === "tool-result"}
- <div class="tool-result" class:tool-result--error={rendered.chunk.isError}>
+ <div class="text-sm" class:text-error={rendered.chunk.isError}>
<strong>{rendered.chunk.toolName}</strong>
- <pre>{rendered.chunk.content}</pre>
+ <pre class="text-xs mt-1">{rendered.chunk.content}</pre>
</div>
{:else if rendered.chunk.type === "error"}
- <div class="error" role="alert">
+ <div class="text-error" role="alert">
{rendered.chunk.message}
{#if rendered.chunk.code}
- <span class="error__code">[{rendered.chunk.code}]</span>
+ <span class="text-xs opacity-70">[{rendered.chunk.code}]</span>
{/if}
</div>
{:else if rendered.chunk.type === "system"}
- <div class="system">{rendered.chunk.text}</div>
+ <div class="text-sm opacity-70">{rendered.chunk.text}</div>
{/if}
</div>
- </article>
+ </div>
{/each}
</div>
diff --git a/src/features/chat/ui/Composer.svelte b/src/features/chat/ui/Composer.svelte
index dc71e11..3762340 100644
--- a/src/features/chat/ui/Composer.svelte
+++ b/src/features/chat/ui/Composer.svelte
@@ -18,16 +18,16 @@
}
</script>
-<form class="composer" onsubmit={prevent => { prevent.preventDefault(); handleSubmit(); }}>
+<form class="flex gap-2 p-4" onsubmit={(e) => { e.preventDefault(); handleSubmit(); }}>
<textarea
- class="composer__input"
+ class="textarea textarea-bordered flex-1"
bind:value={text}
onkeydown={handleKeydown}
placeholder="Type a message..."
rows="3"
aria-label="Message input"
></textarea>
- <button class="composer__send" type="submit" disabled={text.trim().length === 0}>
+ <button class="btn btn-primary" type="submit" disabled={text.trim().length === 0}>
Send
</button>
</form>
diff --git a/src/features/chat/ui/ModelSelector.svelte b/src/features/chat/ui/ModelSelector.svelte
new file mode 100644
index 0000000..3e25ec3
--- /dev/null
+++ b/src/features/chat/ui/ModelSelector.svelte
@@ -0,0 +1,22 @@
+<script lang="ts">
+ let {
+ models,
+ selected,
+ onSelect,
+ }: {
+ models: readonly string[];
+ selected: string;
+ onSelect: (model: string) => void;
+ } = $props();
+</script>
+
+<select
+ class="select"
+ value={selected}
+ onchange={(e) => onSelect(e.currentTarget.value)}
+ aria-label="Model selector"
+>
+ {#each models as model (model)}
+ <option value={model}>{model}</option>
+ {/each}
+</select>