diff --git a/app/components/footer.css.ts b/app/components/footer.css.ts new file mode 100644 index 0000000..e69de29 diff --git a/app/components/footer.tsx b/app/components/footer.tsx new file mode 100644 index 0000000..e5bfdfe --- /dev/null +++ b/app/components/footer.tsx @@ -0,0 +1 @@ +export const PS2LiveLogo = () =>
; diff --git a/app/images/footer.jpg b/app/images/footer.jpg new file mode 100644 index 0000000..27fa63b Binary files /dev/null and b/app/images/footer.jpg differ diff --git a/app/root.css.ts b/app/root.css.ts index e1d36a1..8d68faa 100644 --- a/app/root.css.ts +++ b/app/root.css.ts @@ -4,4 +4,5 @@ export const root = style({ fontFamily: "Arial, Helvetica, sans-serif", background: "#101010", color: "#efefef", + lineHeight: 1.6, }); diff --git a/app/routes/_index.tsx b/app/routes/_index.tsx index 871f53e..e48b4ab 100644 --- a/app/routes/_index.tsx +++ b/app/routes/_index.tsx @@ -1,11 +1,9 @@ import { json, type V2_MetaFunction } from "@remix-run/cloudflare"; import { useLoaderData } from "@remix-run/react"; -import { IndexWorld } from "~/components/index-world"; import { WorldContainer } from "~/components/index-world-container"; import { outer } from "~/components/index.css"; import { fetchMetagameWorlds } from "~/utils/metagame"; import { fetchPopulationWorlds } from "~/utils/population"; -import { indexQuery } from "~/utils/saerro"; export const loader = async () => { const [metagame, population] = await Promise.all([ @@ -29,8 +27,10 @@ export const meta: V2_MetaFunction = () => { export default function Index() { const data = useLoaderData(); return ( -
- +
+
+ +
); } diff --git a/app/routes/worlds.$id.tsx b/app/routes/worlds.$id.tsx index 8877705..0b47207 100644 --- a/app/routes/worlds.$id.tsx +++ b/app/routes/worlds.$id.tsx @@ -1,18 +1,39 @@ import type { LoaderArgs, V2_MetaFunction } from "@remix-run/cloudflare"; import { json } from "@remix-run/cloudflare"; import { useLoaderData } from "@remix-run/react"; -import type { Zone } from "~/utils/saerro"; -import { totalPopulation } from "~/utils/saerro"; -import { allClasses, allVehicles, worldQuery } from "~/utils/saerro"; -import { pascalCaseToTitleCase, toTitleCase, worlds } from "~/utils/strings"; +import type { MetagameWorld } from "~/utils/metagame"; +import { fetchSingleMetagameWorld } from "~/utils/metagame"; +import type { WorldResponse, Zone } from "~/utils/saerro"; +import { + allClasses, + allVehicles, + totalPopulation, + worldQuery, +} from "~/utils/saerro"; +import { + pascalCaseToTitleCase, + toTitleCase, + worlds, + zones, +} from "~/utils/strings"; -export const loader = async ({ params }: LoaderArgs) => { - return json(await worldQuery(params.id as string)); +type LoaderData = { + saerro: WorldResponse; + metagame: MetagameWorld; + id: string; }; +export async function loader({ params }: LoaderArgs) { + const [saerro, metagame] = await Promise.all([ + worldQuery(params.id as string), + fetchSingleMetagameWorld(params.id as string), + ]); + return json({ saerro, metagame, id: params.id } as LoaderData); +} + export const meta: V2_MetaFunction = ({ data }) => { + const { saerro, id } = data as LoaderData; const date = new Date(); - const id = data?.world.id; const worldInfo = worlds[String(id || "default")]; const datetimeHumanFriendly = date.toLocaleString(worldInfo.locale, { timeZone: worldInfo.timeZone, @@ -22,22 +43,35 @@ export const meta: V2_MetaFunction = ({ data }) => { return [ { title: `${ - data?.world.name || "Unknown world" + worldInfo.name || "Unknown world" } | PlanetSide 2 Live Population Stats`, }, { name: "description", - content: `${data?.world.name} currently has ${data?.world.population.total} players online as of ${datetimeHumanFriendly} ${data?.world.name} time. VS: ${data?.world.population.vs}, NC: ${data?.world.population.nc}, TR: ${data?.world.population.tr} -- See more detailed stats on ps2.live.`, + content: `${worldInfo.name} currently has ${totalPopulation( + saerro.world.population + )} players online as of ${datetimeHumanFriendly} ${ + worldInfo.name + } time. VS: ${saerro.world.population.vs}, NC: ${ + saerro.world.population.nc + }, TR: ${ + saerro.world.population.tr + } -- See more detailed stats on ps2.live.`, }, ]; }; export default function World() { - const { world } = useLoaderData(); + const { + saerro: { world }, + id, + } = useLoaderData(); + + const worldInfo = worlds[String(id || "default")]; return (
-

{world.name}

+

{worldInfo.name}

Total Population

{totalPopulation(world.population)} players ({world.population.vs} VS,{" "} @@ -54,9 +88,10 @@ export default function World() { } const ZoneInfo = ({ zone }: { zone: Zone }) => { + const zoneInfo = zones[String(zone.id)]; return (

-

{zone.name}

+

{zoneInfo.name}

{totalPopulation(zone.population)} players ({zone.population.vs} VS,{" "} {zone.population.nc} NC, {zone.population.tr} TR) diff --git a/app/utils/metagame.ts b/app/utils/metagame.ts index 0f60c02..f6c176c 100644 --- a/app/utils/metagame.ts +++ b/app/utils/metagame.ts @@ -30,3 +30,11 @@ export const fetchMetagameWorlds = async (): Promise => { const data: MetagameWorld[] = await response.json(); return data; }; + +export const fetchSingleMetagameWorld = async ( + id: string | number +): Promise => { + const response = await fetch(`https://metagame.ps2.live/${id}`); + const data: MetagameWorld = await response.json(); + return data; +}; diff --git a/app/utils/saerro.ts b/app/utils/saerro.ts index b0773f4..6760946 100644 --- a/app/utils/saerro.ts +++ b/app/utils/saerro.ts @@ -37,60 +37,6 @@ export type World = { }; }; -export type Health = { - ingestReachable: string; - ingest: string; - database: string; - worlds: { - name: string; - status: string; - lastEvent: string; - }[]; -}; - -export type IndexResponse = { - health: Health; - allWorlds: World[]; -}; - -export const indexQuery = async (): Promise => { - const query = `{ - health { - worlds { - name - status - lastEvent - } - } - allWorlds { - id - name - population { - nc - tr - vs - } - zones { - all { - id - name - population { - nc - tr - vs - } - } - } - } - }`; - - const indexData: IndexResponse = await saerroFetch(query); - - indexData.allWorlds.sort((a, b) => a.id - b.id); - - return indexData; -}; - export type WorldResponse = { world: World; }; @@ -129,9 +75,7 @@ export const worldQuery = async (worldID: string): Promise => { const query = `{ world(by: {id: ${Number(worldID)}}) { id - name population { - total nc tr vs @@ -139,7 +83,6 @@ export const worldQuery = async (worldID: string): Promise => { zones { all { id - name classes { ${allClasses.map((cls) => `${cls} { total nc tr vs }`).join(" ")} } @@ -150,7 +93,6 @@ export const worldQuery = async (worldID: string): Promise => { .join(" ")} } population { - total nc tr vs diff --git a/app/utils/strings.ts b/app/utils/strings.ts index 6198263..b1bbc71 100644 --- a/app/utils/strings.ts +++ b/app/utils/strings.ts @@ -19,11 +19,11 @@ export const humanTimeAgo = (ms: number, full?: boolean) => { const hours = Math.floor(minutes / 60); if (hours > 0) { - return full ? `${hours}h ${minutes % 60}m` : `${hours}h`; + return full ? `${hours}h ${minutes % 60}m ${seconds % 60}s` : `${hours}h`; } if (minutes > 0) { - return `${minutes}m`; + return full ? `${minutes}m ${seconds % 60}s` : `${minutes}m`; } if (seconds > 0) {