Skip to content

Commit

Permalink
feat: match making mock UI & update UI (#1)
Browse files Browse the repository at this point in the history
* feat: mock UI new flow

* chore: using count up

* feat: update start screen

* chore: add cover objectfit

* chore: implement modal

* chore: found match screen

* chore: update found match

* fix: face direction

* chore: update player name tag

* chore: update character file name

* chore: add play again button

* chore: using modal

* chore: uncomment refresh interval

* chore: add hover effect

* chore: update UI
  • Loading branch information
toanbku authored Feb 16, 2023
1 parent bc4e3e3 commit 3471ecc
Show file tree
Hide file tree
Showing 34 changed files with 499 additions and 63 deletions.
26 changes: 14 additions & 12 deletions components/Map.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -160,40 +160,42 @@ export const Map = () => {
src={GOALS[goal.player_id! || "a"]}
alt="goal"
fill
className="scale-125"
/>
)}

{player && (
<div
className={[
"absolute w-full h-full",
"absolute w-full h-full scale-110",
playerFacingDirections.current[player.id],
wasHit ? "hit" : "idle",
].join(" ")}
key={player.id}
>
<Image
src={PLAYERS[player.id]}
src={
wasHit
? PLAYERS[player.id].hit
: PLAYERS[player.id].normal
}
fill
className="object-contain !-top-1/4"
alt={player.name ? player.name : player.id}
/>
<div className="md:text-xs text-white">
<div>
<div className="absolute p-[1px] md:p-[2px] min-w-[20px] md:min-w-[30px] -left-1/2 md:-left-1/3 -translate-y-2/3 flex flex-col items-center justify-center text-[8px] md:text-xs text-black bg-white rounded-md opacity-90 hover:opacity-100">
<span>
{player.id === currentPlayer?.id ? (
"You"
) : (
<>{player.name ? player.name : player.id}</>
)}
</div>
<div>{player.points}</div>
</span>
{winner?.id === player.id && (
<span className=" text-green-700">Winner</span>
)}
<span>{player.points}</span>
</div>

{winner?.id === player.id && (
<div className="flex text-green-300 font-bold flex-row text-xs">
Winner🎉
</div>
)}
</div>
)}

Expand Down
33 changes: 33 additions & 0 deletions components/MatchMaking/FoundMatch.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { CountdownCircleTimer } from "react-countdown-circle-timer";

export const FoundMatch = () => {
return (
<div className="w-full h-full fixed bg-black/90 top-0 left-0 z-50 flex justify-center items-center">
<div className="relative w-96 h-96 p-6 text-white border-solid border-2 border-yellow-800 rounded-full">
<div className="w-full h-full rounded-full border border-yellow-300 bg-gray-800">
<div className="w-full h-full rounded-full border-[10px] border-blue-400 flex flex-col justify-center text-center">
<div className="relative w-full h-full p-8 rounded-full border border-yellow-300 flex flex-col justify-center">
<div className="font-bold text-yellow-200 text-2xl">
Match Found
</div>
<div className="text-yellow-100 text-xs">
Summoner&#39;s Rift • Co-op vs. AI • 5v5
</div>

<div className="accept-button bg-black absolute left-1/2 bottom-0 -translate-x-1/2 translate-y-1/2 border border-yellow-300 p-1">
<button className="py-1 px-4 border border-cyan-500 bg-slate-700">
Accept!
</button>
</div>
</div>
</div>
</div>

{/* decline button */}
<button className="px-3 py-1 bg-slate-800 border border-yellow-700 absolute left-1/2 bottom-0 -translate-x-1/2 translate-y-1/2 text-xs">
Decline
</button>
</div>
</div>
);
};
82 changes: 82 additions & 0 deletions components/MatchMaking/ReadyScreen.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import { useState } from "react";
import { Icon } from "@iconify/react";
import Countdown, { CountdownRenderProps } from "react-countdown";
import { Modal } from "../Modal/Modal";

export const ReadyScreen = () => {
const [isReady, setIsReady] = useState(false);

const renderCountDown = ({
minutes,
seconds,
completed,
}: CountdownRenderProps) => {
if (completed) {
// Render a completed state
return (
<span className="text-center text-4xl">
{isReady ? "Game screen" : "Home screen"}
</span>
);
} else {
// Render a countdown
return (
<span className="text-center text-4xl">
{minutes.toString().padStart(2, "0")}:
{seconds.toString().padStart(2, "0")}
</span>
);
}
};

return (
<Modal
isOpen={true}
title="Match Found!"
body={
<>
<div className="grid grid-cols-2 grid-rows-2 gap-4">
<div className="flex flex-col items-center">
<Icon
icon="arcticons:cat-avatar-generator"
width={96}
height={96}
className={`${isReady ? "text-green-500" : ""}`}
/>
You
</div>
<div className="flex flex-col items-center">
<Icon icon="radix-icons:avatar" width={96} height={96} />
User 1
</div>
<div className="flex flex-col items-center">
<Icon icon="radix-icons:avatar" width={96} height={96} />
User 2
</div>
<div className="flex flex-col items-center">
<Icon
icon="radix-icons:avatar"
width={96}
height={96}
className={`${"text-green-500"}`}
/>
User 3
</div>
</div>

<div className="flex justify-center mt-2 md:mt-4">
<Countdown
date={Date.now() + 10000}
zeroPadTime={2}
renderer={renderCountDown}
/>
</div>
</>
}
submitText={isReady ? "Waiting for other players..." : "Ready"}
onSubmit={() => {
setIsReady(true);
}}
/>
);
};
76 changes: 76 additions & 0 deletions components/MatchMaking/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import { useState } from "react";
import CountUp from "react-countup";
import { useDisclosure } from "@dwarvesf/react-hooks";
import { Modal } from "../Modal/Modal";
import { ReadyScreen } from "./ReadyScreen";

export const MatchMaking = () => {
const { isOpen, onOpen, onClose } = useDisclosure();
const [isReady, setIsReady] = useState(false);
const [isTimeOut, setIsTimeOut] = useState(false);
const onFindMatch = () => {
onOpen();
// implement logic later
};

const onCancelFindMatch = () => {
onClose();
setIsTimeOut(false);
// implement logic later
};

const clockFormatter = (value: number) => {
const minutes = Math.floor((value % 3600) / 60);
const seconds = value % 60;

const formattedMinutes = minutes.toString().padStart(2, "0");
const formattedSeconds = seconds.toString().padStart(2, "0");

return `${formattedMinutes}:${formattedSeconds}`;
};

return (
<>
<button type="submit" className="primary w-full" onClick={onFindMatch}>
{isOpen ? "Matching..." : "Find a Match"}
</button>

<Modal
isOpen={isOpen}
title={"Matching..."}
body={
<div className="w-full h-full flex flex-col items-center justify-center">
<div className="flex gap-4 w-full justify-between px-2">
{isTimeOut ? (
<span className="text-red-500">
Sorry, we cannot find your opponent
</span>
) : (
<span>Looking for your opponent...</span>
)}
<CountUp
delay={0}
duration={10}
end={10}
onEnd={() => {
if (Math.random() < 0.5) {
onClose();
setIsReady(true);
} else {
setIsTimeOut(true);
}
}}
formattingFn={clockFormatter}
/>
</div>
</div>
}
cancelText="Cancel"
onCancel={() => {
onCancelFindMatch();
}}
/>
{isReady && <ReadyScreen />}
</>
);
};
67 changes: 67 additions & 0 deletions components/Modal/Modal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
export const Modal = ({
isOpen,
title,
body,
onSubmit,
onCancel,
cancelText = "Cancel",
submitText = "Submit",
}: {
isOpen: boolean;
title: string;
body: React.ReactNode;
onCancel?: () => void;
cancelText?: string;
onSubmit?: () => void;
submitText?: string;
}) => {
return (
<>
{isOpen ? (
<>
<div className="justify-center items-center flex overflow-x-hidden overflow-y-auto fixed inset-0 z-50 outline-none focus:outline-none">
<div className="relative w-auto md:min-w-[384px] my-6 mx-auto max-w-3xl">
{/*content*/}
<div className="border-0 rounded-lg shadow-lg relative flex flex-col w-full bg-white outline-none focus:outline-none">
{/*header*/}
<div className="flex items-start justify-between p-5 border-b border-solid border-slate-200 rounded-t">
<h3 className="text-2xl font-semibold text-purple-700">
{title}
</h3>
</div>
{/*body*/}
<div className="relative p-6 flex-auto">
<p className="my-4 text-black text-lg leading-relaxed">
{body}
</p>
</div>
{/*footer*/}
<div className="flex items-center gap-4 p-2 md:p-4 border-t border-solid border-slate-200 rounded-b">
{onCancel && (
<button
className="flex-1 text-red-500 background-transparent outline-none focus:outline-none ease-linear transition-all duration-150 p-2 md:p-4"
type="button"
onClick={onCancel}
>
{cancelText}
</button>
)}
{onSubmit && (
<button
className="flex-1 bg-purple-500 text-white active:bg-purple-600 rounded shadow hover:shadow-lg outline-none focus:outline-none ease-linear transition-all duration-150 p-2 md:p-4"
type="button"
onClick={onSubmit}
>
{submitText}
</button>
)}
</div>
</div>
</div>
</div>
<div className="opacity-60 fixed inset-0 z-40 bg-black"></div>
</>
) : null}
</>
);
};
Loading

1 comment on commit 3471ecc

@vercel
Copy link

@vercel vercel bot commented on 3471ecc Feb 16, 2023

Choose a reason for hiding this comment

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

Successfully deployed to the following URLs:

hunger-game – ./

hunger-game-git-master-podso.vercel.app
hunger-game-podso.vercel.app
the-hunger-game.vercel.app

Please sign in to comment.