Pomodoro

Çalışma süresi tamamlandığında, bir sonraki başlayıncaya kadar Alarmın sürekli olarak çalması ayarlandı. Zaman anlamında; "Saat, Dakika, Saniye" olarak süre ayarlanabilir. Mola süresi dakika olarak belirleyebilir. "Çalışma+Mola" süresinin kaç tekrar yapması gerektiğini de, "Döngü" ile tanımlayabilirsiniz. "Uygula/sıfırla" butonuna basarak tüm seçimleri aktif edebilirsiniz.

Mola süresi ve Döngü tekrarı yer almaktadır. Bir sonraki başlayıncaya kadar alarmın çalması ayarlandı.

Döngülerde tamamlandığında, "Tamamlandı" bilgisi ile, zaman döngüsü sonlanır.


HTML Kod:
<!DOCTYPE html>
<html lang="tr">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Pomodoro - Zaman Yönetimi</title>
    <style>
        /* Temel Ayarlar ve Beyaz Tema */
        * {
            box-sizing: border-box;
            margin: 0;
            padding: 0;
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
        }

        body {
            background-color: #f5f6fa;
            color: #2f3640;
            display: flex;
            justify-content: center;
            align-items: center;
            min-height: 100vh;
        }

        .container {
            background-color: #ffffff;
            /* Dikey boşluklar daha da azaltıldı */
            padding: 18px 25px;
            border-radius: 18px;
            box-shadow: 0 10px 30px rgba(0, 0, 0, 0.08);
            width: 100%;
            max-width: 500px;
            text-align: center;
        }

        /* Ayar Paneli ve Başlık Kapsayıcısı */
        .settings-wrapper {
            background: #f1f2f6;
            padding: 8px 12px; 
            border-radius: 10px;
            margin-bottom: 12px; 
            width: 100%;
        }

        .main-title {
            font-size: 24px; 
            font-weight: 900; 
            text-align: center;
            color: #2f3640;
            margin-bottom: 6px; 
            letter-spacing: 0.5px;
            border-bottom: 2px solid #dcdde1;
            padding-bottom: 6px; 
            width: 100%;
            white-space: nowrap; 
            overflow: hidden;
            text-overflow: ellipsis;
        }

        .settings-panel {
            display: flex;
            justify-content: space-between;
            gap: 10px;
        }

        .setting-group {
            display: flex;
            flex-direction: column;
            align-items: center;
            flex: 1;
        }

        .setting-group label {
            font-size: 12px; 
            font-weight: 800; 
            color: #2f3640; 
            text-transform: uppercase;
            letter-spacing: 0.5px; 
            margin-bottom: 3px; 
        }

        .input-row {
            display: flex;
            gap: 4px;
            align-items: center;
        }

        input[type="number"] {
            width: 40px;
            padding: 3px; 
            border: 1px solid #dcdde1;
            border-radius: 5px;
            text-align: center;
            font-weight: 600;
            color: #2f3640;
            background: #ffffff;
            outline: none;
            transition: border-color 0.3s;
        }

        input[type="number"]:focus {
            border-color: #1dd1a1;
        }

        .colon { font-weight: bold; color: #718093; }

        /* Döngü Durum Göstergesi */
        .cycle-status {
            font-size: 14px;
            font-weight: 600;
            margin-bottom: 10px; 
            color: #7f8fa6;
        }

        /* Daire ve Zamanlayıcı Alanı */
        .timer-wrapper {
            position: relative;
            width: 230px; /* Dikey alan kazanmak için çember boyutu optimize edildi */
            height: 230px;
            margin: 0 auto 12px auto; 
        }

        .progress-ring {
            width: 100%;
            height: 100%;
        }

        .progress-ring__track {
            stroke: #f1f2f6;
            stroke-width: 22;
            fill: transparent;
        }

        .progress-ring__thin-track {
            stroke: #1dd1a1;
            stroke-width: 4;
            fill: transparent;
            transition: stroke 0.5s ease;
        }

        .progress-ring__circle {
            stroke: #1dd1a1;
            stroke-width: 22;
            fill: transparent;
            stroke-linecap: round;
            transform: rotate(-90deg);
            transform-origin: 50% 50%;
            transition: stroke-dashoffset 1s linear, stroke 0.5s ease;
        }

        /* Ortadaki Dijital Saat */
        .timer-text {
            position: absolute;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            display: flex;
            flex-direction: column;
            align-items: center;
        }

        #time-display {
            font-size: 44px; 
            font-weight: 700;
            color: #2f3640;
            line-height: 1;
            margin-bottom: 4px;
        }

        #mode-label {
            font-size: 13px;
            color: #1dd1a1;
            text-transform: uppercase;
            letter-spacing: 2px;
            font-weight: 700;
            transition: color 0.5s ease;
        }

        /* Kontrol Butonları */
        .controls {
            display: flex;
            gap: 12px;
            justify-content: center;
        }

        button {
            border: none;
            padding: 8px 20px; 
            font-size: 13px;
            font-weight: 700;
            border-radius: 7px;
            cursor: pointer;
            transition: all 0.3s ease;
            text-transform: uppercase;
        }

        .btn-primary {
            background-color: #1dd1a1;
            color: #ffffff;
            box-shadow: 0 4px 12px rgba(29, 209, 161, 0.3);
        }

        .btn-primary:hover {
            background-color: #10ac84;
            transform: translateY(-2px);
        }

        .btn-secondary {
            background-color: #f1f2f6;
            color: #718093;
        }

        .btn-secondary:hover {
            background-color: #dcdde1;
            color: #2f3640;
        }

        /* MOLA MODU (Kırmızı Geçişleri) */
        .break-mode .progress-ring__circle { stroke: #ff6b6b; }
        .break-mode .progress-ring__thin-track { stroke: #ff6b6b; } 
        .break-mode #mode-label { color: #ff6b6b; }
        .break-mode .btn-primary { background-color: #ff6b6b; box-shadow: 0 4px 12px rgba(255, 107, 107, 0.3); }
        .break-mode .btn-primary:hover { background-color: #ee5253; }

        /* TAMAMLANDI MODU (Turuncu Geçişleri) */
        .completed-mode .progress-ring__circle { stroke: #ff9f43; }
        .completed-mode .progress-ring__thin-track { stroke: #ff9f43; } 
        .completed-mode #mode-label { color: #ff9f43; }
        .completed-mode .btn-primary { background-color: #ff9f43; box-shadow: 0 4px 12px rgba(255, 159, 67, 0.3); }
        .completed-mode .btn-primary:hover { background-color: #e67e22; }

        /* İmza (Yazar Bilgisi) */
        .designer-credit {
            margin-top: 15px;
            font-size: 11px;
            font-weight: 600;
            color: #a4b0be; 
            letter-spacing: 0.5px;
        }

    </style>
</head>
<body>

    <div class="container" id="app-container">
        
        <div class="settings-wrapper">
            <h1 class="main-title">Pomodoro - Zaman Yönetimi</h1>
            
            <div class="settings-panel">
                <div class="setting-group">
                    <label>Çalışma</label>
                    <div class="input-row">
                        <input type="number" id="work-h" placeholder="S" min="0" max="23" value="0" title="Saat"> <span class="colon">:</span>
                        <input type="number" id="work-m" placeholder="D" min="0" max="59" value="25" title="Dakika"> <span class="colon">:</span>
                        <input type="number" id="work-s" placeholder="S" min="0" max="59" value="0" title="Saniye">
                    </div>
                </div>
                
                <div class="setting-group">
                    <label>Mola (Dk)</label>
                    <div class="input-row">
                        <input type="number" id="break-m" min="1" max="60" value="5">
                    </div>
                </div>

                <div class="setting-group">
                    <label>Döngü</label>
                    <div class="input-row">
                        <input type="number" id="cycles-input" min="1" max="10" value="4">
                    </div>
                </div>
            </div>
        </div>

        <div class="cycle-status" id="cycle-display">Döngü: 1 / 4</div>

        <div class="timer-wrapper">
            <svg class="progress-ring" viewBox="0 0 300 300">
                <circle class="progress-ring__track" cx="150" cy="150" r="125"></circle>
                <circle class="progress-ring__thin-track" cx="150" cy="150" r="125"></circle>
                <circle class="progress-ring__circle" cx="150" cy="150" r="125"></circle>
            </svg>
            <div class="timer-text">
                <div id="time-display">25:00</div>
                <div id="mode-label">ÇALIŞMA</div>
            </div>
        </div>

        <div class="controls">
            <button id="start-btn" class="btn-primary">Başlat</button>
            <button id="reset-btn" class="btn-secondary">Uygula / Sıfırla</button>
        </div>

        <div class="designer-credit">
            AI Web Designer: Muhammed Yusuf OLGUN
        </div>
    </div>

    <script>
        const appContainer = document.getElementById('app-container');
        const timeDisplay = document.getElementById('time-display');
        const modeLabel = document.getElementById('mode-label');
        const cycleDisplay = document.getElementById('cycle-display');
        const startBtn = document.getElementById('start-btn');
        const resetBtn = document.getElementById('reset-btn');
        const circle = document.querySelector('.progress-ring__circle');

        const inputWorkH = document.getElementById('work-h');
        const inputWorkM = document.getElementById('work-m');
        const inputWorkS = document.getElementById('work-s');
        const inputBreakM = document.getElementById('break-m');
        const inputCycles = document.getElementById('cycles-input');

        const radius = circle.r.baseVal.value;
        const circumference = radius * 2 * Math.PI;
        circle.style.strokeDasharray = `${circumference} ${circumference}`;
        circle.style.strokeDashoffset = 0;

        let isRunning = false;
        let isWorkMode = true;
        let timerInterval;
        let timeRemaining = 0;
        let totalTime = 0;
        let currentCycle = 1;
        let totalCycles = 4;

        let isAlarmRinging = false;
        let alarmLoop;

        function getSettings() {
            const wH = parseInt(inputWorkH.value) || 0;
            const wM = parseInt(inputWorkM.value) || 0;
            const wS = parseInt(inputWorkS.value) || 0;
            const bM = parseInt(inputBreakM.value) || 0;
            
            const workSeconds = (wH * 3600) + (wM * 60) + wS;
            const breakSeconds = (bM * 60);
            totalCycles = parseInt(inputCycles.value) || 1;

            return { workSeconds, breakSeconds };
        }

        function updateDisplay() {
            const h = Math.floor(timeRemaining / 3600);
            const m = Math.floor((timeRemaining % 3600) / 60);
            const s = timeRemaining % 60;
            
            if (h > 0) {
                timeDisplay.textContent = `${h.toString().padStart(2, '0')}:${m.toString().padStart(2, '0')}:${s.toString().padStart(2, '0')}`;
            } else {
                timeDisplay.textContent = `${m.toString().padStart(2, '0')}:${s.toString().padStart(2, '0')}`;
            }
            cycleDisplay.textContent = `Döngü: ${currentCycle} / ${totalCycles}`;
        }

        function updateProgressCircle() {
            const percent = timeRemaining / totalTime;
            const offset = circumference - (percent * circumference);
            circle.style.strokeDashoffset = offset;
        }

        function playAlarmSound() {
            const audioCtx = new (window.AudioContext || window.webkitAudioContext)();
            const now = audioCtx.currentTime;
            
            for (let i = 0; i < 4; i++) {
                const oscillator = audioCtx.createOscillator();
                const gainNode = audioCtx.createGain();
                
                oscillator.connect(gainNode);
                gainNode.connect(audioCtx.destination);
                
                oscillator.type = 'square';
                oscillator.frequency.setValueAtTime(850, now);
                
                const startTime = now + (i * 0.25);
                const duration = 0.1;
                
                gainNode.gain.setValueAtTime(0, startTime);
                gainNode.gain.linearRampToValueAtTime(0.5, startTime + 0.02);
                gainNode.gain.exponentialRampToValueAtTime(0.001, startTime + duration);
                
                oscillator.start(startTime);
                oscillator.stop(startTime + duration);
            }
        }

        function startContinuousAlarm() {
            isAlarmRinging = true;
            playAlarmSound(); 
            alarmLoop = setInterval(playAlarmSound, 2000); 
        }

        function stopContinuousAlarm() {
            if (isAlarmRinging) {
                isAlarmRinging = false;
                clearInterval(alarmLoop);
            }
        }

        function prepareNextSession() {
            const settings = getSettings();
            
            if (isWorkMode) {
                isWorkMode = false;
                timeRemaining = settings.breakSeconds;
                totalTime = settings.breakSeconds;
                modeLabel.textContent = 'MOLA';
                appContainer.classList.add('break-mode');
                updateDisplay();
                updateProgressCircle();
                startBtn.textContent = 'Başlat';
            } else {
                if (currentCycle < totalCycles) {
                    currentCycle++;
                    isWorkMode = true;
                    timeRemaining = settings.workSeconds;
                    totalTime = settings.workSeconds;
                    modeLabel.textContent = 'ÇALIŞMA';
                    appContainer.classList.remove('break-mode');
                    updateDisplay();
                    updateProgressCircle();
                    startBtn.textContent = 'Başlat';
                } else {
                    modeLabel.textContent = 'TAMAMLANDI!';
                    appContainer.classList.remove('break-mode');
                    appContainer.classList.add('completed-mode'); 
                    
                    timeDisplay.textContent = '00:00';
                    circle.style.strokeDashoffset = 0; 
                    startBtn.textContent = 'SIFIRLA';
                    return;
                }
            }
        }

        function startTimer() {
            if (isRunning) return;
            
            if (timeRemaining <= 0) {
                applySettings();
                return;
            }

            isRunning = true;
            startBtn.textContent = 'Duraklat';

            timerInterval = setInterval(() => {
                if (timeRemaining > 0) {
                    timeRemaining--;
                    updateDisplay();
                    updateProgressCircle();
                } else {
                    clearInterval(timerInterval);
                    isRunning = false;
                    startContinuousAlarm();
                    prepareNextSession(); 
                }
            }, 1000);
        }

        function pauseTimer() {
            clearInterval(timerInterval);
            isRunning = false;
            startBtn.textContent = 'Devam Et';
        }

        function applySettings() {
            stopContinuousAlarm(); 
            clearInterval(timerInterval);
            isRunning = false;
            isWorkMode = true;
            currentCycle = 1;
            
            const settings = getSettings();
            timeRemaining = settings.workSeconds;
            totalTime = settings.workSeconds;
            
            appContainer.classList.remove('break-mode', 'completed-mode'); 
            modeLabel.textContent = 'ÇALIŞMA';
            startBtn.textContent = 'Başlat';
            
            updateDisplay();
            updateProgressCircle();
        }

        startBtn.addEventListener('click', () => {
            if (isAlarmRinging) {
                stopContinuousAlarm();
                if (modeLabel.textContent !== 'TAMAMLANDI!') {
                    startTimer(); 
                } else {
                    applySettings();
                }
            } else if (isRunning) {
                pauseTimer();
            } else {
                startTimer();
            }
        });

        resetBtn.addEventListener('click', applySettings);

        applySettings();
    </script>
</body>
</html>