"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 (
)
}