Skip to content

Commit

Permalink
feat(bridge): hero + features sections (#15)
Browse files Browse the repository at this point in the history
* feat(plus): hero and features sections

* fix: hero text spacing

* fix: partners ticker title

* fix: make partners ticker title dynamic

* feat(plus): use cases section

* fix: desktop styles

* fix: image src sets

* fixup

* feat(plus): chains + get started sections

* feat(settlement): page

* feat(bridge): hero + features sections

* fix: design qa

* fix: use custom tw-merge

* fixup

* fixup

* fix: qa

* fix: qa

* fixup

* fix: build

* fixup
  • Loading branch information
dohaki authored Feb 20, 2024
1 parent 57d1112 commit 3e6823d
Show file tree
Hide file tree
Showing 13 changed files with 214 additions and 54 deletions.
55 changes: 55 additions & 0 deletions src/app/(routes)/across-bridge/_components/features-section.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import Image from "next/image";

import {
CodeIcon,
ShieldLargeIcon,
DoubleChevronRightIcon,
DollarIcon,
} from "@/app/_components/icons";
import { Text } from "@/app/_components/text";
import { FeaturesGrid } from "@/app/_components/features-grid";
import bridge2Image from "@/app/_assets/bridge-2.png";

const features = [
{
Icon: <CodeIcon className="h-14 w-14" />,
title: "efficient",
body: "With Across, bridging your tokens at the fastest speed and lowest cost does not come with security tradeoffs. How? At Across, only bridge users or bridge LPs never shoulder the risks associated with cross-chain transfers.",
},
{
Icon: <ShieldLargeIcon className="h-14 w-14" />,
title: "Secure",
body: "Using canonical assets is the only trustless way to transfer value, which is why Across only circulates genuine tokens, never representative or synthetic assets. In every transfer facilitated by Across, user assets are never put at risk.",
},
{
Icon: <DoubleChevronRightIcon className="h-14 w-14" />,
title: "Fast",
body: "Intents architecture enables the fastest bridge experience. By using a network of third party relayers, incentivized to quickly fill transfers, fill times are usually completed in a few seconds.",
},
{
Icon: <DollarIcon className="h-14 w-14" />,
title: "Superior",
body: "Canonical assets are the only trustless way to transfer value, which is why Across only circulates canonical tokens, never representative or synthetic ones. In every transfer at Across, users always receive canonical assets.",
},
];

export function FeaturesSection() {
return (
<section className="container mx-auto -mt-32 flex flex-col gap-16 px-4 sm:gap-24 md:-mt-48">
<Image
src={bridge2Image}
alt="Across settlement layers graphic"
className="-mb-16 self-center sm:-mb-24 sm:max-w-[514px]"
/>
<div className="flex flex-col gap-4">
<Text variant="cap-case" className="text-center text-aqua-100">
built for safe travels
</Text>
<Text variant="heading-2" className="text-center capitalize text-light-200">
Engineered for best execution
</Text>
</div>
<FeaturesGrid features={features} />
</section>
);
}
42 changes: 42 additions & 0 deletions src/app/(routes)/across-bridge/_components/hero-section.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import Image from "next/image";

import { Hero } from "@/app/_components/hero";
import { Text } from "@/app/_components/text";
import { BridgeNowLink } from "@/app/_components/bridge-now-link";
import { ArrowRightIcon } from "@/app/_components/icons/arrow-right";
import bridgeHeroImage from "@/app/_assets/bridge-hero.png";

export function HeroSection() {
return (
<Hero title="supported chains">
<div className="container mx-auto flex flex-col items-center gap-16 px-4 pb-16 pt-8 md:flex-row-reverse md:gap-8 md:pt-16">
<div className="flex max-w-80 flex-1 sm:max-w-100 md:max-w-full">
<Image src={bridgeHeroImage} alt="Across bridge ui" priority={true} />
</div>
<div className="flex flex-1 flex-col gap-6">
<Text
variant="heading-1"
className="text-center tracking-tight-5 sm:tracking-tight-2 md:text-left md:tracking-tight-1"
>
<span className="text-aqua-100">Bridge</span>{" "}
<span className="text-light-100">Without</span>{" "}
<br className="block sm:hidden md:block" />
<span className="text-aqua-100">Compromise</span>
</Text>
<div className="flex w-full flex-row justify-center md:justify-start">
<Text variant="body-nums" className="max-w-[430px] text-center md:text-left">
Experience extraordinarily fast and cost-effective cross-chain bridging,
secured by an intents-based architecture.
</Text>
</div>
<BridgeNowLink className="flex cursor-pointer flex-row items-center justify-center gap-2 text-aqua-100 md:justify-start">
<Text variant="cap-case">bridge now</Text>
<div className="flex h-5 w-5 items-center justify-center rounded-full bg-aqua-100">
<ArrowRightIcon />
</div>
</BridgeNowLink>
</div>
</div>
</Hero>
);
}
8 changes: 6 additions & 2 deletions src/app/(routes)/across-bridge/page.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,18 @@
import { Metadata } from "next";

import { HeroSection } from "./_components/hero-section";
import { FeaturesSection } from "./_components/features-section";

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

export default function BridgeLanding() {
return (
<main className="z-0 min-h-screen overflow-hidden">
<div className="py-10 text-center">Across Bridge</div>
<main className="z-0 mb-24 flex min-h-screen flex-col gap-24 overflow-hidden px-4 sm:gap-32 md:gap-48">
<HeroSection />
<FeaturesSection />
</main>
);
}
14 changes: 3 additions & 11 deletions src/app/(routes)/across-plus/_components/features-section.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
ArrowUpRightThickIcon,
} from "@/app/_components/icons";
import { Text } from "@/app/_components/text";
import { FeaturesGrid } from "@/app/_components/features-grid";
import { INFORMATION_LINKS } from "@/app/_constants";

const features = [
Expand Down Expand Up @@ -42,16 +43,7 @@ export function FeaturesSection() {
Seamless Cross-chain Onboarding
</Text>
</div>
<div className="grid grid-cols-1 gap-12 sm:gap-y-16 md:grid-cols-2">
{features.map((feature) => (
<div key={feature.title}>
{feature.Icon}
<Text variant="heading-4" className="mb-4 mt-8 capitalize text-light-200">
{feature.title}
</Text>
<Text className="max-w-[520px] text-light-300">{feature.body}</Text>
</div>
))}
<FeaturesGrid features={features}>
<div className="flex flex-col items-center gap-8 rounded-2xl bg-teal-100/[.02] p-6 shadow-md sm:items-start">
<div className="flex flex-col items-center justify-center self-center rounded-lg bg-teal-100/[.05] p-2">
<Text variant="cap-case" className="text-teal-100">
Expand All @@ -78,7 +70,7 @@ export function FeaturesSection() {
</a>
</div>
</div>
</div>
</FeaturesGrid>
</section>
);
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import Image from "next/image";

import {
BlocksConnectedIcon,
ChecklistIcon,
CheckmarkIcon,
CrossChainIcon,
} from "@/app/_components/icons";
import { Text } from "@/app/_components/text";
import { FeaturesGrid } from "@/app/_components/features-grid";
import settlement2Image from "@/app/_assets/settlement-2.png";
import Image from "next/image";

const features = [
{
Expand Down Expand Up @@ -49,17 +51,7 @@ export function FeaturesSection() {
Best Execution
</Text>
</div>
<div className="grid grid-cols-1 gap-12 sm:gap-y-16 md:grid-cols-2">
{features.map((feature) => (
<div key={feature.title}>
{feature.Icon}
<Text variant="heading-4" className="mb-4 mt-8 capitalize text-light-200">
{feature.title}
</Text>
<Text className="max-w-100 text-light-300">{feature.body}</Text>
</div>
))}
</div>
<FeaturesGrid features={features} />
</section>
);
}
Binary file added src/app/_assets/bridge-2.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/bridge-hero.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
33 changes: 33 additions & 0 deletions src/app/_components/bridge-now-link.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
"use client";

import { useSearchParams } from "next/navigation";
import { Suspense } from "react";

type Props = React.ComponentProps<"a">;

const bridgeAppBaseUrl = "https://app.across.to";

export function BridgeNowLink(props: Props) {
return (
<Suspense>
<_BridgeNowLink {...props} />
</Suspense>
);
}

function _BridgeNowLink({ className, ...props }: Props) {
const searchParams = useSearchParams();

const refParams = searchParams.get("ref") || searchParams.get("referrer");
const bridgeNowLink = `${bridgeAppBaseUrl}/bridge${refParams ? `?ref=${refParams}` : ""}`;

return (
<a
className={className}
href={bridgeNowLink}
target="_blank"
rel="noopener noreferrer"
{...props}
/>
);
}
33 changes: 33 additions & 0 deletions src/app/_components/features-grid.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { twMerge } from "tailwind-merge";

import { Text } from "./text";

type Feature = {
title: string;
body: string;
Icon: React.ReactNode;
};

type Props = React.ComponentProps<"div"> & {
features: Feature[];
};

export function FeaturesGrid({ className, features, children, ...props }: Props) {
return (
<div
className={twMerge("grid grid-cols-1 gap-12 sm:gap-y-16 md:grid-cols-2", className)}
{...props}
>
{features.map((feature) => (
<div key={feature.title}>
{feature.Icon}
<Text variant="heading-4" className="mb-4 mt-8 capitalize text-light-200">
{feature.title}
</Text>
<Text className="max-w-100 text-light-300">{feature.body}</Text>
</div>
))}
{children}
</div>
);
}
2 changes: 1 addition & 1 deletion src/app/_components/get-started-section.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ export function GetStartedSection(props: {
target="_blank"
rel="noopener noreferrer"
className={twJoin(
"flex h-10 flex-col items-center justify-center rounded-full px-6 py-2 shadow-sm",
"flex flex-col items-center justify-center rounded-full px-6 py-2 shadow-sm",
variants[props.variant].opacityBgClassName,
)}
>
Expand Down
30 changes: 17 additions & 13 deletions src/app/_components/header-nav/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
import Link from "next/link";
import { usePathname } from "next/navigation";
import { useState } from "react";

import { twMerge } from "@/app/_lib/tw-merge";
import { PRODUCT_LINKS, SOCIAL_LINKS } from "@/app/_constants";

import {
AcrossIcon,
Expand All @@ -18,7 +20,7 @@ import {
} from "../icons";
import { Button } from "../button";
import { Text } from "../text";
import { PRODUCT_LINKS, SOCIAL_LINKS } from "@/app/_constants";
import { BridgeNowLink } from "../bridge-now-link";

import { FlyoutMenu } from "./flyout-menu";
import { MobileMenu } from "./mobile-menu";
Expand Down Expand Up @@ -108,18 +110,20 @@ export function HeaderNav() {
</div>
</div>
<div className="flex flex-row gap-3">
<Button
className={twMerge(
"hidden transition md:block",
pathname === "/across-plus"
? "border-teal-100 bg-teal-100/[.05] text-teal-100"
: pathname === "/across-settlement"
? "border-purple-100 bg-purple-100/[.05] text-purple-100"
: "border-aqua-100 bg-aqua-100/[.05] text-aqua-100",
)}
>
<Text variant="cap-case-sm">Bridge now</Text>
</Button>
<BridgeNowLink>
<Button
className={twMerge(
"hidden transition md:block",
pathname === "/across-plus"
? "border-teal-100 bg-teal-100/[.05] text-teal-100"
: pathname === "/across-settlement"
? "border-purple-100 bg-purple-100/[.05] text-purple-100"
: "border-aqua-100 bg-aqua-100/[.05] text-aqua-100",
)}
>
<Text variant="cap-case-sm">Bridge now</Text>
</Button>
</BridgeNowLink>
{/* Only show menu button on mobile */}
<button
className="flex h-10 w-10 items-center justify-center rounded-full border border-grey-600 md:hidden"
Expand Down
28 changes: 16 additions & 12 deletions src/app/_components/header-nav/mobile-menu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import { Transition } from "@headlessui/react";
import { UmaIcon } from "../icons";
import { Button } from "../button";
import { IconBox } from "../icon-box";
import { BridgeNowLink } from "../bridge-now-link";
import { Text } from "../text";

import { NavItem } from "./types";

Expand All @@ -28,18 +30,20 @@ export function MobileMenu(props: {
show={props.isMenuOpen}
>
<div className="absolute flex min-h-screen w-full flex-col gap-6 bg-grey-dark p-4 md:hidden">
<Button
className={twMerge(
"md:hidden",
props.pathname === "/across-plus"
? "border-teal-100/[.05] bg-teal-100/[.05] text-teal-100"
: props.pathname === "/across-settlement"
? "border-purple-100/[.05] bg-purple-100/[.05] text-purple-100"
: "",
)}
>
Bridge now
</Button>
<BridgeNowLink className="flex w-full flex-row">
<Button
className={twMerge(
"w-full",
props.pathname === "/across-plus"
? "border-teal-100 bg-teal-100/[.05] text-teal-100"
: props.pathname === "/across-settlement"
? "border-purple-100 bg-purple-100/[.05] text-purple-100"
: "border-aqua-100 bg-aqua-100/[.05] text-aqua-100",
)}
>
<Text variant="cap-case-sm">Bridge now</Text>
</Button>
</BridgeNowLink>
{props.productsNavItems.map((item) => (
<span key={item.href} className="group">
<Link
Expand Down
7 changes: 4 additions & 3 deletions src/app/_components/icons/gradient/double-chevron-right.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import { SVGProps } from "react";
import { twMerge } from "@/app/_lib/tw-merge";

export function DoubleChevronRightIcon(props: SVGProps<SVGSVGElement>) {
export function DoubleChevronRightIcon({ className, ...props }: SVGProps<SVGSVGElement>) {
return (
<svg
width="96"
height="96"
viewBox="0 0 96 96"
fill="none"
xmlns="http://www.w3.org/2000/svg"
className={twMerge("h-12 w-12", className)}
{...props}
>
<rect
opacity="0.5"
Expand Down

0 comments on commit 3e6823d

Please sign in to comment.