This commit is contained in:
zsviczian
2024-02-02 20:34:23 +01:00
parent 5db4f8dd95
commit e8db9cbff6
26 changed files with 584 additions and 280 deletions

View File

@@ -1,8 +1,8 @@
import { ExcalidrawFrameElement, ExcalidrawImageElement } from "@zsviczian/excalidraw/types/excalidraw/element/types";
import { ExcalidrawEmbeddableElement, ExcalidrawFrameElement, ExcalidrawImageElement } from "@zsviczian/excalidraw/types/excalidraw/element/types";
import { Mutable } from "@zsviczian/excalidraw/types/excalidraw/utility-types";
import { getEA } from "src";
import { ExcalidrawAutomate } from "src/ExcalidrawAutomate";
import { splitFolderAndFilename } from "./FileUtils";
import { getCropFileNameAndFolder, splitFolderAndFilename } from "./FileUtils";
import { Notice, TFile } from "obsidian";
import ExcalidrawView from "src/ExcalidrawView";
import { ExcalidrawImperativeAPI } from "@zsviczian/excalidraw/types/excalidraw/types";
@@ -34,20 +34,20 @@ export const carveOutImage = async (sourceEA: ExcalidrawAutomate, viewImageEl: E
let imageLink = "";
let fname = "";
if(ef.file) {
fname = CROPPED_PREFIX + ef.file.basename;
imageLink = `[[${ef.file.path}]]`;
fname = ef.file.basename;
const ref = ef.linkParts?.ref ? `#${ef.linkParts.ref}` : ``;
imageLink = `[[${ef.file.path}${ref}]]`;
} else {
const imagename = ef.hyperlink?.match(/^.*\/([^?]*)\??.*$/)?.[1];
imageLink = ef.hyperlink;
fname = viewImageEl
? CROPPED_PREFIX + imagename.substring(0,imagename.lastIndexOf("."))
: CROPPED_PREFIX + "_image";
? imagename.substring(0,imagename.lastIndexOf("."))
: "_image";
}
const attachmentPath = await sourceEA.getAttachmentFilepath(fname + ".md");
const {folderpath: foldername, filename} = splitFolderAndFilename(attachmentPath);
const {folderpath, filename} = await getCropFileNameAndFolder(sourceEA.plugin,sourceEA.targetView.file.path,fname);
const file = await createImageCropperFile(targetEA, newImage.id, imageLink, foldername, filename);
const file = await createImageCropperFile(targetEA, newImage.id, imageLink, folderpath, filename);
if(!file) return;
//console.log(await app.vault.read(file));
@@ -65,13 +65,57 @@ export const carveOutImage = async (sourceEA: ExcalidrawAutomate, viewImageEl: E
sourceEA.addElementsToView(false, true, true);
}
export const carveOutPDF = async (sourceEA: ExcalidrawAutomate, embeddableEl: ExcalidrawEmbeddableElement, pdfPathWithPage: string, pdfFile: TFile) => {
if(!embeddableEl || !pdfPathWithPage || !sourceEA?.targetView) return;
const targetEA = getEA(sourceEA.targetView) as ExcalidrawAutomate;
const {height, width} = embeddableEl;
if(!height || !width || height === 0 || width === 0) return;
const imageId = await targetEA.addImage(0,0, pdfPathWithPage);
const newImage = targetEA.getElement(imageId) as Mutable<ExcalidrawImageElement>;
newImage.x = 0;
newImage.y = 0;
newImage.width = width;
newImage.height = height;
const angle = embeddableEl.angle;
const fname = pdfFile.basename;
const imageLink = `[[${pdfPathWithPage}]]`;
const {folderpath, filename} = await getCropFileNameAndFolder(sourceEA.plugin,sourceEA.targetView.file.path,fname);
const file = await createImageCropperFile(targetEA, newImage.id, imageLink, folderpath, filename);
if(!file) return;
//console.log(await app.vault.read(file));
sourceEA.clear();
const replacingImageID = await sourceEA.addImage(embeddableEl.x + embeddableEl.width + 10, embeddableEl.y, file, true);
const replacingImage = sourceEA.getElement(replacingImageID) as Mutable<ExcalidrawImageElement>;
const imageAspectRatio = replacingImage.width / replacingImage.height;
if(imageAspectRatio > 1) {
replacingImage.width = embeddableEl.width;
replacingImage.height = replacingImage.width / imageAspectRatio;
} else {
replacingImage.height = embeddableEl.height;
replacingImage.width = replacingImage.height * imageAspectRatio;
}
replacingImage.angle = angle;
sourceEA.addElementsToView(false, true, true);
}
export const createImageCropperFile = async (targetEA: ExcalidrawAutomate, imageID: string, imageLink:string, foldername: string, filename: string): Promise<TFile> => {
const workspace = targetEA.plugin.app.workspace;
const vault = targetEA.plugin.app.vault;
const newImage = targetEA.getElement(imageID) as Mutable<ExcalidrawImageElement>;
const { width, height } = newImage;
const isPDF = imageLink.match(/\[\[([^#]*)#.*]]/)?.[1]?.endsWith(".pdf");
newImage.opacity = 100;
newImage.locked = true;
newImage.link = imageLink;
const frameID = targetEA.addFrame(0,0,width,height,"Adjust frame to crop image. Add elements for mask: White shows, Black hides.");
const frame = targetEA.getElement(frameID) as Mutable<ExcalidrawFrameElement>;
@@ -87,7 +131,7 @@ export const createImageCropperFile = async (targetEA: ExcalidrawAutomate, image
targetEA.style.roughness = 0;
targetEA.style.roundness = null;
targetEA.canvas.theme = "light";
targetEA.canvas.viewBackgroundColor = "#3d3d3d";
targetEA.canvas.viewBackgroundColor = isPDF ? "#5d5d5d" : "#3d3d3d";
const templateFile = app.vault.getAbstractFileByPath(targetEA.plugin.settings.templateFilePath);
if(templateFile && templateFile instanceof TFile) {
@@ -107,6 +151,7 @@ export const createImageCropperFile = async (targetEA: ExcalidrawAutomate, image
"excalidraw-export-dark": false,
"excalidraw-export-padding": 0,
"excalidraw-export-transparent": true,
...isPDF ? {"cssclasses": "excalidraw-cropped-pdfpage"} : {},
}
});

View File

@@ -98,7 +98,7 @@ export const setDynamicStyle = (
[`--color-gray-50`]: str(text), //frame
[`--color-surface-highlight`]: str(gray1()),
//[`--color-gray-30`]: str(gray1),
[`--color-gray-80`]: str(isDark?text.lighterBy(15):text.darkerBy(15)), //frame
[`--color-gray-80`]: str(isDark?text.darkerBy(40):text.lighterBy(40)), //frame
[`--sidebar-border-color`]: str(gray1()),
[`--color-primary-light`]: str(accent().lighterBy(step)),
[`--button-hover-bg`]: str(gray1()),
@@ -130,7 +130,7 @@ export const setDynamicStyle = (
const frameColor = {
stroke: str(isDark?gray2().lighterBy(15):gray2().darkerBy(15)),
fill: str((isDark?gray2().lighterBy(30):gray2().darkerBy(30)).alphaTo(0.2)),
nameColor: str(isDark?gray2().lighterBy(40):gray2().darkerBy(40)),
nameColor: str(isDark?gray2().lighterBy(50):gray2().darkerBy(50)),
}
const scene = api.getSceneElements();
scene.filter(el=>el.type==="frame").forEach((e:ExcalidrawFrameElement)=>{

View File

@@ -1,8 +1,11 @@
import { MAX_IMAGE_SIZE, IMAGE_TYPES, ANIMATED_IMAGE_TYPES } from "src/constants/constants";
import { TFile } from "obsidian";
import { App, TFile } from "obsidian";
import { ExcalidrawAutomate } from "src/ExcalidrawAutomate";
import { REGEX_LINK, REG_LINKINDEX_HYPERLINK } from "src/ExcalidrawData";
import ExcalidrawView from "src/ExcalidrawView";
import { ExcalidrawElement } from "@zsviczian/excalidraw/types/excalidraw/element/types";
import { getLinkParts } from "./Utils";
export const insertImageToView = async (
ea: ExcalidrawAutomate,
@@ -61,4 +64,56 @@ export const getLinkTextFromLink = (text: string): string => {
if (linktext.match(REG_LINKINDEX_HYPERLINK)) return;
return linktext;
}
export const openTagSearch = (link:string, app: App, view?: ExcalidrawView) => {
const tags = link
.matchAll(/#([\p{Letter}\p{Emoji_Presentation}\p{Number}\/_-]+)/gu)
.next();
if (!tags.value || tags.value.length < 2) {
return;
}
const search = app.workspace.getLeavesOfType("search");
if (search.length == 0) {
return;
}
//@ts-ignore
search[0].view.setQuery(`tag:${tags.value[1]}`);
app.workspace.revealLeaf(search[0]);
if (view && view.isFullscreen()) {
view.exitFullscreen();
}
return;
}
export const openExternalLink = (link:string, app: App, element?: ExcalidrawElement):boolean => {
if (link.match(/^cmd:\/\/.*/)) {
const cmd = link.replace("cmd://", "");
//@ts-ignore
app.commands.executeCommandById(cmd);
return true;
}
if (link.match(REG_LINKINDEX_HYPERLINK)) {
window.open(link, "_blank");
return true;
}
return false;
}
export const getExcalidrawFileForwardLinks = (app: App, excalidrawFile: TFile):string => {
let secondOrderLinks = "";
const forwardLinks = app.metadataCache.getLinks()[excalidrawFile.path];
if(forwardLinks && forwardLinks.length > 0) {
const linkset = new Set<string>();
forwardLinks.forEach(link => {
const linkparts = getLinkParts(link.link);
const f = app.metadataCache.getFirstLinkpathDest(linkparts.path, excalidrawFile.path);
if(f && f.path !== excalidrawFile.path) {
linkset.add(`[[${f.path}${linkparts.ref?"#"+linkparts.ref:""}|Second Order Link: ${f.basename}]]`);
}
});
secondOrderLinks = [...linkset].join(" ");
}
return secondOrderLinks;
}

View File

@@ -5,6 +5,9 @@ import { IMAGE_MIME_TYPES, MimeType } from "src/EmbeddedFileLoader";
import { ExcalidrawSettings } from "src/settings";
import { errorlog, getDataURL } from "./Utils";
import ExcalidrawPlugin from "src/main";
import ExcalidrawView from "src/ExcalidrawView";
import { CROPPED_PREFIX } from "./CarveOut";
import { getAttachmentsFolderAndFilePath } from "./ObsidianUtils";
/**
* Splits a full path including a folderpath and a filename into separate folderpath and filename components
@@ -370,4 +373,17 @@ export const getLink = (
return plugin.settings.embedWikiLink
? `${embed ? "!" : ""}[[${path}${alias ? `|${alias}` : ""}]]`
: `${embed ? "!" : ""}[${alias ?? ""}](${encodeURI(path)})`
}
export const getCropFileNameAndFolder = async (plugin: ExcalidrawPlugin, hostPath: string, baseNewFileName: string):Promise<{folderpath: string, filename: string}> => {
let prefix = plugin.settings.cropPrefix;
if(!prefix || prefix.trim() === "") prefix = CROPPED_PREFIX;
const filename = prefix + baseNewFileName + ".md";
if(!plugin.settings.cropFolder || plugin.settings.cropFolder.trim() === "") {
const folderpath = (await getAttachmentsFolderAndFilePath(plugin.app, hostPath, filename)).folder;
return {folderpath, filename};
}
const folderpath = normalizePath(plugin.settings.cropFolder);
await checkAndCreateFolder(folderpath);
return {folderpath, filename};
}

View File

@@ -1,6 +1,6 @@
import {
App,
normalizePath, parseFrontMatterEntry, TFile, Workspace, WorkspaceLeaf, WorkspaceSplit
normalizePath, parseFrontMatterEntry, TFile, View, Workspace, WorkspaceLeaf, WorkspaceSplit
} from "obsidian";
import ExcalidrawPlugin from "../main";
import { checkAndCreateFolder, splitFolderAndFilename } from "./FileUtils";
@@ -254,4 +254,7 @@ export const getFileCSSClasses = (
return [];
}
return [];
}
}
//@ts-ignore
export const getActivePDFPageNumberFromPDFView = (view: View): number => view?.viewer?.child?.pdfViewer?.page;

View File

@@ -13,15 +13,10 @@ import {
VIRGIL_FONT,
} from "src/constants/constFonts";
import {
FRONTMATTER_KEY_EXPORT_DARK,
FRONTMATTER_KEY_EXPORT_TRANSPARENT,
FRONTMATTER_KEY_EXPORT_SVGPADDING,
FRONTMATTER_KEY_EXPORT_PNGSCALE,
FRONTMATTER_KEY_EXPORT_PADDING,
exportToSvg,
exportToBlob,
IMAGE_TYPES,
FRONTMATTER_KEY_MASK
FRONTMATTER_KEYS,
} from "../constants/constants";
import ExcalidrawPlugin from "../main";
import { ExcalidrawElement } from "@zsviczian/excalidraw/types/excalidraw/element/types";
@@ -548,9 +543,9 @@ export const isMaskFile = (
const fileCache = plugin.app.metadataCache.getFileCache(file);
if (
fileCache?.frontmatter &&
fileCache.frontmatter[FRONTMATTER_KEY_MASK] != null
fileCache.frontmatter[FRONTMATTER_KEYS["mask"].name] != null
) {
return Boolean(fileCache.frontmatter[FRONTMATTER_KEY_MASK]);
return Boolean(fileCache.frontmatter[FRONTMATTER_KEYS["mask"].name]);
}
}
return false;
@@ -564,7 +559,7 @@ export const hasExportTheme = (
const fileCache = plugin.app.metadataCache.getFileCache(file);
if (
fileCache?.frontmatter &&
fileCache.frontmatter[FRONTMATTER_KEY_EXPORT_DARK] != null
fileCache.frontmatter[FRONTMATTER_KEYS["export-dark"].name] != null
) {
return true;
}
@@ -581,9 +576,9 @@ export const getExportTheme = (
const fileCache = plugin.app.metadataCache.getFileCache(file);
if (
fileCache?.frontmatter &&
fileCache.frontmatter[FRONTMATTER_KEY_EXPORT_DARK] != null
fileCache.frontmatter[FRONTMATTER_KEYS["export-dark"].name] != null
) {
return fileCache.frontmatter[FRONTMATTER_KEY_EXPORT_DARK]
return fileCache.frontmatter[FRONTMATTER_KEYS["export-dark"].name]
? "dark"
: "light";
}
@@ -599,7 +594,7 @@ export const hasExportBackground = (
const fileCache = plugin.app.metadataCache.getFileCache(file);
if (
fileCache?.frontmatter &&
fileCache.frontmatter[FRONTMATTER_KEY_EXPORT_TRANSPARENT] != null
fileCache.frontmatter[FRONTMATTER_KEYS["export-transparent"].name] != null
) {
return true;
}
@@ -615,9 +610,9 @@ export const getWithBackground = (
const fileCache = plugin.app.metadataCache.getFileCache(file);
if (
fileCache?.frontmatter &&
fileCache.frontmatter[FRONTMATTER_KEY_EXPORT_TRANSPARENT] != null
fileCache.frontmatter[FRONTMATTER_KEYS["export-transparent"].name] != null
) {
return !fileCache.frontmatter[FRONTMATTER_KEY_EXPORT_TRANSPARENT];
return !fileCache.frontmatter[FRONTMATTER_KEYS["export-transparent"].name];
}
}
return plugin.settings.exportWithBackground;
@@ -631,9 +626,9 @@ export const getExportPadding = (
const fileCache = plugin.app.metadataCache.getFileCache(file);
if(!fileCache?.frontmatter) return plugin.settings.exportPaddingSVG;
if (fileCache.frontmatter[FRONTMATTER_KEY_EXPORT_PADDING] != null) {
if (fileCache.frontmatter[FRONTMATTER_KEYS["export-padding"].name] != null) {
const val = parseInt(
fileCache.frontmatter[FRONTMATTER_KEY_EXPORT_PADDING],
fileCache.frontmatter[FRONTMATTER_KEYS["export-padding"].name],
);
if (!isNaN(val)) {
return val;
@@ -641,9 +636,9 @@ export const getExportPadding = (
}
//depricated. Retained for backward compatibility
if (fileCache.frontmatter[FRONTMATTER_KEY_EXPORT_SVGPADDING] != null) {
if (fileCache.frontmatter[FRONTMATTER_KEYS["export-svgpadding"].name] != null) {
const val = parseInt(
fileCache.frontmatter[FRONTMATTER_KEY_EXPORT_SVGPADDING],
fileCache.frontmatter[FRONTMATTER_KEYS["export-svgpadding"].name],
);
if (!isNaN(val)) {
return val;
@@ -659,10 +654,10 @@ export const getPNGScale = (plugin: ExcalidrawPlugin, file: TFile): number => {
const fileCache = plugin.app.metadataCache.getFileCache(file);
if (
fileCache?.frontmatter &&
fileCache.frontmatter[FRONTMATTER_KEY_EXPORT_PNGSCALE] != null
fileCache.frontmatter[FRONTMATTER_KEYS["export-pngscale"].name] != null
) {
const val = parseFloat(
fileCache.frontmatter[FRONTMATTER_KEY_EXPORT_PNGSCALE],
fileCache.frontmatter[FRONTMATTER_KEYS["export-pngscale"].name],
);
if (!isNaN(val) && val > 0) {
return val;