Skip to content

Commit

Permalink
feat: game over dialog (#39)
Browse files Browse the repository at this point in the history
* feat: game over dialog

* refactor: to async await

* a11y 👎
  • Loading branch information
drewradcliff authored Aug 30, 2024
1 parent bfca7c2 commit 97cca4e
Show file tree
Hide file tree
Showing 4 changed files with 113 additions and 22 deletions.
39 changes: 18 additions & 21 deletions app/components/field.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

import { useEffect, useRef } from "react";
import { useVirtualizer } from "@tanstack/react-virtual";
import { Skull } from "lucide-react";
import { Fade } from "@/components/fade";
import { GameOverDialog } from "@/components/game-over-dialog";
import { Plot } from "@/components/plot";
import { TutorialDialog } from "@/components/tutorial-dialog";
import { useSocketEvent } from "@/hooks/use-socket-event";
Expand Down Expand Up @@ -43,28 +43,24 @@ export function Field() {
);
}, [size]);

return !plots || sessionState === "dead" ? (
return !plots ? (
<div className="absolute z-10 h-[100dvh] w-[100dvw] bg-white dark:bg-slate-950">
<div className="flex h-full items-center justify-center">
{sessionState === "dead" ? (
<Skull className="h-16 w-16 text-red-600 dark:text-red-300" />
) : (
<div
className="grid animate-pulse"
style={{
gap: `${GAP_SIZE}rem`,
gridTemplateColumns: `repeat(3, ${GRID_SIZE}rem)`,
}}
>
{Array.from({ length: 9 }, (_, index) => (
<div
key={index}
className="bg-slate-100 dark:bg-slate-600"
style={{ height: `${GRID_SIZE}rem`, width: `${GRID_SIZE}rem` }}
/>
))}
</div>
)}
<div
className="grid animate-pulse"
style={{
gap: `${GAP_SIZE}rem`,
gridTemplateColumns: `repeat(3, ${GRID_SIZE}rem)`,
}}
>
{Array.from({ length: 9 }, (_, index) => (
<div
key={index}
className="bg-slate-100 dark:bg-slate-600"
style={{ height: `${GRID_SIZE}rem`, width: `${GRID_SIZE}rem` }}
/>
))}
</div>
</div>
</div>
) : (
Expand Down Expand Up @@ -99,6 +95,7 @@ export function Field() {
}),
)}
</div>
{sessionState === "dead" && <GameOverDialog />}
{isNewSession && <TutorialDialog />}
</div>
);
Expand Down
70 changes: 70 additions & 0 deletions app/components/game-over-dialog.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
"use client";

import { useRef, useState } from "react";
import { CheckIcon, CopyIcon, Skull } from "lucide-react";
import { Button } from "@/components/ui/button";
import {
Dialog,
DialogContent,
DialogHeader,
DialogTitle,
} from "@/components/ui/dialog";
import { Input } from "@/components/ui/input";

export function GameOverDialog() {
const [isOpen, setIsOpen] = useState(true);
const [isCopied, setIsCopied] = useState(false);
const inputRef = useRef<HTMLInputElement>(null);
const shareLink = "https://mmmines.fly.dev/";

const copyToClipboard = async () => {
if (inputRef.current) {
inputRef.current.select();
await navigator.clipboard.writeText(shareLink);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
}
};

return (
<Dialog open={isOpen} onOpenChange={setIsOpen}>
<DialogContent className="sm:max-w-md">
<DialogHeader>
<DialogTitle>Game Over</DialogTitle>
</DialogHeader>
<div className="flex flex-col items-center gap-6">
<Skull className="h-12 w-12 text-red-600 dark:text-red-300" />
<div>
<h1 className="pb-2 text-center text-lg font-semibold">
You&apos;re out this round
</h1>
<h2 className="text-center text-sm text-slate-600 dark:text-slate-300">
Share this link with others so you can get back in sooner!
</h2>
</div>
<div className="flex w-full space-x-2">
<Input
ref={inputRef}
readOnly
value={shareLink}
className="flex-grow"
/>
<Button onClick={copyToClipboard} className="w-24">
{isCopied ? (
<>
<CheckIcon className="mr-2 h-4 w-4" />
Copied
</>
) : (
<>
<CopyIcon className="mr-2 h-4 w-4" />
Copy
</>
)}
</Button>
</div>
</div>
</DialogContent>
</Dialog>
);
}
2 changes: 1 addition & 1 deletion app/components/tutorial-dialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ export function TutorialDialog() {

return (
<Dialog open={open} onOpenChange={setOpen} defaultOpen>
<DialogContent className="sm:max-w-[425px]">
<DialogContent className="sm:max-w-md">
<DialogHeader>
<DialogTitle>How to Play</DialogTitle>
</DialogHeader>
Expand Down
24 changes: 24 additions & 0 deletions app/components/ui/input.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import * as React from "react";
import { cn } from "@/utils";

export interface InputProps
extends React.InputHTMLAttributes<HTMLInputElement> {}

const Input = React.forwardRef<HTMLInputElement, InputProps>(
({ className, type, ...props }, ref) => {
return (
<input
type={type}
className={cn(
"flex h-9 w-full rounded-md border border-slate-200 bg-transparent px-3 py-1 text-sm shadow-sm transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-slate-500 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-slate-950 disabled:cursor-not-allowed disabled:opacity-50 dark:border-slate-800 dark:placeholder:text-slate-400 dark:focus-visible:ring-slate-300",
className,
)}
ref={ref}
{...props}
/>
);
},
);
Input.displayName = "Input";

export { Input };

0 comments on commit 97cca4e

Please sign in to comment.