mirror of
https://github.com/zsviczian/obsidian-excalidraw-plugin.git
synced 2025-08-06 05:46:28 +00:00
Compare commits
12 Commits
2.0.20
...
custom-zoo
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d280b33073 | ||
|
|
d1ab6bb7a1 | ||
|
|
146d04ea64 | ||
|
|
fd46a3f8ac | ||
|
|
9974ca1e2e | ||
|
|
2c8a733359 | ||
|
|
4c9eeb9a61 | ||
|
|
de23be8c2d | ||
|
|
bb25a1fde9 | ||
|
|
9267c27bc5 | ||
|
|
591f073413 | ||
|
|
9c28c1ee00 |
@@ -195,7 +195,7 @@ This is relevant when setting a fix height using the `addText()` function.
|
||||
### startArrowHead, endArrowHead
|
||||
String. Valid values are "arrow", "bar", "dot", and "none". Specifies the beginning and ending of an arrow.
|
||||
|
||||
This is relavant when using the `addArrow()` and the `connectObjects()` functions.
|
||||
This is relevant when using the `addArrow()` and the `connectObjects()` functions.
|
||||
|
||||
## canvas
|
||||
Sets the properties of the canvas.
|
||||
|
||||
12
docs/API/ExcalidrawAutomate.d.ts
vendored
12
docs/API/ExcalidrawAutomate.d.ts
vendored
@@ -35,7 +35,7 @@ export declare class ExcalidrawAutomate {
|
||||
*/
|
||||
newFilePrompt(newFileNameOrPath: string, shouldOpenNewFile: boolean, targetPane?: PaneTarget, parentFile?: TFile): Promise<TFile | null>;
|
||||
/**
|
||||
* Generates a new Obsidian Leaf following Excalidraw plugin settings such as open in Main Workspace or not, open in adjacent pane if avaialble, etc.
|
||||
* Generates a new Obsidian Leaf following Excalidraw plugin settings such as open in Main Workspace or not, open in adjacent pane if available, etc.
|
||||
* @param origo // the currently active leaf, the origin of the new leaf
|
||||
* @param targetPane //type PaneTarget = "active-pane"|"new-pane"|"popout-window"|"new-tab"|"md-properties";
|
||||
* @returns
|
||||
@@ -148,7 +148,7 @@ export declare class ExcalidrawAutomate {
|
||||
}>;
|
||||
/**
|
||||
* get all elements from ExcalidrawAutomate elementsDict
|
||||
* @returns elements from elemenetsDict
|
||||
* @returns elements from elementsDict
|
||||
*/
|
||||
getElements(): ExcalidrawElement[];
|
||||
/**
|
||||
@@ -698,25 +698,25 @@ export declare class ExcalidrawAutomate {
|
||||
*/
|
||||
moveViewElementToZIndex(elementId: number, newZIndex: number): void;
|
||||
/**
|
||||
* Depricated. Use getCM / ColorMaster instead
|
||||
* Deprecated. Use getCM / ColorMaster instead
|
||||
* @param color
|
||||
* @returns
|
||||
*/
|
||||
hexStringToRgb(color: string): number[];
|
||||
/**
|
||||
* Depricated. Use getCM / ColorMaster instead
|
||||
* Deprecated. Use getCM / ColorMaster instead
|
||||
* @param color
|
||||
* @returns
|
||||
*/
|
||||
rgbToHexString(color: number[]): string;
|
||||
/**
|
||||
* Depricated. Use getCM / ColorMaster instead
|
||||
* Deprecated. Use getCM / ColorMaster instead
|
||||
* @param color
|
||||
* @returns
|
||||
*/
|
||||
hslToRgb(color: number[]): number[];
|
||||
/**
|
||||
* Depricated. Use getCM / ColorMaster instead
|
||||
* Deprecated. Use getCM / ColorMaster instead
|
||||
* @param color
|
||||
* @returns
|
||||
*/
|
||||
|
||||
@@ -42,7 +42,7 @@ export declare class ExcalidrawAutomate {
|
||||
*/
|
||||
newFilePrompt(newFileNameOrPath: string, shouldOpenNewFile: boolean, targetPane?: PaneTarget, parentFile?: TFile): Promise<TFile | null>;
|
||||
/**
|
||||
* Generates a new Obsidian Leaf following Excalidraw plugin settings such as open in Main Workspace or not, open in adjacent pane if avaialble, etc.
|
||||
* Generates a new Obsidian Leaf following Excalidraw plugin settings such as open in Main Workspace or not, open in adjacent pane if available, etc.
|
||||
* @param origo // the currently active leaf, the origin of the new leaf
|
||||
* @param targetPane //type PaneTarget = "active-pane"|"new-pane"|"popout-window"|"new-tab"|"md-properties";
|
||||
* @returns
|
||||
@@ -155,7 +155,7 @@ export declare class ExcalidrawAutomate {
|
||||
}>;
|
||||
/**
|
||||
* get all elements from ExcalidrawAutomate elementsDict
|
||||
* @returns elements from elemenetsDict
|
||||
* @returns elements from elementsDict
|
||||
*/
|
||||
getElements(): ExcalidrawElement[];
|
||||
/**
|
||||
@@ -705,25 +705,25 @@ export declare class ExcalidrawAutomate {
|
||||
*/
|
||||
moveViewElementToZIndex(elementId: number, newZIndex: number): void;
|
||||
/**
|
||||
* Depricated. Use getCM / ColorMaster instead
|
||||
* Deprecated. Use getCM / ColorMaster instead
|
||||
* @param color
|
||||
* @returns
|
||||
*/
|
||||
hexStringToRgb(color: string): number[];
|
||||
/**
|
||||
* Depricated. Use getCM / ColorMaster instead
|
||||
* Deprecated. Use getCM / ColorMaster instead
|
||||
* @param color
|
||||
* @returns
|
||||
*/
|
||||
rgbToHexString(color: number[]): string;
|
||||
/**
|
||||
* Depricated. Use getCM / ColorMaster instead
|
||||
* Deprecated. Use getCM / ColorMaster instead
|
||||
* @param color
|
||||
* @returns
|
||||
*/
|
||||
hslToRgb(color: number[]): number[];
|
||||
/**
|
||||
* Depricated. Use getCM / ColorMaster instead
|
||||
* Deprecated. Use getCM / ColorMaster instead
|
||||
* @param color
|
||||
* @returns
|
||||
*/
|
||||
|
||||
@@ -88,4 +88,4 @@ This is relevant when setting a fix height using the `addText()` function.
|
||||
### startArrowHead, endArrowHead
|
||||
String. Valid values are "arrow", "bar", "dot", and "none". Specifies the beginning and ending of an arrow.
|
||||
|
||||
This is relavant when using the `addArrow()` and the `connectObjects()` functions.
|
||||
This is relevant when using the `addArrow()` and the `connectObjects()` functions.
|
||||
@@ -22,7 +22,7 @@ Places the generated drawing to the clipboard. Useful when you don't want to cre
|
||||
```typescript
|
||||
getElements():ExcalidrawElement[];
|
||||
```
|
||||
Returns the elements in ExcalidrawAutomate as an array of ExcalidrawElements. This format is usefull when working with ExcalidrawRef.
|
||||
Returns the elements in ExcalidrawAutomate as an array of ExcalidrawElements. This format is useful when working with ExcalidrawRef.
|
||||
|
||||
### getElement()
|
||||
```typescript
|
||||
@@ -156,7 +156,7 @@ You first need to set the view calling `setView()`.
|
||||
|
||||
Gets the array of selected elements in the scene. Returns [] if no elements are selected.
|
||||
|
||||
Note: you can call `getExcalidrawAPI().getSceneElements()` to retreive all the elements in the scene.
|
||||
Note: you can call `getExcalidrawAPI().getSceneElements()` to retrieve all the elements in the scene.
|
||||
|
||||
#### viewToggleFullScreen()
|
||||
```typescript
|
||||
@@ -178,7 +178,7 @@ Same as `connectObjects()`, but ObjectB is the currently selected element in the
|
||||
async addElementsToView(repositionToCursor:boolean=false, save:boolean=false):Promise<boolean>
|
||||
```
|
||||
Adds elements created with ExcalidrawAutomate to the target ExcalidrawView.
|
||||
`repositionToCursor` dafault is false
|
||||
`repositionToCursor` default is false
|
||||
- true: the elements will be moved such that the center point of the elements will be aligned with the current position of the pointer on ExcalidrawView. You can point and place elements to a desired location in your drawing using this switch.
|
||||
- false: elements will be positioned as defined by the x&y coordinates of each element.
|
||||
|
||||
@@ -204,7 +204,7 @@ onDropHook (data: {
|
||||
```
|
||||
|
||||
Callback function triggered when an draggable item is dropped on Excalidraw.
|
||||
The function should return a boolean value. True if the drop was handled by the hook and futher native processing should be stopped, and false if Excalidraw should continue with the processing of the drop.
|
||||
The function should return a boolean value. True if the drop was handled by the hook and further native processing should be stopped, and false if Excalidraw should continue with the processing of the drop.
|
||||
type of drop can be one of:
|
||||
- "file" if a file from Obsidian file explorer is dropped onto Excalidraw. In this case payload.files will contain the list of files dropped.
|
||||
- "text" if a link (e.g. url, or wiki link) or other text is dropped. In this case payload.text will contain the received string
|
||||
|
||||
@@ -21,7 +21,7 @@ This will allow you to assign hotkeys to your favorite scripts just like to any
|
||||
|
||||
## Script development
|
||||
An Excalidraw script will automatically receive two objects:
|
||||
- `ea`: The Script Enginge will initialize the `ea` object including setting the active view to the View from which the script was called.
|
||||
- `ea`: The Script Engine will initialize the `ea` object including setting the active view to the View from which the script was called.
|
||||
- `utils`: I have borrowed functions exposed on utils from [QuickAdd](https://github.com/chhoumann/quickadd/blob/master/docs/QuickAddAPI.md), though currently not all QuickAdd utility functions are implemented in Excalidraw. As of now, these are the available functions. See the example below for details.
|
||||
- `inputPrompt: (header: string, placeholder?: string, value?: string, buttons?: [{caption:string, action:Function}])`
|
||||
- Opens a prompt that asks for an input. Returns a string with the input.
|
||||
|
||||
@@ -8,7 +8,7 @@ With a little work, using ExcalidrawAutomate you can generate simple mindmaps, b
|
||||
## API documentation
|
||||
- **start here** [Introduction to the API](API/introduction.md)
|
||||
- [Overview of Attributes and Functions](API/attributes_functions_overview.md)
|
||||
- [Element Sytle](API/element_style.md)
|
||||
- [Element Style](API/element_style.md)
|
||||
- [Canvas Style](API/canvas_style.md)
|
||||
- [Adding Objects](API/objects.md)
|
||||
- [Utility Functions](API/utility.md)
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
THIS SCRIPT REQUIRES EXCALIDRAW 1.5.15
|
||||
|
||||
The script will
|
||||
1) send the selected image file to [taskbone.com](https://taskbone.com) to exctract the text from the image, and
|
||||
1) send the selected image file to [taskbone.com](https://taskbone.com) to extract the text from the image, and
|
||||
2) will add the text to your drawing as a text element
|
||||
|
||||
I recommend also installing the [Transfer TextElements to Excalidraw markdown metadata](Transfer%20TextElements%20to%20Excalidraw%20markdown%20metadata.md) script as well.
|
||||
|
||||
@@ -15,7 +15,7 @@ In the `Command Palette` installed scripts are prefixed with `Downloaded/`, thus
|
||||
|
||||
## Attention developers and hobby hackers
|
||||
<img src='https://raw.githubusercontent.com/zsviczian/obsidian-excalidraw-plugin/master/images/hobby-programmer.svg' align='left' style='background-color:whitesmoke; width:80px; margin-right:15px; margin-bottom:10px;'/>
|
||||
If you want to modify scripts, I recommend moving them to the `Excalidraw Automate script folder` or a different subfolder under the script folder. Scripts in the `Downloaded` folder will be overwritten when you click the `Update this script` button. Note also, that at this time, I do not check if the script file has been updated on GitHub, thus the `Update this script` button is always visible once you have installed a script, not only when an update is availble (hope to build this feature in the future).
|
||||
If you want to modify scripts, I recommend moving them to the `Excalidraw Automate script folder` or a different subfolder under the script folder. Scripts in the `Downloaded` folder will be overwritten when you click the `Update this script` button. Note also, that at this time, I do not check if the script file has been updated on GitHub, thus the `Update this script` button is always visible once you have installed a script, not only when an update is available (hope to build this feature in the future).
|
||||
|
||||
I would love to include your contribution in the script library. If you have a script of your own that you would like to share with the community, please open a [PR](https://github.com/zsviczian/obsidian-excalidraw-plugin/pulls) on GitHub. Be sure to include the following in your pull request
|
||||
- The [script file](https://github.com/zsviczian/obsidian-excalidraw-plugin/tree/master/ea-scripts) with a self explanetory name. The name of the file will be the name of the script in the Command Palette.
|
||||
@@ -243,7 +243,7 @@ https://raw.githubusercontent.com/zsviczian/obsidian-excalidraw-plugin/master/ea
|
||||
```excalidraw-script-install
|
||||
https://raw.githubusercontent.com/zsviczian/obsidian-excalidraw-plugin/master/ea-scripts/OCR%20-%20Optical%20Character%20Recognition.md
|
||||
```
|
||||
<table><tr valign='top'><td class="label">Author</td><td class="data"><a href='https://github.com/zsviczian'>@zsviczian</a></td></tr><tr valign='top'><td class="label">Source</td><td class="data"><a href='https://github.com/zsviczian/obsidian-excalidraw-plugin/blob/master/ea-scripts/OCR%20-%20Optical%20Character%20Recognition.md'>File on GitHub</a></td></tr><tr valign='top'><td class="label">Description</td><td class="data">REQUIRES EXCALIDRAW 1.5.15<br>The script will 1) send the selected image file to [taskbone.com](https://taskbone.com) to exctract the text from the image, and 2) will add the text to your drawing as a text element.<br><mark>⚠ Note that you will need to manually paste your token into the script after the first run! ⚠</mark><br><img src='https://raw.githubusercontent.com/zsviczian/obsidian-excalidraw-plugin/master/images/scripts-ocr.jpg'><br><iframe width="560" height="315" src="https://www.youtube.com/embed/W2NMzR8s4eE" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe></td></tr></table>
|
||||
<table><tr valign='top'><td class="label">Author</td><td class="data"><a href='https://github.com/zsviczian'>@zsviczian</a></td></tr><tr valign='top'><td class="label">Source</td><td class="data"><a href='https://github.com/zsviczian/obsidian-excalidraw-plugin/blob/master/ea-scripts/OCR%20-%20Optical%20Character%20Recognition.md'>File on GitHub</a></td></tr><tr valign='top'><td class="label">Description</td><td class="data">REQUIRES EXCALIDRAW 1.5.15<br>The script will 1) send the selected image file to [taskbone.com](https://taskbone.com) to extract the text from the image, and 2) will add the text to your drawing as a text element.<br><mark>⚠ Note that you will need to manually paste your token into the script after the first run! ⚠</mark><br><img src='https://raw.githubusercontent.com/zsviczian/obsidian-excalidraw-plugin/master/images/scripts-ocr.jpg'><br><iframe width="560" height="315" src="https://www.youtube.com/embed/W2NMzR8s4eE" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe></td></tr></table>
|
||||
|
||||
## Organic Line
|
||||
```excalidraw-script-install
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/*
|
||||
With This Script it is possible to make boolean Operations on Shapes.
|
||||
The style of the resulting shape will be the style of the highest ranking Element that was used.
|
||||
The ranking of the elemtns is based on their background. The "denser" the background, the higher the ranking (the order of backgroundstyles is shown below). If they have the same background the opacity will decide. If thats also the same its decided by the order they were created.
|
||||
The ranking is also important for the diffrence operation, so a tranparent object for example will cut a hole into a solid object.
|
||||
The ranking of the elements is based on their background. The "denser" the background, the higher the ranking (the order of backgroundstyles is shown below). If they have the same background the opacity will decide. If thats also the same its decided by the order they were created.
|
||||
The ranking is also important for the difference operation, so a transparent object for example will cut a hole into a solid object.
|
||||

|
||||

|
||||
|
||||
@@ -29,7 +29,7 @@ if(elements.length === 0) {
|
||||
}
|
||||
|
||||
const PolyBool = ea.getPolyBool();
|
||||
const polyboolAction = await utils.suggester(["union (a + b)", "intersect (a && b)", "diffrence (a - b)", "reversed diffrence (b - a)", "xor"], [
|
||||
const polyboolAction = await utils.suggester(["union (a + b)", "intersect (a && b)", "difference (a - b)", "reversed difference (b - a)", "xor"], [
|
||||
PolyBool.union, PolyBool.intersect, PolyBool.difference, PolyBool.differenceRev, PolyBool.xor
|
||||
], "What would you like todo with the object");
|
||||
|
||||
|
||||
15
ea-scripts/Custom Zoom.md
Normal file
15
ea-scripts/Custom Zoom.md
Normal file
@@ -0,0 +1,15 @@
|
||||
/*
|
||||
You can set a custom zoom level with this script. This allows you to set a zoom level below 10% or set the zoom level to a specific value. Note however, that Excalidraw has a bug under 10% zoom, and a phantom copy of your image may appear on screen. If this happens, increase the zoom and the phantom should disappear, if it doesn't then close and open the drawing.
|
||||
|
||||
```js*/
|
||||
const api = ea.getExcalidrawAPI();
|
||||
const appState = api.getAppState();
|
||||
const zoomStr = await utils.inputPrompt("Zoom [%]",null,`${appState.zoom.value*100}%`);
|
||||
if(!zoomStr) return;
|
||||
const zoomNum = parseFloat(zoomStr.match(/^\d*/)[0]);
|
||||
if(isNaN(zoomNum)) {
|
||||
new Notice("You must provide a number");
|
||||
return;
|
||||
}
|
||||
|
||||
ea.getExcalidrawAPI().updateScene({appState:{zoom:{value: zoomNum/100 }}});
|
||||
1
ea-scripts/Custom Zoom.svg
Normal file
1
ea-scripts/Custom Zoom.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-scan-search"><g stroke-width="2"><path d="M3 7V5a2 2 0 0 1 2-2h2"/><path d="M17 3h2a2 2 0 0 1 2 2v2"/><path d="M21 17v2a2 2 0 0 1-2 2h-2"/><path d="M7 21H5a2 2 0 0 1-2-2v-2"/><circle cx="12" cy="12" r="3"/><path d="m16 16-1.9-1.9"/></g></svg>
|
||||
|
After Width: | Height: | Size: 444 B |
@@ -26,6 +26,10 @@ const outputTypes = {
|
||||
"image-gen": {
|
||||
instruction: "Return a single message with the generated image prompt in a codeblock",
|
||||
blocktype: "image"
|
||||
},
|
||||
"image-gen-silent": {
|
||||
instruction: "Return a single message with the generated image prompt in a codeblock",
|
||||
blocktype: "image-silent"
|
||||
},
|
||||
"image-edit": {
|
||||
instruction: "",
|
||||
@@ -49,6 +53,12 @@ const systemPrompts = {
|
||||
type: "svg",
|
||||
help: "Convert text prompts into simple icons inserted as Excalidraw elements. Expect only a text prompt. Experimental and may not produce good drawings."
|
||||
},
|
||||
|
||||
"Create a stick figure": {
|
||||
prompt: "You will receive a prompt from the user. Your task involves drawing a simple stick figure or a scene involving a few stick figures based on the user's prompt. Create the stickfigure based on the following style description. DO NOT add any detail, just use it AS-IS: Create a simple stick figure character with a large round head and a face in the style of sketchy caricatures. The stick figure should have a rudimentary body composed of straight lines representing the arms and legs. Hands and toes should be should be represented with round shapes, do not add details such as fingers or toes. Use fine lines, smooth curves, rounded shapes. The stick figure should retain a playful and childlike simplicity, reminiscent of a doodle someone might draw on the corner of a notebook page. Create a black and white drawing, a hand-drawn figure on white background.",
|
||||
type: "image-gen",
|
||||
help: "Send only the text prompt to OpenAI. Provide a detailed description; OpenAI will enrich your prompt automatically. To avoid it, start your prompt like this 'DO NOT add any detail, just use it AS-IS:'"
|
||||
},
|
||||
"Edit an image": {
|
||||
prompt: null,
|
||||
type: "image-edit",
|
||||
@@ -69,6 +79,11 @@ const systemPrompts = {
|
||||
type: "image-gen",
|
||||
help: "ExcaliAI will create an image prompt to illustrate your text input - a quote - with GPT, then generate an image using Dall-e. In case you include the Author's name, GPT will try to generate an image that in some way references the Author."
|
||||
},
|
||||
"Generate 4 icon-variants based on input image": {
|
||||
prompt: "Given a simple sketch and an optional text prompt from the user, your task is to generate a descriptive narrative tailored for effective image generation, capturing the style of the sketch. Utilize the text prompt to guide the description. Your objective is to instruct DALL-E to create a collage of four minimalist black and white hand-drawn pencil sketches in a 2x2 matrix format. Each sketch should convert the user's sketch into simple artistic SVG icons with transparent backgrounds. Ensure the resulting images remain text-free, maintaining a minimalist, easy-to-understand style, and omit framing borders. Only include a pencil in the drawing if it is explicitely metioned in the user prompt or included in the sketch.",
|
||||
type: "image-gen-silent",
|
||||
help: "Generate a collage of 4 icons based on the drawing using ChatGPT-Vision and Dall-e. You may provide a contextual text-prompt to improve accuracy of interpretation."
|
||||
},
|
||||
"Visual brainstorm": {
|
||||
prompt: "Your objective is to interpret a screenshot of a whiteboard, creating an image aimed at sparking further thoughts on the subject. The whiteboard will present diverse ideas about a specific topic. Your generated image should achieve one of two purposes: highlighting concepts that challenge, dispute, or contradict the whiteboard content, or introducing ideas that expand, complement, or enrich the user's thinking. You have the option to include multiple tiles in the resulting image, resembling a sequence akin to a comic strip. Ensure that the image remains devoid of text.",
|
||||
type: "image-gen",
|
||||
@@ -77,7 +92,7 @@ const systemPrompts = {
|
||||
"Wireframe to code": {
|
||||
prompt: `You are an expert tailwind developer. A user will provide you with a low-fidelity wireframe of an application and you will return a single html file that uses tailwind to create the website. Use creative license to make the application more fleshed out. Write the necessary javascript code. If you need to insert an image, use placehold.co to create a placeholder image.`,
|
||||
type: "html",
|
||||
help: "Use GPT Visions to interpret the wireframe and generate a web application. You may copy the resulting code from the active embeddable's top left menu."
|
||||
help: "Use GPT Visions to interpret the wireframe and generate a web application. YOu may copy the resulting code from the active embeddable's top left menu."
|
||||
},
|
||||
}
|
||||
|
||||
@@ -319,7 +334,7 @@ const setMermaidDataToStorage = (mermaidDefinition) => {
|
||||
// --------------------------------------
|
||||
// Submit Prompt
|
||||
// --------------------------------------
|
||||
const generateImage = async(text, spinnerID, bb) => {
|
||||
const generateImage = async(text, spinnerID, bb, silent=false) => {
|
||||
const requestObject = {
|
||||
text,
|
||||
imageGenerationProperties: {
|
||||
@@ -342,7 +357,7 @@ const generateImage = async(text, spinnerID, bb) => {
|
||||
const imageID = await ea.addImage(spinner.x, spinner.y, result.json.data[0].url);
|
||||
const imageEl = ea.getElement(imageID);
|
||||
const revisedPrompt = result.json.data[0].revised_prompt;
|
||||
if(revisedPrompt) {
|
||||
if(revisedPrompt && !silent) {
|
||||
ea.style.fontSize = 16;
|
||||
const rectID = ea.addText(imageEl.x+15, imageEl.y + imageEl.height + 50, revisedPrompt, {
|
||||
width: imageEl.width-30,
|
||||
@@ -356,6 +371,7 @@ const generateImage = async(text, spinnerID, bb) => {
|
||||
}
|
||||
|
||||
await ea.addElementsToView(false, true, true);
|
||||
if(silent) return;
|
||||
ea.getExcalidrawAPI().setToast({
|
||||
message: IMAGE_WARNING,
|
||||
duration: 15000,
|
||||
@@ -371,7 +387,7 @@ const run = async (text) => {
|
||||
|
||||
const systemPrompt = systemPrompts[agentTask];
|
||||
const outputType = outputTypes[systemPrompt.type];
|
||||
const isImageGenRequest = outputType.blocktype === "image";
|
||||
const isImageGenRequest = outputType.blocktype === "image" || outputType.blocktype === "image-silent";
|
||||
const isImageEditRequest = systemPrompt.type === "image-edit";
|
||||
|
||||
if(isImageEditRequest) {
|
||||
@@ -473,7 +489,7 @@ const run = async (text) => {
|
||||
}
|
||||
|
||||
if(isImageGenRequest) {
|
||||
generateImage(content,spinnerID,bb);
|
||||
generateImage(content,spinnerID,bb,outputType.blocktype === "image-silent");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -519,7 +535,7 @@ const run = async (text) => {
|
||||
// --------------------------------------
|
||||
let previewDiv;
|
||||
const fragWithHTML = (html) => createFragment((frag) => (frag.createDiv().innerHTML = html));
|
||||
const isImageGenerationTask = () => systemPrompts[agentTask].type === "image-gen" || systemPrompts[agentTask].type === "image-edit";
|
||||
const isImageGenerationTask = () => systemPrompts[agentTask].type === "image-gen" || systemPrompts[agentTask].type === "image-gen-silent" || systemPrompts[agentTask].type === "image-edit";
|
||||
const addPreviewImage = () => {
|
||||
if(!previewDiv) return;
|
||||
previewDiv.empty();
|
||||
|
||||
@@ -464,7 +464,7 @@ const run = async (text) => {
|
||||
return;
|
||||
}
|
||||
|
||||
//exctract codeblock and display result
|
||||
//extract codeblock and display result
|
||||
let content = ea.extractCodeBlocks(result.json.choices[0]?.message?.content)[0]?.data;
|
||||
|
||||
if(!content) {
|
||||
|
||||
@@ -631,7 +631,7 @@ modal.onOpen = async () => {
|
||||
.addDropdown(dropdown=>dropdown
|
||||
.addOption("none","None")
|
||||
.addOption("top-down","Top down")
|
||||
.addOption("bottom-up","Bootom up")
|
||||
.addOption("bottom-up","Bottom up")
|
||||
.addOption("center-out","Center out")
|
||||
.addOption("center-in","Center in")
|
||||
.setValue(vDirection)
|
||||
|
||||
@@ -33,8 +33,20 @@ const invertColor = (color) => {
|
||||
}
|
||||
}
|
||||
|
||||
const invertPaletteColors = (palette) => Object.keys(palette).forEach(key => palette[key] = invertColor(palette[key]));
|
||||
Object.keys(colorPalette).forEach(key => invertPaletteColors(colorPalette[key]));
|
||||
function invertColorsRecursively(obj) {
|
||||
if (typeof obj === 'string') {
|
||||
return invertColor(obj);
|
||||
} else if (Array.isArray(obj)) {
|
||||
return obj.map(item => invertColorsRecursively(item));
|
||||
} else if (typeof obj === 'object' && obj !== null) {
|
||||
const result = {};
|
||||
Object.keys(obj).forEach(key => result[key] = invertColorsRecursively(obj[key]));
|
||||
return result;
|
||||
} else {
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
colorPalette = invertColorsRecursively(colorPalette);
|
||||
|
||||
ea.copyViewElementsToEAforEditing(ea.getViewElements());
|
||||
ea.getElements().forEach(el=>{
|
||||
|
||||
@@ -58,7 +58,7 @@ Open the script you are interested in and save it to your Obsidian Vault includi
|
||||
|[Mindmap connector](Mindmap%20connector.md)|This script creates mindmap like lines (only right side and down available currently) for selected elements. The line will start according to the creation time of the elements. So you should create the header element first.||[@xllowl](https://github.com/xllowl)|
|
||||
|[Modify background color opacity](Modify%20background%20color%20opacity.md)|This script changes the opacity of the background color of the selected boxes. The default background color in Excalidraw is so dark that the text is hard to read. You can lighten the color a bit by setting transparency. And you can tweak the transparency over and over again until you're happy with it. Although excalidraw has the opacity option in its native property Settings, it also changes the transparency of the border. Use this script to change only the opacity of the background color without affecting the border.||[@1-2-3](https://github.com/1-2-3)|
|
||||
|[Normalize Selected Arrows](Normalize%20Selected%20Arrows.md)|This script will reset the start and end positions of the selected arrows. The arrow will point to the center of the connected box and will have a gap of 8px from the box.||[@1-2-3](https://github.com/1-2-3)|
|
||||
|[OCR - Optical Character Recognition](OCR%20-%20Optical%20Character%20Recognition.md)|The script will 1) send the selected image file to [taskbone.com](https://taskbone.com) to exctract the text from the image, and 2) will add the text to your drawing as a text element.||[@zsviczian](https://github.com/zsviczian)|
|
||||
|[OCR - Optical Character Recognition](OCR%20-%20Optical%20Character%20Recognition.md)|The script will 1) send the selected image file to [taskbone.com](https://taskbone.com) to extract the text from the image, and 2) will add the text to your drawing as a text element.||[@zsviczian](https://github.com/zsviczian)|
|
||||
|[Organic Line](Organic%20Line.md)|Converts selected freedraw lines such that pencil pressure will decrease from maximum to minimum from the beginning of the line to its end. The resulting line is placed at the back of the layers, under all other items. Helpful when drawing organic mindmaps.||[@zsviczian](https://github.com/zsviczian)|
|
||||
|[Repeat Elements](Repeat%20Elements.md)|This script will detect the difference between 2 selected elements, including position, size, angle, stroke and background color, and create several elements that repeat these differences based on the number of repetitions entered by the user.||[@1-2-3](https://github.com/1-2-3)|
|
||||
|[Reverse arrows](Reverse%20arrows.md)|Reverse the direction of **arrows** within the scope of selected elements.||[@zsviczian](https://github.com/zsviczian)|
|
||||
|
||||
@@ -19,7 +19,7 @@ if(!config && (elements.length !==1)) {
|
||||
}
|
||||
}
|
||||
|
||||
const {angle, backgroundColor, fillStyle, fontFamily, fontSize, height, width, opacity, roughness, roundness, strokeColor, strokeStyle, strokeWidth, type, startArrowhead, endArrowhead} = ea.getViewSelectedElement();
|
||||
const {angle, backgroundColor, fillStyle, fontFamily, fontSize, height, width, opacity, roughness, roundness, strokeColor, strokeStyle, strokeWidth, type, startArrowhead, endArrowhead, fileId} = ea.getViewSelectedElement();
|
||||
|
||||
const fragWithHTML = (html) => createFragment((frag) => (frag.createDiv().innerHTML = html));
|
||||
|
||||
@@ -43,7 +43,8 @@ const run = () => {
|
||||
((typeof config.strokeWidth === "undefined") || (el.strokeWidth === config.strokeWidth)) &&
|
||||
((typeof config.type === "undefined") || (el.type === config.type)) &&
|
||||
((typeof config.startArrowhead === "undefined") || (el.startArrowhead === config.startArrowhead)) &&
|
||||
((typeof config.endArrowhead === "undefined") || (el.endArrowhead === config.endArrowhead))
|
||||
((typeof config.endArrowhead === "undefined") || (el.endArrowhead === config.endArrowhead)) &&
|
||||
((typeof config.fileId === "undefined") || (el.fileId === config.fileId))
|
||||
)
|
||||
ea.selectElementsInView(selectedElements);
|
||||
delete window.ExcalidrawSelectConfig;
|
||||
@@ -97,6 +98,7 @@ const selectAttributesToCopy = () => {
|
||||
{name: "End arrowhead", key: "endArrowhead"},
|
||||
{name: "Height", key: "height"},
|
||||
{name: "Width", key: "width"},
|
||||
{name: "ImageID", key: "fileId"},
|
||||
];
|
||||
|
||||
attributes.forEach(attr => {
|
||||
@@ -165,7 +167,7 @@ const selectAttributesToCopy = () => {
|
||||
});
|
||||
|
||||
|
||||
//Add Toggle for the rest of the attirbutes. Organize attributes into a logical sequence or groups by adding
|
||||
//Add Toggle for the rest of the attributes. Organize attributes into a logical sequence or groups by adding
|
||||
//configModal.contentEl.createEl("h") or similar to the code
|
||||
|
||||
new ea.obsidian.Setting(configModal.contentEl)
|
||||
|
||||
@@ -305,11 +305,11 @@ const scrollToNextRect = async ({left,top,right,bottom,nextZoom},steps = TRANSIT
|
||||
zoom:{value:zoom.value-zoomStep*i},
|
||||
}
|
||||
});
|
||||
const ellapsed = Date.now()-startTimer;
|
||||
if(ellapsed > TRANSITION_DELAY) {
|
||||
const elapsed = Date.now()-startTimer;
|
||||
if(elapsed > TRANSITION_DELAY) {
|
||||
i = i<steps ? steps : steps+1;
|
||||
} else {
|
||||
const timeProgress = ellapsed / TRANSITION_DELAY;
|
||||
const timeProgress = elapsed / TRANSITION_DELAY;
|
||||
i=Math.min(Math.round(steps*timeProgress),steps)
|
||||
await sleep(FRAME_SLEEP);
|
||||
}
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -15,7 +15,7 @@ In the `Command Palette` installed scripts are prefixed with `Downloaded/`, thus
|
||||
|
||||
## Attention developers and hobby hackers
|
||||
<img src='https://raw.githubusercontent.com/zsviczian/obsidian-excalidraw-plugin/master/images/hobby-programmer.svg' align='left' style='background-color:whitesmoke; width:80px; margin-right:15px; margin-bottom:10px;'/>
|
||||
If you want to modify scripts, I recommend moving them to the `Excalidraw Automate script folder` or a different subfolder under the script folder. Scripts in the `Downloaded` folder will be overwritten when you click the `Update this script` button. Note also, that at this time, I do not check if the script file has been updated on GitHub, thus the `Update this script` button is always visible once you have installed a script, not only when an update is availble (hope to build this feature in the future).
|
||||
If you want to modify scripts, I recommend moving them to the `Excalidraw Automate script folder` or a different subfolder under the script folder. Scripts in the `Downloaded` folder will be overwritten when you click the `Update this script` button. Note also, that at this time, I do not check if the script file has been updated on GitHub, thus the `Update this script` button is always visible once you have installed a script, not only when an update is available (hope to build this feature in the future).
|
||||
|
||||
I would love to include your contribution in the script library. If you have a script of your own that you would like to share with the community, please open a [PR](https://github.com/zsviczian/obsidian-excalidraw-plugin/pulls) on GitHub. Be sure to include the following in your pull request
|
||||
- The [script file](https://github.com/zsviczian/obsidian-excalidraw-plugin/tree/master/ea-scripts) with a self explanetory name. The name of the file will be the name of the script in the Command Palette.
|
||||
@@ -116,6 +116,7 @@ I would love to include your contribution in the script library. If you have a s
|
||||
|----|-----|
|
||||
|<div><img src="https://raw.githubusercontent.com/zsviczian/obsidian-excalidraw-plugin/master/ea-scripts/Auto%20Draw%20for%20Pen.svg"/></div>|[[#Auto Draw for Pen]]|
|
||||
|<div><img src="https://raw.githubusercontent.com/zsviczian/obsidian-excalidraw-plugin/master/ea-scripts/Boolean%20Operations.svg"/></div>|[[#Boolean Operations]]|
|
||||
|<div><img src="https://raw.githubusercontent.com/zsviczian/obsidian-excalidraw-plugin/master/ea-scripts/Custom%20Zoom.svg"/></div>|[[#Custom Zoom]]|
|
||||
|<div><img src="https://raw.githubusercontent.com/zsviczian/obsidian-excalidraw-plugin/master/ea-scripts/Copy%20Selected%20Element%20Styles%20to%20Global.svg"/></div>|[[#Copy Selected Element Styles to Global]]|
|
||||
|<div><img src="https://raw.githubusercontent.com/zsviczian/obsidian-excalidraw-plugin/master/ea-scripts/ExcaliAI.svg"/></div>|[[#ExcaliAI]]|
|
||||
|<div><img src="https://raw.githubusercontent.com/zsviczian/obsidian-excalidraw-plugin/master/ea-scripts/GPT-Draw-a-UI.svg"/></div>|[[#GPT Draw-a-UI]]|
|
||||
@@ -197,7 +198,7 @@ https://raw.githubusercontent.com/zsviczian/obsidian-excalidraw-plugin/master/ea
|
||||
```excalidraw-script-install
|
||||
https://raw.githubusercontent.com/zsviczian/obsidian-excalidraw-plugin/master/ea-scripts/Boolean%20Operations.md
|
||||
```
|
||||
<table><tr valign='top'><td class="label">Author</td><td class="data"><a href='https://github.com/GColoy'>@GColoy</a></td></tr><tr valign='top'><td class="label">Source</td><td class="data"><a href='https://github.com/zsviczian/obsidian-excalidraw-plugin/blob/master/ea-scripts/Boolean%20Operations.md'>File on GitHub</a></td></tr><tr valign='top'><td class="label">Description</td><td class="data">With This Script it is possible to make boolean Operations on Shapes.<br>The style of the resulting shape will be the style of the highest ranking Element that was used.<br>The ranking of the elemtns is based on their background. The "denser" the background, the higher the ranking (the order of backgroundstyles is shown below). If they have the same background the opacity will decide. If thats also the same its decided by the order they were created.<br>The ranking is also important for the diffrence operation, so a tranparent object for example will cut a hole into a solid object.<br><img src='https://raw.githubusercontent.com/zsviczian/obsidian-excalidraw-plugin/master/images/scripts-boolean-operations-showcase.png'><br><img src='https://raw.githubusercontent.com/zsviczian/obsidian-excalidraw-plugin/master/images/scripts-boolean-operations-element-ranking.png'></td></tr></table>
|
||||
<table><tr valign='top'><td class="label">Author</td><td class="data"><a href='https://github.com/GColoy'>@GColoy</a></td></tr><tr valign='top'><td class="label">Source</td><td class="data"><a href='https://github.com/zsviczian/obsidian-excalidraw-plugin/blob/master/ea-scripts/Boolean%20Operations.md'>File on GitHub</a></td></tr><tr valign='top'><td class="label">Description</td><td class="data">With This Script it is possible to make boolean Operations on Shapes.<br>The style of the resulting shape will be the style of the highest ranking Element that was used.<br>The ranking of the elements is based on their background. The "denser" the background, the higher the ranking (the order of backgroundstyles is shown below). If they have the same background the opacity will decide. If thats also the same its decided by the order they were created.<br>The ranking is also important for the difference operation, so a transparent object for example will cut a hole into a solid object.<br><img src='https://raw.githubusercontent.com/zsviczian/obsidian-excalidraw-plugin/master/images/scripts-boolean-operations-showcase.png'><br><img src='https://raw.githubusercontent.com/zsviczian/obsidian-excalidraw-plugin/master/images/scripts-boolean-operations-element-ranking.png'></td></tr></table>
|
||||
|
||||
|
||||
## Box Each Selected Groups
|
||||
@@ -272,6 +273,12 @@ https://raw.githubusercontent.com/zsviczian/obsidian-excalidraw-plugin/master/ea
|
||||
```
|
||||
<table><tr valign='top'><td class="label">Author</td><td class="data"><a href='https://github.com/zsviczian'>@zsviczian</a></td></tr><tr valign='top'><td class="label">Source</td><td class="data"><a href='https://github.com/zsviczian/obsidian-excalidraw-plugin/blob/master/ea-scripts/Crop%20Vintage%20Mask.md'>File on GitHub</a></td></tr><tr valign='top'><td class="label">Description</td><td class="data">Adds a rounded mask to the image by adding a full cover black mask and a rounded rectangle white mask. The script is also useful for adding just a black mask. In this case, run the script, then delete the white mask and add your custom white mask.<br><img src='https://raw.githubusercontent.com/zsviczian/obsidian-excalidraw-plugin/master/images/scripts-crop-vintage.jpg'></td></tr></table>
|
||||
|
||||
## Custom Zoom
|
||||
```excalidraw-script-install
|
||||
https://raw.githubusercontent.com/zsviczian/obsidian-excalidraw-plugin/master/ea-scripts/Custom%20Zoom.md
|
||||
```
|
||||
<table><tr valign='top'><td class="label">Author</td><td class="data"><a href='https://github.com/zsviczian'>@zsviczian</a></td></tr><tr valign='top'><td class="label">Source</td><td class="data"><a href='https://github.com/zsviczian/obsidian-excalidraw-plugin/blob/master/ea-scripts/Custom%20Zoom.md'>File on GitHub</a></td></tr><tr valign='top'><td class="label">Description</td><td class="data">You can set a custom zoom level with this script. This allows you to set a zoom level below 10% or set the zoom level to a specific value. Note however, that Excalidraw has a bug under 10% zoom... a phantom copy of your image may appear on screen. If this happens, increase the zoom and the phantom should disappear, if it doesn't, then close and open the drawing.</td></tr></table>
|
||||
|
||||
## Darken background color
|
||||
```excalidraw-script-install
|
||||
https://raw.githubusercontent.com/zsviczian/obsidian-excalidraw-plugin/master/ea-scripts/Darken%20background%20color.md
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"id": "obsidian-excalidraw-plugin",
|
||||
"name": "Excalidraw",
|
||||
"version": "2.0.20",
|
||||
"version": "2.0.24",
|
||||
"minAppVersion": "1.1.6",
|
||||
"description": "An Obsidian plugin to edit and view Excalidraw drawings",
|
||||
"author": "Zsolt Viczian",
|
||||
|
||||
19
package.json
19
package.json
@@ -18,23 +18,22 @@
|
||||
"author": "",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@zsviczian/excalidraw": "0.17.1-obsidian-13",
|
||||
"@popperjs/core": "^2.11.8",
|
||||
"@zsviczian/excalidraw": "0.17.1-obsidian-17",
|
||||
"chroma-js": "^2.4.2",
|
||||
"clsx": "^2.0.0",
|
||||
"colormaster": "^1.2.1",
|
||||
"gl-matrix": "^3.4.3",
|
||||
"lucide-react": "^0.263.1",
|
||||
"mathjax-full": "^3.2.2",
|
||||
"monkey-around": "^2.3.0",
|
||||
"nanoid": "^4.0.2",
|
||||
"polybooljs": "^1.2.0",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"roughjs": "^4.5.2",
|
||||
"@popperjs/core": "^2.11.8",
|
||||
"nanoid": "^4.0.2",
|
||||
"lucide-react": "^0.263.1",
|
||||
"mathjax-full": "^3.2.2"
|
||||
"roughjs": "^4.5.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"lz-string": "^1.5.0",
|
||||
"@babel/core": "^7.22.9",
|
||||
"@babel/preset-env": "^7.22.10",
|
||||
"@babel/preset-react": "^7.22.5",
|
||||
@@ -52,8 +51,10 @@
|
||||
"@types/react-dom": "^18.2.18",
|
||||
"@zerollup/ts-transform-paths": "^1.7.18",
|
||||
"cross-env": "^7.0.3",
|
||||
"cssnano": "^6.0.2",
|
||||
"eslint-config-prettier": "^9.0.0",
|
||||
"eslint-plugin-prettier": "^5.0.0",
|
||||
"lz-string": "^1.5.0",
|
||||
"obsidian": "^1.4.0",
|
||||
"prettier": "^3.0.1",
|
||||
"rollup": "^2.70.1",
|
||||
@@ -64,9 +65,7 @@
|
||||
"rollup-plugin-web-worker-loader": "^1.6.1",
|
||||
"tslib": "^2.6.1",
|
||||
"ttypescript": "^1.5.15",
|
||||
"typescript": "^5.2.2",
|
||||
"cssnano": "^6.0.2"
|
||||
|
||||
"typescript": "^5.2.2"
|
||||
},
|
||||
"resolutions": {
|
||||
"@typescript-eslint/typescript-estree": "5.3.0"
|
||||
|
||||
@@ -528,7 +528,8 @@ export class EmbeddedFilesLoader {
|
||||
addFiles: (files: FileData[], isDark: boolean, final?: boolean) => void,
|
||||
depth:number
|
||||
) {
|
||||
if(depth > 4) {
|
||||
|
||||
if(depth > 7) {
|
||||
new Notice(t("INFINITE_LOOP_WARNING")+depth.toString(), 6000);
|
||||
return;
|
||||
}
|
||||
@@ -562,7 +563,7 @@ export class EmbeddedFilesLoader {
|
||||
}
|
||||
//files.push(fileData);
|
||||
}
|
||||
} else if (embeddedFile.isSVGwithBitmap) {
|
||||
} /*else if (embeddedFile.isSVGwithBitmap) {
|
||||
const fileData = {
|
||||
mimeType: embeddedFile.mimeType,
|
||||
id: entry.value[0],
|
||||
@@ -579,7 +580,7 @@ export class EmbeddedFilesLoader {
|
||||
catch(e) {
|
||||
errorlog({ where: "EmbeddedFileLoader.loadSceneFiles", error: e });
|
||||
}
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
let equation;
|
||||
|
||||
@@ -53,7 +53,7 @@ import {
|
||||
scaleLoadedImage,
|
||||
wrapTextAtCharLength,
|
||||
} from "src/utils/Utils";
|
||||
import { getAttachmentsFolderAndFilePath, getLeaf, getNewOrAdjacentLeaf, isObsidianThemeDark } from "src/utils/ObsidianUtils";
|
||||
import { getAttachmentsFolderAndFilePath, getLeaf, getNewOrAdjacentLeaf, isObsidianThemeDark, openLeaf } from "src/utils/ObsidianUtils";
|
||||
import { AppState, BinaryFileData, DataURL, ExcalidrawImperativeAPI, Point } from "@zsviczian/excalidraw/types/excalidraw/types";
|
||||
import { EmbeddedFile, EmbeddedFilesLoader, FileData } from "src/EmbeddedFileLoader";
|
||||
import { tex2dataURL } from "src/LaTeX";
|
||||
@@ -154,7 +154,13 @@ export class ExcalidrawAutomate {
|
||||
return;
|
||||
}
|
||||
|
||||
let isMissing = true;
|
||||
if (funcInfo.code) {
|
||||
isMissing = false;
|
||||
console.log(`Declaration: ${funcInfo.code}`);
|
||||
}
|
||||
if (funcInfo.desc) {
|
||||
isMissing = false;
|
||||
const formattedDesc = funcInfo.desc
|
||||
.replaceAll("<br>", "\n")
|
||||
.replace(/<code>(.*?)<\/code>/g, '%c\u200b$1%c') // Zero-width space
|
||||
@@ -162,10 +168,9 @@ export class ExcalidrawAutomate {
|
||||
.replace(/<a onclick='window\.open\("(.*?)"\)'>(.*?)<\/a>/g, (_, href, text) => `%c\u200b${text}%c\u200b (link: ${href})`); // Zero-width non-joiner
|
||||
|
||||
const styles = Array.from({ length: (formattedDesc.match(/%c/g) || []).length }, (_, i) => i % 2 === 0 ? 'color: #007bff;' : '');
|
||||
|
||||
console.log(`Declaration: ${funcInfo.code}`);
|
||||
console.log(`Description: ${formattedDesc}`, ...styles);
|
||||
} else {
|
||||
}
|
||||
if (isMissing) {
|
||||
console.log("Description not available for this function.");
|
||||
}
|
||||
}
|
||||
@@ -292,7 +297,7 @@ export class ExcalidrawAutomate {
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a new Obsidian Leaf following Excalidraw plugin settings such as open in Main Workspace or not, open in adjacent pane if avaialble, etc.
|
||||
* Generates a new Obsidian Leaf following Excalidraw plugin settings such as open in Main Workspace or not, open in adjacent pane if available, etc.
|
||||
* @param origo // the currently active leaf, the origin of the new leaf
|
||||
* @param targetPane //type PaneTarget = "active-pane"|"new-pane"|"popout-window"|"new-tab"|"md-properties";
|
||||
* @returns
|
||||
@@ -543,7 +548,7 @@ export class ExcalidrawAutomate {
|
||||
|
||||
/**
|
||||
* get all elements from ExcalidrawAutomate elementsDict
|
||||
* @returns elements from elemenetsDict
|
||||
* @returns elements from elementsDict
|
||||
*/
|
||||
getElements(): Mutable<ExcalidrawElement>[] {
|
||||
const elements = [];
|
||||
@@ -2190,6 +2195,19 @@ export class ExcalidrawAutomate {
|
||||
color: string,
|
||||
) => void = null;
|
||||
|
||||
/**
|
||||
* If set, this callback is triggered whenever a drawing is exported to SVG.
|
||||
* The string returned will replace the link in the exported SVG.
|
||||
* The hook is only executed if the link is to a file internal to Obsidian
|
||||
* see: https://github.com/zsviczian/obsidian-excalidraw-plugin/issues/1605
|
||||
*/
|
||||
onUpdateElementLinkForExportHook: (data: {
|
||||
originalLink: string,
|
||||
obsidianLink: string,
|
||||
linkedFile: TFile | null,
|
||||
hostFile: TFile,
|
||||
}) => string = null;
|
||||
|
||||
/**
|
||||
* utility function to generate EmbeddedFilesLoader object
|
||||
* @param isDark
|
||||
@@ -2374,8 +2392,13 @@ export class ExcalidrawAutomate {
|
||||
if (!this.targetView) {
|
||||
return null;
|
||||
}
|
||||
const leaf = getNewOrAdjacentLeaf(this.plugin, this.targetView.leaf);
|
||||
leaf.openFile(file, openState ?? {active: true});
|
||||
|
||||
const {leaf, promise} = openLeaf({
|
||||
plugin: this.plugin,
|
||||
fnGetLeaf: () => getNewOrAdjacentLeaf(this.plugin, this.targetView.leaf),
|
||||
file,
|
||||
openState: openState ?? {active: true}
|
||||
});
|
||||
return leaf;
|
||||
};
|
||||
|
||||
@@ -2515,7 +2538,7 @@ export class ExcalidrawAutomate {
|
||||
};
|
||||
|
||||
/**
|
||||
* Depricated. Use getCM / ColorMaster instead
|
||||
* Deprecated. Use getCM / ColorMaster instead
|
||||
* @param color
|
||||
* @returns
|
||||
*/
|
||||
@@ -2525,7 +2548,7 @@ export class ExcalidrawAutomate {
|
||||
};
|
||||
|
||||
/**
|
||||
* Depricated. Use getCM / ColorMaster instead
|
||||
* Deprecated. Use getCM / ColorMaster instead
|
||||
* @param color
|
||||
* @returns
|
||||
*/
|
||||
@@ -2535,7 +2558,7 @@ export class ExcalidrawAutomate {
|
||||
};
|
||||
|
||||
/**
|
||||
* Depricated. Use getCM / ColorMaster instead
|
||||
* Deprecated. Use getCM / ColorMaster instead
|
||||
* @param color
|
||||
* @returns
|
||||
*/
|
||||
@@ -2545,7 +2568,7 @@ export class ExcalidrawAutomate {
|
||||
};
|
||||
|
||||
/**
|
||||
* Depricated. Use getCM / ColorMaster instead
|
||||
* Deprecated. Use getCM / ColorMaster instead
|
||||
* @param color
|
||||
* @returns
|
||||
*/
|
||||
@@ -2887,7 +2910,15 @@ export const updateElementLinksToObsidianLinks = ({elements, hostFile}:{
|
||||
if(!file) {
|
||||
return el;
|
||||
}
|
||||
const link = app.getObsidianUrl(file);
|
||||
let link = app.getObsidianUrl(file);
|
||||
if(window.ExcalidrawAutomate?.onUpdateElementLinkForExportHook) {
|
||||
link = window.ExcalidrawAutomate.onUpdateElementLinkForExportHook({
|
||||
originalLink: el.link,
|
||||
obsidianLink: link,
|
||||
linkedFile: file,
|
||||
hostFile: hostFile
|
||||
});
|
||||
}
|
||||
const newElement: Mutable<ExcalidrawElement> = cloneElement(el);
|
||||
newElement.link = link;
|
||||
return newElement;
|
||||
@@ -3052,7 +3083,7 @@ function errorMessage(message: string, source: string) {
|
||||
errorlog({
|
||||
where: "ExcalidrawAutomate",
|
||||
source,
|
||||
message: "this function is not avalable on Obsidian Mobile",
|
||||
message: "this function is not available on Obsidian Mobile",
|
||||
});
|
||||
break;
|
||||
default:
|
||||
|
||||
@@ -314,7 +314,10 @@ export class ExcalidrawData {
|
||||
map.set(item.id, item.type);
|
||||
alreadyHasText = true;
|
||||
} else {
|
||||
elements.find((el:ExcalidrawElement)=>el.id===item.id).containerId = null;
|
||||
const elementToClean = elements.find((el:ExcalidrawElement)=>el.id===item.id);
|
||||
if(elementToClean) { //https://github.com/zsviczian/obsidian-excalidraw-plugin/issues/1600
|
||||
elementToClean.containerId = null;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
map.set(item.id, item.type);
|
||||
@@ -819,7 +822,7 @@ export class ExcalidrawData {
|
||||
if (el.id.length > 8) {
|
||||
result = true;
|
||||
id = nanoid();
|
||||
jsonString = jsonString.replaceAll(el.id, id); //brute force approach to replace all occurances (e.g. links, groups,etc.)
|
||||
jsonString = jsonString.replaceAll(el.id, id); //brute force approach to replace all occurrences (e.g. links, groups,etc.)
|
||||
}
|
||||
this.elementLinks.set(id, el.link);
|
||||
}
|
||||
@@ -853,7 +856,7 @@ export class ExcalidrawData {
|
||||
delete this.selectedElementIds[te.id];
|
||||
this.selectedElementIds[id] = true;
|
||||
}
|
||||
jsonString = jsonString.replaceAll(te.id, id); //brute force approach to replace all occurances (e.g. links, groups,etc.)
|
||||
jsonString = jsonString.replaceAll(te.id, id); //brute force approach to replace all occurrences (e.g. links, groups,etc.)
|
||||
if (this.textElements.has(te.id)) {
|
||||
//element was created with onBeforeTextSubmit
|
||||
const text = this.textElements.get(te.id);
|
||||
|
||||
@@ -50,6 +50,7 @@ import {
|
||||
obsidianToExcalidrawMap,
|
||||
MAX_IMAGE_SIZE,
|
||||
fileid,
|
||||
sceneCoordsToViewportCoords,
|
||||
} from "./constants/constants";
|
||||
import ExcalidrawPlugin from "./main";
|
||||
import {
|
||||
@@ -100,7 +101,7 @@ import {
|
||||
fragWithHTML,
|
||||
isMaskFile,
|
||||
} from "./utils/Utils";
|
||||
import { getLeaf, getParentOfClass, obsidianPDFQuoteWithRef } from "./utils/ObsidianUtils";
|
||||
import { getLeaf, getParentOfClass, obsidianPDFQuoteWithRef, openLeaf } from "./utils/ObsidianUtils";
|
||||
import { splitFolderAndFilename } from "./utils/FileUtils";
|
||||
import { ConfirmationPrompt, GenericInputPrompt, NewFileActions, Prompt, linkPrompt } from "./dialogs/Prompt";
|
||||
import { ClipboardData } from "@zsviczian/excalidraw/types/excalidraw/clipboard";
|
||||
@@ -134,8 +135,6 @@ import { nanoid } from "nanoid";
|
||||
import { CustomMutationObserver, isDebugMode } from "./utils/DebugHelper";
|
||||
import { extractCodeBlocks, postOpenAI } from "./utils/AIUtils";
|
||||
import { Mutable } from "@zsviczian/excalidraw/types/excalidraw/utility-types";
|
||||
import no from "./lang/locale/no";
|
||||
import { carveOutImage } from "./utils/CarveOut";
|
||||
|
||||
declare const PLUGIN_VERSION:string;
|
||||
|
||||
@@ -261,6 +260,7 @@ export default class ExcalidrawView extends TextFileView {
|
||||
public canvasNodeFactory: CanvasNodeFactory;
|
||||
private embeddableRefs = new Map<ExcalidrawElement["id"], HTMLIFrameElement | HTMLWebViewElement>();
|
||||
private embeddableLeafRefs = new Map<ExcalidrawElement["id"], any>();
|
||||
// private scrollYBeforeKeyboard: number = null;
|
||||
|
||||
public semaphores: {
|
||||
popoutUnload: boolean; //the unloaded Excalidraw view was the last leaf in the popout window
|
||||
@@ -1004,18 +1004,21 @@ export default class ExcalidrawView extends TextFileView {
|
||||
let secondOrderLinks: string = " ";
|
||||
|
||||
const backlinks = this.app.metadataCache?.getBacklinksForFile(ef.file)?.data;
|
||||
if(backlinks) {
|
||||
const secondOrderLinksSet = new Set<string>();
|
||||
if(backlinks && this.plugin.settings.showSecondOrderLinks) {
|
||||
const linkPaths = Object.keys(backlinks)
|
||||
.filter(path => (path !== this.file.path) && (path !== ef.file.path))
|
||||
.map(path => {
|
||||
const filepathParts = splitFolderAndFilename(path);
|
||||
if(secondOrderLinksSet.has(path)) return "";
|
||||
secondOrderLinksSet.add(path);
|
||||
return `[[${path}|Second Order Link: ${filepathParts.basename}]]`;
|
||||
});
|
||||
secondOrderLinks += linkPaths.join(" ");
|
||||
}
|
||||
|
||||
if(this.plugin.isExcalidrawFile(ef.file)) {
|
||||
secondOrderLinks += getExcalidrawFileForwardLinks(this.app, ef.file);
|
||||
if(this.plugin.settings.showSecondOrderLinks && this.plugin.isExcalidrawFile(ef.file)) {
|
||||
secondOrderLinks += getExcalidrawFileForwardLinks(this.app, ef.file, secondOrderLinksSet);
|
||||
}
|
||||
|
||||
const linkString = (ef.isHyperLink || ef.isLocalLink
|
||||
@@ -1059,7 +1062,6 @@ export default class ExcalidrawView extends TextFileView {
|
||||
if(this.linksAlwaysOpenInANewPane && !anyModifierKeysPressed(keys)) {
|
||||
keys = emulateKeysForLinkClick("new-pane");
|
||||
}
|
||||
const leaf = getLeaf(this.plugin,this.leaf,keys);
|
||||
|
||||
try {
|
||||
//@ts-ignore
|
||||
@@ -1068,6 +1070,7 @@ export default class ExcalidrawView extends TextFileView {
|
||||
if(file.extension === "svg") {
|
||||
const svg = await this.app.vault.cachedRead(file);
|
||||
if(/(<|\<)(mxfile|mxgraph)/i.test(svg)) {
|
||||
const leaf = getLeaf(this.plugin,this.leaf,keys);
|
||||
leaf.setViewState({
|
||||
type: "diagram-edit",
|
||||
state: {
|
||||
@@ -1081,11 +1084,17 @@ export default class ExcalidrawView extends TextFileView {
|
||||
} catch(e) {
|
||||
console.error(e);
|
||||
}
|
||||
|
||||
await leaf.openFile(file, {
|
||||
active: !this.linksAlwaysOpenInANewPane,
|
||||
...subpath ? { eState: { subpath } } : {}
|
||||
|
||||
const {leaf, promise} = openLeaf({
|
||||
plugin: this.plugin,
|
||||
fnGetLeaf: () => getLeaf(this.plugin,this.leaf,keys),
|
||||
file,
|
||||
openState: {
|
||||
active: !this.linksAlwaysOpenInANewPane,
|
||||
...subpath ? { eState: { subpath } } : {}
|
||||
}
|
||||
}); //if file exists open file and jump to reference
|
||||
await promise;
|
||||
//view.app.workspace.setActiveLeaf(leaf, true, true); //0.15.4 ExcaliBrain focus issue
|
||||
} catch (e) {
|
||||
new Notice(e, 4000);
|
||||
@@ -1724,14 +1733,14 @@ export default class ExcalidrawView extends TextFileView {
|
||||
let counter = 0;
|
||||
const timestamp = Date.now();
|
||||
while (!imageCache.isReady() && confirmation) {
|
||||
const message = `You've been now wating for <b>${Math.round((Date.now()-timestamp)/1000)}</b> seconds. `
|
||||
const message = `You've been now waiting for <b>${Math.round((Date.now()-timestamp)/1000)}</b> seconds. `
|
||||
imageCache.initializationNotice = true;
|
||||
const confirmationPrompt = new ConfirmationPrompt(plugin,
|
||||
`${counter>0
|
||||
? counter%4 === 0
|
||||
? message + "The CACHE is still loading.<br><br>"
|
||||
: counter%4 === 1
|
||||
? message + "Watch the top rigth corner for the notification.<br><br>"
|
||||
? message + "Watch the top right corner for the notification.<br><br>"
|
||||
: counter%4 === 2
|
||||
? message + "I really, really hope the backup will work for you! <br><br>"
|
||||
: message + "I am sorry, it is taking a while, there is not much I can do... <br><br>"
|
||||
@@ -2407,7 +2416,7 @@ export default class ExcalidrawView extends TextFileView {
|
||||
this.selectedTextElement = null;
|
||||
return retval;
|
||||
}
|
||||
return { id: null, text: null };
|
||||
//return { id: null, text: null };
|
||||
}
|
||||
const selectedElement = api
|
||||
.getSceneElements()
|
||||
@@ -2468,7 +2477,7 @@ export default class ExcalidrawView extends TextFileView {
|
||||
this.selectedImageElement = null;
|
||||
return retval;
|
||||
}
|
||||
return { id: null, fileId: null };
|
||||
//return { id: null, fileId: null };
|
||||
}
|
||||
const selectedElement = api
|
||||
.getSceneElements()
|
||||
@@ -2515,7 +2524,7 @@ export default class ExcalidrawView extends TextFileView {
|
||||
this.selectedElementWithLink = null;
|
||||
return retval;
|
||||
}
|
||||
return { id: null, text: null };
|
||||
//return { id: null, text: null };
|
||||
}
|
||||
const selectedElement = api
|
||||
.getSceneElements()
|
||||
@@ -4065,11 +4074,61 @@ export default class ExcalidrawView extends TextFileView {
|
||||
]);
|
||||
}
|
||||
|
||||
if(appState.viewModeEnabled) {
|
||||
const isLaserOn = appState.activeTool?.type === "laser";
|
||||
contextMenuActions.push([
|
||||
renderContextMenuAction(
|
||||
isLaserOn ? t("LASER_OFF") : t("LASER_ON"),
|
||||
() => {
|
||||
api.setActiveTool({type: isLaserOn ? "selection" : "laser"});
|
||||
},
|
||||
onClose
|
||||
),
|
||||
]);
|
||||
}
|
||||
|
||||
if(!appState.viewModeEnabled) {
|
||||
const selectedTextElements = this.getViewSelectedElements().filter(el=>el.type === "text");
|
||||
if(selectedTextElements.length===1) {
|
||||
const selectedTextElement = selectedTextElements[0] as ExcalidrawTextElement;
|
||||
this.excalidrawData.getParsedText(selectedTextElement.id);
|
||||
const containerElement = (this.getViewElements() as ExcalidrawElement[]).find(el=>el.id === selectedTextElement.containerId);
|
||||
|
||||
//if the text element in the container no longer has a link associated with it...
|
||||
if(
|
||||
containerElement &&
|
||||
selectedTextElement.link &&
|
||||
this.excalidrawData.getParsedText(selectedTextElement.id)[1] === selectedTextElement.rawText
|
||||
) {
|
||||
contextMenuActions.push([
|
||||
renderContextMenuAction(
|
||||
t("REMOVE_LINK"),
|
||||
() => {
|
||||
const ea = getEA(this) as ExcalidrawAutomate;
|
||||
ea.copyViewElementsToEAforEditing([selectedTextElement]);
|
||||
const el = ea.getElement(selectedTextElement.id) as Mutable<ExcalidrawTextElement>;
|
||||
el.link = null;
|
||||
ea.addElementsToView(false);
|
||||
},
|
||||
onClose
|
||||
),
|
||||
]);
|
||||
}
|
||||
|
||||
if(containerElement) {
|
||||
contextMenuActions.push([
|
||||
renderContextMenuAction(
|
||||
t("SELECT_TEXTELEMENT_ONLY"),
|
||||
() => {
|
||||
setTimeout(()=>
|
||||
(this.excalidrawAPI as ExcalidrawImperativeAPI).selectElements([selectedTextElement])
|
||||
);
|
||||
},
|
||||
onClose
|
||||
),
|
||||
]);
|
||||
}
|
||||
|
||||
if(!containerElement || (containerElement && containerElement.type !== "arrow")) {
|
||||
contextMenuActions.push([
|
||||
renderContextMenuAction(
|
||||
@@ -4412,6 +4471,7 @@ export default class ExcalidrawView extends TextFileView {
|
||||
height: undefined,
|
||||
});
|
||||
|
||||
|
||||
React.useEffect(() => {
|
||||
this.toolsPanelRef = toolsPanelRef;
|
||||
this.embeddableMenuRef = embeddableMenuRef;
|
||||
@@ -4420,6 +4480,7 @@ export default class ExcalidrawView extends TextFileView {
|
||||
this.excalidrawWrapperRef = excalidrawWrapperRef;
|
||||
}, []);
|
||||
|
||||
|
||||
React.useEffect(() => {
|
||||
setDimensions({
|
||||
width: this.contentEl.clientWidth,
|
||||
@@ -4431,7 +4492,54 @@ export default class ExcalidrawView extends TextFileView {
|
||||
const width = this.contentEl.clientWidth;
|
||||
const height = this.contentEl.clientHeight;
|
||||
if(width === 0 || height === 0) return;
|
||||
|
||||
//this is an aweful hack to prevent the keyboard pushing the canvas out of view.
|
||||
//The issue is that contrary to Excalidraw.com where the page is simply pushed up, in
|
||||
//Obsidian the leaf has a fixed top. As a consequence the top of excalidrawWrapperDiv does not get pushed out of view
|
||||
//but shirnks. But the text area is positioned relative to excalidrawWrapperDiv and consequently does not fit, which
|
||||
//the distorts the whole layout.
|
||||
//I hope to grow up one day and clean up this mess of a workaround, that resets the top of excalidrawWrapperDiv
|
||||
//to a negative value, and manually scrolls back elements that were scrolled off screen
|
||||
//I tried updating setDimensions with the value for top... but setting top and height using setDimensions did not do the trick
|
||||
//I found that adding and removing this style solves the issue.
|
||||
//...again, just aweful, but works.
|
||||
const st = this.excalidrawAPI.getAppState();
|
||||
const isKeyboardOutEvent = st.editingElement?.type === "text";
|
||||
const isKeyboardBackEvent = this.semaphores.isEditingText && !isKeyboardOutEvent;
|
||||
if(isKeyboardOutEvent) {
|
||||
const self = this;
|
||||
const appToolHeight = (self.contentEl.querySelector(".Island.App-toolbar") as HTMLElement)?.clientHeight ?? 0;
|
||||
const editingElViewY = sceneCoordsToViewportCoords({sceneX:0, sceneY:st.editingElement.y}, st).y;
|
||||
const scrollViewY = sceneCoordsToViewportCoords({sceneX:0, sceneY:-st.scrollY}, st).y;
|
||||
const delta = editingElViewY - scrollViewY;
|
||||
const isElementAboveKeyboard = height > (delta + appToolHeight*2)
|
||||
const excalidrawWrapper = this.excalidrawWrapperRef.current;
|
||||
console.log({isElementAboveKeyboard});
|
||||
if(excalidrawWrapper && !isElementAboveKeyboard) {
|
||||
excalidrawWrapper.style.top = `${-(st.height - height)}px`;
|
||||
excalidrawWrapper.style.height = `${st.height}px`;
|
||||
self.excalidrawContainer?.querySelector(".App-bottom-bar")?.scrollIntoView();
|
||||
//@ts-ignore
|
||||
self.headerEl?.scrollIntoView();
|
||||
}
|
||||
}
|
||||
if(isKeyboardBackEvent) {
|
||||
const excalidrawWrapper = this.excalidrawWrapperRef.current;
|
||||
const appButtonBar = this.excalidrawContainer?.querySelector(".App-bottom-bar");
|
||||
//@ts-ignore
|
||||
const headerEl = this.headerEl;
|
||||
if(excalidrawWrapper) {
|
||||
excalidrawWrapper.style.top = "";
|
||||
excalidrawWrapper.style.height = "";
|
||||
appButtonBar?.scrollIntoView();
|
||||
headerEl?.scrollIntoView();
|
||||
}
|
||||
}
|
||||
//end of aweful hack
|
||||
|
||||
|
||||
setDimensions({ width, height });
|
||||
|
||||
if (this.toolsPanelRef && this.toolsPanelRef.current) {
|
||||
this.toolsPanelRef.current.updatePosition();
|
||||
}
|
||||
@@ -4579,7 +4687,7 @@ export default class ExcalidrawView extends TextFileView {
|
||||
if (containers.length > 0) {
|
||||
if (this.initialContainerSizeUpdate) {
|
||||
//updateContainerSize will bump scene version which will trigger a false autosave
|
||||
//after load, which will lead to a ping-pong between two syncronizing devices
|
||||
//after load, which will lead to a ping-pong between two synchronizing devices
|
||||
this.semaphores.justLoaded = true;
|
||||
}
|
||||
api.updateContainerSize(containers);
|
||||
|
||||
@@ -45,11 +45,20 @@ let metadataCache: MetadataCache;
|
||||
const getDefaultWidth = (plugin: ExcalidrawPlugin): string => {
|
||||
const width = parseInt(plugin.settings.width);
|
||||
if (isNaN(width) || width === 0 || width === null) {
|
||||
if(getDefaultHeight(plugin)!=="") return "";
|
||||
return "400";
|
||||
}
|
||||
return plugin.settings.width;
|
||||
};
|
||||
|
||||
const getDefaultHeight = (plugin: ExcalidrawPlugin): string => {
|
||||
const height = parseInt(plugin.settings.height);
|
||||
if (isNaN(height) || height === 0 || height === null) {
|
||||
return "";
|
||||
}
|
||||
return plugin.settings.height;
|
||||
};
|
||||
|
||||
export const initializeMarkdownPostProcessor = (p: ExcalidrawPlugin) => {
|
||||
plugin = p;
|
||||
vault = p.app.vault;
|
||||
@@ -123,9 +132,14 @@ const setStyle = ({element,imgAttributes,onCanvas}:{
|
||||
onCanvas: boolean,
|
||||
}
|
||||
) => {
|
||||
let style = `max-width:${imgAttributes.fwidth}${imgAttributes.fwidth.match(/\d$/) ? "px":""}; `; //width:100%;`; //removed !important https://github.com/zsviczian/obsidian-excalidraw-plugin/issues/886
|
||||
let style = "";
|
||||
if(imgAttributes.fwidth) {
|
||||
style = `max-width:${imgAttributes.fwidth}${imgAttributes.fwidth.match(/\d$/) ? "px":""}; `; //width:100%;`; //removed !important https://github.com/zsviczian/obsidian-excalidraw-plugin/issues/886
|
||||
} else {
|
||||
style = "width: fit-content;"
|
||||
}
|
||||
if (imgAttributes.fheight) {
|
||||
style += `height:${imgAttributes.fheight}px;`;
|
||||
style += `${imgAttributes.fwidth?"min-":"max-"}height:${imgAttributes.fheight}px;`;
|
||||
}
|
||||
if(!onCanvas) element.setAttribute("style", style);
|
||||
element.classList.add(...Array.from(imgAttributes.style))
|
||||
@@ -363,7 +377,7 @@ const createImgElement = async (
|
||||
const linkModifier = linkClickModifierType(ev);
|
||||
if (plugin.isExcalidrawFile(f) && isMaskFile(plugin, f)) {
|
||||
(async () => {
|
||||
const linkString = `[[${f.path}${srcParts[2]?"#"+srcParts[2]:""}]] ${getExcalidrawFileForwardLinks(plugin.app, f)}`;
|
||||
const linkString = `[[${f.path}${srcParts[2]?"#"+srcParts[2]:""}]] ${getExcalidrawFileForwardLinks(plugin.app, f, new Set<string>())}`;
|
||||
const result = await linkPrompt(linkString, plugin.app);
|
||||
if(!result) return;
|
||||
const [file, linkText, subpath] = result;
|
||||
@@ -510,9 +524,11 @@ const processInternalEmbed = async (internalEmbedEl: Element, file: TFile ):Prom
|
||||
internalEmbedEl.addClass("image-embed");
|
||||
|
||||
attr.fwidth = internalEmbedEl.getAttribute("width")
|
||||
? internalEmbedEl.getAttribute("width")
|
||||
: getDefaultWidth(plugin);
|
||||
attr.fheight = internalEmbedEl.getAttribute("height");
|
||||
? internalEmbedEl.getAttribute("width")
|
||||
: getDefaultWidth(plugin);
|
||||
attr.fheight = internalEmbedEl.getAttribute("height")
|
||||
? internalEmbedEl.getAttribute("height")
|
||||
: getDefaultHeight(plugin);
|
||||
let alt = internalEmbedEl.getAttribute("alt");
|
||||
attr.style = ["excalidraw-svg"];
|
||||
processAltText(src.split("#")[0],alt,attr);
|
||||
@@ -596,7 +612,7 @@ const tmpObsidianWYSIWYG = async (
|
||||
|
||||
const attr: imgElementAttributes = {
|
||||
fname: ctx.sourcePath,
|
||||
fheight: "",
|
||||
fheight: getDefaultHeight(plugin),
|
||||
fwidth: getDefaultWidth(plugin),
|
||||
style: ["excalidraw-svg"],
|
||||
};
|
||||
@@ -609,8 +625,21 @@ const tmpObsidianWYSIWYG = async (
|
||||
//We are processing the markdown preview of an actual Excalidraw file
|
||||
//the excalidraw file in markdown preview mode
|
||||
const isFrontmatterDiv = Boolean(el.querySelector(".frontmatter"));
|
||||
el.empty();
|
||||
if(!isFrontmatterDiv) {
|
||||
let areaPreview = false;
|
||||
if(Boolean(ctx.frontmatter)) {
|
||||
el.empty();
|
||||
} else {
|
||||
const warningEl = el.querySelector("div>h3[data-heading^='Unable to find section #^");
|
||||
if(warningEl) {
|
||||
const ref = warningEl.getAttr("data-heading").match(/Unable to find section (#\^(?:group=|area=|frame=)[^ ]*)/)?.[1];
|
||||
if(ref) {
|
||||
attr.fname = file.path + ref;
|
||||
areaPreview = true;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
if(!isFrontmatterDiv && !areaPreview) {
|
||||
if(el.parentElement === containerEl) containerEl.removeChild(el);
|
||||
return;
|
||||
}
|
||||
@@ -775,7 +804,7 @@ const legacyExcalidrawPopoverObserverFn: MutationCallback = async (m) => {
|
||||
node.empty();
|
||||
|
||||
//this div will be on top of original DIV. By stopping the propagation of the click
|
||||
//I prevent the default Obsidian feature of openning the link in the native app
|
||||
//I prevent the default Obsidian feature of opening the link in the native app
|
||||
const img = await getIMG({
|
||||
file,
|
||||
fname: file.path,
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -17,6 +17,83 @@ I develop this plugin as a hobby, spending my free time doing this. If you find
|
||||
|
||||
<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.24":`
|
||||
Quality of Life Fixes!
|
||||
|
||||
## Fixed
|
||||
- Text editing issue on mobile devices with an on-screen keyboard is now fixed 🥳. Previously, Excalidraw's UI fell apart when the keyboard was activated, and often even after you stopped editing, the canvas positioning was off. I hope to have solved the issue (we'll see after your testing and feedback!). This is one of those cases that seems insignificant but took enormous effort. It took me 2.5 full days of net time to figure out the root cause and the solution (this is not an exaggeration).
|
||||
- Tool buttons did not get selected on the first click.
|
||||
- Images flicker on Forced Save.
|
||||
- Hover preview fixes:
|
||||
- ${String.fromCharCode(96)}area=${String.fromCharCode(96)}, ${String.fromCharCode(96)}group=${String.fromCharCode(96)}, ${String.fromCharCode(96)}frame=${String.fromCharCode(96)} references now display the part of the image as expected in hover preview (showed an empty preview until now).
|
||||
- Block and section references to notes on the "back side of the drawing" now correctly show up in hover preview (showed an empty preview until now).
|
||||
|
||||
## New
|
||||
- Default height setting in Plugin Settings. Thanks @leoccyao! [#1612](https://github.com/zsviczian/obsidian-excalidraw-plugin/pull/1612)
|
||||
`,
|
||||
"2.0.23":`
|
||||
## New
|
||||
- Additional arrowheads (Circle, Circle Outline, Diamond, Diamond Outline, Triangle Outline) are now available via element properties.
|
||||
- Setting under "Links and Transclusions" to show/hide second-order links
|
||||
|
||||
## Fixed
|
||||
- some styling issues with dynamic styles (e.g.: text color of context menu)
|
||||
|
||||
## New in ExcalidrawAutomate
|
||||
- Excalidraw Publish Support: New hook to modify the link in the exported SVGs. This is useful when you want to export SVGs to your website. If set, this callback is triggered whenever a drawing is exported to SVG. The string returned by the hook will replace the link in the exported SVG. The hook is only executed if the link is to a file internal to Obsidian. [1605](https://github.com/zsviczian/obsidian-excalidraw-plugin/issues/1605)
|
||||
${String.fromCharCode(96,96,96)}js
|
||||
onUpdateElementLinkForExportHook: (data: {
|
||||
* originalLink: string,
|
||||
* obsidianLink: string,
|
||||
* linkedFile: TFile | null,
|
||||
* hostFile: TFile,
|
||||
* }) => string = null;
|
||||
${String.fromCharCode(96,96,96)}
|
||||
`,
|
||||
"2.0.22":`
|
||||
## Fixed
|
||||
- BUG: Unable to load obsidian excalidraw plugin on ipad 15.x or older [#1525](https://github.com/zsviczian/obsidian-excalidraw-plugin/issues/1525)
|
||||
- BUG: ea.help does not display help if only function signature is available [#1601](https://github.com/zsviczian/obsidian-excalidraw-plugin/issues/1601)
|
||||
`,
|
||||
"2.0.21":`
|
||||
## New/changed
|
||||
**"Focus on Existing Tab"**
|
||||
- New Setting: Disabled by default.
|
||||
- Prevents multiple instances of the same drawing from opening when clicking on links within Excalidraw.
|
||||
- Overrides the "Reuse Adjacent Pane" option when the file is already open.
|
||||
- Accessible under "Links, Transclusions, and TODOs" in plugin settings.
|
||||
|
||||
**Enhanced Context Menu Functions for Text Containers**
|
||||
- Two new context menu functions added for containers with a text element:
|
||||
- Right-click to select the text element only, allowing independent color changes from the container.
|
||||
- Remove orphaned element links when the text element has a link but no longer includes a link in the text.
|
||||
|
||||
**Improved Laser Pointer Activation**
|
||||
- Laser pointer activation on double tap in view mode removed due to interference with link navigation and other features.
|
||||
- When the drawing is in "view" mode, laser pointer activation now available via long-press/right-click context menu.
|
||||
- Alternatively, activate the laser pointer with "k" if you have a keyboard.
|
||||
|
||||
## Fixed
|
||||
- **Older iOS and Android webview support**: Rebuilt all packages and dependencies with Node 18, hoping to address (sorry I can't reproduce/test these issues myself) compatibility issues with older iPad OS versions, up to 15.7. [#1525](https://github.com/zsviczian/obsidian-excalidraw-plugin/issues/1525), and Android [1598](https://github.com/zsviczian/obsidian-excalidraw-plugin/issues/1598)
|
||||
- **Double-click navigation**: Fixed the issue where double-clicking an embedded image did not navigate to the link in view mode.
|
||||
- **ExcaliBrain new file creation**: Resolved the issue with new file creation from ExcaliBrain. [#201](https://github.com/zsviczian/excalibrain/issues/201)
|
||||
- **Canvas immersive style**: Removed Canvas immersive embedding style support from the Excalidraw stylesheet to address performance issues experienced by some users with various Obsidian themes. If you require this feature, you can add a CSS snippet with the provided code.
|
||||
|
||||
${String.fromCharCode(96,96,96)}css
|
||||
.canvas-node:not(.is-editing):has(.excalidraw-canvas-immersive) {
|
||||
::-webkit-scrollbar,
|
||||
::-webkit-scrollbar-horizontal {
|
||||
display: none;
|
||||
}
|
||||
background-color: transparent !important;
|
||||
}
|
||||
|
||||
.canvas-node:not(.is-editing) .canvas-node-container:has(.excalidraw-canvas-immersive) {
|
||||
border: unset;
|
||||
box-shadow: unset;
|
||||
}
|
||||
${String.fromCharCode(96,96,96)}
|
||||
`,
|
||||
"2.0.20":`
|
||||
## Fixed in ExcalidrawAutomate
|
||||
- Regression: ${String.fromCharCode(96)}ea.getMaximumGroups(elements)${String.fromCharCode(96)} stopped working after the 2.0.19 update. [#1576](https://github.com/zsviczian/obsidian-excalidraw-plugin/issues/1576)
|
||||
@@ -856,7 +933,7 @@ ${String.fromCharCode(96,96,96)}`,
|
||||
## New
|
||||
- New scripts by @threethan:
|
||||
- [Auto Draw for Pen](https://github.com/zsviczian/obsidian-excalidraw-plugin/blob/master/ea-scripts/Auto%20Draw%20for%20Pen.md): Automatically switches between the select and draw tools, based on whether a pen is being used. Supports most pens including Apple Pencil.
|
||||
- [Hardware Eraser Support](https://github.com/zsviczian/obsidian-excalidraw-plugin/blob/master/ea-scripts/Hardware%20Eraser%20Support.md): Adds support for pen inversion, a.k.a. the hardware eraser on the back of your pen. Supports Windows based styluses. Does not suppoprt Apple Pencil or S-Pen.
|
||||
- [Hardware Eraser Support](https://github.com/zsviczian/obsidian-excalidraw-plugin/blob/master/ea-scripts/Hardware%20Eraser%20Support.md): Adds support for pen inversion, a.k.a. the hardware eraser on the back of your pen. Supports Windows based styluses. Does not support Apple Pencil or S-Pen.
|
||||
- Added separate buttons to support copying link, area or group references to objects on the drawing. [#1063](https://github.com/zsviczian/obsidian-excalidraw-plugin/issues/1063). See [this video](https://youtu.be/yZQoJg2RCKI) for more details on how this works.
|
||||
- Hover preview will no longer trigger for image files (.png, .svg, .jpg, .gif, .webp, .bmp, .ico, .excalidraw)
|
||||
- Minor updates to the [Slideshow](https://github.com/zsviczian/obsidian-excalidraw-plugin/blob/master/ea-scripts/Slideshow.md) script. You can download the updated script from the Excalidraw script library. The slideshow will now correctly run also when initiated in a popout window. When the drawing is in a popout window, the slideshow will not be full screen, but will only occupy the popout window. If you run the slideshow from the main Obsidian workspace, it will be displayed in full-screen mode.
|
||||
|
||||
@@ -393,7 +393,7 @@ export class PenSettingsModal extends Modal {
|
||||
let spSetting: Setting;
|
||||
|
||||
new Setting(ce)
|
||||
.setName("Pressure sensitve pen?")
|
||||
.setName("Pressure sensitive pen?")
|
||||
.setDesc(fragWithHTML(`<b>toggle on</b>: pressure sensitive<br><b>toggle off</b>: constant pressure`))
|
||||
.addToggle(toggle =>
|
||||
toggle
|
||||
|
||||
@@ -12,7 +12,7 @@ import {
|
||||
import ExcalidrawView from "../ExcalidrawView";
|
||||
import ExcalidrawPlugin from "../main";
|
||||
import { escapeRegExp, getLinkParts, sleep } from "../utils/Utils";
|
||||
import { getLeaf } from "../utils/ObsidianUtils";
|
||||
import { getLeaf, openLeaf } from "../utils/ObsidianUtils";
|
||||
import { checkAndCreateFolder, splitFolderAndFilename } from "src/utils/FileUtils";
|
||||
import { KeyEvent, isWinCTRLorMacCMD } from "src/utils/ModifierkeyHelper";
|
||||
import { t } from "src/lang/helpers";
|
||||
@@ -499,7 +499,7 @@ export class NewFileActions extends Modal {
|
||||
this.view = view;
|
||||
this.openNewFile = openNewFile;
|
||||
this.sourceElement = sourceElement;
|
||||
if(!parentFile) this.parentFile = view.file;
|
||||
this.parentFile = parentFile ?? view.file;
|
||||
this.waitForClose = new Promise<TFile|null>((resolve, reject) => {
|
||||
this.resolvePromise = resolve;
|
||||
this.rejectPromise = reject;
|
||||
@@ -515,8 +515,12 @@ export class NewFileActions extends Modal {
|
||||
if (!file || !this.openNewFile) {
|
||||
return;
|
||||
}
|
||||
const leaf = getLeaf(this.plugin,this.view.leaf,this.keys)
|
||||
leaf.openFile(file, {active:true});
|
||||
openLeaf({
|
||||
plugin: this.plugin,
|
||||
fnGetLeaf: () => getLeaf(this.plugin,this.view.leaf,this.keys),
|
||||
file,
|
||||
openState: { active: true },
|
||||
});
|
||||
}
|
||||
|
||||
onClose() {
|
||||
|
||||
@@ -595,7 +595,7 @@ export const EXCALIDRAW_AUTOMATE_INFO: SuggesterInfo[] = [
|
||||
{
|
||||
field: "getleaf",
|
||||
code: "getLeaf(origo: WorkspaceLeaf, targetPane?: PaneTarget): WorkspaceLeaf;",
|
||||
desc: "Generates a new Obsidian Leaf following Excalidraw plugin settings such as open in Main Workspace or not, open in adjacent pane if avaialble, etc.<br>" +
|
||||
desc: "Generates a new Obsidian Leaf following Excalidraw plugin settings such as open in Main Workspace or not, open in adjacent pane if available, etc.<br>" +
|
||||
"@param origo: the currently active leaf, the origin of the new leaf<br>" +
|
||||
'@param targetPane: <code>type PaneTarget = "active-pane"|"new-pane"|"popout-window"|"new-tab"|"md-properties";',
|
||||
after: "",
|
||||
@@ -643,7 +643,7 @@ export const EXCALIDRAW_AUTOMATE_INFO: SuggesterInfo[] = [
|
||||
},
|
||||
{
|
||||
field: "postOpenAI",
|
||||
code: "async postOpenAI(requst: AIRequest): Promise<RequestUrlResponse>",
|
||||
code: "async postOpenAI(request: AIRequest): Promise<RequestUrlResponse>",
|
||||
desc:
|
||||
"This asynchronous function should be awaited. It posts the supplied request to the OpenAI API and returns the response.<br>" +
|
||||
"The response is a dictionary with the following keys:<br><code>{image, text, instruction, systemPrompt, responseType}</code><br>"+
|
||||
|
||||
@@ -105,10 +105,14 @@ export default {
|
||||
BACKUP_RESTORED: "Backup restored",
|
||||
CACHE_NOT_READY: "I apologize for the inconvenience, but an error occurred while loading your file.<br><br><mark>Having a little patience can save you a lot of time...</mark><br><br>The plugin has a backup cache, but it appears that you have just started Obsidian. Initializing the Backup Cache may take some time, usually up to a minute or more depending on your device's performance. You will receive a notification in the top right corner when the cache initialization is complete.<br><br>Please press OK to attempt loading the file again and check if the cache has finished initializing. If you see a completely empty file behind this message, I recommend waiting until the backup cache is ready before proceeding. Alternatively, you can choose Cancel to manually correct your file.<br>",
|
||||
OBSIDIAN_TOOLS_PANEL: "Obsidian Tools Panel",
|
||||
ERROR_SAVING_IMAGE: "Unknown error occured while fetching the image. It could be that for some reason the image is not available or rejected the fetch request from Obsidian",
|
||||
ERROR_SAVING_IMAGE: "Unknown error occurred while fetching the image. It could be that for some reason the image is not available or rejected the fetch request from Obsidian",
|
||||
WARNING_PASTING_ELEMENT_AS_TEXT: "PASTING EXCALIDRAW ELEMENTS AS A TEXT ELEMENT IS NOT ALLOWED",
|
||||
USE_INSERT_FILE_MODAL: "Use 'Insert Any File' to embed a markdown note",
|
||||
CONVERT_TO_MARKDOWN: "Convert to file...",
|
||||
SELECT_TEXTELEMENT_ONLY: "Select text element only (not container)",
|
||||
REMOVE_LINK: "Remove text element link",
|
||||
LASER_ON: "Enable laser pointer",
|
||||
LASER_OFF: "Disable laser pointer",
|
||||
|
||||
//settings.ts
|
||||
RELEASE_NOTES_NAME: "Display Release Notes after update",
|
||||
@@ -306,6 +310,13 @@ FILENAME_HEAD: "Filename",
|
||||
"These settings are different for Apple and non-Apple. If you use Obsidian on multiple platforms, you'll need to make the settings separately. "+
|
||||
"The toggles follow the order of " +
|
||||
(DEVICE.isIOS || DEVICE.isMacOS ? "SHIFT, CMD, OPT, CONTROL." : "SHIFT, CTRL, ALT, META (Windows key)."),
|
||||
FOCUS_ON_EXISTING_TAB_NAME: "Focus on Existing Tab",
|
||||
FOCUS_ON_EXISTING_TAB_DESC: "When opening a link, Excalidraw will focus on the existing tab if the file is already open. " +
|
||||
"Enabling this setting overrides 'Reuse Adjacent Pane' when the file is already open.",
|
||||
SECOND_ORDER_LINKS_NAME: "Show second-order links",
|
||||
SECOND_ORDER_LINKS_DESC: "Show links when clicking on a link in Excalidraw. Second-order link are backlinks pointing to the link being clicked. " +
|
||||
"When using image icons to connect similar notes, second order links allow you to get to related notes in one click instead of two. " +
|
||||
"See <a href='https://youtube.com/shorts/O_1ls9c6wBY?feature=share'>YT Short</a> to understand.",
|
||||
ADJACENT_PANE_NAME: "Reuse adjacent pane",
|
||||
ADJACENT_PANE_DESC:
|
||||
`When ${labelCTRL()}+${labelALT()} clicking a link in Excalidraw, by default the plugin will open the link in a new pane. ` +
|
||||
@@ -458,6 +469,11 @@ FILENAME_HEAD: "Filename",
|
||||
"The default width of an embedded drawing. This applies to live preview edit and reading mode, as well as to hover previews. You can specify a custom " +
|
||||
"width when embedding an image using the <code>![[drawing.excalidraw|100]]</code> or " +
|
||||
"<code>[[drawing.excalidraw|100x100]]</code> format.",
|
||||
EMBED_HEIGHT_NAME: "Default height of embedded (transcluded) image",
|
||||
EMBED_HEIGHT_DESC:
|
||||
"The default height of an embedded drawing. This applies to live preview edit and reading mode, as well as to hover previews. You can specify a custom " +
|
||||
"height when embedding an image using the <code>![[drawing.excalidraw|100]]</code> or " +
|
||||
"<code>[[drawing.excalidraw|100x100]]</code> format.",
|
||||
EMBED_TYPE_NAME: "Type of file to insert into the document",
|
||||
EMBED_TYPE_DESC:
|
||||
"When you embed an image into a document using the command palette this setting will specify if Excalidraw should embed the original Excalidraw file " +
|
||||
|
||||
48
src/main.ts
48
src/main.ts
@@ -98,7 +98,7 @@ import {
|
||||
isCallerFromTemplaterPlugin,
|
||||
decompress,
|
||||
} from "./utils/Utils";
|
||||
import { extractSVGPNGFileName, getActivePDFPageNumberFromPDFView, getAttachmentsFolderAndFilePath, getNewOrAdjacentLeaf, getParentOfClass, isObsidianThemeDark } from "./utils/ObsidianUtils";
|
||||
import { extractSVGPNGFileName, getActivePDFPageNumberFromPDFView, getAttachmentsFolderAndFilePath, getNewOrAdjacentLeaf, getParentOfClass, isObsidianThemeDark, openLeaf } from "./utils/ObsidianUtils";
|
||||
import { ExcalidrawElement, ExcalidrawEmbeddableElement, ExcalidrawImageElement, ExcalidrawTextElement, FileId } from "@zsviczian/excalidraw/types/excalidraw/element/types";
|
||||
import { ScriptEngine } from "./Scripts";
|
||||
import {
|
||||
@@ -2840,29 +2840,37 @@ export default class ExcalidrawPlugin extends Plugin {
|
||||
subpath?: string,
|
||||
justCreated: boolean = false
|
||||
) {
|
||||
if(location === "md-properties") {
|
||||
location = "new-tab";
|
||||
}
|
||||
let leaf: WorkspaceLeaf;
|
||||
if(location === "popout-window") {
|
||||
leaf = app.workspace.openPopoutLeaf();
|
||||
}
|
||||
if(location === "new-tab") {
|
||||
leaf = app.workspace.getLeaf('tab');
|
||||
}
|
||||
if(!leaf) {
|
||||
leaf = this.app.workspace.getLeaf(false);
|
||||
if ((leaf.view.getViewType() !== 'empty') && (location === "new-pane")) {
|
||||
leaf = getNewOrAdjacentLeaf(this, leaf)
|
||||
|
||||
const fnGetLeaf = ():WorkspaceLeaf => {
|
||||
if(location === "md-properties") {
|
||||
location = "new-tab";
|
||||
}
|
||||
let leaf: WorkspaceLeaf;
|
||||
if(location === "popout-window") {
|
||||
leaf = app.workspace.openPopoutLeaf();
|
||||
}
|
||||
if(location === "new-tab") {
|
||||
leaf = app.workspace.getLeaf('tab');
|
||||
}
|
||||
if(!leaf) {
|
||||
leaf = this.app.workspace.getLeaf(false);
|
||||
if ((leaf.view.getViewType() !== 'empty') && (location === "new-pane")) {
|
||||
leaf = getNewOrAdjacentLeaf(this, leaf)
|
||||
}
|
||||
}
|
||||
return leaf;
|
||||
}
|
||||
|
||||
leaf.openFile(
|
||||
drawingFile,
|
||||
!subpath || subpath === ""
|
||||
const {leaf, promise} = openLeaf({
|
||||
plugin: this,
|
||||
fnGetLeaf: () => fnGetLeaf(),
|
||||
file: drawingFile,
|
||||
openState:!subpath || subpath === ""
|
||||
? {active}
|
||||
: { active, eState: { subpath } }
|
||||
).then(()=>{
|
||||
});
|
||||
|
||||
promise.then(()=>{
|
||||
if(justCreated && this.ea.onFileCreateHook) {
|
||||
try {
|
||||
this.ea.onFileCreateHook({
|
||||
@@ -2932,7 +2940,7 @@ export default class ExcalidrawPlugin extends Plugin {
|
||||
//also Excalidraw IDs are inconveniently long
|
||||
if (te.id.length > 8) {
|
||||
id = nanoid();
|
||||
data = data.replaceAll(te.id, id); //brute force approach to replace all occurances.
|
||||
data = data.replaceAll(te.id, id); //brute force approach to replace all occurrences.
|
||||
}
|
||||
outString += `${te.originalText ?? te.text} ^${id}\n\n`;
|
||||
}
|
||||
|
||||
@@ -155,12 +155,12 @@ export class EmbeddableMenu {
|
||||
title={t("NARROW_TO_BLOCK")}
|
||||
action={async () => {
|
||||
if(!file) return;
|
||||
const paragrphs = (await app.metadataCache.blockCache
|
||||
const paragraphs = (await app.metadataCache.blockCache
|
||||
.getForFile({ isCancelled: () => false },file))
|
||||
.blocks.filter((b: any) => b.display && b.node?.type === "paragraph");
|
||||
const values = ["entire-file"].concat(paragrphs);
|
||||
const values = ["entire-file"].concat(paragraphs);
|
||||
const display = [t("SHOW_ENTIRE_FILE")].concat(
|
||||
paragrphs.map((b: any) => `${b.node?.id ? `#^${b.node.id}: ` : ``}${b.display.trim()}`));
|
||||
paragraphs.map((b: any) => `${b.node?.id ? `#^${b.node.id}: ` : ``}${b.display.trim()}`));
|
||||
|
||||
const selectedBlock = await ScriptEngine.suggester(
|
||||
app, display, values, "Select section from document"
|
||||
|
||||
@@ -58,6 +58,7 @@ export interface ExcalidrawSettings {
|
||||
displayExportedImageIfAvailable: boolean;
|
||||
previewMatchObsidianTheme: boolean;
|
||||
width: string;
|
||||
height: string;
|
||||
dynamicStyling: DynamicStyle;
|
||||
isLeftHanded: boolean;
|
||||
iframeMatchExcalidrawTheme: boolean;
|
||||
@@ -72,6 +73,8 @@ export interface ExcalidrawSettings {
|
||||
zoomToFitOnResize: boolean;
|
||||
zoomToFitMaxLevel: number;
|
||||
openInAdjacentPane: boolean;
|
||||
showSecondOrderLinks: boolean;
|
||||
focusOnFileTab: boolean;
|
||||
openInMainWorkspace: boolean;
|
||||
showLinkBrackets: boolean;
|
||||
linkPrefix: string;
|
||||
@@ -201,6 +204,7 @@ export const DEFAULT_SETTINGS: ExcalidrawSettings = {
|
||||
displayExportedImageIfAvailable: false,
|
||||
previewMatchObsidianTheme: false,
|
||||
width: "400",
|
||||
height: "",
|
||||
dynamicStyling: "colorful",
|
||||
isLeftHanded: false,
|
||||
iframeMatchExcalidrawTheme: true,
|
||||
@@ -222,6 +226,8 @@ export const DEFAULT_SETTINGS: ExcalidrawSettings = {
|
||||
hoverPreviewWithoutCTRL: false,
|
||||
linkOpacity: 1,
|
||||
openInAdjacentPane: false,
|
||||
showSecondOrderLinks: true,
|
||||
focusOnFileTab: false,
|
||||
openInMainWorkspace: true,
|
||||
showLinkBrackets: true,
|
||||
allowCtrlClick: true,
|
||||
@@ -1168,6 +1174,18 @@ export class ExcalidrawSettingTab extends PluginSettingTab {
|
||||
(el) => (el.innerHTML = t("LINKS_DESC")),
|
||||
);
|
||||
|
||||
new Setting(detailsEl)
|
||||
.setName(t("SECOND_ORDER_LINKS_NAME"))
|
||||
.setDesc(fragWithHTML(t("SECOND_ORDER_LINKS_DESC")))
|
||||
.addToggle((toggle) =>
|
||||
toggle
|
||||
.setValue(this.plugin.settings.showSecondOrderLinks)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.showSecondOrderLinks = value;
|
||||
this.applySettingsUpdate();
|
||||
}),
|
||||
);
|
||||
|
||||
new Setting(detailsEl)
|
||||
.setName(t("ADJACENT_PANE_NAME"))
|
||||
.setDesc(fragWithHTML(t("ADJACENT_PANE_DESC")))
|
||||
@@ -1179,7 +1197,18 @@ export class ExcalidrawSettingTab extends PluginSettingTab {
|
||||
this.applySettingsUpdate();
|
||||
}),
|
||||
);
|
||||
|
||||
|
||||
new Setting(detailsEl)
|
||||
.setName(t("FOCUS_ON_EXISTING_TAB_NAME"))
|
||||
.setDesc(fragWithHTML(t("FOCUS_ON_EXISTING_TAB_DESC")))
|
||||
.addToggle((toggle) =>
|
||||
toggle
|
||||
.setValue(this.plugin.settings.focusOnFileTab)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.focusOnFileTab = value;
|
||||
this.applySettingsUpdate();
|
||||
}),
|
||||
);
|
||||
|
||||
new Setting(detailsEl)
|
||||
.setName(t("MAINWORKSPACE_PANE_NAME"))
|
||||
@@ -1603,6 +1632,20 @@ export class ExcalidrawSettingTab extends PluginSettingTab {
|
||||
}),
|
||||
);
|
||||
|
||||
new Setting(detailsEl)
|
||||
.setName(t("EMBED_HEIGHT_NAME"))
|
||||
.setDesc(fragWithHTML(t("EMBED_HEIGHT_DESC")))
|
||||
.addText((text) =>
|
||||
text
|
||||
.setPlaceholder("e.g.: 400")
|
||||
.setValue(this.plugin.settings.height)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.height = value;
|
||||
this.applySettingsUpdate();
|
||||
this.requestEmbedUpdate = true;
|
||||
}),
|
||||
);
|
||||
|
||||
let scaleText: HTMLDivElement;
|
||||
|
||||
new Setting(detailsEl)
|
||||
|
||||
@@ -98,7 +98,6 @@ 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.darkerBy(40):text.lighterBy(40)), //frame
|
||||
[`--sidebar-border-color`]: str(gray1()),
|
||||
[`--color-primary-light`]: str(accent().lighterBy(step)),
|
||||
[`--button-hover-bg`]: str(gray1()),
|
||||
@@ -113,6 +112,7 @@ export const setDynamicStyle = (
|
||||
[`--h4-color`]: str(text),
|
||||
[`color`]: str(text),
|
||||
[`--select-highlight-color`]: str(gray1()),
|
||||
[`--color-gray-80`]: str(isDark?text.darkerBy(40):text.lighterBy(40)), //frame
|
||||
};
|
||||
|
||||
const styleString = Object.keys(styleObject)
|
||||
|
||||
@@ -101,7 +101,7 @@ export const openExternalLink = (link:string, app: App, element?: ExcalidrawElem
|
||||
return false;
|
||||
}
|
||||
|
||||
export const getExcalidrawFileForwardLinks = (app: App, excalidrawFile: TFile):string => {
|
||||
export const getExcalidrawFileForwardLinks = (app: App, excalidrawFile: TFile, secondOrderLinksSet: Set<string>):string => {
|
||||
let secondOrderLinks = "";
|
||||
const forwardLinks = app.metadataCache.getLinks()[excalidrawFile.path];
|
||||
if(forwardLinks && forwardLinks.length > 0) {
|
||||
@@ -110,6 +110,8 @@ export const getExcalidrawFileForwardLinks = (app: App, excalidrawFile: TFile):s
|
||||
const linkparts = getLinkParts(link.link);
|
||||
const f = app.metadataCache.getFirstLinkpathDest(linkparts.path, excalidrawFile.path);
|
||||
if(f && f.path !== excalidrawFile.path) {
|
||||
if(secondOrderLinksSet.has(f.path)) return;
|
||||
secondOrderLinksSet.add(f.path);
|
||||
linkset.add(`[[${f.path}${linkparts.ref?"#"+linkparts.ref:""}|Second Order Link: ${f.basename}]]`);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import {
|
||||
App,
|
||||
normalizePath, parseFrontMatterEntry, TFile, View, Workspace, WorkspaceLeaf, WorkspaceSplit
|
||||
normalizePath, OpenViewState, parseFrontMatterEntry, TFile, View, Workspace, WorkspaceLeaf, WorkspaceSplit
|
||||
} from "obsidian";
|
||||
import ExcalidrawPlugin from "../main";
|
||||
import { checkAndCreateFolder, splitFolderAndFilename } from "./FileUtils";
|
||||
@@ -257,4 +257,35 @@ export const getFileCSSClasses = (
|
||||
}
|
||||
|
||||
//@ts-ignore
|
||||
export const getActivePDFPageNumberFromPDFView = (view: View): number => view?.viewer?.child?.pdfViewer?.page;
|
||||
export const getActivePDFPageNumberFromPDFView = (view: View): number => view?.viewer?.child?.pdfViewer?.page;
|
||||
|
||||
export const openLeaf = ({
|
||||
plugin,
|
||||
fnGetLeaf,
|
||||
file,
|
||||
openState
|
||||
}:{
|
||||
plugin: ExcalidrawPlugin,
|
||||
fnGetLeaf: ()=>WorkspaceLeaf,
|
||||
file: TFile,
|
||||
openState?: OpenViewState
|
||||
}) : {
|
||||
leaf: WorkspaceLeaf
|
||||
promise: Promise<void>
|
||||
} => {
|
||||
let leaf:WorkspaceLeaf = null;
|
||||
if (plugin.settings.focusOnFileTab) {
|
||||
plugin.app.workspace.iterateAllLeaves((l) => {
|
||||
if(leaf) return;
|
||||
//@ts-ignore
|
||||
if (l?.view?.file === file) {
|
||||
plugin.app.workspace.setActiveLeaf(l,{focus: true});
|
||||
leaf = l;
|
||||
}
|
||||
});
|
||||
if(leaf) return {leaf, promise: Promise.resolve()};
|
||||
}
|
||||
leaf = fnGetLeaf();
|
||||
const promise = leaf.openFile(file, openState);
|
||||
return {leaf, promise};
|
||||
}
|
||||
@@ -635,7 +635,7 @@ export const getExportPadding = (
|
||||
}
|
||||
}
|
||||
|
||||
//depricated. Retained for backward compatibility
|
||||
//deprecated. Retained for backward compatibility
|
||||
if (fileCache.frontmatter[FRONTMATTER_KEYS["export-svgpadding"].name] != null) {
|
||||
const val = parseInt(
|
||||
fileCache.frontmatter[FRONTMATTER_KEYS["export-svgpadding"].name],
|
||||
|
||||
@@ -485,6 +485,8 @@ hr.excalidraw-setting-hr {
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
//https://github.com/zsviczian/obsidian-excalidraw-plugin/issues/1456
|
||||
.canvas-node:not(.is-editing):has(.excalidraw-canvas-immersive) {
|
||||
::-webkit-scrollbar,
|
||||
::-webkit-scrollbar-horizontal {
|
||||
@@ -497,6 +499,7 @@ hr.excalidraw-setting-hr {
|
||||
border: unset;
|
||||
box-shadow: unset;
|
||||
}
|
||||
*/
|
||||
|
||||
.excalidraw .canvas-node .ex-md-font-hand-drawn {
|
||||
--font-text: "Virgil";
|
||||
|
||||
Reference in New Issue
Block a user