"use client"; import React, { useEffect, useState } from "react"; import { SidebarNav } from "@app/components/SidebarNav"; import { OrgSelector } from "@app/components/OrgSelector"; import { cn } from "@app/lib/cn"; import { ListUserOrgsResponse } from "@server/routers/org"; import SupporterStatus from "@app/components/SupporterStatus"; import { Button } from "@app/components/ui/button"; import { ExternalLink, Menu, X, Server } from "lucide-react"; import Image from "next/image"; import ProfileIcon from "@app/components/ProfileIcon"; import { Sheet, SheetContent, SheetTrigger, SheetTitle, SheetDescription } from "@app/components/ui/sheet"; import { useEnvContext } from "@app/hooks/useEnvContext"; import { Breadcrumbs } from "@app/components/Breadcrumbs"; import Link from "next/link"; import { usePathname } from "next/navigation"; import { useUserContext } from "@app/hooks/useUserContext"; import { useLicenseStatusContext } from "@app/hooks/useLicenseStatusContext"; import { useTheme } from "next-themes"; import { useTranslations } from "next-intl"; interface LayoutProps { children: React.ReactNode; orgId?: string; orgs?: ListUserOrgsResponse["orgs"]; navItems?: Array<{ title: string; href: string; icon?: React.ReactNode; children?: Array<{ title: string; href: string; icon?: React.ReactNode; }>; }>; showSidebar?: boolean; showBreadcrumbs?: boolean; showHeader?: boolean; showTopBar?: boolean; } export function Layout({ children, orgId, orgs, navItems = [], showSidebar = true, showBreadcrumbs = true, showHeader = true, showTopBar = true }: LayoutProps) { const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false); const { env } = useEnvContext(); const pathname = usePathname(); const isAdminPage = pathname?.startsWith("/admin"); const { user } = useUserContext(); const { isUnlocked } = useLicenseStatusContext(); const { theme } = useTheme(); const [path, setPath] = useState(""); // Default logo path useEffect(() => { function getPath() { let lightOrDark = theme; if (theme === "system" || !theme) { lightOrDark = window.matchMedia("(prefers-color-scheme: dark)") .matches ? "dark" : "light"; } if (lightOrDark === "light") { // return "/logo/word_mark_black.png"; return "/logo/pangolin_orange.svg"; } // return "/logo/word_mark_white.png"; return "/logo/pangolin_orange.svg"; } setPath(getPath()); }, [theme, env]); const t = useTranslations(); return (
{/* Full width header */} {showHeader && (
{showSidebar && (
{t('navbar')} {t('navbarDescription')}
setIsMobileMenuOpen( false ) } />
{!isAdminPage && user.serverAdmin && (
setIsMobileMenuOpen( false ) } > {t('serverAdmin')}
)}
{env?.app?.version && (
v{env.app.version}
)}
)} {path && ( Pangolin Logo )} {showBreadcrumbs && (
)}
{showTopBar && (
{t('navbarDocsLink')}
)}
{showBreadcrumbs && (
)}
)}
{/* Desktop Sidebar */} {showSidebar && (
{!isAdminPage && user.serverAdmin && (
{t('serverAdmin')}
)}
{!isUnlocked() ? t('communityEdition') : t('commercialEdition')}
{env?.app?.version && (
v{env.app.version}
)}
)} {/* Main content */}
{children}
); }