From 9c9e9c642a7d9388a9f5e250a05dcb636fce06cd Mon Sep 17 00:00:00 2001 From: Kalidou Diagne Date: Mon, 11 Aug 2025 20:23:46 +0200 Subject: [PATCH] feat: homepage updates (#541) * homepage updates --- .github/workflows/claude.yml | 2 +- app/(pages)/about/page.tsx | 214 ++++++++++-------- app/(pages)/page.tsx | 26 ++- app/(pages)/projects/[id]/page.tsx | 2 +- app/(pages)/projects/page.tsx | 32 +-- .../projects/sections/ProjectContent.tsx | 27 ++- app/(pages)/research/page.tsx | 39 +++- app/labels.ts | 27 ++- app/layout.tsx | 10 +- app/not-found.tsx | 9 +- components/app-link.tsx | 10 +- components/banner.tsx | 17 +- components/blog/article-in-evidance-card.tsx | 6 +- components/blog/blog-recent-articles.tsx | 122 +++++----- components/blog/project-blog-articles.tsx | 4 +- components/cards/wiki-card.tsx | 12 +- components/icons.tsx | 2 +- components/main-nav.tsx | 4 +- components/project/project-card.tsx | 2 +- components/project/project-filters-bar.tsx | 6 +- components/project/project-list.tsx | 4 +- components/research/research-card.tsx | 2 +- components/sections/HomepageHeader.tsx | 70 ------ components/sections/HomepageVideoFeed.tsx | 22 +- .../sections/{WhatWeDo.tsx => OurWork.tsx} | 39 ++-- components/sections/ParallaxHero.tsx | 115 ++++++++++ components/site-footer.tsx | 37 ++- components/site-header-mobile.tsx | 24 +- components/ui/button.tsx | 17 +- components/ui/markdown.tsx | 14 +- .../articles/pse-august-2025-newsletter.md | 12 +- .../the-case-for-privacy-in-dao-voting.md | 13 +- globals.css | 2 +- hooks/useGetProjectRelatedArticles.ts | 2 +- public/hero/hero-dark-mode-mobile.jpg | Bin 0 -> 29378 bytes public/hero/hero-dark-mode.jpg | Bin 0 -> 609486 bytes public/hero/hero-mobile.jpg | Bin 0 -> 20117 bytes public/hero/hero.jpg | Bin 0 -> 177571 bytes public/icons/archstar.webp | Bin 509238 -> 0 bytes public/og-image.png | Bin 760651 -> 0 bytes public/share-image.png | Bin 0 -> 424796 bytes tailwind.config.js | 3 + tests/api/search-indexes.test.ts | 2 +- tests/api/youtube.test.ts | 2 +- tests/setup.tsx | 1 - tests/test-utils.tsx | 5 +- 46 files changed, 546 insertions(+), 413 deletions(-) delete mode 100644 components/sections/HomepageHeader.tsx rename components/sections/{WhatWeDo.tsx => OurWork.tsx} (56%) create mode 100644 components/sections/ParallaxHero.tsx create mode 100644 public/hero/hero-dark-mode-mobile.jpg create mode 100644 public/hero/hero-dark-mode.jpg create mode 100644 public/hero/hero-mobile.jpg create mode 100644 public/hero/hero.jpg delete mode 100644 public/icons/archstar.webp delete mode 100644 public/og-image.png create mode 100644 public/share-image.png diff --git a/.github/workflows/claude.yml b/.github/workflows/claude.yml index cec0364..36fd74f 100644 --- a/.github/workflows/claude.yml +++ b/.github/workflows/claude.yml @@ -49,4 +49,4 @@ jobs: uses: anthropics/claude-code-action@beta with: anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }} - timeout_minutes: "60" \ No newline at end of file + timeout_minutes: "60" diff --git a/app/(pages)/about/page.tsx b/app/(pages)/about/page.tsx index 94753fc..1ff1e5a 100644 --- a/app/(pages)/about/page.tsx +++ b/app/(pages)/about/page.tsx @@ -1,9 +1,7 @@ -import { AppContent } from "@/components/ui/app-content" - -import { Metadata } from "next" -import { HomepageBanner } from "@/components/sections/HomepageBanner" -import { Divider } from "@/components/divider" import { AppLink } from "@/components/app-link" +import { HomepageBanner } from "@/components/sections/HomepageBanner" +import { AppContent } from "@/components/ui/app-content" +import { Metadata } from "next" export const metadata: Metadata = { title: "About", @@ -11,7 +9,7 @@ export const metadata: Metadata = { } export default async function AboutPage() { - const OurWorkItems = [ + const WhatWeDoItems = [ { label: "Incubation", description: @@ -30,96 +28,128 @@ export default async function AboutPage() { ] return ( - -
- -
-

- Our Mission -

- - As Privacy Stewards of Ethereum (PSE), our mission is to deliver - privacy to the{" "} - - Ethereum ecosystem - - . We envision a future where privacy on Ethereum is the norm - rather than the exception. -

- Building{" "} - - “an open society in the electronic age” - {" "} - { - "requires privacy that is usable, scalable, and secure. We are a team of applied cryptographers, mathematicians, developers, designers, and coordinators working to embed programmable cryptography into Ethereum's application layer and make privacy accessible to individuals, developers, and institutions." - }{" "} -

- Privacy is a cornerstone of freedom, safety, and is an{" "} - - important guarantor for decentralization. - {" "} - {`We're building a future where digital infrastructure respects - privacy by default, and permissions are purpose-specific, - informed, uncoerced, and revocable.`} -

- {`Programmable cryptography unlocks transformative capabilities for - digital commerce, identity, governance, and other systems of - coordination. But the road to privacy isn't only technical. It - requires shifts in user behavior, developer priorities, regulatory - frameworks, and cultural norms. This is a collective challenge and - we`}{" "} - - invite you - {" "} - to help us shape a more free digital future. -
-
- -
-

- Our Work -

-
- {OurWorkItems?.map((item, index) => ( -
-
-
- {item.label} -
-

- {item.description} -

-
-
- ))} + <> +
+
+ +
+
+

+ Our Mission +

+ + As Privacy Stewards of Ethereum (PSE), our mission is to + deliver privacy to the Ethereum ecosystem.
+
+ Ethereum is becoming core infrastructure for digital identity, + commerce, and collaboration. But building{" "} + + an open society in the electronic age + {" "} + requires privacy that is usable, scalable, and secure. +
+
+ Privacy is a cornerstone of freedom and an{" "} + + important guarantor for decentralization. + {" "} + It gives people the ability to organize, express, and transact + freely. We envision a future where digital infrastructure + respects privacy by default, and permissions are + purpose-specific, informed, uncoerced, and revocable. +

+ {`Programmable cryptography unlocks transformative capabilities + for digital voting, identity, transactions, and other key + systems of coordination. But the road to privacy isn't only + technical—it demands cultural, social, and institutional change. + This is a collective challenge that we are committed to + catalyzing.`} +
+
+
+

+ How we Work +

+ + {`We are a team of cryptographers, mathematicians, developers, + designers, and coordinators working to make privacy accessible + by embedding programmable cryptography into Ethereum's + application layer. `} +
+
+ Our work is exploratory and full stack. We focus on areas that + are overlooked by academia or industry like foundational + concepts that need clarity, implementation gaps that have + stalled progress, and risky ideas with uncertain but + transformative
+
+ We believe meaningful progress comes from applying research to + real-world needs. Our work is open source, and we maintain a + feedback loop so that challenges from the field can help shape + our focus. We aim to support the ecosystem by benchmarking new + primitives, systematizing knowledge, and offering credible + guidances for building a more private and resilient future for + Ethereum. +
+
+
+ +
+ +
+

+ What we do +

+
+ {WhatWeDoItems?.map((item, index) => ( +
+
+
+ {item.label} +
+

+ {item.description} +

+
+
+ ))} +
+
+
-
-

- Our History -

- - We began in 2018 as Applied ZKP, a team supported by the{" "} - - Ethereum Foundation - {" "} - to push zero-knowledge proofs from theory to practice. In 2021, we - became Privacy & Scaling Explorations (PSE), expanding our scope - to programmable cryptography and tools across the stack. In 2025, - we refined our mission as Privacy Stewards for Ethereum, shifting - our focus toward concrete ecosystem impact. - -
- + +
+

+ Our History +

+ + We began in 2018 as Applied ZKP, a team supported by the + Ethereum Foundation to push zero-knowledge proofs from theory to + practice. In 2021, we became Privacy & Scaling Explorations + (PSE), expanding our scope to programmable cryptography and + tools across the stack. In 2025, we refined our mission as + Privacy Stewards for Ethereum, shifting our focus toward + ecosystem impact. + +
+
+
- + ) } diff --git a/app/(pages)/page.tsx b/app/(pages)/page.tsx index f51f681..f93b83c 100644 --- a/app/(pages)/page.tsx +++ b/app/(pages)/page.tsx @@ -2,9 +2,10 @@ import { LABELS } from "../labels" import { BlogRecentArticles } from "@/components/blog/blog-recent-articles" import { Icons } from "@/components/icons" import { HomepageBanner } from "@/components/sections/HomepageBanner" -import { HomepageHeader } from "@/components/sections/HomepageHeader" import { HomepageVideoFeed } from "@/components/sections/HomepageVideoFeed" -import { WhatWeDo } from "@/components/sections/WhatWeDo" +import { OurWork } from "@/components/sections/OurWork" +import { ParallaxHero } from "@/components/sections/ParallaxHero" +import { AppContent } from "@/components/ui/app-content" import { Button } from "@/components/ui/button" import Link from "next/link" import { Suspense } from "react" @@ -26,15 +27,18 @@ function BlogSection() { export default function IndexPage() { return (
- + -
-
- - {LABELS.HOMEPAGE.MISSION} +
+ + + {LABELS.HOMEPAGE.MISSION_TITLE} + + + {LABELS.HOMEPAGE.MISSION_DESCRIPTION} - -
+
+ + - -
) diff --git a/app/(pages)/projects/[id]/page.tsx b/app/(pages)/projects/[id]/page.tsx index 49cc4ae..258bd63 100644 --- a/app/(pages)/projects/[id]/page.tsx +++ b/app/(pages)/projects/[id]/page.tsx @@ -33,7 +33,7 @@ export async function generateMetadata({ const imageUrl = (project?.image ?? "")?.length > 0 ? `/project-banners/${project?.image}` - : "/og-image.png" + : "/share-image.png" return { title: project?.name, diff --git a/app/(pages)/projects/page.tsx b/app/(pages)/projects/page.tsx index 2cbaa11..01632e1 100644 --- a/app/(pages)/projects/page.tsx +++ b/app/(pages)/projects/page.tsx @@ -17,22 +17,24 @@ export const metadata: Metadata = { export default async function ProjectsPage() { return (
-
- - -
- {LABELS.PROJECTS_PAGE.SUBTITLE} -
-
-
- - - Loading...
}> -
- - + +
+
+
+

+ {LABELS.PROJECTS_PAGE.TITLE} +

+
- +
+ Loading...
}> +
+ +
+ + +
+
diff --git a/app/(pages)/projects/sections/ProjectContent.tsx b/app/(pages)/projects/sections/ProjectContent.tsx index cdd249e..703f111 100644 --- a/app/(pages)/projects/sections/ProjectContent.tsx +++ b/app/(pages)/projects/sections/ProjectContent.tsx @@ -1,27 +1,26 @@ "use client" -import { notFound } from "next/navigation" -import { siteConfig } from "@/config/site" -import { ProjectCategory, ProjectStatus } from "@/lib/types" - -import { cn } from "@/lib/utils" import { LABELS } from "@/app/labels" -import { AppContent } from "@/components/ui/app-content" -import { Markdown, createMarkdownElement } from "@/components/ui/markdown" +import { useProjects } from "@/app/providers/ProjectsProvider" +import { AppLink } from "@/components/app-link" +import { ProjectBlogArticles } from "@/components/blog/project-blog-articles" +import { WikiCard } from "@/components/cards/wiki-card" import { Divider } from "@/components/divider" import { Icons } from "@/components/icons" +import { ProjectLinkIconMap } from "@/components/mappings/project-links" import DiscoverMoreProjects from "@/components/project/discover-more-projects" import { ProjectTags } from "@/components/project/project-detail-tags" import ProjectExtraLinks from "@/components/project/project-extra-links" -import { ProjectLinkIconMap } from "@/components/mappings/project-links" -import { WikiSideNavigation } from "@/components/wiki-side-navigation" -import { WikiCard } from "@/components/cards/wiki-card" import { ProjectTeamMembers } from "@/components/project/project-team" -import { ProjectBlogArticles } from "@/components/blog/project-blog-articles" import { ProjectYouTubeVideos } from "@/components/sections/ProjectYouTubeVideos" -import { useProjects } from "@/app/providers/ProjectsProvider" +import { AppContent } from "@/components/ui/app-content" import { Button } from "@/components/ui/button" -import { AppLink } from "@/components/app-link" +import { Markdown, createMarkdownElement } from "@/components/ui/markdown" +import { WikiSideNavigation } from "@/components/wiki-side-navigation" +import { siteConfig } from "@/config/site" +import { ProjectCategory, ProjectStatus } from "@/lib/types" +import { cn } from "@/lib/utils" +import { notFound } from "next/navigation" const markdownContentClassName = "text-neutral-700 text-[22px] leading-6 font-bold pt-10 pb-4 dark:text-tuatara-100" @@ -60,7 +59,7 @@ const markdownComponents = { p: ({ ...props }) => createMarkdownElement("p", { className: - "py-2 leading-[150%] text-base text-slate-600 dark:text-tuatara-100", + "py-2 leading-[150%] text-base lg:text-xl text-tuatara-500 dark:text-tuatara-100", ...props, }), } diff --git a/app/(pages)/research/page.tsx b/app/(pages)/research/page.tsx index 82dc233..4a35799 100644 --- a/app/(pages)/research/page.tsx +++ b/app/(pages)/research/page.tsx @@ -1,8 +1,10 @@ -import { Metadata } from "next" import { LABELS } from "@/app/labels" -import { AppContent } from "@/components/ui/app-content" -import { Label } from "@/components/ui/label" +import { AppLink } from "@/components/app-link" +import { Icons } from "@/components/icons" import { ResearchList } from "@/components/research/research-list" +import { AppContent } from "@/components/ui/app-content" +import { Button } from "@/components/ui/button" +import { Metadata } from "next" export const metadata: Metadata = { title: "Research", @@ -12,15 +14,28 @@ export const metadata: Metadata = { const ResearchPage = async () => { return ( -
-
- - -
- {LABELS.RESEARCH_PAGE.SUBTITLE} -
-
-
+
+ +
+

+ {LABELS.RESEARCH_PAGE.TITLE} +

+
+ + {LABELS.RESEARCH_PAGE.SUBTITLE} + + + + +
+
+
diff --git a/app/labels.ts b/app/labels.ts index 8a1ffc7..5a916b6 100644 --- a/app/labels.ts +++ b/app/labels.ts @@ -3,8 +3,8 @@ export const LABELS = { TITLE: "Blog", SUBTITLE: "Read our latest articles and stay updated on the latest news in the world of cryptography.", - RECENT_ARTICLES: "Recent articles", - SEE_MORE: "See more", + RECENT_ARTICLES: "Recent posts", + SEE_MORE: "More posts", READ_MORE: "Read more", SEARCH_PLACEHOLDER: "Search PSE's blog", }, @@ -104,20 +104,21 @@ export const LABELS = { MORE_POSTS: "More posts", }, HOMEPAGE: { - MISSION: - "Ethereum is the foundation of a freer digital world, but it will not reach its full potential without privacy. We’re building cryptographic tools, co-creating standards, and coordinating throughout the ecosystem to make privacy practical for Ethereum.", + MISSION_TITLE: "Our Mission", + MISSION_DESCRIPTION: + "Ethereum is the foundation of a freer digital world, but it will not reach its full potential without privacy. We're building cryptographic tools, co-creating standards, and coordinating throughout the ecosystem to make privacy practical for Ethereum.", MISSION_BUTTON: "LEARN MORE ABOUT US", HEADER_TITLE: "Privacy Stewards of Ethereum", HEADER_SUBTITLE: - "PSE is a research and development lab delivering privacy to the Ethereum ecosystem", - JOIN_OUR_DISCORD: "Join our community", + "PSE is a research and development lab delivering privacy to the Ethereum ecosystem.", + JOIN_OUR_DISCORD: "Join our Discord", CONNECT_WITH_US: { TITLE: "Join our programs", DESCRIPTION: "Want to explore the world of programmable cryptography and learn how to make contributions to open-source projects? Join our free programs to start your journey!", }, VIDEOS: "VIDEOS", - VISIT_OUR_CHANNEL: "VISIT OUR CHANNEL", + VISIT_OUR_CHANNEL: "More videos", ERROR_LOADING_VIDEOS: "Error loading videos", CHECK_OUT_OUR_YOUTUBE: "Check out our YouTube to learn the latest in advanced cryptography.", @@ -219,14 +220,12 @@ export const LABELS = { }, }, PROJECTS_PAGE: { - TITLE: "Explore our Project Library", - SUBTITLE: - "Everything PSE works on is public and open source. All of our projects, whether research or development, are resources you can learn from and build with.", + TITLE: "Explore Our Projects", }, RESEARCH_PAGE: { - TITLE: "Research", + TITLE: "Explore Our Research", SUBTITLE: - "Our research model is exploratory, iterative, and full-stack. We work on areas that are often overlooked by academia or industry — foundational concepts that need clarity, implementation gaps that have stalled progress, and risky ideas with uncertain but transformative potential. Sometimes our research unlocks a new breakthrough that leads to prototypes, and sometimes we just clarify assumptions and fill in theoretical gaps. We believe meaningful progress comes from applying research to real-world needs. Our work is open source, and we maintain a feedback loop so that challenges from the field can help shape our focus. We aim to support the broader ecosystem by systematizing knowledge, benchmarking new primitives, and offering credible guidance to advance the world of cryptography.", + "Our research model is open source, iterative, and driven by real-world use cases.", ACTIVE_RESEARCH: "Active Research", PAST_RESEARCH: "Past Research", }, @@ -245,13 +244,13 @@ export const LABELS = { }, WHAT_WE_DO_SECTION: { BUILD: { - TITLE: "Build", + TITLE: "Building open source tools", DESCRIPTION: "We develop open source tools for things like data provenance, private identity, voting, and more to make privacy a core feature of Ethereum's application layer.", ACTION: "See our projects", }, RESEARCH: { - TITLE: "Research", + TITLE: "Researching new applications", DESCRIPTION: "We benchmark primitives, systematize knowledge, and explore new ideas with the potential to transform the capabilities and impact of programmable cryptography.", ACTION: "See our research", diff --git a/app/layout.tsx b/app/layout.tsx index 3a03007..ec69dee 100644 --- a/app/layout.tsx +++ b/app/layout.tsx @@ -1,16 +1,14 @@ import "@/globals.css" -import Script from "next/script" -import { Metadata, Viewport } from "next" - +import { ThemeProvider } from "./components/layouts/ThemeProvider" import { GlobalProviderLayout } from "@/components/layouts/GlobalProviderLayout" import { SiteFooter } from "@/components/site-footer" import { SiteHeader } from "@/components/site-header" import { TailwindIndicator } from "@/components/tailwind-indicator" -import { ThemeProvider } from "./components/layouts/ThemeProvider" import { siteConfig } from "@/config/site" import { cn } from "@/lib/utils" - +import { Metadata, Viewport } from "next" import { DM_Sans, Inter, Space_Grotesk } from "next/font/google" +import Script from "next/script" const inter = Inter({ subsets: ["latin"], @@ -95,7 +93,7 @@ export const metadata: Metadata = { openGraph: { images: [ { - url: "/og-image.png", + url: "/share-image.png", width: 1200, height: 630, }, diff --git a/app/not-found.tsx b/app/not-found.tsx index 1fcffeb..799884e 100644 --- a/app/not-found.tsx +++ b/app/not-found.tsx @@ -1,13 +1,12 @@ "use client" import "@/globals.css" -import React from "react" +import { LABELS } from "./labels" +import { Button } from "@/components/ui/button" +import { Metadata } from "next" import Image from "next/image" import Link from "next/link" -import { Metadata } from "next" - -import { Button } from "@/components/ui/button" -import { LABELS } from "./labels" +import React from "react" export const metadata: Metadata = { title: "404: Page Not Found", diff --git a/components/app-link.tsx b/components/app-link.tsx index e6d80b5..5f43110 100644 --- a/components/app-link.tsx +++ b/components/app-link.tsx @@ -1,11 +1,10 @@ "use client" -import React from "react" -import Link from "next/link" - import { Icons } from "./icons" -import { cva } from "class-variance-authority" import { cn } from "@/lib/utils" +import { cva } from "class-variance-authority" +import Link from "next/link" +import React from "react" interface LinkProps extends React.AnchorHTMLAttributes { children: React.ReactNode @@ -13,7 +12,7 @@ interface LinkProps extends React.AnchorHTMLAttributes { to?: string external?: boolean withExternalIcon?: boolean - variant?: "default" | "blue" | "button" + variant?: "default" | "blue" | "button" | "nav" passHref?: boolean } @@ -23,6 +22,7 @@ const linkClass = cva("inline-flex", { default: "text-black dark:text-white hover:text-orange duration-200 underline", blue: "text-anakiwa-500 hover:text-anakiwa-700", + nav: "text-tuatara-100 hover:text-anakiwa-400 duration-200", button: "flex", }, }, diff --git a/components/banner.tsx b/components/banner.tsx index 06789ef..c9baaa4 100644 --- a/components/banner.tsx +++ b/components/banner.tsx @@ -1,28 +1,35 @@ import { ReactNode } from "react" import { AppContent } from "./ui/app-content" +import { cn } from "@/lib/utils" type BannerProps = { title: ReactNode subtitle?: string children?: ReactNode + className?: string } -const Banner = ({ title, subtitle, children }: BannerProps) => { +const Banner = ({ title, subtitle, children, className }: BannerProps) => { return ( -
+
- +
{typeof title === "string" ? ( -
+
{title}
) : ( title )} {subtitle && ( - + {subtitle} )} diff --git a/components/blog/article-in-evidance-card.tsx b/components/blog/article-in-evidance-card.tsx index 9669caf..c382f86 100644 --- a/components/blog/article-in-evidance-card.tsx +++ b/components/blog/article-in-evidance-card.tsx @@ -2,10 +2,10 @@ import { Icons } from "../icons" import { Button } from "../ui/button" +import { LABELS } from "@/app/labels" import { Article } from "@/lib/content" import { cn } from "@/lib/utils" import Link from "next/link" -import { LABELS } from "@/app/labels" interface ArticleInEvidenceCardProps { article: Article @@ -67,7 +67,7 @@ export const ArticleInEvidenceCard = ({ return (
- {article.date && showDate && ( - - {formatDate(article.date)} - - )} - - {article.title} - - - {article.authors?.join(", ")} - - {article.tldr && !hideTldr && ( - + )} + - {article.tldr} + {article.title} + + + {article.authors?.join(", ")} - )} + {article.tldr && !hideTldr && ( +
+

+ {article.tldr} +

+
+ )} +
{showReadMore && ( - - + +
+ + Read More + + +
)}
@@ -140,10 +150,10 @@ export async function BlogRecentArticles() { const otherArticles = articles.slice(1) return ( -
+
-

+

{LABELS.BLOG_PAGE.RECENT_ARTICLES}

@@ -168,13 +178,13 @@ export async function BlogRecentArticles() { {article.title} {article.authors && ( - + {article.authors?.join(", ")} )} ))} - + - - - - -
- } - /> - ) -} diff --git a/components/sections/HomepageVideoFeed.tsx b/components/sections/HomepageVideoFeed.tsx index b23674b..4e10090 100644 --- a/components/sections/HomepageVideoFeed.tsx +++ b/components/sections/HomepageVideoFeed.tsx @@ -1,14 +1,14 @@ "use client" +import { AppLink } from "../app-link" +import { Icons } from "../icons" +import { AppContent } from "../ui/app-content" +import { Button } from "../ui/button" import { LABELS } from "@/app/labels" +import { useYoutube } from "@/hooks/useYoutube" import { ArrowRight } from "lucide-react" import Image from "next/image" import Link from "next/link" -import { Button } from "../ui/button" -import { AppContent } from "../ui/app-content" -import { Icons } from "../icons" -import { useYoutube } from "@/hooks/useYoutube" -import { AppLink } from "../app-link" interface Video { id: string @@ -41,7 +41,7 @@ const VideoCard = ({ video }: { video: Video }) => {
-

+

{video.title}

@@ -71,10 +71,10 @@ export const HomepageVideoFeed = () => { const { data: videos = [], isLoading, isError } = useYoutube() return ( -
+
-

+

{LABELS.HOMEPAGE.VIDEOS}

@@ -99,16 +99,16 @@ export const HomepageVideoFeed = () => {
- + {LABELS.HOMEPAGE.CHECK_OUT_OUR_YOUTUBE} - - - )} -
+ ))}
diff --git a/components/sections/ParallaxHero.tsx b/components/sections/ParallaxHero.tsx new file mode 100644 index 0000000..017f3bf --- /dev/null +++ b/components/sections/ParallaxHero.tsx @@ -0,0 +1,115 @@ +"use client" + +import { Icons } from "../icons" +import { AppContent } from "../ui/app-content" +import { Button } from "../ui/button" +import { LABELS } from "@/app/labels" +import { cn } from "@/lib/utils" +import { motion, useScroll, useTransform } from "framer-motion" +import Link from "next/link" +import { useRef } from "react" + +export const ParallaxHero = () => { + const containerRef = useRef(null) + const { scrollYProgress } = useScroll({ + target: containerRef, + offset: ["start start", "end start"], + }) + + const backgroundY = useTransform(scrollYProgress, [0, 1], ["0%", "80%"]) + + return ( +
+ + + + + +
+
+ + {LABELS.HOMEPAGE.HEADER_TITLE} + + + {LABELS.HOMEPAGE.HEADER_SUBTITLE} + +
+ + + + + + + + +
+
+
+
+
+ ) +} diff --git a/components/site-footer.tsx b/components/site-footer.tsx index fe10ed5..698506f 100644 --- a/components/site-footer.tsx +++ b/components/site-footer.tsx @@ -22,10 +22,12 @@ const ItemLabel = ({ return (
{external && ( - + )} - {icon &&
{icon}
} - + {icon && ( +
{icon}
+ )} + {label}
@@ -47,7 +49,7 @@ export function SiteFooter() { return (