"use client"; import { AnimatePresence, motion, useReducedMotion } from "framer-motion"; import { Bell, BookOpen, Calendar, ChevronDown, ChevronRight, ExternalLink, FileText, HelpCircle, Home, type LucideIcon, MessageSquare, PanelLeft, PanelLeftClose, Plus, Settings, Users, } from "lucide-react"; import * as React from "react"; import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"; import { Button } from "@/components/ui/button"; import { Collapsible, CollapsibleTrigger } from "@/components/ui/collapsible"; import { Drawer, DrawerContent, DrawerHeader, DrawerTitle, } from "@/components/ui/drawer"; import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger, } from "@/components/ui/dropdown-menu"; import { ScrollArea } from "@/components/ui/scroll-area"; import { Separator } from "@/components/ui/separator"; import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, } from "@/components/ui/tooltip"; import { cn } from "@/lib/utils"; const SIDEBAR_WIDTH = 304; const SIDEBAR_RAIL_WIDTH = 64; const SIDEBAR_PANEL_WIDTH = SIDEBAR_WIDTH - SIDEBAR_RAIL_WIDTH; const SIDEBAR_KEYBOARD_SHORTCUT = "b"; interface SidebarContextValue { isPanelOpen: boolean; setPanelOpen: (open: boolean) => void; togglePanel: () => void; panelState: "expanded" | "collapsed"; } const SidebarContext = React.createContext(null); function useSidebar() { const context = React.useContext(SidebarContext); if (!context) { throw new Error("useSidebar must be used within a SidebarProvider"); } return context; } interface SidebarProviderProps { defaultOpen?: boolean; children: React.ReactNode; } function SidebarProvider({ defaultOpen = true, children, }: SidebarProviderProps) { const [_isPanelOpen, _setIsPanelOpen] = React.useState(defaultOpen); const isPanelOpen = _isPanelOpen; const setPanelOpen = React.useCallback((open: boolean) => { _setIsPanelOpen(open); }, []); const togglePanel = React.useCallback(() => { setPanelOpen(!isPanelOpen); }, [isPanelOpen, setPanelOpen]); React.useEffect(() => { const handleKeyDown = (event: KeyboardEvent) => { if ( event.key === SIDEBAR_KEYBOARD_SHORTCUT && (event.metaKey || event.ctrlKey) ) { event.preventDefault(); togglePanel(); } }; window.addEventListener("keydown", handleKeyDown); return () => window.removeEventListener("keydown", handleKeyDown); }, [togglePanel]); const panelState = isPanelOpen ? "expanded" : "collapsed"; const value = React.useMemo( () => ({ isPanelOpen, setPanelOpen, togglePanel, panelState, }), [isPanelOpen, setPanelOpen, togglePanel, panelState], ); return ( {children} ); } interface NavItemConfig { id: string; label: string; icon: LucideIcon; path: string; } interface NavSectionConfig { id: string; label?: string; items: NavItemConfig[]; } interface NavModuleConfig { id: string; label: string; icon: LucideIcon; defaultPath: string; sections: NavSectionConfig[]; } interface RailIconConfig { moduleId: string; label: string; icon: LucideIcon; defaultPath: string; } const data = { user: { name: "علی رضایی", email: "ali@example.com", avatar: "/block-media/shadcnblocks/block/avatar/avatar1.jpg", }, organization: { name: "شرکت آکمه", logo: "/block-media/shadcnblocks/block/logos/NovaSales-logo.svg", }, railIcons: [ { moduleId: "home", label: "خانه", icon: Home, defaultPath: "#" }, { moduleId: "projects", label: "پروژه‌ها", icon: FileText, defaultPath: "#", }, { moduleId: "calendar", label: "تقویم", icon: Calendar, defaultPath: "#", }, { moduleId: "team", label: "تیم", icon: Users, defaultPath: "#" }, ] as RailIconConfig[], modules: [ { id: "home", label: "خانه", icon: Home, defaultPath: "#", sections: [ { id: "main", items: [ { id: "overview", label: "نمای کلی", icon: Home, path: "#" }, { id: "documents", label: "اسناد", icon: FileText, path: "#" }, { id: "messages", label: "پیام‌ها", icon: MessageSquare, path: "#", }, ], }, { id: "library", label: "کتابخانه", items: [ { id: "guides", label: "راهنماها", icon: BookOpen, path: "#" }, { id: "resources", label: "منابع", icon: FileText, path: "#" }, ], }, ], }, { id: "projects", label: "پروژه‌ها", icon: FileText, defaultPath: "#", sections: [ { id: "main", items: [ { id: "all-projects", label: "همه پروژه‌ها", icon: FileText, path: "#", }, { id: "recent", label: "اخیر", icon: Calendar, path: "#" }, { id: "starred", label: "ستاره‌دار", icon: BookOpen, path: "#" }, ], }, ], }, { id: "calendar", label: "تقویم", icon: Calendar, defaultPath: "#", sections: [ { id: "main", items: [ { id: "schedule", label: "برنامه", icon: Calendar, path: "#" }, { id: "events", label: "رویدادها", icon: Bell, path: "#" }, ], }, ], }, { id: "team", label: "تیم", icon: Users, defaultPath: "#", sections: [ { id: "main", items: [ { id: "members", label: "اعضا", icon: Users, path: "#" }, { id: "activity", label: "فعالیت تیم", icon: MessageSquare, path: "#", }, ], }, ], }, ] as NavModuleConfig[], utilities: [ { id: "help", label: "راهنما و پشتیبانی", icon: HelpCircle, path: "#" }, ] as NavItemConfig[], }; function getInitials(name: string) { return ( name .split(" ") .filter(Boolean) .slice(0, 2) .map((part) => part[0]?.toUpperCase()) .join("") || "U" ); } const SidebarTrigger = React.forwardRef< HTMLButtonElement, React.ComponentPropsWithoutRef & { showTooltip?: boolean } >(({ className, onClick, showTooltip = true, ...props }, ref) => { const { isPanelOpen, togglePanel } = useSidebar(); const button = ( ); if (!showTooltip) { return button; } return ( {button} {isPanelOpen ? "بستن" : "باز کردن"} {"\u2318"}B ); }); SidebarTrigger.displayName = "SidebarTrigger"; interface SidebarRailProps { railIcons: RailIconConfig[]; activeModuleId: string; onModuleChange: (moduleId: string) => void; } function SidebarRail({ railIcons, activeModuleId, onModuleChange, }: SidebarRailProps) { return (
{railIcons.map((item) => { const isActive = item.moduleId === activeModuleId; const Icon = item.icon; return ( {item.label} ); })}
حساب کاربری
); } function UserMenu() { return (

{data.user.name}

{data.user.email}

حساب کاربری صورتحساب اعلان‌ها خروج
); } function OrganizationSwitcher() { return ( سازمان‌ها {data.organization.name} ایجاد سازمان ); } function NotificationBell() { return ( ); } function NewActionButton() { return ( سند جدید پروژه جدید رویداد جدید ); } interface SidebarPanelProps { module: NavModuleConfig; utilities: NavItemConfig[]; } function isItemActive(_pathname: string, itemPath: string): boolean { return itemPath === "#" && _pathname === "#"; } function SidebarPanel({ module, utilities }: SidebarPanelProps) { const [setupOpen, setSetupOpen] = React.useState(false); const prefersReducedMotion = useReducedMotion(); const pathname = "#"; const primarySections = module.sections.filter( (s) => s.id !== "studio-setup", ); const setupSection = module.sections.find((s) => s.id === "studio-setup"); const isSetupActive = setupSection?.items.some((item) => isItemActive(pathname, item.path)) ?? false; React.useEffect(() => { if (isSetupActive) { setSetupOpen(true); } }, [isSetupActive]); return (
{primarySections.map((section) => (
{section.label && (
{section.label}
)}
))}
{(setupSection && setupSection.items.length > 0) || utilities.length > 0 ? (
{setupSection && setupSection.items.length > 0 && (
پیکربندی {setupOpen && ( {setupSection.items.map((item, i) => ( ))} )}
)} {utilities.length > 0 && (
)}
) : null}
); } function NavItem({ item, isActive, }: { item: NavItemConfig; isActive: boolean; }) { const isExternal = item.path.startsWith("http"); const Icon = item.icon; return ( {item.label} {isExternal && ( )} ); } function Area({ visible, direction = "right", children, }: { visible: boolean; direction?: "left" | "right"; children: React.ReactNode; }) { return (
{children}
); } function ContentArea({ activeModule }: { activeModule: NavModuleConfig }) { const { isPanelOpen } = useSidebar(); const showCornerFills = isPanelOpen; return (
); } interface DubSidebarProps { railIcons: RailIconConfig[]; activeModule: NavModuleConfig | null; activeModuleId: string; utilities: NavItemConfig[]; onModuleChange: (moduleId: string) => void; } function DubSidebar({ railIcons, activeModule, activeModuleId, utilities, onModuleChange, }: DubSidebarProps) { const { isPanelOpen } = useSidebar(); const hasContent = activeModule !== null; const showPanel = hasContent && isPanelOpen; return ( ); } interface MobileNavigationProps { open: boolean; onOpenChange: (open: boolean) => void; railIcons: RailIconConfig[]; activeModule: NavModuleConfig | null; activeModuleId: string; utilities: NavItemConfig[]; onModuleChange: (moduleId: string) => void; } function MobileNavigation({ open, onOpenChange, railIcons, activeModule, activeModuleId, utilities, onModuleChange, }: MobileNavigationProps) { const pathname = "#"; const handleItemSelect = () => onOpenChange(false); return ( <> {activeModule?.label ?? "پیمایش"} {activeModule ? ( <>
{activeModule.sections.map((section) => (
{section.label && (
{section.label}
)}
))}
{utilities.length > 0 && (
ابزارها
)} ) : null}
); } function MobileNavItem({ item, isActive, onSelect, }: { item: NavItemConfig; isActive: boolean; onSelect?: () => void; }) { const isExternal = item.path.startsWith("http"); const Icon = item.icon; return ( {item.label} {isExternal && ( )} ); } export const iframeHeight = "800px"; export const description = "سایدبار دوطبقه با تعویض سازمان و اعلان‌ها."; export function ApplicationShell12() { const [isMobilePanelOpen, setIsMobilePanelOpen] = React.useState(false); const [activeModuleId, setActiveModuleId] = React.useState("home"); const activeModule = React.useMemo( () => data.modules.find((m) => m.id === activeModuleId) ?? data.modules[0], [activeModuleId], ); return ( ); }