Skip to main content

ChatBox Component

The ChatBox component is an intelligent chat interface that connects to an AI backend, supports markdown rendering, and can provide context-aware responses about blog posts.

Overview

Located in src/components/ChatBox.tsx, this component provides:
  • AI-powered chat using OpenAI GPT-4o-mini
  • Markdown rendering with syntax highlighting
  • Blog context integration for post summaries
  • Fullscreen mode for extended conversations
  • Auto-scrolling message history
  • Clear chat functionality
  • Loading states and error handling

Props

isOpen
boolean
required
Controls the visibility of the chat interface. When false, the component returns null.
onClose
() => void
required
Callback function triggered when the close button is clicked.
isDarkMode
boolean
default:"true"
Controls the chat interface color scheme. The component is optimized for dark mode.
initialMessage
string
Message to send automatically when opening the chat. Used with blogContext to request summaries.
blogContext
BlogContext
Blog post data for context-aware responses. Includes title, excerpt, and content fields.

Type Definitions

The component uses these TypeScript interfaces:
interface Message {
  role: 'user' | 'assistant' | 'system';
  content: string;
}

interface BlogContext {
  title: string;
  excerpt: string;
  content: string;
}

interface ChatBoxProps {
  isOpen: boolean;
  onClose: () => void;
  isDarkMode?: boolean;
  initialMessage?: string;
  blogContext?: BlogContext;
}

Usage

import ChatBox from './components/ChatBox';

function App() {
  const [isChatOpen, setIsChatOpen] = useState(false);

  return (
    <ChatBox
      isOpen={isChatOpen}
      onClose={() => setIsChatOpen(false)}
      isDarkMode={true}
    />
  );
}

Features

AI Backend Integration

The component connects to a Netlify serverless function:
// From ChatBox.tsx:9-11
const API_URL = process.env.NODE_ENV === 'development' 
  ? '/.netlify/functions/chat'
  : 'https://ethanclinick.netlify.app/.netlify/functions/chat';
Requests are sent with these parameters:
// From ChatBox.tsx:114-126
body: JSON.stringify({
  messages: [
    {
      role: 'system',
      content: createSystemPromptWithBlogContext(activeContext)
    },
    ...messages,
    userMessage
  ],
  temperature: 0.7,
  top_p: 0.9,
  max_tokens: 4000,
  model: "gpt-4o-mini"
})

Markdown Rendering

Messages from the AI are rendered with full markdown support using react-markdown:
  • Headings: H1, H2, H3 with custom styling
  • Lists: Ordered and unordered with spacing
  • Code: Inline code and code blocks
  • Links: Auto-open in new tab with security
  • Blockquotes: With border styling
  • Strong/Bold: Enhanced visibility

Message Formatting

AI responses are automatically formatted for better readability:
// From ChatBox.tsx:14-31
const formatAIResponse = (text: string): string => {
  // Add double line breaks between sections
  text = text.replace(/\n(?=[A-Z])/g, '\n\n');
  
  // Add spacing after punctuation if missing
  text = text.replace(/([.!?])([A-Z])/g, '$1\n\n$2');
  
  // Ensure proper spacing around lists
  text = text.replace(/([.!?])\n([•\-*])/g, '$1\n\n$2');
  
  // Add spacing around code blocks
  text = text.replace(/```/g, '\n```\n');
  
  return text.trim();
};

Fullscreen Mode

Toggle between windowed and fullscreen layouts:
// From ChatBox.tsx:254-256
const toggleFullscreen = () => {
  setIsFullscreen(!isFullscreen);
};
Fullscreen mode is only available on desktop (hidden on mobile via hidden md:block).

Blog Context System

When a blog context is provided, the system prompt is enhanced:
// From ChatBox.tsx:73-91
const createSystemPromptWithBlogContext = (context?: BlogContext) => {
  const basePrompt = createEnhancedSystemPrompt();
  
  if (context) {
    return `${basePrompt}

You are also helping the user understand a blog post. Here is the blog context:

Blog Title: ${context.title}
Blog Excerpt: ${context.excerpt}

Blog Content:
${context.content}

When asked to summarize or discuss this blog, provide helpful insights...`;
  }
  
  return basePrompt;
};

State Management

Internal state tracked by the component:
// From ChatBox.tsx:34-40
const [messages, setMessages] = useState<Message[]>([]);
const [isLoading, setIsLoading] = useState(false);
const [error, setError] = useState<string | null>(null);
const [isFullscreen, setIsFullscreen] = useState(false);
const [currentBlogContext, setCurrentBlogContext] = useState<BlogContext | undefined>(undefined);
const messagesEndRef = useRef<HTMLDivElement>(null);
const hasProcessedInitialMessage = useRef<string | null>(null);

API Configuration

The component expects a serverless function at /.netlify/functions/chat that accepts OpenAI-compatible request format. Ensure your backend is configured with the OpenAI API key.

Styling

The ChatBox uses a dark, modern aesthetic:
  • Container: Fixed positioning with responsive sizing
  • Background: Pure black (bg-black) with glass borders
  • Messages: User messages in gray bubbles, AI messages as full-width text
  • Input: Custom AIInput component (see src/components/ui/ai-input.tsx)

Customization Tips

  1. Change AI model: Update the model parameter in ChatBox.tsx:125
  2. Adjust response length: Modify max_tokens in ChatBox.tsx:124
  3. Update greeting message: Edit the default message in ChatBox.tsx:54-56
  4. Customize markdown styles: Modify the ReactMarkdown components in ChatBox.tsx:181-233

Dependencies

{
  "react-markdown": "^8.x",
  "lucide-react": "^0.x"
}

Build docs developers (and LLMs) love