feat: Add profile/edit icons to island markers, fix planets API
- Add profile button to view user profile from island marker - Add edit button (owner only) to modify island - Style island action buttons with hover animations - Fix planets API endpoint to use /planets/nearby - Fix create planet endpoint to use /planets/create - Match search bar positioning with map overlay (0.7rem top) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
ef075ccb9b
commit
36626fa091
|
|
@ -1,12 +1,12 @@
|
||||||
{
|
{
|
||||||
"name": "sociowire-frontend",
|
"name": "sociowire-frontend",
|
||||||
"version": "0.0.107",
|
"version": "0.0.109",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "sociowire-frontend",
|
"name": "sociowire-frontend",
|
||||||
"version": "0.0.107",
|
"version": "0.0.109",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@fortawesome/fontawesome-free": "^7.1.0",
|
"@fortawesome/fontawesome-free": "^7.1.0",
|
||||||
"axios": "^1.13.2",
|
"axios": "^1.13.2",
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"name": "sociowire-frontend",
|
"name": "sociowire-frontend",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "0.0.107",
|
"version": "0.0.109",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite --host 0.0.0.0",
|
"dev": "vite --host 0.0.0.0",
|
||||||
|
|
|
||||||
|
|
@ -1288,7 +1288,7 @@ export async function fetchPlanets(params = {}) {
|
||||||
if (typeof params.offset === "number") qs.set("offset", String(params.offset));
|
if (typeof params.offset === "number") qs.set("offset", String(params.offset));
|
||||||
if (params.search) qs.set("search", params.search);
|
if (params.search) qs.set("search", params.search);
|
||||||
|
|
||||||
const url = `${apiBase()}/planets?${qs.toString()}`;
|
const url = `${apiBase()}/planets/nearby?${qs.toString()}`;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const res = await fetch(url, { credentials: "include" });
|
const res = await fetch(url, { credentials: "include" });
|
||||||
|
|
@ -1329,7 +1329,7 @@ export async function fetchPlanet(planetId) {
|
||||||
*/
|
*/
|
||||||
export async function createPlanet(payload) {
|
export async function createPlanet(payload) {
|
||||||
try {
|
try {
|
||||||
const res = await fetch(`${apiBase()}/planets`, {
|
const res = await fetch(`${apiBase()}/planets/create`, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
credentials: "include",
|
credentials: "include",
|
||||||
headers: { "Content-Type": "application/json", ...authHeaders() },
|
headers: { "Content-Type": "application/json", ...authHeaders() },
|
||||||
|
|
|
||||||
|
|
@ -16,24 +16,22 @@
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Search bar */
|
/* Search bar - matches map overlay position */
|
||||||
.islands-world-search {
|
.islands-world-search {
|
||||||
position: fixed;
|
position: absolute;
|
||||||
top: 56px;
|
top: 0.7rem;
|
||||||
left: 50%;
|
left: 50%;
|
||||||
transform: translateX(-50%);
|
transform: translateX(-50%);
|
||||||
z-index: 100;
|
z-index: 100;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 8px;
|
gap: 6px;
|
||||||
background: rgba(15, 23, 42, 0.95);
|
background: rgba(6, 10, 22, 0.86);
|
||||||
backdrop-filter: blur(20px);
|
backdrop-filter: blur(10px);
|
||||||
border: 1px solid rgba(56, 189, 248, 0.3);
|
border: 1px solid rgba(56, 189, 248, 0.45);
|
||||||
border-radius: 50px;
|
border-radius: 14px;
|
||||||
padding: 8px 12px;
|
padding: 6px 10px;
|
||||||
width: auto;
|
max-width: min(580px, calc(100vw - 24px));
|
||||||
max-width: 500px;
|
|
||||||
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.islands-world-search .search-icon {
|
.islands-world-search .search-icon {
|
||||||
|
|
@ -166,6 +164,54 @@
|
||||||
margin-top: 2px;
|
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 */
|
/* Tooltip */
|
||||||
.islands-world-tooltip {
|
.islands-world-tooltip {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
|
|
|
||||||
|
|
@ -138,12 +138,24 @@ export default function IslandsWorld({ theme, onIslandClick, onOpenMap, onOpenPl
|
||||||
const lng = centerLng + baseX + jitterX;
|
const lng = centerLng + baseX + jitterX;
|
||||||
const lat = centerLat + baseY + jitterY;
|
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('mouseenter', () => setHoveredIsland(island));
|
||||||
el.addEventListener('mouseleave', () => setHoveredIsland(null));
|
el.addEventListener('mouseleave', () => setHoveredIsland(null));
|
||||||
el.addEventListener('click', (e) => {
|
el.addEventListener('click', (e) => {
|
||||||
e.stopPropagation();
|
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);
|
onIslandClick?.(island);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -251,7 +263,7 @@ export default function IslandsWorld({ theme, onIslandClick, onOpenMap, onOpenPl
|
||||||
/**
|
/**
|
||||||
* Create a stylized island marker element
|
* Create a stylized island marker element
|
||||||
*/
|
*/
|
||||||
function createIslandMarker(island, idx, t) {
|
function createIslandMarker(island, idx, t, currentUsername) {
|
||||||
const el = document.createElement('div');
|
const el = document.createElement('div');
|
||||||
el.className = 'island-marker';
|
el.className = 'island-marker';
|
||||||
|
|
||||||
|
|
@ -268,6 +280,8 @@ function createIslandMarker(island, idx, t) {
|
||||||
// Generate unique island shape
|
// Generate unique island shape
|
||||||
const islandSVG = generateIslandSVG(seed, color);
|
const islandSVG = generateIslandSVG(seed, color);
|
||||||
const postCount = island.content_count || 0;
|
const postCount = island.content_count || 0;
|
||||||
|
const isOwner = currentUsername && island.username &&
|
||||||
|
currentUsername.toLowerCase() === island.username.toLowerCase();
|
||||||
|
|
||||||
el.innerHTML = `
|
el.innerHTML = `
|
||||||
<div class="island-marker-inner" style="animation-delay: ${(idx % 12) * 0.25}s;">
|
<div class="island-marker-inner" style="animation-delay: ${(idx % 12) * 0.25}s;">
|
||||||
|
|
@ -276,6 +290,16 @@ function createIslandMarker(island, idx, t) {
|
||||||
<span class="island-marker-name" style="color: ${color}">@${island.username}</span>
|
<span class="island-marker-name" style="color: ${color}">@${island.username}</span>
|
||||||
<span class="island-marker-meta">${postCount} posts</span>
|
<span class="island-marker-meta">${postCount} posts</span>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="island-marker-actions">
|
||||||
|
<button class="island-action-btn island-profile-btn" data-action="profile" title="View Profile">
|
||||||
|
<i class="fa-solid fa-user"></i>
|
||||||
|
</button>
|
||||||
|
${isOwner ? `
|
||||||
|
<button class="island-action-btn island-edit-btn" data-action="edit" title="Edit Island">
|
||||||
|
<i class="fa-solid fa-pen"></i>
|
||||||
|
</button>
|
||||||
|
` : ''}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,24 +16,22 @@
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Search bar */
|
/* Search bar - matches map overlay position */
|
||||||
.planets-world-search {
|
.planets-world-search {
|
||||||
position: fixed;
|
position: absolute;
|
||||||
top: 56px;
|
top: 0.7rem;
|
||||||
left: 50%;
|
left: 50%;
|
||||||
transform: translateX(-50%);
|
transform: translateX(-50%);
|
||||||
z-index: 100;
|
z-index: 100;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 8px;
|
gap: 6px;
|
||||||
background: rgba(15, 15, 26, 0.95);
|
background: rgba(15, 10, 30, 0.86);
|
||||||
backdrop-filter: blur(20px);
|
backdrop-filter: blur(10px);
|
||||||
border: 1px solid rgba(155, 89, 182, 0.3);
|
border: 1px solid rgba(155, 89, 182, 0.45);
|
||||||
border-radius: 50px;
|
border-radius: 14px;
|
||||||
padding: 8px 12px;
|
padding: 6px 10px;
|
||||||
width: auto;
|
max-width: min(580px, calc(100vw - 24px));
|
||||||
max-width: 500px;
|
|
||||||
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.6);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.planets-world-search .search-icon {
|
.planets-world-search .search-icon {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue