mirror of
https://github.com/zsviczian/obsidian-excalidraw-plugin.git
synced 2025-08-06 05:46:28 +00:00
2.0.0
This commit is contained in:
@@ -1,11 +1,12 @@
|
||||
{
|
||||
"id": "obsidian-excalidraw-plugin",
|
||||
"name": "Excalidraw",
|
||||
"version": "1.9.28",
|
||||
"version": "2.0.0",
|
||||
"minAppVersion": "1.1.6",
|
||||
"description": "An Obsidian plugin to edit and view Excalidraw drawings",
|
||||
"author": "Zsolt Viczian",
|
||||
"authorUrl": "https://zsolt.blog",
|
||||
"fundingUrl": "https://ko-fi.com/zsolt",
|
||||
"helpUrl": "https://github.com/zsviczian/obsidian-excalidraw-plugin#readme",
|
||||
"isDesktopOnly": false
|
||||
}
|
||||
|
||||
@@ -19,13 +19,11 @@ import {
|
||||
getWithBackground,
|
||||
hasExportTheme,
|
||||
convertSVGStringToElement,
|
||||
getFileCSSClasses,
|
||||
} from "./utils/Utils";
|
||||
import { getParentOfClass, isObsidianThemeDark } from "./utils/ObsidianUtils";
|
||||
import { getParentOfClass, isObsidianThemeDark, getFileCSSClasses } from "./utils/ObsidianUtils";
|
||||
import { linkClickModifierType } from "./utils/ModifierkeyHelper";
|
||||
import { ImageKey, imageCache } from "./utils/ImageCache";
|
||||
import { FILENAMEPARTS, PreviewImageType } from "./utils/UtilTypes";
|
||||
import { css } from "chroma-js";
|
||||
|
||||
interface imgElementAttributes {
|
||||
file?: TFile;
|
||||
@@ -401,7 +399,7 @@ const createImgElement = async (
|
||||
newImg.setAttribute("fileSource",fileSource);
|
||||
parent.append(newImg);
|
||||
});
|
||||
const cssClasses = getFileCSSClasses(plugin, attr.file);
|
||||
const cssClasses = getFileCSSClasses(attr.file);
|
||||
cssClasses.forEach((cssClass) => imgOrDiv.addClass(cssClass));
|
||||
return imgOrDiv;
|
||||
}
|
||||
|
||||
@@ -16,6 +16,30 @@ export const RELEASE_NOTES: { [k: string]: string } = {
|
||||
I develop this plugin as a hobby, spending my free time doing this. If you find it valuable, then please say THANK YOU or...
|
||||
|
||||
<div class="ex-coffee-div"><a href="https://ko-fi.com/zsolt"><img src="https://cdn.ko-fi.com/cdn/kofi3.png?v=3" height=45></a></div>
|
||||
`,
|
||||
"2.0.0":`
|
||||
<div class="excalidraw-videoWrapper"><div>
|
||||
<iframe src="https://www.youtube.com/embed/JC1E-jeiWhI" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
|
||||
</div></div>
|
||||
|
||||
## New
|
||||
- Added support for applying CSS classes in frontmatter. Now, when embedding Excalidraw drawings into Obsidian Canvas, you can use [Canvas Candy](https://tfthacker.com/canvas-candy) classes. For instance, ${String.fromCharCode(96)}cssclasses: cc-border-none${String.fromCharCode(96)} removes the canvas node border around the drawing.
|
||||
- Introduced new context menu actions:
|
||||
- Navigate to link or embedded image.
|
||||
- Add any file from the vault to the canvas.
|
||||
- Convert the selected text element or sticky note to an embedded markdown file.
|
||||
- Add a link from the Vault to the selected element.
|
||||
- Frames are now rendered in exported images.
|
||||
- SVG Export includes the ${String.fromCharCode(96)}.excalidraw-svg${String.fromCharCode(96)} class, enabling post-processing of SVGs using publish.js when using custom domains with Obsidian Publish. Also, added a command palette action ${String.fromCharCode(96)}Obsidian Publish: Find SVG and PNG exports that are out of date${String.fromCharCode(96)}.
|
||||
- Added a new Command palette action to open the corresponding Excalidraw file based on the embedded SVG or PNG file. ${String.fromCharCode(96)}Open Excalidraw Drawing${String.fromCharCode(96)} [Issue #1411](https://github.com/zsviczian/obsidian-excalidraw-plugin/issues/1411)
|
||||
|
||||
## Fixed and Improved
|
||||
- Resolved issue with the Mermaid Timeline graph displaying all black. [Issue #1424](https://github.com/zsviczian/obsidian-excalidraw-plugin/issues/1424)
|
||||
- Enabled toggling pen mode off after activation by a pen touch.
|
||||
- Now you are able to unlock elements on mobile; previously, locked elements couldn't be selected.
|
||||
- Fixed the disabled ${String.fromCharCode(96)}complete line button${String.fromCharCode(96)} for multipoint lines on mobile.
|
||||

|
||||
|
||||
`,
|
||||
"1.9.28":`
|
||||
## Fixed & Improved
|
||||
|
||||
@@ -67,8 +67,7 @@ export class PublishOutOfDateFilesDialog extends Modal {
|
||||
text: "Video about Obsidian Publish support",
|
||||
});
|
||||
detailsEl.createEl("br");
|
||||
addIframe(detailsEl, "OX5_UYjXEvc", undefined, "");
|
||||
|
||||
addIframe(detailsEl, "JC1E-jeiWhI");
|
||||
const p = this.contentEl.createEl("p",{text: "Collecting data..."});
|
||||
const statusEl = this.contentEl.createEl("p", {text: "Status: "});
|
||||
const files = await listOfOutOfSyncImgExports(this.plugin, recursive, statusEl);
|
||||
|
||||
@@ -10,6 +10,7 @@ import { labelALT, labelCTRL, labelMETA, labelSHIFT } from "src/utils/Modifierke
|
||||
export default {
|
||||
// main.ts
|
||||
PUBLISH_SVG_CHECK: "Obsidian Publish: Find SVG and PNG exports that are out of date",
|
||||
OPEN_IMAGE_SOURCE: "Open Excalidraw drawing",
|
||||
INSTALL_SCRIPT: "Install the script",
|
||||
UPDATE_SCRIPT: "Update available - Click to install",
|
||||
CHECKING_SCRIPT:
|
||||
@@ -405,6 +406,11 @@ FILENAME_HEAD: "Filename",
|
||||
"or a PNG or an SVG copy. You need to enable auto-export PNG / SVG (see below under Export Settings) for those image types to be available in the dropdown. For drawings that do not have a " +
|
||||
"a corresponding PNG or SVG readily available the command palette action will insert a broken link. You need to open the original drawing and initiate export manually. " +
|
||||
"This option will not autogenerate PNG/SVG files, but will simply reference the already existing files.",
|
||||
EMBED_MARKDOWN_COMMENT_NAME: "Embed link to drawing as comment",
|
||||
EMBED_MARKDOWN_COMMENT_DESC:
|
||||
"Embed the link to the original Excalidraw file as a markdown link under the image, e.g.:<code>%%[[drawing.excalidraw]]%%</code>.<br>" +
|
||||
"Instead of adding a markdown comment you may also select the embedded SVG or PNG line and use the command palette action: " +
|
||||
"'<code>Excalidraw: Open Excalidraw drawing</code>' to open the drawing.",
|
||||
EMBED_WIKILINK_NAME: "Embed Drawing using Wiki link",
|
||||
EMBED_WIKILINK_DESC:
|
||||
"<b><u>Toggle ON:</u></b> Excalidraw will embed a [[wiki link]].<br><b><u>Toggle OFF:</u></b> Excalidraw will embed a [markdown](link).",
|
||||
|
||||
70
src/main.ts
70
src/main.ts
@@ -21,7 +21,6 @@ import {
|
||||
Editor,
|
||||
MarkdownFileInfo,
|
||||
loadMermaid,
|
||||
moment,
|
||||
} from "obsidian";
|
||||
import {
|
||||
BLANK_DRAWING,
|
||||
@@ -92,7 +91,7 @@ import {
|
||||
getExportTheme,
|
||||
isCallerFromTemplaterPlugin,
|
||||
} from "./utils/Utils";
|
||||
import { getAttachmentsFolderAndFilePath, getNewOrAdjacentLeaf, getParentOfClass, isObsidianThemeDark } from "./utils/ObsidianUtils";
|
||||
import { extractSVGPNGFileName, getAttachmentsFolderAndFilePath, getNewOrAdjacentLeaf, getParentOfClass, isObsidianThemeDark } from "./utils/ObsidianUtils";
|
||||
//import { OneOffs } from "./OneOffs";
|
||||
import { ExcalidrawElement, ExcalidrawImageElement, ExcalidrawTextElement, FileId } from "@zsviczian/excalidraw/types/element/types";
|
||||
import { ScriptEngine } from "./Scripts";
|
||||
@@ -117,7 +116,6 @@ import { UniversalInsertFileModal } from "./dialogs/UniversalInsertFileModal";
|
||||
import { imageCache } from "./utils/ImageCache";
|
||||
import { StylesManager } from "./utils/StylesManager";
|
||||
import { MATHJAX_SOURCE_LZCOMPRESSED } from "./constMathJaxSource";
|
||||
import { getEA } from "src";
|
||||
import { PublishOutOfDateFilesDialog } from "./dialogs/PublishOutOfDateFiles";
|
||||
|
||||
declare const EXCALIDRAW_PACKAGES:string;
|
||||
@@ -855,6 +853,37 @@ export default class ExcalidrawPlugin extends Plugin {
|
||||
}
|
||||
})
|
||||
|
||||
this.addCommand({
|
||||
id: "open-image-excalidraw-source",
|
||||
name: t("OPEN_IMAGE_SOURCE"),
|
||||
checkCallback: (checking: boolean) => {
|
||||
const view = this.app.workspace.getActiveViewOfType(MarkdownView);
|
||||
if(!view) return false;
|
||||
if(view.leaf !== this.app.workspace.activeLeaf) return false;
|
||||
const editor = view.editor;
|
||||
if(!editor) return false;
|
||||
const cursor = editor.getCursor();
|
||||
const line = editor.getLine(cursor.line);
|
||||
const fname = extractSVGPNGFileName(line);
|
||||
if(!fname) return false;
|
||||
const imgFile = this.app.metadataCache.getFirstLinkpathDest(fname, view.file.path);
|
||||
if(!imgFile) return false;
|
||||
const excalidrawFname = getIMGFilename(imgFile.path, "md");
|
||||
let excalidrawFile = this.app.metadataCache.getFirstLinkpathDest(excalidrawFname, view.file.path);
|
||||
if(!excalidrawFile) {
|
||||
if(excalidrawFname.endsWith(".dark.md")) {
|
||||
excalidrawFile = this.app.metadataCache.getFirstLinkpathDest(excalidrawFname.replace(/\.dark\.md$/,".md"), view.file.path);
|
||||
}
|
||||
if(excalidrawFname.endsWith(".light.md")) {
|
||||
excalidrawFile = this.app.metadataCache.getFirstLinkpathDest(excalidrawFname.replace(/\.light\.md$/,".md"), view.file.path);
|
||||
}
|
||||
if(!excalidrawFile) return false;
|
||||
}
|
||||
if(checking) return true;
|
||||
this.openDrawing(excalidrawFile, "new-tab", true);
|
||||
}
|
||||
});
|
||||
|
||||
this.addCommand({
|
||||
id: "excalidraw-disable-autosave",
|
||||
name: t("TEMPORARY_DISABLE_AUTOSAVE"),
|
||||
@@ -2362,7 +2391,9 @@ export default class ExcalidrawPlugin extends Plugin {
|
||||
)
|
||||
: "";
|
||||
|
||||
theme = theme===""?"":theme+".";
|
||||
theme = (theme === "")
|
||||
? ""
|
||||
: theme + ".";
|
||||
|
||||
const imageRelativePath = getIMGFilename(
|
||||
excalidrawRelativePath,
|
||||
@@ -2374,12 +2405,13 @@ export default class ExcalidrawPlugin extends Plugin {
|
||||
);
|
||||
|
||||
//will hold incorrect value if theme==="", however in that case it won't be used
|
||||
const otherTheme = theme === "dark." ? "light.":"dark.";
|
||||
const otherImageRelativePath = getIMGFilename(
|
||||
excalidrawRelativePath,
|
||||
otherTheme+this.settings.embedType.toLowerCase(),
|
||||
);
|
||||
|
||||
const otherTheme = theme === "dark." ? "light." : "dark.";
|
||||
const otherImageRelativePath = theme === ""
|
||||
? null
|
||||
: getIMGFilename(
|
||||
excalidrawRelativePath,
|
||||
otherTheme+this.settings.embedType.toLowerCase(),
|
||||
);
|
||||
|
||||
const imgFile = this.app.vault.getAbstractFileByPath(imageFullpath);
|
||||
if (!imgFile) {
|
||||
@@ -2387,13 +2419,21 @@ export default class ExcalidrawPlugin extends Plugin {
|
||||
await sleep(200); //wait for metadata cache to update
|
||||
}
|
||||
|
||||
const inclCom = this.settings.embedMarkdownCommentLinks;
|
||||
|
||||
editor.replaceSelection(
|
||||
this.settings.embedWikiLink
|
||||
? `![[${imageRelativePath}]]\n%%[[${excalidrawRelativePath}|🖋 Edit in Excalidraw]]${
|
||||
otherImageRelativePath ? ", and the [["+otherImageRelativePath+"|"+otherTheme.split(".")[0]+" exported image]]":""}%%`
|
||||
: `})\n%%[🖋 Edit in Excalidraw](${encodeURI(
|
||||
excalidrawRelativePath,
|
||||
)})${otherImageRelativePath?", and the ["+otherTheme.split(".")[0]+" exported image]("+encodeURI(otherImageRelativePath)+")":""}%%`,
|
||||
? `![[${imageRelativePath}]]\n` +
|
||||
(inclCom
|
||||
? `%%[[${excalidrawRelativePath}|🖋 Edit in Excalidraw]]${
|
||||
otherImageRelativePath
|
||||
? ", and the [["+otherImageRelativePath+"|"+otherTheme.split(".")[0]+" exported image]]"
|
||||
: ""
|
||||
}%%`
|
||||
: "")
|
||||
: `})\n` +
|
||||
(inclCom ? `%%[🖋 Edit in Excalidraw](${encodeURI(excalidrawRelativePath,
|
||||
)})${otherImageRelativePath?", and the ["+otherTheme.split(".")[0]+" exported image]("+encodeURI(otherImageRelativePath)+")":""}%%` : ""),
|
||||
);
|
||||
editor.focus();
|
||||
}
|
||||
|
||||
@@ -89,6 +89,7 @@ export interface ExcalidrawSettings {
|
||||
autoExportLightAndDark: boolean;
|
||||
autoexportExcalidraw: boolean;
|
||||
embedType: "excalidraw" | "PNG" | "SVG";
|
||||
embedMarkdownCommentLinks: boolean;
|
||||
embedWikiLink: boolean;
|
||||
syncExcalidraw: boolean;
|
||||
compatibilityMode: boolean;
|
||||
@@ -212,6 +213,7 @@ export const DEFAULT_SETTINGS: ExcalidrawSettings = {
|
||||
autoExportLightAndDark: false,
|
||||
autoexportExcalidraw: false,
|
||||
embedType: "excalidraw",
|
||||
embedMarkdownCommentLinks: true,
|
||||
embedWikiLink: true,
|
||||
syncExcalidraw: false,
|
||||
experimentalFileType: false,
|
||||
@@ -1200,7 +1202,7 @@ export class ExcalidrawSettingTab extends PluginSettingTab {
|
||||
addIframe(detailsEl, "opLd1SqaH_I",8);
|
||||
|
||||
let dropdown: DropdownComponent;
|
||||
|
||||
let embedComment: Setting;
|
||||
new Setting(detailsEl)
|
||||
.setName(t("EMBED_TYPE_NAME"))
|
||||
.setDesc(fragWithHTML(t("EMBED_TYPE_DESC")))
|
||||
@@ -1224,9 +1226,24 @@ export class ExcalidrawSettingTab extends PluginSettingTab {
|
||||
.onChange(async (value) => {
|
||||
//@ts-ignore
|
||||
this.plugin.settings.embedType = value;
|
||||
embedComment.settingEl.style.display = value === "excalidraw" ? "none":"";
|
||||
this.applySettingsUpdate();
|
||||
});
|
||||
});
|
||||
|
||||
embedComment = new Setting(detailsEl)
|
||||
.setName(t("EMBED_MARKDOWN_COMMENT_NAME"))
|
||||
.setDesc(fragWithHTML(t("EMBED_MARKDOWN_COMMENT_DESC")))
|
||||
.addToggle((toggle) =>
|
||||
toggle
|
||||
.setValue(this.plugin.settings.embedMarkdownCommentLinks)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.embedMarkdownCommentLinks = value;
|
||||
this.applySettingsUpdate();
|
||||
}),
|
||||
);
|
||||
|
||||
embedComment.settingEl.style.display = this.plugin.settings.embedType === "excalidraw" ? "none":"";
|
||||
|
||||
new Setting(detailsEl)
|
||||
.setName(t("EMBED_WIKILINK_NAME"))
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import {
|
||||
App,
|
||||
normalizePath, Workspace, WorkspaceLeaf, WorkspaceSplit
|
||||
normalizePath, parseFrontMatterEntry, TFile, Workspace, WorkspaceLeaf, WorkspaceSplit
|
||||
} from "obsidian";
|
||||
import ExcalidrawPlugin from "../main";
|
||||
import { checkAndCreateFolder, splitFolderAndFilename } from "./FileUtils";
|
||||
@@ -233,3 +233,24 @@ export const obsidianPDFQuoteWithRef = (text:string):{quote: string, link: strin
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
export const extractSVGPNGFileName = (text:string) => {
|
||||
const regex = /\[\[([^\]|#^]+\.(?:svg|png))(?:[^\]]+)?\]\]|\[[^\]]+\]\(([^\)]+\.(?:svg|png))\)/;
|
||||
const match = text.match(regex);
|
||||
return match ? (match[1] || match[2]) : null;
|
||||
}
|
||||
|
||||
export const getFileCSSClasses = (
|
||||
file: TFile,
|
||||
): string[] => {
|
||||
if (file) {
|
||||
const plugin = window.ExcalidrawAutomate.plugin;
|
||||
const fileCache = plugin.app.metadataCache.getFileCache(file);
|
||||
if(!fileCache?.frontmatter) return [];
|
||||
const x = parseFrontMatterEntry(fileCache.frontmatter, "cssclasses");
|
||||
if (Array.isArray(x)) return x
|
||||
if (typeof x === "string") return Array.from(new Set(x.split(/[, ]+/).filter(Boolean)));
|
||||
return [];
|
||||
}
|
||||
return [];
|
||||
}
|
||||
@@ -33,7 +33,7 @@ import { generateEmbeddableLink } from "./CustomEmbeddableUtils";
|
||||
import ExcalidrawScene from "src/svgToExcalidraw/elements/ExcalidrawScene";
|
||||
import { FILENAMEPARTS } from "./UtilTypes";
|
||||
import { Mutable } from "@zsviczian/excalidraw/types/utility-types";
|
||||
import { cleanBlockRef, cleanSectionHeading } from "./ObsidianUtils";
|
||||
import { cleanBlockRef, cleanSectionHeading, getFileCSSClasses } from "./ObsidianUtils";
|
||||
import { updateElementLinksToObsidianLinks } from "src/ExcalidrawAutomate";
|
||||
|
||||
|
||||
@@ -295,6 +295,10 @@ export const getSVG = async (
|
||||
});
|
||||
if(svg) {
|
||||
svg.addClass("excalidraw-svg");
|
||||
if(srcFile instanceof TFile) {
|
||||
const cssClasses = getFileCSSClasses(srcFile);
|
||||
cssClasses.forEach((cssClass) => svg.addClass(cssClass));
|
||||
}
|
||||
}
|
||||
return svg;
|
||||
} catch (error) {
|
||||
@@ -616,21 +620,6 @@ export const getExportPadding = (
|
||||
return plugin.settings.exportPaddingSVG;
|
||||
};
|
||||
|
||||
export const getFileCSSClasses = (
|
||||
plugin: ExcalidrawPlugin,
|
||||
file: TFile,
|
||||
): string[] => {
|
||||
if (file) {
|
||||
const fileCache = plugin.app.metadataCache.getFileCache(file);
|
||||
if(!fileCache?.frontmatter) return [];
|
||||
const x = parseFrontMatterEntry(fileCache.frontmatter, "cssclasses");
|
||||
if (Array.isArray(x)) return x
|
||||
if (typeof x === "string") return Array.from(new Set(x.split(/[, ]+/).filter(Boolean)));
|
||||
return [];
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
export const getPNGScale = (plugin: ExcalidrawPlugin, file: TFile): number => {
|
||||
if (file) {
|
||||
const fileCache = plugin.app.metadataCache.getFileCache(file);
|
||||
|
||||
Reference in New Issue
Block a user