-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
chore: move remix folder content to root
- Loading branch information
1 parent
1b690e1
commit 19eff61
Showing
51 changed files
with
648 additions
and
1,643 deletions.
There are no files selected for viewing
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,37 +1,4 @@ | ||
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. | ||
|
||
# dependencies | ||
/node_modules | ||
/.pnp | ||
/data | ||
.pnp.js | ||
.yarn/install-state.gz | ||
|
||
# testing | ||
/coverage | ||
|
||
# next.js | ||
/.next/ | ||
/out/ | ||
|
||
# production | ||
/build | ||
|
||
# misc | ||
.DS_Store | ||
*.pem | ||
|
||
# debug | ||
npm-debug.log* | ||
yarn-debug.log* | ||
yarn-error.log* | ||
|
||
# local env files | ||
.env*.local | ||
|
||
# vercel | ||
.vercel | ||
|
||
# typescript | ||
*.tsbuildinfo | ||
next-env.d.ts | ||
build/ | ||
node_modules/ | ||
games/ | ||
.cache/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
import { | ||
Dialog, | ||
DialogContent, | ||
DialogDescription, | ||
DialogFooter, | ||
DialogHeader, | ||
DialogTitle, | ||
DialogTrigger, | ||
} from "./ui/dialog"; | ||
import { Button, buttonVariants } from "./ui/button"; | ||
import { useFetcher } from "@remix-run/react"; | ||
import { useEffect, useState } from "react"; | ||
import type { GameMetadata } from "@/server/data"; | ||
import { z } from "zod"; | ||
import toast from "react-hot-toast"; | ||
|
||
export const DeleteGameDialog = (props: { game: GameMetadata }) => { | ||
const { game } = props; | ||
const [open, setOpen] = useState(false); | ||
|
||
const fetcher = useFetcher(); | ||
const isSubmitting = fetcher.state !== "idle"; | ||
|
||
const res = z | ||
.object({ success: z.boolean() }) | ||
.or(z.undefined()) | ||
.parse(fetcher.data); | ||
|
||
useEffect(() => { | ||
if (res?.success) { | ||
setOpen(false); | ||
toast.success("Game deleted successfully"); | ||
} | ||
}, [res?.success]); | ||
|
||
return ( | ||
<Dialog open={open} onOpenChange={(o) => setOpen(o)}> | ||
<DialogTrigger> | ||
<div className={buttonVariants({ variant: "destructive" })}>Delete</div> | ||
</DialogTrigger> | ||
<DialogContent> | ||
<DialogHeader> | ||
<DialogTitle>{`Delete game ${game.name}?`}</DialogTitle> | ||
<DialogDescription> | ||
Are you sure you want to delete this game? All of your data will be | ||
permanently removed. This action cannot be undone. | ||
</DialogDescription> | ||
</DialogHeader> | ||
<DialogFooter> | ||
<fetcher.Form action="delete-game" method="post"> | ||
<input type="hidden" name="gameId" value={game.gameId} /> | ||
<Button | ||
variant="destructive" | ||
type="submit" | ||
disabled={isSubmitting} | ||
aria-disabled={isSubmitting} | ||
> | ||
Delete | ||
</Button> | ||
</fetcher.Form> | ||
</DialogFooter> | ||
</DialogContent> | ||
</Dialog> | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
import { | ||
Dialog, | ||
DialogContent, | ||
DialogDescription, | ||
DialogFooter, | ||
DialogHeader, | ||
DialogTitle, | ||
DialogTrigger, | ||
} from "./ui/dialog"; | ||
import { Button, buttonVariants } from "./ui/button"; | ||
import { useFetcher } from "@remix-run/react"; | ||
import { useEffect, useState } from "react"; | ||
import { z } from "zod"; | ||
import toast from "react-hot-toast"; | ||
|
||
type Props = { | ||
saveId: string; | ||
}; | ||
|
||
export const DeleteSaveStateDialog = (props: Props) => { | ||
const { saveId } = props; | ||
const [open, setOpen] = useState(false); | ||
|
||
const fetcher = useFetcher(); | ||
const isSubmitting = fetcher.state !== "idle"; | ||
|
||
const res = z | ||
.object({ success: z.boolean() }) | ||
.or(z.undefined()) | ||
.parse(fetcher.data); | ||
|
||
useEffect(() => { | ||
if (res?.success) { | ||
toast.success("Save state deleted successfully"); | ||
setOpen(false); | ||
} | ||
}, [res?.success]); | ||
|
||
return ( | ||
<Dialog open={open} onOpenChange={(o) => setOpen(o)}> | ||
<DialogTrigger> | ||
<div className={buttonVariants({ variant: "destructive", size: "sm" })}> | ||
Delete | ||
</div> | ||
</DialogTrigger> | ||
<DialogContent> | ||
<DialogHeader> | ||
<DialogTitle>Delete save state?</DialogTitle> | ||
<DialogDescription> | ||
Are you sure you want to delete this save? You won't be able to | ||
recover it. | ||
</DialogDescription> | ||
</DialogHeader> | ||
<DialogFooter> | ||
<fetcher.Form action="delete-save" method="post"> | ||
<input type="hidden" name="saveId" value={saveId} /> | ||
<Button | ||
variant="destructive" | ||
type="submit" | ||
disabled={isSubmitting} | ||
aria-disabled={isSubmitting} | ||
> | ||
Delete | ||
</Button> | ||
</fetcher.Form> | ||
</DialogFooter> | ||
</DialogContent> | ||
</Dialog> | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
import { Button, buttonVariants } from "@/components/ui/button"; | ||
import { | ||
Dialog, | ||
DialogTrigger, | ||
DialogContent, | ||
DialogTitle, | ||
DialogHeader, | ||
DialogDescription, | ||
DialogFooter, | ||
} from "@/components/ui/dialog"; | ||
import { Input } from "@/components/ui/input"; | ||
import { useFetcher } from "@remix-run/react"; | ||
import { useEffect, useState } from "react"; | ||
import toast from "react-hot-toast"; | ||
import { z } from "zod"; | ||
|
||
export const UploadGameDialog = () => { | ||
const [open, setOpen] = useState(false); | ||
|
||
const fetcher = useFetcher(); | ||
const isSubmitting = fetcher.state !== "idle"; | ||
|
||
const res = z | ||
.object({ errors: z.record(z.string()), success: z.boolean() }) | ||
.or(z.undefined()) | ||
.parse(fetcher.data); | ||
|
||
useEffect(() => { | ||
if (res?.success) { | ||
setOpen(false); | ||
toast.success("Game uploaded successfully"); | ||
} | ||
}, [res?.success]); | ||
|
||
return ( | ||
<Dialog open={open} onOpenChange={(o) => setOpen(o)}> | ||
<DialogTrigger> | ||
<div className={buttonVariants()}>Upload a game</div> | ||
</DialogTrigger> | ||
<DialogContent> | ||
<fetcher.Form | ||
id="upload-game-form" | ||
method="post" | ||
action="/upload-game" | ||
encType="multipart/form-data" | ||
> | ||
<DialogHeader> | ||
<DialogTitle>Upload a game</DialogTitle> | ||
<DialogDescription> | ||
GBA, GBC, and GB file types are supported. | ||
</DialogDescription> | ||
</DialogHeader> | ||
<div className="flex flex-col gap-2 my-4"> | ||
<Input | ||
type="file" | ||
name="game_file" | ||
required | ||
accept=".gba,.gbc,.gb" | ||
/> | ||
{res?.errors.game_file && ( | ||
<p id="game_file" className="ml-3 text-sm text-red-500 mb-2"> | ||
{res.errors.game_file} | ||
</p> | ||
)} | ||
<Input type="text" name="name" placeholder="Name" required /> | ||
{res?.errors.name && ( | ||
<p id="name" className="ml-3 text-sm text-red-500"> | ||
{res.errors.name} | ||
</p> | ||
)} | ||
</div> | ||
<DialogFooter> | ||
<Button | ||
type="submit" | ||
disabled={isSubmitting} | ||
aria-disabled={isSubmitting} | ||
> | ||
Upload | ||
</Button> | ||
</DialogFooter> | ||
</fetcher.Form> | ||
</DialogContent> | ||
</Dialog> | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
File renamed without changes.
File renamed without changes.
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
import { GamesTable } from "@/components/games-table"; | ||
import { UploadGameDialog } from "@/components/upload-game-dialog"; | ||
import { getGamesMetadata } from "@/server/data"; | ||
import { json, useLoaderData } from "@remix-run/react"; | ||
|
||
export const loader = async () => { | ||
const games = await getGamesMetadata(); | ||
|
||
return json({ games }); | ||
}; | ||
|
||
export default function Index() { | ||
const { games } = useLoaderData<typeof loader>(); | ||
|
||
return ( | ||
<section> | ||
<div className="relative items-center w-full px-5 py-12 mx-auto md:px-12 lg:px-16 max-w-7xl lg:py-24"> | ||
<div className="flex w-full mx-auto text-left"> | ||
<div className="relative inline-flex items-center mx-auto align-middle"> | ||
<div className="text-center"> | ||
<h1 className="max-w-5xl text-2xl font-bold leading-none tracking-tighter md:text-5xl lg:text-6xl lg:max-w-7xl bg-gradient-to-r from-red-500 to-blue-500 bg-clip-text text-transparent"> | ||
NextGBA | ||
</h1> | ||
<p className="max-w-xl mx-auto mt-4 text-base leading-relaxed text-gray-500"> | ||
Play your favorite GBA games on the web. | ||
<br /> | ||
Powered by <b>EmulatorJS</b>. | ||
</p> | ||
<div className="flex justify-center w-full max-w-2xl gap-2 mx-auto mt-6"> | ||
<div className="mt-3 rounded-lg sm:mt-0"> | ||
<UploadGameDialog /> | ||
</div> | ||
</div> | ||
</div> | ||
</div> | ||
</div> | ||
<div className="w-full mx-auto border-2 p-2 border-dashed mt-24 rounded"> | ||
<GamesTable games={games} /> | ||
</div> | ||
</div> | ||
</section> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
import type { LoaderFunctionArgs } from "@remix-run/node"; | ||
import { getRomFile } from "@/server/data"; | ||
|
||
export async function loader({ request }: LoaderFunctionArgs) { | ||
try { | ||
const { searchParams } = new URL(request.url); | ||
const gameId = searchParams.get("gameId"); | ||
const csl = searchParams.get("console"); | ||
|
||
if (typeof gameId !== "string" || typeof csl !== "string") { | ||
return new Response("Not found", { status: 404 }); | ||
} | ||
|
||
const file = await getRomFile(gameId, csl); | ||
|
||
return new Response(file, { | ||
headers: { | ||
"content-type": "application/octet-stream", | ||
"cache-control": "public, max-age=31536000", | ||
}, | ||
}); | ||
} catch (error) { | ||
console.error(error); | ||
return new Response("Error", { status: 500 }); | ||
} | ||
} |
Oops, something went wrong.