Browse Source

added formating to front

master
nicolas-arnaud 2 years ago
parent
commit
c78c58a3c3
  1. 2
      front/Dockerfile
  2. 27
      front/volume/package-lock.json
  3. 11
      front/volume/package.json
  4. 169
      front/volume/src/App.svelte
  5. 5
      front/volume/src/app.d.ts
  6. 242
      front/volume/src/components/Chat.svelte
  7. 132
      front/volume/src/components/Friends.svelte
  8. 92
      front/volume/src/components/MatchHistory.svelte
  9. 182
      front/volume/src/components/NavBar.svelte
  10. 48
      front/volume/src/components/Play.svelte
  11. 24
      front/volume/src/components/Pong/Ball.ts
  12. 152
      front/volume/src/components/Pong/Game.ts
  13. 44
      front/volume/src/components/Pong/Paddle.ts
  14. 30
      front/volume/src/components/Pong/Player.ts
  15. 183
      front/volume/src/components/Pong/Pong.svelte
  16. 47
      front/volume/src/components/Pong/constants.ts
  17. 142
      front/volume/src/components/Pong/utils.ts
  18. 194
      front/volume/src/components/Profile.svelte
  19. 82
      front/volume/src/components/Spectate.svelte
  20. 4
      front/volume/src/main.ts

2
front/Dockerfile

@ -11,6 +11,6 @@ ENTRYPOINT npm install; \
elif [[ $NODE_ENV == "debug" ]]; then \
npm run dev; \
elif [[ $NODE_ENV == "check" ]]; then \
npm run check; echo "=== FINISH ==="\
npm run format && npm run check; echo "=== FINISH ==="\
else echo "Nothing to do for that NODE_ENV context."; \
fi;

27
front/volume/package-lock.json

@ -14,6 +14,8 @@
"vite": "^4.1.0"
},
"devDependencies": {
"prettier": "^2.8.4",
"prettier-plugin-svelte": "^2.9.0",
"svelte-check": "^2.10.3",
"tslib": "^2.5.0",
"typescript": "^4.9.3"
@ -1017,6 +1019,31 @@
"node": "^10 || ^12 || >=14"
}
},
"node_modules/prettier": {
"version": "2.8.4",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.4.tgz",
"integrity": "sha512-vIS4Rlc2FNh0BySk3Wkd6xmwxB0FpOndW5fisM5H8hsZSxU2VWVB5CWIkIjWvrHjIhxk2g3bfMKM87zNTrZddw==",
"dev": true,
"bin": {
"prettier": "bin-prettier.js"
},
"engines": {
"node": ">=10.13.0"
},
"funding": {
"url": "https://github.com/prettier/prettier?sponsor=1"
}
},
"node_modules/prettier-plugin-svelte": {
"version": "2.9.0",
"resolved": "https://registry.npmjs.org/prettier-plugin-svelte/-/prettier-plugin-svelte-2.9.0.tgz",
"integrity": "sha512-3doBi5NO4IVgaNPtwewvrgPpqAcvNv0NwJNflr76PIGgi9nf1oguQV1Hpdm9TI2ALIQVn/9iIwLpBO5UcD2Jiw==",
"dev": true,
"peerDependencies": {
"prettier": "^1.16.4 || ^2.0.0",
"svelte": "^3.2.0"
}
},
"node_modules/queue-microtask": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",

11
front/volume/package.json

@ -7,17 +7,20 @@
"dev": "vite --host",
"build": "vite build",
"preview": "vite preview --host",
"check": "svelte-check --tsconfig ./tsconfig.json"
"check": "svelte-check --tsconfig ./tsconfig.json",
"format": "prettier --write --plugin-search-dir=. 'src/**/*.{js,ts,html,svelte}'"
},
"devDependencies": {
"prettier": "^2.8.4",
"prettier-plugin-svelte": "^2.9.0",
"svelte-check": "^2.10.3",
"tslib": "^2.5.0",
"typescript": "^4.9.3"
},
"dependencies": {
"svelte": "^3.55.1",
"vite": "^4.1.0",
"@sveltejs/vite-plugin-svelte": "^2.0.2",
"@tsconfig/svelte": "^3.0.0",
"@sveltejs/vite-plugin-svelte": "^2.0.2"
"svelte": "^3.55.1",
"vite": "^4.1.0"
}
}

169
front/volume/src/App.svelte

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

5
front/volume/src/app.d.ts

@ -1,5 +1,4 @@
declare global {
namespace App {
}
namespace App {}
}
export {};
export {};

242
front/volume/src/components/Chat.svelte

@ -1,139 +1,123 @@
<script lang="ts">
let chatIsOpen = false;
const toggleChat = () => (chatIsOpen = !chatIsOpen);
let newText = "";
let chatIsOpen = false;
const toggleChat = () => (chatIsOpen = !chatIsOpen);
let newText = '';
let chatMessages = [
{
name: 'Alice',
text: 'Hello guys! Happy to see you here!'
},
{
name: 'Bob',
text: 'Wanna play?'
},
{
name: 'Carl',
text: 'cyka blyat'
},
]
const sendMessage = () => {
if (newText !== '')
{
const newMessage = {
name: 'You',
text: newText
};
chatMessages = [
...chatMessages,
newMessage
];
newText = '';
}
}
let chatMessages = [
{
name: "Alice",
text: "Hello guys! Happy to see you here!",
},
{
name: "Bob",
text: "Wanna play?",
},
{
name: "Carl",
text: "cyka blyat",
},
];
const sendMessage = () => {
if (newText !== "") {
const newMessage = {
name: "You",
text: newText,
};
chatMessages = [...chatMessages, newMessage];
newText = "";
}
};
</script>
<!-- Main chat div, changes style to hide/unhide the chat depending if it's open or closed -->
<div class={
chatIsOpen
? 'chat-open chat-container'
: 'chat-container'}>
<!-- Button to toggle chat -->
<div class="chat-view-button">
<button on:click={toggleChat}>
{#if chatIsOpen}
<img src="img/close.png" alt="Close" />
{:else}
<img src="img/chat.png" alt="Open" />
{/if}
</button>
</div>
<div class="chat">
<!-- Chat history -->
<div class="messages">
{#each chatMessages as message}
<p class="message">
<span class="message-name">
{message.name}
</span>: {message.text}
</p>
{/each}
</div>
<!-- Form to send message -->
<form on:submit|preventDefault={sendMessage}>
<input
type="text"
placeholder="Type a message..."
bind:value={newText} />
<button>
<img src="img/send.png" alt="send" />
</button>
</form>
</div>
<div class={chatIsOpen ? "chat-open chat-container" : "chat-container"}>
<!-- Button to toggle chat -->
<div class="chat-view-button">
<button on:click={toggleChat}>
{#if chatIsOpen}
<img src="img/close.png" alt="Close" />
{:else}
<img src="img/chat.png" alt="Open" />
{/if}
</button>
</div>
<div class="chat">
<!-- Chat history -->
<div class="messages">
{#each chatMessages as message}
<p class="message">
<span class="message-name">
{message.name}
</span>: {message.text}
</p>
{/each}
</div>
<!-- Form to send message -->
<form on:submit|preventDefault={sendMessage}>
<input type="text" placeholder="Type a message..." bind:value={newText} />
<button>
<img src="img/send.png" alt="send" />
</button>
</form>
</div>
</div>
<style>
.chat-container {
position: absolute;
top: 10rem;
height: calc(100vh - 10rem);
z-index: 42; /* Show it above everything */
display: flex;
width: 300px;
right: -300px;
transition: right 0.3s ease-out;
}
.chat-view-button {
position: absolute;
left: -64px;
top: 0;
bottom: 0;
margin: auto 0;
height: 64px;
}
.chat-view-button button {
border: none;
cursor: pointer;
border-radius: 16px 0 0 16px;
padding: 16px 16px 16px 16px;
}
.chat-open {
right: 0; /* Shows chat */
}
.chat {
display: flex;
flex-direction: column;
width: 100%;
}
.messages {
display: flex;
flex-direction: column;
height: calc(100vh - 10rem);
padding: 1rem;
overflow-y: scroll;
}
.message-name {
cursor: pointer;
}
form {
/* border-bottom: var(--grey) 1px solid; */
margin: 1rem;
display: flex;
justify-content: space-between;
}
input {
border: none;
}
form button {
background: transparent;
border: none;
cursor: pointer;
}
.chat-container {
position: absolute;
top: 10rem;
height: calc(100vh - 10rem);
z-index: 42; /* Show it above everything */
display: flex;
width: 300px;
right: -300px;
transition: right 0.3s ease-out;
}
.chat-view-button {
position: absolute;
left: -64px;
top: 0;
bottom: 0;
margin: auto 0;
height: 64px;
}
.chat-view-button button {
border: none;
cursor: pointer;
border-radius: 16px 0 0 16px;
padding: 16px 16px 16px 16px;
}
.chat-open {
right: 0; /* Shows chat */
}
.chat {
display: flex;
flex-direction: column;
width: 100%;
}
.messages {
display: flex;
flex-direction: column;
height: calc(100vh - 10rem);
padding: 1rem;
overflow-y: scroll;
}
.message-name {
cursor: pointer;
}
form {
/* border-bottom: var(--grey) 1px solid; */
margin: 1rem;
display: flex;
justify-content: space-between;
}
input {
border: none;
}
form button {
background: transparent;
border: none;
cursor: pointer;
}
</style>

132
front/volume/src/components/Friends.svelte

@ -1,80 +1,80 @@
<script lang="ts" context="module">
export interface Friend {
username: string;
status: 'online' | 'offline' | 'in a game';
}
export interface Friend {
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);
export let friends: Array<Friend> = [];
async function addFriend(event: any) {
console.log(typeof event);
event.preventDefault();
const usernameInput = event.target.querySelector('input[type="text"]');
console.log(usernameInput);
event.preventDefault();
const usernameInput = event.target.querySelector('input[type="text"]');
console.log(usernameInput);
const username = usernameInput.value;
// const response = await fetch('', {
// method: 'POST',
// headers: {
// 'Content-Type': 'application/json'
// },
// body: JSON.stringify({ username })
// });
// if (response.ok) {
// console.log('Friend added successfully');
// } else {
// console.log('Failed to add friend');
// }
// usernameInput.value = '';
alert('Trying to add friend' + username);
}
const username = usernameInput.value;
// const response = await fetch('', {
// method: 'POST',
// headers: {
// 'Content-Type': 'application/json'
// },
// body: JSON.stringify({ username })
// });
// if (response.ok) {
// console.log('Friend added successfully');
// } else {
// console.log('Failed to add friend');
// }
// usernameInput.value = '';
alert("Trying to add friend" + username);
}
</script>
<div class="overlay">
<div class="friends" on:click|stopPropagation on:keydown|stopPropagation>
<div>
{#if friends.length > 0}
<h2>Monkey friends</h2>
{#each friends.slice(0, 10) as friend}
<li>
<span>{friend.username} is {friend.status}</span>
</li>
{/each}
{:else}
<p>No friends to display</p>
{/if}
<div>
<h3>Add a friend</h3>
<form on:submit={addFriend}>
<input type="text" />
<button type="submit">Add</button>
</form>
</div>
</div>
</div>
<div class="friends" on:click|stopPropagation on:keydown|stopPropagation>
<div>
{#if friends.length > 0}
<h2>Monkey friends</h2>
{#each friends.slice(0, 10) as friend}
<li>
<span>{friend.username} is {friend.status}</span>
</li>
{/each}
{:else}
<p>No friends to display</p>
{/if}
<div>
<h3>Add a friend</h3>
<form on:submit={addFriend}>
<input type="text" />
<button type="submit">Add</button>
</form>
</div>
</div>
</div>
</div>
<style>
.overlay {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.5);
z-index: 9998;
display: flex;
justify-content: center;
align-items: center;
}
.overlay {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.5);
z-index: 9998;
display: flex;
justify-content: center;
align-items: center;
}
.friends {
background-color: #fff;
border: 1px solid #ccc;
border-radius: 5px;
padding: 1rem;
width: 300px;
}
.friends {
background-color: #fff;
border: 1px solid #ccc;
border-radius: 5px;
padding: 1rem;
width: 300px;
}
</style>

92
front/volume/src/components/MatchHistory.svelte

@ -1,58 +1,58 @@
<script lang="ts" context="module">
export interface Match {
winner: string;
loser: string;
points: number;
rank: string;
}
export interface Match {
winner: string;
loser: string;
points: number;
rank: string;
}
</script>
<script lang="ts">
export let matches: Array<Match> = [];
export let matches: Array<Match> = [];
</script>
<div class="overlay">
<div class="history" on:click|stopPropagation on:keydown|stopPropagation>
<div>
{#if matches.length > 0}
<h2>Last 10 monkey games</h2>
{#each matches.slice(0, 10) as match}
<li>
<span>{match.winner} 1 - 0 {match.loser}</span>
{#if match.points > 0}
<span>+{match.points}</span>
{:else}
<span>{match.points}</span>
{/if}
<span>MP | rank #{match.rank}</span>
</li>
{/each}
{:else}
<p>No matches to display</p>
{/if}
</div>
</div>
<div class="history" on:click|stopPropagation on:keydown|stopPropagation>
<div>
{#if matches.length > 0}
<h2>Last 10 monkey games</h2>
{#each matches.slice(0, 10) as match}
<li>
<span>{match.winner} 1 - 0 {match.loser}</span>
{#if match.points > 0}
<span>+{match.points}</span>
{:else}
<span>{match.points}</span>
{/if}
<span>MP | rank #{match.rank}</span>
</li>
{/each}
{:else}
<p>No matches to display</p>
{/if}
</div>
</div>
</div>
<style>
.overlay {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.5);
z-index: 9998;
display: flex;
justify-content: center;
align-items: center;
}
.overlay {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.5);
z-index: 9998;
display: flex;
justify-content: center;
align-items: center;
}
.history {
background-color: #fff;
border: 1px solid #ccc;
border-radius: 5px;
padding: 1rem;
width: 300px;
}
.history {
background-color: #fff;
border: 1px solid #ccc;
border-radius: 5px;
padding: 1rem;
width: 300px;
}
</style>

182
front/volume/src/components/NavBar.svelte

@ -1,106 +1,106 @@
<script lang="ts">
export let links = [
{ text: 'Home', url: 'img/pong.png' },
{ text: 'Spectate' },
{ text: 'Chat' },
{ text: 'History' },
{ text: 'Friends' },
{ text: 'Profile' }
];
export let clickProfile = () => {};
export let clickHistory = () => {};
export let clickFriends = () => {};
export let clickSpectate = () => {};
export let links = [
{ text: "Home", url: "img/pong.png" },
{ text: "Spectate" },
{ text: "Chat" },
{ text: "History" },
{ text: "Friends" },
{ text: "Profile" },
];
export let clickProfile = () => {};
export let clickHistory = () => {};
export let clickFriends = () => {};
export let clickSpectate = () => {};
</script>
<nav class="navigation-bar">
<ul>
{#each links as link}
{#if link.text === 'Spectate'}
<li>
<button on:click={clickSpectate}>
<p>Spectate</p>
</button>
</li>
{/if}
{#if link.text === 'Friends'}
<li>
<button on:click={clickFriends}>
<p>Friends</p>
</button>
</li>
{/if}
{#if link.text === 'Profile'}
<li>
<button on:click={clickProfile}>
<img src="img/profileicon.png" alt="profile icon" />
</button>
</li>
{/if}
{#if link.text === 'History'}
<li>
<button on:click={clickHistory}>
<p>History</p>
</button>
</li>
{/if}
{#if link.text === 'Home'}
<li>
<a href="/">
<img src="img/pong.png" alt="home-icon" />
</a>
</li>
{/if}
{/each}
</ul>
<ul>
{#each links as link}
{#if link.text === "Spectate"}
<li>
<button on:click={clickSpectate}>
<p>Spectate</p>
</button>
</li>
{/if}
{#if link.text === "Friends"}
<li>
<button on:click={clickFriends}>
<p>Friends</p>
</button>
</li>
{/if}
{#if link.text === "Profile"}
<li>
<button on:click={clickProfile}>
<img src="img/profileicon.png" alt="profile icon" />
</button>
</li>
{/if}
{#if link.text === "History"}
<li>
<button on:click={clickHistory}>
<p>History</p>
</button>
</li>
{/if}
{#if link.text === "Home"}
<li>
<a href="/">
<img src="img/pong.png" alt="home-icon" />
</a>
</li>
{/if}
{/each}
</ul>
</nav>
<style>
.navigation-bar {
display: flex;
justify-content: center;
align-items: center;
background-color: #f5f5f5;
padding: 1rem;
}
.navigation-bar {
display: flex;
justify-content: center;
align-items: center;
background-color: #f5f5f5;
padding: 1rem;
}
.navigation-bar ul {
display: flex;
justify-content: center;
align-items: center;
list-style: none;
padding: 0;
}
.navigation-bar ul {
display: flex;
justify-content: center;
align-items: center;
list-style: none;
padding: 0;
}
.navigation-bar li {
margin: 0 1rem;
}
.navigation-bar li {
margin: 0 1rem;
}
.navigation-bar img {
width: 2rem;
height: 2rem;
}
.navigation-bar img {
width: 2rem;
height: 2rem;
}
.navigation-bar button {
border: none;
}
.navigation-bar button {
border: none;
}
@media (max-width: 768px) {
.navigation-bar {
flex-direction: column;
align-items: stretch;
}
@media (max-width: 768px) {
.navigation-bar {
flex-direction: column;
align-items: stretch;
}
.navigation-bar ul {
flex-direction: column;
align-items: center;
justify-content: center;
}
.navigation-bar ul {
flex-direction: column;
align-items: center;
justify-content: center;
}
.navigation-bar li {
margin: 0;
padding: 1rem;
text-align: center;
}
}
.navigation-bar li {
margin: 0;
padding: 1rem;
text-align: center;
}
}
</style>

48
front/volume/src/components/Play.svelte

@ -1,38 +1,38 @@
<script lang="ts">
// import { navigate } from 'svelte-routing';
// import { navigate } from 'svelte-routing';
// function handleMatchmakingClick() {
// navigate('/matchmaking');
// }
// function handleMatchmakingClick() {
// navigate('/matchmaking');
// }
// function handlePlayWithFriendClick() {
// navigate('/play-with-friend');
// }
// function handlePlayWithFriendClick() {
// navigate('/play-with-friend');
// }
</script>
<!-- dr -->
<main>
<h1>Choose a gamemode</h1>
<!-- <button on:click={handleMatchmakingClick}>Matchmaking</button>
<h1>Choose a gamemode</h1>
<!-- <button on:click={handleMatchmakingClick}>Matchmaking</button>
<button on:click={handlePlayWithFriendClick}>Play with a friend</button> -->
<button>Matchmaking</button>
<button>Play with a friend</button>
<button>Matchmaking</button>
<button>Play with a friend</button>
</main>
<style>
main {
display: flex;
flex-direction: column;
align-items: center;
}
main {
display: flex;
flex-direction: column;
align-items: center;
}
h1 {
margin-bottom: 2rem;
}
h1 {
margin-bottom: 2rem;
}
button {
font-size: 1.5rem;
padding: 1rem 2rem;
margin-bottom: 1rem;
}
button {
font-size: 1.5rem;
padding: 1rem 2rem;
margin-bottom: 1rem;
}
</style>

24
front/volume/src/components/Pong/Ball.ts

@ -1,15 +1,19 @@
import { Point, Rect } from './utils';
import { Point, Rect } from "./utils";
export class Ball {
rect: Rect;
speed: Point;
color: string | CanvasGradient | CanvasPattern = 'white';
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);
}
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);
}
draw(context: CanvasRenderingContext2D) {
this.rect.draw(context, this.color);
}
}

152
front/volume/src/components/Pong/Game.ts

@ -1,82 +1,96 @@
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';
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';
const BG_COLOR = "black";
export class Game {
canvas: HTMLCanvasElement;
context: CanvasRenderingContext2D;
ball: Ball;
players: Player[];
my_paddle: Paddle;
id: string;
canvas: HTMLCanvasElement;
context: CanvasRenderingContext2D;
ball: Ball;
players: Player[];
my_paddle: Paddle;
id: string;
constructor(canvas: HTMLCanvasElement, context: CanvasRenderingContext2D) {
this.canvas = canvas;
this.context = context;
this.players = [];
this.my_paddle = null;
}
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;
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);
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;
this.id = data.gameId;
}
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;
this.id = data.gameId;
}
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!');
}
}
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];
}
}
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);
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);
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);
}
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
);
}
}

44
front/volume/src/components/Pong/Paddle.ts

@ -1,29 +1,29 @@
import { Point, Rect } from './utils';
import { Point, Rect } from "./utils";
export class Paddle {
rect: Rect;
color: string | CanvasGradient | CanvasPattern = 'white';
rect: Rect;
color: string | CanvasGradient | CanvasPattern = "white";
constructor(spawn: Point, size: Point = new Point(6, 100)) {
this.rect = new Rect(spawn, size);
}
constructor(spawn: Point, size: Point = new Point(6, 100)) {
this.rect = new Rect(spawn, size);
}
draw(context: CanvasRenderingContext2D) {
this.rect.draw(context, this.color);
}
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;
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;
}
}
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;
}
}
}

30
front/volume/src/components/Pong/Player.ts

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

183
front/volume/src/components/Pong/Pong.svelte

@ -1,96 +1,111 @@
<script lang="ts">
import { GAME_EVENTS } from './constants';
import { Game } from './Game';
import { formatWebsocketData } from './utils';
import { GAME_EVENTS } from "./constants";
import { Game } from "./Game";
import { formatWebsocketData } from "./utils";
const FPS = 144;
const SERVER_URL = 'ws://localhost:3001';
const FPS = 144;
const SERVER_URL = "ws://localhost:3001";
let connected: boolean = false;
let socket: WebSocket;
let username: string = 'John';
let otherUsername: string = 'Garfield';
let connected: boolean = false;
let socket: WebSocket;
let username: string = "John";
let otherUsername: string = "Garfield";
//Get canvas and its context
window.onload = () => {
const canvas: HTMLCanvasElement = document.getElementById('pong_canvas') as HTMLCanvasElement;
if (canvas) {
const context: CanvasRenderingContext2D = canvas.getContext('2d') as CanvasRenderingContext2D;
if (context) {
setupSocket(canvas, context);
}
}
};
//Get canvas and its context
window.onload = () => {
const canvas: HTMLCanvasElement = document.getElementById(
"pong_canvas"
) as HTMLCanvasElement;
if (canvas) {
const context: CanvasRenderingContext2D = canvas.getContext(
"2d"
) as CanvasRenderingContext2D;
if (context) {
setupSocket(canvas, context);
}
}
};
function setupSocket(canvas: HTMLCanvasElement, context: CanvasRenderingContext2D) {
socket = new WebSocket(SERVER_URL);
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;
function setupSocket(
canvas: HTMLCanvasElement,
context: CanvasRenderingContext2D
) {
socket = new WebSocket(SERVER_URL);
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) {
if (data && data.gameId != game.id) {
game.setInfo(data);
setInterval(() => {
game.draw();
}, 1000 / FPS);
console.log('Game updated!');
}
} else {
console.log('Unknown event from server: ' + event);
}
};
socket.onopen = () => {
connected = true;
};
socket.onclose = () => {
connected = false;
setupSocket(canvas, context);
};
}
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) {
if (data && data.gameId != game.id) {
game.setInfo(data);
setInterval(() => {
game.draw();
}, 1000 / FPS);
console.log("Game updated!");
}
} else {
console.log("Unknown event from server: " + event);
}
};
socket.onopen = () => {
connected = true;
};
socket.onclose = () => {
connected = false;
setupSocket(canvas, context);
};
}
function updateGameInfo() {
socket.send(formatWebsocketData(GAME_EVENTS.GET_GAME_INFO));
}
function updateGameInfo() {
socket.send(formatWebsocketData(GAME_EVENTS.GET_GAME_INFO));
}
function connectToServer() {
socket.send(formatWebsocketData(GAME_EVENTS.REGISTER_PLAYER, { playerName: username }));
setInterval(() => {
updateGameInfo();
}, 1000);
}
function connectToServer() {
socket.send(
formatWebsocketData(GAME_EVENTS.REGISTER_PLAYER, { playerName: username })
);
setInterval(() => {
updateGameInfo();
}, 1000);
}
</script>
<div>
{#if connected}
Your name:
<input bind:value={username} />
<br />
<button on:click={connectToServer}> Connect </button>
<br />
Other player name:
<input bind:value={otherUsername} />
<br />
<button
on:click={() => {
socket.send(formatWebsocketData(GAME_EVENTS.CREATE_GAME, { playerNames: [username, otherUsername] }));
updateGameInfo();
}}
>
Create game vs {otherUsername}
</button>
<br />
<button on:click={() => socket.send(formatWebsocketData(GAME_EVENTS.READY))}>Ready</button>
<br />
<br />
{:else}
Connecting to game server...
{/if}
<canvas id="pong_canvas" />
{#if connected}
Your name:
<input bind:value={username} />
<br />
<button on:click={connectToServer}> Connect </button>
<br />
Other player name:
<input bind:value={otherUsername} />
<br />
<button
on:click={() => {
socket.send(
formatWebsocketData(GAME_EVENTS.CREATE_GAME, {
playerNames: [username, otherUsername],
})
);
updateGameInfo();
}}
>
Create game vs {otherUsername}
</button>
<br />
<button on:click={() => socket.send(formatWebsocketData(GAME_EVENTS.READY))}
>Ready</button
>
<br />
<br />
{:else}
Connecting to game server...
{/if}
<canvas id="pong_canvas" />
</div>

47
front/volume/src/components/Pong/constants.ts

@ -1,37 +1,36 @@
import { Point } from './utils';
import { Point } from "./utils";
export const GAME_EVENTS = {
START_GAME: 'START_GAME',
READY: 'READY',
GAME_TICK: 'GAME_TICK',
PLAYER_MOVE: 'PLAYER_MOVE',
GET_GAME_INFO: 'GET_GAME_INFO',
CREATE_GAME: 'CREATE_GAME',
REGISTER_PLAYER: 'REGISTER_PLAYER'
START_GAME: "START_GAME",
READY: "READY",
GAME_TICK: "GAME_TICK",
PLAYER_MOVE: "PLAYER_MOVE",
GET_GAME_INFO: "GET_GAME_INFO",
CREATE_GAME: "CREATE_GAME",
REGISTER_PLAYER: "REGISTER_PLAYER",
};
export interface GameInfo extends GameInfoConstants {
yourPaddleIndex: number;
gameId: string;
yourPaddleIndex: number;
gameId: string;
}
export interface GameInfoConstants {
mapSize: Point;
paddleSize: Point;
playerXOffset: number;
ballSize: Point;
winScore: number;
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
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[];
paddlesPositions: Point[];
ballPosition: Point;
scores: number[];
}

142
front/volume/src/components/Pong/utils.ts

@ -1,88 +1,96 @@
export class Point {
x: number;
y: number;
x: number;
y: number;
constructor(x: number, y: number) {
this.x = x;
this.y = y;
}
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);
}
//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;
}
//Modifies `this` point
add_inplace(other: Point) {
this.x += other.x;
this.y += other.y;
}
clone(): Point {
return new Point(this.x, this.y);
}
clone(): Point {
return new Point(this.x, this.y);
}
}
export class Rect {
center: Point;
size: Point;
center: Point;
size: Point;
constructor(center: Point, size: Point) {
this.center = center;
this.size = size;
}
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);
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);
}
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;
//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;
}
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;
//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;
}
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);
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;
}
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
});
return JSON.stringify({
event,
data,
});
}

194
front/volume/src/components/Profile.svelte

@ -1,109 +1,109 @@
<script lang="ts">
export let username = '';
export let realname = '';
export let wins = 0;
export let losses = 0;
export let elo = 0;
export let rank = -1;
export let is2faEnabled = false;
async function handleSubmit(event: Event) {
event.preventDefault();
// const response = await fetch('', {
// method: 'POST',
// headers: {
// 'Content-Type': 'application/json'
// },
// body: JSON.stringify({
// username
// })
// });
// if (response.ok) {
// console.log('username updated');
// }
// else {
// console.log('username update failed');
// }
alert('Trying to update username to ' + username);
}
async function handleAvatarUpload(event: Event) {
event.preventDefault();
alert('Trying to upload avatar');
}
async function handle2fa(event: Event) {
event.preventDefault();
alert('Trying to ' + (is2faEnabled ? 'disable' : 'enable') + ' 2FA');
}
export let username = "";
export let realname = "";
export let wins = 0;
export let losses = 0;
export let elo = 0;
export let rank = -1;
export let is2faEnabled = false;
async function handleSubmit(event: Event) {
event.preventDefault();
// const response = await fetch('', {
// method: 'POST',
// headers: {
// 'Content-Type': 'application/json'
// },
// body: JSON.stringify({
// username
// })
// });
// if (response.ok) {
// console.log('username updated');
// }
// else {
// console.log('username update failed');
// }
alert("Trying to update username to " + username);
}
async function handleAvatarUpload(event: Event) {
event.preventDefault();
alert("Trying to upload avatar");
}
async function handle2fa(event: Event) {
event.preventDefault();
alert("Trying to " + (is2faEnabled ? "disable" : "enable") + " 2FA");
}
</script>
<div class="overlay">
<div class="profile" on:click|stopPropagation on:keydown|stopPropagation>
<div class="profile-header">
<img class="profile-img" src="img/profileicon.png" alt="Profile Icon" />
<h3>{realname}</h3>
<form on:submit={handleAvatarUpload}>
<button type="submit">Upload Avatar</button>
</form>
</div>
<div class="profile-body">
<form on:submit={handleSubmit}>
<div class="username">
<label for="username">Username</label>
<input type="text" id="username" bind:value={username} />
</div>
<button type="submit">Submit</button>
</form>
<p>Wins: {wins}</p>
<p>Losses: {losses}</p>
<p>Winrate: {(wins / (wins + losses)) * 100}%</p>
<p>Elo : {elo}</p>
<p>Rank: {rank}</p>
<form class="two-factor-auth" on:submit={handle2fa}>
<button type="submit">
{#if is2faEnabled}
Disable 2FA
{:else}
Enable 2FA
{/if}
</button>
</form>
</div>
</div>
<div class="profile" on:click|stopPropagation on:keydown|stopPropagation>
<div class="profile-header">
<img class="profile-img" src="img/profileicon.png" alt="Profile Icon" />
<h3>{realname}</h3>
<form on:submit={handleAvatarUpload}>
<button type="submit">Upload Avatar</button>
</form>
</div>
<div class="profile-body">
<form on:submit={handleSubmit}>
<div class="username">
<label for="username">Username</label>
<input type="text" id="username" bind:value={username} />
</div>
<button type="submit">Submit</button>
</form>
<p>Wins: {wins}</p>
<p>Losses: {losses}</p>
<p>Winrate: {(wins / (wins + losses)) * 100}%</p>
<p>Elo : {elo}</p>
<p>Rank: {rank}</p>
<form class="two-factor-auth" on:submit={handle2fa}>
<button type="submit">
{#if is2faEnabled}
Disable 2FA
{:else}
Enable 2FA
{/if}
</button>
</form>
</div>
</div>
</div>
<style>
.overlay {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.5);
z-index: 9998;
display: flex;
justify-content: center;
align-items: center;
}
.overlay {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.5);
z-index: 9998;
display: flex;
justify-content: center;
align-items: center;
}
.profile {
background-color: #fff;
border: 1px solid #ccc;
border-radius: 5px;
padding: 1rem;
width: 300px;
}
.profile {
background-color: #fff;
border: 1px solid #ccc;
border-radius: 5px;
padding: 1rem;
width: 300px;
}
.profile-header {
display: flex;
align-items: center;
}
.profile-header {
display: flex;
align-items: center;
}
.profile-img {
width: 50px;
height: 50px;
margin-right: 1rem;
}
.profile-img {
width: 50px;
height: 50px;
margin-right: 1rem;
}
.two-factor-auth {
margin-top: 1rem;
}
.two-factor-auth {
margin-top: 1rem;
}
</style>

82
front/volume/src/components/Spectate.svelte

@ -1,53 +1,53 @@
<script lang="ts" context="module">
export interface SpectateType {
id: string;
player1: string;
player2: string;
}
export interface SpectateType {
id: string;
player1: string;
player2: string;
}
</script>
<script lang="ts">
export let spectate: Array<SpectateType> = [];
export let watch = () => {};
export let spectate: Array<SpectateType> = [];
export let watch = () => {};
</script>
<div class="overlay">
<div class="spectate" on:click|stopPropagation on:keydown|stopPropagation>
<div>
{#if spectate.length > 0}
<h2>Monkey spectating</h2>
{#each spectate.slice(0, 10) as _spectate}
<li>
<span>{_spectate.player1} VS {_spectate.player2}</span>
<button on:click={() => watch(_spectate.id)}>Spectate</button>
</li>
{/each}
{:else}
<p>No matches to spectate</p>
{/if}
</div>
</div>
<div class="spectate" on:click|stopPropagation on:keydown|stopPropagation>
<div>
{#if spectate.length > 0}
<h2>Monkey spectating</h2>
{#each spectate.slice(0, 10) as _spectate}
<li>
<span>{_spectate.player1} VS {_spectate.player2}</span>
<button on:click={() => watch(_spectate.id)}>Spectate</button>
</li>
{/each}
{:else}
<p>No matches to spectate</p>
{/if}
</div>
</div>
</div>
<style>
.overlay {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.5);
z-index: 9998;
display: flex;
justify-content: center;
align-items: center;
}
.overlay {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.5);
z-index: 9998;
display: flex;
justify-content: center;
align-items: center;
}
.spectate {
background-color: #fff;
border: 1px solid #ccc;
border-radius: 5px;
padding: 1rem;
width: 300px;
}
.spectate {
background-color: #fff;
border: 1px solid #ccc;
border-radius: 5px;
padding: 1rem;
width: 300px;
}
</style>

4
front/volume/src/main.ts

@ -1,7 +1,7 @@
import App from './App.svelte';
import App from "./App.svelte";
const app = new App({
target: document.body,
target: document.body,
});
export const prerender = true;

Loading…
Cancel
Save