refactor(react/type_widgets): split note box into separate file

This commit is contained in:
Elian Doran 2025-10-04 09:04:22 +03:00
parent 1913355069
commit 460e01a2d6
No known key found for this signature in database
3 changed files with 122 additions and 107 deletions

View File

@ -0,0 +1,109 @@
import { useCallback, useEffect, useState } from "preact/hooks";
import { useNoteProperty } from "../../react/hooks";
import froca from "../../../services/froca";
import contextMenu from "../../../menus/context_menu";
import { t } from "../../../services/i18n";
import appContext from "../../../components/app_context";
import dialog from "../../../services/dialog";
import server from "../../../services/server";
import { JsPlumbItem } from "./jsplumb";
import FNote from "../../../entities/fnote";
import RelationMapApi, { MapDataNoteEntry } from "./api";
import { RefObject } from "preact";
import NoteLink from "../../react/NoteLink";
import { idToNoteId, noteIdToId } from "./utils";
const NOTE_BOX_SOURCE_CONFIG = {
filter: ".endpoint",
anchor: "Continuous",
connectorStyle: { stroke: "#000", strokeWidth: 1 },
connectionType: "basic",
extract: {
action: "the-action"
}
};
const NOTE_BOX_TARGET_CONFIG = {
dropOptions: { hoverClass: "dragHover" },
anchor: "Continuous",
allowLoopback: true
};
interface NoteBoxProps extends MapDataNoteEntry {
mapApiRef: RefObject<RelationMapApi>;
}
export function NoteBox({ noteId, x, y, mapApiRef }: NoteBoxProps) {
const [ note, setNote ] = useState<FNote | null>();
const title = useNoteProperty(note, "title");
useEffect(() => {
froca.getNote(noteId).then(setNote);
}, [ noteId ]);
const contextMenuHandler = useCallback((e: MouseEvent) => {
e.preventDefault();
contextMenu.show({
x: e.pageX,
y: e.pageY,
items: [
{
title: t("relation_map.open_in_new_tab"),
uiIcon: "bx bx-empty",
handler: () => appContext.tabManager.openTabWithNoteWithHoisting(noteId)
},
{
title: t("relation_map.remove_note"),
uiIcon: "bx bx-trash",
handler: async () => {
if (!note) return;
const result = await dialog.confirmDeleteNoteBoxWithNote(note.title);
if (typeof result !== "object" || !result.confirmed) return;
mapApiRef.current?.removeItem(noteId, result.isDeleteNoteChecked);
}
},
{
title: t("relation_map.edit_title"),
uiIcon: "bx bx-pencil",
handler: async () => {
const title = await dialog.prompt({
title: t("relation_map.rename_note"),
message: t("relation_map.enter_new_title"),
defaultValue: note?.title,
});
if (!title) {
return;
}
await server.put(`notes/${noteId}/title`, { title });
}
}
],
selectMenuItemHandler() {}
})
}, [ note ]);
return note && (
<JsPlumbItem
id={noteIdToId(noteId)}
className={`note-box ${note?.getCssClass()}`}
onContextMenu={contextMenuHandler}
x={x} y={y}
draggable={{
start() {},
drag() {},
stop(params) {
const noteId = idToNoteId(params.el.id);
const [ x, y ] = params.pos;
mapApiRef.current?.moveNote(noteId, x, y);
},
}}
sourceConfig={NOTE_BOX_SOURCE_CONFIG}
targetConfig={NOTE_BOX_TARGET_CONFIG}
>
<NoteLink className="title" title={title} notePath={noteId} noTnLink noContextMenu />
<div className="endpoint" title={t("relation_map.start_dragging_relations")} />
</JsPlumbItem>
)
}

View File

@ -1,11 +1,9 @@
import { useCallback, useEffect, useRef, useState } from "preact/hooks";
import { TypeWidgetProps } from "../type_widget";
import { Defaults, jsPlumb, jsPlumbInstance, OverlaySpec } from "jsplumb";
import { useEditorSpacedUpdate, useNoteBlob, useNoteProperty, useTriliumEvent, useTriliumEvents } from "../../react/hooks";
import { jsPlumbInstance } from "jsplumb";
import { useEditorSpacedUpdate, useTriliumEvent, useTriliumEvents } from "../../react/hooks";
import FNote from "../../../entities/fnote";
import { ComponentChildren, RefObject } from "preact";
import froca from "../../../services/froca";
import NoteLink from "../../react/NoteLink";
import { RefObject } from "preact";
import "./RelationMap.css";
import { t } from "../../../services/i18n";
import panzoom, { PanZoomOptions } from "panzoom";
@ -13,11 +11,11 @@ import dialog from "../../../services/dialog";
import server from "../../../services/server";
import toast from "../../../services/toast";
import { CreateChildrenResponse, RelationMapPostResponse, RelationMapRelation } from "@triliumnext/commons";
import contextMenu from "../../../menus/context_menu";
import appContext from "../../../components/app_context";
import RelationMapApi, { MapData, MapDataNoteEntry } from "./api";
import setupOverlays, { uniDirectionalOverlays } from "./overlays";
import { JsPlumb, JsPlumbItem } from "./jsplumb";
import { JsPlumb } from "./jsplumb";
import { noteIdToId } from "./utils";
import { NoteBox } from "./NoteBox";
interface Clipboard {
noteId: string;
@ -307,105 +305,6 @@ function useNoteCreation({ ntxId, note, containerRef, mapApiRef }: {
return onClickHandler;
}
const NOTE_BOX_SOURCE_CONFIG = {
filter: ".endpoint",
anchor: "Continuous",
connectorStyle: { stroke: "#000", strokeWidth: 1 },
connectionType: "basic",
extract: {
action: "the-action"
}
};
const NOTE_BOX_TARGET_CONFIG = {
dropOptions: { hoverClass: "dragHover" },
anchor: "Continuous",
allowLoopback: true
};
function NoteBox({ noteId, x, y, mapApiRef }: MapDataNoteEntry & { mapApiRef: RefObject<RelationMapApi> }) {
const [ note, setNote ] = useState<FNote | null>();
const title = useNoteProperty(note, "title");
useEffect(() => {
froca.getNote(noteId).then(setNote);
}, [ noteId ]);
const contextMenuHandler = useCallback((e: MouseEvent) => {
e.preventDefault();
contextMenu.show({
x: e.pageX,
y: e.pageY,
items: [
{
title: t("relation_map.open_in_new_tab"),
uiIcon: "bx bx-empty",
handler: () => appContext.tabManager.openTabWithNoteWithHoisting(noteId)
},
{
title: t("relation_map.remove_note"),
uiIcon: "bx bx-trash",
handler: async () => {
if (!note) return;
const result = await dialog.confirmDeleteNoteBoxWithNote(note.title);
if (typeof result !== "object" || !result.confirmed) return;
mapApiRef.current?.removeItem(noteId, result.isDeleteNoteChecked);
}
},
{
title: t("relation_map.edit_title"),
uiIcon: "bx bx-pencil",
handler: async () => {
const title = await dialog.prompt({
title: t("relation_map.rename_note"),
message: t("relation_map.enter_new_title"),
defaultValue: note?.title,
});
if (!title) {
return;
}
await server.put(`notes/${noteId}/title`, { title });
}
}
],
selectMenuItemHandler() {}
})
}, [ note ]);
return note && (
<JsPlumbItem
id={noteIdToId(noteId)}
className={`note-box ${note?.getCssClass()}`}
onContextMenu={contextMenuHandler}
x={x} y={y}
draggable={{
start() {},
drag() {},
stop(params) {
const noteId = idToNoteId(params.el.id);
const [ x, y ] = params.pos;
mapApiRef.current?.moveNote(noteId, x, y);
},
}}
sourceConfig={NOTE_BOX_SOURCE_CONFIG}
targetConfig={NOTE_BOX_TARGET_CONFIG}
>
<NoteLink className="title" title={title} notePath={noteId} noTnLink noContextMenu />
<div className="endpoint" title={t("relation_map.start_dragging_relations")} />
</JsPlumbItem>
)
}
function noteIdToId(noteId: string) {
return `rel-map-note-${noteId}`;
}
function idToNoteId(id: string) {
return id.substr(13);
}
function getZoom(container: HTMLDivElement) {
const transform = window.getComputedStyle(container).transform;
if (transform === "none") {

View File

@ -0,0 +1,7 @@
export function noteIdToId(noteId: string) {
return `rel-map-note-${noteId}`;
}
export function idToNoteId(id: string) {
return id.substr(13);
}