only latest.log, better notification animation, better playtime updates
This commit is contained in:
parent
53a02cc7da
commit
e082fedf19
4 changed files with 88 additions and 27 deletions
|
|
@ -70,16 +70,37 @@ function setButtonIcons() {
|
|||
}
|
||||
}
|
||||
|
||||
// Smoothly animate elements of `container` between their previous and new
|
||||
// positions after `mutate()` changes the layout (FLIP technique).
|
||||
function flipShift(container, mutate) {
|
||||
const entries = [...container.children].map(el => ({ el, top: el.getBoundingClientRect().top }))
|
||||
mutate()
|
||||
for (const { el, top } of entries) {
|
||||
if (!el.isConnected) continue
|
||||
const delta = top - el.getBoundingClientRect().top
|
||||
if (!delta) continue
|
||||
el.style.transition = 'none'
|
||||
el.style.transform = `translateY(${delta}px)`
|
||||
void el.offsetHeight // flush styles so the shift back animates
|
||||
el.style.transition = ''
|
||||
el.style.transform = ''
|
||||
}
|
||||
}
|
||||
|
||||
function toast(message, kind) {
|
||||
const el = document.createElement('div')
|
||||
el.className = 'toast' + (kind ? ' ' + kind : '')
|
||||
el.textContent = message
|
||||
qs('#toasts').appendChild(el)
|
||||
requestAnimationFrame(() => requestAnimationFrame(() => el.classList.add('show')))
|
||||
setTimeout(() => {
|
||||
el.classList.add('hide')
|
||||
setTimeout(() => el.remove(), 300)
|
||||
}, 4000)
|
||||
const container = qs('#toasts')
|
||||
flipShift(container, () => {
|
||||
const el = document.createElement('div')
|
||||
el.className = 'toast' + (kind ? ' ' + kind : '')
|
||||
el.textContent = message
|
||||
container.appendChild(el)
|
||||
requestAnimationFrame(() => requestAnimationFrame(() => el.classList.add('show')))
|
||||
setTimeout(() => {
|
||||
el.classList.add('hide')
|
||||
// after the fade-out, free the slot with an animated shift instead of a jump
|
||||
setTimeout(() => flipShift(container, () => el.remove()), 300)
|
||||
}, 4000)
|
||||
})
|
||||
}
|
||||
|
||||
function showModal(html) {
|
||||
|
|
@ -318,12 +339,12 @@ function renderLibrary() {
|
|||
card.querySelector('h3').textContent = game.name
|
||||
const playBtn = card.querySelector('[data-act=play]')
|
||||
const killBtn = card.querySelector('[data-act=kill]')
|
||||
const lastMeta = card.querySelectorAll('.meta')[1]
|
||||
const metas = card.querySelectorAll('.meta')
|
||||
const applyRunning = isRunning => {
|
||||
playBtn.style.display = isRunning ? 'none' : ''
|
||||
killBtn.style.display = isRunning ? '' : 'none'
|
||||
}
|
||||
runningCards.set(game.id, { applyRunning, lastMeta, game })
|
||||
runningCards.set(game.id, { applyRunning, lastMeta: metas[1], playtimeMeta: metas[2], game })
|
||||
window.plwl.gamesIsRunning(game.id).then(applyRunning)
|
||||
playBtn.onclick = () => playGame(game)
|
||||
killBtn.onclick = async () => {
|
||||
|
|
@ -373,10 +394,14 @@ async function refreshLibraryData() {
|
|||
for (const [id, entry] of runningCards) {
|
||||
entry.applyRunning(runningSet.has(id))
|
||||
const fresh = state.games.find(g => g.id === id)
|
||||
if (fresh && entry.lastMeta) {
|
||||
if (!fresh) continue
|
||||
if (entry.lastMeta) {
|
||||
const last = fresh.lastPlayed ? new Date(fresh.lastPlayed).toLocaleDateString() : t('library.never')
|
||||
entry.lastMeta.textContent = t('library.lastPlayed', last)
|
||||
}
|
||||
if (entry.playtimeMeta) {
|
||||
entry.playtimeMeta.textContent = t('library.playtime', fmtPlaytime(fresh.playSeconds || 0))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -384,6 +409,10 @@ function wireRealtime() {
|
|||
window.plwl.onGamesChanged(() => {
|
||||
if (state.currentView === 'library') refreshLibraryData()
|
||||
})
|
||||
// pick up live playtime/lastPlayed updates while a game is running
|
||||
setInterval(() => {
|
||||
if (state.currentView === 'library' && runningCards.size) refreshLibraryData()
|
||||
}, 15000)
|
||||
}
|
||||
|
||||
async function startImportFlow() {
|
||||
|
|
|
|||
|
|
@ -601,21 +601,21 @@ select {
|
|||
max-width: 24rem;
|
||||
box-shadow: 0 0.5rem 2rem rgba(0, 0, 0, 0.4);
|
||||
opacity: 0;
|
||||
transform: translateY(-1rem);
|
||||
transform: translateX(1.5rem);
|
||||
transition:
|
||||
opacity 0.2s ease,
|
||||
transform 0.25s var(--spring),
|
||||
transform 0.3s ease-out,
|
||||
background-color 0.15s ease;
|
||||
}
|
||||
.toast.error { border-color: var(--big-red); }
|
||||
.toast.success { border-color: var(--big-green); }
|
||||
.toast.show {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
transform: translateX(0);
|
||||
}
|
||||
.toast.hide {
|
||||
opacity: 0;
|
||||
transform: translateY(-0.5rem);
|
||||
transform: translateX(1rem);
|
||||
}
|
||||
|
||||
.progress-row {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue