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
460 changes: 460 additions & 0 deletions bun.lock

Large diffs are not rendered by default.

19 changes: 16 additions & 3 deletions client/src/components/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { Games } from "@/components/games";
import { SceneLayout } from "@/components/scenes/layout";
import { GamePage } from "./pages/game";
import { useEffect } from "react";
import { useLocation } from "react-router-dom";
import { PlayerPage } from "./pages/player";
import { cn } from "@cartridge/ui/utils";
import { useSidebar } from "@/hooks/sidebar";
Expand All @@ -13,11 +14,14 @@ import { useDevice } from "@/hooks/device";
import { MarketPage } from "./pages/market";
import { Filters } from "./filters";
import { UserCard } from "./user/user-card";
import { PredictionPage } from "./pages/prediction";
import { PredictionSidebar } from "./games/prediction-sidebar";

export function App() {
const { isOpen, toggle, handleTouchMove, handleTouchStart } = useSidebar();
const { setPlayer } = useArcade();
const { player, collection } = useProject();
const { player, collection, tab } = useProject();
const location = useLocation();

const { isPWA, isMobile } = useDevice();

Expand Down Expand Up @@ -51,7 +55,13 @@ export function App() {
<div className="lg:space-y-4 h-full flex flex-col">
{!isMobile && <UserCard />}
<div className="flex-1 overflow-hidden">
{!collection ? <Games /> : <Filters />}
{tab && tab.startsWith("prediction") ? (
<PredictionSidebar />
) : !collection ? (
<Games />
) : (
<Filters />
)}
</div>
</div>

Expand All @@ -77,7 +87,10 @@ export function App() {
"bg-background-125 shadow-[0px_0px_8px_0px_rgba(15,20,16,_0.50)]",
)}
>
{!player ? (
{location.pathname.includes("/prediction") ||
(tab && tab.startsWith("prediction-")) ? (
<PredictionPage />
) : !player ? (
!collection ? (
<GamePage />
) : (
Expand Down
1 change: 1 addition & 0 deletions client/src/components/games/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,7 @@ export const Game = ({
const gameName = `${game?.name.toLowerCase().replace(/ /g, "-") || id}`;
pathname = pathname.replace(/\/game\/[^/]+/, "");
pathname = pathname.replace(/\/edition\/[^/]+/, "");
pathname = pathname.replace(/\/prediction$/, "");
if (id !== 0) pathname = joinPaths(`/game/${gameName}`, pathname);
navigate(pathname || "/");
// Close sidebar on mobile when a game is selected
Expand Down
128 changes: 128 additions & 0 deletions client/src/components/games/prediction-sidebar.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
import { useDevice } from "@/hooks/device";
import { useSidebar } from "@/hooks/sidebar";
import {
Button,
Card,
CardContent,
CardHeader,
CardTitle,
cn,
Thumbnail,
} from "@cartridge/ui";

export const PredictionSidebar = () => {
const { isMobile } = useDevice();
const { isOpen, handleTouchStart, handleTouchMove } = useSidebar();

return (
<div
className={cn(
"flex flex-col gap-4 overflow-clip lg:rounded-xl border-r border-spacer-100 lg:border-none lg:border-background-200",
"h-full w-[calc(100vw-64px)] max-w-[360px] lg:flex lg:min-w-[360px]",
isMobile && "fixed z-50 top-0 left-0", // Fixed position for mobile
isOpen ? "translate-x-0" : "-translate-x-full lg:translate-x-0", // Slide in/out animation
"transition-transform duration-300 ease-in-out", // Smooth transition
)}
onTouchStart={handleTouchStart}
onTouchMove={handleTouchMove}
>
<Card className="bg-background-125 border border-background-200 rounded-xl p-4 gap-2">
<CardHeader className="px-2 py-3 bg-background-125">
<CardTitle className="text-foreground-400 text-xs font-semibold">
Vault Details
</CardTitle>
</CardHeader>
<CardContent className="bg-background-125 space-y-2 p-0">
<div
id="metric"
className="py-4 px-6 flex flex-col items-start justify-center gap-1 self-stretch bg-background-200 rounded w-full"
>
<div className="flex items-center gap-1">
<Thumbnail
size="xs"
variant="lighter"
icon="https://imagedelivery.net/0xPAQaDtnQhBs8IzYRIlNg/a3bfe959-50c4-4f89-0aef-b19207d82a00/logo"
/>
<p className="text-foreground-100 text-base/5 font-light font-mono">
8,800
</p>
</div>
<h1 className="text-xs font-normal text-foreground-300">
Vault Total
</h1>
</div>
<div className="flex items-start gap-3 self-stretch">
<div
id="metric"
className="py-4 px-6 flex flex-col items-start justify-center gap-1 self-stretch bg-background-200 rounded w-full"
>
<div className="flex items-center gap-1">
<Thumbnail
size="xs"
variant="lighter"
icon="https://imagedelivery.net/0xPAQaDtnQhBs8IzYRIlNg/a3bfe959-50c4-4f89-0aef-b19207d82a00/logo"
/>
<p className="text-foreground-100 text-base/5 font-light font-mono">
2,200
</p>
</div>
<h1 className="text-xs font-normal text-foreground-300">
Your Stake
</h1>
</div>
<div
id="metric"
className="py-4 px-6 flex flex-col items-start justify-center gap-1 self-stretch bg-background-200 rounded w-full"
>
<div className="flex items-center gap-1">
<Thumbnail
size="xs"
variant="lighter"
icon="https://imagedelivery.net/0xPAQaDtnQhBs8IzYRIlNg/a3bfe959-50c4-4f89-0aef-b19207d82a00/logo"
/>
<p className="text-foreground-100 text-base/5 font-light font-mono">
34
</p>
</div>
<h1 className="text-xs font-normal text-foreground-300">
Fees Earned
</h1>
</div>
</div>
</CardContent>
</Card>
<Card className="bg-background-125 border border-background-200 rounded-xl p-4 gap-2">
<CardHeader className="px-2 py-3 bg-background-125">
<CardTitle className="text-foreground-400 text-xs font-semibold">
Market Fees
</CardTitle>
</CardHeader>
<CardContent className="bg-background-125 space-y-2 p-0 px-2 pb-2">
<div className="flex items-center justify-between self-stretch">
<p className="text-foreground-200 text-xs font-normal">Protocol</p>
<p className="text-foreground-100 text-xs font-normal">0.3%</p>
</div>
<div className="flex items-center justify-between self-stretch">
<p className="text-foreground-200 text-xs font-normal">Oracle</p>
<p className="text-foreground-100 text-xs font-normal">0.5%</p>
</div>
<div className="flex items-center justify-between self-stretch">
<p className="text-foreground-200 text-xs font-normal">Creator</p>
<p className="text-foreground-100 text-xs font-normal">4.2%</p>
</div>
<div className="flex items-center justify-between self-stretch">
<p className="text-foreground-200 text-xs font-normal">Vault</p>
<p className="text-foreground-100 text-xs font-normal">1.39%</p>
</div>
</CardContent>
</Card>
<Card className="bg-background-125 border border-background-200 rounded-xl p-4 gap-2">
<Button variant="primary" className="bg-primary h-10 px-6 py-2.5">
<span className="text-translucent-dark-300 text-base/5 font-semibold">
RESOLVE MARKET
</span>
</Button>
</Card>
</div>
);
};
28 changes: 27 additions & 1 deletion client/src/components/modules/tab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,24 @@ export interface ArcadeTabProps extends VariantProps<typeof arcadeTabVariants> {
label: string;
active?: boolean;
className?: string;
badge?: number;
onClick?: () => void;
}

export const ArcadeTab = React.forwardRef<HTMLButtonElement, ArcadeTabProps>(
(
{ Icon, value, label, active, className, variant, size, onClick, ...props },
{
Icon,
value,
label,
active,
className,
variant,
size,
onClick,
badge,
...props
},
ref,
) => {
return (
Expand All @@ -52,6 +64,20 @@ export const ArcadeTab = React.forwardRef<HTMLButtonElement, ArcadeTabProps>(
>
{Icon}
<p className="font-normal">{label}</p>
{badge && (
<div
className={cn(
"rounded-full min-w-5 px-2 py-0.5 flex items-center gap-2.5",
active
? "bg-background-300 text-primary"
: "bg-background-200 text-foreground-300",
)}
>
<span className="text-xs font-medium">
{badge.toLocaleString()}
</span>
</div>
)}
</div>
<div
data-active={active}
Expand Down
Loading