diff --git a/src/client/AuthorPage.tsx b/src/client/AuthorPage.tsx new file mode 100644 index 0000000..0c976bb --- /dev/null +++ b/src/client/AuthorPage.tsx @@ -0,0 +1,62 @@ +import { Link, useParams } from "react-router-dom" +import { useEffect, useState } from "react"; +import { DbRelease } from "../server/dbal/dbal"; +import { css } from "@emotion/css"; + +type Info = { + author: string | null; + games: {slug: string; releases: DbRelease[]}[]; +} + +export const AuthorPage = () => { + const {author} = useParams(); + const [info, setInfo] = useState(null); + + useEffect(() => { + const fetchInfo = async () => { + let url = `/api/author?author=${author}`; + const information = await fetch(url); + const json = await information.json(); + console.log('json', json); + setInfo(json); + } + fetchInfo(); + }, [setInfo, author]); + + if (!info) { + return ( +
+ LOADING... +
+ ) + } + + if (!info.author) { + return ( +
+ NOT FOUND +
+ ) + } + + return ( +
+

{author}

+ { + info.games.map(game => ( + +

{game.releases[0].manifest.title ?? game.slug}

+ + )) + } +
+ ) +} \ No newline at end of file diff --git a/src/client/GamePage.tsx b/src/client/GamePage.tsx index 869b30a..669a020 100644 --- a/src/client/GamePage.tsx +++ b/src/client/GamePage.tsx @@ -1,4 +1,4 @@ -import { useNavigate, useParams } from "react-router-dom" +import { Link, useParams } from "react-router-dom" import { Pico8Console } from "./pico8-client/Pico8Console"; import { useEffect, useState } from "react"; import { DbRelease } from "../server/dbal/dbal"; @@ -10,15 +10,19 @@ type Info = { } export const GamePage = () => { - const {author, slug, version} = useParams(); - const navigate = useNavigate(); + const {author, slug} = useParams(); + // const [searchParams, setSearchParams] = useSearchParams(); + // const version = searchParams.get('v'); + const [v, setVersion] = useState(null); const [info, setInfo] = useState(null); + const version = v ?? info?.release?.version ?? info?.versions[0]; + useEffect(() => { const fetchInfo = async () => { let url = `/api/release?author=${author}&slug=${slug}`; if (version) { - url += `&version=${version.slice(1)}`; + url += `&version=${version}`; } const information = await fetch(url); const json = await information.json(); @@ -29,9 +33,7 @@ export const GamePage = () => { if (!info) { return ( -
+
LOADING...
) @@ -39,9 +41,7 @@ export const GamePage = () => { if (!info.release) { return ( -
+
NOT FOUND
) @@ -49,53 +49,47 @@ export const GamePage = () => { return (
+
+

{info.release.manifest.title ?? slug!.split("-").map(word => word[0].toUpperCase()+word.slice(1)).join(" ")}

+

by {info.release.author}

+
-
-

{info.release.manifest.title ?? slug!.split("-").map(word => word[0].toUpperCase()+word.slice(1)).join(" ")}

-

by {info.release.author}

+
+
-
setVersion(ev.target.value)}> + { + [...info.versions].reverse().map(v => ( + + )) } - `}> - -
-
- Version: -
+
- {/*
-

This is a paragraph about this game. It is a cool game. And a cool website to play it on. It automagically connects from GitHub.

-
*/}
+ {/*
+

This is a paragraph about this game. It is a cool game. And a cool website to play it on. It automagically connects from GitHub.

+
*/}
) } \ No newline at end of file diff --git a/src/client/routing.tsx b/src/client/routing.tsx index f67a7a0..7955742 100644 --- a/src/client/routing.tsx +++ b/src/client/routing.tsx @@ -1,12 +1,20 @@ import { Outlet, RouterProvider, ScrollRestoration, createBrowserRouter, redirect } from "react-router-dom" import { HomePage } from "./HomePage"; import { GamePage } from "./GamePage"; +import { AuthorPage } from "./AuthorPage"; +import { css } from "@emotion/css"; const RouteRoot = () => { return <> {/* */} } @@ -23,11 +31,11 @@ const router = createBrowserRouter([ // } }, { - path: "/u/:author/:slug", - element: , + path: "/u/:author", + element: , }, { - path: "/u/:author/:slug/:version", + path: "/u/:author/:slug", element: , }, ], diff --git a/src/server/api/getAuthor.ts b/src/server/api/getAuthor.ts new file mode 100644 index 0000000..cb68d0d --- /dev/null +++ b/src/server/api/getAuthor.ts @@ -0,0 +1,34 @@ +import { Type } from "@sinclair/typebox"; +import { FirRouteInput, FirRouteOptions } from "../util/routewrap.ts"; +import { getAuthorGames, getReleases } from "../dbal/dbal.ts"; + +const method = "GET"; +const url = "/api/author"; + +const payloadT = Type.Any(); + +const handler = async ({payload}: FirRouteInput) => { + const {author} = payload; + + if (typeof author !== "string") { + return { + author: null, + releases: [], + }; + } + console.log("author", author); + + const games = await getAuthorGames({author}); + + return { + author, + games, + } +}; + +export default { + method, + url, + payloadT, + handler, +} as const satisfies FirRouteOptions; \ No newline at end of file diff --git a/src/server/dbal/dbal.ts b/src/server/dbal/dbal.ts index edfb45e..e987352 100644 --- a/src/server/dbal/dbal.ts +++ b/src/server/dbal/dbal.ts @@ -38,12 +38,18 @@ const compareByVersion = (a: DbRelease, b: DbRelease) => compareVersions(a.versi export const getReleases = async (where: { author: string; - slug: string; + slug?: string; version?: string; }): Promise => { const {author, slug, version} = where; let rows: DbReleaseInternal[]; - if (!version) { + if (!slug) { + rows = await db.query(sql` + SELECT * from releases + WHERE + author = ${author} + `); + } else if (!version) { rows = await db.query(sql` SELECT * from releases WHERE @@ -84,6 +90,25 @@ export const getRelease = async (where: { } } +export const getAuthorGames = async (where: { + author: string; +}) => { + const releases = await getReleases(where); + const games = releases.reduce((accum, curr) => { + const found = accum.find(r => r.slug === curr.slug); + if (found) { + found.releases.push(curr); + } else { + accum.push({slug: curr.slug, releases: [curr]}); + } + return accum; + }, [] as {slug: string; releases: DbRelease[]}[]); + games.forEach(game => { + game.releases.sort(compareByVersion); + }); + return games; +} + export const insertRelease = async (props: {manifest: PicobookManifest, carts: {name: string; rom: number[]}[]}) => { const {manifest, carts} = props; // console.log('carts', JSON.stringify(carts)); diff --git a/src/server/routelist.ts b/src/server/routelist.ts index 6cb1aec..836de53 100644 --- a/src/server/routelist.ts +++ b/src/server/routelist.ts @@ -1,4 +1,5 @@ import echo from "./api/echo.ts"; +import getAuthor from "./api/getAuthor.ts"; import getRelease from "./api/getRelease.ts"; import release from "./api/release.ts"; import webhook from "./api/webhook.ts"; @@ -8,6 +9,7 @@ export const routeList = [ webhook, release, getRelease, + getAuthor, ]; export type RouteList = typeof routeList; \ No newline at end of file