From 189b7e20dbaaf7a45b3da08e7b6f18467de7862e Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Thu, 4 Sep 2025 21:26:09 +0300 Subject: [PATCH] chore(react/collections/geomap): bring back context menu --- apps/client/src/services/dialog.ts | 2 +- .../src/widgets/collections/geomap/api.ts | 20 ++++++++++++++++ .../geomap}/context_menu.ts | 2 +- .../src/widgets/collections/geomap/index.tsx | 6 ++++- .../src/widgets/collections/geomap/marker.tsx | 9 ++++++-- .../widgets/view_widgets/geo_view/editing.ts | 23 ------------------- .../widgets/view_widgets/geo_view/markers.ts | 8 ------- 7 files changed, 34 insertions(+), 36 deletions(-) rename apps/client/src/widgets/{view_widgets/geo_view => collections/geomap}/context_menu.ts (98%) diff --git a/apps/client/src/services/dialog.ts b/apps/client/src/services/dialog.ts index a1e54f5e8..22efee370 100644 --- a/apps/client/src/services/dialog.ts +++ b/apps/client/src/services/dialog.ts @@ -60,7 +60,7 @@ async function confirmDeleteNoteBoxWithNote(title: string) { return new Promise((res) => appContext.triggerCommand("showConfirmDeleteNoteBoxWithNoteDialog", { title, callback: res })); } -async function prompt(props: PromptDialogOptions) { +export async function prompt(props: PromptDialogOptions) { return new Promise((res) => appContext.triggerCommand("showPromptDialog", { ...props, callback: res })); } diff --git a/apps/client/src/widgets/collections/geomap/api.ts b/apps/client/src/widgets/collections/geomap/api.ts index 7c3b1dbbd..d86ec50b7 100644 --- a/apps/client/src/widgets/collections/geomap/api.ts +++ b/apps/client/src/widgets/collections/geomap/api.ts @@ -1,8 +1,28 @@ import { LatLng } from "leaflet"; import { LOCATION_ATTRIBUTE } from "."; import attributes from "../../../services/attributes"; +import { prompt } from "../../../services/dialog"; +import server from "../../../services/server"; +import { t } from "../../../services/i18n"; +import { CreateChildrenResponse } from "@triliumnext/commons"; + +const CHILD_NOTE_ICON = "bx bx-pin"; export async function moveMarker(noteId: string, latLng: LatLng | null) { const value = latLng ? [latLng.lat, latLng.lng].join(",") : ""; await attributes.setLabel(noteId, LOCATION_ATTRIBUTE, value); } + +export async function createNewNote(noteId: string, e: LeafletMouseEvent) { + const title = await prompt({ message: t("relation_map.enter_title_of_new_note"), defaultValue: t("relation_map.default_new_note_title") }); + + if (title?.trim()) { + const { note } = await server.post(`notes/${noteId}/children?target=into`, { + title, + content: "", + type: "text" + }); + attributes.setLabel(note.noteId, "iconClass", CHILD_NOTE_ICON); + moveMarker(note.noteId, e.latlng); + } +} diff --git a/apps/client/src/widgets/view_widgets/geo_view/context_menu.ts b/apps/client/src/widgets/collections/geomap/context_menu.ts similarity index 98% rename from apps/client/src/widgets/view_widgets/geo_view/context_menu.ts rename to apps/client/src/widgets/collections/geomap/context_menu.ts index 26d91df27..617c4637f 100644 --- a/apps/client/src/widgets/view_widgets/geo_view/context_menu.ts +++ b/apps/client/src/widgets/collections/geomap/context_menu.ts @@ -3,7 +3,7 @@ import appContext, { type CommandMappings } from "../../../components/app_contex import contextMenu, { type MenuItem } from "../../../menus/context_menu.js"; import linkContextMenu from "../../../menus/link_context_menu.js"; import { t } from "../../../services/i18n.js"; -import { createNewNote } from "./editing.js"; +import { createNewNote } from "./api.js"; import { copyTextWithToast } from "../../../services/clipboard_ext.js"; import link from "../../../services/link.js"; diff --git a/apps/client/src/widgets/collections/geomap/index.tsx b/apps/client/src/widgets/collections/geomap/index.tsx index 4e6ced7a6..1b8d35834 100644 --- a/apps/client/src/widgets/collections/geomap/index.tsx +++ b/apps/client/src/widgets/collections/geomap/index.tsx @@ -3,7 +3,7 @@ import "./index.css"; import { ViewModeProps } from "../interface"; import { useNoteLabel, useNoteLabelBoolean, useNoteProperty, useSpacedUpdate } from "../../react/hooks"; import { DEFAULT_MAP_LAYER_NAME } from "./map_layer"; -import { divIcon, LatLng } from "leaflet"; +import { divIcon, LatLng, LeafletMouseEvent } from "leaflet"; import { useCallback, useEffect, useMemo, useState } from "preact/hooks"; import Marker from "./marker"; import froca from "../../../services/froca"; @@ -12,6 +12,7 @@ import markerIcon from "leaflet/dist/images/marker-icon.png"; import markerIconShadow from "leaflet/dist/images/marker-shadow.png"; import appContext from "../../../components/app_context"; import { moveMarker } from "./api"; +import openContextMenu from "./context_menu"; const DEFAULT_COORDINATES: [number, number] = [3.878638227135724, 446.6630455551659]; const DEFAULT_ZOOM = 2; @@ -84,6 +85,8 @@ function NoteMarker({ note, editable }: { note: FNote, editable: boolean }) { moveMarker(note.noteId, newCoordinates); }, [ note.noteId ]); + const onContextMenu = useCallback((e: LeafletMouseEvent) => openContextMenu(note.noteId, e, editable), [ note.noteId, editable ]); + return latLng && } diff --git a/apps/client/src/widgets/collections/geomap/marker.tsx b/apps/client/src/widgets/collections/geomap/marker.tsx index 009d60034..7f9a7cda9 100644 --- a/apps/client/src/widgets/collections/geomap/marker.tsx +++ b/apps/client/src/widgets/collections/geomap/marker.tsx @@ -1,6 +1,6 @@ import { useContext, useEffect } from "preact/hooks"; import { ParentMap } from "./map"; -import { DivIcon, Icon, LatLng, Marker as LeafletMarker, marker, MarkerOptions } from "leaflet"; +import { DivIcon, Icon, LatLng, Marker as LeafletMarker, LeafletMouseEvent, marker, MarkerOptions } from "leaflet"; export interface MarkerProps { coordinates: [ number, number ]; @@ -8,10 +8,11 @@ export interface MarkerProps { onClick?: () => void; onMouseDown?: (e: MouseEvent) => void; onDragged?: ((newCoordinates: LatLng) => void); + onContextMenu: (e: LeafletMouseEvent) => void; draggable?: boolean; } -export default function Marker({ coordinates, icon, draggable, onClick, onDragged, onMouseDown }: MarkerProps) { +export default function Marker({ coordinates, icon, draggable, onClick, onDragged, onMouseDown, onContextMenu }: MarkerProps) { const parentMap = useContext(ParentMap); useEffect(() => { @@ -41,6 +42,10 @@ export default function Marker({ coordinates, icon, draggable, onClick, onDragge }); } + if (onContextMenu) { + newMarker.on("contextmenu", e => onContextMenu(e)) + } + newMarker.addTo(parentMap); return () => newMarker.removeFrom(parentMap); diff --git a/apps/client/src/widgets/view_widgets/geo_view/editing.ts b/apps/client/src/widgets/view_widgets/geo_view/editing.ts index 85753f38d..71041b50a 100644 --- a/apps/client/src/widgets/view_widgets/geo_view/editing.ts +++ b/apps/client/src/widgets/view_widgets/geo_view/editing.ts @@ -9,29 +9,6 @@ import type { DragData } from "../../note_tree.js"; import froca from "../../../services/froca.js"; import branches from "../../../services/branches.js"; -const CHILD_NOTE_ICON = "bx bx-pin"; - -// TODO: Deduplicate -interface CreateChildResponse { - note: { - noteId: string; - }; -} - -export async function createNewNote(noteId: string, e: LeafletMouseEvent) { - const title = await dialog.prompt({ message: t("relation_map.enter_title_of_new_note"), defaultValue: t("relation_map.default_new_note_title") }); - - if (title?.trim()) { - const { note } = await server.post(`notes/${noteId}/children?target=into`, { - title, - content: "", - type: "text" - }); - attributes.setLabel(note.noteId, "iconClass", CHILD_NOTE_ICON); - moveMarker(note.noteId, e.latlng); - } -} - export function setupDragging($container: JQuery, map: Map, mapNoteId: string) { $container.on("dragover", (e) => { // Allow drag. diff --git a/apps/client/src/widgets/view_widgets/geo_view/markers.ts b/apps/client/src/widgets/view_widgets/geo_view/markers.ts index f32824283..0e8e9f4f1 100644 --- a/apps/client/src/widgets/view_widgets/geo_view/markers.ts +++ b/apps/client/src/widgets/view_widgets/geo_view/markers.ts @@ -7,14 +7,6 @@ import L from "leaflet"; let gpxLoaded = false; -export default function processNoteWithMarker(map: Map, note: FNote, location: string, isEditable: boolean) { - newMarker.on("contextmenu", (e) => { - openContextMenu(note.noteId, e, isEditable); - }); - - return newMarker; -} - export async function processNoteWithGpxTrack(map: Map, note: FNote) { if (!gpxLoaded) { const GPX = await import("leaflet-gpx");