rspace-online/modules/rmaps/components/map-share-modal.ts

80 lines
3.8 KiB
TypeScript

/**
* <map-share-modal> — QR code share modal for rMaps rooms.
* Dispatches 'modal-close' on dismiss.
* Set `url` property before appending to DOM.
*/
class MapShareModal extends HTMLElement {
private _url = "";
private _room = "";
set url(v: string) { this._url = v; }
set room(v: string) { this._room = v; }
connectedCallback() { this.render(); }
private esc(s: string): string { const d = document.createElement("div"); d.textContent = s || ""; return d.innerHTML; }
private close() {
this.dispatchEvent(new CustomEvent("modal-close", { bubbles: true, composed: true }));
this.remove();
}
private async render() {
this.style.cssText = `position:fixed;inset:0;z-index:100;display:flex;align-items:center;justify-content:center;background:rgba(0,0,0,0.6);backdrop-filter:blur(4px);`;
this.innerHTML = `
<div style="background:var(--rs-bg-surface);border:1px solid var(--rs-border-strong);border-radius:14px;padding:24px;max-width:360px;width:90%;text-align:center;">
<div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:16px;">
<div style="font-size:16px;font-weight:600;color:var(--rs-text-primary);">Share Room</div>
<button id="s-close" style="background:none;border:none;color:var(--rs-text-muted);cursor:pointer;font-size:18px;">\u2715</button>
</div>
<div id="s-qr" style="margin:16px auto;display:flex;align-items:center;justify-content:center;">
<div style="font-size:12px;color:var(--rs-text-muted);">Generating QR code...</div>
</div>
<div style="background:var(--rs-bg-surface-sunken);border:1px solid var(--rs-border);border-radius:8px;padding:10px;margin:12px 0;font-family:monospace;font-size:11px;color:var(--rs-text-secondary);word-break:break-all;text-align:left;">
${this.esc(this._url)}
</div>
<div style="display:flex;gap:8px;">
<button id="s-copy" style="flex:1;padding:10px;border-radius:8px;border:1px solid var(--rs-border);background:var(--rs-bg-surface);color:var(--rs-text-secondary);cursor:pointer;font-size:13px;font-weight:500;">\u{1F4CB} Copy Link</button>
<button id="s-share" style="flex:1;padding:10px;border-radius:8px;border:none;background:#4f46e5;color:#fff;cursor:pointer;font-size:13px;font-weight:600;">\u{1F4E4} Share</button>
</div>
</div>
`;
// QR code
try {
const QRCode = await import("qrcode");
const dataUrl = await QRCode.toDataURL(this._url, { width: 200, margin: 2, color: { dark: "#000000", light: "#ffffff" } });
const qr = this.querySelector("#s-qr");
if (qr) qr.innerHTML = `<img src="${dataUrl}" alt="QR Code" style="width:200px;height:200px;border-radius:8px;">`;
} catch {
const qr = this.querySelector("#s-qr");
if (qr) qr.innerHTML = `<div style="font-size:12px;color:var(--rs-text-muted);">QR code unavailable</div>`;
}
// Events
this.querySelector("#s-close")?.addEventListener("click", () => this.close());
this.addEventListener("click", (e) => { if (e.target === this) this.close(); });
this.querySelector("#s-copy")?.addEventListener("click", () => {
navigator.clipboard.writeText(this._url).then(() => {
const btn = this.querySelector("#s-copy");
if (btn) { btn.textContent = "\u2713 Copied!"; setTimeout(() => { btn.textContent = "\u{1F4CB} Copy Link"; }, 2000); }
});
});
this.querySelector("#s-share")?.addEventListener("click", () => {
if (navigator.share) {
navigator.share({ title: `rMaps: ${this._room}`, url: this._url }).catch(() => {});
} else {
navigator.clipboard.writeText(this._url).then(() => {
const btn = this.querySelector("#s-share");
if (btn) { btn.textContent = "\u2713 Copied!"; setTimeout(() => { btn.textContent = "\u{1F4E4} Share"; }, 2000); }
});
}
});
}
}
customElements.define("map-share-modal", MapShareModal);
export { MapShareModal };