diff --git a/app/[locale]/assets/_components/assets.tsx b/app/[locale]/assets/_components/assets.tsx index 7b4fd39e058..b6802faef41 100644 --- a/app/[locale]/assets/_components/assets.tsx +++ b/app/[locale]/assets/_components/assets.tsx @@ -54,10 +54,10 @@ import finance from "@/public/images/finance_transparent.png" import future from "@/public/images/future_transparent.png" import hackathon from "@/public/images/hackathon_transparent.png" import communityHero from "@/public/images/heroes/community-hero.png" -import developersHero from "@/public/images/heroes/developers-hub-hero.jpg" +import developersHero from "@/public/images/heroes/developers-hub-hero.png" import garden from "@/public/images/heroes/garden.jpg" import guidesHero from "@/public/images/heroes/guides-hub-hero.jpg" -import layer2Hero from "@/public/images/heroes/layer-2-hub-hero.jpg" +import layer2Hero from "@/public/images/heroes/layer-2-hub-hero.png" import learnHero from "@/public/images/heroes/learn-hub-hero.png" import quizzesHub from "@/public/images/heroes/quizzes-hub-hero.png" import roadmapHero from "@/public/images/heroes/roadmap-hub-hero.jpg" diff --git a/app/[locale]/developers/page.tsx b/app/[locale]/developers/page.tsx index bfc61028a56..251b802a384 100644 --- a/app/[locale]/developers/page.tsx +++ b/app/[locale]/developers/page.tsx @@ -33,7 +33,7 @@ import scaffoldDebugScreenshot from "@/public/images/developers/scaffold-debug-s import stackExchangeScreenshot from "@/public/images/developers/stack-exchange-screenshot.png" import tutorialTagsBanner from "@/public/images/developers/tutorial-tags-banner.png" import dogeImage from "@/public/images/doge-computer.png" -import heroImage from "@/public/images/heroes/developers-hub-hero.jpg" +import heroImage from "@/public/images/heroes/developers-hub-hero.png" const H3 = (props: ChildOnlyProp) =>

diff --git a/app/[locale]/layer-2/_components/layer-2.tsx b/app/[locale]/layer-2/_components/layer-2.tsx index 7216a7c88db..ea7c4fdcc3f 100644 --- a/app/[locale]/layer-2/_components/layer-2.tsx +++ b/app/[locale]/layer-2/_components/layer-2.tsx @@ -14,7 +14,7 @@ import InlineLink from "@/components/ui/Link" import { Rollups } from "@/data/networks/networks" import useTranslation from "@/hooks/useTranslation" -import HeroImage from "@/public/images/heroes/layer-2-hub-hero.jpg" +import HeroImage from "@/public/images/heroes/layer-2-hub-hero.png" import EthereumLogo from "@/public/images/layer-2/ethereum.png" import WalkingImage from "@/public/images/layer-2/layer-2-walking.png" import ExploreImage from "@/public/images/layer-2/learn-hero.png" diff --git a/app/[locale]/page.tsx b/app/[locale]/page.tsx index 1df7621e4f6..c15d7465062 100644 --- a/app/[locale]/page.tsx +++ b/app/[locale]/page.tsx @@ -16,6 +16,7 @@ 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 { getBentoBoxItems } from "@/components/Homepage/utils" import ValuesMarqueeFallback from "@/components/Homepage/ValuesMarquee/Fallback" import BlockHeap from "@/components/icons/block-heap.svg" @@ -89,11 +90,6 @@ import { fetchRSS } from "@/lib/api/fetchRSS" import { fetchTotalEthStaked } from "@/lib/api/fetchTotalEthStaked" import { fetchTotalValueLocked } from "@/lib/api/fetchTotalValueLocked" import EventFallback from "@/public/images/events/event-placeholder.png" -import BuildersImage from "@/public/images/heroes/developers-hub-hero.jpg" -import ActivityImage from "@/public/images/heroes/layer-2-hub-hero.jpg" -import LearnImage from "@/public/images/heroes/learn-hub-hero.png" -import CommunityImage from "@/public/images/heroes/quizzes-hub-hero.png" -import Hero from "@/public/images/home/hero.png" const BentoCardSwiper = dynamic( () => import("@/components/Homepage/BentoCardSwiper"), @@ -427,7 +423,7 @@ const Page = async ({ params }: { params: Promise<{ locale: Lang }> }) => { return ( - +
{subHeroCTAs.map( @@ -507,7 +503,7 @@ const Page = async ({ params }: { params: Promise<{ locale: Lang }> }) => { {/* Activity - The strongest ecosystem */}
- + @@ -556,7 +552,7 @@ const Page = async ({ params }: { params: Promise<{ locale: Lang }> }) => { className="md:flex-row-reverse" > - + @@ -637,7 +633,7 @@ const Page = async ({ params }: { params: Promise<{ locale: Lang }> }) => { {/* Builders - Blockchain's biggest builder community */}
- + @@ -690,7 +686,7 @@ const Page = async ({ params }: { params: Promise<{ locale: Lang }> }) => { className="md:flex-row-reverse" > - + diff --git a/app/[locale]/start/page.tsx b/app/[locale]/start/page.tsx index d4125d17867..33ec5cf8cc4 100644 --- a/app/[locale]/start/page.tsx +++ b/app/[locale]/start/page.tsx @@ -17,7 +17,7 @@ import { getMetadata } from "@/lib/utils/metadata" import { getRequiredNamespacesForPage } from "@/lib/utils/translations" import { getNewToCryptoWallets } from "@/lib/utils/wallets" -import HeroImage from "@/public/images/heroes/developers-hub-hero.jpg" +import HeroImage from "@/public/images/heroes/developers-hub-hero.png" import ManDogeImage from "@/public/images/start-with-ethereum/man-doge-playing.png" const Page = async ({ params }: { params: Promise<{ locale: Lang }> }) => { @@ -92,7 +92,7 @@ export async function generateMetadata({ slug: ["start"], title: t("page-start-meta-title"), description: t("page-start-meta-description"), - image: "/images/heroes/developers-hub-hero.jpg", + image: "/images/heroes/developers-hub-hero.png", }) } diff --git a/public/images/heroes/developers-hub-hero-portrait.png b/public/images/heroes/developers-hub-hero-portrait.png new file mode 100644 index 00000000000..76a6e8a00f6 Binary files /dev/null and b/public/images/heroes/developers-hub-hero-portrait.png differ diff --git a/public/images/heroes/developers-hub-hero.jpg b/public/images/heroes/developers-hub-hero.jpg deleted file mode 100644 index abdf671a49f..00000000000 Binary files a/public/images/heroes/developers-hub-hero.jpg and /dev/null differ diff --git a/public/images/heroes/developers-hub-hero.png b/public/images/heroes/developers-hub-hero.png new file mode 100644 index 00000000000..46c26c8de88 Binary files /dev/null and b/public/images/heroes/developers-hub-hero.png differ diff --git a/public/images/heroes/layer-2-hub-hero-portrait.png b/public/images/heroes/layer-2-hub-hero-portrait.png new file mode 100644 index 00000000000..7069d1a78fb Binary files /dev/null and b/public/images/heroes/layer-2-hub-hero-portrait.png differ diff --git a/public/images/heroes/layer-2-hub-hero.jpg b/public/images/heroes/layer-2-hub-hero.jpg deleted file mode 100644 index 9554c185756..00000000000 Binary files a/public/images/heroes/layer-2-hub-hero.jpg and /dev/null differ diff --git a/public/images/heroes/layer-2-hub-hero.png b/public/images/heroes/layer-2-hub-hero.png new file mode 100644 index 00000000000..77a18fcab4c Binary files /dev/null and b/public/images/heroes/layer-2-hub-hero.png differ diff --git a/public/images/heroes/learn-hub-hero-portrait.png b/public/images/heroes/learn-hub-hero-portrait.png new file mode 100644 index 00000000000..cf26aa0ec7c Binary files /dev/null and b/public/images/heroes/learn-hub-hero-portrait.png differ diff --git a/public/images/heroes/learn-hub-hero.png b/public/images/heroes/learn-hub-hero.png index 41b03361cda..42417c0b9df 100644 Binary files a/public/images/heroes/learn-hub-hero.png and b/public/images/heroes/learn-hub-hero.png differ diff --git a/public/images/heroes/quizzes-hub-hero-portrait.png b/public/images/heroes/quizzes-hub-hero-portrait.png new file mode 100644 index 00000000000..f2b41fbd1ff Binary files /dev/null and b/public/images/heroes/quizzes-hub-hero-portrait.png differ diff --git a/public/images/heroes/quizzes-hub-hero.png b/public/images/heroes/quizzes-hub-hero.png index 41163b0bc7f..0e07cb21343 100644 Binary files a/public/images/heroes/quizzes-hub-hero.png and b/public/images/heroes/quizzes-hub-hero.png differ diff --git a/public/images/home/hero-2xl.png b/public/images/home/hero-2xl.png new file mode 100644 index 00000000000..42c97e3c7a9 Binary files /dev/null and b/public/images/home/hero-2xl.png differ diff --git a/public/images/home/hero.png b/public/images/home/hero.png index ae5670ad9ef..38817ab859d 100644 Binary files a/public/images/home/hero.png and b/public/images/home/hero.png differ diff --git a/src/components/Hero/HomeHero/HomeHero.stories.tsx b/src/components/Hero/HomeHero/HomeHero.stories.tsx new file mode 100644 index 00000000000..cc51a78dff1 --- /dev/null +++ b/src/components/Hero/HomeHero/HomeHero.stories.tsx @@ -0,0 +1,24 @@ +import { Meta, StoryObj } from "@storybook/react" + +import { langViewportModes } from "@/storybook/modes" + +import HomeHeroComponent from "." + +const meta = { + title: "Organisms / Layouts / Hero", + component: HomeHeroComponent, + parameters: { + layout: "none", + chromatic: { + modes: { + ...langViewportModes, + }, + }, + }, +} satisfies Meta + +export default meta + +export const HomeHero: StoryObj = { + render: () => , +} diff --git a/src/components/Hero/HomeHero/index.tsx b/src/components/Hero/HomeHero/index.tsx index 8d41eb1d20a..11d683f0787 100644 --- a/src/components/Hero/HomeHero/index.tsx +++ b/src/components/Hero/HomeHero/index.tsx @@ -1,29 +1,58 @@ -import { getTranslations } from "next-intl/server" +import { getImageProps } from "next/image" +import { getLocale, getTranslations } from "next-intl/server" -import type { ClassNameProp, CommonHeroProps, Lang } from "@/lib/types" +import type { ClassNameProp } from "@/lib/types" import LanguageMorpher from "@/components/Homepage/LanguageMorpher" -import { Image } from "@/components/Image" -export type HomeHeroProps = Pick & - ClassNameProp & { - locale: Lang - } +import { cn } from "@/lib/utils/cn" +import { breakpointAsNumber } from "@/lib/utils/screen" + +import heroBase from "@/public/images/home/hero.png" +import hero2xl from "@/public/images/home/hero-2xl.png" -const HomeHero = async ({ heroImg, className, locale }: HomeHeroProps) => { +const HomeHero = async ({ className }: ClassNameProp) => { + const locale = getLocale() const t = await getTranslations({ locale, namespace: "page-index" }) + const alt = t("page-index-hero-image-alt") + + const common = { + alt, + sizes: `(max-width: ${breakpointAsNumber["2xl"]}px) 100vw, ${breakpointAsNumber["2xl"]}px`, + priority: true, + } + + const { + props: { srcSet: srcSet2xl }, + } = getImageProps({ ...common, ...hero2xl, quality: 20 }) + + const { + props: { srcSet: srcSetMd }, + } = getImageProps({ ...common, ...heroBase, quality: 10 }) + + const { + props: { srcSet: srcSetBase, ...rest }, + } = getImageProps({ ...common, ...heroBase, quality: 5 }) + return ( -
-
- {t("page-index-hero-image-alt")} +
+
+ + + + + {alt} +
diff --git a/src/components/Hero/index.ts b/src/components/Hero/index.ts index c11ed056347..48581c76bd0 100644 --- a/src/components/Hero/index.ts +++ b/src/components/Hero/index.ts @@ -1,5 +1,5 @@ export { default as ContentHero, type ContentHeroProps } from "./ContentHero" -export { default as HomeHero, type HomeHeroProps } from "./HomeHero" +export { default as HomeHero } from "./HomeHero" export { default as HubHero } from "./HubHero" export { default as MdxHero, type MdxHeroProps } from "./MdxHero" export { diff --git a/src/components/Homepage/HomepageSectionImage.tsx b/src/components/Homepage/HomepageSectionImage.tsx new file mode 100644 index 00000000000..0eb616b4c10 --- /dev/null +++ b/src/components/Homepage/HomepageSectionImage.tsx @@ -0,0 +1,97 @@ +import type { StaticImageData } from "next/image" +import { getImageProps } from "next/image" + +import { breakpointAsNumber } from "@/lib/utils/screen" + +// Import all landscape images (all PNG now) +import developersHubHero from "@/public/images/heroes/developers-hub-hero.png" +// Import all portrait images (all PNG) +import developersHubHeroPortrait from "@/public/images/heroes/developers-hub-hero-portrait.png" +import layerTwoHubHero from "@/public/images/heroes/layer-2-hub-hero.png" +import layerTwoHubHeroPortrait from "@/public/images/heroes/layer-2-hub-hero-portrait.png" +import learnHubHero from "@/public/images/heroes/learn-hub-hero.png" +import learnHubHeroPortrait from "@/public/images/heroes/learn-hub-hero-portrait.png" +import quizzesHubHero from "@/public/images/heroes/quizzes-hub-hero.png" +import quizzesHubHeroPortrait from "@/public/images/heroes/quizzes-hub-hero-portrait.png" + +const imageMap: Record< + string, + { + mobile: StaticImageData + desktop: StaticImageData + } +> = { + activity: { + mobile: layerTwoHubHero, + desktop: layerTwoHubHeroPortrait, + }, + learn: { + mobile: learnHubHero, + desktop: learnHubHeroPortrait, + }, + builders: { + mobile: developersHubHero, + desktop: developersHubHeroPortrait, + }, + community: { + mobile: quizzesHubHero, + desktop: quizzesHubHeroPortrait, + }, +} + +type HomepageSectionImageProps = { + sectionId: string // e.g. "activity", "learn", "builders", "community" + alt: string + className?: string +} + +export default function HomepageSectionImage({ + sectionId, + alt, + className, +}: HomepageSectionImageProps) { + const images = imageMap[sectionId] + + if (!images) { + throw new Error( + `Image not found for section: ${sectionId}. Available sections: ${Object.keys(imageMap).join(", ")}` + ) + } + + const common = { + alt, + // Be very specific: Desktop max 512px, Mobile 100vw + sizes: `(max-width: ${breakpointAsNumber.md}px) 100vw, 512px`, + priority: false, + } + + const { + props: { srcSet: desktop }, + } = getImageProps({ + ...common, + ...images.desktop, + quality: 25, + }) + + const { + props: { srcSet: mobile, ...rest }, + } = getImageProps({ + ...common, + ...images.mobile, + quality: 40, + }) + + return ( + + + + {alt} + + ) +} diff --git a/src/data/roadmap/releases.tsx b/src/data/roadmap/releases.tsx index 70d57f6ffc5..ba7c5b4b64d 100644 --- a/src/data/roadmap/releases.tsx +++ b/src/data/roadmap/releases.tsx @@ -1,8 +1,8 @@ import { StaticImageData } from "next/image" -import DevelopersHubHeroImage from "@/public/images/heroes/developers-hub-hero.jpg" +import DevelopersHubHeroImage from "@/public/images/heroes/developers-hub-hero.png" import GuidesHubHeroImage from "@/public/images/heroes/guides-hub-hero.jpg" -import Layer2HubHeroImage from "@/public/images/heroes/layer-2-hub-hero.jpg" +import Layer2HubHeroImage from "@/public/images/heroes/layer-2-hub-hero.png" import QuizzesHubHeroImage from "@/public/images/heroes/quizzes-hub-hero.png" import FusakaImage from "@/public/images/roadmap/roadmap-fusaka.png" import PectraImage from "@/public/images/roadmap/roadmap-pectra.png" diff --git a/src/lib/utils/metadata.ts b/src/lib/utils/metadata.ts index ed8b8523456..5c3002c8c15 100644 --- a/src/lib/utils/metadata.ts +++ b/src/lib/utils/metadata.ts @@ -11,7 +11,7 @@ import { routing } from "@/i18n/routing" * List of default og images for different sections */ const imageForSlug = [ - { section: "developers", image: "/images/heroes/developers-hub-hero.jpg" }, + { section: "developers", image: "/images/heroes/developers-hub-hero.png" }, { section: "roadmap", image: "/images/heroes/roadmap-hub-hero.jpg" }, { section: "guides", image: "/images/heroes/guides-hub-hero.jpg" }, { section: "community", image: "/images/heroes/community-hero.png" },