"use client" import type React from "react" import { useState, useRef, useEffect } from "react" import { createPortal } from "react-dom" import { Button } from "@/components/ui/button" import { SectionHeading } from "@/components/ui/section-heading" import { ComponentContainer } from "@/components/ui/component-container" import { User, Settings, CreditCard, UserPlus, Cloud, LogOut, ChevronRight, Check, Laptop, Moon, Sun, } from "lucide-react" // Update the DropdownsSection component to include a properties toggle export function DropdownsSection() { return (
(
)} generateCode={(props) => ` My Account Profile ⇧⌘P Billing ⌘B Settings Account Notifications Appearance Show notifications Theme Light Dark System `} />
) } type DropdownAlignment = "left" | "right" interface EnhancedDropdownProps { alignment?: DropdownAlignment } function EnhancedDropdown({ alignment = "left" }: EnhancedDropdownProps) { const [isOpen, setIsOpen] = useState(false) const [showNotifications, setShowNotifications] = useState(true) const [theme, setTheme] = useState("system") const [position, setPosition] = useState({ top: 0, left: 0, transformOrigin: "top left" }) const [mounted, setMounted] = useState(false) const [activeSubmenu, setActiveSubmenu] = useState(null) const [submenuPosition, setSubmenuPosition] = useState({ top: 0, left: 0 }) const buttonRef = useRef(null) const dropdownRef = useRef(null) const submenuTriggerRef = useRef(null) // Mount effect useEffect(() => { setMounted(true) return () => setMounted(false) }, []) // Update position when dropdown opens or alignment changes useEffect(() => { if (isOpen && buttonRef.current) { const updatePosition = () => { if (!buttonRef.current) return const rect = buttonRef.current.getBoundingClientRect() const viewportWidth = window.innerWidth const viewportHeight = window.innerHeight const dropdownWidth = 224 // 14rem = 224px const gap = 16 // 1rem gap from edges // Estimate dropdown height (will be refined once it renders) const estimatedHeight = dropdownRef.current?.offsetHeight || 400 // Calculate horizontal position based on alignment let left: number if (alignment === "left") { left = rect.left // Ensure dropdown doesn't overflow right edge if (left + dropdownWidth > viewportWidth - gap) { left = Math.max(gap, viewportWidth - dropdownWidth - gap) } } else { // Right alignment left = rect.right - dropdownWidth // Ensure dropdown doesn't overflow left edge if (left < gap) { left = gap } } // Calculate available space below and above const spaceBelow = viewportHeight - rect.bottom - gap const spaceAbove = rect.top - gap let top: number let transformOrigin: string // Default: position below button if there's enough space if (spaceBelow >= estimatedHeight || spaceBelow >= spaceAbove) { top = rect.bottom + 8 // 8px gap between button and dropdown transformOrigin = alignment === "left" ? "top left" : "top right" // Ensure dropdown doesn't overflow bottom edge if (top + estimatedHeight > viewportHeight - gap) { // Adjust height to fit available space with gap const maxHeight = viewportHeight - top - gap if (dropdownRef.current) { dropdownRef.current.style.maxHeight = `${maxHeight}px` dropdownRef.current.style.overflowY = "auto" } } } else { // Position above button if more space above than below top = rect.top - 8 - estimatedHeight // 8px gap between button and dropdown transformOrigin = alignment === "left" ? "bottom left" : "bottom right" // Ensure dropdown doesn't overflow top edge if (top < gap) { top = gap const maxHeight = rect.top - gap - 8 if (dropdownRef.current) { dropdownRef.current.style.maxHeight = `${maxHeight}px` dropdownRef.current.style.overflowY = "auto" } } } setPosition({ top, left, transformOrigin }) } // Initial position calculation updatePosition() // Recalculate position when window is resized window.addEventListener("resize", updatePosition) // Cleanup return () => { window.removeEventListener("resize", updatePosition) } } }, [isOpen, alignment]) // Update submenu position when active useEffect(() => { if (activeSubmenu && submenuTriggerRef.current) { const rect = submenuTriggerRef.current.getBoundingClientRect() const viewportWidth = window.innerWidth const submenuWidth = 180 // Approximate width // Position to the right of the parent menu by default // Add a -4px (px-1) overlap by subtracting 4px from the right position let left = rect.right - 4 // If it would go off the right edge, position to the left with overlap if (left + submenuWidth > viewportWidth - 16) { left = rect.left - submenuWidth + 4 } setSubmenuPosition({ top: rect.top - 1, // Slight vertical adjustment for better alignment left, }) } }, [activeSubmenu]) // Toggle dropdown const toggleDropdown = () => { setIsOpen(!isOpen) setActiveSubmenu(null) // Close any open submenu } // Close dropdown const closeDropdown = () => { setIsOpen(false) setActiveSubmenu(null) } // Handle menu item click const handleMenuItemClick = (action: string) => { console.log(`Action: ${action}`) closeDropdown() } // Toggle checkbox const toggleNotifications = () => { setShowNotifications(!showNotifications) } // Set theme const handleThemeChange = (newTheme: string) => { setTheme(newTheme) } // Toggle submenu const toggleSubmenu = (name: string) => { setActiveSubmenu(activeSubmenu === name ? null : name) } return (
{/* Trigger button */} {/* Portal dropdown */} {mounted && isOpen && createPortal( <> {/* Backdrop for closing dropdown when clicking outside */}
{/* Dropdown content */}
{/* Account section */}
My Account
{/* Settings submenu trigger */}
toggleSubmenu("settings")} >
Settings
{/* Team section */}
{/* Notifications checkbox */}
{/* Theme section */}
Theme
{/* Logout */}
{/* Submenu */} {activeSubmenu === "settings" && (
)} , document.body, )}
) } // Import missing icons function Bell(props: React.SVGProps) { return ( ) } function Circle(props: React.SVGProps) { return ( ) }