diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 00000000..edfa5c3f --- /dev/null +++ b/.prettierignore @@ -0,0 +1 @@ +*.html diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 00000000..5a938ce1 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,4 @@ +{ + "tabWidth": 4, + "useTabs": false +} diff --git a/app.js b/app.js index c87f4770..77b1f035 100644 --- a/app.js +++ b/app.js @@ -1,52 +1,115 @@ -// require('./clock') -import Clock from './clock.js' + class Clock { + constructor(endDate) { + // expecting a date object + this.setEndDate(endDate) + this.countDown(); + } + + setEndDate(endDate) { + //set endDate to end of year + // todo: check endDate for validity as date + this.endDate = endDate ||new Date(`Jan 1, ${new Date().getFullYear() + 1} 00:00:00`) + + + } + countDown() { + // Set the date we're counting down to + let countDownDate = this.endDate.getTime(); + let now = new Date().getTime(); + var distance = countDownDate - now; + // account for case of the countdown being reached, reset + if (distance >= 0) { + // Time calculations for days, hours, minutes and seconds + this.calculateTimeValues(distance) + } else { + // clear date values + this.resetMethod(); + + + } + } + + resetMethod(){ + this.clearCounter(); + } + + calculateTimeValues(distance){ + this.days = Math.floor(distance / (1000 * 60 * 60 * 24)); + this.hours = Math.floor((distance % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60)); + this.minutes = Math.floor((distance % (1000 * 60 * 60)) / (1000 * 60)); + this.seconds = Math.floor((distance % (1000 * 60)) / 1000); + } + countDays() { + //account for leap year + this.dayLength = ((this.endDate.getFullYear() % 4 != 0) ? 365 : 366) + return this.dayLength - this.days + } + + clearCounter(){ + this.days=this.hours=this.minutes=this.seconds=0; + } +} + +class NewYearClock extends Clock{ + resetMethod(){ + //reset to New Year's for default + this.setEndDate() + } +} // DOM nodes -// let icon = document.getElementsByClassName("toggleMode")[0]; -let icon = document.getElementById('themeToggle'); let dayCount = document.getElementById("countDay"); -// let controls = document.getElementsByClassName("button"); -let startButton = document.getElementById('startButton'); -let stopButton = document.getElementById('stopButton'); -let body = document.body; -let dayNumber =document.getElementById('day-num'); -let hourNumber =document.getElementById("hour-num"); -let minNumber =document.getElementById("min-num"); -let secNumber =document.getElementById("sec-num"); +const animatedCountDuration = 800; + +const body = document.body; +var dayNumber = document.getElementById('day-num'); +var hourNumber = document.getElementById("hour-num"); +var minNumber = document.getElementById("min-num"); +var secNumber = document.getElementById("sec-num"); +var dueDate = document.getElementById('dueDate'); + //to stop the clock let intervalID; -let clockMovement = false; +let customClockMovement = false; +let dayClock = new NewYearClock(); +// Initialize default Clock class +// var myclock = new NewYearClock(); +var myclock = setMainClock(); +var myclock = setMainClock(); +setInnerHtmlForNotNull(dueDate, `Due: ${myclock.endDate.getDate() + ' ' + myclock.endDate.toLocaleString('default', { month: 'long' }) + ', ' + myclock.endDate.getFullYear()}`) +var customClock; -// Initialize Clock class -var myclock = new Clock(); +function setMainClock() { + let mainclock = localStorage.getItem('mainClock'); + if (mainclock !== null && mainclock != undefined) { //countdown set to main + mainclock = JSON.parse(mainclock) + myclock = new Clock(new Date(mainclock.date)); + setMainText(mainclock.text) + } + return myclock || new NewYearClock(); -function startClock() { - intervalID = setInterval(startTime, 500); } -function startTime() { - myclock.countDown(); - let d = myclock.days - let h = myclock.hours - let m = myclock.minutes - let s = myclock.seconds - d= addZeros(d); - h = addZeros(h); - m = addZeros(m); - s = addZeros(s); - dayNumber.innerHTML = `${d}`; - hourNumber.innerHTML = `${h}`; - minNumber.innerHTML = `${m}`; - secNumber.innerHTML = `${s}`; - dayCount.innerHTML= myclock.countDays(); - clockMovement = true; +function setMainText(countdownText) { + const textDisplay = document.getElementById('countdown-text'); + setInnerHtmlForNotNull(textDisplay, countdownText) } -function restartTime() { - if (clockMovement) { - return; - } else { - startClock(); + async function waitForAnimation(clock, domElements, duration) { + await stepIncreaseAndStart(clock || myclock, domElements, duration || animatedCountDuration) + startClock(clock || myclock, domElements); +} + +function startClock(clock, { dayNumber, hourNumber, minNumber, secNumber }) { + intervalID = setInterval(() => { startTime(clock, { dayNumber, hourNumber, minNumber, secNumber }); }, 500); +} + +function startTime(clock, { dayNumber, hourNumber, minNumber, secNumber }) { + // console.log(clock); + updateDisplay(clock, dayNumber, hourNumber, minNumber, secNumber); + setInnerHtmlForNotNull(dayCount, dayClock.countDays()); + if (customClockMovement) { + updateDisplay(customClock, customDayNumber, customHourNumber, customMinNumber, customSecNumber); } } // add zero in front of numbers < 10 @@ -57,70 +120,119 @@ function addZeros(time) { return time; } -function stopClock() { - clearTimeout(intervalID); - clockMovement = false; +function updateDisplay(counter, dayDisplay, hourDisplay, minDisplay, secDisplay) { + counter.countDown(); + let d = counter.days + let h = counter.hours + let m = counter.minutes + let s = counter.seconds + d = addZeros(d); + h = addZeros(h); + m = addZeros(m); + s = addZeros(s); + setInnerHtmlForNotNull(dayDisplay, `${d}`); + setInnerHtmlForNotNull(hourDisplay, `${h}`); + setInnerHtmlForNotNull(minDisplay, `${m}`); + setInnerHtmlForNotNull(secDisplay, `${s}`); } -//light mode if after 6am and after 18:00 evening -function autoLight() { - let h = new Date().getHours(); - //between 6 am and 6pm - if (h > 5 && h < 18) activateLightMode(); +/** + * Listens for a user input for date element + */ +function listenForDate() { + const input = this.value; + // console.log(input, 'run'); + if (input != '') { + customClock = new Clock(new Date(input)); + displayClockRow(); + // do the fast countdown + // set speed faster when day of the year is greater + // todo: change to animateValue + stepIncreaseAndStart(customClock, { customDayNumber, customHourNumber, customMinNumber, customSecNumber }, (365 - customClock.days < 100) ? 365 - customClock.days : 70); + } } -function activateLightMode() { - icon.innerHTML = ``; - body.classList.toggle("light"); +function displayClockRow() { + let customRow = document.getElementById("customDisplay"); + // show row + customRow.style.display = 'block'; +} +/* //restart the clock +function restartTime() { + if (customClockMovement) { + return; + } else { + startClock(); + } +} +*/ +//stop the clock + function stopClock() { + clearTimeout(intervalID); + customClockMovement = false; } -function activateDarkMode() { - icon.innerHTML = ``; - body.classList.toggle("light"); +//for the animated Countdown +function animateValue(domElement, start, end, duration) { + let startTimestamp = null; + const step = (timestamp) => { + if (!startTimestamp) startTimestamp = timestamp; + const progress = Math.min((timestamp - startTimestamp) / duration, 1); + setInnerHtmlForNotNull(domElement, addZeros(Math.floor(progress * (end - start) + start))) + if (progress < 1) { + window.requestAnimationFrame(step); + // animationComplete = false; + } + }; + window.requestAnimationFrame(step); } -function setMode() { - if (!body.classList.contains("light")) { - activateLightMode(); - } else { - activateDarkMode(); - } +async function stepIncreaseAndStart(clockElement, domElements, speed = 50, start_num = 0) { + animateValue(domElements.dayNumber, start_num, clockElement.days, speed); + animateValue(domElements.hourNumber, start_num, clockElement.hours, speed); + animateValue(domElements.minNumber, start_num, clockElement.minutes, speed); + animateValue(domElements.secNumber, start_num, clockElement.seconds, speed); + } -function notifyMode() { - let notifyText; - if (body.classList.contains("light")) { - notifyText = "Light mode set"; - } else { - notifyText = "Dark mode set"; - } - if (document.getElementsByClassName("mode-info")[0]) { - document.getElementsByClassName("mode-info")[0].remove(); - body.insertAdjacentHTML( - "afterbegin", - `${notifyText}` - ); - } else { - body.insertAdjacentHTML( - "afterbegin", - `${notifyText}` - ); +function addWhatappEventHandler() { + let whatsappIcon = document.getElementById('sendWhatsappButton'); + if (whatsappIcon) { + whatsappIcon.addEventListener('click', exportToWhatsapp); } + +} + +function exportToWhatsapp() { + let dayNum = dayCount.innerText; + window.open(`whatsapp://send?text= Day ${dayNum || 'rcountdown'}/365`); +} + +function setInnerHtmlForNotNull(element, value){ + if(element)//check for null + element.innerHTML = value; +} +try { + //show day value before animation runs +setInnerHtmlForNotNull(dayCount, dayClock.countDays()); + +// startTime(); +waitForAnimation(myclock, { dayNumber, hourNumber, minNumber, secNumber }, animatedCountDuration); +addWhatappEventHandler(); +// as; +} catch (error) { + errorHandler("Error in clock"); + console.log(error); } -startClock(); -autoLight(); -// init events -icon.addEventListener("click", setMode); -icon.addEventListener("click", notifyMode); -//Prefer this -// startButton.addEventListener("click", restartTime); -// endButton.addEventListener("click", stopClock); // service worker + if('serviceWorker' in navigator){ window.addEventListener('load', () => { navigator.serviceWorker.register('/sw.js') - .then( (reg)=> console.log('service worker registered', reg)) + .then( (reg)=>{ + console.log('service worker registered', reg) + }) .catch((err)=> console.log('Service worker not registered', err)); }); diff --git a/authors.html b/authors.html deleted file mode 100644 index 8d365788..00000000 --- a/authors.html +++ /dev/null @@ -1,76 +0,0 @@ - - - - - - - - - - - - - - - Final Countdown - - - - - - - - -
-
-
- -
- -
- -
- - - Back to clock -
-
-
- - - - \ No newline at end of file diff --git a/clock.js b/clock.js deleted file mode 100644 index 3f78d692..00000000 --- a/clock.js +++ /dev/null @@ -1,30 +0,0 @@ -export default class Clock { - constructor() { - this.setEndDate() - this.countDown(); - } - setEndDate() { - this.endDate = new Date(`Jan 1, ${new Date().getFullYear() + 1} 00:00:00`) - //account for leap year - this.dayLength = ((this.endDate.getFullYear() % 4 != 0) ? 365 : 366) - } - countDown() { - // Set the date we're counting down to - let countDownDate = this.endDate.getTime(); - let now = new Date().getTime(); - var distance = countDownDate - now; - // account for case of the countdown being reached, reset - if (distance >= 0) { - // Time calculations for days, hours, minutes and seconds - this.days = Math.floor(distance / (1000 * 60 * 60 * 24)); - this.hours = Math.floor((distance % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60)); - this.minutes = Math.floor((distance % (1000 * 60 * 60)) / (1000 * 60)); - this.seconds = Math.floor((distance % (1000 * 60)) / 1000); - } else { - this.setEndDate() - } - } - countDays() { - return this.dayLength - this.days - } -} \ No newline at end of file diff --git a/css/authors.css b/css/authors.css new file mode 100644 index 00000000..b9c88b0c --- /dev/null +++ b/css/authors.css @@ -0,0 +1,366 @@ +@import url("https://fonts.googleapis.com/css2?family=Nunito:wght@500&display=swap"); +/* basic reset */ +*, +*::before, +*::after { + box-sizing: border-box; + margin: 0; + padding: 0; + user-select: none; +} + +/* mode variables */ +:root{ + --color-muted: rgba(255, 255, 255, 0.15); + --color-banner: #7b68ee; + --timer-grad: rgba(255, 255, 255, 0.5); + --bg-url: url("../img/bg.svg"); + --bg-sidebar: var(--color-banner); + --bg-modeToggle: rgba(0, 0, 0, 0.2); + --bg-sidebar: #7b68ee; + --bg-sidebarListHover: rgba(0, 0, 0, 0.1); + --color-sidebar: white; +} +.dark{ + --bg-color: #1b182c; + --color-text: white; + --bg-timer: #474650; +} +.light { + --bg-color: #dbdbdb; + --color-muted: rgba(255, 255, 255, 0.3); + --color-text: var(--color-banner); + --bg-timer: whitesmoke; + --timer-grad: rgba(255, 255, 255, 0.8); + --timer-box: 0 0 5px 1px rgba(0, 0, 0, 0.1); +} +body { + background: var(--bg-url) var(--bg-color) center no-repeat fixed; + background-size: cover; + background-blend-mode: overlay; + transition: background-color 0.2s ease, color 0.2s ease; + color: var(--color-text); + font-family: "Nunito", sans-serif; + width: 100vw; + height: 100vh; +} +.header{ + position: fixed; + top: 0; + background: var(--color-banner); + width: 100vw; + height: 10vh; + display: flex; + align-items: center; + justify-content: space-between; + z-index: 1; +} +.logo{ + display: inline-flex; + gap: 1rem; + height: 7vh; +} +.logo-name{ + text-align: center; + font-size: 5vh; + color: var(--color-sidebar); + /* margin-left: 1rem; incase logo gap doesn't work on mobile browsers */ +} +.logo-ico img{ + width: 7vh; + height: 7vh; + border-radius: 0.9rem; +} +.sidebar{ + position: fixed; + top: 0; + left: -100%; + z-index: 3; + width: 65vmin; + height: 100vh; + background: var(--bg-sidebar); + color: var(--color-sidebar); + box-shadow: var(--timer-box); + overflow: hidden; + transition: left .02s ease-in; + backdrop-filter: blur(1px); + box-shadow: 0 1px 5px 1px rgba(0, 0, 0, 0.2); +} +.sidebar-content{ + display: flex; + justify-content: start; + align-items: flex-start; + flex-direction: column; + width: 100%; + height: 100%; + margin-left: 5vmin; +} +.sidebar-show{ + left: 0%; +} +.sidebar-hide{ + left: -100%; +} +.nav,.sidebar-close{ + display: inline-flex; + align-items: center; + justify-content: center; + padding: 0.3rem 0.4rem; + border-radius: 1vmin; + border: 0.13rem solid white; +} +.sidebar-close{ + right: 0%; + position: absolute; +} +.nav{ + width: 6vh; + height: 6vh; + color: var(--color-sidebar); + margin-left: 5vmin; +} +.brand{ + display: flex; + width: 100%; + margin: 3vmin 0 3vmin 4vmin; +} +.brand-name{ + align-self: center; + font-size: 1.3em; + margin-left: 2vmin; +} +.brand-logo img{ + width: 13vmin; + height: 13vmin; + border-radius: 5vmin; +} +.opt-group{ + color: rgba(255, 255, 255, 0.575); + font-size: 0.7rem; + align-self: center; + width: 90%; + margin: 5vmin 0 1vmin 0vmin; +} +hr{color:rgba(255, 255, 255, 0.2); width: 85%;} +.sidebar-list{ + width: 90%; +} +.sidebar-list-items{ + padding: 2.5vmin 0vmin 2.5vmin 4vmin; + border-radius: 2.5vmin; + margin: 0.5rem auto; +} +.sidebar-list-items:hover{ + background: var(--bg-sidebarListHover); +} +.pick-color{ + justify-content: center; + align-items: flex-end; + gap: 0.4rem; + display: none; + width: 90%; + margin: 0.7rem; +} +.pick-color-ico{ + width: 1.8rem; + height: 1.8rem; + border-radius: 50%; + box-shadow: 0px 0px 1px 0px rgba(0, 0, 0, 0.15); + border: white solid 2px; +} +.pick-color-ico:nth-child(1){ + background: #fe2164; + outline: #fe2164 solid 2px; +} +.pick-color-ico:nth-child(6){ + background: #7b68ee; + outline: #7b68ee solid 2px; +} +.pick-color-ico:nth-child(4){ + background: #1cb65d; + outline: #1cb65d solid 2px; +} +.pick-color-ico:nth-child(5){ + background: #2f8bfc; + outline: #2f8bfc solid 2px; +} +.pick-color-ico:nth-child(3){ + background: #ffc000; + outline: #ffc000 solid 2px; +} +.pick-color-ico:nth-child(2){ + background: #e685b5; + outline: #e685b5 solid 2px; +} +.show-color{ + display: inline-flex; +} + +main{ + width: 100vw; + height: 100vh; +} +.container { + height: 100vh; + width: 100vw; + display: flex; + align-items: center; + flex-direction: column; + gap: 2.5em; + overflow-x: hidden; + padding-top: 13vh; +} + +.mode-info { + background: var(--bg-color); + border-radius: 0.3rem; + color: var(--color-text); + padding: 0.2rem 0.8rem; + -webkit-animation: slide-in 0.2s ease-in forwards, fade-out 2s ease 0.9s forwards; + animation: slide-in 0.2s ease-in forwards, fade-out 2s ease 0.9s forwards; + position: fixed; + left: 50%; + top: -10rem; + transform: translateX(-50%); + z-index: 100; +} + +.light .mode-info { + background: aliceblue; +} +@keyframes slide-in { + to { + top: 2rem; + } +} +@keyframes fade-out { + to { + opacity: 0; + } +} +a{ + text-decoration: none; color: inherit; +} + +.toggleMode { + font-size: 1.4em; + right: 0.8rem; + top: 0.3rem; + width: 1.5em; + height: 1.5em; + display: flex; + justify-content: center; + align-items: center; + border-radius: 50%; + background: var(--bg-modeToggle); + color: #f2e7ac; + z-index: 1; + margin-right: 5vmin; +} + +.banner-row { + display: flex; + justify-content: center; + align-items: center; + font-weight: bold; + font-size: 5vmin; + text-align: center; + width: 100%; +} + +.banner { + padding: 0.5em 1rem; + border-radius: 0.1em; + min-width: 80vmin; + color: var(--color-text); + border-bottom: 0.5rem solid var(--color-banner); +} +.day{ + font-size: 1.7em; + color: var(--color-text); +} + +.clock-row { + position: relative; + display: flex; + flex-direction: column; + text-align: center; + width: 100vw; + align-items: center; + justify-content: center; + border-radius: 0.2em; + padding: 10px; + gap: 5vmin; +} + +.timer{ + font-size: 1rem; + position: relative; + display: flex; + justify-content: center; + align-items: center; + width: 36vmin;height: 35vmin; + border: 2px solid rgba(255, 255, 255, 0.2); + border-radius: .7em; + background: linear-gradient(90deg,var(--color-muted) 50%, var(--timer-grad) 50%); + margin-bottom: 1rem; + backdrop-filter: blur(1px); + color: var(--color-text); +} +.light .timer{ + border: 2px solid rgba(255, 255, 255, 0.7); + box-shadow: var(--timer-box); +} +.timer-num{ + font-size: 13vmin; +} +.timer-text{ + content: ""; + position: absolute; + bottom: -1em; + background: var(--bg-timer); + border-radius: 0.3em; + padding: .5em; + text-align: center; + width: 18vmin; + overflow: clip; + transition: background-color 0.2s ease; +} +.light .timer-text{ + box-shadow: var(--timer-box); +} +/* desktop */ +@media screen and (min-width: 750px) and (orientation: landscape) { + body { + overflow-y: hidden; + } + .container{ + gap: 4em; + } + .banner { + width: 21em; + } + .clock-row { + font-size: 25vmin; + flex-direction: row; + gap: 10vmin; + } +} +/* mobile and small screens */ +@media screen and (max-width: 427px) { + .container{ + gap: 1.6em; + } + .logo-name{ + display: none; + } + .timer-text{ + font-size: 0.75rem; + } + .sidebar{ + width: 75vmin; + } + .new-item{ + bottom: 10vh; + } +} \ No newline at end of file diff --git a/css/countdown-list.css b/css/countdown-list.css new file mode 100644 index 00000000..01f74b90 --- /dev/null +++ b/css/countdown-list.css @@ -0,0 +1,501 @@ +@import url("https://fonts.googleapis.com/css2?family=Nunito:wght@500&display=swap"); +/* basic reset */ +*, +*::before, +*::after { + box-sizing: border-box; + margin: 0; + padding: 0; + user-select: none; +} + +/* mode variables */ +:root{ + --color-muted: rgba(255, 255, 255, 0.15); + --color-banner: #7b68ee; + --timer-grad: rgba(255, 255, 255, 0.5); + --bg-url: url("../img/bg.svg"); + --bg-sidebar: var(--color-banner); + --bg-modeToggle: rgba(0, 0, 0, 0.2); + --bg-sidebar: #7b68ee; + --bg-sidebarListHover: rgba(0, 0, 0, 0.1); + --color-sidebar: white; + --color-cdList: white; + --bg-cdListHover: #303041; + overflow-x: hidden; +} +.dark{ + --bg-color: #1b182c; + --color-text: white; + --bg-timer: #474650; + --bg-cdList: #3b3b50; +} +.light { + --bg-color: #dbdbdb; + --color-muted: rgba(255, 255, 255, 0.3); + --color-text: var(--color-banner); + --bg-timer: whitesmoke; + --timer-grad: rgba(255, 255, 255, 0.8); + --timer-box: 0 0 5px 1px rgba(0, 0, 0, 0.1); + --color-cdList: var(--color-banner); + --bg-cdList: #f0f0f0; + --bg-cdListHover: #ffffff; +} +/* hide the custom clock at start */ +#customDisplay{ + display: none; +} +body { + background: var(--bg-url) var(--bg-color) center no-repeat fixed; + background-size: cover; + background-blend-mode: overlay; + transition: background-color 0.2s ease, color 0.2s ease; + color: var(--color-text); + font-family: "Nunito", sans-serif; + width: 100vw; + height: 100vh; +} +main{ + width: 100vw; + height: 100%; + padding-top: 10vh; +} +.container { + height: 100%; + width: 100vw; + display: flex; + align-items: center; + flex-direction: column; + gap: 2em; + overflow: hidden; + position: relative; +} + +.mode-info { + background: var(--bg-color); + border-radius: 0.3rem; + color: var(--color-text); + padding: 0.2rem 0.8rem; + -webkit-animation: slide-in 0.2s ease-in forwards, fade-out 2s ease 0.9s forwards; + animation: slide-in 0.2s ease-in forwards, fade-out 2s ease 0.9s forwards; + position: fixed; + left: 50%; + top: -10rem; + transform: translateX(-50%); + z-index: 100; +} + +.light .mode-info { + background: aliceblue; +} + +@-webkit-keyframes slide-in { + to { + top: 2rem; + } +} +@keyframes slide-in { + to { + top: 2rem; + } +} +@-webkit-keyframes fade-out { + to { + opacity: 0; + } +} +@keyframes fade-out { + to { + opacity: 0; + } +} + + +.toggleMode { + font-size: 1.4em; + right: 0.8rem; + top: 0.3rem; + width: 1.5em; + height: 1.5em; + display: flex; + justify-content: center; + align-items: center; + border-radius: 50%; + background: var(--bg-modeToggle); + color: #f2e7ac; + z-index: 1; + margin-right: 5vmin; +} + +.banner-row { + display: flex; + justify-content: center; + align-items: center; + font-weight: bold; + font-size: 1.7rem; + text-align: center; + width: 100%; +} + +.banner { + padding: 0.5em 1rem; + border-radius: 0.1em; + min-width: 80vmin; + color: var(--color-text); + border-bottom: 0.5rem solid var(--color-banner); +} +.banner-h2{ + font-size: 0.7em; + font-weight: lighter; + letter-spacing: 0.3em; +} +.day{ + font-size: 1.77em; +} + +.clock-row { + position: sticky; + display: flex; + flex-direction: row; + text-align: center; + /* width: 100vw; */ + align-items: center; + justify-content: center; + border-radius: 0.2em; + gap: 1rem; + display: none; + animation: expand 0.05s forwards ease; + animation-play-state: paused; +} +@keyframes expand { + from{ + width: 0; + } + to{ + width: 100vw; + } +} + +.timer{ + font-size: 1rem; + position: relative; + display: flex; + justify-content: center; + align-items: center; + width: 18vmin; + height: 18vmin; + border: 2px solid rgba(255, 255, 255, 0.2); + border-radius: .5rem; + background: linear-gradient(90deg,var(--color-muted) 50%, var(--timer-grad) 50%); + margin-bottom: 1rem; + backdrop-filter: blur(1px); +} +.light .timer{ + border: 2px solid rgba(255, 255, 255, 0.7); + box-shadow: var(--timer-box); +} +.timer-num{ + font-size: 9vmin; +} +.timer-text{ + font-size: 2.5vmin; + content: ""; + position: absolute; + bottom: -1em; + background: var(--bg-timer); + border-radius: 0.3em; + padding: .5em; + text-align: center; + width: 13vmin; + overflow: clip; + transition: background-color 0.2s ease; +} +.light .timer-text{ + box-shadow: var(--timer-box); +} +.header{ + position: fixed; + top: 0; + background: var(--color-banner); + width: 100vw; + height: 10vh; + display: flex; + align-items: center; + justify-content: space-between; + z-index: 1; +} +.logo{ + display: inline-flex; + gap: 1rem; + height: 7vh; +} +.logo-name{ + text-align: center; + font-size: 2rem; + color: var(--color-sidebar); + /* margin-left: 1rem; incase logo gap doesn't work on mobile browsers */ +} +.logo-ico img{ + width: 7vh; + height: 7vh; + border-radius: 0.9rem; +} +.sidebar{ + position: fixed; + top: 0; + left: -100%; + z-index: 3; + width: 65vmin; + height: 100vh; + background: var(--bg-sidebar); + color: var(--color-sidebar); + box-shadow: var(--timer-box); + overflow: hidden; + transition: left .02s ease-in; + backdrop-filter: blur(1px); + box-shadow: 0 1px 5px 1px rgba(0, 0, 0, 0.2); +} +.sidebar-content{ + display: flex; + justify-content: start; + align-items: flex-start; + flex-direction: column; + width: 100%; + height: 100%; + margin-left: 5vmin; +} +.sidebar-show{ + left: 0%; +} +.sidebar-hide{ + left: -100%; +} +.nav,.sidebar-close{ + display: inline-flex; + align-items: center; + justify-content: center; + padding: 0.3rem 0.4rem; + border-radius: 1vmin; + border: 0.13rem solid white; +} +.sidebar-close{ + right: 0%; + position: absolute; +} +.nav{ + width: 6vh; + height: 6vh; + color: var(--color-sidebar); + margin-left: 5vmin; +} +.brand{ + display: flex; + width: 100%; + margin: 3vmin 0 3vmin 4vmin; +} +.brand-name{ + align-self: center; + font-size: 1.3em; + margin-left: 2vmin; +} +.brand-logo img{ + width: 13vmin; + height: 13vmin; + border-radius: 5vmin; +} +.opt-group{ + color: rgba(255, 255, 255, 0.575); + font-size: 0.7rem; + align-self: center; + width: 90%; + margin: 5vmin 0 1vmin 0vmin; +} +hr{color:rgba(255, 255, 255, 0.2); width: 85%;} +.sidebar-list{ + width: 90%; +} +.sidebar-list-items{ + padding: 2.5vmin 0vmin 2.5vmin 4vmin; + border-radius: 2.5vmin; + margin: 0.5rem auto; +} +.sidebar-list-items:hover{ + background: var(--bg-sidebarListHover); +} +.pick-color{ + justify-content: center; + align-items: flex-end; + gap: 0.4rem; + display: none; + width: 90%; + margin: 0.7rem; +} +.pick-color-ico{ + width: 1.8rem; + height: 1.8rem; + border-radius: 50%; + box-shadow: 0px 0px 1px 0px rgba(0, 0, 0, 0.15); + border: white solid 2px; +} +.pick-color-ico:nth-child(1){ + background: #fe2164; + outline: #fe2164 solid 2px; +} +.pick-color-ico:nth-child(6){ + background: #7b68ee; + outline: #7b68ee solid 2px; +} +.pick-color-ico:nth-child(4){ + background: #1cb65d; + outline: #1cb65d solid 2px; +} +.pick-color-ico:nth-child(5){ + background: #2f8bfc; + outline: #2f8bfc solid 2px; +} +.pick-color-ico:nth-child(3){ + background: #ffc000; + outline: #ffc000 solid 2px; +} +.pick-color-ico:nth-child(2){ + background: #e685b5; + outline: #e685b5 solid 2px; +} +.show-color{ + display: inline-flex; +} + +.new-item{ + position: fixed; + display: flex; + align-items: center; + justify-content: center; + width: 3.5rem; + height: 3.5rem; + border-radius: 50%; + background-color: var(--bg-newItem); + box-shadow: 0 0 5px 1px rgba(0, 0, 0, 0.1); + z-index: 2; + color: var(--color-text); + bottom: 6vh; + right: 50%; + transform: translateX(50%); +} + +.list-container{ + width: 100vw; + height: 100vh; + overflow-y: auto; + overflow-x: hidden; +} +.countdown-list{ + display: flex; + width: 100vw; + flex-direction: column-reverse; + justify-content: center; + align-items: center; + gap: 0.9rem; + overflow-y: auto; + padding-bottom: 10vh; +} +.countdown-list-item:hover{ +background: var(--bg-cdListHover); +box-shadow: inset 0 0 0vmin .4vmin var(--color-banner); +/* border: solid .2vmin var(--color-banner); */ +} +.countdown-list-item{ + background: var(--bg-cdList); + color: var(--color-cdList); + border-radius: .3rem; + width: 80vmin; + display: grid; + grid-template-areas: + 'note options' + 'date options'; +grid-template-columns: 6fr 1fr; +padding: 0 0 0 1rem; +} +.countdown-list-text{ + grid-area: note; + font-size: 1.25rem; + padding: 1rem; + border-right: 1px solid rgba(0, 0, 0, 0.1); + +} +.countdown-list-options{ + grid-area: options; + display: flex; + width: 100%; + height: 100%; + justify-content: center; + align-items: center; + /* border: #1cb65d solid 2px; */ + position: relative; +} +.countdown-list-date{ + grid-area: date; + font-size: 0.65rem; + padding-left: 1rem; + padding-bottom: 0.2rem; + border-right: 1px solid rgba(0, 0, 0, 0.1); +} + +.menu{ + box-shadow: 0 0 5px 1px rgba(0, 0, 0, 0.2); ; + position: absolute; + right: 0; + top: 60%; + width: 30vmin; + border-radius: 0.2rem; + color: var(--color-text);background: var(--bg-timer); + z-index: 2; +} +.menu-opts{ + padding: .2rem; + border-bottom: 1px solid rgba(0, 0, 0, 0.05); +} +.menu-opts:hover{ + background:rgba(0, 0, 0, 0.1); +} + +/* desktop */ +@media screen and (min-width: 750px) and (orientation: landscape) { + .banner { + width: 21em; + } + .clock-row { + /* font-size: 25vmin; */ + gap: 2rem; + } + .clock-row::after, + .clock-row::before { + width: 1.8em; + height: 1.8em; + } + .new-item{ + right: 10vmin; + bottom: 10vmin; + transform: translateX(0%); + } +} +/* mobile and small screens */ +@media screen and (max-width: 427px) { + .container{ + gap: 1em; + } + .banner-row{ + font-size: 1.3rem; + } + .logo-name{ + display: none; + } + .sidebar{ + width: 75vmin; + } +.countdown-list-item{ + grid-template-columns: 5.7fr 1.3fr; +} +.menu{ + width: 38vmin; +} +} \ No newline at end of file diff --git a/css/form.css b/css/form.css new file mode 100644 index 00000000..a1fac10f --- /dev/null +++ b/css/form.css @@ -0,0 +1,122 @@ +/* generic */ +.pop-up-container{ + position: absolute; + top: 0; + width: 100vw; + height: 100vh; + display: flex; + align-items: center; + justify-content: center; + backdrop-filter: blur(5px); + z-index: 10; +} +.pop-up-form{ + position: relative; + width: 80vmin; + height: 80vmin; + display: flex; + align-items: center; + justify-content: center; + flex-flow: column nowrap; + background: #f0f0f0; + box-shadow: var(--timer-box); + border-radius: 0.2rem; + gap: 3vmin; + color: var(--color-banner); +} +.form-header{ + position: absolute; + top: 5vmin; + font-size: 6vmin; + text-transform: uppercase; + font-weight: bold; +} +.close-form{ + position: absolute; + bottom: 3vmin; +} +.close-form button{ + padding: 2vmin 5vmin; + border-radius: .3rem; + border: solid 1px var(--color-banner); + color: var(--color-banner); +} + +/* create countdown form */ +input[type="text"],input[type="datetime-local"]{ + width: 65vmin; + padding: 3vmin; + border-radius: 2vmin; + border: var(--color-banner) solid 1px; + outline: none; +} +input[type="submit"],.reset button{ + padding: 2vmin 6vmin; + border-radius: .3rem; + border: none; + background: var(--color-banner); + color: white; +} +input[type="submit"]:hover,.reset button:hover{ + background: var(--color-banner); + filter:saturate(1.5); + box-shadow: inset 0px 0px 0px 2px var(--color-sidebar), + inset 0px 0px 0px 2px var(--color-sidebar), + 0 0 0 1px var(--color-banner); +} +input[type="submit"]:disabled{ + background: grey; + color: white; + cursor: not-allowed; + /* border: 1px solid grey; */ + box-shadow: inset 0px 0px 0px 2px var(--color-sidebar), + inset 0px 0px 0px 2px var(--color-sidebar), + 0 0 0 1px grey; +} +.form-sections{ + display: inline-flex; + flex-direction: column; + gap: 2vmin; +} + +/* upload image form */ +.bg-presets { + display: flex; + width: 82%; + align-items: center; + justify-content: center; + flex-flow: row wrap; + overflow: hidden; + gap: 1vmin; +} +.bg-presets-preview { + width: 16vmin; + height: 16vmin; +} +.bg-presets-preview img { + width: 16vmin; + height: 16vmin; +} +label[for="upload"] { + display: flex; + width: 100%; + height: 100%; + align-items: center; + justify-content: center; + background-color: rgba(0, 0, 0, 0.1); +} +label[for="upload-info"] { + font-size: 0.6rem; + font-style: italic; +} +input[type="file"] { + display: none; + appearance: none; +} + +/* mobile and small screens */ +@media screen and (max-width: 427px) { + .pop-up-form { + height: 90vmin; + } +} \ No newline at end of file diff --git a/css/styles.css b/css/styles.css new file mode 100644 index 00000000..29f313d4 --- /dev/null +++ b/css/styles.css @@ -0,0 +1,448 @@ +@import url("https://fonts.googleapis.com/css2?family=Nunito:wght@500&display=swap"); +/* basic reset */ +*, +*::before, +*::after { + box-sizing: border-box; + margin: 0; + padding: 0; +} + +/* mode variables */ +:root{ + --color-muted: rgba(255, 255, 255, 0.15); + --color-banner: #7b68ee; + --timer-grad: rgba(255, 255, 255, 0.5); + --bg-url: url("../img/bg.svg"); + --bg-sidebar: var(--color-banner); + --bg-modeToggle: rgba(0, 0, 0, 0.2); + --bg-sidebar: #7b68ee; + --bg-sidebarListHover: rgba(0, 0, 0, 0.1); + --color-sidebar: white; +} +.dark{ + --bg-color: #1b182c; + --color-text: white; + --bg-timer: #474650; +} +.light { + --bg-color: #dbdbdb; + --color-muted: rgba(255, 255, 255, 0.3); + --color-text: var(--color-banner); + --bg-timer: whitesmoke; + --timer-grad: rgba(255, 255, 255, 0.8); + --timer-box: 0 0 5px 1px rgba(0, 0, 0, 0.1); +} +/* hide the custom clock at start */ +#customDisplay{ + display: none; +} +body { + background: var(--bg-url) var(--bg-color) center no-repeat fixed; + background-size: cover; + background-blend-mode: overlay; + transition: background-color 0.2s ease, color 0.2s ease; + color: var(--color-text); + font-family: "Nunito", sans-serif; + width: 100vw; + height: 100vh; +} +main{ + width: 100vw; + height: 100vh; + margin-top: 10vh; +} +.container { + height: 100vh; + width: 100vw; + display: flex; + align-items: center; + flex-direction: column; + gap: 2.5em; + overflow-x: hidden; +} + +.mode-info { + background: var(--bg-color); + border-radius: 0.3rem; + color: var(--color-text); + padding: 0.2rem 0.8rem; + -webkit-animation: slide-in 0.2s ease-in forwards, fade-out 2s ease 0.9s forwards; + animation: slide-in 0.2s ease-in forwards, fade-out 2s ease 0.9s forwards; + position: fixed; + left: 50%; + top: -10rem; + transform: translateX(-50%); + z-index: 100; +} + +.light .mode-info { + background: aliceblue; +} + +.link{ + color: var(--color-text); + text-decoration: none; +} +@-webkit-keyframes slide-in { + to { + top: 2rem; + } +} +@keyframes slide-in { + to { + top: 2rem; + } +} +@-webkit-keyframes fade-out { + to { + opacity: 0; + } +} +@keyframes fade-out { + to { + opacity: 0; + } +} + + +.toggleMode { + font-size: 1.4em; + right: 0.8rem; + top: 0.3rem; + width: 1.5em; + height: 1.5em; + display: flex; + justify-content: center; + align-items: center; + border-radius: 50%; + background: var(--bg-modeToggle); + color: #f2e7ac; + z-index: 1; + margin-right: 5vmin; +} + +.banner-row { + display: flex; + justify-content: center; + align-items: center; + font-weight: bold; + font-size: 1.7rem; + text-align: center; + width: 100%; +} + +.banner { + padding: 0.5em 1rem; + border-radius: 0.1em; + min-width: 80vmin; + color: var(--color-text); + border-bottom: 0.5rem solid var(--color-banner); +} +.banner-h2{ + font-size: 0.7em; + font-weight: lighter; + letter-spacing: 0.3em; +} +.day{ + font-size: 1.77em; +} + +.clock-row { + position: relative; + display: flex; + flex-direction: column; + text-align: center; + width: 100vw; + align-items: center; + justify-content: center; + border-radius: 0.2em; + padding: 10px; + gap: 1rem; +} + +.timer{ + font-size: 1rem; + position: relative; + display: flex; + justify-content: center; + align-items: center; + width: 25vmin; + height: 25vmin; + border: 2px solid rgba(255, 255, 255, 0.2); + border-radius: .7em; + background: linear-gradient(90deg,var(--color-muted) 50%, var(--timer-grad) 50%); + margin-bottom: 1rem; + backdrop-filter: blur(1px); +} +.light .timer{ + border: 2px solid rgba(255, 255, 255, 0.7); + box-shadow: var(--timer-box); +} +.timer-num{ + font-size: 13vmin; +} +.timer-text{ + content: ""; + position: absolute; + bottom: -1em; + background: var(--bg-timer); + border-radius: 0.3em; + padding: .5em; + text-align: center; + width: 18vmin; + overflow: clip; + transition: background-color 0.2s ease; +} +.light .timer-text{ + box-shadow: var(--timer-box); +} + +.controls-row { + display: flex; + flex-flow: column nowrap; + margin-bottom: 5vh; + gap: 1em; + width: 100vw; + height: 20vh; + align-items: center; + justify-content: center; +} + +.author{ + /* position: absolute; + bottom: 15px; + left: 20px; */ + font-size: 0.7em; + color: var(--color-text) +} + +.author:hover{ + color: var(--color-banner) +} +.header{ + position: fixed; + top: 0; + background: var(--color-banner); + width: 100vw; + height: 10vh; + display: flex; + align-items: center; + justify-content: space-between; + z-index: 1; +} +.logo{ + display: inline-flex; + gap: 1rem; + height: 7vh; +} +.logo-name{ + text-align: center; + font-size: 5vh; + color: var(--color-sidebar); + /* margin-left: 1rem; incase logo gap doesn't work on mobile browsers */ +} +.logo-ico img{ + width: 7vh; + height: 7vh; + border-radius: 0.9rem; +} +.sidebar{ + position: fixed; + top: 0; + left: -100%; + z-index: 3; + width: 65vmin; + height: 100vh; + background: var(--bg-sidebar); + color: var(--color-sidebar); + box-shadow: var(--timer-box); + overflow: hidden; + transition: left .02s ease-in; + backdrop-filter: blur(1px); + box-shadow: 0 1px 5px 1px rgba(0, 0, 0, 0.2); +} +.sidebar-content{ + display: flex; + justify-content: start; + align-items: flex-start; + flex-direction: column; + width: 100%; + height: 100%; + margin-left: 5vmin; +} +.sidebar-show{ + left: 0%; +} +.sidebar-hide{ + left: -100%; +} +.nav,.sidebar-close{ + display: inline-flex; + align-items: center; + justify-content: center; + padding: 0.3rem 0.4rem; + border-radius: 1vmin; + border: 0.13rem solid white; +} +.sidebar-close{ + right: 0%; + position: absolute; +} +.nav{ + width: 6vh; + height: 6vh; + color: var(--color-sidebar); + margin-left: 5vmin; +} +.brand{ + display: flex; + width: 100%; + margin: 3vmin 0 3vmin 4vmin; +} +.brand-name{ + align-self: center; + font-size: 1.3em; + margin-left: 2vmin; +} +.brand-logo img{ + width: 13vmin; + height: 13vmin; + border-radius: 5vmin; +} +.opt-group{ + color: rgba(255, 255, 255, 0.575); + font-size: 0.7rem; + align-self: center; + width: 90%; + margin: 5vmin 0 1vmin 0vmin; +} +hr{color:rgba(255, 255, 255, 0.2); width: 85%;} +.sidebar-list{ + width: 90%; +} +.sidebar-list-items{ + padding: 2.5vmin 0vmin 2.5vmin 4vmin; + border-radius: 2.5vmin; + margin: 0.5rem auto; +} +.sidebar-list-items:hover{ + background: var(--bg-sidebarListHover); +} +.pick-color{ + justify-content: center; + align-items: flex-end; + gap: 0.4rem; + display: none; + width: 90%; + margin: 0.7rem; +} +.pick-color-ico{ + width: 1.8rem; + height: 1.8rem; + border-radius: 50%; + box-shadow: 0px 0px 1px 0px rgba(0, 0, 0, 0.15); + border: white solid 2px; +} +.pick-color-ico:nth-child(1){ + background: #fe2164; + outline: #fe2164 solid 2px; +} +.pick-color-ico:nth-child(6){ + background: #7b68ee; + outline: #7b68ee solid 2px; +} +.pick-color-ico:nth-child(4){ + background: #1cb65d; + outline: #1cb65d solid 2px; +} +.pick-color-ico:nth-child(5){ + background: #2f8bfc; + outline: #2f8bfc solid 2px; +} +.pick-color-ico:nth-child(3){ + background: #ffc000; + outline: #ffc000 solid 2px; +} +.pick-color-ico:nth-child(2){ + background: #e685b5; + outline: #e685b5 solid 2px; +} +.show-color{ + display: inline-flex; +} + +.new-item{ + position: fixed; + display: flex; + align-items: center; + justify-content: center; + width: 3.5rem; + height: 3.5rem; + border-radius: 50%; + right: 10vmin; + bottom: 10vmin; + background-color: var(--bg-newItem); + box-shadow: 0 0 5px 1px rgba(0, 0, 0, 0.1); + z-index: 2; + color: var(--color-text); +} + +/* desktop */ +@media screen and (min-width: 750px) and (orientation: landscape) { + body { + overflow-y: hidden; + } + .container{ + gap: 4em; + } + .banner { + width: 21em; + } + .clock-row { + font-size: 25vmin; + flex-direction: row; + gap: 2rem; + } + .clock-row::after, + .clock-row::before { + width: 1.8em; + height: 1.8em; + } + .controls-row { + flex-flow: row nowrap; + gap: 4em; + } + #sendWhatsappButton{ + display: none; + } +} +/* mobile and small screens */ +@media screen and (max-width: 427px) { + .container{ + gap: 1.6em; + } + .banner-row{ + font-size: 1.3rem; + } + .logo-name{ + display: none; + } + .timer-text{ + font-size: 0.75rem; + } + .sidebar{ + width: 75vmin; + } + .new-item{ + bottom: 10vh; + } +/* temporary fix */ + .clock-row{ + justify-content: normal; + } +} + +.countdown-list-item:hover{ + background-color: #130752; +} \ No newline at end of file diff --git a/css/themes.css b/css/themes.css new file mode 100644 index 00000000..3174aac9 --- /dev/null +++ b/css/themes.css @@ -0,0 +1,96 @@ +[data-theme="blue"] { + --color-banner: #2f8bfc; + --color-text: var(--color-banner); + --bg-modeToggle: rgba(0, 0, 0, 0.2); + --bg-sidebar: rgba(47, 139, 252, 0.95); + --bg-sidebarListHover: rgba(0, 0, 0, 0.1); + --bg-newItem: white; +} +.dark[data-theme="blue"] { + --bg-color: #182635; + --color-text: white; + --bg-timer: #56636f; + --bg-cdList:#3f4d61; + --bg-cdListHover: #384557; + --bg-newItem: var(--color-banner); +} +[data-theme="green"] { + --color-banner: #1cb65d; + --color-text: var(--color-banner); + --bg-modeToggle: rgba(0, 0, 0, 0.2); + --bg-sidebar: rgba(28, 182, 92, 0.95); + --bg-sidebarListHover: rgba(0, 0, 0, 0.1); + --bg-newItem: white; +} +.dark[data-theme="green"] { + --bg-color: #18351e; + --color-text: white; + --bg-timer: #506b51; + --bg-cdList:#3a644c; + --bg-cdListHover: #2a553d; + --bg-newItem: var(--color-banner); +} +[data-theme="red"] { + --color-banner: #fe2164; + --color-text: var(--color-banner); + --bg-modeToggle: rgba(0, 0, 0, 0.2); + --bg-sidebar: rgba(254, 33, 99, 0.95); + --bg-sidebarListHover: rgba(0, 0, 0, 0.1); + --bg-newItem: white; +} +.dark[data-theme="red"] { + --bg-color: #35181d; + --color-text: white; + --bg-timer: #826a6a; + --bg-cdList: #4e383d; + --bg-cdListHover: #462f35; + --bg-newItem: var(--color-banner); +} +[data-theme="purple"] { + --color-banner: #7b68ee; + --color-text: var(--color-banner); + --bg-modeToggle: rgba(0, 0, 0, 0.2); + --bg-sidebar: hsla(249, 80%, 67%, 0.95); + --bg-sidebarListHover: rgba(0, 0, 0, 0.1); + --bg-newItem: white; +} +.dark[data-theme="purple"] { + --bg-color: #1b182c; + --color-text: white; + --bg-timer: #474650; + --bg-cdList: #3b3b50; + --bg-cdListHover: #303041; + --bg-newItem: var(--color-banner); +} +[data-theme="yellow"] { + --color-banner: #ffc000; + --color-text: var(--color-banner); + --bg-modeToggle: rgba(0, 0, 0, 0.2); + --bg-sidebar: rgba(255, 191, 0, 0.95); + --bg-sidebarListHover: rgba(0, 0, 0, 0.1); + --bg-newItem: white; +} +.dark[data-theme="yellow"] { + --bg-color: #352e19; + --color-text: white; + --bg-timer: #746b50; + --bg-cdList:#584f31; + --bg-cdListHover: #504727; + --bg-newItem: var(--color-banner); +} +[data-theme="pink"] { + --color-banner: #e685b5; + --color-text: var(--color-banner); + --bg-modeToggle: rgba(0, 0, 0, 0.2); + --bg-sidebar: rgba(230, 132, 181, 0.95); + --bg-sidebarListHover: rgba(0, 0, 0, 0.1); + --bg-newItem: white; +} +.dark[data-theme="pink"] { + --bg-color: #472a39; + --color-text: white; + --bg-timer: #8b7982; + --bg-cdList: #644e59; + --bg-cdListHover: #58464f; + --bg-newItem: var(--color-banner); +} \ No newline at end of file diff --git a/html/authors.html b/html/authors.html new file mode 100644 index 00000000..3bac60d7 --- /dev/null +++ b/html/authors.html @@ -0,0 +1,117 @@ + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/html/countdown-list.html b/html/countdown-list.html new file mode 100644 index 00000000..9d3276a6 --- /dev/null +++ b/html/countdown-list.html @@ -0,0 +1,122 @@ + + + + + + + + + + Final Countdown + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
+ +
+
+ 00 + Days +
+
+ 00 + Hours +
+
+ 00 + Minutes +
+
+ 00 + Seconds +
+
+
+
+ Loading ... +
+ +
+ +
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/fallback.html b/html/fallback.html similarity index 51% rename from fallback.html rename to html/fallback.html index dd9dd7bd..00532886 100644 --- a/fallback.html +++ b/html/fallback.html @@ -8,19 +8,21 @@ Final Countdown - + - - - - - + + + + + + + - - - + + + - + @@ -31,14 +33,14 @@
- +

Back to home

@@ -46,8 +48,7 @@

- + - \ No newline at end of file diff --git a/html/form-upload.html b/html/form-upload.html new file mode 100644 index 00000000..7bf07718 --- /dev/null +++ b/html/form-upload.html @@ -0,0 +1,29 @@ +
+
+
Set Custom Bg
+
+
+ earth +
+
+ basketball_on_court +
+
+ ship_sky_balloons +
+
+ goku +
+
+ wait impatiently +
+
+
+
+ + +
+
+
+
+
\ No newline at end of file diff --git a/img/bg-light.svg b/img/bg-light.svg deleted file mode 100644 index 7fc619ec..00000000 --- a/img/bg-light.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/img/bg.svg b/img/bg.svg index c7071a0e..7fc619ec 100644 --- a/img/bg.svg +++ b/img/bg.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/img/bg/basketball_on_court.jpg b/img/bg/basketball_on_court.jpg new file mode 100644 index 00000000..25e875e8 Binary files /dev/null and b/img/bg/basketball_on_court.jpg differ diff --git a/img/bg/earth.jpg b/img/bg/earth.jpg new file mode 100644 index 00000000..eed0d302 Binary files /dev/null and b/img/bg/earth.jpg differ diff --git a/img/bg/goku.jpg b/img/bg/goku.jpg new file mode 100644 index 00000000..d5540c48 Binary files /dev/null and b/img/bg/goku.jpg differ diff --git a/img/bg/ship_sky_balloons.jpg b/img/bg/ship_sky_balloons.jpg new file mode 100644 index 00000000..dea15fd6 Binary files /dev/null and b/img/bg/ship_sky_balloons.jpg differ diff --git a/img/bg/wait_impatient.gif b/img/bg/wait_impatient.gif new file mode 100644 index 00000000..0fad85ad Binary files /dev/null and b/img/bg/wait_impatient.gif differ diff --git a/index.html b/index.html index 52aa27dd..87d99586 100644 --- a/index.html +++ b/index.html @@ -1,6 +1,5 @@ - @@ -9,31 +8,90 @@ Final Countdown - - - - + + + + + + + + + + - - + + - + - + + +
+ + +
+ +
+
-
- -
@@ -54,18 +112,18 @@ Seconds
- +
+
+
- -
- RD | Nat -
-
- - +
+ + + + + + + \ No newline at end of file diff --git a/js/clock.js b/js/clock.js new file mode 100644 index 00000000..d8346bce --- /dev/null +++ b/js/clock.js @@ -0,0 +1,66 @@ +export default class Clock { + constructor(endDate) { + // expecting a date object + this.setEndDate(endDate) + this.countDown(); + } + + setEndDate(endDate) { + //set endDate to end of year + // todo: check endDate for validity as date + this.endDate = endDate ||new Date(`Jan 1, ${new Date().getFullYear() + 1} 00:00:00`) + + + } + countDown() { + // Set the date we're counting down to + let countDownDate = this.endDate.getTime(); + let now = new Date().getTime(); + var distance = countDownDate - now; + // account for case of the countdown being reached, reset + if (distance >= 0) { + // Time calculations for days, hours, minutes and seconds + this.calculateTimeValues(distance) + } else { + //reset to end of year + // this.setEndDate() + //todo: Countup from the deadline date + // this.calculateTimeValues(Math.abs(distance)); + + // clear date values + this.resetMethod(); + + + } + } + + resetMethod(){ + this.clearCounter(); + } + + calculateTimeValues(distance){ + this.days = Math.floor(distance / (1000 * 60 * 60 * 24)); + this.years = Math.floor(this.days / this.dayLength); + this.days = this.days%this.dayLength + this.hours = Math.floor((distance % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60)); + this.minutes = Math.floor((distance % (1000 * 60 * 60)) / (1000 * 60)); + this.seconds = Math.floor((distance % (1000 * 60)) / 1000); + } + countDays() { + //account for leap year + this.dayLength = ((this.endDate.getFullYear() % 4 != 0) ? 365 : 366) + return this.dayLength - this.days + } + + clearCounter(){ + this.days=this.hours=this.minutes=this.seconds=0; + } +} + +export class NewYearClock extends Clock{ + resetMethod(){ + //reset to New Year's for default + this.setEndDate() + console.log(this.endDate) + } +} \ No newline at end of file diff --git a/js/displayCountdowns.js b/js/displayCountdowns.js new file mode 100644 index 00000000..3655c0d9 --- /dev/null +++ b/js/displayCountdowns.js @@ -0,0 +1,294 @@ +// Dom elements +// begin displaycountdown.js +var hourNumber = document.getElementById("hour-num"); +var minNumber = document.getElementById("min-num"); +var secNumber = document.getElementById("sec-num"); +var countdownTextDisplay = document.getElementById('countdown-text'); +var countdownClock = document.querySelector('.clock-row'); +var countdownList = document.getElementById('countdown-list'); +let test = false; +let arrayOfCountdowns; + + + +function stopClock() { + clearTimeout(intervalID); + customClockMovement = false; +} + +async function stepIncreaseAndStart(clockElement, domElements, speed = 50, start_num = 0) { + animateValue(domElements.dayNumber, start_num, clockElement.days, speed); + animateValue(domElements.hourNumber, start_num, clockElement.hours, speed); + animateValue(domElements.minNumber, start_num, clockElement.minutes, speed); + animateValue(domElements.secNumber, start_num, clockElement.seconds, speed); + +} + +async function waitForAnimation(clock, domElements, duration) { + await stepIncreaseAndStart(clock || myclock, domElements, duration || animatedCountDuration) + startClock(clock || myclock, domElements); +} + +// todo: sort by modified time +async function displayCountdowns() { + + + let jsonListOfCountdowns = await localStorage.getItem('countdown'); + arrayOfCountdowns = JSON.parse(jsonListOfCountdowns); + if (arrayOfCountdowns && arrayOfCountdowns.length) { + + let listItems = populateList(arrayOfCountdowns); + setInnerHtmlForNotNull(countdownList, listItems) + setInnerHtmlForNotNull(countdownTextDisplay, '') + // updateClockAndText(arrayOfCountdowns[arrayOfCountdowns.length-1].date, arrayOfCountdowns[arrayOfCountdowns.length-1].text) + + + } else { + setInnerHtmlForNotNull(countdownList, 'Found no countdowns to display'); + setInnerHtmlForNotNull(countdownTextDisplay, '') + } +} + +function populateList(arrayOfCountdowns) { + let listItems = ''; + arrayOfCountdowns.forEach((countdown, index) => { + let date = new Date(countdown.date); + listItems += ` +
+
${countdown.text}
+
+
+
+ Due: ${date.getDate() + ' ' + date.toLocaleString('default', { month: 'long' }) + ', ' + date.getFullYear()} +
+
` + }); + return listItems; +} + +function updateClockAndText(date, text, animation = true) { + let clock = new Clock(new Date(date)); + setInnerHtmlForNotNull(countdownTextDisplay, text); + stopClock(); + waitForAnimation(clock, { dayNumber, hourNumber, minNumber, secNumber }, 500) +} + +function removeClockAndText(){ + stopClock(); + setInnerHtmlForNotNull(countdownTextDisplay, '') + if(countdownClock){ + // todo: set the display to none instead + countdownClock.style.display = '' + } +} + +const triggerContextMenu = (element) => { + if (element.querySelector(".menu").style.display == "block") { + hideContextMenus(); + } + else { + hideContextMenus();//close all context menus before displaying the clicked one + element.querySelector(".menu").style.display = "block"; + switchContextIconUp(element); + // console.log("context-menu: show"); + } +} +function switchContextIconUp(element){ + element = element.querySelector('.fa-chevron-circle-down') + if(element){ + element.classList.replace('fa-chevron-circle-down', 'fa-chevron-circle-up'); +} +} + +function switchContextIconDown(element){ + if(element) + element.classList.replace('fa-chevron-circle-up', 'fa-chevron-circle-down'); +} +function hideContextMenus(event) { + //if function is not triggered by event listener, event is empty + if ((!(event != null))||!(event.target.className == 'countdown-list-options' || event.target.tagName == 'I')) { + document.querySelectorAll('.menu').forEach(contextMenu => contextMenu.style.display = "none"); + document.querySelectorAll('.fa-chevron-circle-up').forEach(element => switchContextIconDown(element)); + } + +} +function addListEventListener() { + document.querySelector('.countdown-list').addEventListener('click', event => { + //hide all context menus + + const targetElement = event.target; + + // if event is fired on text or date + if (targetElement.className == 'countdown-list-text' || targetElement.className == 'countdown-list-date') { + // hideContextMenus() + // todo: find a better way of accessing element in countdown array + updateClockAndText(arrayOfCountdowns[targetElement.parentElement.getAttribute('data-index')].date, arrayOfCountdowns[targetElement.parentElement.getAttribute('data-index')].text) + + if ([null, "", undefined].includes(document.querySelector(".clock-row").style.display)) { + document.querySelector(".clock-row").style.display = "flex"; + document.querySelector(".clock-row").style.animationPlayState = "running"; + } + } + //if the area for context menu is clicked + else if (targetElement.className == 'countdown-list-options' || targetElement.tagName == 'I') { + //get the countdown list item and pass to function, search for list class .menu + //in case of directly clicking on icon, parent element is .countdown-list-options div + triggerContextMenu(targetElement.parentElement); + + } else if (targetElement.className.search('menu-opts') > -1) { + let count_modified = targetElement.parentElement.getAttribute('data-id'); + if (targetElement.className.search('main') > -1) { + // set as main clicked + // find the element convert to JSON and place it as the main clock + const countdown = arrayOfCountdowns.find((countdown) => countdown.dateModified == count_modified); + const mainCount = JSON.stringify(countdown); + localStorage.setItem('mainClock', mainCount); + let date = new Date(countdown.date); + notifyUser(`Homepage clock set to ${date.getDate()} ${date.toLocaleString('default', { month: 'long' })} ${date.getFullYear()}`); + } else if (targetElement.className.search('del') > -1) { + // delete item clicked + arrayOfCountdowns = arrayOfCountdowns.filter((countdown, index) => countdown.dateModified != count_modified); + test = true; + setCountDownList(arrayOfCountdowns); + countdownList.innerHTML = populateList(arrayOfCountdowns) + // console.log('delete clicked', targetElement.parentElement, arrayOfCountdowns[targetElement.parentElement.getAttribute('data-index')]); + } else if (targetElement.className.search('edit') > -1) { + let editItem = arrayOfCountdowns.find((countdown, index) => countdown.dateModified == count_modified); + // todo: custom error messages for components on fail + try { + if(editItem){ + displayFormPopUp(editItem.text, /\d+-\d+-\d+T\d+:\d+/.exec(editItem.date), count_modified); + handleUpdate(); + }else{ + // something went wrong with the editing + errorHandler('Unable to edit countdown'); + // console.log(editItem); + } + } catch (err) { + console.log(err, 'Error in form display'); + errorHandler('Error in form display'); + } + + + } + } + }) +} + +function handleUpdate() { + // todo: update list with custom fired events + const countdownForm = document.getElementById('customUpDateForm'); + const submitbutton = document.getElementById('countdown-update'); + + + // const event = document.createEvent('Event'); + // console.log(event); + countdownForm.addEventListener('submit', (e) => { + + e.preventDefault(); + submitbutton.disabled = true; + // get text field values, with auto values + let userText = document.getElementById('countdownText').value; + const modifiedTime = document.getElementById('modifiedTime').value; + + // if (!userText) { + // userText = userTextField.placeholder; + // countNumber++; + // localStorage.setItem('countNumber', countNumber) + // } + let userDate = document.getElementById("dateInput").value; + userDate = new Date(userDate); + let countItem = { text: userText, date: userDate, dateModified: new Date() }; + arrayOfCountdowns = arrayOfCountdowns? arrayOfCountdowns: JSON.parse(localStorage.getItem('countdown')); + if (arrayOfCountdowns !== null) { //countdowns already exist + + + let pos = arrayOfCountdowns.findIndex((value) => + value.dateModified == modifiedTime + ); + if(pos>-1){ + console.log(arrayOfCountdowns[pos]); + arrayOfCountdowns[pos].text = countItem.text; + arrayOfCountdowns[pos].date = countItem.date; + arrayOfCountdowns[pos].dateModified = countItem.dateModified; + setCountDownList(arrayOfCountdowns); + displayCountdowns(); + closeFormPopUp(); + removeClockAndText(); + }else{ + console.log("Unable to update Item in displayCountdown, HandleUpdate"); + errorHandler('Unable to update Item'); + } + + } + }) +} + +function setCountDownList(jsArray){ + localStorage.setItem('countdown', JSON.stringify(jsArray)) +} + +function displayFormPopUp(text, dateTime, modifiedTime) { + // todo: Track items without using modifiedTime + if(text && dateTime&& modifiedTime){ + const updateFormHtml = `
+
+
Update Countdown
+
+ + +
+
+ + +
+
+ + + +
+ +
+
+
`; + document.body.insertAdjacentHTML("afterbegin", updateFormHtml); + document.body.style.position = "fixed"; + // setDateAttributes(); + document.getElementsByClassName("close-form")[0].onclick = (e) => { closeFormPopUp(); } +} +} +function closeFormPopUp() { + document.getElementsByClassName("pop-up-container")[0].remove(); + document.body.style.position = ""; +} + +function setCountDownList(arrayOfJSONCountdowns) { + localStorage.setItem('countdown', JSON.stringify(arrayOfJSONCountdowns)) +} + +function addListEventHandlers() { + addListEventListener(); + // add context menu event listener + document.querySelector('.container').addEventListener("click", hideContextMenus); +} +try{ +displayCountdowns().catch((err)=>{ + console.log(err); + errorHandler('Unable to fetch your countdowns') +}); +addListEventHandlers(); +}catch (err) { + console.log(err, 'err in display countdown initialisation'); + errorHandler("Unable to fetch your countdowns"); +} diff --git a/js/error.js b/js/error.js new file mode 100644 index 00000000..4794f72b --- /dev/null +++ b/js/error.js @@ -0,0 +1,69 @@ +let prevErr = false; + + +const closeErrorInfo = () => event.currentTarget.parentNode.remove(); + +errorHandlerWithoutMessage= (err)=>{ + console.log(err); + errorHandler(); +} + +const errorHandler =(msg)=> { + const errMessage = "Oops an error occurred 🤧😐"; + let errHtml = ` +
+ +
+ ${msg||errMessage} +
+ +
+
+
+`; + if (prevErr) { + let item =$(".error-notification")[0] + if(item) + item.remove(); + document.body.insertAdjacentHTML("afterbegin", errHtml); + } else { + document.body.insertAdjacentHTML("afterbegin", errHtml); + prevErr = true; + } +}; +window.onerror = errorHandlerWithoutMessage; \ No newline at end of file diff --git a/js/form.js b/js/form.js new file mode 100644 index 00000000..cfeeda57 --- /dev/null +++ b/js/form.js @@ -0,0 +1,120 @@ +function popForm() { + countNumber = localStorage.getItem('countNumber'); + if (!countNumber) + countNumber = 1; + const popFormHtml = `
+
+
Set Countdown
+
+ + +
+
+ + +
+
+ + +
+
+
+
`; + + document.body.insertAdjacentHTML("afterbegin", popFormHtml); + document.body.style.position = "fixed"; + setDateAttributes(); + document.getElementsByClassName("close-form")[0].onclick = (e) => { closeFormPopUp(); } + handleFormSubmission(); +} + +function addZeros(time) { + if (time < 10) { + time = "0" + time; + } + return time; +} + +function setDateAttributes() { + const dateInput = document.getElementById("dateInput"); + const today = new Date(); + let dd = today.getDate() ;//add 1 to the date so date starts from tomorrow + let mm = today.getMonth() + 1; //January is 0 so need to add 1 to make it 1! + let yyyy = today.getFullYear(); + let hr = addZeros(today.getHours()); + let min = addZeros(today.getMinutes()); + dd = addZeros(dd); + mm = addZeros(mm) + + let todayString = yyyy + '-' + mm + '-' + dd+'T'+ hr+':'+min; + console.log(todayString); + dateInput.setAttribute("min", todayString); + dateInput.value= todayString; +} + +function closeFormPopUp() { + document.getElementsByClassName("pop-up-container")[0].remove(); + document.body.style.position = ""; +} + +function handleFormSubmission() { + const countdownForm = document.getElementById('customDateForm'); + const submitbutton = document.getElementById('countdown-submit'); + + // const event = document.createEvent('Event'); + // console.log(event); + countdownForm.addEventListener('submit', (e) => { + + // e.preventDefault(); + submitbutton.disabled = true; + // get text field values, with auto values + let userTextField = document.getElementById('countdownText'); + let userText = userTextField.value; + + if (!userText) { + userText = userTextField.placeholder; + countNumber++; + localStorage.setItem('countNumber', countNumber) + } + let userDate = document.getElementById("dateInput").value; + userDate = new Date(userDate); + let countItem = { text: userText, date: userDate, dateModified: new Date() }; + let countdown = localStorage.getItem('countdown'); + if(countdown !== null){ //countdowns already exist + countdown = JSON.parse(countdown);//array + + countdown.push(countItem); + // console.log(countdown); + setCountDownList(countdown) + + }else{ + // create first countdown + setCountDownList([countItem]); + } + + // testing + // closeFormPopUp(); + }) +} + +function setCountDownList(jsArray){ + localStorage.setItem('countdown', JSON.stringify(jsArray)) +} + +// DOM Elements +const createButton = document.getElementsByClassName("new-item")[0]; +let countNumber = 1; + +// let dateInput, textInput; + +// todo: remove dynamic seting of css +if (!document.querySelector("[href='css/form.css']")) { + document.head.insertAdjacentHTML( + "beforeend", + `` + ); +} + + + +createButton.addEventListener("click", popForm); \ No newline at end of file diff --git a/js/formupdate.js b/js/formupdate.js new file mode 100644 index 00000000..7fa9459d --- /dev/null +++ b/js/formupdate.js @@ -0,0 +1,125 @@ +function popForm() { + countNumber = localStorage.getItem('countNumber'); + if (!countNumber) + countNumber = 1; + const popFormHtml = `
+
+
Set Countdown
+
+ + +
+
+ + +
+
+ + +
+
+
+
`; + + document.body.insertAdjacentHTML("afterbegin", popFormHtml); + document.body.style.position = "fixed"; + setDateAttributes(); + document.getElementsByClassName("close-form")[0].onclick = (e) => { closeFormPopUp(); } + handleFormSubmission(); +} + +function addZeros(time) { + if (time < 10) { + time = "0" + time; + } + return time; +} + +function setDateAttributes() { + const dateInput = document.getElementById("dateInput"); + const today = new Date(); + let dd = today.getDate() ;//add 1 to the date so date starts from tomorrow + let mm = today.getMonth() + 1; //January is 0 so need to add 1 to make it 1! + let yyyy = today.getFullYear(); + let hr = addZeros(today.getHours()); + let min = addZeros(today.getMinutes()); + dd = addZeros(dd); + mm = addZeros(mm) + + let todayString = yyyy + '-' + mm + '-' + dd+'T'+ hr+':'+min; + console.log(todayString); + dateInput.setAttribute("min", todayString); + dateInput.value= todayString; +} + +function closeFormPopUp() { + document.getElementsByClassName("pop-up-container")[0].remove(); + document.body.style.position = ""; +} + +function handleFormSubmission() { + const countdownForm = document.getElementById('customDateForm'); + const submitbutton = document.getElementById('countdown-submit'); + + // const event = document.createEvent('Event'); + // console.log(event); + countdownForm.addEventListener('submit', (e) => { + + e.preventDefault(); + submitbutton.disabled = true; + // get text field values, with auto values + let userTextField = document.getElementById('countdownText'); + let userText = userTextField.value; + + if (!userText) { + userText = userTextField.placeholder; + countNumber++; + localStorage.setItem('countNumber', countNumber) + } + let userDate = document.getElementById("dateInput").value; + userDate = new Date(userDate); + let countItem = { text: userText, date: userDate, dateModified: new Date() }; + let countdown = localStorage.getItem('countdown'); + if(countdown !== null){ //countdowns already exist + countdown = JSON.parse(countdown);//array + + countdown.push(countItem); + // console.log(countdown); + setCountDownList(countdown); + // external function + displayCountdowns(); + closeFormPopUp(); + + }else{ + // create first countdown + setCountDownList([countItem]); + displayCountdowns(); + closeFormPopUp(); + } + + // testing + // closeFormPopUp(); + }) +} + +function setCountDownList(jsArray){ + localStorage.setItem('countdown', JSON.stringify(jsArray)) +} + +// DOM Elements +const createButton = document.getElementsByClassName("new-item")[0]; +let countNumber = 1; + +// let dateInput, textInput; + +// todo: remove dynamic seting of css +if (!document.querySelector("[href='css/form.css']")) { + document.head.insertAdjacentHTML( + "beforeend", + `` + ); +} + + + +createButton.addEventListener("click", popForm); \ No newline at end of file diff --git a/js/functions.js b/js/functions.js new file mode 100644 index 00000000..46e7b120 --- /dev/null +++ b/js/functions.js @@ -0,0 +1,16 @@ +// for a single source for all the scattered functions +// due to Uc browser fix + +function setCountDownList(arrayOfJSONCountdowns){ + localStorage.setItem('countdown', JSON.stringify(arrayOfJSONCountdowns)) +} + +function setInnerHtmlForNotNull(element, value){ + if(element)//check for null + element.innerHTML = value; +} + +function closeFormPopUp() { + document.getElementsByClassName("pop-up-container")[0].remove(); + document.body.style.position = ""; +} \ No newline at end of file diff --git a/js/loadCustomUI.js b/js/loadCustomUI.js new file mode 100644 index 00000000..017149d0 --- /dev/null +++ b/js/loadCustomUI.js @@ -0,0 +1,115 @@ +let icon = document.getElementById('themeToggle'); + +function activateLightMode() { + setInnerHtmlForNotNull(icon, ``); + if(body.classList.contains("dark")){ + body.classList.replace("dark","light");}else{body.classList.add("light");} + localStorage.setItem("userMode", "light"); + console.log("saving: ", localStorage.getItem("userMode")); +} + +function activateDarkMode() { + setInnerHtmlForNotNull(icon, ``); + if(body.classList.contains("light")){ + body.classList.replace("light","dark");}else{body.classList.add("dark");} + localStorage.setItem("userMode", "dark"); + console.log("saving: ", localStorage.getItem("userMode")); +} + +function setMode() { + if (!body.classList.contains("light")) { + activateLightMode(); + } else { + activateDarkMode(); + } +} +function notifyMode() { + let notifyText; + if (body.classList.contains("light")) { + notifyText = "Light mode set"; + } else { + notifyText = "Dark mode set"; + } + + notifyUser(notifyText); +} + + function notifyUser(message) { + let notifyText = message; + + if (document.getElementsByClassName("mode-info")[0]) { + document.getElementsByClassName("mode-info")[0].remove(); + body.insertAdjacentHTML( + "afterbegin", + `${notifyText}` + ); + } else { + body.insertAdjacentHTML( + "afterbegin", + `${notifyText}` + ); + } +} + +function loadTheme() { + let savedTheme = localStorage.getItem("theme"); + if(!["",null,undefined].includes(savedTheme)){ + document.body.setAttribute("data-theme", savedTheme); + } + // set default mode to go with theme if page has none + if( !["light","dark"].includes(...document.body.classList)){ + document.body.classList.add("light"); + } +} + +function loadAppStatusBarTheme() { + let primaryColor = localStorage.getItem("primaryColor"); + if(!["",null,undefined].includes(primaryColor)){ + document.querySelectorAll("[content='#7b68ee']").forEach(e=>e.setAttribute("content",primaryColor)); + } +} + +function loadBg() { + let savedBg = localStorage.getItem("userBg"); + if( !["",null,undefined].includes(savedBg)){ + document.body.style.backgroundImage = `url(${savedBg})`; + } +} +function loadMode() { + let savedMode = localStorage.getItem("userMode"); + if( !["",null,undefined].includes(savedMode)){ + console.log("loading: ",savedMode); + let modeAlt = (savedMode == "dark") ? "light" : "dark"; + const setModeIcon = (mode)=> { + if (mode == "dark") { + icon.innerHTML = ``; + } + else { + icon.innerHTML = `` + } + console.log("setting mode icon"); + } + + if(!document.body.classList.contains(savedMode)){ + if(!document.body.classList.contains(modeAlt)){ + document.body.classList.add(savedMode); + setModeIcon(savedMode); + } + else{ + document.body.classList.replace(modeAlt,savedMode); + setModeIcon(savedMode); + } + } + else{ + setModeIcon(savedMode); + } + } +} + +loadTheme(); +loadAppStatusBarTheme(); +loadBg(); +loadMode(); + +icon.addEventListener("click", setMode); +icon.addEventListener("click", notifyMode); \ No newline at end of file diff --git a/js/sidebar.js b/js/sidebar.js new file mode 100644 index 00000000..ccff77aa --- /dev/null +++ b/js/sidebar.js @@ -0,0 +1,172 @@ +const $ = (selector) => document.querySelectorAll(selector); +const setLink = (link) => (window.location.href = link); +const nav = $(".nav")[0]; +const sidebar = $(".sidebar")[0]; +const sidebarItems = $(".sidebar-list-items"); +const colorIcons = $(".pick-color-ico"); +nav.addEventListener("click", () => { + if (sidebar.classList.contains("sidebar-hide")) { + sidebar.classList.replace("sidebar-hide", "sidebar-show"); + } +}); +sidebarItems[0].addEventListener("click", () => setLink("../index.html")); +sidebarItems[1].addEventListener("click", () => + setLink("../html/countdown-list.html") +); +sidebarItems[2].addEventListener("click", openBgPicker); +sidebarItems[3].addEventListener("click", openColorPicker); +sidebarItems[4].addEventListener("click", () => setLink("../html/authors.html")); + +function setTheme(event) { + let prevTheme = getComputedStyle(document.body).getPropertyValue( + "--color-banner" + ); + document.body.dataset.theme = event.currentTarget.dataset.settheme; + localStorage.setItem("theme", `${event.currentTarget.dataset.settheme}`); + + function setAppStatusBarTheme() { + let primaryColor = getComputedStyle(document.body).getPropertyValue( + "--color-banner" + ); + $(`[content="${prevTheme}"]`).forEach((e) => + e.setAttribute("content", primaryColor) + ); + localStorage.setItem("primaryColor", primaryColor); + } + setAppStatusBarTheme(); +} + +function openColorPicker() { + $(".pick-color")[0].classList.toggle("show-color"); +} + +colorIcons.forEach((e) => { + e.addEventListener("click", function (e) { + setTheme(e); + }); +}); + +nav.addEventListener("click", (e) => { + $(".container")[0].addEventListener("click", closeSideBarListener); +}); + +const closeSideBarListener = (event) => { + sidebar.classList.add("sidebar-hide"); + event.currentTarget.removeEventListener("click", closeSideBarListener); +}; + +function openBgPicker() { + if (!$("[href='css/form.css']")[0]) { + document.head.insertAdjacentHTML( + "beforeend", + `` + ); + } + const showLoader = () => { + document.body.insertAdjacentHTML( + "afterbegin", + `` + ); + }; + showLoader(); + + const loadForm = async () => { + let file = await fetch("../html/form-upload.html"); + let ft = await file.text(); + document.getElementsByClassName("loader-container")[0].remove(); + document.body.insertAdjacentHTML("afterbegin", ft); + document.body.style.position = "fixed"; + const filePicker = document.querySelector("input[type='file']"); + const reading = (uploadedPic) => { + let reader = new FileReader(); + if(fileSizeOk(uploadedPic)){ + reader.readAsDataURL(uploadedPic); + } + else{ + notifyUser("Picture is too big"); + } + + reader.onload = function () { + let uploadedPic64 = reader.result; + localStorage.setItem("userBg", `${uploadedPic64}`); + document.body.style.backgroundImage = `url(${uploadedPic64})`; + notifyUser("Background is set"); + closeFormPopUp(); + }; + reader.onerror = function () { + errorHandler("Unable to set background"); + console.log(reader.error); + }; + }; + filePicker.onchange = () => { + reading(filePicker.files[0]); + }; + document + .getElementsByClassName("close-form")[0] + .addEventListener("click", closeFormPopUp); + $(".reset")[0].addEventListener("click", () => { + localStorage.removeItem("userBg"); + document.body.style.backgroundImage = ""; + notifyUser("Default background restored"); + closeFormPopUp(); + }); + $(".bg-presets-preview:not(.upload-preview) img").forEach((e) => { + e.addEventListener("click", () => { + const sbg = async () => { + let img = await fetch(e.src); + let imgblob = await img.blob(); + reading(imgblob); + }; + sbg(); + }); + }); + }; + loadForm().catch(err => { + errorHandler("Unable to set custom background"); + console.log(err); + }); +} +const fileSizeOk = (pic)=>{ + console.log((pic.size/1048576).toFixed(2)+"MB"); + return pic.size/1048576 < 3.00 ? true : false; +} \ No newline at end of file diff --git a/styles.css b/styles.css deleted file mode 100644 index 7fc8c3a5..00000000 --- a/styles.css +++ /dev/null @@ -1,306 +0,0 @@ -@import url("https://fonts.googleapis.com/css2?family=Nunito:wght@500&display=swap"); -/* basic reset */ -*, -*::before, -*::after { - box-sizing: border-box; - margin: 0; - padding: 0; -} - -/* mode variables */ -:root { - --color-bg: #182635; - --color-muted: rgba(255, 255, 255, 0.15); - --color-banner: #2f8bfc; - --color-text: hsl(0deg, 0%, 100%); - --timer-bg: #6a7682; - --timer-grad: rgba(255, 255, 255, 0.5); - --bg-url: url("img/bg-light.svg"); -} -.light { - --color-bg: #dfdfdf; - --color-muted: rgba(255, 255, 255, 0.3); - --color-text: rgb(0, 23, 53); - --color-text: var(--color-banner); - --timer-bg: whitesmoke; - --timer-grad: rgba(255, 255, 255, 0.8); - --timer-box: 0 0 5px 1px rgba(0, 0, 0, 0.1); - /* --bg-url: url("img/bg-light.svg"); */ -} - -body { - background: var(--bg-url) var(--color-bg) center no-repeat; - background-size: cover; - background-blend-mode: soft-light; - transition: background-color 0.2s ease, color 0.2s ease; - color: var(--color-text); - font-family: "Nunito", sans-serif; - width: 100vw; - height: 100vh; -} -main{ - width: 100vw; - height: 100vh; -} -.container { - height: 100vh; - width: 100vw; - display: flex; - align-items: center; - flex-direction: column; - gap: 2.5em; - overflow-x: hidden; -} - -.mode-row { - position: relative; - width: 100vw; -} - -.mode-info { - background: #05172b; - border-radius: 0.3rem; - color: var(--color-text); - padding: 0.2rem 0.8rem; - -webkit-animation: slide-in 0.2s ease-in forwards, fade-out 0.5s ease 0.9s forwards; - animation: slide-in 0.2s ease-in forwards, fade-out 0.5s ease 0.9s forwards; - position: absolute; - left: 50%; - top: -10rem; - transform: translateX(-50%); -} - -.light .mode-info { - background: aliceblue; -} - -.link{ - color: var(--color-text); - text-decoration: none; -} -@-webkit-keyframes slide-in { - to { - top: 2rem; - } -} -@keyframes slide-in { - to { - top: 2rem; - } -} -@-webkit-keyframes fade-out { - to { - opacity: 0; - } -} -@keyframes fade-out { - to { - opacity: 0; - } -} - -.toggleMode { - font-size: 1.4em; - position: absolute; - right: 0.8rem; - top: 0.3rem; - width: 1.5em; - height: 1.5em; - display: flex; - justify-content: center; - align-items: center; - border-radius: 50%; - background: #3971b7; - color: #f2e7ac; -} - -.banner-row { - display: flex; - justify-content: center; - align-items: center; - font-weight: bold; - font-size: 1.7em; - text-align: center; - width: 100%; -} - -.banner { - background-color: var(--color-banner); - padding: 0.5em 1rem; - border-radius: 0.3em; - min-width: 80vmin; - color: white; -} -.banner-h2{ - /* font-style: italic; */ - font-size: 0.7em; - font-weight: lighter; - letter-spacing: 0.3em; -} -.day{ - font-size: 1.77em; -} - -.clock-row { - position: relative; - display: flex; - flex-direction: column; - text-align: center; - width: 100vw; - /* height: 30vh; */ - align-items: center; - justify-content: center; - border-radius: 0.2em; - padding: 10px; - gap: 1rem; -} - -.timer{ - font-size: 1rem; - position: relative; - display: flex; - justify-content: center; - align-items: center; - width: 25vmin; - height: 25vmin; - border: 2px solid rgba(255, 255, 255, 0.2); - border-radius: .7em; - background: linear-gradient(90deg,var(--color-muted) 50%, var(--timer-grad) 50%); - margin-bottom: 1rem; -} -.light .timer{ - border: 2px solid rgba(255, 255, 255, 0.7); - box-shadow: var(--timer-box); -} -.timer-num{ - font-size: 13vmin; -} -.timer-text{ - content: ""; - position: absolute; - bottom: -1em; - background: var(--timer-bg); - border-radius: 0.3em; - padding: .5em; - text-align: center; - width: 18vmin; - overflow: clip; - transition: background-color 0.2s ease; -} -.light .timer-text{ - box-shadow: var(--timer-box); -} - -.controls-row { - display: flex; - flex-flow: column nowrap; - margin-bottom: 5vh; - gap: 1em; - width: 100vw; - height: 20vh; - align-items: center; - justify-content: center; -} -.button { - background: linear-gradient(-45deg, #0756b5, #80affa); - padding: 0.5em 1em; - border-radius: 0.3em; - border-top: 1px rgba(7, 85, 181, 0.25) solid; - -webkit-animation: bg 3s ease infinite alternate; - animation: bg 3s ease infinite alternate; - min-width: 16em; - height: 2.2em; - margin: 0.2em; - position: relative; - cursor: pointer; -} -.button::before { - content: ""; - position: absolute; - height: 10px; - width: 10%; - top: 0; - left: 2%; - background: linear-gradient(45deg, rgba(255, 255, 255, 0.15), transparent); - border-radius: 54% 46% 69% 31% / 57% 0% 100% 43%; -} - -.author{ - position: absolute; - bottom: 15px; - left: 20px; - font-size: 0.7em; - color: var(--color-text) -} - -.author:hover{ - color: var(--color-banner) -} -@-webkit-keyframes bg { - from { - -webkit-filter: hue-rotate(-25deg); - filter: hue-rotate(-25deg); - } - to { - -webkit-filter: hue-rotate(80deg); - filter: hue-rotate(80deg); - } -} - -@keyframes bg { - from { - -webkit-filter: hue-rotate(-25deg); - filter: hue-rotate(-25deg); - } - to { - -webkit-filter: hue-rotate(80deg); - filter: hue-rotate(80deg); - } -} -/* desktop */ -@media screen and (min-width: 750px) and (orientation: landscape) { - body { - overflow-y: hidden; - } - - .banner { - width: 21em; - /* padding: 1em 5rem; */ - } - .clock-row { - font-size: 25vmin; - flex-direction: row; - gap: 2rem; - } - .clock-row::after, - .clock-row::before { - width: 1.8em; - height: 1.8em; - } - .controls-row { - flex-flow: row nowrap; - gap: 4em; - } -} -/* mid-range */ -/* @media screen and (min-width: 415px) { - .banner{ - width: 90vmin; - } -} */ -/* mobile and small screens */ -@media screen and (max-width: 415px) { - .banner{ - font-size: 1.1rem; - width: 100%; - border-top-right-radius: 0; - border-top-left-radius: 0; - } - .container { - gap: 0; - } - .timer-text{ - font-size: 0.75rem; - } -} \ No newline at end of file diff --git a/sw.js b/sw.js index e71d50bb..e1329960 100644 --- a/sw.js +++ b/sw.js @@ -1,24 +1,38 @@ -// #2 -const staticCacheName = 'site-static-v2'; -const dynamicCache = 'site-dynamic-v2'; +// #3 + +const staticCacheName = 'site-static-v29'; +const dynamicCache = 'site-dynamic-v29'; + +const dynamicCacheSize = 30; + // caching //assets to cache const assets = [ '/', '/index.html', - '/authors.html', - '/fallback.html', - '/clock.js', + '/html/authors.html', + '/html/countdown-list.html', + '/html/fallback.html', + '/html/form-upload.html', + '/css/styles.css', + '/css/themes.css', + '/css/authors.css', + '/css/countdown-list.css', + '/css/form.css', '/app.js', + '/js/sidebar.js', + '/js/loadCustomUI.js', + '/js/displayCountdowns.js', + '/js/formupdate.js', + '/js/error.js', + '/js/form.js', + '/img/icons/chrome192.png', + '/img/icons/chrome512.png', '/img/bg.svg', - '/img/bg-light.svg', - '/styles.css', - 'img/icons/favicon.png', - 'img/icons/chrome192.png', - 'img/icons/chrome512.png', - "https://cdnjs.cloudflare.com/ajax/libs/normalize/8.0.1/normalize.min.css", + '/img/bg/goku.jpg', + '/img/bg/ship_sky_balloons.jpg', + '/img/icons/favicon.png', "https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/css/all.min.css", - 'https://cdnjs.cloudflare.com/ajax/libs/normalize/8.0.1/normalize.min.css.map', // "https://fonts.googleapis.com/css2?family=Nunito:wght@500&display=swap", // 'https://fonts.gstatic.com/s/nunito/v20/XRXI3I6Li01BKofiOc5wtlZ2di8HDIkhdTk3j77e.woff2' @@ -38,8 +52,19 @@ self.addEventListener('install', evt => { evt.waitUntil( caches.open(staticCacheName).then(cache => { // console.log('caching'); - cache.add('/app.js'); - cache.addAll(assets); + // cache.add('/app.js'); + cache.addAll(assets).catch((reason)=>{ + // try caching again + console.log(reason); + assets.forEach(value=>{ + caches.open(staticCacheName).then(cache => { + // console.log('caching'); + cache.add(value).catch(err=> console.log(err, value)); + console.log('recaching complete'); + }).catch(err=> console.log(err)) + }) + + }); console.log('caching complete'); }) ) @@ -69,13 +94,13 @@ self.addEventListener('fetch', evt => { return cacheRes || fetch(evt.request).then(fetchRes => { return caches.open(dynamicCache).then(cache => { cache.put(evt.request.url, fetchRes.clone()) - limitCacheSize(dynamicCache, 15) + limitCacheSize(dynamicCache, dynamicCacheSize) return fetchRes; }) }); }).catch(()=>{ if(evt.request.url.indexOf('.html')>-1 ) - return caches.match('/fallback.html') + return caches.match('/html/fallback.html') }) ); }) \ No newline at end of file