b019becebe
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>
265 lines
12 KiB
JavaScript
265 lines
12 KiB
JavaScript
// Printable RM Circle flyers, personalized to the member. Each flyer's QR + the
|
||
// tear-off tabs carry /join/<id> (angle-matched per flyer). Reuses qrlib.js.
|
||
(function () {
|
||
'use strict';
|
||
var FLYERS = [
|
||
{ angle: 'pocket', theme: 't-gold', eye: 'PAYS PERSON-TO-PERSON · ON POLYGON',
|
||
h: 'You Already <span class="k">Found the Money.</span>',
|
||
pitch: 'The pocket change that slips through your fingers every week could be starting something instead. Scan for the 90-second look — no sign-up, no pressure, just the math.' },
|
||
{ angle: 'two', theme: 't-teal', eye: 'A CRYPTO TEAM BUILD · POLYGON',
|
||
h: 'You Know <span class="k">Two People.</span> That’s All This Takes.',
|
||
pitch: 'No big network. Nothing to sell. Get two, help them get theirs, and payments roll up to you on-chain as your team grows. Scan to see exactly how it works.' },
|
||
{ angle: 'phone', theme: 't-blue', eye: 'ON-CHAIN · NO MIDDLEMAN',
|
||
h: 'Your Phone Could <span class="k">Start Paying You.</span>',
|
||
pitch: 'The device in your hand is the only tool this needs. A public smart contract on Polygon pays people directly — no company holding the money. Scan and see for yourself.' },
|
||
{ angle: 'graveyard', theme: 't-navy', eye: 'AUTONOMOUS · IMMUTABLE · POLYGON',
|
||
h: 'Tired of Side Hustles <span class="k">That Die?</span>',
|
||
pitch: 'This one can’t be shut off. It runs on a public, immutable smart contract — no company, no owner who can pull the plug and take your momentum with them. Scan to look inside.' }
|
||
];
|
||
var TABS = 8;
|
||
|
||
// Half-sheet handouts: 2 copies per letter page with a cut line. Vibrant
|
||
// themes echo the banner kit. Copy mirrors the approved full-page flyers.
|
||
var HALF = [
|
||
{ angle: 'pocket', theme: 'h-volt', eye: 'TEAM BUILD · ON POLYGON',
|
||
h: 'You Already <span class="k">Found the Money.</span>',
|
||
pitch: 'The pocket change that slips through your fingers every week could be starting something instead. Scan for the 90-second look.',
|
||
chips: ['ONLY 2 TO QUALIFY', 'SPILLOVER HELPS YOU', 'PAID IN SECONDS'] },
|
||
{ angle: 'two', theme: 'h-aqua', eye: 'A CRYPTO TEAM BUILD',
|
||
h: 'You Know <span class="k">Two People.</span> That’s All This Takes.',
|
||
pitch: 'No big network. Nothing to sell. Get two, help them get theirs, and payments roll up to you on-chain as your team grows.',
|
||
chips: ['GET YOUR 2', 'HELP THEM GET THEIRS', 'ON-CHAIN · VERIFIABLE'] },
|
||
{ angle: 'phone', theme: 'h-royal', eye: 'ON-CHAIN · NO MIDDLEMAN',
|
||
h: 'Your Phone Could <span class="k">Start Paying You.</span>',
|
||
pitch: 'The device in your hand is the only tool this needs. A public smart contract on Polygon pays people directly — no company holding the money.',
|
||
chips: ['NO LAPTOP NEEDED', 'PUBLIC SMART CONTRACT', 'PAID IN SECONDS'] },
|
||
{ angle: 'graveyard', theme: 'h-noir', eye: 'AUTONOMOUS · IMMUTABLE',
|
||
h: 'Tired of Side Hustles <span class="k">That Die?</span>',
|
||
pitch: 'This one can’t be shut off. It runs on a public, immutable smart contract — no owner who can pull the plug and take your momentum with them.',
|
||
chips: ['NO PLUG TO PULL', 'IMMUTABLE CONTRACT', 'RUNS ON POLYGON'] },
|
||
{ angle: '', theme: 'h-ember', eye: 'VERIFY IT YOURSELF · POLYGON',
|
||
h: 'Stop <span class="k">Waiting.</span> Start <span class="k">Receiving.</span>',
|
||
pitch: 'Still researching? The whole system is public code you can check before you ever put in a cent. Due diligence takes an evening, not a year.',
|
||
chips: ['ONLY 2 TO QUALIFY', 'VERIFY BEFORE YOU JOIN', 'PAID IN SECONDS'] }
|
||
];
|
||
|
||
function getId() {
|
||
var q = new URLSearchParams(location.search).get('id');
|
||
if (q && /^\d{1,15}$/.test(q)) return q;
|
||
var inp = document.getElementById('flIdInput');
|
||
if (inp && /^\d{1,15}$/.test(inp.value)) return inp.value;
|
||
try { var s = localStorage.getItem('ctb.myId') || localStorage.getItem('rmc.toolsId'); if (s && /^\d{1,15}$/.test(s)) return s; } catch (e) {}
|
||
return '';
|
||
}
|
||
function qrSvg(url) {
|
||
try { var q = qrcode(0, 'M'); q.addData(url); q.make(); return q.createSvgTag({ cellSize: 4, margin: 2, scalable: true }); } catch (e) { return ''; }
|
||
}
|
||
function el(tag, cls, html) { var d = document.createElement(tag); if (cls) d.className = cls; if (html != null) d.innerHTML = html; return d; }
|
||
|
||
function build(id) {
|
||
var host = document.getElementById('flyers');
|
||
host.innerHTML = '';
|
||
var haveId = /^\d{1,15}$/.test(id);
|
||
var idLabel = haveId ? id : '____';
|
||
FLYERS.forEach(function (f) {
|
||
var url = 'https://rmcircle.team/join/' + (haveId ? id : '') + (f.angle ? '?v=' + f.angle : '');
|
||
var shortUrl = 'rmcircle.team/join/' + idLabel;
|
||
var card = el('div', 'fl ' + f.theme);
|
||
var pr = el('button', 'fl-print btn btn-teal btn-sm', '🖨 Print this flyer');
|
||
card.appendChild(pr);
|
||
card.appendChild(el('div', 'fl-hd', '<div class="fl-ring"><span>RM</span></div><div class="fl-eye">' + f.eye + '</div><div class="fl-brand">THE RM CIRCLE</div>'));
|
||
var body = el('div', 'fl-body',
|
||
'<h2>' + f.h + '</h2><p class="pitch">' + f.pitch + '</p>' +
|
||
'<div class="fl-scan"><div class="fl-qr">' + (haveId ? qrSvg(url) : '') + '</div>' +
|
||
'<div class="si"><span class="sm">Scan with your phone camera 📷</span><b>' + shortUrl + '</b><span class="sm">Then take the 2-minute tour.</span></div></div>' +
|
||
'<p class="fl-disc">Independent team resource. Participation takes real effort and involves cryptocurrency risk. No income is guaranteed. Learn more at rmcircle.team.</p>');
|
||
card.appendChild(body);
|
||
var tabs = el('div', 'fl-tabs');
|
||
for (var i = 0; i < TABS; i++) tabs.appendChild(el('div', 'fl-tab', '✂ ' + shortUrl));
|
||
card.appendChild(tabs);
|
||
pr.addEventListener('click', function () {
|
||
document.body.classList.add('print-one'); card.classList.add('printing');
|
||
window.print();
|
||
setTimeout(function () { document.body.classList.remove('print-one'); card.classList.remove('printing'); }, 400);
|
||
});
|
||
host.appendChild(card);
|
||
});
|
||
if (!haveId) {
|
||
var note = el('p', 'micro', 'Enter your member ID above to fill in your QR codes and links. (Blank flyers still print if you want to write the link by hand.)');
|
||
note.style.cssText = 'color:var(--gold);text-align:center;margin:-14px 0 20px';
|
||
host.insertBefore(note, host.firstChild);
|
||
}
|
||
buildHalf(id);
|
||
}
|
||
|
||
function buildHalf(id) {
|
||
var host = document.getElementById('halfsheets');
|
||
if (!host) return;
|
||
host.innerHTML = '';
|
||
var haveId = /^\d{1,15}$/.test(id);
|
||
var idLabel = haveId ? id : '____';
|
||
|
||
HALF.forEach(function (f) {
|
||
var url = 'https://rmcircle.team/join/' + (haveId ? id : '') + (f.angle ? '?v=' + f.angle : '');
|
||
var shortUrl = 'rmcircle.team/join/' + idLabel;
|
||
var imgFile = '/handout-' + (f.angle || 'stop-waiting') + '.png';
|
||
|
||
var page = el('div', 'hs-page');
|
||
var card = el('div', 'hs hs-img-bg');
|
||
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);
|
||
|
||
// 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(el('div', 'hs-cut', 'cut here'));
|
||
|
||
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 () {
|
||
document.body.classList.add('print-one'); page.classList.add('printing');
|
||
window.print();
|
||
setTimeout(function () { document.body.classList.remove('print-one'); page.classList.remove('printing'); }, 400);
|
||
});
|
||
|
||
host.appendChild(page);
|
||
});
|
||
}
|
||
|
||
var input = document.getElementById('flIdInput');
|
||
var initial = getId();
|
||
if (input && initial) input.value = initial;
|
||
build(initial);
|
||
if (input) input.addEventListener('input', function () {
|
||
var v = input.value.replace(/\D/g, '').slice(0, 15); input.value = v;
|
||
if (/^\d{1,15}$/.test(v)) { try { localStorage.setItem('rmc.toolsId', v); } catch (e) {} }
|
||
build(v);
|
||
});
|
||
})();
|