Skip to content
Draft
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
343 changes: 11 additions & 332 deletions bun.lock

Large diffs are not rendered by default.

1 change: 0 additions & 1 deletion declaration.d.ts

This file was deleted.

6 changes: 0 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,30 +19,24 @@
"prepare": "husky"
},
"dependencies": {
"@cowprotocol/cow-sdk": "5.10.3",
"@headlessui/react": "2.2.9",
"@plausible-analytics/tracker": "^0.4.4",
"@rainbow-me/rainbowkit": "2.2.9",
"@react-hookz/web": "24.0.4",
"@tanstack/react-query": "5.90.20",
"@tanstack/react-virtual": "3.13.12",
"cross-fetch": "4.1.0",
"ethers": "5.7.2",
"framer-motion": "12.29.2",
"graphql": "16.12.0",
"react": "19.2.3",
"react-dom": "19.2.3",
"react-hot-toast": "2.6.0",
"react-markdown": "10.1.0",
"react-paginate": "8.3.0",
"react-rewards": "2.1.0",
"react-router": "7.13.0",
"recharts": "2.15.4",
"use-indexeddb": "2.0.2",
"vaul": "1.1.2",
"viem": "2.45.0",
"wagmi": "2.18.2",
"xxhashjs": "0.2.2",
"zod": "4.3.6"
},
"devDependencies": {
Expand Down
1 change: 1 addition & 0 deletions public/Curve.svg
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 public/aerodrome-typemark.svg
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 public/katana-typemark.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/partner-aerodrome.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/partner-curve.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/partner-katana.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/partner-morpho.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
22 changes: 22 additions & 0 deletions public/partner-noise-perlin.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/partner-pooltogether.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/partner-velodrome.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 public/pooltogether.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
14 changes: 13 additions & 1 deletion src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,12 @@ import { useCurrentApp } from '@shared/hooks/useCurrentApp'
import { IconAlertCritical } from '@shared/icons/IconAlertCritical'
import { IconAlertError } from '@shared/icons/IconAlertError'
import { IconCheckmark } from '@shared/icons/IconCheckmark'
import { resolvePartnerFromPath } from '@shared/partners/resolvePartnerFromPath'
import { cl } from '@shared/utils'
import { isIframe } from '@shared/utils/helpers'
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
import type { ReactElement } from 'react'
import { useLayoutEffect } from 'react'
import { useEffect, useLayoutEffect } from 'react'
import { Toaster } from 'react-hot-toast'
import { useLocation } from 'react-router'
import { WagmiProvider } from 'wagmi'
Expand Down Expand Up @@ -60,6 +61,7 @@ function App(): ReactElement {

// Determine dynamic meta for vault detail pages
const asPath = location.pathname
const partnerSlug = resolvePartnerFromPath(asPath)

// Get most basic og and uri info
const ogBaseUrl = 'https://og.yearn.fi'
Expand All @@ -69,6 +71,15 @@ function App(): ReactElement {
? `${ogBaseUrl}/api/og/yearn/vault/${chainID}/${address}`
: manifest.og || 'https://yearn.fi/og.png'
const pageUri = isVaultDetailPage ? `https://yearn.fi${asPath}` : manifest.uri || 'https://yearn.fi'
const canonical = isVaultDetailPage ? undefined : manifest.canonical || (partnerSlug ? pageUri : undefined)

useEffect(() => {
if (!partnerSlug) {
document.documentElement.removeAttribute('data-partner')
return
}
document.documentElement.setAttribute('data-partner', partnerSlug)
}, [partnerSlug])

return (
<>
Expand All @@ -79,6 +90,7 @@ function App(): ReactElement {
themeColor={'#000000'}
og={ogUrl}
uri={pageUri}
canonical={canonical}
/>
<WithFonts>
<main className={'font-aeonik size-full min-h-screen'}>
Expand Down
6 changes: 6 additions & 0 deletions src/components/pages/aerodrome/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import VaultsPage from '@pages/vaults/index'
import type { ReactElement } from 'react'

export default function AerodromePage(): ReactElement {
return <VaultsPage />
}
6 changes: 6 additions & 0 deletions src/components/pages/curve/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import VaultsPage from '@pages/vaults/index'
import type { ReactElement } from 'react'

export default function CurvePage(): ReactElement {
return <VaultsPage />
}
6 changes: 6 additions & 0 deletions src/components/pages/katana/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import VaultsPage from '@pages/vaults/index'
import type { ReactElement } from 'react'

export default function KatanaPage(): ReactElement {
return <VaultsPage />
}
37 changes: 0 additions & 37 deletions src/components/pages/landing/components/common/Header.tsx

This file was deleted.

Empty file.
19 changes: 12 additions & 7 deletions src/components/pages/landing/components/sections/Partners.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,39 +15,44 @@ const partners: TPartner[] = [
{
image: '/landing/x/curve.png',
alt: 'Curve',
href: 'https://curve.yearn.space/'
href: '/curve'
},
{
image: '/landing/x/morpho.png',
alt: 'Morpho',
href: 'https://morpho.yearn.space/'
href: '/morpho'
},
{
image: '/landing/x/katana.png',
alt: 'Katana',
href: 'https://katana.yearn.space/'
href: '/katana'
},
{
image: '/landing/x/aerodrome.png',
alt: 'Aerodrome',
href: 'https://aerodrome.yearn.space/'
href: '/aerodrome'
},
{
image: '/landing/x/velodrome.png',
alt: 'Velodrome',
href: 'https://velodrome.yearn.space/'
href: '/velodrome'
},
{
image: '/landing/x/pooltogether.png',
alt: 'PoolTogether',
href: 'https://pooltogether.yearn.space/'
href: '/pooltogether'
}
]

const PartnerLogo: FC<TPartner> = ({ image, alt, href, size = 60 }) => {
const [isHovered, setIsHovered] = useState(false)
const handlePartnerClick = (): void => {
if (href.startsWith('/')) {
window.scrollTo(0, 0)
}
}
return (
<Link href={href} className={'block flex-1 min-w-0'}>
<Link href={href} className={'block flex-1 min-w-0'} onClick={handlePartnerClick}>
<div
className={
'relative flex h-[56px] min-[375px]:h-[72px] min-h-[44px] cursor-pointer items-center justify-center rounded-lg bg-gradient-to-r from-blue-700 to-blue-800 p-2 min-[375px]:p-3 transition-colors duration-200 hover:opacity-80 sm:h-20 sm:p-4 lg:h-full lg:p-6'
Expand Down
4 changes: 0 additions & 4 deletions src/components/pages/landing/utils/scrollToHash.ts

This file was deleted.

6 changes: 6 additions & 0 deletions src/components/pages/morpho/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import VaultsPage from '@pages/vaults/index'
import type { ReactElement } from 'react'

export default function MorphoPage(): ReactElement {
return <VaultsPage />
}
116 changes: 116 additions & 0 deletions src/components/pages/partners/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
import { Breadcrumbs } from '@shared/components/Breadcrumbs'
import { getAllPartnerConfigs } from '@shared/partners/registry'
import type { ReactElement } from 'react'
import Link from '/src/components/Link'

type TPartnersTile = {
title: string
subtitle: string
href: string
backgroundImage?: string
}

const PARTNER_SUBHEADINGS: Record<string, string> = {
katana: 'Enter the Dojo, deposit on Katana for yields with KAT incentives',
pooltogether: 'Feeling lucky Anon? Win mega yield payouts with prize Vaults.',
curve: "If it's on Curve, you'll get the best max boosted yields with Yearn.",
aerodrome: 'Liftoff for great yields, with Aerodrome on Yearn.',
morpho: 'Time to feel the 🦋 effect!',
velodrome: 'Wear the yield yellow jersey with Velodrome.'
}

function buildPartnerTiles(): TPartnersTile[] {
const partnerTiles = getAllPartnerConfigs().map((partner) => ({
title: `Yearn X ${partner.displayName}`,
subtitle: PARTNER_SUBHEADINGS[partner.slug] ?? partner.manifest.description,
href: `/${partner.slug}`,
backgroundImage: `/partner-${partner.slug}.png`
}))

return [
{
title: 'All Yearn Vaults',
subtitle: 'Browse the full Yearn vault catalog across all chains.',
href: '/vaults'
},
...partnerTiles,
{
title: 'Partner With Yearn',
subtitle: 'Looking to collaborate with Yearn? Reach out to explore partnership opportunities.',
href: 'https://partners.yearn.fi'
}
]
}

export default function PartnersPage(): ReactElement {
const tiles = buildPartnerTiles()

return (
<div className={'min-h-[calc(100vh-var(--header-height))] w-full bg-app'}>
<div className={'mx-auto w-full max-w-[1232px] px-4'}>
<div className={'sticky top-[var(--header-height)] z-40 bg-app py-2'}>
<Breadcrumbs
className={'mb-0'}
items={[
{ label: 'Home', href: '/' },
{ label: 'Partners', href: '/partners', isCurrent: true }
]}
/>
</div>

<div className={'mb-6'}>
<h1 className={'text-3xl font-black text-text-primary'}>{'Yearn X Partners'}</h1>
<p className={'mt-2 max-w-[760px] text-sm text-text-secondary'}>
{'Explore dedicated partner experiences, browse all vaults, or reach out about partnering with Yearn.'}
</p>
</div>

<div className={'grid gap-3 sm:grid-cols-2 lg:grid-cols-4'}>
{tiles.map((tile) => (
<Link key={tile.href} href={tile.href} className={'group block'}>
<article
className={
'relative h-[280px] overflow-hidden rounded-xl border border-white/15 bg-surface shadow-[0_0_0_1px_rgba(255,255,255,0.02)] transition-transform duration-300 group-hover:-translate-y-0.5 group-hover:shadow-xl'
}
style={
tile.backgroundImage
? {
backgroundImage: `url(${tile.backgroundImage})`,
backgroundSize: 'cover',
backgroundPosition: 'center',
backgroundRepeat: 'no-repeat',
backgroundOrigin: 'padding-box',
backgroundClip: 'padding-box'
}
: {
backgroundColor: '#0D2A68',
backgroundOrigin: 'padding-box',
backgroundClip: 'padding-box'
}
}
>
<div
className={
'pointer-events-none absolute inset-0 opacity-0 transition-opacity duration-300 group-hover:opacity-50'
}
style={{
backgroundImage:
'linear-gradient(180deg, rgba(3,11,26,0.86) 0%, rgba(3,11,26,0.72) 40%, rgba(3,11,26,0.64) 100%)',
backgroundRepeat: 'no-repeat',
backgroundSize: '100% 100%'
}}
/>
<div className={'relative z-10 flex h-full flex-col p-5 text-white'}>
<div className={'h-[40%]'}>
<h2 className={'text-2xl font-black leading-tight'}>{tile.title}</h2>
<p className={'mt-2 text-sm leading-snug text-white/90'}>{tile.subtitle}</p>
</div>
</div>
</article>
</Link>
))}
</div>
</div>
</div>
)
}
6 changes: 6 additions & 0 deletions src/components/pages/pooltogether/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import VaultsPage from '@pages/vaults/index'
import type { ReactElement } from 'react'

export default function PoolTogetherPage(): ReactElement {
return <VaultsPage />
}
Loading