diff --git a/dist/fonts/OFL.txt b/dist/fonts/OFL.txt new file mode 100644 index 0000000..366206f --- /dev/null +++ b/dist/fonts/OFL.txt @@ -0,0 +1,93 @@ +Copyright 2010, 2012 Adobe Systems Incorporated (http://www.adobe.com/), with Reserved Font Name 'Source'. All Rights Reserved. Source is a trademark of Adobe Systems Incorporated in the United States and/or other countries. + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +http://scripts.sil.org/OFL + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/dist/fonts/SourceCodePro-Italic-VariableFont_wght.ttf b/dist/fonts/SourceCodePro-Italic-VariableFont_wght.ttf new file mode 100644 index 0000000..d3678bc Binary files /dev/null and b/dist/fonts/SourceCodePro-Italic-VariableFont_wght.ttf differ diff --git a/dist/fonts/SourceCodePro-VariableFont_wght.ttf b/dist/fonts/SourceCodePro-VariableFont_wght.ttf new file mode 100644 index 0000000..19bb671 Binary files /dev/null and b/dist/fonts/SourceCodePro-VariableFont_wght.ttf differ diff --git a/dist/index.html b/dist/index.html index dfb20b8..0e19691 100644 --- a/dist/index.html +++ b/dist/index.html @@ -16,25 +16,32 @@
- +
+ :
- - -
: -
- - - -
: -
- - +
- + : +
+ + + +
+ : +
+ + + +
+
diff --git a/dist/main.css b/dist/main.css index 1417e7b..213559a 100644 --- a/dist/main.css +++ b/dist/main.css @@ -1,50 +1,162 @@ +@font-face { + font-family: "SourceCodePro"; + src: url('fonts/SourceCodePro-VariableFont_wght.ttf') format('truetype'); + font-weight: normal; + font-style: normal; +} + +* { + font-family: "SourceCodePro", sans-serif; +} + body { background-color: black; } #countdown { + text-align: center; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); - width: 50vw; - height: 8vw; - background-color: grey; + width: 85vw; + height: 30vw; } #countdown .part { display: inline-block; position: relative; - padding-top: 1vw; + padding-top: 3vw; } #countdown * { - font-size: 3vw; + font-size: 9vw; + color: white; +} + +#countdown .separator { + font-size: 12vw; +} + +#countdown.blink .separator { + opacity: 0; } #countdown input { - width: 6vw; - height: 3.3vw; + width: 11.2vw; + text-align: center; + height: 9.6vw; + background: transparent; + border: solid; + font-variant-numeric: tabular-nums; +} + +#countdown #days input { + width: 17vw; +} + +#countdown button { + position: relative; + display: block; + background-color: #222; + color: white; + margin-top: 4.5vw; + width: 100%; + border-radius: 0.45vw; + border: solid 1px grey; + transition: background-color 0.2s, border 0.2s; +} + +#countdown button:hover { + background-color: black; + border: 1px white solid; + text-shadow: 0.05em 0 0 #00fffc, -0.03em -0.04em 0 #fc00ff, + 0.025em 0.04em 0 #fffc00; + animation: glitch 725ms infinite; +} + +#countdown button .layer { + width: 100%; + text-align: center; + position: absolute; + top: 0; + left: 0; + display: none; +} + +#countdown button:hover .layer { + display: inline; +} + +#countdown button .layer:first-of-type { + animation: glitch 500ms infinite; + clip-path: polygon(0 0, 100% 0, 100% 35%, 0 35%); + transform: translate(-0.04em, -0.03em); + opacity: 0.75; +} + +#countdown button .layer:last-of-type { + animation: glitch 375ms infinite; + clip-path: polygon(0 65%, 100% 65%, 100% 100%, 0 100%); + transform: translate(0.04em, 0.03em); + opacity: 0.75; +} + +#countdown input:disabled { + background: transparent; } #countdown .up, #countdown .down { position: absolute; - line-height: 3vw; - width: 1vw; + line-height: 9vw; + width: 3.5vw; text-align: center; - left: calc(50% - 0.5vw); + left: calc(50% - 1.5vw); transform: rotate(90deg); cursor: pointer; } #countdown .up { - top: calc(-1vw - 0.2vw); + top: calc(-2.5vw - 0.6vw); } #countdown .down { - top: calc(3.3vw + 0.2vw); + top: calc(10vw + 0.6vw); } #countdown.counting .up, #countdown.counting .down { display: none; -} \ No newline at end of file +} + + +@keyframes glitch { + 0% { + text-shadow: 0.05em 0 0 #00fffc, -0.03em -0.04em 0 #fc00ff, + 0.025em 0.04em 0 #fffc00; + } + 15% { + text-shadow: 0.05em 0 0 #00fffc, -0.03em -0.04em 0 #fc00ff, + 0.025em 0.04em 0 #fffc00; + } + 16% { + text-shadow: -0.05em -0.025em 0 #00fffc, 0.025em 0.035em 0 #fc00ff, + -0.05em -0.05em 0 #fffc00; + } + 49% { + text-shadow: -0.05em -0.025em 0 #00fffc, 0.025em 0.035em 0 #fc00ff, + -0.05em -0.05em 0 #fffc00; + } + 50% { + text-shadow: 0.05em 0.035em 0 #00fffc, 0.03em 0 0 #fc00ff, + 0 -0.04em 0 #fffc00; + } + 99% { + text-shadow: 0.05em 0.035em 0 #00fffc, 0.03em 0 0 #fc00ff, + 0 -0.04em 0 #fffc00; + } + 100% { + text-shadow: -0.05em 0 0 #00fffc, -0.025em -0.04em 0 #fc00ff, + -0.04em -0.025em 0 #fffc00; + } + } + \ No newline at end of file diff --git a/src/index.js b/src/index.js index 6dea6b0..4ddc401 100644 --- a/src/index.js +++ b/src/index.js @@ -1,5 +1,6 @@ (function() { var countdown = null; + var startButton = null; const parts = { "days": { @@ -42,6 +43,10 @@ "current": 0, }; + const convertToDisplayValue = function(raw, part) { + return raw.toString().padStart((parts[part].maxValue - 1).toString().length, "0"); + } + const parseTime = function() { var total = 0; @@ -62,20 +67,28 @@ while (part) { const partObj = parts[part]; const maxValue = partObj.maxValue; - partObj.value = value % maxValue; - partObj.input.value = partObj.value; + const positionValue = value % maxValue; + partObj.value = positionValue; + partObj.input.value = convertToDisplayValue(positionValue, part); value = Math.floor(value / maxValue); part = partObj.next; }; } + const setButtonText = function(text) { + Array.from(startButton.getElementsByTagName("span")).forEach(elem => { + elem.innerText = text; + }); + } + const start = function() { state.total = parseTime(); state.current = state.total; state.counting = true; countdown.classList.add("counting"); + setButtonText("reset"); var part = "seconds"; while(part) { @@ -89,6 +102,7 @@ state.counting = false; countdown.classList.remove("counting"); + setButtonText("start"); var part = "seconds"; while(part) { @@ -100,6 +114,8 @@ window.addEventListener("load", function() { countdown = document.getElementById("countdown"); + startButton = document.getElementById("start"); + Array.from(countdown.getElementsByClassName("part")).forEach(element => { const part = parts[element.id]; part.element = element; @@ -110,31 +126,33 @@ }); part.input.addEventListener("blur", function(event) { const value = parseInt(part.input.value); + var correctedValue = 0; if (value >= part.maxValue) { if (part.next) { - part.input.value = value % part.maxValue; + correctedValue = value % part.maxValue; parts[part.next].input.value = parseInt(parts[part.next].input.value) + Math.floor(value / part.maxValue); parts[part.next].input.dispatchEvent(new FocusEvent("blur")); } else { // ugly hack to only reset to 0 if the blur event was caused by cascading changes if (Math.abs(value - part.value) == 1) { - part.input.value = 0; + correctedValue = 0; } else { - part.input.value = part.maxValue - 1; + correctedValue = part.maxValue - 1; } } } else if (value < 0) { if (part.next) { - part.input.value = value + part.maxValue * Math.ceil(-value / part.maxValue); + correctedValue = value + part.maxValue * Math.ceil(-value / part.maxValue); parts[part.next].input.value = parseInt(parts[part.next].input.value) + Math.floor(value / part.maxValue); parts[part.next].input.dispatchEvent(new FocusEvent("blur")); } else { - part.input.value = part.maxValue - 1; + correctedValue = part.maxValue - 1; } } else { - part.input.value = value; + correctedValue = value; } - part.value = parseInt(part.input.value); + part.value = correctedValue; + part.input.value = convertToDisplayValue(correctedValue, element.id); }); element.getElementsByClassName("up")[0].addEventListener("click", function(event) { @@ -148,7 +166,14 @@ }); }); - document.getElementById("start").addEventListener("click", start); + document.getElementById("start").addEventListener("click", function() { + if (state.counting) { + update(state.total); + stop(); + } else { + start(); + } + }); window.setInterval(function() { if (state.counting) { @@ -156,9 +181,18 @@ state.current--; update(state.current); - if (state.current == 0) { + if (state.current <= 0) { + update(0); stop(); } + + if (countdown.classList.contains("blink")) { + countdown.classList.remove("blink"); + } else { + countdown.classList.add("blink"); + } + } else { + countdown.classList.remove("blink"); } }, 1000); });