diff --git a/app/[locale]/page.tsx b/app/[locale]/page.tsx index b6e1316a797..7fa00381dfd 100644 --- a/app/[locale]/page.tsx +++ b/app/[locale]/page.tsx @@ -12,12 +12,14 @@ import type { } from "@/lib/types" import { CodeExample } from "@/lib/interfaces" +import ABTestWrapper from "@/components/AB/TestWrapper" import ActivityStats from "@/components/ActivityStats" import { ChevronNext } from "@/components/Chevron" import HomeHero from "@/components/Hero/HomeHero" import BentoCard from "@/components/Homepage/BentoCard" import CodeExamples from "@/components/Homepage/CodeExamples" import HomepageSectionImage from "@/components/Homepage/HomepageSectionImage" +import PersonaModalCTA from "@/components/Homepage/PersonaModalCTA" import { getBentoBoxItems } from "@/components/Homepage/utils" import ValuesMarqueeFallback from "@/components/Homepage/ValuesMarquee/Fallback" import BlockHeap from "@/components/icons/block-heap.svg" @@ -450,44 +452,60 @@ const Page = async ({ params }: { params: PageParams }) => {
-
- {subHeroCTAs.map( - ({ label, description, href, className, Svg }, idx) => { - const Link = ( - props: Omit< - SvgButtonLinkProps, - "Svg" | "href" | "label" | "children" - > - ) => ( - -

{description}

-
- ) - return ( - - - - - ) - } - )} -
+ + {subHeroCTAs.map( + ({ label, description, href, className, Svg }, idx) => { + const Link = ( + props: Omit< + SvgButtonLinkProps, + "Svg" | "href" | "label" | "children" + > + ) => ( + +

{description}

+
+ ) + return ( + + + + + ) + } + )} +
, + // Variation1: "Start here" button with persona modal +
+ +
, + ]} + /> {/* What is Ethereum */}
{ const [isOpen, setIsOpen] = useState(false) + const [mounted, setMounted] = useState(false) const [selectedVariant, setSelectedVariant] = useLocalStorage( `ab-test-${testKey}`, null @@ -27,10 +29,14 @@ export const ABTestDebugPanel = ({ useOnClickOutside(panelRef, () => setIsOpen(false)) + useEffect(() => { + setMounted(true) + }, []) + const forceVariant = (variantIndex: number) => setSelectedVariant(variantIndex) - return ( + const panelContent = (
) + + // Only render portal on client side after mount + if (!mounted) return null + + return createPortal(panelContent, document.body) } diff --git a/src/components/Hero/HomeHero/index.tsx b/src/components/Hero/HomeHero/index.tsx index 64ed56b4f85..683ced7545b 100644 --- a/src/components/Hero/HomeHero/index.tsx +++ b/src/components/Hero/HomeHero/index.tsx @@ -3,6 +3,7 @@ import { getLocale, getTranslations } from "next-intl/server" import type { ClassNameProp } from "@/lib/types" +import ABTestWrapper from "@/components/AB/TestWrapper" import LanguageMorpher from "@/components/Homepage/LanguageMorpher" import { cn } from "@/lib/utils/cn" @@ -68,13 +69,44 @@ const HomeHero = async ({
- -
-

{t("page-index-title")}

-

- {t("page-index-description")} -

-
+ + +
+

{t("page-index-title")}

+

+ {t("page-index-description")} +

+
+
, + // Variation1: New title/subtitle for persona modal +
+ +
+

+ The internet +
+ that belongs to you +

+

+ Create, own, build, connect, and transact. +
+ Ethereum is a network that everyone can use and anyone can + build on. +

+
+
, + ]} + /> ) diff --git a/src/components/Homepage/PersonaModalCTA.tsx b/src/components/Homepage/PersonaModalCTA.tsx new file mode 100644 index 00000000000..aedc5b6a994 --- /dev/null +++ b/src/components/Homepage/PersonaModalCTA.tsx @@ -0,0 +1,173 @@ +"use client" + +import { useState } from "react" +import { BookOpen, Building2, Code, ExternalLink } from "lucide-react" + +import { ChevronNext } from "@/components/Chevron" +import { Button } from "@/components/ui/buttons/Button" +import { + Dialog, + DialogContent, + DialogHeader, + DialogTitle, + DialogTrigger, +} from "@/components/ui/dialog-modal" +import { BaseLink } from "@/components/ui/Link" + +import { cn } from "@/lib/utils/cn" +import { trackCustomEvent } from "@/lib/utils/matomo" + +type PersonaLink = { + label: string + href: string + isExternal?: boolean +} + +type PersonaCategory = { + id: string + label: string + Icon: React.FC<{ className?: string }> + iconBgClass: string + iconColorClass: string + links: PersonaLink[] +} + +const categories: PersonaCategory[] = [ + { + id: "beginners", + label: "For beginners", + Icon: BookOpen, + iconBgClass: "bg-accent-a/20", + iconColorClass: "text-accent-a", + links: [ + { label: "What is Ethereum?", href: "/what-is-ethereum/" }, + { label: "Get a wallet", href: "/wallets/find-wallet/" }, + ], + }, + { + id: "developers", + label: "For developers", + Icon: Code, + iconBgClass: "bg-primary-low-contrast", + iconColorClass: "text-primary", + links: [ + { label: "Developer Hub", href: "/developers/" }, + { label: "Docs", href: "/developers/docs/" }, + ], + }, + { + id: "enterprise", + label: "For enterprise", + Icon: Building2, + iconBgClass: "bg-accent-c/20", + iconColorClass: "text-accent-c", + links: [ + { label: "Founders", href: "/founders/" }, + { + label: "Institutions", + href: "https://institutions.ethereum.org/", + isExternal: true, + }, + ], + }, +] + +type PersonaModalCTAProps = { + eventCategory: string +} + +const PersonaModalCTA = ({ eventCategory }: PersonaModalCTAProps) => { + const [isOpen, setIsOpen] = useState(false) + + const handleOpenChange = (open: boolean) => { + if (open) { + trackCustomEvent({ + eventCategory, + eventAction: "start here", + eventName: "start here", + }) + } + setIsOpen(open) + } + + const handleLinkClick = (label: string) => { + trackCustomEvent({ + eventCategory, + eventAction: "modal", + eventName: label, + }) + setIsOpen(false) + } + + return ( + + + + + + + + What brings you here? + + +
+ {categories.map( + ({ id, label, Icon, iconBgClass, iconColorClass, links }) => ( +
+ {/* Icon and Category Label */} +
+
+ +
+

+ {label} +

+
+ + {/* Links */} +
+ {links.map(({ label: linkLabel, href, isExternal }, idx) => ( +
+ {idx > 0 &&
} + handleLinkClick(linkLabel)} + hideArrow + className="group flex items-center justify-between text-xl font-bold text-primary no-underline transition-colors hover:text-primary-hover md:text-3xl" + {...(isExternal && { + target: "_blank", + rel: "noopener noreferrer", + })} + > + + {linkLabel} + {isExternal && ( + + )} + + + +
+ ))} +
+
+ ) + )} +
+ +
+ ) +} + +export default PersonaModalCTA