Image-based half-sheet handouts: vibrant gradient backgrounds with dynamic QR overlay
Replaces text-heavy card design with eye-catching image backgrounds (pocket/two/phone/graveyard/stop-waiting angles, 1700x1100px, half-sheet 2-per-page format). QR code + link overlaid dynamically via Canvas in bottom-right with semi-dark fade for readability. Print layout: two copies per letter page with cut line between. Visual impact first, clean overlay on top. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
+6
-35
@@ -37,45 +37,16 @@
|
|||||||
.t-blue h2 .k{color:#2947c9}
|
.t-blue h2 .k{color:#2947c9}
|
||||||
.t-navy .fl-hd{background:linear-gradient(135deg,#0b1d2e,#071421)}
|
.t-navy .fl-hd{background:linear-gradient(135deg,#0b1d2e,#071421)}
|
||||||
.t-navy h2 .k{color:#c98a12}
|
.t-navy h2 .k{color:#c98a12}
|
||||||
/* ---- half-sheet handouts (2 per letter page, cut in half) ---- */
|
/* ---- half-sheet handouts (2 per letter page, cut in half, image-based) ---- */
|
||||||
.hs-page{margin:0 auto 26px;max-width:680px}
|
.hs-page{margin:0 auto 26px;max-width:680px}
|
||||||
.hs{position:relative;aspect-ratio:8.5/5.5;border-radius:14px;overflow:hidden;color:#fff;display:flex;flex-direction:column;
|
.hs{position:relative;aspect-ratio:8.5/5.5;border-radius:14px;overflow:hidden;box-shadow:0 10px 30px rgba(0,0,0,.35);
|
||||||
box-shadow:0 10px 30px rgba(0,0,0,.35);font-family:Inter,system-ui,sans-serif;
|
display:flex;align-items:flex-end;justify-content:flex-end;font-family:Inter,system-ui,sans-serif;
|
||||||
-webkit-print-color-adjust:exact;print-color-adjust:exact}
|
-webkit-print-color-adjust:exact;print-color-adjust:exact}
|
||||||
.hs-top{display:flex;align-items:center;gap:10px;padding:14px 22px 0}
|
.hs-img-bg{background-size:cover;background-position:center}
|
||||||
.hs-ring{width:34px;height:34px;border:3px solid #f3be43;border-radius:50%;display:flex;align-items:center;justify-content:center;flex:0 0 auto}
|
.hs-canvas{display:block}
|
||||||
.hs-ring span{font-family:Georgia,serif;font-weight:700;font-size:13px;color:#f3be43}
|
.hs-print{position:absolute;top:10px;right:10px;z-index:10;cursor:pointer}
|
||||||
.hs-brand{font-weight:900;font-size:13px;letter-spacing:1.5px}
|
|
||||||
.hs-eye{margin-left:auto;font-weight:800;font-size:9.5px;letter-spacing:2px;opacity:.85;text-align:right}
|
|
||||||
.hs-main{flex:1;display:flex;gap:16px;padding:8px 22px 10px;align-items:center}
|
|
||||||
.hs-left{flex:1;min-width:0}
|
|
||||||
.hs-left h2{font-size:29px;line-height:1.04;font-weight:900;margin:0 0 8px;letter-spacing:-.5px;text-transform:uppercase}
|
|
||||||
.hs-left h2 .k{-webkit-text-fill-color:currentColor}
|
|
||||||
.hs-left .pitch{font-size:12px;line-height:1.45;margin:0 0 10px;opacity:.92}
|
|
||||||
.hs-chips{display:flex;flex-wrap:wrap;gap:6px}
|
|
||||||
.hs-chip{font-size:9.5px;font-weight:800;letter-spacing:.6px;padding:4px 9px;border-radius:999px;border:1.5px solid rgba(255,255,255,.55);background:rgba(0,0,0,.25)}
|
|
||||||
.hs-chip.gold{border-color:#f3be43;color:#ffd977}
|
|
||||||
.hs-qrbox{flex:0 0 auto;background:#fff;border-radius:12px;padding:10px 12px 8px;text-align:center;color:#10151b;box-shadow:0 4px 14px rgba(0,0,0,.35)}
|
|
||||||
.hs-qrbox .q{width:118px;height:118px;line-height:0;margin:0 auto}
|
|
||||||
.hs-qrbox .q svg{width:100%;height:100%}
|
|
||||||
.hs-qrbox .scan{font-size:9.5px;font-weight:800;letter-spacing:1.5px;margin-top:4px}
|
|
||||||
.hs-link{font-size:11px;font-weight:800;word-break:break-all;margin-top:2px}
|
|
||||||
.hs-foot{display:flex;align-items:center;gap:10px;padding:0 22px 10px}
|
|
||||||
.hs-disc{font-size:8.5px;line-height:1.35;opacity:.75}
|
|
||||||
.hs-print{position:absolute;top:10px;right:10px;z-index:5}
|
|
||||||
.hs-copy{display:none}
|
.hs-copy{display:none}
|
||||||
.hs-cut{display:none}
|
.hs-cut{display:none}
|
||||||
/* vibrant themes (match the banner kit looks) */
|
|
||||||
.h-volt{background:linear-gradient(120deg,#1b0733 0%,#3d0d7a 45%,#6a14b8 100%)}
|
|
||||||
.h-volt h2 .k{color:#ffcf3f}
|
|
||||||
.h-ember{background:linear-gradient(120deg,#160406 0%,#4a0a12 55%,#8a1020 100%)}
|
|
||||||
.h-ember h2 .k{color:#ff9d2e}
|
|
||||||
.h-aqua{background:linear-gradient(120deg,#02201f 0%,#04544d 55%,#0a8f7d 100%)}
|
|
||||||
.h-aqua h2 .k{color:#ffd977}
|
|
||||||
.h-royal{background:linear-gradient(120deg,#060d2b 0%,#12246e 55%,#2140c0 100%)}
|
|
||||||
.h-royal h2 .k{color:#68d6ff}
|
|
||||||
.h-noir{background:linear-gradient(120deg,#05090f 0%,#0b1d2e 60%,#14314d 100%)}
|
|
||||||
.h-noir h2 .k{color:#f3be43}
|
|
||||||
@media (max-width:560px){.hs{aspect-ratio:auto}.hs-main{flex-direction:column;align-items:stretch}.hs-qrbox{align-self:center}}
|
@media (max-width:560px){.hs{aspect-ratio:auto}.hs-main{flex-direction:column;align-items:stretch}.hs-qrbox{align-self:center}}
|
||||||
@media print{
|
@media print{
|
||||||
@page{size:letter;margin:0}
|
@page{size:letter;margin:0}
|
||||||
|
|||||||
+139
-12
@@ -92,35 +92,162 @@
|
|||||||
buildHalf(id);
|
buildHalf(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
function halfSheetHtml(f, url, shortUrl, haveId) {
|
|
||||||
return '<div class="hs-top"><div class="hs-ring"><span>RM</span></div><div class="hs-brand">THE RM CIRCLE</div><div class="hs-eye">' + f.eye + '</div></div>' +
|
|
||||||
'<div class="hs-main"><div class="hs-left"><h2>' + f.h + '</h2><p class="pitch">' + f.pitch + '</p>' +
|
|
||||||
'<div class="hs-chips">' + f.chips.map(function (c, i) { return '<span class="hs-chip' + (i === 0 ? ' gold' : '') + '">' + c + '</span>'; }).join('') + '</div></div>' +
|
|
||||||
'<div class="hs-qrbox"><div class="q">' + (haveId ? qrSvg(url) : '') + '</div><div class="scan">SCAN ME 📷</div><div class="hs-link">' + shortUrl + '</div></div></div>' +
|
|
||||||
'<div class="hs-foot"><p class="hs-disc">Independent team resource. Participation takes real effort and involves cryptocurrency risk. No income is guaranteed. Learn more at rmcircle.team.</p></div>';
|
|
||||||
}
|
|
||||||
|
|
||||||
function buildHalf(id) {
|
function buildHalf(id) {
|
||||||
var host = document.getElementById('halfsheets');
|
var host = document.getElementById('halfsheets');
|
||||||
if (!host) return;
|
if (!host) return;
|
||||||
host.innerHTML = '';
|
host.innerHTML = '';
|
||||||
var haveId = /^\d{1,15}$/.test(id);
|
var haveId = /^\d{1,15}$/.test(id);
|
||||||
var idLabel = haveId ? id : '____';
|
var idLabel = haveId ? id : '____';
|
||||||
|
|
||||||
HALF.forEach(function (f) {
|
HALF.forEach(function (f) {
|
||||||
var url = 'https://rmcircle.team/join/' + (haveId ? id : '') + (f.angle ? '?v=' + f.angle : '');
|
var url = 'https://rmcircle.team/join/' + (haveId ? id : '') + (f.angle ? '?v=' + f.angle : '');
|
||||||
var shortUrl = 'rmcircle.team/join/' + idLabel;
|
var shortUrl = 'rmcircle.team/join/' + idLabel;
|
||||||
|
var imgFile = '/handout-' + (f.angle || 'stop-waiting') + '.png';
|
||||||
|
|
||||||
var page = el('div', 'hs-page');
|
var page = el('div', 'hs-page');
|
||||||
var card = el('div', 'hs ' + f.theme, halfSheetHtml(f, url, shortUrl, haveId));
|
var card = el('div', 'hs hs-img-bg');
|
||||||
var pr = el('button', 'hs-print btn btn-teal btn-sm', '🖨 Print (2 per page)');
|
card.style.backgroundImage = 'url(' + imgFile + ')';
|
||||||
|
card.style.backgroundSize = 'cover';
|
||||||
|
card.style.backgroundPosition = 'center';
|
||||||
|
card.style.position = 'relative';
|
||||||
|
|
||||||
|
var canvas = el('canvas');
|
||||||
|
canvas.width = 1700;
|
||||||
|
canvas.height = 1100;
|
||||||
|
canvas.className = 'hs-canvas';
|
||||||
|
canvas.style.position = 'absolute';
|
||||||
|
canvas.style.top = '0';
|
||||||
|
canvas.style.left = '0';
|
||||||
|
canvas.style.zIndex = '1';
|
||||||
|
card.appendChild(canvas);
|
||||||
|
|
||||||
|
var pr = el('button', 'hs-print btn btn-teal btn-sm', 'Print (2 per page)');
|
||||||
|
pr.style.position = 'relative';
|
||||||
|
pr.style.zIndex = '2';
|
||||||
card.appendChild(pr);
|
card.appendChild(pr);
|
||||||
|
|
||||||
|
// Render QR on canvas
|
||||||
|
(function(canvas, url, shortUrl) {
|
||||||
|
var renderQr = function() {
|
||||||
|
var ctx = canvas.getContext('2d');
|
||||||
|
if (!ctx) return;
|
||||||
|
|
||||||
|
ctx.fillStyle = 'rgba(30, 30, 40, 0.6)';
|
||||||
|
ctx.fillRect(1020, 550, 680, 550);
|
||||||
|
|
||||||
|
var qrSize = 240;
|
||||||
|
var qrX = 1700 - qrSize - 40;
|
||||||
|
var qrY = 1100 - qrSize - 100;
|
||||||
|
|
||||||
|
ctx.fillStyle = '#ffffff';
|
||||||
|
ctx.fillRect(qrX - 10, qrY - 10, qrSize + 20, qrSize + 20);
|
||||||
|
ctx.strokeStyle = '#000';
|
||||||
|
ctx.lineWidth = 3;
|
||||||
|
ctx.strokeRect(qrX - 10, qrY - 10, qrSize + 20, qrSize + 20);
|
||||||
|
|
||||||
|
if (url.indexOf('join/') !== -1) {
|
||||||
|
var qrSvgStr = qrSvg(url);
|
||||||
|
if (qrSvgStr) {
|
||||||
|
var tempDiv = document.createElement('div');
|
||||||
|
tempDiv.innerHTML = qrSvgStr;
|
||||||
|
var svg = tempDiv.querySelector('svg');
|
||||||
|
if (svg) {
|
||||||
|
var svgData = new XMLSerializer().serializeToString(svg);
|
||||||
|
var img = new Image();
|
||||||
|
img.onload = function() {
|
||||||
|
ctx.drawImage(img, qrX, qrY, qrSize, qrSize);
|
||||||
|
drawLink();
|
||||||
|
};
|
||||||
|
img.onerror = drawLink;
|
||||||
|
img.src = 'data:image/svg+xml;base64,' + btoa(svgData);
|
||||||
|
} else { drawLink(); }
|
||||||
|
} else { drawLink(); }
|
||||||
|
} else { drawLink(); }
|
||||||
|
|
||||||
|
function drawLink() {
|
||||||
|
ctx.font = 'bold 20px Arial';
|
||||||
|
ctx.fillStyle = '#ffffff';
|
||||||
|
ctx.textAlign = 'center';
|
||||||
|
ctx.shadowColor = 'rgba(0,0,0,0.8)';
|
||||||
|
ctx.shadowBlur = 4;
|
||||||
|
ctx.shadowOffsetX = 2;
|
||||||
|
ctx.shadowOffsetY = 2;
|
||||||
|
ctx.fillText(shortUrl, 1700 - 120, 1100 - 30);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
setTimeout(renderQr, 100);
|
||||||
|
})(canvas, url, shortUrl);
|
||||||
|
|
||||||
page.appendChild(card);
|
page.appendChild(card);
|
||||||
page.appendChild(el('div', 'hs-cut', '✂ cut here ✂'));
|
page.appendChild(el('div', 'hs-cut', 'cut here'));
|
||||||
page.appendChild(el('div', 'hs hs-copy ' + f.theme, halfSheetHtml(f, url, shortUrl, haveId)));
|
|
||||||
|
var card2 = el('div', 'hs hs-img-bg hs-copy');
|
||||||
|
card2.style.backgroundImage = 'url(' + imgFile + ')';
|
||||||
|
card2.style.backgroundSize = 'cover';
|
||||||
|
card2.style.backgroundPosition = 'center';
|
||||||
|
card2.style.position = 'relative';
|
||||||
|
var canvas2 = el('canvas');
|
||||||
|
canvas2.width = 1700;
|
||||||
|
canvas2.height = 1100;
|
||||||
|
canvas2.style.position = 'absolute';
|
||||||
|
canvas2.style.top = '0';
|
||||||
|
canvas2.style.left = '0';
|
||||||
|
card2.appendChild(canvas2);
|
||||||
|
|
||||||
|
(function(canvas, url, shortUrl) {
|
||||||
|
var renderQr = function() {
|
||||||
|
var ctx = canvas.getContext('2d');
|
||||||
|
if (!ctx) return;
|
||||||
|
ctx.fillStyle = 'rgba(30, 30, 40, 0.6)';
|
||||||
|
ctx.fillRect(1020, 550, 680, 550);
|
||||||
|
var qrSize = 240;
|
||||||
|
var qrX = 1700 - qrSize - 40;
|
||||||
|
var qrY = 1100 - qrSize - 100;
|
||||||
|
ctx.fillStyle = '#ffffff';
|
||||||
|
ctx.fillRect(qrX - 10, qrY - 10, qrSize + 20, qrSize + 20);
|
||||||
|
ctx.strokeStyle = '#000';
|
||||||
|
ctx.lineWidth = 3;
|
||||||
|
ctx.strokeRect(qrX - 10, qrY - 10, qrSize + 20, qrSize + 20);
|
||||||
|
if (url.indexOf('join/') !== -1) {
|
||||||
|
var qrSvgStr = qrSvg(url);
|
||||||
|
if (qrSvgStr) {
|
||||||
|
var tempDiv = document.createElement('div');
|
||||||
|
tempDiv.innerHTML = qrSvgStr;
|
||||||
|
var svg = tempDiv.querySelector('svg');
|
||||||
|
if (svg) {
|
||||||
|
var svgData = new XMLSerializer().serializeToString(svg);
|
||||||
|
var img = new Image();
|
||||||
|
img.onload = function() {
|
||||||
|
ctx.drawImage(img, qrX, qrY, qrSize, qrSize);
|
||||||
|
drawLink();
|
||||||
|
};
|
||||||
|
img.onerror = drawLink;
|
||||||
|
img.src = 'data:image/svg+xml;base64,' + btoa(svgData);
|
||||||
|
} else { drawLink(); }
|
||||||
|
} else { drawLink(); }
|
||||||
|
} else { drawLink(); }
|
||||||
|
function drawLink() {
|
||||||
|
ctx.font = 'bold 20px Arial';
|
||||||
|
ctx.fillStyle = '#ffffff';
|
||||||
|
ctx.textAlign = 'center';
|
||||||
|
ctx.shadowColor = 'rgba(0,0,0,0.8)';
|
||||||
|
ctx.shadowBlur = 4;
|
||||||
|
ctx.shadowOffsetX = 2;
|
||||||
|
ctx.shadowOffsetY = 2;
|
||||||
|
ctx.fillText(shortUrl, 1700 - 120, 1100 - 30);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
setTimeout(renderQr, 100);
|
||||||
|
})(canvas2, url, shortUrl);
|
||||||
|
|
||||||
|
page.appendChild(card2);
|
||||||
|
|
||||||
pr.addEventListener('click', function () {
|
pr.addEventListener('click', function () {
|
||||||
document.body.classList.add('print-one'); page.classList.add('printing');
|
document.body.classList.add('print-one'); page.classList.add('printing');
|
||||||
window.print();
|
window.print();
|
||||||
setTimeout(function () { document.body.classList.remove('print-one'); page.classList.remove('printing'); }, 400);
|
setTimeout(function () { document.body.classList.remove('print-one'); page.classList.remove('printing'); }, 400);
|
||||||
});
|
});
|
||||||
|
|
||||||
host.appendChild(page);
|
host.appendChild(page);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
Binary file not shown.
|
After Width: | Height: | Size: 136 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 41 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 168 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 183 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 60 KiB |
Reference in New Issue
Block a user