Compare commits

..

No commits in common. "world-page" and "main" have entirely different histories.

70 changed files with 7207 additions and 7248 deletions

1
.envrc
View file

@ -1 +0,0 @@
use flake;

1
.gitignore vendored
View file

@ -8,4 +8,3 @@ node_modules
.DS_Store
**/.DS_Store
.direnv

View file

@ -1,6 +1,6 @@
import { useEffect, useState } from "react";
import type { MetagameWorld } from "../utils/metagame";
import { humanTimeAgo } from "../utils/strings";
import type { MetagameWorld } from "~/utils/metagame";
import { humanTimeAgo } from "~/utils/strings";
import * as styles from "./alert-timer.css";
const endTime = (alert: Required<MetagameWorld["zones"][0]>["alert"]) => {
@ -51,7 +51,7 @@ export const AlertTimer = ({
}: {
alert: MetagameWorld["zones"][0]["alert"];
}) => {
const [timeLeft, setTimeLeft] = useState(<>s</>);
const [timeLeft, setTimeLeft] = useState(timeLeftString(alert));
useEffect(() => {
if (alert) {

View file

@ -1,15 +0,0 @@
import { style } from "@vanilla-extract/css";
import { background100, background200 } from "../utils/theme";
export const bar = style({
backgroundColor: background200,
width: "0.3em",
height: "1em",
border: `1px solid ${background100}`,
// margin: 2
});
export const container = style({
display: "flex",
});

View file

@ -1,41 +0,0 @@
import { useMemo } from "react";
import { Population } from "../utils/saerro";
import * as styles from "./faction-bar-sxs.css";
import { background200, ncFaction, trFaction, vsFaction } from "../utils/theme";
export const FactionBarSxS = ({
population: { nc, vs, tr },
}: {
population: Population;
}) => {
const { vsPercent, ncPercent, trPercent } = useMemo(() => {
const total = nc + vs + tr;
return {
vsPercent: Math.round((vs / total) * 100) || 0,
ncPercent: Math.round((nc / total) * 100) || 0,
trPercent: Math.round((tr / total) * 100) || 0,
};
}, [vs, nc, tr]);
return (
<div className={styles.container}>
<Bar percent={vsPercent} color={vsFaction} />
<Bar percent={ncPercent} color={ncFaction} />
<Bar percent={trPercent} color={trFaction} />
</div>
);
};
const Bar = (props: { percent: number; color: string }) => (
<div
className={styles.bar}
style={{
backgroundImage: `linear-gradient( to top,
${props.color} 0% ${props.percent}% ,
${background200} ${props.percent + 0.1}% 100%
)`,
}}
>
&nbsp;
</div>
);

View file

@ -1,6 +1,5 @@
import type { ComplexStyleRule } from "@vanilla-extract/css";
import { style } from "@vanilla-extract/css";
import { edge, ncFaction, trFaction, vsFaction } from "../utils/theme";
export const bar = style({
display: "flex",
@ -9,7 +8,7 @@ export const bar = style({
flexDirection: "row",
overflow: "hidden",
borderRadius: "0.4rem",
border: `2px solid ${edge}`,
border: "2px solid #4d4d4d",
});
export const tinyBar = style({
@ -28,16 +27,16 @@ const shared: ComplexStyleRule = {
export const left = style({
...shared,
backgroundColor: vsFaction,
backgroundColor: "#991cba",
});
export const center = style({
...shared,
backgroundColor: ncFaction,
borderLeft: `1px solid ${edge}`,
borderRight: `2px solid ${edge}`,
backgroundColor: "#1564cc",
borderLeft: "1px solid #4d4d4d",
borderRight: "2px solid #4d4d4d",
boxShadow: "inset 0 0 0.5rem rgb(180 180 180 / 10%)",
});
export const right = style({
...shared,
backgroundColor: trFaction,
backgroundColor: "#d30101",
});

View file

@ -1,5 +1,5 @@
import { useMemo } from "react";
import type { Population } from "../utils/saerro";
import type { Population } from "~/utils/saerro";
import * as styles from "./faction-bar.css";
export const FactionBar = ({

View file

@ -1,5 +1,4 @@
import { background200, ncFaction, trFaction, vsFaction } from "../utils/theme";
import type { Population } from "../utils/saerro";
import type { Population } from "~/utils/saerro";
import { pieRoot } from "./faction-pie.css";
export const FactionPie = ({
@ -25,11 +24,10 @@ export const FactionPie = ({
style={
{
fontSize: size || "1em",
backgroundColor: background200,
backgroundImage: `conic-gradient(
${trFaction} 0% ${trPct}%,
${vsFaction} ${trPct}% ${trPct + vsPct}%,
${ncFaction} ${trPct + vsPct}% 100%
#d30101 0% ${trPct}%,
#991cba ${trPct}% ${trPct + vsPct}%,
#1564cc ${trPct + vsPct}% 100%
)`,
"--inner-margin": innerMargin ? `${innerMargin}px` : "0",
"--inner-bg": innerBackground || "none",

View file

@ -1,5 +1,5 @@
import { style } from "@vanilla-extract/css";
import footer from "../images/footer.jpg";
import footer from "~/images/footer.jpg";
export const root = style({
height: 300,

View file

@ -1,7 +1,7 @@
import { IndexWorld } from "./index-world";
import * as styles from "./index-world-container.css";
import type { MetagameWorld } from "../utils/metagame";
import type { PopulationWorld } from "../utils/population";
import type { MetagameWorld } from "~/utils/metagame";
import type { PopulationWorld } from "~/utils/population";
export const WorldContainer = ({
metagame,

View file

@ -1,13 +1,19 @@
import { Link } from "@remix-run/react";
import { snakeCaseToTitleCase, worlds, zones } from "../utils/strings";
import {
humanTimeAgo,
snakeCaseToTitleCase,
worlds,
zones,
} from "~/utils/strings";
import * as styles from "./index-world.css";
import vsLogo from "../images/vs-100.png";
import ncLogo from "../images/nc-100.png";
import trLogo from "../images/tr-100.png";
import vsLogo from "~/images/vs-100.png";
import ncLogo from "~/images/nc-100.png";
import trLogo from "~/images/tr-100.png";
import { FactionBar } from "./faction-bar";
import type { MetagameWorld } from "../utils/metagame";
import type { PopulationWorld } from "../utils/population";
import { c } from "../utils/classes";
import type { MetagameWorld } from "~/utils/metagame";
import type { PopulationWorld } from "~/utils/population";
import { c } from "~/utils/classes";
import { useEffect, useState } from "react";
import { AlertTimer } from "./alert-timer";
export type IndexWorldProps = {

View file

@ -1,58 +0,0 @@
import { style } from "@vanilla-extract/css";
export const zoneContainer = style({
margin: "0.5em 1em",
backgroundColor: "#222",
padding: "1em",
boxSizing: "border-box",
});
export const zoneHeader = style({
display: "flex",
});
export const chartTileTotal = style({
textAlign: "center",
lineHeight: 1,
minWidth: "2em",
maxWidth: "2em",
fontSize: "3rem",
overflowY: "hidden",
});
export const chartTilePopLine = style({
display: "flex",
fontSize: "1.5rem",
fontWeight: "bold",
alignItems: "center",
justifyContent: "center",
lineHeight: 1.1,
margin: 0,
});
export const chartTilePopImage = style({
width: "1em",
// height: "1em",
marginRight: 4,
});
export const chartTile = style({
fontSize: "4rem",
flex: "0 3 33%",
display: "flex",
marginTop: "0.2em",
});
export const classesContainer = style({
display: "flex",
flex: "1 3 100%",
flexWrap: "wrap",
justifyContent: "space-evenly",
});
export const chartTileChart = style({
display: "flex",
flexDirection: "column",
alignItems: "center",
justifyContent: "center",
});

View file

@ -1,98 +0,0 @@
import {
allClasses,
Population,
totalPopulation,
World,
Zone,
} from "../utils/saerro";
import { headerFont } from "./world.css";
import {
chartTile,
chartTileChart,
chartTilePopImage,
chartTilePopLine,
chartTileTotal,
classesContainer,
zoneContainer,
zoneHeader,
} from "./world-zone-container.css";
import { classIconMap } from "../utils/class-icons";
import { FactionBarSxS } from "./faction-bar-sxs";
import { c } from "../utils/classes";
import vsLogo from "../images/vs-100.png";
import ncLogo from "../images/nc-100.png";
import trLogo from "../images/tr-100.png";
export type WZCProps = {
world: World;
zone: Zone;
};
export const WorldZoneContainer = (props: WZCProps) => {
return (
<section className={zoneContainer} title={props.zone.name}>
<div className={zoneHeader}>
<h3 className={headerFont}>{props.zone.name.toUpperCase()}</h3>
{/* TODO: metagame */}
</div>
<div>
<h4 className={headerFont}>CLASSES</h4>
<div style={{ display: "flex" }}>
<Classes classes={props.zone.classes} />
<div style={{ display: "flex", flex: "1 3 100%", flexWrap: "wrap" }}>
&nbsp;
</div>
<div style={{ display: "flex", flex: "1 3 100%", flexWrap: "wrap" }}>
&nbsp;
</div>
</div>
</div>
</section>
);
};
const Classes = (props: { classes: Zone["classes"] }) => {
if (props.classes === undefined) {
return null;
}
return (
<div className={classesContainer}>
{allClasses.map((name) => (
<ChartTile
key={name}
name={name}
pop={(props.classes as Record<string, Population>)[name]}
/>
))}
</div>
);
};
const ChartTile = (props: { name: string; pop: Population }) => (
<div className={chartTile}>
<div className={chartTileChart}>
<FactionBarSxS population={props.pop} />
<img src={(classIconMap as any)[props.name]} />
</div>
<div>
<div className={c(headerFont, chartTileTotal)}>
{totalPopulation(props.pop)}
</div>
<div>
<div className={chartTilePopLine}>
<img className={chartTilePopImage} src={vsLogo} alt="VS" />{" "}
{props.pop.vs}
</div>
<div className={chartTilePopLine}>
<img className={chartTilePopImage} src={ncLogo} alt="NC" />{" "}
{props.pop.nc}
</div>
<div className={chartTilePopLine}>
<img className={chartTilePopImage} src={trLogo} alt="TR" />{" "}
{props.pop.tr}
</div>
</div>
</div>
</div>
);

View file

@ -28,6 +28,7 @@ export const headerSub = style({
export const outer = style({
display: "flex",
justifyContent: "center",
minHeight: "100vh",
flexDirection: "column",
maxWidth: "1920px",

18
app/entry.client.tsx Normal file
View file

@ -0,0 +1,18 @@
/**
* By default, Remix will handle hydrating your app on the client for you.
* You are free to delete this file if you'd like to, but if you ever want it revealed again, you can run `npx remix reveal`
* For more information, see https://remix.run/file-conventions/entry.client
*/
import { RemixBrowser } from "@remix-run/react";
import { startTransition, StrictMode } from "react";
import { hydrateRoot } from "react-dom/client";
startTransition(() => {
hydrateRoot(
document,
<StrictMode>
<RemixBrowser />
</StrictMode>
);
});

38
app/entry.server.tsx Normal file
View file

@ -0,0 +1,38 @@
/**
* By default, Remix will handle generating the HTTP Response for you.
* You are free to delete this file if you'd like to, but if you ever want it revealed again, you can run `npx remix reveal`
* For more information, see https://remix.run/file-conventions/entry.server
*/
import type { EntryContext } from "@remix-run/cloudflare";
import { RemixServer } from "@remix-run/react";
import isbot from "isbot";
import { renderToReadableStream } from "react-dom/server";
export default async function handleRequest(
request: Request,
responseStatusCode: number,
responseHeaders: Headers,
remixContext: EntryContext
) {
const body = await renderToReadableStream(
<RemixServer context={remixContext} url={request.url} />,
{
signal: request.signal,
onError(error: unknown) {
console.error(error);
responseStatusCode = 500;
},
}
);
if (isbot(request.headers.get("user-agent"))) {
await body.allReady;
}
responseHeaders.set("Content-Type", "text/html");
return new Response(body, {
headers: responseHeaders,
status: responseStatusCode,
});
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 844 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1,008 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 902 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 266 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 231 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 375 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 429 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 466 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 505 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 361 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 505 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 505 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 585 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 429 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 554 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 467 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 535 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 511 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 555 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 488 B

View file

@ -1,4 +1,4 @@
import type { LinksFunction } from "@remix-run/node";
import type { LinksFunction } from "@remix-run/cloudflare";
import { cssBundleHref } from "@remix-run/css-bundle";
import {
Links,
@ -14,11 +14,17 @@ import "./reset.css";
export const links: LinksFunction = () => [
{
rel: "preconnect",
href: "https://fonts.bunny.net",
href: "https://fonts.gstatic.com",
crossOrigin: "anonymous",
},
{
rel: "preconnect",
href: "ttps://fonts.googleapis.com",
crossOrigin: "anonymous",
},
{
rel: "stylesheet",
href: "https://fonts.bunny.net/css?family=unbounded:700",
href: "https://fonts.googleapis.com/css2?family=Unbounded:wght@700&display=swap",
},
...(cssBundleHref ? [{ rel: "stylesheet", href: cssBundleHref }] : []),
@ -37,6 +43,7 @@ export default function App() {
<Outlet />
<ScrollRestoration />
<Scripts />
<LiveReload />
</body>
</html>
);

View file

@ -1,10 +1,10 @@
import { json, type MetaFunction } from "@remix-run/node";
import { json, type V2_MetaFunction } from "@remix-run/cloudflare";
import { useLoaderData } from "@remix-run/react";
import { Footer } from "../components/footer";
import { WorldContainer } from "../components/index-world-container";
import { outer } from "../components/index.css";
import { fetchMetagameWorlds } from "../utils/metagame";
import { fetchPopulationWorlds } from "../utils/population";
import { Footer } from "~/components/footer";
import { WorldContainer } from "~/components/index-world-container";
import { outer } from "~/components/index.css";
import { fetchMetagameWorlds } from "~/utils/metagame";
import { fetchPopulationWorlds } from "~/utils/population";
export const loader = async () => {
const [metagame, population] = await Promise.all([
@ -15,7 +15,7 @@ export const loader = async () => {
return json({ metagame: metagame.sort((a, b) => a.id - b.id), population });
};
export const meta: MetaFunction = () => {
export const meta: V2_MetaFunction = () => {
return [
{ title: "PS2.LIVE" },
{

View file

@ -1,4 +1,4 @@
import { Footer } from "../components/footer";
import { Footer } from "~/components/footer";
import {
header,
item,
@ -8,7 +8,7 @@ import {
link,
love,
outer,
} from "../components/about.css";
} from "~/components/about.css";
export default function About() {
return (

View file

@ -1,8 +1,7 @@
import { useState } from "react";
import { FactionBar } from "../components/faction-bar";
import { FactionPie } from "../components/faction-pie";
import type { Population } from "../utils/saerro";
import { FactionBarSxS } from "../components/faction-bar-sxs";
import { FactionBar } from "~/components/faction-bar";
import { FactionPie } from "~/components/faction-pie";
import type { Population } from "~/utils/saerro";
export default function DebugComponents() {
const [population, setPopulation] = useState<Population>({
@ -67,10 +66,6 @@ export default function DebugComponents() {
value={innerColor}
onChange={(e) => setInnerColor(e.target.value)}
/>
<h3>Vertical Side-by-Side Bar Chart</h3>
<div style={{ fontSize: "5rem" }}>
<FactionBarSxS population={population}></FactionBarSxS>
</div>
</div>
</div>
);

View file

@ -1,33 +1,32 @@
import type { MetaFunction } from "@remix-run/node";
import { json } from "@remix-run/node";
import type { LoaderArgs, V2_MetaFunction } from "@remix-run/cloudflare";
import { json } from "@remix-run/cloudflare";
import { useLoaderData } from "@remix-run/react";
import { Footer } from "../components/footer";
import type { MetagameWorld } from "../utils/metagame";
import { fetchSingleMetagameWorld } from "../utils/metagame";
import type { WorldResponse, Zone } from "../utils/saerro";
import { Footer } from "~/components/footer";
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";
} from "~/utils/saerro";
import {
pascalCaseToTitleCase,
toTitleCase,
worlds,
zones,
} from "../utils/strings";
import * as styles from "../components/world.css";
import { c } from "../utils/classes";
import { FactionBar } from "../components/faction-bar";
import { popImage } from "../components/index-world.css";
import vsLogo from "../images/vs-100.png";
import ncLogo from "../images/nc-100.png";
import trLogo from "../images/tr-100.png";
import { FactionPie } from "../components/faction-pie";
import { AlertTimer } from "../components/alert-timer";
import { contPrioritySort, zonePopulationSort } from "../utils/sorting";
import { WorldZoneContainer } from "../components/world-zone-container";
} from "~/utils/strings";
import * as styles from "~/components/world.css";
import { c } from "~/utils/classes";
import { FactionBar } from "~/components/faction-bar";
import { popImage } from "~/components/index-world.css";
import vsLogo from "~/images/vs-100.png";
import ncLogo from "~/images/nc-100.png";
import trLogo from "~/images/tr-100.png";
import { FactionPie } from "~/components/faction-pie";
import { AlertTimer } from "~/components/alert-timer";
import { contPrioritySort } from "~/utils/sorting";
type LoaderData = {
saerro: WorldResponse;
@ -35,7 +34,7 @@ type LoaderData = {
id: string;
};
export async function loader({ params }) {
export async function loader({ params }: LoaderArgs) {
const [saerro, metagame] = await Promise.all([
worldQuery(params.id as string),
fetchSingleMetagameWorld(params.id as string),
@ -43,7 +42,7 @@ export async function loader({ params }) {
return json({ saerro, metagame, id: params.id } as LoaderData);
}
export const meta: MetaFunction<typeof loader> = ({ data }) => {
export const meta: V2_MetaFunction<typeof loader> = ({ data }) => {
const { saerro, id } = data as LoaderData;
const date = new Date();
const worldInfo = worlds[String(id || "default")];
@ -169,16 +168,13 @@ export default function World() {
</div>
</div>
<div>
<h2 className={styles.headerFont}>WARZONES</h2>
<div>
{world.zones.all.sort(zonePopulationSort).map((zone) => (
<WorldZoneContainer key={zone.id} world={world} zone={zone} />
// <ZoneInfo key={zone.id} zone={zone} />
<h2>Continents</h2>
{world.zones.all.map((zone) => (
<ZoneInfo zone={zone} key={zone.id} />
))}
</div>
</div>
</div>
</div>
<Footer isMainPage />
</>
);
@ -187,8 +183,8 @@ export default function World() {
const ZoneInfo = ({ zone }: { zone: Zone }) => {
const zoneInfo = zones[String(zone.id)];
return (
<section className={styles.zone}>
<h3 className={styles.headerFont}>{zoneInfo.name.toUpperCase()}</h3>
<section>
<h3>{zoneInfo.name}</h3>
<p>
{totalPopulation(zone.population)} players ({zone.population.vs} VS,{" "}
{zone.population.nc} NC, {zone.population.tr} TR)

View file

@ -1,17 +0,0 @@
import combatMedic from "../images/icon_medic.png";
import engineer from "../images/icon_engi.png";
import heavyAssault from "../images/icon_heavy.png";
import infiltrator from "../images/icon_infil.png";
import lightAssault from "../images/icon_light.png";
import max from "../images/icon_max.png";
export { combatMedic, engineer, heavyAssault, infiltrator, lightAssault, max };
export const classIconMap = {
combatMedic,
engineer,
heavyAssault,
infiltrator,
lightAssault,
max,
};

View file

@ -1,6 +1,11 @@
export const saerroFetch = async <T>(query: string): Promise<T> => {
const response = await fetch(
`https://saerro.ps2.live/graphql?query=${query}`
`https://saerro.ps2.live/graphql?query=${query}`,
{
cf: {
cacheTtl: 60,
},
}
);
const json: { data: T } = await response.json();
return json.data;
@ -17,10 +22,10 @@ export type Zone = {
id: string;
name: string;
population: Population;
vehicles?: Record<(typeof allVehicles)[number], Population> & {
vehicles?: Record<typeof allVehicles[number], Population> & {
total: number;
};
classes?: Record<(typeof allClasses)[number], Population>;
classes?: Record<typeof allClasses[number], Population>;
};
export type World = {
@ -78,7 +83,6 @@ export const worldQuery = async (worldID: string): Promise<WorldResponse> => {
zones {
all {
id
name
classes {
${allClasses.map((cls) => `${cls} { total nc tr vs }`).join(" ")}
}

View file

@ -1,5 +1,4 @@
import type { MetagameWorld } from "./metagame";
import { totalPopulation, type Zone } from "./saerro";
export const contPrioritySort = (
a: MetagameWorld["zones"][number],
@ -42,24 +41,3 @@ export const contPrioritySort = (
return 0;
};
export const zonePopulationSort = (a: Zone, b: Zone): number => {
const total = ({ nc, vs, tr }: { nc: number; vs: number; tr: number }) =>
nc + vs + tr;
const ap = total(a.population);
const bp = total(b.population);
if (ap < bp) {
return 1;
}
if (ap > bp) {
return -1;
}
if (ap === bp) {
return a.id < b.id ? 1 : -1;
}
return 0;
};

View file

@ -1,8 +0,0 @@
export const trFaction = "#d30101";
export const ncFaction = "#1564cc";
export const vsFaction = "#991cba";
export const background100 = "#222";
export const background200 = "#444";
export const edge = "#4d4d4d";

View file

@ -1,60 +0,0 @@
import ant from "../images/vehicles/ant.png";
import chimera from "../images/vehicles/chimera.png";
import corsair from "../images/vehicles/corsair.png";
import dervish from "../images/vehicles/dervish.png";
import flash from "../images/vehicles/flash.png";
import galaxy from "../images/vehicles/galaxy.png";
import harasser from "../images/vehicles/harasser.png";
import javelin from "../images/vehicles/javelin.png";
import liberator from "../images/vehicles/liberator.png";
import lightning from "../images/vehicles/lightning.png";
import magrider from "../images/vehicles/magrider.png";
import mosquito from "../images/vehicles/mosquito.png";
import prowler from "../images/vehicles/prowler.png";
import reaver from "../images/vehicles/reaver.png";
import scythe from "../images/vehicles/scythe.png";
import sunderer from "../images/vehicles/sunderer.png";
import valkyrie from "../images/vehicles/valkyrie.png";
import vanguard from "../images/vehicles/vanguard.png";
export {
ant,
chimera,
corsair,
dervish,
flash,
galaxy,
harasser,
javelin,
liberator,
lightning,
magrider,
mosquito,
prowler,
reaver,
scythe,
sunderer,
valkyrie,
vanguard,
};
export const vehicleIconMap = {
ant,
chimera,
corsair,
dervish,
flash,
galaxy,
harasser,
javelin,
liberator,
lightning,
magrider,
mosquito,
prowler,
reaver,
scythe,
sunderer,
valkyrie,
vanguard,
};

File diff suppressed because it is too large Load diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -1 +0,0 @@
918ff520

BIN
bun.lockb

Binary file not shown.

58
flake.lock generated
View file

@ -1,58 +0,0 @@
{
"nodes": {
"flake-parts": {
"inputs": {
"nixpkgs-lib": "nixpkgs-lib"
},
"locked": {
"lastModified": 1717285511,
"narHash": "sha256-iKzJcpdXih14qYVcZ9QC9XuZYnPc6T8YImb6dX166kw=",
"owner": "hercules-ci",
"repo": "flake-parts",
"rev": "2a55567fcf15b1b1c7ed712a2c6fadaec7412ea8",
"type": "github"
},
"original": {
"owner": "hercules-ci",
"repo": "flake-parts",
"type": "github"
}
},
"nixpkgs": {
"locked": {
"lastModified": 1718318537,
"narHash": "sha256-4Zu0RYRcAY/VWuu6awwq4opuiD//ahpc2aFHg2CWqFY=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "e9ee548d90ff586a6471b4ae80ae9cfcbceb3420",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs-lib": {
"locked": {
"lastModified": 1717284937,
"narHash": "sha256-lIbdfCsf8LMFloheeE6N31+BMIeixqyQWbSr2vk79EQ=",
"type": "tarball",
"url": "https://github.com/NixOS/nixpkgs/archive/eb9ceca17df2ea50a250b6b27f7bf6ab0186f198.tar.gz"
},
"original": {
"type": "tarball",
"url": "https://github.com/NixOS/nixpkgs/archive/eb9ceca17df2ea50a250b6b27f7bf6ab0186f198.tar.gz"
}
},
"root": {
"inputs": {
"flake-parts": "flake-parts",
"nixpkgs": "nixpkgs"
}
}
},
"root": "root",
"version": 7
}

View file

@ -1,23 +0,0 @@
{
description = "https://noe.sh";
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
flake-parts.url = "github:hercules-ci/flake-parts";
};
outputs = inputs: inputs.flake-parts.lib.mkFlake { inherit inputs; } {
systems = [ "x86_64-linux" "aarch64-linux" ];
perSystem = { config, self', pkgs, lib, system, ... }: {
devShells.default = import ./shell.nix { inherit pkgs; };
packages.default = pkgs.stdenvNoCC.mkDerivation {
name = "noe.sh";
src = ./.;
installPhase = ''
cp -r . $out/
'';
};
};
};
}

View file

@ -1,42 +0,0 @@
import { writeFileSync } from "fs";
import { join } from "path";
// thanks varoombaa
const vehicles = [
["sunderer", 2, 264],
["flash", 1, 262],
["lightning", 3, 258],
["magrider", 4, 259],
["vanguard", 5, 265],
["prowler", 6, 261],
["scythe", 7, 266],
["reaver", 8, 263],
["mosquito", 9, 260],
["liberator", 10, 257],
["galaxy", 11, 256],
["harasser", 12, 8852],
["valkyrie", 14, 79711],
["ant", 15, 84726],
["glaive", 163, 264],
["flash", 1001, 260],
["liberator", 1010, 258],
["galaxy", 1011, 256],
["colossus", 2007, 92801],
["bastion", 2019, 92392],
["javelin", 2033, 92332],
["dervish", 2136, 93607],
["chimera", 2137, 93604],
["corsair", 2142, 95012],
];
for (let [name, , imageID] of vehicles) {
const response = await fetch(
`https://census.daybreakgames.com/files/ps2/images/static/${imageID}.png`
);
const buf = await response.arrayBuffer();
const outPath = `./app/images/vehicles/${name}.png`;
writeFileSync(outPath, Buffer.from(buf));
console.log(`wrote ${name} (${imageID}) to ${outPath}`);
}

11728
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -2,39 +2,39 @@
"name": "ps2.live",
"private": true,
"sideEffects": false,
"type": "module",
"scripts": {
"build": "remix vite:build",
"dev": "node ./server.mjs",
"typecheck": "tsc"
"build": "remix build",
"dev:remix": "remix watch",
"dev:wrangler": "npm run wrangler",
"dev": "cross-env NODE_ENV=development npm-run-all build --parallel \"dev:*\"",
"start": "cross-env NODE_ENV=production npm run wrangler --live-reload",
"typecheck": "tsc",
"wrangler": "wrangler pages dev ./public",
"pages:deploy": "npm run build && wrangler pages publish ./public"
},
"dependencies": {
"@remix-run/css-bundle": "^2.9.2",
"@remix-run/express": "^2.9.2",
"@remix-run/node": "^2.9.2",
"@remix-run/react": "^2.9.2",
"@remix-run/cloudflare": "^1.17.0",
"@remix-run/cloudflare-pages": "^1.17.0",
"@remix-run/css-bundle": "^1.17.0",
"@remix-run/react": "^1.17.0",
"cross-env": "^7.0.3",
"express": "^4.19.2",
"isbot": "^4.4.0",
"react": "^18.3.1",
"react-dom": "^18.3.1"
"isbot": "^3.6.10",
"react": "^18.2.0",
"react-dom": "^18.2.0"
},
"devDependencies": {
"@remix-run/dev": "^2.9.2",
"@remix-run/eslint-config": "^2.9.2",
"@types/react": "^18.3.3",
"@types/react-dom": "^18.3.0",
"@vanilla-extract/css": "^1.15.3",
"@vanilla-extract/vite-plugin": "^4.0.11",
"@cloudflare/workers-types": "3.x",
"@remix-run/dev": "^1.17.0",
"@remix-run/eslint-config": "^1.17.0",
"@types/react": "^18.2.10",
"@types/react-dom": "^18.2.4",
"@vanilla-extract/css": "^1.11.1",
"eslint": "^8.42.0",
"npm-run-all": "^4.1.5",
"typescript": "^5.4.5",
"vite": "^5.3.1"
"typescript": "^5.1.3",
"wrangler": "^3.1.0"
},
"description": "- [Remix Docs](https://remix.run/docs)",
"version": "1.0.0",
"main": ".eslintrc.js",
"keywords": [],
"author": "",
"license": "ISC"
"engines": {
"node": ">=16.13"
}
}

23
remix.config.js Normal file
View file

@ -0,0 +1,23 @@
/** @type {import('@remix-run/dev').AppConfig} */
module.exports = {
devServerBroadcastDelay: 1000,
ignoredRouteFiles: ["**/.*"],
server: "./server.ts",
serverBuildPath: "functions/[[path]].js",
serverConditions: ["worker"],
serverDependenciesToBundle: "all",
serverMainFields: ["browser", "module", "main"],
serverMinify: true,
serverModuleFormat: "esm",
serverPlatform: "neutral",
// appDirectory: "app",
// assetsBuildDirectory: "public/build",
// publicPath: "/build/",
future: {
v2_errorBoundary: true,
v2_headers: true,
v2_meta: true,
v2_normalizeFormMethod: true,
v2_routeConvention: true,
},
};

2
remix.env.d.ts vendored
View file

@ -1 +1,3 @@
/// <reference types="@remix-run/dev" />
/// <reference types="@remix-run/cloudflare" />
/// <reference types="@cloudflare/workers-types" />

View file

@ -1,26 +0,0 @@
import { createRequestHandler } from "@remix-run/express";
import express from "express";
const viteDevServer =
process.env.NODE_ENV === "production"
? null
: await import("vite").then((vite) =>
vite.createServer({
server: { middlewareMode: true },
})
);
const app = express();
app.use(
viteDevServer ? viteDevServer.middlewares : express.static("build/client")
);
const build = viteDevServer
? () => viteDevServer.ssrLoadModule("virtual:remix/server-build")
: await import("./build/server/index.js");
app.all("*", createRequestHandler({ build }));
app.listen(3000, () => {
console.log("App listening on http://localhost:3000");
});

8
server.ts Normal file
View file

@ -0,0 +1,8 @@
import { createPagesFunctionHandler } from "@remix-run/cloudflare-pages";
import * as build from "@remix-run/dev/server-build";
export const onRequest = createPagesFunctionHandler({
build,
getLoadContext: (context) => context.env,
mode: process.env.NODE_ENV,
});

View file

@ -1,8 +0,0 @@
{ pkgs ? import <nixpkgs> {} }: pkgs.mkShell {
buildInputs = with pkgs; [
nodePackages.serve
nodePackages.prettier
nodejs
bun
];
}

View file

@ -12,6 +12,9 @@
"allowJs": true,
"forceConsistentCasingInFileNames": true,
"baseUrl": ".",
"paths": {
"~/*": ["./app/*"]
},
// Remix takes care of building everything in `remix build`.
"noEmit": true

View file

@ -1,7 +0,0 @@
import { vitePlugin as remix } from "@remix-run/dev";
import { vanillaExtractPlugin } from "@vanilla-extract/vite-plugin";
import { defineConfig } from "vite";
export default defineConfig({
plugins: [remix(), vanillaExtractPlugin()],
});

1
wrangler.toml Normal file
View file

@ -0,0 +1 @@
compatibility_date = "2023-06-10"