"use client"; import { signOut } from "@/app/login/actions"; import { IconButton } from "@/components/ui/button"; import { Card, CardContent } from "@/components/ui/card"; import { PendingLink } from "@/components/ui/pending-link"; import { cn } from "@/lib/utils"; import { ChevronUp, LogOut, Menu, Settings } from "lucide-react"; import type { LucideIcon } from "lucide-react"; import Image from "next/image"; import Link from "next/link"; import { usePathname } from "next/navigation"; import { useEffect, useRef, useState } from "react"; export type AppShellNavItem = { title: string; href?: string; icon?: LucideIcon; }; export type AppShellNavGroup = { title: string; items: AppShellNavItem[]; }; type ShellUser = { email: string; displayName: string; shortName: string; avatarUrl: string | null; }; type AppShellProps = { children: React.ReactNode; homeHref: string; navGroups: AppShellNavGroup[]; settingsHref: string; user: ShellUser; progress?: number; }; export function AppShell({ children, homeHref, navGroups, settingsHref, user, progress, }: AppShellProps) { const pathname = usePathname(); const [mobileSidebarState, setMobileSidebarState] = useState({ open: false, pathname, }); const isMobileSidebarOpen = mobileSidebarState.open && mobileSidebarState.pathname === pathname; return (
Ana içeriğe geç
{isMobileSidebarOpen ? (
); } function AppSidebar({ homeHref, navGroups, pathname, progress, settingsHref, user, onNavigate, className, }: { homeHref: string; navGroups: AppShellNavGroup[]; pathname: string; progress?: number; settingsHref: string; user: ShellUser; onNavigate?: () => void; className?: string; }) { return ( ); } function ProgressSummary({ progress }: { progress: number }) { const normalizedProgress = Math.max(0, Math.min(100, progress)); return (
Proje ilerlemesi
%{normalizedProgress} tamamlandı
); } function AccountMenu({ user, settingsHref, onNavigate, }: { user: ShellUser; settingsHref: string; onNavigate?: () => void; }) { const [open, setOpen] = useState(false); const menuRef = useRef(null); const buttonRef = useRef(null); useEffect(() => { function handlePointerDown(event: PointerEvent) { if (!menuRef.current?.contains(event.target as Node)) { setOpen(false); } } function handleKeyDown(event: KeyboardEvent) { if (event.key === "Escape") { setOpen(false); buttonRef.current?.focus(); } } document.addEventListener("pointerdown", handlePointerDown); document.addEventListener("keydown", handleKeyDown); return () => { document.removeEventListener("pointerdown", handlePointerDown); document.removeEventListener("keydown", handleKeyDown); }; }, []); return (
{open ? (
{ setOpen(false); onNavigate?.(); }} className="flex h-9 items-center gap-2 rounded-sm px-3 text-sm hover:bg-accent focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring" showSpinner > Ayarlar
) : null}
); } function UserAvatar({ user }: { user: ShellUser }) { if (user.avatarUrl) { return ( ); } return ( {user.shortName} ); }