ldc-groupe/resources/ts/back/Layouts/AuthenticatedLayout.tsx
2026-02-12 16:13:54 +01:00

113 lines
3.7 KiB
TypeScript

// * Packages
import { motion } from "motion/react";
import { ReactNode, useEffect, useState } from "react";
import { Head, usePage } from "@inertiajs/react";
// * Components shadcn
import { SidebarProvider, useSidebar } from "@/components/ui/sidebar";
import { Toaster } from "@/components/ui/toaster";
import { TooltipProvider } from "@/components/ui/tooltip";
// * Other
import AppSidebar from "@/back/Components/Layout/AppSidebar";
import AppHeader from "@/back/Components/Layout/AppHeader";
import AppFooter from "@/back/Components/Layout/AppFooter";
import { ThemeProvider } from "@/back/providers/ThemeProvider";
type AuthenticatedLayoutProps = {
title: string;
beforeNode?: ReactNode;
afterNode?: ReactNode;
children: ReactNode;
};
function LayoutContent({
title,
beforeNode,
afterNode,
children,
}: Omit<AuthenticatedLayoutProps, "children"> & { children: ReactNode }) {
const { open } = useSidebar();
const [isSm, setIsSm] = useState(false);
let sidebarVar = "0px";
if (!isSm) {
sidebarVar = open
? "var(--sidebar-width)"
: "var(--sidebar-width-icon)";
}
useEffect(() => {
const mediaQuery = window.matchMedia("(max-width: 767px)");
setIsSm(mediaQuery.matches);
const handler = (e: MediaQueryListEvent) => setIsSm(e.matches);
mediaQuery.addEventListener("change", handler);
return () => mediaQuery.removeEventListener("change", handler);
}, []);
return (
<>
<AppSidebar />
<motion.main
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
transition={{ duration: 0.3 }}
style={{ maxWidth: `calc(100% - ${sidebarVar})` }}
className="relative flex flex-col justify-between transition-[max-width] duration-200 ease-linear w-full px-8 pb-4"
>
<div className="container flex flex-col justify-between mx-auto">
<AppHeader />
<div className="flex justify-between items-center py-4">
<Head title={title} />
<div className="flex justify-start items-center">
{beforeNode}
<h1
className={`scroll-m-20 text-4xl font-extrabold tracking-tight lg:text-5xl${
beforeNode ? " ms-2" : ""
}`}
>
{title}
</h1>
</div>
{afterNode}
</div>
{children}
</div>
<Toaster />
<AppFooter />
</motion.main>
</>
);
}
export default function AuthenticatedLayout({
title,
beforeNode,
afterNode,
children,
}: AuthenticatedLayoutProps) {
const isCollapsed =
typeof window !== "undefined"
? localStorage.getItem("vite-ui-collapsed")
: null;
const { locale } = usePage().props.appEnv as unknown as {
locale: string;
};
return (
<ThemeProvider key={locale}>
<SidebarProvider defaultOpen={!isCollapsed}>
<TooltipProvider>
<LayoutContent
title={title}
beforeNode={beforeNode}
afterNode={afterNode}
>
{children}
</LayoutContent>
</TooltipProvider>
</SidebarProvider>
</ThemeProvider>
);
}