From d20597ee6a11203242d0d4e9e64392c9256bb724 Mon Sep 17 00:00:00 2001 From: y-syo Date: Thu, 23 Oct 2025 14:46:15 +0200 Subject: [PATCH 1/2] =?UTF-8?q?=E3=80=8C=F0=9F=8F=97=EF=B8=8F=E3=80=8D=20w?= =?UTF-8?q?ip(front):=20partial=20avatar=20implementation=20(a=20lot=20of?= =?UTF-8?q?=20reworks=20to=20do)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/front/index.html | 5 +- src/front/static/css/style.css | 1 + src/front/static/ts/views/LoginPage.ts | 2 +- src/front/static/ts/views/Profile.ts | 37 ++++++++--- src/front/static/ts/views/ProfileMenu.ts | 1 - src/front/static/ts/views/Settings.ts | 49 ++++++++++++++- src/front/static/ts/views/Tetris.ts | 53 +++++++++++++--- src/front/static/ts/views/TetrisVersus.ts | 8 +-- src/front/static/ts/views/TournamentMenu.ts | 69 ++++++++++++++------- tailwind.config.js | 8 ++- 10 files changed, 181 insertions(+), 52 deletions(-) diff --git a/src/front/index.html b/src/front/index.html index 8532da2..fd32cc8 100644 --- a/src/front/index.html +++ b/src/front/index.html @@ -11,10 +11,7 @@ - - - - +
diff --git a/src/front/static/css/style.css b/src/front/static/css/style.css index 56bb708..65bae17 100644 --- a/src/front/static/css/style.css +++ b/src/front/static/css/style.css @@ -1,3 +1,4 @@ +@import url('https://fonts.googleapis.com/css2?family=Lexend:wght@100..900&display=swap'); @import "tailwindcss"; @layer utilities { .no-scrollbar::-webkit-scrollbar { diff --git a/src/front/static/ts/views/LoginPage.ts b/src/front/static/ts/views/LoginPage.ts index 0ed05c1..cffe8fb 100644 --- a/src/front/static/ts/views/LoginPage.ts +++ b/src/front/static/ts/views/LoginPage.ts @@ -41,7 +41,7 @@ export default class extends Aview { login with John Google - + login with Rusty diff --git a/src/front/static/ts/views/Profile.ts b/src/front/static/ts/views/Profile.ts index b80bd0b..24faa0a 100644 --- a/src/front/static/ts/views/Profile.ts +++ b/src/front/static/ts/views/Profile.ts @@ -44,6 +44,7 @@ export default class extends Aview { if (!await isLogged()) navigationManager("/"); + let pc: number = 0; dragElement(document.getElementById("window")); let uuid: String; uuid = document.cookie.match(new RegExp('(^| )' + "uuid" + '=([^;]+)'))[2]; @@ -63,6 +64,7 @@ export default class extends Aview { credentials: "include", }); let matchCount = await matchCount_req.json(); + pc += matchCount.n_matches; let matches_req = await fetch(`http://localhost:3002/users/${uuid}/matchHistory?game=pong&iStart=0&iEnd=${matchCount.n_matches}`, { method: "GET", @@ -88,7 +90,9 @@ export default class extends Aview { const header = popup.appendChild(document.createElement("div")); header.classList.add("bg-linear-to-r", "from-orange-200", "to-orange-300", "flex", "flex-row", "min-w-35", "justify-between", "px-2"); header.id = `${id}-header`; - header.appendChild(document.createElement("span")).innerText = "score.ts"; + const title = header.appendChild(document.createElement("span")); + title.classList.add("font-[Kubasta]"); + title.innerText = "score-pong.ts"; const btn = header.appendChild(document.createElement("button")); btn.innerText = " × "; btn.onclick = () => { document.getElementById(`${id}`).remove(); }; @@ -116,6 +120,7 @@ export default class extends Aview { credentials: "include", }); matchCount = await matchCount_req.json(); + pc += matchCount.n_matches; matches_req = await fetch(`http://localhost:3002/users/${uuid}/matchHistory?game=tetris&iStart=0&iEnd=${matchCount.n_matches}`, { method: "GET", @@ -131,7 +136,11 @@ export default class extends Aview { for (let match of matches.matchHistory) { const newEntry = document.createElement("li"); newEntry.classList.add("m-1", "default-button", "bg-neutral-200", "dark:bg-neutral-800", "text-neutral-900", "dark:text-white"); - newEntry.innerHTML = match.score.p1Score > match.score.p2Score ? `${match.score.p1} - winner` : `${match.score.p2} - winner`; + newEntry.innerHTML = match.score.p2 != undefined ? + (match.score.p1Score > match.score.p2Score ? `${match.score.p1} - winner` : `${match.score.p2} - winner`) + : + (`solo game - ${match.score.p1Score}`) + ; main.insertBefore(newEntry, main.firstChild); const popup: HTMLDivElement = document.createElement("div"); @@ -141,7 +150,9 @@ export default class extends Aview { const header = popup.appendChild(document.createElement("div")); header.classList.add("bg-linear-to-r", "from-orange-200", "to-orange-300", "flex", "flex-row", "min-w-35", "justify-between", "px-2"); header.id = `${id}-header`; - header.appendChild(document.createElement("span")).innerText = "score.ts"; + const title = header.appendChild(document.createElement("span")); + title.classList.add("font-[Kubasta]"); + title.innerText = "score-tetris.ts"; const btn = header.appendChild(document.createElement("button")); btn.innerText = " × "; btn.onclick = () => { document.getElementById(`${id}`).remove(); }; @@ -152,7 +163,11 @@ export default class extends Aview { popup_content.appendChild(document.createElement("span")).innerText = `${date.toDateString()} ${date.getHours()}:${date.getMinutes().toString().padStart(2, '0')}`; const score = popup_content.appendChild(document.createElement("span")); score.classList.add(); - score.innerText = `${match.score.p1} : ${match.score.p1Score} - ${match.score.p2Score} : ${match.score.p2}`; + score.innerText = match.score.p2 != undefined ? + (`${match.score.p1} : ${match.score.p1Score} - ${match.score.p2Score} : ${match.score.p2}`) + : + (`${match.score.p1} : ${match.score.p1Score}`) + ; const tx = popup_content.appendChild(document.createElement("a")); tx.href = `https://testnet.snowscan.xyz/tx/${match.tx}`; tx.innerText = "transaction proof"; @@ -168,8 +183,12 @@ export default class extends Aview { if (!profile) return; const picture = profile.appendChild(document.createElement("img")); - picture.src = "https://api.kanel.ovh/pp"; - picture.classList.add("text-neutral-900", "dark:text-white", "center", "h-18", "w-18", "mx-3"); + const a = await fetch(`http://localhost:3002/users/${uuid}/avatar`, { + method: "GET", + credentials: "include", + }); + picture.src = a.status === 200 ? `http://localhost:3002/users/${uuid}/avatar` : "https://api.kanel.ovh/pp"; + picture.classList.add("text-neutral-900", "dark:text-white", "center", "h-18", "w-18", "mx-3", "reverse-border"); const nametag = profile.appendChild(document.createElement("div")); nametag.innerHTML = ` @@ -180,9 +199,9 @@ export default class extends Aview { const winrate = profile.appendChild(document.createElement("div")); winrate.innerHTML = ` -
wins: ${userdata.wins}
-
losses: ${userdata.losses}
-
winrate: ${ (userdata.wins != 0 && userdata.losses != 0) ? Math.round(userdata.wins / (userdata.wins + userdata.losses) * 100) + " %" : "-" }
+
total playcount: ${pc}
+
pong winrate: ${ (userdata.pong.wins == 0 && userdata.pong.losses == 0) ? "-" : Math.round(userdata.pong.wins / (userdata.pong.wins + userdata.pong.losses) * 100) + " %" }
+
tetris winrate: ${ (userdata.tetris.wins == 0 && userdata.tetris.losses == 0) ? "-" : Math.round(userdata.tetris.wins / (userdata.tetris.wins + userdata.tetris.losses) * 100) + " %" }
`; winrate.classList.add("text-neutral-900", "dark:text-white", "grow", "content-center"); } diff --git a/src/front/static/ts/views/ProfileMenu.ts b/src/front/static/ts/views/ProfileMenu.ts index 68317c0..40d68f6 100644 --- a/src/front/static/ts/views/ProfileMenu.ts +++ b/src/front/static/ts/views/ProfileMenu.ts @@ -65,7 +65,6 @@ export default class extends Aview {
profile settings - friends `; } diff --git a/src/front/static/ts/views/Settings.ts b/src/front/static/ts/views/Settings.ts index 5c70167..06632fa 100644 --- a/src/front/static/ts/views/Settings.ts +++ b/src/front/static/ts/views/Settings.ts @@ -24,9 +24,18 @@ export default class extends Aview { ×
-
- - +
+
+ + +
+
+ + +
@@ -80,5 +89,39 @@ export default class extends Aview { else console.error("xd"); // xd????????????? }); + + const upload = document.getElementById("upload-file") as HTMLInputElement; + upload.addEventListener("change", () => { + const fileList: FileList | null = upload.files; + if (!fileList) + return console.error("empty"); + if (!fileList[0].type.startsWith("image/")) { + console.error("invalid file"); + return; + } + + document.getElementById("upload-preview")?.classList.remove("hidden"); + const img = document.getElementById("upload-preview-img") as HTMLImageElement; + img.classList.remove("hidden"); + + const reader = new FileReader(); + reader.onload = (e) => { + if (!e.target) + return; + img.src = e.target.result as string; + }; + + reader.readAsDataURL(fileList[0]); + }); + + (document.getElementById("upload-submit") as HTMLButtonElement).onclick = async () => { + const up_req = await fetch(`http://localhost:3002/users/${uuid}/avatar`, { + method: "POST", + headers: { "Content-Type": upload.files[0].type } , + credentials: "include", + body: upload.files[0], //upload uuuh whatever i have to upload + }); + console.log(up_req.status); + }; } } diff --git a/src/front/static/ts/views/Tetris.ts b/src/front/static/ts/views/Tetris.ts index 61c309a..f5a20d3 100644 --- a/src/front/static/ts/views/Tetris.ts +++ b/src/front/static/ts/views/Tetris.ts @@ -509,13 +509,10 @@ export default class extends Aview { this.movePiece(this.direction, 0); this.move = false; } - - /*if (this.keys["ArrowDown"]) - this.softDrop();*/ } - registerListeners() { - window.addEventListener("keydown", (e) => { + removeListeners() { + window.removeEventListener("keydown", (e) => { this.keys[e.key] = true; if (this.isGameOver) return; @@ -553,13 +550,55 @@ export default class extends Aview { } }); + document.removeEventListener("keyup", (e) => { + this.keys[e.key] = false; + }); + } + + registerListeners() { + window.addEventListener("keydown", (e) => { + this.keys[e.key] = true; + + if (this.isGameOver) return; + + if (e.key === "p" || e.key === "P" || e.key === "Escape") + this.isPaused = !this.isPaused; + + if (this.isPaused) return; + + if (e.key === "ArrowLeft") + { + this.inputTimestamp = Date.now(); + this.direction = -1;//this.movePiece(-1, 0); + this.move = true; + } + else if (e.key === "ArrowRight") + { + this.inputTimestamp = Date.now(); + this.direction = 1;//this.movePiece(1, 0); + this.move = true; + } + else if (e.key === "ArrowDown") this.softDrop(); + else if (e.code === "Space") { + //e.preventDefault(); + this.hardDrop(); + } else if (e.key === "Shift" || e.key === "c" || e.key === "C") { + this.hold(); + } else if (e.key === "x" || e.key === "X" || e.key === "ArrowUp") { + //e.preventDefault(); + this.rotatePiece("cw"); + } else if (e.key === "z" || e.key === "Z" || e.key === "Control") { + this.rotatePiece("ccw"); + } + }); + document.addEventListener("keyup", (e) => { this.keys[e.key] = false; }); } async loop(timestamp: number) { - if (!view.running) return; + if (!view.running) return this.removeListeners(); if (!this.lastDrop) this.lastDrop = timestamp; if (!this.isPaused) { @@ -596,9 +635,7 @@ export default class extends Aview { credentials: "include", body: JSON.stringify({ "game": "tetris", - "opponent": "xd", "myScore": this.score, - "opponentScore": 0, "date": Date.now(), }), }); diff --git a/src/front/static/ts/views/TetrisVersus.ts b/src/front/static/ts/views/TetrisVersus.ts index 330b8e6..f9debac 100644 --- a/src/front/static/ts/views/TetrisVersus.ts +++ b/src/front/static/ts/views/TetrisVersus.ts @@ -606,16 +606,16 @@ export default class extends Aview { } else if (this.id === 0 ? e.code === "KeyS" : e.code === "Numpad5") this.softDrop(); else if (this.id === 0 ? e.code === "Space" : e.code === "Numpad0") { - e.preventDefault(); + //e.preventDefault(); this.hardDrop(); } else if (this.id === 0 ? e.code === "ShiftLeft" : e.code === "NumpadEnter") { - e.preventDefault(); + //e.preventDefault(); this.hold(); } else if (this.id === 0 ? (e.code === "KeyE" || e.code === "KeyW") : (e.code === "Numpad9" || e.code === "Numpad8")) { - e.preventDefault(); + //e.preventDefault(); this.rotatePiece("cw"); } else if (this.id === 0 ? (e.code === "KeyQ" || e.code === "ControlLeft") : e.code === "Numpad7") { - e.preventDefault(); + //e.preventDefault(); this.rotatePiece("ccw"); } }); diff --git a/src/front/static/ts/views/TournamentMenu.ts b/src/front/static/ts/views/TournamentMenu.ts index bc2bbd6..00538a8 100644 --- a/src/front/static/ts/views/TournamentMenu.ts +++ b/src/front/static/ts/views/TournamentMenu.ts @@ -1,4 +1,5 @@ import Aview from "./Aview.ts" +import { dragElement } from "./drag.ts"; import { setOnekoState, setBallPos } from "../oneko.ts" export default class extends Aview { @@ -12,18 +13,37 @@ export default class extends Aview { async getHTML() { return ` -
-

how many players ?

-
- - -
+
+
+ pong_game.ts +
+ + + × +
+ +
+

how many players ?

+
+ + +
+
+
`; } async run() { + dragElement(document.getElementById("window")); const generateBracket = async (playerCount: number) => { document.getElementById("bracket").innerHTML = ""; @@ -32,12 +52,10 @@ export default class extends Aview { const byes = totalSlots - playerCount; let odd = 0; - if (playerCount % 2) + if (playerCount > 9 || (playerCount != 3 && playerCount % 2 != 0)) { - //console.error("odd numbers are temporarily invalids"); - //return ; - ++odd; - --playerCount; + console.error("odd numbers are temporarily invalids"); + return ; } let notPowPlayersCount = 0; @@ -46,9 +64,8 @@ export default class extends Aview { notPowPlayersCount = playerCount - (2 ** Math.floor(Math.log2(playerCount))); - let initialPlayers = Array.from({ length: 2 ** Math.floor(Math.log2(playerCount))}, (_, i) => `Player ${i + 1}`); + let initialPlayers = Array.from({ length: 2 ** Math.floor(Math.log2(playerCount))}, (_, i) => `player ${i + 1}`); playerCount = 2 ** Math.floor(Math.log2(playerCount)); - //let initialPlayers = Array.from({ length: playerCount }, (_, i) => `Player ${i + 1}`); const bracketWrapper = document.createElement("div"); bracketWrapper.className = "flex space-x-8 overflow-x-auto"; @@ -63,8 +80,7 @@ export default class extends Aview { input.id = `playerName${i}`; input.value = ""; input.placeholder = name; - input.className = - "w-32 h-10 p-2 text-sm border rounded bg-white shadow disabled:bg-gray-200"; + input.className = "w-32 h-10 p-2 text-sm bg-white disabled:bg-gray-200 input-border"; playerInputColumn.appendChild(input); }); @@ -87,10 +103,10 @@ export default class extends Aview { const input = document.createElement("input"); input.type = "text"; input.id = `playerName${playerCount}`; - input.value = ""; - input.placeholder = `Player ${++playerCount}`; + input.value = `player ${++playerCount}`; + input.placeholder = `player ${++playerCount}`; input.className = - "w-32 h-10 p-2 text-sm border rounded bg-white shadow disabled:bg-gray-200"; + "w-32 h-10 p-2 text-sm bg-white disabled:bg-gray-200 input-border"; roundColumn.appendChild(input); odd--; nextRound.push(""); @@ -103,9 +119,9 @@ export default class extends Aview { input.type = "text"; input.id = `playerName${playerCount}`; input.value = ""; - input.placeholder = `Player ${++playerCount}`; + input.placeholder = `player ${++playerCount}`; input.className = - "w-32 h-10 p-2 text-sm border rounded bg-white shadow disabled:bg-gray-200"; + "w-32 h-10 p-2 text-sm bg-white disabled:bg-gray-200 input-border"; roundColumn.appendChild(input); --notPowPlayersCount; nextRound.push(""); @@ -118,7 +134,7 @@ export default class extends Aview { const matchDiv = document.createElement("div"); matchDiv.className = - "w-32 h-10 flex items-center justify-center bg-white border rounded shadow text-center text-sm"; + "w-32 h-10 flex items-center justify-center bg-white text-center text-sm input-border"; matchDiv.textContent = ""; nextRound.push(""); @@ -130,11 +146,22 @@ export default class extends Aview { currentRound = nextRound; } + document.getElementById("bracket").appendChild(document.createElement("hr")).classList.add("my-4", "mb-8", "w-64", "reverse-border"); document.getElementById("bracket").appendChild(bracketWrapper); + const btn = document.getElementById("bracket").appendChild(document.createElement("button")); + btn.classList.add("default-button", "w-full"); + btn.id = "tournament-play"; + btn.onclick = () => { + console.log("ok"); + }; + btn.innerText = "start tournament !!"; + }; document.getElementById("bracket-generate")?.addEventListener("click", () => { const input: HTMLInputElement = document.getElementById("playerNumber") as HTMLInputElement; + if (input.value == "") + return; generateBracket(+input.value); }); diff --git a/tailwind.config.js b/tailwind.config.js index 9bd8368..53376f7 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -1,7 +1,13 @@ export default { content: ['./src/front/**/*.{html,js,ts,css}'], theme: { - extend: {}, + extend: { + fontFamily: { + jersey: ['"Jersey 10"', 'sans-serif'], + }, + }, + }, + }, }, plugins: [], } From f628b038d011a2929278a2b489b826d3df9afd75 Mon Sep 17 00:00:00 2001 From: adjoly Date: Thu, 23 Oct 2025 16:05:31 +0200 Subject: [PATCH 2/2] =?UTF-8?q?=E3=80=8C=F0=9F=94=A8=E3=80=8D=20fix(front)?= =?UTF-8?q?:=20added=20exception=20catching?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/user/default.js | 4 +-- src/front/static/ts/views/ProfileMenu.ts | 6 ++--- src/front/static/ts/views/RegisterPage.ts | 31 +++++++++++------------ 3 files changed, 20 insertions(+), 21 deletions(-) diff --git a/src/api/user/default.js b/src/api/user/default.js index 1c63b59..2c7902b 100644 --- a/src/api/user/default.js +++ b/src/api/user/default.js @@ -59,9 +59,9 @@ const deleteFriends = database.prepare('DELETE FROM friends WHERE username = ?;' export default async function(fastify, options) { fastify.register(cors, { - origin: process.ENV.CORS_ORIGIN || 'http://localhost:5173', + origin: process.env.CORS_ORIGIN || 'http://localhost:5173', credentials: true, - methods: [ "GET", "POST", "DELETE", "OPTIONS" ] + methods: [ "GET", "POST", "PATCH", "DELETE", "OPTIONS" ] }); fastify.register(fastifyJWT, { diff --git a/src/front/static/ts/views/ProfileMenu.ts b/src/front/static/ts/views/ProfileMenu.ts index 40d68f6..84422ca 100644 --- a/src/front/static/ts/views/ProfileMenu.ts +++ b/src/front/static/ts/views/ProfileMenu.ts @@ -40,13 +40,13 @@ export default class extends Aview { async function getMainHTML() { if (!(await isLogged())) { - document.getElementById("menu-bottom-div").classList.add("hidden"); + document.getElementById("menu-bottom-div")?.classList.add("hidden"); return ` login register `; } - document.getElementById("menu-bottom-div").classList.remove("hidden"); + document.getElementById("menu-bottom-div")?.classList.remove("hidden"); uuid = document.cookie.match(new RegExp('(^| )' + "uuid" + '=([^;]+)'))[2]; const userdata_req = await fetch(`http://localhost:3002/users/${uuid}`, { @@ -71,7 +71,7 @@ export default class extends Aview { document.getElementById("profile-items").innerHTML = await getMainHTML(); - document.getElementById("menu-logout").addEventListener("click", async () => { + document.getElementById("menu-logout")?.addEventListener("click", async () => { let req = await fetch("http://localhost:3001/logout", { method: "GET", credentials: "include", diff --git a/src/front/static/ts/views/RegisterPage.ts b/src/front/static/ts/views/RegisterPage.ts index 30618f1..7485e93 100644 --- a/src/front/static/ts/views/RegisterPage.ts +++ b/src/front/static/ts/views/RegisterPage.ts @@ -5,8 +5,7 @@ import { isLogged, navigationManager } from "../main.ts" export default class extends Aview { - constructor() - { + constructor() { super(); this.setTitle("register"); setOnekoState("default"); @@ -53,7 +52,7 @@ export default class extends Aview { } async run() { - dragElement(document.getElementById("window")); + dragElement(document.getElementById("window")); const login = async () => { const username = (document.getElementById("username") as HTMLInputElement).value; const password = (document.getElementById("password") as HTMLInputElement).value; @@ -67,34 +66,34 @@ export default class extends Aview { }); const data = await data_req.json(); - if (data_req.status === 200) - { + if (data_req.status === 200) { let uuid_req = await fetch("http://localhost:3001/me", { method: "GET", credentials: "include", }); let uuid = await uuid_req.json(); - document.cookie = `uuid=${uuid.user};max-ages=${60*60*24*7}`; + document.cookie = `uuid=${uuid.user};max-ages=${60 * 60 * 24 * 7}`; console.log(document.cookie); isLogged(); navigationManager("/"); } - else if (data_req.status === 400) - { - document.getElementById("login-error-message").innerHTML = "error: " + data.error; - document.getElementById("login-error-message").classList.remove("hidden"); + else if (data_req.status === 400) { + if (document.getElementById("login-error-message")) { + document.getElementById("login-error-message").innerHTML = "error: " + data.error; + document.getElementById("login-error-message")?.classList.remove("hidden"); + } } - else - { + else { throw new Error("invalid response"); } } - catch (error) - { + catch (error) { console.error(error); - document.getElementById("login-error-message").innerHTML = "error: server error, try again later..."; - document.getElementById("login-error-message").classList.remove("hidden"); + if (document.getElementById("login-error-message")) { + document.getElementById("login-error-message").innerHTML = "error: server error, try again later..."; + document.getElementById("login-error-message")?.classList.remove("hidden"); + } } };