Skip to content

Commit 920d6db

Browse files
authored
Merge pull request #15807 from ethereum/developers-rebrand
feat: /developers rebrand
2 parents 0f91039 + 95976df commit 920d6db

37 files changed

+1031
-361
lines changed
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import { Image } from "@/components/Image"
2+
import { ButtonLink } from "@/components/ui/buttons/Button"
3+
import { Card } from "@/components/ui/card"
4+
import { Tag } from "@/components/ui/tag"
5+
6+
import { cn } from "@/lib/utils/cn"
7+
8+
import type { DevelopersPath } from "../types"
9+
10+
type BuildCardProps = {
11+
path: DevelopersPath
12+
className?: string
13+
}
14+
15+
const BuilderCard = ({ path, className }: BuildCardProps) => (
16+
<Card className={cn("flex flex-col gap-8 rounded-4xl border p-6", className)}>
17+
<Image
18+
src={path.imgSrc}
19+
alt={path.imgAlt}
20+
className="mx-auto h-44 object-contain"
21+
sizes="(max-width: 480px) calc(100vw - 6rem), 285px"
22+
/>
23+
<div className="h-full space-y-1">
24+
{path.tag && (
25+
<Tag
26+
status="warning"
27+
size="small"
28+
className="mb-0 rounded-[4px] px-1 py-px font-bold normal-case"
29+
>
30+
{path.tag}
31+
</Tag>
32+
)}
33+
<h3 className="text-lg font-bold">{path.title}</h3>
34+
<p className="mb-4 text-sm text-body-medium">{path.description}</p>
35+
</div>
36+
<ButtonLink
37+
href={path.href}
38+
className="sm:w-fit"
39+
customEventOptions={{
40+
eventCategory: "top_boxes",
41+
eventAction: "click",
42+
eventName: path.tag,
43+
}}
44+
rel="noopener"
45+
>
46+
{path.button}
47+
</ButtonLink>
48+
</Card>
49+
)
50+
51+
export default BuilderCard
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
"use client"
2+
3+
import { Swiper, SwiperSlide } from "@/components/ui/swiper"
4+
5+
import type { DevelopersPath } from "../../types"
6+
import BuilderCard from "../BuilderCard"
7+
import SpeedRunCard from "../SpeedRunCard"
8+
9+
import { useBreakpointValue } from "@/hooks/useBreakpointValue"
10+
11+
type BuilderSwiperProps = {
12+
paths: DevelopersPath[]
13+
speedRunDetails: {
14+
title: string
15+
description: string
16+
ctaLabel: string
17+
}
18+
}
19+
20+
const BuilderSwiper = ({ paths, speedRunDetails }: BuilderSwiperProps) => {
21+
const slidesPerView = useBreakpointValue({
22+
base: 1.15,
23+
sm: 1.6,
24+
})
25+
26+
return (
27+
<Swiper
28+
spaceBetween={8}
29+
slidesPerView={slidesPerView}
30+
lazyPreloadPrevNext={1}
31+
>
32+
{paths.map((path, idx) => (
33+
<SwiperSlide key={idx} className="first:ms-8">
34+
<BuilderCard path={path} />
35+
</SwiperSlide>
36+
))}
37+
<SwiperSlide>
38+
<SpeedRunCard {...speedRunDetails} className="me-16" />
39+
</SwiperSlide>
40+
</Swiper>
41+
)
42+
}
43+
44+
export default BuilderSwiper
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import dynamic from "next/dynamic"
2+
3+
import Loading from "./loading"
4+
5+
export default dynamic(() => import("."), { ssr: false, loading: Loading })
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import { Card } from "@/components/ui/card"
2+
import { Skeleton, SkeletonLines } from "@/components/ui/skeleton"
3+
4+
const Loading = () => (
5+
<Card className="relative ms-8 w-[85vw] space-y-4 rounded-4xl border bg-background px-6 py-6">
6+
<Skeleton data-label="banner" className="mb-6 h-44 w-full rounded-xl" />
7+
<Skeleton data-label="tag" className="h-5 w-19" />
8+
<Skeleton data-label="title" className="-mb-2 h-5 w-1/2" />
9+
<SkeletonLines data-label="description" noOfLines={2} className="m-0 p-0" />
10+
<Skeleton data-label="button" className="h-10 w-1/4" />
11+
</Card>
12+
)
13+
14+
export default Loading
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import { CommunityConference } from "@/lib/types"
2+
3+
import { Image } from "@/components/Image"
4+
import CardImage from "@/components/Image/CardImage"
5+
import {
6+
Card,
7+
CardBanner,
8+
CardContent,
9+
CardHighlight,
10+
CardSubTitle,
11+
CardTitle,
12+
} from "@/components/ui/card"
13+
14+
import EventFallback from "@/public/images/events/event-placeholder.png"
15+
16+
type HackathonCardProps = {
17+
event: CommunityConference
18+
className?: string
19+
}
20+
21+
const HackathonCard = ({ event, className }: HackathonCardProps) => {
22+
const { title, href, description, imageUrl, formattedDate, location } = event
23+
return (
24+
<Card
25+
href={href}
26+
key={title + description}
27+
customEventOptions={{
28+
eventCategory: "hackathons",
29+
eventAction: "click",
30+
eventName: title,
31+
}}
32+
className={className}
33+
>
34+
<CardBanner className="h-36 w-full sm:w-[270px] 2xl:w-full">
35+
{imageUrl ? (
36+
<CardImage src={imageUrl} />
37+
) : (
38+
<Image src={EventFallback} alt="" sizes="276px" />
39+
)}
40+
</CardBanner>
41+
<CardContent>
42+
<CardTitle>{title}</CardTitle>
43+
<CardSubTitle>{formattedDate} </CardSubTitle>
44+
<CardHighlight>{location}</CardHighlight>
45+
</CardContent>
46+
</Card>
47+
)
48+
}
49+
50+
export default HackathonCard
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
"use client"
2+
3+
import type { CommunityConference } from "@/lib/types"
4+
5+
import { Swiper, SwiperSlide } from "@/components/ui/swiper"
6+
7+
import HackathonCard from "../HackathonCard"
8+
9+
type HackathonSwiperProps = {
10+
events: CommunityConference[]
11+
}
12+
13+
const HackathonSwiper = ({ events }: HackathonSwiperProps) => (
14+
<Swiper spaceBetween={16} slidesPerView={1.25}>
15+
{events.map((event, idx) => (
16+
<SwiperSlide key={idx} className="max-2xl:first:ms-8 max-2xl:last:pe-16">
17+
<HackathonCard event={event} />
18+
</SwiperSlide>
19+
))}
20+
</Swiper>
21+
)
22+
23+
export default HackathonSwiper
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import dynamic from "next/dynamic"
2+
3+
import Loading from "./loading"
4+
5+
export default dynamic(() => import("."), { ssr: false, loading: Loading })
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import { SkeletonCardGrid } from "@/components/ui/skeleton"
2+
3+
const Loading = () => <SkeletonCardGrid />
4+
5+
export default Loading
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import { Image } from "@/components/Image"
2+
import { ButtonLink } from "@/components/ui/buttons/Button"
3+
4+
import { cn } from "@/lib/utils/cn"
5+
6+
import speedRunEthereumImage from "@/public/images/dev-tools/speed-run-ethereum-banner.png"
7+
8+
type SpeedRunCardProps = {
9+
title: string
10+
description: string
11+
ctaLabel: string
12+
className?: string
13+
}
14+
const SpeedRunCard = ({
15+
title,
16+
description,
17+
ctaLabel,
18+
className,
19+
}: SpeedRunCardProps) => (
20+
<div
21+
className={cn("relative h-[450px]", className)}
22+
data-label="speedrunethereum-banner"
23+
>
24+
<Image
25+
className="pointer-events-none absolute -z-[1] h-full w-screen rounded-t-4xl object-cover object-[75%_50%]"
26+
src={speedRunEthereumImage}
27+
alt="SpeedRunEthereum banner"
28+
sizes="(max-width: 768px) 100vw, 50vw"
29+
/>
30+
<div className="z-[1] flex flex-col space-y-4 break-words px-6 py-10 md:space-y-6 lg:p-6">
31+
<h3>{title}</h3>
32+
<p>{description}</p>
33+
<ButtonLink
34+
href="https://speedrunethereum.com/"
35+
className="mt-4 sm:w-fit"
36+
customEventOptions={{
37+
eventCategory: "top_boxes",
38+
eventAction: "click",
39+
eventName: "speedrun",
40+
}}
41+
rel="noopener"
42+
>
43+
{ctaLabel}
44+
</ButtonLink>
45+
</div>
46+
</div>
47+
)
48+
49+
export default SpeedRunCard
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import { Image } from "@/components/Image"
2+
import { Card } from "@/components/ui/card"
3+
import { Tag } from "@/components/ui/tag"
4+
5+
import { cn } from "@/lib/utils/cn"
6+
7+
import type { VideoCourse } from "../types"
8+
9+
type VideoCourseCardProps = {
10+
course: VideoCourse
11+
className?: string
12+
}
13+
14+
const VideoCourseCard = ({ course, className }: VideoCourseCardProps) => (
15+
<Card
16+
href={course.href}
17+
className={cn("group h-full w-fit rounded-4xl no-underline", className)}
18+
customEventOptions={{
19+
eventCategory: "video-courses",
20+
eventAction: "click",
21+
eventName: course.title,
22+
}}
23+
>
24+
<div className="h-fit w-full overflow-hidden rounded-2xl">
25+
<Image
26+
src={course.imgSrc}
27+
alt={course.imgAlt}
28+
className="mx-auto h-44 rounded-2xl object-cover transition-transform group-hover:scale-105 group-hover:transition-transform"
29+
sizes="(max-width: 480px) calc(100vw - 2rem), 300px"
30+
/>
31+
</div>
32+
<div className="h-full space-y-1">
33+
<Tag
34+
status="warning"
35+
size="small"
36+
className="mb-2 mt-4 rounded-[4px] px-1 py-0 font-bold normal-case"
37+
>
38+
{course.hours}
39+
</Tag>
40+
<h3 className="text-lg font-bold text-body group-hover:underline">
41+
{course.title}
42+
</h3>
43+
<p className="mb-4 text-sm text-body-medium">{course.description}</p>
44+
</div>
45+
</Card>
46+
)
47+
48+
export default VideoCourseCard

0 commit comments

Comments
 (0)