Skip to content

Instantly share code, notes, and snippets.

@marcoonroad
Created October 13, 2020 02:28
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save marcoonroad/699e968fb2da0a295c1c72d6d1c32c9c to your computer and use it in GitHub Desktop.
Save marcoonroad/699e968fb2da0a295c1c72d6d1c32c9c to your computer and use it in GitHub Desktop.
OTP/2-factor code spinner
<script src="https://unpkg.com/@otplib/preset-browser@^12.0.0/buffer.js"></script>
<script src="https://unpkg.com/@otplib/preset-browser@^12.0.0/index.js"></script>
<div class="wrapper">
<div class="noop">
<div class="background-spin-loop"></div>
<div class="spin-text">
<div><span id="otp-code">123456</span></div>
</div>
<div class="spin-wrapper">
<div class="noop">
<div class="spin-container spin-cursor-container" id="spin-cursor-container-id">
<div class="spin spin-cursor" id="spin-cursor-id"></div>
</div>
<div class="spin-container spin-slices-container" id="spin-slices-container-id">
<div class="spin spin-slices" id="spin-slices-id"></div>
</div>
</div>
</div>
</div>
</div>
<script type="text/javascript">
(function () {
function getSeconds() {
return (new Date()).getSeconds();
}
var auth = window.otplib.authenticator;
var secret = "dummysecretdummy";
function computeToken () {
var token = auth.generate(secret);
var otpTag = document.getElementById("otp-code");
otpTag.textContent = token;
console.log((new Date().toString()), token);
}
var timeout = 30 - (getSeconds() % 30);
computeToken();
var animationDelay = '-' + (30 - timeout).toString() + 's';
document.getElementById('spin-slices-id').style.animationDelay = animationDelay;
document.getElementById('spin-slices-container-id').style.animationDelay = animationDelay;
document.getElementById('spin-cursor-id').style.animationDelay = animationDelay;
document.getElementById('spin-cursor-container-id').style.animationDelay = animationDelay;
if (!timeout) {
setInterval(computeToken, 30000);
return;
}
setTimeout(function () {
computeToken();
setInterval(computeToken, 30000);
}, timeout * 1000);
})();
</script>
:root {
--bg: gray;
--fg: black;
--size: 200px;
--period: 30s;
--border-width: 10px;
--font-size: 2em;
}
.wrapper {
display: flex;
flex-direction: column;
align-items: center;
padding: 0 auto;
height: var(--size);
overflow: hidden;
}
.wrapper div.noop {
width: var(--size);
height: var(--size);
overflow: hidden;
}
.spin-wrapper {
position: absolute;
}
.spin-wrapper div.noop {
overflow: hidden;
width: var(--size);
height: var(--size);
}
.spin-container {
transform: rotate(-45deg);
position: absolute;
overflow: hidden;
}
@keyframes spin-goes-up {
0%, 74% { z-index: -200; }
75%, 100% { z-index: 500; }
}
@keyframes spin-goes-down {
0%, 74% { z-index: 200; }
75%, 100% { z-index: -500; }
}
.spin-cursor-container {
animation: spin-goes-up var(--period) infinite linear;
}
.spin-slices-container {
animation: spin-goes-down var(--period) infinite linear;
}
.spin-text {
display: block;
position: absolute;
height: var(--size);
width: var(--size);
z-index: -1000;
margin-top: 0px;
margin-left: 0px;
border-radius: 50%;
border-width: var(--border-width);
border-style: solid;
border-color: transparent;
}
.background-spin-loop {
border-color: var(--bg);
border-style: solid;
border-width: var(--border-width);
border-radius: 50%;
transform: rotate(-45deg);
position: absolute;
width: var(--size);
height: var(--size);
z-index: -7000;
}
.print-border {
border: solid 1px red;
}
.spin-text div {
display: block;
width: var(--size);
height: var(--size);
}
.spin-text span {
font-weight: bold;
display: inline-block;
font-family: monospace;
font-size: var(--font-size);
text-align: center;
vertical-align: middle;
height: var(--size);
width: var(--size);
line-height: var(--size);
}
span.code {
transform: rotate(45deg);
}
@-webkit-keyframes rotation-animation {
0% { transform: rotate(0deg); }
25% { transform: rotate(90deg); }
50% { transform: rotate(180deg); }
75% { transform: rotate(270deg); }
100% { transform: rotate(360deg); }
}
.spin {
width: var(--size);
height: var(--size);
border-style: solid;
border-width: var(--border-width);
border-color: transparent;
border-radius: 50%;
}
.spin-cursor {
border-top-color: var(--fg) !important;
border-right-color: transparent !important;
border-bottom-color: transparent !important;
border-left-color: transparent !important;
animation: rotation-animation var(--period) infinite linear;
}
@keyframes slices-animation {
0%, 24% {
border-top-color: var(--bg);
border-right-color: transparent;
border-bottom-color: transparent;
border-left-color: transparent;
}
25%, 49% {
border-top-color: var(--bg);
border-right-color: var(--fg);
border-bottom-color: transparent;
border-left-color: transparent;
}
50%, 74% {
border-top-color: var(--bg);
border-right-color: var(--fg);
border-bottom-color: var(--fg);
border-left-color: transparent;
}
75% {
border-top-color: var(--bg);
border-right-color: var(--fg);
border-bottom-color: var(--fg);
border-left-color: var(--fg);
}
76%, 100% {
border-top-color: var(--bg);
border-right-color: var(--fg);
border-bottom-color: var(--fg);
border-left-color: var(--fg);
}
}
.spin-slices {
animation: slices-animation var(--period) infinite linear;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment