aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/docs/components/LogoContext/index.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'docs/components/LogoContext/index.tsx')
-rw-r--r--docs/components/LogoContext/index.tsx169
1 files changed, 169 insertions, 0 deletions
diff --git a/docs/components/LogoContext/index.tsx b/docs/components/LogoContext/index.tsx
new file mode 100644
index 0000000..3f03740
--- /dev/null
+++ b/docs/components/LogoContext/index.tsx
@@ -0,0 +1,169 @@
+import { useEffect, useCallback, useState, useRef } from "react";
+import { useTheme } from "nextra-theme-docs";
+import Link from "next/link";
+import classNames from "classnames";
+import { VercelLogo } from "./icons";
+import { PRODUCT_MENU_ITEMS, PLATFORM_MENU_ITEMS } from "./items";
+import type { MenuItemProps } from "./types";
+import { MouseEvent } from "react";
+import { useTurboSite } from "../SiteSwitcher";
+
+function MenuDivider({ children, ...other }: { children: string }) {
+ return (
+ <h3
+ className={classNames(
+ "group flex items-center px-4 py-2 text-xs dark:text-gray-600 text-gray-500 font-bold"
+ )}
+ {...other}
+ >
+ {children}
+ </h3>
+ );
+}
+
+function MenuItem({
+ children,
+ prefix,
+ className,
+ type,
+ href,
+ onClick,
+ closeMenu,
+ disabled,
+ ...other
+}: MenuItemProps) {
+ const [copied, setCopied] = useState(false);
+
+ const handleClick = () => {
+ if (onClick) {
+ onClick();
+ }
+ if (type === "copy") {
+ setCopied(true);
+ } else {
+ closeMenu();
+ }
+ };
+
+ useEffect(() => {
+ if (copied) {
+ const timeout = setTimeout(() => {
+ setCopied(false);
+ closeMenu();
+ }, 2000);
+ return () => clearTimeout(timeout);
+ }
+ }, [copied, closeMenu]);
+
+ const classes = classNames(
+ className,
+ "group flex items-center px-4 py-2 text-sm dark:hover:bg-gray-800 hover:bg-gray-200 w-full rounded-md"
+ );
+ if (type === "internal") {
+ return (
+ <Link className={classes} href={href} onClick={handleClick} {...other}>
+ {prefix}
+ {children}
+ </Link>
+ );
+ }
+ if (type === "external") {
+ return (
+ <a
+ href={href}
+ onClick={handleClick}
+ target="_blank"
+ rel="noopener noreferrer"
+ className={classes}
+ {...other}
+ >
+ {prefix}
+ {children}
+ </a>
+ );
+ }
+
+ if (type === "copy") {
+ return (
+ <button
+ onClick={handleClick}
+ className={classes}
+ disabled={disabled}
+ {...other}
+ >
+ {prefix}
+ {copied ? "Copied to clipboard!" : children}
+ </button>
+ );
+ }
+}
+
+export function LogoContext() {
+ const [open, setOpen] = useState(false);
+ const site = useTurboSite();
+ const menu = useRef(null);
+ const { theme = "dark" } = useTheme();
+
+ const toggleMenu = (e: MouseEvent<HTMLButtonElement>) => {
+ e.preventDefault();
+ if (e.type === "contextmenu") {
+ setOpen((prev) => !prev);
+ } else {
+ setOpen(false);
+ window.open(`https://vercel.com`, "_blank");
+ }
+ };
+
+ const onClickOutside: EventListener = useCallback(
+ (e) => {
+ if (menu.current && open && !menu.current.contains(e.target)) {
+ setOpen(false);
+ }
+ },
+ [open]
+ );
+
+ useEffect(() => {
+ document.addEventListener("click", onClickOutside, true);
+ return () => {
+ document.removeEventListener("click", onClickOutside, true);
+ };
+ }, [onClickOutside]);
+
+ return (
+ <div className="block relative">
+ <button onClick={toggleMenu} onContextMenu={toggleMenu} className="flex">
+ <VercelLogo />
+ </button>
+ {open && (
+ <div
+ ref={menu}
+ className="absolute border dark:border-gray-700 left-6 z-10 mt-2 w-60 origin-top-right divide-y divide-gray-100 rounded-md bg-white dark:bg-black shadow-sm focus:outline-none"
+ >
+ <div className="p-2">
+ <MenuDivider>Platform</MenuDivider>
+ {PLATFORM_MENU_ITEMS({ theme, site }).map((item) => (
+ <MenuItem
+ key={item.name}
+ closeMenu={() => setOpen(false)}
+ {...item}
+ >
+ {item.children}
+ </MenuItem>
+ ))}
+ <MenuDivider>Products</MenuDivider>
+ {PRODUCT_MENU_ITEMS({ theme, site }).map((item) => (
+ <MenuItem
+ key={item.name}
+ closeMenu={() => setOpen(false)}
+ {...item}
+ >
+ {item.children}
+ </MenuItem>
+ ))}
+ </div>
+ </div>
+ )}
+ </div>
+ );
+}