diff --git a/package-lock.json b/package-lock.json index 3ffdaaa..ebd93c4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -28,7 +28,7 @@ "eslint-config-prettier": "8.3.0", "eslint-plugin-prettier": "^4.0.0", "obsidian": "^0.14.6", - "obsidian-excalidraw-plugin": "1.6.26-6", + "obsidian-excalidraw-plugin": "1.6.26-10", "prettier": "^2.5.1", "rollup": "^2.70.1", "rollup-plugin-terser": "^7.0.2", @@ -12546,9 +12546,9 @@ "integrity": "sha512-xAEnNCT3w2Tg6MA7ly6QqYJvEoY1tm9iIjJ3yMKK9JPlWuRHAMoe5iETwQnx3M9TVbFMfsrBgWKR+IsmswwNjg==" }, "node_modules/obsidian-excalidraw-plugin": { - "version": "1.6.26-6", - "resolved": "https://registry.npmjs.org/obsidian-excalidraw-plugin/-/obsidian-excalidraw-plugin-1.6.26-6.tgz", - "integrity": "sha512-2bBQP/ZchVkcuVF3MzAYU4nDzO08pOWLNmy7bGmzoYvkG+fX/s+3jYjBjVPZSXnyfwo1iXfyYiKMA8ngwCPwgA==", + "version": "1.6.26-10", + "resolved": "https://registry.npmjs.org/obsidian-excalidraw-plugin/-/obsidian-excalidraw-plugin-1.6.26-10.tgz", + "integrity": "sha512-CJml0ibqB/kLx8xXKld89TCANaKZhPxVCZg4/CWZL5ANuLOPtOE4S+GywHVE4yor7ruV0QmQgumpoNWOte0C0A==", "dev": true, "dependencies": { "@types/lz-string": "^1.3.34", @@ -26986,9 +26986,9 @@ } }, "obsidian-excalidraw-plugin": { - "version": "1.6.26-6", - "resolved": "https://registry.npmjs.org/obsidian-excalidraw-plugin/-/obsidian-excalidraw-plugin-1.6.26-6.tgz", - "integrity": "sha512-2bBQP/ZchVkcuVF3MzAYU4nDzO08pOWLNmy7bGmzoYvkG+fX/s+3jYjBjVPZSXnyfwo1iXfyYiKMA8ngwCPwgA==", + "version": "1.6.26-10", + "resolved": "https://registry.npmjs.org/obsidian-excalidraw-plugin/-/obsidian-excalidraw-plugin-1.6.26-10.tgz", + "integrity": "sha512-CJml0ibqB/kLx8xXKld89TCANaKZhPxVCZg4/CWZL5ANuLOPtOE4S+GywHVE4yor7ruV0QmQgumpoNWOte0C0A==", "dev": true, "requires": { "@types/lz-string": "^1.3.34", diff --git a/package.json b/package.json index e25f655..3ea5951 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,7 @@ "@popperjs/core": "^2.11.2" }, "devDependencies": { - "obsidian-excalidraw-plugin": "1.6.26-6", + "obsidian-excalidraw-plugin": "1.6.26-10", "@babel/core": "^7.16.12", "@babel/preset-env": "^7.16.11", "@babel/preset-react": "^7.16.7", diff --git a/src/Scene.ts b/src/Scene.ts index 37c7f05..b1cfcdb 100644 --- a/src/Scene.ts +++ b/src/Scene.ts @@ -8,6 +8,7 @@ import ExcaliBrain from "./main"; import { ExcaliBrainSettings } from "./Settings"; import { SearchBox } from "./Suggesters/SearchBox"; import { Neighbour, RelationType, Role } from "./Types"; +import { log } from "./utils/utils"; export class Scene { settings: ExcaliBrainSettings; @@ -31,6 +32,7 @@ export class Scene { private searchBox: SearchBox; constructor(plugin: ExcaliBrain, newLeaf: boolean, leaf?: WorkspaceLeaf) { + log("construct scene"); this.settings = plugin.settings; this.ea = plugin.EA; this.plugin = plugin; @@ -40,6 +42,7 @@ export class Scene { } public async initialize() { + log("initialize"); await this.initilizeScene(); this.searchBox = new SearchBox((this.leaf.view as TextFileView).contentEl,this.plugin); } @@ -50,7 +53,7 @@ export class Scene { */ public isActive() { //@ts-ignore - return !this.terminated && app.workspace.getLeafById(this._instance.leaf?.id) + return !this.terminated && app.workspace.getLeafById(this.leaf?.id) } /** @@ -113,16 +116,16 @@ export class Scene { await this.render(); } - public async initilizeScene() { - this.disregardLeafChange = false; + public async openExcalidrawLeaf() { + log("openExcalidrawLeaf") const ea = this.ea; - const style = this.settings.baseNodeStyle; + let counter = 0; + let file = this.app.vault.getAbstractFileByPath(this.settings.excalibrainFilepath); if(file && !(file instanceof TFile)) { new Notice(`Please check settings. ExcaliBrain path (${this.settings.excalibrainFilepath}) points to a folder, not a file`); return; } - let counter = 0; if(!file) { file = await app.vault.create(this.settings.excalibrainFilepath,EMPTYBRAIN); //an ugly temporary hack waiting for metadataCache to index the new file @@ -143,6 +146,13 @@ export class Scene { } } await this.leaf.openFile(file as TFile); + } + + public async initilizeScene() { + this.disregardLeafChange = false; + const ea = this.ea; + const style = this.settings.baseNodeStyle; + let counter = 0; ea.setView(this.leaf.view as any) ea.clear(); @@ -154,7 +164,7 @@ export class Scene { new Notice(`Error initializing Excalidraw view`); return; } - this.ea.targetView.hookServer = this.ea; + this.ea.registerThisAsViewEA(); this.ea.targetView.semaphores.saving = true; //disable saving by setting this Excalidraw flag (not published API) ea.style.fontFamily = style.fontFamily; ea.style.fontSize = style.fontSize; @@ -216,8 +226,8 @@ export class Scene { const children =centralPage.getChildren().filter(x=>x.page.path !==centralPage.path).slice(0,this.plugin.settings.maxItemCount); const friends = centralPage.getFriends().filter(x=>x.page.path !== centralPage.path).slice(0,this.plugin.settings.maxItemCount); const siblings = centralPage.getSiblings() - .filter(s => !(parents.some(p=>p.page.path === s.page.path) && - children.some(c=>c.page.path === s.page.path) && + .filter(s => !(parents.some(p=>p.page.path === s.page.path) || + children.some(c=>c.page.path === s.page.path) || friends.some(f=>f.page.path === s.page.path)) && (s.page.path !== centralPage.path)) .slice(0,this.plugin.settings.maxItemCount); @@ -458,11 +468,11 @@ export class Scene { this.removeTimer = undefined; } - if(isBoolean(this.ea.targetView?.linksAlwaysOpenInANewPane)) { + if(this.ea.targetView && isBoolean(this.ea.targetView.linksAlwaysOpenInANewPane)) { this.ea.targetView.linksAlwaysOpenInANewPane = false; } - if(this.ea.targetView?.excalidrawAPI) { + if(this.ea.targetView && this.ea.targetView.excalidrawAPI) { try { this.ea.targetView.semaphores.saving = false; this.ea.targetView.excalidrawAPI.updateScene({appState:{viewModeEnabled:false}}); @@ -470,7 +480,7 @@ export class Scene { } if(this.ea.targetView) { - this.ea.targetView.hookServer = null; + this.ea.deregisterThisAsViewEA(); } this.searchBox?.terminate(); this.searchBox = undefined; diff --git a/src/Settings.ts b/src/Settings.ts index b502b62..10dffbd 100644 --- a/src/Settings.ts +++ b/src/Settings.ts @@ -1,4 +1,3 @@ -import { settings } from "cluster"; import { App, DropdownComponent, @@ -10,11 +9,13 @@ import { } from "obsidian"; import { FillStyle, getEA, StrokeSharpness, StrokeStyle } from "obsidian-excalidraw-plugin"; import { ExcalidrawAutomate } from "obsidian-excalidraw-plugin/lib/ExcalidrawAutomate"; +import { Page } from "./graph/Page"; import { t } from "./lang/helpers"; import ExcaliBrain from "./main"; -import { Scene } from "./Scene"; -import { Hierarchy, NodeStyle, LinkStyle } from "./Types"; +import { Hierarchy, NodeStyle, LinkStyle, RelationType, NodeStyleData } from "./Types"; import { WarningPrompt } from "./utils/Prompts"; +import { Node } from "./graph/Node"; +import { svgToBase64 } from "./utils/utils"; export interface ExcaliBrainSettings { excalibrainFilepath: string; @@ -107,6 +108,9 @@ export const DEFAULT_SETTINGS: ExcaliBrainSettings = { hierarchyStyleList: [] }; +const HIDE_DISABLED_STYLE = "excalibrain-hide-disabled"; +const HIDE_DISABLED_CLASS = "excalibrain-settings-disabled"; + const getHex = (color:string) => color.substring(0,7); const getAlphaFloat = (color:string) => parseInt(color.substring(7,9),16)/255; const getAlphaHex = (a: number) => ((a * 255) | 1 << 8).toString(16).slice(1) @@ -114,36 +118,76 @@ const getAlphaHex = (a: number) => ((a * 255) | 1 << 8).toString(16).slice(1) const fragWithHTML = (html: string) => createFragment((frag) => (frag.createDiv().innerHTML = html)); -const details = (text: string, parent: HTMLElement) => - parent.createEl("details", {}, (d) => d.createEl("summary", { text })); +const removeStylesheet = (name:string) => { + const sheetToBeRemoved = document.getElementById(name); + if(!sheetToBeRemoved) return; + const sheetParent = sheetToBeRemoved.parentNode; + if(!sheetParent) return; + sheetParent.removeChild(sheetToBeRemoved); +} + +const addStylesheet = (stylesheet: string, classname: string) => { + const sheet = document.createElement('style'); + sheet.id = stylesheet; + sheet.innerHTML = `.${classname} {display: none;}`; + document.body.appendChild(sheet); +} export class ExcaliBrainSettingTab extends PluginSettingTab { plugin: ExcaliBrain; ea: ExcalidrawAutomate; private hierarchy: string = null; private dirty:boolean = false; + private demoNode: Node; + private demoImg: HTMLImageElement; + private demoNodeStyle: NodeStyleData; constructor(app: App, plugin: ExcaliBrain) { super(app, plugin); this.plugin = plugin; this.ea = getEA(); - } - - async sampleNode(style: NodeStyle):Promise { - this.ea.canvas.viewBackgroundColor = style.backgroundColor; - return; + const page = new Page( + "This is a demo node that is 46 characters long", + null, + this.plugin + ) + const page2 = new Page( + "Dummy child", + null, + this.plugin + ) + page.addChild(page2,RelationType.DEFINED); + + this.demoNode = new Node({ + page, + isInferred: false, + isCentral: false, + isSibling: false, + friendGateOnLeft: false + }) + this.demoNode.ea = this.ea; } + async updateDemoImg() { + this.ea.reset(); + this.ea.canvas.viewBackgroundColor = this.plugin.settings.backgroundColor; + this.demoNode.style = { + ...this.demoNodeStyle.getInheritedStyle(), + ...this.demoNodeStyle.style + } + this.demoNode.render(); + const svg = await this.ea.createSVG(null,true,{withBackground:true, withTheme:false},null,"",40); + svg.removeAttribute("width"); + svg.removeAttribute("height"); + this.demoImg.setAttribute("src", svgToBase64(svg.outerHTML)); + }; + async hide() { if(!this.dirty) { return; } this.plugin.settings.tagStyleList = Object.keys(this.plugin.settings.tagNodeStyles); - if(this.hierarchy) { - this.plugin.settings.hierarchy = JSON.parse(this.hierarchy); - //this.plugin.initializeIndex(); - } this.plugin.saveSettings(); this.plugin.scene?.reRender(); } @@ -156,7 +200,8 @@ export class ExcaliBrainSettingTab extends PluginSettingTab { setValue:(val:string)=>void, deleteValue:()=>void, allowOverride: boolean, - defaultValue: string + defaultValue: string, + heading:string = "" ) { let sliderComponent: SliderComponent; let picker: HTMLInputElement; @@ -173,6 +218,11 @@ export class ExcaliBrainSettingTab extends PluginSettingTab { } const setDisabled = (isDisabled:boolean) => { + if(isDisabled) { + setting.settingEl.addClass(HIDE_DISABLED_CLASS); + } else { + setting.settingEl.removeClass(HIDE_DISABLED_CLASS); + } picker.disabled = isDisabled; picker.style.opacity = isDisabled ? "0.3" : "1"; sliderComponent.setDisabled(isDisabled); @@ -252,7 +302,8 @@ export class ExcaliBrainSettingTab extends PluginSettingTab { setValue:(val:number)=>void, deleteValue:()=>void, allowOverride: boolean, - defaultValue: number + defaultValue: number, + heading: string = "" ) { let displayText: HTMLDivElement; let toggleComponent: ToggleComponent; @@ -261,6 +312,11 @@ export class ExcaliBrainSettingTab extends PluginSettingTab { const setting = new Setting(containerEl).setName(name); const setDisabled = (isDisabled:boolean) => { + if(isDisabled) { + setting.settingEl.addClass(HIDE_DISABLED_CLASS); + } else { + setting.settingEl.removeClass(HIDE_DISABLED_CLASS); + } sliderComponent.setDisabled(isDisabled); sliderComponent.sliderEl.style.opacity = isDisabled ? "0.3" : "1"; displayText.style.opacity = isDisabled ? "0.3" : "1"; @@ -321,7 +377,8 @@ export class ExcaliBrainSettingTab extends PluginSettingTab { setValue:(val:string)=>void, deleteValue:()=>void, allowOverride: boolean, - defaultValue: string + defaultValue: string, + heading:string = "" ) { let dropdownComponent: DropdownComponent; let toggleComponent: ToggleComponent; @@ -329,6 +386,11 @@ export class ExcaliBrainSettingTab extends PluginSettingTab { const setting = new Setting(containerEl).setName(name); const setDisabled = (isDisabled:boolean) => { + if(isDisabled) { + setting.settingEl.addClass(HIDE_DISABLED_CLASS); + } else { + setting.settingEl.removeClass(HIDE_DISABLED_CLASS); + } dropdownComponent.setDisabled(isDisabled); dropdownComponent.selectEl.style.opacity = isDisabled ? "0.3" : "1"; } @@ -371,18 +433,29 @@ export class ExcaliBrainSettingTab extends PluginSettingTab { setDisabled(allowOverride && !toggleComponent.getValue()); } - nodeSettings(heading: string, setting: NodeStyle, allowOverride: boolean = true) { - const containerEl = details(heading,this.containerEl); - + nodeSettings( + containerEl: HTMLElement, + heading: string, + setting: NodeStyle, + allowOverride: boolean = true, + inheritedStyle: NodeStyle + ) { + let textComponent: TextComponent; let toggleComponent: ToggleComponent; + const prefixSetting = new Setting(containerEl) + .setName(t("NODESTYLE_PREFIX_NAME")) + .setDesc(fragWithHTML(t("NODESTYLE_PREFIX_DESC"))); + const setDisabled = (isDisabled: boolean) => { + if(isDisabled) { + prefixSetting.settingEl.addClass(HIDE_DISABLED_CLASS); + } else { + prefixSetting.settingEl.removeClass(HIDE_DISABLED_CLASS); + } textComponent.setDisabled(isDisabled); textComponent.inputEl.style.opacity = isDisabled ? "0.3": "1"; } - const prefixSetting = new Setting(containerEl) - .setName(t("NODESTYLE_PREFIX_NAME")) - .setDesc(fragWithHTML(t("NODESTYLE_PREFIX_DESC"))); if(allowOverride) { prefixSetting.addToggle(toggle => { toggleComponent = toggle; @@ -395,6 +468,7 @@ export class ExcaliBrainSettingTab extends PluginSettingTab { if(!value) { setDisabled(true); setting.prefix = undefined; + this.updateDemoImg(); return; } setDisabled(false); @@ -405,23 +479,31 @@ export class ExcaliBrainSettingTab extends PluginSettingTab { .addText(text => { textComponent = text; text - .setValue(setting.prefix??"") + .setValue(setting.prefix??inheritedStyle.prefix) .onChange(value => { setting.prefix = value; + this.updateDemoImg(); this.dirty = true; }) }) - textComponent.setDisabled(allowOverride && !toggleComponent.getValue()); + setDisabled(allowOverride && !toggleComponent.getValue()); this.colorpicker( containerEl, t("NODESTYLE_BGCOLOR"), null, ()=>setting.backgroundColor, - val=>setting.backgroundColor=val, - ()=>delete setting.backgroundColor, + val=>{ + setting.backgroundColor=val; + this.updateDemoImg(); + }, + ()=>{ + delete setting.backgroundColor; + this.updateDemoImg(); + }, allowOverride, - this.plugin.settings.baseNodeStyle.backgroundColor + inheritedStyle.backgroundColor, + heading ); this.dropdownpicker( @@ -430,10 +512,17 @@ export class ExcaliBrainSettingTab extends PluginSettingTab { null, {"hachure": "Hachure", "cross-hatch": "Cross-hatch", "solid": "Solid"}, () => setting.fillStyle?.toString(), - (val) => setting.fillStyle = val as FillStyle, - ()=>delete setting.fillStyle, + (val) => { + setting.fillStyle = val as FillStyle; + this.updateDemoImg(); + }, + ()=> { + delete setting.fillStyle; + this.updateDemoImg(); + }, allowOverride, - this.plugin.settings.baseNodeStyle.fillStyle.toString() + inheritedStyle.fillStyle.toString(), + heading ) this.colorpicker( @@ -441,10 +530,17 @@ export class ExcaliBrainSettingTab extends PluginSettingTab { t("NODESTYLE_TEXTCOLOR"), null, ()=>setting.textColor, - val=>setting.textColor=val, - ()=>delete setting.textColor, + val=> { + setting.textColor=val; + this.updateDemoImg(); + }, + ()=> { + delete setting.textColor; + this.updateDemoImg(); + }, allowOverride, - this.plugin.settings.baseNodeStyle.textColor + inheritedStyle.textColor, + heading ); this.colorpicker( @@ -452,10 +548,17 @@ export class ExcaliBrainSettingTab extends PluginSettingTab { t("NODESTYLE_BORDERCOLOR"), null, ()=>setting.borderColor, - val=>setting.borderColor=val, - ()=>delete setting.borderColor, + val=> { + setting.borderColor=val; + this.updateDemoImg(); + }, + ()=> { + delete setting.borderColor; + this.updateDemoImg(); + }, allowOverride, - this.plugin.settings.baseNodeStyle.borderColor + inheritedStyle.borderColor, + heading ); this.numberslider( @@ -464,10 +567,17 @@ export class ExcaliBrainSettingTab extends PluginSettingTab { null, {min:10,max:50,step:5}, () => setting.fontSize, - (val) => setting.fontSize = val, - ()=>delete setting.fontSize, + (val) => { + setting.fontSize = val; + this.updateDemoImg(); + }, + ()=> { + delete setting.fontSize; + this.updateDemoImg(); + }, allowOverride, - this.plugin.settings.baseNodeStyle.fontSize + inheritedStyle.fontSize, + heading ) this.dropdownpicker( @@ -476,10 +586,17 @@ export class ExcaliBrainSettingTab extends PluginSettingTab { null, {1:"Hand-drawn",2:"Normal",3:"Code",4:"Fourth (custom) Font"}, () => setting.fontFamily?.toString(), - (val) => setting.fontFamily = parseInt(val), - ()=>delete setting.fontFamily, + (val) => { + setting.fontFamily = parseInt(val); + this.updateDemoImg(); + }, + ()=> { + delete setting.fontFamily; + this.updateDemoImg(); + }, allowOverride, - this.plugin.settings.baseNodeStyle.fontFamily.toString() + inheritedStyle.fontFamily.toString(), + heading ) this.numberslider( @@ -488,10 +605,17 @@ export class ExcaliBrainSettingTab extends PluginSettingTab { t("NODESTYLE_MAXLABELLENGTH_DESC"), {min:15,max:100,step:5}, () => setting.maxLabelLength, - (val) => setting.maxLabelLength = val, - ()=>delete setting.maxLabelLength, + (val) => { + setting.maxLabelLength = val; + this.updateDemoImg(); + }, + ()=> { + delete setting.maxLabelLength; + this.updateDemoImg(); + }, allowOverride, - this.plugin.settings.baseNodeStyle.maxLabelLength + inheritedStyle.maxLabelLength, + heading ) this.dropdownpicker( @@ -500,10 +624,17 @@ export class ExcaliBrainSettingTab extends PluginSettingTab { null, {0:"Architect",1:"Artist",2:"Cartoonist"}, () => setting.roughness?.toString(), - (val) => setting.roughness = parseInt(val), - ()=>delete setting.roughness, + (val) => { + setting.roughness = parseInt(val); + this.updateDemoImg(); + }, + ()=> { + delete setting.roughness; + this.updateDemoImg(); + }, allowOverride, - this.plugin.settings.baseNodeStyle.toString() + inheritedStyle.toString(), + heading ) this.dropdownpicker( @@ -512,10 +643,17 @@ export class ExcaliBrainSettingTab extends PluginSettingTab { null, {"sharp":"Sharp","round":"Round"}, () => setting.strokeShaprness, - (val) => setting.strokeShaprness = val as StrokeSharpness, - ()=>delete setting.strokeShaprness, + (val) => { + setting.strokeShaprness = val as StrokeSharpness; + this.updateDemoImg(); + }, + ()=> { + delete setting.strokeShaprness; + this.updateDemoImg(); + }, allowOverride, - this.plugin.settings.baseNodeStyle.strokeShaprness + inheritedStyle.strokeShaprness, + heading ) this.numberslider( @@ -524,10 +662,17 @@ export class ExcaliBrainSettingTab extends PluginSettingTab { null, {min:0.5,max:6,step:0.5}, () => setting.strokeWidth, - (val) => setting.strokeWidth = val, - ()=>delete setting.strokeWidth, + (val) => { + setting.strokeWidth = val; + this.updateDemoImg(); + }, + ()=> { + delete setting.strokeWidth; + this.updateDemoImg(); + }, allowOverride, - this.plugin.settings.baseNodeStyle.strokeWidth + inheritedStyle.strokeWidth, + heading ) this.dropdownpicker( @@ -536,10 +681,17 @@ export class ExcaliBrainSettingTab extends PluginSettingTab { null, {"solid":"Solid","dashed":"Dashed","dotted":"Dotted"}, () => setting.strokeStyle, - (val) => setting.strokeStyle = val as StrokeStyle, - ()=>delete setting.strokeStyle, + (val) => { + setting.strokeStyle = val as StrokeStyle; + this.updateDemoImg(); + }, + ()=> { + delete setting.strokeStyle; + this.updateDemoImg(); + }, allowOverride, - this.plugin.settings.baseNodeStyle.strokeStyle + inheritedStyle.strokeStyle, + heading ) this.numberslider( @@ -548,10 +700,17 @@ export class ExcaliBrainSettingTab extends PluginSettingTab { null, {min:5,max:50,step:5}, () => setting.padding, - (val) => setting.padding = val, - ()=>delete setting.padding, + (val) => { + setting.padding = val; + this.updateDemoImg(); + }, + ()=> { + delete setting.padding; + this.updateDemoImg(); + }, allowOverride, - this.plugin.settings.baseNodeStyle.padding + inheritedStyle.padding, + heading ) @@ -561,10 +720,17 @@ export class ExcaliBrainSettingTab extends PluginSettingTab { t("NODESTYLE_GATE_RADIUS_DESC"), {min:3,max:10,step:1}, () => setting.gateRadius, - (val) => setting.gateRadius = val, - ()=>delete setting.gateRadius, + (val) => { + setting.gateRadius = val; + this.updateDemoImg(); + }, + ()=> { + delete setting.gateRadius; + this.updateDemoImg(); + }, allowOverride, - this.plugin.settings.baseNodeStyle.gateRadius + inheritedStyle.gateRadius, + heading ) this.numberslider( @@ -573,10 +739,17 @@ export class ExcaliBrainSettingTab extends PluginSettingTab { t("NODESTYLE_GATE_OFFSET_DESC"), {min:0,max:25,step:1}, () => setting.gateOffset, - (val) => setting.gateOffset = val, - ()=>delete setting.gateOffset, + (val) => { + setting.gateOffset = val; + this.updateDemoImg(); + }, + ()=> { + delete setting.gateOffset; + this.updateDemoImg(); + }, allowOverride, - this.plugin.settings.baseNodeStyle.gateOffset + inheritedStyle.gateOffset, + heading ) this.colorpicker( @@ -584,10 +757,17 @@ export class ExcaliBrainSettingTab extends PluginSettingTab { t("NODESTYLE_GATE_COLOR"), null, ()=>setting.gateStrokeColor, - val=>setting.gateStrokeColor=val, - ()=>delete setting.gateStrokeColor, + val=> { + setting.gateStrokeColor=val; + this.updateDemoImg(); + }, + ()=> { + delete setting.gateStrokeColor; + this.updateDemoImg(); + }, allowOverride, - this.plugin.settings.baseNodeStyle.gateStrokeColor + inheritedStyle.gateStrokeColor, + heading ); this.colorpicker( @@ -595,10 +775,17 @@ export class ExcaliBrainSettingTab extends PluginSettingTab { t("NODESTYLE_GATE_BGCOLOR_NAME"), t("NODESTYLE_GATE_BGCOLOR_DESC"), ()=>setting.gateBackgroundColor, - val=>setting.gateBackgroundColor=val, - ()=>delete setting.gateBackgroundColor, + val=> { + setting.gateBackgroundColor=val; + this.updateDemoImg(); + }, + ()=> { + delete setting.gateBackgroundColor; + this.updateDemoImg(); + }, allowOverride, - this.plugin.settings.baseNodeStyle.gateBackgroundColor + inheritedStyle.gateBackgroundColor, + heading ); this.dropdownpicker( @@ -607,10 +794,17 @@ export class ExcaliBrainSettingTab extends PluginSettingTab { null, {"hachure": "Hachure", "cross-hatch": "Cross-hatch", "solid": "Solid"}, () => setting.gateFillStyle?.toString(), - (val) => setting.gateFillStyle = val as FillStyle, - ()=>delete setting.gateFillStyle, + (val) => { + setting.gateFillStyle = val as FillStyle; + this.updateDemoImg(); + }, + ()=> { + delete setting.gateFillStyle; + this.updateDemoImg(); + }, allowOverride, - this.plugin.settings.baseNodeStyle.gateFillStyle.toString() + inheritedStyle.gateFillStyle.toString(), + heading ) } @@ -662,50 +856,53 @@ export class ExcaliBrainSettingTab extends PluginSettingTab { .inputEl.onblur = () => {text.setValue(this.plugin.settings.excalibrainFilepath)} ) - const malformedJSON = containerEl.createEl("p", { text: t("JSON_MALFORMED"), cls:"excalibrain-warning" }); - malformedJSON.hide(); + this.containerEl.createEl("h1", { + cls: "excalibrain-settings-h1", + text: t("HIERARCHY_HEAD") + }); + const hierarchyDesc = this.containerEl.createEl("p", {}); + hierarchyDesc.innerHTML = t("HIERARCHY_DESC"); + new Setting(containerEl) - .setName(t("HIERARCHY_NAME")) - .setDesc(fragWithHTML(t("HIERARCHY_DESC"))) - .addTextArea((text) => { - text.inputEl.style.minHeight = "300px"; - text.inputEl.style.minWidth = "400px"; + .setName(t("PARENTS_NAME")) + .addText((text)=> { + text.inputEl.style.width = "100%"; text - .setValue(JSON.stringify(this.plugin.settings.hierarchy,null,2)) - .onChange((value) => { - try { - const j = JSON.parse(value); - if(!(j.hasOwnProperty("parents") && j.hasOwnProperty("children") && j.hasOwnProperty("friends"))) { - malformedJSON.setText(t("JSON_MISSING_KEYS")); - malformedJSON.show(); - return; - } - if(!(Array.isArray(j.parents) && Array.isArray(j.children) && Array.isArray(j.friends))) { - malformedJSON.setText(t("JSON_VALUES_NOT_STRING_ARRAYS")); - malformedJSON.show(); - return; - } - if(j.parents.length===0 || j.children.length===0 || j.friends.length === 0) { - malformedJSON.setText(t("JSON_VALUES_NOT_STRING_ARRAYS")); - malformedJSON.show(); - return; - } - if(!(j.parents.every((v:any)=>typeof v === "string") && j.children.every((v:any)=>typeof v === "string") && j.friends.every((v:any)=>typeof v === "string"))) { - malformedJSON.setText(t("JSON_VALUES_NOT_STRING_ARRAYS")); - malformedJSON.show(); - return; - } - malformedJSON.hide(); - this.hierarchy = value; - this.dirty = true; - } - catch { - malformedJSON.setText(t("JSON_MALFORMED")); - malformedJSON.show(); - } - }); - }); + .setValue(this.plugin.settings.hierarchy.parents.join(", ")) + .onChange(value => { + this.plugin.settings.hierarchy.parents = value.split(",").map(s=>s.trim()); + this.dirty = true; + }) + }) + + new Setting(containerEl) + .setName(t("CHILDREN_NAME")) + .addText((text)=> { + text.inputEl.style.width = "100%"; + text + .setValue(this.plugin.settings.hierarchy.children.join(", ")) + .onChange(value => { + this.plugin.settings.hierarchy.children = value.split(",").map(s=>s.trim()); + this.dirty = true; + }) + }) + new Setting(containerEl) + .setName(t("FRIENDS_NAME")) + .addText((text)=> { + text.inputEl.style.width = "100%"; + text + .setValue(this.plugin.settings.hierarchy.friends.join(", ")) + .onChange(value => { + this.plugin.settings.hierarchy.friends = value.split(",").map(s=>s.trim()); + this.dirty = true; + }) + }) + + this.containerEl.createEl("h1", { + cls: "excalibrain-settings-h1", + text: t("DISPLAY_HEAD") + }); new Setting(containerEl) .setName(t("RENDERALIAS_NAME")) .setDesc(fragWithHTML(t("RENDERALIAS_DESC"))) @@ -765,8 +962,14 @@ export class ExcaliBrainSettingTab extends PluginSettingTab { false, 30 ) - - this.containerEl.createEl("h1", { text: t("STYLE_HEAD") }); + + //----------------------------- + //Node Style settings + //----------------------------- + containerEl.createEl("h1", { + cls: "excalibrain-settings-h1", + text: t("STYLE_HEAD") + }); const styleDesc = this.containerEl.createEl("p", {}); styleDesc.innerHTML = t("STYLE_DESC"); @@ -775,41 +978,90 @@ export class ExcaliBrainSettingTab extends PluginSettingTab { t("CANVAS_BGCOLOR"), null, ()=>this.plugin.settings.backgroundColor, - (val)=>this.plugin.settings.backgroundColor=val, + (val)=> { + this.plugin.settings.backgroundColor=val; + this.updateDemoImg(); + }, ()=>{}, false, this.plugin.settings.backgroundColor ) - this.nodeSettings( - t("NODESTYLE_BASE"), - this.plugin.settings.baseNodeStyle, - false - ) - - this.nodeSettings( - t("NODESTYLE_INFERRED"), - this.plugin.settings.inferredNodeStyle - ) - - this.nodeSettings( - t("NODESTYLE_VIRTUAL"), - this.plugin.settings.virtualNodeStyle - ) + const nodeStylesWrapper = containerEl.createDiv({cls:"setting-item"}); + const dropodownWrapper = nodeStylesWrapper.createDiv({cls:"setting-item-info"}); + const nodeStylesDropdown = new DropdownComponent(dropodownWrapper); + + const toggleLabel = nodeStylesWrapper.createDiv({ + text: "Show inherited", + cls: "setting-item-name" + }); + toggleLabel.style.marginRight = "10px"; + + const toggle = new ToggleComponent(nodeStylesWrapper) + toggle + .setValue(true) + .setTooltip("Show/Hide Inherited Properties") + .onChange(value => { + if(value) { + removeStylesheet(HIDE_DISABLED_STYLE); + } else { + addStylesheet(HIDE_DISABLED_STYLE, HIDE_DISABLED_CLASS); + } + }); - this.nodeSettings( - t("NODESTYLE_CENTRAL"), - this.plugin.settings.centralNodeStyle - ) + Object.entries(this.plugin.nodeStyles).forEach(item=>{ + nodeStylesDropdown.addOption(item[0],item[1].display) + }) - this.nodeSettings( - t("NODESTYLE_SIBLING"), - this.plugin.settings.siblingNodeStyle - ) + this.demoImg = containerEl.createEl("img",{cls: "excalibrain-settings-demoimg"}); - this.nodeSettings( - t("NODESTYLE_ATTACHMENT"), - this.plugin.settings.attachmentNodeStyle - ) + const nodeStyleDiv = containerEl.createDiv({ + cls: "excalibrain-setting-nodestyle-section" + }); + removeStylesheet(HIDE_DISABLED_STYLE); + nodeStylesDropdown + .setValue("base") + .onChange(value => { + nodeStyleDiv.empty(); + let nodeStyle = this.plugin.nodeStyles[value]; + if(!nodeStyle) { + this.plugin.nodeStyles[value] = { + style: {}, + allowOverride: true, + userStyle: true, + display: value, + getInheritedStyle: ()=>{ + return { + ...this.plugin.settings.baseNodeStyle, + //...this.plugin.settings.inferredLinkStyle, + //...this.plugin.settings.virtualNodeStyle, + //...this.plugin.settings.centralNodeStyle, + //...this.plugin.settings.siblingNodeStyle, + //...this.plugin.settings.attachmentNodeStyle + } + } + } + nodeStyle = this.plugin.nodeStyles[value]; + } + this.nodeSettings( + nodeStyleDiv, + nodeStyle.display, + nodeStyle.style, + nodeStyle.allowOverride, + nodeStyle.getInheritedStyle() + ) + this.demoNodeStyle = nodeStyle; + this.updateDemoImg(); + }) + const nodeStyle = this.plugin.nodeStyles["base"]; + this.nodeSettings( + nodeStyleDiv, + nodeStyle.display, + nodeStyle.style, + nodeStyle.allowOverride, + nodeStyle.getInheritedStyle() + ) + this.demoNodeStyle = nodeStyle; + this.updateDemoImg(); } -} +} \ No newline at end of file diff --git a/src/Types.ts b/src/Types.ts index 939d1c4..6535ef9 100644 --- a/src/Types.ts +++ b/src/Types.ts @@ -26,7 +26,11 @@ export type Relation = { friendTypeDefinition?: string; } -export type Hierarchy = {[key:string]: string[]} +export type Hierarchy = { + parents: string[], + children: string[], + friends: string[] +} export type NodeStyle = { prefix?: string @@ -49,6 +53,18 @@ export type NodeStyle = { gateFillStyle?: FillStyle, } +export type NodeStyleData = { + style: NodeStyle, + allowOverride:boolean, + userStyle: boolean, + display: string, + getInheritedStyle: ()=>NodeStyle +} + +export type NodeStyles = { + [key:string]: NodeStyleData +}; + export type LinkStyle = { strokeColor?: string, strokeWidth?: number, diff --git a/src/constants/constants.ts b/src/constants/constants.ts index e91d651..885ea5c 100644 --- a/src/constants/constants.ts +++ b/src/constants/constants.ts @@ -1,2 +1,3 @@ -export const APPNAME = "NeoroGraph"; -export const PLUGIN_NAME = "obsidian-excalibrain" \ No newline at end of file +export const APPNAME = "ExcaliBrain"; +export const PLUGIN_NAME = "excalibrain" +export const MINEXCALIDRAWVERSION = "1.6.26" \ No newline at end of file diff --git a/src/constants/emptyBrainFile.ts b/src/constants/emptyBrainFile.ts index 44f7209..f3ee34e 100644 --- a/src/constants/emptyBrainFile.ts +++ b/src/constants/emptyBrainFile.ts @@ -4,7 +4,9 @@ excalidraw-plugin: parsed excalidraw-default-mode: view excalidraw-export-dark: false excalidraw-export-transparent: false -excalidraw-export-svgpadding: 30 +excalidraw-linkbutton-opacity: 0.3 +excalidraw-onload-script: "app.plugins.plugins[${String.fromCharCode(96)}excalibrain${String.fromCharCode(96)}].start(ea.targetView.leaf);" + tags: [excalidraw] --- diff --git a/src/graph/Node.ts b/src/graph/Node.ts index 7303c6e..b80cff7 100644 --- a/src/graph/Node.ts +++ b/src/graph/Node.ts @@ -17,18 +17,24 @@ export class Node { private friendGateOnLeft: boolean; public title: string; - constructor(x:{page:Page, isInferred: boolean, isCentral: boolean, isSibling: boolean, friendGateOnLeft:boolean}) { + constructor(x:{ + page:Page, + isInferred: boolean, + isCentral: boolean, + isSibling: boolean, + friendGateOnLeft:boolean + }) { this.page = x.page; this.settings = x.page.plugin.settings; this.ea = x.page.plugin.EA; this.style = { ...this.settings.baseNodeStyle, - ...this.getTagStyle(), ...x.isInferred?this.settings.inferredNodeStyle:{}, ...x.page.isVirtual?this.settings.virtualNodeStyle:{}, ...x.isCentral?this.settings.centralNodeStyle:{}, ...x.isSibling?this.settings.siblingNodeStyle:{}, - ...x.page.isAttachment?this.settings.attachmentNodeStyle:{} + ...x.page.isAttachment?this.settings.attachmentNodeStyle:{}, + ...this.getTagStyle(), }; this.friendGateOnLeft = x.friendGateOnLeft; this.title = this.getTitle(); @@ -67,8 +73,6 @@ export class Node { } render() { - const includeVirtual = this.settings.showInferredNodes; - const includeAttachments = this.settings.showAttachments; const ea = this.ea; const label = this.displayText(); ea.style.fontSize = this.style.fontSize; diff --git a/src/graph/Page.ts b/src/graph/Page.ts index 2440150..22086a7 100644 --- a/src/graph/Page.ts +++ b/src/graph/Page.ts @@ -293,15 +293,17 @@ export class Page { getSiblings():Neighbour[] { const siblings = new Map(); - this.getParents().forEach(p => { - if(siblings.has(p.page.path)) { - if(p.relationType === RelationType.DEFINED) { - siblings.get(p.page.path).relationType = RelationType.DEFINED; + this.getParents().forEach(p => + p.page.getChildren().forEach(s => { + if(siblings.has(s.page.path)) { + if(s.relationType === RelationType.DEFINED) { + siblings.get(s.page.path).relationType = RelationType.DEFINED; + } + return; } - return; - } - siblings.set(p.page.path,p); - }) - return Object.values(siblings); + siblings.set(s.page.path,s); + }) + ); + return Array.from(siblings.values()); } } \ No newline at end of file diff --git a/src/graph/Pages.ts b/src/graph/Pages.ts index ceea147..b784616 100644 --- a/src/graph/Pages.ts +++ b/src/graph/Pages.ts @@ -95,9 +95,9 @@ export class Pages { Object.keys(unresolvedLinks[parentPath]).forEach(childPath=>{ const newPage = new Page(childPath,null,this.plugin); const parent = this.pages.get(parentPath); - this.add(childPath,newPage); newPage.addParent(parent,RelationType.INFERRED); parent.addChild(newPage,RelationType.INFERRED); + this.add(childPath,newPage); }) }); } diff --git a/src/lang/locale/en.ts b/src/lang/locale/en.ts index 5c4803d..9b90a31 100644 --- a/src/lang/locale/en.ts +++ b/src/lang/locale/en.ts @@ -1,4 +1,4 @@ -import { APPNAME } from "src/constants/constants"; +import { APPNAME, MINEXCALIDRAWVERSION } from "src/constants/constants"; //English export default { @@ -10,8 +10,12 @@ export default { EXCALIBRAIN_FILE_DESC: "⚠ This file will be overwritten by the plugin. If you stop the script and make changes to the graph, you " + "should rename the file so your edits are preserved, because the next time you initiate ExcaliBrain your edits will be overwritten by " + "the automatically generated ExcaliBrain graph.", - HIERARCHY_NAME: "Hierarchy", - HIERARCHY_DESC: "User hierarchy JSON", + HIERARCHY_HEAD: "Hierarchy", + HIERARCHY_DESC: "Enter the Dataview field names separated by comma (,) that you will use to define link directions in your graph.", + PARENTS_NAME: "Parents", + CHILDREN_NAME: "Children", + FRIENDS_NAME: "Friends", + DISPLAY_HEAD: "Display", RENDERALIAS_NAME: "Display alias if available", RENDERALIAS_DESC: "Displays the page alias instead of the filename if it is specified in the page's front matter.", SHOWINFERRED_NAME: "Display inferred relationships", @@ -24,10 +28,10 @@ export default { SHOWATTACHMENTS_DESC: "Toggle ON: Display every type of file on the graph. " + "
Toggle OFF: Display only markdown files.", STYLE_HEAD: "Styling", - STYLE_DESC: "Styles are applied in sequence.
  1. Base node style
  2. Optional tag based style
  3. " + + STYLE_DESC: "Styles are applied in sequence.
    1. Base node style
    2. " + "
    3. Inferred node style (only applied if the node is inferred)
    4. Virtual node style (only applied if the node is virtual)
    5. " + "
    6. Central node style (only applied if the node is in the center)
    7. Sibling node style (only applied if the node is a sibling)
    8. " + - "
    9. Attachment node style (only applied if the node is an attachment)
    " + + "
  4. Attachment node style (only applied if the node is an attachment)
  5. Optional tag based style
" + "All the attributes of the base node style must be specified. " + "All other styles may have partial definitions. e.g. You may add a prefix and override the base node-background color in the tag-based style, " + "override the font color in the inferred-node style and set the border stroke style to dotted in the virtual-node style.", @@ -69,5 +73,6 @@ export default { //main 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" } \ No newline at end of file diff --git a/src/main.ts b/src/main.ts index 465e466..4fd03c7 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,15 +1,17 @@ -import { App, FileView, MetadataCache, Notice, Plugin, PluginManifest, TAbstractFile, TFile, TFolder, WorkspaceLeaf } from 'obsidian'; +import { App, Notice, Plugin, PluginManifest, TAbstractFile, TFile, TFolder, WorkspaceLeaf } from 'obsidian'; import { Page } from './graph/Page'; import { DEFAULT_SETTINGS, ExcaliBrainSettings, ExcaliBrainSettingTab } from './Settings'; import { errorlog, log } from './utils/utils'; import { getAPI } from "obsidian-dataview" import { t } from './lang/helpers'; -import { PLUGIN_NAME } from './constants/constants'; +import { MINEXCALIDRAWVERSION, PLUGIN_NAME } from './constants/constants'; import { DvAPIInterface } from 'obsidian-dataview/lib/typings/api'; import { Pages } from './graph/Pages'; import { getEA } from "obsidian-excalidraw-plugin"; import { ExcalidrawAutomate } from 'obsidian-excalidraw-plugin/lib/ExcalidrawAutomate'; import { Scene } from './Scene'; +import { NodeStyle, NodeStyles } from './Types'; + declare module "obsidian" { interface App { @@ -21,11 +23,13 @@ declare module "obsidian" { export default class ExcaliBrain extends Plugin { public settings:ExcaliBrainSettings; + public nodeStyles: NodeStyles; public pages: Pages; public DVAPI: DvAPIInterface; public EA: ExcalidrawAutomate; public scene: Scene = null; private disregardLeafChangeTimer: NodeJS.Timeout; + private pluginLoaded: boolean = false; constructor(app: App, manifest: PluginManifest) { super(app, manifest); @@ -34,7 +38,7 @@ export default class ExcaliBrain extends Plugin { async onload() { await this.loadSettings(); this.addSettingTab(new ExcaliBrainSettingTab(this.app, this)); - this.app.workspace.onLayoutReady(async()=>{ + this.app.workspace.onLayoutReady(()=>{ this.DVAPI = getAPI(); if(!this.DVAPI) { new Notice(t("DATAVIEW_NOT_FOUND"),4000); @@ -49,38 +53,15 @@ export default class ExcaliBrain extends Plugin { this.app.plugins.disablePlugin(PLUGIN_NAME) return; } - this.registerCommands(); - this.EA.onViewModeChangeHook = (isViewModeEnabled) => { - if(!this.EA.targetView || this.EA.targetView.file?.path !== this.settings.excalibrainFilepath) { - return; - } - if(!isViewModeEnabled) { - this.stop(); - } - } - - this.EA.onLinkHoverHook = (element,linkText) => { - if( - !this.scene || - !this.EA.targetView || - this.EA.targetView.file?.path !== this.settings.excalibrainFilepath || - !this.EA.targetView.excalidrawAPI.getAppState().viewModeEnabled - ) { - return true; - } - this.scene.disregardLeafChange = true; - if(this.disregardLeafChangeTimer) { - clearTimeout(this.disregardLeafChangeTimer); - } - this.disregardLeafChangeTimer = setTimeout(()=>{ - this.disregardLeafChangeTimer = null; - if(!this.scene) { - return; - } - this.scene.disregardLeafChange = false; - },2000); - return true; + if(!this.EA.verifyMinimumPluginVersion(MINEXCALIDRAWVERSION)) { + new Notice(t("EXCALIDRAW_MINAPP_VERSION"), 4000); + errorlog({fn:this.onload, where:"main.ts/onload()", message:"ExcaliBrain requires a new version of Excalidraw"}); + this.app.plugins.disablePlugin(PLUGIN_NAME) + return; } + this.registerCommands(); + this.registerExcalidrawAutomateHooks(); + this.pluginLoaded = true; }); } @@ -125,8 +106,14 @@ export default class ExcaliBrain extends Plugin { this.scene.unloadScene(); this.scene = null; } else { - this.scene = new Scene(this,true,this.getBrainLeaf()) - this.scene.initialize(); + const leaf = this.getBrainLeaf(); + this.scene = new Scene(this,true,this.getBrainLeaf()); + //@ts-ignore + if(leaf.view && leaf.view.file && leaf.view.file.path == this.settings.excalibrainFilepath) { + this.scene.initialize(); + return; + } + this.scene.openExcalidrawLeaf(); } }, }); @@ -147,6 +134,47 @@ export default class ExcaliBrain extends Plugin { return brainLeaf; } + registerExcalidrawAutomateHooks() { + this.EA.onViewModeChangeHook = (isViewModeEnabled) => { + if(!this.EA.targetView || this.EA.targetView.file?.path !== this.settings.excalibrainFilepath) { + return; + } + if(!isViewModeEnabled) { + this.stop(); + } + } + + this.EA.onLinkHoverHook = (element,linkText) => { + if( + !this.scene || + !this.EA.targetView || + this.EA.targetView.file?.path !== this.settings.excalibrainFilepath || + !this.EA.targetView.excalidrawAPI || + !this.EA.targetView.excalidrawAPI.getAppState().viewModeEnabled + ) { + return true; + } + this.scene.disregardLeafChange = true; + if(this.disregardLeafChangeTimer) { + clearTimeout(this.disregardLeafChangeTimer); + } + this.disregardLeafChangeTimer = setTimeout(()=>{ + this.disregardLeafChangeTimer = null; + if(!this.scene) { + return; + } + this.scene.disregardLeafChange = false; + },1000); + return true; + } + + this.EA.onViewUnloadHook = (view) => { + if(this.scene && this.scene.leaf === view.leaf) { + this.stop(); + } + } + } + onunload() { if(this.scene) { this.scene.unloadScene(); @@ -156,6 +184,101 @@ export default class ExcaliBrain extends Plugin { async loadSettings() { this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData()); + this.nodeStyles = {}; + this.nodeStyles["base"] = { + style: this.settings.baseNodeStyle, + allowOverride: false, + userStyle: false, + display: t("NODESTYLE_BASE"), + getInheritedStyle: ()=>{ + return { + ...this.settings.baseNodeStyle, + } + } + }; + this.nodeStyles["inferred"] = { + style: this.settings.inferredNodeStyle, + allowOverride: true, + userStyle: false, + display: t("NODESTYLE_INFERRED"), + getInheritedStyle: ()=>{ + return { + ...this.settings.baseNodeStyle, + } + } + }; + this.nodeStyles["virtual"] = { + style: this.settings.virtualNodeStyle, + allowOverride: true, + userStyle: false, + display: t("NODESTYLE_VIRTUAL"), + getInheritedStyle: ()=>{ + return { + ...this.settings.baseNodeStyle, + //...this.settings.inferredLinkStyle + } + } + }; + this.nodeStyles["central"] = { + style: this.settings.centralNodeStyle, + allowOverride: true, + userStyle: false, + display: t("NODESTYLE_CENTRAL"), + getInheritedStyle: ()=>{ + return { + ...this.settings.baseNodeStyle, + //...this.settings.inferredLinkStyle, + //...this.settings.virtualNodeStyle + } + } + }; + this.nodeStyles["sibling"] = { + style: this.settings.siblingNodeStyle, + allowOverride: true, + userStyle: false, + display: t("NODESTYLE_SIBLING"), + getInheritedStyle: ()=>{ + return { + ...this.settings.baseNodeStyle, + //...this.settings.inferredLinkStyle, + //...this.settings.virtualNodeStyle, + //...this.settings.centralNodeStyle + } + } + }; + this.nodeStyles["attachment"] = { + style: this.settings.attachmentNodeStyle, + allowOverride: true, + userStyle: false, + display: t("NODESTYLE_ATTACHMENT"), + getInheritedStyle: ()=>{ + return { + ...this.settings.baseNodeStyle, + //...this.settings.inferredLinkStyle, + //...this.settings.virtualNodeStyle, + //...this.settings.centralNodeStyle, + //...this.settings.siblingNodeStyle + } + } + }; + Object.entries(this.settings.tagNodeStyles).forEach(item=>{ + this.nodeStyles[item[0]] = { + style: item[1], + allowOverride: true, + userStyle: true, + display: item[0], + getInheritedStyle: ()=>{ + return { + ...this.settings.baseNodeStyle, + //...this.settings.inferredLinkStyle, + //...this.settings.virtualNodeStyle, + //...this.settings.centralNodeStyle, + //...this.settings.siblingNodeStyle, + //...this.settings.attachmentNodeStyle + } + } + } + }) } async saveSettings() { @@ -169,9 +292,22 @@ export default class ExcaliBrain extends Plugin { } } - public start(leaf: WorkspaceLeaf) { + public async start(leaf: WorkspaceLeaf) { + let counter = 0; + while(!this.pluginLoaded && counter++<100) await sleep(50); + if(!this.pluginLoaded) { + new Notice("ExcaliBrain plugin did not load - aborting start()"); + errorlog({where: "ExcaliBrain.start()", fn: this.start, message: "ExcaliBrain did not load. Aborting after 5000ms of trying"}); + return; + } + log("start"); this.stop(); - this.scene = new Scene(this,true,leaf??this.getBrainLeaf()) + if(!leaf) { + this.scene = new Scene(this,true,this.getBrainLeaf()) + this.scene.openExcalidrawLeaf(); + return; + } + this.scene = new Scene(this,true,leaf) this.scene.initialize(); } diff --git a/src/utils/dataview.ts b/src/utils/dataview.ts index fc67a54..1169d0d 100644 --- a/src/utils/dataview.ts +++ b/src/utils/dataview.ts @@ -47,6 +47,7 @@ export const getDVFieldLinksForPage = (plugin: ExcaliBrain, dvPage: Record { + f = f.toLowerCase().replaceAll(" ","-"); if(dvPage[f] && !processed.has(f)) { processed.add(f); readDVField(plugin.app,dvPage[f],dvPage.file).forEach(l=>links.push({link:l,field:f})) diff --git a/src/utils/utils.ts b/src/utils/utils.ts index 1247f07..856eb7c 100644 --- a/src/utils/utils.ts +++ b/src/utils/utils.ts @@ -12,4 +12,10 @@ export const errorlog = (data: ErrorLog) => { export const log = console.log.bind(window.console); export const debug = console.log.bind(window.console); -export const sleep = async (ms: number) => new Promise((resolve) => setTimeout(resolve, ms)); \ No newline at end of file +export const sleep = async (ms: number) => new Promise((resolve) => setTimeout(resolve, ms)); + +export const svgToBase64 = (svg: string): string => { + return `data:image/svg+xml;base64,${btoa( + unescape(encodeURIComponent(svg.replaceAll(" ", " "))), + )}`; +}; \ No newline at end of file diff --git a/styles.css b/styles.css index 6d9acec..c4d50e3 100644 --- a/styles.css +++ b/styles.css @@ -6,4 +6,23 @@ .excalibrain-prompt-center { text-align: center; +} + +.excalibrain-settings-folding-L1 { + font-size: large; + font-weight: bold; + color: var(--text-title-h3); +} + +.excalibrain-settings-h1 { + color: var(--text-title-h1); +} + +.excalibrain-setting-nodestyle-section { + padding-left: 30px; + border-left: 10px solid var(--background-modifier-border); +} + +.excalibrain-settings-demoimg { + max-width: 400px; } \ No newline at end of file