"use client"; import { AnimatePresence, motion } from "framer-motion"; import { SidebarProvider } from "fumadocs-ui/components/sidebar/base"; import type { SidebarTabWithProps } from "fumadocs-ui/components/sidebar/tabs/dropdown"; import { SidebarTabsDropdown } from "fumadocs-ui/components/sidebar/tabs/dropdown"; import { Check } from "lucide-react"; import { usePathname, useRouter } from "next/navigation"; import type { Dispatch, RefObject, SetStateAction } from "react"; import { useEffect, useMemo, useRef, useState } from "react"; import { useDocsVersions, useVersionAvailability } from "@/app/docs/provider"; import type { DocsVersion } from "@/lib/docs-versions"; import { getVersionFromPathname, getVersionTargetHref, } from "@/lib/docs-versions"; function useDismissablePopover( open: boolean, setOpen: Dispatch>, containerRef: RefObject, ) { useEffect(() => { if (!open) return; function onPointerDown(event: MouseEvent) { const target = event.target; if ( containerRef.current && target instanceof Node && !containerRef.current.contains(target) ) { setOpen(false); } } function onKeyDown(event: KeyboardEvent) { if (event.key === "Escape") setOpen(false); } document.addEventListener("mousedown", onPointerDown); document.addEventListener("keydown", onKeyDown); return () => { document.removeEventListener("mousedown", onPointerDown); document.removeEventListener("keydown", onKeyDown); }; }, [containerRef, open, setOpen]); } function getVersionTitle(version: DocsVersion) { if (version.id === "latest") return "Latest Version"; if (version.id === "beta") return "Beta Version"; return `Version ${version.id}`; } export function VersionSwitcher({ className }: { className?: string }) { const docsVersions = useDocsVersions(); const pathname = usePathname() || "/docs"; const router = useRouter(); const versionAvailability = useVersionAvailability(); const [open, setOpen] = useState(false); const timeout = useRef(undefined); const containerRef = useRef(null); const currentVersion = getVersionFromPathname(pathname); useDismissablePopover(open, setOpen, containerRef); useEffect( () => () => { window.clearTimeout(timeout.current); }, [], ); function handleSelect(version: DocsVersion) { setOpen(false); if (version.id === currentVersion.id) return; router.push( getVersionTargetHref( pathname, currentVersion, version, versionAvailability, ), ); } const displayLabel = currentVersion.label; return (
{open && ( { window.clearTimeout(timeout.current); }} onMouseLeave={() => { timeout.current = window.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" id="version-switcher-options" > {docsVersions.map((version, i) => { const isActive = version.id === currentVersion.id; 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} )} ); })} )}
); } function VersionTabsDropdown({ desktop = false }: { desktop?: boolean }) { const docsVersions = useDocsVersions(); const pathname = usePathname() || "/docs"; const versionAvailability = useVersionAvailability(); const currentVersion = getVersionFromPathname(pathname); const [viewportMode, setViewportMode] = useState<"desktop" | "mobile">(); useEffect(() => { const mediaQuery = window.matchMedia("(min-width: 1024px)"); const updateViewportMode = () => { setViewportMode(mediaQuery.matches ? "desktop" : "mobile"); }; mediaQuery.addEventListener("change", updateViewportMode); updateViewportMode(); return () => { mediaQuery.removeEventListener("change", updateViewportMode); }; }, []); const options = useMemo( () => docsVersions.map((version) => { const url = getVersionTargetHref( pathname, currentVersion, version, versionAvailability, ); return { title: getVersionTitle(version), description: version.releaseVersion, url, urls: new Set([url]), props: { className: "px-2", }, }; }), [currentVersion, docsVersions, pathname, versionAvailability], ); return ( ); } export function MobileVersionSwitcher() { return ; } export function SidebarVersionSwitcher() { return (
); }