Seth
update
f80e9b3
import React, { useState } from 'react';
import { Link, useLocation } from 'react-router-dom';
import { createPageUrl } from '@/utils';
import { motion, AnimatePresence } from 'framer-motion';
import {
LayoutDashboard,
FolderOpen,
Calendar,
PenTool,
Link2,
Settings,
Menu,
X,
Bell,
Search,
ChevronDown,
Linkedin,
Sparkles,
LogOut,
User,
HelpCircle
} from 'lucide-react';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar';
import { Badge } from '@/components/ui/badge';
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuLabel,
DropdownMenuSeparator,
DropdownMenuTrigger,
} from '@/components/ui/dropdown-menu';
const navItems = [
{ name: 'Dashboard', icon: LayoutDashboard, href: 'Dashboard' },
{ name: 'Repository', icon: FolderOpen, href: 'Repository' },
{ name: 'Scheduler', icon: Calendar, href: 'Scheduler' },
{ name: 'Post Editor', icon: PenTool, href: 'PostEditor' },
{ name: 'Integrations', icon: Link2, href: 'Integrations' },
];
export default function Layout({ children, currentPageName }) {
const [sidebarOpen, setSidebarOpen] = useState(false);
const location = useLocation();
const currentPage = navItems.find(item => createPageUrl(item.href) === location.pathname)?.href || 'Dashboard';
return (
<div className="min-h-screen bg-slate-50">
{/* Mobile Sidebar Overlay */}
<AnimatePresence>
{sidebarOpen && (
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
className="fixed inset-0 bg-black/50 z-40 lg:hidden"
onClick={() => setSidebarOpen(false)}
/>
)}
</AnimatePresence>
{/* Sidebar */}
<aside className={`fixed top-0 left-0 z-50 h-full w-64 bg-white border-r border-slate-200 transform transition-transform duration-300 ease-in-out lg:translate-x-0 ${
sidebarOpen ? 'translate-x-0' : '-translate-x-full'
}`}>
<div className="flex flex-col h-full">
{/* Logo */}
<div className="h-16 flex items-center justify-between px-4 border-b border-slate-100">
<Link to={createPageUrl('Dashboard')} className="flex items-center gap-2">
<div className="w-9 h-9 rounded-xl bg-gradient-to-br from-blue-600 to-indigo-600 flex items-center justify-center shadow-lg shadow-blue-500/30">
<Linkedin className="w-5 h-5 text-white" />
</div>
<div>
<span className="font-bold text-slate-900 text-lg">PostGen</span>
<span className="text-xs text-slate-500 block -mt-1">LinkedIn Scheduler</span>
</div>
</Link>
<Button
variant="ghost"
size="icon"
className="lg:hidden"
onClick={() => setSidebarOpen(false)}
>
<X className="w-5 h-5" />
</Button>
</div>
{/* Navigation */}
<nav className="flex-1 p-4 space-y-1 overflow-y-auto">
{navItems.map((item) => {
const isActive = currentPage === item.href;
return (
<Link
key={item.name}
to={createPageUrl(item.href)}
onClick={() => setSidebarOpen(false)}
className={`flex items-center gap-3 px-3 py-2.5 rounded-xl text-sm font-medium transition-all ${
isActive
? 'bg-blue-50 text-blue-700'
: 'text-slate-600 hover:bg-slate-50 hover:text-slate-900'
}`}
>
<item.icon className={`w-5 h-5 ${isActive ? 'text-blue-600' : 'text-slate-400'}`} />
{item.name}
{item.name === 'Repository' && (
<Badge className="ml-auto bg-blue-100 text-blue-700 text-[10px] px-1.5 py-0 border-0">
156
</Badge>
)}
</Link>
);
})}
</nav>
{/* Quick Create */}
<div className="p-4 border-t border-slate-100">
<Link to={createPageUrl('PostEditor')}>
<Button className="w-full gap-2 bg-gradient-to-r from-blue-600 to-indigo-600 hover:from-blue-700 hover:to-indigo-700 shadow-lg shadow-blue-500/25">
<Sparkles className="w-4 h-4" />
Create Post
</Button>
</Link>
</div>
{/* User Profile */}
<div className="p-4 border-t border-slate-100">
<DropdownMenu>
<DropdownMenuTrigger asChild>
<button className="flex items-center gap-3 w-full p-2 rounded-xl hover:bg-slate-50 transition-colors">
<Avatar className="h-9 w-9">
<AvatarImage src="https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?w=100&h=100&fit=crop" />
<AvatarFallback>AB</AvatarFallback>
</Avatar>
<div className="flex-1 text-left">
<p className="text-sm font-medium text-slate-900">Alex Business</p>
<p className="text-xs text-slate-500">Pro Plan</p>
</div>
<ChevronDown className="w-4 h-4 text-slate-400" />
</button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end" className="w-56">
<DropdownMenuLabel>My Account</DropdownMenuLabel>
<DropdownMenuSeparator />
<DropdownMenuItem>
<User className="w-4 h-4 mr-2" />
Profile Settings
</DropdownMenuItem>
<DropdownMenuItem>
<Settings className="w-4 h-4 mr-2" />
Preferences
</DropdownMenuItem>
<DropdownMenuItem>
<HelpCircle className="w-4 h-4 mr-2" />
Help & Support
</DropdownMenuItem>
<DropdownMenuSeparator />
<DropdownMenuItem className="text-red-600">
<LogOut className="w-4 h-4 mr-2" />
Sign Out
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
</div>
</div>
</aside>
{/* Main Content */}
<div className="lg:pl-64">
{/* Top Header */}
<header className="h-16 bg-white border-b border-slate-200 sticky top-0 z-30">
<div className="h-full px-4 flex items-center justify-between gap-4">
{/* Mobile Menu Toggle */}
<Button
variant="ghost"
size="icon"
className="lg:hidden"
onClick={() => setSidebarOpen(true)}
>
<Menu className="w-5 h-5" />
</Button>
{/* Search */}
<div className="flex-1 max-w-md hidden sm:block">
<div className="relative">
<Search className="absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-slate-400" />
<Input
placeholder="Search posts, assets, schedules..."
className="pl-10 bg-slate-50 border-slate-200 focus:bg-white"
/>
</div>
</div>
{/* Right Actions */}
<div className="flex items-center gap-2">
<Button variant="ghost" size="icon" className="relative">
<Bell className="w-5 h-5 text-slate-600" />
<span className="absolute top-1.5 right-1.5 w-2 h-2 bg-red-500 rounded-full" />
</Button>
{/* Connection Status */}
<div className="hidden md:flex items-center gap-2 px-3 py-1.5 rounded-lg bg-emerald-50 border border-emerald-100">
<div className="w-2 h-2 rounded-full bg-emerald-500 animate-pulse" />
<span className="text-xs font-medium text-emerald-700">LinkedIn Connected</span>
</div>
</div>
</div>
</header>
{/* Page Content */}
<main>
{children}
</main>
</div>
</div>
);
}