File size: 5,010 Bytes
7a7972b
 
 
 
 
 
911f32b
7a7972b
 
 
 
 
 
 
 
 
 
 
911f32b
7a7972b
911f32b
 
 
 
 
7a7972b
 
911f32b
7a7972b
 
 
911f32b
 
 
 
 
7a7972b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
911f32b
7a7972b
911f32b
7a7972b
911f32b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7a7972b
 
 
911f32b
 
 
 
 
 
 
 
 
 
7a7972b
 
 
911f32b
 
 
 
 
 
 
 
 
7a7972b
 
 
 
 
 
911f32b
7a7972b
 
911f32b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7a7972b
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
'use client';

import { motion, AnimatePresence } from 'framer-motion';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import Link from 'next/link';
import { usePathname } from 'next/navigation';
import { LayoutGrid, MessageSquare, Search, Box, Sparkles, FolderOpen } from 'lucide-react';
import './globals.css';

const queryClient = new QueryClient();

export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <html lang="en" className="dark">
      <body className="antialiased selection:bg-cyan-500/30">
        <QueryClientProvider client={queryClient}>
          {/* Ambient Backgrounds */}
          <div className="bg-aurora" />
          <div className="bg-grain" />

          <div className="min-h-screen flex text-slate-200 font-sans">
            <Sidebar />

            <main className="flex-1 flex flex-col relative z-10 overflow-hidden">
              <AnimatePresence mode="wait">
                <motion.div
                  key="content"
                  initial={{ opacity: 0, filter: 'blur(10px)' }}
                  animate={{ opacity: 1, filter: 'blur(0px)' }}
                  exit={{ opacity: 0, filter: 'blur(10px)' }}
                  transition={{ duration: 0.4, ease: [0.22, 1, 0.36, 1] }}
                  className="flex-1 flex flex-col"
                >
                  {children}
                </motion.div>
              </AnimatePresence>
            </main>
          </div>
        </QueryClientProvider>
      </body>
    </html>
  );
}

function Sidebar() {
  const pathname = usePathname();

  return (
    <motion.aside
      initial={{ x: -20, opacity: 0 }}
      animate={{ x: 0, opacity: 1 }}
      className="w-[280px] glass h-screen sticky top-0 flex flex-col border-r border-white/5 z-20"
    >
      {/* Brand */}
      <div className="p-8">
        <div className="flex items-center gap-3">
          <div className="relative">
            <div className="w-10 h-10 rounded-xl bg-gradient-to-tr from-cyan-500 to-violet-600 flex items-center justify-center shadow-lg shadow-cyan-500/20">
              <span className="text-xl">🦅</span>
            </div>
            <div className="absolute inset-0 bg-cyan-400 blur-lg opacity-40 animate-pulse" />
          </div>
          <div>
            <h1 className="font-bold text-lg text-white tracking-tight font-display">
              CodeFalcon
            </h1>
            <p className="text-[10px] uppercase tracking-widest text-cyan-400 font-semibold">
              Agent V2.0
            </p>
          </div>
        </div>
      </div>

      {/* Nav */}
      <nav className="flex-1 px-4 space-y-2">
        <NavItem href="/" icon={<LayoutGrid size={20} />} label="Overview" active={pathname === '/'} />
        <NavItem href="/chat" icon={<MessageSquare size={20} />} label="Agent Chat" active={pathname === '/chat'} />
        <NavItem href="/search" icon={<Search size={20} />} label="Deep Search" active={pathname === '/search'} />
        <nav className="mt-8 px-4 text-xs font-semibold text-slate-500 uppercase tracking-wider">
          Tools
        </nav>
        <NavItem href="/refactor" icon={<Box size={20} />} label="Refactor" active={pathname === '/refactor'} />
        <NavItem href="/generate" icon={<Sparkles size={20} />} label="Generate" active={pathname === '/generate'} />
      </nav>

      {/* Footer */}
      <div className="p-6 border-t border-white/5">
        <div className="flex items-center gap-3 p-3 rounded-lg bg-white/5 border border-white/5">
          <div className="w-8 h-8 rounded-full bg-gradient-to-r from-slate-700 to-slate-600 flex items-center justify-center text-xs">
            JD
          </div>
          <div className="flex-1 min-w-0">
            <p className="text-sm font-medium text-white truncate">Connected</p>
            <p className="text-xs text-emerald-400">● Online</p>
          </div>
        </div>
      </div>
    </motion.aside>
  );
}

function NavItem({ href, icon, label, active }: { href: string; icon: React.ReactNode; label: string; active: boolean }) {
  return (
    <Link href={href}>
      <div className="relative group">
        {active && (
          <motion.div
            layoutId="activeNav"
            className="absolute inset-0 bg-gradient-to-r from-cyan-500/10 to-violet-500/10 rounded-xl border border-cyan-500/20"
            transition={{ type: "spring", stiffness: 300, damping: 30 }}
          />
        )}
        <div className={`
          relative flex items-center gap-3 px-4 py-3 rounded-xl transition-all duration-300
          ${active ? 'text-cyan-400' : 'text-slate-400 group-hover:text-slate-200 group-hover:bg-white/5'}
        `}>
          {icon}
          <span className="font-medium">{label}</span>
          {active && (
            <div className="ml-auto w-1.5 h-1.5 rounded-full bg-cyan-400 shadow-[0_0_8px_rgba(34,211,238,0.8)]" />
          )}
        </div>
      </div>
    </Link>
  );
}