-
- {memo.displayTime &&
- timestampDate(memo.displayTime).toLocaleDateString(undefined, {
- year: "numeric",
- month: "short",
- day: "numeric",
- })}
-
+
+
+
+
+
+ Memo
+
+
+ {memo.displayTime &&
+ timestampDate(memo.displayTime).toLocaleDateString(undefined, {
+ year: "numeric",
+ month: "short",
+ day: "numeric",
+ })}
+
+
- View
-
+ Open
+
-
{memo.snippet || "No content"}
+
+
{memo.snippet || "No content"}
+
+ {memo.location!.latitude.toFixed(2)}°, {memo.location!.longitude.toFixed(2)}°
+
+
diff --git a/web/src/components/map/LocationPicker.tsx b/web/src/components/map/LocationPicker.tsx
index 3315780dd..cdcf90a54 100644
--- a/web/src/components/map/LocationPicker.tsx
+++ b/web/src/components/map/LocationPicker.tsx
@@ -1,7 +1,7 @@
import L, { LatLng } from "leaflet";
import { ExternalLinkIcon, MinusIcon, PlusIcon } from "lucide-react";
import { type ReactNode, useEffect, useRef, useState } from "react";
-import { createRoot } from "react-dom/client";
+import { createPortal } from "react-dom";
import { MapContainer, Marker, useMap, useMapEvents } from "react-leaflet";
import { cn } from "@/lib/utils";
import { defaultMarkerIcon, ThemedTileLayer } from "./map-utils";
@@ -135,7 +135,7 @@ interface MapControlsProps {
const MapControls = ({ position }: MapControlsProps) => {
const map = useMap();
const controlRef = useRef
(null);
- const rootRef = useRef | null>(null);
+ const [container, setContainer] = useState(null);
const handleOpenInGoogleMaps = () => {
if (!position) return;
@@ -156,39 +156,25 @@ const MapControls = ({ position }: MapControlsProps) => {
const control = new MapControlsContainer({ position: "topright" });
controlRef.current = control;
control.addTo(map);
-
- // Get container and render React component into it
- const container = control.getContainer();
- if (container) {
- rootRef.current = createRoot(container);
- rootRef.current.render(
- ,
- );
- }
+ setContainer(control.getContainer() ?? null);
return () => {
- // Cleanup: unmount React component and remove control
- if (rootRef.current) {
- rootRef.current.unmount();
- rootRef.current = null;
- }
if (controlRef.current) {
controlRef.current.remove();
controlRef.current = null;
}
+ setContainer(null);
};
}, [map]);
- // Update rendered content when position changes
- useEffect(() => {
- if (rootRef.current) {
- rootRef.current.render(
- ,
- );
- }
- }, [position]);
+ if (!container) {
+ return null;
+ }
- return null;
+ return createPortal(
+ ,
+ container,
+ );
};
const MapCleanup = () => {
@@ -222,21 +208,30 @@ const DEFAULT_CENTER_LAT_LNG = new LatLng(48.8584, 2.2945);
const LeafletMap = (props: MapProps) => {
const position = props.latlng || DEFAULT_CENTER_LAT_LNG;
+ const statusLabel = props.readonly ? "Pinned location" : props.latlng ? "Selected location" : "Choose a location";
return (
-
-
- {}} />
-
-
-
+
);
};
diff --git a/web/src/components/map/map-utils.tsx b/web/src/components/map/map-utils.tsx
index 984cf2e36..fe7c490d7 100644
--- a/web/src/components/map/map-utils.tsx
+++ b/web/src/components/map/map-utils.tsx
@@ -7,7 +7,7 @@ import { useAuth } from "@/contexts/AuthContext";
import { resolveTheme } from "@/utils/theme";
const TILE_URLS = {
- light: "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png",
+ light: "https://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}{r}.png",
dark: "https://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}{r}.png",
} as const;
@@ -24,12 +24,17 @@ interface MarkerIconOptions {
}
export const createMarkerIcon = (options?: MarkerIconOptions): DivIcon => {
- const { fill = "orange", size = 28, className = "" } = options || {};
+ const { fill = "var(--primary)", size = 28, className = "" } = options || {};
return new DivIcon({
- className: "relative border-none",
+ className: "relative border-none bg-transparent",
html: ReactDOMServer.renderToString(
- ,
+
+
+
,
),
+ iconSize: [size + 8, size + 8],
+ iconAnchor: [(size + 8) / 2, size + 4],
+ popupAnchor: [0, -(size * 0.7)],
});
};