mission-control/components/layout/sidebar.tsx

198 lines
6.5 KiB
TypeScript

"use client";
import { useState } from "react";
import Link from "next/link";
import { usePathname } from "next/navigation";
import {
LayoutDashboard,
Activity,
Calendar,
Kanban,
FolderKanban,
FileText,
Wrench,
Target,
Menu,
ChevronLeft,
ChevronRight,
} from "lucide-react";
import { Button } from "@/components/ui/button";
import { Sheet, SheetContent, SheetTrigger } from "@/components/ui/sheet";
import { cn } from "@/lib/utils";
const navItems = [
{ name: "Dashboard", href: "/", icon: LayoutDashboard },
{ name: "Activity", href: "/activity", icon: Activity },
{ name: "Calendar", href: "/calendar", icon: Calendar },
{ name: "Tasks", href: "/tasks", icon: Kanban },
{ name: "Projects", href: "/projects", icon: FolderKanban },
{ name: "Documents", href: "/documents", icon: FileText },
{ name: "Tool Builder", href: "/tools", icon: Wrench },
{ name: "Mission", href: "/mission", icon: Target },
];
const MISSION_SHORT = "Build an iOS empire → retire on our terms → travel with Heidi → 53 is just the start";
function SidebarContent({ pathname, collapsed = false }: { pathname: string; collapsed?: boolean }) {
return (
<div className="flex flex-col h-full">
<div className={cn("flex items-center gap-2 py-6", collapsed ? "px-2 justify-center" : "px-4")}>
<div className="w-8 h-8 rounded-lg bg-gradient-to-br from-blue-500 to-purple-600 flex items-center justify-center shrink-0">
<span className="text-white font-bold text-sm">MC</span>
</div>
{!collapsed && <span className="font-bold text-lg">Mission Control</span>}
</div>
{/* Mission Statement - hide when collapsed */}
{!collapsed && (
<div className="px-4 py-3 mx-3 mb-2 rounded-lg bg-gradient-to-r from-blue-500/10 to-purple-500/10 border border-blue-500/20">
<p className="text-[10px] text-muted-foreground leading-tight">
{MISSION_SHORT}
</p>
</div>
)}
<nav className={cn("flex-1 py-4 space-y-1", collapsed ? "px-2" : "px-3")}>
{navItems.map((item) => {
const Icon = item.icon;
const isActive = pathname === item.href;
return (
<Link
key={item.href}
href={item.href}
title={collapsed ? item.name : undefined}
className={cn(
"flex items-center rounded-lg text-sm font-medium transition-colors",
collapsed
? "justify-center px-2 py-3"
: "gap-3 px-3 py-2",
isActive
? "bg-primary text-primary-foreground"
: "text-muted-foreground hover:bg-accent hover:text-accent-foreground"
)}
>
<Icon className="w-4 h-4 shrink-0" />
{!collapsed && <span>{item.name}</span>}
</Link>
);
})}
</nav>
<div className={cn("border-t border-border", collapsed ? "p-2" : "p-4")}>
<div className={cn("flex items-center", collapsed ? "justify-center" : "gap-3")}>
<div className="w-8 h-8 rounded-full bg-gradient-to-br from-green-400 to-blue-500 shrink-0" />
{!collapsed && (
<div className="flex-1 min-w-0">
<p className="text-sm font-medium truncate">Matt Bruce</p>
<p className="text-xs text-muted-foreground truncate">TopDogLabs</p>
</div>
)}
</div>
</div>
</div>
);
}
function MobileSidebar({ pathname }: { pathname: string }) {
const [open, setOpen] = useState(false);
return (
<Sheet open={open} onOpenChange={setOpen}>
<SheetTrigger asChild className="lg:hidden">
<Button variant="ghost" size="icon" className="absolute top-4 left-4 z-50">
<Menu className="w-5 h-5" />
</Button>
</SheetTrigger>
<SheetContent side="left" className="w-64 p-0">
<SidebarContent pathname={pathname} />
</SheetContent>
</Sheet>
);
}
export function DashboardLayout({ children }: { children: React.ReactNode }) {
const [collapsed, setCollapsed] = useState(false);
const pathname = usePathname();
return (
<div className="min-h-screen bg-background">
{/* Desktop Sidebar - Collapsible */}
<div
className={cn(
"hidden lg:flex flex-col fixed inset-y-0 left-0 border-r border-border bg-card transition-all duration-300 z-40",
collapsed ? "w-16" : "w-64"
)}
>
{/* Collapse Toggle Button */}
<button
onClick={() => setCollapsed(!collapsed)}
className={cn(
"absolute -right-4 top-8 w-8 h-8 rounded-full border-2 border-blue-500 bg-blue-500 text-white shadow-lg",
"hover:bg-blue-600 hover:scale-110 transition-all z-50 flex items-center justify-center"
)}
title={collapsed ? "Expand sidebar" : "Collapse sidebar"}
>
{collapsed ? (
<ChevronRight className="w-5 h-5" />
) : (
<ChevronLeft className="w-5 h-5" />
)}
</button>
<SidebarContent pathname={pathname} collapsed={collapsed} />
</div>
{/* Mobile Sidebar */}
<MobileSidebar pathname={pathname} />
<main
className={cn(
"transition-all duration-300",
collapsed ? "lg:pl-16" : "lg:pl-64"
)}
>
<div className="p-4 lg:p-8">{children}</div>
</main>
</div>
);
}
// Backwards compatibility - export Sidebar for pages that import it directly
export function Sidebar() {
const pathname = usePathname();
const [collapsed, setCollapsed] = useState(false);
return (
<>
{/* Desktop Sidebar - Collapsible */}
<div
className={cn(
"hidden lg:flex flex-col fixed inset-y-0 left-0 border-r border-border bg-card transition-all duration-300 z-40",
collapsed ? "w-16" : "w-64"
)}
>
<Button
variant="ghost"
size="icon"
onClick={() => setCollapsed(!collapsed)}
className={cn(
"absolute -right-3 top-6 w-6 h-6 rounded-full border border-border bg-card shadow-sm z-50",
"hover:bg-accent"
)}
>
{collapsed ? (
<ChevronRight className="w-3 h-3" />
) : (
<ChevronLeft className="w-3 h-3" />
)}
</Button>
<SidebarContent pathname={pathname} collapsed={collapsed} />
</div>
{/* Mobile Sidebar */}
<MobileSidebar pathname={pathname} />
</>
);
}