Som robil svoju prvú vlastnú webovú aplikáciu určenú, pre odpočet dní a hodín do ďalších Vianoc. Áno, inšpirovala vianočná nálada mojej ženy.

Vymyslel som si zadanie:

  • Nastaviť 5 pozadí, ktoré sa budú meniť po 10 minútach
  • V pozadí bude hrať vianočná hudba – (Viac playlistov)
  • Bude tam možnosť si zvoliť časové pásmo
  • Zvoliť si prepočet na dni a hodiny
  • Bude možné hudbu zastaviť, stíšiť, znovu spustiť
  • Tlačidlo bude buď zelené -(Hudba hrá)
  • Tlačidlo bude červené – (hudba nehrá)
  • Vyvorenei favicon

Vytvoril som priečinok

mdkir christmas-countdown

Do priečinka som vytvoril textové súbory

  • Dockerfile
  • docker-compose.yaml
  • index.html
  • script.js
  • style.css
  • citaj

A zložky, do ktorých som vložil obrázky a hudbu

  • jpg som pomenoval: christmas1.jpg, christmas2.jpg, christmas3.jpg, christmas4.jpg, christmas5.jpg
  • mp3 som urobil niekoľko hodinový súbor a pomenoval christmas01.mp3.
  • favicon uložil som favicon.png

Ďalej do vytvorených súborov som napísal kódy prostredníctvom buď vim, alebo nano:

Dockerfile

FROM nginx:alpine
# Skopíruj všetky súbory do Nginxu
COPY . /usr/share/nginx/html/
# Tento riadok zabezpečí, že Nginx bude posielať správne hlavičky pre JS
RUN sed -i '/types {/a \    application/javascript js;' /etc/nginx/nginx.conf

docker-compose.yaml

services:
  web:
    image: nginx:alpine
    ports:
      - "3010:80"  # port Vianoce
    volumes:
      - /home/ivan/christmas-countdown:/usr/share/nginx/html:ro
    restart: always

script.js



document.addEventListener('DOMContentLoaded', () => {
console.log("Vianočný web: Plná verzia so všetkými funkciami.");
// --- ELEMENTY ---
const timerDisplay = document.getElementById('timer');
const musicBtn = document.getElementById('music-btn');
const audio = document.getElementById('bg-music');
const playlistSelect = document.getElementById('playlist-select');
const volumeSlider = document.getElementById('volume-slider');
const btnDays = document.getElementById('btn-days');
const btnHours = document.getElementById('btn-hours');
const timezoneSelect = document.getElementById('timezone-select');

// --- 1. NÁHODNÉ POZADIE ---
const backgrounds = ['jpg/christmas1.jpg', 'jpg/christmas2.jpg', 'jpg/christmas3.jpg', 'jpg/christmas4.jpg', 'jpg/christmas5.jpg'];
document.body.style.backgroundImage = `url('${backgrounds[Math.floor(Math.random() * backgrounds.length)]}')`;

// --- 2. HUDBA A PLAYLISTY ---
const updateButtonUI = () => {
    if (!musicBtn) return;
    if (audio.paused) {
        musicBtn.innerText = "🎶 ZAPNÚŤ HUDBU";
        musicBtn.style.setProperty('background-color', '#ff4d4d', 'important');
    } else {
        musicBtn.innerText = "⏸ POZASTAVIŤ";
        musicBtn.style.setProperty('background-color', '#28a745', 'important');
    }
};

// Obsluha tlačidla Play/Pause
musicBtn.addEventListener('click', () => {
    if (!audio.src || audio.src.endsWith('/')) {
        audio.src = playlistSelect.value;
    }
    if (audio.paused) {
        audio.play().then(updateButtonUI).catch(() => alert("Klikni najprv na plochu!"));
    } else {
        audio.pause();
        updateButtonUI();
    }
});

// OPRAVA PREKLIKÁVANIA PLAYLISTOV
playlistSelect.addEventListener('change', () => {
    const wasPlaying = !audio.paused;
    audio.src = playlistSelect.value;
    audio.load();
    if (wasPlaying) {
        audio.play().then(updateButtonUI);
    } else {
        updateButtonUI();
    }
});

// Hlasitosť
if (volumeSlider) {
    audio.volume = volumeSlider.value;
    volumeSlider.addEventListener('input', (e) => {
        audio.volume = e.target.value;
    });
}

// --- 3. ODPOČET A ČASOVÉ PÁSMA ---
let viewMode = 'days'; 

const updateCountdown = () => {
    if (!timerDisplay) return;

    // Funkčné časové pásmo
    const tz = timezoneSelect ? timezoneSelect.value : "Europe/Bratislava";
    const now = new Date(new Date().toLocaleString("en-US", {timeZone: tz}));

    let target = new Date(now.getFullYear(), 11, 24, 0, 0, 0);
    if (now > target) target.setFullYear(target.getFullYear() + 1);

    const diff = target - now;

    if (viewMode === 'days') {
        const d = Math.floor(diff / 86400000);
        const h = Math.floor((diff / 3600000) % 24);
        const m = Math.floor((diff / 60000) % 60);
        const s = Math.floor((diff / 1000) % 60);
        timerDisplay.innerText = `${d}d ${h}h ${m}m ${s}s`;
    } else {
        const hTotal = Math.floor(diff / 3600000);
        const m = Math.floor((diff / 60000) % 60);
        const s = Math.floor((diff / 1000) % 60);
        timerDisplay.innerText = `${hTotal.toLocaleString()}h ${m}m ${s}s`;
    }
};

if (timezoneSelect) timezoneSelect.addEventListener('change', updateCountdown);

btnDays.addEventListener('click', () => {
    viewMode = 'days';
    btnDays.classList.add('active');
    btnHours.classList.remove('active');
    updateCountdown();
});
btnHours.addEventListener('click', () => {
    viewMode = 'hours';
    btnHours.classList.add('active');
    btnDays.classList.remove('active');
    updateCountdown();
});

setInterval(updateCountdown, 1000);
updateCountdown();

// --- 4. SNEŽENIE ---
setInterval(() => {
    const snow = document.createElement('div');
    snow.className = 'snowflake';
    snow.innerHTML = '❄';
    snow.style.left = Math.random() * 100 + 'vw';
    snow.style.animation = `fall ${Math.random() * 3 + 2}s linear forwards`;
    document.body.appendChild(snow);
    setTimeout(() => snow.remove(), 5000);
}, 200);
});

index.html

<!DOCTYPE html>
<html lang="sk">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Vianočný Odpočet — ibasterisk.eu</title>
    <link rel="stylesheet" href="style.css">
    <link rel="icon" type="image/png" href="favicon/favicon.png">
</head>
<body>
    <div id="snow-container"></div>

    <div class="container">
        <h1>🎅 Vianočný Odpočet</h1>

        <div id="countdown">
            <span id="timer">Načítavam...</span>
        </div>

        <div class="view-toggle">
            <button id="btn-days" class="active">Dni</button>
            <button id="btn-hours">Hodiny</button>
        </div>

        <div class="controls-group">
            <label>Časové pásmo:</label>
            <select id="timezone-select">
                <option value="Europe/Bratislava">🇸🇰 Slovensko</option>
                <option value="Asia/Tokyo">🇯🇵 Tokio (Japonsko)</option>
                <option value="Europe/Moscow">🇷🇺 Moskva (Rusko)</option>
                <option value="Australia/Sydney">🇦🇺 Sydney (Austrália)</option>
            </select>
        </div>

        <div class="controls-group">
            <label>Vyber Playlist:</label>
            <select id="playlist-select">
                <option value="mp3/christmas01.mp3">Vianočný Mix 01</option>
                <option value="mp3/buble1.mp3">Michael Bublé 1</option>
                <option value="mp3/buble2.mp3">Michael Bublé 2</option>
                <option value="mp3/top20.mp3">Vianočná Top 20</option>
            </select>
        </div>

        <button id="music-btn" class="btn-stopped">🎶 Zapnúť hudbu</button>

        <div class="volume-container">
            <label>Hlasitosť</label>
            <input type="range" id="volume-slider" min="0" max="1" step="0.1" value="0.5">
        </div>

        <audio id="bg-music" loop></audio>
    </div>

    <script src="script.js"></script>
</body>
</html>

style.css

body {
    margin: 0; padding: 0;
    width: 100vw; height: 100vh;
    display: flex; justify-content: center; align-items: center;
    background-size: cover; background-position: center;
    background-color: #1a1a1a;
    font-family: 'Segoe UI', Arial, sans-serif;
    transition: background-image 2s ease-in-out;
    overflow: hidden;
}

.container {
    background: rgba(0, 0, 0, 0.8);
    backdrop-filter: blur(10px);
    padding: 30px; border-radius: 25px;
    color: white; text-align: center; width: 350px;
    position: relative; z-index: 10;
    box-shadow: 0 10px 30px rgba(0,0,0,0.5);
}

#timer {
    font-size: 2rem; font-weight: bold; color: #ff4d4d;
    display: block; margin: 20px 0;
}

.view-toggle { display: flex; justify-content: center; margin-bottom: 20px; }
.view-toggle button {
    background: #444; color: white; border: none;
    padding: 10px 20px; cursor: pointer; transition: 0.3s;
}
.view-toggle button.active { background: #ff4d4d !important; }
.view-toggle button:first-child { border-radius: 10px 0 0 10px; }
.view-toggle button:last-child { border-radius: 0 10px 10px 0; }

select {
    width: 100%; padding: 12px; border-radius: 10px;
    background: #222; color: white; margin-bottom: 15px; border: 1px solid #444;
}

#music-btn {
    width: 100%; padding: 15px; border-radius: 15px;
    border: none; color: white; font-weight: bold;
    cursor: pointer; text-transform: uppercase;
}

.btn-stopped { background-color: #ff4d4d !important; }
.btn-playing { background-color: #28a745 !important; }

.snowflake {
    position: fixed; top: -10px; color: white !important;
    z-index: 1000; pointer-events: none;
    animation: fall linear forwards;
}

@keyframes fall {
    to { transform: translateY(105vh); }
}

.volume-container input { width: 100%; accent-color: #ff4d4d; margin-top: 10px; 
}

citaj

Tento súbor, nieje dôležitý na koľko sú to len moje poznámky

Následne som spustil kontajner

sudo docker-compose down
sudo docker-compose up --build -d