Skip to content
Draft
79 changes: 79 additions & 0 deletions apps/web/app/(base-org)/developers/verifications/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import { ButtonVariants } from 'apps/web/src/components/base-org/Button/types';
import Container from 'apps/web/src/components/base-org/Container';
import Title from 'apps/web/src/components/base-org/typography/Title';
import { TitleLevel } from 'apps/web/src/components/base-org/typography/Title/types';
import { ButtonWithLinkAndEventLogging } from 'apps/web/src/components/Button/ButtonWithLinkAndEventLogging';
import { CtaBanner } from 'apps/web/src/components/Developers/Shared/CtaBanner';
import { Customers } from 'apps/web/src/components/Developers/Verifications/Customers';
import { InfoCards } from 'apps/web/src/components/Developers/Verifications/InfoCards';
import { ValueProps } from 'apps/web/src/components/Developers/Verifications/ValueProps';
import verification from 'apps/web/src/components/Developers/Verifications/verification.svg';
import Image, { StaticImageData } from 'next/image';

export default async function Verifications() {
return (
<Container>
<main className="mb-32 flex min-h-screen w-full flex-col items-center gap-40 bg-black px-2 pt-20 md:px-0">
{/* Header */}
<div className="flex flex-col gap-2 pt-20 md:items-center">
<div className="flex items-center gap-2 pb-6 text-[#44C28D]">
<Image
src={verification as StaticImageData}
alt="verification"
width={32}
height={32}
className="h-5 w-5"
/>
<Title level={TitleLevel.Title3} className="font-bold">
Verifications
</Title>
</div>
<Title level={TitleLevel.Display3} className="font-bold max-sm:hidden">
Identify your high-quality users
</Title>
<Title level={TitleLevel.Title1} className="font-bold sm:hidden">
Identify your high-quality users
</Title>
<Title level={TitleLevel.Title3} className="max-w-2xl text-gray-muted md:text-center">
Verifications is the link that lets you verify over 500,000+ connected wallets and
Coinbase accounts of specific attributes.
</Title>

<div className="flex gap-6 pt-5">
<ButtonWithLinkAndEventLogging
eventName="verifications-get-started"
iconName="arrowRight"
variant={ButtonVariants.Secondary}
href="https://login.coinbase.com/signin"
target="_blank"
buttonClassNames="rounded-xl"
>
Start building
</ButtonWithLinkAndEventLogging>
</div>
</div>

<InfoCards />
<ValueProps />
<Customers />
<CtaBanner
title="Know your users"
description="Start building with Verifications today"
cta={
<ButtonWithLinkAndEventLogging
variant={ButtonVariants.Secondary}
iconName="arrowRight"
iconSize="12"
buttonClassNames="rounded-xl"
href="https://login.coinbase.com/signin"
target="_blank"
eventName="verifications-get-started"
>
Get started
</ButtonWithLinkAndEventLogging>
}
/>
</main>
</Container>
);
}
30 changes: 30 additions & 0 deletions apps/web/src/components/Developers/Shared/Card.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import Title from 'apps/web/src/components/base-org/typography/Title';
import { TitleLevel } from 'apps/web/src/components/base-org/typography/Title/types';
import { ReactNode } from 'react';

type CardProps = {
icon: ReactNode;
title: string;
description: string;
iconClassName: string;
className?: string;
};
export function Card({
icon,
title,
description,
iconClassName = 'text-white',
className,
}: CardProps) {
return (
<div className={`flex flex-col ${className}`}>
<div className={iconClassName}>{icon}</div>
<Title level={TitleLevel.Title3} className="pt-4 font-bold">
{title}
</Title>
<Title className="pt-2 text-dark-palette-foregroundMuted" level={TitleLevel.Title4}>
{description}
</Title>
</div>
);
}
27 changes: 27 additions & 0 deletions apps/web/src/components/Developers/Shared/CtaBanner.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
'use client';

import { ReactNode } from 'react';
import Title from 'apps/web/src/components/base-org/typography/Title';
import { TitleLevel } from 'apps/web/src/components/base-org/typography/Title/types';

type CtaBannerProps = {
title: string;
description: string;
cta?: ReactNode;
};

export function CtaBanner({ title, description, cta }: CtaBannerProps) {
return (
<section className="w-full bg-black">
<div className="flex flex-col items-center rounded-2xl bg-dark-palette-backgroundAlternate py-16">
<Title level={TitleLevel.Title1} as="h2">
{title}
</Title>
<Title level={TitleLevel.Title4} as="p" className="mt-2 text-center max-sm:max-w-[220px]">
{description}
</Title>
<div className="mt-8 flex flex-col justify-center gap-4 sm:flex-row">{cta}</div>
</div>
</section>
);
}
73 changes: 73 additions & 0 deletions apps/web/src/components/Developers/Shared/Marquee.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import { cn } from 'base-ui/utils/cn';
import { ComponentPropsWithoutRef } from 'react';

export type MarqueeProps = ComponentPropsWithoutRef<'div'> & {
/**
* Optional CSS class name to apply custom styles
*/
className?: string;
/**
* Whether to reverse the animation direction
* @default false
*/
reverse?: boolean;
/**
* Whether to pause the animation on hover
* @default false
*/
pauseOnHover?: boolean;
/**
* Content to be displayed in the marquee
*/
children: React.ReactNode;
/**
* Whether to animate vertically instead of horizontally
* @default false
*/
vertical?: boolean;
/**
* Number of times to repeat the content
* @default 4
*/
repeat?: number;
};

export function Marquee({
className,
reverse = false,
pauseOnHover = false,
children,
vertical = false,
repeat = 4,
...props
}: MarqueeProps) {
return (
<div
{...props}
className={cn(
'group flex overflow-hidden p-2 [--duration:40s] [--gap:1rem] [gap:var(--gap)]',
{
'flex-row': !vertical,
'flex-col': vertical,
},
className,
)}
>
{Array(repeat)
.fill(0)
.map(() => (
<div
key={crypto.randomUUID()}
className={cn('flex shrink-0 justify-around [gap:var(--gap)]', {
'animate-marquee flex-row': !vertical,
'animate-marquee-vertical flex-col': vertical,
'group-hover:[animation-play-state:paused]': pauseOnHover,
'[animation-direction:reverse]': reverse,
})}
>
{children}
</div>
))}
</div>
);
}
39 changes: 39 additions & 0 deletions apps/web/src/components/Developers/Shared/ValueProp.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import Title from 'apps/web/src/components/base-org/typography/Title';
import { TitleLevel } from 'apps/web/src/components/base-org/typography/Title/types';
import Image, { type StaticImageData } from 'next/image';

export type ValuePropProps = {
title: string;
description: string;
icon: StaticImageData;
};

export function ValueProp({ title, description, icon }: ValuePropProps) {
return (
<div className="w-full rounded-xl bg-dark-palette-backgroundAlternate px-6 py-5">
<div className="hidden w-full grid-cols-[auto_1fr] items-center md:grid">
<Image src={icon} alt={title} width={32} height={32} className="h-5 w-5" />
<div className="ml-14 flex items-center">
<Title level={TitleLevel.Title3} className="w-1/2 font-bold">
{title}
</Title>
<Title level={TitleLevel.Title4} className="w-1/2 text-dark-palette-foreground">
{description}
</Title>
</div>
</div>

<div className="flex flex-col md:hidden">
<Image src={icon} alt={title} width={32} height={32} className="h-5 w-5" />
<div className="flex flex-col gap-2 pt-20">
<Title level={TitleLevel.Title3} className="font-bold">
{title}
</Title>
<Title level={TitleLevel.Title4} className="text-dark-palette-foreground">
{description}
</Title>
</div>
</div>
</div>
);
}
39 changes: 39 additions & 0 deletions apps/web/src/components/Developers/Verifications/Customers.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import Title from 'apps/web/src/components/base-org/typography/Title';
import { TitleLevel } from 'apps/web/src/components/base-org/typography/Title/types';
import { Marquee } from 'apps/web/src/components/Developers/Shared/Marquee';
import icebreaker from 'apps/web/src/components/Developers/Verifications/icebreaker.svg';
import deform from 'apps/web/src/components/Developers/Verifications/deform.svg';
import gitcoin from 'apps/web/src/components/Developers/Verifications/gitcoin.svg';
import talentProtocol from 'apps/web/src/components/Developers/Verifications/talent-protocol.svg';
import Image, { StaticImageData } from 'next/image';

export function Customers() {
return (
<div className="flex w-full flex-col gap-10 tracking-tight">
<Title level={TitleLevel.Title1}>
Powering the most consumer-friendly applications onchain.
</Title>
<div className="relative flex w-full flex-col items-center justify-center overflow-hidden">
<Marquee className="[--duration:20s]" pauseOnHover>
<div className="p-4 px-8">
<Image src={icebreaker as StaticImageData} alt="icebreaker" className="h-10 w-auto" />
</div>

<div className="p-4 px-8">
<Image src={deform as StaticImageData} alt="deform" className="h-10 w-auto" />
</div>
<div className="p-4 px-8">
<Image src={gitcoin as StaticImageData} alt="gitcoin" className="h-10 w-auto" />
</div>
<div className="p-4 px-8">
<Image
src={talentProtocol as StaticImageData}
alt="talentProtocol"
className="h-10 w-auto"
/>
</div>
</Marquee>
</div>
</div>
);
}
62 changes: 62 additions & 0 deletions apps/web/src/components/Developers/Verifications/InfoCards.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import { Card } from 'apps/web/src/components/Developers/Shared/Card';
import key from 'apps/web/src/components/Developers/Verifications/key.svg';
import identityCard from 'apps/web/src/components/Developers/Verifications/identityCard.svg';
import complianceProduct from 'apps/web/src/components/Developers/Verifications/complianceProduct.svg';
import Image, { StaticImageData } from 'next/image';

const INFO_CARDS = [
{
icon: (
<Image src={key as StaticImageData} alt="key" width={32} height={32} className="h-8 w-8" />
),
title: 'Access control',
description:
'Implement granular access control using verified Coinbase attestations. Perfect for gating features, content, or entire applications.',
},
{
icon: (
<Image
src={identityCard as StaticImageData}
alt="identityCard"
width={32}
height={32}
className="h-8 w-8"
/>
),
title: 'Identity verification',
description:
'Seamlessly verify user identities without handling sensitive data. Reduce fraud and enhance security in your DeFi applications.',
},
{
icon: (
<Image
src={complianceProduct as StaticImageData}
alt="complianceProduct"
width={32}
height={32}
className="h-8 w-8"
/>
),
title: 'Compliance & reporting',
description:
'Build compliant applications with verifiable attestations. Perfect for KYC requirements and regulatory reporting.',
},
];

export function InfoCards() {
return (
<div className="grid w-full grid-cols-1 gap-20 md:grid-cols-3">
{INFO_CARDS.map((card) => {
return (
<Card
key={card.title}
icon={card.icon}
title={card.title}
description={card.description}
iconClassName="text-[#C9A4FA]"
/>
);
})}
</div>
);
}
Loading