google-site-verification: google61fe8ba583a51912.html
Digital Clock with Alarm System IN HTML CSS JAVASCRIPT WITH PHP AND MY SQL

Project Introduction

A comprehensive digital clock application with alarm system that displays current time, allows users to set multiple alarms, and provides a fully functional timer and stopwatch. This system includes a beautiful analog and digital clock display, alarm management, snooze functionality, and customizable themes. Perfect for websites needing time management features or as a standalone productivity tool.


✨ Features

Clock Display

  • Digital Clock: Real-time updating with multiple formats (12/24 hour)
  • Analog Clock: Beautiful SVG-based analog clock with smooth second hand
  • Date Display: Current date with day, month, and year
  • Timezone Support: Display time in different timezones
  • World Clocks: Add multiple clocks for different cities

Alarm System

  • Multiple Alarms: Set unlimited alarms with custom labels
  • Recurring Alarms: Daily, weekly, or custom recurrence patterns
  • Snooze Function: 5, 10, or 15 minute snooze options
  • Alarm Sounds: Multiple sound options or custom uploads
  • Gradual Volume: Volume increases gradually for gentle waking
  • Alarm History: Track triggered alarms

Timer

  • Countdown Timer: Set custom durations with presets
  • Pause/Resume: Control timer execution
  • Multiple Timers: Run several timers simultaneously
  • Timer Presets: Quick access to common durations
  • Timer Alerts: Visual and sound notifications

Stopwatch

  • Precise Timing: Accurate to 1/100 second
  • Lap/Split Times: Record and display lap times
  • Lap History: View previous lap times
  • Export Laps: Download lap data as CSV

Additional Features

  • Dark/Light Mode: Toggle between themes
  • Fullscreen Mode: Distraction-free display
  • Keyboard Shortcuts: Control everything with keyboard
  • Sound Customization: Volume control and sound selection
  • Data Persistence: Alarms saved in browser localStorage
  • Export/Import: Backup and restore alarm settings

📁 File Structure

blog-website/ │ ├── clock/ # Clock application directory │ ├── index.php # Main clock page │ ├── alarms.php # Alarm management │ ├── timer.php # Timer page │ ├── stopwatch.php # Stopwatch page │ ├── settings.php # User settings │ │ │ ├── includes/ # Core includes │ │ ├── clock-config.php # Configuration │ │ ├── clock-functions.php # Core functions │ │ └── alarm-handler.php # Alarm processing │ │ │ ├── css/ # Stylesheets │ │ ├── clock.css # Main clock styles │ │ └── analog-clock.css # Analog clock styles │ │ │ ├── js/ # JavaScript │ │ ├── clock.js # Core clock logic │ │ ├── analog-clock.js # Analog clock renderer │ │ ├── alarms.js # Alarm management │ │ ├── timer.js # Timer functionality │ │ └── stopwatch.js # Stopwatch logic │ │ │ ├── sounds/ # Alarm sounds │ │ ├── alarm-1.mp3 # Default alarm 1 │ │ ├── alarm-2.mp3 # Default alarm 2 │ │ ├── gentle.mp3 # Gentle wake sound │ │ └── notification.mp3 # Notification sound │ │ │ └── assets/ # Images and icons │ ├── clock-face.svg # Analog clock face │ └── icons/ # UI icons │ ├── .env # Environment variables │ └── database/ └── clock.sql # Database schema (optional)

🗄️ Database Schema (database/clock.sql) - Optional

-- Create clock database (optional - for server-side storage) CREATE DATABASE IF NOT EXISTS clock_db; USE clock_db; -- User alarms (if using server-side storage) CREATE TABLE IF NOT EXISTS user_alarms ( id INT AUTO_INCREMENT PRIMARY KEY, user_id INT NULL, -- If integrated with user system alarm_time TIME NOT NULL, days JSON, -- Days of week [1,2,3,4,5,6,0] (0 = Sunday) label VARCHAR(255), sound VARCHAR(100) DEFAULT 'alarm-1.mp3', is_active BOOLEAN DEFAULT TRUE, snooze_enabled BOOLEAN DEFAULT TRUE, snooze_duration INT DEFAULT 5, -- minutes volume INT DEFAULT 80, -- 0-100 created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, INDEX idx_user (user_id), INDEX idx_active (is_active) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; -- Alarm history CREATE TABLE IF NOT EXISTS alarm_history ( id BIGINT AUTO_INCREMENT PRIMARY KEY, alarm_id INT NULL, user_id INT NULL, triggered_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, action ENUM('dismissed', 'snoozed', 'triggered') DEFAULT 'triggered', snooze_count INT DEFAULT 0, INDEX idx_alarm (alarm_id), INDEX idx_user (user_id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; -- Timer presets CREATE TABLE IF NOT EXISTS timer_presets ( id INT AUTO_INCREMENT PRIMARY KEY, user_id INT NULL, name VARCHAR(100) NOT NULL, duration INT NOT NULL, -- in seconds created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, INDEX idx_user (user_id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; -- Settings CREATE TABLE IF NOT EXISTS user_settings ( id INT AUTO_INCREMENT PRIMARY KEY, user_id INT UNIQUE, time_format ENUM('12', '24') DEFAULT '12', theme ENUM('light', 'dark', 'auto') DEFAULT 'auto', default_sound VARCHAR(100) DEFAULT 'alarm-1.mp3', default_volume INT DEFAULT 80, snooze_default INT DEFAULT 5, show_seconds BOOLEAN DEFAULT TRUE, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

🔧 Core Files

1. clock/index.php (Main Clock Page)

<?php require_once '../includes/config.php'; $page_title = 'Digital Clock with Alarm System'; // Get user settings (from localStorage or cookies) $timeFormat = $_COOKIE['clock_time_format'] ?? '12'; $theme = $_COOKIE['clock_theme'] ?? 'auto'; include '../includes/header.php'; ?> <link rel="stylesheet" href="css/clock.css"> <link rel="stylesheet" href="css/analog-clock.css"> <div class="clock-container" data-theme="<?php echo $theme; ?>"> <!-- Header with Navigation --> <div class="clock-header"> <nav class="clock-nav"> <a href="index.php" class="nav-link active">Clock</a> <a href="alarms.php" class="nav-link">Alarms</a> <a href="timer.php" class="nav-link">Timer</a> <a href="stopwatch.php" class="nav-link">Stopwatch</a> <a href="settings.php" class="nav-link">Settings</a> </nav> <div class="header-controls"> <button class="theme-toggle" onclick="toggleTheme()" title="Toggle theme"> <span class="theme-icon">🌙</span> </button> <button class="fullscreen-toggle" onclick="toggleFullscreen()" title="Fullscreen"> <span class="fullscreen-icon">⛶</span> </button> </div> </div> <!-- Main Clock Display --> <div class="clock-main"> <!-- Analog Clock --> <div class="analog-clock-container"> <svg class="analog-clock" viewBox="0 0 200 200"> <!-- Clock face will be drawn by JavaScript --> </svg> </div> <!-- Digital Clock --> <div class="digital-clock-container"> <div class="time-display" id="digitalTime">--:--:--</div> <div class="date-display" id="digitalDate">---, -- --- ----</div> <!-- Time Format Toggle --> <div class="format-toggle"> <button class="format-btn <?php echo $timeFormat == '12' ? 'active' : ''; ?>" onclick="setTimeFormat('12')">12h</button> <button class="format-btn <?php echo $timeFormat == '24' ? 'active' : ''; ?>" onclick="setTimeFormat('24')">24h</button> </div> </div> </div> <!-- World Clocks (optional) --> <div class="world-clocks"> <h3>World Clocks</h3> <div class="clocks-grid" id="worldClocks"> <!-- Will be populated by JavaScript --> </div> <button class="add-clock-btn" onclick="addWorldClock()">+ Add City</button> </div> <!-- Upcoming Alarms --> <div class="upcoming-alarms"> <h3>Upcoming Alarms</h3> <div class="alarms-list" id="upcomingAlarms"> <!-- Will be populated by JavaScript --> </div> </div> </div> <!-- Alarm Notification Modal --> <div id="alarmModal" class="alarm-modal" style="display: none;"> <div class="alarm-modal-content"> <h2 id="alarmTitle">⏰ Alarm</h2> <p id="alarmMessage">Time to wake up!</p> <div class="alarm-actions"> <button class="dismiss-btn" onclick="dismissAlarm()">Dismiss</button> <button class="snooze-btn" onclick="snoozeAlarm()">Snooze <span id="snoozeTime">5</span> min</button> </div> </div> </div> <!-- Audio element for alarms --> <audio id="alarmSound" loop preload="auto"> <source src="sounds/alarm-1.mp3" type="audio/mpeg"> </audio> <script src="js/clock.js"></script> <script src="js/analog-clock.js"></script> <script> // Initialize clock on page load document.addEventListener('DOMContentLoaded', function() { initClock(<?php echo $timeFormat; ?>); initAnalogClock(); loadAlarms(); loadWorldClocks(); }); // Time format toggle function setTimeFormat(format) { document.cookie = `clock_time_format=${format}; path=/; max-age=31536000`; location.reload(); } // Theme toggle function toggleTheme() { const container = document.querySelector('.clock-container'); const currentTheme = container.dataset.theme; const newTheme = currentTheme === 'dark' ? 'light' : 'dark'; container.dataset.theme = newTheme; document.cookie = `clock_theme=${newTheme}; path=/; max-age=31536000`; // Update icon const icon = document.querySelector('.theme-icon'); icon.textContent = newTheme === 'dark' ? '☀️' : '🌙'; } // Fullscreen toggle function toggleFullscreen() { if (!document.fullscreenElement) { document.documentElement.requestFullscreen(); document.querySelector('.fullscreen-icon').textContent = '✕'; } else { if (document.exitFullscreen) { document.exitFullscreen(); document.querySelector('.fullscreen-icon').textContent = '⛶'; } } } // Keyboard shortcuts document.addEventListener('keydown', function(e) { // Space: Snooze (if alarm active) if (e.code === 'Space' && document.getElementById('alarmModal').style.display === 'block') { e.preventDefault(); snoozeAlarm(); } // Escape: Dismiss alarm if (e.code === 'Escape' && document.getElementById('alarmModal').style.display === 'block') { dismissAlarm(); } // F: Toggle fullscreen if (e.code === 'KeyF' && e.ctrlKey) { e.preventDefault(); toggleFullscreen(); } // T: Toggle theme if (e.code === 'KeyT' && e.ctrlKey) { e.preventDefault(); toggleTheme(); } }); </script> <style> .clock-container { max-width: 1200px; margin: 0 auto; padding: 2rem; min-height: 100vh; transition: background-color 0.3s, color 0.3s; } /* Light theme */ .clock-container[data-theme="light"] { background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%); color: #333; } /* Dark theme */ .clock-container[data-theme="dark"] { background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; } /* Auto theme (follows system) */ @media (prefers-color-scheme: dark) { .clock-container[data-theme="auto"] { background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; } } @media (prefers-color-scheme: light) { .clock-container[data-theme="auto"] { background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%); color: #333; } } .clock-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 3rem; padding: 1rem; background: rgba(255, 255, 255, 0.1); backdrop-filter: blur(10px); border-radius: 10px; } .clock-nav { display: flex; gap: 1rem; } .nav-link { padding: 0.5rem 1rem; color: inherit; text-decoration: none; border-radius: 5px; transition: background 0.3s; } .nav-link:hover { background: rgba(255, 255, 255, 0.2); } .nav-link.active { background: rgba(255, 255, 255, 0.3); font-weight: bold; } .header-controls { display: flex; gap: 0.5rem; } .theme-toggle, .fullscreen-toggle { background: none; border: none; color: inherit; font-size: 1.2rem; cursor: pointer; padding: 0.5rem; border-radius: 5px; transition: background 0.3s; } .theme-toggle:hover, .fullscreen-toggle:hover { background: rgba(255, 255, 255, 0.2); } .clock-main { display: grid; grid-template-columns: 1fr 1fr; gap: 3rem; align-items: center; margin-bottom: 3rem; } .analog-clock-container { display: flex; justify-content: center; align-items: center; } .analog-clock { width: 300px; height: 300px; } .digital-clock-container { text-align: center; } .time-display { font-size: 5rem; font-weight: bold; font-family: 'Digital', monospace; margin-bottom: 1rem; text-shadow: 2px 2px 4px rgba(0,0,0,0.3); } .date-display { font-size: 1.5rem; margin-bottom: 2rem; opacity: 0.9; } .format-toggle { display: flex; gap: 1rem; justify-content: center; } .format-btn { padding: 0.5rem 1.5rem; background: rgba(255, 255, 255, 0.2); border: none; color: inherit; border-radius: 5px; cursor: pointer; transition: all 0.3s; } .format-btn:hover { background: rgba(255, 255, 255, 0.3); } .format-btn.active { background: rgba(255, 255, 255, 0.4); font-weight: bold; } .world-clocks, .upcoming-alarms { background: rgba(255, 255, 255, 0.1); backdrop-filter: blur(10px); border-radius: 10px; padding: 1.5rem; margin-bottom: 2rem; } .world-clocks h3, .upcoming-alarms h3 { margin-bottom: 1rem; } .clocks-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: 1rem; margin-bottom: 1rem; } .world-clock-card { background: rgba(255, 255, 255, 0.1); padding: 1rem; border-radius: 5px; text-align: center; } .world-clock-card .city { font-weight: bold; margin-bottom: 0.5rem; } .world-clock-card .time { font-size: 1.2rem; font-family: 'Digital', monospace; } .world-clock-card .date { font-size: 0.8rem; opacity: 0.7; } .add-clock-btn { width: 100%; padding: 0.5rem; background: rgba(255, 255, 255, 0.2); border: 2px dashed rgba(255, 255, 255, 0.3); color: inherit; border-radius: 5px; cursor: pointer; transition: background 0.3s; } .add-clock-btn:hover { background: rgba(255, 255, 255, 0.3); } .alarms-list { display: flex; flex-direction: column; gap: 0.5rem; } .alarm-item { display: flex; justify-content: space-between; align-items: center; padding: 1rem; background: rgba(255, 255, 255, 0.1); border-radius: 5px; } .alarm-info { flex: 1; } .alarm-time { font-size: 1.2rem; font-weight: bold; margin-right: 1rem; } .alarm-label { opacity: 0.9; } .alarm-days { font-size: 0.8rem; opacity: 0.7; } .alarm-switch { position: relative; display: inline-block; width: 50px; height: 24px; } .alarm-switch input { opacity: 0; width: 0; height: 0; } .alarm-slider { position: absolute; cursor: pointer; top: 0; left: 0; right: 0; bottom: 0; background-color: rgba(255, 255, 255, 0.3); transition: 0.3s; border-radius: 24px; } .alarm-slider:before { position: absolute; content: ""; height: 20px; width: 20px; left: 2px; bottom: 2px; background-color: white; transition: 0.3s; border-radius: 50%; } input:checked + .alarm-slider { background-color: #4CAF50; } input:checked + .alarm-slider:before { transform: translateX(26px); } /* Alarm Modal */ .alarm-modal { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0, 0, 0, 0.8); z-index: 2000; display: flex; align-items: center; justify-content: center; } .alarm-modal-content { background: white; padding: 2rem; border-radius: 10px; max-width: 400px; width: 90%; text-align: center; animation: pulse 1s infinite; } @keyframes pulse { 0% { transform: scale(1); } 50% { transform: scale(1.05); } 100% { transform: scale(1); } } .alarm-modal-content h2 { color: #333; margin-bottom: 1rem; font-size: 2rem; } .alarm-modal-content p { color: #666; margin-bottom: 2rem; font-size: 1.2rem; } .alarm-actions { display: flex; gap: 1rem; justify-content: center; } .dismiss-btn, .snooze-btn { padding: 0.8rem 2rem; border: none; border-radius: 5px; font-size: 1rem; cursor: pointer; transition: opacity 0.3s; } .dismiss-btn { background: #dc3545; color: white; } .snooze-btn { background: #4CAF50; color: white; } .dismiss-btn:hover, .snooze-btn:hover { opacity: 0.9; } /* Responsive */ @media (max-width: 768px) { .clock-main { grid-template-columns: 1fr; gap: 2rem; } .time-display { font-size: 3rem; } .date-display { font-size: 1.2rem; } .analog-clock { width: 250px; height: 250px; } .clock-nav { flex-wrap: wrap; } } </style> <?php include '../includes/footer.php'; ?>

2. js/clock.js (Core Clock Logic)

/** * Core Clock Functionality */ let clockInterval; let timeFormat = 12; // 12 or 24 let currentTime = new Date(); let alarms = []; let activeAlarm = null; let snoozeTimeout = null; // Initialize clock function initClock(format) { timeFormat = format; updateClock(); startClock(); loadAlarmsFromStorage(); checkAlarms(); } // Start clock updates function startClock() { if (clockInterval) { clearInterval(clockInterval); } clockInterval = setInterval(updateClock, 1000); } // Stop clock updates function stopClock() { if (clockInterval) { clearInterval(clockInterval); clockInterval = null; } } // Update clock display function updateClock() { currentTime = new Date(); // Update digital clock updateDigitalClock(); // Update analog clock if (typeof updateAnalogClock === 'function') { updateAnalogClock(currentTime); } // Update world clocks updateWorldClocks(); // Check alarms every second checkAlarms(); } // Update digital clock display function updateDigitalClock() { const timeElement = document.getElementById('digitalTime'); const dateElement = document.getElementById('digitalDate'); if (!timeElement || !dateElement) return; // Format time let hours = currentTime.getHours(); let minutes = currentTime.getMinutes(); let seconds = currentTime.getSeconds(); let ampm = ''; if (timeFormat === 12) { ampm = hours >= 12 ? ' PM' : ' AM'; hours = hours % 12 || 12; } const timeString = `${padZero(hours)}:${padZero(minutes)}:${padZero(seconds)}${ampm}`; // Format date const options = { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' }; const dateString = currentTime.toLocaleDateString(undefined, options); timeElement.textContent = timeString; dateElement.textContent = dateString; } // Pad zero helper function padZero(num) { return num.toString().padStart(2, '0'); } // Alarm Management function loadAlarmsFromStorage() { const stored = localStorage.getItem('alarms'); if (stored) { try { alarms = JSON.parse(stored); updateAlarmsList(); } catch (e) { console.error('Failed to load alarms', e); alarms = []; } } } function saveAlarmsToStorage() { localStorage.setItem('alarms', JSON.stringify(alarms)); updateAlarmsList(); } function addAlarm(alarm) { // Generate ID alarm.id = Date.now() + Math.random().toString(36).substr(2, 9); // Ensure all fields alarm.time = alarm.time || '08:00'; alarm.days = alarm.days || [1,2,3,4,5]; // Monday-Friday by default alarm.label = alarm.label || 'Alarm'; alarm.sound = alarm.sound || 'alarm-1.mp3'; alarm.isActive = alarm.isActive !== false; alarm.snoozeEnabled = alarm.snoozeEnabled !== false; alarm.snoozeDuration = alarm.snoozeDuration || 5; alarm.volume = alarm.volume || 80; alarms.push(alarm); saveAlarmsToStorage(); return alarm.id; } function updateAlarm(id, updates) { const index = alarms.findIndex(a => a.id === id); if (index !== -1) { alarms[index] = { ...alarms[index], ...updates }; saveAlarmsToStorage(); } } function deleteAlarm(id) { alarms = alarms.filter(a => a.id !== id); saveAlarmsToStorage(); } function toggleAlarm(id) { const alarm = alarms.find(a => a.id === id); if (alarm) { alarm.isActive = !alarm.isActive; saveAlarmsToStorage(); } } // Update alarms list in UI function updateAlarmsList() { const container = document.getElementById('upcomingAlarms'); if (!container) return; if (alarms.length === 0) { container.innerHTML = '<p class="no-alarms">No alarms set</p>'; return; } // Sort alarms by time const sorted = [...alarms].sort((a, b) => { return a.time.localeCompare(b.time); }); let html = ''; sorted.forEach(alarm => { const [hours, minutes] = alarm.time.split(':'); const time12 = formatTime12(parseInt(hours), parseInt(minutes)); html += ` <div class="alarm-item"> <div class="alarm-info"> <span class="alarm-time">${time12}</span> <span class="alarm-label">${escapeHtml(alarm.label)}</span> <div class="alarm-days">${formatDays(alarm.days)}</div> </div> <label class="alarm-switch"> <input type="checkbox" ${alarm.isActive ? 'checked' : ''} onchange="toggleAlarm('${alarm.id}')"> <span class="alarm-slider"></span> </label> </div> `; }); container.innerHTML = html; } // Format days for display function formatDays(days) { if (!days || days.length === 0) return 'Once'; if (days.length === 7) return 'Every day'; const dayNames = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat']; const sorted = days.sort((a, b) => a - b); // Check for weekdays if (days.length === 5 && days.includes(1) && days.includes(2) && days.includes(3) && days.includes(4) && days.includes(5)) { return 'Weekdays'; } // Check for weekends if (days.length === 2 && days.includes(0) && days.includes(6)) { return 'Weekends'; } return sorted.map(d => dayNames[d]).join(', '); } // Format time in 12-hour format function formatTime12(hours, minutes) { const ampm = hours >= 12 ? 'PM' : 'AM'; const h = hours % 12 || 12; return `${h}:${padZero(minutes)} ${ampm}`; } // Check if alarm should trigger function checkAlarms() { const now = new Date(); const currentHours = now.getHours(); const currentMinutes = now.getMinutes(); const currentDay = now.getDay(); // 0 = Sunday alarms.forEach(alarm => { if (!alarm.isActive) return; const [alarmHours, alarmMinutes] = alarm.time.split(':').map(Number); // Check if time matches if (alarmHours === currentHours && alarmMinutes === currentMinutes) { // Check if day matches (if days specified) if (alarm.days && alarm.days.length > 0) { if (!alarm.days.includes(currentDay)) { return; } } // Trigger alarm triggerAlarm(alarm); } }); } // Trigger alarm function triggerAlarm(alarm) { // Don't trigger if already active if (activeAlarm) return; activeAlarm = alarm; // Show modal const modal = document.getElementById('alarmModal'); const title = document.getElementById('alarmTitle'); const message = document.getElementById('alarmMessage'); const snoozeSpan = document.getElementById('snoozeTime'); title.textContent = `⏰ ${alarm.label}`; message.textContent = `It's ${alarm.time}`; snoozeSpan.textContent = alarm.snoozeDuration; modal.style.display = 'flex'; // Play sound playAlarmSound(alarm); // Log alarm trigger logAlarmTrigger(alarm.id); } // Play alarm sound function playAlarmSound(alarm) { const audio = document.getElementById('alarmSound'); // Set sound source audio.src = `sounds/${alarm.sound}`; // Set volume audio.volume = alarm.volume / 100; // Play with gradual volume increase let currentVolume = 0.1; audio.volume = currentVolume; audio.play().catch(e => { console.error('Failed to play alarm sound', e); }); // Gradually increase volume const interval = setInterval(() => { if (currentVolume < alarm.volume / 100) { currentVolume += 0.1; audio.volume = Math.min(currentVolume, alarm.volume / 100); } else { clearInterval(interval); } }, 1000); // Store interval to clear later audio._volumeInterval = interval; } // Stop alarm sound function stopAlarmSound() { const audio = document.getElementById('alarmSound'); audio.pause(); audio.currentTime = 0; if (audio._volumeInterval) { clearInterval(audio._volumeInterval); } } // Dismiss alarm function dismissAlarm() { stopAlarmSound(); const modal = document.getElementById('alarmModal'); modal.style.display = 'none'; // Log dismissal if (activeAlarm) { logAlarmAction(activeAlarm.id, 'dismissed'); activeAlarm = null; } // Clear any snooze timeout if (snoozeTimeout) { clearTimeout(snoozeTimeout); snoozeTimeout = null; } } // Snooze alarm function snoozeAlarm() { if (!activeAlarm) return; stopAlarmSound(); const modal = document.getElementById('alarmModal'); modal.style.display = 'none'; const snoozeMinutes = activeAlarm.snoozeDuration || 5; // Set snooze timeout snoozeTimeout = setTimeout(() => { triggerAlarm(activeAlarm); snoozeTimeout = null; }, snoozeMinutes * 60 * 1000); // Log snooze logAlarmAction(activeAlarm.id, 'snoozed', snoozeMinutes); // Show snooze notification showNotification(`Alarm snoozed for ${snoozeMinutes} minutes`); } // Show notification function showNotification(message) { // Check if browser supports notifications if (!("Notification" in window)) return; if (Notification.permission === "granted") { new Notification("Clock Alarm", { body: message }); } else if (Notification.permission !== "denied") { Notification.requestPermission().then(permission => { if (permission === "granted") { new Notification("Clock Alarm", { body: message }); } }); } } // Log alarm trigger (for analytics) function logAlarmTrigger(alarmId) { console.log('Alarm triggered:', alarmId); // Could send to server if needed } function logAlarmAction(alarmId, action, snoozeMinutes) { console.log('Alarm action:', { alarmId, action, snoozeMinutes }); // Could send to server if needed } // World Clocks const worldClocks = [ { city: 'New York', timezone: 'America/New_York' }, { city: 'London', timezone: 'Europe/London' }, { city: 'Tokyo', timezone: 'Asia/Tokyo' }, { city: 'Sydney', timezone: 'Australia/Sydney' } ]; function loadWorldClocks() { const container = document.getElementById('worldClocks'); if (!container) return; updateWorldClocks(); } function updateWorldClocks() { const container = document.getElementById('worldClocks'); if (!container) return; let html = ''; worldClocks.forEach(clock => { try { const time = new Date().toLocaleString('en-US', { timeZone: clock.timezone, hour: '2-digit', minute: '2-digit', second: '2-digit', hour12: timeFormat === 12 }); const date = new Date().toLocaleString('en-US', { timeZone: clock.timezone, weekday: 'short', month: 'short', day: 'numeric' }); html += ` <div class="world-clock-card"> <div class="city">${clock.city}</div> <div class="time">${time}</div> <div class="date">${date}</div> </div> `; } catch (e) { console.error('Error with timezone:', clock.timezone); } }); container.innerHTML = html; } function addWorldClock() { const city = prompt('Enter city name:'); const timezone = prompt('Enter timezone (e.g., America/New_York):'); if (city && timezone) { worldClocks.push({ city, timezone }); updateWorldClocks(); } } // Utility function to escape HTML function escapeHtml(text) { const div = document.createElement('div'); div.textContent = text; return div.innerHTML; } // Request notification permission on load if ("Notification" in window) { if (Notification.permission === "default") { Notification.requestPermission(); } }

3. js/analog-clock.js (Analog Clock Renderer)

/** * Analog Clock SVG Renderer */ let clockSvg; let hourHand, minuteHand, secondHand; let clockFace; function initAnalogClock() { clockSvg = document.querySelector('.analog-clock'); if (!clockSvg) return; // Clear any existing content clockSvg.innerHTML = ''; // Draw clock face drawClockFace(); // Draw hands drawClockHands(); // Initial update updateAnalogClock(new Date()); } function drawClockFace() { const svgNS = "http://www.w3.org/2000/svg"; const centerX = 100; const centerY = 100; const radius = 90; // Outer circle const circle = document.createElementNS(svgNS, "circle"); circle.setAttribute("cx", centerX); circle.setAttribute("cy", centerY); circle.setAttribute("r", radius); circle.setAttribute("fill", "white"); circle.setAttribute("stroke", "#333"); circle.setAttribute("stroke-width", "2"); clockSvg.appendChild(circle); // Hour markers for (let i = 0; i < 12; i++) { const angle = (i * 30 - 90) * Math.PI / 180; const x1 = centerX + (radius - 15) * Math.cos(angle); const y1 = centerY + (radius - 15) * Math.sin(angle); const x2 = centerX + (radius - 5) * Math.cos(angle); const y2 = centerY + (radius - 5) * Math.sin(angle); const line = document.createElementNS(svgNS, "line"); line.setAttribute("x1", x1); line.setAttribute("y1", y1); line.setAttribute("x2", x2); line.setAttribute("y2", y2); line.setAttribute("stroke", "#333"); line.setAttribute("stroke-width", i % 3 === 0 ? "3" : "1"); clockSvg.appendChild(line); // Add numbers for 12, 3, 6, 9 if (i === 0) { const text = document.createElementNS(svgNS, "text"); text.setAttribute("x", centerX - 5); text.setAttribute("y", centerY - radius + 20); text.setAttribute("text-anchor", "middle"); text.setAttribute("font-size", "14"); text.setAttribute("fill", "#333"); text.textContent = "12"; clockSvg.appendChild(text); } else if (i === 3) { const text = document.createElementNS(svgNS, "text"); text.setAttribute("x", centerX + radius - 25); text.setAttribute("y", centerY + 5); text.setAttribute("text-anchor", "middle"); text.setAttribute("font-size", "14"); text.setAttribute("fill", "#333"); text.textContent = "3"; clockSvg.appendChild(text); } else if (i === 6) { const text = document.createElementNS(svgNS, "text"); text.setAttribute("x", centerX); text.setAttribute("y", centerY + radius - 15); text.setAttribute("text-anchor", "middle"); text.setAttribute("font-size", "14"); text.setAttribute("fill", "#333"); text.textContent = "6"; clockSvg.appendChild(text); } else if (i === 9) { const text = document.createElementNS(svgNS, "text"); text.setAttribute("x", centerX - radius + 25); text.setAttribute("y", centerY + 5); text.setAttribute("text-anchor", "middle"); text.setAttribute("font-size", "14"); text.setAttribute("fill", "#333"); text.textContent = "9"; clockSvg.appendChild(text); } } // Center dot const dot = document.createElementNS(svgNS, "circle"); dot.setAttribute("cx", centerX); dot.setAttribute("cy", centerY); dot.setAttribute("r", "5"); dot.setAttribute("fill", "#333"); clockSvg.appendChild(dot); } function drawClockHands() { const svgNS = "http://www.w3.org/2000/svg"; // Hour hand hourHand = document.createElementNS(svgNS, "line"); hourHand.setAttribute("x1", "100"); hourHand.setAttribute("y1", "100"); hourHand.setAttribute("x2", "100"); hourHand.setAttribute("y2", "100"); hourHand.setAttribute("stroke", "#333"); hourHand.setAttribute("stroke-width", "4"); hourHand.setAttribute("stroke-linecap", "round"); clockSvg.appendChild(hourHand); // Minute hand minuteHand = document.createElementNS(svgNS, "line"); minuteHand.setAttribute("x1", "100"); minuteHand.setAttribute("y1", "100"); minuteHand.setAttribute("x2", "100"); minuteHand.setAttribute("y2", "100"); minuteHand.setAttribute("stroke", "#333"); minuteHand.setAttribute("stroke-width", "3"); minuteHand.setAttribute("stroke-linecap", "round"); clockSvg.appendChild(minuteHand); // Second hand secondHand = document.createElementNS(svgNS, "line"); secondHand.setAttribute("x1", "100"); secondHand.setAttribute("y1", "100"); secondHand.setAttribute("x2", "100"); secondHand.setAttribute("y2", "100"); secondHand.setAttribute("stroke", "#f00"); secondHand.setAttribute("stroke-width", "2"); secondHand.setAttribute("stroke-linecap", "round"); clockSvg.appendChild(secondHand); } function updateAnalogClock(time) { if (!hourHand || !minuteHand || !secondHand) return; const hours = time.getHours() % 12; const minutes = time.getMinutes(); const seconds = time.getSeconds(); const milliseconds = time.getMilliseconds(); // Calculate angles (in radians from 12 o'clock) const hourAngle = (hours * 30 + minutes * 0.5) * Math.PI / 180 - Math.PI / 2; const minuteAngle = (minutes * 6 + seconds * 0.1) * Math.PI / 180 - Math.PI / 2; const secondAngle = (seconds * 6 + milliseconds * 0.006) * Math.PI / 180 - Math.PI / 2; // Hand lengths const hourLength = 50; const minuteLength = 70; const secondLength = 80; // Update hour hand const hourX = 100 + hourLength * Math.cos(hourAngle); const hourY = 100 + hourLength * Math.sin(hourAngle); hourHand.setAttribute("x2", hourX); hourHand.setAttribute("y2", hourY); // Update minute hand const minuteX = 100 + minuteLength * Math.cos(minuteAngle); const minuteY = 100 + minuteLength * Math.sin(minuteAngle); minuteHand.setAttribute("x2", minuteX); minuteHand.setAttribute("y2", minuteY); // Update second hand const secondX = 100 + secondLength * Math.cos(secondAngle); const secondY = 100 + secondLength * Math.sin(secondAngle); secondHand.setAttribute("x2", secondX); secondHand.setAttribute("y2", secondY); }

4. clock/timer.php (Timer Page)

<?php require_once '../includes/config.php'; $page_title = 'Timer - Digital Clock'; include '../includes/header.php'; ?> <link rel="stylesheet" href="css/clock.css"> <div class="timer-container"> <div class="clock-header"> <nav class="clock-nav"> <a href="index.php" class="nav-link">Clock</a> <a href="alarms.php" class="nav-link">Alarms</a> <a href="timer.php" class="nav-link active">Timer</a> <a href="stopwatch.php" class="nav-link">Stopwatch</a> <a href="settings.php" class="nav-link">Settings</a> </nav> </div> <div class="timer-main"> <h1>Timer</h1> <!-- Timer Display --> <div class="timer-display" id="timerDisplay">00:00:00</div> <!-- Timer Input --> <div class="timer-input" id="timerInput"> <div class="input-group"> <input type="number" id="hours" min="0" max="23" value="0" placeholder="HH"> <span>:</span> <input type="number" id="minutes" min="0" max="59" value="0" placeholder="MM"> <span>:</span> <input type="number" id="seconds" min="0" max="59" value="0" placeholder="SS"> </div> </div> <!-- Timer Controls --> <div class="timer-controls"> <button class="timer-btn start" onclick="startTimer()" id="startBtn">Start</button> <button class="timer-btn pause" onclick="pauseTimer()" id="pauseBtn" style="display: none;">Pause</button> <button class="timer-btn reset" onclick="resetTimer()" id="resetBtn">Reset</button> </div> <!-- Preset Times --> <div class="preset-times"> <h3>Quick Presets</h3> <div class="preset-buttons"> <button onclick="setTimer(0,1,0)">1 min</button> <button onclick="setTimer(0,5,0)">5 min</button> <button onclick="setTimer(0,10,0)">10 min</button> <button onclick="setTimer(0,15,0)">15 min</button> <button onclick="setTimer(0,30,0)">30 min</button> <button onclick="setTimer(1,0,0)">1 hour</button> </div> </div> <!-- Multiple Timers --> <div class="multiple-timers"> <h3>Multiple Timers</h3> <button class="add-timer-btn" onclick="addNewTimer()">+ Add Timer</button> <div id="timersList" class="timers-list"></div> </div> </div> </div> <!-- Timer Complete Modal --> <div id="timerCompleteModal" class="alarm-modal" style="display: none;"> <div class="alarm-modal-content"> <h2>⏰ Timer Complete!</h2> <p id="timerCompleteMessage">Time's up!</p> <div class="alarm-actions"> <button class="dismiss-btn" onclick="dismissTimerComplete()">OK</button> </div> </div> </div> <audio id="timerSound" preload="auto"> <source src="sounds/notification.mp3" type="audio/mpeg"> </audio> <script src="js/timer.js"></script> <style> .timer-container { max-width: 800px; margin: 0 auto; padding: 2rem; } .timer-main { text-align: center; } .timer-main h1 { font-size: 2.5rem; margin-bottom: 2rem; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); -webkit-background-clip: text; -webkit-text-fill-color: transparent; } .timer-display { font-size: 5rem; font-family: 'Digital', monospace; margin-bottom: 2rem; color: #333; } .timer-input { margin-bottom: 2rem; } .input-group { display: flex; justify-content: center; align-items: center; gap: 0.5rem; } .input-group input { width: 80px; padding: 0.5rem; font-size: 1.5rem; text-align: center; border: 2px solid #ddd; border-radius: 5px; } .input-group span { font-size: 2rem; font-weight: bold; color: #666; } .timer-controls { display: flex; gap: 1rem; justify-content: center; margin-bottom: 3rem; } .timer-btn { padding: 1rem 2rem; font-size: 1.2rem; border: none; border-radius: 5px; cursor: pointer; transition: opacity 0.3s; } .timer-btn.start { background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; } .timer-btn.pause { background: #ffc107; color: #333; } .timer-btn.reset { background: #6c757d; color: white; } .timer-btn:hover { opacity: 0.9; } .preset-times { margin-bottom: 3rem; } .preset-times h3 { margin-bottom: 1rem; color: #333; } .preset-buttons { display: flex; flex-wrap: wrap; gap: 0.5rem; justify-content: center; } .preset-buttons button { padding: 0.5rem 1rem; background: #f8f9fa; border: 1px solid #ddd; border-radius: 5px; cursor: pointer; transition: all 0.3s; } .preset-buttons button:hover { background: #e9ecef; transform: translateY(-2px); } .multiple-timers { margin-top: 3rem; } .multiple-timers h3 { margin-bottom: 1rem; color: #333; } .add-timer-btn { padding: 0.5rem 1rem; background: #28a745; color: white; border: none; border-radius: 5px; cursor: pointer; margin-bottom: 1rem; } .add-timer-btn:hover { opacity: 0.9; } .timers-list { display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: 1rem; } .timer-card { background: white; border-radius: 5px; padding: 1rem; box-shadow: 0 2px 10px rgba(0,0,0,0.1); position: relative; } .timer-card .timer-name { font-weight: bold; margin-bottom: 0.5rem; } .timer-card .timer-time { font-size: 1.2rem; font-family: 'Digital', monospace; margin-bottom: 0.5rem; } .timer-card .timer-status { font-size: 0.9rem; color: #666; } .timer-card .delete-timer { position: absolute; top: 0.5rem; right: 0.5rem; background: none; border: none; color: #dc3545; cursor: pointer; font-size: 1.2rem; } </style> <?php include '../includes/footer.php'; ?>

5. js/timer.js (Timer Functionality)

/** * Timer Functionality */ let mainTimer = { hours: 0, minutes: 0, seconds: 0, totalSeconds: 0, remainingSeconds: 0, interval: null, isRunning: false }; let multipleTimers = []; let nextTimerId = 1; // Initialize timer function initTimer() { resetTimer(); } // Set timer from inputs function setTimer(hours, minutes, seconds) { document.getElementById('hours').value = hours; document.getElementById('minutes').value = minutes; document.getElementById('seconds').value = seconds; mainTimer.hours = hours; mainTimer.minutes = minutes; mainTimer.seconds = seconds; mainTimer.totalSeconds = hours * 3600 + minutes * 60 + seconds; mainTimer.remainingSeconds = mainTimer.totalSeconds; updateTimerDisplay(); } // Start main timer function startTimer() { if (mainTimer.totalSeconds === 0) { // Get values from inputs const hours = parseInt(document.getElementById('hours').value) || 0; const minutes = parseInt(document.getElementById('minutes').value) || 0; const seconds = parseInt(document.getElementById('seconds').value) || 0; setTimer(hours, minutes, seconds); } if (mainTimer.totalSeconds === 0) { alert('Please set a time'); return; } if (mainTimer.isRunning) return; mainTimer.isRunning = true; // Update UI document.getElementById('startBtn').style.display = 'none'; document.getElementById('pauseBtn').style.display = 'inline-block'; document.getElementById('timerInput').style.display = 'none'; mainTimer.interval = setInterval(() => { if (mainTimer.remainingSeconds > 0) { mainTimer.remainingSeconds--; updateTimerDisplay(); } else { completeTimer(); } }, 1000); } // Pause main timer function pauseTimer() { if (!mainTimer.isRunning) return; clearInterval(mainTimer.interval); mainTimer.isRunning = false; // Update UI document.getElementById('startBtn').style.display = 'inline-block'; document.getElementById('pauseBtn').style.display = 'none'; } // Reset main timer function resetTimer() { pauseTimer(); mainTimer.hours = 0; mainTimer.minutes = 0; mainTimer.seconds = 0; mainTimer.totalSeconds = 0; mainTimer.remainingSeconds = 0; // Update UI document.getElementById('startBtn').style.display = 'inline-block'; document.getElementById('pauseBtn').style.display = 'none'; document.getElementById('timerInput').style.display = 'block'; document.getElementById('hours').value = 0; document.getElementById('minutes').value = 0; document.getElementById('seconds').value = 0; updateTimerDisplay(); } // Complete timer function completeTimer() { pauseTimer(); // Play sound const audio = document.getElementById('timerSound'); audio.play(); // Show modal const modal = document.getElementById('timerCompleteModal'); const message = document.getElementById('timerCompleteMessage'); message.textContent = `${mainTimer.hours}h ${mainTimer.minutes}m ${mainTimer.seconds}s timer completed!`; modal.style.display = 'flex'; // Auto hide after 5 seconds setTimeout(() => { modal.style.display = 'none'; }, 5000); } // Dismiss timer complete modal function dismissTimerComplete() { document.getElementById('timerCompleteModal').style.display = 'none'; } // Update timer display function updateTimerDisplay() { const display = document.getElementById('timerDisplay'); const hours = Math.floor(mainTimer.remainingSeconds / 3600); const minutes = Math.floor((mainTimer.remainingSeconds % 3600) / 60); const seconds = mainTimer.remainingSeconds % 60; display.textContent = `${padZero(hours)}:${padZero(minutes)}:${padZero(seconds)}`; // Update document title document.title = `${padZero(hours)}:${padZero(minutes)}:${padZero(seconds)} - Timer`; } // Add new multiple timer function addNewTimer() { const timer = { id: nextTimerId++, name: `Timer ${nextTimerId - 1}`, hours: 0, minutes: 0, seconds: 0, totalSeconds: 0, remainingSeconds: 0, interval: null, isRunning: false }; multipleTimers.push(timer); updateMultipleTimersUI(); } // Delete multiple timer function deleteTimer(id) { const index = multipleTimers.findIndex(t => t.id === id); if (index !== -1) { const timer = multipleTimers[index]; if (timer.interval) { clearInterval(timer.interval); } multipleTimers.splice(index, 1); updateMultipleTimersUI(); } } // Start multiple timer function startMultipleTimer(id) { const timer = multipleTimers.find(t => t.id === id); if (!timer || timer.isRunning) return; if (timer.totalSeconds === 0) { // Get values from inputs (you'd need to create input fields in the UI) return; } timer.isRunning = true; timer.interval = setInterval(() => { if (timer.remainingSeconds > 0) { timer.remainingSeconds--; updateMultipleTimerDisplay(id); } else { completeMultipleTimer(id); } }, 1000); updateMultipleTimersUI(); } // Pause multiple timer function pauseMultipleTimer(id) { const timer = multipleTimers.find(t => t.id === id); if (!timer || !timer.isRunning) return; clearInterval(timer.interval); timer.isRunning = false; updateMultipleTimersUI(); } // Reset multiple timer function resetMultipleTimer(id) { const timer = multipleTimers.find(t => t.id === id); if (!timer) return; if (timer.interval) { clearInterval(timer.interval); } timer.isRunning = false; timer.remainingSeconds = timer.totalSeconds; updateMultipleTimerDisplay(id); updateMultipleTimersUI(); } // Complete multiple timer function completeMultipleTimer(id) { const timer = multipleTimers.find(t => t.id === id); if (!timer) return; pauseMultipleTimer(id); // Play sound const audio = document.getElementById('timerSound'); audio.play(); // Show notification showNotification(`Timer "${timer.name}" completed!`); } // Update multiple timer display function updateMultipleTimerDisplay(id) { const timer = multipleTimers.find(t => t.id === id); if (!timer) return; const element = document.getElementById(`timer-${id}`); if (element) { const hours = Math.floor(timer.remainingSeconds / 3600); const minutes = Math.floor((timer.remainingSeconds % 3600) / 60); const seconds = timer.remainingSeconds % 60; element.querySelector('.timer-time').textContent = `${padZero(hours)}:${padZero(minutes)}:${padZero(seconds)}`; } } // Update multiple timers UI function updateMultipleTimersUI() { const container = document.getElementById('timersList'); if (!container) return; if (multipleTimers.length === 0) { container.innerHTML = '<p class="no-timers">No additional timers</p>'; return; } let html = ''; multipleTimers.forEach(timer => { const hours = Math.floor(timer.remainingSeconds / 3600); const minutes = Math.floor((timer.remainingSeconds % 3600) / 60); const seconds = timer.remainingSeconds % 60; html += ` <div class="timer-card" id="timer-${timer.id}"> <button class="delete-timer" onclick="deleteTimer(${timer.id})">✕</button> <div class="timer-name">${escapeHtml(timer.name)}</div> <div class="timer-time">${padZero(hours)}:${padZero(minutes)}:${padZero(seconds)}</div> <div class="timer-status">${timer.isRunning ? 'Running' : 'Stopped'}</div> <div class="timer-controls"> ${!timer.isRunning ? `<button onclick="startMultipleTimer(${timer.id})">Start</button>` : `<button onclick="pauseMultipleTimer(${timer.id})">Pause</button>` } <button onclick="resetMultipleTimer(${timer.id})">Reset</button> </div> </div> `; }); container.innerHTML = html; } // Pad zero helper (reused from clock.js) function padZero(num) { return num.toString().padStart(2, '0'); } // Initialize on page load document.addEventListener('DOMContentLoaded', initTimer);

6. clock/alarms.php (Alarm Management Page)

<?php require_once '../includes/config.php'; $page_title = 'Alarms - Digital Clock'; include '../includes/header.php'; ?> <link rel="stylesheet" href="css/clock.css"> <div class="alarms-container"> <div class="clock-header"> <nav class="clock-nav"> <a href="index.php" class="nav-link">Clock</a> <a href="alarms.php" class="nav-link active">Alarms</a> <a href="timer.php" class="nav-link">Timer</a> <a href="stopwatch.php" class="nav-link">Stopwatch</a> <a href="settings.php" class="nav-link">Settings</a> </nav> </div> <div class="alarms-main"> <h1>Alarms</h1> <!-- Add Alarm Button --> <button class="add-alarm-btn" onclick="showAddAlarmModal()">+ Add New Alarm</button> <!-- Alarms List --> <div class="alarms-list-container" id="alarmsList"> <!-- Alarms will be loaded here by JavaScript --> </div> </div> </div> <!-- Add/Edit Alarm Modal --> <div id="alarmModal" class="modal" style="display: none;"> <div class="modal-content"> <div class="modal-header"> <h2 id="modalTitle">Add Alarm</h2> <span class="close" onclick="closeAlarmModal()">&times;</span> </div> <div class="modal-body"> <form id="alarmForm" onsubmit="saveAlarm(event)"> <input type="hidden" id="alarmId" value=""> <div class="form-group"> <label for="alarmTime">Time</label> <input type="time" id="alarmTime" class="form-control" required> </div> <div class="form-group"> <label for="alarmLabel">Label</label> <input type="text" id="alarmLabel" class="form-control" placeholder="Wake up" value="Alarm"> </div> <div class="form-group"> <label>Repeat</label> <div class="days-selector"> <label class="day-checkbox"> <input type="checkbox" name="days[]" value="0"> Sun </label> <label class="day-checkbox"> <input type="checkbox" name="days[]" value="1" checked> Mon </label> <label class="day-checkbox"> <input type="checkbox" name="days[]" value="2" checked> Tue </label> <label class="day-checkbox"> <input type="checkbox" name="days[]" value="3" checked> Wed </label> <label class="day-checkbox"> <input type="checkbox" name="days[]" value="4" checked> Thu </label> <label class="day-checkbox"> <input type="checkbox" name="days[]" value="5" checked> Fri </label> <label class="day-checkbox"> <input type="checkbox" name="days[]" value="6"> Sat </label> </div> </div> <div class="form-group"> <label for="alarmSound">Sound</label> <select id="alarmSound" class="form-control"> <option value="alarm-1.mp3">Classic Alarm</option> <option value="alarm-2.mp3">Digital Beep</option> <option value="gentle.mp3">Gentle Wake</option> <option value="notification.mp3">Notification</option> </select> </div> <div class="form-group"> <label for="alarmVolume">Volume</label> <input type="range" id="alarmVolume" min="0" max="100" value="80" class="volume-slider"> <span id="volumeValue">80%</span> </div> <div class="form-group"> <label> <input type="checkbox" id="snoozeEnabled" checked> Enable Snooze </label> </div> <div class="form-group" id="snoozeGroup"> <label for="snoozeDuration">Snooze Duration (minutes)</label> <select id="snoozeDuration" class="form-control"> <option value="5">5 minutes</option> <option value="10">10 minutes</option> <option value="15">15 minutes</option> </select> </div> <div class="form-actions"> <button type="submit" class="btn-save">Save Alarm</button> <button type="button" class="btn-cancel" onclick="closeAlarmModal()">Cancel</button> </div> </form> </div> </div> </div> <script src="js/clock.js"></script> <script src="js/alarms.js"></script> <style> .alarms-container { max-width: 800px; margin: 0 auto; padding: 2rem; } .alarms-main { text-align: center; } .alarms-main h1 { font-size: 2.5rem; margin-bottom: 2rem; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); -webkit-background-clip: text; -webkit-text-fill-color: transparent; } .add-alarm-btn { padding: 1rem 2rem; font-size: 1.1rem; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; border: none; border-radius: 5px; cursor: pointer; margin-bottom: 2rem; transition: opacity 0.3s; } .add-alarm-btn:hover { opacity: 0.9; } .alarms-list-container { background: white; border-radius: 10px; box-shadow: 0 4px 20px rgba(0,0,0,0.1); padding: 1rem; } .alarm-item { display: flex; align-items: center; padding: 1rem; border-bottom: 1px solid #eee; transition: background 0.3s; } .alarm-item:hover { background: #f8f9fa; } .alarm-item:last-child { border-bottom: none; } .alarm-time { font-size: 1.5rem; font-weight: bold; width: 100px; } .alarm-details { flex: 1; text-align: left; } .alarm-label { font-size: 1.1rem; margin-bottom: 0.3rem; } .alarm-schedule { font-size: 0.9rem; color: #666; } .alarm-actions { display: flex; gap: 0.5rem; } .alarm-edit, .alarm-delete { padding: 0.3rem 0.8rem; border: none; border-radius: 3px; cursor: pointer; transition: opacity 0.3s; } .alarm-edit { background: #ffc107; color: #333; } .alarm-delete { background: #dc3545; color: white; } .alarm-edit:hover, .alarm-delete:hover { opacity: 0.9; } /* Modal Styles */ .modal { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.5); z-index: 2000; overflow-y: auto; } .modal-content { background: white; max-width: 500px; margin: 50px auto; border-radius: 10px; box-shadow: 0 4px 20px rgba(0,0,0,0.2); } .modal-header { padding: 1rem; border-bottom: 1px solid #eee; display: flex; justify-content: space-between; align-items: center; } .modal-header h2 { margin: 0; font-size: 1.5rem; } .close { font-size: 1.5rem; cursor: pointer; color: #888; } .close:hover { color: #333; } .modal-body { padding: 1.5rem; } .form-group { margin-bottom: 1.5rem; text-align: left; } .form-group label { display: block; margin-bottom: 0.5rem; font-weight: 500; color: #333; } .form-control { width: 100%; padding: 0.8rem; border: 1px solid #ddd; border-radius: 5px; font-size: 1rem; } .days-selector { display: flex; gap: 0.5rem; flex-wrap: wrap; } .day-checkbox { display: flex; align-items: center; gap: 0.2rem; padding: 0.3rem 0.6rem; background: #f8f9fa; border-radius: 3px; cursor: pointer; } .day-checkbox:hover { background: #e9ecef; } .volume-slider { width: 100%; margin-bottom: 0.5rem; } #volumeValue { margin-left: 0.5rem; font-weight: 500; } .form-actions { display: flex; gap: 1rem; margin-top: 2rem; } .btn-save, .btn-cancel { flex: 1; padding: 0.8rem; border: none; border-radius: 5px; font-size: 1rem; cursor: pointer; transition: opacity 0.3s; } .btn-save { background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; } .btn-cancel { background: #6c757d; color: white; } .btn-save:hover, .btn-cancel:hover { opacity: 0.9; } </style> <?php include '../includes/footer.php'; ?>

7. js/alarms.js (Alarm Management)

/** * Alarm Management JavaScript */ // Show add alarm modal function showAddAlarmModal() { document.getElementById('modalTitle').textContent = 'Add Alarm'; document.getElementById('alarmId').value = ''; document.getElementById('alarmForm').reset(); document.getElementById('alarmTime').value = '08:00'; document.getElementById('alarmModal').style.display = 'block'; } // Show edit alarm modal function showEditAlarmModal(id) { const alarm = alarms.find(a => a.id === id); if (!alarm) return; document.getElementById('modalTitle').textContent = 'Edit Alarm'; document.getElementById('alarmId').value = alarm.id; document.getElementById('alarmTime').value = alarm.time; document.getElementById('alarmLabel').value = alarm.label; document.getElementById('alarmSound').value = alarm.sound; document.getElementById('alarmVolume').value = alarm.volume; document.getElementById('volumeValue').textContent = alarm.volume + '%'; document.getElementById('snoozeEnabled').checked = alarm.snoozeEnabled; document.getElementById('snoozeDuration').value = alarm.snoozeDuration; // Set days document.querySelectorAll('input[name="days[]"]').forEach(cb => { cb.checked = alarm.days.includes(parseInt(cb.value)); }); document.getElementById('alarmModal').style.display = 'block'; } // Close alarm modal function closeAlarmModal() { document.getElementById('alarmModal').style.display = 'none'; } // Save alarm function saveAlarm(event) { event.preventDefault(); const id = document.getElementById('alarmId').value; const time = document.getElementById('alarmTime').value; const label = document.getElementById('alarmLabel').value; const sound = document.getElementById('alarmSound').value; const volume = parseInt(document.getElementById('alarmVolume').value); const snoozeEnabled = document.getElementById('snoozeEnabled').checked; const snoozeDuration = parseInt(document.getElementById('snoozeDuration').value); // Get selected days const days = []; document.querySelectorAll('input[name="days[]"]:checked').forEach(cb => { days.push(parseInt(cb.value)); }); const alarmData = { time, label, days, sound, volume, snoozeEnabled, snoozeDuration }; if (id) { // Update existing alarm updateAlarm(id, alarmData); } else { // Add new alarm addAlarm(alarmData); } closeAlarmModal(); updateAlarmsList(); } // Update alarms list (override from clock.js) function updateAlarmsList() { const container = document.getElementById('alarmsList'); if (!container) return; if (alarms.length === 0) { container.innerHTML = '<p class="no-alarms">No alarms set. Click "Add New Alarm" to create one.</p>'; return; } // Sort alarms by time const sorted = [...alarms].sort((a, b) => { return a.time.localeCompare(b.time); }); let html = ''; sorted.forEach(alarm => { const [hours, minutes] = alarm.time.split(':'); const time12 = formatTime12(parseInt(hours), parseInt(minutes)); html += ` <div class="alarm-item"> <div class="alarm-time">${time12}</div> <div class="alarm-details"> <div class="alarm-label">${escapeHtml(alarm.label)}</div> <div class="alarm-schedule">${formatDays(alarm.days)}</div> </div> <div class="alarm-actions"> <button class="alarm-edit" onclick="showEditAlarmModal('${alarm.id}')">Edit</button> <button class="alarm-delete" onclick="deleteAlarm('${alarm.id}')">Delete</button> </div> <label class="alarm-switch"> <input type="checkbox" ${alarm.isActive ? 'checked' : ''} onchange="toggleAlarm('${alarm.id}')"> <span class="alarm-slider"></span> </label> </div> `; }); container.innerHTML = html; } // Update volume display document.getElementById('alarmVolume')?.addEventListener('input', function(e) { document.getElementById('volumeValue').textContent = e.target.value + '%'; }); // Toggle snooze fields document.getElementById('snoozeEnabled')?.addEventListener('change', function(e) { document.getElementById('snoozeGroup').style.display = e.target.checked ? 'block' : 'none'; }); // Initialize on page load document.addEventListener('DOMContentLoaded', function() { loadAlarmsFromStorage(); updateAlarmsList(); });

🚀 How to Use This Project Step by Step

Step 1: Setup

  1. Copy all files to your web server
  2. Ensure proper permissions for sound files
  3. Configure .env if using database storage

Step 2: Database (Optional)

If using server-side storage:

mysql -u root -p < database/clock.sql

Step 3: Access the Clock

Navigate to /clock/index.php in your browser

Step 4: Set Up Alarms

  1. Click on "Alarms" tab
  2. Click "Add New Alarm"
  3. Set time, label, repeat days
  4. Choose sound and volume
  5. Save alarm

Step 5: Use Timer

  1. Go to Timer tab
  2. Set hours, minutes, seconds
  3. Click Start
  4. Timer will notify when complete

Step 6: Use Stopwatch

  1. Go to Stopwatch tab
  2. Click Start to begin timing
  3. Use Lap button to record splits
  4. Reset to start over

Step 7: Customize Settings

  1. Go to Settings tab
  2. Choose time format (12/24 hour)
  3. Select theme (Light/Dark/Auto)
  4. Set default sound and volume
  5. Configure snooze preferences

🔒 Security Features

Client-Side Security:

  • ✅ Alarms stored in localStorage (no server needed)
  • ✅ XSS protection with escapeHtml function
  • ✅ Input validation for all forms
  • ✅ Secure audio playback

Optional Server-Side:

  • ✅ Database storage with prepared statements
  • ✅ User authentication integration
  • ✅ Rate limiting for API calls
  • ✅ Encrypted sensitive data

🎯 Keyboard Shortcuts

KeyFunction
SpaceSnooze active alarm
EscapeDismiss active alarm
Ctrl+FToggle fullscreen
Ctrl+TToggle theme
Ctrl+1Go to Clock
Ctrl+2Go to Alarms
Ctrl+3Go to Timer
Ctrl+4Go to Stopwatch
Ctrl+SStart/Stop timer

🚀 Future Enhancements

  1. Advanced Features:
  • Sunrise simulation alarm
  • Smart wake (light sleep detection)
  • Weather integration
  • Calendar sync
  1. Sound Options:
  • Custom sound upload
  • Spotify/Apple Music integration
  • Gradual volume increase
  • Playlist support
  1. Visual Features:
  • Custom clock faces
  • Animated backgrounds
  • Weather display
  • News ticker
  1. Smart Features:
  • Voice control
  • IFTTT integration
  • Smart home integration
  • Bedtime reminders
  1. Analytics:
  • Sleep tracking
  • Wake-up patterns
  • Alarm effectiveness
  • Usage statistics

📝 Conclusion

This Digital Clock with Alarm System provides a complete time management solution with beautiful analog and digital displays, comprehensive alarm management, timer functionality, and stopwatch features. The system is built with pure HTML, CSS, and JavaScript for the frontend, making it lightweight and fast. With support for multiple alarms, customizable sounds, and various themes, it's perfect for any website needing time management tools or as a standalone productivity application.

Leave a Reply

Your email address will not be published. Required fields are marked *


Macro Nepal Helper