/*! * 数字我 / Digital Me — embeddable chat widget. * Usage: * * Injects a floating launcher button that opens「和我分身聊天」in a popup. */ (function () { var s = document.currentScript || (function () { var all = document.getElementsByTagName('script'); return all[all.length - 1]; })(); if (!s) return; var slug = s.getAttribute('data-slug'); if (!slug) { console.warn('[digital-me] widget: missing data-slug'); return; } // Where the /me/:slug page is served (the web app). Defaults to the // script's own origin (works when web+api share an origin behind a proxy). var site = s.getAttribute('data-site') || new URL(s.src).origin; var name = s.getAttribute('data-name') || '我的数字分身'; var accent = s.getAttribute('data-accent') || '#6d5efc'; var chatUrl = site.replace(/\/$/, '') + '/me/' + encodeURIComponent(slug); if (document.getElementById('dm-widget-root')) return; // idempotent var root = document.createElement('div'); root.id = 'dm-widget-root'; root.style.cssText = 'position:fixed;right:20px;bottom:20px;z-index:2147483000;font-family:system-ui,-apple-system,sans-serif'; // Popup (iframe) — hidden until opened. var panel = document.createElement('div'); panel.style.cssText = 'width:380px;max-width:calc(100vw - 32px);height:560px;max-height:calc(100vh - 120px);' + 'background:#0f1117;border-radius:16px;overflow:hidden;box-shadow:0 18px 60px rgba(0,0,0,.45);' + 'margin-bottom:12px;display:none;transform-origin:bottom right;transition:opacity .15s,transform .15s;' + 'opacity:0;transform:scale(.96)'; var iframe = document.createElement('iframe'); iframe.src = chatUrl; iframe.title = name; iframe.setAttribute('allow', 'autoplay; microphone'); iframe.style.cssText = 'width:100%;height:100%;border:0'; panel.appendChild(iframe); // Launcher button. var btn = document.createElement('button'); btn.setAttribute('aria-label', '和' + name + '聊天'); btn.style.cssText = 'width:58px;height:58px;border-radius:50%;border:0;cursor:pointer;float:right;' + 'background:' + accent + ';box-shadow:0 8px 24px rgba(0,0,0,.35);display:flex;align-items:center;' + 'justify-content:center;transition:transform .12s'; btn.innerHTML = '' + ''; btn.onmouseenter = function () { btn.style.transform = 'scale(1.06)'; }; btn.onmouseleave = function () { btn.style.transform = 'scale(1)'; }; var open = false; btn.onclick = function () { open = !open; if (open) { panel.style.display = 'block'; requestAnimationFrame(function () { panel.style.opacity = '1'; panel.style.transform = 'scale(1)'; }); } else { panel.style.opacity = '0'; panel.style.transform = 'scale(.96)'; setTimeout(function () { if (!open) panel.style.display = 'none'; }, 150); } }; root.appendChild(panel); root.appendChild(btn); (document.body || document.documentElement).appendChild(root); })();