diff --git a/src/components/SpotMap.tsx b/src/components/SpotMap.tsx
index bda9fc5..04195db 100644
--- a/src/components/SpotMap.tsx
+++ b/src/components/SpotMap.tsx
@@ -193,11 +193,22 @@ const createShopIcon = () => L.divIcon({
// "You are here" user-location marker — SkateSpots logo in a circular badge
// with a pulsing accuracy halo (Google-Maps-style, brand-flavored).
-const createUserLocationIcon = () => {
+const createUserLocationIcon = (picture?: string | null) => {
// BASE_URL resolves correctly for both web ('/') and the Capacitor APK ('./').
// Reuse the small (~24 KB) brand logo for the marker instead of the old
// 2.9 MB user-location.png — same artwork, ~99% smaller payload.
const logoUrl = `${import.meta.env.BASE_URL}images/logo.png`;
+
+ // Show the user's own Nostr profile picture (their npub's "logo") when set.
+ // Layered CSS backgrounds mean a broken/expired avatar URL silently reveals
+ // the brand logo underneath — no inline JS (CSP-safe).
+ const safeAvatar = picture ? sanitizeUrl(picture) : null;
+ const avatarCss = safeAvatar
+ ? encodeURI(safeAvatar).replace(/[()'"]/g, (c) => `%${c.charCodeAt(0).toString(16).toUpperCase()}`)
+ : '';
+ const backgroundImage = avatarCss ? `url('${avatarCss}'), url('${logoUrl}')` : `url('${logoUrl}')`;
+ const backgroundSize = avatarCss ? 'cover, cover' : 'cover';
+
return L.divIcon({
className: 'user-location-marker',
html: `
@@ -212,15 +223,15 @@ const createUserLocationIcon = () => {
background: rgba(255,0,64,0.25);
animation: ssPulse 2s ease-out infinite;
">
-
+
(null);
@@ -1041,12 +1055,14 @@ export function SpotMap({
}
if (userMarkerRef.current) {
- // Move the existing marker to the new position.
+ // Move the existing marker to the new position and refresh its icon
+ // (the profile picture can arrive after the marker was first created).
userMarkerRef.current.setLatLng([userLocation.lat, userLocation.lng]);
+ userMarkerRef.current.setIcon(createUserLocationIcon(userPicture));
} else {
// Create it, on top of everything else.
userMarkerRef.current = L.marker([userLocation.lat, userLocation.lng], {
- icon: createUserLocationIcon(),
+ icon: createUserLocationIcon(userPicture),
zIndexOffset: 1000,
interactive: true,
keyboard: false,
@@ -1054,7 +1070,7 @@ export function SpotMap({
.addTo(map)
.bindPopup(`${escapeHtml(t('mapUi.youAreHere'))}`);
}
- }, [userLocation, t]);
+ }, [userLocation, userPicture, t]);
// Update markers
useEffect(() => {
diff --git a/src/pages/MapPage.tsx b/src/pages/MapPage.tsx
index f1dca5d..91f678b 100644
--- a/src/pages/MapPage.tsx
+++ b/src/pages/MapPage.tsx
@@ -541,6 +541,9 @@ export default function MapPage() {
const navigate = useNavigate();
const [searchParams] = useSearchParams();
const { user } = useCurrentUser();
+ // The user's own profile picture, shown on the "you are here" pin.
+ const meAuthor = useAuthor(user?.pubkey || '');
+ const userPicture = meAuthor.data?.metadata?.picture ?? null;
const { data: followingList } = useFollowing(user?.pubkey);
const followCount = followingList?.length ?? 0;
const { data: spots, isLoading: spotsLoading, refetch: refetchSpots } = useSkateSpots(2000);
@@ -1674,6 +1677,7 @@ export default function MapPage() {
showBtcMap={showBtcMap}
flyTo={flyTo}
userLocation={isMobile && userLocation ? { lat: userLocation.lat, lng: userLocation.lon } : null}
+ userPicture={userPicture}
/>
{/* Loading indicator — a slim, honest top bar. The map stays