Skip to content

Commit

Permalink
Add a banner to display a disclaimer and a button to display game rul…
Browse files Browse the repository at this point in the history
…es (#76)
  • Loading branch information
nonvis authored Jul 8, 2024
1 parent c87431e commit 102feac
Show file tree
Hide file tree
Showing 11 changed files with 854 additions and 177 deletions.
2 changes: 2 additions & 0 deletions app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,12 @@
"@mysten/enoki": "^0.1.3",
"@mysten/sui.js": "^0.41.2",
"@radix-ui/react-accordion": "^1.1.2",
"@radix-ui/react-dialog": "^1.0.5",
"@radix-ui/react-dropdown-menu": "^2.0.5",
"@radix-ui/react-icons": "^1.3.0",
"@radix-ui/react-label": "^2.0.2",
"@radix-ui/react-radio-group": "^1.1.3",
"@radix-ui/react-scroll-area": "^1.0.5",
"@radix-ui/react-select": "^1.2.2",
"@radix-ui/react-slot": "^1.0.2",
"@types/node": "20.4.1",
Expand Down
712 changes: 567 additions & 145 deletions app/pnpm-lock.yaml

Large diffs are not rendered by default.

5 changes: 5 additions & 0 deletions app/public/general/info.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 3 additions & 3 deletions app/src/app/play/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,9 @@ export default function Page() {
<IsWaitingToPlayProvider>
<EndGameCard />
<InsufficientCoinBalance />
<div className="relative flex flex-col space-y-[10px] items-center ">
<div className="relative flex flex-col items-center">
<TotalWon />
<div className="flex justify-center w-full">
<div className="flex justify-center w-full">
<div ref={containerRef} className="relative max-w-full">
{/* Existing content */}
<div
Expand Down Expand Up @@ -104,7 +104,7 @@ export default function Page() {
</div>
</div>
</div>
<div className="flex justify-center w-full 2xl:mt-32">
<div className="flex justify-center w-full">
<PlinkoSettings />
</div>
</IsWaitingToPlayProvider>
Expand Down
51 changes: 51 additions & 0 deletions app/src/components/layouts/InfoIcon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import React from "react";
import Image from "next/image";
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogTrigger } from "@/components/ui/dialog";
import { ScrollArea } from "@/components/ui/scroll-area";
import { Button } from "@/components/ui/button";

export const InfoIcon = () => {
return (
<>
<Dialog>
<DialogTrigger asChild>
<Button
className="w-[40px] h-[40px] relative bg-white hover:bg-gray-100 h-rounded-[10px] border-[1px] border-[#CCCCCC] opacity-80"
>
<Image src="/general/info.svg"
alt="Info"
fill={true}
/>
</Button>
</DialogTrigger>
<DialogContent className="w-3/4 h-1/2">
<DialogHeader>
<DialogTitle>Game Rules</DialogTitle>
</DialogHeader>
<ScrollArea>
<div className="space-y-[10px] text-black text-opacity-80 text-sm">
<div>
Inspired by the popular game show, Plinko is a game of chance where balls are dropped from the top of
a pegged board, and the outcome is determined by the path they take. Our Sui blockchain implementation
offers a unique experience by integrating cryptographic techniques to ensure fairness and
transparency.
</div>
<div>
The game begins with the players selecting the number of balls they want to play and also selecting
the bet size for each ball. This strategic choice allows players to influence their potential rewards.
</div>
<div>
After making their selections, players initiate the game, which then employs blockchain technology
to ensure the randomness and fairness of each ball drop through a pegged board.
The goal is to land the balls in slots at the bottom of the board, each offering different prize
multipliers.
The outcome of the game, dictated by where the balls land, is calculated automatically, with the smart
contract assessing the results to determine the total winnings.
</div>
</div>
</ScrollArea>
</DialogContent>
</Dialog>
</>
);
};
22 changes: 12 additions & 10 deletions app/src/components/layouts/LargeScreenLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import { ChildrenProps } from "@/types/ChildrenProps";
import React from "react";
import { InfoIcon } from "./InfoIcon";
import { TopNavbar } from "./navbars/TopNavbar";
import { useZkLogin } from "@mysten/enoki/react";

Expand All @@ -11,15 +12,16 @@ export const LargeScreenLayout = ({ children }: ChildrenProps) => {
const { address } = useZkLogin();

return (
<div
className={`relative w-full h-full ${
address ? "role-admin" : "role-anonymous"
} flex-col `}
>
<TopNavbar />
{/* <div className="flex-1 p-4 bg-grey-100"> */}
<div>{children}</div>
{/* </div> */}
</div>
<>
<div
className={`static w-full h-full flex-col items-center justify-center ${
address ? "role-admin" : "role-anonymous"
}`}
>
<TopNavbar/>
<div>{children}</div>
<div className="absolute bottom-0 left-0 p-8"><InfoIcon/></div>
</div>
</>
);
};
10 changes: 5 additions & 5 deletions app/src/components/layouts/MobileLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,20 @@ import React from "react";
import { ChildrenProps } from "@/types/ChildrenProps";
import { TopNavbar } from "./navbars/TopNavbar";
import { useZkLogin } from "@mysten/enoki/react";
import { InfoIcon } from "@/components/layouts/InfoIcon";

export const MobileLayout = ({ children }: ChildrenProps) => {
const { address } = useZkLogin();

return (
<div
className={`flex flex-col w-full min-h-screen relative ${
className={`static flex-col w-full h-full ${
address ? "role-admin" : "role-anonymous"
}`}
>
<div className="flex-1 flex flex-col space-y-2 flex-1">
<TopNavbar />
<div className="p-2">{children}</div>
</div>
<TopNavbar/>
{children}
<div className="px-4"><InfoIcon/></div>
</div>
);
};
36 changes: 22 additions & 14 deletions app/src/components/layouts/navbars/TopNavbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,26 +3,34 @@ import Link from "next/link";
import { UserProfileMenu } from "@/components/general/UserProfileMenu";
import { Balance } from "@/components/general/Balance";
import { useZkLogin } from "@mysten/enoki/react";
import useScroll from "@/lib/hooks/use-scroll";

export const TopNavbar = () => {
const { address } = useZkLogin();
const scrolled = useScroll(10);

return (
<div className="backdrop-blur-md md:backdrop-blur-none sticky top-0 flex w-full h-full bg-inherit p-5 space-x-2 md:space-x-4 justify-between items-center z-10">
<Link
href="/play"
className="w-[min-content] md:w-[300px] text-2xl font-bold text-white"
>
Plinko Game
</Link>
<div className="flex flex-1 justify-end items-center space-x-1">
{!!address && (
<div className="flex space-x-2 items-center">
<Balance />
<UserProfileMenu />
<>
<div className={`sticky top-0 flex flex-col w-full justify-evenly z-50 ${
scrolled ? "border-b border-gray-200 bg-transparent/50 backdrop-blur-xl" : "bg-white/0"
}`}>
<span className="w-full text-opacity-90 text-[14px] text-[#4F4F4F] bg-white py-3 px-5 text-center">
[Plinko Game] is provided for testnet purposes only and does not involve real money or the opportunity to win real money.
</span>
<div className="grid grid-cols-6 mx-5 my-5">
<Link href="/play" className="col-span-3 w-[min-content] md:w-[300px] text-2xl font-bold text-white">
Plinko Game
</Link>
<div className="col-span-3 flex justify-end items-center space-x-1">
{!!address && (
<div className="flex space-x-2 items-center">
<Balance/>
<UserProfileMenu/>
</div>
)}
</div>
)}
</div>
</div>
</div>
</>
);
};
123 changes: 123 additions & 0 deletions app/src/components/ui/dialog.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
"use client"

import * as React from "react"
import * as DialogPrimitive from "@radix-ui/react-dialog"
import { X } from "lucide-react"

import { cn } from "@/lib/utils"

const Dialog = DialogPrimitive.Root

const DialogTrigger = DialogPrimitive.Trigger

const DialogPortal = DialogPrimitive.Portal

const DialogClose = DialogPrimitive.Close

const DialogOverlay = React.forwardRef<
React.ElementRef<typeof DialogPrimitive.Overlay>,
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Overlay>
>(({ className, ...props }, ref) => (
<DialogPrimitive.Overlay
ref={ref}
className={cn(
"fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
className
)}
{...props}
/>
))
DialogOverlay.displayName = DialogPrimitive.Overlay.displayName

const DialogContent = React.forwardRef<
React.ElementRef<typeof DialogPrimitive.Content>,
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content>
>(({ className, children, ...props }, ref) => (
<DialogPortal>
<DialogOverlay/>
<DialogPrimitive.Content
ref={ref}
className={cn(
"fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg",
className
)}
{...props}
>
{children}
<DialogPrimitive.Close
className="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground">
<X className="h-4 w-4"/>
<span className="sr-only">Close</span>
</DialogPrimitive.Close>
</DialogPrimitive.Content>
</DialogPortal>
))
DialogContent.displayName = DialogPrimitive.Content.displayName

const DialogHeader = ({
className,
...props
}: React.HTMLAttributes<HTMLDivElement>) => (
<div
className={cn(
"flex flex-col space-y-1.5 text-center sm:text-left",
className
)}
{...props}
/>
)
DialogHeader.displayName = "DialogHeader"

const DialogFooter = ({
className,
...props
}: React.HTMLAttributes<HTMLDivElement>) => (
<div
className={cn(
"flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2",
className
)}
{...props}
/>
)
DialogFooter.displayName = "DialogFooter"

const DialogTitle = React.forwardRef<
React.ElementRef<typeof DialogPrimitive.Title>,
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Title>
>(({ className, ...props }, ref) => (
<DialogPrimitive.Title
ref={ref}
className={cn(
"text-lg font-semibold leading-none tracking-tight",
className
)}
{...props}
/>
))
DialogTitle.displayName = DialogPrimitive.Title.displayName

const DialogDescription = React.forwardRef<
React.ElementRef<typeof DialogPrimitive.Description>,
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Description>
>(({ className, ...props }, ref) => (
<DialogPrimitive.Description
ref={ref}
className={cn("text-sm text-muted-foreground", className)}
{...props}
/>
))
DialogDescription.displayName = DialogPrimitive.Description.displayName

export {
Dialog,
DialogPortal,
DialogOverlay,
DialogClose,
DialogTrigger,
DialogContent,
DialogHeader,
DialogFooter,
DialogTitle,
DialogDescription,
}
48 changes: 48 additions & 0 deletions app/src/components/ui/scroll-area.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
"use client"

import * as React from "react"
import * as ScrollAreaPrimitive from "@radix-ui/react-scroll-area"

import { cn } from "@/lib/utils"

const ScrollArea = React.forwardRef<
React.ElementRef<typeof ScrollAreaPrimitive.Root>,
React.ComponentPropsWithoutRef<typeof ScrollAreaPrimitive.Root>
>(({ className, children, ...props }, ref) => (
<ScrollAreaPrimitive.Root
ref={ref}
className={cn("relative overflow-hidden", className)}
{...props}
>
<ScrollAreaPrimitive.Viewport className="h-full w-full rounded-[inherit]">
{children}
</ScrollAreaPrimitive.Viewport>
<ScrollBar />
<ScrollAreaPrimitive.Corner />
</ScrollAreaPrimitive.Root>
))
ScrollArea.displayName = ScrollAreaPrimitive.Root.displayName

const ScrollBar = React.forwardRef<
React.ElementRef<typeof ScrollAreaPrimitive.ScrollAreaScrollbar>,
React.ComponentPropsWithoutRef<typeof ScrollAreaPrimitive.ScrollAreaScrollbar>
>(({ className, orientation = "vertical", ...props }, ref) => (
<ScrollAreaPrimitive.ScrollAreaScrollbar
ref={ref}
orientation={orientation}
className={cn(
"flex touch-none select-none transition-colors",
orientation === "vertical" &&
"h-full w-2.5 border-l border-l-transparent p-[1px]",
orientation === "horizontal" &&
"h-2.5 flex-col border-t border-t-transparent p-[1px]",
className
)}
{...props}
>
<ScrollAreaPrimitive.ScrollAreaThumb className="relative flex-1 rounded-full bg-border" />
</ScrollAreaPrimitive.ScrollAreaScrollbar>
))
ScrollBar.displayName = ScrollAreaPrimitive.ScrollAreaScrollbar.displayName

export { ScrollArea, ScrollBar }
16 changes: 16 additions & 0 deletions app/src/lib/hooks/use-scroll.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { useCallback, useEffect, useState } from "react";

export default function useScroll(threshold: number) {
const [scrolled, setScrolled] = useState(false);

const onScroll = useCallback(() => {
setScrolled(window.pageYOffset > threshold);
}, [threshold]);

useEffect(() => {
window.addEventListener("scroll", onScroll);
return () => window.removeEventListener("scroll", onScroll);
}, [onScroll]);

return scrolled;
}

0 comments on commit 102feac

Please sign in to comment.