Make shared asset links open directly on map location.
CI / test (push) Successful in 3s

Copy Share Link now generates a demo URL with asset coordinates so recipients can open the map and immediately see the shared object placement.

Made-with: Cursor
This commit is contained in:
2026-03-02 22:16:01 +00:00
parent dda20f82e6
commit 50fa9a5a22
2 changed files with 73 additions and 4 deletions
+36 -2
View File
@@ -73,6 +73,37 @@ function setClientBase(baseUrl) {
setStatus(`API base updated: ${normalized}`); setStatus(`API base updated: ${normalized}`);
} }
function buildMapShareLink(feature, asset) {
const coords = feature?.geometry?.coordinates;
if (!Array.isArray(coords) || coords.length < 2) {
return client.resolveRelativeLink(asset.link);
}
const url = new URL(window.location.origin + window.location.pathname);
url.searchParams.set("shared", "1");
url.searchParams.set("lng", String(coords[0]));
url.searchParams.set("lat", String(coords[1]));
url.searchParams.set("kind", asset.kind || "3d");
url.searchParams.set("public", asset.isPublic ? "1" : "0");
url.searchParams.set("assetId", asset.id);
url.searchParams.set("assetLink", client.resolveRelativeLink(asset.link));
return url.toString();
}
function renderSharedAssetFromQuery() {
const params = new URLSearchParams(window.location.search);
if (params.get("shared") !== "1") return;
const lng = Number(params.get("lng"));
const lat = Number(params.get("lat"));
if (!Number.isFinite(lng) || !Number.isFinite(lat)) return;
const kind = params.get("kind") === "image" ? "image" : "3d";
const isPublic = params.get("public") !== "0";
const assetId = params.get("assetId") || "shared-asset";
const marker = L.marker([lat, lng]).addTo(map);
marker.bindPopup(`Shared ${kind} asset (${isPublic ? "public" : "private"}): ${assetId}`).openPopup();
map.setView([lat, lng], Math.max(map.getZoom(), 14));
setStatus("Shared object loaded on map.");
}
async function ensureKeys() { async function ensureKeys() {
keys = await client.ensureKeysInStorage(); keys = await client.ensureKeysInStorage();
publicKeyPreviewEl.textContent = `Public key: ${keys.publicKey.slice(0, 24)}...`; publicKeyPreviewEl.textContent = `Public key: ${keys.publicKey.slice(0, 24)}...`;
@@ -135,8 +166,9 @@ function renderAssets(features) {
const copyBtn = document.createElement("button"); const copyBtn = document.createElement("button");
copyBtn.textContent = "Copy Share Link"; copyBtn.textContent = "Copy Share Link";
copyBtn.onclick = async () => { copyBtn.onclick = async () => {
await navigator.clipboard.writeText(absoluteLink); const shareLink = buildMapShareLink(feature, asset);
setStatus("Share link copied to clipboard."); await navigator.clipboard.writeText(shareLink);
setStatus("Map share link copied to clipboard.");
}; };
actions.appendChild(copyBtn); actions.appendChild(copyBtn);
@@ -268,3 +300,5 @@ if (savedBase) {
apiBaseEl.value = savedBase; apiBaseEl.value = savedBase;
setClientBase(savedBase); setClientBase(savedBase);
} }
renderSharedAssetFromQuery();
+37 -2
View File
@@ -67,6 +67,39 @@ function setClientBase(baseUrl) {
setStatus(`API base updated: ${normalized}`); setStatus(`API base updated: ${normalized}`);
} }
function buildMapShareLink(feature, asset) {
const coords = feature?.geometry?.coordinates;
if (!Array.isArray(coords) || coords.length < 2) {
return client.resolveRelativeLink(asset.link);
}
const url = new URL(window.location.origin + window.location.pathname);
url.searchParams.set("shared", "1");
url.searchParams.set("lng", String(coords[0]));
url.searchParams.set("lat", String(coords[1]));
url.searchParams.set("kind", asset.kind || "3d");
url.searchParams.set("public", asset.isPublic ? "1" : "0");
url.searchParams.set("assetId", asset.id);
url.searchParams.set("assetLink", client.resolveRelativeLink(asset.link));
return url.toString();
}
function renderSharedAssetFromQuery() {
const params = new URLSearchParams(window.location.search);
if (params.get("shared") !== "1") return;
const lng = Number(params.get("lng"));
const lat = Number(params.get("lat"));
if (!Number.isFinite(lng) || !Number.isFinite(lat)) return;
const kind = params.get("kind") === "image" ? "image" : "3d";
const isPublic = params.get("public") !== "0";
const assetId = params.get("assetId") || "shared-asset";
addObjectMesh(`shared-${assetId}`, lng, lat, isPublic, kind);
if (pendingMarker) pendingMarker.remove();
pendingMarker = new maplibregl.Marker({ color: "#f59e0b" }).setLngLat({ lng, lat }).addTo(map);
map.easeTo({ center: [lng, lat], zoom: Math.max(map.getZoom(), 14), pitch: 55, bearing: -15 });
setStatus("Shared object loaded on map.");
}
function createThreeLayer() { function createThreeLayer() {
return { return {
id: "threejs-custom-layer", id: "threejs-custom-layer",
@@ -198,8 +231,9 @@ function renderAssets(features) {
const copyBtn = document.createElement("button"); const copyBtn = document.createElement("button");
copyBtn.textContent = "Copy Share Link"; copyBtn.textContent = "Copy Share Link";
copyBtn.onclick = async () => { copyBtn.onclick = async () => {
await navigator.clipboard.writeText(absoluteLink); const shareLink = buildMapShareLink(feature, asset);
setStatus("Share link copied to clipboard."); await navigator.clipboard.writeText(shareLink);
setStatus("Map share link copied to clipboard.");
}; };
actions.appendChild(copyBtn); actions.appendChild(copyBtn);
@@ -336,6 +370,7 @@ map.addControl(new maplibregl.NavigationControl(), "top-right");
map.on("load", () => { map.on("load", () => {
threeLayer = createThreeLayer(); threeLayer = createThreeLayer();
map.addLayer(threeLayer); map.addLayer(threeLayer);
renderSharedAssetFromQuery();
}); });
map.on("click", (event) => { map.on("click", (event) => {