Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
25 changes: 13 additions & 12 deletions src/app/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,18 @@ export default function LandingPage() {
visible: true,
message: 'Peanut',
},
cta: {
label: 'TRY NOW',
href: '/pay',
},
ctas: [
{
label: 'TRY NOW',
href: 'https://peanut.me',
primary: true,
},
{
label: 'LEGACY',
href: '/pay',
primary: false,
},
],
}
const story = {
marquee: {
Expand Down Expand Up @@ -154,14 +162,7 @@ export default function LandingPage() {

return (
<Layout className="!m-0 w-full !p-0">
<Hero heading={hero.heading} marquee={hero.marquee} cta={hero.cta} buttonVisible={buttonVisible} />
<FAQs heading={faqs.heading} questions={faqs.questions} marquee={faqs.marquee} />
<BuildOnUs />
<Story marquee={story.marquee} />
<Features sections={[features.sections[1]]} marquee={features.marquee} />
<div className="bg-pink-1">
<Mike lines={mike.lines} />
</div>
<Hero heading={hero.heading} marquee={hero.marquee} ctas={hero.ctas} buttonVisible={buttonVisible} />
</Layout>
)
}
Binary file added src/assets/icons/gitbook-black.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions src/assets/icons/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export { default as DROPDOWN_ICON } from './dropdown.svg'
export { default as ETHEREUM_ICON } from './ethereum.svg'
export { default as GAS_ICON } from './gas.svg'
export { default as GITBOOK_ICON } from './gitbook.png'
export { default as GITBOOK_BLACK_ICON } from './gitbook-black.png'
export { default as GITHUB_INVERTED_ICON } from './github-inverted.png'
export { default as GITHUB_ICON } from './github.png'
export { default as MAIL_ICON } from './mail-icon.svg'
Expand Down
10 changes: 4 additions & 6 deletions src/components/Global/Layout/index.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
'use client'

import { Banner } from '@/components/Global/Banner'
import Footer from '@/components/Global/Footer'
import Header from '@/components/Global/Header'
import { MigrationBanner } from '@/components/Global/MigrationBanner'
import { useFooterVisibility } from '@/context/footerVisibility'
import { Widget } from '@typeform/embed-react'
import { Roboto_Flex } from 'next/font/google'
Expand Down Expand Up @@ -41,10 +40,9 @@ const Layout = ({ children, className }: LayoutProps) => {
font-family: ${roboto.style.fontFamily};
}
`}</style>
<div className={twMerge('relative bg-background', isTryNow && 'bg-background-1')}>
<div className={twMerge('relative bg-background', isTryNow && 'bg-pink-1')}>
<div className="flex min-h-screen flex-col ">
<Header />
<Banner />
<MigrationBanner className="h-[7vh] min-h-[90px]" />
<div className="flex grow justify-center">
<div
className={`4xl:max-w-full flex grow flex-col justify-center pb-2 pt-6 sm:mx-auto sm:px-16 md:px-5 lg:px-6 2xl:px-8 ${className}`}
Expand All @@ -54,7 +52,7 @@ const Layout = ({ children, className }: LayoutProps) => {
</div>
</div>
<FooterVisibilityObserver />
<Footer />
<MigrationBanner className="h-[7vh] min-h-[90px]" />
<Modal
visible={showModal}
onClose={() => {
Expand Down
22 changes: 22 additions & 0 deletions src/components/Global/MigrationBanner/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
'use client'
import React from 'react'
import { MarqueeWrapper } from '../MarqueeWrapper'
import { PEANUTMAN_CHEERING } from '@/assets'
import handThumbsUp from '@/assets/illustrations/hand-thumbs-up.svg'

interface MigrationBannerProps {
className?: string
}

export function MigrationBanner({ className = '' }: MigrationBannerProps) {
return (
<a href="https://peanut.me" className="block cursor-pointer transition-opacity hover:opacity-90">
<MarqueeWrapper backgroundColor="bg-yellow-1" direction="left">
<div className={`mx-4 flex items-center py-4 ${className}`}>
<img src={handThumbsUp.src} alt="Migration Icon" className="animation-thumbsUp mr-3 h-8 w-8" />
<span className="text-h2 font-bold uppercase tracking-wider">WE'VE MIGRATED TO PEANUT.ME</span>
</div>
</MarqueeWrapper>
</a>
)
}
68 changes: 51 additions & 17 deletions src/components/Global/TryNow/index.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,24 @@
import { ARROW_UP_CIRCLE, CASHOUT_ICON, Eyes, STAR_OUTLINE_ICON } from '@/assets'
import {
ARROW_UP_CIRCLE,
CASHOUT_ICON,
Eyes,
STAR_OUTLINE_ICON,
SMILEY_ICON,
TRIANGLE_ICON,
GITBOOK_BLACK_ICON,
} from '@/assets'
import { Card } from '@chakra-ui/react'
import Image from 'next/image'
import Image, { StaticImageData } from 'next/image'
import Link from 'next/link'
import { twMerge } from 'tailwind-merge'

interface ITryNowCard {
title: string
description: string
icon: string
icon: StaticImageData | string
href: string
isExternal?: boolean
needsIconAdjustment?: boolean
}

const cards: ITryNowCard[] = [
Expand All @@ -32,6 +41,33 @@ const cards: ITryNowCard[] = [
icon: ARROW_UP_CIRCLE,
href: '/send',
},
{
title: 'Raffle (legacy)',
description: 'Create crypto raffles and distribute tokens to winners',
icon: STAR_OUTLINE_ICON,
href: '/raffle/create',
},
{
title: 'Batch Send (legacy)',
description: 'Send tokens to multiple recipients at once',
icon: SMILEY_ICON,
href: '/batch/create',
},
{
title: 'Refund (legacy)',
description: 'Refund unclaimed peanut links back to sender',
icon: TRIANGLE_ICON,
href: '/refund',
needsIconAdjustment: true,
},
{
title: 'Docs (legacy)',
description: 'Learn about Peanut Protocol and its features',
icon: GITBOOK_BLACK_ICON,
href: 'https://docs.peanut.to/',
isExternal: true,
needsIconAdjustment: true,
},
]

const TryNow = () => {
Expand Down Expand Up @@ -59,10 +95,15 @@ const TryNow = () => {
<div
className={twMerge(
'hidden size-16 items-center justify-center rounded-full bg-purple-1 md:flex',
index === 0 ? 'p-4' : 'p-2'
index === 0 ? 'p-4' : 'p-2',
index === 6 && 'pt-4'
Comment on lines +98 to +99
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Refactor hardcoded index checks for better maintainability.

The hardcoded index checks (index === 6) are fragile and will break if the cards array order changes. Consider using a more robust approach.

-                                className={twMerge(
-                                    'hidden size-16 items-center justify-center rounded-full bg-purple-1 md:flex',
-                                    index === 0 ? 'p-4' : 'p-2',
-                                    index === 6 && 'pt-4'
-                                )}
+                                className={twMerge(
+                                    'hidden size-16 items-center justify-center rounded-full bg-purple-1 md:flex',
+                                    index === 0 ? 'p-4' : 'p-2',
+                                    card.title === 'Docs (legacy)' && 'pt-4'
+                                )}

Or better yet, add a specific flag to the card interface for special styling needs:

interface ITryNowCard {
    title: string
    description: string
    icon: StaticImageData | string
    href: string
    isExternal?: boolean
    needsIconAdjustment?: boolean
+   needsTopPadding?: boolean
}

Also applies to: 102-106, 115-119

🤖 Prompt for AI Agents
In src/components/Global/TryNow/index.tsx around lines 98 to 99, the code uses
hardcoded index checks like `index === 6` for styling, which is fragile and
breaks if the cards array changes. To fix this, update the card data structure
to include a specific boolean flag indicating special styling needs, then use
that flag in the rendering logic instead of index comparisons. Apply the same
change to lines 102-106 and 115-119 for consistency.

)}
>
<Image src={card.icon} alt={card.title} className="size-12" />
<Image
src={card.icon}
alt={card.title}
className={twMerge('size-12', card.needsIconAdjustment && '-mt-2')}
/>
</div>
<div className="flex items-center justify-normal gap-3">
<div
Expand All @@ -71,7 +112,11 @@ const TryNow = () => {
index === 0 ? 'p-4' : 'p-2'
)}
>
<Image src={card.icon} alt={card.title} className="size-12" />
<Image
src={card.icon}
alt={card.title}
className={twMerge('size-12', card.needsIconAdjustment && '-mt-1')}
/>
</div>
<div className="space-y-1.5">
<h2 className="text-lg font-extrabold md:text-center">{card.title}</h2>
Expand All @@ -84,17 +129,6 @@ const TryNow = () => {
</Link>
))}
</div>
<div className="flex items-center gap-2">
<Image src={Eyes} alt="eyes" className="size-6" />
<Link
href={'https://docs.peanut.to'}
target="_blank"
rel="noreferrer noopener"
className="min-w-fit text-sm hover:underline"
>
What is Peanut Protocol?
</Link>
</div>
</div>
)
}
Expand Down
91 changes: 49 additions & 42 deletions src/components/LandingPage/hero.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import { AboutPeanut, ButterySmoothGlobalMoney, HandThumbsUp, PeanutGuyGIF, Spar
import { Stack } from '@chakra-ui/react'
import { motion } from 'framer-motion'
import { useEffect, useState } from 'react'
import { MarqueeComp } from '../Global/MarqueeWrapper'
import { CloudImages, HeroImages } from './imageAssets'

type HeroProps = {
Expand All @@ -11,14 +10,15 @@ type HeroProps = {
visible: boolean
message?: string
}
cta?: {
ctas?: Array<{
label: string
href: string
}
primary: boolean
}>
buttonVisible?: boolean
}

export function Hero({ heading, marquee = { visible: false }, cta, buttonVisible }: HeroProps) {
export function Hero({ heading, marquee = { visible: false }, ctas, buttonVisible }: HeroProps) {
const [duration, setDuration] = useState(10)
const [screenWidth, setScreenWidth] = useState(typeof window !== 'undefined' ? window.innerWidth : 1200) // Added typeof check for SSR

Expand Down Expand Up @@ -65,45 +65,52 @@ export function Hero({ heading, marquee = { visible: false }, cta, buttonVisible
</Stack>
</div>

<div className="relative z-1">
{marquee && (
<MarqueeComp message={marquee.message} imageSrc={HandThumbsUp.src} backgroundColor="bg-yellow-1" />
)}
</div>

{cta?.href && cta?.label && (
<motion.div
className="fixed bottom-4 right-[calc(50%-60px)] z-20 sm:bottom-8"
initial={{
opacity: 0,
translateY: 4,
translateX: 4,
rotate: 0.75,
}}
animate={{
opacity: buttonVisible ? 1 : 0,
translateY: buttonVisible ? 0 : 20,
translateX: buttonVisible ? 0 : 20,
rotate: buttonVisible ? 0 : 1,
pointerEvents: buttonVisible ? 'auto' : 'none',
}}
whileHover={{
translateY: 6,
translateX: 3,
rotate: 0.75,
}}
transition={{ type: 'spring', damping: 15 }}
>
<img
src={Sparkle.src}
className="absolute -right-4 -top-4 h-auto w-5 sm:-right-5 sm:-top-5 sm:w-6"
alt="Sparkle"
/>
{ctas && ctas.length > 0 && (
<div className="fixed bottom-4 right-[calc(50%-120px)] z-20 flex gap-4 sm:bottom-8">
{ctas.map((cta, index) => (
<motion.div
key={index}
initial={{
opacity: 0,
translateY: 4,
translateX: 4,
rotate: 0.75,
}}
animate={{
opacity: buttonVisible ? 1 : 0,
translateY: buttonVisible ? 0 : 20,
translateX: buttonVisible ? 0 : 20,
rotate: buttonVisible ? 0 : 1,
pointerEvents: buttonVisible ? 'auto' : 'none',
}}
whileHover={{
translateY: 6,
translateX: 3,
rotate: 0.75,
}}
transition={{ type: 'spring', damping: 15 }}
>
{cta.primary && (
<img
src={Sparkle.src}
className="absolute -right-4 -top-4 h-auto w-5 sm:-right-5 sm:-top-5 sm:w-6"
alt="Sparkle"
/>
)}

<a href={cta.href} className="btn-purple px-5 shadow-md">
{cta.label}
</a>
</motion.div>
<a
href={cta.href}
className={`px-5 shadow-md ${
cta.primary
? 'btn-purple'
: 'btn bg-yellow-1 fill-n-1 text-n-1 hover:bg-yellow-1/90'
}`}
>
{cta.label}
</a>
</motion.div>
))}
</div>
)}
</div>
)
Expand Down
5 changes: 2 additions & 3 deletions src/components/Welcome/welcomeSDK.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ import {
SBF_PERSON,
SmileStars,
PEANUTMAN_HAPPY,
REDPACKET_LOTTIE,
TEAL_MOCKUP_1,
DROPDOWN_ICON,
} from '@/assets'
Expand Down Expand Up @@ -178,7 +177,7 @@ const testimonials = [
const defaultLottieOptions = {
loop: true,
autoplay: true,
animationData: REDPACKET_LOTTIE,
animationData: '/lottie/redpacket-lottie.json',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Verify animation data availability at runtime

The change from imported REDPACKET_LOTTIE to string path '/lottie/redpacket-lottie.json' shifts from build-time bundling to runtime loading. Ensure the animation file is available at this path and consider the performance implications of this change.


🏁 Script executed:

#!/bin/bash
# Check if the animation file exists at the expected path
fd -t f "redpacket-lottie.json" --exec ls -la {}

Length of output: 143


Ensure the JSON is served at “/lottie/redpacket-lottie.json” at runtime

We located redpacket-lottie.json under src/assets/lottie/, but referencing it via animationData: '/lottie/redpacket-lottie.json' requires that file to live in your app’s static‐served folder (e.g. public/lottie/) or be copied there by your build pipeline. Otherwise the Lottie player will 404 at runtime.

• Move

  • src/assets/lottie/redpacket-lottie.json
    public/lottie/redpacket-lottie.json

• Or update your bundler (e.g. add a CopyWebpackPlugin entry) to emit lottie/redpacket-lottie.json under dist/public so '/lottie/redpacket-lottie.json' resolves correctly

• After relocating/configuring, test both dev and production builds to confirm the file loads and measure any caching/performance impacts

🤖 Prompt for AI Agents
In src/components/Welcome/welcomeSDK.tsx at line 180, the animationData path
'/lottie/redpacket-lottie.json' expects the JSON file to be served from the
public static folder. To fix this, move the file from
src/assets/lottie/redpacket-lottie.json to public/lottie/redpacket-lottie.json,
or configure your build pipeline (e.g., using CopyWebpackPlugin) to copy it to
the appropriate public directory during build. After making this change, verify
that the file loads correctly in both development and production environments.

rendererSettings: {
preserveAspectRatio: 'xMidYMid slice',
},
Expand Down Expand Up @@ -333,7 +332,7 @@ export function WelcomeSDK() {
target="_blank"
>
<div className="mx-2 flex h-full items-center justify-center object-cover">
<Lottie animationData={REDPACKET_LOTTIE} loop={true} autoplay={true} />
<Lottie animationData={'/lottie/redpacket-lottie.json'} loop={true} autoplay={true} />
</div>
</a>
</div>
Expand Down
Loading