2025-06-28 19:30:35 -03:00
|
|
|
"use client";
|
2025-06-29 20:33:05 -03:00
|
|
|
|
|
|
|
import React, { useState, useEffect } from 'react';
|
2025-06-29 21:33:12 -03:00
|
|
|
import { MessageCircle, Send, X, Minimize2, Maximize2, Monitor, Terminal, Cpu, HardDrive, ChevronUp, ChevronDown } from 'lucide-react';
|
2025-06-28 22:36:36 -03:00
|
|
|
import {
|
2025-06-29 20:33:05 -03:00
|
|
|
ResizableHandle,
|
|
|
|
ResizablePanel,
|
|
|
|
ResizablePanelGroup,
|
|
|
|
} from "@/components/ui/resizable";
|
2025-06-28 19:30:35 -03:00
|
|
|
|
2025-06-29 20:33:05 -03:00
|
|
|
const Footer = ({ className = "", shortcuts }) => {
|
|
|
|
const [messages, setMessages] = useState([]);
|
|
|
|
const [inputValue, setInputValue] = useState('');
|
|
|
|
const [isMobile, setIsMobile] = useState(false);
|
|
|
|
const [currentTime, setCurrentTime] = useState(new Date());
|
2025-06-29 21:33:12 -03:00
|
|
|
const [isMaximized, setIsMaximized] = useState(false);
|
|
|
|
const [isMinimized, setIsMinimized] = useState(false);
|
2025-06-28 19:30:35 -03:00
|
|
|
|
2025-06-29 20:33:05 -03:00
|
|
|
useEffect(() => {
|
|
|
|
const checkMobile = () => {
|
|
|
|
setIsMobile(window.innerWidth < 768);
|
|
|
|
};
|
|
|
|
checkMobile();
|
|
|
|
window.addEventListener('resize', checkMobile);
|
2025-06-28 22:36:36 -03:00
|
|
|
|
2025-06-29 20:33:05 -03:00
|
|
|
const timer = setInterval(() => {
|
|
|
|
setCurrentTime(new Date());
|
|
|
|
}, 1000);
|
2025-06-28 22:36:36 -03:00
|
|
|
|
2025-06-29 20:33:05 -03:00
|
|
|
return () => {
|
|
|
|
window.removeEventListener('resize', checkMobile);
|
|
|
|
clearInterval(timer);
|
|
|
|
};
|
|
|
|
}, []);
|
2025-06-28 22:36:36 -03:00
|
|
|
|
2025-06-29 20:33:05 -03:00
|
|
|
const defaultShortcuts = [
|
|
|
|
[
|
|
|
|
{ key: "F1", label: "Help", action: () => addSystemMessage("F1: Help system activated") },
|
|
|
|
{ key: "F2", label: "Save", action: () => addSystemMessage("F2: Save operation") },
|
|
|
|
{ key: "F3", label: "Search", action: () => addSystemMessage("F3: Search mode") },
|
|
|
|
{ key: "F4", label: "Edit", action: () => addSystemMessage("F4: Edit mode") },
|
|
|
|
{ key: "F5", label: "Refresh", action: () => addSystemMessage("F5: System refresh") },
|
|
|
|
{ key: "F6", label: "Copy", action: () => addSystemMessage("F6: Copy operation") },
|
|
|
|
{ key: "F7", label: "use client", action: () => addSystemMessage("F7: use client operation") },
|
|
|
|
{ key: "F8", label: "Delete", action: () => addSystemMessage("F8: Delete operation") },
|
|
|
|
{ key: "F9", label: "Menu", action: () => addSystemMessage("F9: Menu opened") },
|
|
|
|
{ key: "F10", label: "Exit", action: () => addSystemMessage("F10: Exit requested") },
|
|
|
|
],
|
|
|
|
[
|
|
|
|
{ key: "Ctrl+N", label: "New", action: () => addSystemMessage("New file created") },
|
|
|
|
{ key: "Ctrl+O", label: "Open", action: () => addSystemMessage("Open file dialog") },
|
|
|
|
{ key: "Ctrl+S", label: "Save", action: () => addSystemMessage("File saved") },
|
|
|
|
{ key: "Ctrl+P", label: "Print", action: () => addSystemMessage("Print dialog") },
|
|
|
|
{ key: "Ctrl+X", label: "Cut", action: () => addSystemMessage("Cut to clipboard") },
|
|
|
|
{ key: "Ctrl+C", label: "Copy", action: () => addSystemMessage("Copied to clipboard") },
|
|
|
|
{ key: "Ctrl+V", label: "Paste", action: () => addSystemMessage("Pasted from clipboard") },
|
|
|
|
{ key: "Ctrl+Z", label: "Undo", action: () => addSystemMessage("Undo last action") },
|
|
|
|
{ key: "Ctrl+Y", label: "Redo", action: () => addSystemMessage("Redo last action") },
|
|
|
|
{ key: "Ctrl+A", label: "Select", action: () => addSystemMessage("Select all") },
|
|
|
|
]
|
|
|
|
];
|
|
|
|
|
|
|
|
const shortcutGroups = shortcuts || defaultShortcuts;
|
|
|
|
|
|
|
|
const addSystemMessage = (text) => {
|
|
|
|
setMessages(prev => [...prev, { text, sender: 'system', timestamp: new Date() }]);
|
|
|
|
};
|
|
|
|
|
|
|
|
const handleSendMessage = () => {
|
|
|
|
if (inputValue.trim() !== '') {
|
|
|
|
const userMessage = { text: inputValue, sender: 'user', timestamp: new Date() };
|
|
|
|
setMessages(prev => [...prev, userMessage]);
|
|
|
|
setInputValue('');
|
|
|
|
setTimeout(() => {
|
|
|
|
const responses = [
|
|
|
|
"SYSTEM: Command processed successfully",
|
|
|
|
"ASSISTANT: Processing your request...",
|
|
|
|
"BOT: I understand your query. How can I assist further?",
|
|
|
|
"SYSTEM: Operation completed. Status: OK",
|
|
|
|
"ASSISTANT: Ready for next command",
|
|
|
|
];
|
|
|
|
const randomResponse = responses[Math.floor(Math.random() * responses.length)];
|
|
|
|
setMessages(prev => [...prev, { text: randomResponse, sender: 'bot', timestamp: new Date() }]);
|
|
|
|
}, 800);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
const handleKeyPress = (e) => {
|
|
|
|
if (e.key === 'Enter') {
|
|
|
|
handleSendMessage();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2025-06-29 21:33:12 -03:00
|
|
|
const toggleMaximize = () => {
|
|
|
|
if (isMinimized) {
|
|
|
|
setIsMinimized(false);
|
|
|
|
}
|
|
|
|
setIsMaximized(!isMaximized);
|
|
|
|
};
|
|
|
|
|
|
|
|
const toggleMinimize = () => {
|
|
|
|
setIsMinimized(!isMinimized);
|
|
|
|
if (isMaximized) {
|
|
|
|
setIsMaximized(false);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2025-06-29 20:33:05 -03:00
|
|
|
const formatTime = (date) => {
|
|
|
|
return date.toLocaleTimeString('en-US', {
|
|
|
|
hour12: false,
|
|
|
|
hour: '2-digit',
|
|
|
|
minute: '2-digit',
|
|
|
|
second: '2-digit'
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
|
|
|
const formatShortcutKey = (key) => {
|
|
|
|
const parts = key.split(/(\+)/);
|
|
|
|
return parts.map((part, index) => {
|
|
|
|
if (part === '+') {
|
|
|
|
return part;
|
|
|
|
}
|
|
|
|
return <span key={index} className="text-primary">{part}</span>;
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
2025-06-29 21:33:12 -03:00
|
|
|
const getContainerHeight = () => {
|
|
|
|
if (isMinimized) return 'h-4';
|
|
|
|
if (isMaximized) return 'h-screen fixed inset-0 z-50 bg-background';
|
2025-06-30 08:56:32 -03:00
|
|
|
return isMobile ? 'h-64' : 'h-40';
|
2025-06-29 21:33:12 -03:00
|
|
|
};
|
|
|
|
|
|
|
|
const scrollbarStyles = `
|
|
|
|
/* Webkit browsers */
|
|
|
|
::-webkit-scrollbar {
|
|
|
|
width: 8px;
|
|
|
|
height: 8px;
|
|
|
|
}
|
|
|
|
|
|
|
|
::-webkit-scrollbar-track {
|
|
|
|
background: rgba(0, 0, 0, 0.1);
|
|
|
|
border-radius: 4px;
|
|
|
|
}
|
|
|
|
|
|
|
|
::-webkit-scrollbar-thumb {
|
|
|
|
background: rgba(128, 128, 128, 0.3);
|
|
|
|
border-radius: 4px;
|
|
|
|
border: 1px solid rgba(255, 255, 255, 0.1);
|
|
|
|
}
|
|
|
|
|
|
|
|
::-webkit-scrollbar-thumb:hover {
|
|
|
|
background: rgba(128, 128, 128, 0.5);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Firefox */
|
|
|
|
* {
|
|
|
|
scrollbar-width: thin;
|
|
|
|
scrollbar-color: rgba(128, 128, 128, 0.3) rgba(0, 0, 0, 0.1);
|
|
|
|
}
|
|
|
|
`;
|
|
|
|
|
2025-06-29 20:33:05 -03:00
|
|
|
if (isMobile) {
|
|
|
|
return (
|
2025-06-29 21:33:12 -03:00
|
|
|
<>
|
|
|
|
<style dangerouslySetInnerHTML={{ __html: scrollbarStyles }} />
|
|
|
|
<div className={`${getContainerHeight()} bg-gradient-to-br from-background via-background to-muted/20 border-t border-border shadow-2xl ${className}`}>
|
|
|
|
{isMinimized ? (
|
|
|
|
<div className="h-full flex items-center justify-between px-2 bg-gradient-to-r from-muted/50 to-secondary/50 border-b border-border backdrop-blur-sm cursor-pointer" onClick={toggleMinimize}>
|
|
|
|
<div className="flex items-center gap-2">
|
|
|
|
<div className="w-2 h-2 bg-gradient-to-br from-green-400 to-emerald-500 rounded-full animate-pulse shadow-lg" />
|
|
|
|
<span className="text-xs font-mono text-foreground font-medium">TERMINAL</span>
|
2025-06-29 20:33:05 -03:00
|
|
|
</div>
|
2025-06-29 21:33:12 -03:00
|
|
|
<div className="text-xs text-muted-foreground font-mono bg-secondary/50 px-1.5 py-0.5 rounded-full">
|
|
|
|
{formatTime(currentTime)}
|
2025-06-29 20:33:05 -03:00
|
|
|
</div>
|
|
|
|
</div>
|
2025-06-29 21:33:12 -03:00
|
|
|
) : (
|
|
|
|
<ResizablePanelGroup direction="vertical" className="h-full">
|
|
|
|
<ResizablePanel defaultSize={40} minSize={30}>
|
|
|
|
<div className="h-full flex flex-col bg-gradient-to-br from-card via-card to-secondary/20 border-b border-border/50 shadow-inner">
|
|
|
|
<div className="flex items-center justify-between p-1.5 bg-gradient-to-r from-muted/80 to-secondary/80 border-b border-border/50 backdrop-blur-sm cursor-pointer" onClick={toggleMaximize}>
|
|
|
|
<div className="flex items-center gap-2">
|
|
|
|
<div className="p-1 bg-primary/10 rounded border border-primary/20">
|
|
|
|
<Terminal className="w-3 h-3 text-primary" />
|
2025-06-29 20:33:05 -03:00
|
|
|
</div>
|
2025-06-29 21:33:12 -03:00
|
|
|
<span className="text-xs font-mono text-foreground font-medium">MOBILE TERMINAL</span>
|
|
|
|
</div>
|
|
|
|
<div className="flex items-center gap-2">
|
|
|
|
<div className="text-xs text-muted-foreground font-mono bg-background/50 px-1.5 py-0.5 rounded-full border border-border/50">
|
|
|
|
{formatTime(currentTime)}
|
2025-06-29 20:33:05 -03:00
|
|
|
</div>
|
2025-06-29 21:33:12 -03:00
|
|
|
<div className="w-2 h-2 bg-gradient-to-br from-green-400 to-emerald-500 rounded-full animate-pulse shadow-lg" />
|
2025-06-29 20:33:05 -03:00
|
|
|
</div>
|
2025-06-29 21:33:12 -03:00
|
|
|
</div>
|
|
|
|
<div className="flex-1 p-2">
|
|
|
|
<div className="flex items-center gap-1 bg-gradient-to-r from-background to-background/80 border border-input/50 rounded shadow-inner backdrop-blur-sm">
|
|
|
|
<span className="text-primary text-xs font-mono pl-2 font-bold">></span>
|
|
|
|
<input
|
|
|
|
placeholder="Enter command..."
|
|
|
|
className="flex-1 bg-transparent text-foreground placeholder:text-muted-foreground border-0 outline-none py-2 pr-2 text-xs font-mono"
|
|
|
|
value={inputValue}
|
|
|
|
onChange={(e) => setInputValue(e.target.value)}
|
|
|
|
onKeyPress={handleKeyPress}
|
|
|
|
/>
|
|
|
|
<button
|
|
|
|
onClick={handleSendMessage}
|
|
|
|
className="bg-gradient-to-r from-primary to-primary/90 text-primary-foreground hover:from-primary/90 hover:to-primary/80 rounded-r px-3 py-2 text-xs font-mono transition-all duration-200 flex items-center gap-1 shadow-lg hover:shadow-xl transform hover:scale-105"
|
|
|
|
>
|
|
|
|
<Send className="w-3 h-3" />
|
|
|
|
</button>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</ResizablePanel>
|
|
|
|
<ResizableHandle className="bg-gradient-to-r from-border to-primary/20 hover:from-primary/30 hover:to-primary/40 transition-all duration-200" />
|
|
|
|
<ResizablePanel defaultSize={60} minSize={40}>
|
|
|
|
<div className="h-full flex flex-col bg-gradient-to-br from-card via-card to-accent/10">
|
|
|
|
<div className="flex items-center justify-between p-1.5 bg-gradient-to-r from-muted/80 to-secondary/80 border-b border-border/50 backdrop-blur-sm cursor-pointer" onClick={toggleMinimize}>
|
|
|
|
<div className="flex items-center gap-2">
|
|
|
|
<div className="p-1 bg-primary/10 rounded border border-primary/20">
|
|
|
|
<Monitor className="w-3 h-3 text-primary" />
|
|
|
|
</div>
|
|
|
|
<span className="text-xs font-mono text-foreground font-medium">OUTPUT</span>
|
|
|
|
</div>
|
|
|
|
<div className="flex items-center gap-1">
|
|
|
|
<div className="w-2 h-2 bg-gradient-to-br from-green-400 to-emerald-500 rounded-full animate-pulse shadow-lg" />
|
|
|
|
<span className="text-xs text-muted-foreground font-mono bg-background/50 px-1.5 py-0.5 rounded-full border border-border/50">READY</span>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<div className="flex-1 p-2 overflow-y-auto bg-gradient-to-br from-background/50 to-secondary/20 font-mono text-xs backdrop-blur-sm">
|
|
|
|
{messages.length === 0 ? (
|
|
|
|
<div className="text-muted-foreground text-center py-8">
|
|
|
|
<div className="animate-pulse text-primary text-sm font-bold mb-1">● SYSTEM READY ●</div>
|
|
|
|
<div className="mt-1 text-xs bg-secondary/30 px-2 py-0.5 rounded-full inline-block">Awaiting input...</div>
|
|
|
|
</div>
|
|
|
|
) : (
|
|
|
|
messages.map((message, index) => (
|
|
|
|
<div key={index} className="mb-2 group">
|
|
|
|
<div className="text-xs text-muted-foreground mb-1 bg-secondary/20 px-1.5 py-0.5 rounded-t">
|
|
|
|
[{formatTime(message.timestamp)}] {message.sender.toUpperCase()}:
|
|
|
|
</div>
|
|
|
|
<div className={`p-2 rounded-b rounded-tr shadow-sm transition-all duration-200 group-hover:shadow-md border ${message.sender === 'user'
|
|
|
|
? 'bg-gradient-to-r from-primary/10 to-primary/5 border-primary/30 text-foreground'
|
|
|
|
: message.sender === 'system'
|
|
|
|
? 'bg-gradient-to-r from-accent/50 to-accent/30 border-accent/50 text-accent-foreground'
|
|
|
|
: 'bg-gradient-to-r from-secondary/50 to-secondary/30 border-secondary/50 text-secondary-foreground'
|
|
|
|
}`}>
|
|
|
|
{message.text}
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
))
|
|
|
|
)}
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</ResizablePanel>
|
|
|
|
</ResizablePanelGroup>
|
|
|
|
)}
|
|
|
|
</div>
|
|
|
|
</>
|
2025-06-29 20:33:05 -03:00
|
|
|
);
|
|
|
|
}
|
2025-06-28 19:30:35 -03:00
|
|
|
|
2025-06-29 20:33:05 -03:00
|
|
|
return (
|
2025-06-29 21:33:12 -03:00
|
|
|
<>
|
|
|
|
<style dangerouslySetInnerHTML={{ __html: scrollbarStyles }} />
|
|
|
|
<div className={`${getContainerHeight()} bg-gradient-to-br from-background via-background to-muted/20 border-t border-border shadow-2xl ${className}`}>
|
|
|
|
{isMinimized ? (
|
|
|
|
<div className="h-full flex items-center justify-between px-3 bg-gradient-to-r from-muted/50 to-secondary/50 border-b border-border backdrop-blur-sm cursor-pointer" onClick={toggleMinimize}>
|
|
|
|
<div className="flex items-center gap-3">
|
|
|
|
<div className="flex items-center gap-1.5">
|
|
|
|
<div className="w-2 h-2 bg-gradient-to-br from-green-400 to-emerald-500 rounded-full animate-pulse shadow-lg" />
|
|
|
|
<span className="text-xs font-mono text-foreground font-medium">TERMINAL READY</span>
|
2025-06-29 20:33:05 -03:00
|
|
|
</div>
|
2025-06-29 21:33:12 -03:00
|
|
|
<div className="text-xs text-muted-foreground font-mono bg-secondary/50 px-1.5 py-0.5 rounded-full">
|
|
|
|
MSG: {messages.length}
|
2025-06-28 19:30:35 -03:00
|
|
|
</div>
|
2025-06-29 20:33:05 -03:00
|
|
|
</div>
|
2025-06-29 21:33:12 -03:00
|
|
|
<div className="text-xs text-muted-foreground font-mono bg-secondary/50 px-1.5 py-0.5 rounded-full">
|
|
|
|
{formatTime(currentTime)}
|
2025-06-29 20:33:05 -03:00
|
|
|
</div>
|
|
|
|
</div>
|
2025-06-29 21:33:12 -03:00
|
|
|
) : (
|
|
|
|
<ResizablePanelGroup direction="horizontal" className="h-full">
|
|
|
|
<ResizablePanel defaultSize={30} minSize={20} maxSize={50}>
|
|
|
|
<div className="h-full flex flex-col bg-gradient-to-br from-card via-card to-secondary/20 shadow-inner">
|
|
|
|
<div className="flex items-center justify-between px-3 py-1 bg-gradient-to-r from-muted/80 to-secondary/80 border-b border-border/50 backdrop-blur-sm cursor-pointer" onClick={toggleMaximize}>
|
|
|
|
<div className="flex items-center gap-2">
|
|
|
|
<div className="p-0.5 bg-primary/10 rounded border border-primary/20">
|
|
|
|
<Cpu className="w-3 h-3 text-primary" />
|
|
|
|
</div>
|
|
|
|
<span className="text-xs font-mono text-foreground font-medium">STATUS</span>
|
|
|
|
</div>
|
|
|
|
<div className="flex items-center gap-2">
|
|
|
|
<div className="flex items-center gap-1 text-xs font-mono text-muted-foreground">
|
|
|
|
<span className="inline-flex items-center gap-0.5">
|
|
|
|
<span className="relative w-1.5 h-1.5 rounded-sm bg-gradient-to-br from-yellow-400 to-orange-500 border border-yellow-600 inline-block shadow-sm">
|
|
|
|
<span className="absolute -top-0.5 -right-0.5 w-1.5 h-1.5 rounded-full bg-primary animate-pulse border border-background shadow-md" />
|
|
|
|
</span>
|
|
|
|
<span className="text-xs">Inbox</span>
|
|
|
|
</span>
|
|
|
|
<span className="mx-0.5 text-border">|</span>
|
|
|
|
<span className="inline-flex items-center gap-0.5">
|
|
|
|
<span className="w-1.5 h-1.5 rounded-sm bg-gradient-to-br from-green-400 to-emerald-500 border border-green-600 inline-block shadow-sm" />
|
|
|
|
<span className="text-xs">Tasks</span>
|
|
|
|
</span>
|
|
|
|
<span className="mx-0.5 text-border">|</span>
|
|
|
|
<span className="inline-flex items-center gap-0.5">
|
|
|
|
<span className="w-1.5 h-1.5 rounded-sm bg-gradient-to-br from-red-400 to-rose-500 border border-red-600 inline-block shadow-sm" />
|
|
|
|
<span className="text-xs">Meet</span>
|
|
|
|
</span>
|
|
|
|
<span className="mx-0.5 text-border">|</span>
|
|
|
|
<span className="inline-flex items-center gap-0.5">
|
|
|
|
<span className="w-1.5 h-1.5 rounded-sm bg-gradient-to-br from-blue-400 to-cyan-500 border border-blue-600 inline-block shadow-sm" />
|
|
|
|
<span className="text-xs">Chat</span>
|
|
|
|
</span>
|
|
|
|
</div>
|
|
|
|
</div>
|
2025-06-29 20:33:05 -03:00
|
|
|
</div>
|
2025-06-29 21:33:12 -03:00
|
|
|
<div className="flex-1 flex items-center px-2 py-0.5 border-b border-border/50 bg-gradient-to-r from-secondary/20 to-accent/10">
|
|
|
|
<div className="flex items-center gap-0.5 overflow-x-auto w-full">
|
|
|
|
{shortcutGroups[0].map((shortcut, index) => (
|
|
|
|
<button
|
|
|
|
key={index}
|
|
|
|
className="flex items-center text-xs cursor-pointer hover:bg-gradient-to-r hover:from-accent/50 hover:to-primary/20 hover:text-accent-foreground px-1.5 py-1 rounded transition-all duration-200 min-w-fit border border-border/50 hover:border-primary/50 bg-gradient-to-r from-background/80 to-background/60 backdrop-blur-sm shadow-sm hover:shadow-md transform hover:scale-105"
|
|
|
|
onClick={shortcut.action}
|
|
|
|
>
|
|
|
|
<span className="font-bold text-primary mr-1">{formatShortcutKey(shortcut.key)}</span>
|
|
|
|
<span className="text-muted-foreground">{shortcut.label}</span>
|
|
|
|
</button>
|
|
|
|
))}
|
2025-06-29 20:33:05 -03:00
|
|
|
</div>
|
|
|
|
</div>
|
2025-06-29 21:33:12 -03:00
|
|
|
<div className="flex-1 flex items-center px-2 py-0.5 bg-gradient-to-r from-secondary/20 to-accent/10">
|
|
|
|
<div className="flex items-center gap-0.5 overflow-x-auto w-full">
|
|
|
|
{shortcutGroups[1].map((shortcut, index) => (
|
|
|
|
<button
|
|
|
|
key={index}
|
|
|
|
className="flex items-center text-xs cursor-pointer hover:bg-gradient-to-r hover:from-accent/50 hover:to-primary/20 hover:text-accent-foreground px-1.5 py-1 rounded transition-all duration-200 min-w-fit border border-border/50 hover:border-primary/50 bg-gradient-to-r from-background/80 to-background/60 backdrop-blur-sm shadow-sm hover:shadow-md transform hover:scale-105"
|
|
|
|
onClick={shortcut.action}
|
|
|
|
>
|
|
|
|
<span className="font-bold text-primary mr-1">{formatShortcutKey(shortcut.key)}</span>
|
|
|
|
<span className="text-muted-foreground">{shortcut.label}</span>
|
|
|
|
</button>
|
|
|
|
))}
|
2025-06-29 20:33:05 -03:00
|
|
|
</div>
|
|
|
|
</div>
|
2025-06-28 19:30:35 -03:00
|
|
|
</div>
|
2025-06-29 21:33:12 -03:00
|
|
|
</ResizablePanel>
|
|
|
|
<ResizableHandle className="bg-gradient-to-b from-border to-primary/20 hover:from-primary/30 hover:to-primary/40 transition-all duration-200" />
|
|
|
|
<ResizablePanel defaultSize={30} minSize={20} maxSize={50}>
|
|
|
|
<div className="h-full flex flex-col bg-gradient-to-br from-card via-card to-secondary/20 border-r border-border/50 shadow-inner">
|
|
|
|
<div className="flex items-center justify-between px-3 py-1 bg-gradient-to-r from-muted/80 to-secondary/80 border-b border-border/50 backdrop-blur-sm cursor-pointer" onClick={toggleMinimize}>
|
|
|
|
<div className="flex items-center gap-2">
|
|
|
|
<div className="p-0.5 bg-primary/10 rounded border border-primary/20">
|
|
|
|
<Terminal className="w-3 h-3 text-primary" />
|
2025-06-29 20:33:05 -03:00
|
|
|
</div>
|
2025-06-29 21:33:12 -03:00
|
|
|
<span className="text-xs font-mono text-foreground font-medium">INPUT</span>
|
|
|
|
</div>
|
|
|
|
<div className="text-xs text-muted-foreground font-mono bg-background/50 px-1.5 py-0.5 rounded-full border border-border/50">
|
|
|
|
CMD
|
2025-06-29 20:33:05 -03:00
|
|
|
</div>
|
|
|
|
</div>
|
2025-06-29 21:33:12 -03:00
|
|
|
<div className="flex-1 p-2 bg-gradient-to-br from-background/50 to-secondary/20 backdrop-blur-sm">
|
|
|
|
<div className="h-full flex flex-col">
|
|
|
|
<div className="text-xs text-muted-foreground mb-2 font-mono bg-secondary/20 px-1.5 py-0.5 rounded">
|
|
|
|
COMMAND LINE INTERFACE
|
|
|
|
</div>
|
|
|
|
<div className="flex-1 bg-gradient-to-br from-card to-card/80 border border-input/50 rounded p-2 font-mono text-xs shadow-inner backdrop-blur-sm">
|
|
|
|
<div className="flex items-start gap-1">
|
|
|
|
<span className="text-primary font-bold">></span>
|
|
|
|
<textarea
|
|
|
|
placeholder="Enter your command or query here..."
|
|
|
|
className="flex-1 bg-transparent text-foreground placeholder:text-muted-foreground border-0 outline-none resize-none min-h-12"
|
|
|
|
value={inputValue}
|
|
|
|
onChange={(e) => setInputValue(e.target.value)}
|
|
|
|
onKeyPress={(e) => {
|
|
|
|
if (e.key === 'Enter' && !e.shiftKey) {
|
|
|
|
e.preventDefault();
|
|
|
|
handleSendMessage();
|
|
|
|
}
|
|
|
|
}}
|
|
|
|
/>
|
2025-06-29 20:33:05 -03:00
|
|
|
</div>
|
2025-06-29 21:33:12 -03:00
|
|
|
</div>
|
|
|
|
<div className="mt-2 flex justify-between items-center">
|
|
|
|
<div className="text-xs text-muted-foreground font-mono bg-secondary/20 px-1.5 py-0.5 rounded">
|
|
|
|
Enter to send • Shift+Enter for new line
|
2025-06-29 20:33:05 -03:00
|
|
|
</div>
|
2025-06-29 21:33:12 -03:00
|
|
|
<button
|
|
|
|
onClick={handleSendMessage}
|
|
|
|
className="bg-gradient-to-r from-primary to-primary/90 text-primary-foreground hover:from-primary/90 hover:to-primary/80 rounded px-3 py-1 text-xs font-mono transition-all duration-200 flex items-center gap-1 shadow-lg hover:shadow-xl transform hover:scale-105"
|
|
|
|
>
|
|
|
|
<Send className="w-2.5 h-2.5" />
|
|
|
|
SEND
|
|
|
|
</button>
|
2025-06-29 20:33:05 -03:00
|
|
|
</div>
|
2025-06-29 21:33:12 -03:00
|
|
|
</div>
|
2025-06-29 20:33:05 -03:00
|
|
|
</div>
|
|
|
|
</div>
|
2025-06-29 21:33:12 -03:00
|
|
|
</ResizablePanel>
|
|
|
|
<ResizableHandle className="bg-gradient-to-b from-border to-primary/20 hover:from-primary/30 hover:to-primary/40 transition-all duration-200" />
|
|
|
|
<ResizablePanel defaultSize={40} minSize={25}>
|
|
|
|
<div className="h-full flex flex-col bg-gradient-to-br from-card via-card to-accent/10 shadow-inner">
|
|
|
|
<div className="flex items-center justify-between px-3 py-1 bg-gradient-to-r from-muted/80 to-secondary/80 border-b border-border/50 backdrop-blur-sm cursor-pointer" onClick={toggleMaximize}>
|
|
|
|
<div className="flex items-center gap-2">
|
|
|
|
<div className="p-0.5 bg-primary/10 rounded border border-primary/20">
|
|
|
|
<Monitor className="w-3 h-3 text-primary" />
|
|
|
|
</div>
|
|
|
|
<span className="text-xs font-mono text-foreground font-medium">OUTPUT</span>
|
|
|
|
</div>
|
|
|
|
<div className="flex items-center gap-2">
|
|
|
|
<span className="text-xs text-muted-foreground font-mono bg-background/50 px-1.5 py-0.5 rounded-full border border-border/50">
|
|
|
|
MSG: {messages.length}
|
|
|
|
</span>
|
|
|
|
<div className="w-2 h-2 bg-gradient-to-br from-green-400 to-emerald-500 rounded-full animate-pulse shadow-lg" />
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<div className="flex-1 p-2 overflow-y-auto bg-gradient-to-br from-background/50 to-secondary/20 font-mono text-xs backdrop-blur-sm">
|
|
|
|
{messages.length === 0 ? (
|
|
|
|
<div className="text-muted-foreground text-center py-8">
|
|
|
|
<div className="animate-pulse text-primary text-sm font-bold mb-2">● SYSTEM READY ●</div>
|
|
|
|
<div className="mt-1 text-xs space-y-1">
|
|
|
|
<div className="bg-secondary/30 px-2 py-0.5 rounded-full inline-block">Waiting for input...</div>
|
|
|
|
<div className="text-muted-foreground/70 bg-secondary/20 px-2 py-0.5 rounded-full inline-block">
|
|
|
|
Use F-keys or Ctrl commands
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
) : (
|
|
|
|
<div className="space-y-2">
|
|
|
|
{messages.map((message, index) => (
|
|
|
|
<div key={index} className="group">
|
|
|
|
<div className="text-xs text-muted-foreground mb-1 flex justify-between bg-secondary/20 px-1.5 py-0.5 rounded-t">
|
|
|
|
<span>[{formatTime(message.timestamp)}] {message.sender.toUpperCase()}:</span>
|
|
|
|
<span className="bg-primary/20 px-1 py-0.5 rounded-full text-primary">#{index + 1}</span>
|
|
|
|
</div>
|
|
|
|
<div className={`p-2 rounded-b rounded-tr shadow-sm transition-all duration-200 group-hover:shadow-lg border backdrop-blur-sm ${message.sender === 'user'
|
|
|
|
? 'bg-gradient-to-r from-primary/10 to-primary/5 border-primary/30 text-foreground'
|
|
|
|
: message.sender === 'system'
|
|
|
|
? 'bg-gradient-to-r from-accent/50 to-accent/30 border-accent/50 text-accent-foreground'
|
|
|
|
: 'bg-gradient-to-r from-secondary/50 to-secondary/30 border-secondary/50 text-secondary-foreground'
|
|
|
|
}`}>
|
|
|
|
<div className="whitespace-pre-wrap break-words">
|
|
|
|
{message.text}
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
))}
|
|
|
|
</div>
|
|
|
|
)}
|
|
|
|
</div>
|
|
|
|
<div className="flex items-center justify-between px-3 py-1 bg-gradient-to-r from-muted/50 to-secondary/50 border-t border-border/50 backdrop-blur-sm">
|
|
|
|
<div className="text-xs text-muted-foreground font-mono">
|
|
|
|
Ready for input
|
|
|
|
</div>
|
|
|
|
<div className="flex items-center gap-2">
|
|
|
|
<div className="text-xs text-muted-foreground font-mono bg-background/50 px-1.5 py-0.5 rounded-full border border-border/50">
|
|
|
|
SCROLL: {messages.length > 10 ? 'AUTO' : 'MANUAL'}
|
|
|
|
</div>
|
|
|
|
<div className="w-1 h-1 bg-gradient-to-br from-primary to-primary/70 rounded-full animate-pulse shadow-sm" />
|
|
|
|
</div>
|
2025-06-29 20:33:05 -03:00
|
|
|
</div>
|
2025-06-28 19:30:35 -03:00
|
|
|
</div>
|
2025-06-29 21:33:12 -03:00
|
|
|
</ResizablePanel>
|
|
|
|
</ResizablePanelGroup>
|
|
|
|
)}
|
|
|
|
</div>
|
|
|
|
</>
|
2025-06-28 19:30:35 -03:00
|
|
|
);
|
|
|
|
};
|
|
|
|
|
2025-06-29 21:33:12 -03:00
|
|
|
export default Footer;
|