Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 10 additions & 3 deletions app/[locale]/10years/_components/AdoptionSwiper.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,20 @@ import {

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

import { adoptionCards, adoptionStyles } from "./data"
import { AdoptionCard } from "./types"

const AdoptionSwiper = () => {
type AdoptionCardProps = {
adoptionCards: AdoptionCard[]
adoptionStyles: string[]
}
const AdoptionSwiper = ({
adoptionCards,
adoptionStyles,
}: AdoptionCardProps) => {
return (
<div className="flex flex-1 flex-col gap-6 md:hidden">
<SwiperContainer className="mx-auto w-full max-w-[550px]">
<Swiper>
<Swiper spaceBetween={32}>
{adoptionCards.map((card, index) => (
<SwiperSlide key={card.title}>
<div
Expand Down
7 changes: 5 additions & 2 deletions app/[locale]/10years/_components/InnovationSwiper.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,10 @@ export default function InnovationSwiper() {
return (
<div className="w-[100%]">
<SwiperContainer className="mx-auto w-full max-w-[550px] xl:max-w-[700px]">
<Swiper className="mx-auto w-full max-w-[550px] xl:max-w-[700px]">
<Swiper
className="mx-auto w-full max-w-[550px] xl:max-w-[700px]"
spaceBetween={32}
>
{innovationCards.map((card, index) => (
<SwiperSlide
key={index}
Expand All @@ -23,7 +26,7 @@ export default function InnovationSwiper() {
<Image
src={card.image}
alt={card.title}
className="mx-auto my-4 h-auto max-w-full"
className="mx-auto my-4 h-auto max-h-48 object-contain"
/>
<div>
<h3 className="mb-4">{card.title}</h3>
Expand Down
30 changes: 20 additions & 10 deletions app/[locale]/10years/_components/TenYearGlobe.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"use client"

import { useEffect, useMemo, useRef, useState } from "react"
import { useCallback, useEffect, useMemo, useRef, useState } from "react"
import { useTheme } from "next-themes"
import Globe from "react-globe.gl"
import { type GlobeMethods } from "react-globe.gl"
Expand All @@ -12,6 +12,7 @@ import Link from "@/components/ui/Link"
import countries from "./countries.json"

import { useBreakpointValue } from "@/hooks/useBreakpointValue"
import { usePrefersReducedMotion } from "@/hooks/usePrefersReducedMotion"
import EthLogo from "@/public/images/assets/eth-glyph-colored.png"

// Define a type for event data
Expand Down Expand Up @@ -42,11 +43,12 @@ const TenYearGlobe = ({ events }: { events: EventData[] }) => {
const globeRef = useRef<GlobeMethods>()
const globeContainerRef = useRef<HTMLDivElement>(null)
const { resolvedTheme } = useTheme()
const { prefersReducedMotion } = usePrefersReducedMotion()

const atmosphereColor = resolvedTheme === "dark" ? "#B38DF0" : "#945AF4"

const width = useBreakpointValue({
base: 260,
base: window?.innerWidth - 64 || 260, // Full width on mobile with padding
sm: 400,
md: 500,
lg: 600,
Expand All @@ -61,7 +63,7 @@ const TenYearGlobe = ({ events }: { events: EventData[] }) => {
const b = Math.min(255, Math.floor((basePurple & 0xff) * 1.3))
return `#${r.toString(16).padStart(2, "0")}${g.toString(16).padStart(2, "0")}${b.toString(16).padStart(2, "0")}`
})
}, [countries.features, resolvedTheme])
}, [resolvedTheme])

const hexPolygonColor = (feature: object) => {
const idx = countries.features.indexOf(
Expand All @@ -78,10 +80,18 @@ const TenYearGlobe = ({ events }: { events: EventData[] }) => {
return hexPolygonColors[idx]
}

// Function to safely set auto-rotate based on motion preferences
const setAutoRotate = useCallback(
(controls: ExtendedOrbitControls, value: boolean) => {
controls.autoRotate = value && !prefersReducedMotion
},
[prefersReducedMotion]
)

useEffect(() => {
if (globeRef.current) {
const controls = globeRef.current.controls() as ExtendedOrbitControls
controls.autoRotate = true
setAutoRotate(controls, true)
controls.enablePan = false
controls.enableZoom = false
controls.autoRotateSpeed = 2.0
Expand All @@ -90,7 +100,7 @@ const TenYearGlobe = ({ events }: { events: EventData[] }) => {
const ambientLight = new THREE.AmbientLight(0xffffff, 1)
globeRef.current.scene().add(ambientLight)
}
}, [])
}, [setAutoRotate])

// Prepare htmlElementsData for EthLogo
const htmlElementsData = events.map((event) => ({
Expand Down Expand Up @@ -176,7 +186,7 @@ const TenYearGlobe = ({ events }: { events: EventData[] }) => {
}
// Stop rotation immediately
const controls = globeRef.current.controls() as ExtendedOrbitControls
controls.autoRotate = false
setAutoRotate(controls, false)
if ("autoRotateSpeed" in controls) controls.autoRotateSpeed = 0
if (controls._sphericalDelta) {
controls._sphericalDelta.theta = 0
Expand All @@ -193,15 +203,15 @@ const TenYearGlobe = ({ events }: { events: EventData[] }) => {
if (globeRef.current) {
const controls =
globeRef.current.controls() as ExtendedOrbitControls
controls.autoRotate = true
setAutoRotate(controls, true)
if ("autoRotateSpeed" in controls) controls.autoRotateSpeed = 2.0
}
}
}}
onPointClick={() => {
if (globeRef.current) {
const controls = globeRef.current.controls() as ExtendedOrbitControls
controls.autoRotate = false
setAutoRotate(controls, false)
if ("autoRotateSpeed" in controls) controls.autoRotateSpeed = 0
if (controls._sphericalDelta) {
controls._sphericalDelta.theta = 0
Expand All @@ -227,8 +237,8 @@ const TenYearGlobe = ({ events }: { events: EventData[] }) => {
return (
<div
ref={globeContainerRef}
className="relative cursor-grab"
style={{ width: width, height: width }}
className="relative w-full max-w-full cursor-grab active:cursor-grabbing"
style={{ height: width }}
>
{MemoizedGlobe}
{hoveredEvent && tooltipPos && (
Expand Down
48 changes: 30 additions & 18 deletions app/[locale]/10years/_components/TenYearHero.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,30 +8,32 @@ import ParallaxImage from "@/components/Image/ParallaxImage"
import TenYearBackgroundImage from "@/public/images/10-year-anniversary/10-year-background.png"
import TenYearGraphicImage from "@/public/images/10-year-anniversary/10-year-graphic.png"

const [initialText, ...initialWords] = [
"censorship resistance",
"100% uptime",
"decentralization",
"community building",
"developer growth",
"global collaboration",
"cypherpunk values",
"hackathons",
"censorship resistance",
"permissionless finance",
"credible neutrality",
"the infinite garden",
"client diversity",
]

const TenYearHero = () => {
const [words, setWords] = useState<{ text: string; words: string[] }>({
text: "censorship resistance",
words: [
"censorship resistance",
"100% uptime",
"decentralization",
"community building",
"developer growth",
"global collaboration",
"cypherpunk values",
"hackathons",
"censorship resistance",
"permissionless finance",
"credible neutrality",
"the infinite garden",
"client diversity",
],
text: initialText,
words: initialWords,
})

// loops over chars to morph a text to another
const morpher = (start: string, end: string): void => {
// array of chars to randomly morph the text between start and end
const chars = "abcdefghijklmnopqrstuvwxyz".split("")
const chars = "abcdfgijklnopqsvwxyz".split("")
// duration of the global morph
const duration = 3
// speed of the morph for each letter
Expand Down Expand Up @@ -136,7 +138,17 @@ const TenYearHero = () => {
</div>
<p className="text-center text-3xl">
Celebrating 10 years of{" "}
<span className="font-bold text-accent-b">{words.text}</span>
<span className="relative max-md:block md:w-fit">
<span
className="select-none opacity-0 max-md:hidden"
data-label="space-holder"
>
{initialText}
</span>
<span className="font-bold text-accent-b md:absolute md:start-0 md:text-nowrap">
{words.text}
</span>
</span>
</p>
</div>
)
Expand Down
6 changes: 3 additions & 3 deletions app/[locale]/10years/_components/TenYearHomeBanner.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,11 @@ const TenYearHomeBanner = () => {
<ParallaxImage
src={TenYearGraphicImage}
alt=""
className="mx-auto -mb-2 -mt-16 max-w-[500px] object-contain sm:-mt-24 md:-mt-32"
className="mx-auto -mb-2 -mt-16 max-w-[min(100%,500px)] object-contain sm:-mt-24 md:-mt-32"
/>
<div className="flex justify-center">
<div className="mt-4 flex justify-center">
<TenYearDesktopText className="mb-4 hidden object-contain text-body md:block" />
<TenYearMobileText className="mb-4 block object-contain text-body md:hidden" />
<TenYearMobileText className="mb-4 block object-contain text-5xl text-body md:hidden" />
</div>
<div className="mb-4 flex flex-col gap-2">
<p>
Expand Down
14 changes: 8 additions & 6 deletions app/[locale]/10years/_components/data.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,21 @@
import Link from "@/components/ui/Link"

import { AdoptionCard } from "./types"

import Adoption1Image from "@/public/images/10-year-anniversary/adoption-1.png"
import Adoption2Image from "@/public/images/10-year-anniversary/adoption-2.png"
import Adoption3Image from "@/public/images/10-year-anniversary/adoption-3.png"
import DefiSummerImage from "@/public/images/10-year-anniversary/defi-summer.png"
import EthETFImage from "@/public/images/10-year-anniversary/eth-etf.png"
import EthereumLaunchImage from "@/public/images/10-year-anniversary/ethereum-launch.png"
import NftImage from "@/public/images/10-year-anniversary/nft-frontier.png"
import TheMergeImage from "@/public/images/10-year-anniversary/robot-and-crowd-cheering.png"
import Adoption5Image from "@/public/images/10-year-anniversary/robot-walking.png"
import TheMergeImage from "@/public/images/10-year-anniversary/the-merge.png"
import StableCoinImage from "@/public/images/10-year-anniversary/the-pioneer-stablecoin.png"
import Adoption4Image from "@/public/images/10-year-anniversary/walking-talking-1.png"
import Adoption6Image from "@/public/images/10-year-anniversary/walking-talking-2.png"

const adoptionCards = [
const adoptionCards: AdoptionCard[] = [
{
image: Adoption1Image,
title: "Decade of Decentralization",
Expand Down Expand Up @@ -102,12 +104,12 @@ const adoptionCards = [

// duplicate 1 2 3, 1 2 3 to fix mobile slider bug where styles are not applied
const adoptionStyles = [
"bg-background bg-gradient-to-t from-20% to-60% from-accent-c/10 to-accent-c/5 dark:from-accent-c/20 dark:to-accent-c/10 border-accent-c/10",
"bg-background bg-gradient-to-b from-20% to-60% from-accent-c/10 to-accent-c/5 dark:from-accent-c/20 dark:to-accent-c/10 border-accent-c/10",
"bg-background bg-gradient-to-b from-20% to-60% from-accent-b/10 to-accent-b/5 dark:from-accent-b/20 dark:to-accent-b/10 border-accent-b/10",
"bg-background bg-gradient-to-r from-20% to-60% from-accent-a/10 to-accent-a/5 dark:from-accent-a/20 dark:to-accent-a/10 border-accent-a/10",
"bg-background bg-gradient-to-t from-20% to-60% from-accent-c/10 to-accent-c/5 dark:from-accent-c/20 dark:to-accent-c/10 border-accent-c/10",
"bg-background bg-gradient-to-b from-20% to-60% from-accent-a/10 to-accent-a/5 dark:from-accent-a/20 dark:to-accent-a/10 border-accent-a/10",
"bg-background bg-gradient-to-b from-20% to-60% from-accent-c/10 to-accent-c/5 dark:from-accent-c/20 dark:to-accent-c/10 border-accent-c/10",
"bg-background bg-gradient-to-b from-20% to-60% from-accent-b/10 to-accent-b/5 dark:from-accent-b/20 dark:to-accent-b/10 border-accent-b/10",
"bg-background bg-gradient-to-r from-20% to-60% from-accent-a/10 to-accent-a/5 dark:from-accent-a/20 dark:to-accent-a/10 border-accent-a/10",
"bg-background bg-gradient-to-b from-20% to-60% from-accent-a/10 to-accent-a/5 dark:from-accent-a/20 dark:to-accent-a/10 border-accent-a/10",
]

const innovationCards = [
Expand Down
20 changes: 20 additions & 0 deletions app/[locale]/10years/_components/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { StaticImageData } from "next/image"

export type Story = {
storyEnglish: string
storyOriginal: string
category: string
name: string
date: string
country: string
twitter: string
region: string
}

export type AdoptionCard = {
image: StaticImageData
title: string
description: React.ReactNode
href: string
linkText: string
}
31 changes: 31 additions & 0 deletions app/[locale]/10years/_components/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { formatDate, isValidDate } from "@/lib/utils/date"

import { DEFAULT_LOCALE } from "@/lib/constants"

import type { Story } from "./types"

const parseDate = (date: string, locale = DEFAULT_LOCALE): string => {
// TODO: Remove this check when spreadsheet is fixed
// Currently dates are in the formatted as "DD.MM." which is not parsable by Date.parse
// If partially valid date, reformat it
const partiallyValidDate = /^(\d{1,2})\.(\d{1})\.$/
if (partiallyValidDate.test(date)) {
const [, day, month] = date.match(partiallyValidDate) || []
const newDate = `2025-${month.padStart(2, "0")}-${day.padStart(2, "0")}`
return formatDate(newDate, locale)
}

// If the date is already in a valid format, return it
if (isValidDate(date)) return formatDate(date, locale)
// If the date is not recognized, return original value
return date
}

export const parseStoryDates = (
stories: Story[],
locale = DEFAULT_LOCALE
): Story[] =>
stories.map(({ date, ...story }) => ({
...story,
date: parseDate(date, locale),
}))
14 changes: 10 additions & 4 deletions app/[locale]/10years/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import InnovationSwiper from "./_components/InnovationSwiper"
import Stories from "./_components/Stories"
import TenYearGlobe from "./_components/TenYearGlobe"
import TenYearHero from "./_components/TenYearHero"
import { parseStoryDates } from "./_components/utils"

import { fetch10YearEvents } from "@/lib/api/fetch10YearEvents"
import { fetch10YearStories } from "@/lib/api/fetch10YearStories"
Expand All @@ -54,6 +55,8 @@ const Page = async ({ params }: { params: Promise<{ locale: Lang }> }) => {

const [fetched10YearEvents, fetched10YearStories] = await loadData()

const stories = parseStoryDates(fetched10YearStories, locale)

// Get i18n messages
const allMessages = await getMessages({ locale })
const requiredNamespaces = getRequiredNamespacesForPage("/10years")
Expand Down Expand Up @@ -271,13 +274,16 @@ const Page = async ({ params }: { params: Promise<{ locale: Lang }> }) => {
</p>
</div>
</div>
<AdoptionSwiper />
<AdoptionSwiper
adoptionCards={adoptionCards}
adoptionStyles={adoptionStyles}
/>
<div className="hidden flex-1 flex-col gap-6 md:flex">
{adoptionCards.map((card, index) => (
<div
key={card.title}
className={cn(
"w-[70%] rounded-2xl p-8",
"w-[70%] rounded-2xl p-8 shadow",
index % 2 === 0 && "ml-auto",
index !== 0 && "-mt-10",
zIndexClasses[index],
Expand Down Expand Up @@ -319,15 +325,15 @@ const Page = async ({ params }: { params: Promise<{ locale: Lang }> }) => {
</ButtonLink>
</div>
</div>
<Stories stories={fetched10YearStories} />
<Stories stories={stories} />
</div>

<div className="w-full gap-8 px-8 py-8 pt-32">
<div className="flex flex-col items-center gap-4 rounded-2xl bg-ten-year-gradient p-8">
<Image
src={TenYearLogo}
alt="10 year anniversary logo"
className="-mb-4 max-h-80 object-contain"
className="mb-8 max-h-80 object-contain sm:mb-12"
/>
<h3>Have an idea for how the community can celebrate?</h3>
<p>
Expand Down
5 changes: 4 additions & 1 deletion app/[locale]/_components/home.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -608,7 +608,10 @@ const HomePage = ({
</SectionContent>
</Section>

<Section id="10-year-anniversary">
<Section
id="10-year-anniversary"
className={cn(locale !== "en" && "hidden")} // TODO: Show again when translations ready
>
<TenYearHomeBanner />
</Section>

Expand Down
Loading
Loading