Admin traffic: conversion columns (visit to signup, signup to registered, signup to buyer), stacked centered headers
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
+3
-1
@@ -10,6 +10,8 @@
|
||||
<style>
|
||||
.adm-table{width:100%;table-layout:auto}
|
||||
.adm-table th{cursor:pointer;user-select:none;white-space:nowrap}
|
||||
#trfSources th,#trfAngles th{white-space:normal;text-align:center;line-height:1.2;vertical-align:bottom}
|
||||
#trfSources td:not(:first-child),#trfAngles td:not(:first-child){text-align:center;font-variant-numeric:tabular-nums}
|
||||
.adm-table th.sort-asc::after{content:' \25B2';font-size:9px;color:var(--mint)}
|
||||
.adm-table th.sort-desc::after{content:' \25BC';font-size:9px;color:var(--mint)}
|
||||
.adm-table.kv th{cursor:default;color:var(--muted);font-weight:500}
|
||||
@@ -421,6 +423,6 @@
|
||||
</div>
|
||||
|
||||
<script src="/assets/common.js?v=20260913a"></script>
|
||||
<script src="/assets/admin.js?v=20260913b"></script>
|
||||
<script src="/assets/admin.js?v=20260913c"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -461,10 +461,13 @@
|
||||
const esc = s => String(s == null ? '' : s).replace(/[&<>"]/g, c => ({ '&': '&', '<': '<', '>': '>', '"': '"' }[c]));
|
||||
const n = v => Number(v || 0).toLocaleString();
|
||||
$('trfSub').textContent = 'last ' + d.days + ' days · ' + n(d.totals.hits) + ' page views · ' + n(d.totals.joinViews) + ' join-page views · ' + n(d.totals.signups) + ' signups · ' + n(d.totals.buyers) + ' buyers';
|
||||
$('trfSources').innerHTML = '<tr><th>Source</th><th>Page views</th><th>Join-page views</th><th>Signups</th><th>Registered</th><th>$20+ buyers</th></tr>'
|
||||
+ (d.sources.length ? d.sources.map(s => '<tr><td>' + esc(s.source) + '</td><td>' + n(s.hits) + '</td><td>' + n(s.joinViews) + '</td><td>' + n(s.signups) + '</td><td>' + n(s.registered) + '</td><td>' + n(s.buyers) + '</td></tr>').join('') : '<tr><td colspan="6" class="muted">Nothing recorded in this range yet.</td></tr>');
|
||||
// conversion columns (Marty, 2026-09-13): visits = page views + join-page views; signup rate is per visit,
|
||||
// registered and buyer rates are per signup (what happened to the people who did sign up)
|
||||
const pct = (num, den) => den ? (100 * num / den).toFixed(num && 100 * num / den < 10 ? 1 : 0) + '%' : '<span class="muted">-</span>';
|
||||
$('trfSources').innerHTML = '<tr><th>Source</th><th>Page<br>views</th><th>Join-page<br>views</th><th>Signups</th><th>Visit →<br>signup</th><th>Registered</th><th>Signup →<br>registered</th><th>$20+<br>buyers</th><th>Signup →<br>buyer</th></tr>'
|
||||
+ (d.sources.length ? d.sources.map(s => '<tr><td>' + esc(s.source) + '</td><td>' + n(s.hits) + '</td><td>' + n(s.joinViews) + '</td><td>' + n(s.signups) + '</td><td>' + pct(s.signups, s.hits + s.joinViews) + '</td><td>' + n(s.registered) + '</td><td>' + pct(s.registered, s.signups) + '</td><td>' + n(s.buyers) + '</td><td>' + pct(s.buyers, s.signups) + '</td></tr>').join('') : '<tr><td colspan="9" class="muted">Nothing recorded in this range yet.</td></tr>');
|
||||
$('trfPaths').innerHTML = '<tr><th>Page</th><th>Views</th></tr>' + (d.paths.length ? d.paths.map(p => '<tr><td>' + esc(p.path) + '</td><td>' + n(p.hits) + '</td></tr>').join('') : '<tr><td colspan="2" class="muted">No page views yet.</td></tr>');
|
||||
$('trfAngles').innerHTML = '<tr><th>Angle</th><th>Join-page views</th><th>Signups</th></tr>' + (d.angles.length ? d.angles.map(a => '<tr><td>' + esc(a.angle) + '</td><td>' + n(a.views) + '</td><td>' + n(a.signups) + '</td></tr>').join('') : '<tr><td colspan="3" class="muted">No angle data yet.</td></tr>');
|
||||
$('trfAngles').innerHTML = '<tr><th>Angle</th><th>Join-page<br>views</th><th>Signups</th><th>View →<br>signup</th></tr>' + (d.angles.length ? d.angles.map(a => '<tr><td>' + esc(a.angle) + '</td><td>' + n(a.views) + '</td><td>' + n(a.signups) + '</td><td>' + pct(a.signups, a.views) + '</td></tr>').join('') : '<tr><td colspan="4" class="muted">No angle data yet.</td></tr>');
|
||||
$('trfDaily').innerHTML = '<tr><th>Day</th><th>Page views</th><th>Signups</th></tr>' + (d.daily.length ? d.daily.slice().reverse().map(x => '<tr><td>' + esc(x.day) + '</td><td>' + n(x.hits) + '</td><td>' + n(x.signups) + '</td></tr>').join('') : '<tr><td colspan="3" class="muted">Nothing yet.</td></tr>');
|
||||
}
|
||||
// ── blog: coaching articles, public at /blog (Marty, 2026-09-12) ──
|
||||
|
||||
Reference in New Issue
Block a user