first pass of new server page

This commit is contained in:
41666 2023-06-18 01:00:26 -04:00
parent 23a1f7708b
commit 990013af2b
9 changed files with 443 additions and 57 deletions

View file

@ -0,0 +1,23 @@
import { keyframes, style } from "@vanilla-extract/css";
const alertDotBlink = keyframes({
from: {
backgroundColor: "#ff2d2d",
},
to: {
backgroundColor: "#662929",
},
});
export const alertDot = style({
display: "inline-block",
height: "0.5rem",
width: "0.5rem",
borderRadius: "50%",
background: "#ff2d2d",
animation: `${alertDotBlink} var(--speed) ease-in-out infinite alternate`,
});
export const timer = style({
fontSize: "0.8rem",
});

View file

@ -0,0 +1,51 @@
import { useEffect, useState } from "react";
import { MetagameWorld } from "~/utils/metagame";
import { humanTimeAgo } from "~/utils/strings";
import * as styles from "./alert-timer.css";
const endTime = (alert: Required<MetagameWorld["zones"][0]>["alert"]) => {
const alertDurationMins = alert.alert_type !== "sudden_death" ? 90 : 15;
return new Date(alert.start_time).getTime() + alertDurationMins * 60 * 1000;
};
const timeLeftString = (alert: MetagameWorld["zones"][0]["alert"]) => {
if (alert) {
const time = endTime(alert) - Date.now();
if (time < 2000) {
return <>JUST ENDED</>;
}
const speed = time < 1000 * 60 * 15 ? "1s" : "4s";
return (
<>
{humanTimeAgo(time, true).toUpperCase()} LEFT{" "}
<div
className={styles.alertDot}
style={{ "--speed": speed } as any}
></div>
</>
);
} else {
return <></>;
}
};
export const AlertTimer = ({
alert,
}: {
alert: MetagameWorld["zones"][0]["alert"];
}) => {
const [timeLeft, setTimeLeft] = useState(timeLeftString(alert));
useEffect(() => {
if (alert) {
const interval = setInterval(() => {
setTimeLeft(timeLeftString(alert));
}, 1000);
return () => clearInterval(interval);
}
}, [alert]);
return <div className={styles.timer}>{timeLeft}</div>;
};

View file

@ -0,0 +1,19 @@
import { style } from "@vanilla-extract/css";
export const pieRoot = style({
width: "1em",
height: "1em",
borderRadius: "50%",
position: "relative",
"::after": {
content: "''",
position: "absolute",
top: "var(--inner-margin)",
left: "var(--inner-margin)",
right: "var(--inner-margin)",
bottom: "var(--inner-margin)",
borderRadius: "50%",
background: "var(--inner-bg)",
},
});

View file

@ -0,0 +1,40 @@
import type { Population } from "~/utils/saerro";
import { pieRoot } from "./faction-pie.css";
export const FactionPie = ({
population,
innerMargin,
innerBackground,
size,
}: {
population: Population;
innerMargin?: number;
innerBackground?: string;
size?: string;
}) => {
const { nc, tr, vs } = population;
const total = nc + tr + vs;
const trPct = (tr / total) * 100;
const vsPct = (vs / total) * 100;
return (
<div
className={pieRoot}
style={
{
fontSize: size || "1em",
backgroundImage: `conic-gradient(
#d30101 0% ${trPct}%,
#991cba ${trPct}% ${trPct + vsPct}%,
#1564cc ${trPct + vsPct}% 100%
)`,
"--inner-margin": innerMargin ? `${innerMargin}px` : "0",
"--inner-bg": innerBackground || "none",
} as any
}
>
&nbsp;
</div>
);
};

View file

@ -14,6 +14,7 @@ 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 = {
metagame: MetagameWorld;
@ -131,11 +132,6 @@ const JaegerContinent = ({ zone }: { zone: MetagameWorld["zones"][0] }) => {
);
};
const endTime = (alert: Required<MetagameWorld["zones"][0]>["alert"]) => {
const alertDurationMins = alert.alert_type !== "sudden_death" ? 90 : 15;
return new Date(alert.start_time).getTime() + alertDurationMins * 60 * 1000;
};
const Continent = ({ zone }: { zone: MetagameWorld["zones"][0] }) => {
const {
name,
@ -171,7 +167,7 @@ const Continent = ({ zone }: { zone: MetagameWorld["zones"][0] }) => {
ALERT PROGRESS
</div>{" "}
<div>
<TimeLeft alert={zone.alert} />{" "}
<AlertTimer alert={zone.alert} />{" "}
</div>
</div>
<FactionBar population={zone.alert.percentages} />
@ -182,41 +178,3 @@ const Continent = ({ zone }: { zone: MetagameWorld["zones"][0] }) => {
</div>
);
};
const timeLeftString = (alert: MetagameWorld["zones"][0]["alert"]) => {
if (alert) {
const time = endTime(alert) - Date.now();
if (time < 2000) {
return <>JUST ENDED</>;
}
const speed = time < 1000 * 60 * 15 ? "1s" : "4s";
return (
<>
{humanTimeAgo(time, true).toUpperCase()} LEFT{" "}
<div
className={styles.alertDot}
style={{ "--speed": speed } as any}
></div>
</>
);
} else {
return <></>;
}
};
const TimeLeft = ({ alert }: { alert: MetagameWorld["zones"][0]["alert"] }) => {
const [timeLeft, setTimeLeft] = useState(timeLeftString(alert));
useEffect(() => {
if (alert) {
const interval = setInterval(() => {
setTimeLeft(timeLeftString(alert));
}, 1000);
return () => clearInterval(interval);
}
}, [alert]);
return <>{timeLeft}</>;
};

View file

@ -0,0 +1,92 @@
import { style } from "@vanilla-extract/css";
export const headerFont = style({
fontFamily: "Unbounded, Impact, monospace",
fontWeight: "bold",
});
export const header = style({
backgroundColor: "#222",
padding: "2em",
display: "flex",
flexWrap: "wrap",
fontFamily: "Unbounded, Impact, monospace",
});
export const headerName = style({
fontSize: "4rem",
display: "flex",
alignItems: "center",
flexBasis: "100%",
});
export const headerSub = style({
fontSize: "1rem",
color: "#ccc",
marginLeft: "1em",
});
export const outer = style({
display: "flex",
justifyContent: "center",
minHeight: "100vh",
flexDirection: "column",
maxWidth: "1920px",
});
export const population = style({
display: "flex",
flexWrap: "wrap",
width: "100%",
flexDirection: "column",
justifyContent: "space-evenly",
});
export const populationHead = style({
display: "flex",
alignItems: "center",
justifyContent: "space-evenly",
flexBasis: "100%",
});
export const popNumbers = style({
display: "flex",
justifyContent: "space-evenly",
});
export const popItem = style({
display: "flex",
alignItems: "center",
justifyContent: "center",
});
export const totalPop = style({
fontSize: "2rem",
display: "block",
width: "4em",
});
export const headerConts = style({
display: "flex",
alignItems: "center",
justifyContent: "space-evenly",
flexBasis: "100%",
});
export const contChart = style({
fontSize: "4rem",
});
export const cont = style({
display: "flex",
alignItems: "center",
justifyContent: "center",
flexDirection: "column",
});
export const contSub = style({
width: "10rem",
fontSize: "0.8rem",
textAlign: "center",
color: "#ccc",
paddingTop: "0.5rem",
});