diff --git a/clock-face-christmas.png b/clock-face-christmas.png new file mode 100644 index 0000000..41520b8 Binary files /dev/null and b/clock-face-christmas.png differ diff --git a/clock-face-halloween.png b/clock-face-halloween.png new file mode 100644 index 0000000..4deca4f Binary files /dev/null and b/clock-face-halloween.png differ diff --git a/clock-face.png b/clock-face.png index 5b03bfc..8537749 100644 Binary files a/clock-face.png and b/clock-face.png differ diff --git a/index.html b/index.html index afd1792..c7ebc12 100644 --- a/index.html +++ b/index.html @@ -57,11 +57,6 @@ margin-bottom: 10px; } - .timezone { - font-size: 1rem; - color: rgba(255, 255, 255, 0.7); - } - .analog-clock { width: 340px; height: 340px; @@ -76,29 +71,21 @@ width: 280px; height: 280px; border-radius: 50%; - background: radial-gradient(circle, #f8f6f0 0%, #e8e6e0 70%, #d0cec8 100%); - border: 12px solid; - border-color: #c0c0c0; + background: transparent; + border: none; position: relative; - box-shadow: - 0 0 30px rgba(0, 0, 0, 0.5), - inset 0 0 20px rgba(0, 0, 0, 0.1), - inset 0 0 40px rgba(255, 255, 255, 0.3), - 0 0 0 4px #e8e8e8, - 0 0 0 8px #a8a8a8, - 0 0 15px rgba(255, 255, 255, 0.8); + box-shadow: none; overflow: visible; } .clock-face::after { content: ''; position: absolute; - top: -30px; - left: -30px; - right: -30px; - bottom: -30px; + top: -35px; + left: -35px; + right: -35px; + bottom: -35px; background: url('clock-face.png') center center / cover no-repeat; - border-radius: 50%; z-index: 1; } @@ -111,26 +98,10 @@ right: -18px; bottom: -18px; border-radius: 50%; - background: conic-gradient( - from 0deg, - #a0a0a0 0deg, - #f5f5f5 30deg, - #d0d0d0 60deg, - #f8f8f8 90deg, - #b8b8b8 120deg, - #f0f0f0 150deg, - #c8c8c8 180deg, - #f8f8f8 210deg, - #a8a8a8 240deg, - #f0f0f0 270deg, - #c0c0c0 300deg, - #f5f5f5 330deg, - #a0a0a0 360deg - ); + background: transparent; z-index: -1; - box-shadow: - 0 0 15px rgba(255, 255, 255, 0.8), - inset 0 0 10px rgba(255, 255, 255, 0.6); + box-shadow: none; + display: none; } .hour-markers { @@ -172,7 +143,8 @@ .hand { position: absolute; left: 50%; - top: 50%; + bottom: 50%; + transform: translateX(-50%); transform-origin: 50% 100%; border-radius: 3px; box-shadow: 2px 2px 4px rgba(0, 0, 0, 0.3); @@ -181,84 +153,40 @@ .hour-hand { width: 8px; - height: 95px; + height: 105px; background: linear-gradient(to right, #1a0f08, #2c1810, #1a0f08); - margin-left: -4px; - margin-top: -95px; z-index: 3; border-radius: 4px; } - .hour-hand::before { - content: ''; - position: absolute; - top: -8px; - left: 50%; - transform: translateX(-50%); - width: 0; - height: 0; - border-left: 6px solid transparent; - border-right: 6px solid transparent; - border-bottom: 12px solid #1a0f08; - } - .minute-hand { width: 5px; - height: 130px; + height: 135px; background: linear-gradient(to right, #2c1810, #4a2c1a, #2c1810); - margin-left: -2.5px; - margin-top: -130px; z-index: 2; border-radius: 3px; } - .minute-hand::before { - content: ''; - position: absolute; - top: -6px; - left: 50%; - transform: translateX(-50%); - width: 0; - height: 0; - border-left: 4px solid transparent; - border-right: 4px solid transparent; - border-bottom: 8px solid #2c1810; - } - .second-hand { width: 2px; - height: 140px; + height: 145px; background: linear-gradient(to bottom, #8b0000, #dc143c, #8b0000); - margin-left: -1px; - margin-top: -140px; z-index: 4; border-radius: 1px; } - .second-hand::after { - content: ''; - position: absolute; - bottom: -15px; - left: 50%; - transform: translateX(-50%); - width: 8px; - height: 8px; - background: #8b0000; - border-radius: 50%; - margin-left: -4px; - } - .center-dot { position: absolute; width: 20px; height: 20px; background: radial-gradient(circle, #f5f5f5 20%, #d0d0d0 40%, #a8a8a8 80%, #808080 100%); border-radius: 50%; - top: 50%; + top: calc(50%); left: 50%; transform: translate(-50%, -50%); z-index: 15; border: 2px solid #888; + box-sizing: border-box; box-shadow: 0 0 8px rgba(255, 255, 255, 0.8), inset 0 0 4px rgba(255, 255, 255, 0.6), @@ -279,29 +207,66 @@ .roman-number { position: absolute; - width: 40px; - height: 40px; - text-align: center; - line-height: 40px; - font-size: 20px; - font-weight: bold; - top: 50%; - left: 50%; - transform-origin: 50% 50%; + width: 100%; + height: 100%; + display: flex; + justify-content: center; + align-items: flex-start; + } + + .roman-number[data-hour="12"] { transform: rotate(0deg); } + .roman-number[data-hour="1"] { transform: rotate(30deg); } + .roman-number[data-hour="2"] { transform: rotate(60deg); } + .roman-number[data-hour="3"] { transform: rotate(90deg); } + .roman-number[data-hour="4"] { transform: rotate(120deg); } + .roman-number[data-hour="5"] { transform: rotate(150deg); } + .roman-number[data-hour="6"] { transform: rotate(180deg); } + .roman-number[data-hour="7"] { transform: rotate(210deg); } + .roman-number[data-hour="8"] { transform: rotate(240deg); } + .roman-number[data-hour="9"] { transform: rotate(270deg); } + .roman-number[data-hour="10"] { transform: rotate(300deg); } + .roman-number[data-hour="11"] { transform: rotate(330deg); } + + /* Show fallback elements when image fails to load */ + .analog-clock.image-failed .hour-markers, + .analog-clock.image-failed .clock-numbers { + display: block; + } + + .analog-clock.image-failed .clock-face { + background: radial-gradient(circle, #f8f6f0 0%, #e8e6e0 70%, #d0cec8 100%); + border: 12px solid #c0c0c0; + box-shadow: + 0 0 30px rgba(0, 0, 0, 0.5), + inset 0 0 20px rgba(0, 0, 0, 0.1), + inset 0 0 40px rgba(255, 255, 255, 0.3), + 0 0 0 4px #e8e8e8, + 0 0 0 8px #a8a8a8, + 0 0 15px rgba(255, 255, 255, 0.8); } - .roman-number[data-hour="12"] { transform: translate(-50%, -50%) translateY(-120px); } - .roman-number[data-hour="1"] { transform: translate(-50%, -50%) rotate(30deg) translateY(-120px) rotate(-30deg); } - .roman-number[data-hour="2"] { transform: translate(-50%, -50%) rotate(60deg) translateY(-120px) rotate(-60deg); } - .roman-number[data-hour="3"] { transform: translate(-50%, -50%) rotate(90deg) translateY(-120px) rotate(-90deg); } - .roman-number[data-hour="4"] { transform: translate(-50%, -50%) rotate(120deg) translateY(-120px) rotate(-120deg); } - .roman-number[data-hour="5"] { transform: translate(-50%, -50%) rotate(150deg) translateY(-120px) rotate(-150deg); } - .roman-number[data-hour="6"] { transform: translate(-50%, -50%) rotate(180deg) translateY(-120px) rotate(-180deg); } - .roman-number[data-hour="7"] { transform: translate(-50%, -50%) rotate(210deg) translateY(-120px) rotate(-210deg); } - .roman-number[data-hour="8"] { transform: translate(-50%, -50%) rotate(240deg) translateY(-120px) rotate(-240deg); } - .roman-number[data-hour="9"] { transform: translate(-50%, -50%) rotate(270deg) translateY(-120px) rotate(-270deg); } - .roman-number[data-hour="10"] { transform: translate(-50%, -50%) rotate(300deg) translateY(-120px) rotate(-300deg); } - .roman-number[data-hour="11"] { transform: translate(-50%, -50%) rotate(330deg) translateY(-120px) rotate(-330deg); } + .analog-clock.image-failed .clock-face::before { + display: block; + background: conic-gradient( + from 0deg, + #a0a0a0 0deg, + #f5f5f5 30deg, + #d0d0d0 60deg, + #f8f8f8 90deg, + #b8b8b8 120deg, + #f0f0f0 150deg, + #c8c8c8 180deg, + #f8f8f8 210deg, + #a8a8a8 240deg, + #f0f0f0 270deg, + #c0c0c0 300deg, + #f5f5f5 330deg, + #a0a0a0 360deg + ); + box-shadow: + 0 0 15px rgba(255, 255, 255, 0.8), + inset 0 0 10px rgba(255, 255, 255, 0.6); + } .city-name { font-size: 2rem; @@ -344,26 +309,6 @@ margin-top: -12.5px; } - .roman-number { - font-size: 16px; - width: 30px; - height: 30px; - line-height: 30px; - } - - .roman-number[data-hour="12"] { transform: translate(-50%, -50%) translateY(-90px); } - .roman-number[data-hour="1"] { transform: translate(-50%, -50%) rotate(30deg) translateY(-90px) rotate(-30deg); } - .roman-number[data-hour="2"] { transform: translate(-50%, -50%) rotate(60deg) translateY(-90px) rotate(-60deg); } - .roman-number[data-hour="3"] { transform: translate(-50%, -50%) rotate(90deg) translateY(-90px) rotate(-90deg); } - .roman-number[data-hour="4"] { transform: translate(-50%, -50%) rotate(120deg) translateY(-90px) rotate(-120deg); } - .roman-number[data-hour="5"] { transform: translate(-50%, -50%) rotate(150deg) translateY(-90px) rotate(-150deg); } - .roman-number[data-hour="6"] { transform: translate(-50%, -50%) rotate(180deg) translateY(-90px) rotate(-180deg); } - .roman-number[data-hour="7"] { transform: translate(-50%, -50%) rotate(210deg) translateY(-90px) rotate(-210deg); } - .roman-number[data-hour="8"] { transform: translate(-50%, -50%) rotate(240deg) translateY(-90px) rotate(-240deg); } - .roman-number[data-hour="9"] { transform: translate(-50%, -50%) rotate(270deg) translateY(-90px) rotate(-270deg); } - .roman-number[data-hour="10"] { transform: translate(-50%, -50%) rotate(300deg) translateY(-90px) rotate(-300deg); } - .roman-number[data-hour="11"] { transform: translate(-50%, -50%) rotate(330deg) translateY(-90px) rotate(-330deg); } - .clock { font-size: 2rem; } @@ -371,11 +316,12 @@ .date { font-size: 1rem; } - - .timezone { - font-size: 0.9rem; + + .roman-number { + font-size: 18px; } + .clock-container { padding: 20px; margin: 10px; @@ -622,6 +568,149 @@ }); } + // Theme system + const themes = { + halloween: { + dateRange: { startMonth: 9, startDay: 29, endMonth: 9, endDay: 31 }, // Oct 29-31 + clockFace: 'clock-face-halloween.png', + clockFaceScale: 'cover', // Options: 'cover', 'contain', or percentage like '100%', '110%' + background: 'planks-halloween.png', + backgroundSize: 'cover', // Cover entire background + backgroundRepeat: 'no-repeat', + backgroundPosition: 'center', + backgroundAttachment: 'fixed', + textColor: '#ff8c00', // Orange + centerDotColor: 'radial-gradient(circle, #ffa500 20%, #ff8c00 40%, #8b4513 80%, #5c2e00 100%)', // Orange gradient + centerDotBorder: '#8b4513', // Dark orange/brown border + handColors: { + hour: 'linear-gradient(to right, #00ff00, #39ff14, #00ff00)', // Glowing green + minute: 'linear-gradient(to right, #39ff14, #7fff00, #39ff14)', // Bright glowing green + second: 'linear-gradient(to bottom, #00ff00, #39ff14, #00ff00)' // Glowing green + }, + handGlow: '0 0 10px #39ff14, 0 0 20px #00ff00, 0 0 30px #00ff00' // Green glow effect + }, + christmas: { + dateRange: { startMonth: 11, startDay: 1, endMonth: 11, endDay: 26 }, // Dec 1-26 + clockFace: 'clock-face-christmas.png', + clockFaceScale: 'cover', + background: 'planks-christmas.png', + backgroundSize: 'cover', + backgroundRepeat: 'no-repeat', + backgroundPosition: 'center', + backgroundAttachment: 'fixed', + textColor: '#ff0000', // Red + centerDotColor: 'radial-gradient(circle, #ffd700 20%, #ffed4e 40%, #daa520 80%, #b8860b 100%)', // Gold gradient + centerDotBorder: '#b8860b', // Dark gold border + handColors: { + hour: 'linear-gradient(to right, #0f5e0f, #228b22, #0f5e0f)', // Green + minute: 'linear-gradient(to right, #8b0000, #dc143c, #8b0000)', // Red + second: 'linear-gradient(to bottom, #ffd700, #ffed4e, #ffd700)' // Gold + } + }, + default: { + clockFace: 'clock-face.png', + clockFaceScale: 'cover', + background: 'planks.jpg', + backgroundSize: '400px auto', // Tiled background + backgroundRepeat: 'repeat', + backgroundAttachment: 'fixed', + textColor: 'white', + centerDotColor: 'radial-gradient(circle, #f5f5f5 20%, #d0d0d0 40%, #a8a8a8 80%, #808080 100%)', // Silver gradient + centerDotBorder: '#888', // Dark grey border + handColors: { + hour: 'linear-gradient(to right, #1a0f08, #2c1810, #1a0f08)', + minute: 'linear-gradient(to right, #2c1810, #4a2c1a, #2c1810)', + second: 'linear-gradient(to bottom, #8b0000, #dc143c, #8b0000)' + } + } + }; + + function getCurrentTheme() { + const today = new Date(); + const month = today.getMonth(); // 0-11 + const day = today.getDate(); + + for (const [themeName, theme] of Object.entries(themes)) { + if (theme.dateRange) { + const { startMonth, startDay, endMonth, endDay } = theme.dateRange; + + // Check if current date falls within theme date range + if (month === startMonth && month === endMonth) { + // Same month range + if (day >= startDay && day <= endDay) { + return theme; + } + } else if ( + (month === startMonth && day >= startDay) || + (month === endMonth && day <= endDay) || + (month > startMonth && month < endMonth) + ) { + return theme; + } + } + } + + return themes.default; + } + + function applyTheme() { + const theme = getCurrentTheme(); + + // Apply background image and properties + document.body.style.backgroundImage = `url('${theme.background}')`; + document.body.style.backgroundSize = theme.backgroundSize || 'auto'; + document.body.style.backgroundRepeat = theme.backgroundRepeat || 'repeat'; + document.body.style.backgroundPosition = theme.backgroundPosition || 'top left'; + document.body.style.backgroundAttachment = theme.backgroundAttachment || 'scroll'; + + // Apply text colors + document.querySelectorAll('.clock, .city-name, .date').forEach(element => { + element.style.color = theme.textColor; + }); + + // Apply center dot color + document.querySelectorAll('.center-dot').forEach(element => { + element.style.background = theme.centerDotColor; + element.style.borderColor = theme.centerDotBorder; + }); + + // Apply hand colors and glow effects + const handGlow = theme.handGlow || '2px 2px 4px rgba(0, 0, 0, 0.3)'; // Default shadow or glow + document.querySelectorAll('.hour-hand').forEach(element => { + element.style.background = theme.handColors.hour; + element.style.boxShadow = handGlow; + }); + document.querySelectorAll('.minute-hand').forEach(element => { + element.style.background = theme.handColors.minute; + element.style.boxShadow = handGlow; + }); + document.querySelectorAll('.second-hand').forEach(element => { + element.style.background = theme.handColors.second; + element.style.boxShadow = handGlow; + }); + + // Update CSS for clock face image (pseudo-element) + const existingStyle = document.getElementById('theme-style'); + if (existingStyle) { + existingStyle.remove(); + } + const style = document.createElement('style'); + style.id = 'theme-style'; + const clockFaceScale = theme.clockFaceScale || 'cover'; // Default to cover + style.textContent = ` + .clock-face::after { + background: url('${theme.clockFace}') center center / ${clockFaceScale} no-repeat !important; + } + `; + document.head.appendChild(style); + } + + // Apply theme on page load + applyTheme(); + + // Check for theme change every hour + setInterval(applyTheme, 1000 * 60 * 60); + // Update all clocks immediately updateAllClocks(); @@ -663,6 +752,29 @@ document.getElementById(`clock-${cityKey}`).textContent = timeString; } }); + + // Detect if clock face images fail to load and show fallback + document.addEventListener('DOMContentLoaded', function() { + const analogClocks = document.querySelectorAll('.analog-clock'); + + analogClocks.forEach(clock => { + const clockFace = clock.querySelector('.clock-face'); + if (clockFace) { + // Create a temporary image to test if the background image loads + const img = new Image(); + const bgImage = window.getComputedStyle(clockFace, '::after').backgroundImage; + const urlMatch = bgImage.match(/url\(['"]?([^'"]+)['"]?\)/); + + if (urlMatch && urlMatch[1]) { + img.onerror = function() { + // Image failed to load, show fallback elements + clock.classList.add('image-failed'); + }; + img.src = urlMatch[1]; + } + } + }); + }); diff --git a/planks-christmas.png b/planks-christmas.png new file mode 100644 index 0000000..60f6bf5 Binary files /dev/null and b/planks-christmas.png differ diff --git a/planks-halloween.png b/planks-halloween.png new file mode 100644 index 0000000..0cf4259 Binary files /dev/null and b/planks-halloween.png differ