Current state
This commit is contained in:
@@ -0,0 +1,70 @@
|
||||
"use client"
|
||||
|
||||
import { useState, useEffect } from "react"
|
||||
import { usePathname } from "next/navigation"
|
||||
import { motion, AnimatePresence } from "framer-motion"
|
||||
import { Sidebar } from "./sidebar"
|
||||
import { Topbar } from "./topbar"
|
||||
import { SystemMonitor } from "./system-monitor"
|
||||
|
||||
interface AppShellProps {
|
||||
children: React.ReactNode
|
||||
}
|
||||
|
||||
export function AppShell({ children }: AppShellProps) {
|
||||
const [sidebarCollapsed, setSidebarCollapsed] = useState(false)
|
||||
const [mobileOpen, setMobileOpen] = useState(false)
|
||||
const pathname = usePathname()
|
||||
|
||||
// Close mobile sidebar on route change
|
||||
useEffect(() => {
|
||||
setMobileOpen(false)
|
||||
}, [pathname])
|
||||
|
||||
// Persist sidebar state
|
||||
useEffect(() => {
|
||||
const saved = localStorage.getItem("sidebar-collapsed")
|
||||
if (saved) setSidebarCollapsed(saved === "true")
|
||||
}, [])
|
||||
|
||||
const toggleSidebar = () => {
|
||||
const next = !sidebarCollapsed
|
||||
setSidebarCollapsed(next)
|
||||
localStorage.setItem("sidebar-collapsed", String(next))
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="min-h-screen bg-background dark:bg-[#0A0A0A] relative overflow-hidden">
|
||||
|
||||
<SystemMonitor />
|
||||
<Sidebar
|
||||
collapsed={sidebarCollapsed}
|
||||
onToggle={toggleSidebar}
|
||||
mobileOpen={mobileOpen}
|
||||
onMobileClose={() => setMobileOpen(false)}
|
||||
/>
|
||||
|
||||
<div className={cn("transition-all duration-300", sidebarCollapsed ? "lg:ml-16" : "lg:ml-64")}>
|
||||
<Topbar onMenuClick={() => setMobileOpen(true)} />
|
||||
|
||||
<main className="flex-1 p-4 lg:p-6">
|
||||
<AnimatePresence mode="wait">
|
||||
<motion.div
|
||||
key={pathname}
|
||||
initial={{ opacity: 0, y: 8 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
exit={{ opacity: 0, y: -8 }}
|
||||
transition={{ duration: 0.2 }}
|
||||
>
|
||||
{children}
|
||||
</motion.div>
|
||||
</AnimatePresence>
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
function cn(...classes: (string | boolean | undefined | null)[]) {
|
||||
return classes.filter(Boolean).join(" ")
|
||||
}
|
||||
Reference in New Issue
Block a user