Skip to content

Commit 90279d9

Browse files
authored
Merge pull request #15356 from ethereum/dev
Release candidate v10.2.0
2 parents c86783e + e0d7361 commit 90279d9

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+1687
-264
lines changed

.all-contributorsrc

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12724,6 +12724,15 @@
1272412724
"contributions": [
1272512725
"bug"
1272612726
]
12727+
},
12728+
{
12729+
"login": "microHoffman",
12730+
"name": "microHoffman",
12731+
"avatar_url": "https://avatars.githubusercontent.com/u/61500778?v=4",
12732+
"profile": "http://pwn.xyz",
12733+
"contributions": [
12734+
"bug"
12735+
]
1272712736
}
1272812737
],
1272912738
"contributorsPerLine": 7,

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,3 +60,4 @@ src/data/crowdin/bucketsAwaitingReviewReport.csv
6060
# Storybook
6161
build-storybook.log
6262
storybook-static
63+

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1947,6 +1947,7 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
19471947
</tr>
19481948
<tr>
19491949
<td align="center" valign="top" width="14.28%"><a href="https://github.com/JJOptimist"><img src="https://avatars.githubusercontent.com/u/86833563?v=4?s=100" width="100px;" alt="JJOptimist"/><br /><sub><b>JJOptimist</b></sub></a><br /><a href="https://github.com/ethereum/ethereum-org-website/issues?q=author%3AJJOptimist" title="Bug reports">🐛</a></td>
1950+
<td align="center" valign="top" width="14.28%"><a href="http://pwn.xyz"><img src="https://avatars.githubusercontent.com/u/61500778?v=4?s=100" width="100px;" alt="microHoffman"/><br /><sub><b>microHoffman</b></sub></a><br /><a href="https://github.com/ethereum/ethereum-org-website/issues?q=author%3AmicroHoffman" title="Bug reports">🐛</a></td>
19501951
</tr>
19511952
</tbody>
19521953
</table>

app/[locale]/gas/_components/gas.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import { Image } from "@/components/Image"
1313
import InfoBanner from "@/components/InfoBanner"
1414
import MainArticle from "@/components/MainArticle"
1515
import PageHero from "@/components/PageHero"
16+
import { StandaloneQuizWidget } from "@/components/Quiz/QuizWidget"
1617
import Translation from "@/components/Translation"
1718
import { ButtonLink } from "@/components/ui/buttons/Button"
1819
import { Divider } from "@/components/ui/divider"
@@ -384,6 +385,9 @@ const GasPage = () => {
384385
</Callout>
385386
</Flex>
386387
</Content>
388+
<Content>
389+
<StandaloneQuizWidget quizKey="gas" />
390+
</Content>
387391
<Content>
388392
<FeedbackCard />
389393
</Content>
Lines changed: 264 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,264 @@
1+
"use client"
2+
3+
import { useEffect, useState } from "react"
4+
5+
import { Image } from "@/components/Image"
6+
import { ButtonLink } from "@/components/ui/buttons/Button"
7+
import {
8+
Carousel,
9+
type CarouselApi,
10+
CarouselContent,
11+
CarouselItem,
12+
CarouselNext,
13+
CarouselPrevious,
14+
} from "@/components/ui/carousel"
15+
16+
import { cn } from "@/lib/utils/cn"
17+
import { formatDate } from "@/lib/utils/date"
18+
19+
import { releasesData } from "@/data/roadmap/releases"
20+
21+
const findLatestReleaseIndex = () => {
22+
const today = new Date()
23+
const twoMonthsFromNow = new Date()
24+
twoMonthsFromNow.setMonth(today.getMonth() + 2)
25+
26+
// First try to find a release within the next 2 months
27+
const upcomingReleaseIndex = releasesData.findIndex((release) => {
28+
const releaseDate = new Date(release.releaseDate)
29+
return releaseDate > today && releaseDate <= twoMonthsFromNow
30+
})
31+
32+
// If no upcoming release found, find the most recent release up to today
33+
if (upcomingReleaseIndex === -1) {
34+
const pastReleases = releasesData.filter(
35+
(release) => new Date(release.releaseDate) <= today
36+
)
37+
if (pastReleases.length > 0) {
38+
const mostRecentRelease = pastReleases[pastReleases.length - 1]
39+
return releasesData.findIndex(
40+
(release) => release.releaseDate === mostRecentRelease.releaseDate
41+
)
42+
}
43+
}
44+
45+
return upcomingReleaseIndex
46+
}
47+
48+
const ReleaseCarousel = () => {
49+
const todayDate = new Date()
50+
const twoMonthsFromNow = new Date()
51+
twoMonthsFromNow.setMonth(todayDate.getMonth() + 2)
52+
53+
const [api1, setApi1] = useState<CarouselApi>()
54+
const [api2, setApi2] = useState<CarouselApi>()
55+
const [currentIndex, setCurrentIndex] = useState(() =>
56+
findLatestReleaseIndex()
57+
)
58+
59+
useEffect(() => {
60+
if (!api1 || !api2) {
61+
return
62+
}
63+
64+
api1.on("select", () => {
65+
setCurrentIndex(api1.selectedScrollSnap())
66+
api2.scrollTo(api1.selectedScrollSnap())
67+
})
68+
69+
api2.on("select", () => {
70+
setCurrentIndex(api2.selectedScrollSnap())
71+
api1.scrollTo(api2.selectedScrollSnap())
72+
})
73+
}, [api1, api2])
74+
75+
return (
76+
<div className="w-full max-w-[100vw] overflow-hidden">
77+
<div className="mx-auto w-full max-w-screen-2xl px-4 sm:px-6">
78+
<div className="w-full rounded-2xl bg-background-highlight py-6">
79+
<div className="flex flex-col gap-6">
80+
{/* First Carousel */}
81+
<Carousel
82+
setApi={setApi1}
83+
className="w-full px-16"
84+
opts={{
85+
align: "center",
86+
containScroll: false,
87+
loop: false,
88+
startIndex: findLatestReleaseIndex(),
89+
}}
90+
>
91+
<CarouselContent>
92+
{releasesData.map((release, index) => {
93+
const releaseDate = new Date(release.releaseDate)
94+
const nextRelease =
95+
releaseDate > todayDate && releaseDate <= twoMonthsFromNow
96+
const labelType =
97+
releaseDate < todayDate
98+
? 1
99+
: releaseDate < twoMonthsFromNow
100+
? 2
101+
: 3
102+
103+
return (
104+
<CarouselItem
105+
key={release.releaseName}
106+
className="w-full md:basis-1/3"
107+
>
108+
<div className="flex w-full flex-col items-center justify-center gap-3">
109+
<div className="mb-3 !h-6">
110+
{labelType === 1 && (
111+
<div
112+
className={cn(
113+
"w-fit rounded-lg bg-primary-low-contrast px-2 py-1",
114+
currentIndex !== index && "hidden"
115+
)}
116+
>
117+
<p className="text-sm font-bold">In production</p>
118+
</div>
119+
)}
120+
{labelType === 2 && (
121+
<div
122+
className={cn(
123+
"w-fit rounded-lg bg-warning-light px-2 py-1",
124+
currentIndex !== index && "hidden"
125+
)}
126+
>
127+
<p className="text-sm font-bold text-black">
128+
Coming soon
129+
</p>
130+
</div>
131+
)}
132+
{labelType === 3 && (
133+
<div
134+
className={cn(
135+
"w-fit rounded-lg bg-card-gradient-secondary-hover px-2 py-1",
136+
currentIndex !== index && "hidden"
137+
)}
138+
>
139+
<p className="text-sm font-bold">
140+
In development
141+
</p>
142+
</div>
143+
)}
144+
</div>
145+
<div className="flex w-full items-center justify-center text-center">
146+
<div
147+
className={cn(
148+
"flex h-1 flex-1",
149+
index !== 0
150+
? nextRelease
151+
? "bg-gradient-to-r from-primary to-primary-low-contrast"
152+
: releaseDate.getTime() < todayDate.getTime()
153+
? "bg-primary"
154+
: "bg-primary-low-contrast"
155+
: "bg-transparent"
156+
)}
157+
/>
158+
<div
159+
className={cn(
160+
"h-7 w-7 rounded-full",
161+
releaseDate.getTime() < todayDate.getTime()
162+
? "bg-primary"
163+
: "bg-primary-low-contrast",
164+
nextRelease &&
165+
"border-2 border-primary bg-background"
166+
)}
167+
/>
168+
<div
169+
className={cn(
170+
"flex h-1 flex-1",
171+
index !== releasesData.length - 1
172+
? index < findLatestReleaseIndex()
173+
? "bg-primary"
174+
: "bg-primary-low-contrast"
175+
: "bg-transparent"
176+
)}
177+
/>
178+
</div>
179+
<div className="flex flex-col items-center justify-center text-center">
180+
<p className="text-md font-bold">
181+
{release.releaseName}
182+
</p>
183+
<p className="font-mono text-sm text-body-medium">
184+
{formatDate(release.releaseDate)}
185+
</p>
186+
</div>
187+
</div>
188+
</CarouselItem>
189+
)
190+
})}
191+
</CarouselContent>
192+
<div className="lg:hidden">
193+
<CarouselPrevious />
194+
<CarouselNext />
195+
</div>
196+
</Carousel>
197+
198+
{/* Second Carousel */}
199+
<Carousel
200+
setApi={setApi2}
201+
className="w-full px-4 lg:px-16"
202+
opts={{
203+
align: "center",
204+
containScroll: false,
205+
loop: false,
206+
startIndex: findLatestReleaseIndex(),
207+
}}
208+
>
209+
<CarouselContent>
210+
{releasesData.map((release) => (
211+
<CarouselItem
212+
key={release.releaseName}
213+
className="w-full pl-4"
214+
>
215+
<div className="flex w-full flex-col gap-6 lg:flex-row">
216+
<div className="w-full flex-1 rounded-2xl">
217+
<Image
218+
src={release.image}
219+
alt={release.releaseName}
220+
className="h-[240px] rounded-2xl object-cover md:h-[266px] lg:h-[551px]"
221+
/>
222+
</div>
223+
<div className="flex flex-1 flex-col gap-8">
224+
<div>
225+
<h2 className="text-4xl font-bold lg:text-6xl">
226+
{release.releaseName}
227+
</h2>
228+
<p className="text-md">
229+
{formatDate(release.releaseDate)}
230+
</p>
231+
</div>
232+
233+
<div>
234+
<p className="mb-3 text-xl font-bold">
235+
Main features
236+
</p>
237+
<div className="flex flex-col gap-4">
238+
{release.content}
239+
</div>
240+
</div>
241+
<ButtonLink
242+
href={release.href}
243+
className="w-full lg:w-fit"
244+
>
245+
Learn more
246+
</ButtonLink>
247+
</div>
248+
</div>
249+
</CarouselItem>
250+
))}
251+
</CarouselContent>
252+
<div className="hidden lg:block">
253+
<CarouselPrevious />
254+
<CarouselNext />
255+
</div>
256+
</Carousel>
257+
</div>
258+
</div>
259+
</div>
260+
</div>
261+
)
262+
}
263+
264+
export default ReleaseCarousel

0 commit comments

Comments
 (0)