Compare commits
No commits in common. "6a49c361a05d7bf72c7847237a8e394e5677eb7b" and "c939fb80d3881b4fbdd476cce36d12442a596e96" have entirely different histories.
6a49c361a0
...
c939fb80d3
@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "yukiotoko",
|
||||
"name": "chuni-national-matchmaking-webui",
|
||||
"private": true,
|
||||
"version": "0.0.1",
|
||||
"type": "module",
|
||||
|
@ -7,7 +7,7 @@
|
||||
<title>yukiotoko</title>
|
||||
%sveltekit.head%
|
||||
</head>
|
||||
<body data-sveltekit-preload-data="hover" class="bg-dark text-text">
|
||||
<body data-sveltekit-preload-data="hover" class="bg-dark text-light">
|
||||
<div style="display: contents">%sveltekit.body%</div>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
let { rank, ...rest }: { rank: number } & HTMLAttributes<HTMLDivElement> = $props();
|
||||
|
||||
const [xOffset, yOffset] = $derived(imageOffset(rank));
|
||||
const [xOffset, yOffset] = imageOffset(rank);
|
||||
</script>
|
||||
|
||||
<div {...rest}>
|
||||
|
@ -1,31 +1,16 @@
|
||||
<script lang="ts">
|
||||
let { date }: { date: Date } = $props();
|
||||
|
||||
let currentDate = $state(Date.now());
|
||||
let difference = $derived(currentDate / 1000 - date.getTime() / 1000);
|
||||
let seconds = $derived(~~(difference % 60));
|
||||
let minutes = $derived(~~(difference / 60) % 60);
|
||||
let hours = $derived(~~(difference / 3600) % 24);
|
||||
let days = $derived(~~(difference / 86400));
|
||||
|
||||
setInterval(() => {
|
||||
currentDate = Date.now();
|
||||
});
|
||||
const { date }: { date: Date } = $props();
|
||||
const difference = new Date().getTime() / 1000 - date.getTime() / 1000;
|
||||
const seconds = ~~(difference % 60);
|
||||
const minutes = ~~(difference / 60) % 60;
|
||||
const hours = ~~(difference / 3600) % 24;
|
||||
const days = ~~(difference / 86400);
|
||||
</script>
|
||||
|
||||
<span class="group text-light underline">
|
||||
<p class="group underline">
|
||||
<span class="group-hover:hidden">
|
||||
about
|
||||
{#if days > 0}
|
||||
<span>{days}d</span>
|
||||
{:else if hours > 0}
|
||||
<span>{hours}h</span>
|
||||
{:else if minutes > 0}
|
||||
<span>{minutes}m</span>
|
||||
{:else}
|
||||
<span>{seconds}s</span>
|
||||
{/if}
|
||||
<!-- {#if minutes == 0}
|
||||
{#if minutes == 0}
|
||||
<span>{seconds}s</span>
|
||||
{:else if hours == 0}
|
||||
<span>{minutes}m</span>
|
||||
@ -33,10 +18,10 @@
|
||||
<span>{hours}h</span>
|
||||
{:else}
|
||||
<span>{days}d</span>
|
||||
{/if} -->
|
||||
{/if}
|
||||
ago
|
||||
</span>
|
||||
<span class="hidden group-hover:block">
|
||||
{date.toLocaleString()}
|
||||
</span>
|
||||
</span>
|
||||
</p>
|
||||
|
@ -1,4 +1,4 @@
|
||||
<footer class="bg-medium text-light">
|
||||
<footer class="bg-medium">
|
||||
<div class="mx-auto flex w-full max-w-screen-xl flex-col p-4 md:flex-row md:justify-between">
|
||||
<p>
|
||||
made with <a href="https://svelte.dev/">sveltekit</a>, powered by
|
||||
@ -6,8 +6,8 @@
|
||||
</p>
|
||||
|
||||
<p>
|
||||
wana help out, or issue a bug? you can find the repo <a
|
||||
href="https://tea.metatable.sh/meta/yukiotoko-webui">here</a
|
||||
you can find the repo of the website <a href="https://tea.metatable.sh/meta/yukiotoko-webui"
|
||||
>here</a
|
||||
>
|
||||
</p>
|
||||
</div>
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
let { version, ...rest }: { version: string } & HTMLAttributes<HTMLImageElement> = $props();
|
||||
|
||||
const { minor } = $derived(fromVersionString(version));
|
||||
const { minor } = fromVersionString(version);
|
||||
</script>
|
||||
|
||||
<img src="/versions/{gameVersions[minor.toString()]}" alt={version} {...rest} />
|
||||
|
@ -1,40 +0,0 @@
|
||||
<script lang="ts" generics="T">
|
||||
let {
|
||||
items,
|
||||
itemsPerPage,
|
||||
pageItems = $bindable()
|
||||
}: { items: Array<T>; itemsPerPage: number; pageItems: Array<T> } = $props();
|
||||
|
||||
let currentPage = $state(0);
|
||||
let pageIndexStart = $derived(currentPage * itemsPerPage);
|
||||
let pageIndexEnd = $derived(Math.min(itemsPerPage * (currentPage + 1), items.length));
|
||||
|
||||
$effect(() => {
|
||||
currentPage = Math.min(Math.max(currentPage, 0), ~~(items.length / itemsPerPage));
|
||||
pageItems = items.slice(pageIndexStart, pageIndexEnd);
|
||||
});
|
||||
</script>
|
||||
|
||||
<div class="flex flex-col gap-2">
|
||||
<p>
|
||||
showing <span class="font-bold text-light">{pageIndexStart + 1}</span> to
|
||||
<span class="font-bold text-light">{pageIndexEnd}</span>
|
||||
of <span class="font-bold text-light">{items.length}</span>
|
||||
entires
|
||||
</p>
|
||||
|
||||
<div class="flex divide-x divide-border">
|
||||
<button class="rounded-bl-lg rounded-tl-lg text-light" onclick={() => currentPage--}
|
||||
>prev</button
|
||||
>
|
||||
<button class="rounded-br-lg rounded-tr-lg text-light" onclick={() => currentPage++}
|
||||
>next</button
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
button {
|
||||
@apply bg-medium px-4 py-2 transition hover:brightness-150;
|
||||
}
|
||||
</style>
|
@ -9,11 +9,13 @@
|
||||
|
||||
<div class="flex flex-col gap-2">
|
||||
<div class="flex items-center justify-between">
|
||||
<p class="font-bold text-light">{player.name}</p>
|
||||
<p>{player.name}</p>
|
||||
<div class="flex gap-2">
|
||||
<Rating rating={player.rating} />
|
||||
<BattleRank rank={player.battleRank} class="w-16" />
|
||||
</div>
|
||||
</div>
|
||||
<Team team={player?.team ?? { name: 'No Team', rank: 0 }} />
|
||||
{#if player.team}
|
||||
<Team team={player.team} />
|
||||
{/if}
|
||||
</div>
|
||||
|
@ -4,8 +4,8 @@
|
||||
|
||||
let { rating }: { rating: number } = $props();
|
||||
|
||||
const characters = $derived(rating.toString().padStart(4, '0'));
|
||||
const type = $derived(ratingType(rating));
|
||||
const characters = rating.toString().padStart(4, '0');
|
||||
const type = ratingType(rating);
|
||||
</script>
|
||||
|
||||
<div class="flex items-center">
|
||||
|
@ -8,7 +8,7 @@
|
||||
...rest
|
||||
}: { character: number | '.'; type: number } & HTMLAttributes<HTMLDivElement> = $props();
|
||||
|
||||
const [xOffset, yOffset] = $derived(imageOffset(character, type));
|
||||
const [xOffset, yOffset] = imageOffset(character, type);
|
||||
</script>
|
||||
|
||||
<div {...rest}>
|
||||
|
@ -1,44 +1,20 @@
|
||||
<script lang="ts">
|
||||
import { User, Calendar } from 'lucide-svelte';
|
||||
import { onMount } from 'svelte';
|
||||
import Player from './Player.svelte';
|
||||
import BattleRank from './BattleRank.svelte';
|
||||
import GameVersion from './GameVersion.svelte';
|
||||
import Separator from './Separator.svelte';
|
||||
import Date from './Date.svelte';
|
||||
import axios from 'axios';
|
||||
import type { Room } from './types';
|
||||
import Date from './Date.svelte';
|
||||
|
||||
let { room }: { room: Room } = $props();
|
||||
|
||||
let roomTimer = $state(room.secondsRemaining);
|
||||
let players = $state(room.players);
|
||||
let secondsRemaining = $state(room.secondsRemaining);
|
||||
|
||||
onMount(() => {
|
||||
if (!room.finished) {
|
||||
const roomTimerUpdateInterval = setInterval(() => {
|
||||
if (roomTimer <= 0) {
|
||||
roomTimer = 0;
|
||||
return;
|
||||
}
|
||||
roomTimer--;
|
||||
}, 1000);
|
||||
|
||||
const roomTimerSyncInterval = setInterval(async () => {
|
||||
console.log('updating');
|
||||
const updatedRoom = await axios
|
||||
.get<Room>(`/api/room/${room.roomId}`)
|
||||
.then((result) => result.data);
|
||||
roomTimer = updatedRoom.secondsRemaining;
|
||||
players = updatedRoom.players;
|
||||
if (updatedRoom.finished) {
|
||||
console.log('killing invervals');
|
||||
clearInterval(roomTimerUpdateInterval);
|
||||
clearInterval(roomTimerSyncInterval);
|
||||
}
|
||||
}, 5000);
|
||||
}
|
||||
});
|
||||
const interval = setInterval(() => {
|
||||
if (secondsRemaining <= 0 || room.finished) clearInterval(interval);
|
||||
secondsRemaining--;
|
||||
}, 1000);
|
||||
</script>
|
||||
|
||||
<div class="flex flex-col gap-8 rounded-lg bg-medium p-6">
|
||||
@ -51,19 +27,19 @@
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col">
|
||||
<p class="flex items-center gap-2">game version <Separator /> {room.gameVersion}</p>
|
||||
<p class="flex items-center gap-2">
|
||||
<p class="flex items-center gap-2 text-sub">game version <Separator /> {room.gameVersion}</p>
|
||||
<p class="flex items-center gap-2 text-sub">
|
||||
room battle rank <Separator />
|
||||
{room.roomBattleRank}
|
||||
</p>
|
||||
{#if !room.finished}
|
||||
<p class="flex items-center gap-2">seconds remaining <Separator /> {roomTimer}s</p>
|
||||
<p class="flex items-center gap-2">seconds remaining <Separator /> {secondsRemaining}s</p>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col gap-4">
|
||||
<p class="flex items-center gap-2 text-light">
|
||||
<p class="flex items-center gap-2">
|
||||
<User class="inline-block w-6" />
|
||||
{room.players.length} / 4
|
||||
<Separator />
|
||||
@ -72,7 +48,7 @@
|
||||
</p>
|
||||
|
||||
<div class="grid grid-cols-1 gap-4 sm:grid-cols-2 sm:grid-rows-2">
|
||||
{#each players as player}
|
||||
{#each room.players as player}
|
||||
<Player {player} />
|
||||
{/each}
|
||||
</div>
|
||||
|
@ -1 +1,3 @@
|
||||
<span class="inline-block h-[2px] w-4 rounded-full bg-current brightness-50"></span>
|
||||
<span class="inline-block"
|
||||
><div class="h-[2px] w-4 rounded-full bg-current brightness-50"></div></span
|
||||
>
|
||||
|
@ -11,7 +11,7 @@
|
||||
? 'team-second'
|
||||
: team.rank == 3
|
||||
? 'team-third'
|
||||
: 'text-light'}"
|
||||
: ''}"
|
||||
>
|
||||
<p>
|
||||
{team.name}
|
||||
|
@ -1,5 +1,3 @@
|
||||
export function arrayPadEnd<T>(array: T[], amount: number, data: T) {
|
||||
if (amount > array.length) {
|
||||
array.push(...Array(amount - array.length).fill(data));
|
||||
}
|
||||
for (let i = 0; i < amount - array.length; i++) array.push(data);
|
||||
}
|
||||
|
@ -20,6 +20,7 @@ function toPlayer(apiPlayer: APIPlayer): Player {
|
||||
|
||||
function toRoom(apiRoom: APIRoom): Room {
|
||||
return {
|
||||
id: apiRoom.id,
|
||||
roomId: apiRoom.roomId,
|
||||
createdAt: new Date(apiRoom.updatedAt),
|
||||
gameVersion: apiRoom.dataVersion,
|
||||
@ -30,12 +31,10 @@ function toRoom(apiRoom: APIRoom): Room {
|
||||
};
|
||||
}
|
||||
|
||||
function validRoom(room: Room): boolean {
|
||||
return !greaterThan(fromVersionString(room.gameVersion), fromVersionString(env.MAX_VERSION));
|
||||
}
|
||||
|
||||
function filterRooms(rooms: Room[]): Room[] {
|
||||
return rooms.filter((room) => validRoom(room));
|
||||
return rooms.filter(
|
||||
(room) => !greaterThan(fromVersionString(room.gameVersion), fromVersionString(env.MAX_VERSION))
|
||||
);
|
||||
}
|
||||
|
||||
export async function fetchRooms() {
|
||||
@ -57,20 +56,7 @@ export async function fetchRooms() {
|
||||
};
|
||||
}
|
||||
|
||||
export async function fetchRoom(roomId: number | string): Promise<Room | undefined> {
|
||||
const result = await axios.get<APIRoom[]>(`http://yukiotoko.chara.lol:9000/api/get/${roomId}`, {
|
||||
headers: {
|
||||
Authorization: env.YUKIOTOKO_API_TOKEN
|
||||
}
|
||||
});
|
||||
|
||||
const apiRoom = result.data[0];
|
||||
|
||||
if (!apiRoom) return;
|
||||
|
||||
const room = toRoom(apiRoom);
|
||||
|
||||
if (!validRoom(room)) return;
|
||||
|
||||
return room;
|
||||
}
|
||||
// TODO!
|
||||
// export async function fetchRoom(roomId: string): Promise<Room> {
|
||||
// return new Promise()
|
||||
// }
|
||||
|
@ -56,6 +56,7 @@ export interface APIPlayer {
|
||||
}
|
||||
|
||||
export interface Room {
|
||||
id: string;
|
||||
roomId: number;
|
||||
createdAt: Date;
|
||||
gameVersion: string;
|
||||
|
@ -1,20 +1,6 @@
|
||||
import { fetchRooms } from '$lib/server/yukiotoko';
|
||||
import { arrayPadEnd } from '$lib/array';
|
||||
import type { PageServerLoad } from './$types';
|
||||
import { fetchRooms } from '$lib/server/yukiotoko';
|
||||
|
||||
export const load: PageServerLoad = async ({ fetch }) => {
|
||||
const { activeRooms, archivedRooms } = await fetchRooms();
|
||||
|
||||
archivedRooms.forEach((archivedRoom) =>
|
||||
arrayPadEnd(archivedRoom.players, 4, {
|
||||
name: 'CPU',
|
||||
battleRank: 0,
|
||||
rating: 0
|
||||
})
|
||||
);
|
||||
|
||||
return {
|
||||
activeRooms,
|
||||
archivedRooms
|
||||
};
|
||||
return await fetchRooms();
|
||||
};
|
||||
|
@ -1,20 +1,25 @@
|
||||
<script lang="ts">
|
||||
import Pagination from '$lib/Pagination.svelte';
|
||||
import { arrayPadEnd } from '$lib/array';
|
||||
import Room from '$lib/Room.svelte';
|
||||
import type { PageData } from './$types';
|
||||
|
||||
let { data }: { data: PageData } = $props();
|
||||
let { activeRooms, archivedRooms } = data;
|
||||
let props: { data: PageData } = $props();
|
||||
|
||||
let paginationArchivedRooms = $state([]);
|
||||
let data = $state(props.data);
|
||||
|
||||
data.archivedRooms.forEach((archivedRoom) =>
|
||||
arrayPadEnd(archivedRoom.players, 4, {
|
||||
name: 'CPU',
|
||||
battleRank: 0,
|
||||
rating: 0
|
||||
})
|
||||
);
|
||||
</script>
|
||||
|
||||
<div class="mb-8 space-y-8">
|
||||
<div class="mb-16 space-y-8">
|
||||
<section>
|
||||
<h1 class="text-4xl font-bold text-light">yukiotoko webui</h1>
|
||||
<p>
|
||||
a frontend redesign for <a href="http://yukiotoko.chara.lol/">yukiotoko</a> made by metamethods
|
||||
</p>
|
||||
<h1 class="text-4xl font-bold">yukiotoko webui</h1>
|
||||
<p>a frontend redesign for <a href="http://yukiotoko.chara.lol/">yukiotoko</a></p>
|
||||
<p class="text-sub">refresh the page to fetch newer yukiotoko data</p>
|
||||
</section>
|
||||
</div>
|
||||
@ -22,14 +27,14 @@
|
||||
<div class="flex flex-col gap-8">
|
||||
<section class="flex flex-col gap-4">
|
||||
<div>
|
||||
<h1 class="text-2xl font-bold text-light">
|
||||
active rooms <span class="text-sub">({activeRooms.length})</span>
|
||||
<h1 class="text-2xl font-bold">
|
||||
active rooms <span class="text-sub">({data.activeRooms.length})</span>
|
||||
</h1>
|
||||
<p class="text-sub">all of the currently matchmaking rooms</p>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-1 gap-4 xl:grid-cols-2">
|
||||
{#each activeRooms as activeRoom}
|
||||
{#each data.activeRooms as activeRoom}
|
||||
<Room room={activeRoom} />
|
||||
{/each}
|
||||
</div>
|
||||
@ -37,16 +42,14 @@
|
||||
|
||||
<section class="flex flex-col gap-4">
|
||||
<div>
|
||||
<h1 class="text-2xl font-bold text-light">
|
||||
<h1 class="text-2xl font-bold">
|
||||
archived rooms <span class="text-sub">({data.archivedRooms.length})</span>
|
||||
</h1>
|
||||
<p class="text-sub">rooms that were created from the last 24 hours</p>
|
||||
</div>
|
||||
|
||||
<Pagination items={archivedRooms} itemsPerPage={20} bind:pageItems={paginationArchivedRooms} />
|
||||
|
||||
<div class="grid grid-cols-1 gap-4 xl:grid-cols-2">
|
||||
{#each paginationArchivedRooms as archivedRoom}
|
||||
{#each data.archivedRooms as archivedRoom}
|
||||
<Room room={archivedRoom} />
|
||||
{/each}
|
||||
</div>
|
||||
|
@ -1,10 +0,0 @@
|
||||
import { fetchRoom } from '$lib/server/yukiotoko';
|
||||
import { error, json } from '@sveltejs/kit';
|
||||
|
||||
export async function GET({ params }) {
|
||||
const room = await fetchRoom(params.roomId);
|
||||
|
||||
if (!room) return error(404);
|
||||
|
||||
return json(room);
|
||||
}
|
@ -7,12 +7,11 @@ export default {
|
||||
theme: {
|
||||
extend: {
|
||||
colors: {
|
||||
dark: '#111117',
|
||||
medium: '#1F2128',
|
||||
dark: '#060710',
|
||||
medium: '#0A0B17',
|
||||
light: '#CFD3FA',
|
||||
text: '#9B9FC0',
|
||||
accent: '#8D74FF',
|
||||
border: '#353741'
|
||||
sub: '#4D4D80',
|
||||
accent: '#7E61FF'
|
||||
},
|
||||
|
||||
fontFamily: {
|
||||
|
Loading…
Reference in New Issue
Block a user