Training: section headers; byline 'Brought to you by the Crypto Team Build Network' under every logo

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
martbost
2026-09-10 06:25:58 -05:00
parent 15a881a72b
commit f785016cb5
16 changed files with 39 additions and 28 deletions
+5 -1
View File
@@ -292,7 +292,11 @@
const el = $('trainingList'); if (!el) return;
const items = r.items || [];
if (!items.length) { el.innerHTML = '<p class="muted small">Training materials are being added. Check back soon.</p>'; return; }
let lastGroup = null;
el.innerHTML = items.map(it => {
// optional section header: entries carry a `group`; a header renders when it changes
let head = '';
if (it.group && it.group !== lastGroup) { lastGroup = it.group; head = '<h3 class="tr-group" style="margin:26px 0 6px;font-size:13px;letter-spacing:.12em;text-transform:uppercase;color:var(--muted)">' + esc(it.group) + '</h3>'; }
const isVid = it.videoUrl && /\.(mp4|webm)(\?|$)/i.test(it.videoUrl);
// poster: the admin list can carry one; otherwise assume a .jpg next to the .mp4 (the pipeline uploads both)
const poster = it.posterUrl || (isVid ? it.videoUrl.replace(/\.(mp4|webm)(\?.*)?$/i, '.jpg$2') : '');
@@ -300,7 +304,7 @@
const links = [];
if (it.videoUrl && !isVid) links.push('<a class="btn small sec" href="' + esc(it.videoUrl) + '" target="_blank" rel="noopener">Watch</a>');
if (it.docUrl) links.push('<a class="btn small sec" href="' + esc(it.docUrl) + '" target="_blank" rel="noopener">Open material</a>');
return '<div class="card"><h3>' + esc(it.title || 'Lesson') + '</h3>'
return head + '<div class="card"><h3>' + esc(it.title || 'Lesson') + '</h3>'
+ (it.desc ? '<p class="muted small">' + esc(it.desc) + '</p>' : '')
+ (media ? '<p style="margin:10px 0">' + media + '</p>' : '')
+ (links.length ? '<p>' + links.join(' ') + '</p>' : '') + '</div>';