This commit is contained in:
zsviczian
2023-11-13 22:16:43 +01:00
parent 21bc1f7fa6
commit c440dd9cf0
9 changed files with 135 additions and 40 deletions

View File

@@ -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
}

View File

@@ -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;
}

View File

@@ -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.
![Mobile Editing Image](https://github.com/zsviczian/obsidian-excalidraw-plugin/assets/14358394/e7051c75-818f-4800-ba16-ac276e229184)
`,
"1.9.28":`
## Fixed & Improved

View File

@@ -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);

View File

@@ -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).",

View File

@@ -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]]":""}%%`
: `![](${encodeURI(imageRelativePath)})\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]]"
: ""
}%%`
: "")
: `![](${encodeURI(imageRelativePath)})\n` +
(inclCom ? `%%[🖋 Edit in Excalidraw](${encodeURI(excalidrawRelativePath,
)})${otherImageRelativePath?", and the ["+otherTheme.split(".")[0]+" exported image]("+encodeURI(otherImageRelativePath)+")":""}%%` : ""),
);
editor.focus();
}

View File

@@ -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"))

View File

@@ -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 [];
}

View File

@@ -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);