Skip to content

Commit 1660385

Browse files
authored
Merge pull request #15901 from ethereum/master
master -> staging
2 parents cbdb187 + 675798d commit 1660385

File tree

8 files changed

+185
-142
lines changed

8 files changed

+185
-142
lines changed

app/[locale]/10years/_components/CurrentTorchHolderCard.tsx

Lines changed: 12 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,4 @@
1-
import {
2-
AvatarBase as Avatar,
3-
AvatarFallback,
4-
AvatarImage,
5-
} from "@/components/ui/avatar"
1+
import { Avatar } from "@/components/ui/avatar"
62
import { ButtonLink } from "@/components/ui/buttons/Button"
73
import {
84
Card,
@@ -18,14 +14,15 @@ import { cn } from "@/lib/utils/cn"
1814
import Curved10YearsText from "./10y.svg"
1915

2016
import {
17+
extractTwitterHandle,
2118
formatAddress,
22-
getAddressEtherscanUrl,
2319
getAvatarImage,
24-
type TorchHolderMetadata,
20+
getTxEtherscanUrl,
21+
type TorchHolderEvent,
2522
} from "@/lib/torch"
2623

2724
interface CurrentTorchHolderCardProps {
28-
currentHolder: TorchHolderMetadata | null
25+
currentHolder: TorchHolderEvent | null
2926
isBurned?: boolean
3027
className?: string
3128
}
@@ -78,15 +75,12 @@ const CurrentTorchHolderCard = ({
7875
<CardContent className="p-6">
7976
{currentHolder ? (
8077
<div className="flex items-start gap-4">
81-
<Avatar className="h-19 w-19 !shadow-none">
82-
<AvatarImage
83-
src={getAvatarImage(currentHolder)}
84-
alt={`Avatar for ${currentHolder.name || currentHolder.address}`}
85-
/>
86-
<AvatarFallback>
87-
{currentHolder.name || formatAddress(currentHolder.address)}
88-
</AvatarFallback>
89-
</Avatar>
78+
<Avatar
79+
className="h-19 w-19 !shadow-none"
80+
src={getAvatarImage(currentHolder)}
81+
href={`https://x.com/${extractTwitterHandle(currentHolder.twitter)}`}
82+
name={currentHolder.name || formatAddress(currentHolder.address)}
83+
/>
9084

9185
<div className="flex flex-col">
9286
{/* Name */}
@@ -98,7 +92,7 @@ const CurrentTorchHolderCard = ({
9892
{/* Verify onchain link */}
9993
<BaseLink
10094
className="mt-2 text-xs"
101-
href={getAddressEtherscanUrl(currentHolder.address)}
95+
href={getTxEtherscanUrl(currentHolder.event.transactionHash)}
10296
>
10397
View on Etherscan
10498
</BaseLink>

app/[locale]/10years/_components/TorchHistoryCard.tsx

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,25 @@
11
import React from "react"
22

3-
import {
4-
AvatarBase as Avatar,
5-
AvatarFallback,
6-
AvatarImage,
7-
} from "@/components/ui/avatar"
3+
import { Avatar } from "@/components/ui/avatar"
84
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
95
import { BaseLink } from "@/components/ui/Link"
106
import { Tag } from "@/components/ui/tag"
117

128
import { cn } from "@/lib/utils/cn"
139

14-
import { formatDate, getTxEtherscanUrl } from "@/lib/torch"
10+
import {
11+
extractTwitterHandle,
12+
formatDate,
13+
getTxEtherscanUrl,
14+
} from "@/lib/torch"
1515

1616
interface TorchHistoryCardProps {
1717
name: string
1818
role: string
1919
avatar: string
20+
twitter: string
2021
from: number
21-
to: number
22+
to?: number
2223
transactionHash: string
2324
className?: string
2425
isCurrentHolder?: boolean
@@ -29,6 +30,7 @@ const TorchHistoryCard: React.FC<TorchHistoryCardProps> = ({
2930
name,
3031
role,
3132
avatar,
33+
twitter,
3234
from,
3335
to,
3436
transactionHash,
@@ -48,10 +50,12 @@ const TorchHistoryCard: React.FC<TorchHistoryCardProps> = ({
4850
>
4951
<CardHeader className="flex flex-col p-0">
5052
<div className="mb-4 flex flex-col items-center">
51-
<Avatar className="h-32 w-32 border-2 border-gray-100/50 !shadow-none">
52-
<AvatarImage src={avatar} alt={`Avatar for ${name}`} />
53-
<AvatarFallback>{name}</AvatarFallback>
54-
</Avatar>
53+
<Avatar
54+
className="h-32 w-32 border-2 border-gray-100/50 !shadow-none"
55+
src={avatar}
56+
href={`https://x.com/${extractTwitterHandle(twitter)}`}
57+
name={name}
58+
/>
5559
</div>
5660

5761
{isCurrentHolder && (
@@ -74,7 +78,8 @@ const TorchHistoryCard: React.FC<TorchHistoryCardProps> = ({
7478
{!isPlaceholder && (
7579
<>
7680
<div className="text-xs text-gray-500">
77-
From {formatDate(from)} to {formatDate(to)}
81+
From {formatDate(from)}
82+
{to !== undefined ? ` to ${formatDate(to)}` : " to present"}
7883
</div>
7984
<BaseLink
8085
href={getTxEtherscanUrl(transactionHash)}

app/[locale]/10years/_components/TorchHistorySwiper/index.tsx

Lines changed: 55 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,22 @@ type TorchHistorySwiperProps = {
1919
currentHolderAddress: Address | null
2020
}
2121

22+
const getOrdinalSuffix = (num: number): string => {
23+
const pr = new Intl.PluralRules("en", { type: "ordinal" })
24+
const rule = pr.select(num)
25+
26+
switch (rule) {
27+
case "one":
28+
return `${num}st`
29+
case "two":
30+
return `${num}nd`
31+
case "few":
32+
return `${num}rd`
33+
default:
34+
return `${num}th`
35+
}
36+
}
37+
2238
const TorchHistorySwiper = ({
2339
holders,
2440
currentHolderAddress,
@@ -40,8 +56,8 @@ const TorchHistorySwiper = ({
4056
// Create placeholder for future holder
4157
return {
4258
address: `placeholder-${index}` as Address,
43-
name: `Future Bearer ${index + 1}`,
44-
role: "Coming soon...",
59+
name: `Torchbearer ${index + 1}`,
60+
role: `Coming July ${getOrdinalSuffix(20 + index)}!`,
4561
twitter: "",
4662
event: {
4763
from: "0x0000000000000000000000000000000000000000" as Address,
@@ -75,30 +91,43 @@ const TorchHistorySwiper = ({
7591
modules={[EffectCoverflow, Navigation]}
7692
className="w-full"
7793
>
78-
{allCards.map((card, idx) => (
79-
<SwiperSlide
80-
key={idx}
81-
className="flex !min-h-[400px] !w-60 justify-center"
82-
>
83-
<TorchHistoryCard
84-
className="!min-h-[400px]"
85-
name={card.name}
86-
role={card.role}
87-
avatar={
88-
card.isPlaceholder
89-
? "/images/10-year-anniversary/torch-cover.webp"
90-
: getAvatarImage(card)
91-
}
92-
from={card.event.timestamp}
93-
to={card.event.timestamp}
94-
transactionHash={card.event.transactionHash}
95-
isCurrentHolder={
96-
!card.isPlaceholder && card.address === currentHolderAddress
97-
}
98-
isPlaceholder={card.isPlaceholder}
99-
/>
100-
</SwiperSlide>
101-
))}
94+
{allCards.map((card, idx) => {
95+
// For past holders, "to" is the timestamp of the next holder's event.
96+
// For the current holder, "to" is undefined to signify "present".
97+
// For placeholders, "to" is the same as "from" (0).
98+
const toTimestamp =
99+
!card.isPlaceholder && idx < holders.length - 1
100+
? holders[idx + 1].event.timestamp
101+
: card.isPlaceholder
102+
? card.event.timestamp
103+
: undefined
104+
105+
return (
106+
<SwiperSlide
107+
key={idx}
108+
className="flex !min-h-[400px] !w-60 justify-center"
109+
>
110+
<TorchHistoryCard
111+
className="!min-h-[400px]"
112+
name={card.name}
113+
role={card.role}
114+
avatar={
115+
card.isPlaceholder
116+
? "/images/10-year-anniversary/torch-cover.webp"
117+
: getAvatarImage(card)
118+
}
119+
twitter={card.twitter}
120+
from={card.event.timestamp}
121+
to={toTimestamp}
122+
transactionHash={card.event.transactionHash}
123+
isCurrentHolder={
124+
!card.isPlaceholder && card.address === currentHolderAddress
125+
}
126+
isPlaceholder={card.isPlaceholder}
127+
/>
128+
</SwiperSlide>
129+
)
130+
})}
102131
<SwiperNavigation className="mt-8" />
103132
</Swiper>
104133
</SwiperContainer>

app/[locale]/10years/page.tsx

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -40,16 +40,16 @@ import {
4040
parseStoryDates,
4141
} from "./_components/utils"
4242

43+
import { routing } from "@/i18n/routing"
4344
import { fetch10YearEvents } from "@/lib/api/fetch10YearEvents"
4445
import { fetch10YearStories } from "@/lib/api/fetch10YearStories"
4546
import { fetchTorchHolders } from "@/lib/api/fetchTorchHolders"
4647
import {
47-
getCurrentHolderAddress,
48+
getCurrentHolder,
4849
getHolderEvents,
4950
getTransferEvents,
5051
isAddressFiltered,
5152
isTorchBurned,
52-
TorchHolder,
5353
} from "@/lib/torch"
5454
import TenYearLogo from "@/public/images/10-year-anniversary/10-year-logo.png"
5555

@@ -92,6 +92,8 @@ const Page = async ({ params }: { params: Promise<{ locale: Lang }> }) => {
9292
const adoptionCards = await getAdoptionCards()
9393

9494
// Torch NFT data fetching logic
95+
const transferEvents = await getTransferEvents()
96+
9597
const torchHolderMap: Record<string, (typeof allTorchHolders)[0]> =
9698
allTorchHolders.reduce(
9799
(acc, holder) => {
@@ -101,30 +103,25 @@ const Page = async ({ params }: { params: Promise<{ locale: Lang }> }) => {
101103
{} as Record<string, (typeof allTorchHolders)[0]>
102104
)
103105

106+
const torchHoldersEvents = await getHolderEvents(
107+
torchHolderMap,
108+
transferEvents
109+
)
110+
104111
let isBurned = false
105-
let currentHolder: TorchHolder | null = null
106112
try {
107113
isBurned = await isTorchBurned()
108-
const currentHolderAddress = await getCurrentHolderAddress()
109-
const isFiltered = isAddressFiltered(currentHolderAddress)
110-
111-
currentHolder = isFiltered
112-
? null
113-
: torchHolderMap[currentHolderAddress.toLowerCase()]
114114
} catch (error) {
115-
console.error("Error fetching torch data:", error)
115+
console.error("Error fetching torch burned status:", error)
116116
}
117-
const transferEvents = await getTransferEvents()
118-
const torchHoldersEvents = await getHolderEvents(
119-
torchHolderMap,
120-
transferEvents
121-
)
122117

123118
// Filter out events where the address is in the filtered list
124119
const torchHolders = torchHoldersEvents.filter(
125120
(holder) => !isAddressFiltered(holder.address)
126121
)
127122

123+
const currentHolder = getCurrentHolder(torchHolders)
124+
128125
return (
129126
<MainArticle className="mx-auto flex w-full flex-col items-center">
130127
<TenYearHero locale={locale} />
@@ -488,6 +485,12 @@ const Page = async ({ params }: { params: Promise<{ locale: Lang }> }) => {
488485
)
489486
}
490487

488+
export async function generateStaticParams() {
489+
return routing.locales.map((locale) => ({
490+
locale,
491+
}))
492+
}
493+
491494
export async function generateMetadata({
492495
params,
493496
}: {

next.config.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,10 @@ module.exports = (phase, { defaultConfig }) => {
9393
protocol: "https",
9494
hostname: "coin-images.coingecko.com",
9595
},
96+
{
97+
protocol: "https",
98+
hostname: "unavatar.io",
99+
},
96100
],
97101
},
98102
async headers() {

src/components/ui/avatar.tsx

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -167,11 +167,12 @@ const Avatar = React.forwardRef<
167167
{src ? (
168168
<Image
169169
className="object-fill"
170-
width={64}
171-
height={64}
170+
width={128}
171+
height={128}
172172
sizes="4rem"
173173
src={src}
174174
alt={name}
175+
quality={90}
175176
/>
176177
) : (
177178
<AvatarImage />
@@ -189,11 +190,12 @@ const Avatar = React.forwardRef<
189190
{src ? (
190191
<Image
191192
className="object-fill"
192-
width={64}
193-
height={64}
193+
width={128}
194+
height={128}
194195
sizes="4rem"
195196
src={src}
196197
alt={name}
198+
quality={90}
197199
/>
198200
) : (
199201
<AvatarImage />

0 commit comments

Comments
 (0)