diff --git a/package-lock.json b/package-lock.json index fb6b129..d3ef83a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "sociowire-frontend", - "version": "0.0.107", + "version": "0.0.109", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "sociowire-frontend", - "version": "0.0.107", + "version": "0.0.109", "dependencies": { "@fortawesome/fontawesome-free": "^7.1.0", "axios": "^1.13.2", diff --git a/package.json b/package.json index 415778c..af3f260 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "sociowire-frontend", "private": true, - "version": "0.0.107", + "version": "0.0.109", "type": "module", "scripts": { "dev": "vite --host 0.0.0.0", diff --git a/src/api/client.js b/src/api/client.js index 51b81b7..2005ef5 100644 --- a/src/api/client.js +++ b/src/api/client.js @@ -1288,7 +1288,7 @@ export async function fetchPlanets(params = {}) { if (typeof params.offset === "number") qs.set("offset", String(params.offset)); if (params.search) qs.set("search", params.search); - const url = `${apiBase()}/planets?${qs.toString()}`; + const url = `${apiBase()}/planets/nearby?${qs.toString()}`; try { const res = await fetch(url, { credentials: "include" }); @@ -1329,7 +1329,7 @@ export async function fetchPlanet(planetId) { */ export async function createPlanet(payload) { try { - const res = await fetch(`${apiBase()}/planets`, { + const res = await fetch(`${apiBase()}/planets/create`, { method: "POST", credentials: "include", headers: { "Content-Type": "application/json", ...authHeaders() }, diff --git a/src/components/World/IslandsWorld.css b/src/components/World/IslandsWorld.css index 2d0fad0..10b476c 100644 --- a/src/components/World/IslandsWorld.css +++ b/src/components/World/IslandsWorld.css @@ -16,24 +16,22 @@ height: 100%; } -/* Search bar */ +/* Search bar - matches map overlay position */ .islands-world-search { - position: fixed; - top: 56px; + position: absolute; + top: 0.7rem; left: 50%; transform: translateX(-50%); z-index: 100; display: flex; align-items: center; - gap: 8px; - background: rgba(15, 23, 42, 0.95); - backdrop-filter: blur(20px); - border: 1px solid rgba(56, 189, 248, 0.3); - border-radius: 50px; - padding: 8px 12px; - width: auto; - max-width: 500px; - box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4); + gap: 6px; + background: rgba(6, 10, 22, 0.86); + backdrop-filter: blur(10px); + border: 1px solid rgba(56, 189, 248, 0.45); + border-radius: 14px; + padding: 6px 10px; + max-width: min(580px, calc(100vw - 24px)); } .islands-world-search .search-icon { @@ -166,6 +164,54 @@ margin-top: 2px; } +/* Island action buttons */ +.island-marker-actions { + position: absolute; + top: 5px; + right: -5px; + display: flex; + flex-direction: column; + gap: 4px; + opacity: 0; + transform: translateX(10px); + transition: all 0.3s ease; +} + +.island-marker:hover .island-marker-actions { + opacity: 1; + transform: translateX(0); +} + +.island-action-btn { + width: 28px; + height: 28px; + border: none; + border-radius: 50%; + background: rgba(15, 23, 42, 0.9); + border: 1px solid rgba(56, 189, 248, 0.4); + color: rgba(255, 255, 255, 0.9); + font-size: 11px; + cursor: pointer; + display: flex; + align-items: center; + justify-content: center; + transition: all 0.2s ease; + backdrop-filter: blur(8px); +} + +.island-action-btn:hover { + background: rgba(56, 189, 248, 0.3); + transform: scale(1.1); +} + +.island-profile-btn:hover { + color: #38bdf8; +} + +.island-edit-btn:hover { + color: #10b981; +} + /* Tooltip */ .islands-world-tooltip { position: fixed; diff --git a/src/components/World/IslandsWorld.jsx b/src/components/World/IslandsWorld.jsx index eac1657..58753fe 100644 --- a/src/components/World/IslandsWorld.jsx +++ b/src/components/World/IslandsWorld.jsx @@ -138,12 +138,24 @@ export default function IslandsWorld({ theme, onIslandClick, onOpenMap, onOpenPl const lng = centerLng + baseX + jitterX; const lat = centerLat + baseY + jitterY; - const el = createIslandMarker(island, idx, t); + const el = createIslandMarker(island, idx, t, username); el.addEventListener('mouseenter', () => setHoveredIsland(island)); el.addEventListener('mouseleave', () => setHoveredIsland(null)); el.addEventListener('click', (e) => { e.stopPropagation(); + const action = e.target.closest('[data-action]')?.dataset?.action; + if (action === 'profile') { + // Navigate to user profile + window.location.href = `/profile/${island.username}`; + return; + } + if (action === 'edit') { + // Navigate to island edit + window.location.href = `/island/${island.username}/edit`; + return; + } + // Default: open island viewer onIslandClick?.(island); }); @@ -251,7 +263,7 @@ export default function IslandsWorld({ theme, onIslandClick, onOpenMap, onOpenPl /** * Create a stylized island marker element */ -function createIslandMarker(island, idx, t) { +function createIslandMarker(island, idx, t, currentUsername) { const el = document.createElement('div'); el.className = 'island-marker'; @@ -268,6 +280,8 @@ function createIslandMarker(island, idx, t) { // Generate unique island shape const islandSVG = generateIslandSVG(seed, color); const postCount = island.content_count || 0; + const isOwner = currentUsername && island.username && + currentUsername.toLowerCase() === island.username.toLowerCase(); el.innerHTML = `