This commit is contained in:
2026-01-10 23:41:07 +00:00
commit e7a44a27af
1333 changed files with 483325 additions and 0 deletions

89
public/client.js Normal file
View File

@@ -0,0 +1,89 @@
const socket = io();
// DOM Elements
const counterDisplay = document.getElementById('counter-display');
const incrementBtn = document.getElementById('increment-btn');
const usernameInput = document.getElementById('username');
const quoteInput = document.getElementById('quote');
const errorMessage = document.getElementById('error-message');
const timerDisplay = document.getElementById('timer-display');
// Cookie Helpers
function setCookie(name, value, days) {
const expires = new Date(Date.now() + days * 864e5).toUTCString();
document.cookie = name + '=' + encodeURIComponent(value) + '; expires=' + expires + '; path=/';
}
function getCookie(name) {
return document.cookie.split('; ').reduce((r, v) => {
const parts = v.split('=');
return parts[0] === name ? decodeURIComponent(parts[1]) : r;
}, '');
}
// Load name from cookie
const savedName = getCookie('username');
if (savedName) {
usernameInput.value = savedName;
}
// Socket Events
socket.on('update', (data) => {
counterDisplay.innerText = data.count;
// Animate
counterDisplay.parentElement.classList.remove('pop-anim');
void counterDisplay.parentElement.offsetWidth; // trigger reflow
counterDisplay.parentElement.classList.add('pop-anim');
});
socket.on('error', (msg) => {
showError(msg);
});
// Logic
usernameInput.addEventListener('input', (e) => {
setCookie('username', e.target.value, 365);
});
incrementBtn.addEventListener('click', () => {
const name = usernameInput.value.trim();
if (!name) {
showError("Please enter your name!");
usernameInput.focus();
return;
}
const quote = quoteInput.value.trim();
// Optimistic disable
startCooldown();
socket.emit('increment', { name, quote });
});
function showError(msg) {
errorMessage.innerText = msg;
errorMessage.classList.remove('hidden');
setTimeout(() => {
errorMessage.classList.add('hidden');
}, 3000);
}
let cooldownInterval;
function startCooldown() {
incrementBtn.disabled = true;
let secondsLeft = 30;
timerDisplay.classList.remove('hidden');
timerDisplay.innerText = `Wait ${secondsLeft}s`;
clearInterval(cooldownInterval);
cooldownInterval = setInterval(() => {
secondsLeft--;
timerDisplay.innerText = `Wait ${secondsLeft}s`;
if (secondsLeft <= 0) {
clearInterval(cooldownInterval);
incrementBtn.disabled = false;
timerDisplay.classList.add('hidden');
}
}, 1000);
}