<script lang="ts">
import { appStore } from '$lib/store.svelte.js';
import MessageBubble from './MessageBubble.svelte';
import StreamingMessage from './StreamingMessage.svelte';
import ToolCallBlock from './ToolCallBlock.svelte';
let messagesEl: HTMLDivElement | undefined = $state();
$effect(() => {
if (messagesEl && (appStore.messages.length || appStore.streamingTokens)) {
messagesEl.scrollTop = messagesEl.scrollHeight;
}
});
</script>
<div class="chat-area" bind:this={messagesEl} role="log" aria-label="Chat messages" aria-live="polite">
<div class="chat-inner">
{#each appStore.messages as msg (msg)}
<MessageBubble role={msg.role} content={msg.content} />
{/each}
<StreamingMessage />
<ToolCallBlock />
{#if appStore.error}
<div class="error-banner" role="alert">
<span class="error-icon">!</span>
<span>{appStore.error}</span>
</div>
{/if}
{#if appStore.hiveAgents.size > 0}
<div class="hive-panel">
<div class="hive-header">Hive Agents</div>
{#each [...appStore.hiveAgents.values()] as agent (agent.id)}
<div class="hive-agent" class:done={agent.done} class:success={agent.success}>
<span class="agent-status">{agent.done ? (agent.success ? '✓' : '✗') : '⟳'}</span>
<span class="agent-name">{agent.name}</span>
<span class="agent-task">{agent.task}</span>
{#if !agent.done}
<span class="agent-iter">#{agent.iteration}</span>
{/if}
</div>
{/each}
</div>
{/if}
</div>
</div>
<style>
.chat-area {
flex: 1;
overflow-y: auto;
scrollbar-width: thin;
scrollbar-color: var(--border) transparent;
}
.chat-inner {
max-width: 800px;
margin: 0 auto;
padding: 1.5rem 1rem;
display: flex;
flex-direction: column;
gap: 0.75rem;
}
.error-banner {
display: flex;
align-items: center;
gap: 0.5rem;
padding: 0.75rem 1rem;
background: color-mix(in srgb, var(--red) 12%, transparent);
border: 1px solid color-mix(in srgb, var(--red) 30%, transparent);
border-radius: var(--radius, 8px);
color: var(--red);
font-size: 0.875rem;
}
.error-icon { font-weight: bold; flex-shrink: 0; }
.hive-panel {
border: 1px solid var(--border);
border-radius: var(--radius, 8px);
padding: 0.75rem 1rem;
background: var(--bg-surface);
font-size: 0.875rem;
}
.hive-header {
color: var(--cyan);
margin-bottom: 0.375rem;
text-transform: uppercase;
letter-spacing: 0.05em;
font-size: 0.75rem;
}
.hive-agent {
display: flex;
gap: 0.5rem;
padding: 0.2rem 0;
color: var(--fg-dim);
}
.hive-agent.done.success { color: var(--green); }
.hive-agent.done:not(.success) { color: var(--red); }
.agent-status { flex-shrink: 0; width: 1.25ch; }
.agent-name { color: var(--fg); flex-shrink: 0; }
.agent-task { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.agent-iter { margin-left: auto; color: var(--fg-dim); flex-shrink: 0; }
@media (max-width: 768px) {
.chat-inner { padding: 1rem 0.75rem; }
}
</style>