From fa44224c9c143517f8937d2acbdd9f6f9e308eb4 Mon Sep 17 00:00:00 2001 From: Zsolt Viczian Date: Fri, 6 May 2022 20:38:59 +0200 Subject: [PATCH] 0.0.3 --- manifest.json | 2 +- src/Components/ToggleButton.ts | 40 +++++++++ src/Scene.ts | 23 +++--- src/Suggesters/SearchBox.ts | 44 ---------- src/Suggesters/ToolsPanel.ts | 145 +++++++++++++++++++++++++++++++++ src/lang/locale/en.ts | 9 +- src/main.ts | 8 +- src/utils/dataview.ts | 2 +- styles.css | 26 ++++++ 9 files changed, 237 insertions(+), 62 deletions(-) create mode 100644 src/Components/ToggleButton.ts delete mode 100644 src/Suggesters/SearchBox.ts create mode 100644 src/Suggesters/ToolsPanel.ts diff --git a/manifest.json b/manifest.json index 6119e6f..6b94ede 100644 --- a/manifest.json +++ b/manifest.json @@ -1,7 +1,7 @@ { "id": "excalibrain", "name": "ExcaliBrain", - "version": "0.0.2", + "version": "0.0.3", "minAppVersion": "0.14.0", "description": "A clean, intuitive and editable graph view for Obsidian", "author": "Zsolt Viczian", diff --git a/src/Components/ToggleButton.ts b/src/Components/ToggleButton.ts new file mode 100644 index 0000000..f87a8b0 --- /dev/null +++ b/src/Components/ToggleButton.ts @@ -0,0 +1,40 @@ +import ExcaliBrain from "src/main"; + +export class ToggleButton { + private button: HTMLButtonElement; + + constructor( + plugin: ExcaliBrain, + private getVal: ()=>boolean, + setVal: (val:boolean)=>void, + wrapper: HTMLElement, + options: { + display: string, + tooltip: string + }) { + this.button = wrapper.createEl("button", { + cls: "excalibrain-button", + }); + this.button.createSpan({text: options.display}) + this.button.ariaLabel = options.tooltip; + + this.setColor(); + + this.button.onclick = () => { + setVal(!getVal()); + plugin.saveSettings(); + this.setColor(); + plugin.scene?.reRender(); + } + } + + setColor() { + if(this.getVal()) { + this.button.removeClass("off"); + this.button.addClass("on"); + return; + } + this.button.removeClass("on"); + this.button.addClass("off"); + } +} \ No newline at end of file diff --git a/src/Scene.ts b/src/Scene.ts index f15f705..98ce26e 100644 --- a/src/Scene.ts +++ b/src/Scene.ts @@ -6,10 +6,9 @@ import { Links } from "./graph/Links"; import { Node } from "./graph/Node"; import ExcaliBrain from "./main"; import { ExcaliBrainSettings } from "./Settings"; -import { SearchBox } from "./Suggesters/SearchBox"; +import { ToolsPanel } from "./Suggesters/ToolsPanel"; import { Neighbour, RelationType, Role } from "./Types"; - export class Scene { settings: ExcaliBrainSettings; ea: ExcalidrawAutomate; @@ -29,7 +28,7 @@ export class Scene { private removeEH: Function; private removeTimer: Function; private blockUpdateTimer: boolean = false; - private searchBox: SearchBox; + private toolsPanel: ToolsPanel; constructor(plugin: ExcaliBrain, newLeaf: boolean, leaf?: WorkspaceLeaf) { this.settings = plugin.settings; @@ -43,7 +42,7 @@ export class Scene { public async initialize() { await this.initilizeScene(); - this.searchBox = new SearchBox((this.leaf.view as TextFileView).contentEl,this.plugin); + this.toolsPanel = new ToolsPanel((this.leaf.view as TextFileView).contentEl,this.plugin); } /** @@ -68,6 +67,7 @@ export class Scene { } await this.plugin.createIndex(); //temporary await this.render(); + this.toolsPanel.rerender(); } /** @@ -150,9 +150,9 @@ export class Scene { const ea = this.ea; const style = this.settings.baseNodeStyle; let counter = 0; - - ea.setView(this.leaf.view as any) ea.clear(); + + ea.setView(this.leaf.view as any) counter = 0; while(!ea.targetView.excalidrawAPI && counter++<10) { await sleep(50); @@ -186,7 +186,8 @@ export class Scene { ea.style.strokeColor = style.textColor; ea.addText(0,0,"Open a document in another pane and click it to get started.\n\n" + "For the best experience enable 'Open in adjacent pane'\nin Excalidraw settings " + - "under 'Links and Transclusion'.", {textAlign:"center"}); + "under 'Links and Transclusion'.\n\nNote, that ExcaliBrain may need to wait for " + + "DataView to initialize its index,\nwhich can take up to a few minutes after starting Obsidian.", {textAlign:"center"}); await ea.addElementsToView(); ea.getExcalidrawAPI().zoomToFit(null, 5); @@ -488,14 +489,14 @@ export class Scene { this.ea.targetView.excalidrawAPI.updateScene({appState:{viewModeEnabled:false}}); } catch {} } - - if(this.ea.targetView) { + //@ts-ignore + if(this.ea.targetView && this.ea.targetView._loaded) { try { this.ea.deregisterThisAsViewEA(); } catch {} } - this.searchBox?.terminate(); - this.searchBox = undefined; + this.toolsPanel?.terminate(); + this.toolsPanel = undefined; this.ea.targetView = undefined; this.leaf = undefined; this.centralLeaf = undefined; diff --git a/src/Suggesters/SearchBox.ts b/src/Suggesters/SearchBox.ts deleted file mode 100644 index 33ce4d5..0000000 --- a/src/Suggesters/SearchBox.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { TFile } from "obsidian"; -import ExcaliBrain from "src/main"; -import { Scene } from "src/Scene"; -import { FileSuggest } from "./FileSuggester"; - -export class SearchBox { - private wrapperDiv: HTMLDivElement; - - constructor( - private contentEl: HTMLElement, - private plugin: ExcaliBrain - ) { - contentEl.addClass("excalibrain-contentEl"); - this.wrapperDiv = this.contentEl.createDiv(); - this.wrapperDiv.addClass("excalibrain-search-wrapper"); - const inputEl = this.wrapperDiv.createEl("input",{type: "text"}); - inputEl.style.width = "400px"; - - inputEl.oninput = () => { - const file = app.vault.getAbstractFileByPath(inputEl.value); - if(file && file instanceof TFile) { - this.plugin.scene?.renderGraphForFile(inputEl.value); - inputEl.value = file.basename; - } - } - - new FileSuggest( - this.plugin.app, - inputEl, - this.plugin - ); - this.contentEl.appendChild(this.wrapperDiv); - - } - - terminate() { - if(this.wrapperDiv) { - try{ - this.contentEl?.removeChild(this.wrapperDiv); - } catch{} - this.wrapperDiv = null; - } - } -} \ No newline at end of file diff --git a/src/Suggesters/ToolsPanel.ts b/src/Suggesters/ToolsPanel.ts new file mode 100644 index 0000000..5a02c0e --- /dev/null +++ b/src/Suggesters/ToolsPanel.ts @@ -0,0 +1,145 @@ +import { TFile } from "obsidian"; +import { ExcalidrawElement } from "obsidian-excalidraw-plugin"; +import { ToggleButton } from "src/Components/ToggleButton"; +import { t } from "src/lang/helpers"; +import ExcaliBrain from "src/main"; +import { splitFolderAndFilename } from "src/utils/fileUtils"; +import { FileSuggest } from "./FileSuggester"; + +export class ToolsPanel { + private wrapperDiv: HTMLDivElement; + private buttons: ToggleButton[] = []; + + constructor( + private contentEl: HTMLElement, + private plugin: ExcaliBrain + ) { + contentEl.addClass("excalibrain-contentEl"); + this.wrapperDiv = this.contentEl.createDiv(); + this.wrapperDiv.addClass("excalibrain-search-wrapper"); + + //------ + //search + //------ + const inputEl = this.wrapperDiv.createEl("input",{ + type: "text", + cls: "excalibrain-searchinput" + }); + inputEl.ariaLabel = t("SEARCH_IN_VAULT"); + inputEl.oninput = () => { + const file = app.vault.getAbstractFileByPath(inputEl.value); + if(file && file instanceof TFile) { + this.plugin.scene?.renderGraphForFile(inputEl.value); + inputEl.value = file.basename; + } + } + new FileSuggest( + this.plugin.app, + inputEl, + this.plugin + ); + + + //------------ + //Edit drawing + //------------ + const saveAsDrawingButton = this.wrapperDiv.createEl("button", { + cls: "excalibrain-button", + text: "✏" + }); + saveAsDrawingButton.ariaLabel = t("OPEN_DRAWING"); + saveAsDrawingButton.onclick = () => { + const elements = this.plugin.EA.getExcalidrawAPI().getSceneElements() as ExcalidrawElement[]; + const appState = this.plugin.EA.getExcalidrawAPI().getAppState(); + const ea = this.plugin.EA; //window.ExcalidrawAutomate; + ea.reset(); + ea.canvas.viewBackgroundColor = appState.viewBackgroundColor; + ea.canvas.theme = "light"; + elements.forEach(el=>ea.elementsDict[el.id] = el); + ea.create({ + filename: `ExcaliBrain Snapshot - ${splitFolderAndFilename(this.plugin.scene.centralPagePath).basename}`, + onNewPane:true + }); + } + + //------------ + //Attachments + //------------ + this.buttons.push( + new ToggleButton( + this.plugin, + ()=>this.plugin.settings.showAttachments, + (val:boolean)=>this.plugin.settings.showAttachments = val, + this.wrapperDiv, + { + display: "📎", + tooltip: t("SHOW_HIDE_ATTACHMENTS") + } + ) + ) + + //------------ + //Virtual + //------------ + this.buttons.push( + new ToggleButton( + this.plugin, + ()=>this.plugin.settings.showVirtualNodes, + (val:boolean)=>this.plugin.settings.showVirtualNodes = val, + this.wrapperDiv, + { + display: "∅", + tooltip: t("SHOW_HIDE_VIRTUAL") + } + ) + ) + + //------------ + //Inferred + //------------ + this.buttons.push( + new ToggleButton( + this.plugin, + ()=>this.plugin.settings.showInferredNodes, + (val:boolean)=>this.plugin.settings.showInferredNodes = val, + this.wrapperDiv, + { + display: "🤔", + tooltip: t("SHOW_HIDE_INFERRED") + } + ) + ) + + //------------ + //Alias + //------------ + this.buttons.push( + new ToggleButton( + this.plugin, + ()=>this.plugin.settings.renderAlias, + (val:boolean)=>this.plugin.settings.renderAlias = val, + this.wrapperDiv, + { + display: "🧥", + tooltip: t("SHOW_HIDE_ALIAS") + } + ) + ) + + this.contentEl.appendChild(this.wrapperDiv); + + } + + rerender() { + this.buttons.forEach(b=>b.setColor()); + } + + terminate() { + if(this.wrapperDiv) { + try{ + this.contentEl?.removeChild(this.wrapperDiv); + } catch{} + this.wrapperDiv = null; + } + } +} \ No newline at end of file diff --git a/src/lang/locale/en.ts b/src/lang/locale/en.ts index 6ae33d0..2b1d53e 100644 --- a/src/lang/locale/en.ts +++ b/src/lang/locale/en.ts @@ -88,5 +88,12 @@ export default { DATAVIEW_NOT_FOUND: `Dataview plugin not found. Please install or enable Dataview, then try restarting ${APPNAME}`, EXCALIDRAW_NOT_FOUND: `Excalidraw plugin not found. Please install or enable Excalidraw, then try restarting ${APPNAME}`, EXCALIDRAW_MINAPP_VERSION: `ExcaliBrain requires Excalidraw ${MINEXCALIDRAWVERSION} or higher. Please upgrade Excalidraw`, - COMMAND_START: "Open ExcaliBrain" + COMMAND_START: "Open ExcaliBrain", + //ToolsPanel + OPEN_DRAWING: "Save snapshot for editing", + SEARCH_IN_VAULT: "Search for a file in your Vault", + SHOW_HIDE_ATTACHMENTS: "Show/Hide attachments", + SHOW_HIDE_VIRTUAL: "Show/Hide virtual nodes", + SHOW_HIDE_INFERRED: "Show/Hide inferred nodes", + SHOW_HIDE_ALIAS: "Show/Hide document alias", } \ No newline at end of file diff --git a/src/main.ts b/src/main.ts index 626c629..8b5548d 100644 --- a/src/main.ts +++ b/src/main.ts @@ -78,7 +78,7 @@ export default class ExcaliBrain extends Plugin { this.DVAPI.index.importer.reloadQueue.length > 0 ) { if(counter++ % 100 === 10) { - new Notice("ExcaliBrain is waiting for Dataview initialization",1000); + new Notice("ExcaliBrain is waiting for Dataview to update its index",1000); } await sleep(100); } @@ -296,6 +296,9 @@ export default class ExcaliBrain extends Plugin { } public async start(leaf: WorkspaceLeaf) { + if(!leaf.view) { + return; + } let counter = 0; while(!this.pluginLoaded && counter++<100) await sleep(50); if(!this.pluginLoaded) { @@ -303,9 +306,6 @@ export default class ExcaliBrain extends Plugin { errorlog({where: "ExcaliBrain.start()", fn: this.start, message: "ExcaliBrain did not load. Aborting after 5000ms of trying"}); return; } - if(counter<4) { //sleep as a temp workaround for a race condition starting Excalidraw - while(counter++<8) await sleep(50); - } this.stop(); if(!leaf) { await Scene.openExcalidrawLeaf(window.ExcalidrawAutomate,this.settings,this.getBrainLeaf()); diff --git a/src/utils/dataview.ts b/src/utils/dataview.ts index 1169d0d..cb07250 100644 --- a/src/utils/dataview.ts +++ b/src/utils/dataview.ts @@ -13,7 +13,7 @@ const readDVField = (app: App, field: any, file:TFile):string[] => { //the field is a list of links if(field.values) { field.values.forEach((l:any)=>{ - if(l.type === "file") { + if(l.type === "file" || l.type === "header") { const path = getPathOrSelf(app, l.path,file.path); if(path) { res.add(path); diff --git a/styles.css b/styles.css index 0474978..4083be3 100644 --- a/styles.css +++ b/styles.css @@ -36,4 +36,30 @@ position: absolute; top: 10px; left: 10px; +} + +.excalibrain-button { + vertical-align: middle; + padding-left: 5px; + padding-right: 5px; + margin-left: 5px; + margin-right: 0px; + width: 2em; +} + +.excalibrain-button span { + text-align: center; +} + +.excalibrain-button.off { + background-color: var(--interactive-normal); +} + +.excalibrain-button.on { + background-color: var(--interactive-accent); +} + +.excalibrain-searchinput { + width: 400px; + vertical-align: middle; } \ No newline at end of file