update
This commit is contained in:
3
.obsidian/plugins/lovely-mindmap/data.json
vendored
Normal file
3
.obsidian/plugins/lovely-mindmap/data.json
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"autoFocus": false
|
||||
}
|
595
.obsidian/plugins/lovely-mindmap/main.js
vendored
Normal file
595
.obsidian/plugins/lovely-mindmap/main.js
vendored
Normal file
@@ -0,0 +1,595 @@
|
||||
/*
|
||||
THIS IS A GENERATED/BUNDLED FILE BY ESBUILD
|
||||
if you want to view the source, please visit the github repository of this plugin
|
||||
*/
|
||||
|
||||
var __defProp = Object.defineProperty;
|
||||
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
||||
var __getOwnPropNames = Object.getOwnPropertyNames;
|
||||
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
||||
var __export = (target, all) => {
|
||||
for (var name in all)
|
||||
__defProp(target, name, { get: all[name], enumerable: true });
|
||||
};
|
||||
var __copyProps = (to, from, except, desc) => {
|
||||
if (from && typeof from === "object" || typeof from === "function") {
|
||||
for (let key of __getOwnPropNames(from))
|
||||
if (!__hasOwnProp.call(to, key) && key !== except)
|
||||
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
||||
}
|
||||
return to;
|
||||
};
|
||||
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
||||
var __decorateClass = (decorators, target, key, kind) => {
|
||||
var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
|
||||
for (var i = decorators.length - 1, decorator; i >= 0; i--)
|
||||
if (decorator = decorators[i])
|
||||
result = (kind ? decorator(target, key, result) : decorator(result)) || result;
|
||||
if (kind && result)
|
||||
__defProp(target, key, result);
|
||||
return result;
|
||||
};
|
||||
|
||||
// src/main.ts
|
||||
var main_exports = {};
|
||||
__export(main_exports, {
|
||||
default: () => LovelyMindmap
|
||||
});
|
||||
module.exports = __toCommonJS(main_exports);
|
||||
var import_obsidian2 = require("obsidian");
|
||||
|
||||
// src/tool/index.ts
|
||||
function debounce(delay = 100) {
|
||||
let lastTime = 0;
|
||||
let timer;
|
||||
return function(target, propertyKey, descriptor) {
|
||||
const originalMethod = descriptor.value;
|
||||
descriptor.value = function(...args) {
|
||||
const now = Date.now();
|
||||
clearTimeout(timer);
|
||||
if (now - lastTime < delay) {
|
||||
return;
|
||||
}
|
||||
timer = setTimeout(() => {
|
||||
originalMethod.apply(this, args);
|
||||
lastTime = 0;
|
||||
}, delay);
|
||||
lastTime = now;
|
||||
};
|
||||
return descriptor;
|
||||
};
|
||||
}
|
||||
function calcDistance(a, b) {
|
||||
return Math.sqrt(
|
||||
(a[0] - b[0]) ** 2 + (a[1] - b[1]) ** 2
|
||||
);
|
||||
}
|
||||
function findClosestNodeByBbox(pos, nodes) {
|
||||
return nodes.reduce((prev, cur, idx) => {
|
||||
const a = [cur.bbox.minX, cur.bbox.minY];
|
||||
const b = [cur.bbox.maxX, cur.bbox.minY];
|
||||
const c = [cur.bbox.minX, cur.bbox.maxY];
|
||||
const d = [cur.bbox.maxX, cur.bbox.maxY];
|
||||
const distance = Math.min(
|
||||
calcDistance(pos, a),
|
||||
calcDistance(pos, b),
|
||||
calcDistance(pos, c),
|
||||
calcDistance(pos, d)
|
||||
);
|
||||
if (idx === 0) {
|
||||
return {
|
||||
node: cur,
|
||||
distance
|
||||
};
|
||||
}
|
||||
return distance < prev.distance ? { node: cur, distance } : prev;
|
||||
}, {
|
||||
node: {},
|
||||
distance: 0
|
||||
});
|
||||
}
|
||||
function uuid() {
|
||||
const first = Math.floor(Math.random() * 9 + 1);
|
||||
const rest = String(Math.random()).slice(2, 10);
|
||||
const random9 = first + rest;
|
||||
return string10To64(Date.now()) + string10To64(random9);
|
||||
}
|
||||
function string10To64(str) {
|
||||
const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
|
||||
const radix = chars.length;
|
||||
let num = typeof str === "string" ? parseInt(str) : str;
|
||||
const res = [];
|
||||
do {
|
||||
const mod = num % radix;
|
||||
res.push(chars[mod]);
|
||||
num = (num - mod) / radix;
|
||||
} while (num > 0);
|
||||
return res.join("");
|
||||
}
|
||||
|
||||
// node_modules/autobind-decorator/lib/esm/index.js
|
||||
function _typeof(obj) {
|
||||
if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") {
|
||||
_typeof = function _typeof2(obj2) {
|
||||
return typeof obj2;
|
||||
};
|
||||
} else {
|
||||
_typeof = function _typeof2(obj2) {
|
||||
return obj2 && typeof Symbol === "function" && obj2.constructor === Symbol && obj2 !== Symbol.prototype ? "symbol" : typeof obj2;
|
||||
};
|
||||
}
|
||||
return _typeof(obj);
|
||||
}
|
||||
function boundMethod(target, key, descriptor) {
|
||||
var fn = descriptor.value;
|
||||
if (typeof fn !== "function") {
|
||||
throw new TypeError("@boundMethod decorator can only be applied to methods not: ".concat(_typeof(fn)));
|
||||
}
|
||||
var definingProperty = false;
|
||||
return {
|
||||
configurable: true,
|
||||
get: function get() {
|
||||
if (definingProperty || this === target.prototype || this.hasOwnProperty(key) || typeof fn !== "function") {
|
||||
return fn;
|
||||
}
|
||||
var boundFn = fn.bind(this);
|
||||
definingProperty = true;
|
||||
Object.defineProperty(this, key, {
|
||||
configurable: true,
|
||||
get: function get2() {
|
||||
return boundFn;
|
||||
},
|
||||
set: function set(value) {
|
||||
fn = value;
|
||||
delete this[key];
|
||||
}
|
||||
});
|
||||
definingProperty = false;
|
||||
return boundFn;
|
||||
},
|
||||
set: function set(value) {
|
||||
fn = value;
|
||||
}
|
||||
};
|
||||
}
|
||||
function boundClass(target) {
|
||||
var keys;
|
||||
if (typeof Reflect !== "undefined" && typeof Reflect.ownKeys === "function") {
|
||||
keys = Reflect.ownKeys(target.prototype);
|
||||
} else {
|
||||
keys = Object.getOwnPropertyNames(target.prototype);
|
||||
if (typeof Object.getOwnPropertySymbols === "function") {
|
||||
keys = keys.concat(Object.getOwnPropertySymbols(target.prototype));
|
||||
}
|
||||
}
|
||||
keys.forEach(function(key) {
|
||||
if (key === "constructor") {
|
||||
return;
|
||||
}
|
||||
var descriptor = Object.getOwnPropertyDescriptor(target.prototype, key);
|
||||
if (typeof descriptor.value === "function") {
|
||||
Object.defineProperty(target.prototype, key, boundMethod(target, key, descriptor));
|
||||
}
|
||||
});
|
||||
return target;
|
||||
}
|
||||
function autobind() {
|
||||
if (arguments.length === 1) {
|
||||
return boundClass.apply(void 0, arguments);
|
||||
}
|
||||
return boundMethod.apply(void 0, arguments);
|
||||
}
|
||||
|
||||
// src/module/node.ts
|
||||
var Node = class {
|
||||
constructor(main) {
|
||||
this.main = main;
|
||||
}
|
||||
getNavigationNode() {
|
||||
const node = this.getSingleSelection();
|
||||
if (!node || !node.isFocused || node.isEditing)
|
||||
return null;
|
||||
return node;
|
||||
}
|
||||
getCreationNode() {
|
||||
const node = this.getSingleSelection();
|
||||
if (!node || !node.isFocused || !node.isEditing)
|
||||
return null;
|
||||
return node;
|
||||
}
|
||||
getSelection() {
|
||||
return this.main.canvas.selection;
|
||||
}
|
||||
getSingleSelection() {
|
||||
const selections = this.main.canvas.selection;
|
||||
if (selections.size === 0 || selections.size > 1) {
|
||||
return null;
|
||||
}
|
||||
return selections.values().next().value;
|
||||
}
|
||||
getFromNodes(node) {
|
||||
const fromNodeFilter = (edge) => edge.to.node.id === node.id;
|
||||
return this.main.canvas.getEdgesForNode(node).filter(fromNodeFilter).map((edge) => edge.from.node);
|
||||
}
|
||||
getToNodes(node) {
|
||||
const toNodeFilter = (edge) => edge.from.node.id === node.id;
|
||||
return this.main.canvas.getEdgesForNode(node).filter(toNodeFilter).map((edge) => edge.to.node);
|
||||
}
|
||||
getSibNodes(target) {
|
||||
const fromNodes = this.getFromNodes(target);
|
||||
const toNodes = this.getToNodes(fromNodes[0]);
|
||||
return toNodes.filter((node) => node.id !== target.id);
|
||||
}
|
||||
createChildren() {
|
||||
const selection = this.getNavigationNode();
|
||||
if (!selection)
|
||||
return;
|
||||
const {
|
||||
x,
|
||||
y,
|
||||
width,
|
||||
height
|
||||
} = selection;
|
||||
const rightSideNodeFilter = (node) => {
|
||||
var _a, _b, _c;
|
||||
return ((_a = node == null ? void 0 : node.to) == null ? void 0 : _a.side) === "left" && selection.id !== ((_c = (_b = node == null ? void 0 : node.to) == null ? void 0 : _b.node) == null ? void 0 : _c.id);
|
||||
};
|
||||
const sibNodes = this.main.canvas.getEdgesForNode(selection).filter(rightSideNodeFilter).map((node) => node.to.node);
|
||||
const nextNodeY = Math.max(...sibNodes.map((node) => node.y)) + this.main.setting.EPSILON;
|
||||
const childNode = this.main.canvas.createTextNode({
|
||||
pos: {
|
||||
x: x + width + 200,
|
||||
y: nextNodeY
|
||||
},
|
||||
size: {
|
||||
height,
|
||||
width
|
||||
},
|
||||
text: "",
|
||||
focus: false,
|
||||
save: true
|
||||
});
|
||||
const data = this.main.canvas.getData();
|
||||
this.main.canvas.importData({
|
||||
"edges": [
|
||||
...data.edges,
|
||||
{
|
||||
"id": uuid(),
|
||||
"fromNode": selection.id,
|
||||
"fromSide": "right",
|
||||
"toNode": childNode.id,
|
||||
"toSide": "left"
|
||||
}
|
||||
],
|
||||
"nodes": data.nodes
|
||||
});
|
||||
this.main.layout.useSide(selection, sibNodes.concat(childNode));
|
||||
this.main.view.zoomToNode(childNode);
|
||||
}
|
||||
createSibNode(_, context) {
|
||||
const selection = this.getNavigationNode();
|
||||
if (!selection)
|
||||
return;
|
||||
const {
|
||||
x,
|
||||
y,
|
||||
width,
|
||||
height
|
||||
} = selection;
|
||||
const { EPSILON } = this.main.setting;
|
||||
const isPressedShift = context.modifiers === "Shift";
|
||||
const fromNode = this.main.node.getFromNodes(selection)[0];
|
||||
const toNodes = this.main.node.getToNodes(fromNode);
|
||||
const willInsertedNode = this.main.canvas.createTextNode({
|
||||
pos: {
|
||||
x,
|
||||
y: isPressedShift ? y - EPSILON : y + EPSILON
|
||||
},
|
||||
size: {
|
||||
height,
|
||||
width
|
||||
},
|
||||
text: "",
|
||||
focus: false,
|
||||
save: true
|
||||
});
|
||||
const data = this.main.canvas.getData();
|
||||
this.main.canvas.importData({
|
||||
"edges": [
|
||||
...data.edges,
|
||||
{
|
||||
"id": uuid(),
|
||||
"fromNode": fromNode.id,
|
||||
"fromSide": "right",
|
||||
"toNode": willInsertedNode.id,
|
||||
"toSide": "left"
|
||||
}
|
||||
],
|
||||
"nodes": data.nodes
|
||||
});
|
||||
this.main.layout.useSide(fromNode, toNodes.concat(willInsertedNode));
|
||||
this.main.view.zoomToNode(willInsertedNode);
|
||||
}
|
||||
};
|
||||
__decorateClass([
|
||||
debounce()
|
||||
], Node.prototype, "createChildren", 1);
|
||||
__decorateClass([
|
||||
debounce()
|
||||
], Node.prototype, "createSibNode", 1);
|
||||
Node = __decorateClass([
|
||||
autobind
|
||||
], Node);
|
||||
|
||||
// src/module/keymap.ts
|
||||
var Keymap = class {
|
||||
constructor(main) {
|
||||
this.hotkeys = [];
|
||||
this.main = main;
|
||||
this.node = main.node;
|
||||
}
|
||||
async help() {
|
||||
if (this.main.view.isCreating())
|
||||
return;
|
||||
console.log("this:\n", this);
|
||||
console.log("app:\n", this.main.app);
|
||||
console.log("canvas:\n", this.main.canvas);
|
||||
console.log("selections:\n", this.main.canvas.selection.values().next());
|
||||
}
|
||||
nodeNavigation(_, context) {
|
||||
const { key } = context;
|
||||
const selection = this.node.getSingleSelection();
|
||||
if (!selection || selection.isEditing) {
|
||||
return;
|
||||
}
|
||||
const { OFFSET_WEIGHT } = this.main.setting;
|
||||
const data = this.main.canvas.getViewportNodes();
|
||||
const offsetX = (a, b) => Math.abs(b.x - a.x);
|
||||
const offsetY = (a, b) => Math.abs(b.y - a.y);
|
||||
const endpointOffset = (a, b) => Math.min(
|
||||
Math.abs(b.y - a.y + 2 / a.height),
|
||||
Math.abs(b.y + b.height - a.y - 2 / a.height),
|
||||
Math.abs(b.x - a.x + 2 / a.width),
|
||||
Math.abs(b.x + b.width - a.x + 2 / a.width)
|
||||
);
|
||||
const calcDistance2 = (a, b) => key === "ArrowLeft" || key === "ArrowRight" ? offsetX(a, b) + endpointOffset(a, b) ** OFFSET_WEIGHT : offsetY(a, b) + endpointOffset(a, b) ** OFFSET_WEIGHT;
|
||||
const isSameDirection = (node) => {
|
||||
const notSelf = node.id !== selection.id;
|
||||
const strategies = {
|
||||
ArrowRight: notSelf && node.x > selection.x + selection.width,
|
||||
ArrowLeft: notSelf && node.x + node.width < selection.x,
|
||||
ArrowUp: notSelf && node.y + node.height < selection.y,
|
||||
ArrowDown: notSelf && node.y > selection.y + selection.height
|
||||
};
|
||||
return strategies[key];
|
||||
};
|
||||
const midpoints = data.filter(isSameDirection).map((node) => ({
|
||||
node,
|
||||
offsetX: offsetX(selection, node),
|
||||
offsetY: offsetY(selection, node),
|
||||
endpointOffset: endpointOffset(selection, node),
|
||||
distance: calcDistance2(selection, node)
|
||||
})).sort((a, b) => a.distance - b.distance);
|
||||
if (midpoints.length > 0) {
|
||||
this.main.view.zoomToNode(midpoints[0].node);
|
||||
}
|
||||
}
|
||||
blurNode() {
|
||||
if (this.main.view.isCreating()) {
|
||||
this.main.view.creation2Navigation();
|
||||
return;
|
||||
}
|
||||
if (this.main.view.isNavigating()) {
|
||||
this.main.view.useTouch();
|
||||
return;
|
||||
}
|
||||
}
|
||||
focusNode() {
|
||||
if (this.main.view.isTouching()) {
|
||||
this.main.view.touch2Navigation();
|
||||
return;
|
||||
}
|
||||
const navigationNode = this.main.node.getNavigationNode();
|
||||
if (!!navigationNode) {
|
||||
this.main.view.useCreation(navigationNode);
|
||||
return;
|
||||
}
|
||||
}
|
||||
register(modifiers, key, func) {
|
||||
return this.main.app.scope.register(modifiers, key, func);
|
||||
}
|
||||
registerAll() {
|
||||
this.hotkeys.push(
|
||||
this.register([], "f", this.focusNode),
|
||||
this.register([], "Tab", this.main.node.createChildren),
|
||||
this.register([], "enter", this.main.node.createSibNode),
|
||||
this.register(["Shift"], "enter", this.main.node.createSibNode),
|
||||
this.register(["Alt"], "arrowLeft", this.nodeNavigation),
|
||||
this.register(["Alt"], "arrowRight", this.nodeNavigation),
|
||||
this.register(["Alt"], "arrowUp", this.nodeNavigation),
|
||||
this.register(["Alt"], "arrowDown", this.nodeNavigation)
|
||||
// this.register([], 'h', this.help)
|
||||
);
|
||||
}
|
||||
unregisterAll() {
|
||||
this.hotkeys.forEach((key) => this.main.app.scope.unregister(key));
|
||||
}
|
||||
};
|
||||
__decorateClass([
|
||||
debounce()
|
||||
], Keymap.prototype, "help", 1);
|
||||
Keymap = __decorateClass([
|
||||
autobind
|
||||
], Keymap);
|
||||
|
||||
// src/module/view.ts
|
||||
var View = class {
|
||||
constructor(main) {
|
||||
this.main = main;
|
||||
}
|
||||
isTouching() {
|
||||
return this.main.node.getSelection().size === 0;
|
||||
}
|
||||
isNavigating() {
|
||||
const node = this.main.node.getSingleSelection();
|
||||
if (!node)
|
||||
return false;
|
||||
return node.isFocused && !node.isEditing;
|
||||
}
|
||||
isCreating() {
|
||||
const node = this.main.node.getSingleSelection();
|
||||
if (!node)
|
||||
return false;
|
||||
return node.isFocused && node.isEditing;
|
||||
}
|
||||
useTouch() {
|
||||
this.main.canvas.deselectAll();
|
||||
}
|
||||
useCreation(node) {
|
||||
setTimeout(
|
||||
() => node.startEditing(),
|
||||
this.main.setting.MACRO_TASK_DELAY
|
||||
);
|
||||
}
|
||||
creation2Navigation() {
|
||||
const selection = this.main.node.getSingleSelection();
|
||||
if (!selection || !this.isCreating())
|
||||
return;
|
||||
selection.blur();
|
||||
selection.focus();
|
||||
}
|
||||
touch2Navigation() {
|
||||
const viewportBBox = this.main.canvas.getViewportBBox();
|
||||
const centerPoint = [
|
||||
(viewportBBox.minX + viewportBBox.maxX) / 2,
|
||||
(viewportBBox.minY + viewportBBox.maxY) / 2
|
||||
];
|
||||
const viewportNodes = this.main.canvas.getViewportNodes();
|
||||
const res = findClosestNodeByBbox(centerPoint, viewportNodes);
|
||||
this.zoomToNode(res.node);
|
||||
}
|
||||
zoomToNode(node) {
|
||||
this.main.canvas.selectOnly(node);
|
||||
this.main.canvas.zoomToSelection();
|
||||
if (this.main.config.autoFocus) {
|
||||
this.useCreation(node);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// src/module/setting.ts
|
||||
var import_obsidian = require("obsidian");
|
||||
var DEFAULT_SETTINGS = {
|
||||
autoFocus: false
|
||||
};
|
||||
var Setting = class extends import_obsidian.PluginSettingTab {
|
||||
constructor(main) {
|
||||
super(main.app, main);
|
||||
this.ROW_GAP = 20;
|
||||
this.COLUMN_GAP = 200;
|
||||
this.autoFocus = false;
|
||||
this.MACRO_TASK_DELAY = 50;
|
||||
this.EPSILON = 1;
|
||||
this.OFFSET_WEIGHT = 1.1;
|
||||
this.main = main;
|
||||
console.log("setting");
|
||||
}
|
||||
display() {
|
||||
const { containerEl } = this;
|
||||
containerEl.empty();
|
||||
containerEl.createEl("h3", { text: "\u{1F6A7}\u{1F6A7}\u{1F6A7}" });
|
||||
containerEl.createEl("h3", { text: "The page is under development" });
|
||||
containerEl.createEl("h3", { text: "Most settings are out-of-the-box" });
|
||||
this.addAutoFocus();
|
||||
}
|
||||
addAutoFocus() {
|
||||
new import_obsidian.Setting(this.containerEl).setName("autoFocus").setDesc("auto focus node when create new node").addToggle(
|
||||
(component) => component.setValue(this.main.config.autoFocus).onChange(async (open) => {
|
||||
this.main.config.autoFocus = open;
|
||||
await this.main.saveData(this.main.config);
|
||||
})
|
||||
);
|
||||
}
|
||||
async loadSettings() {
|
||||
this.main.config = { ...DEFAULT_SETTINGS, ...await this.main.loadData() };
|
||||
}
|
||||
};
|
||||
|
||||
// src/module/layout.ts
|
||||
var Layout = class {
|
||||
constructor(main) {
|
||||
this.main = main;
|
||||
}
|
||||
useSide(parent, child) {
|
||||
const { ROW_GAP, COLUMN_GAP } = this.main.setting;
|
||||
const bbox = child.reduce((prev, node, idx) => {
|
||||
return idx > 0 ? {
|
||||
height: prev.height + node.height + ROW_GAP,
|
||||
heightNodes: prev.heightNodes.concat(node.height)
|
||||
} : {
|
||||
height: prev.height + node.height,
|
||||
heightNodes: prev.heightNodes.concat(node.height)
|
||||
};
|
||||
}, {
|
||||
height: 0,
|
||||
heightNodes: []
|
||||
});
|
||||
const top = parent.y + parent.height * 0.5 - bbox.height * 0.5;
|
||||
const getSum = (arr) => arr.reduce((sum, cur) => sum + cur, 0);
|
||||
child.sort((a, b) => a.y - b.y).forEach((node, i) => {
|
||||
node.moveTo({
|
||||
x: parent.width + parent.x + COLUMN_GAP,
|
||||
y: top + ROW_GAP * i + getSum(bbox.heightNodes.slice(0, i))
|
||||
});
|
||||
});
|
||||
}
|
||||
useSurround() {
|
||||
}
|
||||
};
|
||||
|
||||
// src/main.ts
|
||||
var LovelyMindmap = class extends import_obsidian2.Plugin {
|
||||
constructor(app2, manifest) {
|
||||
super(app2, manifest);
|
||||
this.canvas = null;
|
||||
this.intervalTimer = /* @__PURE__ */ new Map();
|
||||
this.node = new Node(this);
|
||||
this.keymap = new Keymap(this);
|
||||
this.view = new View(this);
|
||||
this.setting = new Setting(this);
|
||||
this.layout = new Layout(this);
|
||||
}
|
||||
createCanvasInstance() {
|
||||
const timer = setInterval(() => {
|
||||
var _a, _b;
|
||||
this.canvas = (_b = (_a = app.workspace.getLeavesOfType("canvas").first()) == null ? void 0 : _a.view) == null ? void 0 : _b.canvas;
|
||||
if (!!this.canvas) {
|
||||
clearInterval(this.intervalTimer.get("canvas"));
|
||||
}
|
||||
}, 1e3);
|
||||
if (!this.intervalTimer.get("canvas")) {
|
||||
this.intervalTimer.set("canvas", timer);
|
||||
}
|
||||
}
|
||||
async onload() {
|
||||
await this.setting.loadSettings();
|
||||
this.addSettingTab(new Setting(this));
|
||||
this.keymap.registerAll();
|
||||
this.createCanvasInstance();
|
||||
this.addCommand({
|
||||
id: "blurNode",
|
||||
name: "Blur node",
|
||||
hotkeys: [
|
||||
{
|
||||
modifiers: ["Mod"],
|
||||
key: "Escape"
|
||||
}
|
||||
],
|
||||
checkCallback: () => this.keymap.blurNode()
|
||||
});
|
||||
}
|
||||
onunload() {
|
||||
this.keymap.unregisterAll();
|
||||
this.intervalTimer.forEach(clearInterval);
|
||||
}
|
||||
};
|
15
.obsidian/plugins/lovely-mindmap/manifest.json
vendored
Normal file
15
.obsidian/plugins/lovely-mindmap/manifest.json
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"id": "lovely-mindmap",
|
||||
"name": "Lovely-Mindmap",
|
||||
"version": "1.0.1",
|
||||
"minAppVersion": "0.15.0",
|
||||
"description": "Build your own knowledge graph with smiles :-)",
|
||||
"author": "shaun",
|
||||
"authorUrl": "https://github.com/xincan1949",
|
||||
"fundingUrl": {
|
||||
"By Me a Coffee": "https://www.buymeacoffee.com/xincan1949",
|
||||
"支付宝": "https://cdn.jsdelivr.net/gh/xincan1949/xincan1949.github.io@master/Alipay.jpeg",
|
||||
"微信": "https://cdn.jsdelivr.net/gh/xincan1949/xincan1949.github.io@master/WeChatPay.png"
|
||||
},
|
||||
"isDesktopOnly": false
|
||||
}
|
Reference in New Issue
Block a user