diff --git a/manifest-beta.json b/manifest-beta.json index c13bf42..bbd107e 100644 --- a/manifest-beta.json +++ b/manifest-beta.json @@ -1,7 +1,7 @@ { "id": "obsidian-excalidraw-plugin", "name": "Excalidraw", - "version": "2.7.0-beta-2", + "version": "2.7.0-beta-3", "minAppVersion": "1.1.6", "description": "An Obsidian plugin to edit and view Excalidraw drawings", "author": "Zsolt Viczian", diff --git a/src/customEmbeddable.tsx b/src/customEmbeddable.tsx index 7f2404a..d5c9839 100644 --- a/src/customEmbeddable.tsx +++ b/src/customEmbeddable.tsx @@ -265,20 +265,20 @@ function RenderObsidianView( const color = element?.backgroundColor ? (element.backgroundColor.toLowerCase() === "transparent" ? "transparent" - : ea.getCM(element.backgroundColor).alphaTo(opacity).stringHEX()) + : ea.getCM(element.backgroundColor).alphaTo(opacity).stringHEX({alpha: true})) : "transparent"; color === "transparent" ? canvasNode?.addClass("transparent") : canvasNode?.removeClass("transparent"); canvasNode?.style.setProperty("--canvas-background", color); canvasNode?.style.setProperty("--background-primary", color); canvasNodeContainer?.style.setProperty("background-color", color); - } else if (!(mdProps?.backgroundMatchElement ?? true )) { + } else if (!(mdProps.backgroundMatchElement ?? true )) { const opacity = (mdProps.backgroundOpacity??100)/100; const color = mdProps.backgroundMatchCanvas ? (canvasColor.toLowerCase() === "transparent" ? "transparent" - : ea.getCM(canvasColor).alphaTo(opacity).stringHEX()) - : ea.getCM(mdProps.backgroundColor).alphaTo((mdProps.backgroundOpacity??100)/100).stringHEX(); + : ea.getCM(canvasColor).alphaTo(opacity).stringHEX({alpha: true})) + : ea.getCM(mdProps.backgroundColor).alphaTo((mdProps.backgroundOpacity??100)/100).stringHEX({alpha: true}); color === "transparent" ? canvasNode?.addClass("transparent") : canvasNode?.removeClass("transparent"); canvasNode?.style.setProperty("--canvas-background", color); @@ -291,13 +291,13 @@ function RenderObsidianView( const color = element?.strokeColor ? (element.strokeColor.toLowerCase() === "transparent" ? "transparent" - : ea.getCM(element.strokeColor).alphaTo(opacity).stringHEX()) + : ea.getCM(element.strokeColor).alphaTo(opacity).stringHEX({alpha: true})) : "transparent"; canvasNode?.style.setProperty("--canvas-border", color); canvasNode?.style.setProperty("--canvas-color", color); //canvasNodeContainer?.style.setProperty("border-color", color); } else if(!(mdProps?.borderMatchElement ?? true)) { - const color = ea.getCM(mdProps.borderColor).alphaTo((mdProps.borderOpacity??100)/100).stringHEX(); + const color = ea.getCM(mdProps.borderColor).alphaTo((mdProps.borderOpacity??100)/100).stringHEX({alpha: true}); canvasNode?.style.setProperty("--canvas-border", color); canvasNode?.style.setProperty("--canvas-color", color); //canvasNodeContainer?.style.setProperty("border-color", color); @@ -315,8 +315,16 @@ function RenderObsidianView( const canvasNode = containerRef.current; if(!canvasNode.hasClass("canvas-node")) return; setColors(canvasNode, element, mdProps, canvasColor); + console.log("Setting colors"); }, [ - mdProps, + mdProps?.useObsidianDefaults, + mdProps?.backgroundMatchCanvas, + mdProps?.backgroundMatchElement, + mdProps?.backgroundColor, + mdProps?.backgroundOpacity, + mdProps?.borderMatchElement, + mdProps?.borderColor, + mdProps?.borderOpacity, elementRef.current, containerRef.current, canvasColor, @@ -395,7 +403,8 @@ function RenderObsidianView( const previousIsActive = isActiveRef.current; isActiveRef.current = (activeEmbeddable?.element.id === element.id) && (activeEmbeddable?.state === "active"); - + + const node = leafRef.current?.node as ObsidianCanvasNode; if (previousIsActive === isActiveRef.current) { return; } @@ -414,15 +423,15 @@ function RenderObsidianView( isEditingRef.current = false; return; } - } else if (leafRef.current?.node) { + } else if (node) { //Handle canvas node - if(view.plugin.settings.markdownNodeOneClickEditing && !containerRef.current?.hasClass("is-editing")) { + if(isActiveRef.current && view.plugin.settings.markdownNodeOneClickEditing && !containerRef.current?.hasClass("is-editing")) { //!node.isEditing const newTheme = getTheme(view, themeRef.current); containerRef.current?.addClasses(["is-editing", "is-focused"]); - view.canvasNodeFactory.startEditing(leafRef.current.node, newTheme); + view.canvasNodeFactory.startEditing(node, newTheme); } else { containerRef.current?.removeClasses(["is-editing", "is-focused"]); - view.canvasNodeFactory.stopEditing(leafRef.current.node); + view.canvasNodeFactory.stopEditing(node); } } }, [ diff --git a/src/dialogs/EmbeddableMDFileCustomDataSettingsComponent.ts b/src/dialogs/EmbeddableMDFileCustomDataSettingsComponent.ts index 6c82585..afcd00d 100644 --- a/src/dialogs/EmbeddableMDFileCustomDataSettingsComponent.ts +++ b/src/dialogs/EmbeddableMDFileCustomDataSettingsComponent.ts @@ -46,6 +46,16 @@ export class EmbeddalbeMDFileCustomDataSettingsComponent { ); } contentEl.createEl("h4",{text: t("ES_BACKGROUND_HEAD")}); + const descDiv = contentEl.createDiv({ cls: "excalidraw-setting-desc" }); + descDiv.textContent = t("ES_BACKGROUND_DESC_INFO"); + + descDiv.addEventListener("click", () => { + if (descDiv.textContent === t("ES_BACKGROUND_DESC_INFO")) { + descDiv.textContent = t("ES_BACKGROUND_DESC_DETAIL"); + } else { + descDiv.textContent = t("ES_BACKGROUND_DESC_INFO"); + } + }); let bgSetting: Setting; let bgMatchElementToggle: ToggleComponent; diff --git a/src/lang/locale/en.ts b/src/lang/locale/en.ts index b647b03..7030e7f 100644 --- a/src/lang/locale/en.ts +++ b/src/lang/locale/en.ts @@ -910,6 +910,8 @@ FILENAME_HEAD: "Filename", ES_YOUTUBE_START_INVALID: "The YouTube Start Time is invalid. Please check the format and try again", ES_FILENAME_VISIBLE: "Filename Visible", ES_BACKGROUND_HEAD: "Embedded note background color", + ES_BACKGROUND_DESC_INFO: "Click here for more info on colors", + ES_BACKGROUND_DESC_DETAIL: "Background color affects only the preview mode of the markdown embeddable. When editing, it follows the Obsidian light/dark theme as set for the scene (via document property) or in plugin settings. The background color has two layers: the element background color (lower layer) and a color on top (upper layer). Selecting 'Match Element Background' means both layers follow the element color. Selecting 'Match Canvas' or a specific background color keeps the element background layer. Setting opacity (e.g., 50%) mixes the canvas or selected color with the element background color. To remove the element background layer, set the element color to transparent in Excalidraw's element properties editor. This makes only the upper layer effective.", ES_BACKGROUND_MATCH_ELEMENT: "Match Element Background Color", ES_BACKGROUND_MATCH_CANVAS: "Match Canvas Background Color", ES_BACKGROUND_COLOR: "Background Color", diff --git a/src/menu/EmbeddableActionsMenu.tsx b/src/menu/EmbeddableActionsMenu.tsx index 3b3c749..e72cc95 100644 --- a/src/menu/EmbeddableActionsMenu.tsx +++ b/src/menu/EmbeddableActionsMenu.tsx @@ -127,7 +127,7 @@ export class EmbeddableMenu { blockID = nanoid(); const fileContents = await app.vault.cachedRead(file); if(!fileContents) return; - await app.vault.modify(file, fileContents.slice(0, offset) + ` ^${blockID}` + fileContents.slice(offset)); + await this.view.app.vault.modify(file, fileContents.slice(0, offset) + ` ^${blockID}` + fileContents.slice(offset)); await sleep(200); //wait for cache to update } this.updateElement(`#^${blockID}`, element, file); @@ -170,7 +170,6 @@ export class EmbeddableMenu { renderButtons(appState: AppState) { const view = this.view; - const app = view.app; const api = view?.excalidrawAPI as ExcalidrawImperativeAPI; if(!api) return null; if(!view.file) return null; diff --git a/src/utils/CanvasNodeFactory.ts b/src/utils/CanvasNodeFactory.ts index 426f67a..fd3bd92 100644 --- a/src/utils/CanvasNodeFactory.ts +++ b/src/utils/CanvasNodeFactory.ts @@ -82,51 +82,74 @@ export class CanvasNodeFactory { return node; } - public async startEditing(node: ObsidianCanvasNode, theme: string) { - if (!this.initialized || !node) return; - if (node.file === this.view.file) { - await this.view.setEmbeddableIsEditingSelf(); + private async waitForEditor(node: ObsidianCanvasNode): Promise { + let counter = 0; + while (!node.child.editor?.containerEl?.parentElement?.parentElement && counter++ < 100) { + await new Promise(resolve => setTimeout(resolve, 25)); } - node.startEditing(); - - const obsidianTheme = isObsidianThemeDark() ? "theme-dark" : "theme-light"; - if (obsidianTheme === theme) return; - - (async () => { - let counter = 0; - while (!node.child.editor?.containerEl?.parentElement?.parentElement && counter++ < 100) { - await sleep(25); - } - if (!node.child.editor?.containerEl?.parentElement?.parentElement) return; - node.child.editor.containerEl.parentElement.parentElement.classList.remove(obsidianTheme); - node.child.editor.containerEl.parentElement.parentElement.classList.add(theme); - - const nodeObserverFn: MutationCallback = (mutationsList) => { - for (const mutation of mutationsList) { - if (mutation.type === 'attributes' && mutation.attributeName === 'class') { - const targetElement = mutation.target as HTMLElement; - if (targetElement.classList.contains(obsidianTheme)) { - targetElement.classList.remove(obsidianTheme); - targetElement.classList.add(theme); - } + return node.child.editor?.containerEl?.parentElement?.parentElement; + } + + private setupThemeObserver(editorEl: HTMLElement, obsidianTheme: string, theme: string) { + const nodeObserverFn: MutationCallback = (mutationsList) => { + for (const mutation of mutationsList) { + if (mutation.type === 'attributes' && mutation.attributeName === 'class') { + const targetElement = mutation.target as HTMLElement; + if (targetElement.classList.contains(obsidianTheme)) { + targetElement.classList.remove(obsidianTheme); + targetElement.classList.add(theme); } } - }; - this.observer = DEBUGGING - ? new CustomMutationObserver(nodeObserverFn, "CanvasNodeFactory") - : new MutationObserver(nodeObserverFn); - - this.observer.observe(node.child.editor.containerEl.parentElement.parentElement, { attributes: true }); - })(); - } + } + }; + + this.observer?.disconnect(); + this.observer = DEBUGGING + ? new CustomMutationObserver(nodeObserverFn, "CanvasNodeFactory") + : new MutationObserver(nodeObserverFn); + + this.observer.observe(editorEl, { attributes: true }); + } + + public async startEditing(node: ObsidianCanvasNode, theme: string) { + if (!this.initialized || !node) return; + + try { + if (node.file === this.view.file) { + await this.view.setEmbeddableIsEditingSelf(); + } + node.startEditing(); + node.isEditing = true; + + const obsidianTheme = isObsidianThemeDark() ? "theme-dark" : "theme-light"; + if (obsidianTheme === theme) return; + + const editorEl = await this.waitForEditor(node); + if (!editorEl) return; + + editorEl.classList.remove(obsidianTheme); + editorEl.classList.add(theme); + + this.setupThemeObserver(editorEl, obsidianTheme, theme); + } catch (error) { + console.error('Error starting edit:', error); + node.isEditing = false; + } + } public stopEditing(node: ObsidianCanvasNode) { - if(!this.initialized || !node) return; - if(!node.child.editMode) return; - if(node.file === this.view.file) { - this.view.clearEmbeddableIsEditingSelf(); + if (!this.initialized || !node || !node.isEditing) return; + + try { + if (node.file === this.view.file) { + this.view.clearEmbeddableIsEditingSelf(); + } + node.child.showPreview(); + node.isEditing = false; + this.observer?.disconnect(); + } catch (error) { + console.error('Error stopping edit:', error); } - node.child.showPreview(); } removeNode(node: ObsidianCanvasNode) { diff --git a/styles.css b/styles.css index 1d84ccd..c567239 100644 --- a/styles.css +++ b/styles.css @@ -651,3 +651,17 @@ textarea.excalidraw-wysiwyg, .excalidraw input { .excalidraw .ToolIcon_type_button { color: var(--text-primary-color); } + +.excalidraw-setting-desc { + padding: 10px; + cursor: pointer; + background-color: var(--background-secondary); + border: 1px solid var(--background-modifier-border); + border-radius: 5px; + transition: background-color 0.3s ease, color 0.3s ease; +} + +.excalidraw-setting-desc:hover { + background-color: var(--background-modifier-hover); + color: var(--text-accent); +} \ No newline at end of file