diff --git a/assets/css/routes/user-center/revenue-earnings.css b/assets/css/routes/user-center/revenue-earnings.css index c7ff5643..c33d142d 100644 --- a/assets/css/routes/user-center/revenue-earnings.css +++ b/assets/css/routes/user-center/revenue-earnings.css @@ -214,9 +214,3 @@ .uc-content .uc-revenue-summary-row--explain { grid-template-columns: 1fr; } .uc-content .uc-revenue-summary-row--explain .uc-reward-richtext { grid-column: 1; } } - -/* 推广海报预览弹窗:舞台居中,canvas 自适应弹窗宽度。 */ -.uc-content .uc-affiliate-poster { display: grid; place-items: center; min-height: 120px; } -.uc-content .uc-affiliate-poster img, -.uc-content .uc-affiliate-poster canvas { display: block; max-width: 100%; height: auto; margin: 0 auto; border-radius: 12px; background: var(--surface-2, #f7f8fa); } -.uc-content .uc-affiliate-poster p { margin: 0; text-align: center; } diff --git a/assets/js/credits.js b/assets/js/credits.js index 10b255b0..4934dea8 100644 --- a/assets/js/credits.js +++ b/assets/js/credits.js @@ -150,19 +150,62 @@ }); } - // ===== Referral poster (canvas preview modal: hero image + copy + QR + link) ===== + // ===== Referral poster ===== + // 弹窗形态 1:1 复刻参考主题 poster-share.js:Bootstrap 语义(.in 显隐 + + // .modal-backdrop + body.modal-open + ESC),与下方充值弹窗同构,不复依赖 + // jQuery/Bootstrap 运行时。壳上带 .flex.jc,故打开态用 flex 而非 block。 function initAffiliatePoster(root, url, poster, siteName) { var button = root.querySelector('[data-affiliate-poster]'); var modal = document.querySelector('[data-aksrt-affiliate-poster-modal]'); - var stage = document.querySelector('[data-affiliate-poster-stage]'); - var download = document.querySelector('[data-affiliate-poster-download]'); + var stage = modal ? modal.querySelector('[data-affiliate-poster-stage]') : null; + var loading = modal ? modal.querySelector('[data-affiliate-poster-loading]') : null; + var content = modal ? modal.querySelector('.modal-content') : null; + var download = modal ? modal.querySelector('[data-affiliate-poster-download]') : null; if (!button || !modal) return; if (!url || !poster || poster.enabled !== true) return; button.hidden = false; - [].forEach.call(modal.querySelectorAll('[data-affiliate-poster-close]'), function (closer) { - closer.addEventListener('click', function () { closeModal(modal); }); - }); + + var backdrop = null; var canvas = null; + + function openPosterModal() { + if (modal.classList.contains('in')) return; + modal.style.display = 'flex'; + void modal.offsetWidth; // 强制 reflow,让 .fade 过渡从 scale(0.9) 起手 + modal.classList.add('in'); + modal.setAttribute('aria-hidden', 'false'); + if (!backdrop) { + backdrop = document.createElement('div'); + backdrop.className = 'modal-backdrop fade in'; + backdrop.setAttribute('data-affiliate-poster-backdrop', '1'); + document.body.appendChild(backdrop); + } + document.body.classList.add('modal-open'); + } + + function closePosterModal() { + if (!modal.classList.contains('in')) return; + modal.classList.remove('in'); + modal.setAttribute('aria-hidden', 'true'); + document.body.classList.remove('modal-open'); + if (backdrop && backdrop.parentNode) backdrop.parentNode.removeChild(backdrop); + backdrop = null; + // 等过渡结束再撤 display,复刻 Bootstrap 的 fade-out 收尾 + window.setTimeout(function () { + if (!modal.classList.contains('in')) modal.style.display = ''; + }, 300); + } + + modal.addEventListener('click', function (event) { + // 点遮罩层(.modal 自身)或关闭按钮(data-dismiss="modal") + if (event.target === modal || (event.target.closest && event.target.closest('[data-dismiss="modal"]'))) { + closePosterModal(); + } + }); + document.addEventListener('keydown', function (event) { + if (event.key === 'Escape' && modal.classList.contains('in')) closePosterModal(); + }); + if (download) { download.addEventListener('click', function () { if (!canvas) return; @@ -178,20 +221,47 @@ } }); } + button.addEventListener('click', function () { if (typeof window.qrcode !== 'function') { if (stage) { stage.innerHTML = '
' + '二维码组件未加载。' + '
'; } - openModal(modal); + openPosterModal(); return; } - if (stage) { stage.innerHTML = '' + '正在生成海报…' + '
'; } - if (download) download.hidden = true; - openModal(modal); + if (stage) { stage.innerHTML = ''; stage.classList.remove('loaded'); } + if (loading) loading.style.display = ''; + if (download) download.classList.add('hide'); + openPosterModal(); button.disabled = true; buildPosterCanvas(url, poster, siteName).then(function (built) { canvas = built; - if (stage) { stage.innerHTML = ''; stage.appendChild(built); } - if (download) download.hidden = false; + if (!stage) return; + // 参考主题:img.loaded-img 直接进 .poster-imgbox,遮罩淡出, + // 内容块高度从 220px 过渡到海报实际高度后清掉内联样式。 + var img = document.createElement('img'); + img.src = canvas.toDataURL('image/png'); + img.alt = '推广海报'; + img.className = 'loaded-img'; + // 参考主题按 0.7 比例预设尺寸;.poster-imgbox > img 的 max-width:360px + // 会在窄屏把它压回弹窗宽度,height:100% 让 offsetHeight 反映真实渲染高度。 + img.width = 768 * 0.7; + img.height = 1168 * 0.7; + stage.appendChild(img); + stage.classList.add('loaded'); + if (download) { + download.href = img.src; + download.classList.remove('hide'); + } + if (loading) loading.style.display = 'none'; + if (content) { + content.style.height = stage.offsetHeight + 'px'; + content.style.transition = '.2s'; + window.setTimeout(function () { + content.style.height = ''; + content.style.overflow = ''; + content.style.transition = ''; + }, 200); + } }).catch(function () { if (stage) { stage.innerHTML = '' + '海报生成失败,请重试。' + '
'; } }).finally(function () { diff --git a/inc/helpers/user-center-renderers/affiliate-poster-modal.php b/inc/helpers/user-center-renderers/affiliate-poster-modal.php index d6407544..e1fe8933 100644 --- a/inc/helpers/user-center-renderers/affiliate-poster-modal.php +++ b/inc/helpers/user-center-renderers/affiliate-poster-modal.php @@ -2,8 +2,12 @@ /** * Affiliate poster preview modal. * - * The 推广海报 button lives in the revenue detail link row; the QR code is no - * longer rendered on its own — it exists only inside the generated poster. + * 1:1 replica of the reference theme's poster-share modal (zibll js/poster-share.js + * + css/main.css `.poster-share` block): a borderless 360px Bootstrap-style dialog + * centred by `.modal.flex.jc`, a `.loading-mask` overlay while the canvas renders, + * and circular download/close buttons on a `.hover-show-con` layer that only fades + * in on hover. The 推广海报 button lives in the revenue detail link row; the QR code + * is no longer rendered on its own — it exists only inside the generated poster. * * @package AKSRT */ @@ -15,14 +19,18 @@ if (!empty($GLOBALS['aksrt_affiliate_poster_modal_rendered'])) { } $GLOBALS['aksrt_affiliate_poster_modal_rendered'] = true; ?> -