diff --git a/app/[locale]/developers/_components/BuilderCard.tsx b/app/[locale]/developers/_components/BuilderCard.tsx new file mode 100644 index 00000000000..40bb6b87616 --- /dev/null +++ b/app/[locale]/developers/_components/BuilderCard.tsx @@ -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) => ( + + {path.imgAlt} +
+ {path.tag && ( + + {path.tag} + + )} +

{path.title}

+

{path.description}

+
+ + {path.button} + +
+) + +export default BuilderCard diff --git a/app/[locale]/developers/_components/BuilderSwiper/index.tsx b/app/[locale]/developers/_components/BuilderSwiper/index.tsx new file mode 100644 index 00000000000..1b3167a0881 --- /dev/null +++ b/app/[locale]/developers/_components/BuilderSwiper/index.tsx @@ -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 ( + + {paths.map((path, idx) => ( + + + + ))} + + + + + ) +} + +export default BuilderSwiper diff --git a/app/[locale]/developers/_components/BuilderSwiper/lazy.tsx b/app/[locale]/developers/_components/BuilderSwiper/lazy.tsx new file mode 100644 index 00000000000..c960f08e647 --- /dev/null +++ b/app/[locale]/developers/_components/BuilderSwiper/lazy.tsx @@ -0,0 +1,5 @@ +import dynamic from "next/dynamic" + +import Loading from "./loading" + +export default dynamic(() => import("."), { ssr: false, loading: Loading }) diff --git a/app/[locale]/developers/_components/BuilderSwiper/loading.tsx b/app/[locale]/developers/_components/BuilderSwiper/loading.tsx new file mode 100644 index 00000000000..5a463164c78 --- /dev/null +++ b/app/[locale]/developers/_components/BuilderSwiper/loading.tsx @@ -0,0 +1,14 @@ +import { Card } from "@/components/ui/card" +import { Skeleton, SkeletonLines } from "@/components/ui/skeleton" + +const Loading = () => ( + + + + + + + +) + +export default Loading diff --git a/app/[locale]/developers/_components/HackathonCard.tsx b/app/[locale]/developers/_components/HackathonCard.tsx new file mode 100644 index 00000000000..0bef4027db9 --- /dev/null +++ b/app/[locale]/developers/_components/HackathonCard.tsx @@ -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 ( + + + {imageUrl ? ( + + ) : ( + + )} + + + {title} + {formattedDate} + {location} + + + ) +} + +export default HackathonCard diff --git a/app/[locale]/developers/_components/HackathonSwiper/index.tsx b/app/[locale]/developers/_components/HackathonSwiper/index.tsx new file mode 100644 index 00000000000..d239e06ea9f --- /dev/null +++ b/app/[locale]/developers/_components/HackathonSwiper/index.tsx @@ -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) => ( + + {events.map((event, idx) => ( + + + + ))} + +) + +export default HackathonSwiper diff --git a/app/[locale]/developers/_components/HackathonSwiper/lazy.tsx b/app/[locale]/developers/_components/HackathonSwiper/lazy.tsx new file mode 100644 index 00000000000..c960f08e647 --- /dev/null +++ b/app/[locale]/developers/_components/HackathonSwiper/lazy.tsx @@ -0,0 +1,5 @@ +import dynamic from "next/dynamic" + +import Loading from "./loading" + +export default dynamic(() => import("."), { ssr: false, loading: Loading }) diff --git a/app/[locale]/developers/_components/HackathonSwiper/loading.tsx b/app/[locale]/developers/_components/HackathonSwiper/loading.tsx new file mode 100644 index 00000000000..5256c8f6218 --- /dev/null +++ b/app/[locale]/developers/_components/HackathonSwiper/loading.tsx @@ -0,0 +1,5 @@ +import { SkeletonCardGrid } from "@/components/ui/skeleton" + +const Loading = () => + +export default Loading diff --git a/app/[locale]/developers/_components/SpeedRunCard.tsx b/app/[locale]/developers/_components/SpeedRunCard.tsx new file mode 100644 index 00000000000..9218419cadb --- /dev/null +++ b/app/[locale]/developers/_components/SpeedRunCard.tsx @@ -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) => ( +
+ SpeedRunEthereum banner +
+

{title}

+

{description}

+ + {ctaLabel} + +
+
+) + +export default SpeedRunCard diff --git a/app/[locale]/developers/_components/VideoCourseCard.tsx b/app/[locale]/developers/_components/VideoCourseCard.tsx new file mode 100644 index 00000000000..7024ff7325e --- /dev/null +++ b/app/[locale]/developers/_components/VideoCourseCard.tsx @@ -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) => ( + +
+ {course.imgAlt} +
+
+ + {course.hours} + +

+ {course.title} +

+

{course.description}

+
+
+) + +export default VideoCourseCard diff --git a/app/[locale]/developers/_components/VideoCourseSwiper/index.tsx b/app/[locale]/developers/_components/VideoCourseSwiper/index.tsx new file mode 100644 index 00000000000..2356620562b --- /dev/null +++ b/app/[locale]/developers/_components/VideoCourseSwiper/index.tsx @@ -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) => ( + + {courses.map((course, idx) => ( + + + + ))} + +) + +export default VideoCourseSwiper diff --git a/app/[locale]/developers/_components/VideoCourseSwiper/lazy.tsx b/app/[locale]/developers/_components/VideoCourseSwiper/lazy.tsx new file mode 100644 index 00000000000..c960f08e647 --- /dev/null +++ b/app/[locale]/developers/_components/VideoCourseSwiper/lazy.tsx @@ -0,0 +1,5 @@ +import dynamic from "next/dynamic" + +import Loading from "./loading" + +export default dynamic(() => import("."), { ssr: false, loading: Loading }) diff --git a/app/[locale]/developers/_components/VideoCourseSwiper/loading.tsx b/app/[locale]/developers/_components/VideoCourseSwiper/loading.tsx new file mode 100644 index 00000000000..0ee31a4d461 --- /dev/null +++ b/app/[locale]/developers/_components/VideoCourseSwiper/loading.tsx @@ -0,0 +1,9 @@ +import { SkeletonCardGrid } from "@/components/ui/skeleton" + +const Loading = () => ( +
+ +
+) + +export default Loading diff --git a/app/[locale]/developers/learning-tools/page.tsx b/app/[locale]/developers/learning-tools/page.tsx index fe74c14fd72..cb645c3ef27 100644 --- a/app/[locale]/developers/learning-tools/page.tsx +++ b/app/[locale]/developers/learning-tools/page.tsx @@ -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"), }) } diff --git a/app/[locale]/developers/page.tsx b/app/[locale]/developers/page.tsx index b1c844144c0..bfc61028a56 100644 --- a/app/[locale]/developers/page.tsx +++ b/app/[locale]/developers/page.tsx @@ -1,11 +1,8 @@ -import { ReactNode } from "react" import { getTranslations } from "next-intl/server" -import { Lang } from "@/lib/types" +import type { Lang } from "@/lib/types" import { ChildOnlyProp } from "@/lib/types" -import CalloutSSR from "@/components/CalloutSSR" -import OldCard from "@/components/Card" import { CopyButton } from "@/components/CopyToClipboard" import FeedbackCard from "@/components/FeedbackCard" import HubHero from "@/components/Hero/HubHero" @@ -16,15 +13,27 @@ import { Card } from "@/components/ui/card" import { VStack } from "@/components/ui/flex" import Link from "@/components/ui/Link" import InlineLink from "@/components/ui/Link" +import { Section } from "@/components/ui/section" +import { cn } from "@/lib/utils/cn" import { getMetadata } from "@/lib/utils/metadata" - -import SpeedRunEthereumImage from "@/public/images/dev-tools/speed-run-ethereum-banner.png" -import DevelopersImage from "@/public/images/developers-eth-blocks.png" -import DogeImage from "@/public/images/doge-computer.png" -import HeroImage from "@/public/images/heroes/developers-hub-hero.jpg" - -const H2 = (props: ChildOnlyProp) =>

+import { screens } from "@/lib/utils/screen" + +import BuilderCard from "./_components/BuilderCard" +import BuilderSwiper from "./_components/BuilderSwiper/lazy" +import HackathonCard from "./_components/HackathonCard" +import HackathonSwiper from "./_components/HackathonSwiper/lazy" +import SpeedRunCard from "./_components/SpeedRunCard" +import VideoCourseCard from "./_components/VideoCourseCard" +import VideoCourseSwiper from "./_components/VideoCourseSwiper/lazy" +import { getBuilderPaths, getHackathons, getVideoCourses } from "./utils" + +import resourcesBanner from "@/public/images/developers/resources-banner.png" +import scaffoldDebugScreenshot from "@/public/images/developers/scaffold-debug-screenshot.png" +import stackExchangeScreenshot from "@/public/images/developers/stack-exchange-screenshot.png" +import tutorialTagsBanner from "@/public/images/developers/tutorial-tags-banner.png" +import dogeImage from "@/public/images/doge-computer.png" +import heroImage from "@/public/images/heroes/developers-hub-hero.jpg" const H3 = (props: ChildOnlyProp) =>

@@ -36,19 +45,20 @@ const Column = (props: ChildOnlyProp) => ( const RightColumn = (props: ChildOnlyProp) => (
) -const IntroColumn = (props: ChildOnlyProp) => ( -
-) -type DevelopersPath = { - emoji: string - title: ReactNode - description: ReactNode - url: string - button: ReactNode +const Scroller = ({ + className, + ...props +}: React.HTMLAttributes) => { + return ( +
+ ) } const DevelopersPage = async ({ @@ -66,41 +76,21 @@ const DevelopersPage = async ({ namespace: "common", }) - const paths: DevelopersPath[] = [ - { - emoji: ":woman_student:", - title: t("page-developers-learn"), - description: t("page-developers-learn-desc"), - url: "/developers/docs/", - button: t("page-developers-read-docs"), - }, - { - emoji: ":woman_teacher:", - title: t("page-developers-learn-tutorials"), - description: t("page-developers-learn-tutorials-desc"), - url: "/developers/tutorials/", - button: t("page-developers-learn-tutorials-cta"), - }, - { - emoji: ":woman_scientist:", - title: t("page-developers-resources"), - description: t("page-developers-start-desc"), - url: "/developers/learning-tools/", - button: t("page-developers-play-code"), - }, - { - emoji: ":construction_worker:", - title: t("page-developers-set-up"), - description: t("page-developers-setup-desc"), - url: "/developers/local-environment/", - button: t("page-developers-choose-stack"), - }, - ] + const paths = await getBuilderPaths() + const speedRunDetails = { + title: t("page-developers-start"), + description: t("page-developers-speedrunethereum-description"), + ctaLabel: t("page-developers-speedrunethereum-link"), + } + + const courses = await getVideoCourses() + + const hackathons = (await getHackathons()).slice(0, 5) return ( -

{t("page-developers-get-started")}

+
+

{t("page-developers-get-started")}

-
-
+

{t("page-developers-build-section-desc")}

+ {/* Desktop */} +
+ {paths.map((path, idx) => ( + + ))} + + +
+ + {/* Mobile */} +
+ +
+
+ +
+

+ {t("page-developers-resources-section-title")} +

+ + {/* Quickstart your idea */} + + Scaffold-ETH 2 debug screenshot +
+

{t("page-developers-jump-right-in-title")}

+

+ {t("page-developers-quickstart-scaffold-subtext")}{" "} + + {t("page-developers-quickstart-scaffold-docs")} + +

+
+
+ + npx create-eth@latest + + +
+ +
+ + Scaffold-ETH 2 llms-full.txt + +
+
+ + {/* Get help */} + SpeedRunEthereum banner -
-

{t("page-developers-start")}

-

{t("page-developers-speedrunethereum-description")}

+
+

{t("page-developers-get-help-title")}

+

+ {t("page-developers-get-help-desc")} +

+
+ +
- {t("page-developers-speedrunethereum-link")} + {t("page-developers-stack-exchange")} + {/* + {t("page-developers-ask-ai")} + */}
-
+
- -

{t("page-developers-jump-right-in-title")}

-
-
-

Scaffold-ETH 2

-

- {t("page-developers-quickstart-scaffold-subtext")}{" "} - - {t("page-developers-quickstart-scaffold-docs")} - -

-
- - npx create-eth@latest - - -
-
+ {/* Resources */} + + Banner showing four resource app icons +
+

{t("page-developers-resources-title")}

+

+ {t("page-developers-resources-desc")} +

+
+ + {t("page-developers-play-code")} + +
+
+ + {/* Tutorials */} + + Banner displaying multiple learning topics in a tag cloud
-

Need to learn the language?

- {t("page-developers-tutorials-title")}

+

+ {t("page-developers-tutorials-desc")} +

+ + +
+ - {t("page-developers-solidity-docs")} - + {t("page-developers-learn-tutorials-cta")} +
- - -
- {paths.map((path, idx) => ( - - {path.button} - - ))} -
- -
- -

{t("page-developers-about")}

-

- {t("page-developers-about-desc")} -

- {t("page-developers-about-desc-2")} - - {t("page-developers-feedback")}{" "} - - {t("page-developers-discord")} + + +
+

{t("page-developers-video-courses-title")}

+

{t("page-developers-video-courses-desc")}

+ + {/* DESKTOP */} + + {courses.map((course, idx) => ( + + ))} + + + {/* MOBILE */} +
+ +
+
+ +
+
+

{t("page-developers-explore-documentation")}

+

{t("page-developers-docs-section-desc")}

+
+ +
+ +

{t("page-developers-docs-introductions")}

+ + {t("page-developers-intro-eth-link")} + + {t("page-developers-into-eth-desc")} + + + {t("page-developers-intro-ether-link")} + + {t("page-developers-intro-ether-desc")} + + + {t("page-developers-intro-dapps-link")} + + {t("page-developers-intro-dapps-desc")} + + + {t("page-developers-intro-stack")} + + {t("page-developers-intro-stack-desc")} + + + {t("page-developers-web3-link")} + + {t("page-developers-web3-desc")} + + + {t("page-developers-languages")} + + {t("page-developers-language-desc")} + {t("page-assets-doge")} +
+ +

{t("page-developers-fundamentals")}

+ + {t("page-developers-accounts-link")} + + {t("page-developers-account-desc")} + + + {t("page-developers-transactions-link")} + + {t("page-developers-transactions-desc")} + + + {t("page-developers-blocks-link")} + + {t("page-developers-block-desc")} + + + {t("page-developers-evm-link")} + + {t("page-developers-evm-desc")} + + + {t("page-developers-gas-link")} - - - {t("page-developers-gas-desc")} + + + {t("page-developers-node-clients-link")} + + {t("page-developers-node-clients-desc")} + + + {t("page-developers-networks-link")} + + {t("page-developers-networks-desc")} +
+ +

{t("page-developers-stack")}

+ + {t("page-developers-smart-contracts-link")} + + {t("page-developers-smart-contracts-desc")} + + {t("page-developers-frameworks-link")} + + {t("page-developers-frameworks-desc")} + + {t("page-developers-js-libraries-link")} + + {t("page-developers-js-libraries-desc")} + + {t("page-developers-api-link")} + + {t("page-developers-api-desc")} + + {t("page-developers-block-explorers-link")} + + {t("page-developers-block-explorers-desc")} + + {t("page-developers-smart-contract-security-link")} + + {t("page-developers-smart-contract-security-desc")} + + {t("page-developers-storage-link")} + + {t("page-developers-storage-desc")} + + {t("page-developers-dev-env-link")} + + {t("page-developers-dev-env-desc")} +
+
+
+ +
+

{t("page-developers-hackathons-title")}

+

{t("page-developers-hackathons-desc")}

+ + {/* DESKTOP */} + + {hackathons.map((event, idx) => ( + + ))} + + {/* MOBILE */} +
+ +
+ +
+ + {t("page-developers-visit-ethglobal")} + +
+
+ +
+
-
- - {t("page-developers-contribute")} - +
+
+

{t("page-developers-founders-title")}

+

{t("page-developers-founders-desc")}

+
+
+ + {t("page-developers-get-in-touch")} + + + {t("page-developers-see-grant-options")} + +
- -
+
+
-
-
-

{t("page-developers-explore-documentation")}

-
- -
- -

{t("page-developers-docs-introductions")}

- - {t("page-developers-intro-eth-link")} - - {t("page-developers-into-eth-desc")} - - - {t("page-developers-intro-ether-link")} - - {t("page-developers-intro-ether-desc")} - - - {t("page-developers-intro-dapps-link")} - - {t("page-developers-intro-dapps-desc")} - - - {t("page-developers-intro-stack")} - - {t("page-developers-intro-stack-desc")} - - - {t("page-developers-web3-link")} - - {t("page-developers-web3-desc")} - - - {t("page-developers-languages")} - - {t("page-developers-language-desc")} - {t("page-assets-doge")} -
- -

{t("page-developers-fundamentals")}

- - {t("page-developers-accounts-link")} - - {t("page-developers-account-desc")} - - - {t("page-developers-transactions-link")} - - {t("page-developers-transactions-desc")} - - - {t("page-developers-blocks-link")} - - {t("page-developers-block-desc")} - - - {t("page-developers-evm-link")} - - {t("page-developers-evm-desc")} - - - {t("page-developers-gas-link")} - - {t("page-developers-gas-desc")} - - - {t("page-developers-node-clients-link")} - - {t("page-developers-node-clients-desc")} - - - {t("page-developers-networks-link")} - - {t("page-developers-networks-desc")} - - - {t("page-developers-mining-link")} - - {t("page-developers-mining-desc")} - - - {t("page-developers-mining-algorithms-link")} - - {t("page-developers-mining-algorithms-desc")} -
- -

{t("page-developers-stack")}

- - {t("page-developers-smart-contracts-link")} - - {t("page-developers-smart-contracts-desc")} - - {t("page-developers-frameworks-link")} - - {t("page-developers-frameworks-desc")} - - {t("page-developers-js-libraries-link")} - - {t("page-developers-js-libraries-desc")} - - {t("page-developers-api-link")} - - {t("page-developers-api-desc")} - - {t("page-developers-block-explorers-link")} - - {t("page-developers-block-explorers-desc")} - - {t("page-developers-smart-contract-security-link")} - - {t("page-developers-smart-contract-security-desc")} - - {t("page-developers-storage-link")} - - {t("page-developers-storage-desc")} - - {t("page-developers-dev-env-link")} - - {t("page-developers-dev-env-desc")} -

{t("page-developers-advanced")}

- - {t("page-developers-token-standards-link")} - - {t("page-developers-token-standards-desc")} - - {t("page-developers-mev-link")} - - {t("page-developers-mev-desc")} - - {t("page-developers-oracles-link")} - - {t("page-developers-oracle-desc")} - - {t("page-developers-scaling-link")} - - {t("page-developers-scaling-desc")} - - {t("page-developers-networking-layer-link")} - - {t("page-developers-networking-layer-desc")} - - {t("page-developers-data-structures-and-encoding-link")} - - - {t("page-developers-data-structures-and-encoding-desc")} - -
-
-
) diff --git a/app/[locale]/developers/types.ts b/app/[locale]/developers/types.ts new file mode 100644 index 00000000000..1835d6bd692 --- /dev/null +++ b/app/[locale]/developers/types.ts @@ -0,0 +1,19 @@ +import type { StaticImageData } from "next/image" +import type { ReactNode } from "react" + +type CardInfo = { + imgSrc: StaticImageData + imgAlt: string + title: string + description: ReactNode + href: string +} + +export type DevelopersPath = CardInfo & { + button: ReactNode + tag: string +} + +export type VideoCourse = CardInfo & { + hours: ReactNode +} diff --git a/app/[locale]/developers/utils.tsx b/app/[locale]/developers/utils.tsx new file mode 100644 index 00000000000..8825fa9132a --- /dev/null +++ b/app/[locale]/developers/utils.tsx @@ -0,0 +1,118 @@ +import { getLocale, getTranslations } from "next-intl/server" + +import { CommunityConference } from "@/lib/types" + +import events from "@/data/community-events.json" + +import { getUpcomingEvents } from "../utils" + +import type { DevelopersPath, VideoCourse } from "./types" + +import cyfrinBasicBanner from "@/public/images/developers/cyfrin-basic-banner.webp" +import cyfrinFoundryAdvancedBanner from "@/public/images/developers/cyfrin-foundry-advanced-banner.webp" +import cyfrinFoundryFundamentalsBanner from "@/public/images/developers/cyfrin-foundry-fundamentals-banner.webp" +import cyfrinSecurityBanner from "@/public/images/developers/cyfrin-security-banner.webp" +import cyfrinSolidityBanner from "@/public/images/developers/cyfrin-solidity-banner.webp" +import speedrunNFT from "@/public/images/developers/speedrun-nft.png" +import speedrunStakingApp from "@/public/images/developers/speedrun-staking-app.png" +import speedrunTokenVendor from "@/public/images/developers/speedrun-token-vendor.png" + +export const getBuilderPaths = async (): Promise => { + const locale = await getLocale() + const t = await getTranslations({ + locale, + namespace: "page-developers-index", + }) + + return [ + { + imgSrc: speedrunNFT, + imgAlt: t("page-developers-speedrun-nft-alt"), + title: t("page-developers-speedrun-nft-title"), + description: t("page-developers-speedrun-nft-desc"), + href: "https://speedrunethereum.com/challenge/simple-nft-example", + button: t("page-developers-start-quest"), + tag: t("page-developers-speedrun-challenge-0"), + }, + { + imgSrc: speedrunStakingApp, + imgAlt: t("page-developers-speedrun-staking-alt"), + title: t("page-developers-speedrun-staking-title"), + description: t("page-developers-speedrun-staking-desc"), + href: "https://speedrunethereum.com/challenge/decentralized-staking", + button: t("page-developers-start-quest"), + tag: t("page-developers-speedrun-challenge-1"), + }, + { + imgSrc: speedrunTokenVendor, + imgAlt: t("page-developers-speedrun-token-alt"), + title: t("page-developers-speedrun-token-title"), + description: t("page-developers-speedrun-token-desc"), + href: "https://speedrunethereum.com/challenge/token-vendor", + button: t("page-developers-start-quest"), + tag: t("page-developers-speedrun-challenge-2"), + }, + ] +} + +export const getVideoCourses = async (): Promise => { + const locale = await getLocale() + const t = await getTranslations({ + locale, + namespace: "page-developers-index", + }) + + const getDuration = (hours: number) => + t.rich("page-developers-course-duration", { + span: () => {hours}, + }) + + return [ + { + title: t("page-developers-course-blockchain-basics-title"), + description: t("page-developers-course-blockchain-basics-desc"), + hours: getDuration(3), + imgSrc: cyfrinBasicBanner, + imgAlt: t("page-developers-course-blockchain-basics-alt"), + href: "https://updraft.cyfrin.io/courses/blockchain-basics", + }, + { + title: t("page-developers-course-solidity-title"), + description: t("page-developers-course-solidity-desc"), + hours: getDuration(5), + imgSrc: cyfrinSolidityBanner, + imgAlt: t("page-developers-course-solidity-alt"), + href: "https://updraft.cyfrin.io/courses/solidity", + }, + { + title: t("page-developers-course-foundry-fundamentals-title"), + description: t("page-developers-course-foundry-fundamentals-desc"), + hours: getDuration(10), + imgSrc: cyfrinFoundryFundamentalsBanner, + imgAlt: t("page-developers-course-foundry-fundamentals-alt"), + href: "https://updraft.cyfrin.io/courses/foundry", + }, + { + title: t("page-developers-course-advanced-foundry-title"), + description: t("page-developers-course-advanced-foundry-desc"), + hours: getDuration(13), + imgSrc: cyfrinFoundryAdvancedBanner, + imgAlt: t("page-developers-course-advanced-foundry-alt"), + href: "https://updraft.cyfrin.io/courses/advanced-foundry", + }, + { + title: t("page-developers-course-security-title"), + description: t("page-developers-course-security-desc"), + hours: getDuration(24), + imgSrc: cyfrinSecurityBanner, + imgAlt: t("page-developers-course-security-alt"), + href: "https://updraft.cyfrin.io/courses/security", + }, + ] +} + +export const getHackathons = async (): Promise => { + const locale = await getLocale() + const allUpcomingEvents = getUpcomingEvents(events, locale) + return allUpcomingEvents.filter((e) => e.hackathon) as CommunityConference[] +} diff --git a/app/[locale]/page.tsx b/app/[locale]/page.tsx index 606fe0ca3fc..b76223e2aa2 100644 --- a/app/[locale]/page.tsx +++ b/app/[locale]/page.tsx @@ -8,7 +8,6 @@ import type { CommunityBlog, ValuesPairing, } from "@/lib/types" -import type { EventCardProps } from "@/lib/types" import type { Lang } from "@/lib/types" import { CodeExample } from "@/lib/interfaces" @@ -82,7 +81,7 @@ import { } from "@/lib/constants" import TenYearHomeBanner from "./10years/_components/TenYearHomeBanner" -import { getActivity } from "./utils" +import { getActivity, getUpcomingEvents } from "./utils" import SimpleDomainRegistryContent from "!!raw-loader!@/data/SimpleDomainRegistry.sol" import SimpleTokenContent from "!!raw-loader!@/data/SimpleToken.sol" @@ -402,18 +401,8 @@ const Page = async ({ params }: { params: Promise<{ locale: Lang }> }) => { }, ] - const upcomingEvents = events - .filter((event) => { - const isValid = isValidDate(event.endDate) - const beginningOfEndDate = new Date(event.endDate).getTime() - const endOfEndDate = beginningOfEndDate + 24 * 60 * 60 * 1000 - const isUpcoming = endOfEndDate >= new Date().getTime() - return isValid && isUpcoming - }) - .sort( - (a, b) => new Date(a.endDate).getTime() - new Date(b.endDate).getTime() - ) - .slice(0, 3) as EventCardProps[] // Show 3 events ending soonest + const allUpcomingEvents = getUpcomingEvents(events, locale) + const upcomingEvents = allUpcomingEvents.slice(0, 3) const metricResults: AllHomepageActivityData = { ethPrice, @@ -906,9 +895,9 @@ const Page = async ({ params }: { params: Promise<{ locale: Lang }> }) => { className="max-w-full object-cover object-center" /> ) : ( - + )} - + {title} diff --git a/app/[locale]/utils.ts b/app/[locale]/utils.ts index 0e460245aef..9cf747f3a01 100644 --- a/app/[locale]/utils.ts +++ b/app/[locale]/utils.ts @@ -5,10 +5,18 @@ import { getTranslations } from "next-intl/server" -import type { AllHomepageActivityData, Lang, StatsBoxMetric } from "@/lib/types" +import type { + AllHomepageActivityData, + CommunityConference, + Lang, + StatsBoxMetric, +} from "@/lib/types" +import { isValidDate } from "@/lib/utils/date" import { getLocaleForNumberFormat } from "@/lib/utils/translations" +import { DEFAULT_LOCALE } from "@/lib/constants" + const formatLargeUSD = (value: number, locale: string): string => { return new Intl.NumberFormat(locale, { style: "currency", @@ -124,3 +132,38 @@ export const getActivity = async ( return metrics } + +export const getUpcomingEvents = ( + events: CommunityConference[], + locale = DEFAULT_LOCALE +): CommunityConference[] => + events + .filter((event) => { + const isValid = isValidDate(event.endDate) + const beginningOfEndDate = new Date(event.endDate).getTime() + const endOfEndDate = beginningOfEndDate + 24 * 60 * 60 * 1000 + const isUpcoming = endOfEndDate >= new Date().getTime() + return isValid && isUpcoming + }) + .sort( + (a, b) => new Date(a.endDate).getTime() - new Date(b.endDate).getTime() + ) + .map(({ startDate, endDate, ...event }) => { + const formattedDate = + isValidDate(startDate) || isValidDate(endDate) + ? new Intl.DateTimeFormat(locale, { + month: "long", + day: "numeric", + year: "numeric", + }).formatRange( + new Date(isValidDate(startDate) ? startDate : endDate), + new Date(isValidDate(endDate) ? endDate : startDate) + ) + : "" + return { + ...event, + startDate, + endDate, + formattedDate, + } + }) diff --git a/public/images/developers/cyfrin-basic-banner.webp b/public/images/developers/cyfrin-basic-banner.webp new file mode 100644 index 00000000000..bb2ce75ead2 Binary files /dev/null and b/public/images/developers/cyfrin-basic-banner.webp differ diff --git a/public/images/developers/cyfrin-foundry-advanced-banner.webp b/public/images/developers/cyfrin-foundry-advanced-banner.webp new file mode 100644 index 00000000000..e41e3c6ebb6 Binary files /dev/null and b/public/images/developers/cyfrin-foundry-advanced-banner.webp differ diff --git a/public/images/developers/cyfrin-foundry-fundamentals-banner.webp b/public/images/developers/cyfrin-foundry-fundamentals-banner.webp new file mode 100644 index 00000000000..cc7a639a382 Binary files /dev/null and b/public/images/developers/cyfrin-foundry-fundamentals-banner.webp differ diff --git a/public/images/developers/cyfrin-security-banner.webp b/public/images/developers/cyfrin-security-banner.webp new file mode 100644 index 00000000000..285e0cd52c2 Binary files /dev/null and b/public/images/developers/cyfrin-security-banner.webp differ diff --git a/public/images/developers/cyfrin-solidity-banner.webp b/public/images/developers/cyfrin-solidity-banner.webp new file mode 100644 index 00000000000..fbf25ee9ff4 Binary files /dev/null and b/public/images/developers/cyfrin-solidity-banner.webp differ diff --git a/public/images/developers/resources-banner.png b/public/images/developers/resources-banner.png new file mode 100644 index 00000000000..876d481c2fb Binary files /dev/null and b/public/images/developers/resources-banner.png differ diff --git a/public/images/developers/scaffold-debug-screenshot.png b/public/images/developers/scaffold-debug-screenshot.png new file mode 100644 index 00000000000..95b51acd7eb Binary files /dev/null and b/public/images/developers/scaffold-debug-screenshot.png differ diff --git a/public/images/developers/speedrun-nft.png b/public/images/developers/speedrun-nft.png new file mode 100644 index 00000000000..db1a1449784 Binary files /dev/null and b/public/images/developers/speedrun-nft.png differ diff --git a/public/images/developers/speedrun-staking-app.png b/public/images/developers/speedrun-staking-app.png new file mode 100644 index 00000000000..4cb32704135 Binary files /dev/null and b/public/images/developers/speedrun-staking-app.png differ diff --git a/public/images/developers/speedrun-token-vendor.png b/public/images/developers/speedrun-token-vendor.png new file mode 100644 index 00000000000..f65bfbcd806 Binary files /dev/null and b/public/images/developers/speedrun-token-vendor.png differ diff --git a/public/images/developers/stack-exchange-screenshot.png b/public/images/developers/stack-exchange-screenshot.png new file mode 100644 index 00000000000..2fe821a2f55 Binary files /dev/null and b/public/images/developers/stack-exchange-screenshot.png differ diff --git a/public/images/developers/tutorial-tags-banner.png b/public/images/developers/tutorial-tags-banner.png new file mode 100644 index 00000000000..cb741092143 Binary files /dev/null and b/public/images/developers/tutorial-tags-banner.png differ diff --git a/src/components/EventCard.tsx b/src/components/EventCard.tsx index 2d8bd410946..324da97e00d 100644 --- a/src/components/EventCard.tsx +++ b/src/components/EventCard.tsx @@ -52,7 +52,7 @@ const EventCard: React.FC = ({ className="max-h-[224px] w-full object-cover xl:h-[124px]" /> ) : ( - + )}
diff --git a/src/components/ui/skeleton.tsx b/src/components/ui/skeleton.tsx index 4e7f72626e3..ea2eec850a6 100644 --- a/src/components/ui/skeleton.tsx +++ b/src/components/ui/skeleton.tsx @@ -4,7 +4,7 @@ import { Card, CardBanner, CardContent } from "../ui/card" // Pseudo-random list of skeleton widths for multiple lines const widths = [ - "w-1/3", + "w-2/3", "w-1/5", "w-4", "w-1/4", diff --git a/src/data/community-events.json b/src/data/community-events.json index 463bc90e68d..eeeb76531c0 100644 --- a/src/data/community-events.json +++ b/src/data/community-events.json @@ -15,7 +15,8 @@ "href": "https://ethglobal.com/events/pragma-newyork2025", "location": "New York, NYC, USA", "description": "Bringing developers onchain to build the future of the internet.", - "imageUrl": "https://ethglobal.com/og.png" + "imageUrl": "https://ethglobal.com/og.png", + "hackathon": true }, { "title": "SBC (The Science of Blockchain Conference 2025)", @@ -33,7 +34,8 @@ "href": "https://ethglobal.com/events/newyork2025", "location": "New York, NYC, USA", "description": "Bringing developers onchain to build the future of the internet.", - "imageUrl": "https://ethglobal.com/og.png" + "imageUrl": "https://ethglobal.com/og.png", + "hackathon": true }, { "title": "ProdFest Jos", @@ -87,7 +89,8 @@ "href": "https://ethglobal.com/events/pragma-newdelhi", "location": "New Delhi, IND", "description": "Bringing developers onchain to build the future of the internet.", - "imageUrl": "https://ethglobal.com/og.png" + "imageUrl": "https://ethglobal.com/og.png", + "hackathon": true }, { "title": "ETHGlobal New Delhi", @@ -96,7 +99,8 @@ "href": "https://ethglobal.com/events/newdelhi", "location": "New Delhi, IND", "description": "Bringing developers onchain to build the future of the internet.", - "imageUrl": "https://ethglobal.com/og.png" + "imageUrl": "https://ethglobal.com/og.png", + "hackathon": true }, { "title": "EthAccra", @@ -123,7 +127,8 @@ "href": "https://ethsafari.xyz/", "location": "Nairobi, Kenya", "description": "ETHSafari 2025 - web3 builders conference East Africa Kenya", - "imageUrl": "https://ethsafari.xyz/_next/image?url=%2FHackathon.png&w=640&q=75" + "imageUrl": "https://ethsafari.xyz/_next/image?url=%2FHackathon.png&w=640&q=75", + "hackathon": true }, { "title": "ETH Boston", @@ -168,7 +173,8 @@ "href": "https://ethistanbul.io/", "location": "Istanbul, TR", "description": "ETHIstanbul is a conference and hackathon connecting you with global talents, industry professionals, and web3 companies advancing technology.", - "imageUrl": "https://ethistanbul.io/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fistanbul-background.99d6ad2a.webp&w=3840&q=75" + "imageUrl": "https://ethistanbul.io/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fistanbul-background.99d6ad2a.webp&w=3840&q=75", + "hackathon": true }, { "title": "ETHSofia", diff --git a/src/intl/en/page-developers-index.json b/src/intl/en/page-developers-index.json index 524d5fb7694..1595981a3f5 100644 --- a/src/intl/en/page-developers-index.json +++ b/src/intl/en/page-developers-index.json @@ -1,36 +1,25 @@ { "page-developer-meta-title": "Ethereum Developer Resources", - "page-developers-about": "About these developer resources", - "page-developers-about-desc": "ethereum.org is here to help you build with Ethereum with documentation on foundational concepts as well as the development stack. Plus there are tutorials to get you up and running.", - "page-developers-about-desc-2": "Inspired by the Mozilla Developer Network, we thought Ethereum needed a place to house great developer content and resources. Like our friends at Mozilla, everything here is open-source and ready for you to extend and improve.", "page-developers-account-desc": "Contracts or people on the network", "page-developers-accounts-link": "Accounts", - "page-developers-advanced": "Advanced", "page-developers-api-desc": "Using libraries to interact with smart contracts", "page-developers-api-link": "Backend APIs", "page-developers-block-desc": "Batches of transactions added to the blockchain", "page-developers-block-explorers-desc": "Your portal to Ethereum data", "page-developers-block-explorers-link": "Block explorers", "page-developers-blocks-link": "Blocks", - "page-developers-browse-tutorials": "Browse tutorials", - "page-developers-choose-stack": "Choose your stack", - "page-developers-contribute": "Contribute", "page-developers-dev-env-desc": "IDEs that are suitable for dapp development", "page-developers-dev-env-link": "Development environments", - "page-developers-discord": "Join Discord", "page-developers-docs-introductions": "Introductions", "page-developers-evm-desc": "The computer that processes transactions", "page-developers-evm-link": "The Ethereum virtual machine (EVM)", "page-developers-explore-documentation": "Explore the documentation", - "page-developers-feedback": "If you have any feedback, reach out to us via a GitHub issue or on our Discord server.", "page-developers-frameworks-desc": "Tools for helping speed up development", "page-developers-frameworks-link": "Development frameworks", "page-developers-fundamentals": "Fundamentals", "page-developers-gas-desc": "Ether needed to power transactions", "page-developers-gas-link": "Gas", - "page-developers-get-started": "Experiment with Ethereum", - "page-developers-improve-ethereum": "Help us make ethereum.org better", - "page-developers-improve-ethereum-desc": "Like ethereum.org, these docs are a community effort. Create a PR if you see mistakes, room for improvement, or new opportunities to help Ethereum developers.", + "page-developers-get-started": "What do you want to build today?", "page-developers-into-eth-desc": "An introduction to blockchain and Ethereum", "page-developers-intro-ether-desc": "An introduction to cryptocurrency and Ether", "page-developers-intro-dapps-desc": "An introduction to decentralized applications", @@ -50,46 +39,32 @@ "page-developers-learn-tutorials-cta": "View tutorials", "page-developers-learn-tutorials-desc": "Learn Ethereum development step-by-step from builders who have already done it.", "page-developers-meta-desc": "Documentation, tutorials, and tools for developers building on Ethereum.", - "page-developers-mev-desc": "An introduction to maximal extractable value (MEV)", - "page-developers-mev-link": "Maximal extractable value (MEV)", - "page-developers-mining-desc": "How new blocks are created and consensus was reached using proof-of-work", - "page-developers-mining-link": "Mining", - "page-developers-mining-algorithms-desc": "Information on Ethereum's mining algorithms", - "page-developers-mining-algorithms-link": "Mining algorithms", "page-developers-networks-desc": "An overview of Mainnet and the test networks", "page-developers-networks-link": "Networks", "page-developers-node-clients-desc": "How blocks and transactions are verified in the network", "page-developers-node-clients-link": "Nodes and clients", - "page-developers-oracle-desc": "Getting offchain data into your smart contracts", - "page-developers-oracles-link": "Oracles", "page-developers-play-code": "Play with code", "page-developers-quickstart-scaffold-subtext": "Bootstrap your Ethereum app stack in seconds.", - "page-developers-quickstart-scaffold-docs": "Read Scaffold-ETH 2 docs", + "page-developers-quickstart-scaffold-docs": "Read Scaffold-ETH 2", "page-developers-read-docs": "Read the docs", + "page-developers-start-quest": "Start quest", "page-developers-resources": "Resources", - "page-developers-scaling-desc": "Solutions for faster transactions", - "page-developers-scaling-link": "Scaling", "page-developers-smart-contract-security-desc": "Security measures to consider during development of smart contracts", "page-developers-smart-contract-security-link": "Smart contract security", - "page-developers-set-up": "Set up local environment", - "page-developers-setup-desc": "Get your stack ready for building by configuring a development environment.", "page-developers-smart-contracts-desc": "The logic behind dapps – self-executing agreements", "page-developers-smart-contracts-link": "Smart contracts", "page-developers-solidity-docs": "Read the Solidity docs", "page-developers-speedrunethereum-title": "Learn all the most important concepts by building on Ethereum", - "page-developers-speedrunethereum-description": "Hands-on challenges such as building NFTs, DEXs in a step-by-step tutorial series.", + "page-developers-speedrunethereum-description": "Receive mentorship from others, and learn how to collaborate with fellow developers.", "page-developers-speedrunethereum-link": "SpeedRun Ethereum", "page-developers-stack": "The stack", - "page-developers-start": "Start with guided challenges", - "page-developers-start-desc": "Want to experiment first, ask questions later?", + "page-developers-start": "Challenges and mentorship", "page-developers-storage-desc": "How to handle dapp storage", "page-developers-storage-link": "Storage", - "page-developers-subtitle": "A builders manual for Ethereum. By builders, for builders.", + "page-developers-subtitle": "A builders manual for Ethereum. Everything you need to build and scale your onchain app.", "page-developers-title-1": "Ethereum", "page-developers-title-2": "developer", "page-developers-title-3": "resources", - "page-developers-token-standards-desc": "An overview of accepted token standards", - "page-developers-token-standards-link": "Token standards", "page-developers-transactions-desc": "The way Ethereum state changes", "page-developers-transactions-link": "Transactions", "page-developers-web3-desc": "How the web3 world of development is different", @@ -101,5 +76,53 @@ "page-developers-data-structures-and-encoding-link": "Data structures and encoding", "page-developers-data-structures-and-encoding-desc": "Introduction to the data structures and encoding schema used in the Ethereum stack", "alt-eth-blocks": "Illustration of blocks being organized like an ETH symbol", - "page-assets-doge": "Doge using dapps" + "page-assets-doge": "Doge using dapps", + "page-developers-build-section-desc": "Everything you need to learn and build your first apps on Ethereum", + "page-developers-resources-section-title": "Helpful developer resources", + "page-developers-get-help-title": "Get help", + "page-developers-get-help-desc": "If you are stuck or need help solving problems, be sure to ask for guidance.", + "page-developers-stack-exchange": "Stack Exchange", + "page-developers-ask-ai": "Ask AI", + "page-developers-resources-title": "Resources", + "page-developers-resources-desc": "Want to experiment first, ask questions later? Check sandboxes, bootcamps etc.", + "page-developers-tutorials-title": "Tutorials", + "page-developers-tutorials-desc": "Learn Ethereum development step-by-step from builders who have already done it.", + "page-developers-video-courses-title": "Video courses", + "page-developers-video-courses-desc": "Want to kickstart your professional career in blockchain? These courses will prepare you to get hired as blockchain developer.", + "page-developers-docs-section-desc": "Understand the core concepts of Ethereum and blockchains", + "page-developers-hackathons-title": "Join hackathons", + "page-developers-hackathons-desc": "Hackathons are great opportunities to network and learn from others as well as start projects and earn prizes", + "page-developers-visit-ethglobal": "Visit EthGlobal", + "page-developers-founders-title": "Are you a founder?", + "page-developers-founders-desc": "Have a project idea already or working on a prototype? Explore how to take your project to the next step. We can connect you with relevant organizations and experts in the field.", + "page-developers-get-in-touch": "Get in touch", + "page-developers-see-grant-options": "See grant options", + "page-developers-speedrun-nft-alt": "Speedrun Ethereum NFT banner", + "page-developers-speedrun-nft-title": "Simple NFT Example", + "page-developers-speedrun-nft-desc": "Create a public NFT to learn the basics of scaffold-eth.", + "page-developers-speedrun-challenge-0": "Challenge #0", + "page-developers-speedrun-staking-alt": "Speedrun Ethereum staking app banner", + "page-developers-speedrun-staking-title": "Staking App", + "page-developers-speedrun-staking-desc": "Write a smart contract where users pool funds together.", + "page-developers-speedrun-challenge-1": "Challenge #1", + "page-developers-speedrun-token-alt": "Speedrun Ethereum token vendor project banner", + "page-developers-speedrun-token-title": "Create a token", + "page-developers-speedrun-token-desc": "Build a digital currency and a smart contract that trades it.", + "page-developers-speedrun-challenge-2": "Challenge #2", + "page-developers-course-duration": "-hour course", + "page-developers-course-blockchain-basics-title": "Blockchain basics", + "page-developers-course-blockchain-basics-desc": "Learn how blockchains and smart contracts work, create a wallet, and sign your first transaction.", + "page-developers-course-blockchain-basics-alt": "Cyfrin Updraft Blockchain basics course banner", + "page-developers-course-solidity-title": "Solidity smart contract development", + "page-developers-course-solidity-desc": "Solidity Programming is your gateway to web3 development in Ethereum compatible ecosystems.", + "page-developers-course-solidity-alt": "Cyfrin Updraft Solidity smart contract development course banner", + "page-developers-course-foundry-fundamentals-title": "Foundry fundamentals", + "page-developers-course-foundry-fundamentals-desc": "Level up your Solidity development skills with Foundry and advanced web3 development concepts and tools.", + "page-developers-course-foundry-fundamentals-alt": "Cyfrin Updraft Foundry fundamentals course banner", + "page-developers-course-advanced-foundry-title": "Advanced foundry", + "page-developers-course-advanced-foundry-desc": "Master web3 development techniques with Advanced Foundry for Solidity smart contract development.", + "page-developers-course-advanced-foundry-alt": "Cyfrin Updraft Advanced foundry course banner", + "page-developers-course-security-title": "Smart contract security", + "page-developers-course-security-desc": "Start your career as a smart contract security researcher! Learn smart contract auditing and the best practices.", + "page-developers-course-security-alt": "Cyfrin Updraft Blockchain basics course banner" } diff --git a/src/lib/types.ts b/src/lib/types.ts index f86c3e08e9f..868dfbc0e17 100644 --- a/src/lib/types.ts +++ b/src/lib/types.ts @@ -609,6 +609,8 @@ export type CommunityConference = { startDate: string endDate: string imageUrl: string + hackathon?: boolean + formattedDate?: string } // Chains diff --git a/src/styles/semantic-tokens.css b/src/styles/semantic-tokens.css index 2ecc4b39c38..e76d818472d 100644 --- a/src/styles/semantic-tokens.css +++ b/src/styles/semantic-tokens.css @@ -97,6 +97,16 @@ --card-gradient-secondary-hover: linear-gradient(95deg, rgba(211, 145, 242, 0.2) 0%, rgba(159, 43, 212, 0.2) 102.78%); --ten-year-gradient: linear-gradient(100deg, #F6C9EA 55.38%, #C7A9F1 110.54%); + /* Rainbow gradients */ + --rainbow-gradient: conic-gradient( + from 0deg, + hsla(var(--primary)), + hsla(var(--accent-b)), + hsla(var(--accent-a)), + hsla(var(--accent-c)), + hsla(var(--primary)) + ); + /* Shadows */ --shadow-color-a: hsla(var(--purple-800), 0.02); --shadow-color-b: hsla(var(--red-800), 0.04); diff --git a/tailwind.config.ts b/tailwind.config.ts index 8e6e4cef472..894005e3fb4 100644 --- a/tailwind.config.ts +++ b/tailwind.config.ts @@ -237,6 +237,7 @@ const config = { "card-gradient-secondary": "var(--card-gradient-secondary)", "card-gradient-secondary-hover": "var(--card-gradient-secondary-hover)", "ten-year-gradient": "var(--ten-year-gradient)", + "rainbow-gradient": "var(--rainbow-gradient)", }, boxShadow: { "table-box": "var(--table-box-shadow)", @@ -306,6 +307,12 @@ const config = { "0%": { opacity: "0" }, "100%": { opacity: "1" }, }, + "rotate-back-and-forth": { + "0%": { transform: "rotate(0deg)" }, + "25%": { transform: "rotate(5deg)" }, + "75%": { transform: "rotate(-5deg)" }, + "100%": { transform: "rotate(0deg)" }, + }, }, animation: { "accordion-down": "accordion-down 0.2s ease-out", @@ -320,9 +327,11 @@ const config = { "spin-18": "spin 36s linear infinite", "counter-spin-18": "spin 36s linear infinite reverse", "spin-9": "spin 18s linear infinite", + "spin-4": "spin 4s linear infinite", "counter-spin-9": "spin 18s linear infinite reverse", "pulse-light": "pulse-light 2s cubic-bezier(0.4, 0, 0.6, 1) infinite", "fade-in": "fade-in 150ms ease-in-out", + wave: "rotate-back-and-forth 1s linear infinite", }, // Add custom border-radius tailwinds extension for "4xl" as "2rem" borderRadius: {