diff --git a/README.md b/README.md index 7becd60..cc8d8b0 100644 --- a/README.md +++ b/README.md @@ -48,6 +48,7 @@ The Obsidian-Excalidraw plugin integrates [Excalidraw](https://excalidraw.com/),   SVG import
  OCR
  Bind/unbind text from container, Frontmatter tags to customize export
+  Custom pen support
Quality of life improvements   Mobile Support
@@ -101,8 +102,7 @@ Settings will allow you to customize Excalidraw to your needs: - Experimental feature to add custom TAG to file explorer to mark drawing files. - Enable / disable autosave. -### Embedded images - +### Embedding your drawings into markdown documents - You can customize the size and position of the embedded images using the - `![[image.excalidraw|100]]`, - `![[image.excalidraw|100x100]]`, @@ -112,9 +112,10 @@ Settings will allow you to customize Excalidraw to your needs: - You can add your custom [alignment via CSS](https://www.scaler.com/topics/align-image-in-html/). - Any text that appears in `` will be added to the rendered SVG element style and to the wrapper DIV element. - See [styles.css](https://github.com/zsviczian/obsidian-excalidraw-plugin/blob/master/styles.css) for more insight. +- Excalidraw drawings do not display in Obsidian Publish. If you want to use Excalidraw in your published documents, you can configure in plugin settings, under `Embed & Export`, to automatically insert a PNG or SVG version of the drawing in your document when creating a new file. See `type of file to insert into document` + - Under `Export settings` you can also configure to automatically export a dark and light version of the image, in case your published site supports dark and light mode. ### Hyperlinks - - Supports hyperlinks e.g. - `https://zsolt.blog`, - `[Obsidian](https://obsidian.md)`, and @@ -136,12 +137,10 @@ Settings will allow you to customize Excalidraw to your needs: - Using the block reference you can also reference & transclude text that appears on drawings, in other documents ### LaTeX - Insert LaTeX formulas using the Command Palette action "Insert LaTeX formula". You can edit formulas either in Markdown view, or by CTRL/CMD + Click on the formula. ### Drag & Drop support - - You can drag files from the Obsidian file explorer and they will become links to those files in Excalidraw. - Dragging image files (PNG, SVG, JPG, ICO, GIF, WEBP, Excalidraw) from Obsidian's file explorer while pressing the CTRL (SHIFT on Mac) button will embed the image into your drawing. @@ -161,13 +160,12 @@ You can edit formulas either in Markdown view, or by CTRL/CMD + Click - You can drag and drop web addresses from your browser and they will become links. ### Image support - - On iOS and Android you can add images from your camera by pressing the add image button in Excalidraw. - You can copy/paste images into your drawing. Images will be saved in your vault. - You can drag and drop images as explained above. ### Block referencing parts of images - +For more details see this [video](https://youtu.be/yZQoJg2RCKI) - When referencing an element on the canvas in a link pointing to an Excalidraw file using - the elementId or the section header (i.e. a Text Element containing the `#
`) - e.g. `[[file#^elementID]]`, @@ -186,7 +184,6 @@ You can edit formulas either in Markdown view, or by CTRL/CMD + Click references. ### Markdown - - Since 1.2.0 Drawing files are stored in Markdown files - You can add tags to drawings - You can add metadata to the YAML front matter of drawings @@ -204,7 +201,6 @@ You can edit formulas either in Markdown view, or by CTRL/CMD + Click - `excalidraw-export-pngscale`: This only affects export to PNG. Specify the export scale for the image. The typical range is between 0.5 and 5, but you can experiment with other values as well. ### Embed complete markdown files into your drawings - - Drag from the desired file from the Obsidian file explorer and hold down CTRL/CMD while dropping the file onto the canvas. - Use the command palette action: `Insert markdown file from vault` - Use custom woff, woff2 or TTF font to display the document, you can set the default font to use under Excalidraw Settings. @@ -228,8 +224,14 @@ You can edit formulas either in Markdown view, or by CTRL/CMD + Click - Switch to markdown view or use CTRL/CMD+ALT/OPT click on the image to edit properties of the embed: - `[[filename#^blockref|WIDTHxMAXHEIGHT]]` -### Other +### Custom Font, Custom Pen, OCR support, SVG import +- In plugin settings you can add a custom 4th font. For more details see this [video](https://youtu.be/eKFmrSQhFA4) +- The plugin includes OCR support using Taskbone OCR. For more details see this [video](https://youtu.be/7gu4ETx7zro) +- You can convert SVG files into Excalidraw drawings (with some limitation). For more details see this [video](https://youtu.be/vlC1-iBvIfo) +- You can define custom freedraw pens. See documentation [here](https://github.com/zsviczian/obsidian-excalidraw-plugin/blob/master/ea-scripts/Alternative%20Pens.md), [video](https://youtu.be/uZz5MgzWXiM) +### Other +- Left-handed mode - Includes full - [QuickAdd](https://github.com/chhoumann/quickadd), - [Templater](https://silentvoid13.github.io/Templater/) and diff --git a/images/scripts-organic-line.jpg b/images/scripts-organic-line.jpg index b129ff2..041f691 100644 Binary files a/images/scripts-organic-line.jpg and b/images/scripts-organic-line.jpg differ diff --git a/manifest.json b/manifest.json index e6c526e..9700e1f 100644 --- a/manifest.json +++ b/manifest.json @@ -1,7 +1,7 @@ { "id": "obsidian-excalidraw-plugin", "name": "Excalidraw", - "version": "1.8.7", + "version": "1.8.8", "minAppVersion": "1.0.0", "description": "An Obsidian plugin to edit and view Excalidraw drawings", "author": "Zsolt Viczian", diff --git a/src/ExcalidrawAutomate.ts b/src/ExcalidrawAutomate.ts index 53e93c3..bbfec14 100644 --- a/src/ExcalidrawAutomate.ts +++ b/src/ExcalidrawAutomate.ts @@ -315,10 +315,14 @@ export class ExcalidrawAutomate implements ExcalidrawAutomateInterface { "excalidraw-url-prefix"?: string; "excalidraw-export-transparent"?: boolean; "excalidraw-export-dark"?: boolean; - "excalidraw-export-svgpadding"?: number; + "excalidraw-export-padding"?: number; "excalidraw-export-pngscale"?: number; "excalidraw-default-mode"?: "view" | "zen"; + "excalidraw-onload-script"?: string; + "excalidraw-linkbutton-opacity"?: number; + "excalidraw-autoexport"?: boolean; }; + plaintext?: string; //text to insert above the `# Text Elements` section }): Promise { const template = params?.templatePath ? await getTemplate( @@ -406,8 +410,9 @@ export class ExcalidrawAutomate implements ExcalidrawAutomateInterface { }; const generateMD = ():string => { + let outString = params.plaintext ? params.plaintext + "\n\n" : ""; const textElements = this.getElements().filter(el => el.type === "text") as ExcalidrawTextElement[]; - let outString = "# Text Elements\n"; + outString += "# Text Elements\n"; textElements.forEach(te=> { outString += `${te.rawText ?? (te.originalText ?? te.text)} ^${te.id}\n\n`; }); diff --git a/src/ExcalidrawView.ts b/src/ExcalidrawView.ts index 5dc97e8..c337e56 100644 --- a/src/ExcalidrawView.ts +++ b/src/ExcalidrawView.ts @@ -347,7 +347,7 @@ export default class ExcalidrawView extends TextFileView { ); } - public async svg(scene: any, theme?:string): Promise { + public async svg(scene: any, theme?:string, withBackground: boolean = false): Promise { const exportSettings: ExportSettings = { withBackground: getWithBackground(this.plugin, this.file), withTheme: true, @@ -359,6 +359,7 @@ export default class ExcalidrawView extends TextFileView { appState: { ...scene.appState, theme: theme ?? getExportTheme(this.plugin, this.file, scene.appState.theme), + exportEmbedScene: withBackground, }, }, }, @@ -367,7 +368,7 @@ export default class ExcalidrawView extends TextFileView { ); } - public async saveSVG(scene?: any) { + public async saveSVG(scene?: any, withBackground: boolean = false) { if (!scene) { if (!this.getScene) { return false; @@ -378,7 +379,7 @@ export default class ExcalidrawView extends TextFileView { const exportImage = async (filepath:string, theme?:string) => { const file = app.vault.getAbstractFileByPath(normalizePath(filepath)); - const svg = await this.svg(scene,theme); + const svg = await this.svg(scene,theme, withBackground); if (!svg) { return; } @@ -402,7 +403,7 @@ export default class ExcalidrawView extends TextFileView { } - public async png(scene: any, theme?:string): Promise { + public async png(scene: any, theme?:string, withBackground: boolean = false): Promise { const exportSettings: ExportSettings = { withBackground: getWithBackground(this.plugin, this.file), withTheme: true, @@ -414,6 +415,7 @@ export default class ExcalidrawView extends TextFileView { appState: { ...scene.appState, theme: theme ?? getExportTheme(this.plugin, this.file, scene.appState.theme), + exportEmbedScene: withBackground, }, }, }, @@ -423,7 +425,7 @@ export default class ExcalidrawView extends TextFileView { ); } - public async savePNG(scene?: any) { + public async savePNG(scene?: any, withBackground: boolean = false) { if (!scene) { if (!this.getScene) { return false; @@ -434,7 +436,7 @@ export default class ExcalidrawView extends TextFileView { const exportImage = async (filepath:string, theme?:string) => { const file = app.vault.getAbstractFileByPath(normalizePath(filepath)); - const png = await this.png(scene,theme); + const png = await this.png(scene, theme, withBackground); if (!png) { return; } @@ -1430,7 +1432,7 @@ export default class ExcalidrawView extends TextFileView { setTimeout(runScript,200); return; } - self.plugin.scriptEngine.executeScript(self,script,scriptname); + self.plugin.scriptEngine.executeScript(self,script,scriptname,this.file); } runScript(); } @@ -1871,7 +1873,7 @@ export default class ExcalidrawView extends TextFileView { return; } if (ev[CTRL_OR_CMD]) { - const png = await this.png(this.getScene()); + const png = await this.png(this.getScene(),undefined,ev.shiftKey); if (!png) { return; } @@ -1884,7 +1886,8 @@ export default class ExcalidrawView extends TextFileView { }; return; } - this.savePNG(); + this.savePNG(undefined,ev.shiftKey); + new Notice(`PNG export is ready${ev.shiftKey?" with embedded scene":""}`); }) .setSection("pane"); }) @@ -1898,7 +1901,7 @@ export default class ExcalidrawView extends TextFileView { return; } if (ev[CTRL_OR_CMD]) { - let svg = await this.svg(this.getScene()); + let svg = await this.svg(this.getScene(),undefined,ev.shiftKey); if (!svg) { return null; } @@ -1910,7 +1913,8 @@ export default class ExcalidrawView extends TextFileView { ); return; } - this.saveSVG(); + this.saveSVG(undefined,ev.shiftKey); + new Notice(`SVG export is ready${ev.shiftKey?" with embedded scene":""}`); }); }) .addItem(item => { @@ -2383,6 +2387,8 @@ export default class ExcalidrawView extends TextFileView { currentItemRoundness: st.currentItemRoundness, gridSize: st.gridSize, colorPalette: st.colorPalette, + //@ts-ignore + currentStrokeOptions: st.currentStrokeOptions, }, prevTextMode: this.prevTextMode, files, @@ -3270,7 +3276,8 @@ export default class ExcalidrawView extends TextFileView { } }, - }), + }//,React.createElement(Footer,{},React.createElement(customTextEditor.render)), + ), React.createElement(ToolsPanel, { ref: toolsPanelRef, visible: false, diff --git a/src/Scripts.ts b/src/Scripts.ts index b1b5b77..6bfe11d 100644 --- a/src/Scripts.ts +++ b/src/Scripts.ts @@ -169,7 +169,7 @@ export class ScriptEngine { (async()=>{ const script = await app.vault.read(f); if(script) { - this.executeScript(view, script, scriptName); + this.executeScript(view, script, scriptName,f); } })() return true; @@ -205,7 +205,7 @@ export class ScriptEngine { delete app.commands.commands[commandId]; } - async executeScript(view: ExcalidrawView, script: string, title: string) { + async executeScript(view: ExcalidrawView, script: string, title: string, file: TFile) { if (!view || !script || !title) { return; } @@ -245,6 +245,7 @@ export class ScriptEngine { hint, instructions, ), + scriptFile: file }); /*} catch (e) { new Notice(t("SCRIPT_EXECUTION_ERROR"), 4000); diff --git a/src/dialogs/Messages.ts b/src/dialogs/Messages.ts index 192521a..2e6162a 100644 --- a/src/dialogs/Messages.ts +++ b/src/dialogs/Messages.ts @@ -17,6 +17,25 @@ I develop this plugin as a hobby, spending my free time doing this. If you find
`, +"1.8.8":` +
+ +
+ +# New +- The plugin now includes support for [Perfect Freehand](https://perfect-freehand-example.vercel.app/) pen-options. I've also added a new [Alternative Pens](https://github.com/zsviczian/obsidian-excalidraw-plugin/blob/master/ea-scripts/Alternative%20Pens.md) script. +- Embed scene in exported PNG and SVG images [#860](https://github.com/zsviczian/obsidian-excalidraw-plugin/issues/860). This means that the export will be a normal PNG or SVG image with the added functionality that if someone loads the image into excalidraw.com it will open as a normal excalidraw file. + - I've added 2 new Command Palette actions (export PNG, export SVG with embedded scene). + - If you SHIFT click ${String.fromCharCode(96)} Save as PNG (or SVG)${String.fromCharCode(96)} in the workspace-tab menu, Excalidraw will embed the scene in the export. +- I updated the [Organic Line](https://github.com/zsviczian/obsidian-excalidraw-plugin/blob/master/ea-scripts/Organic%20Line.md) script. It has an improved thick-to-thin look and a new thin-to-thick-to-thin line type. + +# Fixed +- Intelligent image width setting [#955](https://github.com/zsviczian/obsidian-excalidraw-plugin/issues/955). Before this change, when the embedded image was small, the image would be extended to meet the image width setting in plugin settings. From now on, if the image is smaller than max-width, it will only extend to max-width. You can still set 100% width using custom CSS. See more on that [here](https://github.com/zsviczian/obsidian-excalidraw-plugin#embedded-images). + +# New in ExcalidrawAutomate +- I added the ${String.fromCharCode(96)} plaintext${String.fromCharCode(96)} parameter to ${String.fromCharCode(96)}ExcalidrawAutomate.create${String.fromCharCode(96)} . Using this, you can add some text below the frontmatter but above the ${String.fromCharCode(96)}# Text Elements${String.fromCharCode(96)} section. Use this for example to add metadata to your file. (e.g. I use this in my Daily Quote template to add a Dataview field for the ${String.fromCharCode(96)}Author::${String.fromCharCode(96)} and add the quote with a standard block reference, so I can easily reference it in other files. I also add the ${String.fromCharCode(96)}#quote${String.fromCharCode(96)} tag to the file using this.) +- The script running in the ScriptEngine now also receives the ${String.fromCharCode(96)}TFile${String.fromCharCode(96)} object for the script itself. You can access this object during execution via the ${String.fromCharCode(96)}utils.scriptFile${String.fromCharCode(96)} variable. +`, "1.8.7":` ## New from Excalidraw.com - Support shrinking text containers to their original height when text is removed [#6025](https://github.com/excalidraw/excalidraw/pull/6025) diff --git a/src/dialogs/SuggesterInfo.ts b/src/dialogs/SuggesterInfo.ts index 979c251..f3548df 100644 --- a/src/dialogs/SuggesterInfo.ts +++ b/src/dialogs/SuggesterInfo.ts @@ -528,6 +528,12 @@ export const EXCALIDRAW_SCRIPTENGINE_INFO: SuggesterInfo[] = [ desc: "Opens a suggester. Displays the displayItems and returns the corresponding item from items[]\nYou need to await the result of suggester.\nIf the user cancels (ESC), suggester will return undefined\nHint and instructions are optional\n\ninterface Instruction {command: string;purpose: string;}", after: "", }, + { + field: "scriptFile", + code: "scriptFile: TFile", + desc: "The TFile of the currently running script", + after: "", + }, ]; export const FRONTMATTER_KEYS_INFO: SuggesterInfo[] = [ diff --git a/src/lang/locale/en.ts b/src/lang/locale/en.ts index 4d94fbe..a80a1bf 100644 --- a/src/lang/locale/en.ts +++ b/src/lang/locale/en.ts @@ -39,6 +39,8 @@ export default { NEW_IN_POPOUT_WINDOW_EMBED: "Create a new drawing - IN A POPOUT WINDOW - and embed into active document", EXPORT_SVG: "Save as SVG next to the current file", EXPORT_PNG: "Save as PNG next to the current file", + EXPORT_SVG_WITH_SCENE: "Save as SVG with embedded Excalidraw Scene next to the current file", + EXPORT_PNG_WITH_SCENE: "Save as PNG with embedded Excalidraw Scene next to the current file", TOGGLE_LOCK: "Toggle Text Element edit RAW/PREVIEW", DELETE_FILE: "Delete selected Image or Markdown file from Obsidian Vault", INSERT_LINK_TO_ELEMENT: @@ -69,8 +71,8 @@ export default { //ExcalidrawView.ts INSTALL_SCRIPT_BUTTON: "Install or update Excalidraw Scripts", OPEN_AS_MD: "Open as Markdown", - SAVE_AS_PNG: "Save as PNG into Vault (CTRL/CMD+CLICK to export)", - SAVE_AS_SVG: "Save as SVG into Vault (CTRL/CMD+CLICK to export)", + SAVE_AS_PNG: "Save as PNG into Vault (CTRL/CMD+CLICK to export; SHIFT to embed scene)", + SAVE_AS_SVG: "Save as SVG into Vault (CTRL/CMD+CLICK to export; SHIFT to embed scene)", OPEN_LINK: "Open selected text as link\n(SHIFT+CLICK to open in a new pane)", EXPORT_EXCALIDRAW: "Export to an .Excalidraw file", LINK_BUTTON_CLICK_NO_TEXT: diff --git a/src/main.ts b/src/main.ts index 47dbecb..0a1c2f6 100644 --- a/src/main.ts +++ b/src/main.ts @@ -974,6 +974,24 @@ export default class ExcalidrawPlugin extends Plugin { }, }); + this.addCommand({ + id: "export-svg-scene", + name: t("EXPORT_SVG_WITH_SCENE"), + checkCallback: (checking: boolean) => { + if (checking) { + return ( + Boolean(this.app.workspace.getActiveViewOfType(ExcalidrawView)) + ); + } + const view = this.app.workspace.getActiveViewOfType(ExcalidrawView); + if (view) { + view.saveSVG(undefined,true); + return true; + } + return false; + }, + }); + this.addCommand({ id: "run-ocr", name: t("RUN_OCR"), @@ -1054,6 +1072,24 @@ export default class ExcalidrawPlugin extends Plugin { }, }); + this.addCommand({ + id: "export-png-scene", + name: t("EXPORT_PNG_WITH_SCENE"), + checkCallback: (checking: boolean) => { + if (checking) { + return ( + Boolean(this.app.workspace.getActiveViewOfType(ExcalidrawView)) + ); + } + const view = this.app.workspace.getActiveViewOfType(ExcalidrawView); + if (view) { + view.savePNG(undefined, true); + return true; + } + return false; + }, + }); + this.forceSaveCommand = this.addCommand({ id: "save", hotkeys: [{modifiers: ["Ctrl"], key:"s"}], //See also Poposcope diff --git a/src/menu/ToolsPanel.tsx b/src/menu/ToolsPanel.tsx index 8186fea..684aaea 100644 --- a/src/menu/ToolsPanel.tsx +++ b/src/menu/ToolsPanel.tsx @@ -609,7 +609,8 @@ export class ToolsPanel extends React.Component { this.props.view.plugin.scriptEngine.executeScript( this.props.view, await this.props.view.plugin.app.vault.read(f), - this.props.view.plugin.scriptEngine.getScriptName(f) + this.props.view.plugin.scriptEngine.getScriptName(f), + f ); } }}