ol / index.html
thiago12345678's picture
Otimize imagens (use WebP, compressão, lazy loading), minimize CSS/JS, use cache,Isso melhora SEO e acessibilidade,Use media queries, flexbox ou grid, ajuste fontes/tamanhos para mobile,Use ferramentas como Lighthouse, axe, ou o audit do Chrome DevTools,Verifique se cada página tem título único e descrição,Se usar bibliotecas, carregue de forma assíncrona ou somente quando preciso,Por exemplo, mostrar mensagem amigável se API não responder, usar placeholders de imagem - Follow Up Deployment
e98fff6 verified
<!DOCTYPE html>
<html lang="pt-BR">
<head>
<meta name="description" content="Marcador de pontos moderno para o jogo de Truco Paulista. Controle as pontuações, rodadas e históricos de forma simples e intuitiva.">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=5.0">
<meta http-equiv="Cache-Control" content="public, max-age=31536000">
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Marcador de Truco Moderno</title>
<script src="https://cdn.tailwindcss.com"></script>
<script async>
tailwind.config = {
theme: {
extend: {
colors: {
primary: {
50: '#f0f9ff',
100: '#e0f2fe',
200: '#bae6fd',
300: '#7dd3fc',
400: '#38bdf8',
500: '#0ea5e9',
600: '#0284c7',
700: '#0369a1',
800: '#075985',
900: '#0c4a6e',
},
secondary: {
50: '#fdf2f8',
100: '#fce7f3',
200: '#fbcfe8',
300: '#f9a8d4',
400: '#f472b6',
500: '#ec4899',
600: '#db2777',
700: '#be185d',
800: '#9d174d',
900: '#831843',
},
dark: {
50: '#f8fafc',
100: '#f1f5f9',
200: '#e2e8f0',
300: '#cbd5e1',
400: '#94a3b8',
500: '#64748b',
600: '#475569',
700: '#334155',
800: '#1e293b',
900: '#0f172a',
}
},
fontFamily: {
sans: ['Inter', 'sans-serif'],
},
}
}
}
</script>
<link rel="preload" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
<noscript><link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"></noscript>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap" rel="stylesheet" media="print" onload="this.media='all'">
<style media="print" onload="this.media='all'">
.gradient-bg {
background: linear-gradient(135deg, #0f172a 0%, #1e293b 100%);
}
@media (max-width: 768px) {
.score-display {
font-size: 3rem;
}
.team-card {
padding: 1.5rem;
}
.btn-action {
padding: 0.75rem;
font-size: 0.9rem;
}
}
.team-card {
background: rgba(255, 255, 255, 0.05);
backdrop-filter: blur(10px);
border: 1px solid rgba(255, 255, 255, 0.1);
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}
.team-card:hover {
transform: translateY(-5px);
box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.2), 0 10px 10px -5px rgba(0, 0, 0, 0.1);
}
.score-display {
font-size: clamp(3rem, 8vw, 5rem);
font-size: 5rem;
background: linear-gradient(135deg, #0ea5e9 0%, #ec4899 100%);
-webkit-background-clip: text;
background-clip: text;
color: transparent;
text-shadow: 0 2px 10px rgba(14, 165, 233, 0.2);
}
.btn-primary {
background: linear-gradient(135deg, #0ea5e9 0%, #0284c7 100%);
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}
.btn-primary:hover {
transform: translateY(-2px);
box-shadow: 0 10px 15px -3px rgba(14, 165, 233, 0.3);
}
.btn-secondary {
background: linear-gradient(135deg, #ec4899 0%, #db2777 100%);
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}
.btn-secondary:hover {
transform: translateY(-2px);
box-shadow: 0 10px 15px -3px rgba(236, 72, 153, 0.3);
}
.btn-danger {
background: linear-gradient(135deg, #ef4444 0%, #dc2626 100%);
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}
.btn-danger:hover {
transform: translateY(-2px);
box-shadow: 0 10px 15px -3px rgba(239, 68, 68, 0.3);
}
.btn-action:active {
transform: scale(0.95);
}
.truco-btn {
animation: pulse 2s infinite;
background: linear-gradient(135deg, #f59e0b 0%, #d97706 100%);
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}
.truco-btn:hover {
transform: translateY(-2px);
box-shadow: 0 10px 15px -3px rgba(245, 158, 11, 0.3);
}
@keyframes pulse {
0% { transform: scale(1); }
50% { transform: scale(1.05); }
100% { transform: scale(1); }
}
.modal {
background: rgba(15, 23, 42, 0.8);
backdrop-filter: blur(5px);
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}
.modal-content {
background: linear-gradient(135deg, #1e293b 0%, #0f172a 100%);
border: 1px solid rgba(255, 255, 255, 0.1);
}
.history-item {
background: rgba(255, 255, 255, 0.05);
border: 1px solid rgba(255, 255, 255, 0.1);
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}
.history-item:hover {
transform: translateY(-2px);
background: rgba(255, 255, 255, 0.1);
}
.input-modern {
background: rgba(255, 255, 255, 0.05);
border: 1px solid rgba(255, 255, 255, 0.1);
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}
.input-modern:focus {
outline: none;
border-color: #0ea5e9;
box-shadow: 0 0 0 3px rgba(14, 165, 233, 0.3);
}
.select-modern {
background: rgba(255, 255, 255, 0.05);
border: 1px solid rgba(255, 255, 255, 0.1);
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}
.select-modern:focus {
outline: none;
border-color: #0ea5e9;
box-shadow: 0 0 0 3px rgba(14, 165, 233, 0.3);
}
.glow {
box-shadow: 0 0 15px rgba(14, 165, 233, 0.5);
}
</style>
</head>
<body class="min-h-screen gradient-bg font-sans text-white">
<div class="container mx-auto px-4 py-8">
<div class="text-center mb-10">
<h1 class="text-5xl font-bold mb-2 bg-clip-text text-transparent bg-gradient-to-r from-primary-400 to-secondary-500">TRUCO PAULISTA</h1>
<p class="text-lg text-gray-300">Marcador de pontos moderno</p>
</div>
<div class="flex flex-col lg:flex-row gap-8 justify-center items-stretch">
<!-- Team 1 -->
<div class="team-card flex-1 rounded-2xl p-6 text-center">
<div class="mb-6">
<input type="text" id="team1-name" value="Nós"
class="input-modern text-3xl font-bold text-center w-full px-4 py-2 rounded-lg bg-opacity-20 focus:bg-opacity-30">
</div>
<div class="score-display mb-8" id="team1-score">0</div>
<div class="grid grid-cols-3 gap-3 mb-6">
<button onclick="updateScore(1, 1)" class="btn-primary btn-action py-4 rounded-xl font-bold text-lg">
+1
</button>
<button onclick="updateScore(1, 3)" class="btn-secondary btn-action py-4 rounded-xl font-bold text-lg">
+3
</button>
<button onclick="updateScore(1, -1)" class="bg-dark-700 hover:bg-dark-600 btn-action py-4 rounded-xl font-bold text-lg">
-1
</button>
</div>
<button onclick="truco(1)" class="truco-btn w-full py-4 rounded-xl font-bold text-lg mb-4">
<i class="fas fa-bolt mr-2"></i> TRUCO!
</button>
<div class="flex justify-center space-x-3">
<button onclick="showTrucoModal(1)" class="bg-yellow-500 hover:bg-yellow-600 btn-action px-5 py-2.5 rounded-xl text-sm font-medium">
<i class="fas fa-exclamation-circle mr-1"></i> Falta
</button>
<button onclick="resetTeam(1)" class="bg-dark-700 hover:bg-dark-600 btn-action px-5 py-2.5 rounded-xl text-sm font-medium">
<i class="fas fa-redo mr-1"></i> Zerar
</button>
</div>
</div>
<!-- Game Info -->
<div class="flex flex-col justify-center items-center gap-6">
<div class="team-card rounded-2xl p-6 text-center w-full max-w-xs">
<h3 class="font-bold text-gray-300 mb-3">Rodada</h3>
<div class="text-5xl font-bold text-primary-400" id="round">1</div>
</div>
<div class="team-card rounded-2xl p-6 text-center w-full max-w-xs">
<h3 class="font-bold text-gray-300 mb-3">Melhor de</h3>
<select id="max-rounds" class="select-modern text-xl font-bold text-center w-full px-4 py-2 rounded-lg">
<option value="1">1</option>
<option value="3" selected>3</option>
<option value="5">5</option>
<option value="7">7</option>
</select>
</div>
<button onclick="newRound()" class="btn-primary btn-action py-4 px-8 rounded-xl font-bold text-lg">
<i class="fas fa-plus-circle mr-2"></i> Nova Rodada
</button>
<button onclick="resetGame()" class="bg-dark-700 hover:bg-dark-600 btn-action py-3 px-6 rounded-xl text-sm font-medium">
<i class="fas fa-trash-alt mr-1"></i> Reiniciar Jogo
</button>
</div>
<!-- Team 2 -->
<div class="team-card flex-1 rounded-2xl p-6 text-center">
<div class="mb-6">
<input type="text" id="team2-name" value="Eles"
class="input-modern text-3xl font-bold text-center w-full px-4 py-2 rounded-lg bg-opacity-20 focus:bg-opacity-30">
</div>
<div class="score-display mb-8" id="team2-score">0</div>
<div class="grid grid-cols-3 gap-3 mb-6">
<button onclick="updateScore(2, 1)" class="btn-primary btn-action py-4 rounded-xl font-bold text-lg">
+1
</button>
<button onclick="updateScore(2, 3)" class="btn-secondary btn-action py-4 rounded-xl font-bold text-lg">
+3
</button>
<button onclick="updateScore(2, -1)" class="bg-dark-700 hover:bg-dark-600 btn-action py-4 rounded-xl font-bold text-lg">
-1
</button>
</div>
<button onclick="truco(2)" class="truco-btn w-full py-4 rounded-xl font-bold text-lg mb-4">
<i class="fas fa-bolt mr-2"></i> TRUCO!
</button>
<div class="flex justify-center space-x-3">
<button onclick="showTrucoModal(2)" class="bg-yellow-500 hover:bg-yellow-600 btn-action px-5 py-2.5 rounded-xl text-sm font-medium">
<i class="fas fa-exclamation-circle mr-1"></i> Falta
</button>
<button onclick="resetTeam(2)" class="bg-dark-700 hover:bg-dark-600 btn-action px-5 py-2.5 rounded-xl text-sm font-medium">
<i class="fas fa-redo mr-1"></i> Zerar
</button>
</div>
</div>
</div>
<!-- History -->
<div class="mt-12">
<h2 class="text-3xl font-bold text-center mb-6 bg-clip-text text-transparent bg-gradient-to-r from-primary-400 to-secondary-500">
<i class="fas fa-history mr-3"></i>Histórico de Rodadas
</h2>
<div id="history" class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 xl:grid-cols-5 gap-5">
<!-- Rodadas serão adicionadas aqui -->
</div>
</div>
</div>
<!-- Truco Modal -->
<div id="truco-modal" class="modal fixed inset-0 flex items-center justify-center hidden z-50">
<div class="modal-content rounded-2xl p-8 w-full max-w-lg">
<h3 class="text-2xl font-bold text-center mb-6 text-primary-400">Pontuação do Truco</h3>
<div class="grid grid-cols-2 gap-4 mb-8">
<button onclick="acceptTruco(1)" class="btn-primary btn-action py-4 rounded-xl font-bold">
<i class="fas fa-check-circle mr-2"></i>Aceitar (+1)
</button>
<button onclick="acceptTruco(2)" class="btn-primary btn-action py-4 rounded-xl font-bold">
<i class="fas fa-check-circle mr-2"></i>Aceitar (+1)
</button>
<button onclick="rejectTruco(1)" class="btn-danger btn-action py-4 rounded-xl font-bold">
<i class="fas fa-times-circle mr-2"></i>Recusar (+1)
</button>
<button onclick="rejectTruco(2)" class="btn-danger btn-action py-4 rounded-xl font-bold">
<i class="fas fa-times-circle mr-2"></i>Recusar (+1)
</button>
<button onclick="raiseTruco(1)" class="truco-btn btn-action py-4 rounded-xl font-bold">
<i class="fas fa-arrow-up mr-2"></i>Aumentar (+3)
</button>
<button onclick="raiseTruco(2)" class="truco-btn btn-action py-4 rounded-xl font-bold">
<i class="fas fa-arrow-up mr-2"></i>Aumentar (+3)
</button>
</div>
<button onclick="hideTrucoModal()" class="bg-dark-700 hover:bg-dark-600 btn-action w-full py-3 rounded-xl font-medium">
<i class="fas fa-times mr-2"></i>Fechar
</button>
</div>
</div>
<!-- Falta Modal -->
<div id="falta-modal" class="modal fixed inset-0 flex items-center justify-center hidden z-50">
<div class="modal-content rounded-2xl p-8 w-full max-w-lg">
<h3 class="text-2xl font-bold text-center mb-4 text-primary-400">
<i class="fas fa-exclamation-triangle mr-2"></i>Falta
</h3>
<p class="text-center text-gray-300 mb-8">Quantos pontos faltam para o time vencer?</p>
<div class="grid grid-cols-2 gap-4 mb-8">
<button onclick="addFalta(1)" class="btn-primary btn-action py-4 rounded-xl font-bold">
Nós: +1
</button>
<button onclick="addFalta(2)" class="btn-primary btn-action py-4 rounded-xl font-bold">
Eles: +1
</button>
<button onclick="addFalta(0)" class="bg-indigo-500 hover:bg-indigo-600 btn-action py-4 rounded-xl font-bold">
Ambos: +1
</button>
<button onclick="addFalta(3)" class="btn-secondary btn-action py-4 rounded-xl font-bold">
Nós: +3
</button>
<button onclick="addFalta(4)" class="btn-secondary btn-action py-4 rounded-xl font-bold">
Eles: +3
</button>
<button onclick="addFalta(5)" class="bg-indigo-500 hover:bg-indigo-600 btn-action py-4 rounded-xl font-bold">
Ambos: +3
</button>
</div>
<button onclick="hideFaltaModal()" class="bg-dark-700 hover:bg-dark-600 btn-action w-full py-3 rounded-xl font-medium">
<i class="fas fa-times mr-2"></i>Fechar
</button>
</div>
</div>
<script defer>
// Game state
const gameState = {
team1: {
name: "Nós",
score: 0,
roundWins: 0
},
team2: {
name: "Eles",
score: 0,
roundWins: 0
},
currentRound: 1,
maxRounds: 3,
history: [],
trucoTeam: 0,
faltaTeam: 0
};
// Initialize the game
function initGame() {
updateScores();
updateRound();
updateHistory();
// Load from localStorage if available
const savedGame = localStorage.getItem('trucoGame');
if (savedGame) {
const parsed = JSON.parse(savedGame);
Object.assign(gameState, parsed);
document.getElementById('team1-name').value = gameState.team1.name;
document.getElementById('team2-name').value = gameState.team2.name;
document.getElementById('max-rounds').value = gameState.maxRounds;
updateScores();
updateRound();
updateHistory();
}
}
// Update team names
function updateTeamNames() {
gameState.team1.name = document.getElementById('team1-name').value;
gameState.team2.name = document.getElementById('team2-name').value;
saveGame();
}
// Update scores display
function updateScores() {
document.getElementById('team1-score').textContent = gameState.team1.score;
document.getElementById('team2-score').textContent = gameState.team2.score;
// Check for winner
checkWinner();
}
// Update round display
function updateRound() {
document.getElementById('round').textContent = gameState.currentRound;
gameState.maxRounds = parseInt(document.getElementById('max-rounds').value);
saveGame();
}
// Update history display
function updateHistory() {
const historyEl = document.getElementById('history');
historyEl.innerHTML = '';
gameState.history.forEach((round, index) => {
const roundEl = document.createElement('div');
roundEl.className = 'history-item p-5 rounded-xl';
roundEl.innerHTML = `
<h3 class="font-bold text-primary-400 mb-2">Rodada ${index + 1}</h3>
<div class="flex justify-between items-center">
<span class="text-sm text-gray-300">${gameState.team1.name}</span>
<span class="font-bold text-lg">${round.team1}</span>
</div>
<div class="flex justify-between items-center mt-2">
<span class="text-sm text-gray-300">${gameState.team2.name}</span>
<span class="font-bold text-lg">${round.team2}</span>
</div>
<div class="mt-3 pt-3 border-t border-gray-700 text-xs text-gray-400">
${new Date().toLocaleString()}
</div>
`;
historyEl.appendChild(roundEl);
});
}
// Update score for a team
function updateScore(team, points) {
if (team === 1) {
gameState.team1.score += points;
if (gameState.team1.score < 0) gameState.team1.score = 0;
} else {
gameState.team2.score += points;
if (gameState.team2.score < 0) gameState.team2.score = 0;
}
updateScores();
updateTeamNames();
saveGame();
// Add animation
const scoreEl = team === 1 ? document.getElementById('team1-score') : document.getElementById('team2-score');
scoreEl.classList.add('glow');
setTimeout(() => {
scoreEl.classList.remove('glow');
}, 1000);
}
// Truco action
function truco(team) {
gameState.trucoTeam = team;
showTrucoModal();
}
// Show truco modal
function showTrucoModal(team) {
if (typeof team !== 'undefined') {
gameState.faltaTeam = team;
document.getElementById('falta-modal').classList.remove('hidden');
} else {
document.getElementById('truco-modal').classList.remove('hidden');
}
}
// Hide truco modal
function hideTrucoModal() {
document.getElementById('truco-modal').classList.add('hidden');
}
// Hide falta modal
function hideFaltaModal() {
document.getElementById('falta-modal').classList.add('hidden');
}
// Accept truco
function acceptTruco(team) {
updateScore(team === gameState.trucoTeam ? gameState.trucoTeam : (gameState.trucoTeam === 1 ? 2 : 1), 1);
hideTrucoModal();
}
// Reject truco
function rejectTruco(team) {
updateScore(team === gameState.trucoTeam ? (gameState.trucoTeam === 1 ? 2 : 1) : gameState.trucoTeam, 1);
hideTrucoModal();
}
// Raise truco
function raiseTruco(team) {
updateScore(team === gameState.trucoTeam ? gameState.trucoTeam : (gameState.trucoTeam === 1 ? 2 : 1), 3);
hideTrucoModal();
}
// Add falta
function addFalta(type) {
switch(type) {
case 0: // Both +1
updateScore(1, 1);
updateScore(2, 1);
break;
case 1: // Team 1 +1
updateScore(1, 1);
break;
case 2: // Team 2 +1
updateScore(2, 1);
break;
case 3: // Team 1 +3
updateScore(1, 3);
break;
case 4: // Team 2 +3
updateScore(2, 3);
break;
case 5: // Both +3
updateScore(1, 3);
updateScore(2, 3);
break;
}
hideFaltaModal();
}
// Reset a team's score
function resetTeam(team) {
if (confirm(`Zerar a pontuação do time ${team === 1 ? gameState.team1.name : gameState.team2.name}?`)) {
if (team === 1) {
gameState.team1.score = 0;
} else {
gameState.team2.score = 0;
}
updateScores();
saveGame();
}
}
// Start a new round
function newRound() {
// Record current round scores
gameState.history.push({
team1: gameState.team1.score,
team2: gameState.team2.score
});
// Check for game winner
if (gameState.team1.roundWins >= Math.ceil(gameState.maxRounds / 2)) {
alert(`${gameState.team1.name} venceram o jogo!`);
resetGame();
return;
} else if (gameState.team2.roundWins >= Math.ceil(gameState.maxRounds / 2)) {
alert(`${gameState.team2.name} venceram o jogo!`);
resetGame();
return;
}
// Reset scores for new round
gameState.team1.score = 0;
gameState.team2.score = 0;
gameState.currentRound++;
updateScores();
updateRound();
updateHistory();
saveGame();
}
// Reset the entire game
function resetGame() {
if (confirm('Reiniciar todo o jogo? Isso apagará todo o histórico.')) {
gameState.team1.score = 0;
gameState.team2.score = 0;
gameState.team1.roundWins = 0;
gameState.team2.roundWins = 0;
gameState.currentRound = 1;
gameState.history = [];
updateScores();
updateRound();
updateHistory();
saveGame();
}
}
// Check for winner
function checkWinner() {
// Standard Truco is usually played to 12 points
if (gameState.team1.score >= 12) {
gameState.team1.roundWins++;
alert(`${gameState.team1.name} venceram a rodada!`);
newRound();
} else if (gameState.team2.score >= 12) {
gameState.team2.roundWins++;
alert(`${gameState.team2.name} venceram a rodada!`);
newRound();
}
}
// Save game to localStorage
function saveGame() {
localStorage.setItem('trucoGame', JSON.stringify(gameState));
}
// Initialize on load
document.addEventListener('DOMContentLoaded', initGame);
// Event listeners for team name changes
document.getElementById('team1-name').addEventListener('input', updateTeamNames);
document.getElementById('team2-name').addEventListener('input', updateTeamNames);
document.getElementById('max-rounds').addEventListener('change', updateRound);
// Service Worker registration for caching
if ('serviceWorker' in navigator) {
window.addEventListener('load', () => {
navigator.serviceWorker.register('/sw.js').then(registration => {
console.log('ServiceWorker registration successful');
}).catch(err => {
console.log('ServiceWorker registration failed: ', err);
});
});
}
</script>
<p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=thiago12345678/ol" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
</html>