Skip to content
Open
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
25 changes: 25 additions & 0 deletions apps/web/src/components/ad-placeholder.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { cn } from "@/lib/utils";

interface AdPlaceholderProps {
width?: string;
height?: string;
label?: string;
className?: string;
}

export function AdPlaceholder({ width, height, label = "Ad", className }: AdPlaceholderProps) {
return (
<div
className={cn(
"flex flex-col items-center justify-center gap-1 border border-dashed border-[#3a3a3a] bg-[#181818] text-[#444]",
className
)}
style={{ width, height }}
>
<span className="text-[9px] font-bold uppercase tracking-widest text-[#3a3a3a]">
Advertisement
</span>
<span className="text-[10px] text-[#444]">{label}</span>
</div>
);
}
153 changes: 153 additions & 0 deletions apps/web/src/components/house-ad.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
import { useAuth } from "@/context/auth-context";
import { cn } from "@/lib/utils";
import { Link } from "@tanstack/react-router";
import { Gift, TrendingDown, Trophy } from "lucide-react";

interface HouseAdProps {
variant: "banner" | "tower";
className?: string;
}

export function HouseAd({ variant, className }: HouseAdProps) {
const { user, isPending } = useAuth();

if (isPending) {
return (
<div
className={cn(
"animate-pulse rounded bg-[#1a1a1a]",
variant === "banner" ? "h-[90px] w-full" : "h-[600px] w-full",
className
)}
/>
);
}

if (!user) {
return <SignUpAd variant={variant} className={className} />;
}

return <LoggedInAd variant={variant} className={className} />;
}

function SignUpAd({ variant, className }: { variant: "banner" | "tower"; className?: string }) {
if (variant === "banner") {
return (
<Link
to="/signup"
className={cn(
"flex h-[90px] w-full items-center gap-3 rounded border border-[#2a2a2a] bg-gradient-to-r from-[#1a1a1a] to-[#1e1e1e] px-4 transition-colors hover:border-yellow-500/40",
className
)}
>
<div className="flex h-10 w-10 shrink-0 items-center justify-center rounded-full bg-yellow-400/10">
<Trophy className="h-5 w-5 text-yellow-400" />
</div>
<div className="min-w-0 flex-1">
<p className="text-xs font-bold text-white">Play risk-free</p>
<p className="text-[11px] text-[#7090b0]">Start with 1,000 free NoCoins</p>
</div>
<span className="shrink-0 rounded bg-yellow-400 px-2.5 py-1 text-[11px] font-bold text-black">
Sign up
</span>
</Link>
);
}

return (
<div
className={cn(
"flex h-[600px] w-full flex-col items-center justify-center gap-4 rounded border border-[#2a2a2a] bg-[#161616] px-4 py-6 text-center",
className
)}
>
<div className="flex h-14 w-14 items-center justify-center rounded-full bg-yellow-400/10">
<Trophy className="h-7 w-7 text-yellow-400" />
</div>
<div className="space-y-1.5">
<p className="text-sm font-bold leading-snug text-white">Play risk-free</p>
<p className="text-[11px] leading-relaxed text-[#7090b0]">
No real money.
<br />
Just the thrill of the game.
</p>
</div>
<div className="space-y-1 text-center">
<p className="text-2xl font-bold text-yellow-400">1,000</p>
<p className="text-[11px] text-[#7090b0]">NoCoins on sign up</p>
</div>
<Link
to="/signup"
className="mt-2 w-full rounded bg-yellow-400 py-2 text-center text-xs font-bold text-black transition-colors hover:bg-yellow-300"
>
Create free account
</Link>
<p className="text-[10px] text-[#444]">No deposits · No risk</p>
</div>
);
}

function LoggedInAd({ variant, className }: { variant: "banner" | "tower"; className?: string }) {
if (variant === "banner") {
return (
<Link
to="/rewards"
className={cn(
"flex h-[90px] w-full items-center gap-3 rounded border border-[#2a2a2a] bg-gradient-to-r from-[#1a1a1a] to-[#1e1e1e] px-4 transition-colors hover:border-yellow-500/40",
className
)}
>
<div className="flex h-10 w-10 shrink-0 items-center justify-center rounded-full bg-yellow-400/10">
<Gift className="h-5 w-5 text-yellow-400" />
</div>
<div className="min-w-0 flex-1">
<p className="text-xs font-bold text-white">Rewards shop</p>
<p className="text-[11px] text-[#7090b0]">Redeem your NoCoins for real prizes</p>
</div>
<span className="shrink-0 rounded border border-yellow-400/30 bg-yellow-400/10 px-2.5 py-1 text-[11px] font-bold text-yellow-400">
Browse →
</span>
</Link>
);
}

return (
<div className={cn("flex h-[600px] w-full flex-col gap-3", className)}>
<Link
to="/rewards"
className="flex flex-1 flex-col items-center justify-center gap-3 rounded border border-[#2a2a2a] bg-[#161616] px-4 py-5 text-center transition-colors hover:border-yellow-500/40"
>
<div className="flex h-12 w-12 items-center justify-center rounded-full bg-yellow-400/10">
<Gift className="h-6 w-6 text-yellow-400" />
</div>
<div className="space-y-1">
<p className="text-xs font-bold text-white">Rewards Shop</p>
<p className="text-[11px] leading-relaxed text-[#7090b0]">
Trade your NoCoins for real prizes and discounts
</p>
</div>
<span className="rounded bg-yellow-400 px-3 py-1.5 text-[11px] font-bold text-black">
Browse rewards
</span>
</Link>

<Link
to="/dashboard"
className="flex flex-1 flex-col items-center justify-center gap-3 rounded border border-[#2a2a2a] bg-[#161616] px-4 py-5 text-center transition-colors hover:border-blue-500/30"
>
<div className="flex h-12 w-12 items-center justify-center rounded-full bg-blue-400/10">
<TrendingDown className="h-6 w-6 text-blue-400" />
</div>
<div className="space-y-1">
<p className="text-xs font-bold text-white">Your Stats</p>
<p className="text-[11px] leading-relaxed text-[#7090b0]">
See how much you've avoided losing by not betting for real
</p>
</div>
<span className="rounded border border-blue-400/30 bg-blue-400/10 px-3 py-1.5 text-[11px] font-bold text-blue-400">
View dashboard
</span>
</Link>
</div>
);
}
15 changes: 13 additions & 2 deletions apps/web/src/routes/__root.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@ import { BetSlip } from "../components/betting/bet-slip";
import { BottomNav } from "../components/betting/bottom-nav";
import { SportsSidebar } from "../components/betting/sports-sidebar";
import { ErrorBoundary } from "../components/error-boundary";
import { HouseAd } from "../components/house-ad";
import { Footer, Header } from "../components/layout";
import { Sheet, SheetContent } from "../components/ui/sheet";
import { ActiveSportProvider, useActiveSport } from "../context/active-sport-context";
import { useAuth } from "../context/auth-context";
import { AuthProvider } from "../context/auth-context";
import { AuthProvider, useAuth } from "../context/auth-context";
import { BetSlipProvider, useBetSlip } from "../context/bet-slip-context";

function AppLayout() {
Expand Down Expand Up @@ -49,6 +49,12 @@ function AppLayout() {
/>

<div className="flex flex-1 overflow-hidden">
{/* [AD TOWER LEFT] xl only — stays visible while main scrolls */}
<aside className="hidden xl:flex w-44 shrink-0 flex-col border-r border-[#2a2a2a] bg-[#141414] px-3 pt-6">
<HouseAd variant="tower" className="w-full" />
</aside>

{/* Desktop sports sidebar */}
<aside className="hidden w-52 shrink-0 overflow-y-auto lg:block">
<SportsSidebar
sports={sports}
Expand All @@ -65,6 +71,11 @@ function AppLayout() {
<aside className="hidden w-72 shrink-0 border-l border-[#2a2a2a] overflow-y-auto lg:block">
<BetSlip className="min-h-full" />
</aside>

{/* [AD TOWER RIGHT] xl only — stays visible while main scrolls */}
<aside className="hidden xl:flex w-44 shrink-0 flex-col border-l border-[#2a2a2a] bg-[#141414] px-3 pt-6">
<HouseAd variant="tower" className="w-full" />
</aside>
</div>

<Footer />
Expand Down