mirror of
https://github.com/zsviczian/obsidian-excalidraw-plugin.git
synced 2025-08-06 05:46:28 +00:00
Compare commits
30 Commits
2.5.1-beta
...
2.6.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
854eafaf91 | ||
|
|
ee89b80ce1 | ||
|
|
3e6200ac7e | ||
|
|
ee9364b645 | ||
|
|
5bbe66900e | ||
|
|
a775a858c7 | ||
|
|
2dab801ff5 | ||
|
|
07f8a87580 | ||
|
|
91be6e2a2f | ||
|
|
5c709588dd | ||
|
|
19a46e5b11 | ||
|
|
e132d4a9fc | ||
|
|
cf2d9bea24 | ||
|
|
09cbffed1e | ||
|
|
368de8c1f4 | ||
|
|
7dcf9173c2 | ||
|
|
eac312c3a2 | ||
|
|
7a420a9d2d | ||
|
|
7cac94bf2f | ||
|
|
43e98db174 | ||
|
|
253575bf23 | ||
|
|
7a08ced65a | ||
|
|
5a64e1c75e | ||
|
|
fc0ac92dd3 | ||
|
|
4e2d7eb637 | ||
|
|
f8f280c7d5 | ||
|
|
00b87f99c0 | ||
|
|
0b5c74dde8 | ||
|
|
906b3bdf92 | ||
|
|
a5771625df |
17
README.md
17
README.md
@@ -2,7 +2,7 @@
|
||||
|
||||
[简体中文](./docs/zh-cn/README.md)
|
||||
|
||||
👉👉👉 Check out and contribute to the new [Obsidian-Excalidraw Community Wiki](https://excalidraw-obsidian.online/Hobbies/Excalidraw+Blog/WIKI/Welcome+to+the+WIKI)
|
||||
👉👉👉 Check out and contribute to the new [Obsidian-Excalidraw Community Wiki](https://excalidraw-obsidian.online/WIKI/Welcome+to+the+WIKI)
|
||||
|
||||
The Obsidian-Excalidraw plugin integrates [Excalidraw](https://excalidraw.com/), a feature rich sketching tool, into Obsidian. You can store and edit Excalidraw files in your vault, you can embed drawings into your documents, and you can link to documents and other drawings to/and from Excalidraw. For a showcase of Excalidraw features, please read my blog post [here](https://www.zsolt.blog/2021/03/showcasing-excalidraw.html) and/or watch the videos below.
|
||||
|
||||
@@ -100,15 +100,17 @@ Plugin settings are grouped into the following sections:
|
||||
|
||||
#### Templates
|
||||
|
||||
- Template for new drawings. The template will restore stroke properties. This means you can set up defaults in your template for stroke color, stroke width, opacity, font family, font size, fill style, stroke style, etc. This also applies to ExcalidrawAutomate.
|
||||
- Template for new drawings. The template will restore stroke properties. This means you can set up defaults in your template for stroke color, stroke width, opacity, font family, font size, fill style, stroke style, etc. This also applies to ExcalidrawAutomate. With versions 1.6.13 or higher make sure to enable "Decompress Excalidraw JSON in Markdown View" in the settings before editing the JSON in the template. This can be disabled after the canges are performed.
|
||||
- Via the template, you can customize the color palette used by Excalidraw.
|
||||
- Switch to Markdown view.
|
||||
- Scroll down to the bottom of the file and find `"AppState": {`.
|
||||
- Find `"customColorPalette": {` at the end of the AppState section.
|
||||
- You may specify the 3 palettes used in Excalidraw by adding any or all of the following 3 variables:
|
||||
- `"canvasBackground":[], "elementBackground":[], "elementStroke": []`.
|
||||
- Add a comma-separated list of valid HTML colors (e.g. `#FF0000` for red).
|
||||
in the array for each of the variables.
|
||||
- Find `"colorPalette": {` at the end of the AppState section.
|
||||
- You may specify the 3 palettes used in Excalidraw by adding any or all of the following 3 variables:
|
||||
- `"canvasBackground":[], "elementBackground":[], "elementStroke": []`.
|
||||
- Add a comma-separated list of valid HTML colors (e.g. `#FF0000` for red) in the array for each of the variables.
|
||||
- To change the previewed colors, a `"topPicks": {` may be specified containing the same three keys:
|
||||
- `"canvasBackground":[], "elementBackground":[], "elementStroke": []`.
|
||||
- Note that the corresponding arrays must contain 5 elements.
|
||||
- See my videos above for further help.
|
||||
|
||||
#### Export
|
||||
@@ -227,6 +229,7 @@ For more details, see this [video](https://youtu.be/yZQoJg2RCKI)
|
||||
- `excalidraw-export-dark`: true == Dark mode / false == light mode.
|
||||
- `excalidraw-export-padding`: Specify the export padding for the image.
|
||||
- `excalidraw-export-pngscale`: This only affects export to PNG. Specify the export scale for the image. The typical range is between 0.5 and 5, but you can experiment with other values as well.
|
||||
- Since 1.6.13, enable "Decompress Excalidraw JSON in Markdown View" in the settings if you want to change any JSON content.
|
||||
|
||||
### Embed complete markdown files into your drawings
|
||||
|
||||
|
||||
BIN
assets/excalidraw-fonts.zip
Normal file
BIN
assets/excalidraw-fonts.zip
Normal file
Binary file not shown.
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"id": "obsidian-excalidraw-plugin",
|
||||
"name": "Excalidraw",
|
||||
"version": "2.5.1-beta-2",
|
||||
"version": "2.6.0",
|
||||
"minAppVersion": "1.1.6",
|
||||
"description": "An Obsidian plugin to edit and view Excalidraw drawings",
|
||||
"author": "Zsolt Viczian",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"id": "obsidian-excalidraw-plugin",
|
||||
"name": "Excalidraw",
|
||||
"version": "2.5.0",
|
||||
"version": "2.6.0",
|
||||
"minAppVersion": "1.1.6",
|
||||
"description": "An Obsidian plugin to edit and view Excalidraw drawings",
|
||||
"author": "Zsolt Viczian",
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@popperjs/core": "^2.11.8",
|
||||
"@zsviczian/excalidraw": "0.17.1-obsidian-55",
|
||||
"@zsviczian/excalidraw": "0.17.6-7",
|
||||
"chroma-js": "^2.4.2",
|
||||
"clsx": "^2.0.0",
|
||||
"@zsviczian/colormaster": "^1.2.2",
|
||||
@@ -34,7 +34,8 @@
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"roughjs": "^4.5.2",
|
||||
"woff2sfnt-sfnt2woff": "^1.0.0"
|
||||
"woff2sfnt-sfnt2woff": "^1.0.0",
|
||||
"es6-promise-pool": "2.5.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.22.9",
|
||||
|
||||
@@ -8,6 +8,7 @@ import fs from 'fs';
|
||||
import LZString from 'lz-string';
|
||||
import postprocess from '@zsviczian/rollup-plugin-postprocess';
|
||||
import cssnano from 'cssnano';
|
||||
import jsesc from 'jsesc';
|
||||
|
||||
// Load environment variables
|
||||
import dotenv from 'dotenv';
|
||||
@@ -16,7 +17,7 @@ dotenv.config();
|
||||
const DIST_FOLDER = 'dist';
|
||||
const isProd = (process.env.NODE_ENV === "production");
|
||||
const isLib = (process.env.NODE_ENV === "lib");
|
||||
console.log(`Running: ${process.env.NODE_ENV}`);
|
||||
console.log(`Running: ${process.env.NODE_ENV}; isProd: ${isProd}; isLib: ${isLib}`);
|
||||
|
||||
const excalidraw_pkg = isLib ? "" : isProd
|
||||
? fs.readFileSync("./node_modules/@zsviczian/excalidraw/dist/excalidraw.production.min.js", "utf8")
|
||||
@@ -52,11 +53,13 @@ if (!isLib) console.log(manifest.version);
|
||||
const packageString = isLib
|
||||
? ""
|
||||
: ';' + lzstring_pkg +
|
||||
'\nlet EXCALIDRAW_PACKAGES = LZString.decompressFromBase64("' + LZString.compressToBase64(react_pkg + reactdom_pkg + excalidraw_pkg) + '");\n' +
|
||||
'let {react, reactDOM, excalidrawLib} = window.eval.call(window, `(function() {' +
|
||||
'${EXCALIDRAW_PACKAGES};' +
|
||||
'return {react: React, reactDOM: ReactDOM, excalidrawLib: ExcalidrawLib};})();`);\n' +
|
||||
'let PLUGIN_VERSION="' + manifest.version + '";';
|
||||
'\nlet REACT_PACKAGES = `' +
|
||||
jsesc(react_pkg + reactdom_pkg, { quotes: 'backtick' }) +
|
||||
'`;\n' +
|
||||
'let EXCALIDRAW_PACKAGE = ""; const unpackExcalidraw = () => {EXCALIDRAW_PACKAGE = LZString.decompressFromBase64("' + LZString.compressToBase64(excalidraw_pkg) + '");};\n' +
|
||||
'let {react, reactDOM } = window.eval.call(window, `(function() {' + '${REACT_PACKAGES};' + 'return {react: React, reactDOM: ReactDOM};})();`);\n' +
|
||||
`let excalidrawLib = {};\n` +
|
||||
'let PLUGIN_VERSION="' + manifest.version + '";';
|
||||
|
||||
const BASE_CONFIG = {
|
||||
input: 'src/main.ts',
|
||||
|
||||
@@ -36,6 +36,8 @@ import {
|
||||
isMaskFile,
|
||||
getEmbeddedFilenameParts,
|
||||
cropCanvas,
|
||||
promiseTry,
|
||||
PromisePool,
|
||||
} from "./utils/Utils";
|
||||
import { ValueOf } from "./types/types";
|
||||
import { getMermaidImageElements, getMermaidText, shouldRenderMermaid } from "./utils/MermaidUtils";
|
||||
@@ -606,126 +608,169 @@ export class EmbeddedFilesLoader {
|
||||
this.isDark = excalidrawData?.scene?.appState?.theme === "dark";
|
||||
}
|
||||
let entry: IteratorResult<[FileId, EmbeddedFile]>;
|
||||
const files: FileData[] = [];
|
||||
while (!this.terminate && !(entry = entries.next()).done) {
|
||||
if(fileIDWhiteList && !fileIDWhiteList.has(entry.value[0])) continue;
|
||||
const embeddedFile: EmbeddedFile = entry.value[1];
|
||||
if (!embeddedFile.isLoaded(this.isDark)) {
|
||||
//debug({where:"EmbeddedFileLoader.loadSceneFiles",uid:this.uid,status:"embedded Files are not loaded"});
|
||||
const data = await this._getObsidianImage(embeddedFile, depth);
|
||||
if (data) {
|
||||
const fileData: FileData = {
|
||||
mimeType: data.mimeType,
|
||||
id: entry.value[0],
|
||||
dataURL: data.dataURL,
|
||||
created: data.created,
|
||||
size: data.size,
|
||||
hasSVGwithBitmap: data.hasSVGwithBitmap,
|
||||
shouldScale: embeddedFile.shouldScale()
|
||||
};
|
||||
try {
|
||||
addFiles([fileData], this.isDark, false);
|
||||
}
|
||||
catch(e) {
|
||||
errorlog({ where: "EmbeddedFileLoader.loadSceneFiles", error: e });
|
||||
}
|
||||
//files.push(fileData);
|
||||
}
|
||||
} else if (embeddedFile.isSVGwithBitmap && (depth !== 0 || isThemeChange)) {
|
||||
//this will reload the image in light/dark mode when switching themes
|
||||
const fileData = {
|
||||
mimeType: embeddedFile.mimeType,
|
||||
id: entry.value[0],
|
||||
dataURL: embeddedFile.getImage(this.isDark) as DataURL,
|
||||
created: embeddedFile.mtime,
|
||||
size: embeddedFile.size,
|
||||
hasSVGwithBitmap: embeddedFile.isSVGwithBitmap,
|
||||
shouldScale: embeddedFile.shouldScale()
|
||||
};
|
||||
//files.push(fileData);
|
||||
try {
|
||||
addFiles([fileData], this.isDark, false);
|
||||
}
|
||||
catch(e) {
|
||||
errorlog({ where: "EmbeddedFileLoader.loadSceneFiles", error: e });
|
||||
}
|
||||
}
|
||||
}
|
||||
const files: FileData[][] = [];
|
||||
files.push([]);
|
||||
let batch = 0;
|
||||
|
||||
let equation;
|
||||
const equations = excalidrawData.getEquationEntries();
|
||||
while (!this.terminate && !(equation = equations.next()).done) {
|
||||
if(fileIDWhiteList && !fileIDWhiteList.has(equation.value[0])) continue;
|
||||
if (!excalidrawData.getEquation(equation.value[0]).isLoaded) {
|
||||
const latex = equation.value[1].latex;
|
||||
const data = await tex2dataURL(latex);
|
||||
if (data) {
|
||||
const fileData = {
|
||||
mimeType: data.mimeType,
|
||||
id: equation.value[0],
|
||||
dataURL: data.dataURL,
|
||||
created: data.created,
|
||||
size: data.size,
|
||||
hasSVGwithBitmap: false,
|
||||
shouldScale: true
|
||||
};
|
||||
files.push(fileData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(shouldRenderMermaid()) {
|
||||
const mermaidElements = getMermaidImageElements(excalidrawData.scene.elements);
|
||||
for(const element of mermaidElements) {
|
||||
if(this.terminate) {
|
||||
continue;
|
||||
}
|
||||
const data = getMermaidText(element);
|
||||
const result = await mermaidToExcalidraw(data, {fontSize: 20}, true);
|
||||
if(!result) {
|
||||
continue;
|
||||
}
|
||||
if(result?.files) {
|
||||
for (const key in result.files) {
|
||||
function* loadIterator():Generator<Promise<void>> {
|
||||
while (!(entry = entries.next()).done) {
|
||||
if(fileIDWhiteList && !fileIDWhiteList.has(entry.value[0])) continue;
|
||||
const embeddedFile: EmbeddedFile = entry.value[1];
|
||||
const id = entry.value[0];
|
||||
yield promiseTry(async () => {
|
||||
if(this.terminate) {
|
||||
return;
|
||||
}
|
||||
if (!embeddedFile.isLoaded(this.isDark)) {
|
||||
//debug({where:"EmbeddedFileLoader.loadSceneFiles",uid:this.uid,status:"embedded Files are not loaded"});
|
||||
const data = await this._getObsidianImage(embeddedFile, depth);
|
||||
if (data) {
|
||||
const fileData: FileData = {
|
||||
mimeType: data.mimeType,
|
||||
id: id,
|
||||
dataURL: data.dataURL,
|
||||
created: data.created,
|
||||
size: data.size,
|
||||
hasSVGwithBitmap: data.hasSVGwithBitmap,
|
||||
shouldScale: embeddedFile.shouldScale()
|
||||
};
|
||||
files[batch].push(fileData);
|
||||
/* try {
|
||||
addFiles([fileData], this.isDark, false);
|
||||
}
|
||||
catch(e) {
|
||||
errorlog({ where: "EmbeddedFileLoader.loadSceneFiles", error: e });
|
||||
}*/
|
||||
}
|
||||
} else if (embeddedFile.isSVGwithBitmap && (depth !== 0 || isThemeChange)) {
|
||||
//this will reload the image in light/dark mode when switching themes
|
||||
const fileData = {
|
||||
...result.files[key],
|
||||
id: element.fileId,
|
||||
created: Date.now(),
|
||||
hasSVGwithBitmap: false,
|
||||
shouldScale: true,
|
||||
size: await getImageSize(result.files[key].dataURL),
|
||||
mimeType: embeddedFile.mimeType,
|
||||
id: id,
|
||||
dataURL: embeddedFile.getImage(this.isDark) as DataURL,
|
||||
created: embeddedFile.mtime,
|
||||
size: embeddedFile.size,
|
||||
hasSVGwithBitmap: embeddedFile.isSVGwithBitmap,
|
||||
shouldScale: embeddedFile.shouldScale()
|
||||
};
|
||||
files.push(fileData);
|
||||
files[batch].push(fileData);
|
||||
/* try {
|
||||
addFiles([fileData], this.isDark, false);
|
||||
}
|
||||
catch(e) {
|
||||
errorlog({ where: "EmbeddedFileLoader.loadSceneFiles", error: e });
|
||||
}*/
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if(result?.elements) {
|
||||
//handle case that mermaidToExcalidraw has implemented this type of diagram in the mean time
|
||||
const res = await this.getExcalidrawSVG({
|
||||
isDark: this.isDark,
|
||||
file: null,
|
||||
depth,
|
||||
inFile: null,
|
||||
hasSVGwithBitmap: false,
|
||||
elements: result.elements
|
||||
});
|
||||
if(res?.dataURL) {
|
||||
const size = await getImageSize(res.dataURL);
|
||||
const fileData:FileData = {
|
||||
mimeType: "image/svg+xml",
|
||||
id: element.fileId,
|
||||
dataURL: res.dataURL,
|
||||
created: Date.now(),
|
||||
hasSVGwithBitmap: res.hasSVGwithBitmap,
|
||||
size,
|
||||
shouldScale: true,
|
||||
};
|
||||
files.push(fileData);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
let equationItem;
|
||||
const equations = excalidrawData.getEquationEntries();
|
||||
while (!(equationItem = equations.next()).done) {
|
||||
if(fileIDWhiteList && !fileIDWhiteList.has(equationItem.value[0])) continue;
|
||||
const equation = equationItem.value[1];
|
||||
const id = equationItem.value[0];
|
||||
yield promiseTry(async () => {
|
||||
if (this.terminate) {
|
||||
return;
|
||||
}
|
||||
if (!excalidrawData.getEquation(id).isLoaded) {
|
||||
const latex = equation.latex;
|
||||
const data = await tex2dataURL(latex);
|
||||
if (data) {
|
||||
const fileData = {
|
||||
mimeType: data.mimeType,
|
||||
id: id,
|
||||
dataURL: data.dataURL,
|
||||
created: data.created,
|
||||
size: data.size,
|
||||
hasSVGwithBitmap: false,
|
||||
shouldScale: true
|
||||
};
|
||||
files[batch].push(fileData);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if(shouldRenderMermaid()) {
|
||||
const mermaidElements = getMermaidImageElements(excalidrawData.scene.elements);
|
||||
for(const element of mermaidElements) {
|
||||
yield promiseTry(async () => {
|
||||
if(this.terminate) {
|
||||
return;
|
||||
}
|
||||
const data = getMermaidText(element);
|
||||
const result = await mermaidToExcalidraw(data, {fontSize: 20}, true);
|
||||
if(!result) {
|
||||
return;
|
||||
}
|
||||
if(result?.files) {
|
||||
for (const key in result.files) {
|
||||
const fileData = {
|
||||
...result.files[key],
|
||||
id: element.fileId,
|
||||
created: Date.now(),
|
||||
hasSVGwithBitmap: false,
|
||||
shouldScale: true,
|
||||
size: await getImageSize(result.files[key].dataURL),
|
||||
};
|
||||
files[batch].push(fileData);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if(result?.elements) {
|
||||
//handle case that mermaidToExcalidraw has implemented this type of diagram in the mean time
|
||||
if (this.terminate) {
|
||||
return;
|
||||
}
|
||||
const res = await this.getExcalidrawSVG({
|
||||
isDark: this.isDark,
|
||||
file: null,
|
||||
depth,
|
||||
inFile: null,
|
||||
hasSVGwithBitmap: false,
|
||||
elements: result.elements
|
||||
});
|
||||
if(res?.dataURL) {
|
||||
const size = await getImageSize(res.dataURL);
|
||||
const fileData:FileData = {
|
||||
mimeType: "image/svg+xml",
|
||||
id: element.fileId,
|
||||
dataURL: res.dataURL,
|
||||
created: Date.now(),
|
||||
hasSVGwithBitmap: res.hasSVGwithBitmap,
|
||||
size,
|
||||
shouldScale: true,
|
||||
};
|
||||
files[batch].push(fileData);
|
||||
}
|
||||
return;
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
const addFilesTimer = setInterval(() => {
|
||||
if(files[batch].length === 0) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
addFiles(files[batch], this.isDark, false);
|
||||
}
|
||||
catch(e) {
|
||||
errorlog({ where: "EmbeddedFileLoader.loadSceneFiles", error: e });
|
||||
}
|
||||
files.push([]);
|
||||
batch++;
|
||||
}, 1200);
|
||||
|
||||
const iterator = loadIterator.bind(this)();
|
||||
const concurency = 5;
|
||||
await new PromisePool(iterator, concurency).all();
|
||||
|
||||
clearInterval(addFilesTimer);
|
||||
|
||||
this.emptyPDFDocsMap();
|
||||
if (this.terminate) {
|
||||
@@ -734,7 +779,7 @@ export class EmbeddedFilesLoader {
|
||||
//debug({where:"EmbeddedFileLoader.loadSceneFiles",uid:this.uid,status:"add Files"});
|
||||
try {
|
||||
//in try block because by the time files are loaded the user may have closed the view
|
||||
addFiles(files, this.isDark, true);
|
||||
addFiles(files[batch], this.isDark, true);
|
||||
} catch (e) {
|
||||
errorlog({ where: "EmbeddedFileLoader.loadSceneFiles", error: e });
|
||||
}
|
||||
|
||||
@@ -93,6 +93,7 @@ import { EXCALIDRAW_AUTOMATE_INFO, EXCALIDRAW_SCRIPTENGINE_INFO } from "./dialog
|
||||
import { addBackOfTheNoteCard, getFrameBasedOnFrameNameOrId } from "./utils/ExcalidrawViewUtils";
|
||||
import { log } from "./utils/DebugHelper";
|
||||
import { ExcalidrawLib } from "./ExcalidrawLib";
|
||||
import { GlobalPoint } from "@zsviczian/excalidraw/types/math/types";
|
||||
|
||||
extendPlugins([
|
||||
HarmonyPlugin,
|
||||
@@ -1402,8 +1403,8 @@ export class ExcalidrawAutomate {
|
||||
): string {
|
||||
const box = getLineBox(points);
|
||||
id = id ?? nanoid();
|
||||
const startPoint = points[0];
|
||||
const endPoint = points[points.length - 1];
|
||||
const startPoint = points[0] as GlobalPoint;
|
||||
const endPoint = points[points.length - 1] as GlobalPoint;
|
||||
this.elementsDict[id] = {
|
||||
points: normalizeLinePoints(points),
|
||||
lastCommittedPoint: null,
|
||||
@@ -1693,8 +1694,8 @@ export class ExcalidrawAutomate {
|
||||
if (!connectionA) {
|
||||
const intersect = intersectElementWithLine(
|
||||
elA,
|
||||
[bCenterX, bCenterY],
|
||||
[aCenterX, aCenterY],
|
||||
[bCenterX, bCenterY] as GlobalPoint,
|
||||
[aCenterX, aCenterY] as GlobalPoint,
|
||||
GAP,
|
||||
);
|
||||
if (intersect.length === 0) {
|
||||
@@ -1707,8 +1708,8 @@ export class ExcalidrawAutomate {
|
||||
if (!connectionB) {
|
||||
const intersect = intersectElementWithLine(
|
||||
elB,
|
||||
[aCenterX, aCenterY],
|
||||
[bCenterX, bCenterY],
|
||||
[aCenterX, aCenterY] as GlobalPoint,
|
||||
[bCenterX, bCenterY] as GlobalPoint,
|
||||
GAP,
|
||||
);
|
||||
if (intersect.length === 0) {
|
||||
@@ -2421,7 +2422,12 @@ export class ExcalidrawAutomate {
|
||||
b: readonly [number, number],
|
||||
gap?: number,
|
||||
): Point[] {
|
||||
return intersectElementWithLine(element, a, b, gap);
|
||||
return intersectElementWithLine(
|
||||
element,
|
||||
a as GlobalPoint,
|
||||
b as GlobalPoint,
|
||||
gap
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -2878,11 +2884,11 @@ function getFontFamily(id: number):string {
|
||||
}
|
||||
|
||||
export async function initFonts():Promise<void> {
|
||||
await excalidrawLib.registerFontsInCSS();
|
||||
/*await excalidrawLib.registerFontsInCSS();
|
||||
const fonts = excalidrawLib.getFontFamilies();
|
||||
for(let i=0;i<fonts.length;i++) {
|
||||
if(fonts[i] !== "Local Font") await (document as any).fonts.load(`16px ${fonts[i]}`);
|
||||
};
|
||||
};*/
|
||||
}
|
||||
|
||||
export function _measureText(
|
||||
|
||||
@@ -17,6 +17,7 @@ import {
|
||||
FRONTMATTER_KEYS,
|
||||
refreshTextDimensions,
|
||||
getContainerElement,
|
||||
loadSceneFonts,
|
||||
} from "./constants/constants";
|
||||
import ExcalidrawPlugin from "./main";
|
||||
import { TextMode } from "./ExcalidrawView";
|
||||
@@ -52,6 +53,8 @@ import { DEBUGGING, debug } from "./utils/DebugHelper";
|
||||
import { Mutable } from "@zsviczian/excalidraw/types/excalidraw/utility-types";
|
||||
import { updateElementIdsInScene } from "./utils/ExcalidrawSceneUtils";
|
||||
import { getNewUniqueFilepath } from "./utils/FileUtils";
|
||||
import { t } from "./lang/helpers";
|
||||
import { displayFontMessage } from "./utils/ExcalidrawViewUtils";
|
||||
|
||||
type SceneDataWithFiles = SceneData & { files: BinaryFiles };
|
||||
|
||||
@@ -745,6 +748,15 @@ export class ExcalidrawData {
|
||||
|
||||
this.deletedElements = this.scene.elements.filter((el:ExcalidrawElement)=>el.isDeleted);
|
||||
this.scene.elements = this.scene.elements.filter((el:ExcalidrawElement)=>!el.isDeleted);
|
||||
|
||||
const timer = window.setTimeout(()=>{
|
||||
const notice = new Notice(t("FONT_LOAD_SLOW"),15000);
|
||||
notice.noticeEl.oncontextmenu = () => {
|
||||
displayFontMessage(this.app);
|
||||
}
|
||||
},5000);
|
||||
await loadSceneFonts(this.scene.elements);
|
||||
clearTimeout(timer);
|
||||
|
||||
if (!this.scene.files) {
|
||||
this.scene.files = {}; //loading legacy scenes that do not yet have the files attribute.
|
||||
|
||||
15
src/ExcalidrawLib.d.ts
vendored
15
src/ExcalidrawLib.d.ts
vendored
@@ -3,8 +3,10 @@ import { ImportedDataState } from "@zsviczian/excalidraw/types/excalidraw/data/t
|
||||
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 { FontMetadata } from "@zsviczian/excalidraw/types/excalidraw/fonts/metadata";
|
||||
import { AppState, BinaryFiles, DataURL, GenerateDiagramToCode, Point, Zoom } from "@zsviczian/excalidraw/types/excalidraw/types";
|
||||
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 ExcalidrawPlugin from "./main";
|
||||
|
||||
type EmbeddedLink =
|
||||
| ({
|
||||
@@ -75,16 +77,16 @@ declare namespace ExcalidrawLib {
|
||||
|
||||
function determineFocusDistance(
|
||||
element: ExcalidrawBindableElement,
|
||||
a: Point,
|
||||
b: Point,
|
||||
a: GlobalPoint,
|
||||
b: GlobalPoint,
|
||||
): number;
|
||||
|
||||
function intersectElementWithLine(
|
||||
element: ExcalidrawBindableElement,
|
||||
a: Point,
|
||||
b: Point,
|
||||
a: GlobalPoint,
|
||||
b: GlobalPoint,
|
||||
gap?: number,
|
||||
): Point[];
|
||||
): GlobalPoint[];
|
||||
|
||||
function getCommonBoundingBox(
|
||||
elements: ExcalidrawElement[] | readonly NonDeleted<ExcalidrawElement>[],
|
||||
@@ -186,5 +188,6 @@ declare namespace ExcalidrawLib {
|
||||
separator?: string,
|
||||
): string;
|
||||
function safelyParseJSON (json: string): Record<string, any> | null;
|
||||
function loadSceneFonts(elements: NonDeletedExcalidrawElement[]): Promise<void>;
|
||||
}
|
||||
|
||||
|
||||
@@ -1575,6 +1575,7 @@ export default class ExcalidrawView extends TextFileView implements HoverParent{
|
||||
if(!this.plugin) {
|
||||
return;
|
||||
}
|
||||
await this.plugin.awaitInit();
|
||||
//implemented to overcome issue that activeLeafChangeEventHandler is not called when view is initialized from a saved workspace, since Obsidian 1.6.0
|
||||
let counter = 0;
|
||||
while(counter++<50 && (!Boolean(this?.plugin?.activeLeafChangeEventHandler) || !Boolean(this.canvasNodeFactory))) {
|
||||
@@ -2245,6 +2246,7 @@ export default class ExcalidrawView extends TextFileView implements HoverParent{
|
||||
//I am using last loaded file to control when the view reloads.
|
||||
//It seems text file view gets the modified file event after sync before the modifyEventHandler in main.ts
|
||||
//reload can only be triggered via reload()
|
||||
await this.plugin.awaitInit();
|
||||
if(this.lastLoadedFile === this.file) return;
|
||||
this.isLoaded = false;
|
||||
if(!this.file) return;
|
||||
@@ -2275,6 +2277,7 @@ export default class ExcalidrawView extends TextFileView implements HoverParent{
|
||||
if(!this?.app) {
|
||||
return;
|
||||
}
|
||||
await this.plugin.awaitInit();
|
||||
let counter = 0;
|
||||
while ((!this.file || !this.plugin.fourthFontLoaded) && counter++<50) await sleep(50);
|
||||
if(!this.file) return;
|
||||
@@ -2745,6 +2748,8 @@ export default class ExcalidrawView extends TextFileView implements HoverParent{
|
||||
}
|
||||
if(!DEVICE.isMobile) {
|
||||
if(requireApiVersion("0.16.0")) {
|
||||
//@ts-ignore
|
||||
this.leaf.tabHeaderInnerIconEl.style.color="var(--color-accent)"
|
||||
//@ts-ignore
|
||||
this.leaf.tabHeaderInnerTitleEl.style.color="var(--color-accent)"
|
||||
}
|
||||
@@ -2773,6 +2778,8 @@ export default class ExcalidrawView extends TextFileView implements HoverParent{
|
||||
this.actionButtons['save'].querySelector("svg").removeClass("excalidraw-dirty");
|
||||
if(!DEVICE.isMobile) {
|
||||
if(requireApiVersion("0.16.0")) {
|
||||
//@ts-ignore
|
||||
this.leaf.tabHeaderInnerIconEl.style.color=""
|
||||
//@ts-ignore
|
||||
this.leaf.tabHeaderInnerTitleEl.style.color=""
|
||||
}
|
||||
@@ -3444,7 +3451,7 @@ export default class ExcalidrawView extends TextFileView implements HoverParent{
|
||||
toDelete.forEach((k) => delete files[k]);
|
||||
}
|
||||
|
||||
const activeTool = st.activeTool;
|
||||
const activeTool = {...st.activeTool};
|
||||
if(!["freedraw","hand"].includes(activeTool.type)) {
|
||||
activeTool.type = "selection";
|
||||
}
|
||||
@@ -3847,12 +3854,14 @@ export default class ExcalidrawView extends TextFileView implements HoverParent{
|
||||
return;
|
||||
}
|
||||
|
||||
//dobule click
|
||||
const now = Date.now();
|
||||
if ((now - this.doubleClickTimestamp) < 600 && (now - this.doubleClickTimestamp) > 40) {
|
||||
this.identifyElementClicked();
|
||||
if(this.plugin.settings.doubleClickLinkOpenViewMode) {
|
||||
//dobule click
|
||||
const now = Date.now();
|
||||
if ((now - this.doubleClickTimestamp) < 600 && (now - this.doubleClickTimestamp) > 40) {
|
||||
this.identifyElementClicked();
|
||||
}
|
||||
this.doubleClickTimestamp = now;
|
||||
}
|
||||
this.doubleClickTimestamp = now;
|
||||
return;
|
||||
}
|
||||
if (p.button === "up") {
|
||||
@@ -5847,7 +5856,6 @@ export default class ExcalidrawView extends TextFileView implements HoverParent{
|
||||
renderWebview: DEVICE.isDesktop,
|
||||
renderEmbeddable: this.renderEmbeddable.bind(this),
|
||||
renderMermaid: shouldRenderMermaid,
|
||||
obsidianHostPlugin: new WeakRef(this.plugin),
|
||||
showDeprecatedFonts: true,
|
||||
},
|
||||
this.renderCustomActionsMenu(),
|
||||
@@ -5870,6 +5878,7 @@ export default class ExcalidrawView extends TextFileView implements HoverParent{
|
||||
}
|
||||
) {
|
||||
(process.env.NODE_ENV === 'development') && DEBUGGING && debug(this.instantiateExcalidraw, "ExcalidrawView.instantiateExcalidraw", initdata);
|
||||
await this.plugin.awaitInit();
|
||||
while(!this.semaphores.scriptsReady) {
|
||||
await sleep(50);
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@ import { FILENAMEPARTS, PreviewImageType } from "./utils/UtilTypes";
|
||||
import { CustomMutationObserver, debug, DEBUGGING } from "./utils/DebugHelper";
|
||||
import { getExcalidrawFileForwardLinks } from "./utils/ExcalidrawViewUtils";
|
||||
import { linkPrompt } from "./dialogs/Prompt";
|
||||
import { isHTMLElement } from "./utils/typechecks";
|
||||
|
||||
interface imgElementAttributes {
|
||||
file?: TFile;
|
||||
@@ -352,7 +353,8 @@ const getIMG = async (
|
||||
);
|
||||
|
||||
const cacheReady = imageCache.isReady();
|
||||
|
||||
|
||||
await plugin.awaitInit();
|
||||
switch (plugin.settings.previewImageType) {
|
||||
case PreviewImageType.PNG: {
|
||||
const img = createEl("img");
|
||||
@@ -405,12 +407,13 @@ const createImgElement = async (
|
||||
|
||||
let timer:number;
|
||||
const clickEvent = (ev:PointerEvent) => {
|
||||
if(!(ev.target instanceof Element)) {
|
||||
if (!isHTMLElement(ev.target)) {
|
||||
return;
|
||||
}
|
||||
const containerElement = ev.target.hasClass("excalidraw-embedded-img")
|
||||
const targetElement = ev.target as HTMLElement;
|
||||
const containerElement = targetElement.hasClass("excalidraw-embedded-img")
|
||||
? ev.target
|
||||
: getParentOfClass(ev.target, "excalidraw-embedded-img");
|
||||
: getParentOfClass(targetElement, "excalidraw-embedded-img");
|
||||
if (!containerElement) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -82,7 +82,7 @@ export const obsidianToExcalidrawMap: { [key: string]: string } = {
|
||||
};
|
||||
|
||||
|
||||
export const {
|
||||
export let {
|
||||
sceneCoordsToViewportCoords,
|
||||
viewportCoordsToSceneCoords,
|
||||
determineFocusDistance,
|
||||
@@ -103,9 +103,37 @@ export const {
|
||||
getContainerElement,
|
||||
refreshTextDimensions,
|
||||
getCSSFontDefinition,
|
||||
loadSceneFonts,
|
||||
} = excalidrawLib;
|
||||
|
||||
export function updateExcalidrawLib() {
|
||||
({
|
||||
sceneCoordsToViewportCoords,
|
||||
viewportCoordsToSceneCoords,
|
||||
determineFocusDistance,
|
||||
intersectElementWithLine,
|
||||
getCommonBoundingBox,
|
||||
getMaximumGroups,
|
||||
measureText,
|
||||
getLineHeight,
|
||||
wrapText,
|
||||
getFontString,
|
||||
getBoundTextMaxWidth,
|
||||
exportToSvg,
|
||||
exportToBlob,
|
||||
mutateElement,
|
||||
restore,
|
||||
mermaidToExcalidraw,
|
||||
getFontFamilyString,
|
||||
getContainerElement,
|
||||
refreshTextDimensions,
|
||||
getCSSFontDefinition,
|
||||
loadSceneFonts,
|
||||
} = excalidrawLib);
|
||||
}
|
||||
|
||||
export const FONTS_STYLE_ID = "excalidraw-custom-fonts";
|
||||
export const CJK_STYLE_ID = "excalidraw-cjk-fonts";
|
||||
|
||||
export function JSON_parse(x: string): any {
|
||||
return JSON.parse(x.replaceAll("[", "["));
|
||||
|
||||
44
src/dialogs/ExcalidrawLoading.ts
Normal file
44
src/dialogs/ExcalidrawLoading.ts
Normal file
@@ -0,0 +1,44 @@
|
||||
import { FileView, TextFileView, View, WorkspaceLeaf } from "obsidian";
|
||||
import ExcalidrawPlugin from "src/main";
|
||||
import { setExcalidrawView } from "src/utils/ObsidianUtils";
|
||||
|
||||
export default class ExcalidrawLoading extends FileView {
|
||||
constructor(leaf: WorkspaceLeaf, private plugin: ExcalidrawPlugin) {
|
||||
super(leaf);
|
||||
this.switchToeExcalidraw();
|
||||
this.displayLoadingText();
|
||||
}
|
||||
|
||||
public onload() {
|
||||
super.onload();
|
||||
this.displayLoadingText();
|
||||
}
|
||||
|
||||
private async switchToeExcalidraw() {
|
||||
await this.plugin.awaitInit();
|
||||
setExcalidrawView(this.leaf);
|
||||
}
|
||||
|
||||
getViewType(): string {
|
||||
return "excalidra-loading";
|
||||
}
|
||||
|
||||
getDisplayText() {
|
||||
return "Loading Excalidraw... " + (this.file?.basename ?? "");
|
||||
}
|
||||
|
||||
private displayLoadingText() {
|
||||
// Create a div element for displaying the text
|
||||
const loadingTextEl = this.contentEl.createEl("div", {
|
||||
text: this.getDisplayText()
|
||||
});
|
||||
|
||||
// Apply styling to center the text
|
||||
loadingTextEl.style.display = "flex";
|
||||
loadingTextEl.style.alignItems = "center";
|
||||
loadingTextEl.style.justifyContent = "center";
|
||||
loadingTextEl.style.height = "100%";
|
||||
loadingTextEl.style.fontSize = "1.5em"; // Adjust size as needed
|
||||
}
|
||||
|
||||
}
|
||||
@@ -15,7 +15,61 @@ export const RELEASE_NOTES: { [k: string]: string } = {
|
||||
|
||||
I develop this plugin as a hobby, spending my free time doing this. If you find it valuable, then please say THANK YOU or...
|
||||
|
||||
<div class="ex-coffee-div"><a href="https://ko-fi.com/zsolt"><img src="https://cdn.ko-fi.com/cdn/kofi3.png?v=3" height=45></a></div>
|
||||
<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.6.0":`
|
||||
## Performance
|
||||
- Much faster plugin initialization. Down from 1000-3000ms to 100-300ms. According to my testing speed varies on a wide spectrum depending on device, size of Vault and other plugins being loaded. I measured values ranging from 84ms up to 782ms [#2068](https://github.com/zsviczian/obsidian-excalidraw-plugin/issues/2068)
|
||||
- Faster loading of scenes with many embedded illustrations or PDF pages.
|
||||
- SVG export results in even smaller files by further optimizing which characters are included in the embedded fonts. [#8641](https://github.com/excalidraw/excalidraw/pull/8641)
|
||||
|
||||
## New
|
||||
- Image cropping tool. Double click the image to crop it. [#8613](https://github.com/excalidraw/excalidraw/pull/8613)
|
||||
- Single finger panning in pen mode.
|
||||
- Native handwritten CJK Font support [8530](https://github.com/excalidraw/excalidraw/pull/8530)
|
||||
- Created a new **Fonts** section in settings. This includes configuration of the "Local Font" and downloading of the CJK fonts in case you need them offline.
|
||||
- Option under **Appearance and Behavior / Link Click** to disable double-click link navigation in view mode. [#2075](https://github.com/zsviczian/obsidian-excalidraw-plugin/issues/2075)
|
||||
- New RU translation 🙏[@tovBender](https://github.com/tovBender)
|
||||
|
||||
## Updated
|
||||
- CN translation 🙏[@dmscode](https://github.com/dmscode)
|
||||
`,
|
||||
"2.5.2": `
|
||||
## Fixed
|
||||
- Text became disconnected from sticky notes (rectangle/ellipse/diamond + text) if the sticky note contained a link (e.g., URL or wiki link), and in some cases, triggered a save error warning. [#2054](https://github.com/zsviczian/obsidian-excalidraw-plugin/issues/2054)
|
||||
- Long-clicking to open an Excalidraw drawing from a markdown note did not work when the note was in an Obsidian pop-out window.
|
||||
- Active tool was deactivated after autosave, requiring the user to reselect the tool.
|
||||
|
||||
## Minor changes to default settings
|
||||
- I adjusted some of the default settings. This change only affects new installs of Excalidraw; existing installs and settings remain unchanged:
|
||||
- **Reuse Adjacent Pane** is now the default for opening new drawings. Excalidraw will try to open the drawing in the most recently used adjacent pane, if available.
|
||||
- **Focus on Existing Tab** is the default for reopening an already open drawing. Excalidraw will switch to the existing tab where the drawing is open, instead of creating a new one.
|
||||
- **Autosave Interval** is now set to a default value of 1 minute on Desktop and 30 seconds on mobile platforms.
|
||||
`,
|
||||
"2.5.1": `
|
||||
## New
|
||||
- Excalidraw will now save images using the filename from the file system when adding an image via the image tool (in the top toolbar).
|
||||
- Increased the maximum image size from a width/height of 1440 to 2880 when adding an image via the image tool in the top toolbar.
|
||||
- Flip arrowheads: If you have an arrow bound to elements, select only the arrow (not the bound elements) and press SHIFT+H or SHIFT+V to swap the arrowheads. [#8525](https://github.com/excalidraw/excalidraw/pull/8525)
|
||||
|
||||
## Fixed
|
||||
- Zoom
|
||||
- "Zoom to Fit" did not work correctly when multiple Obsidian tabs were open, and Excalidraw was in a lower tab. Additionally, there was an offset when the left side panel was open, especially if the panel was relatively large compared to the canvas area. [#2039](https://github.com/zsviczian/obsidian-excalidraw-plugin/issues/2039)
|
||||
- SHIFT+1 and SHIFT+2 will now honor the max zoom setting in Plugin Settings.
|
||||
- Adding images using the image tool in the toolbar was unreliable. Sometimes it worked, sometimes it didn't, depending on whether the drawing had unsaved changes. Autosave was causing the issue with the image tool. [#1992](https://github.com/zsviczian/obsidian-excalidraw-plugin/issues/1992)
|
||||
- Frame related issues
|
||||
- Fixed an issue where links to the back of the note were broken if an unnamed frame was present in the scene. [#2027](https://github.com/zsviczian/obsidian-excalidraw-plugin/issues/2027)
|
||||
- Frame transclusion was not working when there was a LaTeX equation anywhere in the scene. [#2028](https://github.com/zsviczian/obsidian-excalidraw-plugin/issues/2028)
|
||||
- Frame settings and rounded image corners were not honored when exporting (and auto-exporting) SVGs. [#2026](https://github.com/zsviczian/obsidian-excalidraw-plugin/issues/2026)
|
||||
- Resolved issues with the width, height, and style parsing of Excalidraw drawings embedded in Markdown notes. ${String.fromCharCode(96)}![[my file|10 - my alias]]${String.fromCharCode(96)} was incorrectly parsed as a width of 10 and a style of "- my alias."
|
||||
- Links
|
||||
- When navigating element links, selecting a #tag from the link-list did not open the Obsidian tag in the search.
|
||||
- False-positive tag results in second-order links list.
|
||||
- Arrow label links did not work as expected. Since CTRL/CMD+Click is used in Excalidraw to start the line editor, the solution is not straightforward from a UX perspective. [#2023](https://github.com/zsviczian/obsidian-excalidraw-plugin/issues/2023)
|
||||
- You can open arrow links by ctrl+clicking on the label itself. If the arrow or line element contains the link, ctrl+click on the link indicator in the top right.
|
||||
- You can also right-click the linear element and select "Open Link" from the context menu.
|
||||
- Various elbow-arrow fixes and QoL improvements from excalidraw.com [#8324](https://github.com/excalidraw/excalidraw/pull/8324), [#8448](https://github.com/excalidraw/excalidraw/pull/8448), [#8440](https://github.com/excalidraw/excalidraw/pull/8440)
|
||||
|
||||
`,
|
||||
"2.5.0": `
|
||||
The new [Community Wiki](https://excalidraw-obsidian.online/Hobbies/Excalidraw+Blog/WIKI/Welcome+to+the+WIKI) is waiting for your contribution!
|
||||
|
||||
@@ -5,6 +5,7 @@ import {
|
||||
import { TAG_AUTOEXPORT, TAG_MDREADINGMODE, TAG_PDFEXPORT } from "src/constants/constSettingsTags";
|
||||
import { labelALT, labelCTRL, labelMETA, labelSHIFT } from "src/utils/ModifierkeyHelper";
|
||||
|
||||
const CJK_FONTS = "CJK Fonts";
|
||||
// English
|
||||
export default {
|
||||
// main.ts
|
||||
@@ -97,6 +98,8 @@ export default {
|
||||
RESET_IMG_ASPECT_RATIO: "Reset selected image element aspect ratio",
|
||||
TEMPORARY_DISABLE_AUTOSAVE: "Disable autosave until next time Obsidian starts (only set this if you know what you are doing)",
|
||||
TEMPORARY_ENABLE_AUTOSAVE: "Enable autosave",
|
||||
FONTS_LOADED: "Excalidraw: CJK Fonts loaded",
|
||||
FONTS_LOAD_ERROR: "Excalidraw: Could not find CJK Fonts in the assets folder\n",
|
||||
|
||||
//ExcalidrawView.ts
|
||||
NO_SEARCH_RESULT: "Didn't find a matching element in the drawing",
|
||||
@@ -187,7 +190,7 @@ export default {
|
||||
|
||||
BASIC_HEAD: "Basic",
|
||||
BASIC_DESC: `In the "Basic" settings, you can configure options such as displaying release notes after updates, receiving plugin update notifications, setting the default location for new drawings, specifying the Excalidraw folder for embedding drawings into active documents, defining an Excalidraw template file, and designating an Excalidraw Automate script folder for managing automation scripts.`,
|
||||
FOLDER_NAME: "Excalidraw folder",
|
||||
FOLDER_NAME: "Excalidraw folder (CAsE sEnsITive!)",
|
||||
FOLDER_DESC:
|
||||
"Default location for new drawings. If empty, drawings will be created in the Vault root.",
|
||||
CROP_PREFIX_NAME: "Crop file prefix",
|
||||
@@ -201,10 +204,10 @@ export default {
|
||||
ANNOTATE_PRESERVE_SIZE_NAME: "Preserve image size when annotating",
|
||||
ANNOTATE_PRESERVE_SIZE_DESC:
|
||||
"When annotating an image in markdown the replacment image link will include the width of the original image.",
|
||||
CROP_FOLDER_NAME: "Crop file folder",
|
||||
CROP_FOLDER_NAME: "Crop file folder (CaSE senSItive!)",
|
||||
CROP_FOLDER_DESC:
|
||||
"Default location for new drawings created when cropping an image. If empty, drawings will be created following the Vault attachments settings.",
|
||||
ANNOTATE_FOLDER_NAME: "Image annotation file folder",
|
||||
ANNOTATE_FOLDER_NAME: "Image annotation file folder (CaSe SeNSitIVe!)",
|
||||
ANNOTATE_FOLDER_DESC:
|
||||
"Default location for new drawings created when annotating an image. If empty, drawings will be created following the Vault attachments settings.",
|
||||
FOLDER_EMBED_NAME:
|
||||
@@ -213,7 +216,7 @@ export default {
|
||||
"Define which folder to place the newly inserted drawing into " +
|
||||
"when using the command palette action: 'Create a new drawing and embed into active document'.<br>" +
|
||||
"<b><u>Toggle ON:</u></b> Use Excalidraw folder<br><b><u>Toggle OFF:</u></b> Use the attachments folder defined in Obsidian settings.",
|
||||
TEMPLATE_NAME: "Excalidraw template file or folder",
|
||||
TEMPLATE_NAME: "Excalidraw template file or folder (caSe SenSiTive!)",
|
||||
TEMPLATE_DESC:
|
||||
"Full filepath or folderpath to the Excalidraw template.<br>" +
|
||||
"<b>Template File:</b>E.g.: If your template is in the default Excalidraw folder and its name is " +
|
||||
@@ -431,6 +434,7 @@ FILENAME_HEAD: "Filename",
|
||||
LONG_PRESS_DESKTOP_DESC: "Long press delay in milliseconds to open an Excalidraw Drawing embedded in a Markdown file. ",
|
||||
LONG_PRESS_MOBILE_NAME: "Long press to open mobile",
|
||||
LONG_PRESS_MOBILE_DESC: "Long press delay in milliseconds to open an Excalidraw Drawing embedded in a Markdown file. ",
|
||||
DOUBLE_CLICK_LINK_OPEN_VIEW_MODE: "Allow double-click to open links in view mode",
|
||||
|
||||
FOCUS_ON_EXISTING_TAB_NAME: "Focus on Existing Tab",
|
||||
FOCUS_ON_EXISTING_TAB_DESC: "When opening a link, Excalidraw will focus on the existing tab if the file is already open. " +
|
||||
@@ -747,6 +751,8 @@ FILENAME_HEAD: "Filename",
|
||||
"Enabling this feature simplifies the use of Excalidraw front matter properties, allowing you to leverage many powerful settings. If you prefer not to load these properties automatically, " +
|
||||
"you can disable this feature, but you will need to manually remove any unwanted properties from the suggester. " +
|
||||
"Note that turning on this setting requires restarting the plugin as properties are loaded at startup.",
|
||||
FONTS_HEAD: "Fonts",
|
||||
FONTS_DESC: "Configure local fontfaces and downloaded CJK fonts for Excalidraw.",
|
||||
CUSTOM_FONT_HEAD: "Local font",
|
||||
ENABLE_FOURTH_FONT_NAME: "Enable local font option",
|
||||
ENABLE_FOURTH_FONT_DESC:
|
||||
@@ -760,6 +766,20 @@ FILENAME_HEAD: "Filename",
|
||||
"If no file is selected, Excalidraw will default to the Virgil font. " +
|
||||
"For optimal performance, it is recommended to use a .woff2 file, as Excalidraw will encode only the necessary glyphs when exporting images to SVG. " +
|
||||
"Other font formats will embed the entire font in the exported file, potentially resulting in significantly larger file sizes.",
|
||||
OFFLINE_CJK_NAME: "Offline CJK font support",
|
||||
OFFLINE_CJK_DESC:
|
||||
`<strong>Changes you make here will only take effect after restarting Obsidian.</strong><br>
|
||||
Excalidraw.com offers handwritten CJK fonts. By default these fonts are not included in the plugin locally, but are served from the Internet.
|
||||
If you prefer to keep Excalidraw fully local, allowing it to work without Internet access you can download the necessary <a href="https://github.com/zsviczian/obsidian-excalidraw-plugin/raw/refs/heads/master/assets/excalidraw-fonts.zip" target="_blank">font files from GitHub</a>.
|
||||
After downloading, unzip the contents into a folder within your Vault.<br>
|
||||
Pre-loading fonts will impact startup performance. For this reason you can select which fonts to load.`,
|
||||
CJK_ASSETS_FOLDER_NAME: "CJK Font Folder (cAsE sENsiTIvE!)",
|
||||
CJK_ASSETS_FOLDER_DESC: `You can set the location of the CJK fonts folder here. For example, you may choose to place it under <code>Excalidraw/CJK Fonts</code>.<br><br>
|
||||
<strong>Important:</strong> Do not set this folder to the Vault root! Do not put other fonts in this folder.<br><br>
|
||||
<strong>Note:</strong> If you're using Obsidian Sync and want to synchronize these font files across your devices, ensure that Obsidian Sync is set to synchronize "All other file types".`,
|
||||
LOAD_CHINESE_FONTS_NAME: "Load Chinese fonts from file at startup",
|
||||
LOAD_JAPANESE_FONTS_NAME: "Load Japanese fonts from file at startup",
|
||||
LOAD_KOREAN_FONTS_NAME: "Load Korean fonts frome file at startup",
|
||||
SCRIPT_SETTINGS_HEAD: "Settings for installed Scripts",
|
||||
SCRIPT_SETTINGS_DESC: "Some of the Excalidraw Automate Scripts include settings. Settings are organized by script. Settings will only become visible in this list after you have executed the newly downloaded script once.",
|
||||
TASKBONE_HEAD: "Taskbone Optical Character Recogntion",
|
||||
@@ -816,6 +836,35 @@ FILENAME_HEAD: "Filename",
|
||||
|
||||
//ExcalidrawData.ts
|
||||
LOAD_FROM_BACKUP: "Excalidraw file was corrupted. Loading from backup file.",
|
||||
FONT_LOAD_SLOW: "Loading Fonts...\n\n This is taking longer than expected. If this delay occurs regulary then you may download the fonts locally to your Vault. \n\n" +
|
||||
"(click=dismiss, right-click=Info)",
|
||||
FONT_INFO_TITLE: "Starting v2.5.3 fonts load from the Internet",
|
||||
FONT_INFO_DETAILED: `
|
||||
<p>
|
||||
To improve Obsidian's startup time and manage the large <strong>CJK font family</strong>,
|
||||
I've moved the CJK fonts out of the plugin's <code>main.js</code>. CJK fonts will be loaded from the internet by default.
|
||||
This typically shouldn't cause issues as Obsidian caches these files after first use.
|
||||
</p>
|
||||
<p>
|
||||
If you prefer to keep Obsidian 100% local or experience performance issues, you can download the font assets.
|
||||
</p>
|
||||
<h3>Instructions:</h3>
|
||||
<ol>
|
||||
<li>Download the fonts from <a href="https://github.com/zsviczian/obsidian-excalidraw-plugin/raw/refs/heads/master/assets/excalidraw-fonts.zip">GitHub</a>.</li>
|
||||
<li>Unzip and copy files into a Vault folder (default: <code>Excalidraw/${CJK_FONTS}</code>; folder names are cAse-senSITive).</li>
|
||||
<li><mark>DO NOT</mark> set this folder to the Vault root or mix with other local fonts.</li>
|
||||
</ol>
|
||||
<h3>For Obsidian Sync Users:</h3>
|
||||
<p>
|
||||
Ensure Obsidian Sync is set to synchronize "All other file types" or download and unzip the file on all devices.
|
||||
</p>
|
||||
<h3>Note:</h3>
|
||||
<p>
|
||||
If you find this process cumbersome, please submit a feature request to Obsidian.md for supporting assets in the plugin folder.
|
||||
Currently, only a single <code>main.js</code> is supported, which leads to large files and slow startup times for complex plugins like Excalidraw.
|
||||
I apologize for the inconvenience.
|
||||
</p>
|
||||
`,
|
||||
|
||||
//ObsidianMenu.tsx
|
||||
GOTO_FULLSCREEN: "Goto fullscreen mode",
|
||||
|
||||
@@ -1,3 +1,859 @@
|
||||
// русский
|
||||
import {
|
||||
DEVICE,
|
||||
FRONTMATTER_KEYS,
|
||||
} from "src/constants/constants";
|
||||
import { TAG_AUTOEXPORT, TAG_MDREADINGMODE, TAG_PDFEXPORT } from "src/constants/constSettingsTags";
|
||||
import { labelALT, labelCTRL, labelMETA, labelSHIFT } from "src/utils/ModifierkeyHelper";
|
||||
|
||||
export default {};
|
||||
// русский
|
||||
export default {
|
||||
// main.ts
|
||||
CONVERT_URL_TO_FILE: "Сохранить изображение из URL в локальный файл",
|
||||
UNZIP_CURRENT_FILE: "Распаковать текущий файл Excalidraw",
|
||||
ZIP_CURRENT_FILE: "Сжать текущий файл Excalidraw",
|
||||
PUBLISH_SVG_CHECK: "Obsidian Publish: Поиск устаревших экспортированных SVG и PNG-файлов",
|
||||
EMBEDDABLE_PROPERTIES: "Свойства встраиваемых элементов",
|
||||
EMBEDDABLE_RELATIVE_ZOOM: "Масштабирование выбранных встраиваемых элементов до 100% относительно текущего масштаба холста",
|
||||
OPEN_IMAGE_SOURCE: "Открыть чертеж Excalidraw",
|
||||
INSTALL_SCRIPT: "Установите скрипт",
|
||||
UPDATE_SCRIPT: "Доступно обновление - нажмите для установки",
|
||||
CHECKING_SCRIPT: "Проверка на наличие новой версии - Нажмите для переустановки",
|
||||
UNABLETOCHECK_SCRIPT: "Проверка обновления не удалась - Нажмите, чтобы переустановить",
|
||||
UPTODATE_SCRIPT: "Скрипт обновлен - Нажмите для переустановки",
|
||||
OPEN_AS_EXCALIDRAW: "Открыть как рисунок Excalidraw",
|
||||
TOGGLE_MODE: "Переключение между режимами Excalidraw и Markdown",
|
||||
CONVERT_NOTE_TO_EXCALIDRAW: "Конвертировать заметку в формате Markdown в Excalidraw Drawing",
|
||||
CONVERT_EXCALIDRAW: "Преобразование файлов *.excalidraw в файлы *.md",
|
||||
CREATE_NEW: "Создать новый чертеж",
|
||||
CONVERT_FILE_KEEP_EXT: "*.excalidraw => *.excalidraw.md",
|
||||
CONVERT_FILE_REPLACE_EXT: "*.excalidraw => *.md (совместимость с Logseq)",
|
||||
DOWNLOAD_LIBRARY: "Экспорт библиотеки трафаретов в файл *.excalidrawlib",
|
||||
OPEN_EXISTING_NEW_PANE: "Открыть существующий чертеж - В НОВОЙ ПАНЕЛИ",
|
||||
OPEN_EXISTING_ACTIVE_PANE: "Открыть существующий чертеж - В ТЕКУЩЕЙ АКТИВНОЙ ПАНЕЛИ",
|
||||
TRANSCLUDE: "Вставить чертеж",
|
||||
TRANSCLUDE_MOST_RECENT: "Вставка последнего отредактированного рисунка",
|
||||
TOGGLE_LEFTHANDED_MODE: "Переключить левосторонний режим",
|
||||
TOGGLE_SPLASHSCREEN: "Показывать заставку в новых чертежах",
|
||||
FLIP_IMAGE: "Открыть фоновым рисуноком выбранное изображения excalidraw",
|
||||
NEW_IN_NEW_PANE: "Создать новый рисунок - В СОСЕДНЕМ ОКНЕ",
|
||||
NEW_IN_NEW_TAB: "Создать новый рисунок - В НОВОЙ ТАБЛИЦЕ",
|
||||
NEW_IN_ACTIVE_PANE: "Создать новый рисунок - В ТЕКУЩЕМ АКТИВНОМ ОКНЕ",
|
||||
NEW_IN_POPOUT_WINDOW: "Создать новый рисунок - В ОТКРЫВАЮЩЕМСЯ ОКНЕ",
|
||||
NEW_IN_NEW_PANE_EMBED: "Создание нового рисунка - В СОСЕДНЕМ ОКНЕ - и вставка в активный документ",
|
||||
NEW_IN_NEW_TAB_EMBED: "Создать новый чертеж - В НОВОЙ ТАБЛИЦЕ - и вставить в активный документ",
|
||||
NEW_IN_ACTIVE_PANE_EMBED: "Создать новый рисунок - В ТЕКУЩЕМ АКТИВНОМ ОКНЕ - и вставить в активный документ",
|
||||
NEW_IN_POPOUT_WINDOW_EMBED: "Создать новый рисунок - В ОТКРЫВАЮЩЕМСЯ ОКНЕ - и вставить в активный документ",
|
||||
TOGGLE_LOCK: "Переключение текстового элемента между режимами редактирования RAW (без обработки) и PREVIEW (просмотр)",
|
||||
DELETE_FILE: "Удалить выбранное изображение или файл Markdown из Obsidian хранилища",
|
||||
COPY_ELEMENT_LINK: "Скопировать [[ссылку]] для выбранного элемента(ов)",
|
||||
COPY_DRAWING_LINK: "Скопировать ![[ссылку на вставку]] для этого рисунка",
|
||||
INSERT_LINK_TO_ELEMENT: `Копирование [[ссылка]] для выбранного элемента в буфер обмена. ${labelCTRL()}+CLICK для копирования ссылки 'group='. ${labelSHIFT()}+CLICK для копирования ссылки 'area='.`,
|
||||
INSERT_LINK_TO_ELEMENT_GROUP: "Скопируйте 'group=' ![[ссылка]] для выбранного элемента в буфер обмена.",
|
||||
INSERT_LINK_TO_ELEMENT_AREA: "Скопировать 'area=' ![[ссылка]] для выбранного элемента в буфер обмена.",
|
||||
INSERT_LINK_TO_ELEMENT_FRAME: "Скопировать 'frame=' ![[ссылка]] для выбранного элемента в буфер обмена.",
|
||||
INSERT_LINK_TO_ELEMENT_FRAME_CLIPPED: "Скопировать 'clippedframe=' ![[ссылка]] для выбранного элемента в буфер обмена.",
|
||||
INSERT_LINK_TO_ELEMENT_NORMAL: "Скопировать [[ссылка]] для выбранного элемента в буфер обмена.",
|
||||
INSERT_LINK_TO_ELEMENT_ERROR: "Выбор отдельного элемента в сцене",
|
||||
INSERT_LINK_TO_ELEMENT_READY: "Ссылка ГОТОВА и доступна в буфере обмена",
|
||||
INSERT_LINK: "Вставить ссылку на файл",
|
||||
INSERT_COMMAND: "Вставить команду Obsidian в качестве ссылки",
|
||||
INSERT_IMAGE: "Вставить изображение или рисунок Excalidraw из вашего хранилища",
|
||||
IMPORT_SVG: "Импорт SVG-файла в виде штрихов Excalidraw (поддержка SVG ограничена, TEXT в настоящее время не поддерживается)",
|
||||
IMPORT_SVG_CONTEXTMENU: "Преобразование SVG в штрихи - с ограничениями",
|
||||
INSERT_MD: "Вставка файла markdown из хранилища",
|
||||
INSERT_PDF: "Вставить PDF-файл из хранилища",
|
||||
UNIVERSAL_ADD_FILE: "Вставка ЛЮБОГО файла",
|
||||
INSERT_CARD: "Добавить сноски",
|
||||
CONVERT_CARD_TO_FILE: "Переместить сноску в файл",
|
||||
ERROR_TRY_AGAIN: "Пожалуйста, попробуйте еще раз.",
|
||||
PASTE_CODEBLOCK: "Вставить блок кода",
|
||||
INSERT_LATEX: `Вставьте формулу LaTeX (например, \\\binom{n}{k} = \\\frac{n!}{k!(n-k)!}).`,
|
||||
ENTER_LATEX: "Введите правильное выражение LaTeX",
|
||||
READ_RELEASE_NOTES: "Прочитать последние заметки о выпуске",
|
||||
RUN_OCR: "OCR полного чертежа: Захват текста из freedraw + изображения в буфер обмена и doc.props",
|
||||
RERUN_OCR: "Повторный запуск полного чертежа OCR: Захват текста из freedraw + изображения в буфер обмена и doc.props",
|
||||
RUN_OCR_ELEMENTS: "OCR выделенных элементов: Захват текста из freedraw + изображения в буфер обмена",
|
||||
TRAY_MODE: "Переключение панели свойств в трей-режим",
|
||||
SEARCH: "Поиск текста на чертеже",
|
||||
CROP_PAGE: "Обрезка и маскирование выделенной страницы",
|
||||
CROP_IMAGE: "Обрезка и маскирование изображения",
|
||||
ANNOTATE_IMAGE : "Аннотирование изображения в Excalidraw",
|
||||
INSERT_ACTIVE_PDF_PAGE_AS_IMAGE: "Вставка активной страницы PDF в качестве изображения",
|
||||
RESET_IMG_TO_100: "Установить размер выбранного элемента изображения на 100% от исходного",
|
||||
RESET_IMG_ASPECT_RATIO: "Сбросить соотношение сторон выбранного элемента изображения",
|
||||
TEMPORARY_DISABLE_AUTOSAVE: "Отключить автосохранение до следующего запуска Obsidian (устанавливайте этот параметр, только если вы знаете, что делаете)",
|
||||
TEMPORARY_ENABLE_AUTOSAVE: "Включить автосохранение",
|
||||
|
||||
//ExcalidrawView.ts
|
||||
NO_SEARCH_RESULT: "Не удалось найти подходящий элемент на чертеже",
|
||||
FORCE_SAVE_ABORTED: "Принудительное сохранение прервано, поскольку идет процесс сохранения",
|
||||
LINKLIST_SECOND_ORDER_LINK: "Ссылка второго порядка",
|
||||
MARKDOWN_EMBED_CUSTOMIZE_LINK_PROMPT_TITLE: "Настройка ссылки на встроенный файл",
|
||||
MARKDOWN_EMBED_CUSTOMIZE_LINK_PROMPT: "Не добавляйте [[квадратные скобки]] вокруг имени файла! <br>" +
|
||||
"При редактировании ссылок на изображения в формате markdown-страниц следуйте этому формату: <mark>filename#^blockref|WIDTHxMAXHEIGHT</mark><br>" +
|
||||
"Вы можете привязать изображения Excalidraw к 100% их размера, добавив <code>|100%</code> в конец ссылки.<br>" +
|
||||
"Вы можете изменить страницу PDF, изменив <code>#page=1</code> на <code>#page=2</code> и т.д.<br>" +
|
||||
"Значения обрезки прямоугольника PDF: <code>left, bottom, right, top</code>. Например: <code>#rect=0,0,500,500</code><br>",
|
||||
FRAME_CLIPPING_ENABLED: "Рендеринг кадров: Включено",
|
||||
FRAME_CLIPPING_DISABLED: "Рендеринг кадров: Отключено",
|
||||
ARROW_BINDING_INVERSE_MODE: "Инвертированный режим: Привязка стрелок по умолчанию теперь отключена. Используйте CTRL/CMD, чтобы временно включить привязку, когда это необходимо.",
|
||||
ARROW_BINDING_NORMAL_MODE: "Обычный режим: Привязка стрелок теперь включена. Используйте CTRL/CMD, чтобы временно отключить привязку при необходимости.",
|
||||
EXPORT_FILENAME_PROMPT: "Пожалуйста, укажите имя файла",
|
||||
EXPORT_FILENAME_PROMPT_PLACEHOLDER: "имя файла, оставьте пустым, чтобы отменить действие",
|
||||
WARNING_SERIOUS_ERROR: "ПРЕДУПРЕЖДЕНИЕ: Excalidraw столкнулся с неизвестной проблемой!\n\n" +
|
||||
"Есть риск, что последние изменения не будут сохранены.\n\n" +
|
||||
"На всякий случай...\n" +
|
||||
"1) Выберите рисунок с помощью CTRL/CMD+A и создайте копию с помощью CTRL/CMD+C.\n" +
|
||||
"2) Затем создайте пустой чертеж в новой панели, нажав CTRL/CMD+кнопку ленты Excalidraw,\n" +
|
||||
"3) и вставьте свою работу в новый документ с помощью CTRL/CMD+V.",
|
||||
ARIA_LABEL_TRAY_MODE: "Трей-Режим предлагает альтернативный, более просторный холст",
|
||||
MASK_FILE_NOTICE: "Это файл маски. Он используется для кадрирования изображений и маскирования частей изображения. Нажмите и удерживайте уведомление, чтобы открытьe help video.",
|
||||
INSTALL_SCRIPT_BUTTON: "Установка или обновление скриптов Excalidraw",
|
||||
OPEN_AS_MD: "Открыть как Markdown",
|
||||
EXPORT_IMAGE: `Экспорт изображения`,
|
||||
OPEN_LINK: "Открыть выделенный текст как ссылку\n(SHIFT+CLICK для открытия в новой панели)",
|
||||
EXPORT_EXCALIDRAW: "Экспорт в файл .Excalidraw",
|
||||
LINK_BUTTON_CLICK_NO_TEXT: "Выберите элемент, содержащий внутреннюю или внешнюю ссылку.\n",
|
||||
LINEAR_ELEMENT_LINK_CLICK_ERROR:
|
||||
"Ссылки на элементы со стрелками и линиями нельзя перемещать с помощью " + labelCTRL() + " + КЛИКА по элементу, поскольку при этом также активируется редактор строк.\n" +
|
||||
"Чтобы открыть ссылку, воспользуйтесь контекстным меню правой кнопки мыши или щелкните индикатор ссылки в правом верхнем углу элемента.\n",
|
||||
FILENAME_INVALID_CHARS: 'Имя файла не может содержать ни одного из следующих символов: * " \\ < > : | ? #',
|
||||
FORCE_SAVE: "Сохранить (также будут обновлены включения)",
|
||||
RAW: "Переход в режим PREVIEW (влияет только на текстовые элементы со ссылками или включениями)",
|
||||
PARSED: "Переход в режим RAW (влияет только на текстовые элементы со ссылками или включениями)",
|
||||
NOFILE: "Excalidraw (без файла)",
|
||||
COMPATIBILITY_MODE: "Файл *.excalidraw открыт в режиме совместимости. Конвертируйте в новый формат для полной функциональности плагина.",
|
||||
CONVERT_FILE: "Преобразование в новый формат",
|
||||
BACKUP_AVAILABLE: "Мы столкнулись с ошибкой при загрузке вашего рисунка. Это могло произойти, если Obsidian неожиданно закрылся во время операции сохранения. Например, если вы случайно закрыли Obsidian на своем мобильном устройстве во время сохранения.<br><br><b>ХОРОШАЯ НОВОСТЬ:</b> К счастью, доступна локальная резервная копия. Однако учтите, что если вы последний раз изменяли этот рисунок на другом устройстве (например, на планшете), а сейчас находитесь на рабочем столе, то на другом устройстве, скорее всего, имеется более свежая резервная копия.<br><br>Я рекомендую сначала попробовать открыть рисунок на другом устройстве и восстановить резервную копию из его локального хранилища.<br><br>Хотите загрузить резервную копию?",
|
||||
BACKUP_RESTORED: "Резервная копия восстановлена",
|
||||
CACHE_NOT_READY: "Приношу извинения за неудобства, но при загрузке вашего файла произошла ошибка.<br><br><mark>Немного терпения может сэкономить вам массу времени...</mark><br><br>Плагин имеет резервный кэш, но похоже, что вы только что запустили Obsidian. Инициализация резервного кэша может занять некоторое время, обычно до минуты или больше, в зависимости от производительности вашего устройства. Вы получите уведомление в правом верхнем углу, когда инициализация кэша будет завершена.<br><br>Нажмите OK, чтобы попытаться загрузить файл снова и проверить, завершилась ли инициализация кэша. Если за этим сообщением вы видите абсолютно пустой файл, я рекомендую подождать, пока кэш резервного копирования будет готов, прежде чем продолжать. Кроме того, вы можете выбрать «Отмена», чтобы вручную исправить файл.<br>",
|
||||
OBSIDIAN_TOOLS_PANEL: "Панель инструментов Obsidian",
|
||||
ERROR_SAVING_IMAGE: "При получении изображения произошла неизвестная ошибка. Возможно, по какой-то причине изображение недоступно или отклонен запрос на получение от Obsidian",
|
||||
WARNING_PASTING_ELEMENT_AS_TEXT: "ВСТАВКА ЭЛЕМЕНТОВ EXCALIDRAW В КАЧЕСТВЕ ТЕКСТОВОГО ЭЛЕМЕНТА ЗАПРЕЩЕНА",
|
||||
USE_INSERT_FILE_MODAL: "Используйте 'Вставить любой файл', чтобы вставить заметку в формате markdown",
|
||||
RECURSIVE_INSERT_ERROR: "Нельзя рекурсивно вставлять часть изображения в одно и то же изображение, так как это приведет к созданию бесконечного цикла",
|
||||
CONVERT_TO_MARKDOWN: "Преобразовать в файл...",
|
||||
SELECT_TEXTELEMENT_ONLY: "Выбрать только текстовый элемент (не контейнер)",
|
||||
REMOVE_LINK: "Удалить ссылку на текстовый элемент",
|
||||
LASER_ON: "Включить лазерный указатель",
|
||||
LASER_OFF: "Отключить лазерный указатель",
|
||||
WELCOME_RANK_NEXT: "Больше рисунков до следующего ранга!",
|
||||
WELCOME_RANK_LEGENDARY: "Вы на вершине. Продолжайте быть легендарным!",
|
||||
WELCOME_COMMAND_PALETTE: 'Введите «Excalidraw» в палитре коман',
|
||||
WELCOME_OBSIDIAN_MENU: "Изучите меню Обсидиана в правом верхнем углу",
|
||||
WELCOME_SCRIPT_LIBRARY: "Посетите библиотеку сценариев",
|
||||
WELCOME_HELP_MENU: "Найдите помощь в гамбургер-меню",
|
||||
WELCOME_YOUTUBE_ARIA: "Канал Visual PKM на YouTube",
|
||||
WELCOME_YOUTUBE_LINK: "Загляните на YouTube-канал Visual PKM.",
|
||||
WELCOME_DISCORD_ARIA: "Присоединяйтесь к серверу Discord",
|
||||
WELCOME_DISCORD_LINK: "Присоединяйтесь к серверу Discord",
|
||||
WELCOME_TWITTER_ARIA: "Следите за мной в Twitter",
|
||||
WELCOME_TWITTER_LINK: "Следите за мной в Twitter",
|
||||
WELCOME_LEARN_ARIA: "Изучение Visual PKM",
|
||||
WELCOME_LEARN_LINK: "Запишитесь на семинар по визуальному мышлению",
|
||||
WELCOME_DONATE_ARIA: "Пожертвовать на поддержку Excalidraw-Obsidian",
|
||||
WELCOME_DONATE_LINK: 'Скажите «Спасибо» и поддержите плагин.',
|
||||
SAVE_IS_TAKING_LONG: "Сохранение предыдущего файла занимает много времени. Пожалуйста, подождите...",
|
||||
SAVE_IS_TAKING_VERY_LONG: "Для повышения производительности рассмотрите возможность разделения больших рисунков на несколько файлов меньшего размера.",
|
||||
|
||||
//settings.ts
|
||||
RELEASE_NOTES_NAME: "Отображение информации о выпуске после обновления",
|
||||
RELEASE_NOTES_DESC:
|
||||
"<b><u>Переключатель ВКЛ:</u></b> Отображение информации о выпуске при каждом обновлении Excalidraw до новой версии.<br>" +
|
||||
"<b><u>Переключатель ВЫКЛ:</u></b> Тихий режим. Вы все еще можете прочитать заметки о выпуске на <a href='https://github.com/zsviczian/obsidian-excalidraw-plugin/releases'>GitHub</a>.",
|
||||
NEWVERSION_NOTIFICATION_NAME: "Уведомление об обновлении плагина",
|
||||
NEWVERSION_NOTIFICATION_DESC:
|
||||
"<b><u>Переключатель ВКЛ:</u></b> Показывайте уведомление о появлении новой версии плагина.<br>" +
|
||||
"<b><u>Переключатель ВЫКЛ:</u></b> Тихий режим. Вам необходимо проверить обновления плагинов в разделе Community Plugins.",
|
||||
|
||||
BASIC_HEAD: "Основные",
|
||||
BASIC_DESC: `В настройках "Основные" можно настроить такие параметры, как отображение заметок о выпуске после обновлений, получение уведомлений об обновлении плагинов, установка местоположения по умолчанию для новых чертежей, указание папки Excalidraw для вставки чертежей в активные документы, определение файла шаблона Excalidraw и указание папки сценария Excalidraw Automate для управления сценариями автоматизации.`,
|
||||
FOLDER_NAME: "Папка Excalidraw",
|
||||
FOLDER_DESC: "Место по умолчанию для новых чертежей. Если пусто, чертежи будут создаваться в корне хранилища.",
|
||||
CROP_PREFIX_NAME: "Префикс файла обрезки",
|
||||
CROP_PREFIX_DESC:
|
||||
"Первая часть имени файла для новых чертежей, созданных при обрезке изображения. " +
|
||||
"Если пусто, то по умолчанию будет использоваться значение 'cropped_'.",
|
||||
ANNOTATE_PREFIX_NAME: "Префикс файла аннотации",
|
||||
ANNOTATE_PREFIX_DESC:
|
||||
"Первая часть имени файла для новых чертежей, созданных при аннотировании изображения. " +
|
||||
"Если пусто, то по умолчанию будет использоваться 'annotated_'.",
|
||||
ANNOTATE_PRESERVE_SIZE_NAME: "Preserve image size when annotating",
|
||||
ANNOTATE_PRESERVE_SIZE_DESC: "When annotating an image in markdown the replacment image link will include the width of the original image.",
|
||||
CROP_FOLDER_NAME: "Папка с файлами обрезки",
|
||||
CROP_FOLDER_DESC: "Место по умолчанию для новых чертежей, созданных при обрезке изображения. Если папка пуста, рисунки будут создаваться в соответствии с настройками вложений Хранилища.",
|
||||
ANNOTATE_FOLDER_NAME: "Папка с файлами аннотаций изображений",
|
||||
ANNOTATE_FOLDER_DESC: "Место по умолчанию для новых рисунков, создаваемых при аннотировании изображения. Если пусто, рисунки будут создаваться в соответствии с настройками вложений Хранилища.",
|
||||
FOLDER_EMBED_NAME: "Использовать папку Excalidraw при встраивании рисунка в активный документ",
|
||||
FOLDER_EMBED_DESC:
|
||||
"Определите, в какую папку поместить новый вставленный рисунок " +
|
||||
"при использовании действия палитры команд: 'Создать новый рисунок и вставить в активный документ'.<br>" +
|
||||
"<b><u>Переключатель ВКЛ:</u></b> Используйте папку Excalidraw<br><b><u>Переключатель ВЫКЛ:</u></b> Используйте папку вложений, определенную в настройках Obsidian.",
|
||||
TEMPLATE_NAME: "Файл или папка шаблона Excalidraw",
|
||||
TEMPLATE_DESC:
|
||||
"Полный путь к файлу или папке с шаблоном Excalidraw.<br>" +
|
||||
"<b>Файл шаблона:</b>Например: Если ваш шаблон находится в папке Excalidraw по умолчанию и его имя " +
|
||||
"Template.md, настройка должна быть: Excalidraw/Template.md (или только Excalidraw/Template - вы можете опустить .md расширение файла). " +
|
||||
"Если вы используете Excalidraw в режиме совместимости, то ваш шаблон также должен быть устаревшим файлом Excalidraw " +
|
||||
"такие как Excalidraw/Template.excalidraw. <br><b>Папка с шаблонами:</b> Вы также можете задать папку в качестве шаблона. " +
|
||||
"В этом случае вам будет предложено выбрать шаблон при создании нового чертежа.<br>" +
|
||||
"<b>Совет профи:</b> Если вы используете плагин Obsidian Templater, вы можете добавить код Templater в различные Excalidraw " +
|
||||
"шаблоны для автоматизации настройки чертежей.",
|
||||
SCRIPT_FOLDER_NAME: "Папка скриптов Excalidraw Automate (РеГИстРозависимЫЙ!)",
|
||||
SCRIPT_FOLDER_DESC:
|
||||
"Файлы, которые вы поместите в эту папку, будут рассматриваться как сценарии Excalidraw Automate. " +
|
||||
"Вы можете получить доступ к своим скриптам из Excalidraw через палитру команд Obsidian. Назначьте " +
|
||||
"горячие клавиши для ваших любимых скриптов, как и для любой другой команды Obsidian. " +
|
||||
"Эта папка может не быть корневой папкой вашего хранилища. ",
|
||||
AI_HEAD: "Настройки ИИ - Экспериментальные",
|
||||
AI_DESC: `В настройках "ИИ" вы можете настроить параметры использования GPT API OpenAI. ` +
|
||||
`Пока API OpenAI находится в бета-версии, его использование строго ограничено - поэтому мы требуем, чтобы вы использовали свой собственный ключ API. ` +
|
||||
`Вы можете создать аккаунт OpenAI, добавить небольшой кредит (минимум 5 долларов) и сгенерировать свой собственный ключ API. ` +
|
||||
`После установки API-ключа вы сможете использовать инструменты искусственного интеллекта в Excalidraw.`,
|
||||
AI_OPENAI_TOKEN_NAME: "Ключ API OpenAI",
|
||||
AI_OPENAI_TOKEN_DESC: "Вы можете получить свой ключ API OpenAI из вашего <a href='https://platform.openai.com/api-keys'>OpenAI аккаунта</a>.",
|
||||
AI_OPENAI_TOKEN_PLACEHOLDER: "Введите свой ключ API OpenAI здесь",
|
||||
AI_OPENAI_DEFAULT_MODEL_NAME: "Модель ИИ по умолчанию",
|
||||
AI_OPENAI_DEFAULT_MODEL_DESC:
|
||||
"Модель ИИ по умолчанию, используемая при генерации текста. Это поле свободного текста, поэтому вы можете ввести любое действительное имя модели OpenAI. " +
|
||||
"Узнайте больше о доступных моделях на <a href='https://platform.openai.com/docs/models'>OpenAI сайте</a>.",
|
||||
AI_OPENAI_DEFAULT_MODEL_PLACEHOLDER: "Введите здесь модель искусственного интеллекта по умолчанию, например: gpt-3.5-turbo-1106.",
|
||||
AI_OPENAI_DEFAULT_IMAGE_MODEL_NAME: "Модель ИИ для генерации изображений по умолчанию",
|
||||
AI_OPENAI_DEFAULT_IMAGE_MODEL_DESC:
|
||||
"Модель ИИ по умолчанию, используемая при генерации изображений. Редактирование и изменение изображений поддерживается OpenAI только в dall-e-2, " +
|
||||
"поэтому dall-e-2 будет автоматически использоваться в таких случаях независимо от этой настройки.<br>" +
|
||||
"Это поле свободного текста, поэтому вы можете ввести любое действительное имя модели OpenAI. " +
|
||||
"Узнайте больше о доступных моделях на <a href='https://platform.openai.com/docs/models'>OpenAI сайте</a>.",
|
||||
AI_OPENAI_DEFAULT_IMAGE_MODEL_PLACEHOLDER: "Введите здесь модель ИИ Image Generation по умолчанию, например: dall-e-3.",
|
||||
AI_OPENAI_DEFAULT_VISION_MODEL_NAME: "Модель видения ИИ по умолчанию",
|
||||
AI_OPENAI_DEFAULT_VISION_MODEL_DESC:
|
||||
"Модель зрения ИИ по умолчанию, используемая при генерации текста из изображений. Это поле свободного текста, поэтому вы можете ввести любое действительное имя модели OpenAI. " +
|
||||
"Узнайте больше о доступных моделях на <a href='https://platform.openai.com/docs/models'>OpenAI сайте</a>.",
|
||||
AI_OPENAI_DEFAULT_API_URL_NAME: "URL-адрес API OpenAI",
|
||||
AI_OPENAI_DEFAULT_API_URL_DESC:
|
||||
"URL-адрес OpenAI API по умолчанию. Это поле свободного текста, поэтому вы можете ввести любой действительный URL, совместимый с OpenAI API. " +
|
||||
"Excalidraw будет использовать этот URL при отправке API-запросов в OpenAI. Я не делаю никакой обработки ошибок в этом поле, поэтому убедитесь, что вы вводите правильный URL и изменяйте его только в том случае, если вы знаете, что делаете. ",
|
||||
AI_OPENAI_DEFAULT_IMAGE_API_URL_NAME: "URL-адрес API генерации изображений OpenAI",
|
||||
AI_OPENAI_DEFAULT_VISION_MODEL_PLACEHOLDER: "Введите здесь модель зрения ИИ по умолчанию. Например: gpt-4o",
|
||||
SAVING_HEAD: "Сохранение",
|
||||
SAVING_DESC: "В разделе 'Сохранение' раздела Настройки Excalidraw вы можете настроить способ сохранения ваших чертежей. Сюда входят опции сжатия Excalidraw JSON в Markdown, установки интервалов автосохранения для настольных и мобильных компьютеров, определения форматов имен файлов, а также выбора расширения файла .excalidraw.md или .md. ",
|
||||
COMPRESS_NAME: "Сжатие Excalidraw JSON в формате Markdown",
|
||||
COMPRESS_DESC:
|
||||
"При включении этой функции Excalidraw будет хранить JSON рисунка в формате Base64. " +
|
||||
"формат с использованием алгоритма <a href='https://pieroxy.net/blog/pages/lz-string/index.html'>LZ-String</a>. " +
|
||||
"Это уменьшит вероятность того, что Excalidraw JSON загромоздит результаты поиска в Obsidian. " +
|
||||
"Как побочный эффект, это также уменьшит размер файлов чертежей Excalidraw. " +
|
||||
"При переключении чертежа Excalidraw в режим Markdown с помощью меню опций Excalidraw файл будет " +
|
||||
"сохранен без сжатия, чтобы вы могли читать и редактировать строку JSON. Чертеж будет снова сжат " +
|
||||
"как только вы переключитесь обратно в вид Excalidraw. " +
|
||||
"Настройка имеет силу только 'на перспективу', то есть существующие чертежи не будут затронуты настройкой " +
|
||||
"пока вы не откроете и не сохраните их.<br><b><u>Переключатель ВКЛ:</u></b> Сжать чертеж JSON<br><b><u>Переключатель ВЫКЛ:</u></b> Оставьте JSON для рисования без сжатия",
|
||||
DECOMPRESS_FOR_MD_NAME: "Декомпрессия Excalidraw JSON в Markdown Режим",
|
||||
DECOMPRESS_FOR_MD_DESC:
|
||||
"При включении этой функции Excalidraw будет автоматически распаковывать JSON чертежа при переключении в режим Markdown." +
|
||||
"Это позволит вам легко читать и редактировать строку JSON. Чертеж будет снова сжат " +
|
||||
"как только вы переключитесь обратно в режим Excalidraw и сохраните чертеж (CTRL+S).<br>" +
|
||||
"Я рекомендую отключить эту функцию, так как это приведет к уменьшению размера файлов и избавит от ненужных результатов в поиске Obsidian. " +
|
||||
"Вы всегда можете воспользоваться командой 'Excalidraw: Распаковать текущий файл Excalidraw' из палитры команд. "+
|
||||
"чтобы вручную распаковывать JSON чертежа, когда вам нужно его прочитать или отредактировать.",
|
||||
AUTOSAVE_INTERVAL_DESKTOP_NAME: "Интервал для автосохранения на рабочем столе",
|
||||
AUTOSAVE_INTERVAL_DESKTOP_DESC:
|
||||
"Интервал времени между сохранениями. Автосохранение будет пропущено, если в чертеже нет изменений. " +
|
||||
"Excalidraw также сохранит файл при закрытии вкладки рабочей области или при навигации в Obsidian, но вне активной вкладки Excalidraw (например, при нажатии на ленту Obsidian, проверке обратных ссылок и т. д.). " +
|
||||
"Excalidraw не сможет сохранить вашу работу при завершении работы Obsidian напрямую, либо убив процесс Obsidian, либо нажав кнопку закрытия Obsidian вообще.",
|
||||
AUTOSAVE_INTERVAL_MOBILE_NAME: "Интервал для автосохранения на мобильном телефоне",
|
||||
AUTOSAVE_INTERVAL_MOBILE_DESC:
|
||||
"Для мобильников я рекомендую более частый интервал. " +
|
||||
"Excalidraw также сохранит файл при закрытии вкладки рабочей области или при навигации в Obsidian, но вне активной вкладки Excalidraw (например, при нажатии на ленту Obsidian, проверке обратных ссылок и т. д.). " +
|
||||
"Excalidraw не сможет сохранить вашу работу при прямом завершении работы Obsidian (т.е. смахнув ее). Также обратите внимание, что при переключении приложений на мобильном устройстве, иногда Android и iOS закрываются " +
|
||||
"Obsidian в фоновом режиме для экономии системных ресурсов. В этом случае Excalidraw не сможет сохранить последние изменения.",
|
||||
FILENAME_HEAD: "Имя файла",
|
||||
FILENAME_DESC:
|
||||
"<p>Нажмите на эту ссылку, чтобы получить <a href='https://momentjs.com/docs/#/displaying/format/'>" +
|
||||
"справочник по формату даты и времени</a>.</p>",
|
||||
FILENAME_SAMPLE: "Filename for a new drawing is: ",
|
||||
FILENAME_EMBED_SAMPLE: "Имя файла для нового встроенного чертежа: ",
|
||||
FILENAME_PREFIX_NAME: "Префикс имени файла",
|
||||
FILENAME_PREFIX_DESC: "Первая часть имени файла",
|
||||
FILENAME_PREFIX_EMBED_NAME: "Префикс имени файла при вставке нового чертежа в заметку в формате markdown",
|
||||
FILENAME_PREFIX_EMBED_DESC:
|
||||
"Должно ли имя файла нового вставленного чертежа начинаться с имени активной заметки в формате markdown " +
|
||||
"при использовании действия палитры команд: <code>Создать новый чертеж и вставить его в активный документ</code>?<br>" +
|
||||
"<b><u>Переключатель ВКЛ:</u></b> Да, имя файла нового чертежа должно начинаться с имени файла активного документа<br><b><u>Переключатель ВЫКЛ:</u></b> Нет, имя файла нового чертежа не должно включать имя файла активного документа",
|
||||
FILENAME_POSTFIX_NAME: "Пользовательский текст после имени заметки в формате markdown при вставке",
|
||||
FILENAME_POSTFIX_DESC: "Влияет на имя файла только при вставке в документ markdown. Этот текст будет вставлен после имени заметки, но перед датой.",
|
||||
FILENAME_DATE_NAME: "Дата имени файла",
|
||||
FILENAME_DATE_DESC: "Последняя часть имени файла. Оставьте пустой, если дата не нужна.",
|
||||
FILENAME_EXCALIDRAW_EXTENSION_NAME: ".excalidraw.md или .md",
|
||||
FILENAME_EXCALIDRAW_EXTENSION_DESC:
|
||||
"Эта настройка не применяется, если вы используете Excalidraw в режиме совместимости, " +
|
||||
"т.е. вы не используете файлы разметки Excalidraw.<br><b><u>Переключатель ВКЛ:</u></b> Имя файла заканчивается на .excalidraw.md<br><b><u>Переключатель ВЫКЛ:</u></b> Имя файла заканчивается на .md",
|
||||
DISPLAY_HEAD: "Внешний вид и поведение Excalidraw",
|
||||
DISPLAY_DESC: "В разделе 'Внешний вид и поведение' раздела Настройки Excalidraw вы можете настроить внешний вид и поведение Excalidraw. Сюда входят опции динамической стилизации, режима для левой руки, соответствия тем Excalidraw и Obsidian, режимов по умолчанию и многое другое.",
|
||||
DYNAMICSTYLE_NAME: "Динамическая стилизация",
|
||||
DYNAMICSTYLE_DESC: "Изменение цветов пользовательского интерфейса Excalidraw в соответствии с цветом холста",
|
||||
LEFTHANDED_MODE_NAME: "Левосторонний режим",
|
||||
LEFTHANDED_MODE_DESC:
|
||||
"В настоящее время действует только в трей режиме. Если включить этот режим, трей будет находиться с правой стороны." +
|
||||
"<br><b><u>Переключатель ВКЛ:</u></b> Левосторонний режим.<br><b><u>Переключатель ВЫКЛ:</u></b> Правосторонний режим",
|
||||
IFRAME_MATCH_THEME_NAME: "Вставки Markdown для соответствия теме Excalidraw",
|
||||
IFRAME_MATCH_THEME_DESC:
|
||||
"<b><u>Переключатель ВКЛ:</u></b> Установите значение true, если, например, вы используете Obsidian в темном режиме, но применяете excalidraw со светлым фоном. " +
|
||||
"С этой настройкой встроенный документ разметки Obsidian будет соответствовать теме Excalidraw (т.е. светлые цвета, если Excalidraw находится в светлом режиме).<br>" +
|
||||
"<b><u>Переключатель ВЫКЛ:</u></b> Установите значение false, если хотите, чтобы встроенный в Obsidian документ разметки соответствовал теме Obsidian (т.е. темные цвета, если Obsidian находится в темном режиме).",
|
||||
MATCH_THEME_NAME: "Новый чертеж в соответствии с темой Obsidian",
|
||||
MATCH_THEME_DESC:
|
||||
"Если тема темная, новый рисунок будет создан в темном режиме. Это не относится к случаям, когда вы используете шаблон для новых рисунков. " +
|
||||
"Также это не повлияет на открытие существующего чертежа. Они будут соответствовать теме шаблона/чертежа соответственно." +
|
||||
"<br><b><u>Переключатель ВКЛ:</u></b> Следуйте за Obsidian Theme<br><b><u>Переключатель ВЫКЛ:</u></b> Следовать теме, заданной в вашем шаблоне",
|
||||
MATCH_THEME_ALWAYS_NAME: "Существующие чертежи должны соответствовать теме Obsidian",
|
||||
MATCH_THEME_ALWAYS_DESC:
|
||||
"Если тема темная, чертежи будут открываться в темном режиме. Если тема светлая, они будут открываться в светлом режиме. " +
|
||||
"<br><b><u>Переключатель ВКЛ:</u></b> Соответствовать теме Obsidian<br><b><u>Переключатель ВЫКЛ:</u></b> Открывать ту же тему, что и при последнем сохранении",
|
||||
MATCH_THEME_TRIGGER_NAME: "Excalidraw будет следовать за изменениями Темы Obsidian",
|
||||
MATCH_THEME_TRIGGER_DESC:
|
||||
"Если эта опция включена, открытая панель Excalidraw будет переключаться в светлый/темный режим при смене темы Obsidian. " +
|
||||
"<br><b><u>Переключатель ВКЛ:</u></b> Следить за изменениями темы<br><b><u>Переключатель ВЫКЛ:</u></b> Чертежи не подвержены изменениям темы Obsidian",
|
||||
DEFAULT_OPEN_MODE_NAME: "Режим по умолчанию при открытии Excalidraw",
|
||||
DEFAULT_OPEN_MODE_DESC:
|
||||
"Указывает режим, в котором открывается Excalidraw: Обычный, Zen или режим просмотра. Вы также можете задать это поведение на уровне файла " +
|
||||
"добавив в документ ключ excalidraw-default-mode frontmatter со значением: normal, view или zen.",
|
||||
DEFAULT_PEN_MODE_NAME: "Режим пера",
|
||||
DEFAULT_PEN_MODE_DESC: "Должен ли режим пера автоматически включаться при открытии Excalidraw?",
|
||||
DISABLE_DOUBLE_TAP_ERASER_NAME: "Включение двойного нажатия ластика в режиме пера",
|
||||
SHOW_PEN_MODE_FREEDRAW_CROSSHAIR_NAME: "Показать (+) перекрестие в режиме пера",
|
||||
SHOW_PEN_MODE_FREEDRAW_CROSSHAIR_DESC:
|
||||
"Показывайте перекрестие в режиме пера при использовании инструмента freedraw. <b><u>Toggle Переключатель ВКЛ</u></b> Показывать <b><u>Toggle Переключатель ВЫКЛ</u></b> Скрывать<br>"+
|
||||
"Эффект зависит от устройства. Перекрестие обычно видно на планшетах для рисования, MS Surface, но не на iOS.",
|
||||
SHOW_DRAWING_OR_MD_IN_HOVER_PREVIEW_NAME: "Передача файла Excalidraw в виде изображения в предварительном просмотре при наведении...",
|
||||
SHOW_DRAWING_OR_MD_IN_HOVER_PREVIEW_DESC:
|
||||
"...даже если файл имеет ключ <b>excalidraw-open-md: true</b> frontmatter.<br>" +
|
||||
"Если этот параметр выключен и файл по умолчанию открывается в формате md, при наведении на предварительный просмотр" +
|
||||
"будет показана часть документа, содержащая разметку.",
|
||||
SHOW_DRAWING_OR_MD_IN_READING_MODE_NAME: "Рендеринг в виде изображения при чтении файла Excalidraw в режиме разметки",
|
||||
SHOW_DRAWING_OR_MD_IN_READING_MODE_DESC:
|
||||
"Когда вы находитесь в режиме чтения разметки (а именно, читаете обратную сторону рисунка), должен ли рисунок Excalidraw отображаться как изображение? " +
|
||||
"Этот параметр не влияет на отображение чертежа в режиме Excalidraw, а также при встраивании чертежа в документ с пометками или при предварительном просмотре при наведении.<br><ul>" +
|
||||
"<li>Смотрите другие связанные настройки для <a href='#«+TAG_PDFEXPORT+»'>экспорта PDF</a> в разделе 'Встраивание и экспорт' ниже.</li></ul><br>" +
|
||||
"Вы должны закрыть активный файл excalidraw/markdown и снова открыть его, чтобы это изменение вступило в силу.",
|
||||
SHOW_DRAWING_OR_MD_IN_EXPORTPDF_NAME: "При экспорте файла Excalidraw в PDF файл отображается как изображение.",
|
||||
SHOW_DRAWING_OR_MD_IN_EXPORTPDF_DESC:
|
||||
"Этот параметр управляет поведением Excalidraw при экспорте файла Excalidraw в PDF в режиме просмотра разметки с помощью функции Obsidian <b>Экспорт в PDF</b> <br>" +
|
||||
"<ul><li>Если <b>разрешить</b>, в PDF будет отображаться только чертеж Excalidraw;</li>" +
|
||||
"<li>Если <b>заблокировать</b>, то в PDF будет отображаться разметка документа.</li></ul>" +
|
||||
"См. другие связанные настройки для <a href='#«+TAG_MDREADINGMODE+»'>режима чтения разметки</a> в разделе 'Внешний вид и поведение' выше.<br>" +
|
||||
"⚠️ Обратите внимание, что необходимо закрыть активный файл excalidraw/markdown и открыть его снова, чтобы изменения вступили в силу. ⚠️",
|
||||
HOTKEY_OVERRIDE_HEAD: "Переопределение горячих клавиш",
|
||||
HOTKEY_OVERRIDE_DESC: `Некоторые горячие клавиши Excalidraw, такие как <code>${labelCTRL()}+Enter</code> для редактирования текста или <code>${labelCTRL()}+K</code> создания ссылки на элемент ` +
|
||||
"конфликтуют с настройками горячих клавиш Obsidian. Комбинации горячих клавиш, которые вы добавите ниже, отменят настройки горячих клавиш Obsidian при использовании Excalidraw, таким образом " +
|
||||
`Вы можете добавить <code>${labelCTRL()}+G</code>, если хотите по умолчанию перейти к Группе Объектов в Excalidraw вместо открытия Режима просмотра Графиков.`,
|
||||
THEME_HEAD: "Тема и стиль",
|
||||
ZOOM_HEAD: "Масштабирование",
|
||||
DEFAULT_PINCHZOOM_NAME: "Разрешить масштабирование в режиме пера",
|
||||
DEFAULT_PINCHZOOM_DESC:
|
||||
"По умолчанию зуммирование в режиме пера при использовании инструмента «Свободное рисование» отключено, чтобы предотвратить нежелательное случайное масштабирование с помощью ладони.<br>" +
|
||||
"<b><u>Переключатель ВКЛ:</u></b>Включение щипкового масштабирования в режиме пера<br><b><u>Переключатель ВЫКЛ:</u></b>Выключение щипкового масштабирования в режиме пера",
|
||||
|
||||
DEFAULT_WHEELZOOM_NAME: "Колесо мыши для масштабирования по умолчанию",
|
||||
DEFAULT_WHEELZOOM_DESC:
|
||||
`<b><u>Переключатель ВКЛ:</u></b> Колесо мыши для масштабирования; ${labelCTRL()} + Колесо мыши для прокрутки</br><b><u>Переключатель ВЫКЛ:</u></b>${labelCTRL()} + Колесико мыши для масштабирования; Колесико мыши для прокрутки`,
|
||||
|
||||
ZOOM_TO_FIT_NAME: "Изменение масштаба при изменении размера просмотра",
|
||||
ZOOM_TO_FIT_DESC: "Изменение масштаба чертежа при изменении размера панели" +
|
||||
"<br><b><u>Переключатель ВКЛ:</u></b> Увеличить масштаб<br><b><u>Переключатель ВЫКЛ:</u></b> Автоматическое масштабирование отключено",
|
||||
ZOOM_TO_FIT_ONOPEN_NAME: "Увеличение масштаба при открытии файла",
|
||||
ZOOM_TO_FIT_ONOPEN_DESC: "Изменение масштаба чертежа при его первом открытии" +
|
||||
"<br><b><u>Переключатель ВКЛ:</u></b> Увеличить масштаб<br><b><u>Переключатель ВЫКЛ:</u></b> Автоматическое масштабирование отключено",
|
||||
ZOOM_TO_FIT_MAX_LEVEL_NAME: "Увеличение до максимального уровня масштабирования",
|
||||
ZOOM_TO_FIT_MAX_LEVEL_DESC: "Установите максимальный уровень, до которого масштабирование будет увеличивать чертеж. Минимальное значение - 0,5 (50 %), максимальное - 10 (1000 %).",
|
||||
GRID_HEAD: "Сетка",
|
||||
GRID_DYNAMIC_COLOR_NAME: "Динамический цвет сетки",
|
||||
GRID_DYNAMIC_COLOR_DESC: "<b><u>Переключатель ВКЛ:</u></b>Измените цвет сетки, чтобы он соответствовал цвету холста<br><b><u>Переключатель ВЫКЛ:</u></b>Используйте цвет, указанный ниже, в качестве цвета сетки",
|
||||
GRID_COLOR_NAME: "Цвет сетки",
|
||||
GRID_OPACITY_NAME: "Прозрачность сетки",
|
||||
GRID_OPACITY_DESC: "Прозрачность сетки также будет управлять прозрачностью поля привязки при привязке стрелки к элементу.<br>" +
|
||||
"Установите прозрачность сетки. 0 - прозрачная, 100 - непрозрачная.",
|
||||
LASER_HEAD: "Лазерный указатель",
|
||||
LASER_COLOR: "Цвет лазерного указателя",
|
||||
LASER_DECAY_TIME_NAME: "Время затухания лазерного указателя",
|
||||
LASER_DECAY_TIME_DESC: "Время затухания лазерного указателя в миллисекундах. По умолчанию - 1000 (т. е. 1 секунда).",
|
||||
LASER_DECAY_LENGTH_NAME: "Длительность затухания лазерного указателя.",
|
||||
LASER_DECAY_LENGTH_DESC: "Длина затухания лазерного указателя в точках линии. По умолчанию 50.",
|
||||
LINKS_HEAD: "Ссылки, включение и задачи TODO",
|
||||
LINKS_HEAD_DESC: "В разделе 'Ссылки, включения и TODO' раздела Настройки Excalidraw вы можете настроить, как Excalidraw обрабатывает ссылки, включения и элементы TODO. Сюда входят опции для открытия ссылок, управления панелями, отображения ссылок со скобками, настройки префиксов ссылок, обработки элементов TODO и т. д. ",
|
||||
LINKS_DESC:
|
||||
`${labelCTRL()}+КЛИКНИТЕ на <code>[[Text Elements]]</code> чтобы открыть их как ссылки. ` +
|
||||
"Если выделенный текст имеет более одного <code>[[valid Obsidian links]]</code>, только первый будет открыт. " +
|
||||
"Если текст начинается как правильная веб-ссылка (то есть <code>https://</code> или <code>http://</code>), потом " +
|
||||
"плагин откроет его в браузере. " +
|
||||
"Когда файлы Obsidian изменяются, соответствующие <code>[[link]]</code> в ваших чертежах также изменится. " +
|
||||
"Если вы не хотите, чтобы текст случайно менялся в ваших чертежах, используйте <code>[[links|with aliases]]</code>.",
|
||||
DRAG_MODIFIER_NAME: "Щелкните ссылку и перетащите клавиши-модификаторы",
|
||||
DRAG_MODIFIER_DESC: "Поведение клавиши-модификатора при нажатии на ссылки и перетаскивании элементов. " +
|
||||
"Excalidraw не будет проверять вашу конфигурацию... обратите внимание, чтобы избежать конфликтов настроек. " +
|
||||
"Эти настройки отличаются для Apple и не-Apple. Если вы используете Obsidian на нескольких платформах, вам нужно будет сделать настройки отдельно. "+
|
||||
"Переключатели расположены в порядке" +
|
||||
(DEVICE.isIOS || DEVICE.isMacOS ? "SHIFT, CMD, OPT, CONTROL." : "SHIFT, CTRL, ALT, META (Клавишы Windows)."),
|
||||
LONG_PRESS_DESKTOP_NAME: "Длительное нажатие открывает рабочий стол",
|
||||
LONG_PRESS_DESKTOP_DESC: "Задержка нажатия в миллисекундах для открытия чертежа Excalidraw, встроенного в файл Markdown.",
|
||||
LONG_PRESS_MOBILE_NAME: "Длительное нажатие открывает мобильную версию",
|
||||
LONG_PRESS_MOBILE_DESC: "Задержка нажатия в миллисекундах для открытия чертежа Excalidraw, встроенного в файл Markdown.",
|
||||
|
||||
FOCUS_ON_EXISTING_TAB_NAME: "Фокус на существующей вкладке",
|
||||
FOCUS_ON_EXISTING_TAB_DESC: "При открытии ссылки Excalidraw будет фокусироваться на существующей вкладке, если файл уже открыт. " +
|
||||
"Включение этого параметра отменяет 'Повторное использование соседней панели', если файл уже открыт.",
|
||||
SECOND_ORDER_LINKS_NAME: "Показать ссылки второго порядка",
|
||||
SECOND_ORDER_LINKS_DESC: "Показывать ссылки при нажатии на ссылку в Excalidraw. Ссылки второго порядка - это обратные ссылки, указывающие на ссылку, по которой переходят. " +
|
||||
"При использовании значков изображений для соединения похожих заметок ссылки второго порядка позволяют перейти к связанным заметкам одним щелчком мыши, а не двумя. " +
|
||||
"Для понимания смотрите <a href='https://youtube.com/shorts/O_1ls9c6wBY?feature=share'>YT Short</a>.",
|
||||
ADJACENT_PANE_NAME: "Повторное использование соседней панели",
|
||||
ADJACENT_PANE_DESC:
|
||||
`Когда ${labelCTRL()}+${labelALT()} нажимает на ссылку в Excalidraw, по умолчанию плагин открывает ссылку в новой панели. ` +
|
||||
"Если включить этот параметр, Excalidraw сначала будет искать существующую панель и пытаться открыть ссылку в ней. " +
|
||||
"Excalidraw будет искать другую панель рабочего пространства, основываясь на истории фокуса/навигации, то есть на той панели, которая была активна до того, " +
|
||||
"как вы активировали Excalidraw.",
|
||||
MAINWORKSPACE_PANE_NAME: "Открыть в основном рабочем пространстве",
|
||||
MAINWORKSPACE_PANE_DESC:
|
||||
`Когда ${labelCTRL()}+${labelALT()} нажимает на ссылку в Excalidraw, по умолчанию плагин открывает ссылку в новой панели в текущем активном окне. ` +
|
||||
"Если включить этот параметр, Excalidraw откроет ссылку в существующей или новой панели в основном рабочем пространстве. ",
|
||||
LINK_BRACKETS_NAME: "Показать <code>[[brackets]]</code> вокруг ссылок",
|
||||
LINK_BRACKETS_DESC: `${
|
||||
"В режиме ПРЕДВАРИТЕЛЬНОГО ПРОСМОТРА при разборе элементов текста ставьте скобки вокруг ссылок. " +
|
||||
"Вы можете переопределить эту настройку для конкретного чертежа, добавив <code>"
|
||||
}${FRONTMATTER_KEYS["link-brackets"].name}: true/false</code> в frontmatter файла.`,
|
||||
LINK_PREFIX_NAME: "Префикс ссылки",
|
||||
LINK_PREFIX_DESC: `${
|
||||
"В режиме ПРЕДВАРИТЕЛЬНОГО ПРОСМОТРА, если элемент 'Текст' содержит ссылку, перед текстом должны стоять эти символы. " +
|
||||
"Вы можете переопределить эту настройку для конкретного чертежа, добавив <code>"
|
||||
}${FRONTMATTER_KEYS["link-prefix"].name}: "📍 "</code> в frontmatter файла.`,
|
||||
URL_PREFIX_NAME: "Префикс URL-адреса",
|
||||
URL_PREFIX_DESC: `${
|
||||
"В режиме ПРЕДВАРИТЕЛЬНОГО ПРОСМОТРА, если элемент 'Текст' содержит ссылку URL, перед текстом должны стоять эти символы. " +
|
||||
"Вы можете переопределить эту настройку для конкретного чертежа, добавив <code>"
|
||||
}${FRONTMATTER_KEYS["url-prefix"].name}: "🌐 "</code> в frontmatter файла.`,
|
||||
PARSE_TODO_NAME: "Парсинг TODO",
|
||||
PARSE_TODO_DESC: "Преобразуйте '- [ ] ' и '- [x] ' в чекбокс и поставьте галочку.",
|
||||
TODO_NAME: "Открыть иконку TODO",
|
||||
TODO_DESC: "Иконка для открытых пунктов TODO",
|
||||
DONE_NAME: "Иконка завершенного TODO",
|
||||
DONE_DESC: "Иконка для завершенных элементов TODO",
|
||||
HOVERPREVIEW_NAME: `Предварительный просмотр наведением без нажатия клавиши ${labelCTRL()}`,
|
||||
HOVERPREVIEW_DESC:
|
||||
`<b><u>Переключатель ВКЛ:</u></b> <u>В режиме просмотра</u> Exalidraw предварительный просмотр при наведении на [[вики-ссылки]] будет показан сразу, без необходимости удерживать клавишу ${labelCTRL()}. ` +
|
||||
"В Excalidraw <u>нормальный режим</u>, предварительный просмотр будет показан сразу только при наведении на синий значок ссылки в правом верхнем углу элемента.<br> " +
|
||||
`<b><u>Переключатель ВЫКЛ:</u></b> Предварительный просмотр при наведении отображается только в том случае, если при наведении на ссылку вы удерживаете клавишу ${labelCTRL()}.`,
|
||||
LINKOPACITY_NAME: "Прозрачность значка ссылки",
|
||||
LINKOPACITY_DESC: "Прозрачность значка индикатора ссылки в правом верхнем углу элемента. 1 - непрозрачный, 0 - прозрачный.",
|
||||
LINK_CTRL_CLICK_NAME: `${labelCTRL()}+КЛИК на текст с [[links]] или [](links), чтобы открыть их`,
|
||||
LINK_CTRL_CLICK_DESC:
|
||||
"Вы можете отключить эту функцию, если она мешает работе стандартных функций Excalidraw, которые вы хотите использовать. " +
|
||||
`Если эта функция отключена, для открытия ссылок можно использовать либо ${labelCTRL()} + ${labelMETA()}, либо индикатор ссылок в правом верхнем углу элемента.`,
|
||||
TRANSCLUSION_WRAP_NAME: "Поведение переноса при переполненнии включенного текста",
|
||||
TRANSCLUSION_WRAP_DESC:
|
||||
"Число задает количество символов, через которое должен быть перенесен текст. " +
|
||||
"Устанавливает поведение переноса текста. Включите этот параметр, чтобы принудительно перенести " +
|
||||
" текст (т. е. без переполнения), или выключите, чтобы мягко перенести текст (по ближайшему пробелу).",
|
||||
TRANSCLUSION_DEFAULT_WRAP_NAME: "Перенос по словам включения по умолчанию",
|
||||
TRANSCLUSION_DEFAULT_WRAP_DESC:
|
||||
"Вы можете вручную задать/переопределить длину переноса слов, используя формат `![[page#^block]]{NUMBER}`. " +
|
||||
"Обычно вам не нужно устанавливать значение по умолчанию, поскольку если вы вставите текст внутрь стикера, то Excalidraw автоматически позаботится о переносе слов. " +
|
||||
"Установите это значение на '0', если вы не хотите устанавливать значение по умолчанию. ",
|
||||
PAGE_TRANSCLUSION_CHARCOUNT_NAME: "Максимальное количество символов при включении страниц (трансклюзии)",
|
||||
PAGE_TRANSCLUSION_CHARCOUNT_DESC:
|
||||
"Максимальное количество символов, отображаемых на странице при включении всей страницы" +
|
||||
"в формате ![[markdown page]].",
|
||||
QUOTE_TRANSCLUSION_REMOVE_NAME: "Включение (Трансклюзия) цитат: удалите ведущие '> ' из каждой строки",
|
||||
QUOTE_TRANSCLUSION_REMOVE_DESC: "Удалите начальный '>' из каждой строки включения. Это улучшит читаемость цитат в текстовых включениях <br>" +
|
||||
"<b><u>Переключатель ВКЛ:</u></b> Удалить ведущие '> '<br><b><u>Переключатель ВЫКЛ:</u></b> Не удалить ведущие '> ' (обратите внимание, что он все равно будет удален из первой строки из-за функциональности API Obsidian.)",
|
||||
GET_URL_TITLE_NAME: "Используйте iframely для преобразования заголовка страницы",
|
||||
GET_URL_TITLE_DESC:
|
||||
"Используйте <code>http://iframely.server.crestify.com/iframely?url=</code> для получения заголовка страницы при переходе по ссылке в Excalidraw",
|
||||
PDF_TO_IMAGE: "PDF в изображение",
|
||||
PDF_TO_IMAGE_SCALE_NAME: "Шкала преобразования PDF в изображения",
|
||||
PDF_TO_IMAGE_SCALE_DESC: "Устанавливает разрешение изображения, которое генерируется из PDF-страницы. Более высокое разрешение приведет к увеличению размера изображений в памяти и, как следствие, к увеличению нагрузки на систему (замедлению производительности), но при этом изображение будет более четким. " +
|
||||
"Кроме того, если вы хотите скопировать страницы PDF (как изображения) на Excalidraw.com, больший размер изображения может привести к превышению лимита в 2 МБ на Excalidraw.com.",
|
||||
EMBED_TOEXCALIDRAW_HEAD: "Встраивание файлов в Excalidraw",
|
||||
EMBED_TOEXCALIDRAW_DESC: "В разделе Встраивание файлов раздела Настройки Excalidraw вы можете настроить, как различные файлы будут встраиваться в Excalidraw. Сюда входят опции для встраивания интерактивных файлов разметки (Markdown), PDF-файлов и файлов разметки (Markdown) в виде изображений.",
|
||||
MD_HEAD: "Встраивать разметку в Excalidraw в виде изображения",
|
||||
MD_EMBED_CUSTOMDATA_HEAD_NAME: "Интерактивные файлы Markdown",
|
||||
MD_EMBED_CUSTOMDATA_HEAD_DESC: `Приведенные ниже настройки будут влиять только на будущие вставки. Текущие вставки остаются неизменными. Настройки темы для встроенных фреймов находятся в разделе "Внешний вид и поведение Excalidraw".`,
|
||||
MD_EMBED_SINGLECLICK_EDIT_NAME: "Редактирование встроенной разметки (Markdown) одним щелчком мыши",
|
||||
MD_EMBED_SINGLECLICK_EDIT_DESC:
|
||||
"Однократный щелчок на встроенном файле разметки (Markdown) для его редактирования. " +
|
||||
"Если отключить эту функцию, файл с пометками сначала откроется в режиме предварительного просмотра, а затем переключится в режим редактирования, когда вы снова нажмете на него.",
|
||||
MD_TRANSCLUDE_WIDTH_NAME: "Ширина по умолчанию для включенного документа с разметкой",
|
||||
MD_TRANSCLUDE_WIDTH_DESC:
|
||||
"Ширина страницы разметки (Markdown). Это влияет на обертку слов при встраивание длинных абзацев, а также на ширину элемента изображения " +
|
||||
" Вы можете изменить ширину встроенного файла по умолчанию, " +
|
||||
"используя синтаксис <code>[[filename#heading|WIDTHxMAXHEIGHT]]</code> в режиме просмотра markdown в разделе встроенных файлов.",
|
||||
MD_TRANSCLUDE_HEIGHT_NAME: "Максимальная высота по умолчанию для документа с пометкой встраиваемый",
|
||||
MD_TRANSCLUDE_HEIGHT_DESC:
|
||||
"Встроенное изображение будет настолько высоким, насколько этого требует текст разметки (Markdown), но не выше этого значения. " +
|
||||
"Вы можете переопределить это значение, отредактировав ссылку на встроенное изображение в режиме просмотра markdown со следующим синтаксисом <code>[[filename#^blockref|WIDTHxMAXHEIGHT]]</code>.",
|
||||
MD_DEFAULT_FONT_NAME: "Шрифт по умолчанию, используемый для встроенных файлов разметки (Markdown).",
|
||||
MD_DEFAULT_FONT_DESC:
|
||||
'Установите это значение на "Virgil" или "Cascadia" или на имя файла <code>.ttf</code>, <code>.woff</code>, или <code>.woff2</code> шрифта, например. <code>MyFont.woff2</code> ' +
|
||||
"Вы можете отменить эту настройку, добавив следующий frontmatter-ключ во встроенный файл разметки (markdown): <code>excalidraw-font: font_or_filename</code>",
|
||||
MD_DEFAULT_COLOR_NAME: "Цвет шрифта по умолчанию, используемый для встроенных файлов разметки (markdown).",
|
||||
MD_DEFAULT_COLOR_DESC:
|
||||
'Установите это значение в любое допустимое имя цвета css, например, "steelblue" (<a href="https://www.w3schools.com/colors/colors_names.asp">имена цветов</a>), или допустимый шестнадцатеричный цвет, например "#e67700", ' +
|
||||
"или на любую другую допустимую строку цвета css. Вы можете отменить эту настройку, добавив следующий frontmatter-ключ во встроенный файл разметки (markdown): <code>excalidraw-font-color: steelblue</code>",
|
||||
MD_DEFAULT_BORDER_COLOR_NAME: "Цвет границы, используемый по умолчанию для встроенных файлов разметки (markdown).",
|
||||
MD_DEFAULT_BORDER_COLOR_DESC:
|
||||
'Установите это значение на любое допустимое имя цвета css, например "steelblue" (<a href="https://www.w3schools.com/colors/colors_names.asp">имена цветов</a>), или на допустимый шестнадцатеричный цвет, например "#e67700", ' +
|
||||
"или на любую другую допустимую строку цвета css. Вы можете отменить эту настройку, добавив следующий frontmatter-key во встроенный файл разметки (markdown): <code>excalidraw-border-color: gray</code>. " +
|
||||
"Оставьте пустым, если вам не нужна граница. ",
|
||||
MD_CSS_NAME: "CSS файл",
|
||||
MD_CSS_DESC:
|
||||
"Имя файла CSS для применения к вставкам markdown. Укажите имя файла с расширением (например, 'md-embed.css'). Файл css также может быть обычным файлом " +
|
||||
"markdow (e.g. 'md-embed-css.md'), просто убедитесь, что содержимое написано с использованием правильного синтаксиса css. " +
|
||||
`Если вам нужно просмотреть HTML-код, к которому вы применяете CSS, откройте Obsidian Developer Console (${DEVICE.isIOS || DEVICE.isMacOS ? "CMD+OPT+i" : "CTRL+SHIFT+i"}) и введите следующую команду: ` +
|
||||
'"ExcalidrawAutomate.mostRecentMarkdownSVG". Это отобразит последний SVG, сгенерированный Excalidraw. ' +
|
||||
"Установка font-family в css имеет свои ограничения. По умолчанию доступны только стандартные шрифты вашей операционной системы (подробнее см. в README). " +
|
||||
"Вы можете добавить еще один пользовательский шрифт, используя настройки выше. " +
|
||||
'Вы можете переопределить эту настройку css, добавив следующий frontmatter-ключ во встроенный файл разметки: "excalidraw-css: css_file_in_vault|css-snippet".',
|
||||
EMBED_HEAD: "Встраивание Excalidraw в заметки и экспорт",
|
||||
EMBED_DESC: `В настройках "Вставка и экспорт" можно настроить вставку и экспорт изображений и рисунков Excalidraw в документы. Основные настройки включают выбор типа изображения для предварительного просмотра в формате разметки (например, Native SVG или PNG), указание типа файла для вставки в документ (оригинальный Excalidraw, PNG или SVG) и управление кэшированием изображений для вставки в разметку. Вы также можете управлять размерами изображений, вставлять рисунки с помощью ссылок на вики или ссылок на разметку, а также настраивать темы изображений, цвета фона и интеграцию с Obsidian.
|
||||
Кроме того, есть настройки автоэкспорта, который автоматически генерирует файлы SVG и/или PNG, соответствующие названию ваших рисунков Excalidraw, сохраняя их синхронизацию при переименовании и удалении файлов.`,
|
||||
EMBED_CANVAS: "Поддержка Obsidian Canvas",
|
||||
EMBED_CANVAS_NAME: "Иммерсивное встраивание",
|
||||
EMBED_CANVAS_DESC:
|
||||
"Скрывайте границы и фон узлов холста при встраивании чертежа Excalidraw в холст. " +
|
||||
"Обратите внимание, что для создания полностью прозрачного фона изображения вам все равно придется настроить Excalidraw на экспорт изображений с прозрачным фоном.",
|
||||
EMBED_CACHING: "Кэширование изображений",
|
||||
EXPORT_SUBHEAD: "Настройки экспорта",
|
||||
EMBED_SIZING: "Размер изображения",
|
||||
EMBED_THEME_BACKGROUND: "Тема изображения и цвет фона",
|
||||
EMBED_IMAGE_CACHE_NAME: "Кэширование изображений для вставки в markdown",
|
||||
EMBED_IMAGE_CACHE_DESC: "Кэшируйте изображения для вставки в markdown. Это ускорит процесс встраивания, но в случае, если вы составите изображения из нескольких чертежей-субкомпонентов, " +
|
||||
"встроенное изображение в Markdown не будет обновляться, пока вы не откроете рисунок и не сохраните его, чтобы вызвать обновление кэша.",
|
||||
SCENE_IMAGE_CACHE_NAME: "Кэширование вложенных Excalidraws в Cцене",
|
||||
SCENE_IMAGE_CACHE_DESC: "Кэшируйте вложенные Excalidraws в сцене для ускорения рендеринга сцены. Это ускорит процесс рендеринга, особенно если в сцене есть глубоко вложенные Excalidraw. " +
|
||||
"Excalidraw попытается интеллектуально определить, изменились ли дочерние элементы вложенного Excalidraw, и соответствующим образом обновит кэш. " +
|
||||
"Вы можете отключить эту функцию, если у вас есть подозрения, что кэш обновляется неправильно.",
|
||||
EMBED_IMAGE_CACHE_CLEAR: "Очистка кэша",
|
||||
BACKUP_CACHE_CLEAR: "Очистка резервных копий",
|
||||
BACKUP_CACHE_CLEAR_CONFIRMATION: "Это действие удалит все резервные копии чертежей Excalidraw. Резервные копии используются в качестве меры безопасности на случай повреждения файла рисунка. Каждый раз, когда вы открываете Obsidian, плагин автоматически удаляет резервные копии файлов, которые больше не существуют в вашем хранилище. Вы уверены, что хотите удалить все резервные копии?",
|
||||
EMBED_REUSE_EXPORTED_IMAGE_NAME: "Если найдено, используйте уже экспортированное изображение для предварительного просмотра",
|
||||
EMBED_REUSE_EXPORTED_IMAGE_DESC:
|
||||
"Эта настройка работает в сочетании с настройкой <a href='#«+TAG_AUTOEXPORT+»'>Автоэкспорт SVG/PNG</a>. Если имеется экспортированное изображение, соответствующее имени файла чертежа, используйте это изображение вместо того, " +
|
||||
"чтобы генерировать изображение предварительного просмотра на лету. Однако это позволит ускорить предварительный просмотр, особенно если в чертеже много встроенных объектов, " +
|
||||
"может случиться так, что последние изменения не будут отображаться, а изображение не будет автоматически соответствовать вашей теме Obsidian, " +
|
||||
"если вы изменили тему Obsidian с момента создания экспорта. Эта настройка применяется только для вставки изображений в документы markdown. " +
|
||||
"По ряду причин этот же подход не может быть использован для ускорения загрузки чертежей с большим количеством встроенных объектов. Смотрите демонстрацию <a href='https://github.com/zsviczian/obsidian-excalidraw-plugin/releases/tag/1.6.23' target='_blank'>здесь</a>.",
|
||||
/*EMBED_PREVIEW_SVG_NAME: "Отображение SVG в предварительном просмотре разметки (markdown)",
|
||||
EMBED_PREVIEW_SVG_DESC:
|
||||
"<b><u>Переключатель ВКЛ:</u></b> Вставьте рисунок как изображение <a href='https://en.wikipedia.org/wiki/Scalable_Vector_Graphics' target='_blank'>SVG</a> в предварительный просмотр разметки (markdown).<br>" +
|
||||
"<b><u>Переключатель ВЫКЛ:</u></b> Встроить рисунок как изображение <a href='' target='_blank'>PNG</a>. Обратите внимание, что некоторые из <a href='https://www.youtube.com/watch?v=yZQoJg2RCKI&t=633s' target='_blank'>функций ссылок на блоки изображений</a> не работают с встраиванием PNG.",*/
|
||||
EMBED_PREVIEW_IMAGETYPE_NAME: "Тип изображения в предварительном просмотре разметки (markdown)",
|
||||
EMBED_PREVIEW_IMAGETYPE_DESC:
|
||||
"<b><u>Родной SVG</u></b>: Высокое качество изображения. Встраиваемые веб-сайты, видео с YouTube, ссылки на Obsidian и внешние изображения, вставленные через URL-адрес, будут работать. Встроенные страницы Obsidian не будут<br>" +
|
||||
"<b><u>SVG-изображение</u></b>: Высокое качество изображений. Встроенные элементы и изображения, вставленные по URL, имеют только заполнители, ссылки не работают<br>" +
|
||||
"<b><u>PNG-изображение</u></b>: Более низкое качество изображения, но в некоторых случаях лучшая производительность при работе с большими рисунками. Встроенные элементы и изображения, вставленные по URL, имеют только заполнители, ссылки не работают. Также некоторые функции <a href='https://www.youtube.com/watch?v=yZQoJg2RCKI&t=633s' target='_blank'>ссылки на блок изображений</a> не работают с PNG-вставками.",
|
||||
PREVIEW_MATCH_OBSIDIAN_NAME: "Предварительный просмотр Excalidraw в соответствии с темой Obsidian",
|
||||
PREVIEW_MATCH_OBSIDIAN_DESC:
|
||||
"Предварительный просмотр изображений в документах должен соответствовать теме Obsidian. Если эта функция включена, то когда Obsidian находится в темном режиме, изображения Excalidraw будут отображаться в темном режиме. " +
|
||||
"Когда Obsidian находится в режиме освещения, Excalidraw также будет рендерить в режиме освещения. Вы можете отключить функцию 'Экспортировать изображение с фоном', чтобы получить более интегрированный в Obsidian вид и ощущение.",
|
||||
EMBED_WIDTH_NAME: "Ширина по умолчанию для встроенного ('включенного') изображения",
|
||||
EMBED_WIDTH_DESC:
|
||||
"Ширина по умолчанию для встроенного рисунка. Это относится к режиму редактирования и чтения, а также к предварительным просмотрам при наведении. При вставке изображения можно указать его " +
|
||||
"ширину используя <code>![[drawing.excalidraw|100]]</code> или " +
|
||||
"<code>[[drawing.excalidraw|100x100]]</code> формат.",
|
||||
EMBED_HEIGHT_NAME: "Высота по умолчанию для встроенного ('включенного') изображения",
|
||||
EMBED_HEIGHT_DESC:
|
||||
"Высота по умолчанию для встроенного рисунка. Это относится к режиму редактирования и чтения, а также к предварительным просмотрам при наведении. При вставке изображения можно указать его " +
|
||||
"высоту используя <code>![[drawing.excalidraw|100]]</code> или " +
|
||||
"<code>[[drawing.excalidraw|100x100]]</code> формат.",
|
||||
EMBED_TYPE_NAME: "Тип файла для вставки в документ",
|
||||
EMBED_TYPE_DESC:
|
||||
"Когда вы вставляете изображение в документ с помощью командной палитры, этот параметр определяет, должен ли Excalidraw вставлять оригинальный файл Excalidraw " +
|
||||
"или копию PNG или SVG. Чтобы эти типы изображений были доступны в раскрывающемся списке, их необходимо включить <a href='#"+TAG_AUTOEXPORT+"'>auto-export PNG / SVG</a> (см. ниже в разделе 'Настройки экспорта'). Для чертежей, не имеющих соответствующего PNG или " +
|
||||
"SVG, действие из палитры команд вставит неработающую ссылку. Необходимо открыть исходный чертеж и инициировать экспорт вручную. " +
|
||||
"Эта опция не будет автоматически генерировать файлы PNG/SVG, а просто будет ссылаться на уже существующие файлы.",
|
||||
EMBED_MARKDOWN_COMMENT_NAME: "Вставить ссылку на чертеж как комментари",
|
||||
EMBED_MARKDOWN_COMMENT_DESC:
|
||||
"Вставьте ссылку на исходный файл Excalidraw в виде ссылки в формате markdown под изображением, например: <code>%%[[drawing.excalidraw]]%%</code>.<br>" +
|
||||
"Вместо добавления комментария можно также выделить встроенную строку SVG или PNG и использовать действие из палитры команд: " +
|
||||
"'<code>Excalidraw: Open Excalidraw drawing</code>' чтобы открыть чертеж.",
|
||||
EMBED_WIKILINK_NAME: "Встраивание рисунка с помощью ссылки Wiki",
|
||||
EMBED_WIKILINK_DESC: "<b><u>Переключатель ВКЛ:</u></b> Excalidraw будет встраивать [[wiki link]].<br><b><u>Переключатель ВЫКЛ:</u></b> Excalidraw будет встраивать [markdown](link).",
|
||||
EXPORT_PNG_SCALE_NAME: "Масштаб экспортируемого изображения PNG",
|
||||
EXPORT_PNG_SCALE_DESC: "Масштаб экспортируемого PNG-изображения",
|
||||
EXPORT_BACKGROUND_NAME: "Экспорт изображения с фоном",
|
||||
EXPORT_BACKGROUND_DESC: "Если отключить эту функцию, экспортируемое изображение будет прозрачным.",
|
||||
EXPORT_PADDING_NAME: "Отступы изображений",
|
||||
EXPORT_PADDING_DESC:
|
||||
"Размер (в пикселях) вокруг экспортируемого изображения SVG или PNG. Для ссылок на clippedFrame значение Отступов равно 0." +
|
||||
"Если кривые линии расположены близко к краю изображения, они могут быть обрезаны при экспорте. Вы можете увеличить это значение, чтобы избежать обрезки. " +
|
||||
"Вы также можете отменить эту настройку на уровне файла, добавив ключ frontmatter <code>excalidraw-export-padding: 5<code>.",
|
||||
EXPORT_THEME_NAME: "Экспорт изображения с темой",
|
||||
EXPORT_THEME_DESC:
|
||||
"Экспортируйте изображение, соответствующее темной/светлой теме вашего рисунка. Если отключить эту функцию, " +
|
||||
"рисунки, созданные в темном режиме, будут отображаться так же, как и в светлом режиме. ",
|
||||
EXPORT_EMBED_SCENE_NAME: "Встроить сцену в экспортированное изображение",
|
||||
EXPORT_EMBED_SCENE_DESC:
|
||||
"Вставка сцены Excalidraw в экспортируемое изображение. Можно переопределить на уровне файла, добавив ключ frontmatter. <code>excalidraw-export-embed-scene: true/false<code>. " +
|
||||
"Настройка вступит в силу только при следующем (повторном) открытии чертежей.",
|
||||
EXPORT_HEAD: "Настройки автоэкспорта",
|
||||
EXPORT_SYNC_NAME: "Поддерживайте синхронизацию имен файлов .SVG и/или .PNG с файлом чертежа",
|
||||
EXPORT_SYNC_DESC:
|
||||
"Если плагин включен, он будет автоматически обновлять имена файлов .SVG и/или .PNG при переименовании чертежа в той же папке (и с тем же именем). " +
|
||||
"Плагин также автоматически удалит файлы .SVG и/или .PNG при удалении рисунка в той же папке (и с тем же именем). ",
|
||||
EXPORT_SVG_NAME: "Автоэкспорт SVG",
|
||||
EXPORT_SVG_DESC:
|
||||
"Автоматическое создание SVG-экспорта вашего чертежа, соответствующего названию файла. " +
|
||||
"Плагин сохранит файл *.SVG в той же папке, что и чертеж. " +
|
||||
"Встраивайте .svg-файл в документы вместо Excalidraw, делая вставки независимыми от платформы. " +
|
||||
"Если переключатель автоэкспорта включен, этот файл будет обновляться каждый раз, когда вы редактируете чертеж Excalidraw с соответствующим именем. " +
|
||||
"Вы можете отменить эту настройку на уровне файла, добавив ключ frontmatter <code>excalidraw-autoexport</code>.Допустимыми значениями для этого ключа являются" +
|
||||
"<code>none</code>,<code>both</code>,<code>svg</code>, и <code>png</code>.",
|
||||
EXPORT_PNG_NAME: "Автоэкспорт PNG",
|
||||
EXPORT_PNG_DESC: "То же самое, что и автоэкспорт SVG, но для *.PNG",
|
||||
EXPORT_BOTH_DARK_AND_LIGHT_NAME: "Экспорт изображения с темной и светлой тематикой",
|
||||
EXPORT_BOTH_DARK_AND_LIGHT_DESC: "Если включить эту функцию, Excalidraw будет экспортировать два файла вместо одного: filename.dark.png, filename.light.png и/или filename.dark.svg и filename.light.svg.<br>" +
|
||||
"Двойные файлы будут экспортированы как при включенном автоэкспорте SVG или PNG (или обоих), так и при нажатии кнопки экспорта на одном изображении.",
|
||||
COMPATIBILITY_HEAD: "Особенности совместимости",
|
||||
COMPATIBILITY_DESC: "Включать эти функции следует только в том случае, если у вас есть веские причины работать с файлами excalidraw.com, а не с файлами markdown. Многие функции плагина не поддерживаются в старых файлах. Типичным случаем может быть использование хранилища поверх папки проекта Visual Studio Code, а также наличие чертежей .excalidraw, к которым вы хотите получить доступ из Visual Studio Code. Другим примером может быть параллельное использование Excalidraw в Logseq и Obsidian.",
|
||||
DUMMY_TEXT_ELEMENT_LINT_SUPPORT_NAME: "Совместимость с линтерами",
|
||||
DUMMY_TEXT_ELEMENT_LINT_SUPPORT_DESC: "Excalidraw чувствителен к структуре файлов ниже <code># Excalidraw Data</code>. Автоматическая линтинговая обработка документов может создавать ошибки в Excalidraw Data. " +
|
||||
"Хотя я приложил некоторые усилия, чтобы сделать загрузку данных устойчивой к изменениям линта," +
|
||||
"это решение не является надежным.<br><mark>Лучше всего избегать линтинга или других автоматических изменений документов Excalidraw с помощью различных плагинов.</mark><br>" +
|
||||
"Используйте эту настройку, если по уважительным причинам вы решили проигнорировать мою рекомендацию и настроили линтинг файлов Excalidraw.<br> " +
|
||||
"Раздел <code>## Текстовые элементы</code> чувствителен к пустым строкам. Обычный подход к линтингу заключается в добавлении пустой строки после заголовков разделов. В случае Excalidraw это приведет к поломке/изменению первого текстового элемента в чертеже. " +
|
||||
"Чтобы решить эту проблему, можно включить эту настройку. WhenЕсли она включена, Excalidraw добавит в начало фиктивный элемент, <code>## Текстовые элементы</code> который линтер может безопасно модифицировать." ,
|
||||
PRESERVE_TEXT_AFTER_DRAWING_NAME: "Совместимость Zotero и Footnotes",
|
||||
PRESERVE_TEXT_AFTER_DRAWING_DESC: "Сохраните текст после раздела ## Чертеж в файле Markdown. Это может незначительно повлиять на производительность при сохранении очень больших рисунков.",
|
||||
DEBUGMODE_NAME: "Включить отладочные сообщения",
|
||||
DEBUGMODE_DESC: "Я рекомендую перезапустить Obsidian после включения/выключения этой настройки. Это позволяет выводить отладочные сообщения в консоль. Это полезно для устранения неполадок. " +
|
||||
"Если у вас возникли проблемы с плагином, пожалуйста, включите эту настройку, воспроизведите проблему и включите журнал консоли в проблему, которую вы поднимаете на <a href='https://github.com/zsviczian/obsidian-excalidraw-plugin/issues'>GitHub</a>",
|
||||
SLIDING_PANES_NAME: "Поддержка плагина раздвижных областей окна (Sliding Panes plugin)",
|
||||
SLIDING_PANES_DESC:
|
||||
"Чтобы это изменение вступило в силу, необходимо перезапустить Obsidian.<br>" +
|
||||
"Если вы используете <a href='https://github.com/deathau/sliding-panes-obsidian' target='_blank'>Sliding Panes plugin</a> " +
|
||||
"Вы можете включить эту настройку, чтобы чертежи Excalidraw работали с плагином Sliding Panes.<br>" +
|
||||
"Обратите внимание, что поддержка раздвижных областей окна (Sliding Panes plugin) Excalidraw вызывает проблемы совместимости с рабочими пространствами Obsidian.<br>" +
|
||||
"Обратите внимание, что функция 'Stack Tabs' теперь доступна в Obsidian, обеспечивая встроенную поддержку большинства функций раздвижных областей окна (Sliding Panes plugin)",
|
||||
EXPORT_EXCALIDRAW_NAME: "Автоэкспорт Excalidraw",
|
||||
EXPORT_EXCALIDRAW_DESC: "Аналогично автоэкспорту SVG, но для *.Excalidraw",
|
||||
SYNC_EXCALIDRAW_NAME: "Синхронизация *.excalidraw с *.md-версией одного и того же чертежа",
|
||||
SYNC_EXCALIDRAW_DESC:
|
||||
"Если дата изменения файла *.excalidraw более поздняя, чем дата изменения файла *.md " +
|
||||
"то обновите чертеж в файле .md на основе файла .excalidraw",
|
||||
COMPATIBILITY_MODE_NAME: "Новые чертежи в виде устаревших файлов",
|
||||
COMPATIBILITY_MODE_DESC:
|
||||
"⚠️ Включайте эту функцию, только если вы знаете, что делаете. В 99,9% случаев включать эту функцию НЕ нужно. " +
|
||||
"При включении этой функции рисунки, которые вы создаете с помощью значка ленты, действий палитры команд, " +
|
||||
"и в файловом проводнике, будут все старые файлы *.excalidraw. Эта настройка также отключит напоминание" +
|
||||
"при открытии устаревшего файла для редактирования.",
|
||||
MATHJAX_NAME: "Хост библиотеки javascript MathJax (LaTeX)",
|
||||
MATHJAX_DESC: "Если вы используете уравнения LaTeX в Excalidraw, то плагину необходимо загрузить библиотеку javascript для этого. " +
|
||||
"Некоторые пользователи не могут получить доступ к определенным хост-серверам. Если у вас возникли проблемы, попробуйте сменить хост здесь. "+
|
||||
"Возможно, вам придется перезапустить Obsidian после закрытия настроек, чтобы это изменение вступило в силу.",
|
||||
LATEX_DEFAULT_NAME: "Формула LaTeX по умолчанию для новых уравнений",
|
||||
LATEX_DEFAULT_DESC: "Оставьте пустым, если вам не нужна формула по умолчанию. Здесь можно добавить форматирование по умолчанию, например <code>\\color{white}</code>.",
|
||||
NONSTANDARD_HEAD: "Поддерживаемые функции, не с Excalidraw.com",
|
||||
NONSTANDARD_DESC: `Эти настройки в разделе "Поддерживаемые функции, не относящиеся к Excalidraw.com" предоставляют возможности настройки, выходящие за рамки стандартных функций Excalidraw.com. Эти функции недоступны на сайте excalidraw.com. При экспорте чертежа в Excalidraw.com эти функции будут выглядеть иначе.
|
||||
Вы можете настроить количество пользовательских ручек, отображаемых рядом с меню Obsidian на холсте, что позволит вам выбирать из множества вариантов. Кроме того, можно включить опцию локального шрифта, которая добавляет локальный шрифт в список шрифтов на панели свойств элементов для текстовых элементов. `,
|
||||
RENDER_TWEAK_HEAD: "Улучшения рендеринга",
|
||||
MAX_IMAGE_ZOOM_IN_NAME: "Максимальное разрешение увеличения изображения",
|
||||
MAX_IMAGE_ZOOM_IN_DESC: "В целях экономии памяти и из-за того, что Apple Safari (Obsidian на iOS) имеет некоторые жестко закодированные ограничения, Excalidraw.com ограничивает максимальное разрешение изображений и крупных объектов при увеличении. Вы можете обойти это ограничение с помощью мультипликатора. " +
|
||||
"Это означает, что вы умножаете предел, установленный по умолчанию в Excalidraw. Чем больше множитель, тем лучше будет разрешение увеличения изображения, и тем больше памяти оно будет потреблять. " +
|
||||
"Я рекомендую поиграть с несколькими значениями этой настройки. Вы знаете, что натолкнулись на стену, когда при увеличении масштаба PNG-изображения оно вдруг исчезает из поля зрения. Значение по умолчанию - 1. Настройка не влияет на iOS.",
|
||||
CUSTOM_PEN_HEAD: "Пользовательские Ручки",
|
||||
CUSTOM_PEN_NAME: "Количество пользовательских ручек",
|
||||
CUSTOM_PEN_DESC: "Вы увидите эти ручки рядом с меню Obsidian на холсте. Вы можете настроить ручки на холсте, долго нажимая на кнопку ручки.",
|
||||
EXPERIMENTAL_HEAD: "Разные возможности",
|
||||
EXPERIMENTAL_DESC: `Среди прочих возможностей Excalidraw - установка формул LaTeX по умолчанию для новых уравнений, включение Предложение полей (Suggester) для автозаполнения, отображение индикаторов типов файлов Excalidraw, включение иммерсивного встраивания изображений в режиме предварительного просмотра и эксперименты с оптическим распознаванием символов Taskbone для извлечения текста из изображений и чертежей. Пользователи также могут ввести API-ключ Taskbone для расширенного использования сервиса OCR.`,
|
||||
EA_HEAD: "Автоматизация Excalidraw",
|
||||
EA_DESC:
|
||||
"Excalidraw Автоматизация - это скриптовый и автоматизированный API для Excalidraw. К сожалению, документация по API скудна. " +
|
||||
"Рекомендую прочитать <a href='https://github.com/zsviczian/obsidian-excalidraw-plugin/blob/master/docs/API/ExcalidrawAutomate.d.ts'>ExcalidrawAutomate.d.ts</a> файл, " +
|
||||
"посетить <a href='https://zsviczian.github.io/obsidian-excalidraw-plugin/'>ExcalidrawAutomate How-to</a> страницу - хотя информация " +
|
||||
"здесь давно не обновлялся, - и, наконец, включите расположенный ниже Предложитель полей. Предложитель полей покажет вам доступные " +
|
||||
"функции, их параметры и краткое описание по мере ввода. Предложитель полей - это самая актуальная документация по API.",
|
||||
FIELD_SUGGESTER_NAME: "Включить Предложение полей (Suggester)",
|
||||
FIELD_SUGGESTER_DESC:
|
||||
"Предложение полей (Suggester) позаимствован у плагинов Breadcrumbs и Templater. Предложение полей (Suggester) полей будет показывать " +
|
||||
"меню автозаполнения при вводе текста с описанием функций <code>excalidraw-</code> или <code>ea.</code> в качестве подсказок для отдельных элементов в списке.",
|
||||
STARTUP_SCRIPT_NAME: "Сценарий запуска",
|
||||
STARTUP_SCRIPT_DESC:
|
||||
"Если этот параметр установлен, excalidraw будет выполнять скрипт при запуске плагина. Это полезно, если вы хотите установить какой-либо из крючков Excalidraw Automate. " +
|
||||
"Скрипт запуска - это файл в формате markdown, который должен содержать код javascript, который вы хотите выполнять при запуске Excalidraw.",
|
||||
STARTUP_SCRIPT_BUTTON_CREATE: "Создание сценария запуска",
|
||||
STARTUP_SCRIPT_BUTTON_OPEN: "Открыть сценарий запуска",
|
||||
STARTUP_SCRIPT_EXISTS: "Файл сценария запуска уже существует",
|
||||
FILETYPE_NAME: "Тип отображения (✏️) для файлов excalidraw.md в Файловом Проводнике",
|
||||
FILETYPE_DESC: "Файлы Excalidraw получат индикатор с помощью эмодзи или текста, заданного в следующей настройке.",
|
||||
FILETAG_NAME: "Установка типа индикатора для файлов excalidraw.md",
|
||||
FILETAG_DESC: "Текст или эмодзи для отображения в качестве типа индикатора.",
|
||||
INSERT_EMOJI: "Вставьте эмодзи",
|
||||
LIVEPREVIEW_NAME: "Встраивание изображений в режиме предварительного просмотра в реальном времени",
|
||||
LIVEPREVIEW_DESC:
|
||||
"Включите этот параметр для поддержки стилей вставки изображений, таких как ![[drawing|width|style]], в режиме редактирования живого предварительного просмотра. " +
|
||||
"Настройка не повлияет на открытые в данный момент документы. Чтобы изменения вступили в силу, необходимо закрыть открытые документы и" +
|
||||
"открыть их снова.",
|
||||
FADE_OUT_EXCALIDRAW_MARKUP_NAME: "Затухание разметки Excalidraw",
|
||||
FADE_OUT_EXCALIDRAW_MARKUP_DESC: "В режиме просмотра Markdown раздел после комментария %% исчезает. " +
|
||||
"Текст остается на месте, но визуальный беспорядок уменьшается. Обратите внимание, вы можете поместить %% в строку прямо над #Элементы текста, " +
|
||||
"в этом случае вся разметка рисунка исчезнет, включая #Элементы текста. Побочным эффектом будет то, что вы не сможете блокировать текст ссылок в других примечаниях, то есть после секции комментариев %%. Это редко является проблемой. " +
|
||||
"Если вы захотите отредактировать сценарий разметки Excalidraw, просто переключитесь в режим просмотра разметки и временно удалите комментарий %%.",
|
||||
EXCALIDRAW_PROPERTIES_NAME: "Загрузка свойств Excalidraw в Obsidian Suggester",
|
||||
EXCALIDRAW_PROPERTIES_DESC: "Отключите этот параметр, чтобы при запуске плагина свойства документа Excalidraw загружались в предложение свойств Obsidian. "+
|
||||
"Включение этой функции упрощает использование свойств титульного листа Excalidraw, позволяя использовать множество мощных настроек. Если вы предпочитаете не загружать эти свойства автоматически, " +
|
||||
"Вы можете отключить эту функцию, но при этом вам придется вручную удалить все ненужные свойства из предложения. " +
|
||||
"Обратите внимание, что включение этой настройки требует перезапуска плагина, так как свойства загружаются при запуске.",
|
||||
CUSTOM_FONT_HEAD: "Локальный шрифт",
|
||||
ENABLE_FOURTH_FONT_NAME: "Включите опцию локального шрифта",
|
||||
ENABLE_FOURTH_FONT_DESC:
|
||||
"Включение этой опции добавит локальный шрифт в список шрифтов на панели свойств для текстовых элементов. " +
|
||||
"Имейте в виду, что использование локального шрифта может нарушить независимость от платформы. " +
|
||||
"Файлы, использующие пользовательский шрифт, могут отображаться по-разному при открытии в другом хранилище или в более позднее время, в зависимости от настроек шрифта. " +
|
||||
"Кроме того, на сайте excalidraw.com или других версиях Excalidraw 4-й шрифт по умолчанию будет соответствовать системному шрифту.",
|
||||
FOURTH_FONT_NAME: "Локальный файл шрифта",
|
||||
FOURTH_FONT_DESC:
|
||||
"Выберите файл шрифта .otf, .ttf, .woff или .woff2 из своего хранилища, чтобы использовать его в качестве локального шрифта. " +
|
||||
"Если файл не выбран, Excalidraw по умолчанию использует шрифт Virgil. " +
|
||||
"Для оптимальной производительности рекомендуется использовать файл .woff2, так как Excalidraw закодирует только необходимые глифы при экспорте изображений в SVG. " +
|
||||
"Другие форматы шрифтов будут встраивать весь шрифт в экспортируемый файл, что может привести к значительному увеличению размера файла.",
|
||||
SCRIPT_SETTINGS_HEAD: "Настройки для установленных сценариев",
|
||||
SCRIPT_SETTINGS_DESC: "Некоторые сценарии Excalidraw Automate Scripts включают в себя настройки. Настройки упорядочены по сценариям. Настройки станут видны в этом списке только после того, как вы один раз выполните загруженный скрипт.",
|
||||
TASKBONE_HEAD: "Taskbone Оптический распознаватель символов",
|
||||
TASKBONE_DESC: "Это экспериментальная интеграция оптического распознавания символов в Excalidraw. Обратите внимание, что taskbone - это независимый внешний сервис, не предоставляемый ни Excalidraw, ни проектом плагинов Excalidraw-Obsidian. " +
|
||||
"Сервис OCR выхватывает разборчивый текст из произвольных линий и встроенных изображений на вашем холсте и помещает распознанный текст на передний план вашего рисунка, а также в буфер обмена. " +
|
||||
"Наличие текста во frontmatter позволит вам искать в Obsidian их текстовое содержание. " +
|
||||
"Обратите внимание, что процесс извлечения текста из изображения происходит не локально, а через онлайн API. Сервис taskbone хранит изображение на своих серверах только до тех пор, пока это необходимо для извлечения текста. Однако если вас это не устраивает, не используйте эту функцию.",
|
||||
TASKBONE_ENABLE_NAME: "Включить Taskbone",
|
||||
TASKBONE_ENABLE_DESC: "Включая эту услугу, вы соглашаетесь с <a href='https://www.taskbone.com/legal/terms/' target='_blank'>Условиями использования Taskbone </a> и " +
|
||||
"<a href='https://www.taskbone.com/legal/privacy/' target='_blank'>политикой конфиденциальности</a>.",
|
||||
TASKBONE_APIKEY_NAME: "Taskbone API Ключ",
|
||||
TASKBONE_APIKEY_DESC: "Taskbone предлагает бесплатную услугу с разумным количеством сканирований в месяц. Если вы хотите использовать эту функцию чаще, или вам необходимо повысить " +
|
||||
"разработчика Taskbone (как вы можете себе представить, не существует такого понятия, как «бесплатно», предоставление этого потрясающего сервиса OCR стоит разработчику Taskbone определенных денег), вы можете " +
|
||||
"приобрести платный API-ключ на сайте <a href='https://www.taskbone.com/' target='_blank'>taskbone.com</a>. Если вы уже приобрели ключ, просто перезапишите этот автоматически сгенерированный бесплатный API-ключ своим платным ключом.",
|
||||
|
||||
//HotkeyEditor
|
||||
HOTKEY_PRESS_COMBO_NANE: "Нажмите комбинацию горячих клавиш",
|
||||
HOTKEY_PRESS_COMBO_DESC: "Пожалуйста, нажмите нужную комбинацию клавиш",
|
||||
HOTKEY_BUTTON_ADD_OVERRIDE: "Добавить новое переопределение",
|
||||
HOTKEY_BUTTON_REMOVE: "Удалить",
|
||||
|
||||
//openDrawings.ts
|
||||
SELECT_FILE: "Выберите файл и нажмите Enter.",
|
||||
SELECT_COMMAND: "Выберите команду и нажмите Enter.",
|
||||
SELECT_FILE_WITH_OPTION_TO_SCALE: `Выберите файл и нажмите ENTER, или ${labelSHIFT()}+${labelMETA()}+ENTER для вставки в масштабе 100%.`,
|
||||
NO_MATCH: "Ни один файл не соответствует вашему запросу.",
|
||||
NO_MATCHING_COMMAND: "Ни одна команда не соответствует вашему запросу.",
|
||||
SELECT_FILE_TO_LINK: "Выберите файл, для которого нужно вставить ссылку.",
|
||||
SELECT_COMMAND_PLACEHOLDER: "Выберите команду, для которой нужно вставить ссылку.",
|
||||
SELECT_DRAWING: "Выберите изображение или рисунок, который необходимо вставить.",
|
||||
TYPE_FILENAME: "Введите название чертежа для выбора.",
|
||||
SELECT_FILE_OR_TYPE_NEW: "Выберите существующий чертеж или введите имя нового чертежа, затем нажмите Enter.",
|
||||
SELECT_TO_EMBED: "Выберите чертеж для вставки в активный документ.",
|
||||
SELECT_MD: "Выберите документ в формате markdown для вставки.",
|
||||
SELECT_PDF: "Выберите документ PDF для вставки.",
|
||||
PDF_PAGES_HEADER: "Страницы для загрузки?",
|
||||
PDF_PAGES_DESC: "Формат: 1, 3-5, 7, 9-11",
|
||||
|
||||
//SelectCard.ts
|
||||
TYPE_SECTION: "Введите название раздела для выбора.",
|
||||
SELECT_SECTION_OR_TYPE_NEW: "Выберите существующий раздел или введите название нового раздела, затем нажмите Enter.",
|
||||
INVALID_SECTION_NAME: "Недопустимое название раздела.",
|
||||
EMPTY_SECTION_MESSAGE: "Введите название раздела и нажмите Enter, чтобы создать новый раздел.",
|
||||
|
||||
//EmbeddedFileLoader.ts
|
||||
INFINITE_LOOP_WARNING: "ПРЕДУПРЕЖДЕНИЕ EXCALIDRAW\nОшибка при загрузке встроенных изображений из-за бесконечного цикла в файле:\n",
|
||||
|
||||
//Scripts.ts
|
||||
SCRIPT_EXECUTION_ERROR: "Ошибка выполнения сценария. Пожалуйста, найдите сообщение об ошибке в консоли разработчика.",
|
||||
|
||||
//ExcalidrawData.ts
|
||||
LOAD_FROM_BACKUP: "Файл Excalidraw был поврежден. Загрузка из резервного файла.",
|
||||
|
||||
//ObsidianMenu.tsx
|
||||
GOTO_FULLSCREEN: "Переход в полноэкранный режим",
|
||||
EXIT_FULLSCREEN: "Выход из полноэкранного режима",
|
||||
TOGGLE_FULLSCREEN: "Переключить полноэкранный режим",
|
||||
TOGGLE_DISABLEBINDING: "Переключить инвертирование поведения привязки по умолчанию",
|
||||
TOGGLE_FRAME_RENDERING: "Переключить рендеринг кадра",
|
||||
TOGGLE_FRAME_CLIPPING: "Переключить обрезку кадра",
|
||||
OPEN_LINK_CLICK: "Открыть ссылку",
|
||||
OPEN_LINK_PROPS: "Открыть ссылку на изображение или редактор формул LaTeX",
|
||||
|
||||
//IFrameActionsMenu.tsx
|
||||
NARROW_TO_HEADING: "Узкий к заголовку...",
|
||||
NARROW_TO_BLOCK: "Сузить до блока...",
|
||||
SHOW_ENTIRE_FILE: "Показать весь файл",
|
||||
ZOOM_TO_FIT: "Увеличить до нужного размера",
|
||||
RELOAD: "Перезагрузить исходную ссылку",
|
||||
OPEN_IN_BROWSER: "Открыть текущую ссылку в браузере",
|
||||
PROPERTIES: "Свойства",
|
||||
COPYCODE: "Копировать источник в буфер обмена",
|
||||
|
||||
//EmbeddableSettings.tsx
|
||||
ES_TITLE: "Настройки встраиваемых элементов",
|
||||
ES_RENAME: "Переименовать файл",
|
||||
ES_ZOOM: "Масштабирование встраиваемого контента",
|
||||
ES_YOUTUBE_START: "Время начала YouTube",
|
||||
ES_YOUTUBE_START_DESC: "ss, mm:ss, hh:mm:ss",
|
||||
ES_YOUTUBE_START_INVALID: "Время начала YouTube недействительно. Проверьте формат и повторите попытку.",
|
||||
ES_FILENAME_VISIBLE: "Видимое имя файла",
|
||||
ES_BACKGROUND_HEAD: "Цвет фона встроенной заметки",
|
||||
ES_BACKGROUND_MATCH_ELEMENT: "Соответствие фонового цвета элемента",
|
||||
ES_BACKGROUND_MATCH_CANVAS: "Соответствие цвета фона холста",
|
||||
ES_BACKGROUND_COLOR: "Цвет фона",
|
||||
ES_BORDER_HEAD: "Цвет границы встроенной заметки",
|
||||
ES_BORDER_COLOR: "Цвет границы",
|
||||
ES_BORDER_MATCH_ELEMENT: "Цвет границы элемента",
|
||||
ES_BACKGROUND_OPACITY: "Непрозрачность фона",
|
||||
ES_BORDER_OPACITY: "Непрозрачность границы",
|
||||
ES_EMBEDDABLE_SETTINGS: "Настройки встраиваемой разметки",
|
||||
ES_USE_OBSIDIAN_DEFAULTS: "Использовать настройки Obsidian по умолчанию",
|
||||
ES_ZOOM_100_RELATIVE_DESC: "Кнопка настроит масштаб элемента так, чтобы он отображал содержимое на 100% относительно текущего уровня масштабирования холста",
|
||||
ES_ZOOM_100: "Относительный 100%",
|
||||
|
||||
//Prompts.ts
|
||||
PROMPT_FILE_DOES_NOT_EXIST: "Файл не существует. Вы хотите его создать?",
|
||||
PROMPT_ERROR_NO_FILENAME: "Ошибка: Имя нового файла не может быть пустым",
|
||||
PROMPT_ERROR_DRAWING_CLOSED: "Неизвестная ошибка. Похоже, что ваш чертеж был закрыт или файл чертежа отсутствует",
|
||||
PROMPT_TITLE_NEW_FILE: "Новый файл",
|
||||
PROMPT_TITLE_CONFIRMATION: "Подтверждение",
|
||||
PROMPT_BUTTON_CREATE_EXCALIDRAW: "Создать EX",
|
||||
PROMPT_BUTTON_CREATE_EXCALIDRAW_ARIA: "Создать чертеж Excalidraw и открыть его в новой вкладке",
|
||||
PROMPT_BUTTON_CREATE_MARKDOWN: "Создать MD",
|
||||
PROMPT_BUTTON_CREATE_MARKDOWN_ARIA: "Создать документ в формате markdown и открыть его в новой вкладке",
|
||||
PROMPT_BUTTON_EMBED_MARKDOWN: "Встроить MD",
|
||||
PROMPT_BUTTON_EMBED_MARKDOWN_ARIA: "Замена выбранного элемента встроенным документом с разметкой",
|
||||
PROMPT_BUTTON_NEVERMIND: "Неважно",
|
||||
PROMPT_BUTTON_OK: "OK",
|
||||
PROMPT_BUTTON_CANCEL: "Отменить",
|
||||
PROMPT_BUTTON_INSERT_LINE: "Вставить новую строку",
|
||||
PROMPT_BUTTON_INSERT_SPACE: "Вставить пробел",
|
||||
PROMPT_BUTTON_INSERT_LINK: "Вставить ссылку на файл в формате markdown",
|
||||
PROMPT_BUTTON_UPPERCASE: "Прописные буквы",
|
||||
PROMPT_SELECT_TEMPLATE: "Выберите шаблон",
|
||||
|
||||
//ModifierKeySettings
|
||||
WEB_BROWSER_DRAG_ACTION: "Действие перетаскивания веб-браузера",
|
||||
LOCAL_FILE_DRAG_ACTION: "Действие перетаскивания локального файла ОС",
|
||||
INTERNAL_DRAG_ACTION: "Внутреннее действие перетаскивания в Obsidian",
|
||||
PANE_TARGET: "Поведение при нажатии на ссылку",
|
||||
DEFAULT_ACTION_DESC: "Если ни одна из комбинаций не применяется, для этой группы будет действовать действие по умолчанию: ",
|
||||
|
||||
//FrameSettings.ts
|
||||
FRAME_SETTINGS_TITLE: "Настройки кадров",
|
||||
FRAME_SETTINGS_ENABLE: "Включить кадры",
|
||||
FRAME_SETTIGNS_NAME: "Отображение имени кадра",
|
||||
FRAME_SETTINGS_OUTLINE: "Отображение контура кадра",
|
||||
FRAME_SETTINGS_CLIP: "Включить обрезку кадра",
|
||||
|
||||
//InsertPDFModal.ts
|
||||
IPM_PAGES_TO_IMPORT_NAME: "Страницы для импорта",
|
||||
IPM_SELECT_PAGES_TO_IMPORT: "Пожалуйста, выберите страницы для импорта",
|
||||
IPM_ADD_BORDER_BOX_NAME: "Добавить рамку",
|
||||
IPM_ADD_FRAME_NAME: "Добавить страницу в кадр",
|
||||
IPM_ADD_FRAME_DESC: "Для удобства работы я рекомендую зафиксировать страницу внутри кадра. " +
|
||||
"Однако если вы заблокировали страницу внутри кадра, то единственный способ разблокировать ее - щелкнуть правой кнопкой мыши кадр, выбрать пункт «Удалить элементы из кадра», а затем разблокировать страницу.",
|
||||
IPM_GROUP_PAGES_NAME: "Страницы группы",
|
||||
IPM_GROUP_PAGES_DESC: "Это позволит объединить все страницы в одну группу. Это рекомендуется делать, если вы блокируете страницы после импорта, потому что группу будет легче разблокировать позже, чем разблокировать каждую по отдельности.",
|
||||
IPM_SELECT_PDF: "Пожалуйста, выберите файл PDF",
|
||||
|
||||
};
|
||||
|
||||
@@ -5,6 +5,7 @@ import {
|
||||
import { TAG_AUTOEXPORT, TAG_MDREADINGMODE, TAG_PDFEXPORT } from "src/constants/constSettingsTags";
|
||||
import { labelALT, labelCTRL, labelMETA, labelSHIFT } from "src/utils/ModifierkeyHelper";
|
||||
|
||||
const CJK_FONTS = "CJK Fonts";
|
||||
// 简体中文
|
||||
export default {
|
||||
// main.ts
|
||||
@@ -97,6 +98,8 @@ export default {
|
||||
RESET_IMG_ASPECT_RATIO: "重置所选图像元素的纵横比",
|
||||
TEMPORARY_DISABLE_AUTOSAVE: "临时禁用自动保存功能,直到本次 Obsidian 退出(小白慎用!)",
|
||||
TEMPORARY_ENABLE_AUTOSAVE: "启用自动保存功能",
|
||||
FONTS_LOADED : "Excalidraw: CJK 字体已加载" ,
|
||||
FONTS_LOAD_ERROR : "Excalidraw: 在资源文件夹下找不到 CJK 字体\n" ,
|
||||
|
||||
//ExcalidrawView.ts
|
||||
NO_SEARCH_RESULT: "在绘图中未找到匹配的元素",
|
||||
@@ -187,7 +190,7 @@ export default {
|
||||
|
||||
BASIC_HEAD: "基本",
|
||||
BASIC_DESC: `包括:更新说明,更新提示,新绘图文件、模板文件、脚本文件的存储路径等的设置。`,
|
||||
FOLDER_NAME: "Excalidraw 文件夹",
|
||||
FOLDER_NAME: "Excalidraw 文件夹(區分大小寫!)",
|
||||
FOLDER_DESC:
|
||||
"新绘图的默认存储路径。若为空,将在库的根目录中创建新绘图。",
|
||||
CROP_PREFIX_NAME: "剪贴文件的前缀",
|
||||
@@ -201,10 +204,10 @@ export default {
|
||||
ANNOTATE_PRESERVE_SIZE_NAME: "在标注时保留图像尺寸",
|
||||
ANNOTATE_PRESERVE_SIZE_DESC:
|
||||
"当在 Markdown 中标注图像时,替换后的图像链接将包含原始图像的宽度。",
|
||||
CROP_FOLDER_NAME: "剪贴文件文件夹",
|
||||
CROP_FOLDER_NAME: "剪贴文件文件夹(區分大小寫!)",
|
||||
CROP_FOLDER_DESC:
|
||||
"剪贴图像时创建新绘图的默认存储路径。如果留空,将按照 Vault 附件设置创建。",
|
||||
ANNOTATE_FOLDER_NAME: "图片标注文件文件夹",
|
||||
ANNOTATE_FOLDER_NAME: "图片标注文件文件夹(區分大小寫!)",
|
||||
ANNOTATE_FOLDER_DESC:
|
||||
"创建图片标注是的默认存储路径。如果留空,将按照 Vault 附件设置创建。",
|
||||
FOLDER_EMBED_NAME:
|
||||
@@ -213,7 +216,7 @@ export default {
|
||||
"在命令面板中执行“新建绘图”系列命令时," +
|
||||
"新建的绘图文件的存储路径。<br>" +
|
||||
"<b>开启:</b>使用上面的 Excalidraw 文件夹。 <br><b>关闭:</b>使用 Obsidian 设置的新附件默认位置。",
|
||||
TEMPLATE_NAME: "Excalidraw 模板文件",
|
||||
TEMPLATE_NAME: "Excalidraw 模板文件(區分大小寫!)",
|
||||
TEMPLATE_DESC:
|
||||
"Excalidraw 模板文件(文件夹)的存储路径。<br>" +
|
||||
"<b>模板文件:</b>比如:如果您的模板在默认的 Excalidraw 文件夹中且文件名是 " +
|
||||
@@ -431,6 +434,7 @@ FILENAME_HEAD: "文件名",
|
||||
LONG_PRESS_DESKTOP_DESC: "长按(以毫秒为单位)打开在 Markdown 文件中嵌入的 Excalidraw 绘图。",
|
||||
LONG_PRESS_MOBILE_NAME: "长按打开(移动端)",
|
||||
LONG_PRESS_MOBILE_DESC: "长按(以毫秒为单位)打开在 Markdown 文件中嵌入的 Excalidraw 绘图。",
|
||||
DOUBLE_CLICK_LINK_OPEN_VIEW_MODE: "在查看模式下允许双击打开链接",
|
||||
|
||||
FOCUS_ON_EXISTING_TAB_NAME: "聚焦于当前标签页",
|
||||
FOCUS_ON_EXISTING_TAB_DESC: "当打开一个链接时,如果该文件已经打开,Excalidraw 将会聚焦到现有的标签页上 " +
|
||||
@@ -747,6 +751,8 @@ FILENAME_HEAD: "文件名",
|
||||
"启用此功能简化了 Excalidraw 前置属性的使用,使您能够利用许多强大的设置。如果您不希望自动加载这些属性," +
|
||||
"您可以禁用此功能,但您将需要手动从自动提示中移除任何不需要的属性。" +
|
||||
"请注意,启用此设置需要重启插件,因为属性是在启动时加载的。",
|
||||
FONTS_HEAD: "字体",
|
||||
FONTS_DESC: "配置本地字体并下载的 CJK 字体以供 Excalidraw 使用。",
|
||||
CUSTOM_FONT_HEAD: "本地字体",
|
||||
ENABLE_FOURTH_FONT_NAME: "为文本元素启用本地字体",
|
||||
ENABLE_FOURTH_FONT_DESC:
|
||||
@@ -760,6 +766,20 @@ FILENAME_HEAD: "文件名",
|
||||
"如果没有选择文件,Excalidraw 将默认使用 Virgil 字体。"+
|
||||
"为了获得最佳性能,建议使用 .woff2 文件,因为当导出到 SVG 格式的图像时,Excalidraw 只会编码必要的字形。"+
|
||||
"其他字体格式将在导出文件中嵌入整个字体,可能会导致文件大小显著增加。<mark>译者注:</mark>您可以在<a href='https://wangchujiang.com/free-font/' target='_blank'>Free Font</a>获取免费商用中文手写字体。",
|
||||
OFFLINE_CJK_NAME: "离线 CJK 字体支持",
|
||||
OFFLINE_CJK_DESC:
|
||||
`<strong>您在这里所做的更改将在重启 Obsidian 后生效。</strong><br>
|
||||
Excalidraw.com 提供手写风格的 CJK 字体。默认情况下,这些字体并未在插件中本地包含,而是从互联网获取。
|
||||
如果您希望 Excalidraw 完全本地化,以便在没有互联网连接的情况下使用,可以从 <a href="https://github.com/zsviczian/obsidian-excalidraw-plugin/raw/refs/heads/master/assets/excalidraw-fonts.zip" target="_blank">GitHub 下载所需的字体文件</a>。
|
||||
下载后,将内容解压到您的 Vault 中的一个文件夹内。<br>
|
||||
预加载字体会影响启动性能。因此,您可以选择加载哪些字体。`,
|
||||
CJK_ASSETS_FOLDER_NAME: "CJK 字体文件夹(區分大小寫!)",
|
||||
CJK_ASSETS_FOLDER_DESC: `您可以在此设置 CJK 字体文件夹的位置。例如,您可以选择将其放置在 <code>Excalidraw/CJK Fonts</code> 下。<br><br>
|
||||
<strong>重要:</strong> 请勿将此文件夹设置为 Vault 根目录!请勿在此文件夹中放置其他字体。<br><br>
|
||||
<strong>注意:</strong> 如果您使用 Obsidian Sync 并希望在设备之间同步这些字体文件,请确保 Obsidian Sync 设置为同步“所有其他文件类型”。`,
|
||||
LOAD_CHINESE_FONTS_NAME: "启动时从文件加载中文字体",
|
||||
LOAD_JAPANESE_FONTS_NAME: "启动时从文件加载日文字体",
|
||||
LOAD_KOREAN_FONTS_NAME: "启动时从文件加载韩文字体",
|
||||
SCRIPT_SETTINGS_HEAD: "已安装脚本的设置",
|
||||
SCRIPT_SETTINGS_DESC: "有些 Excalidraw 自动化脚本包含设置项,当执行这些脚本时,它们会在该列表下添加设置项。",
|
||||
TASKBONE_HEAD: "Taskbone OCR(光学符号识别)",
|
||||
@@ -816,7 +836,35 @@ FILENAME_HEAD: "文件名",
|
||||
|
||||
//ExcalidrawData.ts
|
||||
LOAD_FROM_BACKUP: "Excalidraw 文件已损坏。尝试从备份文件中加载。",
|
||||
|
||||
FONT_LOAD_SLOW: "正在加载字体...\n\n 这比预期花费的时间更长。如果这种延迟经常发生,您可以将字体下载到您的 Vault 中。\n\n" +
|
||||
"(点击=忽略提示,右键=更多信息)",
|
||||
FONT_INFO_TITLE: "从互联网加载 v2.5.3 字体",
|
||||
FONT_INFO_DETAILED: `
|
||||
<p>
|
||||
为了提高 Obsidian 的启动时间并管理大型 <strong>CJK 字体系列</strong>,
|
||||
我已将 CJK 字体移出插件的 <code>main.js</code>。默认情况下,CJK 字体将从互联网加载。
|
||||
这通常不会造成问题,因为 Obsidian 在首次使用后会缓存这些文件。
|
||||
</p>
|
||||
<p>
|
||||
如果您希望 Obsidian 完全离线或遇到性能问题,可以下载字体资源。
|
||||
</p>
|
||||
<h3>说明:</h3>
|
||||
<ol>
|
||||
<li>从 <a href="https://github.com/zsviczian/obsidian-excalidraw-plugin/raw/refs/heads/master/assets/excalidraw-fonts.zip">GitHub</a> 下载字体。</li>
|
||||
<li>解压并将文件复制到 Vault 文件夹中(默认:<code>Excalidraw/${CJK_FONTS}</code>; 文件夹名称區分大小寫!)。</li>
|
||||
<li><mark>请勿</mark>将此文件夹设置为 Vault 根目录或与其他本地字体混合。</li>
|
||||
</ol>
|
||||
<h3>对于 Obsidian Sync 用户:</h3>
|
||||
<p>
|
||||
确保 Obsidian Sync 设置为同步“所有其他文件类型”,或者在所有设备上下载并解压文件。
|
||||
</p>
|
||||
<h3>注意:</h3>
|
||||
<p>
|
||||
如果您觉得这个过程繁琐,请向 Obsidian.md 提交功能请求,以支持插件文件夹中的资源。
|
||||
目前,仅支持(同步)单个 <code>main.js</code>,这导致大型文件和复杂插件(如 Excalidraw)启动时间较慢。
|
||||
对此带来的不便,我深表歉意。
|
||||
</p>
|
||||
`,
|
||||
//ObsidianMenu.tsx
|
||||
GOTO_FULLSCREEN: "进入全屏模式",
|
||||
EXIT_FULLSCREEN: "退出全屏模式",
|
||||
|
||||
210
src/main.ts
210
src/main.ts
@@ -45,6 +45,8 @@ import {
|
||||
DEVICE,
|
||||
sceneCoordsToViewportCoords,
|
||||
FONTS_STYLE_ID,
|
||||
CJK_STYLE_ID,
|
||||
updateExcalidrawLib,
|
||||
} from "./constants/constants";
|
||||
import ExcalidrawView, { TextMode, getTextMode } from "./ExcalidrawView";
|
||||
import {
|
||||
@@ -140,8 +142,12 @@ import { Rank, SwordColors } from "./menu/ActionIcons";
|
||||
import { RankMessage } from "./dialogs/RankMessage";
|
||||
import { initCompressionWorker, terminateCompressionWorker } from "./workers/compression-worker";
|
||||
import { WeakArray } from "./utils/WeakArray";
|
||||
import { getCJKDataURLs } from "./utils/CJKLoader";
|
||||
import ExcalidrawLoading from "./dialogs/ExcalidrawLoading";
|
||||
|
||||
declare let EXCALIDRAW_PACKAGES:string;
|
||||
declare let EXCALIDRAW_PACKAGE:string;
|
||||
declare let REACT_PACKAGES:string;
|
||||
declare const unpackExcalidraw: Function;
|
||||
declare let react:any;
|
||||
declare let reactDOM:any;
|
||||
declare let excalidrawLib: typeof ExcalidrawLib;
|
||||
@@ -193,6 +199,8 @@ export default class ExcalidrawPlugin extends Plugin {
|
||||
//private slob:string;
|
||||
private ribbonIcon:HTMLElement;
|
||||
public loadTimestamp:number;
|
||||
private isLocalCJKFontAvailabe:boolean = undefined
|
||||
public isReady = false;
|
||||
|
||||
constructor(app: App, manifest: PluginManifest) {
|
||||
super(app, manifest);
|
||||
@@ -267,7 +275,7 @@ export default class ExcalidrawPlugin extends Plugin {
|
||||
//@ts-ignore
|
||||
const {react:r, reactDOM:rd, excalidrawLib:e} = win.eval.call(win,
|
||||
`(function() {
|
||||
${EXCALIDRAW_PACKAGES};
|
||||
${REACT_PACKAGES + EXCALIDRAW_PACKAGE};
|
||||
return {react:React,reactDOM:ReactDOM,excalidrawLib:ExcalidrawLib};
|
||||
})()`);
|
||||
this.packageMap.set(win,{react:r, reactDOM:rd, excalidrawLib:e});
|
||||
@@ -313,12 +321,47 @@ export default class ExcalidrawPlugin extends Plugin {
|
||||
};
|
||||
}*/
|
||||
|
||||
public getCJKFontSettings() {
|
||||
const assetsFoler = this.settings.fontAssetsPath;
|
||||
if(typeof this.isLocalCJKFontAvailabe === "undefined") {
|
||||
this.isLocalCJKFontAvailabe = this.app.vault.getFiles().some(f=>f.path.startsWith(assetsFoler));
|
||||
}
|
||||
if(!this.isLocalCJKFontAvailabe) {
|
||||
return { c: false, j: false, k: false };
|
||||
}
|
||||
return {
|
||||
c: this.settings.loadChineseFonts,
|
||||
j: this.settings.loadJapaneseFonts,
|
||||
k: this.settings.loadKoreanFonts,
|
||||
}
|
||||
}
|
||||
|
||||
public async loadFontFromFile(fontName: string): Promise<ArrayBuffer|undefined> {
|
||||
const assetsFoler = this.settings.fontAssetsPath;
|
||||
|
||||
if(!this.isLocalCJKFontAvailabe) {
|
||||
return;
|
||||
}
|
||||
const file = this.app.vault.getAbstractFileByPath(normalizePath(assetsFoler + "/" + fontName));
|
||||
if(!file || !(file instanceof TFile)) {
|
||||
return;
|
||||
}
|
||||
return await this.app.vault.readBinary(file);
|
||||
}
|
||||
|
||||
async onload() {
|
||||
initCompressionWorker();
|
||||
this.loadTimestamp = Date.now();
|
||||
addIcon(ICON_NAME, EXCALIDRAW_ICON);
|
||||
addIcon(SCRIPTENGINE_ICON_NAME, SCRIPTENGINE_ICON);
|
||||
addIcon(EXPORT_IMG_ICON_NAME, EXPORT_IMG_ICON);
|
||||
this.registerView(
|
||||
VIEW_TYPE_EXCALIDRAW,
|
||||
(leaf: WorkspaceLeaf) => {
|
||||
if(this.isReady) {
|
||||
return new ExcalidrawView(leaf, this);
|
||||
} else {
|
||||
return new ExcalidrawLoading(leaf, this);
|
||||
}
|
||||
},
|
||||
);
|
||||
//Compatibility mode with .excalidraw files
|
||||
this.registerExtensions(["excalidraw"], VIEW_TYPE_EXCALIDRAW);
|
||||
|
||||
await this.loadSettings({reEnableAutosave:true});
|
||||
const updateSettings = !this.settings.onceOffCompressFlagReset || !this.settings.onceOffGPTVersionReset;
|
||||
@@ -334,68 +377,83 @@ export default class ExcalidrawPlugin extends Plugin {
|
||||
if(updateSettings) {
|
||||
await this.saveSettings();
|
||||
}
|
||||
this.excalidrawConfig = new ExcalidrawConfig(this);
|
||||
await loadMermaid();
|
||||
this.editorHandler = new EditorHandler(this);
|
||||
this.editorHandler.setup();
|
||||
|
||||
this.addSettingTab(new ExcalidrawSettingTab(this.app, this));
|
||||
this.ea = await initExcalidrawAutomate(this);
|
||||
|
||||
this.registerView(
|
||||
VIEW_TYPE_EXCALIDRAW,
|
||||
(leaf: WorkspaceLeaf) => new ExcalidrawView(leaf, this),
|
||||
);
|
||||
|
||||
//Compatibility mode with .excalidraw files
|
||||
this.registerExtensions(["excalidraw"], VIEW_TYPE_EXCALIDRAW);
|
||||
|
||||
this.addMarkdownPostProcessor();
|
||||
this.registerInstallCodeblockProcessor();
|
||||
this.addThemeObserver();
|
||||
this.experimentalFileTypeDisplayToggle(this.settings.experimentalFileType);
|
||||
this.registerCommands();
|
||||
this.registerEventListeners();
|
||||
this.runStartupScript();
|
||||
this.initializeFonts();
|
||||
this.registerEditorSuggest(new FieldSuggester(this));
|
||||
this.setPropertyTypes();
|
||||
|
||||
this.app.workspace.onLayoutReady(async () => {
|
||||
unpackExcalidraw();
|
||||
excalidrawLib = window.eval.call(window,`(function() {${EXCALIDRAW_PACKAGE};return ExcalidrawLib;})()`);
|
||||
this.packageMap.set(window,{react, reactDOM, excalidrawLib});
|
||||
updateExcalidrawLib();
|
||||
initCompressionWorker();
|
||||
this.loadTimestamp = Date.now();
|
||||
addIcon(ICON_NAME, EXCALIDRAW_ICON);
|
||||
addIcon(SCRIPTENGINE_ICON_NAME, SCRIPTENGINE_ICON);
|
||||
addIcon(EXPORT_IMG_ICON_NAME, EXPORT_IMG_ICON);
|
||||
|
||||
//inspiration taken from kanban:
|
||||
//https://github.com/mgmeyers/obsidian-kanban/blob/44118e25661bff9ebfe54f71ae33805dc88ffa53/src/main.ts#L267
|
||||
this.registerMonkeyPatches();
|
||||
this.excalidrawConfig = new ExcalidrawConfig(this);
|
||||
await loadMermaid();
|
||||
this.editorHandler = new EditorHandler(this);
|
||||
this.editorHandler.setup();
|
||||
|
||||
this.registerInstallCodeblockProcessor();
|
||||
this.addThemeObserver();
|
||||
this.experimentalFileTypeDisplayToggle(this.settings.experimentalFileType);
|
||||
this.registerCommands();
|
||||
this.registerEventListeners();
|
||||
this.runStartupScript();
|
||||
this.initializeFonts();
|
||||
this.registerEditorSuggest(new FieldSuggester(this));
|
||||
this.setPropertyTypes();
|
||||
|
||||
this.stylesManager = new StylesManager(this);
|
||||
//inspiration taken from kanban:
|
||||
//https://github.com/mgmeyers/obsidian-kanban/blob/44118e25661bff9ebfe54f71ae33805dc88ffa53/src/main.ts#L267
|
||||
this.registerMonkeyPatches();
|
||||
|
||||
// const patches = new OneOffs(this);
|
||||
if (this.settings.showReleaseNotes) {
|
||||
//I am repurposing imageElementNotice, if the value is true, this means the plugin was just newly installed to Obsidian.
|
||||
const obsidianJustInstalled = this.settings.previousRelease === "0.0.0"
|
||||
this.stylesManager = new StylesManager(this);
|
||||
|
||||
if (isVersionNewerThanOther(PLUGIN_VERSION, this.settings.previousRelease)) {
|
||||
new ReleaseNotes(
|
||||
this.app,
|
||||
this,
|
||||
obsidianJustInstalled ? null : PLUGIN_VERSION,
|
||||
).open();
|
||||
// const patches = new OneOffs(this);
|
||||
if (this.settings.showReleaseNotes) {
|
||||
//I am repurposing imageElementNotice, if the value is true, this means the plugin was just newly installed to Obsidian.
|
||||
const obsidianJustInstalled = this.settings.previousRelease === "0.0.0"
|
||||
|
||||
if (isVersionNewerThanOther(PLUGIN_VERSION, this.settings.previousRelease)) {
|
||||
new ReleaseNotes(
|
||||
this.app,
|
||||
this,
|
||||
obsidianJustInstalled ? null : PLUGIN_VERSION,
|
||||
).open();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.switchToExcalidarwAfterLoad();
|
||||
this.switchToExcalidarwAfterLoad();
|
||||
|
||||
this.app.workspace.onLayoutReady(() => {
|
||||
(process.env.NODE_ENV === 'development') && DEBUGGING && debug(this.onload,"ExcalidrawPlugin.onload > app.workspace.onLayoutReady");
|
||||
this.scriptEngine = new ScriptEngine(this);
|
||||
imageCache.initializeDB(this);
|
||||
this.taskbone = new Taskbone(this);
|
||||
this.isReady = true;
|
||||
|
||||
this.app.workspace.onLayoutReady(() => {
|
||||
(process.env.NODE_ENV === 'development') && DEBUGGING && debug(this.onload,"ExcalidrawPlugin.onload > app.workspace.onLayoutReady");
|
||||
this.scriptEngine = new ScriptEngine(this);
|
||||
imageCache.initializeDB(this);
|
||||
});
|
||||
});
|
||||
this.taskbone = new Taskbone(this);
|
||||
}
|
||||
|
||||
public async awaitInit() {
|
||||
let counter = 0;
|
||||
while(!this.isReady && counter < 150) {
|
||||
await sleep(50);
|
||||
}
|
||||
}
|
||||
|
||||
private setPropertyTypes() {
|
||||
if(!this.settings.loadPropertySuggestions) return;
|
||||
const app = this.app;
|
||||
this.app.workspace.onLayoutReady(() => {
|
||||
this.app.workspace.onLayoutReady(async () => {
|
||||
(process.env.NODE_ENV === 'development') && DEBUGGING && debug(this.setPropertyTypes, `ExcalidrawPlugin.setPropertyTypes > app.workspace.onLayoutReady`);
|
||||
await this.awaitInit();
|
||||
Object.keys(FRONTMATTER_KEYS).forEach((key) => {
|
||||
if(FRONTMATTER_KEYS[key].depricated === true) return;
|
||||
const {name, type} = FRONTMATTER_KEYS[key];
|
||||
@@ -407,7 +465,22 @@ export default class ExcalidrawPlugin extends Plugin {
|
||||
public initializeFonts() {
|
||||
this.app.workspace.onLayoutReady(async () => {
|
||||
(process.env.NODE_ENV === 'development') && DEBUGGING && debug(this.initializeFonts, `ExcalidrawPlugin.initializeFonts > app.workspace.onLayoutReady`);
|
||||
|
||||
await this.awaitInit();
|
||||
const cjkFontDataURLs = await getCJKDataURLs(this);
|
||||
if(typeof cjkFontDataURLs === "boolean" && !cjkFontDataURLs) {
|
||||
new Notice(t("FONTS_LOAD_ERROR") + this.settings.fontAssetsPath,6000);
|
||||
}
|
||||
|
||||
if(typeof cjkFontDataURLs === "object") {
|
||||
const fontDeclarations = cjkFontDataURLs.map(dataURL =>
|
||||
`@font-face { font-family: 'Xiaolai'; src: url("${dataURL}"); font-display: swap; font-weight: 400; }`
|
||||
);
|
||||
for(const ownerDocument of this.getOpenObsidianDocuments()) {
|
||||
await this.addFonts(fontDeclarations, ownerDocument, CJK_STYLE_ID);
|
||||
};
|
||||
new Notice(t("FONTS_LOADED"));
|
||||
}
|
||||
|
||||
const font = await getFontDataURL(
|
||||
this.app,
|
||||
this.settings.experimantalFourthFont,
|
||||
@@ -449,12 +522,12 @@ export default class ExcalidrawPlugin extends Plugin {
|
||||
});
|
||||
}
|
||||
|
||||
public async addFonts(declarations: string[],ownerDocument:Document = document) {
|
||||
public async addFonts(declarations: string[],ownerDocument:Document = document, styleId:string = FONTS_STYLE_ID) {
|
||||
// replace the old local font <style> element with the one we just created
|
||||
const newStylesheet = ownerDocument.createElement("style");
|
||||
newStylesheet.id = FONTS_STYLE_ID;
|
||||
newStylesheet.id = styleId;
|
||||
newStylesheet.textContent = declarations.join("");
|
||||
const oldStylesheet = ownerDocument.getElementById(FONTS_STYLE_ID);
|
||||
const oldStylesheet = ownerDocument.getElementById(styleId);
|
||||
ownerDocument.head.appendChild(newStylesheet);
|
||||
if (oldStylesheet) {
|
||||
ownerDocument.head.removeChild(oldStylesheet);
|
||||
@@ -464,11 +537,15 @@ export default class ExcalidrawPlugin extends Plugin {
|
||||
|
||||
public removeFonts() {
|
||||
this.getOpenObsidianDocuments().forEach((ownerDocument) => {
|
||||
const oldStylesheet = ownerDocument.getElementById(FONTS_STYLE_ID);
|
||||
if (oldStylesheet) {
|
||||
ownerDocument.head.removeChild(oldStylesheet);
|
||||
const oldCustomFontStylesheet = ownerDocument.getElementById(FONTS_STYLE_ID);
|
||||
if (oldCustomFontStylesheet) {
|
||||
ownerDocument.head.removeChild(oldCustomFontStylesheet);
|
||||
}
|
||||
})
|
||||
const oldCJKFontStylesheet = ownerDocument.getElementById(CJK_STYLE_ID);
|
||||
if (oldCJKFontStylesheet) {
|
||||
ownerDocument.head.removeChild(oldCJKFontStylesheet);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private getOpenObsidianDocuments(): Document[] {
|
||||
@@ -484,8 +561,9 @@ export default class ExcalidrawPlugin extends Plugin {
|
||||
}
|
||||
|
||||
private switchToExcalidarwAfterLoad() {
|
||||
this.app.workspace.onLayoutReady(() => {
|
||||
this.app.workspace.onLayoutReady(async () => {
|
||||
(process.env.NODE_ENV === 'development') && DEBUGGING && debug(this.switchToExcalidarwAfterLoad, `ExcalidrawPlugin.switchToExcalidarwAfterLoad > app.workspace.onLayoutReady`);
|
||||
await this.awaitInit();
|
||||
let leaf: WorkspaceLeaf;
|
||||
for (leaf of this.app.workspace.getLeavesOfType("markdown")) {
|
||||
if ( leaf.view instanceof MarkdownView && this.isExcalidrawFile(leaf.view.file)) {
|
||||
@@ -717,9 +795,9 @@ export default class ExcalidrawPlugin extends Plugin {
|
||||
initializeMarkdownPostProcessor(this);
|
||||
this.registerMarkdownPostProcessor(markdownPostProcessor);
|
||||
|
||||
this.app.workspace.onLayoutReady(() => {
|
||||
this.app.workspace.onLayoutReady(async () => {
|
||||
(process.env.NODE_ENV === 'development') && DEBUGGING && debug(this.addMarkdownPostProcessor, `ExcalidrawPlugin.addMarkdownPostProcessor > app.workspace.onLayoutReady`);
|
||||
|
||||
await this.awaitInit();
|
||||
// internal-link quick preview
|
||||
this.registerEvent(this.app.workspace.on("hover-link", hoverEvent));
|
||||
|
||||
@@ -839,8 +917,9 @@ export default class ExcalidrawPlugin extends Plugin {
|
||||
? new CustomMutationObserver(fileExplorerObserverFn, "fileExplorerObserver")
|
||||
: new MutationObserver(fileExplorerObserverFn);
|
||||
|
||||
this.app.workspace.onLayoutReady(() => {
|
||||
this.app.workspace.onLayoutReady(async () => {
|
||||
(process.env.NODE_ENV === 'development') && DEBUGGING && debug(this.experimentalFileTypeDisplay, `ExcalidrawPlugin.experimentalFileTypeDisplay > app.workspace.onLayoutReady`);
|
||||
await this.awaitInit();
|
||||
document.querySelectorAll(".nav-file-title").forEach(insertFiletype); //apply filetype to files already displayed
|
||||
const container = document.querySelector(".nav-files-container");
|
||||
if (container) {
|
||||
@@ -2712,6 +2791,7 @@ export default class ExcalidrawPlugin extends Plugin {
|
||||
}
|
||||
this.app.workspace.onLayoutReady(async () => {
|
||||
(process.env.NODE_ENV === 'development') && DEBUGGING && debug(this.runStartupScript, `ExcalidrawPlugin.runStartupScript > app.workspace.onLayoutReady, scriptPath:${this.settings?.startupScriptPath}`);
|
||||
await this.awaitInit();
|
||||
const path = this.settings.startupScriptPath.endsWith(".md")
|
||||
? this.settings.startupScriptPath
|
||||
: `${this.settings.startupScriptPath}.md`;
|
||||
@@ -2872,6 +2952,7 @@ export default class ExcalidrawPlugin extends Plugin {
|
||||
private registerEventListeners() {
|
||||
this.app.workspace.onLayoutReady(async () => {
|
||||
(process.env.NODE_ENV === 'development') && DEBUGGING && debug(this.registerEventListeners,`ExcalidrawPlugin.registerEventListeners > app.workspace.onLayoutReady`);
|
||||
await this.awaitInit();
|
||||
const onPasteHandler = (
|
||||
evt: ClipboardEvent,
|
||||
editor: Editor,
|
||||
@@ -3320,7 +3401,8 @@ export default class ExcalidrawPlugin extends Plugin {
|
||||
|
||||
this.settings = null;
|
||||
clearMathJaxVariables();
|
||||
EXCALIDRAW_PACKAGES = "";
|
||||
EXCALIDRAW_PACKAGE = "";
|
||||
REACT_PACKAGES = "";
|
||||
//pluginPackages = null;
|
||||
PLUGIN_VERSION = null;
|
||||
//@ts-ignore
|
||||
|
||||
103
src/settings.ts
103
src/settings.ts
@@ -49,6 +49,10 @@ export interface ExcalidrawSettings {
|
||||
embedUseExcalidrawFolder: boolean;
|
||||
templateFilePath: string;
|
||||
scriptFolderPath: string;
|
||||
fontAssetsPath: string;
|
||||
loadChineseFonts: boolean;
|
||||
loadJapaneseFonts: boolean;
|
||||
loadKoreanFonts: boolean;
|
||||
compress: boolean;
|
||||
decompressForMDView: boolean;
|
||||
onceOffCompressFlagReset: boolean; //used to reset compress to true in 2.2.0
|
||||
@@ -205,6 +209,7 @@ export interface ExcalidrawSettings {
|
||||
areaZoomLimit: number;
|
||||
longPressDesktop: number;
|
||||
longPressMobile: number;
|
||||
doubleClickLinkOpenViewMode: boolean;
|
||||
isDebugMode: boolean;
|
||||
rank: Rank;
|
||||
modifierKeyOverrides: {modifiers: Modifier[], key: string}[];
|
||||
@@ -220,13 +225,17 @@ export const DEFAULT_SETTINGS: ExcalidrawSettings = {
|
||||
embedUseExcalidrawFolder: false,
|
||||
templateFilePath: "Excalidraw/Template.excalidraw",
|
||||
scriptFolderPath: "Excalidraw/Scripts",
|
||||
fontAssetsPath: "Excalidraw/CJK Fonts",
|
||||
loadChineseFonts: false,
|
||||
loadJapaneseFonts: false,
|
||||
loadKoreanFonts: false,
|
||||
compress: true,
|
||||
decompressForMDView: false,
|
||||
onceOffCompressFlagReset: false,
|
||||
onceOffGPTVersionReset: false,
|
||||
autosave: true,
|
||||
autosaveIntervalDesktop: 30000,
|
||||
autosaveIntervalMobile: 20000,
|
||||
autosaveIntervalDesktop: 60000,
|
||||
autosaveIntervalMobile: 30000,
|
||||
drawingFilenamePrefix: "Drawing ",
|
||||
drawingEmbedPrefixWithFilename: true,
|
||||
drawingFilnameEmbedPostfix: " ",
|
||||
@@ -268,9 +277,9 @@ export const DEFAULT_SETTINGS: ExcalidrawSettings = {
|
||||
done: "🗹",
|
||||
hoverPreviewWithoutCTRL: false,
|
||||
linkOpacity: 1,
|
||||
openInAdjacentPane: false,
|
||||
openInAdjacentPane: true,
|
||||
showSecondOrderLinks: true,
|
||||
focusOnFileTab: false,
|
||||
focusOnFileTab: true,
|
||||
openInMainWorkspace: true,
|
||||
showLinkBrackets: true,
|
||||
allowCtrlClick: true,
|
||||
@@ -472,6 +481,7 @@ export const DEFAULT_SETTINGS: ExcalidrawSettings = {
|
||||
areaZoomLimit: 1,
|
||||
longPressDesktop: 500,
|
||||
longPressMobile: 500,
|
||||
doubleClickLinkOpenViewMode: true,
|
||||
isDebugMode: false,
|
||||
rank: "Bronze",
|
||||
modifierKeyOverrides: [
|
||||
@@ -720,7 +730,6 @@ export class ExcalidrawSettingTab extends PluginSettingTab {
|
||||
}),
|
||||
);
|
||||
|
||||
|
||||
// ------------------------------------------------
|
||||
// Saving
|
||||
// ------------------------------------------------
|
||||
@@ -1486,6 +1495,18 @@ export class ExcalidrawSettingTab extends PluginSettingTab {
|
||||
el.innerText = ` ${this.plugin.settings.longPressMobile.toString()}`;
|
||||
});
|
||||
|
||||
new Setting(detailsEl)
|
||||
.setName(t("DOUBLE_CLICK_LINK_OPEN_VIEW_MODE"))
|
||||
.addToggle((toggle) =>
|
||||
toggle
|
||||
.setValue(this.plugin.settings.doubleClickLinkOpenViewMode)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.doubleClickLinkOpenViewMode = value;
|
||||
this.applySettingsUpdate();
|
||||
}),
|
||||
);
|
||||
|
||||
|
||||
new ModifierKeySettingsComponent(
|
||||
detailsEl,
|
||||
this.plugin.settings.modifierKeyConfig,
|
||||
@@ -2331,7 +2352,7 @@ export class ExcalidrawSettingTab extends PluginSettingTab {
|
||||
d.addOption("Assistant", "Assistant");
|
||||
this.app.vault
|
||||
.getFiles()
|
||||
.filter((f) => ["ttf", "woff", "woff2", "otf"].contains(f.extension))
|
||||
.filter((f) => ["ttf", "woff", "woff2", "otf"].contains(f.extension) && !f.path.startsWith(this.plugin.settings.fontAssetsPath))
|
||||
.forEach((f: TFile) => {
|
||||
d.addOption(f.path, f.name);
|
||||
});
|
||||
@@ -2456,8 +2477,20 @@ export class ExcalidrawSettingTab extends PluginSettingTab {
|
||||
this.applySettingsUpdate(false);
|
||||
})
|
||||
)
|
||||
|
||||
// ------------------------------------------------
|
||||
// Fonts supported features
|
||||
// ------------------------------------------------
|
||||
containerEl.createEl("hr", { cls: "excalidraw-setting-hr" });
|
||||
containerEl.createDiv({ text: t("FONTS_DESC"), cls: "setting-item-description" });
|
||||
detailsEl = this.containerEl.createEl("details");
|
||||
const fontsDetailsEl = detailsEl;
|
||||
detailsEl.createEl("summary", {
|
||||
text: t("FONTS_HEAD"),
|
||||
cls: "excalidraw-setting-h1",
|
||||
});
|
||||
|
||||
detailsEl = nonstandardDetailsEl.createEl("details");
|
||||
detailsEl = fontsDetailsEl.createEl("details");
|
||||
detailsEl.createEl("summary", {
|
||||
text: t("CUSTOM_FONT_HEAD"),
|
||||
cls: "excalidraw-setting-h3",
|
||||
@@ -2484,7 +2517,7 @@ export class ExcalidrawSettingTab extends PluginSettingTab {
|
||||
d.addOption("Virgil", "Virgil");
|
||||
this.app.vault
|
||||
.getFiles()
|
||||
.filter((f) => ["ttf", "woff", "woff2", "otf"].contains(f.extension))
|
||||
.filter((f) => ["ttf", "woff", "woff2", "otf"].contains(f.extension) && !f.path.startsWith(this.plugin.settings.fontAssetsPath))
|
||||
.forEach((f: TFile) => {
|
||||
d.addOption(f.path, f.name);
|
||||
});
|
||||
@@ -2498,7 +2531,61 @@ export class ExcalidrawSettingTab extends PluginSettingTab {
|
||||
);
|
||||
});
|
||||
|
||||
detailsEl = fontsDetailsEl.createEl("details");
|
||||
detailsEl.createEl("summary", {
|
||||
text: t("OFFLINE_CJK_NAME"),
|
||||
cls: "excalidraw-setting-h3",
|
||||
});
|
||||
|
||||
const cjkdescdiv = detailsEl.createDiv({ cls: "setting-item-description" });
|
||||
cjkdescdiv.innerHTML = t("OFFLINE_CJK_DESC");
|
||||
|
||||
new Setting(detailsEl)
|
||||
.setName(t("CJK_ASSETS_FOLDER_NAME"))
|
||||
.setDesc(fragWithHTML(t("CJK_ASSETS_FOLDER_DESC")))
|
||||
.addText((text) =>
|
||||
text
|
||||
.setPlaceholder("e.g.: Excalidraw/FontAssets")
|
||||
.setValue(this.plugin.settings.fontAssetsPath)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.fontAssetsPath = value;
|
||||
this.applySettingsUpdate();
|
||||
}),
|
||||
);
|
||||
|
||||
new Setting(detailsEl)
|
||||
.setName(t("LOAD_CHINESE_FONTS_NAME"))
|
||||
.addToggle((toggle) =>
|
||||
toggle
|
||||
.setValue(this.plugin.settings.loadChineseFonts)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.loadChineseFonts = value;
|
||||
this.applySettingsUpdate();
|
||||
}),
|
||||
);
|
||||
|
||||
new Setting(detailsEl)
|
||||
.setName(t("LOAD_JAPANESE_FONTS_NAME"))
|
||||
.addToggle((toggle) =>
|
||||
toggle
|
||||
.setValue(this.plugin.settings.loadJapaneseFonts)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.loadJapaneseFonts = value;
|
||||
this.applySettingsUpdate();
|
||||
}),
|
||||
);
|
||||
|
||||
new Setting(detailsEl)
|
||||
.setName(t("LOAD_KOREAN_FONTS_NAME"))
|
||||
.addToggle((toggle) =>
|
||||
toggle
|
||||
.setValue(this.plugin.settings.loadKoreanFonts)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.loadKoreanFonts = value;
|
||||
this.applySettingsUpdate();
|
||||
}),
|
||||
);
|
||||
|
||||
// ------------------------------------------------
|
||||
// Experimental features
|
||||
// ------------------------------------------------
|
||||
|
||||
1403
src/utils/CJKLoader.ts
Normal file
1403
src/utils/CJKLoader.ts
Normal file
File diff suppressed because it is too large
Load Diff
@@ -23,6 +23,9 @@ export function updateElementIdsInScene(
|
||||
boundEl.boundElements?.filter(x=>x.id === elementToChange.id).forEach( x => {
|
||||
(x.id as Mutable<string>) = newID;
|
||||
});
|
||||
if(boundEl.type === "text") {
|
||||
boundEl.containerId = newID;
|
||||
}
|
||||
if(boundEl.type === "arrow") {
|
||||
const arrow = boundEl as Mutable<ExcalidrawArrowElement>;
|
||||
if(arrow.startBinding?.elementId === elementToChange.id) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
|
||||
import { MAX_IMAGE_SIZE, IMAGE_TYPES, ANIMATED_IMAGE_TYPES, MD_EX_SECTIONS } from "src/constants/constants";
|
||||
import { App, Notice, TFile, WorkspaceLeaf } from "obsidian";
|
||||
import { App, Modal, Notice, TFile, WorkspaceLeaf } from "obsidian";
|
||||
import { ExcalidrawAutomate } from "src/ExcalidrawAutomate";
|
||||
import { REGEX_LINK, REG_LINKINDEX_HYPERLINK, getExcalidrawMarkdownHeaderSection, REGEX_TAGS } from "src/ExcalidrawData";
|
||||
import ExcalidrawView from "src/ExcalidrawView";
|
||||
@@ -402,3 +402,19 @@ export function isTextImageTransclusion (
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
export function displayFontMessage(app: App) {
|
||||
const modal = new Modal(app);
|
||||
|
||||
modal.onOpen = () => {
|
||||
const contentEl = modal.contentEl;
|
||||
contentEl.createEl("h2", { text: t("FONT_INFO_TITLE") });
|
||||
|
||||
const releaseNotesHTML = t("FONT_INFO_DETAILED");
|
||||
|
||||
const div = contentEl.createDiv({ cls: "release-notes" });
|
||||
div.innerHTML = releaseNotesHTML;
|
||||
}
|
||||
|
||||
modal.open();
|
||||
}
|
||||
@@ -41,6 +41,7 @@ export class StylesManager {
|
||||
this.plugin = plugin;
|
||||
plugin.app.workspace.onLayoutReady(async () => {
|
||||
(process.env.NODE_ENV === 'development') && DEBUGGING && debug(undefined, "StylesManager.constructor > app.workspace.onLayoutReady", this);
|
||||
await plugin.awaitInit();
|
||||
await this.harvestStyles();
|
||||
getAllWindowDocuments(plugin.app).forEach(doc => this.copyPropertiesToTheme(doc));
|
||||
|
||||
|
||||
@@ -29,6 +29,7 @@ import { updateElementLinksToObsidianLinks } from "src/ExcalidrawAutomate";
|
||||
import { CropImage } from "./CropImage";
|
||||
import opentype from 'opentype.js';
|
||||
import { runCompressionWorker } from "src/workers/compression-worker";
|
||||
import Pool from "es6-promise-pool";
|
||||
|
||||
declare const PLUGIN_VERSION:string;
|
||||
declare var LZString: any;
|
||||
@@ -968,4 +969,63 @@ export function cropCanvas(
|
||||
0, 0, output.width, output.height
|
||||
);
|
||||
return dstCanvas;
|
||||
}
|
||||
|
||||
// Promise.try, adapted from https://github.com/sindresorhus/p-try
|
||||
export async function promiseTry <TValue, TArgs extends unknown[]>(
|
||||
fn: (...args: TArgs) => PromiseLike<TValue> | TValue,
|
||||
...args: TArgs
|
||||
): Promise<TValue> {
|
||||
return new Promise((resolve) => {
|
||||
resolve(fn(...args));
|
||||
});
|
||||
};
|
||||
|
||||
// extending the missing types
|
||||
// relying on the [Index, T] to keep a correct order
|
||||
type TPromisePool<T, Index = number> = Pool<[Index, T][]> & {
|
||||
addEventListener: (
|
||||
type: "fulfilled",
|
||||
listener: (event: { data: { result: [Index, T] } }) => void,
|
||||
) => (event: { data: { result: [Index, T] } }) => void;
|
||||
removeEventListener: (
|
||||
type: "fulfilled",
|
||||
listener: (event: { data: { result: [Index, T] } }) => void,
|
||||
) => void;
|
||||
};
|
||||
|
||||
export class PromisePool<T> {
|
||||
private readonly pool: TPromisePool<T>;
|
||||
private readonly entries: Record<number, T> = {};
|
||||
|
||||
constructor(
|
||||
source: IterableIterator<Promise<void | readonly [number, T]>>,
|
||||
concurrency: number,
|
||||
) {
|
||||
this.pool = new Pool(
|
||||
source as unknown as () => void | PromiseLike<[number, T][]>,
|
||||
concurrency,
|
||||
) as TPromisePool<T>;
|
||||
}
|
||||
|
||||
public all() {
|
||||
const listener = (event: { data: { result: void | [number, T] } }) => {
|
||||
if (event.data.result) {
|
||||
// by default pool does not return the results, so we are gathering them manually
|
||||
// with the correct call order (represented by the index in the tuple)
|
||||
const [index, value] = event.data.result;
|
||||
this.entries[index] = value;
|
||||
}
|
||||
};
|
||||
|
||||
this.pool.addEventListener("fulfilled", listener);
|
||||
|
||||
return this.pool.start().then(() => {
|
||||
setTimeout(() => {
|
||||
this.pool.removeEventListener("fulfilled", listener);
|
||||
});
|
||||
|
||||
return Object.values(this.entries);
|
||||
});
|
||||
}
|
||||
}
|
||||
18
src/utils/typechecks.ts
Normal file
18
src/utils/typechecks.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
/**
|
||||
* Checks if a given target is an HTMLElement.
|
||||
*
|
||||
* This function is necessary because `instanceof HTMLElement` can fail
|
||||
* in environments with multiple execution contexts (e.g., popout windows),
|
||||
* where `HTMLElement` comes from different global objects.
|
||||
* Instead, we use feature detection by checking for key properties
|
||||
* common to all HTML elements (nodeType and tagName).
|
||||
*
|
||||
* @param target - The target to check.
|
||||
* @returns True if the target is an HTMLElement, false otherwise.
|
||||
*/
|
||||
export function isHTMLElement (target: any): target is HTMLElement {
|
||||
return target &&
|
||||
typeof target === 'object' &&
|
||||
target.nodeType === 1 && // nodeType 1 means it's an element
|
||||
typeof target.tagName === 'string'; // tagName exists on HTML elements
|
||||
}
|
||||
@@ -650,4 +650,4 @@ textarea.excalidraw-wysiwyg, .excalidraw input {
|
||||
|
||||
.excalidraw .ToolIcon_type_button {
|
||||
color: var(--text-primary-color);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user