From 50fa9a5a224411e7c0fb24d12388d9c739c394da Mon Sep 17 00:00:00 2001 From: Andriy Oblivantsev Date: Mon, 2 Mar 2026 22:16:01 +0000 Subject: [PATCH] Make shared asset links open directly on map location. 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 --- web/leaflet-demo.js | 38 ++++++++++++++++++++++++++++++++++++-- web/maplibre-demo.js | 39 +++++++++++++++++++++++++++++++++++++-- 2 files changed, 73 insertions(+), 4 deletions(-) diff --git a/web/leaflet-demo.js b/web/leaflet-demo.js index 7d6d22b..bd76a45 100644 --- a/web/leaflet-demo.js +++ b/web/leaflet-demo.js @@ -73,6 +73,37 @@ function setClientBase(baseUrl) { 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() { keys = await client.ensureKeysInStorage(); publicKeyPreviewEl.textContent = `Public key: ${keys.publicKey.slice(0, 24)}...`; @@ -135,8 +166,9 @@ function renderAssets(features) { const copyBtn = document.createElement("button"); copyBtn.textContent = "Copy Share Link"; copyBtn.onclick = async () => { - await navigator.clipboard.writeText(absoluteLink); - setStatus("Share link copied to clipboard."); + const shareLink = buildMapShareLink(feature, asset); + await navigator.clipboard.writeText(shareLink); + setStatus("Map share link copied to clipboard."); }; actions.appendChild(copyBtn); @@ -268,3 +300,5 @@ if (savedBase) { apiBaseEl.value = savedBase; setClientBase(savedBase); } + +renderSharedAssetFromQuery(); diff --git a/web/maplibre-demo.js b/web/maplibre-demo.js index e4a0df9..9156e20 100644 --- a/web/maplibre-demo.js +++ b/web/maplibre-demo.js @@ -67,6 +67,39 @@ function setClientBase(baseUrl) { 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() { return { id: "threejs-custom-layer", @@ -198,8 +231,9 @@ function renderAssets(features) { const copyBtn = document.createElement("button"); copyBtn.textContent = "Copy Share Link"; copyBtn.onclick = async () => { - await navigator.clipboard.writeText(absoluteLink); - setStatus("Share link copied to clipboard."); + const shareLink = buildMapShareLink(feature, asset); + await navigator.clipboard.writeText(shareLink); + setStatus("Map share link copied to clipboard."); }; actions.appendChild(copyBtn); @@ -336,6 +370,7 @@ map.addControl(new maplibregl.NavigationControl(), "top-right"); map.on("load", () => { threeLayer = createThreeLayer(); map.addLayer(threeLayer); + renderSharedAssetFromQuery(); }); map.on("click", (event) => {