Skip to content

Commit

Permalink
Switch to new data source for demos (#75)
Browse files Browse the repository at this point in the history
* Refactor env.

* Refactor hub.

* Add cloudfront service.

* Refactor scoreboard.

* Disable playlists.

* Update supabase types.

* Remove playlist.

* Major refactoring; switch to results from games table.

* Update game browser settings.

* Update browser, sidebar, pagination limit.
  • Loading branch information
vikpe committed Jun 15, 2024
1 parent 13f71eb commit 4465564
Show file tree
Hide file tree
Showing 56 changed files with 700 additions and 655 deletions.
2 changes: 1 addition & 1 deletion .env.local.example
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
CONVEX_DEPLOYMENT="dev:alpha-beta-123" # Deployment used by `npx convex dev`
VITE_CONVEX_URL="https://alpha-beta-123.convex.cloud"
VITE_QUAKEWORLD_CLOUDFRONT_URL="https://d3mei09tvo6qxe.cloudfront.net"
VITE_DEMOS_CLOUDFRONT_URL="https://d.quake.world"
VITE_ASSETS_CLOUDFRONT_URL="https://a.quake.world"
VITE_SUPABASE_URL="https://myproject.supabase.co"
VITE_SUPABASE_ANON_KEY="AAA"
2 changes: 1 addition & 1 deletion .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ jobs:
timeout-minutes: 5
runs-on: ubuntu-latest
env:
VITE_QUAKEWORLD_CLOUDFRONT_URL: '${{ secrets.VITE_QUAKEWORLD_CLOUDFRONT_URL }}'
VITE_DEMOS_CLOUDFRONT_URL: '${{ secrets.VITE_DEMOS_CLOUDFRONT_URL }}'
VITE_ASSETS_CLOUDFRONT_URL: '${{ secrets.VITE_ASSETS_CLOUDFRONT_URL }}'
VITE_SUPABASE_URL: '${{ secrets.VITE_SUPABASE_URL }}'
VITE_SUPABASE_ANON_KEY: '${{ secrets.VITE_SUPABASE_ANON_KEY }}'
Expand Down
15 changes: 8 additions & 7 deletions src/pages/games/App.jsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Player } from "@qwhub/pages/games/player/Player";
import { GameDetails } from "@qwhub/pages/games/player/GameDetails.tsx";
import { ServerPoller } from "@qwhub/servers/Servers.jsx";
import { useEffect } from "react";
import { ToastContainer } from "react-toastify";
Expand All @@ -7,8 +7,9 @@ import { SiteFooter } from "../../site/Footer";
import { SiteHeader } from "../../site/Header";
import { Sidebar } from "./Sidebar";
import { Browser } from "./browser/Browser";
import { useDemos } from "./browser/context.tsx";
import { useCurrentDemoId } from "./playlist/hooks";
import { useGames } from "./browser/context.tsx";

import { useCurrentGameId } from "./hooks";

function getAppBodySize() {
const el = document.getElementById("AppBody");
Expand All @@ -20,8 +21,8 @@ function getAppBodySize() {
}

export const App = () => {
const demoId = useCurrentDemoId();
const { isLoading } = useDemos();
const gameId = useCurrentGameId();
const { isLoading } = useGames();

function handleAppBodySizeChange() {
dispatchEvent(
Expand Down Expand Up @@ -49,8 +50,8 @@ export const App = () => {
<div className="3xl:flex gap-6 my-4">
<div className="w-full">
<div id="AppBody" ref={bodyRef}>
{demoId && <Player demoId={demoId} />}
{!demoId && <Browser />}
{gameId && <GameDetails id={gameId} />}
{!gameId && <Browser />}
</div>
</div>
<Sidebar />
Expand Down
5 changes: 2 additions & 3 deletions src/pages/games/Sidebar.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { useState } from "react";
import { useEventListener } from "./hooks.ts";
import { Playlist } from "./playlist/Playlist.tsx";

const minHeight = 480;

Expand All @@ -16,11 +15,11 @@ export const Sidebar = () => {

return (
<div
className="my-6 max-w-[480px] 3xl:my-0 3xl:w-[420px]"
className="my-6 max-w-[480px] 3xl:my-0 3xl:w-[25%]"
style={{ maxHeight }}
id="AppSidebar"
>
<Playlist />
{/*<Playlist />*/}
</div>
);
};
33 changes: 16 additions & 17 deletions src/pages/games/browser/Browser.tsx
Original file line number Diff line number Diff line change
@@ -1,39 +1,38 @@
import { DemoGrid } from "./DemoGrid.tsx";
import { DemoList } from "./DemoList.tsx";
import { DemoProvider, useDemos } from "./context.tsx";
import { GameGrid } from "./GameGrid.tsx";
import { GameList } from "./GameList.tsx";
import { GamesProvider, useGames } from "./context.tsx";
import { Pagination } from "./settings/Pagination.tsx";
import { Toolbar } from "./settings/Toolbar.tsx";
import { DemoSettingsProvider, useDemoSettings } from "./settings/context.tsx";
import { GameSettingsProvider, useGameSettings } from "./settings/context.tsx";

export const Browser = () => {
return (
<div className="space-y-4">
<DemoSettingsProvider localStorageKey="mainDemoBrowser.settings.v2">
<DemoProvider>
<GameSettingsProvider localStorageKey="mainDemoBrowser.settings.v3">
<GamesProvider>
<Toolbar />
<Demos />
<Games />
<Pagination />
</DemoProvider>
</DemoSettingsProvider>
</GamesProvider>
</GameSettingsProvider>
</div>
);
};

const Demos = () => {
const { displayMode } = useDemoSettings();
const { demos, hasDemos, isLoading } = useDemos();
const Games = () => {
const { displayMode } = useGameSettings();
const { games, hasGames, isLoading } = useGames();

return (
<div>
{displayMode === "Grid" ? (
<DemoGrid demos={demos} />
<GameGrid games={games} />
) : (
<DemoList demos={demos} />
<GameList games={games} />
)}
{isLoading && <div className="text-slate-400">Loading demos...</div>}

{!isLoading && !hasDemos && (
<div className="text-slate-400">No demos found.</div>
{!isLoading && !hasGames && (
<div className="text-slate-400">No games found.</div>
)}
</div>
);
Expand Down
8 changes: 4 additions & 4 deletions src/pages/games/browser/Controls.tsx
Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@
import { faFloppyDisk, faPlay } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { getDemoDownloadUrl } from "../services/supabase/demo.ts";
import { getDownloadUrl } from "../services/cloudfront/cdemos.ts";

export const PlayButton = ({ id }: { id: number }) => {
return (
<a
href={`/games/?demoId=${id}`}
href={`/games/?gameId=${id}`}
className="flex items-center justify-center text-blue-500 hover:text-blue-300 w-8 h-8 hover:scale-125 transition-transform"
title="Play"
>
<FontAwesomeIcon fixedWidth icon={faPlay} size={"lg"} />
</a>
);
};
export const DownloadButton = ({ s3_key }: { s3_key: string }) => {
export const DownloadButton = ({ sha256 }: { sha256: string }) => {
return (
<a
href={getDemoDownloadUrl(s3_key)}
href={getDownloadUrl(sha256)}
className="flex items-center justify-center text-slate-500 hover:text-slate-300 w-8 h-8 hover:scale-125 transition-transform"
title="Download"
>
Expand Down
102 changes: 0 additions & 102 deletions src/pages/games/browser/DemoList.tsx

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,33 +1,32 @@
import classNames from "classnames";
import { Timestamp } from "../Timestamp.tsx";
import { ToggleButton } from "../playlist/Playlist.tsx";
import type { Demo } from "../services/supabase/supabase.types.ts";
import type { Game } from "../services/supabase/supabase.types.ts";
import { btnSecondary } from "../ui/theme.ts";
import { DownloadButton } from "./Controls.tsx";
import { ScoreboardLink } from "./Scoreboard.tsx";
import { useDemoScoreSpoiler } from "./hooks.ts";

export const DemoGrid = ({ demos }: { demos: Demo[] | null }) => {
export const GameGrid = ({ games }: { games: Game[] | null }) => {
return (
<div className="grid grid-cols-servers gap-4">
{demos?.map((demo) => (
<GridItem key={demo.id} demo={demo} />
{games?.map((game) => (
<GridItem key={game.id} game={game} />
))}
</div>
);
};

const GridItem = (props: { demo: Demo }) => {
const { demo } = props;
const GridItem = (props: { game: Game }) => {
const { game } = props;
const { isVisible, show } = useDemoScoreSpoiler();

return (
<div className="flex flex-col h-full">
<ScoreboardLink demo={demo} showScores={isVisible} />
<ScoreboardLink game={game} showScores={isVisible} />

<div className="flex items-center mt-1 text-xs justify-between">
<div className="w-1/3 text-slate-500">
<Timestamp timestamp={demo.timestamp} />
<Timestamp timestamp={game.timestamp} />
</div>
<div className="w-1/3">
<button
Expand All @@ -39,10 +38,11 @@ const GridItem = (props: { demo: Demo }) => {
Show scores
</button>
</div>
<div className="flex items-center space-x-1 w-1/3 justify-end">
<ToggleButton demo={demo} />
<DownloadButton s3_key={demo.s3_key} />
</div>
{game.demo_sha256 && (
<div className="flex items-center space-x-1 w-1/3 justify-end">
<DownloadButton sha256={game.demo_sha256} />
</div>
)}
</div>
</div>
);
Expand Down
68 changes: 68 additions & 0 deletions src/pages/games/browser/GameList.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import { Timestamp } from "../Timestamp.tsx";
import type {
Game,
GamePlayer,
GameTeam,
} from "../services/supabase/supabase.types.ts";
import { DownloadButton, PlayButton } from "./Controls.tsx";
import { ScoreSpoiler } from "./ScoreSpoiler.tsx";

export const GameList = ({ games }: { games: Game[] | null }) => {
return (
<table className="text-left">
<thead>
<tr className="text-slate-300 text-xs">
<th className="p-2 min-w-[100px]">Date</th>
<th className="p-2">Score</th>
<th className="p-2" />
</tr>
</thead>
<tbody className="text-sm">
{games?.map((demo) => (
<ListItem key={demo.id} Game={demo} />
))}
</tbody>
</table>
);
};

const ListItem = ({ Game }: { Game: Game }) => {
return (
<tr className="odd:bg-[#1a1a2a] hover:bg-white/10">
<td className="p-2 text-slate-400 text-xs">
<Timestamp timestamp={Game.timestamp} />
</td>
<td className="p-2 text-slate-400 text-right">{Game.mode}</td>
<td className="p-2 text-slate-400">{Game.map}</td>
<td className="p-2">TODO</td>
<td className="text-center">
<ScoreSpoiler
score={getDemoScores(
Game.teams as GameTeam[],
Game.players as GamePlayer[],
)}
/>
</td>
<td className="p-2 flex items-center space-x-2">
<PlayButton id={Game.id} />
{Game.demo_sha256 && <DownloadButton sha256={Game.demo_sha256} />}
</td>
</tr>
);
};

function getDemoScores(
teams: GameTeam[] = [],
players: GamePlayer[] = [],
): string {
let p: number[];

if (teams.length > 0) {
teams.sort((a, b) => a.name.localeCompare(b.name));
p = teams.map((t) => t.frags);
} else {
p = players.map((p) => p.frags);
}

return p.join(" : ");
}
Loading

0 comments on commit 4465564

Please sign in to comment.