"use client"; import { AnimatePresence, motion } from "framer-motion"; import { Check } from "lucide-react"; import { usePathname, useRouter } from "next/navigation"; import { useEffect, useRef, useState } from "react"; import type { DocsVersion } from "@/lib/docs-versions"; import { docsVersions, getVersionFromPathname, stripVersionPrefix, versionedDocsHref, } from "@/lib/docs-versions"; export function VersionSwitcher({ className }: { className?: string }) { const pathname = usePathname() || "/docs"; const router = useRouter(); const [open, setOpen] = useState(false); const timeout = useRef(undefined); const containerRef = useRef(null); const currentVersion = getVersionFromPathname(pathname); useEffect(() => { function onClickOutside(e: MouseEvent) { if ( containerRef.current && !containerRef.current.contains(e.target as Node) ) { setOpen(false); } } if (open) { document.addEventListener("mousedown", onClickOutside); } return () => document.removeEventListener("mousedown", onClickOutside); }, [open]); function handleSelect(version: DocsVersion) { setOpen(false); if (version.slug === currentVersion.slug) return; const pagePath = stripVersionPrefix(pathname, currentVersion); const targetHref = versionedDocsHref(pagePath, version); router.push(targetHref); } const displayLabel = currentVersion.label; return (
{open && ( { clearTimeout(timeout.current); }} onMouseLeave={() => { timeout.current = setTimeout(() => setOpen(false), 150); }} className="absolute top-full right-0 z-50 min-w-[160px] border border-foreground/[0.08] bg-background shadow-2xl shadow-black/20 dark:shadow-black/60 py-1" > {docsVersions.map((version, i) => { const isActive = version.slug === currentVersion.slug; return ( handleSelect(version)} className="flex w-full items-center gap-2 px-3 py-1.5 hover:bg-foreground/[0.06] transition-colors duration-150 cursor-pointer" > {isActive && ( )} {version.label} {version.badge && ( {version.badge} )} ); })} )}
); } /** Simplified version for mobile — just a row of buttons. */ export function MobileVersionSwitcher() { const pathname = usePathname() || "/docs"; const router = useRouter(); const currentVersion = getVersionFromPathname(pathname); function handleSelect(version: DocsVersion) { if (version.slug === currentVersion.slug) return; const pagePath = stripVersionPrefix(pathname, currentVersion); router.push(versionedDocsHref(pagePath, version)); } return (
{docsVersions.map((version) => { const isActive = version.slug === currentVersion.slug; return ( ); })}
); } /** Version switcher for the docs sidebar — full-width popover dropdown below the search bar. */ export function SidebarVersionSwitcher() { const pathname = usePathname() || "/docs"; const router = useRouter(); const [open, setOpen] = useState(false); const containerRef = useRef(null); const currentVersion = getVersionFromPathname(pathname); useEffect(() => { function onClickOutside(e: MouseEvent) { if ( containerRef.current && !containerRef.current.contains(e.target as Node) ) { setOpen(false); } } if (open) { document.addEventListener("mousedown", onClickOutside); } return () => document.removeEventListener("mousedown", onClickOutside); }, [open]); function handleSelect(version: DocsVersion) { setOpen(false); if (version.slug === currentVersion.slug) return; const pagePath = stripVersionPrefix(pathname, currentVersion); router.push(versionedDocsHref(pagePath, version)); } return (
{open && ( {docsVersions.map((version) => { const isActive = version.slug === currentVersion.slug; return ( ); })} )}
); }