Add stopwatch fill button and asset cache-busting
- Stopwatch ⏱ button appears in add/quick-book rows when sw >= 1s, fills input with floor(seconds) - AppController passes md5 hashes of app.js/style.css to template for automatic cache-busting Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
f0cbe5b5d0
commit
a8f6692de4
3 changed files with 23 additions and 6 deletions
|
|
@ -715,18 +715,23 @@ document.addEventListener('visibilitychange',function(){
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
(function(){
|
var sw = (function(){
|
||||||
var swEl = document.getElementById('sw');
|
var swEl = document.getElementById('sw');
|
||||||
var state = 0; // 0=stopped, 1=running, 2=paused
|
var state = 0; // 0=stopped, 1=running, 2=paused
|
||||||
var start = 0, elapsed = 0, raf = null;
|
var start = 0, elapsed = 0, raf = null;
|
||||||
|
|
||||||
function fmt(ms){
|
function getMs(){ return state === 1 ? elapsed + (Date.now() - start) : elapsed; }
|
||||||
var s = ms / 1000;
|
|
||||||
return s.toFixed(2) + 's';
|
function updateFillBtns(){
|
||||||
|
var show = getMs() >= 1000;
|
||||||
|
document.querySelectorAll('.btn-sw-fill').forEach(function(b){ b.style.display = show ? '' : 'none'; });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function fmt(ms){ return (ms / 1000).toFixed(2) + 's'; }
|
||||||
|
|
||||||
function tick(){
|
function tick(){
|
||||||
swEl.textContent = fmt(Date.now() - start + elapsed);
|
swEl.textContent = fmt(Date.now() - start + elapsed);
|
||||||
|
updateFillBtns();
|
||||||
raf = requestAnimationFrame(tick);
|
raf = requestAnimationFrame(tick);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -740,12 +745,20 @@ document.addEventListener('visibilitychange',function(){
|
||||||
elapsed += Date.now() - start;
|
elapsed += Date.now() - start;
|
||||||
swEl.textContent = fmt(elapsed);
|
swEl.textContent = fmt(elapsed);
|
||||||
swEl.classList.remove('running');
|
swEl.classList.remove('running');
|
||||||
state = 2;
|
state = 2; updateFillBtns();
|
||||||
} else {
|
} else {
|
||||||
cancelAnimationFrame(raf);
|
cancelAnimationFrame(raf);
|
||||||
elapsed = 0; swEl.textContent = '0.00s';
|
elapsed = 0; swEl.textContent = '0.00s';
|
||||||
swEl.classList.remove('running');
|
swEl.classList.remove('running');
|
||||||
state = 0;
|
state = 0; updateFillBtns();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
document.addEventListener('click', function(e){
|
||||||
|
if(!e.target.classList.contains('btn-sw-fill')) return;
|
||||||
|
var inp = e.target.closest('.add-row, .qb-row').querySelector('.num-in');
|
||||||
|
if(inp) inp.value = Math.floor(getMs() / 1000);
|
||||||
|
});
|
||||||
|
|
||||||
|
return { getMs: getMs };
|
||||||
})();
|
})();
|
||||||
|
|
|
||||||
|
|
@ -73,6 +73,8 @@ body{font-family:'DM Sans',sans-serif;background:var(--bg);color:var(--text);min
|
||||||
.ulbl{font-size:12px;color:var(--text3)}
|
.ulbl{font-size:12px;color:var(--text3)}
|
||||||
.btn-as{flex:1;padding:8px;border-radius:var(--rs);background:var(--blue-bg);color:var(--blue);border:1px solid rgba(37,99,235,.2);cursor:pointer;font-family:'DM Sans',sans-serif;font-size:13px;font-weight:600}
|
.btn-as{flex:1;padding:8px;border-radius:var(--rs);background:var(--blue-bg);color:var(--blue);border:1px solid rgba(37,99,235,.2);cursor:pointer;font-family:'DM Sans',sans-serif;font-size:13px;font-weight:600}
|
||||||
.btn-as:active{opacity:.7}
|
.btn-as:active{opacity:.7}
|
||||||
|
.btn-sw-fill{flex:none;padding:7px 9px;border-radius:var(--rs);background:var(--bg3);color:var(--text2);border:1px solid var(--border2);cursor:pointer;font-size:13px;line-height:1}
|
||||||
|
.btn-sw-fill:active{opacity:.7}
|
||||||
.nosets{font-size:12px;color:var(--text3);padding:4px 0 8px}
|
.nosets{font-size:12px;color:var(--text3);padding:4px 0 8px}
|
||||||
.card-foot{padding:8px 16px 12px;display:flex;justify-content:flex-end}
|
.card-foot{padding:8px 16px 12px;display:flex;justify-content:flex-end}
|
||||||
.btn-del{background:none;border:none;color:var(--text3);font-size:12px;cursor:pointer;padding:4px 0;font-family:'DM Sans',sans-serif}
|
.btn-del{background:none;border:none;color:var(--text3);font-size:12px;cursor:pointer;padding:4px 0;font-family:'DM Sans',sans-serif}
|
||||||
|
|
|
||||||
|
|
@ -55,6 +55,7 @@
|
||||||
<div class="add-row">
|
<div class="add-row">
|
||||||
<input class="num-in" type="number" min="1"/>
|
<input class="num-in" type="number" min="1"/>
|
||||||
<span class="ulbl"></span>
|
<span class="ulbl"></span>
|
||||||
|
<button class="btn-sw-fill" style="display:none">⏱</button>
|
||||||
<button class="btn-as">Eintragen</button>
|
<button class="btn-as">Eintragen</button>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
@ -74,6 +75,7 @@
|
||||||
<div class="qb-name"></div>
|
<div class="qb-name"></div>
|
||||||
<div class="qb-stat"></div>
|
<div class="qb-stat"></div>
|
||||||
<input class="num-in" type="number" min="1"/>
|
<input class="num-in" type="number" min="1"/>
|
||||||
|
<button class="btn-sw-fill" style="display:none">⏱</button>
|
||||||
<button class="btn-as">Eintragen</button>
|
<button class="btn-as">Eintragen</button>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue