feat(web): chat UI with conversations and WebSocket streaming (#84)

Co-authored-by: Jason Woltje <jason@diversecanvas.com>
Co-committed-by: Jason Woltje <jason@diversecanvas.com>
This commit was merged in pull request #84.
This commit is contained in:
2026-03-13 13:25:28 +00:00
committed by jason.woltje
parent 600da70960
commit f0d1d4bafa
10 changed files with 381 additions and 5 deletions

View File

@@ -0,0 +1,57 @@
'use client';
import { cn } from '@/lib/cn';
import type { Conversation } from '@/lib/types';
interface ConversationListProps {
conversations: Conversation[];
activeId: string | null;
onSelect: (id: string) => void;
onNew: () => void;
}
export function ConversationList({
conversations,
activeId,
onSelect,
onNew,
}: ConversationListProps): React.ReactElement {
return (
<div className="flex h-full w-64 flex-col border-r border-surface-border bg-surface-card">
<div className="flex items-center justify-between p-3">
<h2 className="text-sm font-medium text-text-secondary">Conversations</h2>
<button
type="button"
onClick={onNew}
className="rounded-md px-2 py-1 text-xs text-blue-400 transition-colors hover:bg-surface-elevated"
>
+ New
</button>
</div>
<div className="flex-1 overflow-y-auto">
{conversations.length === 0 && (
<p className="px-3 py-2 text-xs text-text-muted">No conversations yet</p>
)}
{conversations.map((conv) => (
<button
key={conv.id}
type="button"
onClick={() => onSelect(conv.id)}
className={cn(
'w-full px-3 py-2 text-left text-sm transition-colors',
activeId === conv.id
? 'bg-blue-600/20 text-blue-400'
: 'text-text-secondary hover:bg-surface-elevated',
)}
>
<span className="block truncate">{conv.title ?? 'Untitled'}</span>
<span className="block text-xs text-text-muted">
{new Date(conv.updatedAt).toLocaleDateString()}
</span>
</button>
))}
</div>
</div>
);
}