diff --git a/Domains/Frontend/MiniProjects/Pomodoro/README.md b/Domains/Frontend/MiniProjects/Pomodoro/README.md new file mode 100644 index 00000000..2f242461 --- /dev/null +++ b/Domains/Frontend/MiniProjects/Pomodoro/README.md @@ -0,0 +1,232 @@ +# Pomodoro Timer + +A modern, SaaS-level Pomodoro timer application built with vanilla HTML, CSS, and JavaScript. Stay focused and boost productivity with customizable work and break intervals. + +## Features + +✨ **Modern UI Design** + +- Clean, professional interface with gradient background +- Smooth animations and transitions +- Fully responsive design (desktop, tablet, mobile) + +⏱️ **Timer Functionality** + +- Default 25-minute work sessions and 5-minute breaks +- Customizable work and break durations +- Real-time timer display with MM:SS format +- Session indicators showing work/break mode + +🎮 **Controls** + +- Start, Pause, and Reset buttons +- Resume functionality to continue paused sessions +- Automatic session switching between work and break + +📊 **Statistics & Tracking** + +- Track completed work sessions +- Monitor total focus time accumulated +- Stats update automatically after each work session + +🔊 **Audio Notifications** + +- Sound alert when sessions complete +- Smooth tone-based notification system + +## File Structure + +``` +pomodoro-timer/ +├── index.html # HTML markup and structure +├── styles.css # Styling, animations, and responsive design +├── script.js # Timer logic and interactivity +└── README.md # Project documentation +``` + +## Getting Started + +### Prerequisites + +- Any modern web browser (Chrome, Firefox, Safari, Edge) +- No additional dependencies or installation required + +### Installation + +1. Clone or download the project files: + +```bash +git clone +cd pomodoro-timer +``` + +2. Open the application: + + - Simply open `index.html` in your web browser + - Or use a local server for best results: + + ```bash + # Using Python 3 + python -m http.server 8000 + + # Using Python 2 + python -m SimpleHTTPServer 8000 + + # Using Node.js (http-server) + npx http-server + ``` + + - Then navigate to `http://localhost:8000` + +## Usage + +1. **Start a Session** + + - Click the "Start" button to begin a 25-minute work session + - Watch the timer count down in MM:SS format + +2. **Pause or Resume** + + - Click "Pause" to temporarily stop the timer + - Click "Resume" to continue where you left off + +3. **Reset Timer** + + - Click "Reset" to restart the current session + +4. **Customize Durations** + + - Enter desired minutes in the "Work Duration" input field + - Enter desired minutes in the "Break Duration" input field + - Click "Apply" to update the timer with new values + +5. **Track Progress** + + - View the count of completed work sessions + - Monitor accumulated focus time (displayed in hours) + - Stats update automatically when work sessions complete + +6. **Automatic Session Switching** + - When a work session completes, the timer automatically switches to break mode + - When a break completes, it automatically returns to work mode + - A notification sound plays when each session ends + +## How It Works + +The Pomodoro Technique is a time-management method that uses timed intervals: + +- Work for a focused period (default: 25 minutes) +- Take a short break (default: 5 minutes) +- Repeat the cycle + +This timer automates the process, helping you maintain focus and avoid burnout. + +## Customization + +### Change Default Durations + +Edit `script.js` and modify these variables: + +```javascript +let workDuration = 25; // Work session in minutes +let breakDuration = 5; // Break session in minutes +``` + +### Modify Colors and Theme + +Edit `styles.css` to change the design: + +```css +/* Primary gradient color */ +background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); + +/* Accent color */ +color: #667eea; +``` + +### Adjust Notification Sound + +Edit `script.js` in the `playNotification()` function: + +```javascript +oscillator.frequency.value = 800; // Frequency in Hz +gainNode.gain.setValueAtTime(0.3, audioContext.currentTime); // Volume +``` + +## Browser Compatibility + +- ✅ Chrome 90+ +- ✅ Firefox 88+ +- ✅ Safari 14+ +- ✅ Edge 90+ +- ✅ Mobile browsers (iOS Safari, Chrome Mobile) + +## Technical Details + +### Technologies Used + +- **HTML5** - Semantic markup and SVG +- **CSS3** - Flexbox, Grid, gradients, animations, and media queries +- **Vanilla JavaScript** - No frameworks or external dependencies + +### Key Features + +- Real-time timer with 1-second precision +- Web Audio API for notifications +- In-memory state management +- Mobile-first responsive design + +## Performance + +- Lightweight: ~15KB total (uncompressed) +- Instant load time +- Smooth animations +- Minimal memory footprint +- No external API calls or network requests + +## Accessibility + +- Semantic HTML structure +- High contrast color scheme +- Clear, descriptive button labels +- Visible visual feedback for interactions +- Responsive design for all screen sizes + +## Troubleshooting + +**Sound notification not playing?** + +- Check browser audio permissions +- Some browsers require user interaction before playing audio +- Ensure system volume is not muted + +**Timer not updating?** + +- Refresh the page +- Check browser console for errors +- Ensure JavaScript is enabled + +**Styling looks incorrect?** + +- Clear browser cache and refresh +- Try a different browser +- Verify CSS file is in the same directory as index.html + +## License + +This project is open-source and available for personal and commercial use. + +## Support + +For issues or questions: + +1. Check the troubleshooting section above +2. Review the code comments in `script.js` +3. Test in a different browser +4. Clear browser cache and retry + +--- + +**Happy focusing! 🍅⏲️** + +Use the Pomodoro Technique to boost your productivity and achieve your goals through structured, focused work sessions. diff --git a/Domains/Frontend/MiniProjects/Pomodoro/index.html b/Domains/Frontend/MiniProjects/Pomodoro/index.html new file mode 100644 index 00000000..e1e1e164 --- /dev/null +++ b/Domains/Frontend/MiniProjects/Pomodoro/index.html @@ -0,0 +1,97 @@ + + + + + + Pomodoro Timer + + + +
+
+

Pomodoro Timer

+

Stay focused, stay productive

+
+
Work
+
Break
+
+
+ + + + + + +
+
25:00
+
Work Session
+
+ +
+ + + +
+ +
+
+ +
+ + +
+
+ +
+ +
+ + +
+
+ +
+
+
0
+
Sessions
+
+
+
0h
+
Focus Time
+
+
+
+
+ + + + diff --git a/Domains/Frontend/MiniProjects/Pomodoro/script.js b/Domains/Frontend/MiniProjects/Pomodoro/script.js new file mode 100644 index 00000000..c4b9bb41 --- /dev/null +++ b/Domains/Frontend/MiniProjects/Pomodoro/script.js @@ -0,0 +1,169 @@ +let workDuration = 25; +let breakDuration = 5; +let timeLeft = workDuration * 60; +let isRunning = false; +let isWorkSession = true; +let timerInterval = null; +let sessionsCompleted = 0; +let totalFocusTime = 0; + +const timerDisplay = document.getElementById("timerDisplay"); +const timerLabel = document.getElementById("timerLabel"); +const startBtn = document.getElementById("startBtn"); +const pauseBtn = document.getElementById("pauseBtn"); +const progressCircle = document.getElementById("progressCircle"); +const workBadge = document.getElementById("workBadge"); +const breakBadge = document.getElementById("breakBadge"); + +const circumference = 2 * Math.PI * 90; +progressCircle.style.strokeDasharray = circumference; + +/** + * Updates the timer display with formatted time and progress ring + */ +function updateDisplay() { + const minutes = Math.floor(timeLeft / 60); + const seconds = timeLeft % 60; + timerDisplay.textContent = `${String(minutes).padStart(2, "0")}:${String( + seconds + ).padStart(2, "0")}`; + + const totalTime = isWorkSession ? workDuration * 60 : breakDuration * 60; + const progress = 1 - timeLeft / totalTime; + progressCircle.style.strokeDashoffset = circumference * (1 - progress); +} + +/** + * Updates the session badges and label + */ +function updateBadges() { + if (isWorkSession) { + workBadge.classList.add("active"); + breakBadge.classList.remove("active"); + timerLabel.textContent = "Work Session"; + } else { + breakBadge.classList.add("active"); + workBadge.classList.remove("active"); + timerLabel.textContent = "Break Time"; + } +} + +/** + * Starts the timer countdown + */ +function startTimer() { + if (isRunning) return; + isRunning = true; + startBtn.textContent = "Running"; + startBtn.disabled = true; + pauseBtn.disabled = false; + + timerInterval = setInterval(() => { + if (timeLeft > 0) { + timeLeft--; + updateDisplay(); + } else { + completeSession(); + } + }, 1000); +} + +/** + * Pauses the timer + */ +function pauseTimer() { + if (!isRunning) return; + isRunning = false; + clearInterval(timerInterval); + startBtn.textContent = "Resume"; + startBtn.disabled = false; + pauseBtn.disabled = true; +} + +/** + * Resets the timer to its initial state + */ +function resetTimer() { + isRunning = false; + clearInterval(timerInterval); + timeLeft = isWorkSession ? workDuration * 60 : breakDuration * 60; + updateDisplay(); + startBtn.textContent = "Start"; + startBtn.disabled = false; + pauseBtn.disabled = true; +} + +/** + * Handles session completion and switches between work/break + */ +function completeSession() { + clearInterval(timerInterval); + isRunning = false; + + if (isWorkSession) { + sessionsCompleted++; + totalFocusTime += workDuration; + document.getElementById("sessionsCompleted").textContent = + sessionsCompleted; + document.getElementById("focusTime").textContent = `${Math.floor( + totalFocusTime / 60 + )}h`; + } + + isWorkSession = !isWorkSession; + timeLeft = isWorkSession ? workDuration * 60 : breakDuration * 60; + updateDisplay(); + updateBadges(); + + startBtn.textContent = "Start"; + startBtn.disabled = false; + pauseBtn.disabled = true; + + playNotification(); +} + +/** + * Applies new duration settings and resets the timer + */ +function applySettings() { + const newWork = parseInt(document.getElementById("workDuration").value); + const newBreak = parseInt(document.getElementById("breakDuration").value); + + if (newWork > 0 && newWork <= 60) workDuration = newWork; + if (newBreak > 0 && newBreak <= 30) breakDuration = newBreak; + + resetTimer(); +} + +/** + * Plays a notification sound when a session completes + */ +function playNotification() { + try { + const audioContext = new (window.AudioContext || + window.webkitAudioContext)(); + const oscillator = audioContext.createOscillator(); + const gainNode = audioContext.createGain(); + + oscillator.connect(gainNode); + gainNode.connect(audioContext.destination); + + oscillator.frequency.value = 800; + oscillator.type = "sine"; + + gainNode.gain.setValueAtTime(0.3, audioContext.currentTime); + gainNode.gain.exponentialRampToValueAtTime( + 0.01, + audioContext.currentTime + 0.5 + ); + + oscillator.start(audioContext.currentTime); + oscillator.stop(audioContext.currentTime + 0.5); + } catch (e) { + console.log("Audio notification not supported"); + } +} + +// Initialize the timer display +updateDisplay(); +updateBadges(); diff --git a/Domains/Frontend/MiniProjects/Pomodoro/style.css b/Domains/Frontend/MiniProjects/Pomodoro/style.css new file mode 100644 index 00000000..32410b57 --- /dev/null +++ b/Domains/Frontend/MiniProjects/Pomodoro/style.css @@ -0,0 +1,275 @@ +* { + margin: 0; + padding: 0; + box-sizing: border-box; +} + +body { + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, + "Helvetica Neue", sans-serif; + background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); + display: flex; + justify-content: center; + align-items: center; + min-height: 100vh; + padding: 20px; +} + +.container { + background: white; + border-radius: 24px; + box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3); + padding: 60px 40px; + width: 100%; + max-width: 500px; + animation: slideIn 0.5s ease-out; +} + +@keyframes slideIn { + from { + opacity: 0; + transform: translateY(20px); + } + to { + opacity: 1; + transform: translateY(0); + } +} + +.header { + text-align: center; + margin-bottom: 40px; +} + +.title { + font-size: 28px; + font-weight: 700; + color: #2d3748; + margin-bottom: 8px; +} + +.subtitle { + font-size: 14px; + color: #a0aec0; +} + +.session-indicator { + display: flex; + justify-content: center; + gap: 8px; + margin-top: 20px; + flex-wrap: wrap; +} + +.session-badge { + padding: 6px 12px; + background: #f7fafc; + border-radius: 12px; + font-size: 12px; + font-weight: 600; + color: #718096; + text-transform: uppercase; + letter-spacing: 0.5px; +} + +.session-badge.active { + background: #667eea; + color: white; +} + +.timer-display { + text-align: center; + margin: 50px 0; +} + +.timer-text { + font-size: 72px; + font-weight: 700; + color: #2d3748; + font-variant-numeric: tabular-nums; + letter-spacing: -2px; +} + +.timer-label { + font-size: 14px; + color: #a0aec0; + margin-top: 12px; + text-transform: uppercase; + letter-spacing: 1px; +} + +.progress-ring { + width: 200px; + height: 200px; + margin: -100px auto 40px; + display: none; +} + +.progress-ring.active { + display: block; +} + +.progress-ring-circle { + transition: stroke-dashoffset 0.3s linear; + transform: rotate(-90deg); + transform-origin: 50% 50%; + stroke: #667eea; + stroke-width: 8; + fill: none; + stroke-linecap: round; +} + +.controls { + display: flex; + gap: 12px; + margin-bottom: 30px; +} + +button { + flex: 1; + padding: 14px 24px; + border: none; + border-radius: 12px; + font-size: 14px; + font-weight: 600; + cursor: pointer; + transition: all 0.2s ease; + text-transform: uppercase; + letter-spacing: 0.5px; +} + +.btn-primary { + background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); + color: white; +} + +.btn-primary:hover { + transform: translateY(-2px); + box-shadow: 0 8px 20px rgba(102, 126, 234, 0.4); +} + +.btn-primary:active { + transform: translateY(0); +} + +.btn-secondary { + background: #f7fafc; + color: #2d3748; +} + +.btn-secondary:hover { + background: #edf2f7; + transform: translateY(-2px); +} + +.btn-secondary:active { + transform: translateY(0); +} + +.settings { + background: #f7fafc; + border-radius: 16px; + padding: 24px; +} + +.setting-group { + margin-bottom: 20px; +} + +.setting-group:last-child { + margin-bottom: 0; +} + +.setting-label { + font-size: 12px; + font-weight: 600; + color: #718096; + text-transform: uppercase; + letter-spacing: 0.5px; + margin-bottom: 10px; + display: block; +} + +.input-group { + display: flex; + gap: 8px; + align-items: center; +} + +input[type="number"] { + flex: 1; + padding: 10px 12px; + border: 1px solid #e2e8f0; + border-radius: 8px; + font-size: 14px; + font-weight: 600; + color: #2d3748; +} + +input[type="number"]:focus { + outline: none; + border-color: #667eea; + box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1); +} + +.btn-small { + padding: 10px 12px; + background: white; + color: #2d3748; + border: 1px solid #e2e8f0; + border-radius: 8px; + font-weight: 600; + cursor: pointer; + transition: all 0.2s ease; +} + +.btn-small:hover { + background: #edf2f7; + border-color: #cbd5e0; +} + +.stats { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 16px; + margin-top: 24px; +} + +.stat { + background: white; + padding: 16px; + border-radius: 12px; + text-align: center; +} + +.stat-value { + font-size: 24px; + font-weight: 700; + color: #667eea; +} + +.stat-label { + font-size: 12px; + color: #a0aec0; + margin-top: 4px; + text-transform: uppercase; + letter-spacing: 0.5px; +} + +.hidden { + display: none; +} + +@media (max-width: 480px) { + .container { + padding: 40px 24px; + } + + .timer-text { + font-size: 56px; + } + + .title { + font-size: 24px; + } +}