Complete UI overhaul with luxury design: 3D agent carousel, credits system, enhanced sidebar, profile features, and logo updates
This commit is contained in:
153
src/components/AgentPanel.tsx
Normal file
153
src/components/AgentPanel.tsx
Normal file
@@ -0,0 +1,153 @@
|
||||
import React, { useMemo } from 'react';
|
||||
|
||||
export type Agent = {
|
||||
id: string;
|
||||
name: string;
|
||||
color: string; // tailwind gradient colors
|
||||
emoji: string;
|
||||
};
|
||||
|
||||
interface AgentPanelProps {
|
||||
agents: Agent[];
|
||||
activeAgentId: string;
|
||||
onChangeAgent: (id: string) => void;
|
||||
}
|
||||
|
||||
const AgentPanel: React.FC<AgentPanelProps> = ({ agents, activeAgentId, onChangeAgent }) => {
|
||||
const active = useMemo(() => agents.find(a => a.id === activeAgentId) || agents[0], [agents, activeAgentId]);
|
||||
|
||||
// 8 diverse agents for the 3D carousel
|
||||
const carouselAgents = useMemo(() => [
|
||||
{ id: 'hr', name: 'HR Command', emoji: '👥', color: 'from-luxury-gold/30 to-brass/30' },
|
||||
{ id: 'finance', name: 'Finance Sage', emoji: '💰', color: 'from-bronze/30 to-luxury-gold/30' },
|
||||
{ id: 'project', name: 'Project Sensei', emoji: '📊', color: 'from-brass/30 to-bronze/30' },
|
||||
{ id: 'marketing', name: 'Marketing Genius', emoji: '🎯', color: 'from-luxury-gold/30 to-cream/30' },
|
||||
{ id: 'analytics', name: 'Data Wizard', emoji: '📈', color: 'from-bronze/30 to-brass/30' },
|
||||
{ id: 'security', name: 'Security Guard', emoji: '🛡️', color: 'from-deep-forest/40 to-luxury-gold/30' },
|
||||
{ id: 'support', name: 'Support Hero', emoji: '🎧', color: 'from-brass/30 to-rich-brown/30' },
|
||||
{ id: 'research', name: 'Research Bot', emoji: '🔍', color: 'from-luxury-gold/30 to-bronze/30' }
|
||||
], []);
|
||||
|
||||
return (
|
||||
<div className="h-full w-full border border-luxury-gold/25 rounded-2xl p-4 md:p-6 bg-deep-forest/50 backdrop-blur-xl overflow-hidden flex flex-col shadow-luxury-inner">
|
||||
<div className="flex items-center justify-between mb-4">
|
||||
<h3 className="font-playfair text-xl text-cream">Personal Assistant</h3>
|
||||
<div className="text-cream/80 text-sm font-montserrat">
|
||||
{active.name}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="relative rounded-xl bg-gradient-to-br from-deep-forest/60 to-rich-brown/40 border border-luxury-gold/25 overflow-hidden flex-1">
|
||||
<div className={`absolute inset-0 opacity-40 bg-gradient-to-br ${active.color}`} />
|
||||
|
||||
{/* Creative Orbital Agent Display */}
|
||||
<div className="absolute inset-0 grid place-items-center">
|
||||
{/* Central Hub */}
|
||||
<div className="relative">
|
||||
{/* Outer orbital ring */}
|
||||
<div className="w-72 h-72 rounded-full border border-luxury-gold/20 animate-spin-ultra-slow relative">
|
||||
{/* Orbital path indicator */}
|
||||
<div className="absolute inset-4 rounded-full border border-luxury-gold/10"></div>
|
||||
<div className="absolute inset-8 rounded-full border border-luxury-gold/5"></div>
|
||||
|
||||
{/* Rotating agents on the orbit */}
|
||||
{carouselAgents.map((agent, index) => {
|
||||
const angle = (index * 360) / carouselAgents.length;
|
||||
const isActive = agent.id === activeAgentId;
|
||||
const radian = (angle * Math.PI) / 180;
|
||||
const radius = 130;
|
||||
const x = Math.cos(radian) * radius;
|
||||
const y = Math.sin(radian) * radius;
|
||||
|
||||
return (
|
||||
<div key={agent.id} className="contents">
|
||||
<button
|
||||
onClick={() => onChangeAgent(agent.id)}
|
||||
className={`absolute w-14 h-14 rounded-2xl transition-all duration-500 hover:scale-125 focus:outline-none group ${
|
||||
isActive
|
||||
? 'bg-gradient-to-br from-luxury-gold/60 to-brass/60 border-2 border-luxury-gold shadow-[0_0_25px_rgba(197,157,89,0.8)] scale-110 z-10'
|
||||
: 'bg-deep-forest/70 border border-luxury-gold/30 hover:border-luxury-gold/60 hover:bg-deep-forest/80'
|
||||
}`}
|
||||
style={{
|
||||
left: '50%',
|
||||
top: '50%',
|
||||
transform: `translate(${x - 28}px, ${y - 28}px)`,
|
||||
}}
|
||||
title={agent.name}
|
||||
>
|
||||
<div className="flex flex-col items-center justify-center h-full">
|
||||
<span className={`text-lg transition-all duration-300 ${isActive ? 'text-deep-forest' : 'text-cream'}`}>
|
||||
{agent.emoji}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
{/* Connection line to center for active agent */}
|
||||
{isActive && (
|
||||
<div
|
||||
className="absolute w-0.5 bg-gradient-to-r from-luxury-gold to-transparent opacity-60"
|
||||
style={{
|
||||
height: `${radius - 20}px`,
|
||||
left: '50%',
|
||||
top: '50%',
|
||||
transformOrigin: 'top center',
|
||||
transform: `translateX(-50%) rotate(${180 + angle}deg)`
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</button>
|
||||
|
||||
{/* Tooltip positioned outside rotating container */}
|
||||
<div
|
||||
className="absolute opacity-0 group-hover:opacity-100 transition-opacity duration-300 pointer-events-none z-50"
|
||||
style={{
|
||||
left: '50%',
|
||||
top: '50%',
|
||||
transform: `translate(${x - 28}px, ${y + 40}px)`,
|
||||
}}
|
||||
>
|
||||
<div className="bg-deep-forest/95 text-cream text-sm px-3 py-2 rounded-xl border border-luxury-gold/40 whitespace-nowrap font-montserrat font-medium shadow-[0_4px_12px_rgba(0,0,0,0.4)] -translate-x-1/2">
|
||||
{agent.name}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
|
||||
{/* Central Control Hub */}
|
||||
<div className="absolute top-1/2 left-1/2 w-20 h-20 -translate-x-1/2 -translate-y-1/2 z-20">
|
||||
<div className="w-full h-full rounded-full bg-gradient-to-br from-deep-forest/80 to-rich-brown/60 border-2 border-luxury-gold/40 shadow-[0_0_20px_rgba(197,157,89,0.3)] flex items-center justify-center group cursor-pointer">
|
||||
<div className="text-center">
|
||||
<div className="text-2xl mb-1">🤖</div>
|
||||
<div className="text-xs text-cream/80 font-montserrat font-medium">HUB</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Pulsing energy rings */}
|
||||
<div className="absolute inset-0 rounded-full border border-luxury-gold/20 animate-ping"></div>
|
||||
<div className="absolute inset-2 rounded-full border border-luxury-gold/10 animate-ping animation-delay-1000"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Floating particles for ambiance */}
|
||||
<div className="absolute inset-0 pointer-events-none">
|
||||
{[...Array(6)].map((_, i) => (
|
||||
<div
|
||||
key={i}
|
||||
className="absolute w-1 h-1 bg-luxury-gold rounded-full animate-ping"
|
||||
style={{
|
||||
left: `${20 + Math.random() * 60}%`,
|
||||
top: `${20 + Math.random() * 60}%`,
|
||||
animationDelay: `${Math.random() * 2}s`,
|
||||
animationDuration: `${1.5 + Math.random() * 1}s`
|
||||
}}
|
||||
></div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default AgentPanel;
|
||||
Reference in New Issue
Block a user