refactor(collections/map): extract context menus to standalone component

This commit is contained in:
Elian Doran
2026-02-16 19:45:36 +02:00
parent 71e9eae5e6
commit 48ff643c7a
3 changed files with 45 additions and 39 deletions

View File

@@ -1,14 +1,49 @@
import type { GeoMouseEvent } from "./map.js";
import { useCallback, useContext, useEffect } from "preact/hooks";
import appContext, { type CommandMappings } from "../../../components/app_context.js";
import contextMenu, { type MenuItem } from "../../../menus/context_menu.js";
import linkContextMenu from "../../../menus/link_context_menu.js";
import NoteColorPicker from "../../../menus/custom-items/NoteColorPicker.jsx";
import { t } from "../../../services/i18n.js";
import { createNewNote } from "./api.js";
import linkContextMenu from "../../../menus/link_context_menu.js";
import { copyTextWithToast } from "../../../services/clipboard_ext.js";
import { t } from "../../../services/i18n.js";
import link from "../../../services/link.js";
import { createNewNote } from "./api.js";
import { type GeoMouseEvent,ParentMap, toMapLibreEvent } from "./map.js";
import { MARKER_LAYER } from "./marker_data.js";
export default function openContextMenu(noteId: string, e: GeoMouseEvent, isEditable: boolean) {
export default function ContextMenus({ note, isReadOnly }: { note: FNote, isReadOnly }) {
const map = useContext(ParentMap);
const onContextMenu = useCallback((e: GeoMouseEvent) => {
if (!map) return;
const features = map.queryRenderedFeatures(e.point, {
layers: [ MARKER_LAYER ]
});
if (features.length > 0) {
// Marker context menu.
openContextMenu(features[0].properties.id, e, !isReadOnly);
} else {
// Empty area context menu.
openMapContextMenu(note.noteId, e, !isReadOnly);
}
}, [ map, note.noteId, isReadOnly ]);
useEffect(() => {
if (!onContextMenu || !map) return;
const handler = (e: maplibregl.MapMouseEvent) => {
e.preventDefault();
onContextMenu(toMapLibreEvent(e));
};
map.on("contextmenu", handler);
return () => { map.off("contextmenu", handler); };
}, [ map, onContextMenu ]);
return null;
}
export function openContextMenu(noteId: string, e: GeoMouseEvent, isEditable: boolean) {
let items: MenuItem<keyof CommandMappings>[] = [
...buildGeoLocationItem(e),
{ kind: "separator" },
@@ -58,7 +93,7 @@ export function openMapContextMenu(noteId: string, e: GeoMouseEvent, isEditable:
handler: () => createNewNote(noteId, e),
uiIcon: "bx bx-plus"
}
]
];
}
contextMenu.show({

View File

@@ -1,8 +1,6 @@
import "./index.css";
import type maplibregl from "maplibre-gl";
import { MapMouseEvent, Popup } from "maplibre-gl";
import { RefObject } from "preact";
import { useCallback, useContext, useEffect, useMemo, useRef, useState } from "preact/hooks";
import appContext from "../../../components/app_context";
@@ -20,11 +18,11 @@ import { ParentComponent } from "../../react/react_utils";
import TouchBar, { TouchBarButton, TouchBarSlider } from "../../react/TouchBar";
import { ViewModeProps } from "../interface";
import { createNewNote, moveMarker } from "./api";
import openContextMenu, { openMapContextMenu } from "./context_menu";
import ContextMenus from "./ContextMenus";
import Map, { GeoMouseEvent } from "./map";
import { DEFAULT_MAP_LAYER_NAME, MAP_LAYERS, MapLayer } from "./map_layer";
import Marker, { GpxTrack } from "./marker";
import { MARKER_LAYER, MARKER_SVG, useMarkerData } from "./marker_data";
import { MARKER_SVG, useMarkerData } from "./marker_data";
import Tooltips from "./Tooltips";
const DEFAULT_COORDINATES: [number, number] = [3.878638227135724, 446.6630455551659];
@@ -100,22 +98,6 @@ export default function GeoView({ note, noteIds, viewConfig, saveConfig }: ViewM
}
}, [ state ]);
const onContextMenu = useCallback((e: GeoMouseEvent) => {
const map = apiRef.current;
if (!map) return;
const features = map.queryRenderedFeatures(e.point, {
layers: [ MARKER_LAYER ]
});
if (features.length > 0) {
// Marker context menu.
openContextMenu(features[0].properties.id, e, !isReadOnly);
} else {
// Empty area context menu.
openMapContextMenu(note.noteId, e, !isReadOnly);
}
}, [ note.noteId, isReadOnly ]);
// Dragging
const containerRef = useRef<HTMLDivElement>(null);
const apiRef = useRef<maplibregl.Map | null>(null);
@@ -175,10 +157,10 @@ export default function GeoView({ note, noteIds, viewConfig, saveConfig }: ViewM
spacedUpdate.scheduleUpdate();
}}
onClick={onClick}
onContextMenu={onContextMenu}
scale={hasScale}
>
<Tooltips />
<ContextMenus note={note} isReadOnly={isReadOnly} />
</Map>}
<GeoMapTouchBar state={state} map={apiRef.current} />
</div>

View File

@@ -29,7 +29,7 @@ interface MapProps {
scale: boolean;
}
function toMapLibreEvent(e: maplibregl.MapMouseEvent): GeoMouseEvent {
export function toMapLibreEvent(e: maplibregl.MapMouseEvent): GeoMouseEvent {
return {
latlng: { lat: e.lngLat.lat, lng: e.lngLat.lng },
originalEvent: e.originalEvent,
@@ -176,17 +176,6 @@ export default function Map({ coordinates, zoom, layerData, viewportChanged, chi
return () => { map.off("click", handler); };
}, [ map, onClick ]);
useEffect(() => {
if (!onContextMenu || !map) return;
const handler = (e: maplibregl.MapMouseEvent) => {
e.preventDefault();
onContextMenu(toMapLibreEvent(e));
};
map.on("contextmenu", handler);
return () => { map.off("contextmenu", handler); };
}, [ map, onContextMenu ]);
useEffect(() => {
if (!onZoom || !map) return;