mirror of
https://github.com/zsviczian/obsidian-excalidraw-plugin.git
synced 2025-08-06 05:46:28 +00:00
canvas node wip
This commit is contained in:
@@ -93,10 +93,11 @@ import {
|
||||
hyperlinkIsYouTubeLink,
|
||||
getYouTubeThumbnailLink,
|
||||
isContainer,
|
||||
fragWithHTML,
|
||||
} from "./utils/Utils";
|
||||
import { getLeaf, getParentOfClass } from "./utils/ObsidianUtils";
|
||||
import { splitFolderAndFilename } from "./utils/FileUtils";
|
||||
import { ConfirmationPrompt, NewFileActions, Prompt } from "./dialogs/Prompt";
|
||||
import { ConfirmationPrompt, GenericInputPrompt, NewFileActions, Prompt } from "./dialogs/Prompt";
|
||||
import { ClipboardData } from "@zsviczian/excalidraw/types/clipboard";
|
||||
import { updateEquation } from "./LaTeX";
|
||||
import {
|
||||
@@ -778,7 +779,14 @@ export default class ExcalidrawView extends TextFileView {
|
||||
el.addClass(SHOW);
|
||||
el = el.parentElement;
|
||||
}
|
||||
if(el) el.addClass(SHOW);
|
||||
if(el) {
|
||||
el.addClass(SHOW);
|
||||
el.querySelectorAll(`div.workspace-split:not(.${SHOW})`).forEach(el=>el.addClass(SHOW));
|
||||
el.querySelector(`div.workspace-leaf-content.${SHOW} > .view-header`).addClass(SHOW);
|
||||
el.querySelectorAll(`div.workspace-tab-container.${SHOW} > div.workspace-leaf:not(.${SHOW})`).forEach(el=>el.addClass(SHOW));
|
||||
el.querySelectorAll(`div.workspace-tabs.${SHOW} > div.workspace-tab-header-container`).forEach(el=>el.addClass(SHOW));
|
||||
el.querySelectorAll(`div.workspace-split.${SHOW} > div.workspace-tabs:not(.${SHOW})`).forEach(el=>el.addClass(SHOW));
|
||||
}
|
||||
const doc = this.ownerDocument;
|
||||
doc.body.querySelectorAll(`div.workspace-split:not(.${SHOW})`).forEach(el=>el.addClass(HIDE));
|
||||
doc.body.querySelector(`div.workspace-leaf-content.${SHOW} > .view-header`).addClass(HIDE);
|
||||
@@ -991,22 +999,28 @@ export default class ExcalidrawView extends TextFileView {
|
||||
ef.file.extension === "md" &&
|
||||
!this.plugin.isExcalidrawFile(ef.file)
|
||||
) {
|
||||
const prompt = new Prompt(
|
||||
app,
|
||||
"Customize the link",
|
||||
ef.linkParts.original,
|
||||
"",
|
||||
"Do not add [[square brackets]] around the filename!<br>Follow this format when editing your link:<br><mark>filename#^blockref|WIDTHxMAXHEIGHT</mark>",
|
||||
);
|
||||
prompt.openAndGetValue(async (link: string) => {
|
||||
const handler = async (link:string) => {
|
||||
if (!link || ef.linkParts.original === link) {
|
||||
return;
|
||||
}
|
||||
ef.resetImage(this.file.path, link);
|
||||
this.setDirty(2);
|
||||
await this.save(false);
|
||||
await this.loadSceneFiles();
|
||||
this.setDirty(2);
|
||||
});
|
||||
}
|
||||
GenericInputPrompt.Prompt(
|
||||
this,
|
||||
this.plugin,
|
||||
app,
|
||||
"Customize the link",
|
||||
undefined,
|
||||
ef.linkParts.original,
|
||||
[{caption: "✅", action: handler}],
|
||||
1,
|
||||
false,
|
||||
(container) => container.createEl("p",{text: fragWithHTML("Do not add [[square brackets]] around the filename!<br>Follow this format when editing your link:<br><mark>filename#^blockref|WIDTHxMAXHEIGHT</mark>")}),
|
||||
false
|
||||
).then(handler, () => {});
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -3769,7 +3783,7 @@ export default class ExcalidrawView extends TextFileView {
|
||||
|
||||
}
|
||||
},
|
||||
iframeURLWhitelist: [/.*/],
|
||||
iframeURLWhitelist: [true],
|
||||
renderCustomIFrame: (
|
||||
element: NonDeletedExcalidrawElement,
|
||||
radius: number,
|
||||
|
||||
@@ -2,7 +2,7 @@ import { NonDeletedExcalidrawElement } from "@zsviczian/excalidraw/types/element
|
||||
import ExcalidrawView from "./ExcalidrawView";
|
||||
import { Notice, Workspace, WorkspaceLeaf, WorkspaceSplit } from "obsidian";
|
||||
import * as React from "react";
|
||||
import { getParentOfClass, isObsidianThemeDark } from "./utils/ObsidianUtils";
|
||||
import { ConstructableWorkspaceSplit, getContainerForDocument, getParentOfClass, isObsidianThemeDark } from "./utils/ObsidianUtils";
|
||||
import { getLinkParts } from "./utils/Utils";
|
||||
import { DEVICE, REG_LINKINDEX_INVALIDCHARS } from "./Constants";
|
||||
import { ExcalidrawImperativeAPI, UIAppState } from "@zsviczian/excalidraw/types/types";
|
||||
@@ -58,17 +58,6 @@ const VIMEO_REG =
|
||||
/^(?:http(?:s)?:\/\/)?(?:(?:w){3}.)?(?:player\.)?vimeo\.com\/(?:video\/)?([^?\s]+)(?:\?.*)?$/;
|
||||
const TWITTER_REG = /^(?:http(?:s)?:\/\/)?(?:(?:w){3}.)?twitter.com/;
|
||||
|
||||
type ConstructableWorkspaceSplit = new (ws: Workspace, dir: "horizontal"|"vertical") => WorkspaceSplit;
|
||||
|
||||
const getContainerForDocument = (doc:Document) => {
|
||||
if (doc !== document && app.workspace.floatingSplit) {
|
||||
for (const container of app.workspace.floatingSplit.children) {
|
||||
if (container.doc === doc) return container;
|
||||
}
|
||||
}
|
||||
return app.workspace.rootSplit;
|
||||
};
|
||||
|
||||
export const useDefaultExcalidrawFrame = (element: NonDeletedExcalidrawElement) => {
|
||||
return element.link.match(YOUTUBE_REG) || element.link.match(VIMEO_REG);
|
||||
}
|
||||
@@ -226,6 +215,8 @@ function RenderObsidianView(
|
||||
return;
|
||||
}
|
||||
leafRef.current.view.setMode(modes['source']);
|
||||
//@ts-ignore
|
||||
window.al = leafRef.current;
|
||||
app.workspace.setActiveLeaf(leafRef.current);
|
||||
isEditingRef.current = true;
|
||||
patchMobileView();
|
||||
@@ -309,22 +300,6 @@ export const CustomIFrame: React.FC<{element: NonDeletedExcalidrawElement; radiu
|
||||
view={view}
|
||||
containerRef={containerRef}
|
||||
appState={appState}/>
|
||||
{(appState.activeIFrame?.element === element && appState.activeIFrame?.state === "hover") && (<div
|
||||
style={{
|
||||
content: "",
|
||||
position: "absolute",
|
||||
top: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
width: `100%`,
|
||||
height: `100%`,
|
||||
background: `radial-gradient(
|
||||
ellipse at center,
|
||||
rgba(0, 0, 0, 0) 20%,
|
||||
rgba(0, 0, 0, 0.6) 80%
|
||||
)`,
|
||||
}}/>)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -192,12 +192,15 @@ export class UniversalInsertFileModal extends Modal {
|
||||
.setButtonText("as Image")
|
||||
.onClick(async () => {
|
||||
const ea:ExcalidrawAutomate = getEA(this.view);
|
||||
const isMarkdown = file && file.extension === "md" && !ea.isExcalidrawFile(file);
|
||||
ea.selectElementsInView(
|
||||
[await insertImageToView (
|
||||
ea,
|
||||
this.center,
|
||||
//this.view.currentPosition,
|
||||
file,
|
||||
isMarkdown && sectionPicker.selectEl.value && sectionPicker.selectEl.value !== ""
|
||||
? `${file.path}${sectionPicker.selectEl.value}`
|
||||
: file,
|
||||
ea.isExcalidrawFile(file) ? !anchorTo100 : undefined,
|
||||
)]
|
||||
);
|
||||
|
||||
@@ -100,6 +100,7 @@ export default {
|
||||
CACHE_NOT_READY: "I am sorry, but there was an error loading your file. The plugin has a backup cache, but it looks like as if you've just started Obsidian. Initialization of the Backup Cache " +
|
||||
"can take up to a minute (or more depending on your device). You will be notified when the cache initialization is completed." +
|
||||
"<br><br>Press OK to try again, or Cancel to manually correct your file or to come back later.",
|
||||
OBSIDIAN_TOOLS_PANEL: "Obsidian Tools Panel",
|
||||
|
||||
//settings.ts
|
||||
RELEASE_NOTES_NAME: "Display Release Notes after update",
|
||||
|
||||
@@ -10,6 +10,7 @@ import { PENS } from "src/utils/Pens";
|
||||
import ExcalidrawPlugin from "../main";
|
||||
import { ICONS, penIcon, stringToSVG } from "./ActionIcons";
|
||||
import { UniversalInsertFileModal } from "src/dialogs/UniversalInsertFileModal";
|
||||
import { t } from "src/lang/helpers";
|
||||
|
||||
declare const PLUGIN_VERSION:string;
|
||||
|
||||
@@ -251,7 +252,7 @@ export class ObsidianMenu {
|
||||
);
|
||||
}}
|
||||
>
|
||||
<div className="ToolIcon__icon" aria-hidden="true">
|
||||
<div className="ToolIcon__icon" aria-label={t("OBSIDIAN_TOOLS_PANEL")}>
|
||||
{ICONS.obsidian}
|
||||
</div>
|
||||
</label>
|
||||
@@ -268,7 +269,7 @@ export class ObsidianMenu {
|
||||
insertFileModal.open();
|
||||
}}
|
||||
>
|
||||
<div className="ToolIcon__icon" aria-hidden="true">
|
||||
<div className="ToolIcon__icon" aria-label={t("UNIVERSAL_ADD_FILE")}>
|
||||
{ICONS["add-file"]}
|
||||
</div>
|
||||
</label>
|
||||
|
||||
88
src/utils/CanvasNodeFactory.ts
Normal file
88
src/utils/CanvasNodeFactory.ts
Normal file
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
l = app.workspace.activeLeaf
|
||||
canvas = app.internalPlugins.plugins["canvas"].views.canvas(l)
|
||||
f = app.vault.getAbstractFileByPath("Daily Notes/2022-03-18 Friday.md")
|
||||
node = canvas.canvas.createFileNode({pos: {x:0,y:0}, file:f, subpath: "#Work", save: false})
|
||||
node.setFilePath("Daily Notes/2022-03-18 Friday.md","#Work");
|
||||
node.render();
|
||||
container.appendChild(node.contentEl)
|
||||
*/
|
||||
|
||||
import { TFile, WorkspaceLeaf, WorkspaceSplit } from "obsidian";
|
||||
import ExcalidrawView from "src/ExcalidrawView";
|
||||
import { getContainerForDocument, ConstructableWorkspaceSplit } from "./ObsidianUtils";
|
||||
|
||||
declare module "obsidian" {
|
||||
interface Workspace {
|
||||
floatingSplit: any;
|
||||
}
|
||||
|
||||
interface WorkspaceSplit {
|
||||
containerEl: HTMLDivElement;
|
||||
}
|
||||
}
|
||||
|
||||
interface ObsidianCanvas {
|
||||
createFileNode: Function;
|
||||
removeNode: Function;
|
||||
}
|
||||
|
||||
interface ObsidianCanvasNode {
|
||||
startEditing: Function;
|
||||
child: any;
|
||||
}
|
||||
|
||||
export class CanvasNodeFactory {
|
||||
leaf: WorkspaceLeaf;
|
||||
canvas: ObsidianCanvas;
|
||||
nodes = new Map<string, ObsidianCanvasNode>();
|
||||
|
||||
constructor(
|
||||
private view: ExcalidrawView,
|
||||
) {
|
||||
}
|
||||
|
||||
public async initialize() {
|
||||
//@ts-ignore
|
||||
const canvasPlugin = app.internalPlugins.plugins["canvas"];
|
||||
|
||||
if(!canvasPlugin._loaded) {
|
||||
await canvasPlugin.load();
|
||||
}
|
||||
const doc = this.view.ownerDocument;
|
||||
const rootSplit:WorkspaceSplit = new (WorkspaceSplit as ConstructableWorkspaceSplit)(app.workspace, "vertical");
|
||||
rootSplit.getRoot = () => app.workspace[doc === document ? 'rootSplit' : 'floatingSplit'];
|
||||
rootSplit.getContainer = () => getContainerForDocument(doc);
|
||||
this.leaf = app.workspace.createLeafInParent(rootSplit, 0);
|
||||
this.canvas = canvasPlugin.views.canvas(this.leaf);
|
||||
}
|
||||
|
||||
public createFileNote(file: TFile, subpath: string, containerEl: HTMLDivElement, elementId: string) {
|
||||
const node = this.canvas.createFileNode({pos: {x:0,y:0}, file, subpath, save: false});
|
||||
node.setFilePath(file.path,subpath);
|
||||
node.render();
|
||||
containerEl.style.background = "var(--background-primary)";
|
||||
containerEl.appendChild(node.contentEl)
|
||||
this.nodes.set(elementId, node);
|
||||
}
|
||||
|
||||
public startEditing(elementId: string, theme: string) {
|
||||
const node = this.nodes.get(elementId);
|
||||
if(!node) return;
|
||||
node.startEditing();
|
||||
node.child.editor.containerEl.parentElement.parentElement.removeClass("theme-light");
|
||||
node.child.editor.containerEl.parentElement.parentElement.removeClass("theme-dark");
|
||||
node.child.editor.containerEl.parentElement.parentElement.addClass(theme);
|
||||
}
|
||||
|
||||
public stopEditing(elementId: string) {
|
||||
}
|
||||
|
||||
public purgeNodes() {
|
||||
this.nodes.forEach(node => {
|
||||
this.canvas.removeNode(node);
|
||||
});
|
||||
this.nodes.clear();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ import { ExcalidrawAutomate } from "src/ExcalidrawAutomate";
|
||||
export const insertImageToView = async (
|
||||
ea: ExcalidrawAutomate,
|
||||
position: { x: number, y: number },
|
||||
file: TFile,
|
||||
file: TFile | string,
|
||||
scale?: boolean,
|
||||
):Promise<string> => {
|
||||
ea.clear();
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { main } from "@popperjs/core";
|
||||
import {
|
||||
App,
|
||||
normalizePath, Notice, WorkspaceLeaf
|
||||
normalizePath, Notice, Workspace, WorkspaceLeaf, WorkspaceSplit
|
||||
} from "obsidian";
|
||||
import { DEVICE } from "src/Constants";
|
||||
import ExcalidrawPlugin from "../main";
|
||||
@@ -189,3 +189,14 @@ export const getAttachmentsFolderAndFilePath = async (
|
||||
};
|
||||
|
||||
export const isObsidianThemeDark = () => document.body.classList.contains("theme-dark");
|
||||
|
||||
export type ConstructableWorkspaceSplit = new (ws: Workspace, dir: "horizontal"|"vertical") => WorkspaceSplit;
|
||||
|
||||
export const getContainerForDocument = (doc:Document) => {
|
||||
if (doc !== document && app.workspace.floatingSplit) {
|
||||
for (const container of app.workspace.floatingSplit.children) {
|
||||
if (container.doc === doc) return container;
|
||||
}
|
||||
}
|
||||
return app.workspace.rootSplit;
|
||||
};
|
||||
Reference in New Issue
Block a user