// /app/(app)/layout.tsx 'use client'; import { useState, type ReactNode } from 'react'; import { Dialog, DialogBackdrop, DialogPanel, Menu, MenuButton, MenuItem, MenuItems, TransitionChild, } from '@headlessui/react'; import { Bars3Icon, BellIcon, CalendarIcon, CameraIcon, ChartPieIcon, Cog6ToothIcon, DocumentDuplicateIcon, FolderIcon, ComputerDesktopIcon, HomeIcon, UsersIcon, XMarkIcon, } from '@heroicons/react/24/outline'; import { ChevronDownIcon, MagnifyingGlassIcon } from '@heroicons/react/20/solid'; import { usePathname } from 'next/navigation'; import { useSession, signOut } from 'next-auth/react'; import { Skeleton } from '@/components/ui/Skeleton'; const navigation = [ { name: 'Dashboard', href: '/dashboard', icon: HomeIcon }, { name: 'Geräte', href: '/devices', icon: ComputerDesktopIcon }, ]; const teams = [ { id: 1, name: 'Heroicons', href: '#', initial: 'H' }, { id: 2, name: 'Tailwind Labs', href: '#', initial: 'T' }, { id: 3, name: 'Workcation', href: '#', initial: 'W' }, ]; const userNavigation = [ { name: 'Your profile', href: '#' }, { name: 'Abmelden', href: '#' }, ]; function classNames(...classes: Array) { return classes.filter(Boolean).join(' '); } // feste Liste an erlaubten Tailwind-Hintergrundfarben const AVATAR_COLORS = [ 'bg-indigo-500', 'bg-sky-500', 'bg-emerald-500', 'bg-amber-500', 'bg-rose-500', 'bg-purple-500', ]; function getInitial(name: string) { const trimmed = name.trim(); if (!trimmed) return ''; return trimmed.charAt(0).toUpperCase(); } // deterministische "zufällige" Farbe auf Basis des Namens function getAvatarColor(name: string) { if (!name) return AVATAR_COLORS[0]; let hash = 0; for (let i = 0; i < name.length; i++) { hash = (hash + name.charCodeAt(i)) % AVATAR_COLORS.length; } return AVATAR_COLORS[hash]; } /* ───────── User-Menü, wenn Session geladen ───────── */ type UserMenuProps = { displayName: string; avatarInitial: string; avatarColorClass: string; }; function UserMenu({ displayName, avatarInitial, avatarColorClass }: UserMenuProps) { return ( Open user menu {/* Avatar mit Zufallsfarbe & Initial */}
{avatarInitial}
{userNavigation.map((item) => ( {item.name === 'Abmelden' ? ( ) : ( {item.name} )} ))}
); } /* ───────── Layout ───────── */ export default function AppLayout({ children }: { children: ReactNode }) { const [sidebarOpen, setSidebarOpen] = useState(false); const pathname = usePathname(); const { data: session, status } = useSession(); const rawName = status === 'authenticated' ? (session?.user?.name ?? session?.user?.email ?? '') : ''; const displayName = rawName; const avatarInitial = getInitial(rawName); const avatarColorClass = getAvatarColor(rawName); return (
{/* Mobile Sidebar */}
{/* Sidebar mobil */}
Inventar
{/* Sidebar Desktop */}
Inventar
{/* Topbar + Inhalt */}