diff --git a/flake.nix b/flake.nix index ecdab7e..fb52ec3 100644 --- a/flake.nix +++ b/flake.nix @@ -39,7 +39,7 @@ nodejs_22 pnpm just - foundry + foundry ]; shellHook = '' if [ ! -d node_modules/ ]; then diff --git a/src/front/index.html b/src/front/index.html index e7a3f05..97c4aea 100644 --- a/src/front/index.html +++ b/src/front/index.html @@ -1,21 +1,28 @@ - - - - Vite + Tailwind Test - - - - - -
-

Vite + Tailwind

-

🚀 Looks like it's working!

- -
- + + + + + + Vite + Tailwind Test + + + + + + + + + + +
+
+ + + diff --git a/src/front/main.tsx b/src/front/main.tsx deleted file mode 100644 index 2a2392b..0000000 --- a/src/front/main.tsx +++ /dev/null @@ -1 +0,0 @@ -console.log("test") diff --git a/src/front/static/assets/favicon.ico b/src/front/static/assets/favicon.ico new file mode 100644 index 0000000..18945be Binary files /dev/null and b/src/front/static/assets/favicon.ico differ diff --git a/src/front/static/css/style.css b/src/front/static/css/style.css new file mode 100644 index 0000000..0d686fe --- /dev/null +++ b/src/front/static/css/style.css @@ -0,0 +1,5 @@ +@import "tailwindcss"; + +@theme { + --color-accent-500: #f55151; +} diff --git a/src/front/static/ts/main.ts b/src/front/static/ts/main.ts new file mode 100644 index 0000000..676a313 --- /dev/null +++ b/src/front/static/ts/main.ts @@ -0,0 +1,69 @@ +/*import MainMenu from "./views/MainMenu.ts"; +import PongMenu from "./views/PongMenu.ts"; + +import LoginPage from "./views/LoginPage.ts"; +import RegisterPage from "./views/RegisterPage.ts"; + +import Game from "./views/Game.ts";*/ + +const navigationManager = url => { + history.pushState(null, null, url); + router(); +}; + +let view; + +const routes = [ + /*{ path: "/", view: MainMenu }, + + { path: "/pong", view: PongMenu }, + { path: "/pong/solo", view: Game }, + + { path: "/login", view: LoginPage }, + { path: "/register", view: RegisterPage },*/ + { path: "/", view: () => import("./views/MainMenu.ts") }, + + { path: "/pong", view: () => import("./views/PongMenu.ts") }, + { path: "/pong/solo", view: () => import("./views/Game.ts") }, + + { path: "/login", view: () => import("./views/LoginPage.ts") }, + { path: "/register", view: () => import("./views/RegisterPage.ts") }, +]; + +const router = async () => { + + const routesMap = routes.map(route => { + return { route: route, isMatch: location.pathname === route.path }; + }); + + let match = routesMap.find(routeMap => routeMap.isMatch); + + if (!match) + match = { route: routes[0], isMatch: true }; + + if (view) + view.running = false; + + console.log(match); + + const module = await match.route.view(); + view = new module.default(); + + document.querySelector("#app").innerHTML = await view.getHTML(); + view.run(); +}; + +window.addEventListener("popstate", router); + +document.addEventListener("DOMContentLoaded", () => { + + document.body.addEventListener("click", e=> { + if (e.target.matches("[data-link]")) + { + e.preventDefault(); + navigationManager(e.target.href); + } + }); + + router(); +}); diff --git a/src/front/static/ts/views/Aview.ts b/src/front/static/ts/views/Aview.ts new file mode 100644 index 0000000..810d3ab --- /dev/null +++ b/src/front/static/ts/views/Aview.ts @@ -0,0 +1,10 @@ +export default class { + contructor() + { + } + + setTitle(title) { document.title = title; } + + async getHTML() { return ""; } + async run() { } +}; diff --git a/src/front/static/ts/views/Game.ts b/src/front/static/ts/views/Game.ts new file mode 100644 index 0000000..5610676 --- /dev/null +++ b/src/front/static/ts/views/Game.ts @@ -0,0 +1,214 @@ +import Aview from "./Aview.ts" + +export default class extends Aview { + + running: boolean; + + constructor() + { + super(); + this.setTitle("pog or pong ? :3"); + this.running = true; + } + + async getHTML() { + return ` + +
+ + +
+ `; + } + + async run() { + let start: number = 0; + let elapsed: number; + + let game_playing: boolean = false; + let match_over: boolean = false; + let p1_score: number = 0; + let p2_score: number = 0; + + let countdown: number = 3; + let countdownTimer: number = 0; + + const canvas = document.getElementById("gameCanvas") as HTMLCanvasElement; + const ctx = canvas.getContext("2d"); + + const paddleOffset: number = 15; + const paddleHeight: number = 100; + const paddleWidth: number = 10; + const ballSize: number = 10; + + let leftPaddleY: number = canvas.height / 2 - paddleHeight / 2; + let rightPaddleY: number = canvas.height / 2 - paddleHeight / 2; + let paddleSpeed: number = 727 * 0.69; + let ballX: number = canvas.width / 2; + let ballY: number = canvas.height / 2; + let ballSpeed: number = 200; + let ballSpeedX: number = 300; + let ballSpeedY: number = 10; + + const keys: Record = {}; + + document.addEventListener("keydown", e => { keys[e.key] = true; }); + document.addEventListener("keyup", e => { keys[e.key] = false; }); + + function movePaddles() { + if (keys["w"] && leftPaddleY > 0) + leftPaddleY -= paddleSpeed * elapsed; + if (keys["s"] && leftPaddleY < canvas.height - paddleHeight) + leftPaddleY += paddleSpeed * elapsed; + if (keys["ArrowUp"] && rightPaddleY > 0) + rightPaddleY -= paddleSpeed * elapsed; + if (keys["ArrowDown"] && rightPaddleY < canvas.height - paddleHeight) + rightPaddleY += paddleSpeed * elapsed; + } + + function getBounceVelocity(paddleY) { + const speed = ballSpeed; + const paddleCenterY = paddleY + paddleHeight / 2; + + let n = (ballY - paddleCenterY) / (paddleHeight / 2); + n = Math.max(-1, Math.min(1, n)); + let theta = n * ((75 * Math.PI) / 180); + ballSpeedY = ballSpeed * Math.sin(theta); + } + + function moveBall() { + let length = Math.sqrt(ballSpeedX * ballSpeedX + ballSpeedY * ballSpeedY); + let scale = ballSpeed / length; + ballX += (ballSpeedX * scale) * elapsed; + ballY += (ballSpeedY * scale) * elapsed; + + if (ballY <= 0 || ballY >= canvas.height - ballSize) + ballSpeedY *= -1; + + if (ballX <= paddleWidth + paddleOffset && ballX >= paddleOffset && + ballY > leftPaddleY && ballY < leftPaddleY + paddleHeight) + { + ballSpeedX *= -1; + ballX = paddleWidth + paddleOffset; + getBounceVelocity(leftPaddleY); + ballSpeed += 10; + } + + if (ballX >= canvas.width - paddleWidth - ballSize - paddleOffset && ballX <= canvas.width - ballSize - paddleOffset && + ballY > rightPaddleY && ballY < rightPaddleY + paddleHeight) + { + ballSpeedX *= -1; + ballX = canvas.width - paddleWidth - ballSize - paddleOffset; + getBounceVelocity(rightPaddleY); + ballSpeed += 10; + } + + // scoring + if (ballX < 0 || ballX > canvas.width - ballSize) + { + game_playing = false; + if (ballX < 0) + p2_score++; + else + p1_score++; + + if (p1_score === 3 || p2_score === 3) + match_over = true; + else + { + countdown = 3; + countdownTimer = performance.now(); + } + + ballX = canvas.width / 2; + ballY = canvas.height / 2; + ballSpeed = 200; + ballSpeedX = 300 * ((ballSpeedX > 0) ? 1 : -1); + ballSpeedY = 10; + ballSpeedX = -ballSpeedX; + leftPaddleY = canvas.height / 2 - paddleHeight / 2; + rightPaddleY = canvas.height / 2 - paddleHeight / 2; + } + } + + function draw() { + ctx.fillStyle = "black"; + ctx.fillRect(0, 0, canvas.width, canvas.height); + + ctx.fillStyle = "white"; + ctx.fillRect(paddleOffset, leftPaddleY, paddleWidth, paddleHeight); + ctx.fillRect(canvas.width - paddleWidth - paddleOffset, rightPaddleY, paddleWidth, paddleHeight); + + ctx.fillStyle = "white"; + if (game_playing) + ctx.fillRect(ballX, ballY, ballSize, ballSize); + + ctx.font = "24px sans-serif"; + ctx.fillText(`${p1_score} - ${p2_score}`, canvas.width / 2 - 20, 30); + + if (match_over) + { + ctx.font = "48px sans-serif"; + const winner = p1_score > p2_score ? "Player 1" : "Player 2"; + ctx.fillText(`${winner} won :D`, canvas.width / 2 - 150, canvas.height / 2 + 22); + document.getElementById("game-buttons").classList.remove("hidden"); + } + } + + function startCountdown() + { + const now = performance.now(); + if (countdown > 0) + { + if (now - countdownTimer >= 500) + { + countdown--; + countdownTimer = now; + } + ctx.font = "48px sans-serif"; + ctx.fillText(countdown.toString(), canvas.width / 2 - 10, canvas.height / 2 + 24); + } + else if (countdown === 0) + { + ctx.font = "48px sans-serif"; + ctx.fillText("Go!", canvas.width / 2 - 30, canvas.height / 2 + 24); + setTimeout(() => { + game_playing = true; + countdown = -1; + }, 500); + } + } + + const gameLoop = (timestamp: number) => { + elapsed = (timestamp - start) / 1000; + start = timestamp; + if (game_playing) + { + movePaddles(); + moveBall(); + } + draw(); + console.log(game_playing); + if (!game_playing) + startCountdown(); + if (this.running) + requestAnimationFrame(gameLoop); + }; + + + document.getElementById("game-retry")?.addEventListener("click", () => { + document.getElementById("game-buttons").classList.add("hidden"); + game_playing = false; + match_over = false; + p1_score = 0; + p2_score = 0; + + countdown = 3; + countdownTimer = performance.now(); + }); + requestAnimationFrame(gameLoop); + } +} diff --git a/src/front/static/ts/views/LoginPage.ts b/src/front/static/ts/views/LoginPage.ts new file mode 100644 index 0000000..bdfc553 --- /dev/null +++ b/src/front/static/ts/views/LoginPage.ts @@ -0,0 +1,66 @@ +import Aview from "./Aview.ts" + +export default class extends Aview { + + constructor() + { + super(); + this.setTitle("login"); + } + + async getHTML() { + return ` +
+

login

+ + + + + + + + register + +
+ `; + } + + async run() { + const login = async () => { + const username = (document.getElementById("username") as HTMLInputElement).value; + const password = (document.getElementById("password") as HTMLInputElement).value; + + try { + /*const response = await fetch("https://localhost/login", { + method: "POST", + headers: { "Content-Type": "application/json", }, + credentials: "include", + body: JSON.stringify({ user: username, password: password }), + }); + + const data = await response.json();*/ + const data = { "error": "invalid password or smth" }; + const response = { status: 400}; + + + if (response.status === 200) + { + navigationManager("/"); + } + else if (response.status === 400) + { + document.getElementById("login-error-message").innerHTML = "error: " + data.error; + document.getElementById("login-error-message").classList.remove("hidden"); + } + + } + catch (error) + { + document.getElementById("login-error-message").innerHTML = "error: server error, try again later..."; + document.getElementById("login-error-message").classList.remove("hidden"); + } + }; + + document.getElementById("login-button")?.addEventListener("click", login); + } +} diff --git a/src/front/static/ts/views/MainMenu.ts b/src/front/static/ts/views/MainMenu.ts new file mode 100644 index 0000000..9d00ee0 --- /dev/null +++ b/src/front/static/ts/views/MainMenu.ts @@ -0,0 +1,22 @@ +import Aview from "./Aview.ts" + +export default class extends Aview { + + constructor() + { + super(); + this.setTitle("knl is trans(cendence)"); + } + + async getHTML() { + return ` +
+

knl_meowscendence :D

+

i like pong

+ + Pong + +
+ `; + } +} diff --git a/src/front/static/ts/views/PongMenu.ts b/src/front/static/ts/views/PongMenu.ts new file mode 100644 index 0000000..90dabdd --- /dev/null +++ b/src/front/static/ts/views/PongMenu.ts @@ -0,0 +1,21 @@ +import Aview from "./Aview.ts" + +export default class extends Aview { + + constructor() + { + super(); + this.setTitle("ponging ur mom"); + } + + async getHTML() { + return ` +
+

pong is funny yay

+ + solo + +
+ `; + } +} diff --git a/src/front/static/ts/views/RegisterPage.ts b/src/front/static/ts/views/RegisterPage.ts new file mode 100644 index 0000000..7e97a62 --- /dev/null +++ b/src/front/static/ts/views/RegisterPage.ts @@ -0,0 +1,27 @@ +import Aview from "./Aview.ts" + +export default class extends Aview { + + constructor() + { + super(); + this.setTitle("ft_trans 🏳️‍⚧️"); + } + + async getHTML() { + return ` +
+

register

+ + + + + + + + i already have an account + +
+ `; + } +} diff --git a/src/front/style.css b/src/front/style.css deleted file mode 100644 index f5645cf..0000000 --- a/src/front/style.css +++ /dev/null @@ -1,5 +0,0 @@ -@import "tailwindcss"; - -/*@tailwind base; -@tailwind components; -@tailwind utilities;*/