commit 53a9634926ab3ee9b7e75484b2dfbf244a1e8f7a Author: lelgenio <lelgenio@lelgenio.com> Date: Fri Mar 21 19:26:18 2025 -0300 initial commit diff --git a/README.md b/README.md new file mode 100644 index 0000000..636597b --- /dev/null +++ b/README.md @@ -0,0 +1,35 @@ +# Contador da Viagem + +Um site simples que mostra um contador regressivo até uma data específica. Exibe dias, horas, minutos e segundos restantes. + +## Funcionalidades + +- Contador regressivo em tempo real +- Exibição de dias, horas, minutos e segundos +- Mensagem especial quando a data já passou +- Efeito de fogos de artifício quando a data alvo é alcançada +- Design responsivo para dispositivos móveis +- Fácil personalização da data alvo + +## Como usar + +1. Clone este repositório ou baixe os arquivos +2. Abra o arquivo `index.html` em qualquer navegador + +## Personalizando a data alvo + +Para alterar a data do contador, edite a linha 3 no arquivo `script.js`: + +```javascript +const targetDate = new Date(2023, 11, 31, 0, 0, 0).getTime(); +``` + +O formato é: `new Date(ano, mês-1, dia, hora, minuto, segundo)` + +**Observação:** O mês começa em 0 (janeiro = 0, fevereiro = 1, ..., dezembro = 11) + +## Tecnologias utilizadas + +- HTML5 +- CSS3 +- JavaScript (vanilla) \ No newline at end of file diff --git a/index.html b/index.html new file mode 100644 index 0000000..8ba3a86 --- /dev/null +++ b/index.html @@ -0,0 +1,47 @@ +<!DOCTYPE html> +<html lang="pt-BR"> + +<head> + <meta charset="UTF-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <title>Contador da Viagem</title> + <link rel="stylesheet" href="styles.css"> +</head> + +<body> + <canvas id="fireworks-canvas"></canvas> + <div class="container"> + <h1>Contador até a viagem</h1> + <div id="countdown-container"> + <div class="countdown"> + <div class="time-section"> + <div id="days" class="time-value">00</div> + <div class="time-label">Dias</div> + </div> + <div class="separator">:</div> + <div class="time-section"> + <div id="hours" class="time-value">00</div> + <div class="time-label">Horas</div> + </div> + <div class="separator">:</div> + <div class="time-section"> + <div id="minutes" class="time-value">00</div> + <div class="time-label">Minutos</div> + </div> + <div class="separator">:</div> + <div class="time-section"> + <div id="seconds" class="time-value">00</div> + <div class="time-label">Segundos</div> + </div> + </div> + <div id="expired-message" class="hidden">Estou indo para Santana!</div> + </div> + <div class="target-date-container"> + <p>Contando até: <span id="target-date">10 de Abril de 2025</span></p> + </div> + </div> + + <script src="script.js"></script> +</body> + +</html> \ No newline at end of file diff --git a/script.js b/script.js new file mode 100644 index 0000000..4b90bac --- /dev/null +++ b/script.js @@ -0,0 +1,228 @@ +// Target date for countdown (YYYY, Month-1, Day, Hour, Minute, Second) +// Default date is set to December 31, 2023 +let targetDate = new Date(2025, 3, 10, 0, 0, 0).getTime(); + +const test = true; + +if (test) { + // Para teste: descomentar a linha abaixo para simular que a data já passou + // targetDate = new Date().getTime() - 1000; // 1 segundo no passado + targetDate = new Date(2025, 2, 10, 0, 0, 0).getTime(); +} + +// Update the target date display +document.getElementById('target-date').textContent = new Date(targetDate).toLocaleDateString('pt-BR', { + day: 'numeric', + month: 'long', + year: 'numeric' +}); + +// Elements +const daysElement = document.getElementById('days'); +const hoursElement = document.getElementById('hours'); +const minutesElement = document.getElementById('minutes'); +const secondsElement = document.getElementById('seconds'); +const countdownElement = document.querySelector('.countdown'); +const expiredMessageElement = document.getElementById('expired-message'); +const canvas = document.getElementById('fireworks-canvas'); +const body = document.body; + +// Fireworks variables +let context; +let fireworks = []; +let particles = []; +let fireworksActive = false; + +// Canvas setup +function setupCanvas() { + if (!canvas) return; + + context = canvas.getContext('2d'); + canvas.width = window.innerWidth; + canvas.height = window.innerHeight; + + // Event to resize canvas when window resizes + window.addEventListener('resize', () => { + canvas.width = window.innerWidth; + canvas.height = window.innerHeight; + }); +} + +// Firework class +class Firework { + constructor() { + this.x = Math.random() * canvas.width; + this.y = canvas.height; + this.targetX = Math.random() * canvas.width; + this.targetY = Math.random() * canvas.height / 2; + this.speed = 2 + Math.random() * 3; + this.angle = Math.atan2(this.targetY - this.y, this.targetX - this.x); + this.velocityX = Math.cos(this.angle) * this.speed; + this.velocityY = Math.sin(this.angle) * this.speed; + this.size = 2; + this.color = `hsl(${Math.random() * 360}, 100%, 50%)`; + this.particleCount = 80 + Math.floor(Math.random() * 40); + } + + update() { + this.x += this.velocityX; + this.y += this.velocityY; + + // Check if firework reached its target + if (Math.abs(this.x - this.targetX) < 10 && Math.abs(this.y - this.targetY) < 10) { + this.explode(); + return false; + } + return true; + } + + explode() { + for (let i = 0; i < this.particleCount; i++) { + particles.push(new Particle(this.x, this.y, this.color)); + } + } + + draw() { + context.fillStyle = this.color; + context.beginPath(); + context.arc(this.x, this.y, this.size, 0, Math.PI * 2); + context.fill(); + } +} + +// Particle class (for explosion) +class Particle { + constructor(x, y, color) { + this.x = x; + this.y = y; + this.velocityX = (Math.random() - 0.5) * 5; + this.velocityY = (Math.random() - 0.5) * 5; + this.size = Math.random() * 3; + this.color = color; + this.alpha = 1; + this.gravity = 0.05; + this.resistance = 0.92; + } + + update() { + this.velocityX *= this.resistance; + this.velocityY *= this.resistance; + this.velocityY += this.gravity; + + this.x += this.velocityX; + this.y += this.velocityY; + this.alpha -= 0.01; + + return this.alpha > 0; + } + + draw() { + context.globalAlpha = this.alpha; + context.fillStyle = this.color; + context.beginPath(); + context.arc(this.x, this.y, this.size, 0, Math.PI * 2); + context.fill(); + context.globalAlpha = 1; + } +} + +// Animation loop for fireworks +function animateFireworks() { + if (!fireworksActive) return; + + requestAnimationFrame(animateFireworks); + + context.fillStyle = 'rgba(0, 0, 0, 0.1)'; + context.fillRect(0, 0, canvas.width, canvas.height); + + // Random chance to create a new firework + if (fireworks.length < 5 && Math.random() < 0.03) { + fireworks.push(new Firework()); + } + + // Update and draw fireworks + fireworks = fireworks.filter(firework => { + firework.draw(); + return firework.update(); + }); + + // Update and draw particles + particles = particles.filter(particle => { + particle.draw(); + return particle.update(); + }); +} + +// Start fireworks +function startFireworks() { + if (fireworksActive) return; + + setupCanvas(); + fireworksActive = true; + body.classList.add('fireworks-active'); + animateFireworks(); +} + +// Update the countdown every second +function updateCountdown() { + // Get the current date and time + const now = new Date().getTime(); + + // Find the distance between now and the target date + const distance = targetDate - now; + + // Check if the target date has passed + if (distance < 0) { + // Hide countdown and show expired message + countdownElement.classList.add('hidden'); + expiredMessageElement.classList.remove('hidden'); + startFireworks(); + return; + } + + // Time calculations for days, hours, minutes and seconds + const days = Math.floor(distance / (1000 * 60 * 60 * 24)); + const hours = Math.floor((distance % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60)); + const minutes = Math.floor((distance % (1000 * 60 * 60)) / (1000 * 60)); + const seconds = Math.floor((distance % (1000 * 60)) / 1000); + + // Display the results + daysElement.innerHTML = days.toString().padStart(2, '0'); + hoursElement.innerHTML = hours.toString().padStart(2, '0'); + minutesElement.innerHTML = minutes.toString().padStart(2, '0'); + secondsElement.innerHTML = seconds.toString().padStart(2, '0'); +} + +// Initial call to set correct values +updateCountdown(); + +// Update the countdown every second +const countdownInterval = setInterval(updateCountdown, 1000); + +// Function to change the target date +function changeTargetDate(newDate) { + // You can call this function to change the target date dynamically + targetDate = new Date(newDate).getTime(); + + // Update the target date display + document.getElementById('target-date').textContent = new Date(targetDate).toLocaleDateString('pt-BR', { + day: 'numeric', + month: 'long', + year: 'numeric' + }); + + // Reset the countdown display + countdownElement.classList.remove('hidden'); + expiredMessageElement.classList.add('hidden'); + + // Reset fireworks if active + if (fireworksActive) { + fireworksActive = false; + body.classList.remove('fireworks-active'); + fireworks = []; + particles = []; + } + + // Update the countdown immediately + updateCountdown(); +} \ No newline at end of file diff --git a/styles.css b/styles.css new file mode 100644 index 0000000..51462a5 --- /dev/null +++ b/styles.css @@ -0,0 +1,144 @@ +* { + margin: 0; + padding: 0; + box-sizing: border-box; +} + +body { + font-family: 'Arial', sans-serif; + background-color: #f0f8ff; + color: #333; + min-height: 100vh; + display: flex; + justify-content: center; + align-items: center; + position: relative; + overflow: hidden; +} + +#fireworks-canvas { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + z-index: -1; + pointer-events: none; + display: none; +} + +.fireworks-active #fireworks-canvas { + display: block; +} + +.fireworks-active { + background-color: #000; +} + +.fireworks-active .container { + background-color: rgba(255, 255, 255, 0.8); +} + +.fireworks-active #expired-message { + color: #ff3b00; + text-shadow: 0 0 10px rgba(255, 59, 0, 0.5); +} + +.container { + text-align: center; + padding: 2rem; + background-color: white; + border-radius: 10px; + box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1); + max-width: 800px; + width: 90%; + z-index: 1; +} + +h1 { + margin-bottom: 2rem; + color: #2c3e50; + font-size: 2.5rem; +} + +.countdown { + display: flex; + justify-content: center; + align-items: center; + margin: 2rem 0; +} + +.time-section { + display: flex; + flex-direction: column; + align-items: center; + margin: 0 0.5rem; +} + +.time-value { + font-size: 3.5rem; + font-weight: bold; + background-color: #2c3e50; + color: white; + border-radius: 8px; + padding: 0.5rem 1rem; + min-width: 120px; +} + +.time-label { + margin-top: 0.5rem; + font-size: 1rem; + text-transform: uppercase; + letter-spacing: 1px; + color: #7f8c8d; +} + +.separator { + font-size: 3.5rem; + font-weight: bold; + color: #2c3e50; + margin: 0 0.25rem; + align-self: flex-start; + padding-top: 0.5rem; +} + +#expired-message { + font-size: 2rem; + font-weight: bold; + color: #e74c3c; + margin: 2rem 0; +} + +.hidden { + display: none; +} + +.target-date-container { + font-size: 1.2rem; + color: #7f8c8d; + margin-top: 2rem; +} + +#target-date { + font-weight: bold; + color: #3498db; +} + +@media (max-width: 768px) { + .countdown { + flex-wrap: wrap; + } + + .time-value { + font-size: 2.5rem; + min-width: 80px; + } + + .separator { + font-size: 2.5rem; + } + + .time-section { + margin: 0.5rem; + } +} \ No newline at end of file