mirror of
https://github.com/zadam/trilium.git
synced 2026-01-07 15:14:24 +01:00
refactor(react/type_widgets): split note box into separate file
This commit is contained in:
parent
1913355069
commit
460e01a2d6
109
apps/client/src/widgets/type_widgets/relation_map/NoteBox.tsx
Normal file
109
apps/client/src/widgets/type_widgets/relation_map/NoteBox.tsx
Normal 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>
|
||||||
|
)
|
||||||
|
}
|
||||||
@ -1,11 +1,9 @@
|
|||||||
import { useCallback, useEffect, useRef, useState } from "preact/hooks";
|
import { useCallback, useEffect, useRef, useState } from "preact/hooks";
|
||||||
import { TypeWidgetProps } from "../type_widget";
|
import { TypeWidgetProps } from "../type_widget";
|
||||||
import { Defaults, jsPlumb, jsPlumbInstance, OverlaySpec } from "jsplumb";
|
import { jsPlumbInstance } from "jsplumb";
|
||||||
import { useEditorSpacedUpdate, useNoteBlob, useNoteProperty, useTriliumEvent, useTriliumEvents } from "../../react/hooks";
|
import { useEditorSpacedUpdate, useTriliumEvent, useTriliumEvents } from "../../react/hooks";
|
||||||
import FNote from "../../../entities/fnote";
|
import FNote from "../../../entities/fnote";
|
||||||
import { ComponentChildren, RefObject } from "preact";
|
import { RefObject } from "preact";
|
||||||
import froca from "../../../services/froca";
|
|
||||||
import NoteLink from "../../react/NoteLink";
|
|
||||||
import "./RelationMap.css";
|
import "./RelationMap.css";
|
||||||
import { t } from "../../../services/i18n";
|
import { t } from "../../../services/i18n";
|
||||||
import panzoom, { PanZoomOptions } from "panzoom";
|
import panzoom, { PanZoomOptions } from "panzoom";
|
||||||
@ -13,11 +11,11 @@ import dialog from "../../../services/dialog";
|
|||||||
import server from "../../../services/server";
|
import server from "../../../services/server";
|
||||||
import toast from "../../../services/toast";
|
import toast from "../../../services/toast";
|
||||||
import { CreateChildrenResponse, RelationMapPostResponse, RelationMapRelation } from "@triliumnext/commons";
|
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 RelationMapApi, { MapData, MapDataNoteEntry } from "./api";
|
||||||
import setupOverlays, { uniDirectionalOverlays } from "./overlays";
|
import setupOverlays, { uniDirectionalOverlays } from "./overlays";
|
||||||
import { JsPlumb, JsPlumbItem } from "./jsplumb";
|
import { JsPlumb } from "./jsplumb";
|
||||||
|
import { noteIdToId } from "./utils";
|
||||||
|
import { NoteBox } from "./NoteBox";
|
||||||
|
|
||||||
interface Clipboard {
|
interface Clipboard {
|
||||||
noteId: string;
|
noteId: string;
|
||||||
@ -307,105 +305,6 @@ function useNoteCreation({ ntxId, note, containerRef, mapApiRef }: {
|
|||||||
return onClickHandler;
|
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) {
|
function getZoom(container: HTMLDivElement) {
|
||||||
const transform = window.getComputedStyle(container).transform;
|
const transform = window.getComputedStyle(container).transform;
|
||||||
if (transform === "none") {
|
if (transform === "none") {
|
||||||
|
|||||||
@ -0,0 +1,7 @@
|
|||||||
|
export function noteIdToId(noteId: string) {
|
||||||
|
return `rel-map-note-${noteId}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function idToNoteId(id: string) {
|
||||||
|
return id.substr(13);
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user