Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions apps/web-roo-code/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
},
"dependencies": {
"@radix-ui/react-dialog": "^1.1.15",
"@radix-ui/react-navigation-menu": "^1.2.14",
"@radix-ui/react-slot": "^1.2.4",
"@roo-code/evals": "workspace:^",
"@roo-code/types": "^1.108.0",
Expand Down
235 changes: 136 additions & 99 deletions apps/web-roo-code/src/components/chromes/nav-bar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,17 @@ import { EXTERNAL_LINKS } from "@/lib/constants"
import { useLogoSrc } from "@/lib/hooks/use-logo-src"
import { ScrollButton } from "@/components/ui"
import ThemeToggle from "@/components/chromes/theme-toggle"
import { Brain, ChevronDown, Cloud, Puzzle, Slack, X } from "lucide-react"
import { Brain, Cloud, Puzzle, Slack, X } from "lucide-react"
import {
NavigationMenu,
NavigationMenuContent,
NavigationMenuItem,
NavigationMenuLink,
NavigationMenuList,
NavigationMenuTrigger,
navigationMenuTriggerStyle,
} from "@/components/ui/navigation-menu"
import { cn } from "@/lib/utils"

function LinearIcon({ className }: { className?: string }) {
return (
Expand All @@ -30,115 +40,142 @@ interface NavBarProps {

export function NavBar({ stars, downloads }: NavBarProps) {
const [isMenuOpen, setIsMenuOpen] = useState(false)
const [openDropdown, setOpenDropdown] = useState<string | null>(null)
const logoSrc = useLogoSrc()

return (
<header className="sticky font-light top-0 z-50 border-b border-border bg-background/80 backdrop-blur-md">
<div className="container flex h-16 items-center justify-between px-4 sm:px-6 lg:px-8">
<div className="flex items-center">
<div className="flex items-center flex-shrink-0">
<Link href="/" className="flex items-center">
<Image src={logoSrc} alt="Roo Code Logo" width={130} height={24} className="h-[24px] w-auto" />
</Link>
</div>

{/* Desktop Navigation */}
<nav className="grow ml-6 hidden text-sm md:flex md:items-center">
{/* Product Dropdown */}
<div
className="relative"
onMouseEnter={() => setOpenDropdown("product")}
onMouseLeave={() => setOpenDropdown(null)}>
<button className="flex items-center px-4 py-6 gap-1 transition-transform duration-200 hover:scale-105 hover:text-foreground">
Product
<ChevronDown className="size-3 ml-1 mt-0.5" />
</button>
<div
className={`absolute left-0 top-12 mt-2 w-[260px] rounded-md border border-border bg-background py-1 shadow-lg transition-all duration-200 ${openDropdown === "product" ? "opacity-100 translate-y-0 pointer-events-auto" : "opacity-0 -translate-y-2 pointer-events-none"}`}>
<Link
href="/extension"
className="block px-4 py-2 text-sm transition-colors hover:bg-accent hover:text-foreground"
onClick={() => setOpenDropdown(null)}>
<Puzzle className="size-3 inline mr-2 -mt-0.5" />
Roo Code VS Code Extension
</Link>
<Link
href="/cloud"
className="block px-4 py-2 text-sm transition-colors hover:bg-accent hover:text-foreground"
onClick={() => setOpenDropdown(null)}>
<Cloud className="size-3 inline mr-2 -mt-0.5" />
Roo Code Cloud
</Link>
<Link
href="/slack"
className="block px-4 py-2 text-sm transition-colors hover:bg-accent hover:text-foreground"
onClick={() => setOpenDropdown(null)}>
<Slack className="size-3 inline mr-2 -mt-0.5" />
Roo Code for Slack
</Link>
<Link
href="/linear"
className="block px-4 py-2 text-sm transition-colors hover:bg-accent hover:text-foreground"
onClick={() => setOpenDropdown(null)}>
<LinearIcon className="size-3 inline mr-2 -mt-0.5" />
Roo Code for Linear
</Link>
<Link
href="/provider"
className="block px-4 py-2 text-sm transition-colors hover:bg-accent hover:text-foreground"
onClick={() => setOpenDropdown(null)}>
<Brain className="size-3 inline mr-2 -mt-0.5" />
Roo Code Router
</Link>
</div>
</div>
{/* Resources Dropdown */}
<div
className="relative"
onMouseEnter={() => setOpenDropdown("resources")}
onMouseLeave={() => setOpenDropdown(null)}>
<button className="flex items-center px-4 py-6 gap-1 transition-transform duration-200 hover:scale-105 hover:text-foreground">
Resources
<ChevronDown className="size-3 ml-1 mt-0.5" />
</button>
<div
className={`absolute left-0 top-12 mt-2 w-40 rounded-md border border-border bg-background py-1 shadow-lg transition-all duration-200 ${openDropdown === "resources" ? "opacity-100 translate-y-0 pointer-events-auto" : "opacity-0 -translate-y-2 pointer-events-none"}`}>
<Link
href="/evals"
className="block px-4 py-2 text-sm transition-colors hover:bg-accent hover:text-foreground"
onClick={() => setOpenDropdown(null)}>
Evals
</Link>
<a
href={EXTERNAL_LINKS.DISCORD}
target="_blank"
rel="noopener noreferrer"
className="block px-4 py-2 text-sm transition-colors hover:bg-accent hover:text-foreground"
onClick={() => setOpenDropdown(null)}>
Discord
</a>
<a
href={EXTERNAL_LINKS.SECURITY}
target="_blank"
rel="noopener noreferrer"
className="block px-4 py-2 text-sm transition-colors hover:bg-accent hover:text-foreground"
onClick={() => setOpenDropdown(null)}>
Trust Center
</a>
</div>
</div>
<a
href={EXTERNAL_LINKS.DOCUMENTATION}
target="_blank"
className="px-4 py-6 transition-transform duration-200 hover:scale-105 hover:text-foreground">
Docs
</a>
<Link
href="/pricing"
className="px-4 py-6 transition-transform duration-200 hover:scale-105 hover:text-foreground">
Pricing
</Link>
</nav>
<NavigationMenu className="grow ml-6 hidden text-sm md:flex">
<NavigationMenuList>
{/* Product Dropdown */}
<NavigationMenuItem>
<NavigationMenuTrigger className="bg-transparent font-light">Product</NavigationMenuTrigger>
<NavigationMenuContent>
<ul className="grid min-w-[260px] gap-1 p-2">
<li>
<NavigationMenuLink asChild>
<Link
href="/extension"
className="flex items-center select-none rounded-md px-3 py-2 text-sm leading-none no-underline outline-none transition-colors hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground">
<Puzzle className="size-3 mr-2" />
Roo Code VS Code Extension
</Link>
</NavigationMenuLink>
</li>
<li>
<NavigationMenuLink asChild>
<Link
href="/cloud"
className="flex items-center select-none rounded-md px-3 py-2 text-sm leading-none no-underline outline-none transition-colors hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground">
<Cloud className="size-3 mr-2" />
Roo Code Cloud
</Link>
</NavigationMenuLink>
</li>
<li>
<NavigationMenuLink asChild>
<Link
href="/slack"
className="flex items-center select-none rounded-md px-3 py-2 text-sm leading-none no-underline outline-none transition-colors hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground">
<Slack className="size-3 mr-2" />
Roo Code for Slack
</Link>
</NavigationMenuLink>
</li>
<li>
<NavigationMenuLink asChild>
<Link
href="/linear"
className="flex items-center select-none rounded-md px-3 py-2 text-sm leading-none no-underline outline-none transition-colors hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground">
<LinearIcon className="size-3 mr-2" />
Roo Code for Linear
</Link>
</NavigationMenuLink>
</li>
<li>
<NavigationMenuLink asChild>
<Link
href="/provider"
className="flex items-center select-none rounded-md px-3 py-2 text-sm leading-none no-underline outline-none transition-colors hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground">
<Brain className="size-3 mr-2" />
Roo Code Router
</Link>
</NavigationMenuLink>
</li>
</ul>
</NavigationMenuContent>
</NavigationMenuItem>

{/* Resources Dropdown */}
<NavigationMenuItem>
<NavigationMenuTrigger className="bg-transparent font-light">
Resources
</NavigationMenuTrigger>
<NavigationMenuContent>
<ul className="grid min-w-[260px] gap-1 p-2">
<li>
<NavigationMenuLink asChild>
<Link
href="/evals"
className="block select-none rounded-md px-3 py-2 text-sm leading-none no-underline outline-none transition-colors hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground">
Evals
</Link>
</NavigationMenuLink>
</li>
<li>
<NavigationMenuLink asChild>
<a
href={EXTERNAL_LINKS.DISCORD}
target="_blank"
rel="noopener noreferrer"
className="block select-none rounded-md px-3 py-2 text-sm leading-none no-underline outline-none transition-colors hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground">
Discord
</a>
</NavigationMenuLink>
</li>
<li>
<NavigationMenuLink asChild>
<a
href={EXTERNAL_LINKS.SECURITY}
target="_blank"
rel="noopener noreferrer"
className="block select-none rounded-md px-3 py-2 text-sm leading-none no-underline outline-none transition-colors hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground">
Trust Center
</a>
</NavigationMenuLink>
</li>
</ul>
</NavigationMenuContent>
</NavigationMenuItem>

{/* Docs Link */}
<NavigationMenuItem>
<NavigationMenuLink
asChild
className={cn(navigationMenuTriggerStyle(), "bg-transparent font-light")}>
<a href={EXTERNAL_LINKS.DOCUMENTATION} target="_blank">
Docs
</a>
</NavigationMenuLink>
</NavigationMenuItem>

{/* Pricing Link */}
<NavigationMenuItem>
<NavigationMenuLink
asChild
className={cn(navigationMenuTriggerStyle(), "bg-transparent font-light")}>
<Link href="/pricing">Pricing</Link>
</NavigationMenuLink>
</NavigationMenuItem>
</NavigationMenuList>
</NavigationMenu>

<div className="hidden md:flex md:items-center md:space-x-4 flex-shrink-0 font-medium">
<div className="flex flex-row space-x-2 flex-shrink-0">
Expand Down
117 changes: 117 additions & 0 deletions apps/web-roo-code/src/components/ui/navigation-menu.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
import * as React from "react"
import * as NavigationMenuPrimitive from "@radix-ui/react-navigation-menu"
import { cva } from "class-variance-authority"
import { ChevronDown } from "lucide-react"

import { cn } from "@/lib/utils"

const NavigationMenu = React.forwardRef<
React.ElementRef<typeof NavigationMenuPrimitive.Root>,
React.ComponentPropsWithoutRef<typeof NavigationMenuPrimitive.Root>
>(({ className, children, ...props }, ref) => (
<NavigationMenuPrimitive.Root
ref={ref}
className={cn("relative z-10 flex max-w-max flex-1 items-center", className)}
{...props}>
{children}
<NavigationMenuViewport />
</NavigationMenuPrimitive.Root>
))
NavigationMenu.displayName = NavigationMenuPrimitive.Root.displayName

const NavigationMenuList = React.forwardRef<
React.ElementRef<typeof NavigationMenuPrimitive.List>,
React.ComponentPropsWithoutRef<typeof NavigationMenuPrimitive.List>
>(({ className, ...props }, ref) => (
<NavigationMenuPrimitive.List
ref={ref}
className={cn("group flex flex-1 list-none items-center space-x-1", className)}
{...props}
/>
))
NavigationMenuList.displayName = NavigationMenuPrimitive.List.displayName

const NavigationMenuItem = NavigationMenuPrimitive.Item

const navigationMenuTriggerStyle = cva(
"group inline-flex h-9 w-max items-center justify-center rounded-md bg-background px-4 py-2 text-sm font-medium transition-colors hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground focus:outline-none disabled:pointer-events-none disabled:opacity-50 data-[state=open]:text-accent-foreground data-[state=open]:bg-accent/50 data-[state=open]:hover:bg-accent data-[state=open]:focus:bg-accent",
)

const NavigationMenuTrigger = React.forwardRef<
React.ElementRef<typeof NavigationMenuPrimitive.Trigger>,
React.ComponentPropsWithoutRef<typeof NavigationMenuPrimitive.Trigger>
>(({ className, children, ...props }, ref) => (
<NavigationMenuPrimitive.Trigger
ref={ref}
className={cn(navigationMenuTriggerStyle(), "group", className)}
{...props}>
{children}{" "}
<ChevronDown
className="relative top-[1px] ml-1 h-3 w-3 transition duration-300 group-data-[state=open]:rotate-180"
aria-hidden="true"
/>
</NavigationMenuPrimitive.Trigger>
))
NavigationMenuTrigger.displayName = NavigationMenuPrimitive.Trigger.displayName

const NavigationMenuContent = React.forwardRef<
React.ElementRef<typeof NavigationMenuPrimitive.Content>,
React.ComponentPropsWithoutRef<typeof NavigationMenuPrimitive.Content>
>(({ className, ...props }, ref) => (
<NavigationMenuPrimitive.Content
ref={ref}
className={cn(
"left-0 top-0 w-full data-[motion^=from-]:animate-in data-[motion^=to-]:animate-out data-[motion^=from-]:fade-in data-[motion^=to-]:fade-out data-[motion=from-end]:slide-in-from-right-52 data-[motion=from-start]:slide-in-from-left-52 data-[motion=to-end]:slide-out-to-right-52 data-[motion=to-start]:slide-out-to-left-52 md:absolute md:w-auto ",
className,
)}
{...props}
/>
))
NavigationMenuContent.displayName = NavigationMenuPrimitive.Content.displayName

const NavigationMenuLink = NavigationMenuPrimitive.Link

const NavigationMenuViewport = React.forwardRef<
React.ElementRef<typeof NavigationMenuPrimitive.Viewport>,
React.ComponentPropsWithoutRef<typeof NavigationMenuPrimitive.Viewport>
>(({ className, ...props }, ref) => (
<div className={cn("absolute left-0 top-full flex justify-center")}>
<NavigationMenuPrimitive.Viewport
className={cn(
"origin-top-center relative mt-1.5 h-[var(--radix-navigation-menu-viewport-height)] w-full overflow-hidden rounded-md border bg-popover text-popover-foreground shadow data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-90 md:w-[var(--radix-navigation-menu-viewport-width)]",
className,
)}
ref={ref}
{...props}
/>
</div>
))
NavigationMenuViewport.displayName = NavigationMenuPrimitive.Viewport.displayName

const NavigationMenuIndicator = React.forwardRef<
React.ElementRef<typeof NavigationMenuPrimitive.Indicator>,
React.ComponentPropsWithoutRef<typeof NavigationMenuPrimitive.Indicator>
>(({ className, ...props }, ref) => (
<NavigationMenuPrimitive.Indicator
ref={ref}
className={cn(
"top-full z-[1] flex h-1.5 items-end justify-center overflow-hidden data-[state=visible]:animate-in data-[state=hidden]:animate-out data-[state=hidden]:fade-out data-[state=visible]:fade-in",
className,
)}
{...props}>
<div className="relative top-[60%] h-2 w-2 rotate-45 rounded-tl-sm bg-border shadow-md" />
</NavigationMenuPrimitive.Indicator>
))
NavigationMenuIndicator.displayName = NavigationMenuPrimitive.Indicator.displayName

export {
navigationMenuTriggerStyle,
NavigationMenu,
NavigationMenuList,
NavigationMenuItem,
NavigationMenuContent,
NavigationMenuTrigger,
NavigationMenuLink,
NavigationMenuIndicator,
NavigationMenuViewport,
}
Loading
Loading