Compare commits

..

15 Commits

Author SHA1 Message Date
zsviczian bd9721f308 2.11.0-beta-1, 0.18.0-12 : added screenshot feature
CodeQL / Analyze (javascript) (push) Has been cancelled
2025-04-27 16:50:22 +02:00
zsviczian 875bd4cb35 Merge pull request #2332 from dmscode/master
Update zh-cn.ts to 4a803f4
2025-04-27 16:29:49 +02:00
zsviczian ec575c307a updated type references matching Excalidraw component updates
CodeQL / Analyze (javascript) (push) Has been cancelled
2025-04-27 11:05:38 +02:00
dmscode 05087874e2 Update zh-cn.ts to 4a803f4 2025-04-26 17:45:11 +08:00
zsviczian 4a803f4b46 PDF export: HD Screen and Martch Image + disable double click text create
CodeQL / Analyze (javascript) (push) Has been cancelled
2025-04-26 08:13:06 +02:00
zsviczian a48222022e Merge pull request #2328 from dmscode/master
CodeQL / Analyze (javascript) (push) Has been cancelled
Update zh-cn.ts to 4840470
2025-04-20 12:19:49 +02:00
稻米鼠 eebbde1c40 Merge branch 'zsviczian:master' into master 2025-04-20 18:12:27 +08:00
dmscode c0a7686338 Update zh-cn.ts to 4840470 2025-04-20 18:11:07 +08:00
zsviczian 4840470b60 Fix dimensions undefined 2025-04-20 11:40:24 +02:00
zsviczian 091d9b9669 updated authorURL 2025-04-20 10:09:32 +02:00
zsviczian d5b86289b6 Merge branch 'master' of https://github.com/zsviczian/obsidian-excalidraw-plugin 2025-04-20 10:02:54 +02:00
zsviczian dceb6ce690 2.10.2-beta-1 0.18.0-8 2025-04-20 10:02:42 +02:00
zsviczian c29c25d252 Merge pull request #2323 from dmscode/master
CodeQL / Analyze (javascript) (push) Has been cancelled
Update zh-cn.ts to 6e57d4e
2025-04-18 15:39:03 +02:00
dmscode a2fb36671d Update zh-cn.ts to 6e57d4e 2025-04-17 06:56:13 +08:00
zsviczian 6e57d4e69a 2.10.1 0.18.0-7
CodeQL / Analyze (javascript) (push) Has been cancelled
2025-04-16 20:33:48 +02:00
47 changed files with 853 additions and 467 deletions
+2 -2
View File
@@ -1,5 +1,5 @@
import ExcalidrawPlugin from "src/core/main";
import { FillStyle, StrokeStyle, ExcalidrawElement, ExcalidrawBindableElement, FileId, NonDeletedExcalidrawElement, ExcalidrawImageElement, StrokeRoundness, RoundnessType } from "@zsviczian/excalidraw/types/excalidraw/element/types";
import { FillStyle, StrokeStyle, ExcalidrawElement, ExcalidrawBindableElement, FileId, NonDeletedExcalidrawElement, ExcalidrawImageElement, StrokeRoundness, RoundnessType } from "@zsviczian/excalidraw/types/element/src/types";
import { ColorMap, MimeType } from "./EmbeddedFileLoader";
import { Editor, OpenViewState, RequestUrlResponse, TFile, TFolder, WorkspaceLeaf } from "obsidian";
import * as obsidian_module from "obsidian";
@@ -11,7 +11,7 @@ import { ColorMaster } from "@zsviczian/colormaster";
import { TInput } from "@zsviczian/colormaster/types";
import { ClipboardData } from "@zsviczian/excalidraw/types/excalidraw/clipboard";
import { PaneTarget } from "src/utils/modifierkeyHelper";
import { Mutable } from "@zsviczian/excalidraw/types/excalidraw/utility-types";
import { Mutable } from "@zsviczian/excalidraw/types/common/src/utility-types";
import { EmbeddableMDCustomProps } from "./Dialogs/EmbeddableSettings";
import { AIRequest } from "../utils/AIUtils";
import { AddImageOptions, ImageInfo, SVGColorInfo } from "src/types/excalidrawAutomateTypes";
+2 -2
View File
@@ -1,5 +1,5 @@
import ExcalidrawPlugin from "src/core/main";
import { FillStyle, StrokeStyle, ExcalidrawElement, ExcalidrawBindableElement, FileId, NonDeletedExcalidrawElement, ExcalidrawImageElement, StrokeRoundness, RoundnessType } from "@zsviczian/excalidraw/types/excalidraw/element/types";
import { FillStyle, StrokeStyle, ExcalidrawElement, ExcalidrawBindableElement, FileId, NonDeletedExcalidrawElement, ExcalidrawImageElement, StrokeRoundness, RoundnessType } from "@zsviczian/excalidraw/types/element/src/types";
import { ColorMap, MimeType } from "./EmbeddedFileLoader";
import { Editor, OpenViewState, RequestUrlResponse, TFile, TFolder, WorkspaceLeaf } from "obsidian";
import * as obsidian_module from "obsidian";
@@ -11,7 +11,7 @@ import { ColorMaster } from "@zsviczian/colormaster";
import { TInput } from "@zsviczian/colormaster/types";
import { ClipboardData } from "@zsviczian/excalidraw/types/excalidraw/clipboard";
import { PaneTarget } from "src/utils/modifierkeyHelper";
import { Mutable } from "@zsviczian/excalidraw/types/excalidraw/utility-types";
import { Mutable } from "@zsviczian/excalidraw/types/common/src/utility-types";
import { EmbeddableMDCustomProps } from "./Dialogs/EmbeddableSettings";
import { AIRequest } from "../utils/AIUtils";
import { AddImageOptions, ImageInfo, SVGColorInfo } from "src/types/excalidrawAutomateTypes";
+2 -2
View File
@@ -1,10 +1,10 @@
{
"id": "obsidian-excalidraw-plugin",
"name": "Excalidraw",
"version": "2.10.0",
"version": "2.11.0-beta-1",
"minAppVersion": "1.1.6",
"description": "An Obsidian plugin to edit and view Excalidraw drawings",
"author": "Zsolt Viczian",
"authorUrl": "https://zsolt.blog",
"authorUrl": "https://excalidraw-obsidian.online",
"isDesktopOnly": false
}
+2 -2
View File
@@ -1,11 +1,11 @@
{
"id": "obsidian-excalidraw-plugin",
"name": "Excalidraw",
"version": "2.10.0",
"version": "2.10.1",
"minAppVersion": "1.1.6",
"description": "An Obsidian plugin to edit and view Excalidraw drawings",
"author": "Zsolt Viczian",
"authorUrl": "https://www.zsolt.blog",
"authorUrl": "https://excalidraw-obsidian.online",
"fundingUrl": "https://ko-fi.com/zsolt",
"helpUrl": "https://github.com/zsviczian/obsidian-excalidraw-plugin#readme",
"isDesktopOnly": false
+126 -312
View File
@@ -11,11 +11,12 @@
"dependencies": {
"@popperjs/core": "^2.11.8",
"@zsviczian/colormaster": "^1.2.2",
"@zsviczian/excalidraw": "0.18.0-2",
"@zsviczian/excalidraw": "0.18.0-9",
"chroma-js": "^2.4.2",
"clsx": "^2.0.0",
"es6-promise-pool": "2.5.0",
"gl-matrix": "^3.4.3",
"html2canvas": "^1.4.1",
"js-yaml": "^4.1.0",
"lucide-react": "^0.479.0",
"mathjax-full": "^3.2.2",
@@ -1543,6 +1544,7 @@
"version": "7.26.9",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.26.9.tgz",
"integrity": "sha512-aA63XwOkcl4xxQa3HjPMqOP6LiK0ZDv3mUPYEFXkpHbaFjtGggE1A61FjFzJnB+p7/oy2gA8E+rcBNl/zC1tMg==",
"dev": true,
"dependencies": {
"regenerator-runtime": "^0.14.0"
},
@@ -2128,66 +2130,28 @@
}
},
"node_modules/@radix-ui/react-collection": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.0.1.tgz",
"integrity": "sha512-uuiFbs+YCKjn3X1DTSx9G7BHApu4GHbi3kgiwsnFUbOKCrwejAJv4eE4Vc8C0Oaxt9T0aV4ox0WCOdx+39Xo+g==",
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.1.2.tgz",
"integrity": "sha512-9z54IEKRxIa9VityapoEYMuByaG42iSy1ZXlY2KcuLSEtq8x4987/N6m15ppoMffgZX72gER2uHe1D9Y6Unlcw==",
"dependencies": {
"@babel/runtime": "^7.13.10",
"@radix-ui/react-compose-refs": "1.0.0",
"@radix-ui/react-context": "1.0.0",
"@radix-ui/react-primitive": "1.0.1",
"@radix-ui/react-slot": "1.0.1"
"@radix-ui/react-compose-refs": "1.1.1",
"@radix-ui/react-context": "1.1.1",
"@radix-ui/react-primitive": "2.0.2",
"@radix-ui/react-slot": "1.1.2"
},
"peerDependencies": {
"react": "^16.8 || ^17.0 || ^18.0",
"react-dom": "^16.8 || ^17.0 || ^18.0"
}
},
"node_modules/@radix-ui/react-collection/node_modules/@radix-ui/react-compose-refs": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.0.0.tgz",
"integrity": "sha512-0KaSv6sx787/hK3eF53iOkiSLwAGlFMx5lotrqD2pTjB18KbybKoEIgkNZTKC60YECDQTKGTRcDBILwZVqVKvA==",
"dependencies": {
"@babel/runtime": "^7.13.10"
"@types/react": "*",
"@types/react-dom": "*",
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
},
"peerDependencies": {
"react": "^16.8 || ^17.0 || ^18.0"
}
},
"node_modules/@radix-ui/react-collection/node_modules/@radix-ui/react-context": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.0.0.tgz",
"integrity": "sha512-1pVM9RfOQ+n/N5PJK33kRSKsr1glNxomxONs5c49MliinBY6Yw2Q995qfBUUo0/Mbg05B/sGA0gkgPI7kmSHBg==",
"dependencies": {
"@babel/runtime": "^7.13.10"
},
"peerDependencies": {
"react": "^16.8 || ^17.0 || ^18.0"
}
},
"node_modules/@radix-ui/react-collection/node_modules/@radix-ui/react-primitive": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-1.0.1.tgz",
"integrity": "sha512-fHbmislWVkZaIdeF6GZxF0A/NH/3BjrGIYj+Ae6eTmTCr7EB0RQAAVEiqsXK6p3/JcRqVSBQoceZroj30Jj3XA==",
"dependencies": {
"@babel/runtime": "^7.13.10",
"@radix-ui/react-slot": "1.0.1"
},
"peerDependencies": {
"react": "^16.8 || ^17.0 || ^18.0",
"react-dom": "^16.8 || ^17.0 || ^18.0"
}
},
"node_modules/@radix-ui/react-collection/node_modules/@radix-ui/react-slot": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.0.1.tgz",
"integrity": "sha512-avutXAFL1ehGvAXtPquu0YK5oz6ctS474iM3vNGQIkswrVhdrS52e3uoMQBzZhNRAIE0jBnUyXWNmSjGHhCFcw==",
"dependencies": {
"@babel/runtime": "^7.13.10",
"@radix-ui/react-compose-refs": "1.0.0"
},
"peerDependencies": {
"react": "^16.8 || ^17.0 || ^18.0"
"peerDependenciesMeta": {
"@types/react": {
"optional": true
},
"@types/react-dom": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-compose-refs": {
@@ -2219,14 +2183,17 @@
}
},
"node_modules/@radix-ui/react-direction": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@radix-ui/react-direction/-/react-direction-1.0.0.tgz",
"integrity": "sha512-2HV05lGUgYcA6xgLQ4BKPDmtL+QbIZYH5fCOTAOOcJ5O0QbWS3i9lKaurLzliYUDhORI2Qr3pyjhJh44lKA3rQ==",
"dependencies": {
"@babel/runtime": "^7.13.10"
},
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@radix-ui/react-direction/-/react-direction-1.1.0.tgz",
"integrity": "sha512-BUuBvgThEiAXh2DWu93XsT+a3aWrGqolGlqqw5VU1kG7p/ZH2cuDlM1sRLNnY3QcBS69UIz2mcKhMxDsdewhjg==",
"peerDependencies": {
"react": "^16.8 || ^17.0 || ^18.0"
"@types/react": "*",
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-dismissable-layer": {
@@ -2446,125 +2413,33 @@
}
},
"node_modules/@radix-ui/react-roving-focus": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-1.0.2.tgz",
"integrity": "sha512-HLK+CqD/8pN6GfJm3U+cqpqhSKYAWiOJDe+A+8MfxBnOue39QEeMa43csUn2CXCHQT0/mewh1LrrG4tfkM9DMA==",
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-1.1.2.tgz",
"integrity": "sha512-zgMQWkNO169GtGqRvYrzb0Zf8NhMHS2DuEB/TiEmVnpr5OqPU3i8lfbxaAmC2J/KYuIQxyoQQ6DxepyXp61/xw==",
"dependencies": {
"@babel/runtime": "^7.13.10",
"@radix-ui/primitive": "1.0.0",
"@radix-ui/react-collection": "1.0.1",
"@radix-ui/react-compose-refs": "1.0.0",
"@radix-ui/react-context": "1.0.0",
"@radix-ui/react-direction": "1.0.0",
"@radix-ui/react-id": "1.0.0",
"@radix-ui/react-primitive": "1.0.1",
"@radix-ui/react-use-callback-ref": "1.0.0",
"@radix-ui/react-use-controllable-state": "1.0.0"
"@radix-ui/primitive": "1.1.1",
"@radix-ui/react-collection": "1.1.2",
"@radix-ui/react-compose-refs": "1.1.1",
"@radix-ui/react-context": "1.1.1",
"@radix-ui/react-direction": "1.1.0",
"@radix-ui/react-id": "1.1.0",
"@radix-ui/react-primitive": "2.0.2",
"@radix-ui/react-use-callback-ref": "1.1.0",
"@radix-ui/react-use-controllable-state": "1.1.0"
},
"peerDependencies": {
"react": "^16.8 || ^17.0 || ^18.0",
"react-dom": "^16.8 || ^17.0 || ^18.0"
}
},
"node_modules/@radix-ui/react-roving-focus/node_modules/@radix-ui/primitive": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.0.0.tgz",
"integrity": "sha512-3e7rn8FDMin4CgeL7Z/49smCA3rFYY3Ha2rUQ7HRWFadS5iCRw08ZgVT1LaNTCNqgvrUiyczLflrVrF0SRQtNA==",
"dependencies": {
"@babel/runtime": "^7.13.10"
}
},
"node_modules/@radix-ui/react-roving-focus/node_modules/@radix-ui/react-compose-refs": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.0.0.tgz",
"integrity": "sha512-0KaSv6sx787/hK3eF53iOkiSLwAGlFMx5lotrqD2pTjB18KbybKoEIgkNZTKC60YECDQTKGTRcDBILwZVqVKvA==",
"dependencies": {
"@babel/runtime": "^7.13.10"
"@types/react": "*",
"@types/react-dom": "*",
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
},
"peerDependencies": {
"react": "^16.8 || ^17.0 || ^18.0"
}
},
"node_modules/@radix-ui/react-roving-focus/node_modules/@radix-ui/react-context": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.0.0.tgz",
"integrity": "sha512-1pVM9RfOQ+n/N5PJK33kRSKsr1glNxomxONs5c49MliinBY6Yw2Q995qfBUUo0/Mbg05B/sGA0gkgPI7kmSHBg==",
"dependencies": {
"@babel/runtime": "^7.13.10"
},
"peerDependencies": {
"react": "^16.8 || ^17.0 || ^18.0"
}
},
"node_modules/@radix-ui/react-roving-focus/node_modules/@radix-ui/react-id": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.0.0.tgz",
"integrity": "sha512-Q6iAB/U7Tq3NTolBBQbHTgclPmGWE3OlktGGqrClPozSw4vkQ1DfQAOtzgRPecKsMdJINE05iaoDUG8tRzCBjw==",
"dependencies": {
"@babel/runtime": "^7.13.10",
"@radix-ui/react-use-layout-effect": "1.0.0"
},
"peerDependencies": {
"react": "^16.8 || ^17.0 || ^18.0"
}
},
"node_modules/@radix-ui/react-roving-focus/node_modules/@radix-ui/react-primitive": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-1.0.1.tgz",
"integrity": "sha512-fHbmislWVkZaIdeF6GZxF0A/NH/3BjrGIYj+Ae6eTmTCr7EB0RQAAVEiqsXK6p3/JcRqVSBQoceZroj30Jj3XA==",
"dependencies": {
"@babel/runtime": "^7.13.10",
"@radix-ui/react-slot": "1.0.1"
},
"peerDependencies": {
"react": "^16.8 || ^17.0 || ^18.0",
"react-dom": "^16.8 || ^17.0 || ^18.0"
}
},
"node_modules/@radix-ui/react-roving-focus/node_modules/@radix-ui/react-slot": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.0.1.tgz",
"integrity": "sha512-avutXAFL1ehGvAXtPquu0YK5oz6ctS474iM3vNGQIkswrVhdrS52e3uoMQBzZhNRAIE0jBnUyXWNmSjGHhCFcw==",
"dependencies": {
"@babel/runtime": "^7.13.10",
"@radix-ui/react-compose-refs": "1.0.0"
},
"peerDependencies": {
"react": "^16.8 || ^17.0 || ^18.0"
}
},
"node_modules/@radix-ui/react-roving-focus/node_modules/@radix-ui/react-use-callback-ref": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.0.0.tgz",
"integrity": "sha512-GZtyzoHz95Rhs6S63D2t/eqvdFCm7I+yHMLVQheKM7nBD8mbZIt+ct1jz4536MDnaOGKIxynJ8eHTkVGVVkoTg==",
"dependencies": {
"@babel/runtime": "^7.13.10"
},
"peerDependencies": {
"react": "^16.8 || ^17.0 || ^18.0"
}
},
"node_modules/@radix-ui/react-roving-focus/node_modules/@radix-ui/react-use-controllable-state": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.0.0.tgz",
"integrity": "sha512-FohDoZvk3mEXh9AWAVyRTYR4Sq7/gavuofglmiXB2g1aKyboUD4YtgWxKj8O5n+Uak52gXQ4wKz5IFST4vtJHg==",
"dependencies": {
"@babel/runtime": "^7.13.10",
"@radix-ui/react-use-callback-ref": "1.0.0"
},
"peerDependencies": {
"react": "^16.8 || ^17.0 || ^18.0"
}
},
"node_modules/@radix-ui/react-roving-focus/node_modules/@radix-ui/react-use-layout-effect": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.0.0.tgz",
"integrity": "sha512-6Tpkq+R6LOlmQb1R5NNETLG0B4YP0wc+klfXafpUCj6JGyaUc8il7/kUZ7m59rGbXGczE9Bs+iz2qloqsZBduQ==",
"dependencies": {
"@babel/runtime": "^7.13.10"
},
"peerDependencies": {
"react": "^16.8 || ^17.0 || ^18.0"
"peerDependenciesMeta": {
"@types/react": {
"optional": true
},
"@types/react-dom": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-slot": {
@@ -2585,138 +2460,32 @@
}
},
"node_modules/@radix-ui/react-tabs": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/@radix-ui/react-tabs/-/react-tabs-1.0.2.tgz",
"integrity": "sha512-gOUwh+HbjCuL0UCo8kZ+kdUEG8QtpdO4sMQduJ34ZEz0r4922g9REOBM+vIsfwtGxSug4Yb1msJMJYN2Bk8TpQ==",
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/@radix-ui/react-tabs/-/react-tabs-1.1.3.tgz",
"integrity": "sha512-9mFyI30cuRDImbmFF6O2KUJdgEOsGh9Vmx9x/Dh9tOhL7BngmQPQfwW4aejKm5OHpfWIdmeV6ySyuxoOGjtNng==",
"dependencies": {
"@babel/runtime": "^7.13.10",
"@radix-ui/primitive": "1.0.0",
"@radix-ui/react-context": "1.0.0",
"@radix-ui/react-direction": "1.0.0",
"@radix-ui/react-id": "1.0.0",
"@radix-ui/react-presence": "1.0.0",
"@radix-ui/react-primitive": "1.0.1",
"@radix-ui/react-roving-focus": "1.0.2",
"@radix-ui/react-use-controllable-state": "1.0.0"
"@radix-ui/primitive": "1.1.1",
"@radix-ui/react-context": "1.1.1",
"@radix-ui/react-direction": "1.1.0",
"@radix-ui/react-id": "1.1.0",
"@radix-ui/react-presence": "1.1.2",
"@radix-ui/react-primitive": "2.0.2",
"@radix-ui/react-roving-focus": "1.1.2",
"@radix-ui/react-use-controllable-state": "1.1.0"
},
"peerDependencies": {
"react": "^16.8 || ^17.0 || ^18.0",
"react-dom": "^16.8 || ^17.0 || ^18.0"
}
},
"node_modules/@radix-ui/react-tabs/node_modules/@radix-ui/primitive": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.0.0.tgz",
"integrity": "sha512-3e7rn8FDMin4CgeL7Z/49smCA3rFYY3Ha2rUQ7HRWFadS5iCRw08ZgVT1LaNTCNqgvrUiyczLflrVrF0SRQtNA==",
"dependencies": {
"@babel/runtime": "^7.13.10"
}
},
"node_modules/@radix-ui/react-tabs/node_modules/@radix-ui/react-compose-refs": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.0.0.tgz",
"integrity": "sha512-0KaSv6sx787/hK3eF53iOkiSLwAGlFMx5lotrqD2pTjB18KbybKoEIgkNZTKC60YECDQTKGTRcDBILwZVqVKvA==",
"dependencies": {
"@babel/runtime": "^7.13.10"
"@types/react": "*",
"@types/react-dom": "*",
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
},
"peerDependencies": {
"react": "^16.8 || ^17.0 || ^18.0"
}
},
"node_modules/@radix-ui/react-tabs/node_modules/@radix-ui/react-context": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.0.0.tgz",
"integrity": "sha512-1pVM9RfOQ+n/N5PJK33kRSKsr1glNxomxONs5c49MliinBY6Yw2Q995qfBUUo0/Mbg05B/sGA0gkgPI7kmSHBg==",
"dependencies": {
"@babel/runtime": "^7.13.10"
},
"peerDependencies": {
"react": "^16.8 || ^17.0 || ^18.0"
}
},
"node_modules/@radix-ui/react-tabs/node_modules/@radix-ui/react-id": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.0.0.tgz",
"integrity": "sha512-Q6iAB/U7Tq3NTolBBQbHTgclPmGWE3OlktGGqrClPozSw4vkQ1DfQAOtzgRPecKsMdJINE05iaoDUG8tRzCBjw==",
"dependencies": {
"@babel/runtime": "^7.13.10",
"@radix-ui/react-use-layout-effect": "1.0.0"
},
"peerDependencies": {
"react": "^16.8 || ^17.0 || ^18.0"
}
},
"node_modules/@radix-ui/react-tabs/node_modules/@radix-ui/react-presence": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.0.0.tgz",
"integrity": "sha512-A+6XEvN01NfVWiKu38ybawfHsBjWum42MRPnEuqPsBZ4eV7e/7K321B5VgYMPv3Xx5An6o1/l9ZuDBgmcmWK3w==",
"dependencies": {
"@babel/runtime": "^7.13.10",
"@radix-ui/react-compose-refs": "1.0.0",
"@radix-ui/react-use-layout-effect": "1.0.0"
},
"peerDependencies": {
"react": "^16.8 || ^17.0 || ^18.0",
"react-dom": "^16.8 || ^17.0 || ^18.0"
}
},
"node_modules/@radix-ui/react-tabs/node_modules/@radix-ui/react-primitive": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-1.0.1.tgz",
"integrity": "sha512-fHbmislWVkZaIdeF6GZxF0A/NH/3BjrGIYj+Ae6eTmTCr7EB0RQAAVEiqsXK6p3/JcRqVSBQoceZroj30Jj3XA==",
"dependencies": {
"@babel/runtime": "^7.13.10",
"@radix-ui/react-slot": "1.0.1"
},
"peerDependencies": {
"react": "^16.8 || ^17.0 || ^18.0",
"react-dom": "^16.8 || ^17.0 || ^18.0"
}
},
"node_modules/@radix-ui/react-tabs/node_modules/@radix-ui/react-slot": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.0.1.tgz",
"integrity": "sha512-avutXAFL1ehGvAXtPquu0YK5oz6ctS474iM3vNGQIkswrVhdrS52e3uoMQBzZhNRAIE0jBnUyXWNmSjGHhCFcw==",
"dependencies": {
"@babel/runtime": "^7.13.10",
"@radix-ui/react-compose-refs": "1.0.0"
},
"peerDependencies": {
"react": "^16.8 || ^17.0 || ^18.0"
}
},
"node_modules/@radix-ui/react-tabs/node_modules/@radix-ui/react-use-callback-ref": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.0.0.tgz",
"integrity": "sha512-GZtyzoHz95Rhs6S63D2t/eqvdFCm7I+yHMLVQheKM7nBD8mbZIt+ct1jz4536MDnaOGKIxynJ8eHTkVGVVkoTg==",
"dependencies": {
"@babel/runtime": "^7.13.10"
},
"peerDependencies": {
"react": "^16.8 || ^17.0 || ^18.0"
}
},
"node_modules/@radix-ui/react-tabs/node_modules/@radix-ui/react-use-controllable-state": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.0.0.tgz",
"integrity": "sha512-FohDoZvk3mEXh9AWAVyRTYR4Sq7/gavuofglmiXB2g1aKyboUD4YtgWxKj8O5n+Uak52gXQ4wKz5IFST4vtJHg==",
"dependencies": {
"@babel/runtime": "^7.13.10",
"@radix-ui/react-use-callback-ref": "1.0.0"
},
"peerDependencies": {
"react": "^16.8 || ^17.0 || ^18.0"
}
},
"node_modules/@radix-ui/react-tabs/node_modules/@radix-ui/react-use-layout-effect": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.0.0.tgz",
"integrity": "sha512-6Tpkq+R6LOlmQb1R5NNETLG0B4YP0wc+klfXafpUCj6JGyaUc8il7/kUZ7m59rGbXGczE9Bs+iz2qloqsZBduQ==",
"dependencies": {
"@babel/runtime": "^7.13.10"
},
"peerDependencies": {
"react": "^16.8 || ^17.0 || ^18.0"
"peerDependenciesMeta": {
"@types/react": {
"optional": true
},
"@types/react-dom": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-use-callback-ref": {
@@ -3430,14 +3199,14 @@
"license": "MIT"
},
"node_modules/@zsviczian/excalidraw": {
"version": "0.18.0-2",
"resolved": "https://registry.npmjs.org/@zsviczian/excalidraw/-/excalidraw-0.18.0-2.tgz",
"integrity": "sha512-Ge1Dnng9/4iEalNr3DvDfmzoYcccKtKFJREvfx9J2Nqzf6eX2xNOusMYmSYzkC5WWhYaTDGdGP6aUPWsRkc8HA==",
"version": "0.18.0-9",
"resolved": "https://registry.npmjs.org/@zsviczian/excalidraw/-/excalidraw-0.18.0-9.tgz",
"integrity": "sha512-Eao+ETW1TF5O7Lskh0rJfZRQcPoHgXbnKPVooZzhmWPp3K3N2opbGgJrgt6QsdmCB49LUo2QTllXDNpSJdB7iA==",
"dependencies": {
"@braintree/sanitize-url": "6.0.2",
"@excalidraw/random-username": "1.1.0",
"@radix-ui/react-popover": "1.1.6",
"@radix-ui/react-tabs": "1.0.2",
"@radix-ui/react-tabs": "1.1.3",
"@zsviczian/laser-pointer": "1.3.1",
"@zsviczian/mermaid-to-excalidraw": "1.1.2",
"browser-fs-access": "0.29.1",
@@ -3707,6 +3476,14 @@
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
"dev": true
},
"node_modules/base64-arraybuffer": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz",
"integrity": "sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ==",
"engines": {
"node": ">= 0.6.0"
}
},
"node_modules/binary-extensions": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz",
@@ -4034,6 +3811,14 @@
"postcss": "^8.0.9"
}
},
"node_modules/css-line-break": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/css-line-break/-/css-line-break-2.1.0.tgz",
"integrity": "sha512-FHcKFCZcAha3LwfVBhCQbW2nCNbkZXn7KVUJcsT5/P8YmfsVja0FMPJr0B903j/E69HUphKiV9iQArX8SDYA4w==",
"dependencies": {
"utrie": "^1.0.2"
}
},
"node_modules/css-select": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz",
@@ -5558,6 +5343,18 @@
"node": ">= 0.4"
}
},
"node_modules/html2canvas": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/html2canvas/-/html2canvas-1.4.1.tgz",
"integrity": "sha512-fPU6BHNpsyIhr8yyMpTLLxAbkaK8ArIBcmZIRiBLiDhjeqvXolaEmDGmELFuX9I4xDcaKKcJl+TKZLqruBbmWA==",
"dependencies": {
"css-line-break": "^2.1.0",
"text-segmentation": "^1.0.3"
},
"engines": {
"node": ">=8.0.0"
}
},
"node_modules/iconv-lite": {
"version": "0.6.3",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
@@ -7784,7 +7581,8 @@
"node_modules/regenerator-runtime": {
"version": "0.14.1",
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz",
"integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw=="
"integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==",
"dev": true
},
"node_modules/regenerator-transform": {
"version": "0.15.2",
@@ -8602,6 +8400,14 @@
"integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
"dev": true
},
"node_modules/text-segmentation": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/text-segmentation/-/text-segmentation-1.0.3.tgz",
"integrity": "sha512-iOiPUo/BGnZ6+54OsWxZidGCsdU8YbE4PSpdPinp7DeMtUJNJBoJ/ouUSTJjHkh1KntHaltHl/gDs2FC4i5+Nw==",
"dependencies": {
"utrie": "^1.0.2"
}
},
"node_modules/text-table": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
@@ -8930,6 +8736,14 @@
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
"dev": true
},
"node_modules/utrie": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/utrie/-/utrie-1.0.2.tgz",
"integrity": "sha512-1MLa5ouZiOmQzUbjbu9VmjLzn1QLXBhwpUa7kdLUQK+KQ5KA9I1vk5U4YHe/X2Ch7PYnJfWuWT+VbuxbGwljhw==",
"dependencies": {
"base64-arraybuffer": "^1.0.2"
}
},
"node_modules/uuid": {
"version": "9.0.1",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz",
+1 -1
View File
@@ -23,7 +23,7 @@
"license": "MIT",
"dependencies": {
"@popperjs/core": "^2.11.8",
"@zsviczian/excalidraw": "0.18.0-6",
"@zsviczian/excalidraw": "0.18.0-12",
"chroma-js": "^2.4.2",
"clsx": "^2.0.0",
"@zsviczian/colormaster": "^1.2.2",
+1 -1
View File
@@ -2,7 +2,7 @@ import "obsidian";
//import { ExcalidrawAutomate } from "./ExcalidrawAutomate";
//export ExcalidrawAutomate from "./ExcalidrawAutomate";
//export {ExcalidrawAutomate} from "./ExcaildrawAutomate";
export type { ExcalidrawBindableElement, ExcalidrawElement, FileId, FillStyle, StrokeRoundness, StrokeStyle } from "@zsviczian/excalidraw/types/excalidraw/element/types";
export type { ExcalidrawBindableElement, ExcalidrawElement, FileId, FillStyle, StrokeRoundness, StrokeStyle } from "@zsviczian/excalidraw/types/element/src/types";
export type { Point } from "src/types/types";
export const getEA = (view?:any): any => {
try {
+1 -1
View File
@@ -61,7 +61,7 @@ import {
getFontMetrics,
} from "../utils/utils";
import { foldExcalidrawSection, getExcalidrawViews, setExcalidrawView } from "../utils/obsidianUtils";
import { FileId } from "@zsviczian/excalidraw/types/excalidraw/element/types";
import { FileId } from "@zsviczian/excalidraw/types/element/src/types";
import { ScriptEngine } from "../shared/Scripts";
import { hoverEvent, initializeMarkdownPostProcessor, markdownPostProcessor, legacyExcalidrawPopoverObserver } from "./managers/MarkdownPostProcessor";
import { FieldSuggester } from "../shared/Suggesters/FieldSuggester";
+2 -2
View File
@@ -51,7 +51,7 @@ import {
getImageSize,
} from "../../utils/utils";
import { extractSVGPNGFileName, getActivePDFPageNumberFromPDFView, getAttachmentsFolderAndFilePath, isObsidianThemeDark, mergeMarkdownFiles, setExcalidrawView } from "../../utils/obsidianUtils";
import { ExcalidrawElement, ExcalidrawEmbeddableElement, ExcalidrawImageElement, ExcalidrawTextElement, FileId } from "@zsviczian/excalidraw/types/excalidraw/element/types";
import { ExcalidrawElement, ExcalidrawEmbeddableElement, ExcalidrawImageElement, ExcalidrawTextElement, FileId } from "@zsviczian/excalidraw/types/element/src/types";
import { ReleaseNotes } from "../../shared/Dialogs/ReleaseNotes";
import { ScriptInstallPrompt } from "../../shared/Dialogs/ScriptInstallPrompt";
import Taskbone from "../../shared/OCR/Taskbone";
@@ -64,7 +64,7 @@ import { EmbeddableSettings } from "../../shared/Dialogs/EmbeddableSettings";
import { processLinkText } from "../../utils/customEmbeddableUtils";
import { getEA } from "src/core";
import { ExcalidrawImperativeAPI } from "@zsviczian/excalidraw/types/excalidraw/types";
import { Mutable } from "@zsviczian/excalidraw/types/excalidraw/utility-types";
import { Mutable } from "@zsviczian/excalidraw/types/common/src/utility-types";
import { carveOutImage, carveOutPDF, createImageCropperFile } from "../../utils/carveout";
import { showFrameSettings } from "../../shared/Dialogs/FrameSettings";
import { insertImageToView } from "../../utils/excalidrawViewUtils";
+1 -1
View File
@@ -1,5 +1,5 @@
import { WorkspaceLeaf, TFile, Editor, MarkdownView, MarkdownFileInfo, MetadataCache, App, EventRef, Menu, FileView } from "obsidian";
import { ExcalidrawElement } from "@zsviczian/excalidraw/types/excalidraw/element/types";
import { ExcalidrawElement } from "@zsviczian/excalidraw/types/element/src/types";
import { getLink } from "../../utils/fileUtils";
import { editorInsertText, getExcalidrawViews, getParentOfClass, isUnwantedLeaf, setExcalidrawView } from "../../utils/obsidianUtils";
import ExcalidrawPlugin from "src/core/main";
+1 -1
View File
@@ -130,7 +130,7 @@ export class ObserverManager {
return;
}
if (this.plugin.isExcalidrawFile(f)) {
el.insertBefore(
el.insertAfter(
createDiv({
cls: "nav-file-tag",
text: this.settings.experimentalFileTag,
+85 -11
View File
@@ -43,8 +43,10 @@ import { HotkeyEditor } from "src/shared/Dialogs/HotkeyEditor";
import { getExcalidrawViews } from "src/utils/obsidianUtils";
import { createSliderWithText } from "src/utils/sliderUtils";
import { PDFExportSettingsComponent, PDFExportSettings } from "src/shared/Dialogs/PDFExportSettingsComponent";
import de from "src/lang/locale/de";
export interface ExcalidrawSettings {
disableDoubleClickTextEditing: boolean;
folder: string;
cropFolder: string;
annotateFolder: string;
@@ -199,6 +201,7 @@ export interface ExcalidrawSettings {
markdownNodeOneClickEditing: boolean;
canvasImmersiveEmbed: boolean,
startupScriptPath: string,
aiEnabled: boolean,
openAIAPIToken: string,
openAIDefaultTextModel: string,
openAIDefaultVisionModel: string,
@@ -226,6 +229,7 @@ export interface ExcalidrawSettings {
declare const PLUGIN_VERSION:string;
export const DEFAULT_SETTINGS: ExcalidrawSettings = {
disableDoubleClickTextEditing: false,
folder: "Excalidraw",
cropFolder: "",
annotateFolder: "",
@@ -380,6 +384,7 @@ export const DEFAULT_SETTINGS: ExcalidrawSettings = {
DYNAMIC_COLOR: true,
COLOR: "#000000",
OPACITY: 50,
GRID_DIRECTION: {horizontal: true, vertical: true},
},
laserSettings: {
DECAY_LENGTH: 50,
@@ -400,6 +405,7 @@ export const DEFAULT_SETTINGS: ExcalidrawSettings = {
markdownNodeOneClickEditing: false,
canvasImmersiveEmbed: true,
startupScriptPath: "",
aiEnabled: true,
openAIAPIToken: "",
openAIDefaultTextModel: "gpt-3.5-turbo-1106",
openAIDefaultVisionModel: "gpt-4o",
@@ -680,6 +686,17 @@ export class ExcalidrawSettingTab extends PluginSettingTab {
}),
);
new Setting(detailsEl)
.setName(t("TOGGLE_SPLASHSCREEN"))
.addToggle((toggle) =>
toggle
.setValue(this.plugin.settings.showSplashscreen)
.onChange((value)=> {
this.plugin.settings.showSplashscreen = value;
this.applySettingsUpdate();
})
)
new Setting(detailsEl)
.setName(t("FOLDER_NAME"))
.setDesc(fragWithHTML(t("FOLDER_DESC")))
@@ -992,6 +1009,27 @@ export class ExcalidrawSettingTab extends PluginSettingTab {
cls: "excalidraw-setting-h1",
});
let aiEl: HTMLElement;
new Setting(detailsEl)
.setName(t("AI_ENABLED_NAME"))
.setDesc(fragWithHTML(t("AI_ENABLED_DESC")))
.addToggle((toggle) =>
toggle
.setValue(this.plugin.settings.aiEnabled??true)
.onChange(async (value) => {
aiEl.style.display = value ? "block" : "none";
this.plugin.settings.aiEnabled = value;
this.applySettingsUpdate();
}),
);
detailsEl = detailsEl.createDiv();
aiEl = detailsEl;
if(!(this.plugin.settings.aiEnabled??true)) {
detailsEl.style.display = "none";
}
new Setting(detailsEl)
.setName(t("AI_OPENAI_TOKEN_NAME"))
.setDesc(fragWithHTML(t("AI_OPENAI_TOKEN_DESC")))
@@ -1069,6 +1107,17 @@ export class ExcalidrawSettingTab extends PluginSettingTab {
cls: "excalidraw-setting-h1",
});
new Setting(detailsEl)
.setName(t("ENABLE_DOUBLE_CLICK_TEXT_EDITING_NAME"))
.addToggle((toggle) =>
toggle
.setValue(!this.plugin.settings.disableDoubleClickTextEditing)
.onChange(async (value) => {
this.plugin.settings.disableDoubleClickTextEditing = !value;
this.applySettingsUpdate();
}),
);
const readingModeEl = new Setting(detailsEl)
.setName(t("SHOW_DRAWING_OR_MD_IN_READING_MODE_NAME"))
.setDesc(fragWithHTML(t("SHOW_DRAWING_OR_MD_IN_READING_MODE_DESC")))
@@ -1111,17 +1160,6 @@ export class ExcalidrawSettingTab extends PluginSettingTab {
);
addIframe(detailsEl, "H8Njp7ZXYag",999);
new Setting(detailsEl)
.setName(t("TOGGLE_SPLASHSCREEN"))
.addToggle((toggle) =>
toggle
.setValue(this.plugin.settings.showSplashscreen)
.onChange((value)=> {
this.plugin.settings.showSplashscreen = value;
this.applySettingsUpdate();
})
)
detailsEl = displayDetailsEl.createEl("details");
detailsEl.createEl("summary", {
text: t("HOTKEY_OVERRIDE_HEAD"),
@@ -1380,6 +1418,42 @@ export class ExcalidrawSettingTab extends PluginSettingTab {
getExcalidrawViews(this.app).forEach(excalidrawView=>excalidrawView.updateGridColor());
};
const updateGridDirection = () => {
getExcalidrawViews(this.app).forEach(excalidrawView=>
excalidrawView.updateGridDirection(this.plugin.settings.gridSettings.GRID_DIRECTION));
}
new Setting(detailsEl)
.setName(t("GRID_DIRECTION_NAME"))
.setDesc(t("GRID_DIRECTION_DESC"))
.addToggle((toggle) =>
toggle
.setTooltip(t("GRID_HORIZONTAL"))
.setValue(this.plugin.settings.gridSettings.GRID_DIRECTION?.horizontal ?? true)
.onChange((value) => {
if(!this.plugin.settings.gridSettings.GRID_DIRECTION) {
this.plugin.settings.gridSettings.GRID_DIRECTION = { horizontal: true, vertical: true };
} //2.10.1 migration
this.plugin.settings.gridSettings.GRID_DIRECTION.horizontal = value;
this.applySettingsUpdate();
updateGridDirection();
}),
)
.addToggle((toggle) =>
toggle
.setTooltip(t("GRID_VERTICAL"))
.setValue(this.plugin.settings.gridSettings.GRID_DIRECTION?.vertical ?? true)
.onChange((value) => {
if(!this.plugin.settings.gridSettings.GRID_DIRECTION) {
this.plugin.settings.gridSettings.GRID_DIRECTION = { horizontal: true, vertical: true };
} //2.10.1 migration
this.plugin.settings.gridSettings.GRID_DIRECTION.vertical = value;
this.applySettingsUpdate();
updateGridDirection();
}),
);
// Dynamic color toggle
let gridColorSection: HTMLDivElement;
new Setting(detailsEl)
+16
View File
@@ -247,6 +247,8 @@ export default {
`While the OpenAI API is in beta, its use is strictly limited — as such we require you use your own API key. ` +
`You can create an OpenAI account, add a small credit (5 USD minimum), and generate your own API key. ` +
`Once API key is set, you can use the AI tools in Excalidraw.`,
AI_ENABLED_NAME: "Enable AI features",
AI_ENABLED_DESC: "You need to reopen Excalidraw for the changes to take effect.",
AI_OPENAI_TOKEN_NAME: "OpenAI API key",
AI_OPENAI_TOKEN_DESC:
"You can get your OpenAI API key from your <a href='https://platform.openai.com/api-keys'>OpenAI account</a>.",
@@ -369,6 +371,7 @@ FILENAME_HEAD: "Filename",
DEFAULT_PEN_MODE_NAME: "Pen mode",
DEFAULT_PEN_MODE_DESC:
"Should pen mode be automatically enabled when opening Excalidraw?",
ENABLE_DOUBLE_CLICK_TEXT_EDITING_NAME: "Enable double-click text create",
DISABLE_DOUBLE_TAP_ERASER_NAME: "Enable double-tap eraser in pen mode",
DISABLE_SINGLE_FINGER_PANNING_NAME: "Enable single-finger panning in pen mode",
SHOW_PEN_MODE_FREEDRAW_CROSSHAIR_NAME: "Show (+) crosshair in pen mode",
@@ -427,6 +430,10 @@ FILENAME_HEAD: "Filename",
GRID_OPACITY_NAME: "Grid opacity",
GRID_OPACITY_DESC: "Grid opacity will also control the opacity of the binding box when binding an arrow to an element.<br>" +
"Set the opacity of the grid. 0 is transparent, 100 is opaque.",
GRID_DIRECTION_NAME: "Grid direction",
GRID_DIRECTION_DESC: "The first toggle shows/hides the horizontal grid, the second toggle shows/hides the vertical grid.",
GRID_HORIZONTAL: "Render horizontal grid",
GRID_VERTICAL: "Render vertical grid",
LASER_HEAD: "Laser pointer",
LASER_COLOR: "Laser pointer color",
LASER_DECAY_TIME_NAME: "Laser pointer decay time",
@@ -1093,6 +1100,15 @@ FILENAME_HEAD: "Filename",
EXPORTDIALOG_PDF_PROGRESS_DONE: "Export complete",
EXPORTDIALOG_PDF_PROGRESS_ERROR: "Error exporting PDF, check developer console for details",
// Screenshot tab
EXPORTDIALOG_TAB_SCREENSHOT: "Screenshot",
EXPORTDIALOG_SCREENSHOT_DESC: "Screenshots will include embeddables such as markdown pages, YouTube, websites, etc. They are only available on desktop, cannot be automatically exported, and only support PNG format.",
SCREENSHOT_DESKTOP_ONLY: "Screenshot feature is only available on desktop",
SCREENSHOT_FILE_SUCCESS: "Screenshot saved to vault",
SCREENSHOT_CLIPBOARD_SUCCESS: "Screenshot copied to clipboard",
SCREENSHOT_CLIPBOARD_ERROR: "Failed to copy screenshot to clipboard: ",
SCREENSHOT_ERROR: "Error capturing screenshot - see console log",
//exportUtils.ts
PDF_EXPORT_DESKTOP_ONLY: "PDF export is only available on desktop",
};
+7
View File
@@ -247,6 +247,8 @@ export default {
`目前 OpenAI API 还处于测试中,您需要在自己的。` +
`OpenAI 账户中充值至少 5 美元后才能生成 API key,` +
`然后就可以在 Excalidraw 中配置并使用 AI。`,
AI_ENABLED_NAME : "启用 AI 功能" ,
AI_ENABLED_DESC : "您需要重新打开 Excalidraw 才能使更改生效。" ,
AI_OPENAI_TOKEN_NAME: "OpenAI API key",
AI_OPENAI_TOKEN_DESC:
"您可以访问您的<a href='https://platform.openai.com/api-keys'> OpenAI 账户</a>来获取自己的 OpenAI API key。",
@@ -369,6 +371,7 @@ FILENAME_HEAD: "文件名",
DEFAULT_PEN_MODE_NAME: "触控笔模式(Pen mode",
DEFAULT_PEN_MODE_DESC:
"打开绘图时,是否自动开启触控笔模式?",
ENABLE_DOUBLE_CLICK_TEXT_EDITING_NAME : "启用双击文本创建",
DISABLE_DOUBLE_TAP_ERASER_NAME: "启用手写模式下的双击橡皮擦功能",
DISABLE_SINGLE_FINGER_PANNING_NAME: "启用手写模式下的单指平移功能",
SHOW_PEN_MODE_FREEDRAW_CROSSHAIR_NAME: "在触控笔模式下显示十字准星(+)",
@@ -427,6 +430,10 @@ FILENAME_HEAD: "文件名",
GRID_OPACITY_NAME: "网格透明度",
GRID_OPACITY_DESC: "网格透明度还将控制将箭头绑定到元素时绑定框的透明度。<br>"+
"设置网格的不透明度。 0 表示完全透明,100 表示完全不透明。",
GRID_DIRECTION_NAME : "网格方向" ,
GRID_DIRECTION_DESC : "第一个开关显示/隐藏水平网格,第二个开关显示/隐藏垂直网格。" ,
GRID_HORIZONTAL : "渲染水平网格" ,
GRID_VERTICAL : "渲染垂直网格" ,
LASER_HEAD: "激光笔工具(更多工具 > 激光笔)",
LASER_COLOR: "激光笔颜色",
LASER_DECAY_TIME_NAME: "激光笔消失时间",
+2 -2
View File
@@ -1,6 +1,6 @@
import { ExcalidrawElement, FileId } from "@zsviczian/excalidraw/types/excalidraw/element/types";
import { ExcalidrawElement, FileId } from "@zsviczian/excalidraw/types/element/src/types";
import { BinaryFileData } from "@zsviczian/excalidraw/types/excalidraw/types";
import { Mutable } from "@zsviczian/excalidraw/types/excalidraw/utility-types";
import { Mutable } from "@zsviczian/excalidraw/types/common/src/utility-types";
import { Notice } from "obsidian";
import { getEA } from "src/core";
+3 -3
View File
@@ -1,5 +1,5 @@
import { ExcalidrawEmbeddableElement } from "@zsviczian/excalidraw/types/excalidraw/element/types";
import { Mutable } from "@zsviczian/excalidraw/types/excalidraw/utility-types";
import { ExcalidrawEmbeddableElement } from "@zsviczian/excalidraw/types/element/src/types";
import { Mutable } from "@zsviczian/excalidraw/types/common/src/utility-types";
import { Modal, Notice, Setting, TFile, ToggleComponent } from "obsidian";
import { getEA } from "src/core";
import { ExcalidrawAutomate } from "src/shared/ExcalidrawAutomate";
@@ -12,6 +12,7 @@ import { getYouTubeStartAt, isValidYouTubeStart, isYouTube, updateYouTubeStartTi
import { EmbeddalbeMDFileCustomDataSettingsComponent } from "./EmbeddableMDFileCustomDataSettingsComponent";
import { isWinCTRLorMacCMD } from "src/utils/modifierkeyHelper";
import { ExcalidrawImperativeAPI } from "@zsviczian/excalidraw/types/excalidraw/types";
import { CaptureUpdateAction } from "src/constants/constants";
export type EmbeddableMDCustomProps = {
useObsidianDefaults: boolean;
@@ -225,7 +226,6 @@ export class EmbeddableSettings extends Modal {
if(dirty) {
(async() => {
await this.ea.addElementsToView();
//@ts-ignore
this.ea.viewUpdateScene({appState: {}, captureUpdate: CaptureUpdateAction.NEVER});
this.close(); //close should only run once update scene is done
})();
+146 -40
View File
@@ -6,9 +6,11 @@ import { ExcalidrawAutomate } from "src/shared/ExcalidrawAutomate";
import ExcalidrawView from "src/view/ExcalidrawView";
import ExcalidrawPlugin from "src/core/main";
import { fragWithHTML, getExportPadding, getExportTheme, getPNGScale, getWithBackground, shouldEmbedScene } from "src/utils/utils";
import { PageOrientation, PageSize, PDFPageAlignment, PDFPageMarginString, exportSVGToClipboard } from "src/utils/exportUtils";
import { PageOrientation, PageSize, PDFPageAlignment, PDFPageMarginString, exportSVGToClipboard, exportPNG, exportPNGToClipboard } from "src/utils/exportUtils";
import { t } from "src/lang/helpers";
import { PDFExportSettings, PDFExportSettingsComponent } from "./PDFExportSettingsComponent";
import { captureScreenshot } from "src/utils/screenshot";
import { createOrOverwriteFile, getIMGFilename } from "src/utils/fileUtils";
@@ -34,7 +36,7 @@ export class ExportDialog extends Modal {
public saveToVault: boolean;
public pageSize: PageSize = "A4";
public pageOrientation: PageOrientation = "portrait";
private activeTab: "image" | "pdf" = "image";
private activeTab: "image" | "pdf" | "screenshot" = "image";
private contentContainer: HTMLDivElement;
private buttonContainerRow1: HTMLDivElement;
private buttonContainerRow2: HTMLDivElement;
@@ -43,6 +45,7 @@ export class ExportDialog extends Modal {
public customPaperColor: string = "#ffffff";
public alignment: PDFPageAlignment = "center";
public margin: PDFPageMarginString = "normal";
private scaleSetting:Setting;
constructor(
private plugin: ExcalidrawPlugin,
@@ -85,6 +88,17 @@ export class ExportDialog extends Modal {
this.selectedOnlySetting = null;
this.containerEl.remove();
}
updateBoundingBox() {
if(this.hasSelectedElements && this.exportSelectedOnly) {
this.boundingBox = this.ea.getBoundingBox(this.view.getViewSelectedElements());
} else {
this.boundingBox = this.ea.getBoundingBox(this.ea.getViewElements());
}
if(this.scaleSetting) {
this.scaleSetting.setDesc(this.size());
}
}
onOpen(): void {
this.containerEl.classList.add("excalidraw-release");
@@ -92,6 +106,7 @@ export class ExportDialog extends Modal {
this.hasSelectedElements = this.view.getViewSelectedElements().length > 0;
//@ts-ignore
this.selectedOnlySetting.setVisibility(this.hasSelectedElements);
this.updateBoundingBox();
}
async onClose() {
@@ -113,11 +128,17 @@ export class ExportDialog extends Modal {
cls: `nav-button ${this.activeTab === "pdf" ? "is-active" : ""}`
});
const screenshotTab = tabContainer.createEl("button", {
text: t("EXPORTDIALOG_TAB_SCREENSHOT"),
cls: `nav-button ${this.activeTab === "screenshot" ? "is-active" : ""}`
});
// Tab click handlers
imageTab.onclick = () => {
this.activeTab = "image";
imageTab.addClass("is-active");
pdfTab.removeClass("is-active");
screenshotTab.removeClass("is-active");
this.renderContent();
};
@@ -125,8 +146,17 @@ export class ExportDialog extends Modal {
this.activeTab = "pdf";
pdfTab.addClass("is-active");
imageTab.removeClass("is-active");
screenshotTab.removeClass("is-active");
this.renderContent();
};
screenshotTab.onclick = () => {
this.activeTab = "screenshot";
screenshotTab.addClass("is-active");
imageTab.removeClass("is-active");
pdfTab.removeClass("is-active");
this.renderContent();
}
}
// Create content container
@@ -157,32 +187,56 @@ export class ExportDialog extends Modal {
this.buttonContainerRow1.empty();
this.buttonContainerRow2.empty();
if (this.activeTab === "image") {
this.createImageSettings();
this.createExportSettings();
this.createImageButtons();
} else {
this.createImageSettings();
this.createPDFSettings();
this.createPDFButton();
this.createHeader();
switch (this.activeTab) {
case "pdf":
this.createImageSettings();
this.createPDFSettings();
this.createPDFButton();
break;
case "screenshot":
this.createImageSettings(true);
this.createImageButtons(true);
break;
case "image":
default:
this.createImageSettings(false);
this.createExportSettings();
this.createImageButtons();
break;
}
}
private size ():DocumentFragment {
const width = Math.round(this.scale*this.boundingBox.width + this.padding*2);
const height = Math.round(this.scale*this.boundingBox.height + this.padding*2);
return fragWithHTML(`${t("EXPORTDIALOG_SIZE_DESC")}<br>${t("EXPORTDIALOG_SCALE_VALUE")} <b>${this.scale}</b><br>${t("EXPORTDIALOG_IMAGE_SIZE")} <b>${width}x${height}</b>`);
}
private createHeader() {
switch (this.activeTab) {
case "pdf":
this.contentContainer.createEl("h1",{text: t("EXPORTDIALOG_PDF_SETTINGS")});
//this.contentContainer.createEl("p",{text: t("EXPORTDIALOG_PDF_DESC")});
break;
case "screenshot":
this.contentContainer.createEl("h1",{text: t("EXPORTDIALOG_TAB_SCREENSHOT")});
this.contentContainer.createEl("p",{text: t("EXPORTDIALOG_SCREENSHOT_DESC")})
break;
case "image":
default:
this.contentContainer.createEl("h1",{text: t("EXPORTDIALOG_IMAGE_SETTINGS")});
this.contentContainer.createEl("p",{text: t("EXPORTDIALOG_IMAGE_DESC")})
break;
}
}
private createImageSettings() {
let scaleSetting:Setting;
private createImageSettings(isScreenshot: boolean = false) {
let paddingSetting: Setting;
this.contentContainer.createEl("h1",{text: t("EXPORTDIALOG_IMAGE_SETTINGS")});
this.contentContainer.createEl("p",{text: t("EXPORTDIALOG_IMAGE_DESC")})
this.createSaveSettingsDropdown();
const size = ():DocumentFragment => {
const width = Math.round(this.scale*this.boundingBox.width + this.padding*2);
const height = Math.round(this.scale*this.boundingBox.height + this.padding*2);
return fragWithHTML(`${t("EXPORTDIALOG_SIZE_DESC")}<br>${t("EXPORTDIALOG_SCALE_VALUE")} <b>${this.scale}</b><br>${t("EXPORTDIALOG_IMAGE_SIZE")} <b>${width}x${height}</b>`);
}
const padding = ():DocumentFragment => {
return fragWithHTML(`${t("EXPORTDIALOG_CURRENT_PADDING")} <b>${this.padding}</b>`);
}
@@ -196,21 +250,21 @@ export class ExportDialog extends Modal {
.setValue(this.padding)
.onChange(value => {
this.padding = value;
scaleSetting.setDesc(size());
this.scaleSetting.setDesc(this.size());
paddingSetting.setDesc(padding());
})
})
scaleSetting = new Setting(this.contentContainer)
this.scaleSetting = new Setting(this.contentContainer)
.setName(t("EXPORTDIALOG_SCALE"))
.setDesc(size())
.setDesc(this.size())
.addSlider(slider =>
slider
.setLimits(0.2,7,0.1)
.setValue(this.scale)
.onChange(value => {
this.scale = value;
scaleSetting.setDesc(size());
this.scaleSetting.setDesc(this.size());
})
)
@@ -226,17 +280,19 @@ export class ExportDialog extends Modal {
})
)
new Setting(this.contentContainer)
.setName(t("EXPORTDIALOG_BACKGROUND"))
.addDropdown(dropdown =>
dropdown
.addOption("transparent", t("EXPORTDIALOG_BACKGROUND_TRANSPARENT"))
.addOption("with-color", t("EXPORTDIALOG_BACKGROUND_USE_COLOR"))
.setValue(this.transparent?"transparent":"with-color")
.onChange(value => {
this.transparent = value === "transparent";
})
)
if(!isScreenshot) {
new Setting(this.contentContainer)
.setName(t("EXPORTDIALOG_BACKGROUND"))
.addDropdown(dropdown =>
dropdown
.addOption("transparent", t("EXPORTDIALOG_BACKGROUND_TRANSPARENT"))
.addOption("with-color", t("EXPORTDIALOG_BACKGROUND_USE_COLOR"))
.setValue(this.transparent?"transparent":"with-color")
.onChange(value => {
this.transparent = value === "transparent";
})
)
}
this.selectedOnlySetting = new Setting(this.contentContainer)
.setName(t("EXPORTDIALOG_SELECTED_ELEMENTS"))
@@ -247,8 +303,11 @@ export class ExportDialog extends Modal {
.setValue(this.exportSelectedOnly?"selected":"all")
.onChange(value => {
this.exportSelectedOnly = value === "selected";
this.updateBoundingBox();
})
);
//@ts-ignore
this.selectedOnlySetting.setVisibility(this.hasSelectedElements);
}
private createExportSettings() {
@@ -295,14 +354,29 @@ export class ExportDialog extends Modal {
).render();
}
private createImageButtons() {
private createImageButtons(isScreenshot: boolean = false) {
if(DEVICE.isDesktop) {
const bPNG = this.buttonContainerRow1.createEl("button", {
text: t("EXPORTDIALOG_PNGTOFILE"),
cls: "excalidraw-export-button"
});
bPNG.onclick = () => {
this.view.exportPNG(this.embedScene, this.hasSelectedElements && this.exportSelectedOnly);
if(isScreenshot) {
//allow dialot to close before taking screenshot
setTimeout(async () => {
const png = await captureScreenshot(this.view, {
zoom: this.scale,
margin: this.padding,
selectedOnly: this.exportSelectedOnly,
theme: this.theme
});
if(png) {
exportPNG(png, this.view.file.basename);
}
});
} else {
this.view.exportPNG(this.embedScene, this.hasSelectedElements && this.exportSelectedOnly);
}
this.close();
};
}
@@ -312,7 +386,22 @@ export class ExportDialog extends Modal {
cls: "excalidraw-export-button"
});
bPNGVault.onclick = () => {
this.view.savePNG(this.view.getScene(this.hasSelectedElements && this.exportSelectedOnly));
if(isScreenshot) {
//allow dialot to close before taking screenshot
setTimeout(async () => {
const png = await captureScreenshot(this.view, {
zoom: this.scale,
margin: this.padding,
selectedOnly: this.exportSelectedOnly,
theme: this.theme
});
if(png) {
createOrOverwriteFile(this.app, getIMGFilename(this.view.file.path,"png"), png);
}
});
} else {
this.view.savePNG(this.view.getScene(this.hasSelectedElements && this.exportSelectedOnly));
}
this.close();
};
@@ -321,10 +410,27 @@ export class ExportDialog extends Modal {
cls: "excalidraw-export-button"
});
bPNGClipboard.onclick = async () => {
this.view.exportPNGToClipboard(this.embedScene, this.hasSelectedElements && this.exportSelectedOnly);
if(isScreenshot) {
//allow dialot to close before taking screenshot
setTimeout(async () => {
const png = await captureScreenshot(this.view, {
zoom: this.scale,
margin: this.padding,
selectedOnly: this.exportSelectedOnly,
theme: this.theme
});
if(png) {
exportPNGToClipboard(png);
}
});
} else {
this.view.exportPNGToClipboard(this.embedScene, this.hasSelectedElements && this.exportSelectedOnly);
}
this.close();
};
if(isScreenshot) return;
if(DEVICE.isDesktop) {
const bExcalidraw = this.buttonContainerRow2.createEl("button", {
text: t("EXPORTDIALOG_EXCALIDRAW"),
+2 -2
View File
@@ -70,7 +70,7 @@ export class InsertPDFModal extends Modal {
this.setImageSizeMessage = null;
}
private async getPageDimensions (pdfDoc: any) {
private async getPDFPageDimensions (pdfDoc: any) {
try {
const scale = this.plugin.settings.pdfScale;
const canvas = createEl("canvas");
@@ -197,7 +197,7 @@ export class InsertPDFModal extends Modal {
rangeOnChange(`1-${numPages}`);
importButtonMessages();
numPagesMessages();
this.getPageDimensions(this.pdfDoc);
this.getPDFPageDimensions(this.pdfDoc);
} else {
importButton.setDisabled(true);
}
+41 -3
View File
@@ -11,12 +11,50 @@ Thank you & Enjoy!
`;
export const RELEASE_NOTES: { [k: string]: string } = {
Intro: `After each update you'll be prompted with the release notes. You can disable this in plugin settings.
Intro: `After each update, youll see these release notes (you can turn this off in the plugin settings).
I develop this plugin as a hobby, spending my free time doing this. If you find it valuable, then please say THANK YOU or...
I build this plugin in my free time, as a labor of love. Curious about the philosophy behind it? Check out [📕 Sketch Your Mind](https://sketch-your-mind.com). If you find it valuable, say THANK YOU or…
<div class="ex-coffee-div"><a href="https://ko-fi.com/zsolt"><img src="https://storage.ko-fi.com/cdn/kofi6.png?v=6" border="0" alt="Buy Me a Coffee at ko-fi.com" height=45></a></div>
`,
"2.11.0": `
## New
- New "Screenshot" option in the Export Image dialog. This allows you to take a screenshot of the current view, including embedded web pages, youtube videos, and markdown documents. Screenshot is only possible in PNG.
- Expose parameter in plugin settings to disable AI functionality [#2325](https://github.com/zsviczian/obsidian-excalidraw-plugin/issues/2325)
- Enable double-click text editing option in Excalidraw appearance and behavior (based on request on Discord)
- Added two new PDF export sizes: "Match image", "HD Screen".
## Fixed in the plugin
- Scaling multiple embeddables at once did not work. [#2276](https://github.com/zsviczian/obsidian-excalidraw-plugin/issues/2276)
- When creating multiple back-of-the-note the second card is not created correctly if autosave has not yet happened.
- Drawing reloads while editing the back-of-the-note card in certain cases causes editing to be interrupted.
- Moved Excalidraw filetype indicator to after filename where other filetype tags are displayed. You can turn the filetype indicator on/off in plugin settings under Miscellaneous.
## Fixed by Excalidraw.com
- Alt-duplicate now preserves the original element. Previously, using Alt to duplicate would swap the original with the new element, leading to unexpected behavior and several downstream issues. [#9403](https://github.com/excalidraw/excalidraw/pull/9403)
- When dragging the arrow endpoint, update the binding only on the dragged side [#9367](https://github.com/excalidraw/excalidraw/pull/9367)
- Laser pointer trail disappearing on pointerup [#9413](https://github.com/excalidraw/excalidraw/pull/9413) [#9427](https://github.com/excalidraw/excalidraw/pull/9427)
`,
"2.10.1": `
## Fixed by Excalidraw.com
- Eraser performance improvement regression. Erasing locked elements. [#9400](https://github.com/excalidraw/excalidraw/pull/9400)
## New
- Grid Customization Options in plugin settings (appearance and behavior/grid): You can now selectively show or hide vertical and horizontal grid lines independently. This allows you to create alternative grid styles, such as horizontal-only lined grids instead of the traditional checkered pattern.
## Fixed in ExcalidrawAutomate
- ${String.fromCharCode(96)}ea.createSVG${String.fromCharCode(96)} throws error [#2321](https://github.com/zsviczian/obsidian-excalidraw-plugin/issues/2321)
---
## Enjoying the plugin?
Support my work by checking out my new book, now available for pre-order:
[Sketch Your Mind: Nurture a Playful and Creative Brain](https://sketch-your-mind.com) is about visual Personal Knowledge Management. It explores the thinking behind Excalidraw and how it helps you structure and evolve ideas visually. Its the book I wish I had when I began my own PKM journey.
<div class="ex-coffee-div"><a href="https://sketch-your-mind.com"><img src="https://raw.githubusercontent.com/zsviczian/sketch-your-mind/refs/heads/main/images/cover-mini.jpg" border="0" alt="Pre-order Sketch Your Mind" height="100%"></a></div>
`,
"2.10.0": `
## New from Excalidraw.com
- Lasso select [#9169](https://github.com/excalidraw/excalidraw/pull/9169)
@@ -28,7 +66,7 @@ I develop this plugin as a hobby, spending my free time doing this. If you find
- Keep arrow label horizontal [#9364](https://github.com/excalidraw/excalidraw/pull/9364)
## Fixed in ExcalidrawAutomate
- ea.addText did not honor the width parameter.
- ${String.fromCharCode(96)}ea.addText${String.fromCharCode(96)} did not honor the width parameter.
`,
"2.9.2":`
- More minor fix. Toolbars are not responsive when dynamic styling is turned off. [#2287](https://github.com/zsviczian/obsidian-excalidraw-plugin/issues/2287)
@@ -21,6 +21,10 @@ export class PDFExportSettingsComponent {
if (!update) this.update = () => {};
}
isOrientationAndTilingVisible() {
return !(this.settings.pageSize === "HD Screen" || this.settings.pageSize === "MATCH IMAGE");
}
render() {
const pageSizeOptions: Record<string, string> = Object.keys(STANDARD_PAGE_SIZES)
.reduce((acc, key) => ({
@@ -28,6 +32,8 @@ export class PDFExportSettingsComponent {
[key]: key
}), {});
let div: HTMLDivElement;
new Setting(this.contentEl)
.setName(t("EXPORTDIALOG_PAGE_SIZE"))
.addDropdown(dropdown =>
@@ -36,11 +42,15 @@ export class PDFExportSettingsComponent {
.setValue(this.settings.pageSize)
.onChange(value => {
this.settings.pageSize = value as PageSize;
div.style.display = this.isOrientationAndTilingVisible() ? "block" : "none";
this.update();
})
);
new Setting(this.contentEl)
div = this.contentEl.createDiv();
div.style.display = this.isOrientationAndTilingVisible() ? "block" : "none";
new Setting(div)
.setName(t("EXPORTDIALOG_PAGE_ORIENTATION"))
.addDropdown(dropdown =>
dropdown
@@ -55,7 +65,7 @@ export class PDFExportSettingsComponent {
})
);
new Setting(this.contentEl)
new Setting(div)
.setName(t("EXPORTDIALOG_PDF_FIT_TO_PAGE"))
.addDropdown(dropdown =>
dropdown
+1 -1
View File
@@ -1,7 +1,7 @@
//https://stackoverflow.com/questions/2068344/how-do-i-get-a-youtube-video-thumbnail-from-the-youtube-api
//https://img.youtube.com/vi/uZz5MgzWXiM/maxresdefault.jpg
import { ExcalidrawElement, FileId } from "@zsviczian/excalidraw/types/excalidraw/element/types";
import { ExcalidrawElement, FileId } from "@zsviczian/excalidraw/types/element/src/types";
import { BinaryFileData, DataURL } from "@zsviczian/excalidraw/types/excalidraw/types";
import { App, MarkdownRenderer, Notice, TFile } from "obsidian";
import {
+9 -8
View File
@@ -12,7 +12,7 @@ import {
RoundnessType,
ExcalidrawFrameElement,
ExcalidrawTextContainer,
} from "@zsviczian/excalidraw/types/excalidraw/element/types";
} from "@zsviczian/excalidraw/types/element/src/types";
import { ColorMap, MimeType } from "./EmbeddedFileLoader";
import { Editor, Notice, OpenViewState, RequestUrlResponse, TFile, TFolder, WorkspaceLeaf } from "obsidian";
import * as obsidian_module from "obsidian";
@@ -43,7 +43,6 @@ import {
arrayToMap,
addAppendUpdateCustomData,
getSVG,
getWithBackground,
} from "src/utils/utils";
import { getAttachmentsFolderAndFilePath, getExcalidrawViews, getLeaf, getNewOrAdjacentLeaf, isObsidianThemeDark, mergeMarkdownFiles, openLeaf } from "src/utils/obsidianUtils";
import { AppState, BinaryFileData, DataURL, ExcalidrawImperativeAPI, SceneData } from "@zsviczian/excalidraw/types/excalidraw/types";
@@ -70,7 +69,7 @@ import {ConversionResult, svgToExcalidraw} from "src/shared/svgToExcalidraw/pars
import { ROUNDNESS } from "src/constants/constants";
import { ClipboardData } from "@zsviczian/excalidraw/types/excalidraw/clipboard";
import { emulateKeysForLinkClick, PaneTarget } from "src/utils/modifierkeyHelper";
import { Mutable } from "@zsviczian/excalidraw/types/excalidraw/utility-types";
import { Mutable } from "@zsviczian/excalidraw/types/common/src/utility-types";
import PolyBool from "polybooljs";
import { EmbeddableMDCustomProps } from "./Dialogs/EmbeddableSettings";
import {
@@ -82,7 +81,7 @@ import { EXCALIDRAW_AUTOMATE_INFO, EXCALIDRAW_SCRIPTENGINE_INFO } from "./Dialog
import { addBackOfTheNoteCard } from "../utils/excalidrawViewUtils";
import { log } from "../utils/debugHelper";
import { ExcalidrawLib } from "../types/excalidrawLib";
import { GlobalPoint } from "@zsviczian/excalidraw/types/math/types";
import { GlobalPoint } from "@zsviczian/excalidraw/types/math/src/types";
import { AddImageOptions, ImageInfo, SVGColorInfo } from "src/types/excalidrawAutomateTypes";
import { _measureText, cloneElement, createPNG, createSVG, errorMessage, filterColorMap, getEmbeddedFileForImageElment, getFontFamily, getLineBox, getTemplate, isColorStringTransparent, isSVGColorInfo, mergeColorMapIntoSVGColorInfo, normalizeLinePoints, repositionElementsToCursor, svgColorInfoToColorMap, updateOrAddSVGColorInfo, verifyMinimumPluginVersion } from "src/utils/excalidrawAutomateUtils";
import { exportToPDF, getMarginValue, getPageDimensions, PageDimensions, PageOrientation, PageSize, PDFExportScale, PDFPageProperties } from "src/utils/exportUtils";
@@ -1096,13 +1095,14 @@ export class ExcalidrawAutomate {
? "light"
: undefined;
}
if (theme && !exportSettings) {
if (!exportSettings) {
exportSettings = {
withBackground: this.plugin.settings.exportWithBackground,
withTheme: true,
isMask: false,
skipInliningFonts: !embedFont,
};
}
}
if (!loader) {
loader = new EmbeddedFilesLoader(
this.plugin,
@@ -1654,7 +1654,8 @@ export class ExcalidrawAutomate {
arrayToMap(this.getElements()),
originalText,
);
if(dimensions) {
if(dimensions && !formatting?.width) {
textElement.width = dimensions.width;
textElement.height = dimensions.height;
textElement.x = dimensions.x;
@@ -2605,7 +2606,7 @@ export class ExcalidrawAutomate {
viewUpdateScene (
scene: {
elements?: ExcalidrawElement[],
appState?: AppState,
appState?: AppState | {},
files?: BinaryFileData,
commitToHistory?: boolean,
storeAction?: "capture" | "none" | "update",
+2 -2
View File
@@ -44,13 +44,13 @@ import {
ExcalidrawImageElement,
ExcalidrawTextElement,
FileId,
} from "@zsviczian/excalidraw/types/excalidraw/element/types";
} from "@zsviczian/excalidraw/types/element/src/types";
import { BinaryFiles, DataURL, SceneData } from "@zsviczian/excalidraw/types/excalidraw/types";
import { EmbeddedFile, MimeType } from "./EmbeddedFileLoader";
import { ConfirmationPrompt } from "./Dialogs/Prompt";
import { getMermaidImageElements, getMermaidText, shouldRenderMermaid } from "../utils/mermaidUtils";
import { DEBUGGING, debug } from "../utils/debugHelper";
import { Mutable } from "@zsviczian/excalidraw/types/excalidraw/utility-types";
import { Mutable } from "@zsviczian/excalidraw/types/common/src/utility-types";
import { updateElementIdsInScene } from "../utils/excalidrawSceneUtils";
import { checkAndCreateFolder, getNewUniqueFilepath, splitFolderAndFilename } from "../utils/fileUtils";
import { t } from "../lang/helpers";
+1 -1
View File
@@ -2,7 +2,7 @@
import { DataURL } from "@zsviczian/excalidraw/types/excalidraw/types";
import ExcalidrawView from "../view/ExcalidrawView";
import { FileData, MimeType } from "./EmbeddedFileLoader";
import { FileId } from "@zsviczian/excalidraw/types/excalidraw/element/types";
import { FileId } from "@zsviczian/excalidraw/types/element/src/types";
import ExcalidrawPlugin from "src/core/main";
declare const loadMathjaxToSVG: Function;
+1 -1
View File
@@ -3,7 +3,7 @@ import {Notice, requestUrl} from "obsidian"
import ExcalidrawPlugin from "../../core/main"
import ExcalidrawView, { ExportSettings } from "../../view/ExcalidrawView"
import FrontmatterEditor from "src/shared/Frontmatter";
import { ExcalidrawElement } from "@zsviczian/excalidraw/types/excalidraw/element/types";
import { ExcalidrawElement } from "@zsviczian/excalidraw/types/element/src/types";
import { EmbeddedFilesLoader } from "../EmbeddedFileLoader";
import { blobToBase64 } from "src/utils/fileUtils";
import { getEA } from "src/core";
@@ -1,6 +1,6 @@
import { randomId, randomInteger } from "../utils";
import { ExcalidrawLinearElement, FillStyle, GroupId, RoundnessType, StrokeStyle } from "@zsviczian/excalidraw/types/excalidraw/element/types";
import { ExcalidrawLinearElement, FillStyle, GroupId, RoundnessType, StrokeStyle } from "@zsviczian/excalidraw/types/element/src/types";
export type Point = [number, number];
+1 -1
View File
@@ -1,4 +1,4 @@
import { ExcalidrawElement, ExcalidrawLinearElement, ExcalidrawTextElement, FillStyle, GroupId, RoundnessType, StrokeStyle } from "@zsviczian/excalidraw/types/excalidraw/element/types";
import { ExcalidrawElement, ExcalidrawLinearElement, ExcalidrawTextElement, FillStyle, GroupId, RoundnessType, StrokeStyle } from "@zsviczian/excalidraw/types/element/src/types";
export type PathCommand = {
type: string;
+3 -3
View File
@@ -1,11 +1,11 @@
import { RestoredDataState } from "@zsviczian/excalidraw/types/excalidraw/data/restore";
import { ImportedDataState } from "@zsviczian/excalidraw/types/excalidraw/data/types";
import { BoundingBox } from "@zsviczian/excalidraw/types/excalidraw/element/bounds";
import { ElementsMap, ExcalidrawBindableElement, ExcalidrawElement, ExcalidrawFrameElement, ExcalidrawFrameLikeElement, ExcalidrawTextContainer, ExcalidrawTextElement, FontFamilyValues, FontString, NonDeleted, NonDeletedExcalidrawElement, Theme } from "@zsviczian/excalidraw/types/excalidraw/element/types";
import { ElementsMap, ExcalidrawBindableElement, ExcalidrawElement, ExcalidrawFrameElement, ExcalidrawFrameLikeElement, ExcalidrawTextContainer, ExcalidrawTextElement, FontFamilyValues, FontString, NonDeleted, NonDeletedExcalidrawElement, Theme } from "@zsviczian/excalidraw/types/element/src/types";
import { FontMetadata } from "@zsviczian/excalidraw/types/excalidraw/fonts/FontMetadata";
import { AppState, BinaryFiles, DataURL, GenerateDiagramToCode, Zoom } from "@zsviczian/excalidraw/types/excalidraw/types";
import { Mutable } from "@zsviczian/excalidraw/types/excalidraw/utility-types";
import { GlobalPoint } from "@zsviczian/excalidraw/types/math/types";
import { Mutable } from "@zsviczian/excalidraw/types/common/src/utility-types";
import { GlobalPoint } from "@zsviczian/excalidraw/types/math/src/types";
interface MermaidConfig {
/**
+1 -1
View File
@@ -1,7 +1,7 @@
// src/types/ExcalidrawViewTypes.ts
import { WorkspaceLeaf } from "obsidian";
import { FileId } from "@zsviczian/excalidraw/types/excalidraw/element/types";
import { FileId } from "@zsviczian/excalidraw/types/element/src/types";
import { ObsidianCanvasNode } from "../view/managers/CanvasNodeFactory";
export type Position = { x: number; y: number };
+1
View File
@@ -18,6 +18,7 @@ export type GridSettings = {
DYNAMIC_COLOR: boolean; // Whether the grid color is dynamic
COLOR: string; // The grid color (in hex format)
OPACITY: number; // The grid opacity (hex value between "00" and "FF")
GRID_DIRECTION: {horizontal: boolean, vertical: boolean}; // Whether the grid is horizontal or vertical
};
export type DeviceType = {
+1 -1
View File
@@ -1,6 +1,6 @@
//for future use, not used currently
import { ImageCrop } from "@zsviczian/excalidraw/types/excalidraw/element/types";
import { ImageCrop } from "@zsviczian/excalidraw/types/element/src/types";
import { PDFPageViewProps } from "src/shared/EmbeddedFileLoader";
export function getPDFCropRect (props: {
+3 -3
View File
@@ -1,10 +1,10 @@
import { ExcalidrawEmbeddableElement, ExcalidrawFrameElement, ExcalidrawImageElement } from "@zsviczian/excalidraw/types/excalidraw/element/types";
import { Mutable } from "@zsviczian/excalidraw/types/excalidraw/utility-types";
import { ExcalidrawEmbeddableElement, ExcalidrawFrameElement, ExcalidrawImageElement } from "@zsviczian/excalidraw/types/element/src/types";
import { Mutable } from "@zsviczian/excalidraw/types/common/src/utility-types";
import { getEA } from "src/core";
import { ExcalidrawAutomate } from "src/shared/ExcalidrawAutomate";
import { getCropFileNameAndFolder, getListOfTemplateFiles, splitFolderAndFilename } from "./fileUtils";
import { Notice, TFile } from "obsidian";
import { Radians } from "@zsviczian/excalidraw/types/math";
import { Radians } from "@zsviczian/excalidraw/types/math/src/types";
export const CROPPED_PREFIX = "cropped_";
export const ANNOTATED_PREFIX = "annotated_";
+1 -1
View File
@@ -1,4 +1,4 @@
import { NonDeletedExcalidrawElement } from "@zsviczian/excalidraw/types/excalidraw/element/types";
import { NonDeletedExcalidrawElement } from "@zsviczian/excalidraw/types/element/src/types";
import { DEVICE, REG_LINKINDEX_INVALIDCHARS } from "src/constants/constants";
import { getParentOfClass } from "./obsidianUtils";
import { App, Notice, TFile, WorkspaceLeaf } from "obsidian";
+1 -1
View File
@@ -4,7 +4,7 @@ import { ExcalidrawAutomate } from "src/shared/ExcalidrawAutomate";
import ExcalidrawView from "src/view/ExcalidrawView";
import { DynamicStyle } from "src/types/types";
import { cloneElement } from "./excalidrawAutomateUtils";
import { ExcalidrawFrameElement } from "@zsviczian/excalidraw/types/excalidraw/element/types";
import { ExcalidrawFrameElement } from "@zsviczian/excalidraw/types/element/src/types";
import { addAppendUpdateCustomData } from "./utils";
import { mutateElement } from "src/constants/constants";
import { CaptureUpdateAction } from "src/constants/constants";
+2 -2
View File
@@ -5,7 +5,7 @@ import {
ExcalidrawElement,
ExcalidrawImageElement,
FileId,
} from "@zsviczian/excalidraw/types/excalidraw/element/types";
} from "@zsviczian/excalidraw/types/element/src/types";
import { normalizePath, TFile } from "obsidian";
import ExcalidrawView, { ExportSettings, getTextMode } from "src/view/ExcalidrawView";
@@ -32,7 +32,7 @@ import {
} from "src/utils/utils";
import { GenericInputPrompt, NewFileActions } from "src/shared/Dialogs/Prompt";
import { t } from "src/lang/helpers";
import { Mutable } from "@zsviczian/excalidraw/types/excalidraw/utility-types";
import { Mutable } from "@zsviczian/excalidraw/types/common/src/utility-types";
import {
postOpenAI as _postOpenAI,
extractCodeBlocks as _extractCodeBlocks,
+2 -2
View File
@@ -1,5 +1,5 @@
import { ExcalidrawArrowElement, ExcalidrawElement, ExcalidrawTextElement } from "@zsviczian/excalidraw/types/excalidraw/element/types";
import { Mutable } from "@zsviczian/excalidraw/types/excalidraw/utility-types";
import { ExcalidrawArrowElement, ExcalidrawElement, ExcalidrawTextElement } from "@zsviczian/excalidraw/types/element/src/types";
import { Mutable } from "@zsviczian/excalidraw/types/common/src/utility-types";
export function updateElementIdsInScene(
+2 -2
View File
@@ -4,7 +4,7 @@ import { App, Modal, Notice, TFile, WorkspaceLeaf } from "obsidian";
import { ExcalidrawAutomate } from "src/shared/ExcalidrawAutomate";
import { REGEX_LINK, REG_LINKINDEX_HYPERLINK, getExcalidrawMarkdownHeaderSection, REGEX_TAGS } from "../shared/ExcalidrawData";
import ExcalidrawView from "src/view/ExcalidrawView";
import { ExcalidrawElement, ExcalidrawFrameElement, ExcalidrawImageElement } from "@zsviczian/excalidraw/types/excalidraw/element/types";
import { ExcalidrawElement, ExcalidrawFrameElement, ExcalidrawImageElement } from "@zsviczian/excalidraw/types/element/src/types";
import { getEmbeddedFilenameParts, getLinkParts, isImagePartRef } from "./utils";
import { cleanSectionHeading } from "./obsidianUtils";
import { getEA } from "src/core";
@@ -12,7 +12,7 @@ import { ExcalidrawImperativeAPI } from "@zsviczian/excalidraw/types/excalidraw/
import { EmbeddableMDCustomProps } from "src/shared/Dialogs/EmbeddableSettings";
import { nanoid } from "nanoid";
import { t } from "src/lang/helpers";
import { Mutable } from "@zsviczian/excalidraw/types/excalidraw/utility-types";
import { Mutable } from "@zsviczian/excalidraw/types/common/src/utility-types";
import { EmbeddedFile } from "src/shared/EmbeddedFileLoader";
import { CaptureUpdateAction } from "src/constants/constants";
+41 -5
View File
@@ -1,6 +1,8 @@
import { Notice } from 'obsidian';
import { DEVICE } from 'src/constants/constants';
import { t } from 'src/lang/helpers';
import { download } from './fileUtils';
import { svgToBase64 } from './utils';
const DPI = 96;
@@ -54,7 +56,9 @@ export const STANDARD_PAGE_SIZES = {
Legal: { width: 816, height: 1344 }, // 8.5 × 14 inches
Letter: { width: 816, height: 1056 }, // 8.5 × 11 inches
Tabloid: { width: 1056, height: 1632 }, // 11 × 17 inches
Ledger: { width: 1632, height: 1056 } // 17 × 11 inches
Ledger: { width: 1632, height: 1056 }, // 17 × 11 inches
"HD Screen": { width: 1920, height: 1080 },// 16:9 aspect ratio
"MATCH IMAGE": { width: 0, height: 0 }, // 0 means use the current screen size
} as const;
export type PageSize = keyof typeof STANDARD_PAGE_SIZES;
@@ -69,9 +73,15 @@ export function getMarginValue(margin:PDFPageMarginString): PDFMargin {
}
}
export function getPageDimensions(pageSize: PageSize, orientation: PageOrientation): PageDimensions {
const dimensions = STANDARD_PAGE_SIZES[pageSize];
return orientation === "portrait"
export function getPageDimensions(pageSize: PageSize, orientation: PageOrientation, dims?: {width: number, height: number}): PageDimensions {
let dimensions:{width: number, height: number};
dimensions = STANDARD_PAGE_SIZES[pageSize];
if (dims && dimensions.width === 0 && dimensions.height === 0) {
dimensions = { width: dims.width, height: dims.height };
}
return orientation === "portrait" || pageSize === "MATCH IMAGE" || pageSize === "HD Screen"
? { width: dimensions.width, height: dimensions.height }
: { width: dimensions.height, height: dimensions.width };
}
@@ -504,4 +514,30 @@ export async function exportSVGToClipboard(svg: SVGSVGElement) {
} catch (error) {
console.error("Failed to copy SVG to clipboard: ", error);
}
}
}
export async function exportPNGToClipboard(png: Blob) {
await navigator.clipboard.write([
new window.ClipboardItem({
"image/png": png,
}),
]);
}
export function exportPNG(png: Blob, filename: string) {
const reader = new FileReader();
reader.readAsDataURL(png);
reader.onloadend = () => {
const base64data = reader.result;
download(null, base64data, `${filename}.png`);
};
}
export function exportSVG(svg: SVGSVGElement, filename: string) {
download(
null,
svgToBase64(svg.outerHTML),
`${filename}.svg`,
);
}
+8 -5
View File
@@ -404,8 +404,8 @@ export const getAliasWithSize = (alias: string, size: string): string => {
}
export const getCropFileNameAndFolder = async (plugin: ExcalidrawPlugin, hostPath: string, baseNewFileName: string):Promise<{folderpath: string, filename: string}> => {
let prefix = plugin.settings.cropPrefix;
if(!prefix || prefix.trim() === "") prefix = CROPPED_PREFIX;
let prefix = plugin.settings.cropPrefix || "";
if(prefix.trim() === "") prefix = CROPPED_PREFIX;
const filename = prefix + baseNewFileName + ".md";
if(!plugin.settings.cropFolder || plugin.settings.cropFolder.trim() === "") {
const folderpath = (await getAttachmentsFolderAndFilePath(plugin.app, hostPath, filename)).folder;
@@ -417,8 +417,8 @@ export const getCropFileNameAndFolder = async (plugin: ExcalidrawPlugin, hostPat
}
export const getAnnotationFileNameAndFolder = async (plugin: ExcalidrawPlugin, hostPath: string, baseNewFileName: string):Promise<{folderpath: string, filename: string}> => {
let prefix = plugin.settings.annotatePrefix;
if(!prefix || prefix.trim() === "") prefix = ANNOTATED_PREFIX;
let prefix = plugin.settings.annotatePrefix || "";
if(prefix.trim() === "") prefix = ANNOTATED_PREFIX;
const filename = prefix + baseNewFileName + ".md";
if(!plugin.settings.annotateFolder || plugin.settings.annotateFolder.trim() === "") {
const folderpath = (await getAttachmentsFolderAndFilePath(plugin.app, hostPath, filename)).folder;
@@ -494,8 +494,11 @@ export const hasExcalidrawEmbeddedImagesTreeChanged = (sourceFile: TFile, mtime:
return fileList.some(f=>f.stat.mtime > mtime);
}
export async function createOrOverwriteFile(app: App, path: string, content: string | ArrayBuffer): Promise<TFile> {
export async function createOrOverwriteFile(app: App, path: string, content: string | ArrayBuffer | Blob): Promise<TFile> {
const file = app.vault.getAbstractFileByPath(normalizePath(path));
if (content instanceof Blob) {
content = await content.arrayBuffer();
}
if(content instanceof ArrayBuffer) {
if(file && file instanceof TFile) {
await app.vault.modifyBinary(file, content);
+1 -1
View File
@@ -1,4 +1,4 @@
import { ExcalidrawElement, ExcalidrawImageElement, ExcalidrawTextElement } from "@zsviczian/excalidraw/types/excalidraw/element/types";
import { ExcalidrawElement, ExcalidrawImageElement, ExcalidrawTextElement } from "@zsviczian/excalidraw/types/element/src/types";
import { REGEX_LINK, REG_LINKINDEX_HYPERLINK } from "../shared/ExcalidrawData";
import ExcalidrawView, { TextMode } from "src/view/ExcalidrawView";
import { rotatedDimensions } from "./utils";
+1 -1
View File
@@ -1,5 +1,5 @@
import { THEME } from "../constants/constants";
import type { Theme } from "@zsviczian/excalidraw/types/excalidraw/element/types";
import type { Theme } from "@zsviczian/excalidraw/types/element/src/types";
import type { DataURL } from "@zsviczian/excalidraw/types/excalidraw/types";
import type { OpenAIInput, OpenAIOutput } from "@zsviczian/excalidraw/types/excalidraw/data/ai/types";
+1 -1
View File
@@ -1,4 +1,4 @@
import { ExcalidrawElement, ExcalidrawImageElement } from "@zsviczian/excalidraw/types/excalidraw/element/types";
import { ExcalidrawElement, ExcalidrawImageElement } from "@zsviczian/excalidraw/types/element/src/types";
import { requireApiVersion } from "obsidian";
export function getMermaidImageElements (elements: ExcalidrawElement[]):ExcalidrawImageElement[] {
+273
View File
@@ -0,0 +1,273 @@
import { ExcalidrawImperativeAPI } from "@zsviczian/excalidraw/types/excalidraw/types";
import { request } from "http";
import { Notice } from "obsidian";
import { DEVICE } from "src/constants/constants";
import { getEA } from "src/core";
import { t } from "src/lang/helpers";
import { ExcalidrawAutomate } from "src/shared/ExcalidrawAutomate";
import ExcalidrawView from "src/view/ExcalidrawView";
export interface ScreenshotOptions {
zoom: number;
margin: number;
selectedOnly: boolean;
theme: string;
}
export async function captureScreenshot(view: ExcalidrawView, options: ScreenshotOptions): Promise<Blob | null> {
if (!DEVICE.isDesktop) {
new Notice(t("SCREENSHOT_DESKTOP_ONLY"));
return null;
}
(view.excalidrawAPI as ExcalidrawImperativeAPI).setForceRenderAllEmbeddables(true);
const remote = window.require("electron").remote;
const scene = view.getScene();
const viewSelectedElements = view.getViewSelectedElements();
const selectedIDs = new Set(options.selectedOnly ? viewSelectedElements.map(el => el.id) : []);
const savedOpacity: { id: string; opacity: number }[] = [];
const ea = getEA(view) as ExcalidrawAutomate;
// Save the current browser zoom level
const webContents = remote.getCurrentWebContents();
const originalZoomFactor = webContents.getZoomFactor();
// Set browser zoom to 100%
webContents.setZoomFactor(1.0);
await sleep(100); // Give the browser time to apply zoom
const devicePixelRatio = window.devicePixelRatio || 1;
if (options.selectedOnly) {
ea.copyViewElementsToEAforEditing(ea.getViewElements().filter(el => !selectedIDs.has(el.id)));
ea.getElements().forEach(el => {
savedOpacity.push({
id: el.id,
opacity: el.opacity
});
el.opacity = 0;
});
if (savedOpacity.length > 0) {
await ea.addElementsToView(false, false, false, false);
}
}
let boundingBox = ea.getBoundingBox(options.selectedOnly ? viewSelectedElements : scene.elements);
boundingBox = {
topX: Math.ceil(boundingBox.topX),
topY: Math.ceil(boundingBox.topY),
width: Math.ceil(boundingBox.width),
height: Math.ceil(boundingBox.height)
}
const margin = options.margin;
const availableWidth = Math.floor(view.excalidrawAPI.getAppState().width);
const availableHeight = Math.floor(view.excalidrawAPI.getAppState().height);
// Apply zoom to the total dimensions
const totalWidth = Math.ceil(boundingBox.width * options.zoom + margin * 2);
const totalHeight = Math.ceil(boundingBox.height * options.zoom + margin * 2);
// Calculate number of tiles
const cols = Math.ceil(totalWidth / availableWidth);
const rows = Math.ceil(totalHeight / availableHeight);
// Use exact tile sizes to avoid rounding issues
const tileWidth = Math.ceil(totalWidth / cols);
const tileHeight = Math.ceil(totalHeight / rows);
// Adjust totalWidth and totalHeight to be multiples of tileWidth and tileHeight
const adjustedTotalWidth = tileWidth * cols;
const adjustedTotalHeight = tileHeight * rows;
// Save and set state
const saveState = () => {
const {
scrollX,
scrollY,
zoom,
viewModeEnabled,
linkOpacity,
theme,
} = view.excalidrawAPI.getAppState();
return {
scrollX,
scrollY,
zoom,
viewModeEnabled,
linkOpacity,
theme,
};
}
const restoreState = (st: any) => {
view.updateScene({
appState: {
...st
}
});
}
const savedState = saveState();
// Switch to view mode for layerUIWrapper to be rendered so it can be hidden
view.updateScene({
appState: {
viewModeEnabled: true,
linkOpacity: 0,
theme: options.theme,
},
});
await sleep(50);
// Hide UI elements (must be after changing to view mode)
const container = view.excalidrawWrapperRef.current;
const layerUIWrapper = container.querySelector(".layer-ui__wrapper");
const layerUIWrapperOriginalDisplay = layerUIWrapper.style.display;
layerUIWrapper.style.display = "none";
const originalStyle = {
width: container.style.width,
height: container.style.height,
left: container.style.left,
top: container.style.top,
position: container.style.position,
overflow: container.style.overflow,
};
try {
container.style.width = tileWidth + "px";
container.style.height = tileHeight + "px";
container.style.overflow = "visible";
// Set canvas size and zoom value for capture
view.updateScene({
appState: {
zoom: {
value: options.zoom
},
width: tileWidth,
height: tileHeight
},
});
await sleep(50); // wait for frame to render
// Prepare to collect tile images as data URLs
const rect = container.getBoundingClientRect();
const tiles = [];
for (let row = 0; row < rows; row++) {
for (let col = 0; col < cols; col++) {
// Calculate scroll position for this tile (adjusted for zoom)
const scrollX = boundingBox.topX - margin / options.zoom + (col * tileWidth) / options.zoom;
const scrollY = boundingBox.topY - margin / options.zoom + (row * tileHeight) / options.zoom;
view.updateScene({
appState: {
scrollX: -scrollX,
scrollY: -scrollY,
zoom: {
value: options.zoom
},
width: tileWidth,
height: tileHeight
},
});
await sleep(250);
// Calculate the exact width/height for this tile
const captureWidth = col === cols - 1 ? adjustedTotalWidth - tileWidth * (cols - 1) : tileWidth;
const captureHeight = row === rows - 1 ? adjustedTotalHeight - tileHeight * (rows - 1) : tileHeight;
const image = await remote.getCurrentWebContents().capturePage({
x: rect.left * devicePixelRatio,
y: rect.top * devicePixelRatio,
width: captureWidth * devicePixelRatio,
height: captureHeight * devicePixelRatio,
});
tiles.push({
url: "data:image/png;base64," + image.toPNG().toString("base64"),
width: captureWidth,
height: captureHeight,
col: col,
row: row
});
}
}
// Restore original styles
Object.assign(container.style, originalStyle);
// Stitch tiles together using a browser canvas
const canvas = document.createElement("canvas");
canvas.width = adjustedTotalWidth * devicePixelRatio;
canvas.height = adjustedTotalHeight * devicePixelRatio;
canvas.style.width = `${adjustedTotalWidth}px`;
canvas.style.height = `${adjustedTotalHeight}px`;
const ctx = canvas.getContext("2d");
ctx.scale(1, 1);
ctx.imageSmoothingEnabled = true;
ctx.imageSmoothingQuality = 'high';
let y = 0;
for (let row = 0; row < rows; row++) {
let x = 0;
for (let col = 0; col < cols; col++) {
const tile = tiles[row * cols + col];
const img = new window.Image();
img.src = tile.url;
await new Promise(res => {
img.onload = res;
});
ctx.drawImage(img, x, y);
x += tile.width * devicePixelRatio;
}
y += tiles[row * cols].height * devicePixelRatio; // Use the height of the first tile in the row
}
// Return the blob for the caller to handle
return new Promise<Blob>((resolve) => {
canvas.toBlob((blob) => {
resolve(blob);
}, "image/png");
});
} catch (e) {
console.error(e);
new Notice(t("SCREENSHOT_ERROR"));
return null;
} finally {
// Restore browser zoom to its original value
webContents.setZoomFactor(originalZoomFactor);
// Restore UI elements
try {
const container = view.excalidrawWrapperRef.current;
const layerUIWrapper = container.querySelector(".layer-ui__wrapper");
if (layerUIWrapper) {
layerUIWrapper.style.display = layerUIWrapperOriginalDisplay;
}
// Restore original state
restoreState(savedState);
// Restore opacity for selected elements if necessary
if (options.selectedOnly && savedOpacity.length > 0) {
ea.clear();
ea.copyViewElementsToEAforEditing(ea.getViewElements().filter(el => !selectedIDs.has(el.id)));
savedOpacity.forEach(x => {
ea.getElement(x.id).opacity = x.opacity;
});
await ea.addElementsToView(false, false, false, false);
}
} catch (e) {
console.error("Error in cleanup:", e);
}
}
}
+2 -2
View File
@@ -18,12 +18,12 @@ import {
getContainerElement,
} from "../constants/constants";
import ExcalidrawPlugin from "../core/main";
import { ExcalidrawElement, ExcalidrawImageElement, ExcalidrawTextElement, ImageCrop } from "@zsviczian/excalidraw/types/excalidraw/element/types";
import { ExcalidrawElement, ExcalidrawImageElement, ExcalidrawTextElement, ImageCrop } from "@zsviczian/excalidraw/types/element/src/types";
import { ExportSettings } from "../view/ExcalidrawView";
import { getDataURLFromURL, getIMGFilename, getMimeType, getURLImageExtension } from "./fileUtils";
import { generateEmbeddableLink } from "./customEmbeddableUtils";
import { FILENAMEPARTS } from "../types/utilTypes";
import { Mutable } from "@zsviczian/excalidraw/types/excalidraw/utility-types";
import { Mutable } from "@zsviczian/excalidraw/types/common/src/utility-types";
import { cleanBlockRef, cleanSectionHeading, getFileCSSClasses } from "./obsidianUtils";
import { updateElementLinksToObsidianLinks } from "./excalidrawAutomateUtils";
import { CropImage } from "../shared/CropImage";
+36 -29
View File
@@ -22,7 +22,7 @@ import {
ExcalidrawTextElement,
FileId,
NonDeletedExcalidrawElement,
} from "@zsviczian/excalidraw/types/excalidraw/element/types";
} from "@zsviczian/excalidraw/types/element/src/types";
import {
AppState,
BinaryFileData,
@@ -77,7 +77,6 @@ import {
getExcalidrawMarkdownHeaderSection,
} from "../shared/ExcalidrawData";
import {
arrayBufferToBase64,
checkAndCreateFolder,
createOrOverwriteFile,
download,
@@ -142,7 +141,7 @@ import { getMermaidText, shouldRenderMermaid } from "../utils/mermaidUtils";
import { nanoid } from "nanoid";
import { CustomMutationObserver, DEBUGGING, debug, log} from "../utils/debugHelper";
import { errorHTML, extractCodeBlocks, postOpenAI } from "../utils/AIUtils";
import { Mutable } from "@zsviczian/excalidraw/types/excalidraw/utility-types";
import { Mutable } from "@zsviczian/excalidraw/types/common/src/utility-types";
import { SelectCard } from "../shared/Dialogs/SelectCard";
import { Packages } from "../types/types";
import React from "react";
@@ -152,7 +151,7 @@ import { getPDFCropRect } from "../utils/PDFUtils";
import { Position, ViewSemaphores } from "../types/excalidrawViewTypes";
import { DropManager } from "./managers/DropManager";
import { ImageInfo } from "src/types/excalidrawAutomateTypes";
import { exportToPDF, getMarginValue, getPageDimensions, PageOrientation, PageSize } from "src/utils/exportUtils";
import { exportPNG, exportPNGToClipboard, exportSVG, exportToPDF, getMarginValue, getPageDimensions, PageOrientation, PageSize } from "src/utils/exportUtils";
import { FrameRenderingOptions } from "src/types/utilTypes";
import { CaptureUpdateAction } from "src/constants/constants";
@@ -582,11 +581,7 @@ export default class ExcalidrawView extends TextFileView implements HoverParent{
if (!svg) {
return;
}
download(
null,
svgToBase64(svg.outerHTML),
`${this.file.basename}.svg`,
);
exportSVG(svg, this.file.basename);
}
public async getSVG(embedScene?: boolean, selectedOnly?: boolean):Promise<SVGSVGElement> {
@@ -611,8 +606,10 @@ export default class ExcalidrawView extends TextFileView implements HoverParent{
return;
}
const scene = this.getScene(selectedOnly);
const svg = await this.svg(
this.getScene(selectedOnly),
scene,
undefined,
false,
true
@@ -621,20 +618,26 @@ export default class ExcalidrawView extends TextFileView implements HoverParent{
if (!svg) {
return;
}
const boundingBox = this.plugin.ea.getBoundingBox(scene.elements);
const margin = getMarginValue(this.exportDialog.margin);
const [width, height] = [boundingBox.width, boundingBox.height];
exportToPDF({
SVG: [svg],
scale: {
zoom: this.exportDialog.scale,
fitToPage: this.exportDialog.fitToPage
fitToPage: pageSize === "MATCH IMAGE" || pageSize === "HD Screen"
? 1
: this.exportDialog.fitToPage
},
pageProps: {
dimensions: getPageDimensions(pageSize, orientation),
dimensions: getPageDimensions(pageSize, orientation, {width, height}),
backgroundColor: this.exportDialog.getPaperColor(),
margin: getMarginValue(this.exportDialog.margin),
margin,
alignment: this.exportDialog.alignment,
},
filename: this.file.basename,
filename: this.file.basename+".pdf",
});
}
@@ -678,7 +681,7 @@ export default class ExcalidrawView extends TextFileView implements HoverParent{
if (!png) {
return;
}
await createOrOverwriteFile(this.app, filepath, await png.arrayBuffer());
await createOrOverwriteFile(this.app, filepath, png);
}
if(this.plugin.settings.autoExportLightAndDark) {
@@ -707,11 +710,7 @@ export default class ExcalidrawView extends TextFileView implements HoverParent{
//
// not await so that we can detect whether the thrown error likely relates
// to a lack of support for the Promise ClipboardItem constructor
await navigator.clipboard.write([
new window.ClipboardItem({
"image/png": png,
}),
]);
await exportPNGToClipboard(png);
}
public async exportPNG(embedScene?:boolean, selectedOnly?: boolean):Promise<void> {
@@ -724,12 +723,7 @@ export default class ExcalidrawView extends TextFileView implements HoverParent{
if (!png) {
return;
}
const reader = new FileReader();
reader.readAsDataURL(png);
reader.onloadend = () => {
const base64data = reader.result;
download(null, base64data, `${this.file.basename}.png`);
};
exportPNG(png, this.file.basename);
}
public setPreventReload() {
@@ -749,8 +743,8 @@ export default class ExcalidrawView extends TextFileView implements HoverParent{
public async setEmbeddableNodeIsEditing() {
(process.env.NODE_ENV === 'development') && DEBUGGING && debug(this.setEmbeddableNodeIsEditing, "ExcalidrawView.setEmbeddableNodeIsEditing");
this.clearEmbeddableNodeIsEditingTimer();
await this.forceSave(true);
this.semaphores.embeddableIsEditingSelf = true;
await this.forceSave(true);
}
public clearEmbeddableNodeIsEditingTimer () {
@@ -2769,6 +2763,7 @@ export default class ExcalidrawView extends TextFileView implements HoverParent{
allowWheelZoom: this.plugin.settings.allowWheelZoom,
pinnedScripts: this.plugin.settings.pinnedScripts,
customPens: this.plugin.settings.customPens.slice(0,this.plugin.settings.numberOfCustomPens),
gridDirection: this.plugin.settings.gridSettings.GRID_DIRECTION ?? {horizontal: true, vertical: true},
},
captureUpdate: CaptureUpdateAction.NEVER,
},
@@ -2797,6 +2792,7 @@ export default class ExcalidrawView extends TextFileView implements HoverParent{
allowWheelZoom: this.plugin.settings.allowWheelZoom,
pinnedScripts: this.plugin.settings.pinnedScripts,
customPens: this.plugin.settings.customPens.slice(0,this.plugin.settings.numberOfCustomPens),
gridDirection: this.plugin.settings.gridSettings.GRID_DIRECTION,
},
files: excalidrawData.files,
libraryItems: await this.getLibrary(),
@@ -3738,6 +3734,9 @@ export default class ExcalidrawView extends TextFileView implements HoverParent{
return;
}
const ef = this.excalidrawData.getFile(selectedImgElement.fileId);
if(!ef.file) {
return;
}
if (
(ef.isHyperLink || ef.isLocalLink) || //web images don't have a preview
(IMAGE_TYPES.contains(ef.file.extension)) || //images don't have a preview
@@ -3939,6 +3938,13 @@ export default class ExcalidrawView extends TextFileView implements HoverParent{
window.setTimeout(()=>this.updateScene({appState:{gridColor: this.getGridColor(canvasColor, st)}, captureUpdate: CaptureUpdateAction.NEVER}));
}
public updateGridDirection(gridDirection: {horizontal: boolean, vertical: boolean}) {
window.setTimeout(()=>this.updateScene({appState:{gridDirection: {
horizontal: gridDirection.horizontal,
vertical: gridDirection.vertical}
}, captureUpdate: CaptureUpdateAction.NEVER}));
}
private canvasColorChangeHook(st: AppState) {
(process.env.NODE_ENV === 'development') && DEBUGGING && debug(this.canvasColorChangeHook, "ExcalidrawView.canvasColorChangeHook", st);
const canvasColor = st.viewBackgroundColor === "transparent" ? "white" : st.viewBackgroundColor;
@@ -4552,6 +4558,7 @@ export default class ExcalidrawView extends TextFileView implements HoverParent{
public async insertBackOfTheNoteCard() {
(process.env.NODE_ENV === 'development') && DEBUGGING && debug(this.insertBackOfTheNoteCard, "ExcalidrawView.insertBackOfTheNoteCard");
await this.forceSave(true);
const sections = await this.getBackOfTheNoteSections();
const selectCardDialog = new SelectCard(this.app,this,sections);
selectCardDialog.start();
@@ -5481,7 +5488,7 @@ export default class ExcalidrawView extends TextFileView implements HoverParent{
libraryReturnUrl: "app://obsidian.md",
autoFocus: true,
langCode: obsidianToExcalidrawMap[this.plugin.locale]??"en-EN",
aiEnabled: true,
aiEnabled: this.plugin.settings.aiEnabled??true,
onChange: this.onChange.bind(this),
onLibraryChange: this.onLibraryChange.bind(this),
renderTopRightUI: this.renderTopRightUI.bind(this), //(isMobile: boolean, appState: AppState) => this.obsidianMenu.renderButton (isMobile, appState),
+1 -1
View File
@@ -1,4 +1,4 @@
import { NonDeletedExcalidrawElement } from "@zsviczian/excalidraw/types/excalidraw/element/types";
import { NonDeletedExcalidrawElement } from "@zsviczian/excalidraw/types/element/src/types";
import ExcalidrawView from "src/view/ExcalidrawView";
import { Notice, WorkspaceLeaf, WorkspaceSplit } from "obsidian";
import * as React from "react";
@@ -1,7 +1,7 @@
import { TFile } from "obsidian";
import * as React from "react";
import ExcalidrawView from "../../ExcalidrawView";
import { ExcalidrawElement, ExcalidrawEmbeddableElement } from "@zsviczian/excalidraw/types/excalidraw/element/types";
import { ExcalidrawElement, ExcalidrawEmbeddableElement } from "@zsviczian/excalidraw/types/element/src/types";
import { AppState, ExcalidrawImperativeAPI } from "@zsviczian/excalidraw/types/excalidraw/types";
import { ActionButton } from "./ActionButton";
import { ICONS } from "../../../constants/actionIcons";