|
<template> |
|
<div id="app"> |
|
<header> |
|
<nav> |
|
<ul> |
|
<li> |
|
<a href="#">{{ translations[locale].home }}</a> |
|
</li> |
|
<li> |
|
<a href="#">{{ translations[locale].about }}</a> |
|
</li> |
|
<li> |
|
<a href="#">{{ translations[locale].contact }}</a> |
|
</li> |
|
</ul> |
|
</nav> |
|
<div class="auth-buttons"> |
|
<button @click="showLogin = true"> |
|
{{ translations[locale].login }} |
|
</button> |
|
<button @click="showRegister = true"> |
|
{{ translations[locale].register }} |
|
</button> |
|
</div> |
|
</header> |
|
|
|
<main> |
|
<h1>{{ translations[locale].gameTitle }}</h1> |
|
<div class="timer-settings"> |
|
<label>{{ translations[locale].timerMode }}</label> |
|
<select v-model="timerMode"> |
|
<option value="none">{{ translations[locale].none }}</option> |
|
<option value="blitz">{{ translations[locale].blitz }}</option> |
|
<option value="bullet">{{ translations[locale].bullet }}</option> |
|
</select> |
|
<button @click="startGame">{{ translations[locale].startGame }}</button> |
|
</div> |
|
<div class="board"> |
|
<div |
|
v-for="(square, index) in board" |
|
:key="index" |
|
class="square" |
|
:class="getSquareColor(index)" |
|
@click="handleSquareClick(index)" |
|
> |
|
<img v-if="square" :src="getPieceImage(square)" alt="Piece" /> |
|
</div> |
|
</div> |
|
<div class="timer-section" v-if="timerMode !== 'none'"> |
|
<h2>{{ formattedTime }}</h2> |
|
<button @click="pauseResumeTimer"> |
|
{{ |
|
isRunning ? translations[locale].pause : translations[locale].resume |
|
}} |
|
</button> |
|
</div> |
|
<div class="tasks"> |
|
<h2>{{ translations[locale].tasks }}</h2> |
|
<input |
|
v-model="newTask" |
|
type="text" |
|
:placeholder="translations[locale].addNewTask" |
|
@keyup.enter="addTask" |
|
/> |
|
<ul> |
|
<li v-for="(task, index) in tasks" :key="index"> |
|
<input |
|
type="checkbox" |
|
v-model="task.completed" |
|
@change="completeTask(index)" |
|
/> |
|
{{ task.name }} |
|
<button @click="deleteTask(index)">✖</button> |
|
</li> |
|
</ul> |
|
</div> |
|
</main> |
|
|
|
<footer> |
|
<p> |
|
Check out my |
|
<a href="https://linkedin.com/in/kevin-marville" target="_blank"> |
|
LinkedIn |
|
</a> |
|
</p> |
|
</footer> |
|
<div class="floating-bubble"> |
|
<a href="https://kvnbbg-creations.io" target="_blank"> |
|
Je cherche de nouvelles opportunités sur le marché du travail |
|
aujourd'hui |
|
<span>🐼🌱</span> |
|
</a> |
|
</div> |
|
<audio ref="audio" :src="alarmSound"></audio> |
|
</div> |
|
</template> |
|
<script> |
|
export default { |
|
data() { |
|
return { |
|
locale: "en", |
|
translations: { |
|
en: { |
|
home: "Home", |
|
about: "About", |
|
contact: "Contact", |
|
login: "Login", |
|
register: "Register", |
|
gameTitle: "Vue.js Chess Game", |
|
timerMode: "Timer Mode", |
|
none: "None", |
|
blitz: "Blitz", |
|
bullet: "Bullet", |
|
startGame: "Start Game", |
|
start: "Start", |
|
pause: "Pause", |
|
resume: "Resume", |
|
reset: "Reset", |
|
tasks: "Tasks", |
|
addNewTask: "Add a new task", |
|
loginSuccess: "You have successfully logged in!", |
|
loginFail: "Login failed. Please check your username and password.", |
|
registerSuccess: "You have successfully registered!", |
|
registerFail: "Registration failed. Please check your details." |
|
}, |
|
fr: { |
|
home: "Accueil", |
|
about: "À propos", |
|
contact: "Contact", |
|
login: "Connexion", |
|
register: "Inscription", |
|
gameTitle: "Jeu d'échecs Vue.js", |
|
timerMode: "Mode minuterie", |
|
none: "Aucun", |
|
blitz: "Blitz", |
|
bullet: "Bullet", |
|
startGame: "Commencer le jeu", |
|
start: "Démarrer", |
|
pause: "Pause", |
|
resume: "Reprendre", |
|
reset: "Réinitialiser", |
|
tasks: "Tâches", |
|
addNewTask: "Ajouter une nouvelle tâche", |
|
loginSuccess: "Vous vous êtes connecté avec succès!", |
|
loginFail: |
|
"Échec de la connexion. Veuillez vérifier votre nom d'utilisateur et votre mot de passe.", |
|
registerSuccess: "Vous vous êtes inscrit avec succès!", |
|
registerFail: "Échec de l'inscription. Veuillez vérifier vos détails." |
|
}, |
|
es: { |
|
home: "Inicio", |
|
about: "Acerca de", |
|
contact: "Contacto", |
|
login: "Iniciar sesión", |
|
register: "Registrarse", |
|
gameTitle: "Juego de ajedrez Vue.js", |
|
timerMode: "Modo de temporizador", |
|
none: "Ninguno", |
|
blitz: "Blitz", |
|
bullet: "Bullet", |
|
startGame: "Iniciar juego", |
|
start: "Comenzar", |
|
pause: "Pausa", |
|
resume: "Reanudar", |
|
reset: "Restablecer", |
|
tasks: "Tareas", |
|
addNewTask: "Agregar una nueva tarea", |
|
loginSuccess: "¡Has iniciado sesión con éxito!", |
|
loginFail: |
|
"Error de inicio de sesión. Por favor, verifique su nombre de usuario y contraseña.", |
|
registerSuccess: "¡Te has registrado con éxito!", |
|
registerFail: "Error de registro. Por favor, verifique sus datos." |
|
}, |
|
de: { |
|
home: "Startseite", |
|
about: "Über", |
|
contact: "Kontakt", |
|
login: "Anmelden", |
|
register: "Registrieren", |
|
gameTitle: "Vue.js Schachspiel", |
|
timerMode: "Timer-Modus", |
|
none: "Keiner", |
|
blitz: "Blitz", |
|
bullet: "Bullet", |
|
startGame: "Spiel starten", |
|
start: "Start", |
|
pause: "Pause", |
|
resume: "Fortsetzen", |
|
reset: "Zurücksetzen", |
|
tasks: "Aufgaben", |
|
addNewTask: "Neue Aufgabe hinzufügen", |
|
loginSuccess: "Sie haben sich erfolgreich angemeldet!", |
|
loginFail: |
|
"Anmeldung fehlgeschlagen. Bitte überprüfen Sie Ihren Benutzernamen und Ihr Passwort.", |
|
registerSuccess: "Sie haben sich erfolgreich registriert!", |
|
registerFail: |
|
"Registrierung fehlgeschlagen. Bitte überprüfen Sie Ihre Angaben." |
|
} |
|
}, |
|
gameTitle: "Vue.js Chess Game", |
|
board: this.initializeBoard(), |
|
selectedSquare: null, |
|
turn: "white", |
|
pieceImages: { |
|
wp: "path/to/white-pawn.png", |
|
wr: "path/to/white-rook.png", |
|
wn: "path/to/white-knight.png", |
|
wb: "path/to/white-bishop.png", |
|
wq: "path/to/white-queen.png", |
|
wk: "path/to/white-king.png", |
|
bp: "path/to/black-pawn.png", |
|
br: "path/to/black-rook.png", |
|
bn: "path/to/black-knight.png", |
|
bb: "path/to/black-bishop.png", |
|
bq: "path/to/black-queen.png", |
|
bk: "path/to/black-king.png" |
|
}, |
|
time: 0, |
|
timer: null, |
|
isRunning: false, |
|
timerMode: "none", |
|
tasks: [], |
|
newTask: "", |
|
alarmSound: "https://www.soundjay.com/button/beep-07.wav", |
|
showLogin: false, |
|
showRegister: false, |
|
username: "", |
|
password: "", |
|
confirmPassword: "" |
|
}; |
|
}, |
|
computed: { |
|
formattedTime() { |
|
const minutes = Math.floor(this.time / 60); |
|
const seconds = this.time % 60; |
|
return `${minutes |
|
.toString() |
|
.padStart(2, "0")}:${seconds.toString().padStart(2, "0")}`; |
|
} |
|
}, |
|
methods: { |
|
initializeBoard() { |
|
return [ |
|
"br", |
|
"bn", |
|
"bb", |
|
"bq", |
|
"bk", |
|
"bb", |
|
"bn", |
|
"br", |
|
"bp", |
|
"bp", |
|
"bp", |
|
"bp", |
|
"bp", |
|
"bp", |
|
"bp", |
|
"bp", |
|
"", |
|
"", |
|
"", |
|
"", |
|
"", |
|
"", |
|
"", |
|
"", |
|
"", |
|
"", |
|
"", |
|
"", |
|
"", |
|
"", |
|
"", |
|
"", |
|
"", |
|
"", |
|
"", |
|
"", |
|
"", |
|
"", |
|
"", |
|
"", |
|
"", |
|
"", |
|
"", |
|
"", |
|
"", |
|
"", |
|
"", |
|
"", |
|
"wp", |
|
"wp", |
|
"wp", |
|
"wp", |
|
"wp", |
|
"wp", |
|
"wp", |
|
"wp", |
|
"wr", |
|
"wn", |
|
"wb", |
|
"wq", |
|
"wk", |
|
"wb", |
|
"wn", |
|
"wr" |
|
]; |
|
}, |
|
getSquareColor(index) { |
|
const row = Math.floor(index / 8); |
|
const col = index % 8; |
|
return (row + col) % 2 === 0 ? "light-square" : "dark-square"; |
|
}, |
|
getPieceImage(piece) { |
|
return this.pieceImages[piece]; |
|
}, |
|
handleSquareClick(index) { |
|
if (this.selectedSquare === null) { |
|
if (this.board[index] && this.board[index][0] === this.turn[0]) { |
|
this.selectedSquare = index; |
|
} |
|
} else { |
|
const validMove = this.isValidMove(this.selectedSquare, index); |
|
if (validMove) { |
|
this.board[index] = this.board[this.selectedSquare]; |
|
this.board[this.selectedSquare] = ""; |
|
this.selectedSquare = null; |
|
this.turn = this.turn === "white" ? "black" : "white"; |
|
this.autoPlay(); |
|
} else { |
|
this.selectedSquare = null; |
|
} |
|
} |
|
}, |
|
isValidMove(fromIndex, toIndex) { |
|
const piece = this.board[fromIndex]; |
|
const target = this.board[toIndex]; |
|
if (target && target[0] === piece[0]) { |
|
return false; |
|
} |
|
if (piece[1] === "p") { |
|
const direction = piece[0] === "w" ? -1 : 1; |
|
const startRow = piece[0] === "w" ? 6 : 1; |
|
const fromRow = Math.floor(fromIndex / 8); |
|
const toRow = Math.floor(toIndex / 8); |
|
const toCol = toIndex % 8; |
|
const fromCol = fromIndex % 8; |
|
if (fromCol === toCol && !target) { |
|
if (fromRow + direction === toRow) { |
|
return true; |
|
} |
|
if (fromRow === startRow && fromRow + 2 * direction === toRow) { |
|
return true; |
|
} |
|
} |
|
if ( |
|
Math.abs(fromCol - toCol) === 1 && |
|
fromRow + direction === toRow && |
|
target |
|
) { |
|
return true; |
|
} |
|
} |
|
return false; |
|
}, |
|
autoPlay() { |
|
setTimeout(() => { |
|
const possibleMoves = this.getAllPossibleMoves(this.turn); |
|
if (possibleMoves.length > 0) { |
|
const randomMove = |
|
possibleMoves[Math.floor(Math.random() * possibleMoves.length)]; |
|
this.board[randomMove.to] = this.board[randomMove.from]; |
|
this.board[randomMove.from] = ""; |
|
this.turn = this.turn === "white" ? "black" : "white"; |
|
this.autoPlay(); |
|
} |
|
}, 1000); |
|
}, |
|
getAllPossibleMoves(turn) { |
|
const moves = []; |
|
this.board.forEach((piece, index) => { |
|
if (piece && piece[0] === turn[0]) { |
|
for (let toIndex = 0; toIndex < 64; toIndex++) { |
|
if (this.isValidMove(index, toIndex)) { |
|
moves.push({ from: index, to: toIndex }); |
|
} |
|
} |
|
} |
|
}); |
|
return moves; |
|
}, |
|
startGame() { |
|
if (this.timerMode === "blitz") { |
|
this.time = 5 * 60; |
|
} else if (this.timerMode === "bullet") { |
|
this.time = 1 * 60; |
|
} |
|
this.isRunning = true; |
|
this.startTimer(); |
|
}, |
|
startTimer() { |
|
this.timer = setInterval(() => { |
|
if (this.time > 0) { |
|
this.time--; |
|
} else { |
|
clearInterval(this.timer); |
|
this.isRunning = false; |
|
} |
|
}, 1000); |
|
}, |
|
pauseResumeTimer() { |
|
if (this.isRunning) { |
|
clearInterval(this.timer); |
|
} else { |
|
this.startTimer(); |
|
} |
|
this.isRunning = !this.isRunning; |
|
}, |
|
resetTimer() { |
|
clearInterval(this.timer); |
|
this.time = 0; |
|
this.isRunning = false; |
|
}, |
|
addTask() { |
|
if (this.newTask.trim()) { |
|
this.tasks.push({ name: this.newTask, completed: false }); |
|
this.newTask = ""; |
|
} |
|
}, |
|
deleteTask(index) { |
|
this.tasks.splice(index, 1); |
|
}, |
|
completeTask(index) { |
|
if (this.tasks[index].completed) { |
|
this.deleteTask(index); |
|
} |
|
}, |
|
login() { |
|
if (this.username && this.password) { |
|
alert( |
|
`Bravo ${this.username}! ${ |
|
this.translations[this.locale].loginSuccess |
|
}` |
|
); |
|
this.showLogin = false; |
|
} else { |
|
alert(this.translations[this.locale].loginFail); |
|
} |
|
}, |
|
register() { |
|
if ( |
|
this.username && |
|
this.password && |
|
this.password === this.confirmPassword |
|
) { |
|
alert( |
|
`Bravo ${this.username}! ${ |
|
this.translations[this.locale].registerSuccess |
|
}` |
|
); |
|
this.showRegister = false; |
|
} else { |
|
alert(this.translations[this.locale].registerFail); |
|
} |
|
} |
|
}, |
|
beforeDestroy() { |
|
clearInterval(this.timer); |
|
} |
|
}; |
|
</script> |
|
|
|
<style> |
|
#app { |
|
font-family: Avenir, Helvetica, Arial, sans-serif; |
|
text-align: center; |
|
color: #2c3e50; |
|
margin-top: 60px; |
|
} |
|
|
|
header nav ul { |
|
list-style: none; |
|
padding: 0; |
|
} |
|
|
|
header nav ul li { |
|
display: inline; |
|
margin: 0 10px; |
|
} |
|
|
|
.auth-buttons { |
|
margin-top: 20px; |
|
} |
|
|
|
.board { |
|
display: grid; |
|
grid-template-columns: repeat(8, 50px); |
|
grid-template-rows: repeat(8, 50px); |
|
gap: 0; |
|
margin: 20px auto; |
|
border: 2px solid #000; |
|
} |
|
|
|
.square { |
|
width: 50px; |
|
height: 50px; |
|
display: flex; |
|
align-items: center; |
|
justify-content: center; |
|
} |
|
|
|
.light-square { |
|
background-color: #f0d9b5; |
|
} |
|
|
|
.dark-square { |
|
background-color: #b58863; |
|
} |
|
|
|
.square img { |
|
width: 100%; |
|
height: auto; |
|
} |
|
|
|
footer { |
|
margin-top: 20px; |
|
} |
|
|
|
footer a { |
|
color: #4fc08d; |
|
text-decoration: none; |
|
} |
|
|
|
.floating-bubble { |
|
position: fixed; |
|
bottom: 20px; |
|
right: 20px; |
|
background: #4fc08d; |
|
color: #fff; |
|
padding: 10px; |
|
border-radius: 5px; |
|
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); |
|
animation: float 5s ease-in-out infinite; |
|
} |
|
|
|
.floating-bubble a { |
|
color: #fff; |
|
text-decoration: none; |
|
} |
|
|
|
@keyframes float { |
|
0% { |
|
transform: translateY(0); |
|
} |
|
50% { |
|
transform: translateY(-10px); |
|
} |
|
100% { |
|
transform: translateY(0); |
|
} |
|
} |
|
|
|
.timer-settings { |
|
margin: 20px 0; |
|
} |
|
|
|
.timer-section { |
|
margin: 20px 0; |
|
} |
|
|
|
.tasks { |
|
text-align: left; |
|
margin-top: 20px; |
|
} |
|
|
|
.tasks h2 { |
|
font-size: 1.5em; |
|
margin-bottom: 10px; |
|
} |
|
|
|
.tasks ul { |
|
list-style: none; |
|
padding: 0; |
|
} |
|
|
|
.tasks li { |
|
background: #ececec; |
|
border: 1px solid #ddd; |
|
margin: 10px 0; |
|
padding: 10px; |
|
border-radius: 5px; |
|
display: flex; |
|
justify-content: space-between; |
|
align-items: center; |
|
} |
|
|
|
.tasks input[type="text"] { |
|
padding: 10px; |
|
border: 1px solid #ddd; |
|
border-radius: 5px; |
|
width: calc(100% - 40px); |
|
} |
|
|
|
.tasks input[type="checkbox"] { |
|
margin-right: 10px; |
|
} |
|
</style> |