Browse Source

* Added typescript modules & typescript config

* Formatted & typescripted svelte files
* Added pong game
master
vvandenb 2 years ago
parent
commit
25320b826c
  1. 3
      package.json
  2. 58
      rollup.config.js
  3. 72
      src/App.svelte
  4. 21
      src/components/Friends.svelte
  5. 13
      src/components/MatchHistory.svelte
  6. 26
      src/components/NavBar.svelte
  7. 3
      src/components/Play.svelte
  8. 15
      src/components/Pong/Ball.ts
  9. 80
      src/components/Pong/Game.ts
  10. 29
      src/components/Pong/Paddle.ts
  11. 19
      src/components/Pong/Player.ts
  12. 65
      src/components/Pong/Pong.svelte
  13. 32
      src/components/Pong/constants.ts
  14. 52
      src/components/Pong/pong.ts
  15. 88
      src/components/Pong/utils.ts
  16. 12
      src/components/Profile.svelte
  17. 19
      src/components/Spectate.svelte
  18. 14
      tsconfig.json

3
package.json

@ -19,7 +19,10 @@
"svelte": "^3.0.0" "svelte": "^3.0.0"
}, },
"dependencies": { "dependencies": {
"@rollup/plugin-typescript": "^11.0.0",
"sirv-cli": "^2.0.0", "sirv-cli": "^2.0.0",
"svelte-check": "^3.0.3",
"svelte-preprocess": "^5.0.1",
"svelte-routing": "^1.6.0" "svelte-routing": "^1.6.0"
} }
} }

58
rollup.config.js

@ -1,9 +1,11 @@
import svelte from 'rollup-plugin-svelte'; import svelte from "rollup-plugin-svelte";
import commonjs from '@rollup/plugin-commonjs'; import commonjs from "@rollup/plugin-commonjs";
import resolve from '@rollup/plugin-node-resolve'; import resolve from "@rollup/plugin-node-resolve";
import livereload from 'rollup-plugin-livereload'; import livereload from "rollup-plugin-livereload";
import { terser } from 'rollup-plugin-terser'; import { terser } from "rollup-plugin-terser";
import css from 'rollup-plugin-css-only'; import css from "rollup-plugin-css-only";
import autoPreprocess from "svelte-preprocess";
import typescript from "@rollup/plugin-typescript";
const production = !process.env.ROLLUP_WATCH; const production = !process.env.ROLLUP_WATCH;
@ -17,35 +19,41 @@ function serve() {
return { return {
writeBundle() { writeBundle() {
if (server) return; if (server) return;
server = require('child_process').spawn('npm', ['run', 'start', '--', '--dev'], { server = require("child_process").spawn(
stdio: ['ignore', 'inherit', 'inherit'], "npm",
shell: true ["run", "start", "--", "--dev"],
}); {
stdio: ["ignore", "inherit", "inherit"],
process.on('SIGTERM', toExit); shell: true,
process.on('exit', toExit);
} }
);
process.on("SIGTERM", toExit);
process.on("exit", toExit);
},
}; };
} }
export default { export default {
input: 'src/main.ts', input: "src/main.ts",
output: { output: {
sourcemap: true, sourcemap: true,
format: 'iife', format: "iife",
name: 'app', name: "app",
file: 'public/build/bundle.js' file: "public/build/bundle.js",
}, },
plugins: [ plugins: [
svelte({ svelte({
preprocess: autoPreprocess(),
compilerOptions: { compilerOptions: {
// enable run-time checks when not in production // enable run-time checks when not in production
dev: !production dev: !production,
} },
}), }),
typescript({ sourceMap: !production }),
// we'll extract any component CSS out into // we'll extract any component CSS out into
// a separate file - better for performance // a separate file - better for performance
css({ output: 'bundle.css' }), css({ output: "bundle.css" }),
// If you have external dependencies installed from // If you have external dependencies installed from
// npm, you'll most likely need these plugins. In // npm, you'll most likely need these plugins. In
@ -54,7 +62,7 @@ export default {
// https://github.com/rollup/plugins/tree/master/packages/commonjs // https://github.com/rollup/plugins/tree/master/packages/commonjs
resolve({ resolve({
browser: true, browser: true,
dedupe: ['svelte'] dedupe: ["svelte"],
}), }),
commonjs(), commonjs(),
@ -64,13 +72,13 @@ export default {
// Watch the `public` directory and refresh the // Watch the `public` directory and refresh the
// browser on changes when not in production // browser on changes when not in production
!production && livereload('public'), !production && livereload("public"),
// If we're building for production (npm run build // If we're building for production (npm run build
// instead of npm run dev), minify // instead of npm run dev), minify
production && terser() production && terser(),
], ],
watch: { watch: {
clearScreen: false clearScreen: false,
} },
}; };

72
src/App.svelte

@ -1,10 +1,15 @@
<script> <script lang="ts">
import Navbar from './components/NavBar.svelte'; import Navbar from './components/NavBar.svelte';
import Profile from './components/Profile.svelte'; import Profile from './components/Profile.svelte';
import MatchHistory from './components/MatchHistory.svelte'; import MatchHistory from './components/MatchHistory.svelte';
import type { Match } from './components/MatchHistory.svelte';
import Friends from './components/Friends.svelte'; import Friends from './components/Friends.svelte';
import type { Friend } from './components/Friends.svelte';
import Spectate from './components/Spectate.svelte'; import Spectate from './components/Spectate.svelte';
import type { SpectateType } from './components/Spectate.svelte';
import Play from './components/Play.svelte'; import Play from './components/Play.svelte';
import Pong from './components/Pong/Pong.svelte';
let isProfileOpen = false; let isProfileOpen = false;
function clickProfile() { function clickProfile() {
isProfileOpen = true; isProfileOpen = true;
@ -13,63 +18,64 @@
function clickHistory() { function clickHistory() {
isHistoryOpen = true; isHistoryOpen = true;
} }
let matches = [ let matches: Array<Match> = [
{winner : "Alice", loser : "Bob", points : "-5", rank : "22"}, { winner: 'Alice', loser: 'Bob', points: -5, rank: '22' },
{winner : "Alice", loser : "Bob", points : "10", rank : "24"}, { winner: 'Alice', loser: 'Bob', points: 10, rank: '24' },
{winner : "Alice", loser : "Bob", points : "10", rank : "24"}, { winner: 'Alice', loser: 'Bob', points: 10, rank: '24' },
{winner : "Alice", loser : "Bob", points : "7", rank : "23"}, { winner: 'Alice', loser: 'Bob', points: 7, rank: '23' },
{winner : "Alice", loser : "Bob", points : "10", rank : "24"}, { winner: 'Alice', loser: 'Bob', points: 10, rank: '24' },
{winner : "Alice", loser : "Bob", points : "10", rank : "24"}, { winner: 'Alice', loser: 'Bob', points: 10, rank: '24' }
] ];
let isFriendOpen = false; let isFriendOpen = false;
function clickFriends() { function clickFriends() {
isFriendOpen = true; isFriendOpen = true;
} }
let friends = [ let friends: Array<Friend> = [
{username : "Alice", status : "online"}, { username: 'Alice', status: 'online' },
{username : "Bob", status : "online"}, { username: 'Bob', status: 'online' },
{username : "Charlie", status : "offline"}, { username: 'Charlie', status: 'offline' },
{username : "Dave", status : "offline"}, { username: 'Dave', status: 'offline' },
{username : "Eve", status : "in a game"}, { username: 'Eve', status: 'in a game' },
{username : "Frank", status : "online"}, { username: 'Frank', status: 'online' }
] ];
let isSpectateOpen = false; let isSpectateOpen = false;
function clickSpectate() { function clickSpectate() {
isSpectateOpen = true; isSpectateOpen = true;
} }
let spectate = [ let spectate: Array<SpectateType> = [
{player1 : "Alice", player2 : "Bob", id : "1"}, { player1: 'Alice', player2: 'Bob', id: '1' },
{player1 : "Alice", player2 : "Bob", id : "4"}, { player1: 'Alice', player2: 'Bob', id: '4' },
{player1 : "Alice", player2 : "Bob", id : "6"}, { player1: 'Alice', player2: 'Bob', id: '6' },
{player1 : "Alice", player2 : "Bob", id : "8"}, { player1: 'Alice', player2: 'Bob', id: '8' },
{player1 : "Alice", player2 : "Bob", id : "2"}, { player1: 'Alice', player2: 'Bob', id: '2' },
{player1 : "Alice", player2 : "Bob", id : "3"}, { player1: 'Alice', player2: 'Bob', id: '3' }
] ];
</script> </script>
<main> <main>
<Navbar clickProfile={clickProfile} clickHistory={clickHistory} clickFriends={clickFriends} clickSpectate={clickSpectate} /> <Navbar {clickProfile} {clickHistory} {clickFriends} {clickSpectate} />
{#if isSpectateOpen} {#if isSpectateOpen}
<div on:click={() => isSpectateOpen = false} on:keydown={() => isSpectateOpen = false}> <div on:click={() => (isSpectateOpen = false)} on:keydown={() => (isSpectateOpen = false)}>
<Spectate spectate={spectate} /> <Spectate {spectate} />
</div> </div>
{/if} {/if}
{#if isFriendOpen} {#if isFriendOpen}
<div on:click={() => isFriendOpen = false} on:keydown={() => isFriendOpen = false}> <div on:click={() => (isFriendOpen = false)} on:keydown={() => (isFriendOpen = false)}>
<Friends friends={friends} /> <Friends {friends} />
</div> </div>
{/if} {/if}
{#if isHistoryOpen} {#if isHistoryOpen}
<div on:click={() => isHistoryOpen = false} on:keydown={() => isHistoryOpen = false}> <div on:click={() => (isHistoryOpen = false)} on:keydown={() => (isHistoryOpen = false)}>
<MatchHistory matches={matches} /> <MatchHistory {matches} />
</div> </div>
{/if} {/if}
{#if isProfileOpen} {#if isProfileOpen}
<div on:click={() => isProfileOpen = false} on:keydown={() => isProfileOpen = false}> <div on:click={() => (isProfileOpen = false)} on:keydown={() => (isProfileOpen = false)}>
<Profile username="Alice" wins={10} losses={5} elo={256} rank={23} is2faEnabled={false} /> <Profile username="Alice" wins={10} losses={5} elo={256} rank={23} is2faEnabled={false} />
</div> </div>
{/if} {/if}
<Play /> <Play />
<Pong />
</main> </main>
<style> <style>

21
src/components/Friends.svelte

@ -1,8 +1,19 @@
<script> <script lang="ts" context="module">
export let friends = []; export interface Friend {
async function addFriend(event) { username: string;
status: 'online' | 'offline' | 'in a game';
}
</script>
<script lang="ts">
export let friends: Array<Friend> = [];
async function addFriend(event: any) {
console.log(typeof event);
event.preventDefault(); event.preventDefault();
const usernameInput = event.target.querySelector('input[type="text"]'); const usernameInput = event.target.querySelector('input[type="text"]');
console.log(usernameInput);
const username = usernameInput.value; const username = usernameInput.value;
// const response = await fetch('', { // const response = await fetch('', {
// method: 'POST', // method: 'POST',
@ -26,9 +37,9 @@
<div> <div>
{#if friends.length > 0} {#if friends.length > 0}
<h2>Monkey friends</h2> <h2>Monkey friends</h2>
{#each friends.slice(0, 10) as friends} {#each friends.slice(0, 10) as friend}
<li> <li>
<span>{friends.username} is {friends.status}</span> <span>{friend.username} is {friend.status}</span>
</li> </li>
{/each} {/each}
{:else} {:else}

13
src/components/MatchHistory.svelte

@ -1,5 +1,14 @@
<script> <script lang="ts" context="module">
export let matches = []; export interface Match {
winner: string;
loser: string;
points: number;
rank: string;
}
</script>
<script lang="ts">
export let matches: Array<Match> = [];
</script> </script>
<div class="overlay"> <div class="overlay">

26
src/components/NavBar.svelte

@ -1,11 +1,11 @@
<script lang="ts"> <script lang="ts">
export let links = [ export let links = [
{ text: "Home" , url : "img/pong.png" }, { text: 'Home', url: 'img/pong.png' },
{ text: "Spectate" }, { text: 'Spectate' },
{ text: "Chat" }, { text: 'Chat' },
{ text: "History" }, { text: 'History' },
{ text: "Friends" }, { text: 'Friends' },
{ text: "Profile" } { text: 'Profile' }
]; ];
export let clickProfile = () => {}; export let clickProfile = () => {};
export let clickHistory = () => {}; export let clickHistory = () => {};
@ -16,38 +16,38 @@
<nav class="navigation-bar"> <nav class="navigation-bar">
<ul> <ul>
{#each links as link} {#each links as link}
{#if link.text === "Spectate"} {#if link.text === 'Spectate'}
<li> <li>
<button on:click={clickSpectate}> <button on:click={clickSpectate}>
<p>Spectate</p> <p>Spectate</p>
</button> </button>
</li> </li>
{/if} {/if}
{#if link.text === "Friends"} {#if link.text === 'Friends'}
<li> <li>
<button on:click={clickFriends}> <button on:click={clickFriends}>
<p>Friends</p> <p>Friends</p>
</button> </button>
</li> </li>
{/if} {/if}
{#if link.text === "Profile"} {#if link.text === 'Profile'}
<li> <li>
<button on:click={clickProfile}> <button on:click={clickProfile}>
<img src="img/profileicon.png" alt="profile icon"> <img src="img/profileicon.png" alt="profile icon" />
</button> </button>
</li> </li>
{/if} {/if}
{#if link.text === "History"} {#if link.text === 'History'}
<li> <li>
<button on:click={clickHistory}> <button on:click={clickHistory}>
<p>History</p> <p>History</p>
</button> </button>
</li> </li>
{/if} {/if}
{#if link.text === "Home"} {#if link.text === 'Home'}
<li> <li>
<a href="/"> <a href="/">
<img src="img/pong.png" alt="home-icon"> <img src="img/pong.png" alt="home-icon" />
</a> </a>
</li> </li>
{/if} {/if}

3
src/components/Play.svelte

@ -1,4 +1,4 @@
<script> <script lang="ts">
// import { navigate } from 'svelte-routing'; // import { navigate } from 'svelte-routing';
// function handleMatchmakingClick() { // function handleMatchmakingClick() {
@ -9,6 +9,7 @@
// navigate('/play-with-friend'); // navigate('/play-with-friend');
// } // }
</script> </script>
<!-- dr --> <!-- dr -->
<main> <main>
<h1>Choose a gamemode</h1> <h1>Choose a gamemode</h1>

15
src/components/Pong/Ball.ts

@ -0,0 +1,15 @@
import { Point, Rect } from './utils';
export class Ball {
rect: Rect;
speed: Point;
color: string | CanvasGradient | CanvasPattern = 'white';
constructor(spawn: Point, size: Point = new Point(20, 20), speed: Point = new Point(10, 2)) {
this.rect = new Rect(spawn, size);
}
draw(context: CanvasRenderingContext2D) {
this.rect.draw(context, this.color);
}
}

80
src/components/Pong/Game.ts

@ -0,0 +1,80 @@
import { Ball } from './Ball';
import { GAME_EVENTS } from './constants';
import type { GameInfo, GameUpdate } from './constants';
import { Paddle } from './Paddle';
import { Player } from './Player';
import { formatWebsocketData, Point } from './utils';
const BG_COLOR = 'black';
export class Game {
canvas: HTMLCanvasElement;
context: CanvasRenderingContext2D;
ball: Ball;
players: Player[];
my_paddle: Paddle;
constructor(canvas: HTMLCanvasElement, context: CanvasRenderingContext2D) {
this.canvas = canvas;
this.context = context;
this.players = [];
this.my_paddle = null;
}
setInfo(data: GameInfo) {
this.canvas.width = data.mapSize.x;
this.canvas.height = data.mapSize.y;
this.ball = new Ball(new Point(this.canvas.width / 2, this.canvas.height / 2), data.ballSize);
const paddle1: Paddle = new Paddle(new Point(data.playerXOffset, this.canvas.height / 2), data.paddleSize);
const paddle2: Paddle = new Paddle(
new Point(this.canvas.width - data.playerXOffset, this.canvas.height / 2),
data.paddleSize
);
this.players = [new Player(paddle1), new Player(paddle2)];
this.my_paddle = this.players[data.yourPaddleIndex].paddle;
}
start(socket: WebSocket) {
if (this.my_paddle) {
this.canvas.addEventListener('mousemove', (e) => {
this.my_paddle.move(e);
socket.send(
formatWebsocketData(GAME_EVENTS.PLAYER_MOVE, {
position: this.my_paddle.rect.center
})
);
});
console.log('Game started!');
}
}
update(data: GameUpdate) {
if (this.players[0].paddle != this.my_paddle) {
this.players[0].paddle.rect.center = data.paddlesPositions[0];
}
if (this.players[1].paddle != this.my_paddle) {
this.players[1].paddle.rect.center = data.paddlesPositions[1];
}
this.ball.rect.center = data.ballPosition;
for (let i = 0; i < data.scores.length; i++) {
this.players[i].score = data.scores[i];
}
}
draw() {
this.context.fillStyle = BG_COLOR;
this.context.fillRect(0, 0, this.canvas.width, this.canvas.height);
this.players.forEach((p) => p.draw(this.context));
this.ball.draw(this.context);
const max_width = 50;
this.context.font = '50px Arial';
const text_width = this.context.measureText('0').width;
const text_offset = 50;
this.players[0].drawScore(this.canvas.width / 2 - (text_width + text_offset), max_width, this.context);
this.players[1].drawScore(this.canvas.width / 2 + text_offset, max_width, this.context);
}
}

29
src/components/Pong/Paddle.ts

@ -0,0 +1,29 @@
import { Point, Rect } from './utils';
export class Paddle {
rect: Rect;
color: string | CanvasGradient | CanvasPattern = 'white';
constructor(spawn: Point, size: Point = new Point(6, 100)) {
this.rect = new Rect(spawn, size);
}
draw(context: CanvasRenderingContext2D) {
this.rect.draw(context, this.color);
}
move(e: MouseEvent) {
const canvas = e.target as HTMLCanvasElement;
const rect = canvas.getBoundingClientRect();
const new_y = ((e.clientY - rect.top) * canvas.height) / rect.height;
const offset: number = this.rect.size.y / 2;
if (new_y - offset < 0) {
this.rect.center.y = offset;
} else if (new_y + offset > canvas.height) {
this.rect.center.y = canvas.height - offset;
} else {
this.rect.center.y = new_y;
}
}
}

19
src/components/Pong/Player.ts

@ -0,0 +1,19 @@
import type { Paddle } from './Paddle';
export class Player {
paddle: Paddle;
score: number;
constructor(paddle: Paddle) {
this.paddle = paddle;
this.score = 0;
}
draw(context: CanvasRenderingContext2D) {
this.paddle.draw(context);
}
drawScore(score_position_x: number, max_width: number, context: CanvasRenderingContext2D) {
context.fillText(this.score.toString(), score_position_x, 50, max_width);
}
}

65
src/components/Pong/Pong.svelte

@ -0,0 +1,65 @@
<script lang="ts">
import { GAME_EVENTS } from './constants';
import { Game } from './Game';
import { formatWebsocketData } from './utils';
const FPS = 144;
const SERVER_URL = 'ws://localhost:3001';
const socket: WebSocket = new WebSocket(SERVER_URL);
socket.onopen = () => {
console.log('Connected to game server!');
socket.send(formatWebsocketData(GAME_EVENTS.GET_GAME_INFO));
};
let canvas: HTMLCanvasElement;
let context: CanvasRenderingContext2D;
//Get canvas and its context
window.onload = () => {
canvas = document.getElementById('pong_canvas') as HTMLCanvasElement;
if (canvas) {
context = canvas.getContext('2d') as CanvasRenderingContext2D;
if (context) {
setupGame();
}
}
};
function setupGame() {
const game = new Game(canvas, context);
socket.onmessage = function (e) {
const event_json = JSON.parse(e.data);
const event = event_json.event;
const data = event_json.data;
if (event == GAME_EVENTS.START_GAME) {
game.start(socket);
} else if (event == GAME_EVENTS.GAME_TICK) {
game.update(data);
} else if (event == GAME_EVENTS.GET_GAME_INFO) {
game.setInfo(data);
setInterval(() => {
game.draw();
}, 1000 / FPS);
console.log('Game loaded!');
} else {
console.log('Received unknown event from server:');
console.log(event_json);
}
};
}
</script>
<div>
<button
on:click={() => {
socket.send(formatWebsocketData(GAME_EVENTS.START_GAME));
}}
>
Start game
</button>
<br />
<br />
<canvas id="pong_canvas" />
</div>

32
src/components/Pong/constants.ts

@ -0,0 +1,32 @@
import { Point } from './utils';
export const GAME_EVENTS = {
START_GAME: 'START_GAME',
GAME_TICK: 'GAME_TICK',
PLAYER_MOVE: 'PLAYER_MOVE',
GET_GAME_INFO: 'GET_GAME_INFO'
};
export interface GameInfo extends GameInfoConstants {
yourPaddleIndex: number;
}
export interface GameInfoConstants {
mapSize: Point;
paddleSize: Point;
playerXOffset: number;
ballSize: Point;
winScore: number;
}
export const gameInfoConstants: GameInfoConstants = {
mapSize: new Point(600, 400),
paddleSize: new Point(6, 50),
playerXOffset: 50,
ballSize: new Point(20, 20),
winScore: 2
};
export interface GameUpdate {
paddlesPositions: Point[];
ballPosition: Point;
scores: number[];
}

52
src/components/Pong/pong.ts

@ -0,0 +1,52 @@
import { GAME_EVENTS } from './constants';
import { Game } from './Game';
import { formatWebsocketData, Point } from './utils';
const FPS = 144;
const socket: WebSocket = new WebSocket('ws://localhost:3001');
socket.onopen = () => {
console.log('Connected to game server!');
socket.send(formatWebsocketData(GAME_EVENTS.GET_GAME_INFO));
};
let canvas: HTMLCanvasElement;
let context: CanvasRenderingContext2D;
//Get canvas and its context
window.onload = () => {
document.getElementById('start_game_button').addEventListener('click', () => {
socket.send(formatWebsocketData(GAME_EVENTS.START_GAME));
});
canvas = document.getElementById('pong_canvas') as HTMLCanvasElement;
if (canvas) {
context = canvas.getContext('2d') as CanvasRenderingContext2D;
if (context) {
setupGame();
}
}
};
function setupGame() {
const game = new Game(canvas, context);
socket.onmessage = function (e) {
const event_json = JSON.parse(e.data);
const event = event_json.event;
const data = event_json.data;
if (event == GAME_EVENTS.START_GAME) {
game.start(socket);
} else if (event == GAME_EVENTS.GAME_TICK) {
game.update(data);
} else if (event == GAME_EVENTS.GET_GAME_INFO) {
game.setInfo(data);
setInterval(() => {
game.draw();
}, 1000 / FPS);
console.log('Game loaded!');
} else {
console.log('Received unknown event from server:');
console.log(event_json);
}
};
}

88
src/components/Pong/utils.ts

@ -0,0 +1,88 @@
export class Point {
x: number;
y: number;
constructor(x: number, y: number) {
this.x = x;
this.y = y;
}
//Returns a new point
add(other: Point) {
return new Point(this.x + other.x, this.y + other.y);
}
//Modifies `this` point
add_inplace(other: Point) {
this.x += other.x;
this.y += other.y;
}
clone(): Point {
return new Point(this.x, this.y);
}
}
export class Rect {
center: Point;
size: Point;
constructor(center: Point, size: Point) {
this.center = center;
this.size = size;
}
draw(context: CanvasRenderingContext2D, color: string | CanvasGradient | CanvasPattern) {
const offset: Point = new Point(this.size.x / 2, this.size.y / 2);
context.fillStyle = color;
context.fillRect(this.center.x - offset.x, this.center.y - offset.y, this.size.x, this.size.y);
}
//True if `this` rect contains `other` rect in the x-axis
contains_x(other: Rect): boolean {
const offset: number = this.size.x / 2;
const offset_other: number = other.size.x / 2;
if (
this.center.x - offset <= other.center.x - offset_other &&
this.center.x + offset >= other.center.x + offset_other
)
return true;
return false;
}
//True if `this` rect contains `other` rect in the y-axis
contains_y(other: Rect): boolean {
const offset: number = this.size.y / 2;
const offset_other: number = other.size.y / 2;
if (
this.center.y - offset <= other.center.y - offset_other &&
this.center.y + offset >= other.center.y + offset_other
)
return true;
return false;
}
collides(other: Rect): boolean {
const offset: Point = new Point(this.size.x / 2, this.size.y / 2);
const offset_other: Point = new Point(other.size.x / 2, other.size.y / 2);
if (
this.center.x - offset.x < other.center.x + offset_other.x &&
this.center.x + offset.x > other.center.x - offset_other.x &&
this.center.y - offset.y < other.center.y + offset_other.y &&
this.center.y + offset.y > other.center.y - offset_other.y
)
return true;
return false;
}
}
export function formatWebsocketData(event: string, data?: any): string {
return JSON.stringify({
event,
data
});
}

12
src/components/Profile.svelte

@ -1,4 +1,4 @@
<script> <script lang="ts">
export let username = ''; export let username = '';
export let realname = ''; export let realname = '';
export let wins = 0; export let wins = 0;
@ -6,7 +6,7 @@
export let elo = 0; export let elo = 0;
export let rank = -1; export let rank = -1;
export let is2faEnabled = false; export let is2faEnabled = false;
async function handleSubmit (event) { async function handleSubmit(event: Event) {
event.preventDefault(); event.preventDefault();
// const response = await fetch('', { // const response = await fetch('', {
// method: 'POST', // method: 'POST',
@ -25,11 +25,11 @@
// } // }
alert('Trying to update username to ' + username); alert('Trying to update username to ' + username);
} }
async function handleAvatarUpload (event) { async function handleAvatarUpload(event: Event) {
event.preventDefault(); event.preventDefault();
alert('Trying to upload avatar'); alert('Trying to upload avatar');
} }
async function handle2fa (event) { async function handle2fa(event: Event) {
event.preventDefault(); event.preventDefault();
alert('Trying to ' + (is2faEnabled ? 'disable' : 'enable') + ' 2FA'); alert('Trying to ' + (is2faEnabled ? 'disable' : 'enable') + ' 2FA');
} }
@ -38,7 +38,7 @@
<div class="overlay"> <div class="overlay">
<div class="profile" on:click|stopPropagation on:keydown|stopPropagation> <div class="profile" on:click|stopPropagation on:keydown|stopPropagation>
<div class="profile-header"> <div class="profile-header">
<img class="profile-img" src="img/profileicon.png" alt="Profile Icon"> <img class="profile-img" src="img/profileicon.png" alt="Profile Icon" />
<h3>{realname}</h3> <h3>{realname}</h3>
<form on:submit={handleAvatarUpload}> <form on:submit={handleAvatarUpload}>
<button type="submit">Upload Avatar</button> <button type="submit">Upload Avatar</button>
@ -54,7 +54,7 @@
</form> </form>
<p>Wins: {wins}</p> <p>Wins: {wins}</p>
<p>Losses: {losses}</p> <p>Losses: {losses}</p>
<p>Winrate: {wins / (wins + losses) * 100}%</p> <p>Winrate: {(wins / (wins + losses)) * 100}%</p>
<p>Elo : {elo}</p> <p>Elo : {elo}</p>
<p>Rank: {rank}</p> <p>Rank: {rank}</p>
<form class="two-factor-auth" on:submit={handle2fa}> <form class="two-factor-auth" on:submit={handle2fa}>

19
src/components/Spectate.svelte

@ -1,5 +1,13 @@
<script> <script lang="ts" context="module">
export let spectate = []; export interface SpectateType {
id: string;
player1: string;
player2: string;
}
</script>
<script lang="ts">
export let spectate: Array<SpectateType> = [];
export let watch = () => {}; export let watch = () => {};
</script> </script>
@ -8,10 +16,10 @@
<div> <div>
{#if spectate.length > 0} {#if spectate.length > 0}
<h2>Monkey spectating</h2> <h2>Monkey spectating</h2>
{#each spectate.slice(0, 10) as spectate} {#each spectate.slice(0, 10) as _spectate}
<li> <li>
<span>{spectate.player1} VS {spectate.player2}</span> <span>{_spectate.player1} VS {_spectate.player2}</span>
<button on:click={() => watch(spectate.id)}>Spectate</button> <button on:click={() => watch(_spectate.id)}>Spectate</button>
</li> </li>
{/each} {/each}
{:else} {:else}
@ -42,5 +50,4 @@
padding: 1rem; padding: 1rem;
width: 300px; width: 300px;
} }
</style> </style>

14
tsconfig.json

@ -11,7 +11,9 @@
"allowSyntheticDefaultImports": true, "allowSyntheticDefaultImports": true,
"sourceMap": true, "sourceMap": true,
"baseUrl": ".", "baseUrl": ".",
"types": ["svelte"], "types": [
"svelte"
],
"experimentalDecorators": true, "experimentalDecorators": true,
"emitDecoratorMetadata": true, "emitDecoratorMetadata": true,
"skipDefaultLibCheck": true, "skipDefaultLibCheck": true,
@ -19,6 +21,12 @@
"declaration": false, "declaration": false,
"downlevelIteration": true "downlevelIteration": true
}, },
"include": ["src/**/*.ts"], "include": [
"exclude": ["node_modules/*", "public/*"] "src/**/*"
],
"exclude": [
"node_modules/*",
"public/*"
],
"extends": "@tsconfig/svelte/tsconfig.json"
} }
Loading…
Cancel
Save