Vibe Code Time Counter
Wiki topics:
💻 · Programming
Vibe Code Time Counter

<!DOCTYPE html>
<html lang="tr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Zamanlayıcı Arayüzü</title>
<link rel="stylesheet" href="style.css">
<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@400;500;700&display=swap" rel="stylesheet">
</head>
<body>
<div class="phone-wrapper">
<div class="preset-buttons">
<button class="preset-btn" data-time="5">5 mins</button>
<button class="preset-btn" data-time="10">10 mins</button>
<button class="preset-btn active" data-time="20">20 mins</button>
</div>
<div class="timer-app">
<div class="time-display">
<p class="timer-label">Timer</p>
<h1 id="time-left">20:00</h1>
<button id="stop-btn">Stop</button>
</div>
<div class="progress-container">
<div class="progress-circle-bg">
<div id="progress-spinner"></div>
<div class="progress-inner-circle">
<button id="pause-play-btn">
<div class="icon pause-icon">
<div class="pause-bar"></div>
<div class="pause-bar"></div>
</div>
<div class="icon play-icon" style="display: none;"></div>
</button>
</div>
</div>
</div>
</div>
<div class="home-indicator"></div>
</div>
<script src="script.js"></script>
</body>
</html>
:root {
--bg-gray: #E1E2E6;
--app-bg: #1C1C1E;
--widget-bg: #003865;
--text-primary: #FFFFFF;
--text-secondary: #8E8E93;
--button-inactive: #5A5A5E;
--button-active: #0A84FF; /* A slightly brighter blue for better visibility */
--button-stop: #3A3A3C;
--progress-bar: #50E3C2;
--progress-track: #2E6C91;
--font-family: 'Inter', system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
}
body {
background-color: var(--bg-gray);
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
font-family: var(--font-family);
margin: 0;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.phone-wrapper {
display: flex;
flex-direction: column;
align-items: center;
gap: 16px;
padding: 20px;
}
.preset-buttons {
display: flex;
gap: 12px;
}
.preset-btn {
border: none;
padding: 8px 18px;
border-radius: 16px;
font-size: 14px;
font-weight: 500;
color: var(--text-primary);
background-color: var(--button-inactive);
cursor: pointer;
transition: background-color 0.2s ease, transform 0.1s ease;
}
.preset-btn:active {
transform: scale(0.95);
}
.preset-btn.active {
background-color: var(--button-active);
}
.timer-app {
width: 380px;
height: 180px;
background-color: var(--app-bg);
border-radius: 28px;
padding: 20px 25px;
display: flex;
justify-content: space-between;
align-items: center;
box-shadow: 0 10px 30px rgba(0,0,0,0.1);
box-sizing: border-box;
}
.time-display {
display: flex;
flex-direction: column;
align-items: flex-start;
justify-content: space-between;
height: 100%;
color: var(--text-primary);
}
.timer-label {
font-size: 16px;
font-weight: 500;
color: var(--text-secondary);
margin: 0;
}
#time-left {
font-size: 60px;
font-weight: 700;
margin: 0;
line-height: 1;
letter-spacing: 1px;
}
#stop-btn {
border: none;
background-color: var(--button-stop);
color: var(--text-primary);
font-size: 16px;
font-weight: 500;
padding: 10px 24px;
border-radius: 12px;
cursor: pointer;
transition: background-color 0.2s ease;
}
#stop-btn:hover {
background-color: #4a4a4c;
}
.progress-container {
width: 140px;
height: 140px;
display: flex;
justify-content: center;
align-items: center;
}
.progress-circle-bg {
width: 100%;
height: 100%;
background-color: var(--widget-bg);
border-radius: 24px;
display: flex;
justify-content: center;
align-items: center;
position: relative;
}
#progress-spinner {
position: absolute;
width: 110px;
height: 110px;
border-radius: 50%;
background: conic-gradient(var(--progress-bar) 0deg, var(--progress-track) 0deg);
transition: background 0.2s linear;
}
.progress-inner-circle {
width: 80px;
height: 80px;
background-color: #000000;
border-radius: 50%;
position: relative;
z-index: 1;
display: flex;
justify-content: center;
align-items: center;
}
#pause-play-btn {
width: 100%;
height: 100%;
background: none;
border: none;
cursor: pointer;
padding: 0;
display: flex;
justify-content: center;
align-items: center;
}
.icon {
color: white;
}
.pause-icon {
width: 20px;
height: 24px;
display: flex;
justify-content: space-between;
align-items: center;
}
.pause-bar {
width: 6px;
height: 100%;
background-color: var(--text-primary);
border-radius: 2px;
}
.play-icon {
width: 0;
height: 0;
border-top: 12px solid transparent;
border-bottom: 12px solid transparent;
border-left: 20px solid var(--text-primary);
margin-left: 5px; /* Visual centering */
}
.home-indicator {
width: 134px;
height: 5px;
background-color: #000000;
border-radius: 100px;
opacity: 0.8;
}
document.addEventListener('DOMContentLoaded', () => {
const timeLeftDisplay = document.getElementById('time-left');
const stopBtn = document.getElementById('stop-btn');
const pausePlayBtn = document.getElementById('pause-play-btn');
const spinner = document.getElementById('progress-spinner');
const presetBtns = document.querySelectorAll('.preset-btn');
const pauseIcon = document.querySelector('.pause-icon');
const playIcon = document.querySelector('.play-icon');
let countdown;
let totalTime = 0;
let remainingTime = 0;
let isPaused = false;
function startTimer(minutes) {
// Clear any existing timer
clearInterval(countdown);
// Update active button
presetBtns.forEach(btn => {
btn.classList.remove('active');
if (parseInt(btn.dataset.time) === minutes) {
btn.classList.add('active');
}
});
totalTime = minutes * 60;
remainingTime = totalTime;
isPaused = false;
updateDisplay(remainingTime);
updateSpinner(remainingTime);
showPauseIcon();
countdown = setInterval(() => {
if (!isPaused) {
remainingTime--;
updateDisplay(remainingTime);
updateSpinner(remainingTime);
if (remainingTime <= 0) {
clearInterval(countdown);
}
}
}, 1000);
}
function updateDisplay(seconds) {
const mins = Math.floor(seconds / 60);
const secs = seconds % 60;
timeLeftDisplay.textContent = `${String(mins).padStart(2, '0')}:${String(secs).padStart(2, '0')}`;
}
function updateSpinner(seconds) {
if (totalTime === 0) return;
const percentage = ((totalTime - seconds) / totalTime) * 100;
const degrees = percentage * 3.6;
spinner.style.background = `conic-gradient(var(--progress-bar) ${degrees}deg, var(--progress-track) ${degrees}deg)`;
}
function stopTimer() {
clearInterval(countdown);
remainingTime = totalTime; // Reset to initial time of the active preset
isPaused = true;
updateDisplay(remainingTime);
updateSpinner(remainingTime);
showPlayIcon();
}
function togglePause() {
if (remainingTime <= 0) return; // Don't do anything if timer is finished
isPaused = !isPaused;
if (isPaused) {
showPlayIcon();
} else {
showPauseIcon();
}
}
function showPlayIcon() {
pauseIcon.style.display = 'none';
playIcon.style.display = 'block';
}
function showPauseIcon() {
pauseIcon.style.display = 'flex';
playIcon.style.display = 'none';
}
// Event Listeners
presetBtns.forEach(button => {
button.addEventListener('click', () => {
const time = parseInt(button.dataset.time);
startTimer(time);
});
});
stopBtn.addEventListener('click', stopTimer);
pausePlayBtn.addEventListener('click', togglePause);
// Initial state
startTimer(20); // Start with 20 minutes as in the picture
togglePause(); // Start in a paused-like state until user interacts
});
[embed]
메타데이터
- post_id
- 679078e791e7
- slug
- vibe-code-time-counter-679078e791e7
- url
- https://medium.com/@ebarslann/vibe-code-time-counter-679078e791e7
- canonical_url
- https://medium.com/@ebarslann/vibe-code-time-counter-679078e791e7
- author_url
- https://medium.com/@ebarslann
- status
- ok
- fetched_at
- 2026-06-26 21:52:29