player lists

This commit is contained in:
Emmaline Autumn 2023-10-04 05:43:00 -06:00
parent b63db82a99
commit 6e582e11dc
10 changed files with 96 additions and 45 deletions

View File

@ -1,9 +1,9 @@
import { VNode } from "preact"; import { FunctionComponent } from "preact";
export function Content(props: { children?: VNode | VNode[] }) { export const Content: FunctionComponent = ({ children }) => {
return ( return (
<div class="bg-smoke-200 dark:bg-smoke-900 border-4 border-licorice-800 p-8 rounded-3xl"> <div class="bg-smoke-200 dark:bg-smoke-900 border-4 border-licorice-800 p-8 rounded-3xl">
{props.children} {children}
</div> </div>
); );
} };

View File

@ -1,19 +1,23 @@
import { VNode, toChildArray } from "preact"; import { FunctionComponent, toChildArray } from "preact";
export function OL(props: {children?: VNode | VNode[], color?: string;}) { export const OL: FunctionComponent<{ color?: string }> = (props) => {
const childs = toChildArray(props.children); const childs = toChildArray(props.children);
props.color = props.color || 'bg-sky'; props.color = props.color || "bg-sky";
return ( return (
<ol> <ol>
{childs.map((c, i) => ( {childs.map((c, i) => (
<li class="flex gap-4 p-1 even:bg-black/10"> <li class="flex gap-4 p-1 even:bg-black/10">
<div class={`w-16 h-16 relative p-2 ${props.color} rounded-md text-white`}> <div
<span class="text-6xl font-pixel absolute -bottom-1 right-0 text-smoke-800/30">{i+1}</span> class={`w-16 h-16 relative p-2 ${props.color} rounded-md text-white`}
>
<span class="text-6xl font-pixel absolute -bottom-1 right-0 text-smoke-800/30">
{i + 1}
</span>
<span class="text-5xl font-pixel">{i + 1}</span> <span class="text-5xl font-pixel">{i + 1}</span>
</div> </div>
{c} {c}
</li> </li>
))} ))}
</ol> </ol>
) );
} };

View File

@ -3,8 +3,16 @@ import { StatusManager } from "./statusManager.tsx";
import { IS_BROWSER } from "$fresh/runtime.ts"; import { IS_BROWSER } from "$fresh/runtime.ts";
import { PlayerData } from "../util/players.ts"; import { PlayerData } from "../util/players.ts";
import { Button } from "../components/Button.tsx"; import { Button } from "../components/Button.tsx";
import { JSX } from "preact/jsx-runtime";
import { FunctionComponent } from "preact";
export function ActivePlayerList() { export function PlayerList(
{ whitelist, banlist, oplist }: {
whitelist: PlayerData[];
banlist: PlayerData[];
oplist: PlayerData[];
},
) {
const [players, setPlayers] = useState<PlayerData[]>([]); const [players, setPlayers] = useState<PlayerData[]>([]);
useEffect(() => { useEffect(() => {
@ -29,27 +37,51 @@ export function ActivePlayerList() {
}; };
return ( return (
<div> <div class="flex flex-col gap-8">
<StatusManager onAction={followStatusManager} /> <StatusManager onAction={followStatusManager} />
<div class="grid grid-cols-2 p-8"> <div class="grid grid-cols-2 p-8 bg-black/50 rounded-3xl">
<h2 class="col-span-2 font-pixel text-xl">Active Players</h2> <h2 class="col-span-2 font-pixel text-xl">Active Players</h2>
{players.map((p) => <PlayerCard player={p} />)} {players.map((p) => <PlayerCard player={p} />)}
</div> </div>
<div className="grid grid-cols-3 gap-8 rounded-3xl">
<div class="flex flex-col gap-4 bg-smoke p-4 rounded-3xl">
<h2 className="font-pixel text-xl">Whitelisted Players</h2>
{whitelist.map((p) => <PlayerCard player={p} />)}
</div>
<div class="flex flex-col gap-4 bg-smoke p-4 rounded-3xl">
<h2 className="font-pixel text-xl">Banned Players</h2>
{banlist.map((p) => (
<PlayerCard player={p}>
{!!p.banReason && <p>{p.banReason}</p>}
</PlayerCard>
))}
</div>
<div class="flex flex-col gap-4 bg-smoke p-4 rounded-3xl">
<h2 className="font-pixel text-xl">Ops</h2>
{oplist.map((p) => <PlayerCard player={p} />)}
</div>
</div>
</div> </div>
); );
} }
function PlayerCard({ player }: { player: PlayerData }) { const PlayerCard: FunctionComponent<{ player: PlayerData }> = (
{ player, children },
) => {
return ( return (
<div class="flex gap-4"> <div class="flex gap-4">
<img class="w-16" src={player.avatar} alt={`${player.username}'s avatar`} /> <img
class="w-24 rounded-md"
src={player.avatar}
alt={`${player.username}'s avatar`}
/>
<div> <div>
<h3>{player.username}</h3> <h3>{player.username}</h3>
<small class="opacity-50">UUID: {player.id}</small> <small class="opacity-50">UUID: {player.id}</small>
<div> <div class="flex items-center gap-4">
Did you know that bats are the only mammal that can fly? {children}
</div> </div>
</div> </div>
</div> </div>
); );
} };

View File

@ -10,7 +10,6 @@ export function StatusManager(
}, },
) { ) {
const sendCommand = async (action: ManageAction) => { const sendCommand = async (action: ManageAction) => {
console.log(action);
const res = await fetch("/api/manage", { const res = await fetch("/api/manage", {
method: "POST", method: "POST",
body: action, body: action,

View File

@ -23,7 +23,6 @@ export function Terminal(props: { channelId: string }) {
}); });
document.addEventListener('keyup', (e) => { document.addEventListener('keyup', (e) => {
console.log(e.key)
switch (e.key) { switch (e.key) {
case 'Up': case 'Up':
case 'ArrowUp': case 'ArrowUp':

View File

@ -7,19 +7,15 @@ export const handler: Handlers = {
let listener: (e: CustomEvent) => void; let listener: (e: CustomEvent) => void;
const body = new ReadableStream({ const body = new ReadableStream({
async start(controller){ async start(controller){
console.log('did the thing')
if (SERVER_STATE.status !== 'running') return; if (SERVER_STATE.status !== 'running') return;
const players = await getActivePlayers(); const players = await getActivePlayers();
const event = `event:players\ndata:${JSON.stringify(players)}\n\n` const event = `event:players\ndata:${JSON.stringify(players)}\n\n`
controller.enqueue(event); controller.enqueue(event);
console.log('sent the thing')
listener = async (e: CustomEvent<string>) => { listener = async (e: CustomEvent<string>) => {
console.log('message received')
if (e.detail.includes('joined the game') || e.detail.includes('lost connection')) { if (e.detail.includes('joined the game') || e.detail.includes('lost connection')) {
console.log('connection change')
const players = await getActivePlayers(); const players = await getActivePlayers();
const event = `event: players\ndata: ${JSON.stringify(players)}\n\n` const event = `event: players\ndata: ${JSON.stringify(players)}\n\n`
@ -28,10 +24,8 @@ export const handler: Handlers = {
} }
globalThis.addEventListener('stdoutmsg' as any, listener); globalThis.addEventListener('stdoutmsg' as any, listener);
console.log('listened the thing')
}, },
cancel() { cancel() {
console.log('cancelled')
globalThis.removeEventListener('stdoutmsg' as any, listener); globalThis.removeEventListener('stdoutmsg' as any, listener);
} }
}) })

View File

@ -1,12 +1,35 @@
import { Content } from "../components/Content.tsx"; import { Content } from "../components/Content.tsx";
import { ActivePlayerList } from "../islands/players.tsx"; import { PlayerList } from "../islands/players.tsx";
import { getPlayerData, PlayerData } from "../util/players.ts";
export default function PlayerManger() { export default async function PlayerManager() {
// TODO: change these to support instances
const whitelist = await Promise.all<PlayerData[]>(
JSON.parse(await Deno.readTextFile("./server/whitelist.json")).map(async (
p: { name: string },
) => await getPlayerData(p.name)),
);
const banlist = await Promise.all<PlayerData[]>(
JSON.parse(await Deno.readTextFile("./server/banned-players.json")).map(
async (
p: { name: string; reason: string },
) => ({ ...await getPlayerData(p.name), banReason: p.reason }),
),
);
const oplist = await Promise.all<PlayerData[]>(
JSON.parse(await Deno.readTextFile("./server/ops.json")).map(async (
p: { name: string },
) => await getPlayerData(p.name)),
);
return ( return (
<div className="container p-8"> <div className="container p-8">
<Content> <Content>
<ActivePlayerList /> <PlayerList
whitelist={whitelist}
banlist={banlist}
oplist={oplist}
/>
</Content> </Content>
</div> </div>
) );
} }

File diff suppressed because one or more lines are too long

View File

@ -8,6 +8,5 @@ export const checkEULA = (instance = "server") =>
export const acceptEULA = (instance = "server") => { export const acceptEULA = (instance = "server") => {
const eula = Deno.readTextFileSync(`./${instance}/eula.txt`); const eula = Deno.readTextFileSync(`./${instance}/eula.txt`);
const mod = eula.replace(eulaRegex, "eula=true"); const mod = eula.replace(eulaRegex, "eula=true");
console.log(mod);
!IS_BROWSER && Deno.writeTextFileSync(`./${instance}/eula.txt`, mod); !IS_BROWSER && Deno.writeTextFileSync(`./${instance}/eula.txt`, mod);
}; };

View File

@ -23,9 +23,10 @@ export type PlayerData = {
username: string; username: string;
id: string; id: string;
avatar: string; avatar: string;
banReason?: string;
} }
const getPlayerData = async (username: string) => { export const getPlayerData = async (username: string) => {
username = username.trim(); username = username.trim();
if (!username) return; if (!username) return;
const cacheFile = 'players.cache.json' const cacheFile = 'players.cache.json'