95 lines
3.5 KiB
JavaScript
95 lines
3.5 KiB
JavaScript
/*!
|
|
* 数字我 / Digital Me — embeddable chat widget.
|
|
* Usage:
|
|
* <script src="https://YOUR-API/widget.js"
|
|
* data-slug="your-slug"
|
|
* data-site="https://your-web-origin"
|
|
* data-name="你的名字"></script>
|
|
* 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 =
|
|
'<svg width="26" height="26" viewBox="0 0 24 24" fill="none" stroke="#fff" ' +
|
|
'stroke-width="2" stroke-linecap="round" stroke-linejoin="round">' +
|
|
'<path d="M21 11.5a8.38 8.38 0 0 1-.9 3.8 8.5 8.5 0 0 1-7.6 4.7 8.38 8.38 0 0 1-3.8-.9L3 21l1.9-5.7a8.38 8.38 0 0 1-.9-3.8 8.5 8.5 0 0 1 4.7-7.6 8.38 8.38 0 0 1 3.8-.9h.5a8.48 8.48 0 0 1 8 8v.5z"/></svg>';
|
|
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);
|
|
})();
|