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
14 changes: 14 additions & 0 deletions apps/dashboard/src/@/analytics/report.ts
Original file line number Diff line number Diff line change
Expand Up @@ -691,3 +691,17 @@ export function reportProductFeedback(properties: {
source: properties.source,
});
}

/**
* ### Why do we need to report this event?
* - To track conversions for the bridge page links
*
* ### Who is responsible for this event?
* @MananTank
*
*/
export function reportBridgePageLinkClick(params: {
linkType: "integrate-bridge" | "trending-tokens";
}) {
posthog.capture("bridge page link clicked", params);
}
2 changes: 1 addition & 1 deletion apps/dashboard/src/@/components/DarkVeil.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -188,5 +188,5 @@ export function DarkVeil({
backgroundOpacity,
patternLightness,
]);
return <canvas ref={ref} className="w-full h-full block" />;
return <canvas ref={ref} className="w-full h-full block bg-background" />;
}
32 changes: 15 additions & 17 deletions apps/dashboard/src/@/components/blocks/faq-section.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,23 +9,21 @@ export function FaqSection(props: {
faqs: Array<{ title: string; description: string }>;
}) {
return (
<div className="py-10">
<section className="">
<h2 className="text-2xl md:text-3xl font-semibold mb-4 tracking-tight">
Frequently asked questions
</h2>
<div className="flex flex-col">
{props.faqs.map((faq, faqIndex) => (
<FaqItem
key={faq.title}
title={faq.title}
description={faq.description}
className={cn(faqIndex === props.faqs.length - 1 && "border-b-0")}
/>
))}
</div>
</section>
</div>
<section>
<h2 className="text-2xl md:text-3xl font-semibold mb-4 tracking-tight">
Frequently asked questions
</h2>
<div className="flex flex-col">
{props.faqs.map((faq, faqIndex) => (
<FaqItem
key={faq.title}
title={faq.title}
description={faq.description}
className={cn(faqIndex === props.faqs.length - 1 && "border-b-0")}
/>
))}
</div>
</section>
);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,9 @@ export default async function Page(props: Props) {
)}

{chainSeo?.faqs && chainSeo.faqs.length > 0 && (
<FaqSection faqs={chainSeo.faqs} />
<div className="py-10">
<FaqSection faqs={chainSeo.faqs} />
</div>
Comment on lines 69 to +72
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Restore container width for FAQ section

The new wrapper adds vertical padding but drops the horizontal container gutter that FaqSection used to provide, so the FAQ content now stretches full width while the rest of the page stays container-aligned. Please keep the container on this wrapper to avoid the layout regression.

-        <div className="py-10">
+        <div className="container py-10">
🤖 Prompt for AI Agents
In
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/page.tsx
around lines 69 to 72, the wrapper for the FAQ removed the horizontal
container/gutter so FAQs render full width; restore the horizontal container by
adding the same container wrapper/class used by the rest of the page (e.g., the
project's standard "container" or equivalent classes) to this div so the
FaqSection retains consistent left/right padding and alignment while keeping the
vertical py-10 spacing.

)}
</div>
);
Expand Down
33 changes: 33 additions & 0 deletions apps/dashboard/src/app/bridge/components/client/pill-link.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
"use client";
import { ChevronRightIcon, DollarSignIcon, TrendingUpIcon } from "lucide-react";
import Link from "next/link";
import { reportBridgePageLinkClick } from "@/analytics/report";
import { cn } from "@/lib/utils";

export function PillLink(props: {
children: React.ReactNode;
href: string;
linkType: "integrate-bridge" | "trending-tokens";
}) {
const Icon =
props.linkType === "integrate-bridge" ? DollarSignIcon : TrendingUpIcon;
return (
<Link
href={props.href}
target="_blank"
onClick={() => reportBridgePageLinkClick({ linkType: props.linkType })}
className={cn(
"shadow-sm text-center justify-center inline-flex items-center gap-4 text-foreground group",
"text-sm bg-card/50 backdrop-blur-lg border border-border/70",
"rounded-full px-4 py-2.5 transition-colors duration-300 text-pretty leading-5",
"hover:bg-pink-300/20 dark:hover:bg-pink-950/30 hover:text-foreground hover:border-pink-400 dark:hover:border-pink-800",
)}
>
<div className="flex items-center gap-2.5">
<Icon className="size-4 shrink-0 text-pink-600" />
{props.children}
</div>
<ChevronRightIcon className="size-4 shrink-0 text-muted-foreground/50 group-hover:translate-x-1 transition-all duration-300 group-hover:text-foreground" />
</Link>
);
}
54 changes: 28 additions & 26 deletions apps/dashboard/src/app/bridge/page.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
import { cn } from "@workspace/ui/lib/utils";
import { ChevronRightIcon } from "lucide-react";
import type { Metadata } from "next";
import Link from "next/link";
import type { Address } from "thirdweb";
import { defineChain } from "thirdweb/chains";
import { getContract } from "thirdweb/contract";
import { getCurrencyMetadata } from "thirdweb/extensions/erc20";
import { FaqSection } from "@/components/blocks/faq-section";
import { AppFooter } from "@/components/footers/app-footer";
import { BridgeVeil } from "./components/BridgeVeil";
import { PillLink } from "./components/client/pill-link";
import { UniversalBridgeEmbed } from "./components/client/UniversalBridgeEmbed";
import { PageHeader } from "./components/header";
import { bridgeAppThirdwebClient } from "./constants";
Expand Down Expand Up @@ -56,15 +55,17 @@ export default async function BridgePage({

return (
<div className="grow flex flex-col relative overflow-hidden">
<div className="absolute top-0 left-0 right-0 h-dvh md:h-[1200px] fade-in-0 animate-in duration-1000">
<div className="absolute top-0 left-0 right-0 h-dvh md:h-[1200px] fade-in-0 animate-in duration-700">
<BridgeVeil />
</div>

<div className="relative z-10">
<PageHeader />

<div className="pt-28 pb-32 min-h-dvh relative z-10">
<div className="container mb-20">
<div className="h-20" />

<div className="relative z-10">
<div className="container">
<h1 className="text-5xl md:text-6xl font-bold mb-6 tracking-tighter text-center leading-none text-pretty">
Bridge and Swap tokens <br className="max-sm:hidden" /> across any
chain, instantly
Expand All @@ -77,6 +78,8 @@ export default async function BridgePage({
</div>
</div>

<div className="h-16" />

<div className="flex grow items-center justify-center px-4 relative">
<DotsBackgroundPattern />
<UniversalBridgeEmbed
Expand All @@ -95,21 +98,33 @@ export default async function BridgePage({
</div>
</div>

<div className="mb-24 container max-w-4xl">
<BridgeFaqSection />
</div>
<div className="h-32" />

<div className="flex flex-col gap-4 items-center mb-28 container">
<PillLink href="https://portal.thirdweb.com/bridge">
<div className="flex flex-col gap-4 items-center container">
<PillLink
href="https://portal.thirdweb.com/bridge"
linkType="integrate-bridge"
>
Integrate Bridge in your apps in minutes, and start generating
revenue
</PillLink>

<PillLink href="https://thirdweb.com/tokens">
<PillLink
href="https://thirdweb.com/tokens"
linkType="trending-tokens"
>
Discover Trending Tokens
</PillLink>
</div>
Comment on lines +103 to 118
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Add rel="noopener noreferrer" to PillLink's external targets.
Line 105 opens https://portal.thirdweb.com/bridge in a new tab through PillLink, whose implementation (apps/dashboard/src/app/bridge/components/client/pill-link.tsx) currently sets target="_blank" without a rel attribute. That leaves window.opener exposed, making the dashboard vulnerable to tab-nabbing if the external page is ever compromised. Please add a defensive rel="noopener noreferrer" in the client component before we ship this.

Apply this diff in apps/dashboard/src/app/bridge/components/client/pill-link.tsx:

-    <Link
-      href={props.href}
-      target="_blank"
+    <Link
+      href={props.href}
+      target="_blank"
+      rel="noopener noreferrer"
🤖 Prompt for AI Agents
In apps/dashboard/src/app/bridge/components/client/pill-link.tsx (where the
anchor with target="_blank" is rendered), the external links open in a new tab
but do not set rel, exposing window.opener; add rel="noopener noreferrer" to the
rendered <a> (or set a default rel prop on the PillLink component and pass it to
the anchor) so any target="_blank" anchors include rel="noopener noreferrer"; if
the component is typed, update the props/type to accept an optional rel or
ensure the hardcoded anchor includes the attribute.


<div className="h-32" />

<div className="container max-w-2xl">
<BridgeFaqSection />
</div>

<div className="h-32" />

<div className="relative">
<AppFooter />
</div>
Expand All @@ -120,30 +135,17 @@ export default async function BridgePage({

function DataPill(props: { children: React.ReactNode }) {
return (
<p className="flex items-center gap-1.5 text-foreground/60 text-xs bg-accent/30 backdrop-blur-lg border border-border/70 rounded-full px-3 py-1.5 hover:text-foreground transition-colors duration-300">
<p className="flex items-center gap-1.5 text-foreground/50 text-xs bg-accent/30 backdrop-blur-lg border border-border/70 rounded-full px-3 py-1.5 hover:text-foreground transition-colors duration-300">
{props.children}
</p>
);
}

function PillLink(props: { children: React.ReactNode; href: string }) {
return (
<Link
href={props.href}
target="_blank"
className="shadow-lg text-center justify-center inline-flex items-center gap-2 text-foreground text-sm bg-card/50 backdrop-blur-lg border border-border/70 hover:border-active-border rounded-full px-5 py-2.5 hover:text-foreground transition-colors duration-300 text-pretty leading-5"
>
{props.children}
<ChevronRightIcon className="size-3.5 shrink-0 text-muted-foreground" />
</Link>
);
}

function DotsBackgroundPattern(props: { className?: string }) {
return (
<div
className={cn(
"pointer-events-none absolute -inset-20 text-foreground/30 dark:text-foreground/10",
"pointer-events-none absolute -inset-x-36 -inset-y-24 text-pink-700/30 dark:text-pink-500/20",
props.className,
)}
style={{
Expand Down
Loading