45 lines
1.2 KiB
TypeScript
45 lines
1.2 KiB
TypeScript
"use client";
|
|
|
|
import { createContext, useContext, useEffect, useState } from "react";
|
|
|
|
const STORAGE_KEY = "organize:sidenav-collapsed";
|
|
|
|
interface SideNavContextValue {
|
|
collapsed: boolean;
|
|
toggle: () => void;
|
|
}
|
|
|
|
const SideNavContext = createContext<SideNavContextValue | null>(null);
|
|
|
|
export function SideNavProvider({ children }: { children: React.ReactNode }) {
|
|
// Default expanded on both server and first client render to avoid a
|
|
// hydration mismatch; the real persisted value is applied right after
|
|
// mount, trading a one-frame flash for zero hydration warnings.
|
|
const [collapsed, setCollapsed] = useState(false);
|
|
|
|
useEffect(() => {
|
|
const stored = localStorage.getItem(STORAGE_KEY);
|
|
if (stored !== null) setCollapsed(stored === "true");
|
|
}, []);
|
|
|
|
const toggle = () => {
|
|
setCollapsed((prev) => {
|
|
const next = !prev;
|
|
localStorage.setItem(STORAGE_KEY, String(next));
|
|
return next;
|
|
});
|
|
};
|
|
|
|
return (
|
|
<SideNavContext.Provider value={{ collapsed, toggle }}>
|
|
{children}
|
|
</SideNavContext.Provider>
|
|
);
|
|
}
|
|
|
|
export function useSideNav() {
|
|
const ctx = useContext(SideNavContext);
|
|
if (!ctx) throw new Error("useSideNav must be used within a SideNavProvider");
|
|
return ctx;
|
|
}
|