Spaces:
Running
Running
File size: 5,133 Bytes
89a11b6 a79917c 89a11b6 a79917c 89a11b6 a79917c 19a0889 a79917c 89a11b6 a79917c 0e29296 19a0889 0e29296 19a0889 0e29296 a79917c 89a11b6 a79917c 89a11b6 a79917c 89a11b6 a79917c 89a11b6 a79917c 53fd305 a79917c 53fd305 a79917c 53fd305 a79917c 89a11b6 a79917c |
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 132 133 134 135 136 137 138 139 140 141 142 143 144 |
// frontend/src/Layout.jsx
import React, { useState } from "react";
import { Link } from "react-router-dom";
import { createPageUrl } from "./utils";
import {
LayoutDashboard,
History as HistoryIcon,
ChevronLeft,
Sparkles,
} from "lucide-react";
import { cn } from "@/lib/utils";
// Import logo - Vite will process this and handle the path correctly
// For production, the logo should be in frontend/public/logo.png
// Vite will copy it to dist/logo.png during build
const logoPath = "/logo.png";
export default function Layout({ children, currentPageName }) {
const [collapsed, setCollapsed] = useState(false);
const navItems = [
{ name: "Dashboard", icon: LayoutDashboard, page: "Dashboard" },
{ name: "History", icon: HistoryIcon, page: "History" },
];
return (
<div className="min-h-screen bg-[#FAFAFA] flex">
{/* Sidebar */}
<aside
className={cn(
"fixed left-0 top-0 h-screen bg-white border-r border-slate-200/80 z-50 transition-all duration-300 ease-out flex flex-col",
collapsed ? "w-[72px]" : "w-[260px]"
)}
>
{/* Logo */}
<div
className={cn(
"h-16 flex items-center border-b border-slate-100 px-4",
collapsed ? "justify-center" : "justify-between"
)}
>
<Link to={createPageUrl("Dashboard")} className="flex items-center gap-3">
<div className="h-9 w-9 flex items-center justify-center flex-shrink-0">
<img
src={logoPath}
alt="EZOFIS AI Logo"
className="h-full w-full object-contain"
onError={(e) => {
// Fallback: hide image and show placeholder if logo not found
e.target.style.display = 'none';
}}
/>
</div>
{!collapsed && (
<div className="flex flex-col">
<span className="font-semibold text-slate-900 tracking-tight">EZOFIS AI</span>
<span className="text-[10px] text-slate-400 font-medium tracking-wide uppercase">
Agentic Extract
</span>
</div>
)}
</Link>
{!collapsed && (
<button
onClick={() => setCollapsed(true)}
className="h-7 w-7 rounded-lg hover:bg-slate-100 flex items-center justify-center text-slate-400 hover:text-slate-600 transition-colors"
>
<ChevronLeft className="h-4 w-4" />
</button>
)}
</div>
{/* Navigation */}
<nav className="flex-1 p-3 space-y-1">
{navItems.map((item) => {
const isActive = currentPageName === item.page;
return (
<Link
key={item.name}
to={createPageUrl(item.page)}
className={cn(
"flex items-center gap-3 px-3 py-2.5 rounded-xl transition-all duration-200 group",
isActive
? "bg-gradient-to-r from-indigo-50 to-violet-50 text-indigo-600"
: "text-slate-500 hover:bg-slate-50 hover:text-slate-700"
)}
>
<item.icon
className={cn(
"h-5 w-5 flex-shrink-0",
isActive ? "text-indigo-600" : "text-slate-400 group-hover:text-slate-600"
)}
/>
{!collapsed && (
<span className="font-medium text-sm">{item.name}</span>
)}
</Link>
);
})}
</nav>
{/* Collapse Toggle (when collapsed) */}
{collapsed && (
<button
onClick={() => setCollapsed(false)}
className="m-3 h-10 rounded-xl bg-slate-50 hover:bg-slate-100 flex items-center justify-center text-slate-400 hover:text-slate-600 transition-colors"
>
<ChevronLeft className="h-4 w-4 rotate-180" />
</button>
)}
{/* Pro Badge */}
{!collapsed && (
<div className="p-3">
<div className="p-4 rounded-2xl bg-gradient-to-br from-slate-900 to-slate-800 text-white">
<div className="flex items-center gap-2 mb-2">
<Sparkles className="h-4 w-4 text-amber-400" />
<span className="text-xs font-semibold tracking-wide">DEPLOY THIS AGENT</span>
</div>
<p className="text-xs text-slate-400 mb-3">
Unlock batch extractions & API access
</p>
<button className="w-full py-2 px-3 rounded-lg bg-white text-slate-900 text-sm font-semibold hover:bg-slate-100 transition-colors">
Talk to us
</button>
</div>
</div>
)}
</aside>
{/* Main Content */}
<main
className={cn(
"flex-1 transition-all duration-300",
collapsed ? "ml-[72px]" : "ml-[260px]"
)}
>
{children}
</main>
</div>
);
}
|