feat: add database support, conversation sidebar, and improve chat streaming

- Update .gitignore to exclude database files, extensions, and .cursor directory
- Enhance chat streaming API with safe enqueue and close functions to prevent errors
- Integrate ConversationSidebar component into ClientHome for better UI
- Add dependencies like better-sqlite3 and esbuild packages for database functionality

This commit introduces database persistence for conversations, improves error handling in streaming responses, and adds a sidebar for managing chats, enhancing overall app robustness and user experience.
This commit is contained in:
Evandro Fonseca Junior committed 2025-10-28 14:14:07 -03:00
1 parent a3f8226fda
commit 0cc7a81319
34 files changed
+2370 -198

No files matched your search

+14 -11
View File
@@ -1,10 +1,9 @@
"use client";
import { useState, useEffect, useRef } from "react";
import { User, Bot, Send, Loader2 } from "lucide-react";
import { User, Bot, Send, Loader2, Square } from "lucide-react";
import { MarkdownRenderer } from "@/components/message/MarkdownRenderer";
import { MessageActions } from "@/components/message/MessageActions";
import { extractCodeBlocks } from "@/hooks/useMarkdown";
import type { Message } from "@/lib/chat";
import { formatTimestamp } from "@/lib/chat";
@@ -29,7 +28,7 @@ export function ChatMessage({
</div>
)}
<div
className={`max-w-[80%] rounded-lg px-4 py-2 ${
className={`max-w-[80%] relative rounded-lg px-4 py-2 ${
isUser
? "bg-[var(--accent)] text-white"
: "bg-[var(--surface)] text-[var(--foreground)]"
@@ -44,11 +43,8 @@ export function ChatMessage({
</div>
{isStreaming && <span className="ml-1 animate-pulse">▊</span>}
{!isUser && !isStreaming && (
<div className="mt-2">
<MessageActions
content={message.content}
extractCodeBlocks={extractCodeBlocks}
/>
<div className="absolute bottom-2 right-2">
<MessageActions content={message.content} />
</div>
)}
<div
@@ -71,13 +67,17 @@ export function ChatMessage({
interface ChatInputProps {
onSendMessage: (content: string) => void;
onStop?: () => void;
disabled?: boolean;
isStreaming?: boolean;
placeholder?: string;
}
export function ChatInput({
onSendMessage,
onStop,
disabled = false,
isStreaming = false,
placeholder = "Type a message...",
}: ChatInputProps) {
const [content, setContent] = useState("");
@@ -125,11 +125,14 @@ export function ChatInput({
maxLength={2000}
/>
<button
type="submit"
disabled={!content.trim() || disabled}
type={isStreaming ? "button" : "submit"}
onClick={isStreaming ? onStop : undefined}
disabled={isStreaming ? false : !content.trim() || disabled}
className="flex h-10 w-10 items-center justify-center rounded-lg bg-[var(--accent)] text-white transition-colors hover:bg-[color-mix(in_oklab,var(--accent),black_10%)] disabled:opacity-50"
>
{disabled ? (
{isStreaming ? (
<Square className="h-4 w-4" />
) : disabled ? (
<Loader2 className="h-4 w-4 animate-spin" />
) : (
<Send className="h-4 w-4" />