Add /training page with four self-hosted walkthrough videos
- Videos loudness-normalized to -16 LUFS (originals were ~-33 LUFS). - Static file serving rewritten to stream with HTTP Range support so video seeking works; .mp4/.webm MIME types added. - Training nav links on homepage and /start, plus a first-time callout on /start; training page views tracked per source in admin analytics. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
+3
-3
@@ -8,8 +8,8 @@ function statusClass(s){return `status status-${s}`}
|
||||
function pct(n,d){return d?`${Math.round((n/d)*100)}%`:'—'}
|
||||
function renderAnalytics(){
|
||||
const src=(state.analytics&&state.analytics.sources)||{};
|
||||
const tot={bridge:0,start:0,click:0};
|
||||
const list=Object.entries(src).map(([name,r])=>{tot.bridge+=r.bridge||0;tot.start+=r.start||0;tot.click+=r.click||0;return{name,bridge:r.bridge||0,start:r.start||0,click:r.click||0}})
|
||||
const tot={bridge:0,start:0,click:0,training:0};
|
||||
const list=Object.entries(src).map(([name,r])=>{tot.bridge+=r.bridge||0;tot.start+=r.start||0;tot.click+=r.click||0;tot.training+=r.training||0;return{name,bridge:r.bridge||0,start:r.start||0,click:r.click||0,training:r.training||0}})
|
||||
.sort((a,b)=>b.click-a.click||b.start-a.start||b.bridge-a.bridge);
|
||||
document.getElementById('funnelStats').innerHTML=
|
||||
`<div class="fact"><small>Bridge views</small><strong>${tot.bridge}</strong></div>`+
|
||||
@@ -17,7 +17,7 @@ function renderAnalytics(){
|
||||
`<div class="fact"><small>Join clicks</small><strong>${tot.click}</strong></div>`+
|
||||
`<div class="fact"><small>Bridge → Start</small><strong>${pct(tot.start,tot.bridge)}</strong></div>`+
|
||||
`<div class="fact"><small>Start → Join</small><strong>${pct(tot.click,tot.start)}</strong></div>`;
|
||||
document.getElementById('trafficRows').innerHTML=list.map(r=>`<tr><td><strong>${esc(r.name)}</strong></td><td>${r.bridge}</td><td>${r.start}</td><td>${r.click}</td><td>${pct(r.click,r.start)}</td></tr>`).join('')||'<tr><td colspan="5" class="empty">No traffic recorded yet.</td></tr>';
|
||||
document.getElementById('trafficRows').innerHTML=list.map(r=>`<tr><td><strong>${esc(r.name)}</strong></td><td>${r.bridge}</td><td>${r.start}</td><td>${r.training}</td><td>${r.click}</td><td>${pct(r.click,r.start)}</td></tr>`).join('')||'<tr><td colspan="6" class="empty">No traffic recorded yet.</td></tr>';
|
||||
}
|
||||
function esc(s){return String(s??'').replace(/[&<>'"]/g,c=>({'&':'&','<':'<','>':'>',"'":''','"':'"'}[c]))}
|
||||
function render(){
|
||||
|
||||
Reference in New Issue
Block a user