chore(client/ts): port mind_map

This commit is contained in:
Elian Doran 2025-01-14 19:18:44 +02:00
parent e16f4a1a71
commit 580bebb4a3
No known key found for this signature in database
5 changed files with 36 additions and 13 deletions

View File

@ -262,6 +262,9 @@ type EventMappings = {
}; };
noteContextRemovedEvent: { noteContextRemovedEvent: {
ntxIds: string[]; ntxIds: string[];
};
exportSvg: {
ntxId: string;
} }
}; };

View File

@ -35,7 +35,7 @@ const NOTE_TYPE_ICONS = {
* end user. Those types should be used only for checking against, they are * end user. Those types should be used only for checking against, they are
* not for direct use. * not for direct use.
*/ */
type NoteType = "file" | "image" | "search" | "noteMap" | "launcher" | "doc" | "contentWidget" | "text" | "relationMap" | "render" | "canvas" | "mermaid" | "book" | "webView" | "code"; type NoteType = "file" | "image" | "search" | "noteMap" | "launcher" | "doc" | "contentWidget" | "text" | "relationMap" | "render" | "canvas" | "mermaid" | "book" | "webView" | "code" | "mindMap";
interface NotePathRecord { interface NotePathRecord {
isArchived: boolean; isArchived: boolean;

View File

@ -20,3 +20,7 @@ declare module "draggabilly" {
destroy(); destroy();
} }
} }
declare module '@mind-elixir/node-menu' {
export default mindmap;
}

View File

@ -1,7 +1,11 @@
import TypeWidget from "./type_widget.js"; import TypeWidget from "./type_widget.js";
import utils from "../../services/utils.js"; import utils from "../../services/utils.js";
import MindElixir from "mind-elixir"; import MindElixir, { type MindElixirCtor } from "mind-elixir";
import nodeMenu from "@mind-elixir/node-menu"; import nodeMenu from "@mind-elixir/node-menu";
import type FNote from "../../entities/fnote.js";
import type { EventData } from "../../components/app_context.js";
const NEW_TOPIC_NAME = "";
const TPL = ` const TPL = `
<div class="note-detail-mind-map note-detail-printable"> <div class="note-detail-mind-map note-detail-printable">
@ -138,6 +142,11 @@ const TPL = `
`; `;
export default class MindMapWidget extends TypeWidget { export default class MindMapWidget extends TypeWidget {
private $content!: JQuery<HTMLElement>;
private triggeredByUserOperation?: boolean;
private mind?: ReturnType<MindElixirCtor["new"]>;
static getType() { static getType() {
return "mindMap"; return "mindMap";
} }
@ -164,7 +173,7 @@ export default class MindMapWidget extends TypeWidget {
super.doRender(); super.doRender();
} }
async doRefresh(note) { async doRefresh(note: FNote) {
if (this.triggeredByUserOperation) { if (this.triggeredByUserOperation) {
this.triggeredByUserOperation = false; this.triggeredByUserOperation = false;
return; return;
@ -178,12 +187,14 @@ export default class MindMapWidget extends TypeWidget {
this.triggeredByUserOperation = false; this.triggeredByUserOperation = false;
} }
async #loadData(note) { async #loadData(note: FNote) {
const blob = await note.getBlob(); const blob = await note.getBlob();
const content = blob.getJsonContent() || MindElixir.new(); const content = blob?.getJsonContent() || MindElixir.new(NEW_TOPIC_NAME);
this.mind.refresh(content); if (this.mind) {
this.mind.toCenter(); this.mind.refresh(content);
this.mind.toCenter();
}
} }
#initLibrary() { #initLibrary() {
@ -194,8 +205,9 @@ export default class MindMapWidget extends TypeWidget {
mind.install(nodeMenu); mind.install(nodeMenu);
this.mind = mind; this.mind = mind;
mind.init(MindElixir.new()); mind.init(MindElixir.new(NEW_TOPIC_NAME));
mind.bus.addListener("operation", (operation) => { // TODO: See why the typeof mindmap is not correct.
mind.bus.addListener("operation", (operation: { name: string }) => {
this.triggeredByUserOperation = true; this.triggeredByUserOperation = true;
if (operation.name !== "beginEdit") { if (operation.name !== "beginEdit") {
this.spacedUpdate.scheduleUpdate(); this.spacedUpdate.scheduleUpdate();
@ -234,14 +246,14 @@ export default class MindMapWidget extends TypeWidget {
return await this.mind.exportSvg().text(); return await this.mind.exportSvg().text();
} }
async entitiesReloadedEvent({ loadResults }) { async entitiesReloadedEvent({ loadResults }: EventData<"entitiesReloaded"> ) {
if (loadResults.isNoteReloaded(this.noteId)) { if (this.noteId && loadResults.isNoteReloaded(this.noteId)) {
this.refresh(); this.refresh();
} }
} }
async exportSvgEvent({ ntxId }) { async exportSvgEvent({ ntxId }: EventData<"exportSvg">) {
if (!this.isNoteContext(ntxId) || this.note.type !== "mindMap") { if (!this.isNoteContext(ntxId) || this.note?.type !== "mindMap") {
return; return;
} }

View File

@ -2,8 +2,12 @@ import NoteContextAwareWidget from "../note_context_aware_widget.js";
import appContext, { type EventData, type EventNames } from "../../components/app_context.js"; import appContext, { type EventData, type EventNames } from "../../components/app_context.js";
import type FNote from "../../entities/fnote.js"; import type FNote from "../../entities/fnote.js";
import type NoteDetailWidget from "../note_detail.js"; import type NoteDetailWidget from "../note_detail.js";
import type SpacedUpdate from "../../services/spaced_update.js";
export default abstract class TypeWidget extends NoteContextAwareWidget { export default abstract class TypeWidget extends NoteContextAwareWidget {
protected spacedUpdate!: SpacedUpdate;
// for overriding // for overriding
static getType() {} static getType() {}