Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
87 commits
Select commit Hold shift + click to select a range
f829eb1
removed legacy button and changed try now button colors
FacuBozzi Jul 10, 2025
f04f971
try now button color and hero description
FacuBozzi Jul 10, 2025
115c646
YourMoney component
FacuBozzi Jul 10, 2025
79a1ab8
NoFees component first part
FacuBozzi Jul 10, 2025
937e219
stars done
FacuBozzi Jul 10, 2025
308affe
scribble in zero fees
FacuBozzi Jul 10, 2025
b29f9ba
no hidden fees section done
FacuBozzi Jul 10, 2025
7e031b0
securityBuiltIn done
FacuBozzi Jul 10, 2025
816ea56
sendInSeconds progress
FacuBozzi Jul 11, 2025
9efb3b8
sendInSeconds done
FacuBozzi Jul 11, 2025
a02ddbf
updated try now button to be a link
FacuBozzi Jul 11, 2025
d676230
business integration initiation
FacuBozzi Jul 11, 2025
9dfd540
businessIntegrate done
FacuBozzi Jul 11, 2025
f880669
order and marquee reusability
FacuBozzi Jul 11, 2025
e9793eb
order fixed
FacuBozzi Jul 11, 2025
aef2901
background animations in Landing Page compoejnnts
FacuBozzi Jul 11, 2025
41f8bd4
changed image for text in hero section
FacuBozzi Jul 11, 2025
493e397
figma details
FacuBozzi Jul 11, 2025
8bfd951
landing page responsiveness improvements
FacuBozzi Jul 11, 2025
f04694f
landing page responsiveness done
FacuBozzi Jul 11, 2025
3ee08ff
coderabbit suggestion
FacuBozzi Jul 11, 2025
59bafbd
business integration button
FacuBozzi Jul 11, 2025
47fe20b
fixed iphone screenshots
FacuBozzi Jul 11, 2025
ee887ec
CTA button animation
FacuBozzi Jul 11, 2025
d279d39
added debugging for CTA button animation
FacuBozzi Jul 11, 2025
a437c66
changed animation since react gave errors
FacuBozzi Jul 11, 2025
2bf4cac
arrows in hero section
FacuBozzi Jul 11, 2025
180a2b0
NoFees new Zero
FacuBozzi Jul 11, 2025
2a2e4b1
no fees responsiveness fixed
FacuBozzi Jul 11, 2025
8244af6
sendInSeconds details done
FacuBozzi Jul 11, 2025
2c3641e
coderabbit suggestions
FacuBozzi Jul 11, 2025
c7cc461
formatting
FacuBozzi Jul 11, 2025
145faff
hand-token wasnt pushed? forgot to stage or sum? anyways fixed
FacuBozzi Jul 11, 2025
84f72f7
build issues fixed
FacuBozzi Jul 11, 2025
6416326
coderabbit optimization
FacuBozzi Jul 11, 2025
947348b
code formatting
FacuBozzi Jul 11, 2025
8ce6a0c
arrows and ZERO thickness
FacuBozzi Jul 12, 2025
ce533b9
shade in try now button
FacuBozzi Jul 14, 2025
2369977
progress in button animation
FacuBozzi Jul 14, 2025
e5ae9ca
undoing button changes
FacuBozzi Jul 14, 2025
c4b7c84
small detail fixes
FacuBozzi Jul 14, 2025
e5c6688
added asset
FacuBozzi Jul 14, 2025
22640b0
changed peanut business to svg
FacuBozzi Jul 14, 2025
3fd2f5d
integrate peanut component done
FacuBozzi Jul 14, 2025
9dc96b6
added pay-zero-fees.svg
FacuBozzi Jul 14, 2025
e7a3acc
Merge branch 'feat/new-landing-page' of github.com:peanutprotocol/pea…
FacuBozzi Jul 14, 2025
a2c4751
added new illustrations
FacuBozzi Jul 14, 2025
a9a5e8f
uout money anywhere svg
FacuBozzi Jul 14, 2025
10255be
securitybuiltin component SVGs
FacuBozzi Jul 14, 2025
611935d
adding YourMoney new SVGs
FacuBozzi Jul 14, 2025
caf15a7
your money anywhere component
FacuBozzi Jul 14, 2025
e98fd35
instantly send & receive svg
FacuBozzi Jul 14, 2025
af10bd4
desktop with SVGs version
FacuBozzi Jul 14, 2025
9b084cd
Merge branch 'peanut-wallet-dev' into feat/new-landing-page
FacuBozzi Jul 14, 2025
a757ac8
arrows fixed
FacuBozzi Jul 15, 2025
69749d0
button and arrows done
FacuBozzi Jul 15, 2025
00bf151
desktop sendinseconds button done
FacuBozzi Jul 15, 2025
2c89cc8
removed arrows disappearing effect
FacuBozzi Jul 15, 2025
dd7f976
MOBILE: hero button done
FacuBozzi Jul 15, 2025
91b8d32
added mobile svg
FacuBozzi Jul 15, 2025
ae4b1dc
yourMoney responsive component done
FacuBozzi Jul 15, 2025
bc0048d
added mobile-zero-fees.svg
FacuBozzi Jul 15, 2025
0987258
added no-hidden-fees.svg
FacuBozzi Jul 15, 2025
1d12567
noFees mobile svg
FacuBozzi Jul 15, 2025
ecfed14
noFees desktop + mobile improvements
FacuBozzi Jul 15, 2025
f4c207b
noFees done
FacuBozzi Jul 15, 2025
0779abd
mobile security built in SVG
FacuBozzi Jul 15, 2025
75f765d
Merge branch 'feat/new-landing-page' of github.com:peanutprotocol/pea…
FacuBozzi Jul 15, 2025
fc54d27
securityprivacy mobile done
FacuBozzi Jul 15, 2025
101a77c
mobile-send-in-seconds.svg
FacuBozzi Jul 15, 2025
da44bd4
sendInSeconds mobile done
FacuBozzi Jul 15, 2025
afeacec
business integrate mobile
FacuBozzi Jul 15, 2025
1a185b2
business integrate button and final details
FacuBozzi Jul 15, 2025
abd0b58
removed footer
FacuBozzi Jul 15, 2025
f187165
formatting
FacuBozzi Jul 15, 2025
7dea627
removed pino-pretty
FacuBozzi Jul 15, 2025
a9e6ad3
fixed button instead of sticky/floating
FacuBozzi Jul 16, 2025
de67bd4
removed index.ts at TOP LEVEL
FacuBozzi Jul 16, 2025
e7786cb
fixed background color hardcoded
FacuBozzi Jul 16, 2025
99c038f
fixed duplicate marquee
FacuBozzi Jul 16, 2025
037dd83
reusing animations (implementing hooks)
FacuBozzi Jul 16, 2025
5735105
exclamation points SVG only appearing in large screens
FacuBozzi Jul 16, 2025
de56d76
mobile and desktop hero sections margins
FacuBozzi Jul 16, 2025
ddb42e9
all stars in the same size
FacuBozzi Jul 16, 2025
e2ace5f
format
FacuBozzi Jul 16, 2025
1579cc3
Merge branch 'peanut-wallet-dev' into feat/new-landing-page
FacuBozzi Jul 16, 2025
63c26d4
Delete public/lottie directory
FacuBozzi Jul 17, 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
38 changes: 28 additions & 10 deletions src/app/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,13 @@ import {
BusinessIntegrate,
FAQs,
Hero,
Marquee,
NoFees,
SecurityBuiltIn,
SendInSeconds,
YourMoney,
} from '@/components/LandingPage'
import { MarqueeComp } from '@/components/Global/MarqueeWrapper'
import { HandThumbsUp } from '@/assets'
import { useFooterVisibility } from '@/context/footerVisibility'
import { useEffect, useState, useRef } from 'react'

Expand All @@ -30,7 +31,6 @@ export default function LandingPage() {
const hero = {
heading: 'Peanut',
marquee: {
visible: true,
message: ['No fees', 'Instant', '24/7', 'USD', 'EUR', 'CRYPTO', 'GLOBAL', 'SELF-CUSTODIAL'],
},
primaryCta: {
Expand Down Expand Up @@ -158,7 +158,11 @@ export default function LandingPage() {
}
}, [isScrollFrozen, animationComplete, shrinkingPhase, hasGrown])

const marqueeProps = { visible: hero.marquee.visible, message: hero.marquee.message }
const marqueeProps = {
message: hero.marquee.message,
imageSrc: HandThumbsUp.src,
backgroundColor: 'bg-secondary-1',
}

return (
<Layout className="!m-0 w-full !p-0">
Expand All @@ -168,21 +172,35 @@ export default function LandingPage() {
buttonVisible={buttonVisible}
buttonScale={buttonScale}
/>
<Marquee {...marqueeProps} />
<div className="relative z-1">
<MarqueeComp {...marqueeProps} />
</div>
<YourMoney />
<Marquee {...marqueeProps} />
<div className="relative z-1">
<MarqueeComp {...marqueeProps} />
</div>
<NoFees />
<Marquee {...marqueeProps} />
<div className="relative z-1">
<MarqueeComp {...marqueeProps} />
</div>
<SecurityBuiltIn />
<Marquee {...marqueeProps} />
<div className="relative z-1">
<MarqueeComp {...marqueeProps} />
</div>
<FAQs heading={faqs.heading} questions={faqs.questions} marquee={faqs.marquee} />
<Marquee {...marqueeProps} />
<div className="relative z-1">
<MarqueeComp {...marqueeProps} />
</div>
<div ref={sendInSecondsRef}>
<SendInSeconds />
</div>
<Marquee {...marqueeProps} />
<div className="relative z-1">
<MarqueeComp {...marqueeProps} />
</div>
<BusinessIntegrate />
<Marquee {...marqueeProps} />
<div className="relative z-1">
<MarqueeComp {...marqueeProps} />
</div>
</Layout>
)
}
8 changes: 1 addition & 7 deletions src/components/LandingPage/businessIntegrate.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,9 @@ import { Star } from '@/assets'
import scribble from '@/assets/scribble.svg'
import peanutMeans from '@/assets/illustrations/peanut-means.svg'

// Define the background color as a constant
const businessBgColor = '#90A8ED'

export function BusinessIntegrate() {
return (
<section
className="relative min-h-[500px] overflow-hidden px-4 py-16 text-n-1 md:min-h-[900px]"
style={{ backgroundColor: businessBgColor }}
>
<section className="relative min-h-[500px] overflow-hidden bg-secondary-3 px-4 py-16 text-n-1 md:min-h-[900px]">
<div className="relative mx-auto max-w-3xl text-center">
{/* Main heading */}
<div className="mb-8 mt-8 md:mb-24 md:mt-20">
Expand Down
74 changes: 25 additions & 49 deletions src/components/LandingPage/hero.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { ButterySmoothGlobalMoney, PeanutGuyGIF, Sparkle } from '@/assets'
import { Stack } from '@chakra-ui/react'
import { motion } from 'framer-motion'
import { useEffect, useState } from 'react'
import { twMerge } from 'tailwind-merge'
import { CloudImages, HeroImages } from './imageAssets'
import Image from 'next/image'
import instantlySendReceive from '@/assets/illustrations/instantly-send-receive.svg'
import { useResizeHandler, useScrollHandler, createButtonAnimation } from '@/hooks/useAnimations'

type CTAButton = {
label: string
Expand All @@ -22,29 +22,6 @@ type HeroProps = {
}

// Helper functions moved outside component for better performance
const getInitialAnimation = (variant: 'primary' | 'secondary') => ({
opacity: 0,
translateY: 4,
translateX: variant === 'primary' ? 0 : 4,
rotate: 0.75,
})

const getAnimateAnimation = (variant: 'primary' | 'secondary', buttonVisible?: boolean, buttonScale?: number) => ({
opacity: buttonVisible ? 1 : 0,
translateY: buttonVisible ? 0 : 20,
translateX: buttonVisible ? (variant === 'primary' ? 0 : 0) : 20,
rotate: buttonVisible ? 0 : 1,
scale: buttonScale || 1,
pointerEvents: buttonVisible ? ('auto' as const) : ('none' as const),
})

const getHoverAnimation = (variant: 'primary' | 'secondary') => ({
translateY: 6,
translateX: variant === 'primary' ? 0 : 3,
rotate: 0.75,
})

const transitionConfig = { type: 'spring', damping: 15 } as const

const getButtonContainerClasses = (variant: 'primary' | 'secondary') =>
`relative z-20 mt-8 md:mt-12 ${variant === 'primary' ? 'mx-auto w-fit' : 'right-[calc(50%-120px)]'}`
Expand Down Expand Up @@ -100,38 +77,34 @@ const renderArrows = (variant: 'primary' | 'secondary', arrowOpacity: number, bu
)

export function Hero({ heading, primaryCta, secondaryCta, buttonVisible, buttonScale = 1 }: HeroProps) {
const [screenWidth, setScreenWidth] = useState(typeof window !== 'undefined' ? window.innerWidth : 1200)
const [scrollY, setScrollY] = useState(0)

useEffect(() => {
const handleResize = () => {
setScreenWidth(window.innerWidth)
}

const handleScroll = () => {
setScrollY(window.scrollY)
}

handleResize()
window.addEventListener('resize', handleResize)
window.addEventListener('scroll', handleScroll)
const screenWidth = useResizeHandler()
const scrollY = useScrollHandler()

const primaryButtonAnimation = createButtonAnimation(
buttonVisible || false,
buttonScale,
{ translateX: 0 },
{ translateX: 0 }
)

return () => {
window.removeEventListener('resize', handleResize)
window.removeEventListener('scroll', handleScroll)
}
}, [])
const secondaryButtonAnimation = createButtonAnimation(
buttonVisible || false,
buttonScale,
{ translateX: 4 },
{ translateX: 3 }
)

const renderCTAButton = (cta: CTAButton, variant: 'primary' | 'secondary') => {
const arrowOpacity = 1 // Always visible
const animation = variant === 'primary' ? primaryButtonAnimation : secondaryButtonAnimation

return (
<motion.div
className={getButtonContainerClasses(variant)}
initial={getInitialAnimation(variant)}
animate={getAnimateAnimation(variant, buttonVisible, buttonScale)}
whileHover={getHoverAnimation(variant)}
transition={transitionConfig}
initial={animation.initial}
animate={animation.animate}
whileHover={animation.hover}
transition={animation.transition}
>
{/* {renderSparkle(variant)} */}

Expand Down Expand Up @@ -161,7 +134,10 @@ export function Hero({ heading, primaryCta, secondaryCta, buttonVisible, buttonS
alt="Peanut Guy"
/>

<Stack spacing={2} className="relative h-1/3 items-center justify-center px-4 text-center lg:h-full">
<Stack
spacing={2}
className="relative !mb-56 h-1/3 items-center justify-center px-4 text-center md:!mb-20 lg:h-full"
>
<img
src={ButterySmoothGlobalMoney.src}
className="z-0 mx-auto w-full max-w-[1000px] object-contain lg:w-3/4"
Expand Down
1 change: 0 additions & 1 deletion src/components/LandingPage/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
export * from './businessIntegrate'
export * from './faq'
export * from './hero'
export * from './marquee'
export * from './noFees'
export * from './nutsDivider'
export * from './securityBuiltIn'
Expand Down
79 changes: 22 additions & 57 deletions src/components/LandingPage/noFees.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useEffect, useState } from 'react'
import React from 'react'
import { motion } from 'framer-motion'
import gotItHand from '@/assets/illustrations/got-it-hand.svg'
import gotItHandFlipped from '@/assets/illustrations/got-it-hand-flipped.svg'
Expand All @@ -9,34 +9,19 @@ import noHiddenFees from '@/assets/illustrations/no-hidden-fees.svg'
import { Star } from '@/assets'
import scribble from '@/assets/scribble.svg'
import Image from 'next/image'
import { useResizeHandler, createStarAnimation, createCloudAnimation } from '@/hooks/useAnimations'

export function NoFees() {
const [screenWidth, setScreenWidth] = useState(typeof window !== 'undefined' ? window.innerWidth : 1200)
const screenWidth = useResizeHandler()

useEffect(() => {
const handleResize = () => {
setScreenWidth(window.innerWidth)
}
const starAnimation1 = createStarAnimation(0.2, 5, { rotate: 22 }, { rotate: 22 })
const starAnimation2 = createStarAnimation(0.4, 5, { translateY: 28, translateX: -5, rotate: -17 }, { rotate: -17 })
const starAnimation3 = createStarAnimation(0.6, 5, { rotate: 22 }, { rotate: 22 })
const starAnimation4 = createStarAnimation(0.8, 5, { translateY: 15, translateX: -5, rotate: -7 }, { rotate: -7 })
const starAnimation5 = createStarAnimation(1.0, 5, { translateY: 25, translateX: -5, rotate: -5 }, { rotate: -5 })

handleResize()
window.addEventListener('resize', handleResize)
return () => window.removeEventListener('resize', handleResize)
}, [])

const createCloudAnimation = (side: 'left' | 'right', top: string, width: number, speed: number) => {
const vpWidth = screenWidth || 1080
const totalDistance = vpWidth + width

return {
initial: { x: side === 'left' ? -width : vpWidth },
animate: { x: side === 'left' ? vpWidth : -width },
transition: {
ease: 'linear',
duration: totalDistance / speed,
repeat: Infinity,
},
}
}
const cloud1Animation = createCloudAnimation('left', 200, 35, screenWidth)
const cloud2Animation = createCloudAnimation('right', 220, 40, screenWidth)

return (
<section className="relative overflow-hidden bg-secondary-3 px-4 py-24 md:py-40">
Expand All @@ -47,14 +32,14 @@ export function NoFees() {
alt="Floating Border Cloud"
className="absolute left-0"
style={{ top: '20%', width: 200 }}
{...createCloudAnimation('left', '20%', 200, 35)}
{...cloud1Animation}
/>
<motion.img
src={borderCloud.src}
alt="Floating Border Cloud"
className="absolute right-0"
style={{ top: '60%', width: 220 }}
{...createCloudAnimation('right', '60%', 220, 40)}
{...cloud2Animation}
/>
</div>

Expand All @@ -63,52 +48,32 @@ export function NoFees() {
<motion.img
src={Star.src}
alt="Floating Star"
width={50}
height={50}
className="absolute -right-36 -top-12"
initial={{ opacity: 0, translateY: 20, translateX: 5, rotate: 22 }}
whileInView={{ opacity: 1, translateY: 0, translateX: 0, rotate: 22 }}
transition={{ type: 'spring', damping: 5, delay: 0.2 }}
className="absolute -right-36 -top-12 w-8 md:w-12"
{...starAnimation1}
/>
<motion.img
src={Star.src}
alt="Floating Star"
width={50}
height={50}
className="absolute -right-58 top-30"
initial={{ opacity: 0, translateY: 28, translateX: -5, rotate: -17 }}
whileInView={{ opacity: 1, translateY: 0, translateX: 0, rotate: -17 }}
transition={{ type: 'spring', damping: 5, delay: 0.4 }}
className="absolute -right-58 top-30 w-8 md:w-12"
{...starAnimation2}
/>
<motion.img
src={Star.src}
alt="Floating Star"
width={50}
height={50}
className="absolute -right-0 -top-16 md:top-58"
initial={{ opacity: 0, translateY: 20, translateX: 5, rotate: 22 }}
whileInView={{ opacity: 1, translateY: 0, translateX: 0, rotate: 22 }}
transition={{ type: 'spring', damping: 5, delay: 0.6 }}
className="absolute -right-0 -top-16 w-8 md:top-58 md:w-12"
{...starAnimation3}
/>
<motion.img
src={Star.src}
alt="Floating Star"
width={50}
height={50}
className="absolute -left-36 -top-20"
initial={{ opacity: 0, translateY: 15, translateX: -5, rotate: -7 }}
whileInView={{ opacity: 1, translateY: 0, translateX: 0, rotate: -7 }}
transition={{ type: 'spring', damping: 5, delay: 0.8 }}
className="absolute -left-36 -top-20 w-8 md:w-12"
{...starAnimation4}
/>
<motion.img
src={Star.src}
alt="Floating Star"
width={50}
height={50}
className="absolute -bottom-6 -left-10"
initial={{ opacity: 0, translateY: 25, translateX: -5, rotate: -5 }}
whileInView={{ opacity: 1, translateY: 0, translateX: 0, rotate: -5 }}
transition={{ type: 'spring', damping: 5, delay: 1.0 }}
className="absolute -bottom-6 -left-10 w-8 md:w-12"
{...starAnimation5}
/>
{/* Main stylized headline */}
<div className="md:mb-4">
Expand Down
Loading
Loading