feat(views/geomap): add a context menu for empty area

This commit is contained in:
Elian Doran 2025-07-06 23:34:07 +03:00
parent a563330136
commit d31af2ddc2
No known key found for this signature in database
3 changed files with 53 additions and 26 deletions

View file

@ -1,8 +1,10 @@
import { LeafletMouseEvent } from "leaflet";
import appContext from "../../../components/app_context.js"; import appContext from "../../../components/app_context.js";
import type { ContextMenuEvent } from "../../../menus/context_menu.js"; import type { ContextMenuEvent } from "../../../menus/context_menu.js";
import contextMenu from "../../../menus/context_menu.js"; import contextMenu from "../../../menus/context_menu.js";
import linkContextMenu from "../../../menus/link_context_menu.js"; import linkContextMenu from "../../../menus/link_context_menu.js";
import { t } from "../../../services/i18n.js"; import { t } from "../../../services/i18n.js";
import { createNewNote } from "./editing.js";
export default function openContextMenu(noteId: string, e: ContextMenuEvent) { export default function openContextMenu(noteId: string, e: ContextMenuEvent) {
contextMenu.show({ contextMenu.show({
@ -30,3 +32,22 @@ export default function openContextMenu(noteId: string, e: ContextMenuEvent) {
} }
}); });
} }
export function openMapContextMenu(noteId: string, e: LeafletMouseEvent) {
contextMenu.show({
x: e.originalEvent.pageX,
y: e.originalEvent.pageY,
items: [
{ title: t("geo-map-context.add-note"), command: "addNoteToMap", uiIcon: "bx bx-plus" }
],
selectMenuItemHandler: ({ command }) => {
switch (command) {
case "addNoteToMap":
createNewNote(noteId, e);
break;
default:
appContext.triggerCommand(command);
}
}
});
}

View file

@ -1,8 +1,34 @@
import { LatLng } from "leaflet"; import { LatLng, LeafletMouseEvent } from "leaflet";
import attributes from "../../../services/attributes"; import attributes from "../../../services/attributes";
import { LOCATION_ATTRIBUTE } from "./index.js"; import { LOCATION_ATTRIBUTE } from "./index.js";
import dialog from "../../../services/dialog";
import server from "../../../services/server";
import { t } from "../../../services/i18n";
const CHILD_NOTE_ICON = "bx bx-pin";
// TODO: Deduplicate
interface CreateChildResponse {
note: {
noteId: string;
};
}
export async function moveMarker(noteId: string, latLng: LatLng | null) { export async function moveMarker(noteId: string, latLng: LatLng | null) {
const value = latLng ? [latLng.lat, latLng.lng].join(",") : ""; const value = latLng ? [latLng.lat, latLng.lng].join(",") : "";
await attributes.setLabel(noteId, LOCATION_ATTRIBUTE, value); await attributes.setLabel(noteId, LOCATION_ATTRIBUTE, value);
} }
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<CreateChildResponse>(`notes/${noteId}/children?target=into`, {
title,
content: "",
type: "text"
});
attributes.setLabel(note.noteId, "iconClass", CHILD_NOTE_ICON);
moveMarker(note.noteId, e.latlng);
}
}

View file

@ -7,18 +7,9 @@ import processNoteWithMarker, { processNoteWithGpxTrack } from "./markers.js";
import { hasTouchBar } from "../../../services/utils.js"; import { hasTouchBar } from "../../../services/utils.js";
import toast from "../../../services/toast.js"; import toast from "../../../services/toast.js";
import { CommandListenerData, EventData } from "../../../components/app_context.js"; import { CommandListenerData, EventData } from "../../../components/app_context.js";
import dialog from "../../../services/dialog.js"; import { createNewNote, moveMarker } from "./editing.js";
import server from "../../../services/server.js";
import attributes from "../../../services/attributes.js";
import { moveMarker } from "./editing.js";
import link from "../../../services/link.js"; import link from "../../../services/link.js";
import { openMapContextMenu } from "./context_menu.js";
// TODO: Deduplicate
interface CreateChildResponse {
note: {
noteId: string;
};
}
const TPL = /*html*/` const TPL = /*html*/`
<div class="geo-view"> <div class="geo-view">
@ -102,7 +93,6 @@ interface MapData {
const DEFAULT_COORDINATES: [number, number] = [3.878638227135724, 446.6630455551659]; const DEFAULT_COORDINATES: [number, number] = [3.878638227135724, 446.6630455551659];
const DEFAULT_ZOOM = 2; const DEFAULT_ZOOM = 2;
export const LOCATION_ATTRIBUTE = "geolocation"; export const LOCATION_ATTRIBUTE = "geolocation";
const CHILD_NOTE_ICON = "bx bx-pin";
enum State { enum State {
Normal, Normal,
@ -166,7 +156,8 @@ export default class GeoView extends ViewMode<MapData> {
const updateFn = () => this.spacedUpdate.scheduleUpdate(); const updateFn = () => this.spacedUpdate.scheduleUpdate();
map.on("moveend", updateFn); map.on("moveend", updateFn);
map.on("zoomend", updateFn); map.on("zoomend", updateFn);
map.on("click", (e) => this.#onMapClicked(e)); map.on("click", (e) => this.#onMapClicked(e))
map.on("contextmenu", (e) => openMapContextMenu(this.parentNote.noteId, e));
this.#reloadMarkers(); this.#reloadMarkers();
@ -299,18 +290,7 @@ export default class GeoView extends ViewMode<MapData> {
} }
toast.closePersistent("geo-new-note"); toast.closePersistent("geo-new-note");
const title = await dialog.prompt({ message: t("relation_map.enter_title_of_new_note"), defaultValue: t("relation_map.default_new_note_title") }); await createNewNote(this.parentNote.noteId, e);
if (title?.trim()) {
const { note } = await server.post<CreateChildResponse>(`notes/${this.parentNote.noteId}/children?target=into`, {
title,
content: "",
type: "text"
});
attributes.setLabel(note.noteId, "iconClass", CHILD_NOTE_ICON);
moveMarker(note.noteId, e.latlng);
}
this.#changeState(State.Normal); this.#changeState(State.Normal);
} }