Featured to top, centered, capped; banner ads capped 728px centered; slot CTA

- Featured card moved to the top of Overview, centered, max 760px; the rotating
  link is capped to 728px and centered (banner-sized, not a huge block).
- Served banner creatives cap at min(100%,728px), centered — kills the oversized
  sample banner; ad slots center their creative + label.
- Featured self-sell: shows "N of C slots open today" + "Feature your link →"
  that jumps to Campaigns with Featured preselected.
- Campaign target/image/video URL fields get autocomplete=off and clear when the
  Campaigns pane opens, so no residual (e.g. massifly) URL carries over.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
martbost
2026-09-07 08:08:47 -05:00
parent 3a6d9d037c
commit bc95965814
9 changed files with 34 additions and 17 deletions
+2 -1
View File
@@ -117,8 +117,9 @@ window.IAP = (function () {
const el = $(elId);
if (!ad || !el) return;
if (ad.imageUrl) {
el.style.textAlign = 'center';
el.innerHTML = '<a href="' + ad.targetUrl + '" target="_blank" rel="noopener nofollow">'
+ '<img src="' + ad.imageUrl + '" alt="advertisement" style="max-width:100%;border-radius:8px"></a>'
+ '<img src="' + ad.imageUrl + '" alt="advertisement" style="max-width:min(100%,728px);height:auto;display:block;margin:0 auto;border-radius:8px"></a>'
+ '<div class="small muted">member ad' + reportTag(ad) + '</div>';
} else {
el.innerHTML = '<a href="' + ad.targetUrl + '" target="_blank" rel="noopener nofollow"><b>' + ad.title + '</b>'
+13
View File
@@ -46,6 +46,18 @@
renderOneFeatured(); // show ONE at a time (true rotation), cycle if more than one
clearInterval(featTimer);
if (featItems.length > 1) featTimer = setInterval(() => { featIdx++; renderOneFeatured(); }, 6000);
// self-sell: today's open slots + a CTA to feature your own link
try {
const st = await (await fetch('/api/featured/stats')).json();
const today = (st.occupancy || []).find(d => d.offset === 0);
const cta = $('featCta');
if (cta) {
cta.innerHTML = (today ? '<span class="muted">' + today.open + ' of ' + today.cap + ' featured slots open today. </span>' : '')
+ '<a href="#campaigns" id="featBuy" style="color:var(--mint);font-weight:700;text-decoration:none">Feature your link →</a>';
const fb = $('featBuy');
if (fb) fb.addEventListener('click', e => { e.preventDefault(); setPane('campaigns'); const ct = $('cType'); if (ct) { ct.value = 'featured'; ct.dispatchEvent(new Event('change')); } });
}
} catch (e) {}
} catch (e) {}
}
@@ -376,6 +388,7 @@
if (name === 'earn') setEarnSub(earnSub); // refresh whichever sub-tab is active
if (name === 'profile') loadLineBanner();
if (name === 'line') { loadLineage(); loadUplineMessages(); }
if (name === 'campaigns') ['cTarget', 'cImage', 'cVideoUrl'].forEach(id => { if ($(id)) $(id).value = ''; }); // no residual URL between visits
document.getElementById('memberArea').classList.remove('side-open'); // close mobile drawer
if (location.hash !== '#' + name) history.replaceState(null, '', '#' + name);
}
+3 -1
View File
@@ -274,7 +274,9 @@ textarea{resize:vertical;font:inherit}
.feat-day .fd-occ{font-family:var(--mono);font-size:11px;color:var(--muted)}
.feat-day.open2 .fd-occ{color:var(--mint)}
/* ── featured rotation strip ── */
.feat-strip{display:flex;flex-direction:column;gap:8px;margin-top:10px}
.feat-top{max-width:760px;margin:0 auto 16px}
.feat-strip{display:flex;justify-content:center;margin-top:10px}
.feat-strip a{max-width:728px;width:100%}
.feat-strip a{display:flex;justify-content:space-between;gap:10px;padding:11px 14px;border-radius:10px;
background:var(--panel);border:1px solid var(--line-strong);color:var(--ink);text-decoration:none;font-weight:600}
.feat-strip a:hover{border-color:var(--mint)}