From 044ffbb84e1673cd7999e3c7cab30f1e22a3ad4f Mon Sep 17 00:00:00 2001 From: Kacper Wojciechowski <39823706+jog1t@users.noreply.github.com> Date: Mon, 28 Jul 2025 21:16:49 +0200 Subject: [PATCH] feat(site): add brand dropdown --- frontend/packages/components/package.json | 1 + frontend/packages/components/src/index.ts | 1 + .../components/src/ui/context-menu.tsx | 257 ++++++++++++++++++ site/src/components/v2/Header.tsx | 45 +-- site/src/components/v2/LogoContextMenu.tsx | 54 ++++ yarn.lock | 25 ++ 6 files changed, 363 insertions(+), 20 deletions(-) create mode 100644 frontend/packages/components/src/ui/context-menu.tsx create mode 100644 site/src/components/v2/LogoContextMenu.tsx diff --git a/frontend/packages/components/package.json b/frontend/packages/components/package.json index 5494e08b03..6dd1e47599 100644 --- a/frontend/packages/components/package.json +++ b/frontend/packages/components/package.json @@ -41,6 +41,7 @@ "@radix-ui/react-accordion": "^1.1.2", "@radix-ui/react-avatar": "^1.0.4", "@radix-ui/react-checkbox": "^1.1.5", + "@radix-ui/react-context-menu": "^2.2.15", "@radix-ui/react-dialog": "^1.1.7", "@radix-ui/react-dropdown-menu": "^2.1.7", "@radix-ui/react-label": "^2.1.3", diff --git a/frontend/packages/components/src/index.ts b/frontend/packages/components/src/index.ts index 1d8bf02ab5..8a6a97b1a7 100644 --- a/frontend/packages/components/src/index.ts +++ b/frontend/packages/components/src/index.ts @@ -71,6 +71,7 @@ export * from "./ui/kbd"; export * from "./ui/checkbox"; export { default as Filters } from "./ui/filters"; export * from "./ui/filters"; +export * from "./ui/context-menu"; export * from "./lib/utils"; export * from "./lib/filesize"; export * from "./lib/timing"; diff --git a/frontend/packages/components/src/ui/context-menu.tsx b/frontend/packages/components/src/ui/context-menu.tsx new file mode 100644 index 0000000000..35205c4e63 --- /dev/null +++ b/frontend/packages/components/src/ui/context-menu.tsx @@ -0,0 +1,257 @@ +"use client"; + +import type * as React from "react"; +import * as ContextMenuPrimitive from "@radix-ui/react-context-menu"; +import { Icon, faCheck, faChevronRight, faCircle } from "@rivet-gg/icons"; +import { cn } from "../lib/utils"; + +function ContextMenu({ + ...props +}: React.ComponentProps) { + return ; +} + +function ContextMenuTrigger({ + ...props +}: React.ComponentProps) { + return ( + + ); +} + +function ContextMenuGroup({ + ...props +}: React.ComponentProps) { + return ( + + ); +} + +function ContextMenuPortal({ + ...props +}: React.ComponentProps) { + return ( + + ); +} + +function ContextMenuSub({ + ...props +}: React.ComponentProps) { + return ; +} + +function ContextMenuRadioGroup({ + ...props +}: React.ComponentProps) { + return ( + + ); +} + +function ContextMenuSubTrigger({ + className, + inset, + children, + ...props +}: React.ComponentProps & { + inset?: boolean; +}) { + return ( + + {children} + + + ); +} + +function ContextMenuSubContent({ + className, + ...props +}: React.ComponentProps) { + return ( + + ); +} + +function ContextMenuContent({ + className, + ...props +}: React.ComponentProps) { + return ( + + + + ); +} + +function ContextMenuItem({ + className, + inset, + variant = "default", + ...props +}: React.ComponentProps & { + inset?: boolean; + variant?: "default" | "destructive"; +}) { + return ( + + ); +} + +function ContextMenuCheckboxItem({ + className, + children, + checked, + ...props +}: React.ComponentProps) { + return ( + + + + + + + {children} + + ); +} + +function ContextMenuRadioItem({ + className, + children, + ...props +}: React.ComponentProps) { + return ( + + + + + + + {children} + + ); +} + +function ContextMenuLabel({ + className, + inset, + ...props +}: React.ComponentProps & { + inset?: boolean; +}) { + return ( + + ); +} + +function ContextMenuSeparator({ + className, + ...props +}: React.ComponentProps) { + return ( + + ); +} + +function ContextMenuShortcut({ + className, + ...props +}: React.ComponentProps<"span">) { + return ( + + ); +} + +export { + ContextMenu, + ContextMenuTrigger, + ContextMenuContent, + ContextMenuItem, + ContextMenuCheckboxItem, + ContextMenuRadioItem, + ContextMenuLabel, + ContextMenuSeparator, + ContextMenuShortcut, + ContextMenuGroup, + ContextMenuPortal, + ContextMenuSub, + ContextMenuSubContent, + ContextMenuSubTrigger, + ContextMenuRadioGroup, +}; diff --git a/site/src/components/v2/Header.tsx b/site/src/components/v2/Header.tsx index 61f3758ffc..870839438d 100644 --- a/site/src/components/v2/Header.tsx +++ b/site/src/components/v2/Header.tsx @@ -12,6 +12,7 @@ import { type ReactNode, useEffect, useState } from "react"; import { usePathname } from "next/navigation"; import { GitHubDropdown } from "./GitHubDropdown"; import { HeaderSearch } from "./HeaderSearch"; +import { LogoContextMenu } from "./LogoContextMenu"; interface TextNavItemProps { href: string; @@ -100,16 +101,18 @@ export function Header({ - Rivet logo - + + + Rivet logo + + } subnav={subnav} support={ @@ -197,16 +200,18 @@ export function Header({ subnav ? "pb-2 md:pb-0 md:pt-4" : "md:py-4", )} logo={ - - Rivet logo - + + + Rivet logo + + } subnav={subnav} support={ diff --git a/site/src/components/v2/LogoContextMenu.tsx b/site/src/components/v2/LogoContextMenu.tsx new file mode 100644 index 0000000000..8fa7f2a73e --- /dev/null +++ b/site/src/components/v2/LogoContextMenu.tsx @@ -0,0 +1,54 @@ +"use client"; +import { useRef } from "react"; +import { + ContextMenu, + ContextMenuContent, + ContextMenuItem, + ContextMenuTrigger, + toast, +} from "@rivet-gg/components"; +import { Icon, faCopy, faDownload } from "@rivet-gg/icons"; + +import logoUrl from "@/images/rivet-logos/icon-text-white.svg"; + +interface LogoContextMenuProps { + children: React.ReactNode; +} + +export function LogoContextMenu({ children }: LogoContextMenuProps) { + const menuRef = useRef(null); + + const copyLogoAsSVG = async () => { + try { + const response = await fetch(logoUrl.src); + const svgContent = await response.text(); + + await navigator.clipboard.writeText(svgContent); + toast.success("Logo copied as SVG!"); + } catch (err) { + toast.error("Failed to copy logo as SVG."); + } + }; + + const downloadBrandAssets = () => { + window.open("https://releases.rivet.gg/press-kit.zip", "_blank"); + }; + + return ( + <> + + {children} + + + + Copy logo as SVG + + + + Download brand assets + + + + + ); +} diff --git a/yarn.lock b/yarn.lock index c71f47259c..954b19c337 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3311,6 +3311,30 @@ __metadata: languageName: node linkType: hard +"@radix-ui/react-context-menu@npm:^2.2.15": + version: 2.2.15 + resolution: "@radix-ui/react-context-menu@npm:2.2.15" + dependencies: + "@radix-ui/primitive": "npm:1.1.2" + "@radix-ui/react-context": "npm:1.1.2" + "@radix-ui/react-menu": "npm:2.1.15" + "@radix-ui/react-primitive": "npm:2.1.3" + "@radix-ui/react-use-callback-ref": "npm:1.1.1" + "@radix-ui/react-use-controllable-state": "npm:1.2.2" + peerDependencies: + "@types/react": "*" + "@types/react-dom": "*" + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + "@types/react": + optional: true + "@types/react-dom": + optional: true + checksum: 10c0/a49f053028ecc6b1703348b83fb066f2453d43a27633871dc9bc7f5d2a44473534364bae76aa70f8cc15423422a5ed41dc25409c8c3d8f75eb8d8eb746269cc4 + languageName: node + linkType: hard + "@radix-ui/react-context@npm:1.1.2": version: 1.1.2 resolution: "@radix-ui/react-context@npm:1.1.2" @@ -4357,6 +4381,7 @@ __metadata: "@radix-ui/react-accordion": "npm:^1.1.2" "@radix-ui/react-avatar": "npm:^1.0.4" "@radix-ui/react-checkbox": "npm:^1.1.5" + "@radix-ui/react-context-menu": "npm:^2.2.15" "@radix-ui/react-dialog": "npm:^1.1.7" "@radix-ui/react-dropdown-menu": "npm:^2.1.7" "@radix-ui/react-label": "npm:^2.1.3"