rspace-online/modules/rmaps/components/map-privacy-panel.ts

62 lines
2.8 KiB
TypeScript

/**
* <map-privacy-panel> — privacy settings dropdown for rMaps.
* Dispatches 'precision-change' and 'ghost-toggle' CustomEvents.
*/
import type { PrecisionLevel, PrivacySettings } from "./map-sync";
const PRECISION_LABELS: Record<PrecisionLevel, string> = {
exact: "Exact",
building: "~50m (Building)",
area: "~500m (Area)",
approximate: "~5km (Approximate)",
};
class MapPrivacyPanel extends HTMLElement {
private _settings: PrivacySettings = { precision: "exact", ghostMode: false };
static get observedAttributes() { return ["precision", "ghost"]; }
get settings(): PrivacySettings { return this._settings; }
set settings(v: PrivacySettings) { this._settings = v; this.render(); }
attributeChangedCallback() {
this._settings.precision = (this.getAttribute("precision") as PrecisionLevel) || "exact";
this._settings.ghostMode = this.getAttribute("ghost") === "true";
this.render();
}
connectedCallback() { this.render(); }
private render() {
this.innerHTML = `
<div style="font-size:12px;font-weight:600;color:var(--rs-text-secondary);margin-bottom:8px;">Privacy Settings</div>
<label style="font-size:12px;color:var(--rs-text-secondary);display:block;margin-bottom:6px;">Location Precision</label>
<select id="precision-select" style="width:100%;padding:6px 8px;border-radius:6px;border:1px solid var(--rs-border);background:var(--rs-input-bg);color:var(--rs-text-primary);font-size:12px;margin-bottom:10px;">
${(["exact", "building", "area", "approximate"] as PrecisionLevel[]).map(p =>
`<option value="${p}" ${this._settings.precision === p ? "selected" : ""}>${PRECISION_LABELS[p]}</option>`
).join("")}
</select>
<label style="display:flex;align-items:center;gap:8px;font-size:12px;color:var(--rs-text-secondary);cursor:pointer;">
<input type="checkbox" id="ghost-toggle" ${this._settings.ghostMode ? "checked" : ""} style="accent-color:#8b5cf6;">
<span>\u{1F47B} Ghost Mode</span>
</label>
<div style="font-size:10px;color:var(--rs-text-muted);margin-top:4px;line-height:1.4;">
Ghost mode hides your location from all participants and stops GPS tracking.
</div>
`;
this.querySelector("#precision-select")?.addEventListener("change", (e) => {
this._settings.precision = (e.target as HTMLSelectElement).value as PrecisionLevel;
this.dispatchEvent(new CustomEvent("precision-change", { detail: this._settings.precision, bubbles: true, composed: true }));
});
this.querySelector("#ghost-toggle")?.addEventListener("change", () => {
this._settings.ghostMode = !this._settings.ghostMode;
this.dispatchEvent(new CustomEvent("ghost-toggle", { detail: this._settings.ghostMode, bubbles: true, composed: true }));
});
}
}
customElements.define("map-privacy-panel", MapPrivacyPanel);
export { MapPrivacyPanel };