diff --git a/.all-contributorsrc b/.all-contributorsrc index 6c8f304d3d5..24aa9246167 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -12724,6 +12724,15 @@ "contributions": [ "bug" ] + }, + { + "login": "microHoffman", + "name": "microHoffman", + "avatar_url": "https://avatars.githubusercontent.com/u/61500778?v=4", + "profile": "http://pwn.xyz", + "contributions": [ + "bug" + ] } ], "contributorsPerLine": 7, diff --git a/.gitignore b/.gitignore index 063f615e818..30517221f8a 100644 --- a/.gitignore +++ b/.gitignore @@ -60,3 +60,4 @@ src/data/crowdin/bucketsAwaitingReviewReport.csv # Storybook build-storybook.log storybook-static + diff --git a/README.md b/README.md index 9de12654da5..ef45247f0f9 100644 --- a/README.md +++ b/README.md @@ -1947,6 +1947,7 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d JJOptimist
JJOptimist

🐛 + microHoffman
microHoffman

🐛 diff --git a/app/[locale]/gas/_components/gas.tsx b/app/[locale]/gas/_components/gas.tsx index 3210d07ece7..79fdcdd3022 100644 --- a/app/[locale]/gas/_components/gas.tsx +++ b/app/[locale]/gas/_components/gas.tsx @@ -13,6 +13,7 @@ import { Image } from "@/components/Image" import InfoBanner from "@/components/InfoBanner" import MainArticle from "@/components/MainArticle" import PageHero from "@/components/PageHero" +import { StandaloneQuizWidget } from "@/components/Quiz/QuizWidget" import Translation from "@/components/Translation" import { ButtonLink } from "@/components/ui/buttons/Button" import { Divider } from "@/components/ui/divider" @@ -384,6 +385,9 @@ const GasPage = () => { + + + diff --git a/app/[locale]/roadmap/_components/ReleaseCarousel.tsx b/app/[locale]/roadmap/_components/ReleaseCarousel.tsx new file mode 100644 index 00000000000..c092d5eebe0 --- /dev/null +++ b/app/[locale]/roadmap/_components/ReleaseCarousel.tsx @@ -0,0 +1,264 @@ +"use client" + +import { useEffect, useState } from "react" + +import { Image } from "@/components/Image" +import { ButtonLink } from "@/components/ui/buttons/Button" +import { + Carousel, + type CarouselApi, + CarouselContent, + CarouselItem, + CarouselNext, + CarouselPrevious, +} from "@/components/ui/carousel" + +import { cn } from "@/lib/utils/cn" +import { formatDate } from "@/lib/utils/date" + +import { releasesData } from "@/data/roadmap/releases" + +const findLatestReleaseIndex = () => { + const today = new Date() + const twoMonthsFromNow = new Date() + twoMonthsFromNow.setMonth(today.getMonth() + 2) + + // First try to find a release within the next 2 months + const upcomingReleaseIndex = releasesData.findIndex((release) => { + const releaseDate = new Date(release.releaseDate) + return releaseDate > today && releaseDate <= twoMonthsFromNow + }) + + // If no upcoming release found, find the most recent release up to today + if (upcomingReleaseIndex === -1) { + const pastReleases = releasesData.filter( + (release) => new Date(release.releaseDate) <= today + ) + if (pastReleases.length > 0) { + const mostRecentRelease = pastReleases[pastReleases.length - 1] + return releasesData.findIndex( + (release) => release.releaseDate === mostRecentRelease.releaseDate + ) + } + } + + return upcomingReleaseIndex +} + +const ReleaseCarousel = () => { + const todayDate = new Date() + const twoMonthsFromNow = new Date() + twoMonthsFromNow.setMonth(todayDate.getMonth() + 2) + + const [api1, setApi1] = useState() + const [api2, setApi2] = useState() + const [currentIndex, setCurrentIndex] = useState(() => + findLatestReleaseIndex() + ) + + useEffect(() => { + if (!api1 || !api2) { + return + } + + api1.on("select", () => { + setCurrentIndex(api1.selectedScrollSnap()) + api2.scrollTo(api1.selectedScrollSnap()) + }) + + api2.on("select", () => { + setCurrentIndex(api2.selectedScrollSnap()) + api1.scrollTo(api2.selectedScrollSnap()) + }) + }, [api1, api2]) + + return ( +
+
+
+
+ {/* First Carousel */} + + + {releasesData.map((release, index) => { + const releaseDate = new Date(release.releaseDate) + const nextRelease = + releaseDate > todayDate && releaseDate <= twoMonthsFromNow + const labelType = + releaseDate < todayDate + ? 1 + : releaseDate < twoMonthsFromNow + ? 2 + : 3 + + return ( + +
+
+ {labelType === 1 && ( +
+

In production

+
+ )} + {labelType === 2 && ( +
+

+ Coming soon +

+
+ )} + {labelType === 3 && ( +
+

+ In development +

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

+ {release.releaseName} +

+

+ {formatDate(release.releaseDate)} +

+
+
+ + ) + })} + +
+ + +
+ + + {/* Second Carousel */} + + + {releasesData.map((release) => ( + +
+
+ {release.releaseName} +
+
+
+

+ {release.releaseName} +

+

+ {formatDate(release.releaseDate)} +

+
+ +
+

+ Main features +

+
+ {release.content} +
+
+ + Learn more + +
+
+
+ ))} +
+
+ + +
+
+
+
+
+
+ ) +} + +export default ReleaseCarousel diff --git a/app/[locale]/roadmap/_components/roadmap.tsx b/app/[locale]/roadmap/_components/roadmap.tsx new file mode 100644 index 00000000000..b373eb20747 --- /dev/null +++ b/app/[locale]/roadmap/_components/roadmap.tsx @@ -0,0 +1,377 @@ +import BannerNotification from "@/components/Banners/BannerNotification" +import ExpandableCard from "@/components/ExpandableCard" +import FeedbackCard from "@/components/FeedbackCard" +import { HubHero } from "@/components/Hero" +import type { HubHeroProps } from "@/components/Hero/HubHero" +import { + AccountAbstractionIcon, + BetterUserExperienceIcon, + CheaperTransactionsIcon, + DankshardingIcon, + ExtraSecurityIcon, + FutureProofingIcon, + ProposerBuilderSeparationIcon, + SecretLeaderElectionIcon, + SingleSlotFinalityIcon, + StatelessnessIcon, + VerkleTreesIcon, +} from "@/components/icons/roadmap" +import { Image } from "@/components/Image" +import MainArticle from "@/components/MainArticle" +import { ButtonLink } from "@/components/ui/buttons/Button" +import Link from "@/components/ui/Link" +import InlineLink from "@/components/ui/Link" +import { LinkBox, LinkOverlay } from "@/components/ui/link-box" + +import ReleaseCarousel from "./ReleaseCarousel" + +import { useTranslation } from "@/hooks/useTranslation" +import ethBlocksImage from "@/public/images/developers-eth-blocks.png" +import communityHeroImg from "@/public/images/heroes/community-hero.png" +import roadmapHeroImg from "@/public/images/heroes/roadmap-hub-hero.jpg" + +const RoadmapPage = () => { + const { t } = useTranslation("page-roadmap") + + const heroContent: HubHeroProps = { + title: "", + header: t("page-roadmap-meta-title"), + description: t("page-roadmap-meta-description"), + heroImg: roadmapHeroImg, + } + + const changesComingItems = [ + { + title: "Cheaper transactions", + icon: , + description: + "Rollups are too expensive and rely on centralized components, causing users to place too much trust in their operators. The roadmap includes fixes for both of these problems.", + button: { + label: "More on reducing fees", + href: "/roadmap/scaling", + }, + }, + { + title: "Extra security", + icon: , + description: + "Ethereum is already very secure but it can be made even stronger, ready to withstand all kinds of attack far into the future.", + button: { + label: "More on security", + href: "/roadmap/security", + }, + }, + { + title: "Better user experience", + icon: , + description: + "More support for smart contract wallets and light-weight nodes will make using Ethereum simpler and safer.", + button: { + label: "More on user experience", + href: "/roadmap/user-experience", + }, + }, + { + title: "Future-proofing", + icon: , + description: + "Ethereum researchers and developers are solving tomorrow's problems today, readying the network for future generations.", + button: { + label: "More on future-proofing", + href: "/roadmap/future-proofing", + }, + }, + ] + + const technicalUpgradesItems = [ + { + icon: , + title: "Danksharding", + description: + "Danksharding makes L2 rollups much cheaper for users by adding “blobs” of data to Ethereum blocks.", + href: "/roadmap/danksharding", + }, + { + icon: , + title: "Single slot finality", + description: + "Instead of waiting for fifteen minutes, blocks could get proposed and finalized in the same slot. This is more convenient for apps and difficult to attack.", + href: "/roadmap/single-slot-finality", + }, + { + icon: , + title: "Proposer-builder separation", + description: + "Splitting the block building and block proposal tasks across separate validators creates a fairer, more censorship resistant and efficient way for Ethereum to come to consensus.", + href: "/roadmap/pbs", + }, + { + icon: , + title: "Secret leader election", + description: + "Clever cryptography can be used to ensure that the identity of the current block proposer is not made public, protecting them from certain types of attack.", + href: "/roadmap/secret-leader-election", + }, + { + icon: , + title: "Account abstraction", + description: + "Account abstraction is a class of upgrades that support smart contract wallets natively on Ethereum, rather than having to use complex middleware.", + href: "/roadmap/account-abstraction", + }, + { + icon: , + title: "Verkle trees", + description: + "Verkle trees are a data structure that can be used to enable stateless clients on Ethereum. These clients will require a small amount of storage space but will still be able to verify new blocks.", + href: "/roadmap/verkle-trees", + }, + { + icon: , + title: "Statelessness", + description: + "Stateless clients will be able to verify new blocks without having to store large amounts of data. This will provide all the benefits of running a node with only a tiny fraction of today’s costs.", + href: "/roadmap/statelessness", + }, + ] + + // TODO: MATOMO EVENTS + return ( + + +

+ Ethereum's development is community-driven and subject to change. +

+
+
+ + +
+ +
+ +
+

What changes are coming to Ethereum?

+

+ Ethereum is already a powerful platform, but it is still being + improved. An ambitious set of improvements will upgrade Ethereum + from its current form into a fully scaled, maximally resilient + platform. +

+
+ {changesComingItems.map((item) => ( +
+
+

{item.title}

+
+ {item.icon} +
+
+

{item.description}

+ + {item.button.label} + +
+ ))} +
+
+ +
+
+

Why does Ethereum need a roadmap?

+

+ Ethereum gets regular upgrades that enhance its scalability, + security, or sustainability. One of Ethereum's core strengths + is adapting as new ideas emerge from research and development. + Adaptability gives Ethereum the flexibility to tackle emerging + challenges and keep up with the most advanced technological + breakthroughs. +

+

How the roadmap is defined

+

+ The roadmap is mostly the result of years of work by researchers + and developers - because the protocol is very technical - but any + motivated person can participate. +

+

+ Ideas usually start off as discussions on a forum such as{" "} + ethresear.ch,{" "} + + Ethereum Magicians + {" "} + or the Eth R&D discord server. They may be responses to new + vulnerabilities that are discovered, suggestions from + organizations working in the application layer (such as dapps and + exchanges) or from known frictions for end users (such as costs or + transaction speeds). +

+

+ When these ideas mature, they can be proposed as{" "} + + Ethereum Improvement Proposals + + . This is all done in public so that anyone from the community can + weigh in at any time. +

+ + More on Ethereum governance + +
+
+ Ethereum roadmap +
+
+ +
+

+ What technical upgrades are coming to Ethereum? +

+
+ {technicalUpgradesItems.map((item) => ( + +
+
{item.icon}
+

{item.title}

+
+

+ {item.description} +

+ + + + Learn more + + +
+ ))} +
+
+ +
+
+ Ethereum blocks +
+
+

What is the timeline for these upgrades?

+
+ +
+

+ Yes—almost definitely. The roadmap is the + current plan for upgrading Ethereum, covering both near-term + and future plans. We expect the roadmap to change as new + information and technology become available. +

+

+ Think of Ethereum's roadmap as a set of intentions for + improving Ethereum; it is the core researchers' and + developers' best hypothesis of Ethereum's most + optimal path forward. +

+
+
+ +
+

+ Some upgrades are lower priority and likely not to be + implemented for the next 5-10 years (e.g. quantum + resistance).{" "} + + Giving precise timing of each upgrade is complicated + {" "} + to predict as many roadmap items are worked on in parallel + and developed at different speeds. The urgency of an upgrade + can also change over time depending on external factors + (e.g. a sudden leap in the performance and availability of + quantum computers may make quantum-resistant cryptography + more urgent). +

+

+ One way to think about Ethereum development is by analogy to + biological evolution. A network that is able to adapt to new + challenges and maintain fitness is more likely to succeed + that one that is resistant to change, although as the + network becomes more and more performant, scalable and + secure fewer changes to the protocol will be required. +

+
+
+ +
+

+ Upgrades tend not to impact end-users except by providing + better user-experiences and a more secure protocol and + perhaps more options for how to interact with + Ethereum.{" "} + + Regular users are not required to actively participate in + an upgrade, nor are they required to do anything** to + secure their assets. + {" "} + Node operators will need + to update their clients to prepare for an upgrade. Some + upgrades may lead to changes for application developers. For + example, history expiry upgrades may lead application + developers to grab historical data from new sources. +

+
+
+ +
+

+ Sharding is splitting up the Ethereum blockchain so that + subsets of{" "} + validators are only + responsible for a fraction of the total data. This was + originally intended to be the way for Ethereum to scale. + However, layer 2{" "} + rollups have developed much faster than expected and have + provided a lot of scaling already, and will provide much + more after Proto-Danksharding is implemented. This means + "shard chains" are no longer needed and have been + dropped from the roadmap. +

+
+
+
+
+
+ + +
+
+ ) +} + +export default RoadmapPage diff --git a/app/[locale]/roadmap/page.tsx b/app/[locale]/roadmap/page.tsx new file mode 100644 index 00000000000..587c593c66d --- /dev/null +++ b/app/[locale]/roadmap/page.tsx @@ -0,0 +1,48 @@ +import pick from "lodash.pick" +import { getTranslations } from "next-intl/server" + +import { Lang } from "@/lib/types" + +import I18nProvider from "@/components/I18nProvider" + +import { getMetadata } from "@/lib/utils/metadata" +import { getRequiredNamespacesForPage } from "@/lib/utils/translations" + +import RoadmapPage from "./_components/roadmap" + +import { loadMessages } from "@/i18n/loadMessages" + +const Page = async ({ params }: { params: Promise<{ locale: Lang }> }) => { + const { locale } = await params + + // Get i18n messages + const allMessages = await loadMessages(locale) + const requiredNamespaces = getRequiredNamespacesForPage("/roadmap") + const messages = pick(allMessages, requiredNamespaces) + + return ( + + + + ) +} + +export async function generateMetadata({ + params, +}: { + params: Promise<{ locale: string }> +}) { + const { locale } = await params + + const t = await getTranslations({ locale, namespace: "page-roadmap" }) + + return await getMetadata({ + locale, + slug: ["roadmap"], + title: t("page-roadmap-meta-title"), + description: t("page-roadmap-meta-description"), + image: "/images/roadmap/roadmap-hub-hero.png", + }) +} + +export default Page diff --git a/package.json b/package.json index f9eec08d1c2..15a66c9a9bb 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ethereum-org-website", - "version": "10.1.0", + "version": "10.2.0", "license": "MIT", "private": true, "scripts": { @@ -42,7 +42,7 @@ "@radix-ui/react-radio-group": "^1.2.0", "@radix-ui/react-scroll-area": "^1.2.2", "@radix-ui/react-select": "^2.1.1", - "@radix-ui/react-slot": "^1.1.0", + "@radix-ui/react-slot": "^1.2.0", "@radix-ui/react-switch": "^1.1.0", "@radix-ui/react-tabs": "^1.1.0", "@radix-ui/react-tooltip": "^1.1.2", @@ -56,6 +56,7 @@ "class-variance-authority": "^0.7.0", "clsx": "^2.1.1", "cmdk": "^1.0.0", + "embla-carousel-react": "^8.6.0", "ethereum-blockies-base64": "^1.0.2", "framer-motion": "^10.13.0", "gray-matter": "^4.0.3", diff --git a/public/content/roadmap/index.md b/public/content/roadmap/index.md deleted file mode 100644 index 1de5fe6a33b..00000000000 --- a/public/content/roadmap/index.md +++ /dev/null @@ -1,118 +0,0 @@ ---- -title: Ethereum roadmap -description: The path to more scalability, security and sustainability for Ethereum. -lang: en -template: roadmap -image: /images/heroes/roadmap-hub-hero.jpg -alt: "Ethereum roadmap" -summaryPoints: -buttons: - - content: Further upgrades - toId: what-changes-are-coming - - content: Past upgrades - href: /history/ - variant: outline ---- - -Ethereum is already a powerful platform for global coordination, but it is still being improved. An ambitious set of improvements will upgrade Ethereum from its current form into a fully scaled, maximally resilient platform. These upgrades are laid out in the Ethereum roadmap. - -**To learn about previous upgrades to Ethereum, please visit our [History](/history/) page** - -## What changes are coming to Ethereum? {#what-changes-are-coming} - -The Ethereum roadmap outlines the specific improvements that will be made to protocol in the future. Overall, the roadmap will bring the following benefits to Ethereum users: - - - - - - - - -## Why does Ethereum need a roadmap? {#why-does-ethereum-need-a-roadmap} - -Ethereum gets regular upgrades that enhance its scalability, security, or sustainability. One of Ethereum's core strengths is adapting as new ideas emerge from research and development. Adaptability gives Ethereum the flexibility to tackle emerging challenges and keep up with the most advanced technological breakthroughs. - - - -The roadmap is mostly the result of years of work by researchers and developers - because the protocol is very technical - but any motivated person can participate. Ideas usually start off as discussions on a forum such as [ethresear.ch](https://ethresear.ch/), [Ethereum Magicians](https://ethereum-magicians.org/) or the Eth R&D discord server. They may be responses to new vulnerabilities that are discovered, suggestions from organizations working in the application layer (such as [dapps](/glossary/#dapp) and exchanges) or from known frictions for end users (such as costs or transaction speeds). When these ideas mature, they can be proposed as [Ethereum Improvement Proposals](https://eips.ethereum.org/). This is all done in public so that anyone from the community can weigh in at any time. - -[More on Ethereum governance](/governance/) - - - - -

What was ETH2?

- -

The term 'Eth2' was commonly used to describe the future of Ethereum before the switch to proof-of-stake but it was phased out in favor of more precise terminology. It was originally used to differentiate the Ethereum network before the switch to proof-of-stake and the network after, or sometimes to refer to the different Ethereum clients (execution clients were sometimes referred to as ETH1 clients and consensus clients were sometimes referred to as ETH2 clients).

- -
- -## Will Ethereum's roadmap change over time? {#will-ethereums-roadmap-change-over-time} - -**Yes—almost definitely**. The roadmap is the current plan for upgrading Ethereum, covering both near-term and future plans. We expect the roadmap to change as new information and technology become available. - -Think of Ethereum's roadmap as a set of intentions for improving Ethereum; it is the core researchers' and developers' best hypothesis of Ethereum's most optimal path forward. - -## When will the roadmap be finished? {#when-will-the-roadmap-be-finished} - -Some upgrades are lower priority and likely not to be implemented for the next 5-10 years (e.g. quantum resistance). **Giving precise timing of each upgrade is complicated to predict** as many roadmap items are worked on in parallel and developed at different speeds. The urgency of an upgrade can also change over time depending on external factors (e.g. a sudden leap in the performance and availability of quantum computers may make quantum-resistant cryptography more urgent). - -One way to think about Ethereum development is by analogy to biological evolution. A network that is able to adapt to new challenges and maintain fitness is more likely to succeed that one that is resistant to change, although as the network becomes more and more performant, scalable and secure fewer changes to the protocol will be required. - -## Do I have to do anything when there is an upgrade? {#do-i-have-to-do-anything-when-there-is-an-upgrade} - -Upgrades tend not to impact end-users except by providing better user-experiences and a more secure protocol and perhaps more options for how to interact with Ethereum. **Regular users are not required to actively participate in an upgrade, nor are they required to do anything** to secure their assets. [Node](/glossary/#node) operators will need to update their clients to prepare for an upgrade. Some upgrades may lead to changes for application developers. For example, history expiry upgrades may lead application developers to grab historical data from new sources. - -## What about The Verge, The Splurge, etc? {#what-about-the-verge-splurge-etc} - -[Vitalik Buterin proposed a vision for the Ethereum roadmap](https://twitter.com/VitalikButerin/status/1741190491578810445) that was organized into several categories linked by their effects on Ethereum's architecture. It included: - -- **The Merge**: upgrades relating to the switch from [proof-of-work](/glossary/#pow) to [proof-of-stake](/glossary/#pos) -- **The Surge**: upgrades related to scalability by [rollups](/glossary/#rollups) and data sharding -- **The Scourge**: upgrades related to censorship resistance, decentralization and protocol risks from [MEV](/glossary/#mev) -- **The Verge**: upgrades related to verifying [blocks](/glossary/#block) more easily -- **The Purge**: upgrades related to reducing the computational costs of running nodes and simplifying the protocol -- **The Splurge**: other upgrades that don't fit well into the previous categories. - -We decided not to use this terminology because we wanted to use a simpler and more user-centric model. Although we use user-centric language, the vision remains the same as the one proposed by Vitalik. - -## What about sharding? {#what-about-sharding} - -Sharding is splitting up the Ethereum blockchain so that subsets of [validators](/glossary/#validator) are only responsible for a fraction of the total data. This was originally intended to be the way for Ethereum to scale. However, [layer 2](/glossary/#layer-2) rollups have developed much faster than expected and have provided a lot of scaling already, and will provide much more after Proto-Danksharding is implemented. This means "shard chains" are no longer needed and have been dropped from the roadmap. - -## Looking for specific technical upgrades? {#looking-for-specific-technical-upgrades} - -- [Pectra](/roadmap/pectra) - Prague/Electra hardfork that brings new approach to account abstraction, improves scalability and more. -- [Danksharding](/roadmap/danksharding) - Danksharding makes layer 2 rollups much cheaper for users by adding “blobs” of data to Ethereum blocks. -- [Staking withdrawals](/staking/withdrawals) - The Shanghai/Capella upgrade enabled staking withdrawals on Ethereum, allowing people to unlock their staked ETH. -- [Single slot finality](/roadmap/single-slot-finality) - Instead of waiting for fifteen minutes, blocks could get proposed and finalized in the same slot. This is more convenient for apps and much more difficult to attack. -- [Proposer-builder separation](/roadmap/pbs) - Splitting the block building and block proposal tasks across separate validators creates a fairer, more censorship resistant and efficient way for Ethereum to come to consensus. -- [Secret leader election](/roadmap/secret-leader-election) - Clever cryptography can be used to ensure that the identity of the current block proposer is not made public, protecting them from certain types of attack. -- [Account abstraction](/roadmap/account-abstraction) - Account abstraction is a class of upgrades that support smart contract wallets natively on Ethereum, rather than having to use complex middleware. -- [Verkle trees](/roadmap/verkle-trees) - Verkle trees are a data structure that can be used to enable stateless clients on Ethereum. These “stateless” clients will require a tiny amount of storage space but will still be able to verify new blocks. -- [Statelessness](/roadmap/statelessness) - Stateless clients will be able to verify new blocks without having to store large amounts of data. This will provide all the benefits of running a node with only a tiny fraction of today’s costs. diff --git a/public/images/roadmap/roadmap-pectra.png b/public/images/roadmap/roadmap-pectra.png new file mode 100644 index 00000000000..82a3d2a2c3f Binary files /dev/null and b/public/images/roadmap/roadmap-pectra.png differ diff --git a/src/components/DocLink/index.tsx b/src/components/DocLink/index.tsx index b4d84471af3..a5e4b7fc61c 100644 --- a/src/components/DocLink/index.tsx +++ b/src/components/DocLink/index.tsx @@ -4,6 +4,7 @@ import { cn } from "@/lib/utils/cn" import Emoji from "../Emoji" import { Center, Flex, Stack } from "../ui/flex" +import InlineLink from "../ui/Link" import { LinkBox, LinkOverlay } from "../ui/link-box" import { useRtlFlip } from "@/hooks/useRtlFlip" @@ -30,10 +31,12 @@ const DocLink = ({ href, children, isExternal = false }: DocLinkProps) => { - -

- {children} -

+ + +

+ {children} +

+
diff --git a/src/components/ExpandableCard.tsx b/src/components/ExpandableCard.tsx index 65084d5ab75..aad9b420c7a 100644 --- a/src/components/ExpandableCard.tsx +++ b/src/components/ExpandableCard.tsx @@ -4,6 +4,7 @@ import React, { type ReactNode, useState } from "react" import { Flex, HStack, VStack } from "@/components/ui/flex" +import { cn } from "@/lib/utils/cn" import { trackCustomEvent } from "@/lib/utils/matomo" import type { IconBaseType } from "./icons/icon-base" @@ -25,6 +26,7 @@ export type ExpandableCardProps = { eventCategory?: string eventName?: string visible?: boolean + className?: string } const ExpandableCard = ({ @@ -36,6 +38,7 @@ const ExpandableCard = ({ eventCategory = "", eventName = "", visible = false, + className, }: ExpandableCardProps) => { const [isVisible, setIsVisible] = useState(visible) const { t } = useTranslation("common") @@ -62,7 +65,7 @@ const ExpandableCard = ({ + + + ), +}) diff --git a/src/components/icons/roadmap/BetterUserExperienceIcon.tsx b/src/components/icons/roadmap/BetterUserExperienceIcon.tsx new file mode 100644 index 00000000000..dde3eb9af99 --- /dev/null +++ b/src/components/icons/roadmap/BetterUserExperienceIcon.tsx @@ -0,0 +1,35 @@ +import { createIconBase } from "../icon-base" + +export const BetterUserExperienceIcon = createIconBase({ + displayName: "BetterUserExperienceIcon", + viewBox: "0 0 50 50", + className: "w-[50px] h-[50px]", + children: ( + <> + + + + + + + + ), +}) diff --git a/src/components/icons/roadmap/CheaperTransactionsIcon.tsx b/src/components/icons/roadmap/CheaperTransactionsIcon.tsx new file mode 100644 index 00000000000..8c3481c6d13 --- /dev/null +++ b/src/components/icons/roadmap/CheaperTransactionsIcon.tsx @@ -0,0 +1,27 @@ +import { createIconBase } from "../icon-base" + +export const CheaperTransactionsIcon = createIconBase({ + displayName: "CheaperTransactionsIcon", + viewBox: "0 0 54 40", + className: "w-[54px] h-[40px]", + children: ( + <> + + + + + + ), +}) diff --git a/src/components/icons/roadmap/DankshardingIcon.tsx b/src/components/icons/roadmap/DankshardingIcon.tsx new file mode 100644 index 00000000000..e01a7173c7d --- /dev/null +++ b/src/components/icons/roadmap/DankshardingIcon.tsx @@ -0,0 +1,15 @@ +import { createIconBase } from "../icon-base" + +export const DankshardingIcon = createIconBase({ + displayName: "DankshardingIcon", + viewBox: "0 0 28 28", + className: "w-[28px] h-[28px]", + children: ( + <> + + + ), +}) diff --git a/src/components/icons/roadmap/ExtraSecurityIcon.tsx b/src/components/icons/roadmap/ExtraSecurityIcon.tsx new file mode 100644 index 00000000000..7b304aeae4e --- /dev/null +++ b/src/components/icons/roadmap/ExtraSecurityIcon.tsx @@ -0,0 +1,23 @@ +import { createIconBase } from "../icon-base" + +export const ExtraSecurityIcon = createIconBase({ + displayName: "ExtraSecurityIcon", + viewBox: "0 0 44 53", + className: "w-[44px] h-[53px]", + children: ( + <> + + + + + ), +}) diff --git a/src/components/icons/roadmap/FutureProofingIcon.tsx b/src/components/icons/roadmap/FutureProofingIcon.tsx new file mode 100644 index 00000000000..cfbe18c7b30 --- /dev/null +++ b/src/components/icons/roadmap/FutureProofingIcon.tsx @@ -0,0 +1,31 @@ +import { createIconBase } from "../icon-base" + +export const FutureProofingIcon = createIconBase({ + displayName: "FutureProofingIcon", + viewBox: "0 0 56 56", + className: "w-[56px] h-[56px]", + children: ( + <> + + + + + + + ), +}) diff --git a/src/components/icons/roadmap/ProposerBuilderSeparationIcon.tsx b/src/components/icons/roadmap/ProposerBuilderSeparationIcon.tsx new file mode 100644 index 00000000000..4828f3918af --- /dev/null +++ b/src/components/icons/roadmap/ProposerBuilderSeparationIcon.tsx @@ -0,0 +1,15 @@ +import { createIconBase } from "../icon-base" + +export const ProposerBuilderSeparationIcon = createIconBase({ + displayName: "ProposerBuilderSeparationIcon", + viewBox: "0 0 28 28", + className: "w-[28px] h-[28px]", + children: ( + <> + + + ), +}) diff --git a/src/components/icons/roadmap/SecretLeaderElectionIcon.tsx b/src/components/icons/roadmap/SecretLeaderElectionIcon.tsx new file mode 100644 index 00000000000..63faec198db --- /dev/null +++ b/src/components/icons/roadmap/SecretLeaderElectionIcon.tsx @@ -0,0 +1,15 @@ +import { createIconBase } from "../icon-base" + +export const SecretLeaderElectionIcon = createIconBase({ + displayName: "SecretLeaderElectionIcon", + viewBox: "0 0 28 28", + className: "w-[28px] h-[28px]", + children: ( + <> + + + ), +}) diff --git a/src/components/icons/roadmap/SingleSlotFinalityIcon.tsx b/src/components/icons/roadmap/SingleSlotFinalityIcon.tsx new file mode 100644 index 00000000000..6b2f7653f6a --- /dev/null +++ b/src/components/icons/roadmap/SingleSlotFinalityIcon.tsx @@ -0,0 +1,15 @@ +import { createIconBase } from "../icon-base" + +export const SingleSlotFinalityIcon = createIconBase({ + displayName: "SingleSlotFinalityIcon", + viewBox: "0 0 28 28", + className: "w-[28px] h-[28px]", + children: ( + <> + + + ), +}) diff --git a/src/components/icons/roadmap/StakingWithdrawalsIcon.tsx b/src/components/icons/roadmap/StakingWithdrawalsIcon.tsx new file mode 100644 index 00000000000..2023033b85f --- /dev/null +++ b/src/components/icons/roadmap/StakingWithdrawalsIcon.tsx @@ -0,0 +1,15 @@ +import { createIconBase } from "../icon-base" + +export const StakingWithdrawalsIcon = createIconBase({ + displayName: "StakingWithdrawalsIcon", + viewBox: "0 0 28 28", + className: "w-[28px] h-[28px]", + children: ( + <> + + + ), +}) diff --git a/src/components/icons/roadmap/StatelessnessIcon.tsx b/src/components/icons/roadmap/StatelessnessIcon.tsx new file mode 100644 index 00000000000..c90ccc5d227 --- /dev/null +++ b/src/components/icons/roadmap/StatelessnessIcon.tsx @@ -0,0 +1,15 @@ +import { createIconBase } from "../icon-base" + +export const StatelessnessIcon = createIconBase({ + displayName: "StatelessnessIcon", + viewBox: "0 0 28 28", + className: "w-[28px] h-[28px]", + children: ( + <> + + + ), +}) diff --git a/src/components/icons/roadmap/VerkleTreesIcon.tsx b/src/components/icons/roadmap/VerkleTreesIcon.tsx new file mode 100644 index 00000000000..326f3c4c4e6 --- /dev/null +++ b/src/components/icons/roadmap/VerkleTreesIcon.tsx @@ -0,0 +1,15 @@ +import { createIconBase } from "../icon-base" + +export const VerkleTreesIcon = createIconBase({ + displayName: "VerkleTreesIcon", + viewBox: "0 0 28 28", + className: "w-[28px] h-[28px]", + children: ( + <> + + + ), +}) diff --git a/src/components/icons/roadmap/index.ts b/src/components/icons/roadmap/index.ts new file mode 100644 index 00000000000..5beac56b0b2 --- /dev/null +++ b/src/components/icons/roadmap/index.ts @@ -0,0 +1,27 @@ +import { AccountAbstractionIcon } from "./AccountAbstractionIcon" +import { BetterUserExperienceIcon } from "./BetterUserExperienceIcon" +import { CheaperTransactionsIcon } from "./CheaperTransactionsIcon" +import { DankshardingIcon } from "./DankshardingIcon" +import { ExtraSecurityIcon } from "./ExtraSecurityIcon" +import { FutureProofingIcon } from "./FutureProofingIcon" +import { ProposerBuilderSeparationIcon } from "./ProposerBuilderSeparationIcon" +import { SecretLeaderElectionIcon } from "./SecretLeaderElectionIcon" +import { SingleSlotFinalityIcon } from "./SingleSlotFinalityIcon" +import { StakingWithdrawalsIcon } from "./StakingWithdrawalsIcon" +import { StatelessnessIcon } from "./StatelessnessIcon" +import { VerkleTreesIcon } from "./VerkleTreesIcon" + +export { + AccountAbstractionIcon, + BetterUserExperienceIcon, + CheaperTransactionsIcon, + DankshardingIcon, + ExtraSecurityIcon, + FutureProofingIcon, + ProposerBuilderSeparationIcon, + SecretLeaderElectionIcon, + SingleSlotFinalityIcon, + StakingWithdrawalsIcon, + StatelessnessIcon, + VerkleTreesIcon, +} diff --git a/src/components/ui/carousel.tsx b/src/components/ui/carousel.tsx new file mode 100644 index 00000000000..32b67c80cfb --- /dev/null +++ b/src/components/ui/carousel.tsx @@ -0,0 +1,261 @@ +import * as React from "react" +import useEmblaCarousel, { + type UseEmblaCarouselType, +} from "embla-carousel-react" + +import { ChevronNext, ChevronPrev } from "@/components/Chevron" +import { Button } from "@/components/ui/buttons/Button" + +import { cn } from "@/lib/utils/cn" + +type CarouselApi = UseEmblaCarouselType[1] +type UseCarouselParameters = Parameters +type CarouselOptions = UseCarouselParameters[0] +type CarouselPlugin = UseCarouselParameters[1] + +type CarouselProps = { + opts?: CarouselOptions + plugins?: CarouselPlugin + orientation?: "horizontal" | "vertical" + setApi?: (api: CarouselApi) => void +} + +type CarouselContextProps = { + carouselRef: ReturnType[0] + api: ReturnType[1] + scrollPrev: () => void + scrollNext: () => void + canScrollPrev: boolean + canScrollNext: boolean +} & CarouselProps + +const CarouselContext = React.createContext(null) + +function useCarousel() { + const context = React.useContext(CarouselContext) + + if (!context) { + throw new Error("useCarousel must be used within a ") + } + + return context +} + +const Carousel = React.forwardRef< + HTMLDivElement, + React.HTMLAttributes & CarouselProps +>( + ( + { + orientation = "horizontal", + opts, + setApi, + plugins, + className, + children, + ...props + }, + ref + ) => { + const [carouselRef, api] = useEmblaCarousel( + { + ...opts, + axis: orientation === "horizontal" ? "x" : "y", + }, + plugins + ) + const [canScrollPrev, setCanScrollPrev] = React.useState(false) + const [canScrollNext, setCanScrollNext] = React.useState(false) + + const onSelect = React.useCallback((api: CarouselApi) => { + if (!api) { + return + } + + setCanScrollPrev(api.canScrollPrev()) + setCanScrollNext(api.canScrollNext()) + }, []) + + const scrollPrev = React.useCallback(() => { + api?.scrollPrev() + }, [api]) + + const scrollNext = React.useCallback(() => { + api?.scrollNext() + }, [api]) + + const handleKeyDown = React.useCallback( + (event: React.KeyboardEvent) => { + if (event.key === "ArrowLeft") { + event.preventDefault() + scrollPrev() + } else if (event.key === "ArrowRight") { + event.preventDefault() + scrollNext() + } + }, + [scrollPrev, scrollNext] + ) + + React.useEffect(() => { + if (!api || !setApi) { + return + } + + setApi(api) + }, [api, setApi]) + + React.useEffect(() => { + if (!api) { + return + } + + onSelect(api) + api.on("reInit", onSelect) + api.on("select", onSelect) + + return () => { + api?.off("select", onSelect) + } + }, [api, onSelect]) + + return ( + +
+ {children} +
+
+ ) + } +) +Carousel.displayName = "Carousel" + +const CarouselContent = React.forwardRef< + HTMLDivElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => { + const { carouselRef, orientation } = useCarousel() + + return ( +
+
+
+ ) +}) +CarouselContent.displayName = "CarouselContent" + +const CarouselItem = React.forwardRef< + HTMLDivElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => { + const { orientation } = useCarousel() + + return ( +
+ ) +}) +CarouselItem.displayName = "CarouselItem" + +const CarouselPrevious = React.forwardRef< + HTMLButtonElement, + React.ComponentProps +>(({ className, variant = "outline", size = "sm", ...props }, ref) => { + const { orientation, scrollPrev, canScrollPrev } = useCarousel() + + return ( + + ) +}) +CarouselPrevious.displayName = "CarouselPrevious" + +const CarouselNext = React.forwardRef< + HTMLButtonElement, + React.ComponentProps +>(({ className, variant = "outline", size = "sm", ...props }, ref) => { + const { orientation, scrollNext, canScrollNext } = useCarousel() + + return ( + + ) +}) +CarouselNext.displayName = "CarouselNext" + +export { + Carousel, + type CarouselApi, + CarouselContent, + CarouselItem, + CarouselNext, + CarouselPrevious, +} diff --git a/src/data/chains.ts b/src/data/chains.ts index 645a5fe5434..a21c60241ad 100644 --- a/src/data/chains.ts +++ b/src/data/chains.ts @@ -1044,6 +1044,17 @@ const chains = [ }, chain: "ETH", }, + { + name: "Settlus", + infoURL: "https://settlus.org", + chainId: 5371, + nativeCurrency: { + name: "Ether", + symbol: "ETH", + decimals: 18, + }, + chain: "ETH", + }, { name: "Nahmii 2 Mainnet", infoURL: "https://nahmii.io", @@ -1440,17 +1451,6 @@ const chains = [ }, chain: "Liveplex OracleEVM Network", }, - { - name: "Reddio Devnet", - infoURL: "https://www.reddio.com", - chainId: 50341, - nativeCurrency: { - name: "Red", - symbol: "RED", - decimals: 18, - }, - chain: "ETH", - }, { name: "BirdLayer", infoURL: "https://www.dodochain.com", diff --git a/src/data/published.json b/src/data/published.json index 7e21d1f3b43..226406d18f6 100644 --- a/src/data/published.json +++ b/src/data/published.json @@ -1 +1 @@ -{"date":"2025-04-16"} +{"date":"2025-04-30"} diff --git a/src/data/quizzes/index.ts b/src/data/quizzes/index.ts index 182ac70c1a1..898d5077148 100644 --- a/src/data/quizzes/index.ts +++ b/src/data/quizzes/index.ts @@ -53,6 +53,10 @@ const quizzes = { title: "learn-quizzes:page-assets-merge", questions: ["merge-1", "merge-2", "merge-3", "merge-4", "merge-5"], }, + gas: { + title: "gas", + questions: ["gas-1", "gas-2", "gas-3", "gas-4", "gas-5"], + }, daos: { title: "DAOs", questions: ["daos-1", "daos-2", "daos-3", "daos-4", "daos-5"], @@ -163,6 +167,10 @@ const usingEthereumQuizzesRaw: QuizzesSection[] = [ id: "staking-solo", level: "advanced", }, + { + id: "gas", + level: "advanced", + }, ] export const usingEthereumQuizzes: QuizzesSection[] = addNextQuiz( diff --git a/src/data/quizzes/questionBank.ts b/src/data/quizzes/questionBank.ts index e7e5eaba981..4e510e110b0 100644 --- a/src/data/quizzes/questionBank.ts +++ b/src/data/quizzes/questionBank.ts @@ -107,6 +107,13 @@ const questionBankConfig: QuestionBankConfig = { { totalAnswers: 2, correctAnswer: 2 }, { totalAnswers: 4, correctAnswer: 2 }, ], + gas: [ + { totalAnswers: 4, correctAnswer: 4 }, + { totalAnswers: 4, correctAnswer: 4 }, + { totalAnswers: 4, correctAnswer: 1 }, + { totalAnswers: 4, correctAnswer: 2 }, + { totalAnswers: 4, correctAnswer: 2 }, + ], daos: [ { totalAnswers: 4, correctAnswer: 4 }, { totalAnswers: 4, correctAnswer: 4 }, diff --git a/src/data/roadmap/releases.tsx b/src/data/roadmap/releases.tsx new file mode 100644 index 00000000000..571ce583f48 --- /dev/null +++ b/src/data/roadmap/releases.tsx @@ -0,0 +1,186 @@ +import { StaticImageData } from "next/image" + +import CommunityHeroImage from "@/public/images/heroes/community-hero.png" +import DevelopersHubHeroImage from "@/public/images/heroes/developers-hub-hero.jpg" +import GuidesHubHeroImage from "@/public/images/heroes/guides-hub-hero.jpg" +import Layer2HubHeroImage from "@/public/images/heroes/layer-2-hub-hero.jpg" +import QuizzesHubHeroImage from "@/public/images/heroes/quizzes-hub-hero.png" +import PectraImage from "@/public/images/roadmap/roadmap-pectra.png" + +interface Release { + image: StaticImageData + releaseName: string + releaseDate: string + content: React.ReactNode + href: string +} + +export const releasesData: Release[] = [ + { + image: DevelopersHubHeroImage, + releaseName: "Paris (The Merge)", + releaseDate: "2022-09-15", + content: ( +
+

Transition to Proof of Stake

+
    +
  • Replaced energy-intensive mining with staking-based consensus
  • +
  • Reduced Ethereum's energy consumption by ~99.95%
  • +
+

Beacon Chain Integration

+
    +
  • Merged the Beacon Chain with the Ethereum mainnet
  • +
  • Enabled the full transition to PoS consensus mechanism
  • +
+

Difficulty Bomb Removal

+
    +
  • + Removed the difficulty bomb that was increasing mining difficulty +
  • +
  • Ensured smooth transition to the new consensus mechanism
  • +
+
+ ), + href: "/upgrades/merge", + }, + { + image: QuizzesHubHeroImage, + releaseName: "Shapella", + releaseDate: "2023-04-12", + content: ( +
+

Staking withdrawals

+
    +
  • Enabled validators to withdraw their staked ETH and rewards
  • +
  • Introduced partial and full withdrawal capabilities
  • +
+

EIP-4895: Beacon chain push withdrawals

+
    +
  • Added a new system-level operation for withdrawals
  • +
  • + Ensured secure and efficient processing of withdrawal requests +
  • +
+

EIP-3651: Warm COINBASE

+
    +
  • Reduced gas costs for accessing the COINBASE address
  • +
  • Improved efficiency of certain smart contract operations
  • +
+
+ ), + href: "/staking/withdrawals", + }, + { + image: Layer2HubHeroImage, + releaseName: "Dencun", + releaseDate: "2024-03-13", + content: ( +
+

Proto-danksharding (EIP-4844)

+
    +
  • + Introduced blob transactions to significantly reduce rollup + transaction costs +
  • +
  • + Added a new transaction type that stores data temporarily and + cheaply +
  • +
+

EIP-1153: Transient storage opcodes

+
    +
  • + Added TSTORE and TLOAD opcodes for temporary storage during + transaction execution +
  • +
  • + Enables more efficient smart contract patterns and reduces gas costs +
  • +
+

EIP-4788: Beacon block root in the EVM

+
    +
  • Exposes consensus layer information to smart contracts
  • +
  • + Enables new trust-minimized applications and cross-chain bridges +
  • +
+
+ ), + href: "/roadmap/dencun", + }, + { + image: PectraImage, + releaseName: "Pectra", + releaseDate: "2025-05-07", + content: ( +
+

Enhance EOA wallets with smart contract functionality

+
    +
  • + Users can set their address to be represented by a code of an + existing smart contract and gain benefits such as transaction batching, transaction fee sponsorship or better recovery mechanisms +
  • +
+

Increase the max effective balance

+
    +
  • + Stakers can now choose an arbitrary amount of ETH to stake and + receive rewards on every 1 ETH above the minimum +
  • +
+

Blob throughput increase

+
    +
  • + The blob count will be increased from 3 to 6 targets, with a maximum + of 9, resulting in cheaper fees in Ethereum rollups +
  • +
+
+ ), + href: "/roadmap/pectra", + }, + { + image: CommunityHeroImage, + releaseName: "Fusaka", + releaseDate: "2026", + content: ( +
+

+ PeerDAS (Peer-to-Peer Data Availability Sampling) +

+
    +
  • Enables more efficient data availability for rollups
  • +
  • + Makes running a node more accessible while maintaining + decentralization +
  • +
+

Potential Additional Features

+
    +
  • + EIP-7688: Enhanced smart contract access to network information +
  • +
  • Blob fee market improvementse
  • +
  • + Further improvements to validator efficiency and network performance +
  • +
+
+ ), + href: "/roadmap/fusaka", + }, + { + image: GuidesHubHeroImage, + releaseName: "Glamsterdam", + releaseDate: "2026", + content: ( +
+

Discussed for Glamsterdam

+
    +
  • Verkle trees
  • +
+
+ ), + href: "https://eips.ethereum.org/EIPS/eip-7773", + }, +] diff --git a/src/data/translationProgress.json b/src/data/translationProgress.json index d0691f05035..b54d6106081 100644 --- a/src/data/translationProgress.json +++ b/src/data/translationProgress.json @@ -3,686 +3,686 @@ "languageId": "af", "words": { "approved": 1554, - "total": 281162 + "total": 281165 } }, { "languageId": "am", "words": { "approved": 10713, - "total": 281162 + "total": 281165 } }, { "languageId": "ar", "words": { "approved": 37264, - "total": 281162 + "total": 281165 } }, { "languageId": "az", "words": { "approved": 22282, - "total": 281162 + "total": 281165 } }, { "languageId": "be", "words": { "approved": 35870, - "total": 281162 + "total": 281165 } }, { "languageId": "bg", "words": { "approved": 18855, - "total": 281162 + "total": 281165 } }, { "languageId": "bi", "words": { "approved": 0, - "total": 281162 + "total": 281165 } }, { "languageId": "bn", "words": { "approved": 29381, - "total": 281162 + "total": 281165 } }, { "languageId": "br-FR", "words": { "approved": 43, - "total": 281162 + "total": 281165 } }, { "languageId": "bs", "words": { "approved": 7431, - "total": 281162 + "total": 281165 } }, { "languageId": "ca", "words": { - "approved": 26718, - "total": 281162 + "approved": 27103, + "total": 281165 } }, { "languageId": "cs", "words": { - "approved": 126946, - "total": 281162 + "approved": 140318, + "total": 281165 } }, { "languageId": "da", "words": { "approved": 2485, - "total": 281162 + "total": 281165 } }, { "languageId": "de", "words": { - "approved": 201514, - "total": 281162 + "approved": 201812, + "total": 281165 } }, { "languageId": "dv", "words": { "approved": 0, - "total": 281162 + "total": 281165 } }, { "languageId": "ee", "words": { "approved": 2505, - "total": 281162 + "total": 281165 } }, { "languageId": "el", "words": { - "approved": 227476, - "total": 281162 + "approved": 250441, + "total": 281165 } }, { "languageId": "eo", "words": { "approved": 46, - "total": 281162 + "total": 281165 } }, { "languageId": "es-EM", "words": { - "approved": 252187, - "total": 281162 + "approved": 258776, + "total": 281165 } }, { "languageId": "et", "words": { "approved": 19, - "total": 281162 + "total": 281165 } }, { "languageId": "eu", "words": { "approved": 10, - "total": 281162 + "total": 281165 } }, { "languageId": "fa", "words": { - "approved": 246534, - "total": 281162 + "approved": 246929, + "total": 281165 } }, { "languageId": "fa-AF", "words": { "approved": 64, - "total": 281162 + "total": 281165 } }, { "languageId": "fi", "words": { "approved": 19035, - "total": 281162 + "total": 281165 } }, { "languageId": "fil", "words": { "approved": 52867, - "total": 281162 + "total": 281165 } }, { "languageId": "fr", "words": { - "approved": 267582, - "total": 281162 + "approved": 268444, + "total": 281165 } }, { "languageId": "ga-IE", "words": { - "approved": 98731, - "total": 281224 + "approved": 157938, + "total": 281227 } }, { "languageId": "gi", "words": { "approved": 0, - "total": 281162 + "total": 281165 } }, { "languageId": "gl", "words": { "approved": 2487, - "total": 281162 + "total": 281165 } }, { "languageId": "gu-IN", "words": { "approved": 2599, - "total": 281162 + "total": 281165 } }, { "languageId": "ha", "words": { "approved": 41923, - "total": 281162 + "total": 281165 } }, { "languageId": "he", "words": { "approved": 3203, - "total": 281162 + "total": 281165 } }, { "languageId": "hi", "words": { - "approved": 166486, - "total": 281162 + "approved": 170485, + "total": 281165 } }, { "languageId": "hr", "words": { "approved": 20491, - "total": 281162 + "total": 281165 } }, { "languageId": "hu", "words": { - "approved": 252981, - "total": 281162 + "approved": 261878, + "total": 281165 } }, { "languageId": "hy-AM", "words": { "approved": 9478, - "total": 281162 + "total": 281165 } }, { "languageId": "id", "words": { - "approved": 128937, - "total": 281162 + "approved": 131019, + "total": 281165 } }, { "languageId": "ig", "words": { "approved": 21811, - "total": 281162 + "total": 281165 } }, { "languageId": "it", "words": { - "approved": 265324, - "total": 281162 + "approved": 265322, + "total": 281165 } }, { "languageId": "ja", "words": { - "approved": 251004, - "total": 281162 + "approved": 251234, + "total": 281165 } }, { "languageId": "ka", "words": { "approved": 5302, - "total": 281162 + "total": 281165 } }, { "languageId": "kk", "words": { "approved": 10260, - "total": 281162 + "total": 281165 } }, { "languageId": "km", "words": { "approved": 11925, - "total": 281162 + "total": 281165 } }, { "languageId": "kn", "words": { - "approved": 37366, - "total": 281162 + "approved": 42416, + "total": 281165 } }, { "languageId": "ko", "words": { "approved": 51916, - "total": 281162 + "total": 281165 } }, { "languageId": "ku", "words": { "approved": 0, - "total": 281162 + "total": 281165 } }, { "languageId": "ky", "words": { "approved": 74, - "total": 281162 + "total": 281165 } }, { "languageId": "lb", "words": { "approved": 0, - "total": 281162 + "total": 281165 } }, { "languageId": "lt", "words": { "approved": 2972, - "total": 281162 + "total": 281165 } }, { "languageId": "lv", "words": { "approved": 0, - "total": 281162 + "total": 281165 } }, { "languageId": "mai", "words": { "approved": 0, - "total": 281162 + "total": 281165 } }, { "languageId": "mk", "words": { "approved": 54, - "total": 281162 + "total": 281165 } }, { "languageId": "ml-IN", "words": { "approved": 17972, - "total": 281162 + "total": 281165 } }, { "languageId": "mn", "words": { "approved": 48, - "total": 281162 + "total": 281165 } }, { "languageId": "mr", "words": { "approved": 21374, - "total": 281162 + "total": 281165 } }, { "languageId": "ms", "words": { "approved": 70512, - "total": 281162 + "total": 281165 } }, { "languageId": "my", "words": { "approved": 65, - "total": 281162 + "total": 281165 } }, { "languageId": "ne-NP", "words": { "approved": 2498, - "total": 281162 + "total": 281165 } }, { "languageId": "nl", "words": { "approved": 102935, - "total": 281162 + "total": 281165 } }, { "languageId": "no", "words": { "approved": 2950, - "total": 281162 + "total": 281165 } }, { "languageId": "ny", "words": { "approved": 0, - "total": 281162 + "total": 281165 } }, { "languageId": "or", "words": { "approved": 0, - "total": 281162 + "total": 281165 } }, { "languageId": "pa-IN", "words": { "approved": 3, - "total": 281162 + "total": 281165 } }, { "languageId": "pcm", "words": { "approved": 71416, - "total": 281162 + "total": 281165 } }, { "languageId": "pl", "words": { "approved": 110128, - "total": 281162 + "total": 281165 } }, { "languageId": "ps", "words": { "approved": 0, - "total": 281162 + "total": 281165 } }, { "languageId": "pt-BR", "words": { - "approved": 259659, - "total": 281162 + "approved": 265206, + "total": 281165 } }, { "languageId": "pt-PT", "words": { - "approved": 36755, - "total": 281162 + "approved": 36946, + "total": 281165 } }, { "languageId": "ro", "words": { - "approved": 42665, - "total": 281162 + "approved": 43582, + "total": 281165 } }, { "languageId": "ru", "words": { - "approved": 117135, - "total": 281162 + "approved": 117280, + "total": 281165 } }, { "languageId": "sat", "words": { "approved": 57, - "total": 281162 + "total": 281165 } }, { "languageId": "si-LK", "words": { "approved": 65, - "total": 281162 + "total": 281165 } }, { "languageId": "sk", "words": { "approved": 45417, - "total": 281162 + "total": 281165 } }, { "languageId": "sl", "words": { - "approved": 25930, - "total": 281162 + "approved": 30507, + "total": 281165 } }, { "languageId": "sn", "words": { - "approved": 5519, - "total": 281162 + "approved": 6984, + "total": 281165 } }, { "languageId": "so", "words": { "approved": 62, - "total": 281162 + "total": 281165 } }, { "languageId": "sq", "words": { "approved": 67, - "total": 281162 + "total": 281165 } }, { "languageId": "sr-CS", "words": { "approved": 37505, - "total": 281162 + "total": 281165 } }, { "languageId": "sv-SE", "words": { "approved": 10101, - "total": 281162 + "total": 281165 } }, { "languageId": "sw", "words": { - "approved": 23925, - "total": 281162 + "approved": 24807, + "total": 281165 } }, { "languageId": "ta", "words": { "approved": 2764, - "total": 281162 + "total": 281165 } }, { "languageId": "te", "words": { - "approved": 26565, - "total": 281162 + "approved": 26795, + "total": 281165 } }, { "languageId": "tg", "words": { "approved": 0, - "total": 281162 + "total": 281165 } }, { "languageId": "th", "words": { - "approved": 6275, - "total": 281162 + "approved": 7419, + "total": 281165 } }, { "languageId": "ti", "words": { "approved": 0, - "total": 281162 + "total": 281165 } }, { "languageId": "tk", "words": { "approved": 6163, - "total": 281162 + "total": 281165 } }, { "languageId": "tl", "words": { "approved": 49041, - "total": 281162 + "total": 281165 } }, { "languageId": "tr", "words": { - "approved": 250782, - "total": 281162 + "approved": 251894, + "total": 281165 } }, { "languageId": "tw", "words": { "approved": 5991, - "total": 281162 + "total": 281165 } }, { "languageId": "uk", "words": { "approved": 82392, - "total": 281162 + "total": 281165 } }, { "languageId": "ur-IN", "words": { "approved": 2478, - "total": 281162 + "total": 281165 } }, { "languageId": "ur-PK", "words": { "approved": 865, - "total": 281162 + "total": 281165 } }, { "languageId": "uz", "words": { "approved": 36683, - "total": 281162 + "total": 281165 } }, { "languageId": "vi", "words": { "approved": 34827, - "total": 281162 + "total": 281165 } }, { "languageId": "yo", "words": { "approved": 43667, - "total": 281162 + "total": 281165 } }, { "languageId": "zh-CN", "words": { - "approved": 268074, - "total": 281162 + "approved": 269456, + "total": 281165 } }, { "languageId": "zh-TW", "words": { "approved": 240791, - "total": 281162 + "total": 281165 } }, { "languageId": "zu", "words": { "approved": 43, - "total": 281162 + "total": 281165 } } ] \ No newline at end of file diff --git a/src/intl/en/learn-quizzes.json b/src/intl/en/learn-quizzes.json index 62ca7fc486e..56050af1242 100644 --- a/src/intl/en/learn-quizzes.json +++ b/src/intl/en/learn-quizzes.json @@ -326,6 +326,51 @@ "merge-5-c-explanation": "Eth1 was the original name given to the execution layer, not the consensus layer.", "merge-5-d-label": "Staking", "merge-5-d-explanation": "Staking is depositing ETH into a smart contract to help secure the chain.", + "gas-1-prompt": "What are gas fees?", + "gas-1-a-label": "A fee associated with transactions and smart contract operations", + "gas-1-a-explanation": "Partially correct, gas fees represent the cost of transactions and smart contract operations.", + "gas-1-b-label": "The amount of gas used to perform an operation, multiplied by the cost per unit of gas", + "gas-1-b-explanation": "Partially correct. While true, it is not the best answer given the choices.", + "gas-1-c-label": "A payment that includes a priority fee to potentially expedite transaction processing", + "gas-1-c-explanation": "Partially correct, the total gas fee includes a base fee and a priority fee that can influence transaction processing speed", + "gas-1-d-label": "All of the above", + "gas-1-d-explanation": "Gas fees encompass all these aspects: they compensate for computation, apply to both transactions and smart contracts, and can include priority fees for faster inclusion.", + "gas-2-prompt": "Which of the following is the LEAST effective strategy for reducing the cost of gas?", + "gas-2-a-label": "Executing transactions during low-congestion periods", + "gas-2-a-explanation": "Timing transactions during off-peak hours can lower gas costs.", + "gas-2-b-label": "Waiting for gas prices to decrease", + "gas-2-b-explanation": "Waiting for gas prices to decrease is a valid strategy since gas fluctuates based on congestion.", + "gas-2-c-label": "Using layer 2 chains for lower fees", + "gas-2-c-explanation": "Layer 2 solutions reduce fees and are an effective way to save on gas.", + "gas-2-d-label": "Using complex smart contract logic that increases computational requirements", + "gas-2-d-explanation": "Complex smart contract logic increases gas costs by requiring more computation. Efficient design minimizes steps, storage, and redundant operations to reduce fees.", + "gas-3-prompt": "What causes gas fees to be high?", + "gas-3-a-label": "Network computation exceeding a specific threshold", + "gas-3-a-explanation": "When computation on Ethereum exceeds a threshold, gas fees increase, especially during high activity periods like dapps or NFT drops.", + "gas-3-b-label": "Validators increasing the base fee manually", + "gas-3-b-explanation": "Validators do not manually set base fees; they are adjusted by the protocol based on demand in previous block.", + "gas-3-c-label": "Well-written, optimized smart contracts", + "gas-3-c-explanation": "Well-written smart contract logic such as efficient use of storage and loops can lead to lower gas consumption.", + "gas-3-d-label": "A lack of available ETH on the network", + "gas-3-d-explanation": "Gas fees are not affected by the amount of ETH available on the network.", + "gas-4-prompt": "How do gas fees help keep Ethereum secure?", + "gas-4-a-label": "By incentivizing validators to act honestly", + "gas-4-a-explanation": "Validators are compensated in a few ways, but gas fees primarily discourage spam and excessive resource use.", + "gas-4-b-label": "By disincentivizing spam and malicious activity with financial costs", + "gas-4-b-explanation": "Gas fees make spam or malicious activity expensive, preventing abuse and helping maintain network stability.", + "gas-4-c-label": "By ensuring transactions are processed in order of priority", + "gas-4-c-explanation": "Priority can be determined by the tip, not the gas fees themselves.", + "gas-4-d-label": "By increasing the total amount of ETH in circulation", + "gas-4-d-explanation": "The base fee (part of the total gas fee) is burned, reducing ETH in circulation, not increasing it", + "gas-5-prompt": "How are gas fees calculated?", + "gas-5-a-label": "Gas price × transaction size", + "gas-5-a-explanation": "Gas fees are based on computation, not transaction size.", + "gas-5-b-label": "Units of gas used × (base fee + priority fee)", + "gas-5-b-explanation": "Gas fees are determined using the formula: units of gas used × (base fee + priority fee).", + "gas-5-c-label": "Block size × validator tip cap", + "gas-5-c-explanation": "Block size does not directly factor into this formula.", + "gas-5-d-label": "Base fee + priority fee + tip", + "gas-5-d-explanation": "The base fee and priority fee are part of the formula; the tip is the priority fee.", "daos-1-prompt": "What is true about DAOs?", "daos-1-a-label": "DAOs are collectively owned via governance tokens", "daos-1-a-explanation": "DAOs are collectively owned, but that’s not the only correct statement.", @@ -614,4 +659,4 @@ "defi-5-c-explanation": "This is incorrect. Bitcoin is a simple network for storing value, not for running advanced programs. DeFi requires a more flexible system, like Ethereum, that can run complex programs to handle loans and trades automatically.", "defi-5-d-label": "Traditional financial institutions", "defi-5-d-explanation": "This is incorrect. DeFi apps don’t need traditional financial institutions. They use blockchain programs called smart contracts to handle transactions automatically." -} +} \ No newline at end of file diff --git a/src/intl/en/page-learn.json b/src/intl/en/page-learn.json index f1ddc535de9..37fe0f44a28 100644 --- a/src/intl/en/page-learn.json +++ b/src/intl/en/page-learn.json @@ -121,4 +121,4 @@ "unchained-description": "Dives deep into the people building the decentralized internet, the details of this technology that could underpin our future, and some of the thorniest topics in crypto, such as regulation, security and privacy", "the-daily-gwei-title": "The Daily Gwei", "the-daily-gwei-description": "Ethereum news recaps, updates and analysis" -} +} \ No newline at end of file diff --git a/src/intl/en/page-roadmap.json b/src/intl/en/page-roadmap.json new file mode 100644 index 00000000000..3a9faa530bc --- /dev/null +++ b/src/intl/en/page-roadmap.json @@ -0,0 +1,4 @@ +{ + "page-roadmap-meta-title": "Ethereum roadmap", + "page-roadmap-meta-description": "The path to more scalability, security and sustainability for Ethereum." +} \ No newline at end of file diff --git a/src/lib/utils/date.ts b/src/lib/utils/date.ts index 4f8f4555f8f..1bea2c4553b 100644 --- a/src/lib/utils/date.ts +++ b/src/lib/utils/date.ts @@ -6,3 +6,14 @@ export const isValidDate = (dateString?: string | number): boolean => { const date = new Date(dateString) return !isNaN(date.getTime()) } + +export const formatDate = (date: string) => { + if (/^\d{4}$/.test(date)) { + return date + } + return new Date(date).toLocaleDateString("en-US", { + month: "long", + day: "numeric", + year: "numeric", + }) +} diff --git a/src/lib/utils/translations.ts b/src/lib/utils/translations.ts index e50f83fb820..6825585afcd 100644 --- a/src/lib/utils/translations.ts +++ b/src/lib/utils/translations.ts @@ -187,6 +187,10 @@ const getRequiredNamespacesForPath = (relativePath: string) => { requiredNamespaces = [...requiredNamespaces, "table"] } + if (path.startsWith("/roadmap/")) { + primaryNamespace = "page-roadmap" + } + if (path.startsWith("/start/")) { requiredNamespaces = [...requiredNamespaces] } @@ -229,7 +233,8 @@ const getRequiredNamespacesForPath = (relativePath: string) => { path.startsWith("/what-is-ethereum/") || path.startsWith("/quizzes/") || path.startsWith("/stablecoins/") || - path.startsWith("/defi/") + path.startsWith("/defi/") || + path.startsWith("/gas/") ) { requiredNamespaces = [...requiredNamespaces, "learn-quizzes"] } diff --git a/src/styles/semantic-tokens.css b/src/styles/semantic-tokens.css index 8f97e469fa4..b8fb9a8be9f 100644 --- a/src/styles/semantic-tokens.css +++ b/src/styles/semantic-tokens.css @@ -85,6 +85,10 @@ #000000 69.77% ); + --card-gradient: linear-gradient(123deg, rgba(255, 255, 255, 0.20) 58.99%, rgba(174, 110, 203, 0.13) 104.04%); + --card-gradient-secondary: linear-gradient(95deg, rgba(211, 145, 242, 0.12) 0%, rgba(159, 43, 212, 0.12) 102.78%); + --card-gradient-secondary-hover: linear-gradient(95deg, rgba(211, 145, 242, 0.2) 0%, rgba(159, 43, 212, 0.2) 102.78%); + /* Shadows */ --shadow-color-a: hsla(var(--purple-800), 0.02); --shadow-color-b: hsla(var(--red-800), 0.04); @@ -198,6 +202,8 @@ #8db4ff 69.77% ); + --roadmap-card-gradient: linear-gradient(123deg, rgba(34, 34, 34, 0.20) 40.53%, rgba(174, 110, 203, 0.13) 104.05%); + /* Shadows (dark mode adjustments) */ --shadow-color: hsla(var(--white), 0.04); --shadow-svg-button-link-1: -2px 2px 12px 1px var(--shadow-color); diff --git a/tailwind.config.ts b/tailwind.config.ts index e555b78700a..268a8425fa4 100644 --- a/tailwind.config.ts +++ b/tailwind.config.ts @@ -231,6 +231,9 @@ const config = { "radial-a": "var(--radial-a)", "linear-bug-bounty-title": "var(--linear-bug-bounty-title)", "gradient-staking": "var(--gradient-staking)", + "card-gradient": "var(--card-gradient)", + "card-gradient-secondary": "var(--card-gradient-secondary)", + "card-gradient-secondary-hover": "var(--card-gradient-secondary-hover)", }, boxShadow: { "table-box": "var(--table-box-shadow)", diff --git a/yarn.lock b/yarn.lock index b6979aff574..0a2535d4268 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3265,6 +3265,11 @@ resolved "https://registry.yarnpkg.com/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.1.tgz#6f766faa975f8738269ebb8a23bad4f5a8d2faec" integrity sha512-Y9VzoRDSJtgFMUCoiZBDVo084VQ5hfpXxVE+NgkdNsjiDBByiImMZKKhxMwCbdHvhlENG6a833CbFkOQvTricw== +"@radix-ui/react-compose-refs@1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.2.tgz#a2c4c47af6337048ee78ff6dc0d090b390d2bb30" + integrity sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg== + "@radix-ui/react-context@1.0.1": version "1.0.1" resolved "https://registry.yarnpkg.com/@radix-ui/react-context/-/react-context-1.0.1.tgz#fe46e67c96b240de59187dcb7a1a50ce3e2ec00c" @@ -3643,7 +3648,7 @@ "@babel/runtime" "^7.13.10" "@radix-ui/react-compose-refs" "1.0.1" -"@radix-ui/react-slot@1.1.0", "@radix-ui/react-slot@^1.1.0": +"@radix-ui/react-slot@1.1.0": version "1.1.0" resolved "https://registry.yarnpkg.com/@radix-ui/react-slot/-/react-slot-1.1.0.tgz#7c5e48c36ef5496d97b08f1357bb26ed7c714b84" integrity sha512-FUCf5XMfmW4dtYl69pdS4DbxKy8nj4M7SafBgPllysxmdachynNflAdp/gCsnYWNDnge6tI9onzMp5ARYc1KNw== @@ -3657,6 +3662,13 @@ dependencies: "@radix-ui/react-compose-refs" "1.1.1" +"@radix-ui/react-slot@^1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@radix-ui/react-slot/-/react-slot-1.2.0.tgz#57727fc186ddb40724ccfbe294e1a351d92462ba" + integrity sha512-ujc+V6r0HNDviYqIK3rW4ffgYiZ8g5DEHrGJVk4x7kTlLXRDILnKX9vAUYeIsLOoDpDJ0ujpqMkjH4w2ofuo6w== + dependencies: + "@radix-ui/react-compose-refs" "1.1.2" + "@radix-ui/react-switch@^1.1.0": version "1.1.0" resolved "https://registry.yarnpkg.com/@radix-ui/react-switch/-/react-switch-1.1.0.tgz#fcf8e778500f1d60d4b2bec2fc3fad77a7c118e3" @@ -8363,6 +8375,24 @@ elliptic@^6.5.7: minimalistic-assert "^1.0.1" minimalistic-crypto-utils "^1.0.1" +embla-carousel-react@^8.6.0: + version "8.6.0" + resolved "https://registry.yarnpkg.com/embla-carousel-react/-/embla-carousel-react-8.6.0.tgz#b737042a32761c38d6614593653b3ac619477bd1" + integrity sha512-0/PjqU7geVmo6F734pmPqpyHqiM99olvyecY7zdweCw+6tKEXnrE90pBiBbMMU8s5tICemzpQ3hi5EpxzGW+JA== + dependencies: + embla-carousel "8.6.0" + embla-carousel-reactive-utils "8.6.0" + +embla-carousel-reactive-utils@8.6.0: + version "8.6.0" + resolved "https://registry.yarnpkg.com/embla-carousel-reactive-utils/-/embla-carousel-reactive-utils-8.6.0.tgz#607f1d8ab9921c906a555c206251b2c6db687223" + integrity sha512-fMVUDUEx0/uIEDM0Mz3dHznDhfX+znCCDCeIophYb1QGVM7YThSWX+wz11zlYwWFOr74b4QLGg0hrGPJeG2s4A== + +embla-carousel@8.6.0: + version "8.6.0" + resolved "https://registry.yarnpkg.com/embla-carousel/-/embla-carousel-8.6.0.tgz#abcedff2bff36992ea8ac27cd30080ca5b6a3f58" + integrity sha512-SjWyZBHJPbqxHOzckOfo8lHisEaJWmwd23XppYFYVh10bU66/Pn5tkVkbkCMZVdbUE5eTCI2nD8OyIP4Z+uwkA== + emoji-regex@^10.3.0: version "10.3.0" resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-10.3.0.tgz#76998b9268409eb3dae3de989254d456e70cfe23"