diff --git a/src/pages/MapPage.tsx b/src/pages/MapPage.tsx
index 6351cf7..2407d09 100644
--- a/src/pages/MapPage.tsx
+++ b/src/pages/MapPage.tsx
@@ -68,6 +68,8 @@ import {
MapPin,
LocateFixed,
LocateOff,
+ Store,
+ Info,
} from 'lucide-react';
import { CameraCapture } from '@/components/CameraCapture';
import { useUploadFile } from '@/hooks/useUploadFile';
@@ -595,6 +597,10 @@ export default function MapPage() {
const [flyTo, setFlyTo] = useState<{ lat: number; lng: number; zoom?: number } | null>(null);
const [nearMeLoading, setNearMeLoading] = useState(false);
const [nearMeError, setNearMeError] = useState<'denied' | 'unavailable' | 'timeout' | null>(null);
+ const [showLocationHelp, setShowLocationHelp] = useState(false);
+
+ // Speed-dial FAB open state
+ const [fabOpen, setFabOpen] = useState(false);
const handleNearMe = () => {
// Clear previous error
@@ -623,11 +629,7 @@ export default function MapPage() {
setNearMeLoading(false);
if (err.code === err.PERMISSION_DENIED) {
setNearMeError('denied');
- toast({
- title: 'Location access denied',
- description: 'To find spots near you, allow location access in your browser settings, then try again.',
- variant: 'destructive',
- });
+ setShowLocationHelp(true);
} else if (err.code === err.TIMEOUT) {
setNearMeError('timeout');
toast({
@@ -734,6 +736,8 @@ export default function MapPage() {
);
const handleMapClick = (lat: number, lng: number) => {
+ // Close speed-dial FAB if open
+ setFabOpen(false);
if (!user) return;
// Navigate to create spot with coordinates pre-filled
navigate(`/create-spot?lat=${lat.toFixed(6)}&lng=${lng.toFixed(6)}`);
@@ -1420,31 +1424,63 @@ export default function MapPage() {
)}
- {/* Add Spot FAB — primary CTA, bottom-left.
- Hidden when Sasquatch panel is open (user is in chat mode).
- Hidden when mobile filters or spot sheet is open. */}
+ {/* Speed-dial FAB — bottom-right, above filter pills, clear of bottom nav.
+ Tap the + button to expand into Add Spot + Add Shop options.
+ Hidden when overlays open. Desktop gets a different layout so md:hidden. */}
- {user ? (
-
-
{/* Near Me button + attribution — floating top-right, hidden when any overlay is open */}
@@ -1453,7 +1489,7 @@ export default function MapPage() {
mobileFiltersOpen ? "opacity-0 pointer-events-none" : "opacity-100"
)}>
setShowLocationHelp(true) : handleNearMe}
disabled={nearMeLoading}
size="sm"
className={cn(
@@ -1463,7 +1499,7 @@ export default function MapPage() {
: "bg-black/80 hover:bg-black/95 border-white/20"
)}
title={nearMeError === 'denied' ? 'Location access denied — tap for help' : 'Find spots near me'}
- aria-label="Find spots near my location"
+ aria-label={nearMeError === 'denied' ? 'Location access denied — tap for help' : 'Find spots near my location'}
>
{nearMeLoading ? (
@@ -1485,9 +1521,54 @@ export default function MapPage() {
+ {/* Location permission help dialog */}
+ {showLocationHelp && (
+
+
setShowLocationHelp(false)}
+ />
+
+
+
+
+
+
+
Location Blocked
+
+ Your browser has blocked location access for this site. Here's how to re-enable it:
+
+
+
+
+ {[
+ { platform: '📱 Android Chrome', steps: 'Tap the lock icon in the address bar → Site settings → Location → Allow' },
+ { platform: '🍎 iOS Safari', steps: 'Settings app → Safari → Location → Allow (or tap the "AA" button in Safari\'s address bar)' },
+ { platform: '💻 Desktop Chrome', steps: 'Click the lock icon → Site settings → Location → Allow' },
+ { platform: '🦊 Firefox', steps: 'Click the lock icon → Connection secure → More info → Permissions → Access your location → Allow' },
+ ].map(({ platform, steps }) => (
+
+ ))}
+
+
{
+ setShowLocationHelp(false);
+ setNearMeError(null);
+ }}
+ className="w-full py-3 rounded-xl bg-white/8 hover:bg-white/12 border border-white/10 text-sm font-bold text-white transition-all active:scale-[0.98]"
+ >
+ Got it
+
+
+
+ )}
+
{/* Right-side control column — filter pills + Quick Snap (mobile only, hidden when overlays open) */}
{/* Layer filter pills — compact icon-only */}