nextav/src/contexts/sidebar-context.tsx

57 lines
1.7 KiB
TypeScript

"use client";
import { createContext, useContext, useState, useEffect, useCallback, ReactNode } from "react";
import { usePathname } from "next/navigation";
interface SidebarContextType {
isCollapsed: boolean;
isMobileOpen: boolean;
toggleCollapse: () => void;
openMobile: () => void;
closeMobile: () => void;
isMobile: boolean;
}
const SidebarContext = createContext<SidebarContextType | undefined>(undefined);
export function SidebarProvider({ children }: { children: ReactNode }) {
const [isCollapsed, setIsCollapsed] = useState(false);
const [isMobileOpen, setIsMobileOpen] = useState(false);
const [isMobile, setIsMobile] = useState(false);
const pathname = usePathname();
useEffect(() => {
const mq = window.matchMedia("(max-width: 1023px)");
const handler = (e: MediaQueryListEvent | MediaQueryList) => {
setIsMobile(e.matches);
if (!e.matches) setIsMobileOpen(false);
};
handler(mq);
mq.addEventListener("change", handler);
return () => mq.removeEventListener("change", handler);
}, []);
// Auto-close mobile drawer on route change
useEffect(() => {
setIsMobileOpen(false);
}, [pathname]);
const toggleCollapse = useCallback(() => setIsCollapsed((v) => !v), []);
const openMobile = useCallback(() => setIsMobileOpen(true), []);
const closeMobile = useCallback(() => setIsMobileOpen(false), []);
return (
<SidebarContext.Provider
value={{ isCollapsed, isMobileOpen, toggleCollapse, openMobile, closeMobile, isMobile }}
>
{children}
</SidebarContext.Provider>
);
}
export function useSidebar() {
const ctx = useContext(SidebarContext);
if (!ctx) throw new Error("useSidebar must be used within SidebarProvider");
return ctx;
}