From 4fd95e85c8c55fe385f64f78325a8fcd56276851 Mon Sep 17 00:00:00 2001 From: Mauricio Siu Date: Tue, 10 Mar 2026 11:54:50 -0600 Subject: [PATCH] feat: update navigation and pricing components for improved user experience - Enhanced the Header component with a new NavigationMenu for better organization of links. - Integrated a ContactFormModal in the EnterpriseLanding component for direct user engagement. - Added an FAQ section in the Pricing component using an Accordion for better information accessibility. - Updated dependencies in package.json and pnpm-lock.yaml for consistency and maintenance. --- apps/website/components/EnterpriseLanding.tsx | 13 +- apps/website/components/Header.tsx | 232 +++++++++++++----- apps/website/components/pricing.tsx | 73 ++++++ .../website/components/ui/navigation-menu.tsx | 137 +++++++++++ apps/website/package.json | 15 +- pnpm-lock.yaml | 11 +- 6 files changed, 407 insertions(+), 74 deletions(-) create mode 100644 apps/website/components/ui/navigation-menu.tsx diff --git a/apps/website/components/EnterpriseLanding.tsx b/apps/website/components/EnterpriseLanding.tsx index 4b2d224..357cc08 100644 --- a/apps/website/components/EnterpriseLanding.tsx +++ b/apps/website/components/EnterpriseLanding.tsx @@ -11,8 +11,10 @@ import { Shield, Users, } from "lucide-react"; +import { useState } from "react"; import Link from "next/link"; import { Container } from "./Container"; +import { ContactFormModal } from "./ContactFormModal"; import AnimatedGradientText from "./ui/animated-gradient-text"; import AnimatedGridPattern from "./ui/animated-grid-pattern"; import { Button } from "./ui/button"; @@ -74,8 +76,11 @@ const hostingOptions = [ ]; export function EnterpriseLanding() { + const [contactOpen, setContactOpen] = useState(false); + return (
+ {/* Hero Section */}
@@ -147,8 +152,8 @@ export function EnterpriseLanding() { animate={{ opacity: 1, y: 0 }} transition={{ duration: 0.3, delay: 0.4 }} > -

Questions? Email us at{" "} diff --git a/apps/website/components/Header.tsx b/apps/website/components/Header.tsx index ab74bf9..d45f29d 100644 --- a/apps/website/components/Header.tsx +++ b/apps/website/components/Header.tsx @@ -2,16 +2,23 @@ import { cn } from "@/lib/utils"; import { Popover, Transition } from "@headlessui/react"; -import { ChevronRight, HeartIcon } from "lucide-react"; +import { ChevronRight } from "lucide-react"; import Link from "next/link"; import { Fragment, type JSX, type SVGProps } from "react"; import { Container } from "./Container"; import GithubStars from "./GithubStars"; -import { NavLink } from "./NavLink"; import { trackGAEvent } from "./analitycs"; import { Logo } from "./shared/Logo"; -import AnimatedGradientText from "./ui/animated-gradient-text"; -import { Button, buttonVariants } from "./ui/button"; +import { Button } from "./ui/button"; +import { + NavigationMenu, + NavigationMenuContent, + NavigationMenuItem, + NavigationMenuLink, + NavigationMenuList, + NavigationMenuTrigger, + navigationMenuTriggerStyle, +} from "./ui/navigation-menu"; function MobileNavLink({ href, @@ -65,24 +72,6 @@ function MobileNavIcon({ open }: { open: boolean }) { ); } -const I18nIcon = (props: JSX.IntrinsicAttributes & SVGProps) => ( - - - -); - function MobileNavigation() { return ( @@ -116,33 +105,41 @@ function MobileNavigation() { > + Features Pricing - FAQ +


+

+ Solutions +

+ Enterprise + Partners +
Docs +
+

+ Resources +

+ Templates Blog + FAQ +
Contact - @@ -152,6 +149,49 @@ function MobileNavigation() { ); } +function ListItem({ + className, + title, + href, + target, + children, +}: { + className?: string; + title: string; + href: string; + target?: string; + children?: React.ReactNode; +}) { + return ( +
  • + + + trackGAEvent({ + action: "Nav Link Clicked", + category: "Navigation", + label: href, + }) + } + className={cn( + "block select-none space-y-1 rounded-md p-3 leading-none no-underline outline-none transition-colors hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground", + className, + )} + > +
    {title}
    + {children && ( +

    + {children} +

    + )} + +
    +
  • + ); +} + export function Header() { return (
    @@ -161,16 +201,102 @@ export function Header() { -
    - Pricing - FAQ - - Docs - - Blog +
    + + + + + + trackGAEvent({ + action: "Nav Link Clicked", + category: "Navigation", + label: "/#features", + }) + } + > + Features + + + + + + + + trackGAEvent({ + action: "Nav Link Clicked", + category: "Navigation", + label: "/pricing", + }) + } + > + Pricing + + + + + + Solutions + +
      + + Enterprise-grade deployment platform + + + Partner program and integrations + +
    +
    +
    + + + + + trackGAEvent({ + action: "Nav Link Clicked", + category: "Navigation", + label: "https://docs.dokploy.com/docs/core", + }) + } + > + Docs + + + + + + Resources + +
      + + Ready-to-deploy templates + + + Latest news and updates + + + Frequently asked questions + +
    +
    +
    +
    +
    @@ -208,20 +334,6 @@ export function Header() { - {/* - - {t("navigation.support")}{" "} - - - */} -
    + + {/* Pricing FAQ */} +
    +

    + Frequently asked questions +

    +

    + Have a different question? Contact us via Discord or email. +

    + + {pricingFaqs.map((faq, index) => ( + + + {faq.question} + + {faq.answer} + + ))} + +
    , + React.ComponentPropsWithoutRef +>(({ className, children, ...props }, ref) => ( + + {children} + +)) +NavigationMenu.displayName = NavigationMenuPrimitive.Root.displayName + +const NavigationMenuList = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +NavigationMenuList.displayName = NavigationMenuPrimitive.List.displayName + +const NavigationMenuItem = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +NavigationMenuItem.displayName = NavigationMenuPrimitive.Item.displayName + +const navigationMenuTriggerStyle = cva( + "group inline-flex h-10 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, + React.ComponentPropsWithoutRef +>(({ className, children, ...props }, ref) => ( + + {children}{" "} + +)) +NavigationMenuTrigger.displayName = NavigationMenuPrimitive.Trigger.displayName + +const NavigationMenuContent = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +NavigationMenuContent.displayName = NavigationMenuPrimitive.Content.displayName + +const NavigationMenuLink = NavigationMenuPrimitive.Link + +const NavigationMenuViewport = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( +
    + +
    +)) +NavigationMenuViewport.displayName = + NavigationMenuPrimitive.Viewport.displayName + +const NavigationMenuIndicator = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +
    + +)) +NavigationMenuIndicator.displayName = + NavigationMenuPrimitive.Indicator.displayName + +export { + navigationMenuTriggerStyle, + NavigationMenu, + NavigationMenuList, + NavigationMenuItem, + NavigationMenuContent, + NavigationMenuTrigger, + NavigationMenuLink, + NavigationMenuIndicator, + NavigationMenuViewport, +} diff --git a/apps/website/package.json b/apps/website/package.json index f0c4ae5..4497acd 100644 --- a/apps/website/package.json +++ b/apps/website/package.json @@ -12,12 +12,14 @@ }, "browserslist": "defaults, not ie <= 11", "dependencies": { - "@next/third-parties": "16.0.7", - "hast-util-to-jsx-runtime": "^2.3.5", "@headlessui/react": "^2.2.0", "@headlessui/tailwindcss": "^0.2.0", + "@next/third-parties": "16.0.7", + "@prettier/plugin-xml": "^3.4.1", "@radix-ui/react-accordion": "^1.2.1", "@radix-ui/react-avatar": "^1.1.1", + "@radix-ui/react-dialog": "1.1.15", + "@radix-ui/react-navigation-menu": "^1.2.14", "@radix-ui/react-scroll-area": "^1.2.0", "@radix-ui/react-select": "^2.0.0", "@radix-ui/react-slot": "^1.0.2", @@ -26,17 +28,17 @@ "@radix-ui/react-tooltip": "^1.1.3", "@tabler/icons-react": "3.21.0", "@tryghost/content-api": "^1.11.21", - "@radix-ui/react-dialog":"1.1.15", "@types/node": "20.4.6", "@types/turndown": "^5.0.5", "autoprefixer": "^10.4.12", "axios": "^1.8.1", - "resend": "6.5.2", "class-variance-authority": "^0.7.0", "clsx": "^2.1.0", "framer-motion": "^11.3.19", + "hast-util-to-jsx-runtime": "^2.3.5", "lucide-react": "0.364.0", "next": "16.1.5", + "prettier": "^3.3.3", "react": "^19.2.0", "react-dom": "^19.2.0", "react-ga4": "^2.1.0", @@ -45,6 +47,7 @@ "rehype-raw": "^7.0.0", "remark-gfm": "^4.0.1", "remark-toc": "^9.0.0", + "resend": "6.5.2", "satori": "^0.12.1", "sharp": "^0.33.5", "shiki": "^3.20.0", @@ -54,9 +57,7 @@ "tailwindcss-animate": "^1.0.7", "turndown": "^7.2.0", "turndown-plugin-gfm": "^1.0.2", - "typescript": "5.1.6", - "prettier": "^3.3.3", - "@prettier/plugin-xml": "^3.4.1" + "typescript": "5.1.6" }, "devDependencies": { "@babel/core": "^7.26.9", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e486724..0a82a6f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -32,7 +32,7 @@ importers: dependencies: '@next/third-parties': specifier: 16.0.7 - version: 16.0.7(next@16.1.5(@babel/core@7.26.9)(react-dom@19.2.1(react@19.2.1))(react@19.2.1))(react@19.2.1) + version: 16.0.7(next@16.1.5(react-dom@19.2.1(react@19.2.1))(react@19.2.1))(react@19.2.1) '@radix-ui/react-dropdown-menu': specifier: ^2.1.16 version: 2.1.16(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.1(react@19.2.1))(react@19.2.1) @@ -111,7 +111,7 @@ importers: version: 0.2.1(tailwindcss@3.4.7) '@next/third-parties': specifier: 16.0.7 - version: 16.0.7(next@16.1.5(@babel/core@7.26.9)(react-dom@19.2.1(react@19.2.1))(react@19.2.1))(react@19.2.1) + version: 16.0.7(next@16.1.5(react-dom@19.2.1(react@19.2.1))(react@19.2.1))(react@19.2.1) '@prettier/plugin-xml': specifier: ^3.4.1 version: 3.4.1(prettier@3.3.3) @@ -124,6 +124,9 @@ importers: '@radix-ui/react-dialog': specifier: 1.1.15 version: 1.1.15(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + '@radix-ui/react-navigation-menu': + specifier: ^1.2.14 + version: 1.2.14(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.1(react@19.2.1))(react@19.2.1) '@radix-ui/react-scroll-area': specifier: ^1.2.0 version: 1.2.0(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.1(react@19.2.1))(react@19.2.1) @@ -2916,6 +2919,7 @@ packages: git-raw-commits@4.0.0: resolution: {integrity: sha512-ICsMM1Wk8xSGMowkOmPrzo2Fgmfo4bMHLNX6ytHjajRJUqvHOw/TFapQ+QG75c3X/tTDDhOSRPGC52dDbNM8FQ==} engines: {node: '>=16'} + deprecated: This package is no longer maintained. For the JavaScript API, please use @conventional-changelog/git-client instead. hasBin: true github-slugger@2.0.0: @@ -2931,6 +2935,7 @@ packages: glob@10.4.5: resolution: {integrity: sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==} + deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me hasBin: true global-directory@4.0.1: @@ -5160,7 +5165,7 @@ snapshots: '@next/swc-win32-x64-msvc@16.1.5': optional: true - '@next/third-parties@16.0.7(next@16.1.5(@babel/core@7.26.9)(react-dom@19.2.1(react@19.2.1))(react@19.2.1))(react@19.2.1)': + '@next/third-parties@16.0.7(next@16.1.5(react-dom@19.2.1(react@19.2.1))(react@19.2.1))(react@19.2.1)': dependencies: next: 16.1.5(@babel/core@7.26.9)(react-dom@19.2.1(react@19.2.1))(react@19.2.1) react: 19.2.1