203 lines
7.4 KiB
TypeScript
203 lines
7.4 KiB
TypeScript
"use client";
|
|
|
|
import React from 'react';
|
|
import { Send, Sparkles, Code, MessageSquare, TestTube, RefreshCw, Lock, Search } from 'lucide-react';
|
|
import { ScrollArea } from '@/components/ui/scroll-area';
|
|
import { Button } from '@/components/ui/button';
|
|
import { Textarea } from '@/components/ui/textarea';
|
|
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
|
|
|
|
interface Message {
|
|
id: string;
|
|
role: 'user' | 'assistant';
|
|
content: string;
|
|
code?: {
|
|
language: string;
|
|
code: string;
|
|
};
|
|
}
|
|
|
|
export function AIAssistant() {
|
|
const [messages, setMessages] = React.useState<Message[]>([
|
|
{
|
|
id: '1',
|
|
role: 'assistant',
|
|
content: 'Hello! I\'m your AeThex AI Assistant. I can help you with cross-platform development, Nexus Engine integration, Passport authentication, and more. How can I help you today?',
|
|
},
|
|
]);
|
|
const [input, setInput] = React.useState('');
|
|
const [model, setModel] = React.useState('gemini-pro');
|
|
const scrollRef = React.useRef<HTMLDivElement>(null);
|
|
|
|
const quickActions = [
|
|
{ icon: <Search className="w-4 h-4" />, label: 'Explain Code', color: 'bg-blue-500/10 text-blue-400' },
|
|
{ icon: <MessageSquare className="w-4 h-4" />, label: 'Add Comments', color: 'bg-purple-500/10 text-purple-400' },
|
|
{ icon: <TestTube className="w-4 h-4" />, label: 'Generate Tests', color: 'bg-green-500/10 text-green-400' },
|
|
{ icon: <RefreshCw className="w-4 h-4" />, label: 'Cross-Platform Convert', color: 'bg-cyan-500/10 text-cyan-400' },
|
|
{ icon: <Lock className="w-4 h-4" />, label: 'Add Nexus Sync', color: 'bg-orange-500/10 text-orange-400' },
|
|
{ icon: <Lock className="w-4 h-4" />, label: 'Setup Passport Auth', color: 'bg-pink-500/10 text-pink-400' },
|
|
];
|
|
|
|
const prebuiltPrompts = [
|
|
"Set up cross-platform player movement",
|
|
"Add Nexus Engine state sync for [variable]",
|
|
"Create Passport login flow",
|
|
"Generate GameForge anti-cheat rules",
|
|
"Build multiplayer matchmaking system",
|
|
];
|
|
|
|
const sendMessage = () => {
|
|
if (!input.trim()) return;
|
|
|
|
const userMessage: Message = {
|
|
id: Date.now().toString(),
|
|
role: 'user',
|
|
content: input,
|
|
};
|
|
|
|
setMessages(prev => [...prev, userMessage]);
|
|
setInput('');
|
|
|
|
// Simulate AI response
|
|
setTimeout(() => {
|
|
const aiMessage: Message = {
|
|
id: (Date.now() + 1).toString(),
|
|
role: 'assistant',
|
|
content: 'I can help you with that! Here\'s a code example:',
|
|
code: {
|
|
language: 'typescript',
|
|
code: `// Example cross-platform code\nexport class PlayerController {\n move(x: number, y: number) {\n // Update position\n nexusEngine.setState('playerX', x);\n nexusEngine.setState('playerY', y);\n }\n}`,
|
|
},
|
|
};
|
|
setMessages(prev => [...prev, aiMessage]);
|
|
}, 1000);
|
|
};
|
|
|
|
React.useEffect(() => {
|
|
if (scrollRef.current) {
|
|
scrollRef.current.scrollTop = scrollRef.current.scrollHeight;
|
|
}
|
|
}, [messages]);
|
|
|
|
return (
|
|
<div className="h-full flex flex-col bg-gray-900">
|
|
{/* Header */}
|
|
<div className="flex items-center justify-between px-4 py-3 border-b border-gray-800">
|
|
<div className="flex items-center gap-2">
|
|
<Sparkles className="w-5 h-5 text-primary" />
|
|
<span className="font-semibold text-white">AI Assistant</span>
|
|
</div>
|
|
<Select value={model} onValueChange={setModel}>
|
|
<SelectTrigger className="w-32 h-8 text-xs border-gray-700 bg-surface">
|
|
<SelectValue />
|
|
</SelectTrigger>
|
|
<SelectContent className="bg-surface border-gray-700">
|
|
<SelectItem value="gemini-pro">Gemini Pro</SelectItem>
|
|
<SelectItem value="claude-3">Claude 3</SelectItem>
|
|
<SelectItem value="gpt-4">GPT-4</SelectItem>
|
|
</SelectContent>
|
|
</Select>
|
|
</div>
|
|
|
|
{/* Quick Actions */}
|
|
<div className="p-3 border-b border-gray-800">
|
|
<div className="grid grid-cols-2 gap-2">
|
|
{quickActions.map((action, i) => (
|
|
<button
|
|
key={i}
|
|
className={`flex items-center gap-2 px-3 py-2 rounded-lg text-xs font-medium transition-colors ${action.color} hover:opacity-80`}
|
|
>
|
|
{action.icon}
|
|
{action.label}
|
|
</button>
|
|
))}
|
|
</div>
|
|
</div>
|
|
|
|
{/* Messages */}
|
|
<ScrollArea ref={scrollRef} className="flex-1 p-4">
|
|
<div className="space-y-4">
|
|
{messages.map((message) => (
|
|
<div
|
|
key={message.id}
|
|
className={`flex ${message.role === 'user' ? 'justify-end' : 'justify-start'}`}
|
|
>
|
|
<div
|
|
className={`max-w-[85%] rounded-lg px-4 py-2 ${
|
|
message.role === 'user'
|
|
? 'bg-blue-600 text-white'
|
|
: 'bg-primary/20 text-white'
|
|
}`}
|
|
>
|
|
<p className="text-sm whitespace-pre-wrap">{message.content}</p>
|
|
{message.code && (
|
|
<div className="mt-2 bg-background rounded-lg p-3 font-mono text-xs">
|
|
<div className="flex items-center justify-between mb-2">
|
|
<span className="text-gray-400">{message.code.language}</span>
|
|
<div className="flex gap-2">
|
|
<button className="text-xs text-primary hover:text-primary-light">
|
|
Copy
|
|
</button>
|
|
<button className="text-xs text-green-400 hover:text-green-300">
|
|
Insert into editor
|
|
</button>
|
|
</div>
|
|
</div>
|
|
<pre className="text-gray-200">{message.code.code}</pre>
|
|
</div>
|
|
)}
|
|
</div>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</ScrollArea>
|
|
|
|
{/* Prebuilt Prompts */}
|
|
<div className="px-3 py-2 border-t border-gray-800">
|
|
<ScrollArea className="max-h-20">
|
|
<div className="flex flex-wrap gap-1">
|
|
{prebuiltPrompts.map((prompt, i) => (
|
|
<button
|
|
key={i}
|
|
onClick={() => setInput(prompt)}
|
|
className="text-xs px-2 py-1 bg-surface hover:bg-surface/70 rounded text-gray-300 transition-colors whitespace-nowrap"
|
|
>
|
|
{prompt}
|
|
</button>
|
|
))}
|
|
</div>
|
|
</ScrollArea>
|
|
</div>
|
|
|
|
{/* Input */}
|
|
<div className="p-3 border-t border-gray-800">
|
|
<div className="flex gap-2">
|
|
<Textarea
|
|
value={input}
|
|
onChange={(e) => setInput(e.target.value)}
|
|
onKeyDown={(e) => {
|
|
if (e.key === 'Enter' && !e.shiftKey) {
|
|
e.preventDefault();
|
|
sendMessage();
|
|
}
|
|
}}
|
|
placeholder="Ask anything..."
|
|
className="resize-none bg-surface border-gray-700 text-white placeholder:text-gray-500"
|
|
rows={2}
|
|
/>
|
|
<Button
|
|
onClick={sendMessage}
|
|
disabled={!input.trim()}
|
|
className="px-4 bg-primary hover:bg-primary-light"
|
|
>
|
|
<Send className="w-4 h-4" />
|
|
</Button>
|
|
</div>
|
|
<div className="mt-2 flex items-center justify-between text-xs text-gray-400">
|
|
<span>Press Enter to send, Shift+Enter for new line</span>
|
|
<span>450K / 500K tokens used</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|