diff --git a/components/dashboard/Sidebar.tsx b/components/dashboard/Sidebar.tsx index dca4d4b..d852bd1 100644 --- a/components/dashboard/Sidebar.tsx +++ b/components/dashboard/Sidebar.tsx @@ -1,6 +1,7 @@ 'use client' import { useState, useEffect, useRef, useCallback } from 'react' +import { createPortal } from 'react-dom' import Link from 'next/link' import { usePathname, useRouter } from 'next/navigation' import { listSites, type Site } from '@/lib/api/sites' @@ -80,6 +81,45 @@ function Label({ children, collapsed }: { children: React.ReactNode; collapsed: ) } +// ─── Sidebar Tooltip (portal-based, escapes overflow-hidden) ── + +function SidebarTooltip({ children, label }: { children: React.ReactNode; label: string }) { + const [show, setShow] = useState(false) + const [pos, setPos] = useState({ x: 0, y: 0 }) + const ref = useRef(null) + const timerRef = useRef>(undefined) + + const handleEnter = () => { + timerRef.current = setTimeout(() => { + if (ref.current) { + const rect = ref.current.getBoundingClientRect() + setPos({ x: rect.right + 8, y: rect.top + rect.height / 2 }) + setShow(true) + } + }, 100) + } + + const handleLeave = () => { + clearTimeout(timerRef.current) + setShow(false) + } + + return ( +
+ {children} + {show && typeof document !== 'undefined' && createPortal( + + {label} + , + document.body + )} +
+ ) +} + // ─── Nav Item ─────────────────────────────────────────────── function NavLink({ @@ -94,29 +134,25 @@ function NavLink({ const matchesPending = pendingHref !== null && (item.matchPrefix ? pendingHref.startsWith(href) : pendingHref === href) const active = matchesPathname || matchesPending - return ( -
- { onNavigate(href); onClick?.() }} - className={`flex items-center gap-2.5 rounded-lg px-2.5 py-2 text-sm font-medium overflow-hidden transition-all duration-150 ${ - active - ? 'bg-brand-orange/10 text-brand-orange' - : 'text-neutral-400 hover:text-white hover:bg-white/[0.06] hover:translate-x-0.5' - }`} - > - - - - - - {collapsed && ( - - {item.label} - - )} -
+ const link = ( + { onNavigate(href); onClick?.() }} + className={`flex items-center gap-2.5 rounded-lg px-2.5 py-2 text-sm font-medium overflow-hidden transition-all duration-150 ${ + active + ? 'bg-brand-orange/10 text-brand-orange' + : 'text-neutral-400 hover:text-white hover:bg-white/[0.06] hover:translate-x-0.5' + }`} + > + + + + + ) + + if (collapsed) return {link} + return link } // ─── Settings Button (opens unified modal instead of navigating) ───── @@ -128,27 +164,23 @@ function SettingsButton({ }) { const { openUnifiedSettings } = useUnifiedSettings() - return ( -
- - {collapsed && ( - - {item.label} - - )} -
+ const btn = ( + ) + + if (collapsed) return {btn} + return btn } // ─── Home Nav Link (static href, no siteId) ─────────────── @@ -162,30 +194,26 @@ function HomeNavLink({ const pathname = usePathname() const active = !external && pathname === href - return ( -
- - - - - - - {collapsed && ( - - {label} - - )} -
+ const link = ( + + + + + + ) + + if (collapsed) return {link} + return link } // ─── Home Site Link (favicon + name) ─────────────────────── @@ -199,33 +227,29 @@ function HomeSiteLink({ const href = `/sites/${site.id}` const active = pathname.startsWith(href) - return ( -
- - - - - - - {collapsed && ( - - {site.name} - - )} -
+ const link = ( + + + + + + ) + + if (collapsed) return {link} + return link } // ─── Sidebar Content ──────────────────────────────────────── @@ -354,17 +378,36 @@ function SidebarContent({
{/* Notifications, Profile — same layout as nav items */}
-
+ {c ? ( + + + + + + ) : ( - {c && ( - - Notifications - - )} -
-
+ )} + {c ? ( + + router.push('/onboarding')} + allowPersonalOrganization={false} + onOpenSettings={openSettings} + onOpenOrgSettings={openOrgSettings} + compact + anchor="right" + > + + + + ) : ( - {c && ( - - {user?.display_name?.trim() || 'Profile'} - - )} -
+ )}