Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(home): stats section #9

Merged
merged 22 commits into from
Feb 14, 2024
Merged
Show file tree
Hide file tree
Changes from 17 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
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,14 @@
"dependencies": {
"@headlessui/react": "^1.7.18",
"next": "14.1.0",
"numeral": "^2.0.6",
"react": "^18",
"react-dom": "^18",
"tailwind-merge": "^2.2.1"
},
"devDependencies": {
"@types/node": "^20",
"@types/numeral": "^2.0.5",
"@types/react": "^18",
"@types/react-dom": "^18",
"autoprefixer": "^10.0.1",
Expand Down
43 changes: 43 additions & 0 deletions src/app/(routes)/_components/hero-section.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import Image from "next/image";

import { Hero } from "../../_components/hero";
import { Text } from "../../_components/text";
import { ArrowRightIcon } from "../../_components/icons/arrow-right";
import landingHeroSrc from "../../_assets/landing-1.png";
import { INFORMATION_LINKS } from "../../_constants";

export function HeroSection() {
return (
<Hero>
<div className="container mx-auto flex flex-col items-center gap-16 px-4 pb-16 pt-8 md:flex-row-reverse">
<div className="flex max-w-80 flex-1 sm:max-w-100 md:max-w-full">
<Image src={landingHeroSrc} alt="Across protocol diagram" priority={true} />
</div>
<div className="flex flex-1 flex-col gap-6">
<Text variant="heading-1" className="text-center md:text-left">
<span className="text-aqua-100">Interoperability</span>
<br />
<span className="text-light-100">Powered By</span>{" "}
<br className="hidden md:block" />
<span className="text-aqua-100">Intents</span>
</Text>
<Text variant="body-nums" className="max-w-[433px] text-center md:text-left">
A new paradigm in cross-chain experiences, seamlessly connecting users with
applications.
</Text>
<a
className="flex cursor-pointer flex-row items-center justify-center gap-2 text-aqua-100 md:justify-start"
href={INFORMATION_LINKS.docs.href}
target="_blank"
rel="noopener noreferrer"
>
<Text variant="cap-case">start building</Text>
<div className="flex h-5 w-5 items-center justify-center rounded-full bg-aqua-100">
<ArrowRightIcon />
</div>
</a>
</div>
</div>
</Hero>
);
}
83 changes: 83 additions & 0 deletions src/app/(routes)/_components/stats-section.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import { Text } from "../../_components/text";
import { StatBox } from "../../_components/stat-box";

import { getProtocolStats } from "../../_lib/scraper";
import { humanReadableNumber } from "../../_lib/format";

const fallbackStats = {
totalVolumeUsd: "$5B+",
totalDeposits: "3M+",
avgFillTimeInMinutes: "1m",
bridgeFee: "<$1",
};

async function getFormattedStatsData() {
try {
const protocolStats = await getProtocolStats();

return {
totalVolumeUsd: `$${humanReadableNumber(protocolStats.totalVolumeUsd)}`,
totalDeposits: `${humanReadableNumber(protocolStats.totalDeposits)}`,
avgFillTimeInMinutes: `${protocolStats.avgFillTimeInMinutes < 1 ? "<" : ""} ${Math.max(
protocolStats.avgFillTimeInMinutes,
1,
)}m`,
bridgeFee: "<$1",
};
} catch (error) {
console.error("Failed to fetch stats");
return fallbackStats;
}
}

export async function StatsSection() {
const formattedStatsData = await getFormattedStatsData();
return (
<section className="container mx-auto flex flex-col gap-10 px-4 sm:gap-16">
<div className="flex flex-col items-center gap-4">
<Text variant="cap-case" className="text-aqua-100 md:text-center">
power in originality
</Text>
<Text variant="heading-2" className="text-center capitalize text-light-200">
Production ready <br />
Empirically Proven
</Text>
<Text className="max-w-xl text-center">
Across is the only cross-chain intents protocol in production today, enabling
the fastest and lowest-cost interoperability solution without security
tradeoffs.
</Text>
</div>
<div className="grid grid-cols-2 gap-3 sm:grid-cols-4">
<StatBox
title="volume"
value={formattedStatsData.totalVolumeUsd}
titleClassName="text-teal-100"
className="group-hover:border-teal-100"
dividerClassName="group-hover:bg-teal-100/[.5]"
/>
<StatBox
title="transaction"
value={formattedStatsData.totalDeposits}
titleClassName="text-orange-100"
className="group-hover:border-orange-100"
dividerClassName="group-hover:bg-orange-100/[.5]"
/>
<StatBox
title="avg. fill time"
value={formattedStatsData.avgFillTimeInMinutes}
titleClassName="text-purple-100"
className="group-hover:border-purple-100"
dividerClassName="group-hover:bg-purple-100/[.5]"
/>
<StatBox
title="bridge 1 eth"
value={formattedStatsData.bridgeFee}
titleClassName="text-aqua-100"
className="group-hover:border-aqua-100"
dividerClassName="group-hover:bg-aqua-100/[.5]"
/>
</div>
</section>
);
}
65 changes: 65 additions & 0 deletions src/app/(routes)/_components/technology-section.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import { ChatIcon, FeatherIcon, BlocksDiagonalIcon } from "../../_components/icons";
import { Text } from "../../_components/text";
import landingTechnologySrc from "../../_assets/landing-2.png";
import landingTechnologyMobileSrc from "../../_assets/landing-2-mobile.png";

const sections = [
{
Icon: ChatIcon,
title: "User-Centric",
body: "Intents replace explicit execution steps with implicit user outcomes, relying on a competitive network of market makers to fulfill outcomes. Cross-chain intents are a cross-chain limit order plus an action to execute.",
},
{
Icon: FeatherIcon,
title: "Elegant Abstraction",
body: "Across connects users and applications via intents, not blockchains to other blockchains via complex or trusted message passing. Developers only need to attach a standard order to protocol actions to create seamless cross-chain experiences.",
},
{
Icon: BlocksDiagonalIcon,
title: "Modular Interoperability",
body: (
<>
Cross-chain intents are powered by a modular system of 3 layers:
<ol className="list-decimal pl-6">
<li>Request for quote mechanism</li>
<li>Network of competitive market makers</li>
<li>Settlement layer to escrow user input funds, verify, and repay relayers</li>
</ol>
</>
),
},
];

export function TechnologySection() {
return (
<section className="container mx-auto flex flex-col gap-16 px-4 sm:gap-24 ">
<div className="flex flex-col gap-4">
<Text variant="cap-case" className="text-aqua-100 md:text-center">
the technology
</Text>
<Text variant="heading-2" className="capitalize text-light-200 md:text-center">
How intents work
</Text>
</div>
<div className="grid grid-cols-1 gap-12 sm:grid-cols-2 sm:gap-y-16 md:grid-cols-3">
{sections.map((section) => (
<div key={section.title}>
<section.Icon className="mb-8 h-14 w-14" />
<Text variant="heading-4" className="mb-4 text-light-200">
{section.title}
</Text>
<Text className="text-light-300">{section.body}</Text>
</div>
))}
</div>
<div className="flex flex-col items-center">
<div className="flex max-w-100 flex-1 sm:max-w-lg md:max-w-full">
<picture>
<source srcSet={landingTechnologySrc.src} media="(min-width: 760px)" />
<img src={landingTechnologyMobileSrc.src} alt="MDN" />
</picture>
</div>
</div>
</section>
);
}
9 changes: 6 additions & 3 deletions src/app/(routes)/across-bridge/page.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Metadata } from "next";
import Image from "next/image";

import { Hero } from "@/app/_components/hero";

export const metadata: Metadata = {
title: "Across Bridge",
Expand All @@ -8,8 +9,10 @@ export const metadata: Metadata = {

export default function BridgeLanding() {
return (
<main className="flex min-h-screen flex-col items-center justify-between p-24">
Across Bridge
<main className="z-0 min-h-screen overflow-hidden">
<Hero>
<div className="py-10 text-center">Across Bridge</div>
</Hero>
</main>
);
}
9 changes: 6 additions & 3 deletions src/app/(routes)/across-plus/page.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Metadata } from "next";
import Image from "next/image";

import { Hero } from "@/app/_components/hero";

export const metadata: Metadata = {
title: "Across Plus",
Expand All @@ -8,8 +9,10 @@ export const metadata: Metadata = {

export default function PlusLanding() {
return (
<main className="flex min-h-screen flex-col items-center justify-between p-24">
Across+
<main className="z-0 min-h-screen overflow-hidden">
<Hero>
<div className="py-10 text-center">Across Plus</div>
</Hero>
</main>
);
}
9 changes: 6 additions & 3 deletions src/app/(routes)/across-settlement/page.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Metadata } from "next";
import Image from "next/image";

import { Hero } from "@/app/_components/hero";

export const metadata: Metadata = {
title: "Across Settlement",
Expand All @@ -8,8 +9,10 @@ export const metadata: Metadata = {

export default function SettlementLanding() {
return (
<main className="flex min-h-screen flex-col items-center justify-between p-24">
Settlement
<main className="z-0 min-h-screen overflow-hidden">
<Hero>
<div className="py-10 text-center">Across Settlement</div>
</Hero>
</main>
);
}
9 changes: 9 additions & 0 deletions src/app/(routes)/globals.css
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
@tailwind base;
@tailwind components;
@tailwind utilities;

:root {
/* These variables are used for the infinite scrolling effect in _components/partners-carousel.tsx */
--no-of-slides: 6;
--slides-in-view: 4;
--slide-width: 200px;
--slide-height: 56px;
--iteration-time: 15s;
}
6 changes: 5 additions & 1 deletion src/app/(routes)/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,11 @@ import { Footer } from "@/app/_components/footer";

import "./globals.css";

const inter = Barlow({ subsets: ["latin"], weight: ["200", "300", "400", "500"] });
const inter = Barlow({
subsets: ["latin"],
weight: ["200", "300", "400", "500"],
display: "swap",
});

export const metadata: Metadata = {
title: {
Expand Down
10 changes: 8 additions & 2 deletions src/app/(routes)/page.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,20 @@
import { Metadata } from "next";

import { HeroSection } from "./_components/hero-section";
import { TechnologySection } from "./_components/technology-section";
import { StatsSection } from "./_components/stats-section";

export const metadata: Metadata = {
title: "Home | Across Protocol",
description: "Interoperability powered by Intents.",
};

export default function Home() {
return (
<main className="flex min-h-screen flex-col items-center justify-between p-24">
Home
<main className="z-0 flex min-h-screen flex-col gap-16 overflow-hidden px-4">
<HeroSection />
<TechnologySection />
<StatsSection />
</main>
);
}
Binary file added src/app/_assets/landing-1.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 src/app/_assets/landing-2-mobile.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 src/app/_assets/landing-2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion src/app/_components/footer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ function FooterBoxItem(props: {
<IconBox className={twMerge("h-10 w-10", props.item.iconContainerClassName)}>
<props.item.Icon className={props.item.iconClassName} />
</IconBox>
<div className=" text-sm lining-nums tabular-nums">{props.item.label}</div>
<div className="text-sm lining-nums tabular-nums">{props.item.label}</div>
</div>
);
}
8 changes: 4 additions & 4 deletions src/app/_components/header-nav/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ export function HeaderNav() {
);

return (
<header className="sticky top-0 bg-grey-dark">
<header className="sticky top-0 z-10 bg-grey-dark">
<nav className="mx-auto max-w-7xl p-4">
<div className="flex flex-row items-center justify-between">
<div className="flex flex-row items-center">
Expand All @@ -96,7 +96,7 @@ export function HeaderNav() {
)}
/>
</Link>
<div className="hidden flex-row items-center gap-6 sm:flex">
<div className="hidden flex-row items-center gap-6 md:flex">
<Link href="/">Home</Link>
<FlyoutMenu buttonLabel="Products" menuItems={productsNavigationItems} />
<FlyoutMenu
Expand All @@ -109,7 +109,7 @@ export function HeaderNav() {
<div className="flex flex-row gap-3">
<Button
className={twMerge(
"hidden transition sm:block",
"hidden transition md:block",
pathname === "/across-plus"
? "border-teal-100/[.05] bg-teal-100/[.05] text-teal-100"
: pathname === "/across-settlement"
Expand All @@ -121,7 +121,7 @@ export function HeaderNav() {
</Button>
{/* Only show menu button on mobile */}
<button
className="flex h-10 w-10 items-center justify-center rounded-full border border-grey-600 sm:hidden"
className="flex h-10 w-10 items-center justify-center rounded-full border border-grey-600 md:hidden"
onClick={() => setIsMenuOpen((isMenuOpen) => !isMenuOpen)}
>
{isMenuOpen ? <MinusIcon /> : <MenuIcon />}
Expand Down
4 changes: 2 additions & 2 deletions src/app/_components/header-nav/mobile-menu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,10 @@ export function MobileMenu(props: {
leaveTo="opacity-0 translate-y-1"
show={props.isMenuOpen}
>
<div className="absolute flex min-h-screen w-full flex-col gap-6 bg-grey-dark p-4 sm:hidden">
<div className="absolute flex min-h-screen w-full flex-col gap-6 bg-grey-dark p-4 md:hidden">
<Button
className={twMerge(
"sm:hidden",
"md:hidden",
props.pathname === "/across-plus"
? "border-teal-100/[.05] bg-teal-100/[.05] text-teal-100"
: props.pathname === "/across-settlement"
Expand Down
15 changes: 15 additions & 0 deletions src/app/_components/hero.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { ComponentProps } from "react";
import { twMerge } from "tailwind-merge";

import { PartnersTicker } from "./partners-ticker";

type HeroProps = ComponentProps<"section">;

export function Hero({ className, children, ...props }: HeroProps) {
return (
<section className={twMerge("min-h-screen", className)} {...props}>
{children}
<PartnersTicker />
</section>
);
}
Loading
Loading