diff --git a/app/[locale]/community/_components/community.tsx b/app/[locale]/community/_components/community.tsx deleted file mode 100644 index 43257d496e6..00000000000 --- a/app/[locale]/community/_components/community.tsx +++ /dev/null @@ -1,342 +0,0 @@ -"use client" - -import { BaseHTMLAttributes } from "react" - -import { ChildOnlyProp } from "@/lib/types" -import { ICard, IGetInvolvedCard } from "@/lib/interfaces" - -import ActionCard from "@/components/ActionCard" -import Callout from "@/components/Callout" -import Card from "@/components/Card" -import FeedbackCard from "@/components/FeedbackCard" -import { HubHero } from "@/components/Hero" -import type { HubHeroProps } from "@/components/Hero/HubHero" -import { Image } from "@/components/Image" -import MainArticle from "@/components/MainArticle" -import Translation from "@/components/Translation" -import { ButtonLink, ButtonLinkProps } from "@/components/ui/buttons/Button" -import { Divider } from "@/components/ui/divider" -import { Flex } from "@/components/ui/flex" - -import { cn } from "@/lib/utils/cn" - -import { useTranslation } from "@/hooks/useTranslation" -import developersEthBlockImg from "@/public/images/developers-eth-blocks.png" -import dogeComputerImg from "@/public/images/doge-computer.png" -import ethImg from "@/public/images/eth.png" -import financeTransparentImg from "@/public/images/finance_transparent.png" -import futureTransparentImg from "@/public/images/future_transparent.png" -import hackathonTransparentImg from "@/public/images/hackathon_transparent.png" -import communityHeroImg from "@/public/images/heroes/community-hero.png" -import upgradesCoreImg from "@/public/images/upgrades/core.png" -import whatIsEthereumImg from "@/public/images/what-is-ethereum.png" - -const CardContainer = ({ children }: ChildOnlyProp) => { - return {children} -} - -const Content = ({ children }: ChildOnlyProp) => { - return
{children}
-} - -const Page = ({ children }: ChildOnlyProp) => { - return ( - - {children} - - ) -} - -const ButtonRow = ({ children }: ChildOnlyProp) => { - return {children} -} - -const StyledButtonLink = ({ children, ...props }: ButtonLinkProps) => { - return ( - - {children} - - ) -} - -const RowReverse = ({ children }: ChildOnlyProp) => { - return ( - - {children} - - ) -} - -const ImageContainer = ({ children }: ChildOnlyProp) => { - return {children} -} - -const Subtitle = ({ children }: ChildOnlyProp) => { - return

{children}

-} - -const FeatureContent = ({ children }: ChildOnlyProp) => { - return ( - - {children} - - ) -} - -const H2 = ({ - children, - className, - ...props -}: BaseHTMLAttributes) => { - return ( -

- {children} -

- ) -} - -const CommunityPage = () => { - const { t } = useTranslation("page-community") - - const cards: Array = [ - { - image: upgradesCoreImg, - title: t("page-community-card-1-title"), - description: t("page-community-card-1-description"), - alt: t("page-index-get-started-wallet-image-alt"), - href: "/community/online/", - }, - { - image: ethImg, - title: t("page-community-card-2-title"), - description: t("page-community-card-2-description"), - alt: t("page-index-get-started-eth-image-alt"), - href: "/community/events/", - }, - { - image: dogeComputerImg, - title: t("page-community-card-3-title"), - description: t("page-community-card-3-description"), - alt: t("page-index-get-started-dapps-image-alt"), - href: "/community/get-involved/", - }, - { - image: futureTransparentImg, - title: t("page-community-card-4-title"), - description: t("page-community-card-4-description"), - alt: t("page-index-get-started-dapps-image-alt"), - href: "/community/grants/", - }, - ] - - const whyGetInvolvedCards: Array = [ - { - emoji: ":mage:", - title: t("page-community-why-get-involved-card-1-title"), - description: t("page-community-why-get-involved-card-1-description"), - }, - { - emoji: ":dollar:", - title: t("page-community-why-get-involved-card-2-title"), - description: t("page-community-why-get-involved-card-2-description"), - }, - { - emoji: ":collision:", - title: t("page-community-why-get-involved-card-3-title"), - description: t("page-community-why-get-involved-card-3-description"), - }, - ] - - const heroContent: HubHeroProps = { - title: t("page-community-hero-title"), - header: t("page-community-hero-header"), - description: t("page-community-hero-subtitle"), - heroImg: communityHeroImg, - } - - return ( - - - - -
- -

- {t("page-community-why-get-involved-title")} -

-
- - {whyGetInvolvedCards.map((card, idx) => ( - - ))} - -
-
-
-
- -
-

- {t("page-community-get-involved-title")} -

- - - -
- - {t("page-community-get-involved-image-alt")} - -
-
- {cards.map((card, idx) => ( - - ))} -
-
-
- - - -

{t("page-community-open-source")}

- {t("page-community-open-source-description")} - - - {t("page-community-find-a-job")} - - - {t("page-community-explore-grants")} - - -
- - {t("page-community-open-source-image-alt")} - -
-
- - - - -

{t("page-community-contribute")}

- {t("page-community-contribute-description")} - - - {t("page-community-contribute-button")} - - - {t("page-community-contribute-secondary-button")} - - -
-
- - {t("page-index-internet-image-alt")} - -
-
- - - -

{t("page-community-support")}

- {t("page-community-support-description")} -
- - {t("page-community-support-button")} - -
-
- - {t("page-community-support-alt")} - -
-
- - -
-

- {t("page-community-try-ethereum")} -

-
-
- - - -
- - {t("page-community-get-eth")} - -
-
- -
- - {t("page-community-explore-dapps")} - -
-
-
-
- -
- ) -} - -export default CommunityPage diff --git a/app/[locale]/community/page.tsx b/app/[locale]/community/page.tsx index 61bef534282..433b1f53017 100644 --- a/app/[locale]/community/page.tsx +++ b/app/[locale]/community/page.tsx @@ -1,3 +1,4 @@ +import { type BaseHTMLAttributes } from "react" import { pick } from "lodash" import { getMessages, @@ -5,24 +6,103 @@ import { setRequestLocale, } from "next-intl/server" -import type { Lang, PageParams } from "@/lib/types" +import type { ChildOnlyProp, Lang, PageParams } from "@/lib/types" +import type { ICard, IGetInvolvedCard } from "@/lib/interfaces" +import ActionCard from "@/components/ActionCard" +import Callout from "@/components/Callout" +import Card from "@/components/Card" +import FeedbackCard from "@/components/FeedbackCard" +import { HubHero } from "@/components/Hero" +import type { HubHeroProps } from "@/components/Hero/HubHero" import I18nProvider from "@/components/I18nProvider" +import { Image } from "@/components/Image" +import MainArticle from "@/components/MainArticle" +import Translation from "@/components/Translation" +import { ButtonLink, ButtonLinkProps } from "@/components/ui/buttons/Button" +import { Divider } from "@/components/ui/divider" +import { Flex } from "@/components/ui/flex" +import { cn } from "@/lib/utils/cn" import { getAppPageContributorInfo } from "@/lib/utils/contributors" import { getMetadata } from "@/lib/utils/metadata" import { getRequiredNamespacesForPage } from "@/lib/utils/translations" -import CommunityPage from "./_components/community" import CommunityJsonLD from "./page-jsonld" +import developersEthBlockImg from "@/public/images/developers-eth-blocks.png" +import dogeComputerImg from "@/public/images/doge-computer.png" +import ethImg from "@/public/images/eth.png" +import financeTransparentImg from "@/public/images/finance_transparent.png" +import futureTransparentImg from "@/public/images/future_transparent.png" +import hackathonTransparentImg from "@/public/images/hackathon_transparent.png" +import communityHeroImg from "@/public/images/heroes/community-hero.png" +import upgradesCoreImg from "@/public/images/upgrades/core.png" +import whatIsEthereumImg from "@/public/images/what-is-ethereum.png" + +const CardContainer = ({ children }: ChildOnlyProp) => ( + {children} +) + +const Content = ({ children }: ChildOnlyProp) => ( +
{children}
+) + +const PageContainer = ({ children }: ChildOnlyProp) => ( + + {children} + +) + +const ButtonRow = ({ children }: ChildOnlyProp) => ( + {children} +) + +const StyledButtonLink = ({ children, ...props }: ButtonLinkProps) => ( + + {children} + +) + +const RowReverse = ({ children }: ChildOnlyProp) => ( + + {children} + +) + +const ImageContainer = ({ children }: ChildOnlyProp) => ( + {children} +) + +const Subtitle = ({ children }: ChildOnlyProp) => ( +

{children}

+) + +const FeatureContent = ({ children }: ChildOnlyProp) => ( + + {children} + +) + +const H2 = ({ + children, + className, + ...props +}: BaseHTMLAttributes) => ( +

+ {children} +

+) + export default async function Page(props: { params: Promise }) { const params = await props.params const { locale } = params setRequestLocale(locale) - // Get i18n messages const allMessages = await getMessages({ locale }) const requiredNamespaces = getRequiredNamespacesForPage("/community") const pickedMessages = pick(allMessages, requiredNamespaces) @@ -32,11 +112,250 @@ export default async function Page(props: { params: Promise }) { locale as Lang ) + const t = await getTranslations("page-community") + + const cards: ICard[] = [ + { + image: upgradesCoreImg, + title: t("page-community-card-1-title"), + description: t("page-community-card-1-description"), + alt: t("page-index-get-started-wallet-image-alt"), + href: "/community/online/", + }, + { + image: ethImg, + title: t("page-community-card-2-title"), + description: t("page-community-card-2-description"), + alt: t("page-index-get-started-eth-image-alt"), + href: "/community/events/", + }, + { + image: dogeComputerImg, + title: t("page-community-card-3-title"), + description: t("page-community-card-3-description"), + alt: t("page-index-get-started-dapps-image-alt"), + href: "/community/get-involved/", + }, + { + image: futureTransparentImg, + title: t("page-community-card-4-title"), + description: t("page-community-card-4-description"), + alt: t("page-index-get-started-dapps-image-alt"), + href: "/community/grants/", + }, + ] + + const whyGetInvolvedCards: IGetInvolvedCard[] = [ + { + emoji: ":mage:", + title: t("page-community-why-get-involved-card-1-title"), + description: t("page-community-why-get-involved-card-1-description"), + }, + { + emoji: ":dollar:", + title: t("page-community-why-get-involved-card-2-title"), + description: t("page-community-why-get-involved-card-2-description"), + }, + { + emoji: ":collision:", + title: t("page-community-why-get-involved-card-3-title"), + description: t("page-community-why-get-involved-card-3-description"), + }, + ] + + const heroContent: HubHeroProps = { + title: t("page-community-hero-title"), + header: t("page-community-hero-header"), + description: t("page-community-hero-subtitle"), + heroImg: communityHeroImg, + } + return ( <> - + + + + +
+ +

+ {t("page-community-why-get-involved-title")} +

+
+ + {whyGetInvolvedCards.map((card, idx) => ( + + ))} + +
+
+
+
+ +
+

+ {t("page-community-get-involved-title")} +

+ + + +
+ + {t("page-community-get-involved-image-alt")} + +
+
+ {cards.map((card, idx) => ( + + ))} +
+
+
+ + + +

{t("page-community-open-source")}

+ + {t("page-community-open-source-description")} + + + + {t("page-community-find-a-job")} + + + {t("page-community-explore-grants")} + + +
+ + {t("page-community-open-source-image-alt")} + +
+
+ + + + +

{t("page-community-contribute")}

+ + {t("page-community-contribute-description")} + + + + {t("page-community-contribute-button")} + + + {t("page-community-contribute-secondary-button")} + + +
+
+ + {t("page-index-internet-image-alt")} + +
+
+ + + +

{t("page-community-support")}

+ {t("page-community-support-description")} +
+ + {t("page-community-support-button")} + +
+
+ + {t("page-community-support-alt")} + +
+
+ + +
+

+ {t("page-community-try-ethereum")} +

+
+
+ + + +
+ + {t("page-community-get-eth")} + +
+
+ +
+ + {t("page-community-explore-dapps")} + +
+
+
+
+ +
) diff --git a/app/[locale]/contributing/translation-program/contributors/_components/contributors.tsx b/app/[locale]/contributing/translation-program/contributors/_components/contributors.tsx deleted file mode 100644 index b0a581cc663..00000000000 --- a/app/[locale]/contributing/translation-program/contributors/_components/contributors.tsx +++ /dev/null @@ -1,106 +0,0 @@ -"use client" - -import { BaseHTMLAttributes } from "react" - -import { CostLeaderboardData } from "@/lib/types" - -import Breadcrumbs from "@/components/Breadcrumbs" -import FeedbackCard from "@/components/FeedbackCard" -import MainArticle from "@/components/MainArticle" -import { Flex } from "@/components/ui/flex" -import InlineLink from "@/components/ui/Link" -import { List, ListItem } from "@/components/ui/list" - -import { cn } from "@/lib/utils/cn" - -import allTimeData from "@/data/translation-reports/alltime/alltime-data.json" - -import { useTranslation } from "@/hooks/useTranslation" -import { usePathname } from "@/i18n/navigation" - -const Content = ({ ...props }: BaseHTMLAttributes) => ( - -) - -const Text = ({ - className, - ...props -}: BaseHTMLAttributes) => ( -

-) - -const Contributors = () => { - const { t } = useTranslation( - "page-contributing-translation-program-contributors" - ) - const pathname = usePathname() - - const translators = (allTimeData as CostLeaderboardData[]) - .map((item: CostLeaderboardData) => item.username) - .filter((item) => item.length > 0) - - return ( - - - -

- {t("page-contributing-translation-program-contributors-title")} -

-

- {t( - "page-contributing-translation-program-contributors-number-of-contributors" - )}{" "} - {translators.length} -

- - {t( - "page-contributing-translation-program-contributors-our-translators-1" - )} - - - {t( - "page-contributing-translation-program-contributors-our-translators-2" - )} - - - {t( - "page-contributing-translation-program-contributors-our-translators-3" - )} - - - {t("common:page-languages-interested")}{" "} - - {t("common:page-languages-learn-more")} - - . - -

- {t("page-contributing-translation-program-contributors-thank-you")} -

- - {translators - .sort((user1, user2) => - user1.toLowerCase().localeCompare(user2.toLowerCase()) - ) - .map((user) => ( - - {user} - - ))} - - - {t("common:page-languages-interested")}{" "} - - {t("common:page-languages-learn-more")} - - . - - - - - - - ) -} - -export default Contributors diff --git a/app/[locale]/contributing/translation-program/contributors/page.tsx b/app/[locale]/contributing/translation-program/contributors/page.tsx index 4844a3a61d1..68bc5081af6 100644 --- a/app/[locale]/contributing/translation-program/contributors/page.tsx +++ b/app/[locale]/contributing/translation-program/contributors/page.tsx @@ -1,3 +1,4 @@ +import { type BaseHTMLAttributes } from "react" import { pick } from "lodash" import { getMessages, @@ -5,17 +6,39 @@ import { setRequestLocale, } from "next-intl/server" -import type { Lang, PageParams } from "@/lib/types" +import type { CostLeaderboardData, Lang, PageParams } from "@/lib/types" +import Breadcrumbs from "@/components/Breadcrumbs" +import FeedbackCard from "@/components/FeedbackCard" import I18nProvider from "@/components/I18nProvider" +import MainArticle from "@/components/MainArticle" +import { Flex } from "@/components/ui/flex" +import InlineLink from "@/components/ui/Link" +import { List, ListItem } from "@/components/ui/list" +import { cn } from "@/lib/utils/cn" import { getAppPageContributorInfo } from "@/lib/utils/contributors" import { getMetadata } from "@/lib/utils/metadata" import { getRequiredNamespacesForPage } from "@/lib/utils/translations" -import Contributors from "./_components/contributors" +import allTimeData from "@/data/translation-reports/alltime/alltime-data.json" + import ContributorsJsonLD from "./page-jsonld" +const SLUG = "/contributing/translation-program/contributors" +const NAMESPACE = "page-contributing-translation-program-contributors" + +const Content = ({ ...props }: BaseHTMLAttributes) => ( + +) + +const Text = ({ + className, + ...props +}: BaseHTMLAttributes) => ( +

+) + const Page = async (props: { params: Promise }) => { const params = await props.params const { locale } = params @@ -27,18 +50,83 @@ const Page = async (props: { params: Promise }) => { locale as Lang ) - // Get i18n messages const allMessages = await getMessages({ locale }) - const requiredNamespaces = getRequiredNamespacesForPage( - "/contributing/translation-program/contributors" - ) + const requiredNamespaces = getRequiredNamespacesForPage(SLUG) const messages = pick(allMessages, requiredNamespaces) + const t = await getTranslations(NAMESPACE) + const tCommon = await getTranslations("common") + + const translators = (allTimeData as CostLeaderboardData[]) + .map((item) => item.username) + .filter((item) => item.length > 0) + return ( <> - + + + +

+ {t("page-contributing-translation-program-contributors-title")} +

+

+ {t( + "page-contributing-translation-program-contributors-number-of-contributors" + )}{" "} + {translators.length} +

+ + {t( + "page-contributing-translation-program-contributors-our-translators-1" + )} + + + {t( + "page-contributing-translation-program-contributors-our-translators-2" + )} + + + {t( + "page-contributing-translation-program-contributors-our-translators-3" + )} + + + {tCommon("page-languages-interested")}{" "} + + {tCommon("page-languages-learn-more")} + + . + +

+ {t( + "page-contributing-translation-program-contributors-thank-you" + )} +

+ + {translators + .sort((user1, user2) => + user1.toLowerCase().localeCompare(user2.toLowerCase()) + ) + .map((user) => ( + + {user} + + ))} + + + {tCommon("page-languages-interested")}{" "} + + {tCommon("page-languages-learn-more")} + + . + + + + + + ) @@ -50,9 +138,7 @@ export async function generateMetadata(props: { const params = await props.params const { locale } = params - const t = await getTranslations( - "page-contributing-translation-program-contributors" - ) + const t = await getTranslations(NAMESPACE) return await getMetadata({ locale, diff --git a/app/[locale]/gas/_components/gas.tsx b/app/[locale]/gas/_components/gas.tsx deleted file mode 100644 index a7eb1e6ebce..00000000000 --- a/app/[locale]/gas/_components/gas.tsx +++ /dev/null @@ -1,419 +0,0 @@ -"use client" - -import { BaseHTMLAttributes, ComponentPropsWithRef } from "react" - -import { PageWithContributorsProps } from "@/lib/types" - -import Callout from "@/components/Callout" -import Card from "@/components/Card" -import Emoji from "@/components/Emoji" -import ExpandableCard from "@/components/ExpandableCard" -import FeedbackCard from "@/components/FeedbackCard" -import FileContributors from "@/components/FileContributors" -import GhostCard from "@/components/GhostCard" -import HorizontalCard from "@/components/HorizontalCard" -import { Image } from "@/components/Image" -import MainArticle from "@/components/MainArticle" -import PageHero from "@/components/PageHero" -import { StandaloneQuizWidget } from "@/components/Quiz/QuizWidget" -import Translation from "@/components/Translation" -import { Alert, AlertContent, AlertTitle } from "@/components/ui/alert" -import { ButtonLink } from "@/components/ui/buttons/Button" -import { Divider } from "@/components/ui/divider" -import { Flex, FlexProps } from "@/components/ui/flex" -import InlineLink, { BaseLink } from "@/components/ui/Link" -import { ListItem, UnorderedList } from "@/components/ui/list" -import { - Table, - TableBody, - TableCaption, - TableCell, - TableHead, - TableHeader, - TableRow, -} from "@/components/ui/table" -import { Tag } from "@/components/ui/tag" - -import { cn } from "@/lib/utils/cn" - -import { useTranslation } from "@/hooks/useTranslation" -// Static assets -import dogeComputerImg from "@/public/images/doge-computer.png" -import ethImg from "@/public/images/eth.png" -import infrastructureTransparentImg from "@/public/images/infrastructure_transparent.png" -import walletImg from "@/public/images/wallet.png" -import whatIsEthereumImg from "@/public/images/what-is-ethereum.png" - -const Content = ({ - className, - ...props -}: BaseHTMLAttributes) => ( -
-) - -const Page = ({ className, ...props }: FlexProps) => ( - - - -) - -export const StyledCard = (props: ComponentPropsWithRef) => ( - -) - -const H2 = ({ - className, - ...props -}: BaseHTMLAttributes) => ( -

-) - -const H3 = ({ - className, - ...props -}: BaseHTMLAttributes) => ( -

-) - -const GasPage = ({ - contributors, - lastEditLocaleTimestamp, -}: PageWithContributorsProps) => { - const { t } = useTranslation("page-gas") - - const benefits = [ - { - emoji: "🪪", - description: ( - - ), - }, - { - emoji: ":money_with_wings:", - description: t("page-gas-benefits-2-description"), - }, - { - emoji: ":hourglass_flowing_sand:", - description: t("page-gas-benefits-3-description"), - }, - ] - - const heroContent = { - title: t("page-gas-hero-title"), - header: t("page-gas-hero-header"), - image: infrastructureTransparentImg, - alt: "Hero header image", - buttons: [ - { - content: t("page-gas-hero-button-1-content"), - toId: "what-is-gas", - matomo: { - eventCategory: "gas hero buttons", - eventAction: "click", - eventName: "what is gas", - }, - }, - ], - } - - return ( - -
-
- - {t("page-gas-hero-subtitle-1")} -
- {t("page-gas-hero-subtitle-2")} - - ), - ...heroContent, - }} - /> -
-
- - -
- - - - {t("page-gas-summary-title")} - - - {t("page-gas-summary-item-1")} - {t("page-gas-summary-item-2")} - {t("page-gas-summary-item-3")} - - - -

- {t("page-gas-what-are-gas-fees-header")} -

-

{t("page-gas-what-are-gas-fees-text-1")}

-

- -

-
- -
- A robot -
-
-
- - -
-

- {t("page-gas-how-do-i-pay-less-gas-header")} -

-

{t("page-gas-how-do-i-pay-less-gas-text")}

- - - - - - {t("page-gas-try-layer-2")} - - - -
-
-
- - -
-

- {t("page-gas-what-causes-high-gas-fees-header")} -

-

- {t("page-gas-what-causes-high-gas-fees-text-1")} -

-

- -

-

- {t("page-gas-what-causes-high-gas-fees-text-3")} -

-

- {t("page-gas-want-to-dive-deeper")}{" "} - - {t("page-gas-check-out-the-developer-docs")} - -

-
- - -

{t("page-gas-attack-of-the-cryptokitties-header")}

-

- {t("page-gas-attack-of-the-cryptokitties-text")} -

-
-
-
- - -
-
-

- {t("page-gas-why-do-we-need-gas-header")} -

-

{t("page-gas-why-do-we-need-gas-text")}

-
- {benefits.map((benefit, index) => ( -
- -
- ))} -
-
- -
-
-
- - -
- -

- {t("page-gas-how-is-gas-calculated-header")} -

- - - {t("page-gas-advanced")} - -
-

{t("page-gas-how-is-gas-calculated-text-1")}

- - - - - - - - - - - - - - - - -

- -

-
- - - - - - - {t("page-gas-table-header-1")} - {t("page-gas-table-header-2")} - - - - - - {t("page-gas-table-item-1-transaction-type")} - - 21,000 - - - - {t("page-gas-table-item-2-transaction-type")} - - 65,000 - - - - {t("page-gas-table-item-3-transaction-type")} - - 84,904 - - - - {t("page-gas-table-item-4-transaction-type")} - - 184,523 - - -
-
-
- -

{t("page-gas-faq-header")}

- {/* MaxWidth will be enforced by FAQ component once implemented */} -
- -

- -

-

- -

-
- -

- -

- - - -
- -

- -

-

{t("page-gas-faq-question-3-a-2")}

-
-
-
- - - - -
- - {t("page-gas-use-layer-2")} - -
-
- -
- - {t("page-community:page-community-explore-dapps")} - -
-
-
-
- - - - - - - -
- ) -} - -export default GasPage diff --git a/app/[locale]/gas/page.tsx b/app/[locale]/gas/page.tsx index 19615342138..66c77e9f3e8 100644 --- a/app/[locale]/gas/page.tsx +++ b/app/[locale]/gas/page.tsx @@ -1,3 +1,4 @@ +import { type BaseHTMLAttributes, type ComponentPropsWithRef } from "react" import { pick } from "lodash" import { getMessages, @@ -7,22 +8,93 @@ import { import type { Lang, PageParams } from "@/lib/types" +import Callout from "@/components/Callout" +import Card from "@/components/Card" +import Emoji from "@/components/Emoji" +import ExpandableCard from "@/components/ExpandableCard" +import FeedbackCard from "@/components/FeedbackCard" +import FileContributors from "@/components/FileContributors" +import GhostCard from "@/components/GhostCard" +import HorizontalCard from "@/components/HorizontalCard" import I18nProvider from "@/components/I18nProvider" +import { Image } from "@/components/Image" +import MainArticle from "@/components/MainArticle" +import PageHero from "@/components/PageHero" +import { StandaloneQuizWidget } from "@/components/Quiz/QuizWidget" +import Translation from "@/components/Translation" +import { Alert, AlertContent, AlertTitle } from "@/components/ui/alert" +import { ButtonLink } from "@/components/ui/buttons/Button" +import { Divider } from "@/components/ui/divider" +import { Flex, type FlexProps } from "@/components/ui/flex" +import InlineLink, { BaseLink } from "@/components/ui/Link" +import { ListItem, UnorderedList } from "@/components/ui/list" +import { + Table, + TableBody, + TableCaption, + TableCell, + TableHead, + TableHeader, + TableRow, +} from "@/components/ui/table" +import { Tag } from "@/components/ui/tag" +import { cn } from "@/lib/utils/cn" import { getAppPageContributorInfo } from "@/lib/utils/contributors" import { getMetadata } from "@/lib/utils/metadata" import { getRequiredNamespacesForPage } from "@/lib/utils/translations" -import GasPage from "./_components/gas" import GasPageJsonLD from "./page-jsonld" +import dogeComputerImg from "@/public/images/doge-computer.png" +import ethImg from "@/public/images/eth.png" +import infrastructureTransparentImg from "@/public/images/infrastructure_transparent.png" +import walletImg from "@/public/images/wallet.png" +import whatIsEthereumImg from "@/public/images/what-is-ethereum.png" + +const Content = ({ + className, + ...props +}: BaseHTMLAttributes) => ( +
+) + +const PageContainer = ({ className, ...props }: FlexProps) => ( + + + +) + +const StyledCard = (props: ComponentPropsWithRef) => ( + +) + +const H2 = ({ + className, + ...props +}: BaseHTMLAttributes) => ( +

+) + +const H3 = ({ + className, + ...props +}: BaseHTMLAttributes) => ( +

+) + const Page = async (props: { params: Promise }) => { const params = await props.params const { locale } = params setRequestLocale(locale) - // Get i18n messages const allMessages = await getMessages({ locale }) const requiredNamespaces = getRequiredNamespacesForPage("/gas") const messages = pick(allMessages, requiredNamespaces) @@ -30,6 +102,44 @@ const Page = async (props: { params: Promise }) => { const { contributors, lastEditLocaleTimestamp } = await getAppPageContributorInfo("gas", locale as Lang) + const t = await getTranslations("page-gas") + const tCommunity = await getTranslations("page-community") + + const benefits = [ + { + emoji: "🪪", + description: ( + + ), + }, + { + emoji: ":money_with_wings:", + description: t("page-gas-benefits-2-description"), + }, + { + emoji: ":hourglass_flowing_sand:", + description: t("page-gas-benefits-3-description"), + }, + ] + + const heroContent = { + title: t("page-gas-hero-title"), + header: t("page-gas-hero-header"), + image: infrastructureTransparentImg, + alt: "Hero header image", + buttons: [ + { + content: t("page-gas-hero-button-1-content"), + toId: "what-is-gas", + matomo: { + eventCategory: "gas hero buttons", + eventAction: "click", + eventName: "what is gas", + }, + }, + ], + } + return ( }) => { lastEditLocaleTimestamp={lastEditLocaleTimestamp} contributors={contributors} /> - + +
+
+ + {t("page-gas-hero-subtitle-1")} +
+ {t("page-gas-hero-subtitle-2")} + + ), + ...heroContent, + }} + /> +
+
+ + +
+ + + + {t("page-gas-summary-title")} + + + {t("page-gas-summary-item-1")} + {t("page-gas-summary-item-2")} + {t("page-gas-summary-item-3")} + + + +

+ {t("page-gas-what-are-gas-fees-header")} +

+

{t("page-gas-what-are-gas-fees-text-1")}

+

+ +

+
+ +
+ A robot +
+
+
+ + +
+

+ {t("page-gas-how-do-i-pay-less-gas-header")} +

+

{t("page-gas-how-do-i-pay-less-gas-text")}

+ + + + + + {t("page-gas-try-layer-2")} + + + +
+
+
+ + +
+

+ {t("page-gas-what-causes-high-gas-fees-header")} +

+

+ {t("page-gas-what-causes-high-gas-fees-text-1")} +

+

+ +

+

+ {t("page-gas-what-causes-high-gas-fees-text-3")} +

+

+ {t("page-gas-want-to-dive-deeper")}{" "} + + {t("page-gas-check-out-the-developer-docs")} + +

+
+ + +

{t("page-gas-attack-of-the-cryptokitties-header")}

+

+ {t("page-gas-attack-of-the-cryptokitties-text")} +

+
+
+
+ + +
+
+

+ {t("page-gas-why-do-we-need-gas-header")} +

+

{t("page-gas-why-do-we-need-gas-text")}

+
+ {benefits.map((benefit, index) => ( +
+ +
+ ))} +
+
+ +
+
+
+ + +
+ +

+ {t("page-gas-how-is-gas-calculated-header")} +

+ + + {t("page-gas-advanced")} + +
+

+ {t("page-gas-how-is-gas-calculated-text-1")} +

+ + + + + + + + + + + + + + + + +

+ +

+
+ + + + + + + {t("page-gas-table-header-1")} + {t("page-gas-table-header-2")} + + + + + + {t("page-gas-table-item-1-transaction-type")} + + 21,000 + + + + {t("page-gas-table-item-2-transaction-type")} + + 65,000 + + + + {t("page-gas-table-item-3-transaction-type")} + + 84,904 + + + + {t("page-gas-table-item-4-transaction-type")} + + 184,523 + + +
+
+
+ +

{t("page-gas-faq-header")}

+
+ +

+ +

+

+ +

+
+ +

+ +

+ + + +
+ +

+ +

+

{t("page-gas-faq-question-3-a-2")}

+
+
+
+ + + + +
+ + {t("page-gas-use-layer-2")} + +
+
+ +
+ + {tCommunity("page-community-explore-dapps")} + +
+
+
+
+ + + + + + + +
) } diff --git a/app/[locale]/layer-2/_components/layer-2.tsx b/app/[locale]/layer-2/_components/layer-2.tsx deleted file mode 100644 index 68a9f50ff07..00000000000 --- a/app/[locale]/layer-2/_components/layer-2.tsx +++ /dev/null @@ -1,528 +0,0 @@ -"use client" - -import type { GrowThePieData, Lang } from "@/lib/types" - -import CalloutSSR from "@/components/CalloutSSR" -import Card from "@/components/Card" -import ExpandableCard from "@/components/ExpandableCard" -import HubHero, { HubHeroProps } from "@/components/Hero/HubHero" -import { Image } from "@/components/Image" -import MainArticle from "@/components/MainArticle" -import Translation from "@/components/Translation" -import { ButtonLink } from "@/components/ui/buttons/Button" -import InlineLink from "@/components/ui/Link" - -import { numberFormat } from "@/lib/utils/numbers" - -import { Rollups } from "@/data/networks/networks" - -import useTranslation from "@/hooks/useTranslation" -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" -import ManDogCardImage from "@/public/images/man-and-dog-playing.png" - -type Layer2HubProps = { - randomL2s: Rollups - userRandomL2s: Rollups - growThePieData: GrowThePieData - locale: Lang -} - -const Layer2Hub = ({ - randomL2s, - userRandomL2s, - growThePieData, - locale, -}: Layer2HubProps) => { - const { t } = useTranslation(["page-layer-2", "common"]) - const medianTxCost = - "error" in growThePieData.txCostsMedianUsd - ? { error: growThePieData.txCostsMedianUsd.error } - : growThePieData.txCostsMedianUsd.value - - const heroContent: HubHeroProps = { - title: t("page-layer-2-hero-title"), - header: t("page-layer-2-hero-header"), - description: t("page-layer-2-hero-description"), - heroImg: HeroImage, - buttons: [ - { - content: t("common:nav-networks-explore-networks-label"), - href: "/layer-2/networks", - matomo: { - eventCategory: "l2_hub", - eventAction: "button_click", - eventName: "hero_explore_networks", - }, - }, - { - content: t("page-layer-2-hero-button-2-content"), - href: "#layer-2-powered-by-ethereum", - matomo: { - eventCategory: "l2_hub", - eventAction: "button_click", - eventName: "hero_get_started", - }, - }, - ], - } - - const calloutCards = [ - { - title: t("page-layer-2-calloutCard-1-title"), - description: t("page-layer-2-calloutCard-1-description"), - emoji: ":money_with_wings:", - }, - { - title: t("page-layer-2-calloutCard-2-title"), - description: t("page-layer-2-calloutCard-2-description"), - emoji: ":closed_lock_with_key:", - }, - { - title: t("page-layer-2-calloutCard-3-title"), - description: t("page-layer-2-calloutCard-3-description"), - emoji: ":hammer_and_wrench:", - }, - ] - - return ( - <> - - - -
-
-
-

{t("page-layer-2-powered-by-ethereum-title")}

-

- - {" "} - - {t("page-layer-2-powered-by-ethereum-description-2")} -

-

{t("page-layer-2-powered-by-ethereum-description-3")}

-
-
- {t("page-layer-2-man-and-dog-alt")} -
-
-
- -
-
-
-
-
-

- $ - {numberFormat(locale, { - minimumFractionDigits: 2, - maximumFractionDigits: 2, - }).format(growThePieData.dailyTxCosts["ethereum"] || 0)} -

-

- {t("page-layer-2-blockchain-transaction-cost")} -

-
-
-
-
-
-

- $ - {numberFormat(locale, { - minimumFractionDigits: 2, - maximumFractionDigits: 3, - }).format( - typeof medianTxCost === "number" ? medianTxCost : 0 - )} -

-

- {t("page-layer-2-networks-transaction-cost")} -

-
-
-
-
-
- -
-
-

{t("page-layer-2-network-of-networks-title")}

-

- {t("page-layer-2-network-of-networks-description")} -

-
- {/* Outer ring */} -
-
- {/* Top logo */} -
- {randomL2s[0].name} -
- {/* Bottom right logo */} -
- {randomL2s[1].name} -
- {/* Bottom left logo */} -
- {randomL2s[2].name} -
-
- - {/* Middle ring */} -
-
- {/* Top logo */} -
- {randomL2s[3].name} -
- {/* Bottom right logo */} -
- {randomL2s[4].name} -
- {/* Bottom left logo */} -
- {randomL2s[5].name} -
-
- - {/* Inner ring */} -
-
- {/* Top logo */} -
- {randomL2s[6].name} -
- {/* Bottom right logo */} -
- {randomL2s[7].name} -
- {/* Bottom left logo */} -
- {randomL2s[8].name} -
-
- - {/* Center Ethereum Logo */} -
- Ethereum -
-
-
-
- -
-
- {calloutCards.map((card, idx) => { - return ( -
- -
- ) - })} -
-
- -
-
-

{t("page-layer-2-ready-to-start-title")}

-

{t("page-layer-2-ready-to-start-description")}

-
- - {t("page-layer-2-ready-to-start-button")} - -
-
-
- -
-
-
- {userRandomL2s.map((l2, idx) => { - return ( -
-
-
- {l2.name} -
-
-

{l2.name}

-

{t(l2.description)}

-
-
-
- - {t("page-layer-2-go")} - -
-
- ) - })} -
- -
-
- {t("page-layer-2-ethereum-logo-alt")} -

{t("page-layer-2-powered-by-ethereum-title")}

-
-
-
-
- -
-
-
- Walking -
-
-

{t("page-layer-2-why-do-we-need-multiple-networks-1")}

-

{t("page-layer-2-why-do-we-need-multiple-networks-2")}

-
- - {t("common:learn-more")} - -
-
-
-
- -
-

{t("page-layer-2-faq-title")}

-
- -
-

- {t("page-layer-2-faq-ExpandableCard-1-description-1")}{" "} - - {t("common:nav-ethereum-networks")} - - {t("page-layer-2-period")} -

-

{t("page-layer-2-faq-ExpandableCard-1-description-2")}

-
-
- -
-

- {t("page-layer-2-faq-ExpandableCard-2-description-1")}{" "} - - {t("page-layer-2-faq-ExpandableCard-2-link")} - - {t("page-layer-2-period")} -

-

{t("page-layer-2-faq-ExpandableCard-2-description-2")}

-
-
- -

{t("page-layer-2-faq-ExpandableCard-3-description")}

-
- -

{t("page-layer-2-faq-ExpandableCard-4-description")}

-
-
-
- -
- -
- - {t("common:nav-networks-explore-networks-label")} - -
-
- -
- - {t("common:learn-more")} - -
-
-
- - - ) -} - -export default Layer2Hub diff --git a/app/[locale]/layer-2/learn/_components/learn.tsx b/app/[locale]/layer-2/learn/_components/learn.tsx deleted file mode 100644 index 4c8ac527bf7..00000000000 --- a/app/[locale]/layer-2/learn/_components/learn.tsx +++ /dev/null @@ -1,339 +0,0 @@ -"use client" - -import { PageWithContributorsProps } from "@/lib/types" - -import CalloutSSR from "@/components/CalloutSSR" -import Card from "@/components/Card" -import FileContributors from "@/components/FileContributors" -import { ContentHero, type ContentHeroProps } from "@/components/Hero" -import { Image } from "@/components/Image" -import MainArticle from "@/components/MainArticle" -import { StandaloneQuizWidget } from "@/components/Quiz/QuizWidget" -import Translation from "@/components/Translation" -import { ButtonLink } from "@/components/ui/buttons/Button" - -import useTranslation from "@/hooks/useTranslation" -import { usePathname } from "@/i18n/navigation" -import Callout2Image from "@/public/images/layer-2/learn-hero.png" -import heroImg from "@/public/images/layer-2/learn-hero.png" -import OptimisticRollupImage from "@/public/images/layer-2/optimistic_rollup.png" -import RollupImage from "@/public/images/layer-2/rollup-2.png" -import ZKRollupImage from "@/public/images/layer-2/zk_rollup.png" -import Callout1Image from "@/public/images/man-and-dog-playing.png" -import DAOImage from "@/public/images/use-cases/dao-2.png" -import WhatIsEthereumImage from "@/public/images/what-is-ethereum.png" - -const Layer2Learn = ({ - contributors, - lastEditLocaleTimestamp, -}: PageWithContributorsProps) => { - const { t } = useTranslation("page-layer-2-learn") - const pathname = usePathname() - - const heroProps: ContentHeroProps = { - breadcrumbs: { slug: pathname, startDepth: 1 }, - heroImg, - title: t("page-layer-2-learn-title"), - description: t("page-layer-2-learn-description"), - buttons: [ - { - content: t("page-layer-2-learn-button-1-label"), - href: "/layer-2/", - matomo: { - eventCategory: "l2_learn", - eventAction: "button_click", - eventName: "what_is_l2", - }, - }, - { - content: t("page-layer-2-learn-button-2-label"), - href: "/layer-2/networks", - matomo: { - eventCategory: "l2_learn", - eventAction: "button_click", - eventName: "use_l2", - }, - }, - ], - } - - const layer2Cards = [ - { - emoji: ":money_with_wings:", - title: t("page-layer-2-learn-layer2Cards-1-title"), - description: t("page-layer-2-learn-layer2Cards-1-description"), - }, - { - emoji: ":closed_lock_with_key:", - title: t("page-layer-2-learn-layer2Cards-2-title"), - description: t("page-layer-2-learn-layer2Cards-2-description"), - }, - { - emoji: ":hammer_and_wrench:", - title: t("page-layer-2-learn-layer2Cards-3-title"), - description: t("page-layer-2-learn-layer2Cards-3-description"), - }, - ] - - const rollupCards = [ - { - image: OptimisticRollupImage, - title: t("page-layer-2-learn-rollupCards-optimistic-title"), - description: t("page-layer-2-learn-rollupCards-optimistic-description"), - childSentence: t( - "page-layer-2-learn-rollupCards-optimistic-childSentence" - ), - childLink: "/developers/docs/scaling/optimistic-rollups/", - }, - { - image: ZKRollupImage, - title: t("page-layer-2-learn-rollupCards-zk-title"), - description: t("page-layer-2-learn-rollupCards-zk-description"), - childSentence: t("page-layer-2-learn-rollupCards-zk-childSentence"), - childLink: "/developers/docs/scaling/zk-rollups/", - }, - ] - - return ( - - - -
-
-

{t("page-layer-2-learn-what-is-layer-2-title")}

-

- -

-

- -

-
-
- What is Ethereum -
-
- -
-

{t("page-layer-2-learn-what-is-layer-1-title")}

-
-
-

- -

-

- -

-
-
-

- {t("page-layer-2-learn-layer-1-list-title")} -

-
    -
  1. - - - - -
  2. -
  3. - - - - -
  4. -
  5. - - - - -
  6. -
  7. - - - - -
  8. -
-
-
-
- -
-
- -
- -
-

{t("page-layer-2-learn-why-do-we-need-layer-2-title")}

-

{t("page-layer-2-learn-why-do-we-need-layer-2-1")}

-

{t("page-layer-2-learn-why-do-we-need-layer-2-2")}

-

{t("page-layer-2-learn-why-do-we-need-layer-2-scalability")}

-

- -

-

{t("page-layer-2-learn-why-do-we-need-layer-2-scalability-2")}

-
-
- -
-
- {layer2Cards.map((card, idx) => { - return ( -
- -
- ) - })} -
-
- -
-
-

{t("page-layer-2-learn-how-does-layer-2-work-title")}

-

{t("page-layer-2-learn-how-does-layer-2-work-1")}

-

{t("page-layer-2-learn-how-does-layer-2-work-2")}

-

{t("page-layer-2-learn-how-does-layer-2-work-rollups-title")}

-

{t("page-layer-2-learn-how-does-layer-2-work-rollups-1")}

-

{t("page-layer-2-learn-how-does-layer-2-work-rollups-2")}

-
-
- {""} -
-
- -
- {rollupCards.map((card, idx) => { - return ( -
- {""} -

{card.title}

-

{card.description}

- {card.childSentence} -
- ) - })} -
- -
-
-

{t("page-layer-2-learn-dyor-title")}

-
-

- -

-

{t("page-layer-2-learn-dyor-2")}

-
-
- - {t("page-layer-2-learn-dyor-link")} - -
-
-
- -
-

{t("page-layer-2-learn-note-on-alt-l1-title")}

-
-
-

{t("page-layer-2-learn-note-on-alt-l1-1")}

-
-
-

- -

-
-
- -
- -
-
- -
- - {t("page-layer-2-learn-learn-more")} - -
-
- -
- - {t("page-layer-2-learn-explore-networks")} - -
-
-
-
- -
- -
-
- ) -} - -export default Layer2Learn diff --git a/app/[locale]/layer-2/learn/page.tsx b/app/[locale]/layer-2/learn/page.tsx index 14b31f6f7bb..df0ac16bd4a 100644 --- a/app/[locale]/layer-2/learn/page.tsx +++ b/app/[locale]/layer-2/learn/page.tsx @@ -7,29 +7,113 @@ import { import type { Lang, PageParams } from "@/lib/types" +import CalloutSSR from "@/components/CalloutSSR" +import Card from "@/components/Card" +import FileContributors from "@/components/FileContributors" +import { ContentHero, type ContentHeroProps } from "@/components/Hero" import I18nProvider from "@/components/I18nProvider" +import { Image } from "@/components/Image" +import MainArticle from "@/components/MainArticle" +import { StandaloneQuizWidget } from "@/components/Quiz/QuizWidget" +import Translation from "@/components/Translation" +import { ButtonLink } from "@/components/ui/buttons/Button" import { getAppPageContributorInfo } from "@/lib/utils/contributors" import { getMetadata } from "@/lib/utils/metadata" import { getRequiredNamespacesForPage } from "@/lib/utils/translations" -import LearnPage from "./_components/learn" import Layer2LearnPageJsonLD from "./page-jsonld" +import Callout2Image from "@/public/images/layer-2/learn-hero.png" +import heroImg from "@/public/images/layer-2/learn-hero.png" +import OptimisticRollupImage from "@/public/images/layer-2/optimistic_rollup.png" +import RollupImage from "@/public/images/layer-2/rollup-2.png" +import ZKRollupImage from "@/public/images/layer-2/zk_rollup.png" +import Callout1Image from "@/public/images/man-and-dog-playing.png" +import DAOImage from "@/public/images/use-cases/dao-2.png" +import WhatIsEthereumImage from "@/public/images/what-is-ethereum.png" + +const SLUG = "/layer-2/learn" + const Page = async (props: { params: Promise }) => { const params = await props.params const { locale } = params setRequestLocale(locale) - // Get i18n messages const allMessages = await getMessages({ locale }) - const requiredNamespaces = getRequiredNamespacesForPage("/layer-2/learn") + const requiredNamespaces = getRequiredNamespacesForPage(SLUG) const messages = pick(allMessages, requiredNamespaces) const { contributors, lastEditLocaleTimestamp } = await getAppPageContributorInfo("layer-2/learn", locale as Lang) + const t = await getTranslations("page-layer-2-learn") + + const heroProps: ContentHeroProps = { + breadcrumbs: { slug: SLUG, startDepth: 1 }, + heroImg, + title: t("page-layer-2-learn-title"), + description: t("page-layer-2-learn-description"), + buttons: [ + { + content: t("page-layer-2-learn-button-1-label"), + href: "/layer-2/", + matomo: { + eventCategory: "l2_learn", + eventAction: "button_click", + eventName: "what_is_l2", + }, + }, + { + content: t("page-layer-2-learn-button-2-label"), + href: "/layer-2/networks", + matomo: { + eventCategory: "l2_learn", + eventAction: "button_click", + eventName: "use_l2", + }, + }, + ], + } + + const layer2Cards = [ + { + emoji: ":money_with_wings:", + title: t("page-layer-2-learn-layer2Cards-1-title"), + description: t("page-layer-2-learn-layer2Cards-1-description"), + }, + { + emoji: ":closed_lock_with_key:", + title: t("page-layer-2-learn-layer2Cards-2-title"), + description: t("page-layer-2-learn-layer2Cards-2-description"), + }, + { + emoji: ":hammer_and_wrench:", + title: t("page-layer-2-learn-layer2Cards-3-title"), + description: t("page-layer-2-learn-layer2Cards-3-description"), + }, + ] + + const rollupCards = [ + { + image: OptimisticRollupImage, + title: t("page-layer-2-learn-rollupCards-optimistic-title"), + description: t("page-layer-2-learn-rollupCards-optimistic-description"), + childSentence: t( + "page-layer-2-learn-rollupCards-optimistic-childSentence" + ), + childLink: "/developers/docs/scaling/optimistic-rollups/", + }, + { + image: ZKRollupImage, + title: t("page-layer-2-learn-rollupCards-zk-title"), + description: t("page-layer-2-learn-rollupCards-zk-description"), + childSentence: t("page-layer-2-learn-rollupCards-zk-childSentence"), + childLink: "/developers/docs/scaling/zk-rollups/", + }, + ] + return ( }) => { lastEditLocaleTimestamp={lastEditLocaleTimestamp} contributors={contributors} /> - + + + +
+
+

{t("page-layer-2-learn-what-is-layer-2-title")}

+

+ +

+

+ +

+
+
+ +
+
+ +
+

{t("page-layer-2-learn-what-is-layer-1-title")}

+
+
+

+ +

+

+ +

+
+
+

+ {t("page-layer-2-learn-layer-1-list-title")} +

+
    +
  1. + + + + +
  2. +
  3. + + + + +
  4. +
  5. + + + + +
  6. +
  7. + + + + +
  8. +
+
+
+
+ +
+
+ +
+ +
+

{t("page-layer-2-learn-why-do-we-need-layer-2-title")}

+

{t("page-layer-2-learn-why-do-we-need-layer-2-1")}

+

{t("page-layer-2-learn-why-do-we-need-layer-2-2")}

+

+ {t("page-layer-2-learn-why-do-we-need-layer-2-scalability")} +

+

+ +

+

+ {t("page-layer-2-learn-why-do-we-need-layer-2-scalability-2")} +

+
+
+ +
+
+ {layer2Cards.map((card, idx) => ( +
+ +
+ ))} +
+
+ +
+
+

{t("page-layer-2-learn-how-does-layer-2-work-title")}

+

{t("page-layer-2-learn-how-does-layer-2-work-1")}

+

{t("page-layer-2-learn-how-does-layer-2-work-2")}

+

+ {t("page-layer-2-learn-how-does-layer-2-work-rollups-title")} +

+

{t("page-layer-2-learn-how-does-layer-2-work-rollups-1")}

+

{t("page-layer-2-learn-how-does-layer-2-work-rollups-2")}

+
+
+ {""} +
+
+ +
+ {rollupCards.map((card, idx) => ( +
+ {""} +

{card.title}

+

{card.description}

+ {card.childSentence} +
+ ))} +
+ +
+
+

{t("page-layer-2-learn-dyor-title")}

+
+

+ +

+

{t("page-layer-2-learn-dyor-2")}

+
+
+ + {t("page-layer-2-learn-dyor-link")} + +
+
+
+ +
+

{t("page-layer-2-learn-note-on-alt-l1-title")}

+
+
+

{t("page-layer-2-learn-note-on-alt-l1-1")}

+
+
+

+ +

+
+
+ +
+ +
+
+ +
+ + {t("page-layer-2-learn-learn-more")} + +
+
+ +
+ + {t("page-layer-2-learn-explore-networks")} + +
+
+
+
+ +
+ +
+
) } diff --git a/app/[locale]/layer-2/page.tsx b/app/[locale]/layer-2/page.tsx index 7170b8f5a3a..04b87021d9f 100644 --- a/app/[locale]/layer-2/page.tsx +++ b/app/[locale]/layer-2/page.tsx @@ -7,19 +7,33 @@ import { import type { Lang, PageParams } from "@/lib/types" +import CalloutSSR from "@/components/CalloutSSR" +import Card from "@/components/Card" +import ExpandableCard from "@/components/ExpandableCard" +import HubHero, { type HubHeroProps } from "@/components/Hero/HubHero" import I18nProvider from "@/components/I18nProvider" +import { Image } from "@/components/Image" +import MainArticle from "@/components/MainArticle" +import Translation from "@/components/Translation" +import { ButtonLink } from "@/components/ui/buttons/Button" +import InlineLink from "@/components/ui/Link" import { getAppPageContributorInfo } from "@/lib/utils/contributors" import { getMetadata } from "@/lib/utils/metadata" import { networkMaturity } from "@/lib/utils/networkMaturity" +import { numberFormat } from "@/lib/utils/numbers" import { getRequiredNamespacesForPage } from "@/lib/utils/translations" import { layer2Data } from "@/data/networks/networks" -import Layer2Page from "./_components/layer-2" import Layer2PageJsonLD from "./page-jsonld" import { getGrowThePieData, getL2beatData } from "@/lib/data" +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" +import ManDogCardImage from "@/public/images/man-and-dog-playing.png" const Page = async (props: { params: Promise }) => { const params = await props.params @@ -27,13 +41,11 @@ const Page = async (props: { params: Promise }) => { setRequestLocale(locale) - // Fetch data using the new data-layer functions (already cached) const [growThePieData, l2beatData] = await Promise.all([ getGrowThePieData(), getL2beatData(), ]) - // Handle null cases - throw error if required data is missing if (!l2beatData) { throw new Error("Failed to fetch L2beat data") } @@ -43,26 +55,24 @@ const Page = async (props: { params: Promise }) => { } const getRandomL2s = () => { - let randomL2s = layer2Data.filter( + let candidates = layer2Data.filter( (network) => networkMaturity(l2beatData.projects[network.l2beatID]) === "robust" ) - if (randomL2s.length === 0) { - randomL2s = layer2Data.filter( + if (candidates.length === 0) { + candidates = layer2Data.filter( (network) => networkMaturity(l2beatData.projects[network.l2beatID]) === "maturing" ) } - return randomL2s.sort(() => 0.5 - Math.random()).slice(0, 3) + return candidates.sort(() => 0.5 - Math.random()).slice(0, 3) } const randomL2s = layer2Data.sort(() => 0.5 - Math.random()).slice(0, 9) - const userRandomL2s = getRandomL2s() - // Get i18n messages const allMessages = await getMessages({ locale }) const requiredNamespaces = getRequiredNamespacesForPage("/layer-2") const messages = pick(allMessages, requiredNamespaces) @@ -72,15 +82,477 @@ const Page = async (props: { params: Promise }) => { locale as Lang ) + const t = await getTranslations("page-layer-2") + const tCommon = await getTranslations("common") + + const medianTxCost = + "error" in growThePieData.txCostsMedianUsd + ? { error: growThePieData.txCostsMedianUsd.error } + : growThePieData.txCostsMedianUsd.value + + const heroContent: HubHeroProps = { + title: t("page-layer-2-hero-title"), + header: t("page-layer-2-hero-header"), + description: t("page-layer-2-hero-description"), + heroImg: HeroImage, + buttons: [ + { + content: tCommon("nav-networks-explore-networks-label"), + href: "/layer-2/networks", + matomo: { + eventCategory: "l2_hub", + eventAction: "button_click", + eventName: "hero_explore_networks", + }, + }, + { + content: t("page-layer-2-hero-button-2-content"), + href: "#layer-2-powered-by-ethereum", + matomo: { + eventCategory: "l2_hub", + eventAction: "button_click", + eventName: "hero_get_started", + }, + }, + ], + } + + const calloutCards = [ + { + title: t("page-layer-2-calloutCard-1-title"), + description: t("page-layer-2-calloutCard-1-description"), + emoji: ":money_with_wings:", + }, + { + title: t("page-layer-2-calloutCard-2-title"), + description: t("page-layer-2-calloutCard-2-description"), + emoji: ":closed_lock_with_key:", + }, + { + title: t("page-layer-2-calloutCard-3-title"), + description: t("page-layer-2-calloutCard-3-description"), + emoji: ":hammer_and_wrench:", + }, + ] + return ( - + + + +
+
+
+

{t("page-layer-2-powered-by-ethereum-title")}

+

+ + {" "} + + {t("page-layer-2-powered-by-ethereum-description-2")} +

+

{t("page-layer-2-powered-by-ethereum-description-3")}

+
+
+ {t("page-layer-2-man-and-dog-alt")} +
+
+
+ +
+
+
+
+
+

+ $ + {numberFormat(locale, { + minimumFractionDigits: 2, + maximumFractionDigits: 2, + }).format(growThePieData.dailyTxCosts["ethereum"] || 0)} +

+

+ {t("page-layer-2-blockchain-transaction-cost")} +

+
+
+
+
+
+

+ $ + {numberFormat(locale, { + minimumFractionDigits: 2, + maximumFractionDigits: 3, + }).format( + typeof medianTxCost === "number" ? medianTxCost : 0 + )} +

+

+ {t("page-layer-2-networks-transaction-cost")} +

+
+
+
+
+
+ +
+
+

{t("page-layer-2-network-of-networks-title")}

+

+ {t("page-layer-2-network-of-networks-description")} +

+
+
+
+
+ {randomL2s[0].name} +
+
+ {randomL2s[1].name} +
+
+ {randomL2s[2].name} +
+
+ +
+
+
+ {randomL2s[3].name} +
+
+ {randomL2s[4].name} +
+
+ {randomL2s[5].name} +
+
+ +
+
+
+ {randomL2s[6].name} +
+
+ {randomL2s[7].name} +
+
+ {randomL2s[8].name} +
+
+ +
+ Ethereum +
+
+
+
+ +
+
+ {calloutCards.map((card, idx) => ( +
+ +
+ ))} +
+
+ +
+
+

{t("page-layer-2-ready-to-start-title")}

+

{t("page-layer-2-ready-to-start-description")}

+
+ + {t("page-layer-2-ready-to-start-button")} + +
+
+
+ +
+
+
+ {userRandomL2s.map((l2, idx) => ( +
+
+
+ {l2.name} +
+
+

{l2.name}

+

{t(l2.description)}

+
+
+
+ + {t("page-layer-2-go")} + +
+
+ ))} +
+ +
+
+ {t("page-layer-2-ethereum-logo-alt")} +

{t("page-layer-2-powered-by-ethereum-title")}

+
+
+
+
+ +
+
+
+ Walking +
+
+

{t("page-layer-2-why-do-we-need-multiple-networks-1")}

+

{t("page-layer-2-why-do-we-need-multiple-networks-2")}

+
+ + {tCommon("learn-more")} + +
+
+
+
+ +
+

{t("page-layer-2-faq-title")}

+
+ +
+

+ {t("page-layer-2-faq-ExpandableCard-1-description-1")}{" "} + + {tCommon("nav-ethereum-networks")} + + {t("page-layer-2-period")} +

+

{t("page-layer-2-faq-ExpandableCard-1-description-2")}

+
+
+ +
+

+ {t("page-layer-2-faq-ExpandableCard-2-description-1")}{" "} + + {t("page-layer-2-faq-ExpandableCard-2-link")} + + {t("page-layer-2-period")} +

+

{t("page-layer-2-faq-ExpandableCard-2-description-2")}

+
+
+ +

{t("page-layer-2-faq-ExpandableCard-3-description")}

+
+ +

{t("page-layer-2-faq-ExpandableCard-4-description")}

+
+
+
+ +
+ +
+ + {tCommon("nav-networks-explore-networks-label")} + +
+
+ +
+ + {tCommon("learn-more")} + +
+
+
+ ) } diff --git a/app/[locale]/roadmap/_vision/_components/vision.tsx b/app/[locale]/roadmap/_vision/_components/vision.tsx deleted file mode 100644 index b3ada71ef8c..00000000000 --- a/app/[locale]/roadmap/_vision/_components/vision.tsx +++ /dev/null @@ -1,263 +0,0 @@ -"use client" - -import type { ComponentProps, ComponentPropsWithRef } from "react" - -import type { ChildOnlyProp, PageWithContributorsProps } from "@/lib/types" - -import Breadcrumbs from "@/components/Breadcrumbs" -import Card from "@/components/Card" -import Emoji from "@/components/Emoji" -import FeedbackCard from "@/components/FeedbackCard" -import FileContributors from "@/components/FileContributors" -import MainArticle from "@/components/MainArticle" -import PageHero, { - type ContentType as PageHeroContent, -} from "@/components/PageHero" -import Trilemma from "@/components/Trilemma" -import { Alert } from "@/components/ui/alert" -import { ButtonLink } from "@/components/ui/buttons/Button" -import { Divider } from "@/components/ui/divider" -import { Flex, type FlexProps, VStack } from "@/components/ui/flex" -import InlineLink from "@/components/ui/Link" -import { List, ListItem } from "@/components/ui/list" - -import { cn } from "@/lib/utils/cn" - -import useTranslation from "@/hooks/useTranslation" -import { usePathname } from "@/i18n/navigation" -import oldship from "@/public/images/upgrades/oldship.png" - -/** - * TODO: Consider replacing this with a global style for the `p` element - */ -const Text = (props: Omit, "className">) => ( -

-) - -const Page = (props: ChildOnlyProp) => ( - - - -) - -const PageContent = (props: ChildOnlyProp) => ( - -) - -const H2 = ({ className, ...props }: ComponentProps<"h2">) => ( -

-) - -const CenterH2 = (props: Omit, "className">) => ( -

-) - -const H3 = (props: Omit, "className">) => ( -

-) - -const CardContainer = ({ className, ...props }: FlexProps) => ( - -) - -const ProblemCardContainer = (props: ChildOnlyProp) => { - return -} - -const CentreCard = (props: ComponentPropsWithRef) => ( - -) - -const CentralContent = (props: ChildOnlyProp) => ( -
-) - -const TrilemmaContent = (props: ChildOnlyProp) => ( -
-) - -const VisionPage = ({ - contributors, - lastEditLocaleTimestamp, -}: PageWithContributorsProps) => { - const { t } = useTranslation(["page-roadmap-vision", "page-upgrades-index"]) - const pathname = usePathname() - - const paths = [ - { - emoji: ":vertical_traffic_light:", - title: t("page-roadmap-vision-title-1"), - description: t("page-roadmap-vision-desc-1"), - }, - { - emoji: ":minidisc:", - title: t("page-roadmap-vision-title-2"), - description: t("page-roadmap-vision-desc-2"), - }, - ] - - const heroContent: PageHeroContent = { - title: t("page-roadmap-vision-title"), - header: t("page-roadmap-vision-future"), - subtitle: t("page-roadmap-vision-subtitle"), - image: oldship, - alt: t("page-eth-whats-eth-hero-alt"), - } - - return ( - <> - - - - - - - {t("page-roadmap-vision-upgrade-needs")} - {t("page-roadmap-vision-upgrade-needs-desc")} - {t("page-roadmap-vision-upgrade-needs-desc-2")} - {t("page-roadmap-vision-upgrade-needs-desc-3")} - - - - {t("page-roadmap-vision-2022")} - - - - - {t("page-roadmap-vision-2021-updates")} - - - - - {t("page-roadmap-vision-2021")} - - - - - {t("page-roadmap-vision-upgrade-needs-serenity")} - - - - - {t("page-roadmap-vision-2014")} - - - - {t("page-roadmap-vision-upgrade-needs-desc-5")} - {t("page-roadmap-vision-upgrade-needs-desc-6")} - - - - - {t("page-roadmap-vision-problems")} - - {paths.map((path, idx) => ( - - ))} - - - - - - - - - {t("page-roadmap-vision-understanding")} -

- {t("page-roadmap-vision-scalability")} -

- {t("page-roadmap-vision-scalability-desc")} - {t("page-roadmap-vision-scalability-desc-3")} - - {t("page-roadmap-vision-scalability-desc-4")}{" "} - - {t("page-roadmap-vision-danksharding")} - {" "} - -

- {t("page-roadmap-vision-security")} -

- {t("page-roadmap-vision-security-desc")} - - {t("page-roadmap-vision-security-desc-3")}{" "} - - {t("page-upgrades-index:page-upgrades-proof-stake-link")} - {" "} - - - {t("page-roadmap-vision-security-desc-5")}{" "} - - {t("page-roadmap-vision-security-desc-5-link")} - - - {t("page-roadmap-vision-security-desc-10")} - - {t("page-roadmap-vision-security-validator")}{" "} - - {t("page-roadmap-vision-ethereum-node")} - - - - {t("page-roadmap-vision-security-staking")} - -

- {t("page-roadmap-vision-sustainability")}{" "} - -

- {t("page-roadmap-vision-sustainability-subtitle")} - - {t("page-roadmap-vision-sustainability-desc-1")}{" "} - - {t("page-roadmap-vision-mining")} - - - - {t("page-roadmap-vision-sustainability-desc-2")}{" "} - - {t("page-roadmap-vision-staking-lower")} - - - {t("page-roadmap-vision-sustainability-desc-3")} - -
- {t("page-roadmap-vision-sustainability-desc-8")} - - {t("page-upgrades-index:page-upgrades-merge-btn")} - -
-
-
- -
- - -
- - ) -} - -export default VisionPage diff --git a/app/[locale]/roadmap/_vision/page.tsx b/app/[locale]/roadmap/_vision/page.tsx index bfad46be1d3..98d3db537fa 100644 --- a/app/[locale]/roadmap/_vision/page.tsx +++ b/app/[locale]/roadmap/_vision/page.tsx @@ -1,3 +1,4 @@ +import { type ComponentProps, type ComponentPropsWithRef } from "react" import { pick } from "lodash" import { getMessages, @@ -5,31 +6,135 @@ import { setRequestLocale, } from "next-intl/server" -import type { Lang, PageParams } from "@/lib/types" +import type { ChildOnlyProp, Lang, PageParams } from "@/lib/types" +import Breadcrumbs from "@/components/Breadcrumbs" +import Card from "@/components/Card" +import Emoji from "@/components/Emoji" +import FeedbackCard from "@/components/FeedbackCard" +import FileContributors from "@/components/FileContributors" import I18nProvider from "@/components/I18nProvider" +import MainArticle from "@/components/MainArticle" +import PageHero, { + type ContentType as PageHeroContent, +} from "@/components/PageHero" +import Trilemma from "@/components/Trilemma" +import { Alert } from "@/components/ui/alert" +import { ButtonLink } from "@/components/ui/buttons/Button" +import { Divider } from "@/components/ui/divider" +import { Flex, type FlexProps, VStack } from "@/components/ui/flex" +import InlineLink from "@/components/ui/Link" +import { List, ListItem } from "@/components/ui/list" +import { cn } from "@/lib/utils/cn" import { getAppPageContributorInfo } from "@/lib/utils/contributors" import { getMetadata } from "@/lib/utils/metadata" import { getRequiredNamespacesForPage } from "@/lib/utils/translations" -import VisionPage from "./_components/vision" import RoadmapVisionPageJsonLD from "./page-jsonld" +import oldship from "@/public/images/upgrades/oldship.png" + +const SLUG = "/roadmap/vision" + +const Text = (props: Omit, "className">) => ( +

+) + +const PageContainer = (props: ChildOnlyProp) => ( + + + +) + +const PageContent = (props: ChildOnlyProp) => ( + +) + +const H2 = ({ className, ...props }: ComponentProps<"h2">) => ( +

+) + +const CenterH2 = (props: Omit, "className">) => ( +

+) + +const H3 = (props: Omit, "className">) => ( +

+) + +const CardContainer = ({ className, ...props }: FlexProps) => ( + +) + +const ProblemCardContainer = (props: ChildOnlyProp) => ( + +) + +const CentreCard = (props: ComponentPropsWithRef) => ( + +) + +const CentralContent = (props: ChildOnlyProp) => ( +
+) + +const TrilemmaContent = (props: ChildOnlyProp) => ( +
+) + const Page = async (props: { params: Promise }) => { const params = await props.params const { locale } = params setRequestLocale(locale) - // Get i18n messages const allMessages = await getMessages({ locale }) - const requiredNamespaces = getRequiredNamespacesForPage("/roadmap/vision") + const requiredNamespaces = getRequiredNamespacesForPage(SLUG) const messages = pick(allMessages, requiredNamespaces) const { contributors, lastEditLocaleTimestamp } = await getAppPageContributorInfo("roadmap/vision", locale as Lang) + const t = await getTranslations("page-roadmap-vision") + const tUpgrades = await getTranslations("page-upgrades-index") + + const paths = [ + { + emoji: ":vertical_traffic_light:", + title: t("page-roadmap-vision-title-1"), + description: t("page-roadmap-vision-desc-1"), + }, + { + emoji: ":minidisc:", + title: t("page-roadmap-vision-title-2"), + description: t("page-roadmap-vision-desc-2"), + }, + ] + + const heroContent: PageHeroContent = { + title: t("page-roadmap-vision-title"), + header: t("page-roadmap-vision-future"), + subtitle: t("page-roadmap-vision-subtitle"), + image: oldship, + alt: t("page-eth-whats-eth-hero-alt"), + } + return ( }) => { lastEditLocaleTimestamp={lastEditLocaleTimestamp} contributors={contributors} /> - + + + + + + + {t("page-roadmap-vision-upgrade-needs")} + {t("page-roadmap-vision-upgrade-needs-desc")} + {t("page-roadmap-vision-upgrade-needs-desc-2")} + {t("page-roadmap-vision-upgrade-needs-desc-3")} + + + + {t("page-roadmap-vision-2022")} + + + + + {t("page-roadmap-vision-2021-updates")} + + + + + {t("page-roadmap-vision-2021")} + + + + + {t("page-roadmap-vision-upgrade-needs-serenity")} + + + + + {t("page-roadmap-vision-2014")} + + + + {t("page-roadmap-vision-upgrade-needs-desc-5")} + {t("page-roadmap-vision-upgrade-needs-desc-6")} + + + + + {t("page-roadmap-vision-problems")} + + {paths.map((path, idx) => ( + + ))} + + + + + + + + + {t("page-roadmap-vision-understanding")} +

+ {t("page-roadmap-vision-scalability")} +

+ {t("page-roadmap-vision-scalability-desc")} + {t("page-roadmap-vision-scalability-desc-3")} + + {t("page-roadmap-vision-scalability-desc-4")}{" "} + + {t("page-roadmap-vision-danksharding")} + {" "} + +

+ {t("page-roadmap-vision-security")} +

+ {t("page-roadmap-vision-security-desc")} + + {t("page-roadmap-vision-security-desc-3")}{" "} + + {tUpgrades("page-upgrades-proof-stake-link")} + {" "} + + + {t("page-roadmap-vision-security-desc-5")}{" "} + + {t("page-roadmap-vision-security-desc-5-link")} + + + {t("page-roadmap-vision-security-desc-10")} + + {t("page-roadmap-vision-security-validator")}{" "} + + {t("page-roadmap-vision-ethereum-node")} + + + + {t("page-roadmap-vision-security-staking")} + +

+ {t("page-roadmap-vision-sustainability")}{" "} + +

+ {t("page-roadmap-vision-sustainability-subtitle")} + + {t("page-roadmap-vision-sustainability-desc-1")}{" "} + + {t("page-roadmap-vision-mining")} + + + + {t("page-roadmap-vision-sustainability-desc-2")}{" "} + + {t("page-roadmap-vision-staking-lower")} + + + {t("page-roadmap-vision-sustainability-desc-3")} + +
+ {t("page-roadmap-vision-sustainability-desc-8")} + + {tUpgrades("page-upgrades-merge-btn")} + +
+
+
+ +
+ + +
) } diff --git a/app/[locale]/run-a-node/_components/run-a-node.tsx b/app/[locale]/run-a-node/_components/run-a-node.tsx deleted file mode 100644 index 7fbb402dccf..00000000000 --- a/app/[locale]/run-a-node/_components/run-a-node.tsx +++ /dev/null @@ -1,775 +0,0 @@ -"use client" - -import { HTMLAttributes } from "react" -import type { ReactNode } from "react" - -import type { ChildOnlyProp, PageWithContributorsProps } from "@/lib/types" - -import Emoji from "@/components/Emoji" -import ExpandableCard from "@/components/ExpandableCard" -import FeedbackCard from "@/components/FeedbackCard" -import FileContributors from "@/components/FileContributors" -import Discord from "@/components/icons/discord.svg" -import { - DecentralizationGlyphIcon, - DownloadGlyphIcon, - EarthGlyphIcon, - HardwareGlyphIcon, - MegaphoneGlyphIcon, - PrivacyGlyphIcon, - SovereigntyGlyphIcon, - VoteGlyphIcon, -} from "@/components/icons/run-a-node" -import { Image } from "@/components/Image" -import MainArticle from "@/components/MainArticle" -import PageHero from "@/components/PageHero" -import { StandaloneQuizWidget as QuizWidget } from "@/components/Quiz/QuizWidget" -import Translation from "@/components/Translation" -import { Button, ButtonLink } from "@/components/ui/buttons/Button" -import { Divider } from "@/components/ui/divider" -import { Center, Flex, Stack, VStack } from "@/components/ui/flex" -import InlineLink from "@/components/ui/Link" - -import { cn } from "@/lib/utils/cn" - -import { useTranslation } from "@/hooks/useTranslation" -import community from "@/public/images/enterprise-eth.png" -import hackathon from "@/public/images/hackathon_transparent.png" -import impact from "@/public/images/impact_transparent.png" -import Dappnode from "@/public/images/run-a-node/dappnode.svg" -import Dapptap from "@/public/images/run-a-node/dapptap.svg" -import ethereumInside from "@/public/images/run-a-node/ethereum-inside.png" -import Terminal from "@/public/images/run-a-node/terminal.svg" -import leslie from "@/public/images/upgrades/upgrade_rhino.png" - -const GappedPage = (props: ChildOnlyProp) => ( - -) - -const GappedContent = (props: ChildOnlyProp) => ( - -) - -const Content = (props: HTMLAttributes) => ( -
-) - -const TwoColumnContent = (props: ChildOnlyProp) => ( - -) - -const SplitContent = ({ - className, - ...props -}: HTMLAttributes) => ( - -) - -const Column = (props: ChildOnlyProp) =>
- -const SoftwareHighlight = ({ - className, - ...props -}: HTMLAttributes) => ( -
-) - -const ColumnFill = (props: ChildOnlyProp) => ( -
-) - -const ColumnNarrow = (props: ChildOnlyProp) => ( - -) - -const FlexContent = (props: ChildOnlyProp) => ( - -) - -const FlexContainer = ({ - className, - ...props -}: HTMLAttributes) => ( - -) - -const MarginFlex = (props: ChildOnlyProp) => ( - -) - -const Container = ({ - className, - ...props -}: HTMLAttributes) => ( - -) - -const BuildBox = ({ - className, - ...props -}: HTMLAttributes) => ( - -) - -const BuildBoxSpace = (props: ChildOnlyProp) => ( - -) - -const FullyLoaded = (props: ChildOnlyProp) => ( - -) - -const SvgTitle = (props: ChildOnlyProp) => ( - -) - -const ButtonContainer = (props: ChildOnlyProp) => ( - -) - -const BuildContainer = (props: ChildOnlyProp) => ( - -) - -const StakingCalloutContainer = (props: ChildOnlyProp) => ( - -) - -const H2 = (props: ChildOnlyProp) => ( -

-) - -const H3 = ({ className, ...props }: HTMLAttributes) => ( -

-) - -const H4 = (props: ChildOnlyProp) => ( -

-) - -const Text = ({ className, ...props }: HTMLAttributes) => ( -

-) - -const Width60 = (props: ChildOnlyProp) => ( -

-) - -const Width40 = (props: ChildOnlyProp) => ( -
-) - -type RunANodeCard = { - Svg: React.FC> - title: string - preview: ReactNode - body: string[] - alt: string -} - -const RunANodePage = ({ - contributors, - lastEditLocaleTimestamp, -}: PageWithContributorsProps) => { - const { t } = useTranslation("page-run-a-node") - const heroContent = { - title: t("page-run-a-node-title"), - header: , - subtitle: t("page-run-a-node-hero-subtitle"), - image: ethereumInside, - alt: t("page-run-a-node-hero-alt"), - buttons: [ - { - content: t("page-run-a-node-hero-cta-1"), - toId: "what-is-a-node", - matomo: { - eventCategory: "run a node hero buttons", - eventAction: "click", - eventName: "learn more", - }, - }, - ], - } - - const whyRunANodeCards: RunANodeCard[] = [ - { - Svg: PrivacyGlyphIcon, - title: t("page-run-a-node-privacy-title"), - preview: t("page-run-a-node-privacy-preview"), - body: [ - t("page-run-a-node-privacy-1"), - t("page-run-a-node-privacy-2"), - t("page-run-a-node-privacy-3"), - ], - alt: t("page-run-a-node-glyph-alt-privacy"), - }, - { - Svg: MegaphoneGlyphIcon, - title: t("page-run-a-node-censorship-resistance-title"), - preview: t("page-run-a-node-censorship-resistance-preview"), - body: [ - t("page-run-a-node-censorship-resistance-1"), - t("page-run-a-node-censorship-resistance-2"), - ], - alt: t("page-run-a-node-glyph-alt-censorship-resistance"), - }, - { - Svg: EarthGlyphIcon, - title: t("page-run-a-node-participate-title"), - preview: ( - - ), - body: [ - t("page-run-a-node-participate-1"), - t("page-run-a-node-participate-2"), - ], - alt: t("page-run-a-node-glyph-alt-earth"), - }, - { - Svg: DecentralizationGlyphIcon, - title: t("page-run-a-node-decentralized-title"), - preview: t("page-run-a-node-decentralized-preview"), - body: [ - t("page-run-a-node-decentralized-1"), - t("page-run-a-node-decentralized-2"), - ], - alt: t("page-run-a-node-glyph-alt-decentralization"), - }, - { - Svg: VoteGlyphIcon, - title: t("page-run-a-node-voice-your-choice-title"), - preview: t("page-run-a-node-voice-your-choice-preview"), - body: [ - t("page-run-a-node-voice-your-choice-1"), - t("page-run-a-node-voice-your-choice-2"), - ], - alt: t("page-run-a-node-glyph-alt-vote"), - }, - { - Svg: SovereigntyGlyphIcon, - title: t("page-run-a-node-sovereignty-title"), - preview: t("page-run-a-node-sovereignty-preview"), - body: [ - t("page-run-a-node-sovereignty-1"), - t("page-run-a-node-sovereignty-2"), - ], - alt: t("page-run-a-node-glyph-alt-sovereignty"), - }, - ] - - return ( - <> - -
-
- -
-
- - - - -

- -

-

{t("page-run-a-node-what-1-subtitle")}

- - - -

{t("page-run-a-node-what-2-subtitle")}

- {t("page-run-a-node-what-2-text")} -

{t("page-run-a-node-what-3-subtitle")}

- {t("page-run-a-node-what-3-text")} -
- - - -
-
- - - - - -
-

- -

-

- -

-
-
-
-

- -

-

{t("page-run-a-node-who-copy-2")}

-

{t("page-run-a-node-who-copy-3")}

-

- {t("page-run-a-node-who-copy-bold")} -

-
-
-
- - -

- -

-
- {whyRunANodeCards.map(({ Svg, title, preview, body }) => ( - ( - - )} - key={title} - > - {body.map((item) => ( -

{item}

- ))} -
- ))} -
-
- - - - -

{t("page-run-a-node-getting-started-title")}

- - - - - {t("page-run-a-node-getting-started-software-section-1")} - - - - - {t( - "page-run-a-node-getting-started-software-section-1-alert" - )} - - - - {t("page-run-a-node-getting-started-software-section-1-link")} - - - - - - - - - - - - - - - - - - - - - - {t("page-run-a-node-getting-started-software-section-3a")} - - - - - - - - - - -
- - -

{t("page-run-a-node-choose-your-adventure-title")}

- {t("page-run-a-node-choose-your-adventure-1")} - {t("page-run-a-node-choose-your-adventure-2")} - - -
-

- - {t("page-run-a-node-buy-fully-loaded-title")} -

- {t("page-run-a-node-buy-fully-loaded-description")} -
    -
  • {t("page-run-a-node-buy-fully-loaded-note-1")}
  • -
  • {t("page-run-a-node-buy-fully-loaded-note-2")}
  • -
  • - {t("page-run-a-node-buy-fully-loaded-note-3")} -
  • -
-
- - - {t("page-run-a-node-shop-dappnode")} - - - {t("page-run-a-node-shop-avado")} - - -
- - -
-

- - {t("page-run-a-node-build-your-own-title")} -

- - {t("page-run-a-node-choose-your-adventure-build-1")} - -
    -
  • - {t("page-run-a-node-choose-your-adventure-build-bullet-1")} -
  • -
  • - {t("page-run-a-node-choose-your-adventure-build-bullet-2")} -
  • -
  • - {t("page-run-a-node-choose-your-adventure-build-bullet-3")} -
  • -
-
- -
-
-
- - -

{t("page-run-a-node-build-your-own-title")}

- - - - -

{t("page-run-a-node-build-your-own-hardware-title")}

-
- - - -

{t("page-run-a-node-build-your-own-minimum-specs")}

-
    -
  • - {t("page-run-a-node-build-your-own-min-ram")} - - - {t("page-run-a-node-build-your-own-ram-note-1")} - - - - - {t("page-run-a-node-build-your-own-ram-note-2")} - - -
  • -
  • - {t("page-run-a-node-build-your-own-min-ssd")} - - - - {t("page-run-a-node-build-your-own-ssd-note")} - - - -
  • -
-
- - -

{t("page-run-a-node-build-your-own-recommended")}

-
    -
  • - {t("page-run-a-node-build-your-own-nuc")} - - - {t("page-run-a-node-build-your-own-nuc-small")} - - -
  • -
  • - {t("page-run-a-node-build-your-own-connection")} - - - {t("page-run-a-node-build-your-own-connection-small")} - - -
  • -
  • - {t("page-run-a-node-build-your-own-peripherals")} - - - {t("page-run-a-node-build-your-own-peripherals-small")} - - -
  • -
-
-
-
- - - - -

{t("page-run-a-node-build-your-own-software")}

-
- - - -
-

- {t( - "page-run-a-node-build-your-own-software-option-1-title" - )} -

- - {t( - "page-run-a-node-build-your-own-software-option-1-description" - )} - -
- - - {t( - "page-run-a-node-build-your-own-software-option-1-button" - )} - - -
- - -
-

- {t( - "page-run-a-node-build-your-own-software-option-2-title" - )} -

- - {t( - "page-run-a-node-build-your-own-software-option-2-description-1" - )} - - - {t( - "page-run-a-node-build-your-own-software-option-2-description-2" - )} - -
- - - - {t( - "page-run-a-node-build-your-own-software-option-2-button" - )} - - - -
-
-
-
- - - - -

{t("page-run-a-node-community-title")}

- {t("page-run-a-node-community-description-1")} - {t("page-run-a-node-community-description-2")} - - - - {t("page-run-a-node-community-link-1")} - - - {t("page-run-a-node-community-link-2")} - - -
- - - -
-
- - -

{t("page-run-a-node-further-reading-title")}

-
    -
  • - - {t("page-run-a-node-further-reading-1-link")} - {" "} - - {t("page-run-a-node-further-reading-1-author")} -
  • -
  • - - {t("page-run-a-node-further-reading-2-link")} - -
  • -
  • - - {t("page-run-a-node-further-reading-3-link")} - {" "} - - {t("page-run-a-node-further-reading-3-author")} -
  • -
-
- - - - - - - - -

{t("page-run-a-node-staking-title")}

- {t("page-run-a-node-staking-description")} - - - {t("page-run-a-node-staking-link")} - - -
-
- -

- - {t("page-run-a-node-staking-plans-title")} -

- - - - - {t("page-run-a-node-staking-plans-ethstaker-link-description")} -{" "} - - {t("page-run-a-node-staking-plans-ethstaker-link-label")} - - -

- - {t("page-run-a-node-rasp-pi-title")} -

- {t("page-run-a-node-rasp-pi-description")} -
    -
  • - - {t("page-run-a-node-rasp-pi-note-2-link")} - {" "} - - {t("page-run-a-node-rasp-pi-note-2-description")} -
  • -
  • - - {t("page-run-a-node-rasp-pi-note-3-link")} - {" "} - - {t("page-run-a-node-rasp-pi-note-3-description")} -
  • -
-
- - - - - -
- - ) -} - -export default RunANodePage diff --git a/app/[locale]/run-a-node/page.tsx b/app/[locale]/run-a-node/page.tsx index 911b8b1d6a3..5cbdd9146d9 100644 --- a/app/[locale]/run-a-node/page.tsx +++ b/app/[locale]/run-a-node/page.tsx @@ -1,3 +1,4 @@ +import { type HTMLAttributes, type ReactNode } from "react" import { pick } from "lodash" import { getMessages, @@ -5,24 +6,217 @@ import { setRequestLocale, } from "next-intl/server" -import type { Lang, PageParams } from "@/lib/types" +import type { ChildOnlyProp, Lang, PageParams } from "@/lib/types" +import Emoji from "@/components/Emoji" +import ExpandableCard from "@/components/ExpandableCard" +import FeedbackCard from "@/components/FeedbackCard" +import FileContributors from "@/components/FileContributors" import I18nProvider from "@/components/I18nProvider" +import Discord from "@/components/icons/discord.svg" +import { + DecentralizationGlyphIcon, + DownloadGlyphIcon, + EarthGlyphIcon, + HardwareGlyphIcon, + MegaphoneGlyphIcon, + PrivacyGlyphIcon, + SovereigntyGlyphIcon, + VoteGlyphIcon, +} from "@/components/icons/run-a-node" +import { Image } from "@/components/Image" +import MainArticle from "@/components/MainArticle" +import PageHero from "@/components/PageHero" +import { StandaloneQuizWidget as QuizWidget } from "@/components/Quiz/QuizWidget" +import Translation from "@/components/Translation" +import { Button, ButtonLink } from "@/components/ui/buttons/Button" +import { Divider } from "@/components/ui/divider" +import { Center, Flex, Stack, VStack } from "@/components/ui/flex" +import InlineLink from "@/components/ui/Link" +import { cn } from "@/lib/utils/cn" import { getAppPageContributorInfo } from "@/lib/utils/contributors" import { getMetadata } from "@/lib/utils/metadata" import { getRequiredNamespacesForPage } from "@/lib/utils/translations" -import RunANodePage from "./_components/run-a-node" import RunANodePageJsonLD from "./page-jsonld" +import community from "@/public/images/enterprise-eth.png" +import hackathon from "@/public/images/hackathon_transparent.png" +import impact from "@/public/images/impact_transparent.png" +import Dappnode from "@/public/images/run-a-node/dappnode.svg" +import Dapptap from "@/public/images/run-a-node/dapptap.svg" +import ethereumInside from "@/public/images/run-a-node/ethereum-inside.png" +import Terminal from "@/public/images/run-a-node/terminal.svg" +import leslie from "@/public/images/upgrades/upgrade_rhino.png" + +const GappedPage = (props: ChildOnlyProp) => ( + +) + +const GappedContent = (props: ChildOnlyProp) => ( + +) + +const Content = (props: HTMLAttributes) => ( +
+) + +const TwoColumnContent = (props: ChildOnlyProp) => ( + +) + +const SplitContent = ({ + className, + ...props +}: HTMLAttributes) => ( + +) + +const Column = (props: ChildOnlyProp) =>
+ +const SoftwareHighlight = ({ + className, + ...props +}: HTMLAttributes) => ( +
+) + +const ColumnFill = (props: ChildOnlyProp) => ( +
+) + +const ColumnNarrow = (props: ChildOnlyProp) => ( + +) + +const FlexContent = (props: ChildOnlyProp) => ( + +) + +const FlexContainer = ({ + className, + ...props +}: HTMLAttributes) => ( + +) + +const MarginFlex = (props: ChildOnlyProp) => ( + +) + +const Container = ({ + className, + ...props +}: HTMLAttributes) => ( + +) + +const BuildBox = ({ + className, + ...props +}: HTMLAttributes) => ( + +) + +const BuildBoxSpace = (props: ChildOnlyProp) => ( + +) + +const FullyLoaded = (props: ChildOnlyProp) => ( + +) + +const SvgTitle = (props: ChildOnlyProp) => ( + +) + +const ButtonContainer = (props: ChildOnlyProp) => ( + +) + +const BuildContainer = (props: ChildOnlyProp) => ( + +) + +const StakingCalloutContainer = (props: ChildOnlyProp) => ( + +) + +const H2 = (props: ChildOnlyProp) => ( +

+) + +const H3 = ({ className, ...props }: HTMLAttributes) => ( +

+) + +const H4 = (props: ChildOnlyProp) => ( +

+) + +const Text = ({ className, ...props }: HTMLAttributes) => ( +

+) + +const Width60 = (props: ChildOnlyProp) => ( +

+) + +const Width40 = (props: ChildOnlyProp) => ( +
+) + +type RunANodeCard = { + Svg: React.FC> + title: string + preview: ReactNode + body: string[] + alt: string +} + const Page = async (props: { params: Promise }) => { const params = await props.params const { locale } = params setRequestLocale(locale) - // Get i18n messages const allMessages = await getMessages({ locale }) const requiredNamespaces = getRequiredNamespacesForPage("/run-a-node") const messages = pick(allMessages, requiredNamespaces) @@ -30,6 +224,93 @@ const Page = async (props: { params: Promise }) => { const { contributors, lastEditLocaleTimestamp } = await getAppPageContributorInfo("run-a-node", locale as Lang) + const t = await getTranslations("page-run-a-node") + + const heroContent = { + title: t("page-run-a-node-title"), + header: , + subtitle: t("page-run-a-node-hero-subtitle"), + image: ethereumInside, + alt: t("page-run-a-node-hero-alt"), + buttons: [ + { + content: t("page-run-a-node-hero-cta-1"), + toId: "what-is-a-node", + matomo: { + eventCategory: "run a node hero buttons", + eventAction: "click", + eventName: "learn more", + }, + }, + ], + } + + const whyRunANodeCards: RunANodeCard[] = [ + { + Svg: PrivacyGlyphIcon, + title: t("page-run-a-node-privacy-title"), + preview: t("page-run-a-node-privacy-preview"), + body: [ + t("page-run-a-node-privacy-1"), + t("page-run-a-node-privacy-2"), + t("page-run-a-node-privacy-3"), + ], + alt: t("page-run-a-node-glyph-alt-privacy"), + }, + { + Svg: MegaphoneGlyphIcon, + title: t("page-run-a-node-censorship-resistance-title"), + preview: t("page-run-a-node-censorship-resistance-preview"), + body: [ + t("page-run-a-node-censorship-resistance-1"), + t("page-run-a-node-censorship-resistance-2"), + ], + alt: t("page-run-a-node-glyph-alt-censorship-resistance"), + }, + { + Svg: EarthGlyphIcon, + title: t("page-run-a-node-participate-title"), + preview: ( + + ), + body: [ + t("page-run-a-node-participate-1"), + t("page-run-a-node-participate-2"), + ], + alt: t("page-run-a-node-glyph-alt-earth"), + }, + { + Svg: DecentralizationGlyphIcon, + title: t("page-run-a-node-decentralized-title"), + preview: t("page-run-a-node-decentralized-preview"), + body: [ + t("page-run-a-node-decentralized-1"), + t("page-run-a-node-decentralized-2"), + ], + alt: t("page-run-a-node-glyph-alt-decentralization"), + }, + { + Svg: VoteGlyphIcon, + title: t("page-run-a-node-voice-your-choice-title"), + preview: t("page-run-a-node-voice-your-choice-preview"), + body: [ + t("page-run-a-node-voice-your-choice-1"), + t("page-run-a-node-voice-your-choice-2"), + ], + alt: t("page-run-a-node-glyph-alt-vote"), + }, + { + Svg: SovereigntyGlyphIcon, + title: t("page-run-a-node-sovereignty-title"), + preview: t("page-run-a-node-sovereignty-preview"), + body: [ + t("page-run-a-node-sovereignty-1"), + t("page-run-a-node-sovereignty-2"), + ], + alt: t("page-run-a-node-glyph-alt-sovereignty"), + }, + ] + return ( }) => { lastEditLocaleTimestamp={lastEditLocaleTimestamp} contributors={contributors} /> - + +
+
+ +
+
+ + + + +

+ +

+

{t("page-run-a-node-what-1-subtitle")}

+ + + +

{t("page-run-a-node-what-2-subtitle")}

+ {t("page-run-a-node-what-2-text")} +

{t("page-run-a-node-what-3-subtitle")}

+ {t("page-run-a-node-what-3-text")} +
+ + + +
+
+ + + + + +
+

+ +

+

+ +

+
+
+
+

+ +

+

{t("page-run-a-node-who-copy-2")}

+

{t("page-run-a-node-who-copy-3")}

+

+ {t("page-run-a-node-who-copy-bold")} +

+
+
+
+ + +

+ +

+
+ {whyRunANodeCards.map(({ Svg, title, preview, body }) => ( + } + key={title} + > + {body.map((item) => ( +

{item}

+ ))} +
+ ))} +
+
+ + + + +

{t("page-run-a-node-getting-started-title")}

+ + + + + {t("page-run-a-node-getting-started-software-section-1")} + + + + + {t( + "page-run-a-node-getting-started-software-section-1-alert" + )} + + + + {t("page-run-a-node-getting-started-software-section-1-link")} + + + + + + + + + + + + + + + + + + + + + + {t("page-run-a-node-getting-started-software-section-3a")} + + + + + + + + + + +
+ + +

{t("page-run-a-node-choose-your-adventure-title")}

+ {t("page-run-a-node-choose-your-adventure-1")} + {t("page-run-a-node-choose-your-adventure-2")} + + +
+

+ + {t("page-run-a-node-buy-fully-loaded-title")} +

+ {t("page-run-a-node-buy-fully-loaded-description")} +
    +
  • {t("page-run-a-node-buy-fully-loaded-note-1")}
  • +
  • {t("page-run-a-node-buy-fully-loaded-note-2")}
  • +
  • + {t("page-run-a-node-buy-fully-loaded-note-3")} +
  • +
+
+ + + {t("page-run-a-node-shop-dappnode")} + + + {t("page-run-a-node-shop-avado")} + + +
+ + +
+

+ + {t("page-run-a-node-build-your-own-title")} +

+ + {t("page-run-a-node-choose-your-adventure-build-1")} + +
    +
  • + {t("page-run-a-node-choose-your-adventure-build-bullet-1")} +
  • +
  • + {t("page-run-a-node-choose-your-adventure-build-bullet-2")} +
  • +
  • + {t("page-run-a-node-choose-your-adventure-build-bullet-3")} +
  • +
+
+ +
+
+
+ + +

{t("page-run-a-node-build-your-own-title")}

+ + + + +

{t("page-run-a-node-build-your-own-hardware-title")}

+
+ + + +

{t("page-run-a-node-build-your-own-minimum-specs")}

+
    +
  • + {t("page-run-a-node-build-your-own-min-ram")} + + + {t("page-run-a-node-build-your-own-ram-note-1")} + + + + + {t("page-run-a-node-build-your-own-ram-note-2")} + + +
  • +
  • + {t("page-run-a-node-build-your-own-min-ssd")} + + + + {t("page-run-a-node-build-your-own-ssd-note")} + + + +
  • +
+
+ + +

{t("page-run-a-node-build-your-own-recommended")}

+
    +
  • + {t("page-run-a-node-build-your-own-nuc")} + + + {t("page-run-a-node-build-your-own-nuc-small")} + + +
  • +
  • + {t("page-run-a-node-build-your-own-connection")} + + + {t("page-run-a-node-build-your-own-connection-small")} + + +
  • +
  • + {t("page-run-a-node-build-your-own-peripherals")} + + + {t("page-run-a-node-build-your-own-peripherals-small")} + + +
  • +
+
+
+
+ + + + +

{t("page-run-a-node-build-your-own-software")}

+
+ + + +
+

+ {t( + "page-run-a-node-build-your-own-software-option-1-title" + )} +

+ + {t( + "page-run-a-node-build-your-own-software-option-1-description" + )} + +
+ + + {t( + "page-run-a-node-build-your-own-software-option-1-button" + )} + + +
+ + +
+

+ {t( + "page-run-a-node-build-your-own-software-option-2-title" + )} +

+ + {t( + "page-run-a-node-build-your-own-software-option-2-description-1" + )} + + + {t( + "page-run-a-node-build-your-own-software-option-2-description-2" + )} + +
+ + + + {t( + "page-run-a-node-build-your-own-software-option-2-button" + )} + + + +
+
+
+
+ + + + +

{t("page-run-a-node-community-title")}

+ {t("page-run-a-node-community-description-1")} + {t("page-run-a-node-community-description-2")} + + + + {t("page-run-a-node-community-link-1")} + + + {t("page-run-a-node-community-link-2")} + + +
+ + + +
+
+ + +

{t("page-run-a-node-further-reading-title")}

+
    +
  • + + {t("page-run-a-node-further-reading-1-link")} + {" "} + - {t("page-run-a-node-further-reading-1-author")} +
  • +
  • + + {t("page-run-a-node-further-reading-2-link")} + +
  • +
  • + + {t("page-run-a-node-further-reading-3-link")} + {" "} + - {t("page-run-a-node-further-reading-3-author")} +
  • +
+
+ + + + + + + + +

{t("page-run-a-node-staking-title")}

+ {t("page-run-a-node-staking-description")} + + + {t("page-run-a-node-staking-link")} + + +
+
+ +

+ + {t("page-run-a-node-staking-plans-title")} +

+ + + + + {t("page-run-a-node-staking-plans-ethstaker-link-description")} -{" "} + + {t("page-run-a-node-staking-plans-ethstaker-link-label")} + + +

+ + {t("page-run-a-node-rasp-pi-title")} +

+ {t("page-run-a-node-rasp-pi-description")} +
    +
  • + + {t("page-run-a-node-rasp-pi-note-2-link")} + {" "} + - {t("page-run-a-node-rasp-pi-note-2-description")} +
  • +
  • + + {t("page-run-a-node-rasp-pi-note-3-link")} + {" "} + - {t("page-run-a-node-rasp-pi-note-3-description")} +
  • +
+
+ + + + + +
) } diff --git a/app/[locale]/staking/_components/staking.tsx b/app/[locale]/staking/_components/staking.tsx deleted file mode 100644 index 6196ea39878..00000000000 --- a/app/[locale]/staking/_components/staking.tsx +++ /dev/null @@ -1,565 +0,0 @@ -import { type HTMLAttributes, ReactNode } from "react" -import { getTranslations } from "next-intl/server" - -import type { - ChildOnlyProp, - PageWithContributorsProps, - StakingStatsData, -} from "@/lib/types" - -import { List as ButtonDropdownList } from "@/components/ButtonDropdown" -import Card from "@/components/Card" -import ExpandableCard from "@/components/ExpandableCard" -import FeedbackCard from "@/components/FeedbackCard" -import FileContributors from "@/components/FileContributors" -import { ContentContainer, Page } from "@/components/MdComponents" -import MobileButtonDropdown from "@/components/MobileButtonDropdown" -import PageHero from "@/components/PageHero" -import StakingCommunityCallout from "@/components/Staking/StakingCommunityCallout" -import StakingHierarchy from "@/components/Staking/StakingHierarchy" -import StakingStatsBox from "@/components/Staking/StakingStatsBox" -import TableOfContents from "@/components/TableOfContents" -import Translation from "@/components/Translation" -import { - ButtonLink, - type ButtonLinkProps, -} from "@/components/ui/buttons/Button" -import { Divider } from "@/components/ui/divider" -import { Flex, Stack, VStack } from "@/components/ui/flex" -import InlineLink from "@/components/ui/Link" -import { ListItem, UnorderedList } from "@/components/ui/list" - -import { cn } from "@/lib/utils/cn" - -import rhino from "@/public/images/upgrades/upgrade_rhino.png" - -type BenefitsType = { - title: string - emoji: string - description: ReactNode - linkText?: string - href?: string -} - -const PageContainer = (props: ChildOnlyProp) => ( - -) - -const HeroStatsWrapper = (props: ChildOnlyProp) => ( - -) - -const ComparisonGrid = (props: ChildOnlyProp) => { - return ( -
- ) -} - -const H2 = (props: HTMLAttributes) => ( -

-) - -const ColorH3 = ({ - color, - children, -}: { - color: `text-${string} dark:text-${string}` - children: ReactNode -}) =>

{children}

- -const H4 = (props: HTMLAttributes) => ( -

-) - -const StyledButtonLink = ({ - href, - children, -}: Pick) => ( - {children} -) - -const CardGrid = (props: ChildOnlyProp) => ( -
-) - -const StyledCard = (props: { - title: string - emoji: string - description: ReactNode - key: number - children: ReactNode -}) => ( - - {props.children} - -) - -type Props = PageWithContributorsProps & { - data: StakingStatsData -} - -const StakingPage = async ({ - data, - contributors, - lastEditLocaleTimestamp, -}: Props) => { - const t = await getTranslations("page-staking") - - const heroContent = { - title: t("page-staking-hero-title"), - header: t("page-staking-hero-header"), - subtitle: t("page-staking-hero-subtitle"), - image: rhino, - alt: t("page-staking-image-alt"), - buttons: [], - } - - const benefits: BenefitsType[] = [ - { - title: t("page-staking-benefits-1-title"), - emoji: "💰", - description: ( - - ), - }, - { - title: t("page-staking-benefits-2-title"), - emoji: ":shield:", - description: t("page-staking-benefits-2-description"), - }, - { - title: t("page-staking-benefits-3-title"), - emoji: "🍃", - description: t("page-staking-benefits-3-description"), - linkText: t("page-staking-benefits-3-link"), - href: "/energy-consumption", - }, - ] - - const dropdownLinks: ButtonDropdownList = { - text: t("page-staking-dropdown-staking-options"), - ariaLabel: t("page-staking-dropdown-staking-options-alt"), - items: [ - { - text: t("page-staking-dropdown-home"), - href: "/staking/", - matomo: { - eventCategory: `Staking dropdown`, - eventAction: `Clicked`, - eventName: "clicked staking home", - }, - }, - { - text: t("page-staking-dropdown-solo"), - href: "/staking/solo/", - matomo: { - eventCategory: `Staking dropdown`, - eventAction: `Clicked`, - eventName: "clicked solo staking", - }, - }, - { - text: t("page-staking-dropdown-saas"), - href: "/staking/saas/", - matomo: { - eventCategory: `Staking dropdown`, - eventAction: `Clicked`, - eventName: "clicked staking as a service", - }, - }, - { - text: t("page-staking-dropdown-pools"), - href: "/staking/pools/", - matomo: { - eventCategory: `Staking dropdown`, - eventAction: `Clicked`, - eventName: "clicked pooled staking", - }, - }, - { - text: t("page-staking-dropdown-withdrawals"), - href: "/staking/withdrawals/", - matomo: { - eventCategory: `Staking dropdown`, - eventAction: `Clicked`, - eventName: "clicked about withdrawals", - }, - }, - { - text: t("page-staking-dropdown-dvt"), - href: "/staking/dvt/", - matomo: { - eventCategory: `Staking dropdown`, - eventAction: `Clicked`, - eventName: "clicked about dvt", - }, - }, - ], - } - - const tocItems = { - whatIsStaking: { - id: "what-is-staking", - title: t("page-staking-section-what-title"), - }, - whyStakeYourEth: { - id: "why-stake-your-eth", - title: t("page-staking-section-why-title"), - }, - howToStakeYourEth: { - id: "how-to-stake-your-eth", - title: t("page-staking-toc-how-to-stake-your-eth"), - }, - comparisonOfOptions: { - id: "comparison-of-options", - title: t("page-staking-toc-comparison-of-options"), - }, - joinTheCommunity: { - id: "join-the-community", - title: t("page-staking-join-community"), - }, - faq: { - id: "faq", - title: t("page-staking-toc-faq"), - }, - further: { - id: "further", - title: t("page-staking-toc-further"), - }, - } as const - - const tocArray = Object.keys(tocItems).map((key) => { - const { id, title } = tocItems[key as keyof typeof tocItems] - return { title, url: "#" + id } - }) - - return ( - - - - - - - - - -
-

- {tocItems.whatIsStaking.title} -

-

- -

-
-
-

- {tocItems.whyStakeYourEth.title} -

- - {benefits.map( - ({ title, description, emoji, linkText, href }, idx) => ( - - {href && linkText && ( - {linkText} - )} - - ) - )} - -
-
-

- {tocItems.howToStakeYourEth.title} -

- -

{t("page-staking-section-why-p1")}

-

{t("page-staking-section-why-p2")}

-
-
- -
-

- -

-
- -
-

- {tocItems.comparisonOfOptions.title} -

-

- {t("page-staking-section-comparison-subtitle")} -

- - - {t("page-staking-dropdown-solo")} - -
-

{t("page-staking-section-comparison-rewards-title")}

- - - {t("page-staking-section-comparison-solo-rewards-li1")} - - - {t("page-staking-section-comparison-solo-rewards-li2")} - - - {t("page-staking-section-comparison-solo-rewards-li3")} - - -
-
-

{t("page-staking-section-comparison-risks-title")}

- - - {t("page-staking-section-comparison-solo-risks-li1")} - - - {t("page-staking-section-comparison-solo-risks-li2")} - - - {t("page-staking-section-comparison-solo-risks-li3")} - - - {t("page-staking-section-comparison-solo-risks-li4")} - - -
-
-

- {t("page-staking-section-comparison-requirements-title")} -

- - - - - - - - - - - -
-
- - {t("page-staking-more-on-solo")} - -
- - {t("page-staking-dropdown-saas")} - -
-

{t("page-staking-section-comparison-rewards-title")}

- - - {t("page-staking-section-comparison-saas-rewards-li1")} - - - {t("page-staking-section-comparison-saas-rewards-li2")} - - -
-
-

{t("page-staking-section-comparison-risks-title")}

- - - {t("page-staking-section-comparison-saas-risks-li1")} - - - {t("page-staking-section-comparison-saas-risks-li2")} - - -
-
-

- {t("page-staking-section-comparison-requirements-title")} -

- - - - - - - - - - - -
-
- - {t("page-staking-more-on-saas")} - -
- - - {t("page-staking-dropdown-pools")} - -
-

{t("page-staking-section-comparison-rewards-title")}

- - - - - - - - - - - -
-
-

{t("page-staking-section-comparison-risks-title")}

- - - - - - - - -
-
-

- {t("page-staking-section-comparison-requirements-title")} -

- - - - - - - - -
-
- - {t("page-staking-more-on-pools")} - -
-
-
- - -
-

{tocItems.faq.title}

- - -

{t("page-staking-faq-4-answer-p1")}

-

{t("page-staking-faq-4-answer-p2")}

-

{t("page-staking-faq-4-answer-p3")}

- - {t("page-upgrades-merge-btn")} - -
-
- - -

{t("page-staking-faq-5-answer-p1")}

-

{t("page-staking-faq-5-answer-p2")}

- - {t("page-staking-faq-5-answer-link")} - -
-
- - - - - {t("page-staking-faq-2-answer")} - - - -

{t("page-staking-faq-3-answer-p1")}

-

- -

-
-
-
-
-

{tocItems.further.title}

- - - - {t("page-staking-further-reading-2-link")} - {" "} - -{" "} - - {t("page-staking-further-reading-author-vitalik-buterin")} - - - - - {t("page-staking-further-reading-4-link")} - {" "} - - {t("page-staking-further-reading-4-author")} - - - - {t("page-staking-further-reading-5-link")} - {" "} - - {t("page-staking-further-reading-5-author")} - - - - {t("page-staking-further-reading-6-link")} - - - - - {t("page-staking-further-reading-8-link")} - - - - - {t("page-staking-further-reading-9-link")} - - - - - {t("page-staking-further-reading-10-link")} - - - - -
-
- -
-
-
- -
-
- ) -} - -export default StakingPage diff --git a/app/[locale]/staking/page.tsx b/app/[locale]/staking/page.tsx index 85c552b005e..15c04143998 100644 --- a/app/[locale]/staking/page.tsx +++ b/app/[locale]/staking/page.tsx @@ -1,3 +1,4 @@ +import { type HTMLAttributes, type ReactNode } from "react" import { pick } from "lodash" import { getMessages, @@ -5,18 +6,111 @@ import { setRequestLocale, } from "next-intl/server" -import { Lang, PageParams, StakingStatsData } from "@/lib/types" +import type { + ChildOnlyProp, + Lang, + PageParams, + StakingStatsData, +} from "@/lib/types" +import { type List as ButtonDropdownList } from "@/components/ButtonDropdown" +import Card from "@/components/Card" +import ExpandableCard from "@/components/ExpandableCard" +import FeedbackCard from "@/components/FeedbackCard" +import FileContributors from "@/components/FileContributors" import I18nProvider from "@/components/I18nProvider" +import { ContentContainer, Page as MdPage } from "@/components/MdComponents" +import MobileButtonDropdown from "@/components/MobileButtonDropdown" +import PageHero from "@/components/PageHero" +import StakingCommunityCallout from "@/components/Staking/StakingCommunityCallout" +import StakingHierarchy from "@/components/Staking/StakingHierarchy" +import StakingStatsBox from "@/components/Staking/StakingStatsBox" +import TableOfContents from "@/components/TableOfContents" +import Translation from "@/components/Translation" +import { + ButtonLink, + type ButtonLinkProps, +} from "@/components/ui/buttons/Button" +import { Divider } from "@/components/ui/divider" +import { Flex, Stack, VStack } from "@/components/ui/flex" +import InlineLink from "@/components/ui/Link" +import { ListItem, UnorderedList } from "@/components/ui/list" +import { cn } from "@/lib/utils/cn" import { getAppPageContributorInfo } from "@/lib/utils/contributors" import { getMetadata } from "@/lib/utils/metadata" import { getRequiredNamespacesForPage } from "@/lib/utils/translations" -import StakingPage from "./_components/staking" import StakingPageJsonLD from "./page-jsonld" import { getBeaconchainData } from "@/lib/data" +import rhino from "@/public/images/upgrades/upgrade_rhino.png" + +type BenefitsType = { + title: string + emoji: string + description: ReactNode + linkText?: string + href?: string +} + +const PageContainer = (props: ChildOnlyProp) => ( + +) + +const HeroStatsWrapper = (props: ChildOnlyProp) => ( + +) + +const ComparisonGrid = (props: ChildOnlyProp) => ( +
+) + +const H2 = (props: HTMLAttributes) => ( +

+) + +const ColorH3 = ({ + color, + children, +}: { + color: `text-${string} dark:text-${string}` + children: ReactNode +}) =>

{children}

+ +const H4 = (props: HTMLAttributes) => ( +

+) + +const StyledButtonLink = ({ + href, + children, +}: Pick) => ( + {children} +) + +const CardGrid = (props: ChildOnlyProp) => ( +
+) + +const StyledCard = (props: { + title: string + emoji: string + description: ReactNode + children: ReactNode +}) => ( + + {props.children} + +) const Page = async (props: { params: Promise }) => { const params = await props.params @@ -49,6 +143,136 @@ const Page = async (props: { params: Promise }) => { const { contributors, lastEditLocaleTimestamp } = await getAppPageContributorInfo("staking", locale as Lang) + const t = await getTranslations("page-staking") + + const heroContent = { + title: t("page-staking-hero-title"), + header: t("page-staking-hero-header"), + subtitle: t("page-staking-hero-subtitle"), + image: rhino, + alt: t("page-staking-image-alt"), + buttons: [], + } + + const benefits: BenefitsType[] = [ + { + title: t("page-staking-benefits-1-title"), + emoji: "💰", + description: ( + + ), + }, + { + title: t("page-staking-benefits-2-title"), + emoji: ":shield:", + description: t("page-staking-benefits-2-description"), + }, + { + title: t("page-staking-benefits-3-title"), + emoji: "🍃", + description: t("page-staking-benefits-3-description"), + linkText: t("page-staking-benefits-3-link"), + href: "/energy-consumption", + }, + ] + + const dropdownLinks: ButtonDropdownList = { + text: t("page-staking-dropdown-staking-options"), + ariaLabel: t("page-staking-dropdown-staking-options-alt"), + items: [ + { + text: t("page-staking-dropdown-home"), + href: "/staking/", + matomo: { + eventCategory: `Staking dropdown`, + eventAction: `Clicked`, + eventName: "clicked staking home", + }, + }, + { + text: t("page-staking-dropdown-solo"), + href: "/staking/solo/", + matomo: { + eventCategory: `Staking dropdown`, + eventAction: `Clicked`, + eventName: "clicked solo staking", + }, + }, + { + text: t("page-staking-dropdown-saas"), + href: "/staking/saas/", + matomo: { + eventCategory: `Staking dropdown`, + eventAction: `Clicked`, + eventName: "clicked staking as a service", + }, + }, + { + text: t("page-staking-dropdown-pools"), + href: "/staking/pools/", + matomo: { + eventCategory: `Staking dropdown`, + eventAction: `Clicked`, + eventName: "clicked pooled staking", + }, + }, + { + text: t("page-staking-dropdown-withdrawals"), + href: "/staking/withdrawals/", + matomo: { + eventCategory: `Staking dropdown`, + eventAction: `Clicked`, + eventName: "clicked about withdrawals", + }, + }, + { + text: t("page-staking-dropdown-dvt"), + href: "/staking/dvt/", + matomo: { + eventCategory: `Staking dropdown`, + eventAction: `Clicked`, + eventName: "clicked about dvt", + }, + }, + ], + } + + const tocItems = { + whatIsStaking: { + id: "what-is-staking", + title: t("page-staking-section-what-title"), + }, + whyStakeYourEth: { + id: "why-stake-your-eth", + title: t("page-staking-section-why-title"), + }, + howToStakeYourEth: { + id: "how-to-stake-your-eth", + title: t("page-staking-toc-how-to-stake-your-eth"), + }, + comparisonOfOptions: { + id: "comparison-of-options", + title: t("page-staking-toc-comparison-of-options"), + }, + joinTheCommunity: { + id: "join-the-community", + title: t("page-staking-join-community"), + }, + faq: { + id: "faq", + title: t("page-staking-toc-faq"), + }, + further: { + id: "further", + title: t("page-staking-toc-further"), + }, + } as const + + const tocArray = Object.keys(tocItems).map((key) => { + const { id, title } = tocItems[key as keyof typeof tocItems] + return { title, url: "#" + id } + }) + return ( }) => { lastEditLocaleTimestamp={lastEditLocaleTimestamp} contributors={contributors} /> - + + + + + + + + + +
+

+ {tocItems.whatIsStaking.title} +

+

+ +

+
+
+

+ {tocItems.whyStakeYourEth.title} +

+ + {benefits.map( + ({ title, description, emoji, linkText, href }, idx) => ( + + {href && linkText && ( + {linkText} + )} + + ) + )} + +
+
+

+ {tocItems.howToStakeYourEth.title} +

+ +

{t("page-staking-section-why-p1")}

+

{t("page-staking-section-why-p2")}

+
+
+ +
+

+ +

+
+ +
+

+ {tocItems.comparisonOfOptions.title} +

+

+ {t("page-staking-section-comparison-subtitle")} +

+ + + {t("page-staking-dropdown-solo")} + +
+

+ {t("page-staking-section-comparison-rewards-title")} +

+ + + {t("page-staking-section-comparison-solo-rewards-li1")} + + + {t("page-staking-section-comparison-solo-rewards-li2")} + + + {t("page-staking-section-comparison-solo-rewards-li3")} + + +
+
+

{t("page-staking-section-comparison-risks-title")}

+ + + {t("page-staking-section-comparison-solo-risks-li1")} + + + {t("page-staking-section-comparison-solo-risks-li2")} + + + {t("page-staking-section-comparison-solo-risks-li3")} + + + {t("page-staking-section-comparison-solo-risks-li4")} + + +
+
+

+ {t("page-staking-section-comparison-requirements-title")} +

+ + + + + + + + + + + +
+
+ + {t("page-staking-more-on-solo")} + +
+ + {t("page-staking-dropdown-saas")} + +
+

+ {t("page-staking-section-comparison-rewards-title")} +

+ + + {t("page-staking-section-comparison-saas-rewards-li1")} + + + {t("page-staking-section-comparison-saas-rewards-li2")} + + +
+
+

{t("page-staking-section-comparison-risks-title")}

+ + + {t("page-staking-section-comparison-saas-risks-li1")} + + + {t("page-staking-section-comparison-saas-risks-li2")} + + +
+
+

+ {t("page-staking-section-comparison-requirements-title")} +

+ + + + + + + + + + + +
+
+ + {t("page-staking-more-on-saas")} + +
+ + + {t("page-staking-dropdown-pools")} + +
+

+ {t("page-staking-section-comparison-rewards-title")} +

+ + + + + + + + + + + +
+
+

{t("page-staking-section-comparison-risks-title")}

+ + + + + + + + +
+
+

+ {t("page-staking-section-comparison-requirements-title")} +

+ + + + + + + + +
+
+ + {t("page-staking-more-on-pools")} + +
+
+
+ + +
+

{tocItems.faq.title}

+ + +

{t("page-staking-faq-4-answer-p1")}

+

{t("page-staking-faq-4-answer-p2")}

+

{t("page-staking-faq-4-answer-p3")}

+ + {t("page-upgrades-merge-btn")} + +
+
+ + +

{t("page-staking-faq-5-answer-p1")}

+

{t("page-staking-faq-5-answer-p2")}

+ + {t("page-staking-faq-5-answer-link")} + +
+
+ + + + + {t("page-staking-faq-2-answer")} + + + +

{t("page-staking-faq-3-answer-p1")}

+

+ +

+
+
+
+
+

{tocItems.further.title}

+ + + + {t("page-staking-further-reading-2-link")} + {" "} + -{" "} + + {t("page-staking-further-reading-author-vitalik-buterin")} + + + + + {t("page-staking-further-reading-4-link")} + {" "} + - {t("page-staking-further-reading-4-author")} + + + + {t("page-staking-further-reading-5-link")} + {" "} + - {t("page-staking-further-reading-5-author")} + + + + {t("page-staking-further-reading-6-link")} + + + + + {t("page-staking-further-reading-8-link")} + + + + + {t("page-staking-further-reading-9-link")} + + + + + {t("page-staking-further-reading-10-link")} + + + + +
+
+ +
+
+
+ +
+
) } diff --git a/src/components/ExpandableCard.tsx b/src/components/ExpandableCard.tsx index 8b0c4659b38..dd7b03b3530 100644 --- a/src/components/ExpandableCard.tsx +++ b/src/components/ExpandableCard.tsx @@ -21,7 +21,7 @@ export type ExpandableCardProps = { children?: ReactNode contentPreview?: ReactNode title: ReactNode - svg?: React.FC> + svg?: ReactNode eventAction?: string eventCategory?: string eventName?: string @@ -33,7 +33,7 @@ const ExpandableCard = ({ children, contentPreview, title, - svg: Svg, + svg, eventAction = "Clicked", eventCategory = "", eventName = "", @@ -83,7 +83,7 @@ const ExpandableCard = ({ >
- {Svg && } + {svg}

{title}

{contentPreview && (