Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
937822a
redesign: /developers above-the-fold (desktop)
wackerow Jul 9, 2025
4b763e0
feat: mobile above-the-fold, ssr/lazy swiper
wackerow Jul 9, 2025
d036e2c
feat: add dev resource cards section
wackerow Jul 10, 2025
ecbe68c
feat: trim documentation listings
wackerow Jul 10, 2025
5a958ea
feat: add video courses section
wackerow Jul 10, 2025
9fd1bec
feat: template hackathons, add founders
wackerow Jul 10, 2025
5161e40
fix: resources links
wackerow Jul 10, 2025
32b3202
fix: course hours lengths
wackerow Jul 10, 2025
3283201
i18n: extract strings for translation
wackerow Jul 10, 2025
6991fd6
feat: add glow button variant
wackerow Jul 5, 2025
aef6519
temp: hide AI button
wackerow Jul 10, 2025
7f576b9
chore: upres tag banner; size adjust
wackerow Jul 11, 2025
c3f2e1b
refactor: use x-scroll div on non-mobile for video course cards
wackerow Jul 11, 2025
b24e8ae
feat: clean up video course cards
wackerow Jul 12, 2025
f1b9466
feat: add Hackathon section
wackerow Jul 12, 2025
479ab5e
fix: resources
wackerow Jul 12, 2025
e2ae549
fix: add sizes to eventcard
wackerow Jul 12, 2025
94308ca
fix: /learning-tools metadata
wackerow Jul 12, 2025
42ebde0
fix: founder buttons positioning
wackerow Jul 12, 2025
0000a6a
fix: builder swiper layout
wackerow Jul 12, 2025
b10cd9b
adjust: ui/skeleton
wackerow Jul 12, 2025
9aef607
Merge branch 'dev' into developers-rebrand
wackerow Jul 12, 2025
f6e5840
feat: update all /developers action trackers
wackerow Jul 14, 2025
6ae6a7e
fix: scaffold llm label
wackerow Jul 14, 2025
f193f88
revert: ui/button glow variant
wackerow Jul 14, 2025
95976df
i18n: extract string for translation
wackerow Jul 15, 2025
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
51 changes: 51 additions & 0 deletions app/[locale]/developers/_components/BuilderCard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { Image } from "@/components/Image"
import { ButtonLink } from "@/components/ui/buttons/Button"
import { Card } from "@/components/ui/card"
import { Tag } from "@/components/ui/tag"

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

import type { DevelopersPath } from "../types"

type BuildCardProps = {
path: DevelopersPath
className?: string
}

const BuilderCard = ({ path, className }: BuildCardProps) => (
<Card className={cn("flex flex-col gap-8 rounded-4xl border p-6", className)}>
<Image
src={path.imgSrc}
alt={path.imgAlt}
className="mx-auto h-44 object-contain"
sizes="(max-width: 480px) calc(100vw - 6rem), 285px"
/>
<div className="h-full space-y-1">
{path.tag && (
<Tag
status="warning"
size="small"
className="mb-0 rounded-[4px] px-1 py-px font-bold normal-case"
>
{path.tag}
</Tag>
)}
<h3 className="text-lg font-bold">{path.title}</h3>
<p className="mb-4 text-sm text-body-medium">{path.description}</p>
</div>
<ButtonLink
href={path.href}
className="sm:w-fit"
customEventOptions={{
eventCategory: "top_boxes",
eventAction: "click",
eventName: path.tag,
}}
rel="noopener"
>
{path.button}
</ButtonLink>
</Card>
)

export default BuilderCard
44 changes: 44 additions & 0 deletions app/[locale]/developers/_components/BuilderSwiper/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
"use client"

import { Swiper, SwiperSlide } from "@/components/ui/swiper"

import type { DevelopersPath } from "../../types"
import BuilderCard from "../BuilderCard"
import SpeedRunCard from "../SpeedRunCard"

import { useBreakpointValue } from "@/hooks/useBreakpointValue"

type BuilderSwiperProps = {
paths: DevelopersPath[]
speedRunDetails: {
title: string
description: string
ctaLabel: string
}
}

const BuilderSwiper = ({ paths, speedRunDetails }: BuilderSwiperProps) => {
const slidesPerView = useBreakpointValue({
base: 1.15,
sm: 1.6,
})

return (
<Swiper
spaceBetween={8}
slidesPerView={slidesPerView}
lazyPreloadPrevNext={1}
>
{paths.map((path, idx) => (
<SwiperSlide key={idx} className="first:ms-8">
<BuilderCard path={path} />
</SwiperSlide>
))}
<SwiperSlide>
<SpeedRunCard {...speedRunDetails} className="me-16" />
</SwiperSlide>
</Swiper>
)
}

export default BuilderSwiper
5 changes: 5 additions & 0 deletions app/[locale]/developers/_components/BuilderSwiper/lazy.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import dynamic from "next/dynamic"

import Loading from "./loading"

export default dynamic(() => import("."), { ssr: false, loading: Loading })
14 changes: 14 additions & 0 deletions app/[locale]/developers/_components/BuilderSwiper/loading.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { Card } from "@/components/ui/card"
import { Skeleton, SkeletonLines } from "@/components/ui/skeleton"

const Loading = () => (
<Card className="relative ms-8 w-[85vw] space-y-4 rounded-4xl border bg-background px-6 py-6">
<Skeleton data-label="banner" className="mb-6 h-44 w-full rounded-xl" />
<Skeleton data-label="tag" className="h-5 w-19" />
<Skeleton data-label="title" className="-mb-2 h-5 w-1/2" />
<SkeletonLines data-label="description" noOfLines={2} className="m-0 p-0" />
<Skeleton data-label="button" className="h-10 w-1/4" />
</Card>
)

export default Loading
50 changes: 50 additions & 0 deletions app/[locale]/developers/_components/HackathonCard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { CommunityConference } from "@/lib/types"

import { Image } from "@/components/Image"
import CardImage from "@/components/Image/CardImage"
import {
Card,
CardBanner,
CardContent,
CardHighlight,
CardSubTitle,
CardTitle,
} from "@/components/ui/card"

import EventFallback from "@/public/images/events/event-placeholder.png"

type HackathonCardProps = {
event: CommunityConference
className?: string
}

const HackathonCard = ({ event, className }: HackathonCardProps) => {
const { title, href, description, imageUrl, formattedDate, location } = event
return (
<Card
href={href}
key={title + description}
customEventOptions={{
eventCategory: "hackathons",
eventAction: "click",
eventName: title,
}}
className={className}
>
<CardBanner className="h-36 w-full sm:w-[270px] 2xl:w-full">
{imageUrl ? (
<CardImage src={imageUrl} />
) : (
<Image src={EventFallback} alt="" sizes="276px" />
)}
</CardBanner>
<CardContent>
<CardTitle>{title}</CardTitle>
<CardSubTitle>{formattedDate} </CardSubTitle>
<CardHighlight>{location}</CardHighlight>
</CardContent>
</Card>
)
}

export default HackathonCard
23 changes: 23 additions & 0 deletions app/[locale]/developers/_components/HackathonSwiper/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
"use client"

import type { CommunityConference } from "@/lib/types"

import { Swiper, SwiperSlide } from "@/components/ui/swiper"

import HackathonCard from "../HackathonCard"

type HackathonSwiperProps = {
events: CommunityConference[]
}

const HackathonSwiper = ({ events }: HackathonSwiperProps) => (
<Swiper spaceBetween={16} slidesPerView={1.25}>
{events.map((event, idx) => (
<SwiperSlide key={idx} className="max-2xl:first:ms-8 max-2xl:last:pe-16">
<HackathonCard event={event} />
</SwiperSlide>
))}
</Swiper>
)

export default HackathonSwiper
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import dynamic from "next/dynamic"

import Loading from "./loading"

export default dynamic(() => import("."), { ssr: false, loading: Loading })
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { SkeletonCardGrid } from "@/components/ui/skeleton"

const Loading = () => <SkeletonCardGrid />

export default Loading
49 changes: 49 additions & 0 deletions app/[locale]/developers/_components/SpeedRunCard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import { Image } from "@/components/Image"
import { ButtonLink } from "@/components/ui/buttons/Button"

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

import speedRunEthereumImage from "@/public/images/dev-tools/speed-run-ethereum-banner.png"

type SpeedRunCardProps = {
title: string
description: string
ctaLabel: string
className?: string
}
const SpeedRunCard = ({
title,
description,
ctaLabel,
className,
}: SpeedRunCardProps) => (
<div
className={cn("relative h-[450px]", className)}
data-label="speedrunethereum-banner"
>
<Image
className="pointer-events-none absolute -z-[1] h-full w-screen rounded-t-4xl object-cover object-[75%_50%]"
src={speedRunEthereumImage}
alt="SpeedRunEthereum banner"
sizes="(max-width: 768px) 100vw, 50vw"
/>
<div className="z-[1] flex flex-col space-y-4 break-words px-6 py-10 md:space-y-6 lg:p-6">
<h3>{title}</h3>
<p>{description}</p>
<ButtonLink
href="https://speedrunethereum.com/"
className="mt-4 sm:w-fit"
customEventOptions={{
eventCategory: "top_boxes",
eventAction: "click",
eventName: "speedrun",
}}
rel="noopener"
>
{ctaLabel}
</ButtonLink>
</div>
</div>
)

export default SpeedRunCard
48 changes: 48 additions & 0 deletions app/[locale]/developers/_components/VideoCourseCard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { Image } from "@/components/Image"
import { Card } from "@/components/ui/card"
import { Tag } from "@/components/ui/tag"

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

import type { VideoCourse } from "../types"

type VideoCourseCardProps = {
course: VideoCourse
className?: string
}

const VideoCourseCard = ({ course, className }: VideoCourseCardProps) => (
<Card
href={course.href}
className={cn("group h-full w-fit rounded-4xl no-underline", className)}
customEventOptions={{
eventCategory: "video-courses",
eventAction: "click",
eventName: course.title,
}}
>
<div className="h-fit w-full overflow-hidden rounded-2xl">
<Image
src={course.imgSrc}
alt={course.imgAlt}
className="mx-auto h-44 rounded-2xl object-cover transition-transform group-hover:scale-105 group-hover:transition-transform"
sizes="(max-width: 480px) calc(100vw - 2rem), 300px"
/>
</div>
<div className="h-full space-y-1">
<Tag
status="warning"
size="small"
className="mb-2 mt-4 rounded-[4px] px-1 py-0 font-bold normal-case"
>
{course.hours}
</Tag>
<h3 className="text-lg font-bold text-body group-hover:underline">
{course.title}
</h3>
<p className="mb-4 text-sm text-body-medium">{course.description}</p>
</div>
</Card>
)

export default VideoCourseCard
25 changes: 25 additions & 0 deletions app/[locale]/developers/_components/VideoCourseSwiper/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
"use client"

import { Swiper, SwiperSlide } from "@/components/ui/swiper"

import type { VideoCourse } from "../../types"
import VideoCourseCard from "../VideoCourseCard"

type VideoCourseSwiperProps = {
courses: VideoCourse[]
}

const VideoCourseSwiper = ({ courses }: VideoCourseSwiperProps) => (
<Swiper spaceBetween={16} slidesPerView={1.25}>
{courses.map((course, idx) => (
<SwiperSlide
key={idx}
className="max-xl://[&:last-child_div]:pe-16 max-2xl:first:ms-8 max-2xl:last:pe-16"
>
<VideoCourseCard course={course} />
</SwiperSlide>
))}
</Swiper>
)

export default VideoCourseSwiper
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import dynamic from "next/dynamic"

import Loading from "./loading"

export default dynamic(() => import("."), { ssr: false, loading: Loading })
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { SkeletonCardGrid } from "@/components/ui/skeleton"

const Loading = () => (
<div className="px-8">
<SkeletonCardGrid />
</div>
)

export default Loading
6 changes: 2 additions & 4 deletions app/[locale]/developers/learning-tools/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,8 @@ export async function generateMetadata({
return await getMetadata({
locale,
slug: ["developers", "learning-tools"],
title: t("page-developers-learning-tools:page-learning-tools-meta-title"),
description: t(
"page-developers-learning-tools:page-learning-tools-meta-desc"
),
title: t("page-learning-tools-meta-title"),
description: t("page-learning-tools-meta-desc"),
})
}

Expand Down
Loading