Ç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>


