Add visual timer
This commit is contained in:
parent
d20ee9ab7b
commit
d852740998
2 changed files with 81 additions and 6 deletions
41
popup.css
41
popup.css
|
|
@ -77,17 +77,40 @@ h2 {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.entry .otp-container {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
.entry .otp {
|
.entry .otp {
|
||||||
background-color: var(--light-bg-color);
|
background-color: var(--light-bg-color);
|
||||||
padding: 4px 8px;
|
padding: 4px 8px;
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
flex-grow: 1;
|
||||||
|
margin-right: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.entry .otp:hover {
|
.entry .otp:hover {
|
||||||
background-color: var(--highlight-bg-color);
|
background-color: var(--highlight-bg-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.entry svg {
|
||||||
|
width: 1.5em;
|
||||||
|
height: 1.5em;
|
||||||
|
transform: rotateY(-180deg) rotateZ(-90deg);
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.entry svg circle {
|
||||||
|
stroke-dasharray: 6.28318px;
|
||||||
|
stroke-dashoffset: 0;
|
||||||
|
stroke-width: 100%;
|
||||||
|
stroke: var(--border-color);
|
||||||
|
fill: none;
|
||||||
|
animation: timer1 30s linear 1 forwards;
|
||||||
|
}
|
||||||
|
|
||||||
#entry-list .entry {
|
#entry-list .entry {
|
||||||
border-top: 1px solid var(--border-color);
|
border-top: 1px solid var(--border-color);
|
||||||
}
|
}
|
||||||
|
|
@ -170,3 +193,21 @@ h2 {
|
||||||
height: 2em;
|
height: 2em;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@keyframes timer0 {
|
||||||
|
from {
|
||||||
|
stroke-dashoffset: 0;
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
stroke-dashoffset: 6.28318px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes timer1 {
|
||||||
|
from {
|
||||||
|
stroke-dashoffset: 0;
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
stroke-dashoffset: 6.28318px;
|
||||||
|
}
|
||||||
|
}
|
||||||
44
popup.js
44
popup.js
|
|
@ -151,16 +151,20 @@ class Store
|
||||||
refresh()
|
refresh()
|
||||||
{
|
{
|
||||||
const now = Date.now()
|
const now = Date.now()
|
||||||
|
const count_time = now / 30000
|
||||||
|
const counter = Math.floor(count_time)
|
||||||
|
const animation_delay = (count_time - counter) * 30
|
||||||
|
|
||||||
if(refresh_timeout !== null)
|
if(refresh_timeout !== null)
|
||||||
clearTimeout(refresh_timeout)
|
clearTimeout(refresh_timeout)
|
||||||
refresh_timeout = setTimeout(
|
refresh_timeout = setTimeout(
|
||||||
() => { store.refresh() },
|
() => { store.refresh() },
|
||||||
((Math.floor(now / 30000) + 1) * 30000) - now + 1)
|
((counter + 1) * 30000) - now + 1)
|
||||||
|
|
||||||
const counter = Math.floor(now / 30000)
|
|
||||||
for(const entry of this.entries)
|
for(const entry of this.entries)
|
||||||
{
|
{
|
||||||
entry.refresh(counter)
|
entry.refresh(counter)
|
||||||
|
entry.refreshTimer(animation_delay)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -193,6 +197,7 @@ class Entry
|
||||||
this.name = name
|
this.name = name
|
||||||
this.secret = secret
|
this.secret = secret
|
||||||
this.key = key
|
this.key = key
|
||||||
|
this.timer_count = 0
|
||||||
|
|
||||||
let new_elt = document.createElement('div')
|
let new_elt = document.createElement('div')
|
||||||
new_elt.className = 'entry'
|
new_elt.className = 'entry'
|
||||||
|
|
@ -222,18 +227,32 @@ class Entry
|
||||||
new_elt.appendChild(header_elt)
|
new_elt.appendChild(header_elt)
|
||||||
|
|
||||||
// Entry OTP
|
// Entry OTP
|
||||||
|
let otp_container_elt = document.createElement('div')
|
||||||
|
otp_container_elt.className = 'otp-container'
|
||||||
let otp_elt = document.createElement('div')
|
let otp_elt = document.createElement('div')
|
||||||
otp_elt.className = 'otp'
|
otp_elt.className = 'otp'
|
||||||
otp_elt.addEventListener('click', () => {
|
otp_elt.addEventListener('click', () => {
|
||||||
navigator.clipboard.writeText(otp_elt.textContent)
|
navigator.clipboard.writeText(otp_elt.textContent)
|
||||||
})
|
})
|
||||||
new_elt.appendChild(otp_elt)
|
otp_container_elt.appendChild(otp_elt)
|
||||||
|
// let svg_timer_elt = document.createElement('svg')
|
||||||
|
const svgNS = 'http://www.w3.org/2000/svg'
|
||||||
|
let svg_timer_elt = document.createElementNS(svgNS, 'svg')
|
||||||
|
svg_timer_elt.setAttributeNS(null, 'viewBox', '0 0 2 2')
|
||||||
|
let timer_circle_elt = document.createElementNS(svgNS, 'circle')
|
||||||
|
timer_circle_elt.setAttributeNS(null, 'r', '1')
|
||||||
|
timer_circle_elt.setAttributeNS(null, 'cx', '1')
|
||||||
|
timer_circle_elt.setAttributeNS(null, 'cy', '1')
|
||||||
|
svg_timer_elt.appendChild(timer_circle_elt)
|
||||||
|
otp_container_elt.appendChild(svg_timer_elt)
|
||||||
|
new_elt.appendChild(otp_container_elt)
|
||||||
|
|
||||||
this.elements = {
|
this.elements = {
|
||||||
main: new_elt,
|
main: new_elt,
|
||||||
header: header_elt,
|
header: header_elt,
|
||||||
title: title_elt,
|
title: title_elt,
|
||||||
otp: otp_elt,
|
otp: otp_elt,
|
||||||
|
timer_circle: timer_circle_elt,
|
||||||
action: action_elt,
|
action: action_elt,
|
||||||
edit: edit_elt,
|
edit: edit_elt,
|
||||||
delete: delete_elt
|
delete: delete_elt
|
||||||
|
|
@ -246,7 +265,10 @@ class Entry
|
||||||
const key = await window.crypto.subtle.importKey(
|
const key = await window.crypto.subtle.importKey(
|
||||||
'raw', new Uint8Array(b32decode(secret)), {name: 'HMAC', hash: 'SHA-1'}, false, ['sign'])
|
'raw', new Uint8Array(b32decode(secret)), {name: 'HMAC', hash: 'SHA-1'}, false, ['sign'])
|
||||||
const new_entry = new Entry(name, secret, key)
|
const new_entry = new Entry(name, secret, key)
|
||||||
await new_entry.refresh(Math.floor(Date.now() / 30000))
|
const count_time = Date.now() / 30000
|
||||||
|
const counter = Math.floor(count_time)
|
||||||
|
await new_entry.refresh(counter)
|
||||||
|
new_entry.refreshTimer((count_time - counter) * 30)
|
||||||
return new_entry
|
return new_entry
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -276,6 +298,13 @@ class Entry
|
||||||
signature.slice(offset, offset + 4).buffer).getUint32().toString().slice(-6)
|
signature.slice(offset, offset + 4).buffer).getUint32().toString().slice(-6)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
refreshTimer(animation_delay)
|
||||||
|
{
|
||||||
|
this.timer_count = 1- this.timer_count
|
||||||
|
this.elements.timer_circle.style.animationDelay = `-${animation_delay}s`
|
||||||
|
this.elements.timer_circle.style.animationName = `timer${this.timer_count}`
|
||||||
|
}
|
||||||
|
|
||||||
insert()
|
insert()
|
||||||
{
|
{
|
||||||
entry_list_elt.appendChild(this.elements.main)
|
entry_list_elt.appendChild(this.elements.main)
|
||||||
|
|
@ -323,7 +352,12 @@ class Entry
|
||||||
this.name = name_input_elt.value
|
this.name = name_input_elt.value
|
||||||
this.elements.title.textContent = this.name
|
this.elements.title.textContent = this.name
|
||||||
this.secret = secret_input_elt.value
|
this.secret = secret_input_elt.value
|
||||||
this.regenerateKey().then(() => { this.refresh(Math.floor(Date.now() / 30000)) })
|
this.regenerateKey().then(() => {
|
||||||
|
const count_time = Date.now() / 30000
|
||||||
|
const counter = Math.floor(count_time)
|
||||||
|
this.refresh(counter)
|
||||||
|
this.refreshTimer((count_time - counter) * 30)
|
||||||
|
})
|
||||||
store.save()
|
store.save()
|
||||||
this.elements.main.removeChild(secret_container_elt)
|
this.elements.main.removeChild(secret_container_elt)
|
||||||
this.elements.action.removeChild(done_elt)
|
this.elements.action.removeChild(done_elt)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue