Compare commits

...

25 Commits

Author SHA1 Message Date
dwelle fe973e3513 purify getDefaultAppState by removing name 2021-01-03 23:53:30 +01:00
Aakansha Doshi ade2565f49 feat: add langCode and renderFooter props (#2644)
Co-authored-by: Aakansha Doshi <aakansha1216@gmail.com>
Co-authored-by: dwelle <luzar.david@gmail.com>
2021-01-03 21:51:52 +01:00
dependabot[bot] c35d983fef chore(deps): bump @testing-library/jest-dom from 5.11.6 to 5.11.8 (#2702)
Bumps [@testing-library/jest-dom](https://github.com/testing-library/jest-dom) from 5.11.6 to 5.11.8.
- [Release notes](https://github.com/testing-library/jest-dom/releases)
- [Changelog](https://github.com/testing-library/jest-dom/blob/master/CHANGELOG.md)
- [Commits](https://github.com/testing-library/jest-dom/compare/v5.11.6...v5.11.8)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-01-03 10:52:02 +01:00
Lipis 69878167c2 improvement: Make dialogs look more like dialogs (#2686)
Co-authored-by: Jed Fox <git@jedfox.com>
Co-authored-by: dwelle <luzar.david@gmail.com>
2021-01-03 10:50:41 +01:00
dependabot[bot] eb1f717d35 chore(deps-dev): bump ts-loader in /src/packages/utils (#2700)
Bumps [ts-loader](https://github.com/TypeStrong/ts-loader) from 8.0.12 to 8.0.13.
- [Release notes](https://github.com/TypeStrong/ts-loader/releases)
- [Changelog](https://github.com/TypeStrong/ts-loader/blob/master/CHANGELOG.md)
- [Commits](https://github.com/TypeStrong/ts-loader/compare/v8.0.12...v8.0.13)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-01-03 15:20:28 +05:30
dependabot[bot] 8e9af5c51b chore(deps-dev): bump webpack in /src/packages/excalidraw (#2698)
Bumps [webpack](https://github.com/webpack/webpack) from 5.11.0 to 5.11.1.
- [Release notes](https://github.com/webpack/webpack/releases)
- [Commits](https://github.com/webpack/webpack/compare/v5.11.0...v5.11.1)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-01-03 15:20:06 +05:30
dependabot[bot] afe0c760f6 chore(deps-dev): bump webpack-cli in /src/packages/utils (#2701)
Bumps [webpack-cli](https://github.com/webpack/webpack-cli) from 4.2.0 to 4.3.1.
- [Release notes](https://github.com/webpack/webpack-cli/releases)
- [Changelog](https://github.com/webpack/webpack-cli/blob/master/CHANGELOG.md)
- [Commits](https://github.com/webpack/webpack-cli/compare/webpack-cli@4.2.0...webpack-cli@4.3.1)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-01-03 15:14:21 +05:30
dependabot[bot] a231cefac0 chore(deps-dev): bump webpack-cli in /src/packages/excalidraw (#2697)
Bumps [webpack-cli](https://github.com/webpack/webpack-cli) from 4.2.0 to 4.3.1.
- [Release notes](https://github.com/webpack/webpack-cli/releases)
- [Changelog](https://github.com/webpack/webpack-cli/blob/master/CHANGELOG.md)
- [Commits](https://github.com/webpack/webpack-cli/compare/webpack-cli@4.2.0...webpack-cli@4.3.1)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-01-03 15:14:01 +05:30
dependabot[bot] cb4c9d16fc chore(deps-dev): bump webpack in /src/packages/utils (#2699)
Bumps [webpack](https://github.com/webpack/webpack) from 5.11.0 to 5.11.1.
- [Release notes](https://github.com/webpack/webpack/releases)
- [Commits](https://github.com/webpack/webpack/compare/v5.11.0...v5.11.1)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-01-03 15:02:27 +05:30
dependabot[bot] 7366f089ba chore(packages/excalidraw): bump ts-loader from 8.0.12 to 8.0.13. (#2696)
Bumps [ts-loader](https://github.com/TypeStrong/ts-loader) from 8.0.12 to 8.0.13.
- [Release notes](https://github.com/TypeStrong/ts-loader/releases)
- [Changelog](https://github.com/TypeStrong/ts-loader/blob/master/CHANGELOG.md)
- [Commits](https://github.com/TypeStrong/ts-loader/compare/v8.0.12...v8.0.13)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-01-03 15:01:57 +05:30
Benja Kugler 7c3513b9df feat: browse libraries styles fixed (#2694)
* feat: browse libraries styles fixed

* simplify jsx & css

* remove justify-content

* fix padding/margin

* Update src/components/LayerUI.scss

Co-authored-by: benjamin.kugler <benjamin.kugler@elliemae.com>
Co-authored-by: dwelle <luzar.david@gmail.com>
2021-01-02 17:13:48 +01:00
David Luzar aef3644c93 fix: scene not initialized properly when tab not focused (#2677)
Co-authored-by: Lipis <lipiridis@gmail.com>
2020-12-29 21:03:34 +01:00
David Luzar 0cf58adb4c chore: Update portal URL (#2689) 2020-12-28 13:14:22 +01:00
David Luzar 3aab81bc35 docs: add tsdoc for certain element props (#2673)
Co-authored-by: Panayiotis Lipiridis <lipiridis@gmail.com>
2020-12-28 00:17:27 +02:00
Jed Fox 3b0fb1562d feat: Require use of a preset dialog size; adjust dialog sizing (#2684) 2020-12-28 00:07:05 +02:00
Jed Fox 0488b7b5c6 fix(css): Fix compile error (#2685) 2020-12-27 23:42:23 +02:00
Jed Fox b8d13c98b5 refactor: Media queries (#2680) 2020-12-27 23:27:25 +02:00
Lipis 6f82a88b79 chore: Cleanup unused labels (#2682) 2020-12-27 18:51:47 +02:00
Lipis 022f349dc6 feat: Add line chart and paste dialog selection (#2670)
Co-authored-by: dwelle <luzar.david@gmail.com>
Co-authored-by: Jed Fox <git@jedfox.com>
2020-12-27 18:26:30 +02:00
dependabot[bot] c1e2146d78 chore(deps-dev): bump firebase-tools from 9.0.1 to 9.1.0 (#2676)
Bumps [firebase-tools](https://github.com/firebase/firebase-tools) from 9.0.1 to 9.1.0.
- [Release notes](https://github.com/firebase/firebase-tools/releases)
- [Commits](https://github.com/firebase/firebase-tools/compare/v9.0.1...v9.1.0)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2020-12-27 13:51:54 +02:00
Harshil Parmar 8091ac6c08 style: media query for hiding shortcuts for mobile view (#2667)
Co-authored-by: Lipis <lipiridis@gmail.com>
2020-12-26 21:23:51 +02:00
Luo bc414ccaaf feat: tweak editing behavior (#2668)
* feat: tweak editing behavior

* fix tests

Co-authored-by: dwelle <luzar.david@gmail.com>
2020-12-25 19:34:47 +01:00
Kostas Bariotis 0cf5f1ac1f chore: update Sentry (#2669) 2020-12-25 20:02:12 +02:00
Lipis e9cb7ee77c chore: New Crowdin updates (#2620)
Co-authored-by: Kostas Bariotis <konmpar@gmail.com>
2020-12-25 12:15:34 +02:00
Lipis 86c036505b chore: Remove unused cursorX, cursorY from AppState (#2665) 2020-12-24 22:05:22 +01:00
93 changed files with 2842 additions and 2053 deletions
+1 -1
View File
@@ -1,5 +1,5 @@
REACT_APP_BACKEND_V1_GET_URL=https://json.excalidraw.com/api/v1/
REACT_APP_BACKEND_V2_GET_URL=https://json.excalidraw.com/api/v2/
REACT_APP_BACKEND_V2_POST_URL=https://json.excalidraw.com/api/v2/post/
REACT_APP_SOCKET_SERVER_URL=https://excalidraw-socket.herokuapp.com
REACT_APP_SOCKET_SERVER_URL=https://portal.excalidraw.com
REACT_APP_FIREBASE_CONFIG='{"apiKey":"AIzaSyAd15pYlMci_xIp9ko6wkEsDzAAA0Dn0RU","authDomain":"excalidraw-room-persistence.firebaseapp.com","databaseURL":"https://excalidraw-room-persistence.firebaseio.com","projectId":"excalidraw-room-persistence","storageBucket":"excalidraw-room-persistence.appspot.com","messagingSenderId":"654800341332","appId":"1:654800341332:web:4a692de832b55bd57ce0c1"}'
+44 -44
View File
@@ -2663,70 +2663,70 @@
}
},
"@sentry/browser": {
"version": "5.29.0",
"resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-5.29.0.tgz",
"integrity": "sha512-kRlt1mE2wrYjspnIupNnPxqsUrRuy02SuXhbpP7J6uu8QasoEmJ78hk0hHz4jOZRmuWwfs2zIXD4tLGgWOKq8A==",
"version": "5.29.2",
"resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-5.29.2.tgz",
"integrity": "sha512-uxZ7y7rp85tJll+RZtXRhXPbnFnOaxZqJEv05vJlXBtBNLQtlczV5iCtU9mZRLVHDtmZ5VVKUV8IKXntEqqDpQ==",
"requires": {
"@sentry/core": "5.29.0",
"@sentry/types": "5.29.0",
"@sentry/utils": "5.29.0",
"@sentry/core": "5.29.2",
"@sentry/types": "5.29.2",
"@sentry/utils": "5.29.2",
"tslib": "^1.9.3"
}
},
"@sentry/core": {
"version": "5.29.0",
"resolved": "https://registry.npmjs.org/@sentry/core/-/core-5.29.0.tgz",
"integrity": "sha512-a1sZBJ2u3NG0YDlGvOTwUCWiNjhfmDtAQiKK1o6RIIbcrWy9TlSps7CYDkBP239Y3A4pnvohjEEKEP3v3L3LZQ==",
"version": "5.29.2",
"resolved": "https://registry.npmjs.org/@sentry/core/-/core-5.29.2.tgz",
"integrity": "sha512-7WYkoxB5IdlNEbwOwqSU64erUKH4laavPsM0/yQ+jojM76ErxlgEF0u//p5WaLPRzh3iDSt6BH+9TL45oNZeZw==",
"requires": {
"@sentry/hub": "5.29.0",
"@sentry/minimal": "5.29.0",
"@sentry/types": "5.29.0",
"@sentry/utils": "5.29.0",
"@sentry/hub": "5.29.2",
"@sentry/minimal": "5.29.2",
"@sentry/types": "5.29.2",
"@sentry/utils": "5.29.2",
"tslib": "^1.9.3"
}
},
"@sentry/hub": {
"version": "5.29.0",
"resolved": "https://registry.npmjs.org/@sentry/hub/-/hub-5.29.0.tgz",
"integrity": "sha512-kcDPQsRG4cFdmqDh+TzjeO7lWYxU8s1dZYAbbl1J4uGKmhNB0J7I4ak4SGwTsXLY6fhbierxr6PRaoNojCxjPw==",
"version": "5.29.2",
"resolved": "https://registry.npmjs.org/@sentry/hub/-/hub-5.29.2.tgz",
"integrity": "sha512-LaAIo2hwUk9ykeh9RF0cwLy6IRw+DjEee8l1HfEaDFUM6TPGlNNGObMJNXb9/95jzWp7jWwOpQjoIE3jepdQJQ==",
"requires": {
"@sentry/types": "5.29.0",
"@sentry/utils": "5.29.0",
"@sentry/types": "5.29.2",
"@sentry/utils": "5.29.2",
"tslib": "^1.9.3"
}
},
"@sentry/integrations": {
"version": "5.29.0",
"resolved": "https://registry.npmjs.org/@sentry/integrations/-/integrations-5.29.0.tgz",
"integrity": "sha512-SGqpi1Qd1a7gGL6aYrJnKqU/DNJcHvnhD3qOgow23ivEpaJv1BtQSKxv17IbO/CIFn3A0o1a18wY6xef9isKEQ==",
"version": "5.29.2",
"resolved": "https://registry.npmjs.org/@sentry/integrations/-/integrations-5.29.2.tgz",
"integrity": "sha512-bH50B0xubbHrJFq8xZRxOc5BgXe1PXKfC0OqQkhhSd+Bu2WDLCHcn0CEzV+8thZTYkipAoFAFJNdEWcsM2Wcew==",
"requires": {
"@sentry/types": "5.29.0",
"@sentry/utils": "5.29.0",
"@sentry/types": "5.29.2",
"@sentry/utils": "5.29.2",
"localforage": "1.8.1",
"tslib": "^1.9.3"
}
},
"@sentry/minimal": {
"version": "5.29.0",
"resolved": "https://registry.npmjs.org/@sentry/minimal/-/minimal-5.29.0.tgz",
"integrity": "sha512-nhXofdjtO41/caiF1wk1oT3p/QuhOZDYdF/b29DoD2MiAMK9IjhhOXI/gqaRpDKkXlDvd95fDTcx4t/MqqcKXA==",
"version": "5.29.2",
"resolved": "https://registry.npmjs.org/@sentry/minimal/-/minimal-5.29.2.tgz",
"integrity": "sha512-0aINSm8fGA1KyM7PavOBe1GDZDxrvnKt+oFnU0L+bTcw8Lr+of+v6Kwd97rkLRNOLw621xP076dL/7LSIzMuhw==",
"requires": {
"@sentry/hub": "5.29.0",
"@sentry/types": "5.29.0",
"@sentry/hub": "5.29.2",
"@sentry/types": "5.29.2",
"tslib": "^1.9.3"
}
},
"@sentry/types": {
"version": "5.29.0",
"resolved": "https://registry.npmjs.org/@sentry/types/-/types-5.29.0.tgz",
"integrity": "sha512-iDkxT/9sT3UF+Xb+JyLjZ5caMXsgLfRyV9VXQEiR2J6mgpMielj184d9jeF3bm/VMuAf/VFFqrHlcVsVgmrrMw=="
"version": "5.29.2",
"resolved": "https://registry.npmjs.org/@sentry/types/-/types-5.29.2.tgz",
"integrity": "sha512-dM9wgt8wy4WRty75QkqQgrw9FV9F+BOMfmc0iaX13Qos7i6Qs2Q0dxtJ83SoR4YGtW8URaHzlDtWlGs5egBiMA=="
},
"@sentry/utils": {
"version": "5.29.0",
"resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-5.29.0.tgz",
"integrity": "sha512-b2B1gshw2u3EHlAi84PuI5sfmLKXW1z9enMMhNuuNT/CoRp+g5kMAcUv/qYTws7UNnYSvTuVGuZG30v1e0hP9A==",
"version": "5.29.2",
"resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-5.29.2.tgz",
"integrity": "sha512-nEwQIDjtFkeE4k6yIk4Ka5XjGRklNLThWLs2xfXlL7uwrYOH2B9UBBOOIRUraBm/g/Xrra3xsam/kRxuiwtXZQ==",
"requires": {
"@sentry/types": "5.29.0",
"@sentry/types": "5.29.2",
"tslib": "^1.9.3"
}
},
@@ -3030,9 +3030,9 @@
}
},
"@testing-library/jest-dom": {
"version": "5.11.6",
"resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-5.11.6.tgz",
"integrity": "sha512-cVZyUNRWwUKI0++yepYpYX7uhrP398I+tGz4zOlLVlUYnZS+Svuxv4fwLeCIy7TnBYKXUaOlQr3vopxL8ZfEnA==",
"version": "5.11.8",
"resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-5.11.8.tgz",
"integrity": "sha512-ScyKrWQM5xNcr79PkSewnA79CLaoxVskE+f7knTOhDD9ftZSA1Jw8mj+pneqhEu3x37ncNfW84NUr7lqK+mXjA==",
"requires": {
"@babel/runtime": "^7.9.2",
"@types/testing-library__jest-dom": "^5.9.1",
@@ -9039,9 +9039,9 @@
}
},
"firebase-tools": {
"version": "9.0.1",
"resolved": "https://registry.npmjs.org/firebase-tools/-/firebase-tools-9.0.1.tgz",
"integrity": "sha512-OktyHgjIBJR/JPNU4Xv4NsRLWu5gDnTmYd88VUsMwzUMCkbao2NNpeBi6+0rn6U1zNhwP2WW9PngccJWg/wvSA==",
"version": "9.1.0",
"resolved": "https://registry.npmjs.org/firebase-tools/-/firebase-tools-9.1.0.tgz",
"integrity": "sha512-hTfxL2meJSl5WuwAS6bEJ5nay7tu3MNYb4ZL2KmPL7yLM3IeT+Qd2z1evHhW1VvbDXKR6RTwlBxzdWPs4l75kA==",
"dev": true,
"requires": {
"@google-cloud/pubsub": "^2.7.0",
@@ -10085,9 +10085,9 @@
}
},
"@types/node": {
"version": "12.19.9",
"resolved": "https://registry.npmjs.org/@types/node/-/node-12.19.9.tgz",
"integrity": "sha512-yj0DOaQeUrk3nJ0bd3Y5PeDRJ6W0r+kilosLA+dzF3dola/o9hxhMSg2sFvVcA2UHS5JSOsZp4S0c1OEXc4m1Q==",
"version": "12.19.11",
"resolved": "https://registry.npmjs.org/@types/node/-/node-12.19.11.tgz",
"integrity": "sha512-bwVfNTFZOrGXyiQ6t4B9sZerMSShWNsGRw8tC5DY1qImUNczS9SjT4G6PnzjCnxsu5Ubj6xjL2lgwddkxtQl5w==",
"dev": true
},
"ansi-styles": {
+4 -4
View File
@@ -19,9 +19,9 @@
]
},
"dependencies": {
"@sentry/browser": "5.29.0",
"@sentry/integrations": "5.29.0",
"@testing-library/jest-dom": "5.11.6",
"@sentry/browser": "5.29.2",
"@sentry/integrations": "5.29.2",
"@testing-library/jest-dom": "5.11.8",
"@testing-library/react": "11.2.2",
"@types/jest": "26.0.19",
"@types/nanoid": "2.1.0",
@@ -54,7 +54,7 @@
"@types/pako": "1.0.1",
"eslint-config-prettier": "7.1.0",
"eslint-plugin-prettier": "3.3.0",
"firebase-tools": "9.0.1",
"firebase-tools": "9.1.0",
"husky": "4.3.6",
"jest-canvas-mock": "2.3.0",
"lint-staged": "10.5.3",
+8 -9
View File
@@ -24,6 +24,7 @@ const crowdinMap = {
"nl-NL": "en-nl",
"nn-NO": "en-nnno",
"pl-PL": "en-pl",
"pt-BR": "en-ptbr",
"pt-PT": "en-pt",
"ro-RO": "en-ro",
"ru-RU": "en-ru",
@@ -57,6 +58,7 @@ const flags = {
"nl-NL": "🇳🇱",
"nn-NO": "🇳🇴",
"pl-PL": "🇵🇱",
"pt-BR": "🇧🇷",
"pt-PT": "🇵🇹",
"ro-RO": "🇷🇴",
"ru-RU": "🇷🇺",
@@ -90,6 +92,7 @@ const languages = {
"nl-NL": "Nederlands",
"nn-NO": "Norsk nynorsk",
"pl-PL": "Polski",
"pt-BR": "Português Brasileiro",
"pt-PT": "Português",
"ro-RO": "Română",
"ru-RU": "Русский",
@@ -114,16 +117,14 @@ const boldIf = (text, condition) => (condition ? `**${text}**` : text);
const printHeader = () => {
let result = "| | Flag | Locale | % |\n";
result += "| --: | :--: | -- | --: |";
result += "| :--: | :--: | -- | :--: |";
return result;
};
const printRow = (id, locale, coverage) => {
const isOver = coverage > THRESSHOLD;
let result = `| ${boldIf(id, isOver)} | `;
const isOver = coverage >= THRESSHOLD;
let result = `| ${isOver ? id : "..."} | `;
result += `${locale in flags ? flags[locale] : ""} | `;
const language = locale in languages ? languages[locale] : locale;
if (locale in crowdinMap && crowdinMap[locale]) {
result += `[${boldIf(
@@ -133,14 +134,12 @@ const printRow = (id, locale, coverage) => {
} else {
result += `${boldIf(language, isOver)} | `;
}
result += `${boldIf(coverage, isOver)} |`;
result += `${coverage === 100 ? "✅" : boldIf(coverage, isOver)} |`;
return result;
};
console.info("## Languages check");
console.info("\n\r");
console.info(
`Our translations for every languages should be at least **${THRESSHOLD}%** to appear on Excalidraw. Join our project in [Crowdin](https://crowdin.com/project/excalidraw) and help us translate it in your language. **Can't find your own?** Open an [issue](https://github.com/excalidraw/excalidraw/issues/new) and we'll add it to the list.`,
`Each language must be at least **${THRESSHOLD}%** translated in order to appear on Excalidraw. Join us on [Crowdin](https://crowdin.com/project/excalidraw) and help us translate your own language. **Can't find yours yet?** Open an [issue](https://github.com/excalidraw/excalidraw/issues/new) and we'll add it to the list.`,
);
console.info("\n\r");
console.info(printHeader());
+15 -14
View File
@@ -1,23 +1,22 @@
import React from "react";
import { ColorPicker } from "../components/ColorPicker";
import { EVENT_ACTION, EVENT_CHANGE, trackEvent } from "../analytics";
import { getDefaultAppState } from "../appState";
import { trash, zoomIn, zoomOut, resetZoom } from "../components/icons";
import colors from "../colors";
import { ColorPicker } from "../components/ColorPicker";
import { resetZoom, trash, zoomIn, zoomOut } from "../components/icons";
import { ToolButton } from "../components/ToolButton";
import { t } from "../i18n";
import { getNormalizedZoom, getSelectedElements } from "../scene";
import { getNonDeletedElements } from "../element";
import { CODES, KEYS } from "../keys";
import { getShortcutKey } from "../utils";
import useIsMobile from "../is-mobile";
import { register } from "./register";
import { getCommonBounds, getNonDeletedElements } from "../element";
import { newElementWith } from "../element/mutateElement";
import { ExcalidrawElement } from "../element/types";
import { AppState, NormalizedZoomValue } from "../types";
import { getCommonBounds } from "../element";
import { getNewZoom } from "../scene/zoom";
import { t } from "../i18n";
import useIsMobile from "../is-mobile";
import { CODES, KEYS } from "../keys";
import { getNormalizedZoom, getSelectedElements } from "../scene";
import { centerScrollOn } from "../scene/scroll";
import { EVENT_ACTION, EVENT_CHANGE, trackEvent } from "../analytics";
import colors from "../colors";
import { getNewZoom } from "../scene/zoom";
import { AppState, NormalizedZoomValue } from "../types";
import { getNewSceneName, getShortcutKey } from "../utils";
import { register } from "./register";
export const actionChangeViewBackgroundColor = register({
name: "changeViewBackgroundColor",
@@ -60,6 +59,7 @@ export const actionClearCanvas = register({
),
appState: {
...getDefaultAppState(),
name: getNewSceneName(),
appearance: appState.appearance,
elementLocked: appState.elementLocked,
exportBackground: appState.exportBackground,
@@ -67,6 +67,7 @@ export const actionClearCanvas = register({
gridSize: appState.gridSize,
shouldAddWatermark: appState.shouldAddWatermark,
showStats: appState.showStats,
pasteDialog: appState.pasteDialog,
},
commitToHistory: true,
};
+2 -1
View File
@@ -12,6 +12,7 @@ import { KEYS } from "../keys";
import { muteFSAbortError } from "../utils";
import { register } from "./register";
import "../components/ToolIcon.scss";
import { SCENE_NAME_FALLBACK } from "../constants";
export const actionChangeProjectName = register({
name: "changeProjectName",
@@ -22,7 +23,7 @@ export const actionChangeProjectName = register({
PanelComponent: ({ appState, updateData }) => (
<ProjectName
label={t("labels.fileTitle")}
value={appState.name || "Unnamed"}
value={appState.name || SCENE_NAME_FALLBACK}
onChange={(name: string) => updateData(name)}
/>
),
+71 -66
View File
@@ -1,79 +1,84 @@
import oc from "open-color";
import { AppState, FlooredNumber, NormalizedZoomValue } from "./types";
import { getDateTime } from "./utils";
import { t } from "./i18n";
import {
DEFAULT_FONT_SIZE,
DEFAULT_FONT_FAMILY,
DEFAULT_FONT_SIZE,
SCENE_NAME_FALLBACK,
DEFAULT_TEXT_ALIGN,
} from "./constants";
import { AppState, FlooredNumber, NormalizedZoomValue } from "./types";
export const getDefaultAppState = (): Omit<
AppState,
"offsetTop" | "offsetLeft"
> => {
type DefaultAppState = Omit<AppState, "offsetTop" | "offsetLeft" | "name"> & {
/**
* You should override this with current appState.name, or whatever is
* applicable at a given place where you get default appState.
*/
name: undefined;
};
export const getDefaultAppState = (): DefaultAppState => {
return {
appearance: "light",
isLoading: false,
errorMessage: null,
collaborators: new Map(),
currentChartType: "bar",
currentItemBackgroundColor: "transparent",
currentItemEndArrowhead: "arrow",
currentItemFillStyle: "hachure",
currentItemFontFamily: DEFAULT_FONT_FAMILY,
currentItemFontSize: DEFAULT_FONT_SIZE,
currentItemLinearStrokeSharpness: "round",
currentItemOpacity: 100,
currentItemRoughness: 1,
currentItemStartArrowhead: null,
currentItemStrokeColor: oc.black,
currentItemStrokeSharpness: "sharp",
currentItemStrokeStyle: "solid",
currentItemStrokeWidth: 1,
currentItemTextAlign: DEFAULT_TEXT_ALIGN,
cursorButton: "up",
draggingElement: null,
resizingElement: null,
multiElement: null,
editingElement: null,
startBoundElement: null,
editingGroupId: null,
editingLinearElement: null,
elementType: "selection",
elementLocked: false,
elementType: "selection",
errorMessage: null,
exportBackground: true,
exportEmbedScene: false,
shouldAddWatermark: false,
currentItemStrokeColor: oc.black,
currentItemBackgroundColor: "transparent",
currentItemFillStyle: "hachure",
currentItemStrokeWidth: 1,
currentItemStrokeStyle: "solid",
currentItemRoughness: 1,
currentItemOpacity: 100,
currentItemFontSize: DEFAULT_FONT_SIZE,
currentItemFontFamily: DEFAULT_FONT_FAMILY,
currentItemTextAlign: DEFAULT_TEXT_ALIGN,
currentItemStrokeSharpness: "sharp",
currentItemLinearStrokeSharpness: "round",
currentItemStartArrowhead: null,
currentItemEndArrowhead: "arrow",
viewBackgroundColor: oc.white,
scrollX: 0 as FlooredNumber,
scrollY: 0 as FlooredNumber,
cursorX: 0,
cursorY: 0,
cursorButton: "up",
scrolledOutside: false,
name: `${t("labels.untitled")}-${getDateTime()}`,
fileHandle: null,
gridSize: null,
height: window.innerHeight,
isBindingEnabled: true,
isLibraryOpen: false,
isLoading: false,
isResizing: false,
isRotating: false,
selectionElement: null,
zoom: {
value: 1 as NormalizedZoomValue,
translation: { x: 0, y: 0 },
},
openMenu: null,
lastPointerDownWith: "mouse",
selectedElementIds: {},
multiElement: null,
// for safety (because TS mostly doesn't distinguish optional types and
// undefined values), we set `name` to the fallback name, but we cast it to
// `undefined` so that TS forces us to explicitly specify it wherever
// possible
name: (SCENE_NAME_FALLBACK as unknown) as undefined,
openMenu: null,
pasteDialog: { shown: false, data: null },
previousSelectedElementIds: {},
resizingElement: null,
scrolledOutside: false,
scrollX: 0 as FlooredNumber,
scrollY: 0 as FlooredNumber,
selectedElementIds: {},
selectedGroupIds: {},
selectionElement: null,
shouldAddWatermark: false,
shouldCacheIgnoreZoom: false,
showShortcutsDialog: false,
suggestedBindings: [],
zenModeEnabled: false,
gridSize: null,
editingGroupId: null,
selectedGroupIds: {},
width: window.innerWidth,
height: window.innerHeight,
isLibraryOpen: false,
fileHandle: null,
collaborators: new Map(),
showStats: false,
startBoundElement: null,
suggestedBindings: [],
viewBackgroundColor: oc.white,
width: window.innerWidth,
zenModeEnabled: false,
zoom: { value: 1 as NormalizedZoomValue, translation: { x: 0, y: 0 } },
};
};
@@ -93,26 +98,25 @@ const APP_STATE_STORAGE_CONF = (<
config: { [K in keyof T]: K extends keyof AppState ? T[K] : never },
) => config)({
appearance: { browser: true, export: false },
collaborators: { browser: false, export: false },
currentChartType: { browser: true, export: false },
currentItemBackgroundColor: { browser: true, export: false },
currentItemEndArrowhead: { browser: true, export: false },
currentItemFillStyle: { browser: true, export: false },
currentItemFontFamily: { browser: true, export: false },
currentItemFontSize: { browser: true, export: false },
currentItemLinearStrokeSharpness: { browser: true, export: false },
currentItemOpacity: { browser: true, export: false },
currentItemRoughness: { browser: true, export: false },
currentItemStartArrowhead: { browser: true, export: false },
currentItemStrokeColor: { browser: true, export: false },
currentItemStrokeSharpness: { browser: true, export: false },
currentItemStrokeStyle: { browser: true, export: false },
currentItemStrokeWidth: { browser: true, export: false },
currentItemTextAlign: { browser: true, export: false },
currentItemStrokeSharpness: { browser: true, export: false },
currentItemLinearStrokeSharpness: { browser: true, export: false },
currentItemStartArrowhead: { browser: true, export: false },
currentItemEndArrowhead: { browser: true, export: false },
cursorButton: { browser: true, export: false },
cursorX: { browser: true, export: false },
cursorY: { browser: true, export: false },
draggingElement: { browser: false, export: false },
editingElement: { browser: false, export: false },
startBoundElement: { browser: false, export: false },
editingGroupId: { browser: true, export: false },
editingLinearElement: { browser: false, export: false },
elementLocked: { browser: true, export: false },
@@ -120,6 +124,7 @@ const APP_STATE_STORAGE_CONF = (<
errorMessage: { browser: false, export: false },
exportBackground: { browser: true, export: false },
exportEmbedScene: { browser: true, export: false },
fileHandle: { browser: false, export: false },
gridSize: { browser: true, export: true },
height: { browser: false, export: false },
isBindingEnabled: { browser: false, export: false },
@@ -130,7 +135,10 @@ const APP_STATE_STORAGE_CONF = (<
lastPointerDownWith: { browser: true, export: false },
multiElement: { browser: false, export: false },
name: { browser: true, export: false },
offsetLeft: { browser: false, export: false },
offsetTop: { browser: false, export: false },
openMenu: { browser: true, export: false },
pasteDialog: { browser: false, export: false },
previousSelectedElementIds: { browser: true, export: false },
resizingElement: { browser: false, export: false },
scrolledOutside: { browser: true, export: false },
@@ -142,16 +150,13 @@ const APP_STATE_STORAGE_CONF = (<
shouldAddWatermark: { browser: true, export: false },
shouldCacheIgnoreZoom: { browser: true, export: false },
showShortcutsDialog: { browser: false, export: false },
showStats: { browser: true, export: false },
startBoundElement: { browser: false, export: false },
suggestedBindings: { browser: false, export: false },
viewBackgroundColor: { browser: true, export: true },
width: { browser: false, export: false },
zenModeEnabled: { browser: true, export: false },
zoom: { browser: true, export: false },
offsetTop: { browser: false, export: false },
offsetLeft: { browser: false, export: false },
fileHandle: { browser: false, export: false },
collaborators: { browser: false, export: false },
showStats: { browser: true, export: false },
});
const _clearAppStateForStorage = <ExportType extends "export" | "browser">(
+311 -115
View File
@@ -1,13 +1,16 @@
import { EVENT_MAGIC, trackEvent } from "./analytics";
import colors from "./colors";
import { DEFAULT_FONT_FAMILY, DEFAULT_FONT_SIZE } from "./constants";
import { newElement, newTextElement, newLinearElement } from "./element";
import { ExcalidrawElement } from "./element/types";
import { DEFAULT_FONT_FAMILY, DEFAULT_FONT_SIZE, ENV } from "./constants";
import { newElement, newLinearElement, newTextElement } from "./element";
import { NonDeletedExcalidrawElement } from "./element/types";
import { randomId } from "./random";
export type ChartElements = readonly NonDeletedExcalidrawElement[];
const BAR_WIDTH = 32;
const BAR_GAP = 12;
const BAR_HEIGHT = 256;
const GRID_OPACITY = 50;
export interface Spreadsheet {
title: string | null;
@@ -139,114 +142,48 @@ export const tryParseSpreadsheet = (text: string): ParseSpreadsheetResult => {
return transposedResults;
}
}
return result;
};
// For the maths behind it https://excalidraw.com/#json=6320864370884608,O_5xfD-Agh32tytHpRJx1g
export const renderSpreadsheet = (
const bgColors = colors.elementBackground.slice(
2,
colors.elementBackground.length,
);
// Put all the common properties here so when the whole chart is selected
// the properties dialog shows the correct selected values
const commonProps = {
fillStyle: "hachure",
fontFamily: DEFAULT_FONT_FAMILY,
fontSize: DEFAULT_FONT_SIZE,
opacity: 100,
roughness: 1,
strokeColor: colors.elementStroke[0],
strokeSharpness: "sharp",
strokeStyle: "solid",
strokeWidth: 1,
verticalAlign: "middle",
} as const;
const getChartDimentions = (spreadsheet: Spreadsheet) => {
const chartWidth =
(BAR_WIDTH + BAR_GAP) * spreadsheet.values.length + BAR_GAP;
const chartHeight = BAR_HEIGHT + BAR_GAP * 2;
return { chartWidth, chartHeight };
};
const chartXLabels = (
spreadsheet: Spreadsheet,
x: number,
y: number,
): ExcalidrawElement[] => {
const values = spreadsheet.values;
const max = Math.max(...values);
const chartHeight = BAR_HEIGHT + BAR_GAP * 2;
const chartWidth = (BAR_WIDTH + BAR_GAP) * values.length + BAR_GAP;
const maxColors = colors.elementBackground.length;
const bgColors = colors.elementBackground.slice(2, maxColors);
// Put all the common properties here so when the whole chart is selected
// the properties dialog shows the correct selected values
const commonProps = {
backgroundColor: bgColors[Math.floor(Math.random() * bgColors.length)],
fillStyle: "hachure",
fontFamily: DEFAULT_FONT_FAMILY,
fontSize: DEFAULT_FONT_SIZE,
groupIds: [randomId()],
opacity: 100,
roughness: 1,
strokeColor: colors.elementStroke[0],
strokeSharpness: "sharp",
strokeStyle: "solid",
strokeWidth: 1,
verticalAlign: "middle",
} as const;
const minYLabel = newTextElement({
...commonProps,
x: x - BAR_GAP,
y: y - BAR_GAP,
text: "0",
textAlign: "right",
});
const maxYLabel = newTextElement({
...commonProps,
x: x - BAR_GAP,
y: y - BAR_HEIGHT - minYLabel.height / 2,
text: max.toLocaleString(),
textAlign: "right",
});
const xAxisLine = newLinearElement({
type: "line",
x,
y,
startArrowhead: null,
endArrowhead: null,
width: chartWidth,
points: [
[0, 0],
[chartWidth, 0],
],
...commonProps,
});
const yAxisLine = newLinearElement({
type: "line",
x,
y,
startArrowhead: null,
endArrowhead: null,
height: chartHeight,
points: [
[0, 0],
[0, -chartHeight],
],
...commonProps,
});
const maxValueLine = newLinearElement({
type: "line",
x,
y: y - BAR_HEIGHT - BAR_GAP,
startArrowhead: null,
endArrowhead: null,
...commonProps,
strokeStyle: "dotted",
width: chartWidth,
points: [
[0, 0],
[chartWidth, 0],
],
});
const bars = values.map((value, index) => {
const barHeight = (value / max) * BAR_HEIGHT;
return newElement({
...commonProps,
type: "rectangle",
x: x + index * (BAR_WIDTH + BAR_GAP) + BAR_GAP,
y: y - barHeight - BAR_GAP,
width: BAR_WIDTH,
height: barHeight,
});
});
const xLabels =
groupId: string,
backgroundColor: string,
): ChartElements => {
return (
spreadsheet.labels?.map((label, index) => {
return newTextElement({
groupIds: [groupId],
backgroundColor,
...commonProps,
text: label.length > 8 ? `${label.slice(0, 5)}...` : label,
x: x + index * (BAR_WIDTH + BAR_GAP) + BAR_GAP * 2,
@@ -257,29 +194,288 @@ export const renderSpreadsheet = (
textAlign: "center",
verticalAlign: "top",
});
}) || [];
}) || []
);
};
const chartYLabels = (
spreadsheet: Spreadsheet,
x: number,
y: number,
groupId: string,
backgroundColor: string,
): ChartElements => {
const minYLabel = newTextElement({
groupIds: [groupId],
backgroundColor,
...commonProps,
x: x - BAR_GAP,
y: y - BAR_GAP,
text: "0",
textAlign: "right",
});
const maxYLabel = newTextElement({
groupIds: [groupId],
backgroundColor,
...commonProps,
x: x - BAR_GAP,
y: y - BAR_HEIGHT - minYLabel.height / 2,
text: Math.max(...spreadsheet.values).toLocaleString(),
textAlign: "right",
});
return [minYLabel, maxYLabel];
};
const chartLines = (
spreadsheet: Spreadsheet,
x: number,
y: number,
groupId: string,
backgroundColor: string,
): ChartElements => {
const { chartWidth, chartHeight } = getChartDimentions(spreadsheet);
const xLine = newLinearElement({
backgroundColor,
groupIds: [groupId],
...commonProps,
type: "line",
x,
y,
startArrowhead: null,
endArrowhead: null,
width: chartWidth,
points: [
[0, 0],
[chartWidth, 0],
],
});
const yLine = newLinearElement({
backgroundColor,
groupIds: [groupId],
...commonProps,
type: "line",
x,
y,
startArrowhead: null,
endArrowhead: null,
height: chartHeight,
points: [
[0, 0],
[0, -chartHeight],
],
});
const maxLine = newLinearElement({
backgroundColor,
groupIds: [groupId],
...commonProps,
type: "line",
x,
y: y - BAR_HEIGHT - BAR_GAP,
startArrowhead: null,
endArrowhead: null,
strokeStyle: "dotted",
width: chartWidth,
opacity: GRID_OPACITY,
points: [
[0, 0],
[chartWidth, 0],
],
});
return [xLine, yLine, maxLine];
};
// For the maths behind it https://excalidraw.com/#json=6320864370884608,O_5xfD-Agh32tytHpRJx1g
const chartBaseElements = (
spreadsheet: Spreadsheet,
x: number,
y: number,
groupId: string,
backgroundColor: string,
debug?: boolean,
): ChartElements => {
const { chartWidth, chartHeight } = getChartDimentions(spreadsheet);
const title = spreadsheet.title
? newTextElement({
backgroundColor,
groupIds: [groupId],
...commonProps,
text: spreadsheet.title,
x: x + chartWidth / 2,
y: y - BAR_HEIGHT - BAR_GAP * 2 - maxYLabel.height,
y: y - BAR_HEIGHT - BAR_GAP * 2 - DEFAULT_FONT_SIZE,
strokeSharpness: "sharp",
strokeStyle: "solid",
textAlign: "center",
})
: null;
trackEvent(EVENT_MAGIC, "chart", "bars", bars.length);
const debugRect = debug
? newElement({
backgroundColor,
groupIds: [groupId],
...commonProps,
type: "rectangle",
x,
y: y - chartHeight,
width: chartWidth,
height: chartHeight,
strokeColor: colors.elementStroke[0],
fillStyle: "solid",
opacity: 6,
})
: null;
return [
title,
...bars,
...xLabels,
xAxisLine,
yAxisLine,
maxValueLine,
minYLabel,
maxYLabel,
].filter((element) => element !== null) as ExcalidrawElement[];
...(debugRect ? [debugRect] : []),
...(title ? [title] : []),
...chartXLabels(spreadsheet, x, y, groupId, backgroundColor),
...chartYLabels(spreadsheet, x, y, groupId, backgroundColor),
...chartLines(spreadsheet, x, y, groupId, backgroundColor),
];
};
const chartTypeBar = (
spreadsheet: Spreadsheet,
x: number,
y: number,
): ChartElements => {
const max = Math.max(...spreadsheet.values);
const groupId = randomId();
const backgroundColor = bgColors[Math.floor(Math.random() * bgColors.length)];
const bars = spreadsheet.values.map((value, index) => {
const barHeight = (value / max) * BAR_HEIGHT;
return newElement({
backgroundColor,
groupIds: [groupId],
...commonProps,
type: "rectangle",
x: x + index * (BAR_WIDTH + BAR_GAP) + BAR_GAP,
y: y - barHeight - BAR_GAP,
width: BAR_WIDTH,
height: barHeight,
});
});
return [
...bars,
...chartBaseElements(
spreadsheet,
x,
y,
groupId,
backgroundColor,
process.env.NODE_ENV === ENV.DEVELOPMENT,
),
];
};
const chartTypeLine = (
spreadsheet: Spreadsheet,
x: number,
y: number,
): ChartElements => {
const max = Math.max(...spreadsheet.values);
const groupId = randomId();
const backgroundColor = bgColors[Math.floor(Math.random() * bgColors.length)];
let index = 0;
const points = [];
for (const value of spreadsheet.values) {
const cx = index * (BAR_WIDTH + BAR_GAP);
const cy = -(value / max) * BAR_HEIGHT;
points.push([cx, cy]);
index++;
}
const maxX = Math.max(...points.map((element) => element[0]));
const maxY = Math.max(...points.map((element) => element[1]));
const minX = Math.min(...points.map((element) => element[0]));
const minY = Math.min(...points.map((element) => element[1]));
const line = newLinearElement({
backgroundColor,
groupIds: [groupId],
...commonProps,
type: "line",
x: x + BAR_GAP + BAR_WIDTH / 2,
y: y - BAR_GAP,
startArrowhead: null,
endArrowhead: null,
height: maxY - minY,
width: maxX - minX,
strokeWidth: 2,
points: points as any,
});
const dots = spreadsheet.values.map((value, index) => {
const cx = index * (BAR_WIDTH + BAR_GAP) + BAR_GAP / 2;
const cy = -(value / max) * BAR_HEIGHT + BAR_GAP / 2;
return newElement({
backgroundColor,
groupIds: [groupId],
...commonProps,
fillStyle: "solid",
strokeWidth: 2,
type: "ellipse",
x: x + cx + BAR_WIDTH / 2,
y: y + cy - BAR_GAP * 2,
width: BAR_GAP,
height: BAR_GAP,
});
});
const lines = spreadsheet.values.map((value, index) => {
const cx = index * (BAR_WIDTH + BAR_GAP) + BAR_GAP / 2;
const cy = (value / max) * BAR_HEIGHT + BAR_GAP / 2 + BAR_GAP;
return newLinearElement({
backgroundColor,
groupIds: [groupId],
...commonProps,
type: "line",
x: x + cx + BAR_WIDTH / 2 + BAR_GAP / 2,
y: y - cy,
startArrowhead: null,
endArrowhead: null,
height: cy,
strokeStyle: "dotted",
opacity: GRID_OPACITY,
points: [
[0, 0],
[0, cy],
],
});
});
return [
...chartBaseElements(
spreadsheet,
x,
y,
groupId,
backgroundColor,
process.env.NODE_ENV === ENV.DEVELOPMENT,
),
line,
...lines,
...dots,
];
};
export const renderSpreadsheet = (
chartType: string,
spreadsheet: Spreadsheet,
x: number,
y: number,
): ChartElements => {
trackEvent(EVENT_MAGIC, "chart", chartType, spreadsheet.values.length);
if (chartType === "line") {
return chartTypeLine(spreadsheet, x, y);
}
return chartTypeBar(spreadsheet, x, y);
};
+189 -177
View File
@@ -1,181 +1,168 @@
import { Point, simplify } from "points-on-curve";
import React from "react";
import rough from "roughjs/bin/rough";
import { RoughCanvas } from "roughjs/bin/canvas";
import { simplify, Point } from "points-on-curve";
import {
newElement,
newTextElement,
duplicateElement,
isInvisiblySmallElement,
isTextElement,
textWysiwyg,
getCommonBounds,
getCursorForResizingElement,
getPerfectElementSize,
getNormalizedDimensions,
newLinearElement,
transformElements,
getElementWithTransformHandleType,
getResizeOffsetXY,
getResizeArrowDirection,
getTransformHandleTypeFromCoords,
isNonDeletedElement,
updateTextElement,
dragSelectedElements,
getDragOffsetXY,
dragNewElement,
hitTest,
isHittingElementBoundingBoxWithoutHittingElement,
getNonDeletedElements,
} from "../element";
import {
getElementsWithinSelection,
isOverScrollBars,
getElementsAtPosition,
getElementContainingPosition,
getNormalizedZoom,
getSelectedElements,
isSomeElementSelected,
calculateScrollCenter,
} from "../scene";
import { loadFromBlob, exportCanvas } from "../data";
import { renderScene } from "../renderer";
import {
AppState,
GestureEvent,
Gesture,
ExcalidrawProps,
SceneData,
} from "../types";
import {
ExcalidrawElement,
ExcalidrawTextElement,
NonDeleted,
ExcalidrawGenericElement,
ExcalidrawLinearElement,
ExcalidrawBindableElement,
} from "../element/types";
import { distance2d, isPathALoop, getGridPoint } from "../math";
import {
isWritableElement,
isInputLike,
isToolIcon,
debounce,
distance,
resetCursor,
viewportCoordsToSceneCoords,
sceneCoordsToViewportCoords,
setCursorForShape,
tupleToCoors,
ResolvablePromise,
resolvablePromise,
withBatchedUpdates,
} from "../utils";
import {
KEYS,
isArrowKey,
getResizeCenterPointKey,
getResizeWithSidesSameLengthKey,
getRotateWithDiscreteAngleKey,
CODES,
} from "../keys";
import { findShapeByKey } from "../shapes";
import { createHistory, SceneHistory } from "../history";
import ContextMenu from "./ContextMenu";
import { ActionManager } from "../actions/manager";
import rough from "roughjs/bin/rough";
import "../actions";
import { actionDeleteSelected, actionFinalize } from "../actions";
import { createRedoAction, createUndoAction } from "../actions/actionHistory";
import { ActionManager } from "../actions/manager";
import { actions } from "../actions/register";
import { ActionResult } from "../actions/types";
import { getDefaultAppState } from "../appState";
import { t, getLanguage } from "../i18n";
import {
copyToClipboard,
parseClipboard,
probablySupportsClipboardBlob,
probablySupportsClipboardWriteText,
} from "../clipboard";
import { normalizeScroll } from "../scene";
import { getCenter, getDistance } from "../gesture";
import { createUndoAction, createRedoAction } from "../actions/actionHistory";
import {
CURSOR_TYPE,
ELEMENT_SHIFT_TRANSLATE_AMOUNT,
ELEMENT_TRANSLATE_AMOUNT,
POINTER_BUTTON,
DRAGGING_THRESHOLD,
TEXT_TO_CENTER_SNAP_THRESHOLD,
LINE_CONFIRM_THRESHOLD,
EVENT,
ENV,
CANVAS_ONLY_ACTIONS,
DEFAULT_VERTICAL_ALIGN,
GRID_SIZE,
MIME_TYPES,
TAP_TWICE_TIMEOUT,
TOUCH_CTX_MENU_TIMEOUT,
APP_NAME,
} from "../constants";
import LayerUI from "./LayerUI";
import { ScrollBars, SceneState } from "../scene/types";
import { mutateElement } from "../element/mutateElement";
import { invalidateShapeForElement } from "../renderer/renderElement";
import {
isLinearElement,
isLinearElementType,
isBindingElement,
isBindingElementType,
} from "../element/typeChecks";
import { actionFinalize, actionDeleteSelected } from "../actions";
import { LinearElementEditor } from "../element/linearElementEditor";
import {
getSelectedGroupIds,
isSelectedViaGroup,
selectGroupsForSelectedElements,
isElementInGroup,
getSelectedGroupIdForElement,
getElementsInGroup,
editGroupForSelectedElement,
} from "../groups";
import { Library } from "../data/library";
import Scene from "../scene/Scene";
import {
getHoveredElementForBinding,
maybeBindLinearElement,
getEligibleElementsForBinding,
bindOrUnbindSelectedElements,
unbindLinearElements,
fixBindingsAfterDuplication,
fixBindingsAfterDeletion,
isLinearElementSimpleAndAlreadyBound,
isBindingEnabled,
updateBoundElements,
shouldEnableBindingForPointerEvent,
} from "../element/binding";
import { MaybeTransformHandleType } from "../element/transformHandles";
import { deepCopyElement } from "../element/newElement";
import { renderSpreadsheet } from "../charts";
import { isValidLibrary } from "../data/json";
import { getNewZoom } from "../scene/zoom";
import { restore } from "../data/restore";
import {
EVENT_DIALOG,
EVENT_LIBRARY,
EVENT_SHAPE,
trackEvent,
} from "../analytics";
import { getDefaultAppState } from "../appState";
import {
copyToClipboard,
parseClipboard,
probablySupportsClipboardBlob,
probablySupportsClipboardWriteText,
} from "../clipboard";
import {
APP_NAME,
CANVAS_ONLY_ACTIONS,
CURSOR_TYPE,
DEFAULT_VERTICAL_ALIGN,
DRAGGING_THRESHOLD,
ELEMENT_SHIFT_TRANSLATE_AMOUNT,
ELEMENT_TRANSLATE_AMOUNT,
ENV,
EVENT,
GRID_SIZE,
LINE_CONFIRM_THRESHOLD,
MIME_TYPES,
POINTER_BUTTON,
TAP_TWICE_TIMEOUT,
TEXT_TO_CENTER_SNAP_THRESHOLD,
TOUCH_CTX_MENU_TIMEOUT,
} from "../constants";
import { exportCanvas, loadFromBlob } from "../data";
import { isValidLibrary } from "../data/json";
import { Library } from "../data/library";
import { restore } from "../data/restore";
import {
dragNewElement,
dragSelectedElements,
duplicateElement,
getCommonBounds,
getCursorForResizingElement,
getDragOffsetXY,
getElementWithTransformHandleType,
getNonDeletedElements,
getNormalizedDimensions,
getPerfectElementSize,
getResizeArrowDirection,
getResizeOffsetXY,
getTransformHandleTypeFromCoords,
hitTest,
isHittingElementBoundingBoxWithoutHittingElement,
isInvisiblySmallElement,
isNonDeletedElement,
isTextElement,
newElement,
newLinearElement,
newTextElement,
textWysiwyg,
transformElements,
updateTextElement,
} from "../element";
import {
bindOrUnbindSelectedElements,
fixBindingsAfterDeletion,
fixBindingsAfterDuplication,
getEligibleElementsForBinding,
getHoveredElementForBinding,
isBindingEnabled,
isLinearElementSimpleAndAlreadyBound,
maybeBindLinearElement,
shouldEnableBindingForPointerEvent,
unbindLinearElements,
updateBoundElements,
} from "../element/binding";
import { LinearElementEditor } from "../element/linearElementEditor";
import { mutateElement } from "../element/mutateElement";
import { deepCopyElement } from "../element/newElement";
import { MaybeTransformHandleType } from "../element/transformHandles";
import {
isBindingElement,
isBindingElementType,
isLinearElement,
isLinearElementType,
} from "../element/typeChecks";
import {
ExcalidrawBindableElement,
ExcalidrawElement,
ExcalidrawGenericElement,
ExcalidrawLinearElement,
ExcalidrawTextElement,
NonDeleted,
} from "../element/types";
import { getCenter, getDistance } from "../gesture";
import {
editGroupForSelectedElement,
getElementsInGroup,
getSelectedGroupIdForElement,
getSelectedGroupIds,
isElementInGroup,
isSelectedViaGroup,
selectGroupsForSelectedElements,
} from "../groups";
import { createHistory, SceneHistory } from "../history";
import { t, getLanguage, setLanguage, languages, defaultLang } from "../i18n";
import {
CODES,
getResizeCenterPointKey,
getResizeWithSidesSameLengthKey,
getRotateWithDiscreteAngleKey,
isArrowKey,
KEYS,
} from "../keys";
import { distance2d, getGridPoint, isPathALoop } from "../math";
import { renderScene } from "../renderer";
import { invalidateShapeForElement } from "../renderer/renderElement";
import {
calculateScrollCenter,
getElementContainingPosition,
getElementsAtPosition,
getElementsWithinSelection,
getNormalizedZoom,
getSelectedElements,
isOverScrollBars,
isSomeElementSelected,
normalizeScroll,
} from "../scene";
import Scene from "../scene/Scene";
import { SceneState, ScrollBars } from "../scene/types";
import { getNewZoom } from "../scene/zoom";
import { findShapeByKey } from "../shapes";
import {
AppState,
ExcalidrawProps,
Gesture,
GestureEvent,
SceneData,
} from "../types";
import {
debounce,
distance,
getNewSceneName,
isInputLike,
isToolIcon,
isWritableElement,
resetCursor,
ResolvablePromise,
resolvablePromise,
sceneCoordsToViewportCoords,
setCursorForShape,
tupleToCoors,
viewportCoordsToSceneCoords,
withBatchedUpdates,
} from "../utils";
import ContextMenu from "./ContextMenu";
import LayerUI from "./LayerUI";
import { Stats } from "./Stats";
const { history } = createHistory();
@@ -295,6 +282,7 @@ class App extends React.Component<ExcalidrawProps, AppState> {
} = props;
this.state = {
...defaultAppState,
name: getNewSceneName(),
isLoading: true,
width,
height,
@@ -346,7 +334,7 @@ class App extends React.Component<ExcalidrawProps, AppState> {
offsetLeft,
} = this.state;
const { onCollabButtonClick, onExportToBackend } = this.props;
const { onCollabButtonClick, onExportToBackend, renderFooter } = this.props;
const canvasScale = window.devicePixelRatio;
const canvasWidth = canvasDOMWidth * canvasScale;
@@ -374,7 +362,7 @@ class App extends React.Component<ExcalidrawProps, AppState> {
elements={this.scene.getElements()}
onCollabButtonClick={onCollabButtonClick}
onLockToggle={this.toggleLock}
onInsertShape={(elements) =>
onInsertElements={(elements) =>
this.addElementsFromPasteOrLibrary(
elements,
DEFAULT_PASTE_X,
@@ -383,9 +371,10 @@ class App extends React.Component<ExcalidrawProps, AppState> {
}
zenModeEnabled={zenModeEnabled}
toggleZenMode={this.toggleZenMode}
lng={getLanguage().lng}
langCode={getLanguage().code}
isCollaborating={this.props.isCollaborating || false}
onExportToBackend={onExportToBackend}
renderCustomFooter={renderFooter}
/>
{this.state.showStats && (
<Stats
@@ -541,6 +530,7 @@ class App extends React.Component<ExcalidrawProps, AppState> {
this.scene.replaceAllElements([]);
this.setState((state) => ({
...getDefaultAppState(),
name: getNewSceneName(),
isLoading: opts?.resetLoadingState ? false : state.isLoading,
appearance: this.state.appearance,
}));
@@ -752,6 +742,10 @@ class App extends React.Component<ExcalidrawProps, AppState> {
}
componentDidUpdate(prevProps: ExcalidrawProps, prevState: AppState) {
if (prevProps.langCode !== this.props.langCode) {
this.updateLanguage();
}
if (
prevProps.width !== this.props.width ||
prevProps.height !== this.props.height ||
@@ -875,7 +869,16 @@ class App extends React.Component<ExcalidrawProps, AppState> {
history.record(this.state, this.scene.getElementsIncludingDeleted());
this.props.onChange?.(this.scene.getElementsIncludingDeleted(), this.state);
// Do not notify consumers if we're still loading the scene. Among other
// potential issues, this fixes a case where the tab isn't focused during
// init, which would trigger onChange with empty elements, which would then
// override whatever is in localStorage currently.
if (!this.state.isLoading) {
this.props.onChange?.(
this.scene.getElementsIncludingDeleted(),
this.state,
);
}
}
// Copy/paste
@@ -1004,9 +1007,12 @@ class App extends React.Component<ExcalidrawProps, AppState> {
if (data.errorMessage) {
this.setState({ errorMessage: data.errorMessage });
} else if (data.spreadsheet) {
this.addElementsFromPasteOrLibrary(
renderSpreadsheet(data.spreadsheet, cursorX, cursorY),
);
this.setState({
pasteDialog: {
data: data.spreadsheet,
shown: true,
},
});
} else if (data.elements) {
this.addElementsFromPasteOrLibrary(data.elements);
} else if (data.text) {
@@ -2462,8 +2468,7 @@ class App extends React.Component<ExcalidrawProps, AppState> {
// otherwise, it will trigger selection based on current
// state of the box
if (!this.state.selectedElementIds[hitElement.id]) {
// if we are currently editing a group, treat all selections outside of the group
// as exiting editing mode.
// if we are currently editing a group, exiting editing mode and deselect the group.
if (
this.state.editingGroupId &&
!isElementInGroup(hitElement, this.state.editingGroupId)
@@ -2473,7 +2478,6 @@ class App extends React.Component<ExcalidrawProps, AppState> {
selectedGroupIds: {},
editingGroupId: null,
});
return true;
}
// Add hit element to selection. At this point if we're not holding
@@ -3853,6 +3857,14 @@ class App extends React.Component<ExcalidrawProps, AppState> {
offsetTop: typeof offsets?.offsetTop === "number" ? offsets.offsetTop : 0,
};
}
private async updateLanguage() {
const currentLang =
languages.find((lang) => lang.code === this.props.langCode) ||
defaultLang;
await setLanguage(currentLang);
this.setAppState({});
}
}
// -----------------------------------------------------------------------------
+1 -1
View File
@@ -218,7 +218,7 @@
left: 2px;
}
@media #{$media-query} {
@media #{$is-mobile-query} {
display: none;
}
}
+19 -5
View File
@@ -1,4 +1,4 @@
@import "open-color/open-color.scss";
@import "../css/_variables";
.excalidraw {
.context-menu {
@@ -42,16 +42,16 @@
}
&.dangerous {
div:nth-child(1) {
.context-menu-option__label {
color: $oc-red-7;
}
}
div:nth-child(1) {
.context-menu-option__label {
justify-self: start;
margin-inline-end: 20px;
}
div:nth-child(2) {
.context-menu-option__shortcut {
justify-self: end;
opacity: 0.6;
font-size: 0.7rem;
@@ -63,7 +63,7 @@
background-color: var(--select-highlight-color);
&.dangerous {
div:nth-child(1) {
.context-menu-option__label {
color: var(--popup-background-color);
}
background-color: $oc-red-6;
@@ -73,4 +73,18 @@
.context-menu-option:focus {
z-index: 1;
}
@media #{$is-mobile-query} {
.context-menu-option {
display: block;
.context-menu-option__label {
margin-inline-end: 0;
}
.context-menu-option__shortcut {
display: none;
}
}
}
}
+2 -2
View File
@@ -51,8 +51,8 @@ const ContextMenu = ({ options, onCloseRequest, top, left }: Props) => {
${checked ? "checkmark" : ""}`}
onClick={action}
>
<div>{label}</div>
<div>
<div className="context-menu-option__label">{label}</div>
<div className="context-menu-option__shortcut">
{shortcutName
? getShortcutFromShortcutName(shortcutName)
: ""}
+9 -7
View File
@@ -7,6 +7,9 @@
margin-top: 0;
grid-template-columns: 1fr calc(var(--space-factor) * 7);
grid-gap: var(--metric);
padding: calc(var(--space-factor) * 2);
text-align: center;
font-variant: small-caps;
}
.Dialog__titleContent {
@@ -18,7 +21,11 @@
margin: 0;
}
@media #{$media-query} {
.Dialog__content {
padding: 0 16px 16px;
}
@media #{$is-mobile-query} {
.Dialog {
--metric: calc(var(--space-factor) * 4);
--inset-left: #{"max(var(--metric), var(--sal))"};
@@ -30,13 +37,8 @@
var(--space-factor) * 7
);
position: sticky;
top: calc(-1 * var(--metric));
margin: calc(-1 * var(--inset-right));
margin-top: calc(-1 * var(--metric));
margin-bottom: var(--metric);
top: 0;
padding: calc(var(--space-factor) * 2);
padding-left: var(--inset-left);
padding-right: var(--inset-right);
background: var(--bg-color-island);
font-size: 1.25em;
+13 -13
View File
@@ -1,13 +1,12 @@
import React, { useCallback, useEffect, useState } from "react";
import clsx from "clsx";
import { Modal } from "./Modal";
import { Island } from "./Island";
import React, { useCallback, useEffect, useState } from "react";
import { t } from "../i18n";
import useIsMobile from "../is-mobile";
import { back, close } from "./icons";
import { KEYS } from "../keys";
import "./Dialog.scss";
import { back, close } from "./icons";
import { Island } from "./Island";
import { Modal } from "./Modal";
const useRefState = <T,>() => {
const [refValue, setRefValue] = useState<T | null>(null);
@@ -20,9 +19,10 @@ const useRefState = <T,>() => {
export const Dialog = (props: {
children: React.ReactNode;
className?: string;
maxWidth?: number;
small?: boolean;
onCloseRequest(): void;
title: React.ReactNode;
autofocus?: boolean;
}) => {
const [islandNode, setIslandNode] = useRefState<HTMLDivElement>();
@@ -33,7 +33,7 @@ export const Dialog = (props: {
const focusableElements = queryFocusableElements(islandNode);
if (focusableElements.length > 0) {
if (focusableElements.length > 0 && props.autofocus !== false) {
// If there's an element other than close, focus it.
(focusableElements[1] || focusableElements[0]).focus();
}
@@ -62,7 +62,7 @@ export const Dialog = (props: {
islandNode.addEventListener("keydown", handleKeyDown);
return () => islandNode.removeEventListener("keydown", handleKeyDown);
}, [islandNode]);
}, [islandNode, props.autofocus]);
const queryFocusableElements = (node: HTMLElement) => {
const focusableElements = node.querySelectorAll<HTMLElement>(
@@ -76,11 +76,11 @@ export const Dialog = (props: {
<Modal
className={clsx("Dialog", props.className)}
labelledBy="dialog-title"
maxWidth={props.maxWidth}
maxWidth={props.small ? 550 : 800}
onCloseRequest={props.onCloseRequest}
>
<Island padding={4} ref={setIslandNode}>
<h2 id="dialog-title" className="Dialog__title">
<Island ref={setIslandNode}>
<h3 id="dialog-title" className="Dialog__title">
<span className="Dialog__titleContent">{props.title}</span>
<button
className="Modal__close"
@@ -89,8 +89,8 @@ export const Dialog = (props: {
>
{useIsMobile() ? back : close}
</button>
</h2>
{props.children}
</h3>
<div className="Dialog__content">{props.children}</div>
</Island>
</Modal>
);
+1 -1
View File
@@ -24,7 +24,7 @@ export const ErrorDialog = ({
<>
{modalIsShown && (
<Dialog
maxWidth={500}
small
onCloseRequest={handleClose}
title={t("errorDialog.title")}
>
+1 -3
View File
@@ -37,7 +37,7 @@
}
}
@media (max-width: 550px) {
@media #{$is-mobile-query} {
.ExportDialog {
display: flex;
flex-direction: column;
@@ -51,9 +51,7 @@
.ExportDialog__actions > * {
margin-bottom: calc(var(--space-factor) * 3);
}
}
@media #{$media-query} {
.ExportDialog__preview canvas {
max-height: 30vh;
}
+1 -5
View File
@@ -262,11 +262,7 @@ export const ExportDialog = ({
ref={triggerButton}
/>
{modalIsShown && (
<Dialog
maxWidth={800}
onCloseRequest={handleClose}
title={t("buttons.export")}
>
<Dialog onCloseRequest={handleClose} title={t("buttons.export")}>
<ExportModal
elements={elements}
appState={appState}
+5 -5
View File
@@ -1,5 +1,8 @@
@import "../css/_variables";
// this is loosely based on the longest hint text
$wide-viewport-width: 1000px;
.excalidraw {
.HintViewer {
pointer-events: none;
@@ -16,12 +19,9 @@
color: $oc-gray-6;
font-size: 0.8rem;
@media (min-width: 1200px) {
white-space: pre;
}
@media #{$media-query} {
@media #{$is-mobile-query} {
position: static;
padding-right: 2em;
}
> span {
+1 -1
View File
@@ -110,7 +110,7 @@
:root[dir="rtl"] & {
left: 2px;
}
@media #{$media-query} {
@media #{$is-mobile-query} {
display: none;
}
}
+17 -6
View File
@@ -1,18 +1,29 @@
import React from "react";
import { LoadingMessage } from "./LoadingMessage";
import { setLanguageFirstTime } from "../i18n";
import {
defaultLang,
Language,
languages,
setLanguageFirstTime,
} from "../i18n";
export class InitializeApp extends React.Component<
any,
{ isLoading: boolean }
> {
interface Props {
langCode: Language["code"];
}
interface State {
isLoading: boolean;
}
export class InitializeApp extends React.Component<Props, State> {
public state: { isLoading: boolean } = {
isLoading: true,
};
async componentDidMount() {
await setLanguageFirstTime();
const currentLang =
languages.find((lang) => lang.code === this.props.langCode) ||
defaultLang;
await setLanguageFirstTime(currentLang);
this.setState({
isLoading: false,
});
+1 -1
View File
@@ -4,7 +4,7 @@
background-color: var(--bg-color-island);
backdrop-filter: saturate(100%) blur(10px);
box-shadow: var(--shadow-island);
border-radius: var(--border-radius-m);
border-radius: 4px;
padding: calc(var(--padding) * var(--space-factor));
position: relative;
transition: box-shadow 0.5s ease-in-out;
+17 -5
View File
@@ -7,11 +7,23 @@
align-items: center;
justify-content: center;
.browse-libraries {
position: absolute;
right: 12px;
top: 16px;
white-space: nowrap;
.layer-ui__library-header {
display: flex;
align-items: center;
width: 100%;
margin: 2px 0;
button {
// 2px from the left to account for focus border of left-most button
margin: 0 2px;
}
a {
margin-left: auto;
// 17px for scrollbar (needed for overlay scrollbars on Big Sur?) + 1px extra
padding-right: 18px;
white-space: nowrap;
}
}
}
+83 -77
View File
@@ -19,8 +19,7 @@ import { FixedSideContainer } from "./FixedSideContainer";
import { UserList } from "./UserList";
import { LockIcon } from "./LockIcon";
import { ExportDialog, ExportCB } from "./ExportDialog";
import { LanguageList } from "./LanguageList";
import { t, languages, setLanguage } from "../i18n";
import { Language, t } from "../i18n";
import { HintViewer } from "./HintViewer";
import useIsMobile from "../is-mobile";
@@ -51,6 +50,7 @@ import {
EVENT_LIBRARY,
trackEvent,
} from "../analytics";
import { PasteChartDialog } from "./PasteChartDialog";
interface LayerUIProps {
actionManager: ActionManager;
@@ -60,16 +60,17 @@ interface LayerUIProps {
elements: readonly NonDeletedExcalidrawElement[];
onCollabButtonClick?: () => void;
onLockToggle: () => void;
onInsertShape: (elements: LibraryItem) => void;
onInsertElements: (elements: readonly NonDeletedExcalidrawElement[]) => void;
zenModeEnabled: boolean;
toggleZenMode: () => void;
lng: string;
langCode: Language["code"];
isCollaborating: boolean;
onExportToBackend?: (
exportedElements: readonly NonDeletedExcalidrawElement[],
appState: AppState,
canvas: HTMLCanvasElement | null,
) => void;
renderCustomFooter?: (isMobile: boolean) => JSX.Element;
}
const useOnClickOutside = (
@@ -123,9 +124,42 @@ const LibraryMenuItems = ({
let addedPendingElements = false;
rows.push(
<>
<div className="layer-ui__library-header">
<ToolButton
key="import"
type="button"
title={t("buttons.load")}
aria-label={t("buttons.load")}
icon={load}
onClick={() => {
importLibraryFromJSON()
.then(() => {
// Maybe we should close and open the menu so that the items get updated.
// But for now we just close the menu.
setAppState({ isLibraryOpen: false });
})
.catch(muteFSAbortError)
.catch((error) => {
setAppState({ errorMessage: error.message });
});
}}
/>
<ToolButton
key="export"
type="button"
title={t("buttons.export")}
aria-label={t("buttons.export")}
icon={exportFile}
onClick={() => {
saveLibraryAsJSON()
.catch(muteFSAbortError)
.catch((error) => {
setAppState({ errorMessage: error.message });
});
}}
/>
<a
className="browse-libraries"
href="https://libraries.excalidraw.com"
target="_excalidraw_libraries"
onClick={() => {
@@ -134,48 +168,7 @@ const LibraryMenuItems = ({
>
{t("labels.libraries")}
</a>
<Stack.Row
align="center"
gap={1}
key={"actions"}
style={{ padding: "2px" }}
>
<ToolButton
key="import"
type="button"
title={t("buttons.load")}
aria-label={t("buttons.load")}
icon={load}
onClick={() => {
importLibraryFromJSON()
.then(() => {
// Maybe we should close and open the menu so that the items get updated.
// But for now we just close the menu.
setAppState({ isLibraryOpen: false });
})
.catch(muteFSAbortError)
.catch((error) => {
setAppState({ errorMessage: error.message });
});
}}
/>
<ToolButton
key="export"
type="button"
title={t("buttons.export")}
aria-label={t("buttons.export")}
icon={exportFile}
onClick={() => {
saveLibraryAsJSON()
.catch(muteFSAbortError)
.catch((error) => {
setAppState({ errorMessage: error.message });
});
}}
/>
</Stack.Row>
</>,
</div>,
);
for (let row = 0; row < numRows; row++) {
@@ -318,11 +311,12 @@ const LayerUI = ({
elements,
onCollabButtonClick,
onLockToggle,
onInsertShape,
onInsertElements,
zenModeEnabled,
toggleZenMode,
isCollaborating,
onExportToBackend,
renderCustomFooter,
}: LayerUIProps) => {
const isMobile = useIsMobile();
@@ -456,7 +450,7 @@ const LayerUI = ({
<LibraryMenu
pendingElements={getSelectedElements(elements, appState)}
onClickOutside={closeLibrary}
onInsertShape={onInsertShape}
onInsertShape={onInsertElements}
onAddToLibrary={deselectItems}
setAppState={setAppState}
/>
@@ -558,14 +552,7 @@ const LayerUI = ({
"transition-right disable-pointerEvents": zenModeEnabled,
})}
>
<LanguageList
onChange={async (lng) => {
await setLanguage(lng);
setAppState({});
}}
languages={languages}
floating
/>
{renderCustomFooter?.(false)}
{actionManager.renderAction("toggleShortcuts")}
</div>
<button
@@ -592,21 +579,8 @@ const LayerUI = ({
</footer>
);
return isMobile ? (
<MobileMenu
appState={appState}
elements={elements}
actionManager={actionManager}
libraryMenu={libraryMenu}
exportButton={renderExportDialog()}
setAppState={setAppState}
onCollabButtonClick={onCollabButtonClick}
onLockToggle={onLockToggle}
canvas={canvas}
isCollaborating={isCollaborating}
/>
) : (
<div className="layer-ui__wrapper">
const dialogs = (
<>
{appState.isLoading && <LoadingMessage />}
{appState.errorMessage && (
<ErrorDialog
@@ -619,6 +593,41 @@ const LayerUI = ({
onClose={() => setAppState({ showShortcutsDialog: false })}
/>
)}
{appState.pasteDialog.shown && (
<PasteChartDialog
setAppState={setAppState}
appState={appState}
onInsertChart={onInsertElements}
onClose={() =>
setAppState({
pasteDialog: { shown: false, data: null },
})
}
/>
)}
</>
);
return isMobile ? (
<>
{dialogs}
<MobileMenu
appState={appState}
elements={elements}
actionManager={actionManager}
libraryMenu={libraryMenu}
exportButton={renderExportDialog()}
setAppState={setAppState}
onCollabButtonClick={onCollabButtonClick}
onLockToggle={onLockToggle}
canvas={canvas}
isCollaborating={isCollaborating}
renderCustomFooter={renderCustomFooter}
/>
</>
) : (
<div className="layer-ui__wrapper">
{dialogs}
{renderFixedSideContainer()}
{renderBottomAppMenu()}
{
@@ -641,8 +650,6 @@ const LayerUI = ({
const areEqual = (prev: LayerUIProps, next: LayerUIProps) => {
const getNecessaryObj = (appState: AppState): Partial<AppState> => {
const {
cursorX,
cursorY,
suggestedBindings,
startBoundElement: boundElement,
...ret
@@ -653,9 +660,8 @@ const areEqual = (prev: LayerUIProps, next: LayerUIProps) => {
const nextAppState = getNecessaryObj(next.appState);
const keys = Object.keys(prevAppState) as (keyof Partial<AppState>)[];
return (
prev.lng === next.lng &&
prev.langCode === next.langCode &&
prev.elements === next.elements &&
keys.every((key) => prevAppState[key] === nextAppState[key])
);
+6 -6
View File
@@ -1,13 +1,13 @@
import React, { useRef, useEffect, useState } from "react";
import clsx from "clsx";
import { exportToSvg } from "../scene/export";
import oc from "open-color";
import React, { useEffect, useRef, useState } from "react";
import { close } from "../components/icons";
import "./LibraryUnit.scss";
import { MIME_TYPES } from "../constants";
import { t } from "../i18n";
import useIsMobile from "../is-mobile";
import { exportToSvg } from "../scene/export";
import { LibraryItem } from "../types";
import { MIME_TYPES } from "../constants";
import "./LibraryUnit.scss";
// fa-plus
const PLUS_ICON = (
@@ -38,7 +38,7 @@ export const LibraryUnit = ({
}
const svg = exportToSvg(elementsToRender, {
exportBackground: false,
viewBackgroundColor: "#fff",
viewBackgroundColor: oc.white,
shouldAddWatermark: false,
});
for (const child of ref.current!.children) {
+4 -13
View File
@@ -1,9 +1,8 @@
import React from "react";
import { AppState } from "../types";
import { ActionManager } from "../actions/manager";
import { t, setLanguage } from "../i18n";
import { t } from "../i18n";
import Stack from "./Stack";
import { LanguageList } from "./LanguageList";
import { showSelectedShapeActions } from "../element";
import { NonDeletedExcalidrawElement } from "../element/types";
import { FixedSideContainer } from "./FixedSideContainer";
@@ -15,7 +14,6 @@ import { Section } from "./Section";
import CollabButton from "./CollabButton";
import { SCROLLBAR_WIDTH, SCROLLBAR_MARGIN } from "../scene/scrollbars";
import { LockIcon } from "./LockIcon";
import { LoadingMessage } from "./LoadingMessage";
import { UserList } from "./UserList";
import { BackgroundPickerAndDarkModeToggle } from "./BackgroundPickerAndDarkModeToggle";
import { EVENT_ACTION, trackEvent } from "../analytics";
@@ -31,6 +29,7 @@ type MobileMenuProps = {
onLockToggle: () => void;
canvas: HTMLCanvasElement | null;
isCollaborating: boolean;
renderCustomFooter?: (isMobile: boolean) => JSX.Element;
};
export const MobileMenu = ({
@@ -44,9 +43,9 @@ export const MobileMenu = ({
onLockToggle,
canvas,
isCollaborating,
renderCustomFooter,
}: MobileMenuProps) => (
<>
{appState.isLoading && <LoadingMessage />}
<FixedSideContainer side="top">
<Section heading="shapes">
{(heading) => (
@@ -104,15 +103,7 @@ export const MobileMenu = ({
appState={appState}
setAppState={setAppState}
/>
<fieldset>
<legend>{t("labels.language")}</legend>
<LanguageList
onChange={async (lng) => {
await setLanguage(lng);
setAppState({});
}}
/>
</fieldset>
{renderCustomFooter?.(true)}
<fieldset>
<legend>{t("labels.collaborators")}</legend>
<UserList mobile>
+10 -8
View File
@@ -30,18 +30,26 @@
z-index: 2;
width: 100%;
max-width: var(--max-width);
max-height: 100%;
opacity: 0;
transform: translateY(10px);
animation: Modal__content_fade-in 0.1s ease-out 0.05s forwards;
position: relative;
overflow-y: auto;
// for modals, reset blurry bg
background: var(--bg-color-island);
backdrop-filter: none;
@media #{$media-query} {
border: 1px solid var(--dialog-border);
box-shadow: 0 2px 10px transparentize($oc-black, 0.75);
border-radius: 6px;
@media #{$is-mobile-query} {
max-width: 100%;
border: 0;
border-radius: 0;
}
}
@@ -68,13 +76,7 @@
}
}
.Modal__close--floating {
position: absolute;
right: calc(var(--space-factor) * 5);
top: calc(var(--space-factor) * 5);
}
@media #{$media-query} {
@media #{$is-mobile-query} {
.Modal {
padding: 0;
}
+1 -5
View File
@@ -36,11 +36,7 @@ export const Modal = (props: {
<div className="Modal__background" onClick={props.onCloseRequest}></div>
<div
className="Modal__content"
style={{
"--max-width": `${props.maxWidth}px`,
maxHeight: "100%",
overflowY: "scroll",
}}
style={{ "--max-width": `${props.maxWidth}px` }}
>
{props.children}
</div>
+46
View File
@@ -0,0 +1,46 @@
@import "../css/_variables";
.excalidraw {
.PasteChartDialog {
@media #{$is-mobile-query} {
.Island {
display: flex;
flex-direction: column;
}
}
.container {
display: flex;
align-items: center;
justify-content: space-around;
flex-wrap: wrap;
@media #{$is-mobile-query} {
flex-direction: column;
justify-content: center;
}
}
.ChartPreview {
margin: 8px;
text-align: center;
width: 192px;
height: 128px;
border-radius: 2px;
padding: 1px;
border: 1px solid $oc-gray-4;
display: flex;
align-items: center;
justify-content: center;
background: transparent;
div {
display: inline-block;
}
svg {
max-height: 120px;
max-width: 186px;
}
&:hover {
padding: 0;
border: 2px solid $oc-blue-5;
}
}
}
}
+122
View File
@@ -0,0 +1,122 @@
import oc from "open-color";
import React, { useLayoutEffect, useRef, useState } from "react";
import { ChartElements, renderSpreadsheet, Spreadsheet } from "../charts";
import { ChartType } from "../element/types";
import { t } from "../i18n";
import { exportToSvg } from "../scene/export";
import { AppState, LibraryItem } from "../types";
import { Dialog } from "./Dialog";
import "./PasteChartDialog.scss";
type OnInsertChart = (chartType: ChartType, elements: ChartElements) => void;
const ChartPreviewBtn = (props: {
spreadsheet: Spreadsheet | null;
chartType: ChartType;
selected: boolean;
onClick: OnInsertChart;
}) => {
const previewRef = useRef<HTMLDivElement | null>(null);
const [chartElements, setChartElements] = useState<ChartElements | null>(
null,
);
useLayoutEffect(() => {
if (!props.spreadsheet) {
return;
}
const elements = renderSpreadsheet(
props.chartType,
props.spreadsheet,
0,
0,
);
setChartElements(elements);
const svg = exportToSvg(elements, {
exportBackground: false,
viewBackgroundColor: oc.white,
shouldAddWatermark: false,
});
const previewNode = previewRef.current!;
previewNode.appendChild(svg);
if (props.selected) {
(previewNode.parentNode as HTMLDivElement).focus();
}
return () => {
previewNode.removeChild(svg);
};
}, [props.spreadsheet, props.chartType, props.selected]);
return (
<button
className="ChartPreview"
onClick={() => {
if (chartElements) {
props.onClick(props.chartType, chartElements);
}
}}
>
<div ref={previewRef} />
</button>
);
};
export const PasteChartDialog = ({
setAppState,
appState,
onClose,
onInsertChart,
}: {
appState: AppState;
onClose: () => void;
setAppState: React.Component<any, AppState>["setState"];
onInsertChart: (elements: LibraryItem) => void;
}) => {
const handleClose = React.useCallback(() => {
if (onClose) {
onClose();
}
}, [onClose]);
const handleChartClick = (chartType: ChartType, elements: ChartElements) => {
onInsertChart(elements);
setAppState({
currentChartType: chartType,
pasteDialog: {
shown: false,
data: null,
},
});
};
return (
<Dialog
small
onCloseRequest={handleClose}
title={t("labels.pasteCharts")}
className={"PasteChartDialog"}
autofocus={false}
>
<div className={"container"}>
<ChartPreviewBtn
chartType="bar"
spreadsheet={appState.pasteDialog.data}
selected={appState.currentChartType === "bar"}
onClick={handleChartClick}
/>
<ChartPreviewBtn
chartType="line"
spreadsheet={appState.pasteDialog.data}
selected={appState.currentChartType === "line"}
onClick={handleChartClick}
/>
</div>
</Dialog>
);
};
+1 -5
View File
@@ -130,11 +130,7 @@ export const ShortcutsDialog = ({ onClose }: { onClose?: () => void }) => {
return (
<>
<Dialog
maxWidth={900}
onCloseRequest={handleClose}
title={t("shortcutsDialog.title")}
>
<Dialog onCloseRequest={handleClose} title={t("shortcutsDialog.title")}>
<Columns>
<Column>
<ShortcutIsland caption={t("shortcutsDialog.shapes")}>
-1
View File
@@ -85,7 +85,6 @@ export const Stats = (props: {
<td>{t("stats.total")}</td>
<td>{nFormatter(storageSizes.total, 1)}</td>
</tr>
{selectedElements.length === 1 && (
<tr>
<th colSpan={2}>{t("stats.element")}</th>
+5 -1
View File
@@ -142,6 +142,7 @@
user-select: none;
}
// shrink shape icons on small viewports to make them fit
@media (max-width: 425px) {
.Shape .ToolIcon__icon {
width: 2rem;
@@ -153,6 +154,8 @@
}
}
// move the lock button out of the way on small viewports
// it begins to collide with the GitHub icon before we switch to mobile mode
@media (max-width: 760px) {
.ToolIcon.ToolIcon__lock {
display: inline-block;
@@ -162,6 +165,7 @@
margin-left: 0;
border-radius: 20px 0 0 20px;
z-index: 1;
background-color: var(--button-gray-1);
@@ -189,7 +193,7 @@
margin-left: 5px;
margin-top: 1px;
@media #{$media-query} {
@media #{$is-mobile-query} {
display: none;
}
}
+2
View File
@@ -88,3 +88,5 @@ export const STORAGE_KEYS = {
export const TAP_TWICE_TIMEOUT = 300;
export const TOUCH_CTX_MENU_TIMEOUT = 500;
export const TITLE_TIMEOUT = 10000;
export const SCENE_NAME_FALLBACK = "Untitled";
+2 -1
View File
@@ -1,3 +1,4 @@
@import "open-color/open-color.scss";
$media-query: "(max-width: 600px), (max-height: 500px) and (max-width: 1000px)";
// keep up to date with is-mobile.tsx
$is-mobile-query: "(max-width: 600px), (max-height: 500px) and (max-width: 1000px)";
+1 -1
View File
@@ -441,7 +441,7 @@
}
}
@media #{$media-query} {
@media #{$is-mobile-query} {
aside {
display: none;
}
+2 -6
View File
@@ -3,7 +3,6 @@
:root {
--bg-color-island: rgba(255, 255, 255, 0.9);
--popup-background-color: #{$oc-white};
--border-radius-m: 4px;
--space-factor: 0.25rem;
--button-gray-1: #{$oc-gray-2};
--button-gray-2: #{$oc-gray-4};
@@ -15,7 +14,6 @@
--icon-fill-color: #{$oc-black};
--icon-green-fill-color: #{$oc-green-9};
--keybinding-color: #{$oc-gray-5};
--color-overlay-text-color: #ccc;
--sat: env(safe-area-inset-top);
--sab: env(safe-area-inset-bottom);
--sal: env(safe-area-inset-left);
@@ -23,8 +21,6 @@
--text-color-primary: #{$oc-gray-8};
--shadow-island: 0 1px 5px #{transparentize($oc-black, 0.85)};
--overlay-background-color: #{transparentize($oc-white, 0.12)};
--border-radius-m: 4px;
--space-factor: 0.25rem;
--dropdown-icon: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="292.4" height="292.4" viewBox="0 0 292 292"><path d="M287 197L159 69c-4-3-8-5-13-5s-9 2-13 5L5 197c-3 4-5 8-5 13s2 9 5 13c4 4 8 5 13 5h256c5 0 9-1 13-5s5-8 5-13-1-9-5-13z"/></svg>');
--focus-highlight-color: #{$oc-blue-2};
--select-highlight-color: #{$oc-blue-5};
@@ -35,6 +31,7 @@
--popup-secondary-background-color: #{$oc-gray-1};
--popup-text-color: #{$oc-black};
--popup-text-inverted-color: #{$oc-white};
--dialog-border: #{$oc-gray-6};
}
.excalidraw {
@@ -60,10 +57,8 @@
--icon-fill-color: #{$oc-gray-4};
--icon-green-fill-color: #{$oc-green-4};
--keybinding-color: #{$oc-gray-6};
--color-overlay-text-color: #bbb;
--shadow-island: 0 1px 5px #{transparentize($oc-black, 0.7)};
--overlay-background-color: rgba(30, 30, 30, 0.88);
// #{$oc-gray-4}; inlined
--dropdown-icon: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="292.4" height="292.4" viewBox="0 0 292 292"><path fill="%23ced4da" d="M287 197L159 69c-4-3-8-5-13-5s-9 2-13 5L5 197c-3 4-5 8-5 13s2 9 5 13c4 4 8 5 13 5h256c5 0 9-1 13-5s5-8 5-13-1-9-5-13z"/></svg>');
--focus-highlight-color: #{$oc-blue-6};
--select-highlight-color: #{$oc-blue-4};
@@ -74,5 +69,6 @@
--popup-secondary-background-color: #222;
--popup-text-color: #{$oc-gray-4};
--popup-text-inverted-color: #2c2c2c;
--dialog-border: #{$oc-gray-9};
}
}
+2
View File
@@ -15,6 +15,7 @@ import {
DEFAULT_VERTICAL_ALIGN,
} from "../constants";
import { getDefaultAppState } from "../appState";
import { getNewSceneName } from "../utils";
const getFontFamilyByName = (fontFamilyName: string): FontFamily => {
for (const [id, fontFamilyString] of Object.entries(FONT_FAMILY)) {
@@ -166,6 +167,7 @@ const restoreAppState = (
return {
...nextAppState,
name: appState.name ?? localAppState?.name ?? getNewSceneName(),
offsetLeft: appState.offsetLeft || 0,
offsetTop: appState.offsetTop || 0,
// Migrates from previous version where appState.zoom was a number
+11
View File
@@ -1,6 +1,7 @@
import { Point } from "../types";
import { FONT_FAMILY } from "../constants";
export type ChartType = "bar" | "line";
export type FillStyle = "hachure" | "cross-hatch" | "solid";
export type FontFamily = keyof typeof FONT_FAMILY;
export type FontString = string & { _brand: "fontString" };
@@ -26,11 +27,21 @@ type _ExcalidrawElementBase = Readonly<{
width: number;
height: number;
angle: number;
/** Random integer used to seed shape generation so that the roughjs shape
doesn't differ across renders. */
seed: number;
/** Integer that is sequentially incremented on each change. Used to reconcile
elements during collaboration or when saving to server. */
version: number;
/** Random integer that is regenerated on each change.
Used for deterministic reconciliation of updates during collaboration,
in case the versions (see above) are identical. */
versionNonce: number;
isDeleted: boolean;
/** List of groups the element belongs to.
Ordered from deepest to shallowest. */
groupIds: readonly GroupId[];
/** Ids of (linear) elements that are bound to this element. */
boundElementIds: readonly ExcalidrawLinearElement["id"][] | null;
}>;
+1 -5
View File
@@ -123,11 +123,7 @@ const RoomDialog = ({
);
};
return (
<Dialog
maxWidth={800}
onCloseRequest={handleClose}
title={t("labels.createRoom")}
>
<Dialog small onCloseRequest={handleClose} title={t("labels.createRoom")}>
{renderRoomDialog()}
</Dialog>
);
@@ -1,16 +1,16 @@
import React from "react";
import clsx from "clsx";
import * as i18n from "../i18n";
import * as i18n from "../../i18n";
export const LanguageList = ({
onChange,
languages = i18n.languages,
currentLanguage = i18n.getLanguage().lng,
currentLangCode = i18n.getLanguage().code,
floating,
}: {
languages?: { lng: string; label: string }[];
onChange: (value: string) => void;
currentLanguage?: string;
languages?: { code: string; label: string }[];
onChange: (langCode: i18n.Language["code"]) => void;
currentLangCode?: i18n.Language["code"];
floating?: boolean;
}) => (
<React.Fragment>
@@ -19,12 +19,12 @@ export const LanguageList = ({
"dropdown-select--floating": floating,
})}
onChange={({ target }) => onChange(target.value)}
value={currentLanguage}
value={currentLangCode}
aria-label={i18n.t("buttons.selectLanguage")}
>
{languages.map((language) => (
<option key={language.lng} value={language.lng}>
{language.label}
{languages.map((lang) => (
<option key={lang.code} value={lang.code}>
{lang.label}
</option>
))}
</select>
+2 -1
View File
@@ -6,6 +6,7 @@ import {
} from "../../appState";
import { clearElementsForLocalStorage } from "../../element";
import { STORAGE_KEYS as APP_STORAGE_KEYS } from "../../constants";
import { ImportedDataState } from "../../data/types";
export const STORAGE_KEYS = {
LOCAL_STORAGE_ELEMENTS: "excalidraw",
@@ -81,7 +82,7 @@ export const importFromLocalStorage = () => {
}
}
let appState = null;
let appState: ImportedDataState["appState"] = null;
if (savedState) {
try {
appState = {
+66 -18
View File
@@ -1,6 +1,16 @@
import React, { useState, useLayoutEffect, useEffect, useRef } from "react";
import React, {
useState,
useLayoutEffect,
useEffect,
useRef,
useCallback,
} from "react";
import LanguageDetector from "i18next-browser-languagedetector";
import Excalidraw from "../packages/excalidraw/index";
import Excalidraw, {
languages,
defaultLang,
} from "../packages/excalidraw/index";
import {
getTotalStorageSize,
@@ -12,7 +22,7 @@ import {
import { ImportedDataState } from "../data/types";
import CollabWrapper, { CollabAPI } from "./collab/CollabWrapper";
import { TopErrorBoundary } from "../components/TopErrorBoundary";
import { t } from "../i18n";
import { Language, t } from "../i18n";
import { exportToBackend, loadScene } from "./data";
import { getCollaborationLinkData } from "./data";
import { EVENT } from "../constants";
@@ -29,6 +39,16 @@ import { EVENT_LOAD, EVENT_SHARE, trackEvent } from "../analytics";
import { ErrorDialog } from "../components/ErrorDialog";
import { getDefaultAppState } from "../appState";
import { APP_NAME, TITLE_TIMEOUT } from "../constants";
import { LanguageList } from "./components/LanguageList";
const languageDetector = new LanguageDetector();
languageDetector.init({
languageUtils: {
formatLanguageCode: (langCode: Language["code"]) => langCode,
isWhitelisted: () => true,
},
checkWhitelist: false,
});
const excalidrawRef: React.MutableRefObject<
MarkRequired<ExcalidrawAPIRefValue, "ready" | "readyPromise">
@@ -93,7 +113,6 @@ type Scene = ImportedDataState & { commitToHistory: boolean };
const initializeScene = async (opts: {
resetScene: ExcalidrawImperativeAPI["resetScene"];
initializeSocketClient: CollabAPI["initializeSocketClient"];
onLateInitialization?: (scene: Scene) => void;
}): Promise<Scene | null> => {
const searchParams = new URLSearchParams(window.location.search);
const id = searchParams.get("id");
@@ -124,17 +143,15 @@ const initializeScene = async (opts: {
} else {
// https://github.com/excalidraw/excalidraw/issues/1919
if (document.hidden) {
window.addEventListener(
"focus",
() =>
initializeScene(opts).then((_scene) => {
opts?.onLateInitialization?.(_scene || scene);
}),
{
once: true,
},
);
return null;
return new Promise((resolve, reject) => {
window.addEventListener(
"focus",
() => initializeScene(opts).then(resolve).catch(reject),
{
once: true,
},
);
});
}
isCollabScene = false;
@@ -185,6 +202,8 @@ function ExcalidrawWrapper(props: { collab: CollabAPI }) {
height: window.innerHeight,
});
const [errorMessage, setErrorMessage] = useState("");
const currentLangCode = languageDetector.detect() || defaultLang.code;
const [langCode, setLangCode] = useState(currentLangCode);
useLayoutEffect(() => {
const onResize = () => {
@@ -222,9 +241,6 @@ function ExcalidrawWrapper(props: { collab: CollabAPI }) {
initializeScene({
resetScene: excalidrawApi.resetScene,
initializeSocketClient: collab.initializeSocketClient,
onLateInitialization: (scene) => {
initialStatePromiseRef.current.promise.resolve(scene);
},
}).then((scene) => {
initialStatePromiseRef.current.promise.resolve(scene);
});
@@ -262,6 +278,10 @@ function ExcalidrawWrapper(props: { collab: CollabAPI }) {
};
}, [collab.initializeSocketClient]);
useEffect(() => {
languageDetector.cacheUserLanguage(langCode);
}, [langCode]);
const onChange = (
elements: readonly ExcalidrawElement[],
appState: AppState,
@@ -297,6 +317,32 @@ function ExcalidrawWrapper(props: { collab: CollabAPI }) {
}
}
};
const renderFooter = useCallback(
(isMobile: boolean) => {
const renderLanguageList = () => (
<LanguageList
onChange={(langCode) => {
setLangCode(langCode);
}}
languages={languages}
floating={!isMobile}
currentLangCode={langCode}
/>
);
if (isMobile) {
return (
<fieldset>
<legend>{t("labels.language")}</legend>
{renderLanguageList()}
</fieldset>
);
}
return renderLanguageList();
},
[langCode],
);
return (
<>
<Excalidraw
@@ -310,6 +356,8 @@ function ExcalidrawWrapper(props: { collab: CollabAPI }) {
isCollaborating={collab.isCollaborating}
onPointerUpdate={collab.onPointerUpdate}
onExportToBackend={onExportToBackend}
renderFooter={renderFooter}
langCode={langCode}
/>
{errorMessage && (
<ErrorDialog
+56 -73
View File
@@ -1,93 +1,85 @@
import LanguageDetector from "i18next-browser-languagedetector";
import { EVENT_CHANGE, trackEvent } from "./analytics";
import fallbackLanguageData from "./locales/en.json";
import fallbackLangData from "./locales/en.json";
import percentages from "./locales/percentages.json";
const COMPLETION_THRESHOLD_TO_EXCEED = 85;
const COMPLETION_THRESHOLD = 85;
interface Language {
lng: string;
export interface Language {
code: string;
label: string;
rtl?: boolean;
}
const allLanguages: Language[] = [
{ lng: "ar-SA", label: "العربية", rtl: true },
{ lng: "bg-BG", label: "Български" },
{ lng: "ca-ES", label: "Catalan" },
{ lng: "de-DE", label: "Deutsch" },
{ lng: "el-GR", label: "Ελληνικά" },
{ lng: "es-ES", label: "Español" },
{ lng: "fa-IR", label: "فارسی", rtl: true },
{ lng: "fi-FI", label: "Suomi" },
{ lng: "fr-FR", label: "Français" },
{ lng: "he-IL", label: "עברית", rtl: true },
{ lng: "hi-IN", label: "हिन्दी" },
{ lng: "hu-HU", label: "Magyar" },
{ lng: "id-ID", label: "Bahasa Indonesia" },
{ lng: "it-IT", label: "Italiano" },
{ lng: "ja-JP", label: "日本語" },
{ lng: "ko-KR", label: "한국어" },
{ lng: "my-MM", label: "Burmese" },
{ lng: "nb-NO", label: "Norsk bokmål" },
{ lng: "nl-NL", label: "Nederlands" },
{ lng: "nn-NO", label: "Norsk nynorsk" },
{ lng: "pl-PL", label: "Polski" },
{ lng: "pt-PT", label: "Português" },
{ lng: "ro-RO", label: "Română" },
{ lng: "ru-RU", label: "Русский" },
{ lng: "sk-SK", label: "Slovenčina" },
{ lng: "sv-SE", label: "Svenska" },
{ lng: "tr-TR", label: "Türkçe" },
{ lng: "uk-UA", label: "Українська" },
{ lng: "zh-CN", label: "简体中文" },
{ lng: "zh-TW", label: "繁體中文" },
{ code: "ar-SA", label: "العربية", rtl: true },
{ code: "bg-BG", label: "Български" },
{ code: "ca-ES", label: "Catalan" },
{ code: "de-DE", label: "Deutsch" },
{ code: "el-GR", label: "Ελληνικά" },
{ code: "es-ES", label: "Español" },
{ code: "fa-IR", label: "فارسی", rtl: true },
{ code: "fi-FI", label: "Suomi" },
{ code: "fr-FR", label: "Français" },
{ code: "he-IL", label: "עברית", rtl: true },
{ code: "hi-IN", label: "हिन्दी" },
{ code: "hu-HU", label: "Magyar" },
{ code: "id-ID", label: "Bahasa Indonesia" },
{ code: "it-IT", label: "Italiano" },
{ code: "ja-JP", label: "日本語" },
{ code: "ko-KR", label: "한국어" },
{ code: "my-MM", label: "Burmese" },
{ code: "nb-NO", label: "Norsk bokmål" },
{ code: "nl-NL", label: "Nederlands" },
{ code: "nn-NO", label: "Norsk nynorsk" },
{ code: "pl-PL", label: "Polski" },
{ code: "pt-BR", label: "Português Brasileiro" },
{ code: "pt-PT", label: "Português" },
{ code: "ro-RO", label: "Română" },
{ code: "ru-RU", label: "Русский" },
{ code: "sk-SK", label: "Slovenčina" },
{ code: "sv-SE", label: "Svenska" },
{ code: "tr-TR", label: "Türkçe" },
{ code: "uk-UA", label: "Українська" },
{ code: "zh-CN", label: "简体中文" },
{ code: "zh-TW", label: "繁體中文" },
];
export const languages: Language[] = [{ lng: "en", label: "English" }]
export const defaultLang = { code: "en", label: "English" };
export const languages: Language[] = [defaultLang]
.concat(
allLanguages.sort((left, right) => (left.label > right.label ? 1 : -1)),
)
.filter(
(lang) =>
(percentages as Record<string, number>)[lang.lng] >
COMPLETION_THRESHOLD_TO_EXCEED,
(percentages as Record<string, number>)[lang.code] >=
COMPLETION_THRESHOLD,
);
let currentLanguage = languages[0];
let currentLanguageData = {};
const fallbackLanguage = languages[0];
let currentLang: Language = defaultLang;
let currentLangData = {};
export const setLanguage = async (newLng: string | undefined) => {
currentLanguage =
languages.find((language) => language.lng === newLng) || fallbackLanguage;
export const setLanguage = async (lang: Language) => {
currentLang = lang;
document.documentElement.dir = currentLang.rtl ? "rtl" : "ltr";
document.documentElement.dir = currentLanguage.rtl ? "rtl" : "ltr";
currentLanguageData = await import(
/* webpackChunkName: "i18n-[request]" */ `./locales/${currentLanguage.lng}.json`
currentLangData = await import(
/* webpackChunkName: "i18n-[request]" */ `./locales/${currentLang.code}.json`
);
languageDetector.cacheUserLanguage(currentLanguage.lng);
trackEvent(EVENT_CHANGE, "language", currentLanguage.lng);
trackEvent(EVENT_CHANGE, "language", currentLang.code);
};
export const setLanguageFirstTime = async () => {
const newLng: string | undefined = languageDetector.detect();
export const setLanguageFirstTime = async (lang: Language) => {
currentLang = lang;
document.documentElement.dir = currentLang.rtl ? "rtl" : "ltr";
currentLanguage =
languages.find((language) => language.lng === newLng) || fallbackLanguage;
document.documentElement.dir = currentLanguage.rtl ? "rtl" : "ltr";
currentLanguageData = await import(
/* webpackChunkName: "i18n-[request]" */ `./locales/${currentLanguage.lng}.json`
currentLangData = await import(
/* webpackChunkName: "i18n-[request]" */ `./locales/${currentLang.code}.json`
);
languageDetector.cacheUserLanguage(currentLanguage.lng);
};
export const getLanguage = () => currentLanguage;
export const getLanguage = () => currentLang;
const findPartsForData = (data: any, parts: string[]) => {
for (let index = 0; index < parts.length; ++index) {
@@ -106,8 +98,8 @@ const findPartsForData = (data: any, parts: string[]) => {
export const t = (path: string, replacement?: { [key: string]: string }) => {
const parts = path.split(".");
let translation =
findPartsForData(currentLanguageData, parts) ||
findPartsForData(fallbackLanguageData, parts);
findPartsForData(currentLangData, parts) ||
findPartsForData(fallbackLangData, parts);
if (translation === undefined) {
throw new Error(`Can't find translation for ${path}`);
}
@@ -119,12 +111,3 @@ export const t = (path: string, replacement?: { [key: string]: string }) => {
}
return translation;
};
const languageDetector = new LanguageDetector();
languageDetector.init({
languageUtils: {
formatLanguageCode: (lng: string) => lng,
isWhitelisted: () => true,
},
checkWhitelist: false,
});
+2
View File
@@ -1,5 +1,6 @@
import { exportToCanvas } from "./scene/export";
import { getDefaultAppState } from "./appState";
import { SCENE_NAME_FALLBACK } from "./constants";
const { registerFont, createCanvas } = require("canvas");
@@ -61,6 +62,7 @@ const canvas = exportToCanvas(
elements as any,
{
...getDefaultAppState(),
name: SCENE_NAME_FALLBACK,
offsetTop: 0,
offsetLeft: 0,
},
+1
View File
@@ -11,6 +11,7 @@ export const IsMobileProvider = ({
if (!query.current) {
query.current = window.matchMedia
? window.matchMedia(
// keep up to date with _variables.scss
"(max-width: 640px), (max-height: 500px) and (max-width: 1000px)",
)
: (({
+8 -7
View File
@@ -37,7 +37,7 @@
"fontSize": "حجم الخط",
"fontFamily": "نوع الخط",
"onlySelected": "المحدد فقط",
"withBackground": "مع الخلفية",
"withBackground": "",
"exportEmbedScene": "تضمين المشهد في ملف التصدير",
"exportEmbedScene_details": "سيتم حفظ بيانات المشهد في ملف PNG/SVG المصدّر بحيث يمكن استعادة المشهد منه.\nسيزيد حجم الملف المصدر.",
"addWatermark": "إضافة \"مصنوعة بواسطة Excalidraw\"",
@@ -76,8 +76,7 @@
"group": "تحديد مجموعة",
"ungroup": "إلغاء تحديد مجموعة",
"collaborators": "المتعاونون",
"toggleGridMode": "التبديل إلى وضع الشبكة",
"toggleStats": "",
"gridMode": "",
"addToLibrary": "أضف إلى المكتبة",
"removeFromLibrary": "حذف من المكتبة",
"libraryLoadingMessage": "جارٍ تحميل المكتبة...",
@@ -118,9 +117,10 @@
"redo": "إعادة تنفيذ",
"roomDialog": "بدء المشاركة الحية",
"createNewRoom": "إنشاء غرفة جديدة",
"toggleFullScreen": "التبديل لوضع ملء الشاشة",
"toggleDarkMode": "تبديل الوضع الليلي",
"toggleZenMode": "تبديل الوضع الليلي",
"fullScreen": "",
"darkMode": "",
"lightMode": "",
"zenMode": "",
"exitZenMode": "إلغاء الوضع الليلى"
},
"alerts": {
@@ -136,7 +136,7 @@
"loadSceneOverridePrompt": "تحميل الرسم الخارجي سيحل محل المحتوى الموجود لديك. هل ترغب في المتابعة؟",
"errorLoadingLibrary": "حصل خطأ أثناء تحميل مكتبة الطرف الثالث.",
"confirmAddLibrary": "هذا سيضيف {{numShapes}} شكل إلى مكتبتك. هل أنت متأكد؟",
"imageDoesNotContainScene": "لا يحتوي ملف الصورة على بيانات المشهد. هل قمت بتمكين هذا أثناء التصدير؟",
"imageDoesNotContainScene": "",
"cannotRestoreFromImage": "تعذر استعادة المشهد من ملف الصورة"
},
"toolBar": {
@@ -161,6 +161,7 @@
"freeDraw": "انقر واسحب، افرج عند الانتهاء",
"text": "نصيحة: يمكنك أيضًا إضافة نص بالنقر المزدوج في أي مكان بأداة الاختيار",
"linearElementMulti": "انقر فوق النقطة الأخيرة أو اضغط على Esc أو Enter للإنهاء",
"lockAngle": "",
"resize": "يمكنك تقييد النسب بالضغط على SHIFT أثناء تغيير الحجم،\nاضغط على ALT لتغيير الحجم من المركز",
"rotate": "يمكنك تقييد الزوايا من خلال الضغط على SHIFT أثناء الدوران",
"lineEditor_info": "انقر نقراً مزدوجاً أو اضغط Enter لتعديل النقاط",
+8 -7
View File
@@ -31,13 +31,13 @@
"round": "",
"arrowheads": "",
"arrowhead_none": "",
"arrowhead_arrow": "",
"arrowhead_arrow": "Стрелка",
"arrowhead_bar": "",
"arrowhead_dot": "",
"fontSize": "Размер на шрифта",
"fontFamily": "Семейство шрифтове",
"onlySelected": "Само избраното",
"withBackground": "С фон",
"withBackground": "",
"exportEmbedScene": "",
"exportEmbedScene_details": "",
"addWatermark": "",
@@ -76,8 +76,7 @@
"group": "",
"ungroup": "",
"collaborators": "",
"toggleGridMode": "",
"toggleStats": "",
"gridMode": "",
"addToLibrary": "",
"removeFromLibrary": "",
"libraryLoadingMessage": "",
@@ -118,9 +117,10 @@
"redo": "Повтори",
"roomDialog": "Започнете сътрудничество на живо",
"createNewRoom": "Създай нова стая",
"toggleFullScreen": "Превключване на цял екран",
"toggleDarkMode": "",
"toggleZenMode": "",
"fullScreen": "",
"darkMode": "",
"lightMode": "",
"zenMode": "",
"exitZenMode": ""
},
"alerts": {
@@ -161,6 +161,7 @@
"freeDraw": "",
"text": "",
"linearElementMulti": "Кликнете върху последната точка или натиснете Escape или Enter, за да завършите",
"lockAngle": "",
"resize": "",
"rotate": "Можете да ограничите ъглите, като държите SHIFT, докато се въртите",
"lineEditor_info": "",
+7 -6
View File
@@ -37,7 +37,7 @@
"fontSize": "Mida de lletra",
"fontFamily": "Tipus de lletra",
"onlySelected": "Només seleccionats",
"withBackground": "Amb fons",
"withBackground": "",
"exportEmbedScene": "",
"exportEmbedScene_details": "",
"addWatermark": "Afegir \"Fet amb Excalidraw\"",
@@ -76,8 +76,7 @@
"group": "Agrupar la selecció",
"ungroup": "Desagrupar la selecció",
"collaborators": "Col·laboradors",
"toggleGridMode": "Commutar línies de graella",
"toggleStats": "",
"gridMode": "",
"addToLibrary": "Afegir a la biblioteca",
"removeFromLibrary": "Eliminar de la biblioteca",
"libraryLoadingMessage": "Carregant la biblioteca...",
@@ -118,9 +117,10 @@
"redo": "Refer",
"roomDialog": "Començar col·laboració en directe",
"createNewRoom": "Crear sala nova",
"toggleFullScreen": "Commutar pantalla completa",
"toggleDarkMode": "Commutar modo fosc",
"toggleZenMode": "Commutar modo zen",
"fullScreen": "",
"darkMode": "",
"lightMode": "",
"zenMode": "",
"exitZenMode": "Sortir de modo zen"
},
"alerts": {
@@ -161,6 +161,7 @@
"freeDraw": "Fer clic i arrosegar, deixar anar al punt final",
"text": "Consell: també pots afegir text fent doble clic a qualsevol lloc amb l'eina de selecció",
"linearElementMulti": "Fer clic a l'ultim punt, o polsar Escape o Enter per acabar",
"lockAngle": "",
"resize": "Per restringir les proporcions mentres es canvia la mida, mantenir premut el majúscul (SHIFT); per canviar la mida des del centre, mantenir premut ALT",
"rotate": "Per restringir els angles mentre gira, mantenir premut el majúscul (SHIFT)",
"lineEditor_info": "Fes doble clic o premi Enter per editar punts",
+8 -7
View File
@@ -76,8 +76,7 @@
"group": "Auswahl gruppieren",
"ungroup": "Gruppierung aufheben",
"collaborators": "Mitarbeitende",
"toggleGridMode": "Gitterlinien ein-/ausschalten",
"toggleStats": "Statistiken für Nerds ein-/ausschalten",
"gridMode": "Rastermodus",
"addToLibrary": "Zur Bibliothek hinzufügen",
"removeFromLibrary": "Aus Bibliothek entfernen",
"libraryLoadingMessage": "Lade Bibliothek...",
@@ -118,9 +117,10 @@
"redo": "Wiederholen",
"roomDialog": "Live-Kollaborationssitzung starten",
"createNewRoom": "Neuen Raum erstellen",
"toggleFullScreen": "Vollbild umschalten",
"toggleDarkMode": "Dunkles Design umschalten",
"toggleZenMode": "Zen-Modus umschalten",
"fullScreen": "Vollbildanzeige",
"darkMode": "Dunkles Design",
"lightMode": "Helles Design",
"zenMode": "Zen-Modus",
"exitZenMode": "Zen-Modus verlassen"
},
"alerts": {
@@ -136,7 +136,7 @@
"loadSceneOverridePrompt": "Das Laden der externen Zeichnung ersetzt den vorhandenen Inhalt. Möchtest Du fortfahren?",
"errorLoadingLibrary": "Beim Laden der Drittanbieter-Bibliothek ist ein Fehler aufgetreten.",
"confirmAddLibrary": "Dieses fügt {{numShapes}} Form(en) zu deiner Bibliothek hinzu. Bist du sicher?",
"imageDoesNotContainScene": "Bilddatei enthält keine Zeichnungsdaten. Hast du das Einbetten beim Export aktiviert?",
"imageDoesNotContainScene": "Das Importieren von Bildern wird derzeit nicht unterstützt.\n\nMöchtest du eine Szene importieren? Dieses Bild scheint keine Zeichnungsdaten zu enthalten. Hast du dies beim Exportieren aktiviert?",
"cannotRestoreFromImage": "Die Zeichnung konnte aus dieser Bilddatei nicht wiederhergestellt werden"
},
"toolBar": {
@@ -161,6 +161,7 @@
"freeDraw": "Klicke und ziehe. Lass los, wenn du fertig bist",
"text": "Tipp: Du kannst auch Text hinzufügen indem Du mit dem Auswahlwerkzeug auf eine beliebige Stelle doppelklickst",
"linearElementMulti": "Zum Beenden auf den letzten Punkt klicken oder Escape oder Eingabe drücken",
"lockAngle": "Du kannst Winkel einschränken, indem du SHIFT gedrückt hältst",
"resize": "Du kannst die Proportionen einschränken, indem du SHIFT während der Größenänderung gedrückt hältst. Halte ALT gedrückt, um die Größe vom Zentrum aus zu ändern",
"rotate": "Du kannst Winkel einschränken, indem du SHIFT während der Drehung gedrückt hältst",
"lineEditor_info": "Doppelklicken oder Eingabetaste drücken, um Punkte zu bearbeiten",
@@ -213,7 +214,7 @@
"textNewLine": "Neue Zeile hinzufügen (Text)",
"textFinish": "Bearbeiten beenden (Text)",
"zoomToFit": "Zoomen um alle Elemente einzupassen",
"zoomToSelection": "",
"zoomToSelection": "Zoomauswahl",
"preventBinding": "Pfeil-Bindung verhindern"
},
"encrypted": {
+11 -10
View File
@@ -37,7 +37,7 @@
"fontSize": "Μέγεθος γραμματοσειράς",
"fontFamily": "Γραμματοσειρά",
"onlySelected": "Μόνο τα Επιλεγμένα",
"withBackground": "Με Φόντο",
"withBackground": "Με φόντο",
"exportEmbedScene": "Ενσωμάτωση της σκηνής στο αρχείο προς εξαγωγή",
"exportEmbedScene_details": "Τα δεδομένα σκηνής θα αποθηκευτούν στο αρχείο PNG/SVG προς εξαγωγή ώστε η σκηνή να είναι δυνατό να αποκατασταθεί από αυτό.\nΘα αυξήσει το μέγεθος του αρχείου προς εξαγωγή.",
"addWatermark": "Προσθήκη \"Φτιαγμένο με Excalidraw\"",
@@ -76,8 +76,7 @@
"group": "Δημιουργία ομάδας από επιλογή",
"ungroup": "Κατάργηση ομάδας από επιλογή",
"collaborators": "Συνεργάτες",
"toggleGridMode": "Εναλλαγή λειτουργίας πλέγματος",
"toggleStats": "",
"gridMode": "Εμφάνιση σε πλέγμα",
"addToLibrary": "Προσθήκη στη βιβλιοθήκη",
"removeFromLibrary": "Αφαίρεση από τη βιβλιοθήκη",
"libraryLoadingMessage": "Φόρτωση βιβλιοθήκης...",
@@ -118,9 +117,10 @@
"redo": "Επαναφορά",
"roomDialog": "Έναρξη ζωντανής συνεργασίας",
"createNewRoom": "Δημιουργία νέου χώρου",
"toggleFullScreen": "Εναλλαγή πλήρους οθόνης",
"toggleDarkMode": "Εναλλαγή εμφάνισης σε dark",
"toggleZenMode": "Εναλλαγή λειτουργίας Zen",
"fullScreen": "Πλήρης οθόνη",
"darkMode": "Σκοτεινή λειτουργία",
"lightMode": "Φωτεινή λειτουργία",
"zenMode": "Λειτουργία Zεν",
"exitZenMode": "Έξοδος απο την λειτουργία Zen"
},
"alerts": {
@@ -136,7 +136,7 @@
"loadSceneOverridePrompt": "Η φόρτωση εξωτερικού σχεδίου θα αντικαταστήσει το υπάρχον περιεχόμενο. Επιθυμείτε να συνεχίσετε;",
"errorLoadingLibrary": "Υπήρξε ένα σφάλμα κατά τη φόρτωση της βιβλιοθήκης τρίτου μέρους.",
"confirmAddLibrary": "Αυτό θα προσθέσει {{numShapes}} σχήμα(τα) στη βιβιλιοθήκη σας. Είστε σίγουροι;",
"imageDoesNotContainScene": "Το αρχείο εικόνας δεν έχει δεδομένα σκηνής. Το είχατε ενεργοποιήσει αυτό κατά την εξαγωγή;",
"imageDoesNotContainScene": "",
"cannotRestoreFromImage": "Η σκηνή δεν ήταν δυνατό να αποκατασταθεί από αυτό το αρχείο εικόνας"
},
"toolBar": {
@@ -161,6 +161,7 @@
"freeDraw": "Κάντε κλικ και σύρατε, απελευθερώσατε όταν έχετε τελειώσει",
"text": "Tip: μπορείτε επίσης να προσθέστε κείμενο με διπλό-κλικ οπουδήποτε με το εργαλείο επιλογών",
"linearElementMulti": "Κάνε κλικ στο τελευταίο σημείο ή πάτησε Escape ή Enter για να τελειώσεις",
"lockAngle": "",
"resize": "Μπορείς να περιορίσεις τις αναλογίες κρατώντας το SHIFT ενώ αλλάζεις μέγεθος,\nκράτησε πατημένο το ALT για αλλαγή μεγέθους από το κέντρο",
"rotate": "Μπορείς να περιορίσεις τις γωνίες κρατώντας πατημένο το πλήκτρο SHIFT κατά την περιστροφή",
"lineEditor_info": "Διπλό-κλικ ή πιέστε Enter για να επεξεργαστείτε τα σημεία",
@@ -169,7 +170,7 @@
},
"canvasError": {
"cannotShowPreview": "",
"canvasTooBig": "",
"canvasTooBig": "Ο καμβάς μπορεί να είναι μεγάλος.",
"canvasTooBigTip": ""
},
"errorSplash": {
@@ -224,10 +225,10 @@
"element": "Στοιχείο",
"elements": "Στοιχεία",
"height": "Ύψος",
"scene": "",
"scene": "Σκηνή",
"selected": "Επιλεγμένα",
"storage": "Χώρος",
"title": "",
"title": "Στατιστικά για σπασίκλες",
"total": "Σύνολο ",
"width": "Πλάτος"
}
+1
View File
@@ -1,6 +1,7 @@
{
"labels": {
"paste": "Paste",
"pasteCharts": "Paste charts",
"selectAll": "Select all",
"multiSelect": "Add element to selection",
"moveCanvas": "Move canvas",
+42 -41
View File
@@ -4,7 +4,7 @@
"selectAll": "Seleccionar todo",
"multiSelect": "Añadir elemento a la selección",
"moveCanvas": "Mover el lienzo",
"cut": "",
"cut": "Cortar",
"copy": "Copiar",
"copyAsPng": "Copiar al portapapeles como PNG",
"copyAsSvg": "Copiar al portapapeles como SVG",
@@ -29,17 +29,17 @@
"edges": "Bordes",
"sharp": "Afilado",
"round": "Redondo",
"arrowheads": "",
"arrowhead_none": "",
"arrowhead_arrow": "",
"arrowhead_bar": "",
"arrowhead_dot": "",
"arrowheads": "Puntas de flecha",
"arrowhead_none": "Vacía",
"arrowhead_arrow": "Flecha",
"arrowhead_bar": "Barra",
"arrowhead_dot": "Punto",
"fontSize": "Tamaño de la fuente",
"fontFamily": "Tipo de fuente",
"onlySelected": "Sólo seleccionados",
"withBackground": "Con fondo",
"exportEmbedScene": "",
"exportEmbedScene_details": "",
"exportEmbedScene": "Insertar escena en el archivo exportado",
"exportEmbedScene_details": "Los datos de escena se guardarán en el archivo PNG/SVG exportado para que la escena pueda ser restaurada de ella.\nIncrementará el tamaño del archivo exportado.",
"addWatermark": "Agregar \"Hecho con Excalidraw\"",
"handDrawn": "Dibujado a mano",
"normal": "Normal",
@@ -60,7 +60,7 @@
"architect": "Arquitecto",
"artist": "Artista",
"cartoonist": "Caricatura",
"fileTitle": "",
"fileTitle": "Título del archivo",
"colorPicker": "Selector de color",
"canvasBackground": "Fondo del lienzo",
"drawingCanvas": "Lienzo de dibujo",
@@ -69,29 +69,28 @@
"language": "Idioma",
"createRoom": "Compartir una sesión de colaboración en vivo",
"duplicateSelection": "Duplicar",
"untitled": "",
"untitled": "Sin título",
"name": "Nombre",
"yourName": "Tu nombre",
"madeWithExcalidraw": "Hecho con Excalidraw",
"group": "Selección de grupo",
"ungroup": "Desagrupar",
"collaborators": "Colaboradores",
"toggleGridMode": "Alternar modo cuadrícula",
"toggleStats": "",
"gridMode": "Modo cuadrícula",
"addToLibrary": "Añadir a la biblioteca",
"removeFromLibrary": "Eliminar de la biblioteca",
"libraryLoadingMessage": "Cargando biblioteca...",
"libraries": "",
"libraries": "Explorar librerías",
"loadingScene": "Cargando escena...",
"align": "",
"alignTop": "",
"alignBottom": "",
"alignLeft": "",
"alignRight": "",
"centerVertically": "",
"centerHorizontally": "",
"distributeHorizontally": "",
"distributeVertically": ""
"align": "Alinear",
"alignTop": "Alinear arriba",
"alignBottom": "Alinear abajo",
"alignLeft": "Alinear a la izquierda",
"alignRight": "Alinear a la derecha",
"centerVertically": "Centrar verticalmente",
"centerHorizontally": "Centrar horizontalmente",
"distributeHorizontally": "Distribuir horizontalmente",
"distributeVertically": "Distribuir verticalmente"
},
"buttons": {
"clearReset": "Limpiar lienzo y reiniciar el color de fondo",
@@ -118,15 +117,16 @@
"redo": "Rehacer",
"roomDialog": "Iniciar colaboración en vivo",
"createNewRoom": "Crear nueva sala",
"toggleFullScreen": "Alternar pantalla completa",
"toggleDarkMode": "Cambiar a modo oscuro",
"toggleZenMode": "Alternar modo zen",
"fullScreen": "Pantalla completa",
"darkMode": "Modo oscuro",
"lightMode": "Modo claro",
"zenMode": "Modo Zen",
"exitZenMode": "Salir del modo Zen"
},
"alerts": {
"clearReset": "Esto limpiará todo el lienzo. Estás seguro?",
"couldNotCreateShareableLink": "No se pudo crear un enlace para compartir.",
"couldNotCreateShareableLinkTooBig": "",
"couldNotCreateShareableLinkTooBig": "No se pudo crear el enlace para compartir: la escena es demasiado grande",
"couldNotLoadInvalidFile": "No se pudo cargar el archivo inválido",
"importBackendFailed": "La importación falló.",
"cannotExportEmptyCanvas": "No se puede exportar un lienzo vació",
@@ -136,8 +136,8 @@
"loadSceneOverridePrompt": "Si carga este dibujo externo, reemplazará el que tiene. ¿Desea continuar?",
"errorLoadingLibrary": "Se ha producido un error al cargar la biblioteca de terceros.",
"confirmAddLibrary": "Esto añadirá {{numShapes}} forma(s) a tu biblioteca. ¿Estás seguro?",
"imageDoesNotContainScene": "",
"cannotRestoreFromImage": ""
"imageDoesNotContainScene": "La importación de imágenes no está soportada en este momento.\n\n¿Querías importar una escena? Esta imagen no parece contener ningún dato de escena. ¿Lo ha activado durante la exportación?",
"cannotRestoreFromImage": "No se pudo restaurar la escena desde este archivo de imagen"
},
"toolBar": {
"selection": "Selección",
@@ -161,6 +161,7 @@
"freeDraw": "Haz clic y arrastra, suelta al terminar",
"text": "Consejo: también puedes añadir texto haciendo doble clic en cualquier lugar con la herramienta de selección",
"linearElementMulti": "Haga clic en el último punto o pulse Escape o Enter para finalizar",
"lockAngle": "",
"resize": "Para mantener las proporciones mantén SHIFT presionado mientras modificas el tamaño, \nmantén presionado ALT para modificar el tamaño desde el centro",
"rotate": "Puede restringir los ángulos manteniendo presionado SHIFT mientras gira",
"lineEditor_info": "haga doble clic o pulse Enter para editar puntos",
@@ -168,9 +169,9 @@
"lineEditor_nothingSelected": "Seleccione un punto para mover o eliminar, o mantenga pulsado Alt y haga clic para añadir nuevos puntos"
},
"canvasError": {
"cannotShowPreview": "",
"canvasTooBig": "",
"canvasTooBigTip": ""
"cannotShowPreview": "No se puede mostrar la vista previa",
"canvasTooBig": "El lienzo podría ser demasiado grande.",
"canvasTooBigTip": "Sugerencia: intenta acercar un poco los elementos más lejanos."
},
"errorSplash": {
"headingMain_pre": "Se encontró un error. Intente ",
@@ -213,22 +214,22 @@
"textNewLine": "Añadir nueva línea (texto)",
"textFinish": "Finalizar edición (texto)",
"zoomToFit": "Ajustar para mostrar todos los elementos",
"zoomToSelection": "",
"zoomToSelection": "Hacer zoom a la selección",
"preventBinding": "Evitar enlace de flecha"
},
"encrypted": {
"tooltip": "Tus dibujos están cifrados de punto a punto, por lo que los servidores de Excalidraw nunca los verán."
},
"stats": {
"angle": "",
"element": "",
"elements": "",
"height": "",
"scene": "",
"selected": "",
"storage": "",
"angle": "Ángulo",
"element": "Elemento",
"elements": "Elementos",
"height": "Alto",
"scene": "Escena",
"selected": "Seleccionado",
"storage": "Almacenamiento",
"title": "",
"total": "",
"width": ""
"total": "Total",
"width": "Ancho"
}
}
+8 -7
View File
@@ -37,7 +37,7 @@
"fontSize": "اندازه قلم",
"fontFamily": "نوع قلم",
"onlySelected": "فقط انتخاب شده ها",
"withBackground": "با پس زمینه",
"withBackground": "",
"exportEmbedScene": "قرار دادن صحنه در فایل خروجی",
"exportEmbedScene_details": "متحوای صحنه به فایل خروجی SVG/PNG اضافه خواهد شد برای بازیابی صحنه به آن اضافه خواهد شد.\nباعث افزایش حجم فایل خروجی میشود.",
"addWatermark": "\"ساخته شده با Excalidraw\" را اضافه کن",
@@ -76,8 +76,7 @@
"group": "گروهبندی انتخابها",
"ungroup": "حذف گروهبندی انتخابها",
"collaborators": "همکاران",
"toggleGridMode": "سويچ خطوط راهنما",
"toggleStats": "",
"gridMode": "",
"addToLibrary": "افزودن به کتابخانه",
"removeFromLibrary": "حذف از کتابخانه",
"libraryLoadingMessage": "بارگذاری کتابخانه...",
@@ -118,9 +117,10 @@
"redo": "از سر",
"roomDialog": "همکاری آنلاین را شروع کنید",
"createNewRoom": "ایجاد یک اتاق جدید",
"toggleFullScreen": "تغییر به حالت تمام صفحه",
"toggleDarkMode": "تغییر به حالت تاریک",
"toggleZenMode": "تغییر به حالت تمرکز",
"fullScreen": "",
"darkMode": "",
"lightMode": "",
"zenMode": "",
"exitZenMode": "خروج از حالت تمرکز"
},
"alerts": {
@@ -136,7 +136,7 @@
"loadSceneOverridePrompt": "بارگزاری یک طرح خارجی محتوای فعلی رو از بین میبرد. آیا میخواهید ادامه دهید؟",
"errorLoadingLibrary": "خطایی در بارگذاری کتابخانه ثالث وجود داشت.",
"confirmAddLibrary": "{{numShapes}} از اشکال به کتابخانه شما اضافه خواهد شد. مطمئن هستید؟",
"imageDoesNotContainScene": "فایل تصویر دارای محتوای صحنه نیست. آیا در هنگام خروجی گرفتن آن را فعال کرده‌اید؟",
"imageDoesNotContainScene": "",
"cannotRestoreFromImage": "صحنه را نمی توان از این فایل تصویری بازیابی کرد"
},
"toolBar": {
@@ -161,6 +161,7 @@
"freeDraw": "کلیک کنید و بکشید و وقتی کار تمام شد رها کنید",
"text": "نکته: با برنامه انتخاب شده شما میتوانید با دوبار کلیک کردن هرکجا میخواید متن اظاف کنید",
"linearElementMulti": "روی آخرین نقطه کلیک کنید یا کلید ESC را بزنید یا کلید Enter را بزنید برای اتمام کار",
"lockAngle": "",
"resize": "می توانید با نگه داشتن SHIFT در هنگام تغییر اندازه، نسبت ها را محدود کنید،ALT را برای تغییر اندازه از مرکز نگه دارید",
"rotate": "با نگه داشتن SHIFT هنگام چرخش می توانید زاویه ها را محدود کنید",
"lineEditor_info": "دوبار کلیک کنید یا Enter را فشار دهید تا نقاط را ویرایش کنید",
+7 -6
View File
@@ -76,8 +76,7 @@
"group": "Ryhmitä valinta",
"ungroup": "Pura valittu ryhmä",
"collaborators": "Yhteistyökumppanit",
"toggleGridMode": "Ruudukko päälle/pois",
"toggleStats": "Nörttien tilastot päälle/pois",
"gridMode": "Ruudukkotila",
"addToLibrary": "Lisää kirjastoon",
"removeFromLibrary": "Poista kirjastosta",
"libraryLoadingMessage": "Ladataan kirjastoa...",
@@ -118,9 +117,10 @@
"redo": "Tee uudelleen",
"roomDialog": "Aloita live-yhteistyö",
"createNewRoom": "Luo huone",
"toggleFullScreen": "Koko näytön tila päälle/pois",
"toggleDarkMode": "Pimeä tila päälle/pois",
"toggleZenMode": "Zen-tila päälle",
"fullScreen": "Koko näyttö",
"darkMode": "Tumma tila",
"lightMode": "Vaalea tila",
"zenMode": "Zen-tila",
"exitZenMode": "Poistu zen-tilasta"
},
"alerts": {
@@ -136,7 +136,7 @@
"loadSceneOverridePrompt": "Ulkopuolisen piirroksen lataaminen korvaa nykyisen sisältösi. Haluatko jatkaa?",
"errorLoadingLibrary": "Kolmannen osapuolen kirjastoa ladattaessa tapahtui virhe.",
"confirmAddLibrary": "Tämä lisää {{numShapes}} muotoa kirjastoosi. Oletko varma?",
"imageDoesNotContainScene": "Kuvatiedosto ei sisällä teostietoja. Valitsitko sisällyttää ne tallennusvaiheessa?",
"imageDoesNotContainScene": "Kuvien lisääminen ei ole tällä hetkellä mahdollista.\n\nHaluatko tuoda piirroksen? Tämä kuva ei näytä sisältävän tarvittavia tietoja. Oletko ottanut piirrostietojen tallennuksen käyttöön viennin aikana?",
"cannotRestoreFromImage": "Teosta ei voitu palauttaa tästä kuvatiedostosta"
},
"toolBar": {
@@ -161,6 +161,7 @@
"freeDraw": "Paina ja raahaa, päästä irti kun olet valmis",
"text": "Vinkki: voit myös lisätä tekstiä kaksoisnapsauttamalla mihin tahansa valintatyökalulla",
"linearElementMulti": "Klikkaa viimeistä pistettä, paina Escape tai paina Enter lopettaaksesi",
"lockAngle": "Voit rajoittaa kulmaa pitämällä SHIFT pohjassa",
"resize": "Voit rajoittaa mittasuhteet pitämällä SHIFT pohjassa kun muutat kokoa, pidä ALT pohjassa muuttaaksesi kokoa keskipisteen suhteen",
"rotate": "Voit rajoittaa kulman pitämällä SHIFT pohjassa pyörittäessäsi",
"lineEditor_info": "Kaksoisnapauta tai paina Enter muokataksesi pisteitä",
+13 -12
View File
@@ -76,22 +76,21 @@
"group": "Grouper la sélection",
"ungroup": "Dégrouper la sélection",
"collaborators": "Collaborateurs",
"toggleGridMode": "Basculer le mode grille",
"toggleStats": "Activer/désactiver les stats pour les nerds",
"gridMode": "Mode grille",
"addToLibrary": "Ajouter à la bibliothèque",
"removeFromLibrary": "Supprimer de la bibliothèque",
"libraryLoadingMessage": "Chargement de la bibliothèque...",
"libraries": "Explorer les bibliothèques",
"loadingScene": "Chargement de la scène...",
"align": "Aligner",
"align": "Alignement",
"alignTop": "Aligner en haut",
"alignBottom": "Aligner en bas",
"alignLeft": "Aligner à gauche",
"alignRight": "Aligner à droite",
"centerVertically": "Centrer verticalement",
"centerHorizontally": "Centrer horizontalement",
"distributeHorizontally": "Répartir horizontalement",
"distributeVertically": "Répartir verticalement"
"distributeHorizontally": "Distribuer horizontalement",
"distributeVertically": "Distribuer verticalement"
},
"buttons": {
"clearReset": "Effacer le canvas & réinitialiser la couleur d'arrière-plan",
@@ -118,9 +117,10 @@
"redo": "Rétablir",
"roomDialog": "Démarrer le collaboration en temps réel",
"createNewRoom": "Créer un nouveau salon",
"toggleFullScreen": "Activer/désactiver le mode plein écran",
"toggleDarkMode": "Activer/désactiver le mode sombre",
"toggleZenMode": "Activer/désactiver le mode zen",
"fullScreen": "Plein écran",
"darkMode": "Mode sombre",
"lightMode": "Mode Clair",
"zenMode": "Mode Zen",
"exitZenMode": "Quitter le mode zen"
},
"alerts": {
@@ -136,7 +136,7 @@
"loadSceneOverridePrompt": "Le chargement d'un dessin externe remplacera votre contenu actuel. Souhaitez-vous continuer ?",
"errorLoadingLibrary": "Une erreur s'est produite lors du chargement de la bibliothèque tierce.",
"confirmAddLibrary": "Cela va ajouter {{numShapes}} forme(s) à votre bibliothèque. Êtes-vous sûr(e) ?",
"imageDoesNotContainScene": "Le fichier image ne contient pas de données de scène. L'avez-vous activé lors de l'export ?",
"imageDoesNotContainScene": "L'importation des images n'est pas prise en charge pour le moment.\n\nVoulez-vous importer une scène ? Cette image ne semble pas contenir de données de scène. Avez-vous activé cette option lors de l'exportation ?",
"cannotRestoreFromImage": "Impossible de restaurer la scène depuis ce fichier image"
},
"toolBar": {
@@ -161,6 +161,7 @@
"freeDraw": "Cliquez et faites glissez, relâchez quand vous avez terminé",
"text": "Astuce : vous pouvez également ajouter du texte en double-cliquant n'importe où avec l'outil de sélection",
"linearElementMulti": "Cliquez sur le dernier point ou appuyez sur Échap ou Entrée pour terminer",
"lockAngle": "Vous pouvez contraindre l'angle en maintenant SHIFT",
"resize": "Vous pouvez conserver les proportions en maintenant la touche SHIFT pendant le redimensionnement,\nen maintenant la touche ALT pour redimensionner par rapport au centre",
"rotate": "Vous pouvez contraindre les angles en maintenant MAJ enfoncé pendant la rotation",
"lineEditor_info": "Double-cliquez ou appuyez sur Entrée pour éditer les points",
@@ -169,8 +170,8 @@
},
"canvasError": {
"cannotShowPreview": "Impossible dafficher laperçu",
"canvasTooBig": "Le tableau peut être trop grand.",
"canvasTooBigTip": "Astuce : essayez de rapprocher un peu les éléments les plus éloignés ensemble."
"canvasTooBig": "Le dessin est peut-être trop grand.",
"canvasTooBigTip": "Conseil : essayez de rapprocher un peu plus les éléments les plus éloignés."
},
"errorSplash": {
"headingMain_pre": "Une erreur est survenue. Essayez ",
@@ -227,7 +228,7 @@
"scene": "Scène",
"selected": "Sélectionné",
"storage": "Stockage",
"title": "Stats pour nerds",
"title": "Stats pour les nerds",
"total": "Total",
"width": "Largeur"
}
+63 -62
View File
@@ -2,9 +2,9 @@
"labels": {
"paste": "הדבק",
"selectAll": "בחר הכל",
"multiSelect": "",
"moveCanvas": "",
"cut": "",
"multiSelect": "הוסף אובייקט לבחירה",
"moveCanvas": "הזז את הקנבס",
"cut": "חתוך",
"copy": "העתק",
"copyAsPng": "העתק ללוח כ PNG",
"copyAsSvg": "העתק ללוח כ SVG",
@@ -26,20 +26,20 @@
"sloppiness": "סגנון",
"opacity": "אטימות",
"textAlign": "יישור טקסט",
"edges": "",
"sharp": "",
"round": "",
"arrowheads": "",
"arrowhead_none": "",
"arrowhead_arrow": "",
"arrowhead_bar": "",
"arrowhead_dot": "",
"edges": "קצוות",
"sharp": "חד",
"round": "עגול",
"arrowheads": "ראשי חצים",
"arrowhead_none": "ללא",
"arrowhead_arrow": "חץ",
"arrowhead_bar": "שורה",
"arrowhead_dot": "נקודה",
"fontSize": "גודל גופן",
"fontFamily": "סוג הגופן",
"onlySelected": "רק מה שנבחר",
"withBackground": "עם רקע",
"exportEmbedScene": "",
"exportEmbedScene_details": "",
"exportEmbedScene": "שלב את התצוגה בקובץ המיוצא",
"exportEmbedScene_details": "מידע התצוגה יישמר לקובץ המיוצא מסוג PNG/SVG כך שיהיה ניתן לשחזרה ממנו.\nהפעולה תגדיל את גודל הקובץ המיוצא.",
"addWatermark": "הוסף \"נוצר באמצעות Excalidraw\"",
"handDrawn": "כתב יד",
"normal": "רגיל",
@@ -60,7 +60,7 @@
"architect": "ארכיטקט",
"artist": "אמן",
"cartoonist": "קריקטוריסט",
"fileTitle": "",
"fileTitle": "כותרת הקובץ",
"colorPicker": "בחירת צבע",
"canvasBackground": "רקע הלוח",
"drawingCanvas": "לוח ציור",
@@ -69,29 +69,28 @@
"language": "שפה",
"createRoom": "התחל שיתוף פעולה חי",
"duplicateSelection": "שכפל",
"untitled": "",
"untitled": "ללא כותרת",
"name": "שם",
"yourName": "שם",
"madeWithExcalidraw": "נוצר באמצעות Excalidraw",
"group": "אחד לקבוצה",
"ungroup": "פרק קבוצה",
"collaborators": "",
"toggleGridMode": "",
"toggleStats": "",
"addToLibrary": "",
"removeFromLibrary": "",
"libraryLoadingMessage": "",
"libraries": "",
"loadingScene": "",
"align": "",
"alignTop": "",
"alignBottom": "",
"alignLeft": "",
"alignRight": "",
"centerVertically": "",
"centerHorizontally": "",
"distributeHorizontally": "",
"distributeVertically": ""
"collaborators": "שותפים",
"gridMode": "",
"addToLibrary": "הוסף לספריה",
"removeFromLibrary": "הסר מספריה",
"libraryLoadingMessage": "טוען ספריה...",
"libraries": "דפדף בספריות",
"loadingScene": "טוען תצוגה...",
"align": "יישר",
"alignTop": "יישר למעלה",
"alignBottom": "יישר למטה",
"alignLeft": "יישר לשמאל",
"alignRight": "יישר לימין",
"centerVertically": "מרכז אנכית",
"centerHorizontally": "מרכז אופקית",
"distributeHorizontally": "חלוקה אופקית",
"distributeVertically": "חלוקה אנכית"
},
"buttons": {
"clearReset": "אפס את הלוח",
@@ -100,9 +99,9 @@
"exportToSvg": "יצא ל SVG",
"copyToClipboard": "העתק ללוח",
"copyPngToClipboard": "העתק PNG ללוח",
"scale": "",
"scale": "קנה מידה",
"save": "שמור",
"saveAs": "",
"saveAs": "שמירה בשם",
"load": "טען",
"getShareableLink": "קבל קישור לשיתוף",
"close": "סגור",
@@ -118,26 +117,27 @@
"redo": "בצע מחדש",
"roomDialog": "התחל שיתוף חי",
"createNewRoom": "צור חדר",
"toggleFullScreen": "הפעל/הפסק מסך מלא",
"toggleDarkMode": "",
"toggleZenMode": "התחל/הפסק מצב תפריט מרחף",
"fullScreen": "",
"darkMode": "",
"lightMode": "",
"zenMode": "",
"exitZenMode": "צא ממצב תפריט מרחף"
},
"alerts": {
"clearReset": "פעולה זו תנקה את כל הלוח. אתה בטוח?",
"couldNotCreateShareableLink": "לא ניתן לייצר לינק לשיתוף.",
"couldNotCreateShareableLinkTooBig": "",
"couldNotCreateShareableLinkTooBig": "לא הצלחנו לייצר קישור לשיתוף: התצוגה גדולה מדי",
"couldNotLoadInvalidFile": "לא ניתן לטעון קובץ שאיננו תואם",
"importBackendFailed": "ייבוא מהשרת נכשל.",
"cannotExportEmptyCanvas": "לא ניתן לייצא לוח ריק.",
"couldNotCopyToClipboard": "לא ניתן להעתיק ללוח. נסה להשתמש בדפדפן Chrome.",
"decryptFailed": "לא ניתן לפענח מידע.",
"uploadedSecurly": "ההעלאה הוצפנה מקצה לקצה, ולכן שרת Excalidraw וצד שלישי לא יכולים לקרוא את התוכן.",
"loadSceneOverridePrompt": "",
"errorLoadingLibrary": "",
"confirmAddLibrary": "",
"loadSceneOverridePrompt": "טעינה של ציור חיצוני תחליף את התוכן הקיים שלך. האם תרצה להמשיך?",
"errorLoadingLibrary": "קרתה שגיאה בטעינת הספריה החיצונית.",
"confirmAddLibrary": "הפעולה תוסיף {{numShapes}} צורה(ות) לספריה שלך. האם אתה בטוח?",
"imageDoesNotContainScene": "",
"cannotRestoreFromImage": ""
"cannotRestoreFromImage": "לא הצלחנו לשחזר את התצוגה מקובץ התמונה"
},
"toolBar": {
"selection": "בחירה",
@@ -148,7 +148,7 @@
"arrow": "חץ",
"line": "קו",
"text": "טקסט",
"library": "",
"library": "ספריה",
"lock": "השאר את הכלי הנבחר פעיל גם לאחר סיום הציור"
},
"headings": {
@@ -159,18 +159,19 @@
"hints": {
"linearElement": "הקלק בשביל לבחור נקודות מרובות, גרור בשביל קו בודד",
"freeDraw": "לחץ וגרור, שחרר כשסיימת",
"text": "",
"text": "טיפ: אפשר להוסיף טקסט על ידי לחיצה כפולה בכל מקום עם כלי הבחירה",
"linearElementMulti": "הקלק על הנקודה האחרונה או הקש Escape או Enter לסיום",
"lockAngle": "",
"resize": "ניתן להגביל פרופורציות על ידי לחיצה על SHIFT תוך כדי שינוי גודל,\nהחזק ALT בשביל לשנות גודל ביחס למרכז",
"rotate": "ניתן להגביל זוויות על ידי לחיצה על SHIFT תוך כדי סיבוב",
"lineEditor_info": "",
"lineEditor_pointSelected": "",
"lineEditor_nothingSelected": ""
"lineEditor_info": "לחץ לחיצה כפולה או אנטר לעריכת הנקודות",
"lineEditor_pointSelected": "לחץ על Delete להסרת נקודה, CtrlOrCmd+D לשכפל, או גרור להזזה",
"lineEditor_nothingSelected": "בחר נקודה להזזה או הסרה, או החזק את כפתור Alt והקלק להוספת נקודות חדשות"
},
"canvasError": {
"cannotShowPreview": "",
"canvasTooBig": "",
"canvasTooBigTip": ""
"cannotShowPreview": "לא הצלחנו להציג את התצוגה המקדימה",
"canvasTooBig": "הקנבס עלול להיות גדול מדי.",
"canvasTooBigTip": "טיפ: נסה להזיז את האלמנטים הרחוקים ביותר מעט קרוב יותר יחד."
},
"errorSplash": {
"headingMain_pre": "אירעה שגיאה. נסה ",
@@ -213,22 +214,22 @@
"textNewLine": "הוסף שורה חדשה (טקסט)",
"textFinish": "סיים עריכה (טקסט)",
"zoomToFit": "זום להתאמת כל האלמנטים למסך",
"zoomToSelection": "",
"preventBinding": ""
"zoomToSelection": "התמקד בבחירה",
"preventBinding": "מנע השתלבות חצים"
},
"encrypted": {
"tooltip": "הרישומים שלך מוצפנים מקצה לקצה כך שהשרתים של Excalidraw לא יראו אותם לעולם."
},
"stats": {
"angle": "",
"element": "",
"elements": "",
"height": "",
"scene": "",
"selected": "",
"storage": "",
"title": "",
"total": "",
"width": ""
"angle": "זווית",
"element": "אלמנט",
"elements": "אלמנטים",
"height": "גובה",
"scene": "תצוגה",
"selected": "נבחר/ים",
"storage": "אחסון",
"title": "סטטיסטיקות לחנונים",
"total": "סה״כ",
"width": "רוחב"
}
}
+10 -9
View File
@@ -29,11 +29,11 @@
"edges": "किनारा",
"sharp": "नुकीला",
"round": "गोल",
"arrowheads": "",
"arrowhead_none": "",
"arrowheads": "तीर शीर्ष",
"arrowhead_none": "कोई भी नहीं",
"arrowhead_arrow": "तीर",
"arrowhead_bar": "",
"arrowhead_dot": "",
"arrowhead_bar": "बार",
"arrowhead_dot": "बिंदु",
"fontSize": "फ़ॉन्ट का आकार",
"fontFamily": "फ़ॉन्ट का परिवार",
"onlySelected": "केवल चयनित",
@@ -76,8 +76,7 @@
"group": "समूह चयन",
"ungroup": "समूह चयन असमूहीकृत करें",
"collaborators": "सहयोगी",
"toggleGridMode": "टॉगल ग्रिड मोड",
"toggleStats": "",
"gridMode": "",
"addToLibrary": "लाइब्रेरी से जोड़ें",
"removeFromLibrary": "लाइब्रेरी से निकालें",
"libraryLoadingMessage": "लाइब्रेरी खुल रही है",
@@ -118,9 +117,10 @@
"redo": "फिर से करें",
"roomDialog": "लाइव सहयोग शुरू करें",
"createNewRoom": "एक नया कमरा बनाएं",
"toggleFullScreen": "पूर्णस्क्रीन चालू करें",
"toggleDarkMode": "",
"toggleZenMode": "टॉगल ज़ेन मोड",
"fullScreen": "",
"darkMode": "",
"lightMode": "",
"zenMode": "",
"exitZenMode": "जेन मोड से बाहर निकलें"
},
"alerts": {
@@ -161,6 +161,7 @@
"freeDraw": "क्लिक करें और खींचें। समाप्त करने के लिए, छोड़ो",
"text": "",
"linearElementMulti": "अंतिम बिंदु पर क्लिक करें या समाप्त होने के लिए एस्केप या एंटर दबाएं",
"lockAngle": "",
"resize": "आकार बदलते समय आप SHIFT को पकड़ कर अनुपात में कमी कर सकते हैं,\nकेंद्र से आकार बदलने के लिए ALT दबाए रखें",
"rotate": "आप घूर्णन करते समय SHIFT पकड़कर कोणों को विवश कर सकते हैं",
"lineEditor_info": "बिंदुओं को संपादित करने के लिए Enter पर डबल-क्लिक करें या दबाएँ",
+107 -106
View File
@@ -2,96 +2,95 @@
"labels": {
"paste": "Beillesztés",
"selectAll": "Összes kijelölése",
"multiSelect": "",
"moveCanvas": "",
"cut": "",
"multiSelect": "Elem hozzáadása a kiválasztáshoz",
"moveCanvas": "Vászon mozgatása",
"cut": "Kivágás",
"copy": "Másolás",
"copyAsPng": "Vágólapra másolás mint PNG",
"copyAsSvg": "Vágólapra másolás mint SVG",
"bringForward": "Előrébb hozás",
"sendToBack": "",
"bringToFront": "",
"sendBackward": "",
"sendToBack": "Hátraküldés",
"bringToFront": "Előrehozás",
"sendBackward": "Hátrébb küldés",
"delete": "Törlés",
"copyStyles": "",
"pasteStyles": "",
"copyStyles": "Stílus másolása",
"pasteStyles": "Stílus beillesztése",
"stroke": "Körvonal",
"background": "Háttér",
"fill": "Kitöltés",
"strokeWidth": "",
"strokeStyle": "",
"strokeStyle_solid": "",
"strokeStyle_dashed": "",
"strokeStyle_dotted": "",
"strokeWidth": "Körvonal vastagsága",
"strokeStyle": "Körvonal stílusa",
"strokeStyle_solid": "Kitöltött",
"strokeStyle_dashed": "Szaggatott",
"strokeStyle_dotted": "Pontozott",
"sloppiness": "Stílus",
"opacity": "Áttetszőség",
"textAlign": "",
"edges": "",
"sharp": "",
"round": "",
"arrowheads": "",
"arrowhead_none": "",
"arrowhead_arrow": "",
"arrowhead_bar": "",
"arrowhead_dot": "",
"fontSize": "",
"fontFamily": "",
"textAlign": "Szöveg igazítása",
"edges": "Szélek",
"sharp": "Éles",
"round": "Kerek",
"arrowheads": "Nyílhegyek",
"arrowhead_none": "Nincs",
"arrowhead_arrow": "Nyíl",
"arrowhead_bar": "Oszlop",
"arrowhead_dot": "Pont",
"fontSize": "Betűméret",
"fontFamily": "Betűkészlet család",
"onlySelected": "Csak a kiválasztott",
"withBackground": "Háttérrel együtt",
"exportEmbedScene": "",
"withBackground": "",
"exportEmbedScene": "Jelenet beágyazása az exportált fájlba",
"exportEmbedScene_details": "",
"addWatermark": "",
"handDrawn": "",
"addWatermark": "Add hozzá, hogy \"Excalidraw-val készült\"",
"handDrawn": "Kézzel rajzolt",
"normal": "Normál",
"code": "Code",
"small": "Kicsi",
"medium": "Közepes",
"large": "Nagy",
"veryLarge": "",
"veryLarge": "Nagyon nagy",
"solid": "Kitöltött",
"hachure": "Vonalkázott",
"crossHatch": "",
"crossHatch": "Keresztcsíkozott",
"thin": "Vékony",
"bold": "Félkövér",
"left": "Bal",
"center": "",
"right": "",
"extraBold": "",
"center": "Közép",
"right": "Jobb",
"extraBold": "Extra Félkövér",
"architect": "Tervezői",
"artist": "Művészi",
"cartoonist": "Karikatúrás",
"fileTitle": "",
"fileTitle": "Fájl címe",
"colorPicker": "Színválasztó",
"canvasBackground": "Vászon háttérszíne",
"drawingCanvas": "",
"drawingCanvas": "Rajzvászon",
"layers": "Rétegek",
"actions": "Műveletek",
"language": "Nyelv",
"createRoom": "Élő együttmüködés megosztása",
"duplicateSelection": "",
"untitled": "",
"duplicateSelection": "Duplikálás",
"untitled": "Névtelen",
"name": "Név",
"yourName": "",
"madeWithExcalidraw": "",
"group": "",
"ungroup": "",
"collaborators": "",
"toggleGridMode": "",
"toggleStats": "",
"addToLibrary": "",
"removeFromLibrary": "",
"libraryLoadingMessage": "",
"libraries": "",
"loadingScene": "",
"align": "",
"alignTop": "",
"alignBottom": "",
"alignLeft": "",
"alignRight": "",
"centerVertically": "",
"centerHorizontally": "",
"distributeHorizontally": "",
"distributeVertically": ""
"yourName": "Neved",
"madeWithExcalidraw": "Excalidraw-val készült",
"group": "Csoportosítás",
"ungroup": "Csoportbontás",
"collaborators": "Közreműködők",
"gridMode": "",
"addToLibrary": "Hozzáadás a könyvtárhoz",
"removeFromLibrary": "Eltávólítás a könyvtárból",
"libraryLoadingMessage": "Könyvtár betöltése...",
"libraries": "Könyvtárak böngészése",
"loadingScene": "Jelenet betöltése...",
"align": "Igazítás",
"alignTop": "Felülre igazítás",
"alignBottom": "Alulra igazítás",
"alignLeft": "Balra igazítás",
"alignRight": "Jobbra igazítás",
"centerVertically": "Függőlegesen középre igazított",
"centerHorizontally": "Vízszintesen középre igazított",
"distributeHorizontally": "Vízszintes elosztás",
"distributeVertically": "Függőleges elosztás"
},
"buttons": {
"clearReset": "Vászon törlése",
@@ -100,13 +99,13 @@
"exportToSvg": "Exportálás SVG-be",
"copyToClipboard": "Vágólapra másolás",
"copyPngToClipboard": "PNG másolása a vágólapra",
"scale": "",
"scale": "Nagyítás",
"save": "Mentés",
"saveAs": "",
"saveAs": "Mentés másként",
"load": "Betöltés",
"getShareableLink": "Megosztható link létrehozása",
"close": "Bezárás",
"selectLanguage": "",
"selectLanguage": "Nyelv kiválasztása",
"scrollBackToContent": "Visszagörgetés a tartalomhoz",
"zoomIn": "Nagyítás",
"zoomOut": "Kicsinyítés",
@@ -118,37 +117,38 @@
"redo": "Újra végrehajtás",
"roomDialog": "Élő együttműködés indítása",
"createNewRoom": "Új szoba létrehozása",
"toggleFullScreen": "",
"toggleDarkMode": "",
"toggleZenMode": "",
"exitZenMode": ""
"fullScreen": "",
"darkMode": "",
"lightMode": "",
"zenMode": "",
"exitZenMode": "Zen mód elhagyása"
},
"alerts": {
"clearReset": "Ez a művelet törli a vászont. Biztos benne?",
"couldNotCreateShareableLink": "Nem sikerült megosztható linket létrehozni.",
"couldNotCreateShareableLinkTooBig": "",
"couldNotLoadInvalidFile": "",
"couldNotCreateShareableLinkTooBig": "Nem sikerült megosztható linket látrehozni: túl nagy a jelenet",
"couldNotLoadInvalidFile": "Nem sikerült betölteni a helytelen fájlt",
"importBackendFailed": "Nem sikerült betölteni a szerverről.",
"cannotExportEmptyCanvas": "Üres vászont nem lehet exportálni.",
"couldNotCopyToClipboard": "Nem sikerült vágólapra menteni. Próbálja meg Chrome böngészővel.",
"decryptFailed": "Nem sikerült dekódolni az adatot.",
"decryptFailed": "Nem sikerült visszafejteni a titkosított adatot.",
"uploadedSecurly": "A feltöltést végpontok közötti titkosítással biztosítottuk, ami azt jelenti, hogy az Excalidraw szerver és harmadik felek nem tudják elolvasni a feltöltés tartalmát.",
"loadSceneOverridePrompt": "",
"errorLoadingLibrary": "",
"confirmAddLibrary": "",
"loadSceneOverridePrompt": "A betöltött külső rajz felül fogja írnia meglévőt. Szeretnéd folytatni?",
"errorLoadingLibrary": "Hibába ütközött a harmarmadik féltől származó könyvtár betöltése.",
"confirmAddLibrary": "Ez a művelet {{numShapes}} formát fog hozzáadni a könyvtáradhoz. Biztos vagy benne?",
"imageDoesNotContainScene": "",
"cannotRestoreFromImage": ""
},
"toolBar": {
"selection": "Kiválasztás",
"draw": "",
"draw": "Szabadkézi rajz",
"rectangle": "Téglalap",
"diamond": "Rombusz",
"ellipse": "Ellipszis",
"arrow": "Nyíl",
"line": "Vonal",
"text": "Szöveg",
"library": "",
"library": "Könyvtár",
"lock": "Rajzolás után az aktív eszközt tartsa kiválasztva"
},
"headings": {
@@ -158,19 +158,20 @@
},
"hints": {
"linearElement": "Kattintson a több pont elindításához, húzza az egyenes vonalhoz",
"freeDraw": "",
"text": "",
"freeDraw": "Kattints és húzd, majd engedd el, amikor végeztél",
"text": "Tipp: A kiválasztó eszközzel bárhol létrehozhatsz szöveget dupla kattintással",
"linearElementMulti": "Kattintson az utolsó pontra, vagy nyomja meg az Escape vagy az Enter billentyűt a befejezéshez",
"lockAngle": "",
"resize": "",
"rotate": "A SHIFT billentyű lenyomva tartásával korlátozhatja a szögek illesztését",
"lineEditor_info": "",
"lineEditor_pointSelected": "",
"lineEditor_nothingSelected": ""
"lineEditor_info": "Kattints duplán, vagy nyomj entert a pontok szerkesztéséhez",
"lineEditor_pointSelected": "Nyomd meg a delete gombot a pont eltávolításához, Ctrl vagy Cmd + D-t a duplikáláshoz, vagy húzva mozgasd",
"lineEditor_nothingSelected": "Válassz ki egy pontot a mozgatáshoz vagy törtléshez, vagy az Alt lenyomása mellett kattintva hozz létre új pontokat"
},
"canvasError": {
"cannotShowPreview": "",
"canvasTooBig": "",
"canvasTooBigTip": ""
"cannotShowPreview": "Előnézet nem jeleníthető meg",
"canvasTooBig": "A vászon talán túl nagy.",
"canvasTooBigTip": "Tipp: próbáld meg a legtávolabbi elemeket közelebb mozgazni egy máshoz."
},
"errorSplash": {
"headingMain_pre": "Hiba történt. Próbálja ",
@@ -192,43 +193,43 @@
"button_stopSession": "Munkamenet leállítása",
"desc_inProgressIntro": "Az élő együttműködési munkamenet folyamatban van.",
"desc_shareLink": "Ossza meg ezt a linket bárkivel, akivel együtt szeretne működni:",
"desc_exitSession": ""
"desc_exitSession": "Az munkamenet leállítása kilépteti önt a szobából, de folytathatja a munkát a saját gépén. Vegye figyelembe, hogy ez nem érinti más emberek munkáját és ők továbbra is együttműködhetnek a saját változatukon."
},
"errorDialog": {
"title": ""
"title": "Hiba"
},
"shortcutsDialog": {
"title": "",
"shapes": "",
"or": "",
"click": "",
"drag": "",
"curvedArrow": "",
"curvedLine": "",
"editor": "",
"view": "",
"blog": "",
"howto": "",
"github": "",
"textNewLine": "",
"textFinish": "",
"title": "Gyorsbillentyűk",
"shapes": "Formák",
"or": "vagy",
"click": "klikk",
"drag": "húzd",
"curvedArrow": "Ívelt nyíl",
"curvedLine": "Ívelt vonal",
"editor": "Szerkesztő",
"view": "Nézet",
"blog": "Olvasd a blogunkat",
"howto": "Kövesd az útmutatóinkat",
"github": "Hibát találtál? Küld be",
"textNewLine": "Új sor hozzáadása (szöveg)",
"textFinish": "Szerkesztés befejezése (szöveg)",
"zoomToFit": "",
"zoomToSelection": "",
"zoomToSelection": "Kijelölésre nagyítás",
"preventBinding": ""
},
"encrypted": {
"tooltip": ""
},
"stats": {
"angle": "",
"element": "",
"elements": "",
"height": "",
"angle": "Szög",
"element": "Elem",
"elements": "Elemek",
"height": "Magasság",
"scene": "",
"selected": "",
"storage": "",
"selected": "Kiválasztott",
"storage": "Tárhely",
"title": "",
"total": "",
"width": ""
"total": "Összesen",
"width": "Szélesség"
}
}
+9 -8
View File
@@ -37,7 +37,7 @@
"fontSize": "Ukuran font",
"fontFamily": "Jenis font",
"onlySelected": "Hanya yang Dipilih",
"withBackground": "Dengan Latar",
"withBackground": "Dengan latar",
"exportEmbedScene": "Sematkan pemandangan ke dalam file yang diekspor",
"exportEmbedScene_details": "Data pemandangan akan disimpan dalam file PNG/SVG yang diekspor, sehingga pemandangan itu dapat dipulihkan darinya.\nAkan membesarkan ukuran file yang diekspor.",
"addWatermark": "Tambahkan \"Dibuat dengan Excalidraw\"",
@@ -76,8 +76,7 @@
"group": "Kelompokan pilihan",
"ungroup": "Pisahkan pilihan",
"collaborators": "Kolaborator",
"toggleGridMode": "Aktifkan/Matikan mode kisi",
"toggleStats": "Aktifkan statistik untuk nerd",
"gridMode": "Mode grid",
"addToLibrary": "Tambahkan ke pustaka",
"removeFromLibrary": "Hapus dari pustaka",
"libraryLoadingMessage": "Memuat pustaka...",
@@ -118,9 +117,10 @@
"redo": "Ulangi",
"roomDialog": "Mulai kolaborasi langsung",
"createNewRoom": "Buat ruang baru",
"toggleFullScreen": "Beralih ke layar penuh",
"toggleDarkMode": "Aktifkan/Matikan mode gelap",
"toggleZenMode": "Aktifkan/Matikan mode zen",
"fullScreen": "Layar penuh",
"darkMode": "Mode gelap",
"lightMode": "Mode terang",
"zenMode": "Mode zen",
"exitZenMode": "Keluar dari mode zen"
},
"alerts": {
@@ -136,7 +136,7 @@
"loadSceneOverridePrompt": "Memuat gambar external akan mengganti konten Anda yang ada. Apakah Anda ingin melanjutkan?",
"errorLoadingLibrary": "Terdapat kesalahan dalam memuat pustaka pihak ketiga.",
"confirmAddLibrary": "Ini akan menambahkan {{numShapes}} bentuk ke pustaka Anda. Anda yakin?",
"imageDoesNotContainScene": "File gambar tidak berisi data pemandangan. Apa Anda sudah aktifkan ini selama ekspor?",
"imageDoesNotContainScene": "Mengimpor gambar tidak didukung saat ini.\n\nApakah Anda ingin impor pemandangan? Gambar ini tidak berisi data pemandangan. Sudah ka Anda aktifkan ini ketika ekspor?",
"cannotRestoreFromImage": "Pemandangan tidak dapat dipulihkan dari file gambar ini"
},
"toolBar": {
@@ -161,6 +161,7 @@
"freeDraw": "Klik dan seret, lepaskan jika Anda selesai",
"text": "Tip: Anda juga dapat menambahkan teks dengan klik ganda di mana saja dengan alat pemilihan",
"linearElementMulti": "Klik pada titik akhir atau tekan Escape atau Enter untuk menyelesaikan",
"lockAngle": "Anda dapat menjaga sudut dengan menahan SHIFT",
"resize": "Anda dapat menjaga proposi dengan menekan SHIFT sambil mengubah ukuran,\ntekan AlT untuk mengubah ukuran dari tengah",
"rotate": "Anda dapat menjaga sudut dengan menahan SHIFT sambil memutar",
"lineEditor_info": "Klik ganda atau tekan Enter untuk mengedit titik",
@@ -213,7 +214,7 @@
"textNewLine": "Tambahkan baris baru (teks)",
"textFinish": "Selesai mengedit (teks)",
"zoomToFit": "Perbesar agar sesuai dengan semua elemen",
"zoomToSelection": "",
"zoomToSelection": "Perbesar ke seleksi",
"preventBinding": "Cegah pengikatan panah"
},
"encrypted": {
+8 -7
View File
@@ -37,7 +37,7 @@
"fontSize": "Dimensione carattere",
"fontFamily": "Carattere",
"onlySelected": "Solo selezionati",
"withBackground": "Con Sfondo",
"withBackground": "Con sfondo",
"exportEmbedScene": "Incorpora la scena nel file esportato",
"exportEmbedScene_details": "I dati della scena saranno salvati nel file PNG/SVG esportato in modo che la scena possa essere ripristinata da esso.\nQuesto aumenterà la dimensione del file esportato.",
"addWatermark": "Aggiungi \"Creato con Excalidraw\"",
@@ -76,8 +76,7 @@
"group": "Crea gruppo da selezione",
"ungroup": "Dividi gruppo da selezione",
"collaborators": "Collaboratori",
"toggleGridMode": "Attiva/disattiva modalità griglia",
"toggleStats": "Attiva/disattiva statistiche per nerd",
"gridMode": "Modalità griglia",
"addToLibrary": "Aggiungi alla biblioteca",
"removeFromLibrary": "Rimuovi dalla biblioteca",
"libraryLoadingMessage": "Caricamento della biblioteca...",
@@ -118,9 +117,10 @@
"redo": "Ripeti",
"roomDialog": "Inizia collaborazione in diretta",
"createNewRoom": "Crea nuova stanza",
"toggleFullScreen": "Attiva/Disattiva schermo intero",
"toggleDarkMode": "Attiva tema scuro",
"toggleZenMode": "Attiva/Disattiva modalità zen",
"fullScreen": "Schermo intero",
"darkMode": "Tema scuro",
"lightMode": "Tema chiaro",
"zenMode": "Modalità Zen",
"exitZenMode": "Uscire dalla modalità zen"
},
"alerts": {
@@ -136,7 +136,7 @@
"loadSceneOverridePrompt": "Se carichi questo disegno esterno, sostituirà quello che hai. Vuoi continuare?",
"errorLoadingLibrary": "Si è verificato un errore nel caricamento della libreria di terze parti.",
"confirmAddLibrary": "Questo aggiungerà {{numShapes}} forma(e) alla tua biblioteca. Sei sicuro?",
"imageDoesNotContainScene": "Il file immagine non contiene dati di scena. È stato abilitato durante l'esportazione?",
"imageDoesNotContainScene": "L'importazione di immagini al momento non è supportata.\n\nVuoi importare una scena? Questa immagine non sembra contenere alcun dato di scena. Hai abilitato questa opzione durante l'esportazione?",
"cannotRestoreFromImage": "Impossibile ripristinare la scena da questo file immagine"
},
"toolBar": {
@@ -161,6 +161,7 @@
"freeDraw": "Clicca e trascina, rilascia quando avrai finito",
"text": "Suggerimento: puoi anche aggiungere del testo facendo doppio clic ovunque con lo strumento di selezione",
"linearElementMulti": "Clicca sull'ultimo punto o premi Esc o Invio per finire",
"lockAngle": "Puoi limitare l'angolo tenendo premuto SHIFT",
"resize": "Per vincolare le proporzioni, tenir premuto MAIUSC durante il ridimensionamento;\nper ridimensionare dal centro, tenir premuto ALT",
"rotate": "Puoi mantenere gli angoli tenendo premuto SHIFT durante la rotazione",
"lineEditor_info": "Fai doppio click o premi invio per modificare i punti",
+8 -7
View File
@@ -37,7 +37,7 @@
"fontSize": "フォントの大きさ",
"fontFamily": "フォントの種類",
"onlySelected": "選択中のみ",
"withBackground": "背景を含める",
"withBackground": "",
"exportEmbedScene": "エクスポートされたファイルにシーンを埋め込みます",
"exportEmbedScene_details": "シーンデータはエクスポートされたPNG/SVGファイルに保存され、シーンを復元することができます。\nエクスポートされたファイルのサイズは増加します。",
"addWatermark": "\"Made with Excalidraw\"と表示",
@@ -76,8 +76,7 @@
"group": "図形のグループ化",
"ungroup": "グループ化を解除",
"collaborators": "共同編集者",
"toggleGridMode": "グリッドモードに切り替える",
"toggleStats": "",
"gridMode": "",
"addToLibrary": "ライブラリに追加",
"removeFromLibrary": "ライブラリから削除",
"libraryLoadingMessage": "ライブラリを読み込み中...",
@@ -118,9 +117,10 @@
"redo": "やり直し",
"roomDialog": "共同編集を開始する",
"createNewRoom": "新しい部屋を作成する",
"toggleFullScreen": "全画面表示に切り替える",
"toggleDarkMode": "ダークモードに切り替える",
"toggleZenMode": "集中モードに切り替える",
"fullScreen": "",
"darkMode": "",
"lightMode": "",
"zenMode": "",
"exitZenMode": "集中モードをやめる"
},
"alerts": {
@@ -136,7 +136,7 @@
"loadSceneOverridePrompt": "外部図面を読み込むと、既存のコンテンツが置き換わります。続行しますか?",
"errorLoadingLibrary": "サードパーティライブラリの読み込み中にエラーが発生しました。",
"confirmAddLibrary": "{{numShapes}} 個の図形をライブラリに追加します。よろしいですか?",
"imageDoesNotContainScene": "画像ファイルにシーンデータが含まれていません。エクスポート中にこれを有効にしましたか?",
"imageDoesNotContainScene": "",
"cannotRestoreFromImage": "このイメージファイルからシーンを復元できませんでした"
},
"toolBar": {
@@ -161,6 +161,7 @@
"freeDraw": "クリックしてドラッグします。離すと終了します",
"text": "ヒント: 選択ツールを使用して任意の場所をダブルクリックしてテキストを追加することもできます",
"linearElementMulti": "最後のポイントをクリックするか、エスケープまたはEnterを押して終了します",
"lockAngle": "",
"resize": "サイズを変更中にSHIFTを押しすと比率を制御できます。Altを押すと中央からサイズを変更できます。",
"rotate": "回転中にSHIFT キーを押すと角度を制限することができます",
"lineEditor_info": "ポイントを編集するには、ダブルクリックまたはEnterキーを押します",
+11 -10
View File
@@ -4,7 +4,7 @@
"selectAll": "전체 선택",
"multiSelect": "선택 영역에 추가하기",
"moveCanvas": "캔버스 이동",
"cut": "",
"cut": "잘라내기",
"copy": "복사하기",
"copyAsPng": "클립보드로 PNG 이미지 복사",
"copyAsSvg": "클립보드로 SVG 이미지 복사",
@@ -29,15 +29,15 @@
"edges": "가장자리",
"sharp": "선명하게",
"round": "둥글게",
"arrowheads": "",
"arrowhead_none": "",
"arrowhead_arrow": "",
"arrowheads": "화살표 모양",
"arrowhead_none": "없음",
"arrowhead_arrow": "화살표",
"arrowhead_bar": "",
"arrowhead_dot": "",
"fontSize": "폰트 크기",
"fontFamily": "폰트 스타일",
"onlySelected": "선택한 항목만",
"withBackground": "배경 포함",
"withBackground": "",
"exportEmbedScene": "",
"exportEmbedScene_details": "",
"addWatermark": "\"Made with Excalidraw\" 추가",
@@ -76,8 +76,7 @@
"group": "그룹 생성",
"ungroup": "그룹 해제",
"collaborators": "공동 작업자",
"toggleGridMode": "격자 모드 켜기/끄기",
"toggleStats": "",
"gridMode": "",
"addToLibrary": "라이브러리에 추가",
"removeFromLibrary": "라이브러리에서 제거",
"libraryLoadingMessage": "라이브러리 불러오는 중...",
@@ -118,9 +117,10 @@
"redo": "다시 실행",
"roomDialog": "실시간 협업 시작하기",
"createNewRoom": "방 만들기",
"toggleFullScreen": "전체화면",
"toggleDarkMode": "다크 모드 켜기/끄기",
"toggleZenMode": "젠 모드 켜기/끄기",
"fullScreen": "",
"darkMode": "",
"lightMode": "",
"zenMode": "",
"exitZenMode": "젠 모드 종료하기"
},
"alerts": {
@@ -161,6 +161,7 @@
"freeDraw": "클릭 후 드래그하세요. 완료되면 놓으세요.",
"text": "",
"linearElementMulti": "마지막 지점을 클릭하거나 Esc 또는 Enter 키를 눌러 완료하세요.",
"lockAngle": "",
"resize": "",
"rotate": "SHIFT 키를 누르면서 회전하면 각도를 제한할 수 있습니다.",
"lineEditor_info": "포인트를 수정하려면 두 번 클릭하거나 엔터 키를 누르세요.",
+8 -7
View File
@@ -37,7 +37,7 @@
"fontSize": "စာလုံးအရွယ်",
"fontFamily": "စာလုံးပုံစံ",
"onlySelected": "ရွေးထားသလောက်",
"withBackground": "နောက်ခံပါထည့်",
"withBackground": "",
"exportEmbedScene": "မြင်ကွင်းပါမြှုပ်နှံ၍ထုတ်ပါ",
"exportEmbedScene_details": "ထုတ်ယူလိုက်သော PNG/SVG ထဲမြင်ကွင်းအချက်အလက်များပါဝင်သဖြင့် ပြန်လည်ရယူနိုင်သော်လည်း ဖိုင်အရွယ်အစားကြီးပါမည်။",
"addWatermark": "\"Excalidraw ဖြင့်ဖန်တီးသည်။\" စာသားထည့်",
@@ -76,8 +76,7 @@
"group": "အုပ်စုဖွဲ့",
"ungroup": "အုပ်စုဖျက်သိမ်း",
"collaborators": "ပူးပေါင်းပါဝင်သူများ",
"toggleGridMode": "ဇယားကွက်ဖော်/ဖျောက်",
"toggleStats": "",
"gridMode": "",
"addToLibrary": "မှတ်တမ်းတင်",
"removeFromLibrary": "မှတ်တမ်းမှထုတ်",
"libraryLoadingMessage": "မှတ်တမ်းအား တင်သွင်းနေသည်...",
@@ -118,9 +117,10 @@
"redo": "ထပ်လုပ်",
"roomDialog": "တိုက်ရိုက်ပူးပေါင်းမှုစတင်",
"createNewRoom": "အခန်းသစ်ဖွဲ့",
"toggleFullScreen": "မြင်ကွင်းကျယ်ဖွင့်/ပိတ်",
"toggleDarkMode": "အလင်း/အမှောင်",
"toggleZenMode": "ဇင်မြင်ကွင်းဖွင့်/ပိတ်",
"fullScreen": "",
"darkMode": "",
"lightMode": "",
"zenMode": "",
"exitZenMode": "ဇင်မြင်ကွင်းမှထွက်"
},
"alerts": {
@@ -136,7 +136,7 @@
"loadSceneOverridePrompt": "လက်ရှိရေးဆွဲထားသမျှအား ပြင်ပမှတင်သွင်းသောပုံနှင့်အစားထိုးပါမည်။ ဆက်လက်ဆောင်ရွက်လိုပါသလား။",
"errorLoadingLibrary": "ပြင်ပမှမှတ်တမ်းအားတင်သွင်းရာတွင်အမှားအယွင်းရှိနေသည်။",
"confirmAddLibrary": "{{numShapes}} ခုသောပုံသဏ္ဌာန်အားမှတ်တမ်းတင်ပါမည်။ အတည်ပြုပါ။",
"imageDoesNotContainScene": "ပုံတွင် မြင်ကွင်းအချက်အလက်များမပါဝင်ပါ။ ပုံထုတ်ယူချိန်တွင်ထည့်သွင်းခဲ့ပါသလား။",
"imageDoesNotContainScene": "",
"cannotRestoreFromImage": "ဤပုံဖြင့်မြင်ကွင်းပြန်လည်မရယူနိုင်ပါ။"
},
"toolBar": {
@@ -161,6 +161,7 @@
"freeDraw": "ကလစ်နှိပ်၍ တရွတ်ဆွဲပါ၊ ပြီးလျှင်လွှတ်ပါ။",
"text": "မှတ်ချက်။ ။မည်သည့်ကိရိယာရွေးထားသည်ဖြစ်စေ ကလစ်နှစ်ချက်နှိပ်၍စာသားထည့်နိုင်သည်",
"linearElementMulti": "နောက်ဆုံးအမှတ်ပေါ်တွင်ကလစ်နှိပ်ခြင်း၊ Escape (သို့) Enter နှိပ်ခြင်းတို့ဖြင့်အဆုံးသတ်နိုင်",
"lockAngle": "",
"resize": "အချိုးအစားကန့်သတ်ရန် Shift နှင့် ဗဟိုမှချိန်ညှိရန် Alt တို့ကိုနှိပ်ထားနိုင်သည်",
"rotate": "Shift ကိုနှိပ်ထားခြင်းဖြင့် ထောင့်အလိုက်လှည့်နိုင်သည်",
"lineEditor_info": "အမှတ်များပြင်ဆင်သတ်မှတ်ရင် ကလစ်နှစ်ချက် (သို့) Enter ကိုနှိပ်ပါ",
+8 -7
View File
@@ -37,7 +37,7 @@
"fontSize": "Skriftstørrelse",
"fontFamily": "Fontfamilie",
"onlySelected": "Kun valgte",
"withBackground": "Inkluder bakgrunn",
"withBackground": "Med bakgrunn",
"exportEmbedScene": "Bygg inn scenen i den eksporterte filen",
"exportEmbedScene_details": "Scenedata vil bli lagret i den eksporterte PNG/SVG-filen, slik at scenen kan gjenopprettes fra den.\nDet vil øke den eksporterte filstørrelsen.",
"addWatermark": "Legg til \"Laget med Excalidraw\"",
@@ -76,8 +76,7 @@
"group": "Gruppér utvalg",
"ungroup": "Avgruppér utvalg",
"collaborators": "Samarbeidspartnere",
"toggleGridMode": "Slå av/på rutenett",
"toggleStats": "Skru av/på statistikk for nerder",
"gridMode": "Rutevisning",
"addToLibrary": "Legg til i bibliotek",
"removeFromLibrary": "Fjern fra bibliotek",
"libraryLoadingMessage": "Laster bibliotek...",
@@ -118,9 +117,10 @@
"redo": "Gjør om",
"roomDialog": "Start sanntids-samarbeid",
"createNewRoom": "Opprett et nytt rom",
"toggleFullScreen": "Skru fullskjerm av/på",
"toggleDarkMode": "Skru mørk modus av/på",
"toggleZenMode": "Slå av/på zen-modus",
"fullScreen": "Fullskjerm",
"darkMode": "Mørk modus",
"lightMode": "Lys modus",
"zenMode": "Zen-modus",
"exitZenMode": "Avslutt zen-modus"
},
"alerts": {
@@ -136,7 +136,7 @@
"loadSceneOverridePrompt": "Å laste inn ekstern tegning vil erstatte det eksisterende innholdet. Ønsker du å fortsette?",
"errorLoadingLibrary": "Det oppstod en feil under lasting av tredjepartsbiblioteket.",
"confirmAddLibrary": "Dette vil legge til {{numShapes}} figur(er) i biblioteket ditt. Er du sikker?",
"imageDoesNotContainScene": "Bildefilen inneholder ikke scenedata. Har du aktivert dette under eksport?",
"imageDoesNotContainScene": "Importering av bilder støttes ikke for øyeblikket.\n\nVil du importere en scene? Dette bildet ser ikke ut til å inneholde noen scene-data. Har du aktivert dette under eksporten?",
"cannotRestoreFromImage": "Scenen kunne ikke gjenopprettes fra denne bildefilen"
},
"toolBar": {
@@ -161,6 +161,7 @@
"freeDraw": "Klikk og dra, slipp når du er ferdig",
"text": "Tips: du kan også legge til tekst ved å dobbeltklikke hvor som helst med utvalgsverktøyet",
"linearElementMulti": "Klikk på siste punkt eller trykk Escape eller Enter for å fullføre",
"lockAngle": "Du kan låse vinkelen ved å holde nede SHIFT",
"resize": "Du kan beholde forholdet ved å trykke SHIFT mens du endrer størrelse,\ntrykk ALT for å endre størrelsen fra midten",
"rotate": "Du kan låse vinklene ved å holde SHIFT mens du roterer",
"lineEditor_info": "Dobbeltklikk eller trykk Enter for å redigere punkter",
+47 -46
View File
@@ -4,12 +4,12 @@
"selectAll": "Alles selecteren",
"multiSelect": "Voeg element toe aan selectie",
"moveCanvas": "Canvas verplaatsen",
"cut": "",
"cut": "Knip",
"copy": "Kopiëren",
"copyAsPng": "Kopieer als PNG",
"copyAsSvg": "Kopieer als SVG",
"copyAsSvg": "Kopieer naar klembord als SVG",
"bringForward": "Breng naar voren",
"sendToBack": "Breng naar achtergrond",
"sendToBack": "Stuur naar achtergrond",
"bringToFront": "Breng naar voorgrond",
"sendBackward": "Breng naar achter",
"delete": "Verwijderen",
@@ -29,17 +29,17 @@
"edges": "Randen",
"sharp": "Hoekig",
"round": "Rond",
"arrowheads": "",
"arrowhead_none": "",
"arrowhead_arrow": "",
"arrowhead_bar": "",
"arrowhead_dot": "",
"arrowheads": "Pijlpunten",
"arrowhead_none": "Geen",
"arrowhead_arrow": "Pijl",
"arrowhead_bar": "Balk",
"arrowhead_dot": "Punt",
"fontSize": "Tekstgrootte",
"fontFamily": "Lettertype",
"onlySelected": "Enkel geselecteerde",
"withBackground": "Met achtergrond",
"exportEmbedScene": "",
"exportEmbedScene_details": "",
"exportEmbedScene": "Scène in geëxporteerd bestand invoegen",
"exportEmbedScene_details": "Scènegegevens worden in het geëxporteerde PNG/SVG-bestand opgeslagen zodat de scène kan worden hersteld.\nDe grootte van de geëxporteerde bestanden zal toenemen.",
"addWatermark": "Voeg \"Gemaakt met Excalidraw\" toe",
"handDrawn": "Handgetekend",
"normal": "Normaal",
@@ -60,7 +60,7 @@
"architect": "Architect",
"artist": "Artiest",
"cartoonist": "Cartoonist",
"fileTitle": "",
"fileTitle": "Bestandsnaam",
"colorPicker": "Kleurenkiezer",
"canvasBackground": "Canvas achtergrond",
"drawingCanvas": "Canvas",
@@ -69,29 +69,28 @@
"language": "Taal",
"createRoom": "Deel een live-samenwerkingssessie",
"duplicateSelection": "Dupliceer",
"untitled": "",
"untitled": "Naamloos",
"name": "Naam",
"yourName": "Jouw naam",
"madeWithExcalidraw": "Gemaakt met Excalidraw",
"group": "Groeperen",
"ungroup": "Groep opheffen",
"collaborators": "Deelnemers",
"toggleGridMode": "Rasterlijnen in-/uitschakelen",
"toggleStats": "",
"gridMode": "Rasterweergave",
"addToLibrary": "Voeg toe aan bibliotheek",
"removeFromLibrary": "Verwijder uit bibliotheek",
"libraryLoadingMessage": "Bibliotheek laden...",
"libraries": "",
"libraries": "Blader door bibliotheken",
"loadingScene": "Scène laden...",
"align": "",
"alignTop": "",
"alignBottom": "",
"alignLeft": "",
"alignRight": "",
"centerVertically": "",
"centerHorizontally": "",
"distributeHorizontally": "",
"distributeVertically": ""
"align": "Uitlijnen",
"alignTop": "Boven uitlijnen",
"alignBottom": "Onder uitlijnen",
"alignLeft": "Links uitlijnen",
"alignRight": "Rechts uitlijnen",
"centerVertically": "Verticaal Centreren",
"centerHorizontally": "Horizontaal Centreren",
"distributeHorizontally": "Horizontaal verspreiden",
"distributeVertically": "Verticaal distribueren"
},
"buttons": {
"clearReset": "Canvas opnieuw instellen",
@@ -118,15 +117,16 @@
"redo": "Herstel ongedaan maken",
"roomDialog": "Live-samenwerkingssessie starten",
"createNewRoom": "Creëer live-samenwerkingssessie",
"toggleFullScreen": "Volledig scherm in-/uitschakelen",
"toggleDarkMode": "Donkere modus in-/uitschakelen",
"toggleZenMode": "Zen modus in-/uitschakelen",
"fullScreen": "Volledig scherm",
"darkMode": "Donkere modus",
"lightMode": "Lichte modus",
"zenMode": "Zen modus",
"exitZenMode": "Verlaat zen modus"
},
"alerts": {
"clearReset": "Dit zal het hele canvas verwijderen. Weet je het zeker?",
"couldNotCreateShareableLink": "Kon geen deelbare link aanmaken.",
"couldNotCreateShareableLinkTooBig": "",
"couldNotCreateShareableLinkTooBig": "Kan geen deelbare link aanmaken: de scène is te groot",
"couldNotLoadInvalidFile": "Kan ongeldig bestand niet laden",
"importBackendFailed": "Importeren vanuit backend mislukt.",
"cannotExportEmptyCanvas": "Kan geen leeg canvas exporteren.",
@@ -136,8 +136,8 @@
"loadSceneOverridePrompt": "Het laden van externe tekening zal uw bestaande inhoud vervangen. Wil je doorgaan?",
"errorLoadingLibrary": "Bij het laden van de externe bibliotheek is een fout opgetreden.",
"confirmAddLibrary": "Hiermee worden {{numShapes}} vorm(n) aan uw bibliotheek toegevoegd. Ben je het zeker?",
"imageDoesNotContainScene": "",
"cannotRestoreFromImage": ""
"imageDoesNotContainScene": "Afbeeldingen importeren wordt op dit moment niet ondersteund.\n\nWil je een scène importeren? Deze afbeelding lijkt geen scène gegevens te bevatten. Heb je dit geactiveerd tijdens het exporteren?",
"cannotRestoreFromImage": "Scène kan niet worden hersteld vanuit dit afbeeldingsbestand"
},
"toolBar": {
"selection": "Selectie",
@@ -161,6 +161,7 @@
"freeDraw": "Klik en sleep, laat los als je klaar bent",
"text": "Tip: je kunt tekst toevoegen door ergens dubbel te klikken met de selectietool",
"linearElementMulti": "Klik op het laatste punt of druk op Escape of Enter om te stoppen",
"lockAngle": "Je kunt de hoek beperken door SHIFT ingedrukt te houden",
"resize": "Houd tijdens het vergroten SHIFT ingedrukt om verhoudingen te behouden,\ngebruik ALT om vanuit het midden te vergroten/verkleinen",
"rotate": "Je kan hoeken beperken door SHIFT ingedrukt te houden wanneer je draait",
"lineEditor_info": "Dubbelklik of druk op Enter om punten te bewerken",
@@ -168,9 +169,9 @@
"lineEditor_nothingSelected": "Selecteer een punt om te verplaatsen of te verwijderen, of houd Alt ingedrukt en klik om nieuwe punten toe te voegen"
},
"canvasError": {
"cannotShowPreview": "",
"canvasTooBig": "",
"canvasTooBigTip": ""
"cannotShowPreview": "Kan voorbeeld niet tonen",
"canvasTooBig": "Het canvas is mogelijk te groot.",
"canvasTooBigTip": "Tip: beweeg de verste elementen iets dichter bij elkaar."
},
"errorSplash": {
"headingMain_pre": "Fout opgetreden. Probeer ",
@@ -192,7 +193,7 @@
"button_stopSession": "Sessie afbreken",
"desc_inProgressIntro": "De live-samenwerkingssessie is nu gestart.",
"desc_shareLink": "Deel deze link met iedereen waarmee je wil samenwerken:",
"desc_exitSession": ""
"desc_exitSession": "Het stoppen van de sessie zal je loskoppelen van de kamer, maar je kunt lokaal doorwerken met de scène.\nPas op: dit heeft geen invloed op andere mensen en dat zij nog steeds in staat zullen zijn om samen te werken aan hun versie."
},
"errorDialog": {
"title": "Fout"
@@ -213,22 +214,22 @@
"textNewLine": "Nieuwe regel toevoegen (tekst)",
"textFinish": "Voltooi bewerken (tekst)",
"zoomToFit": "Zoom in op alle elementen",
"zoomToSelection": "",
"preventBinding": ""
"zoomToSelection": "Inzoomen op selectie",
"preventBinding": "Pijlbinding voorkomen"
},
"encrypted": {
"tooltip": "Je tekeningen zijn beveiligd met end-to-end encryptie, dus Excalidraw's servers zullen nooit zien wat je tekent."
},
"stats": {
"angle": "",
"element": "",
"elements": "",
"height": "",
"scene": "",
"selected": "",
"storage": "",
"title": "",
"total": "",
"width": ""
"angle": "Hoek",
"element": "Element",
"elements": "Elementen",
"height": "Hoogte",
"scene": "Scene",
"selected": "Geselecteerd",
"storage": "Opslag",
"title": "Statistieken voor nerds",
"total": "Totaal",
"width": "Breedte"
}
}
+44 -43
View File
@@ -4,7 +4,7 @@
"selectAll": "Vel alt",
"multiSelect": "Legg til element i utval",
"moveCanvas": "Flytt lerretet",
"cut": "",
"cut": "Klipp ut",
"copy": "Kopier",
"copyAsPng": "Kopier til utklippstavla som PNG",
"copyAsSvg": "Kopier til utklippstavla som SVG",
@@ -29,17 +29,17 @@
"edges": "Kanter",
"sharp": "Skarp",
"round": "Rund",
"arrowheads": "",
"arrowhead_none": "",
"arrowhead_arrow": "",
"arrowhead_bar": "",
"arrowhead_dot": "",
"arrowheads": "Pilhovud",
"arrowhead_none": "Ingen",
"arrowhead_arrow": "Pil",
"arrowhead_bar": "Stolpe",
"arrowhead_dot": "Prikk",
"fontSize": "Skriftstorleik",
"fontFamily": "Skrifttype",
"onlySelected": "Kun valde",
"withBackground": "Inkluder bakgrunn",
"exportEmbedScene": "",
"exportEmbedScene_details": "",
"withBackground": "Med bakgrunn",
"exportEmbedScene": "Bygg scena inn i eksportert fil",
"exportEmbedScene_details": "Scenedataa vert lagra i den eksporterte PNG- eller SVG-fila slik at scena kan bli gjenopprettast frå den. Dette vil auke eksportert filstorleik.",
"addWatermark": "Legg til «Laga med Excalidraw»",
"handDrawn": "Handteikna",
"normal": "Normal",
@@ -60,7 +60,7 @@
"architect": "Arkitekt",
"artist": "Kunstnar",
"cartoonist": "Teiknar",
"fileTitle": "",
"fileTitle": "Filnamn",
"colorPicker": "Fargeveljar",
"canvasBackground": "Lerretsbakgrunn",
"drawingCanvas": "Lerret",
@@ -69,29 +69,28 @@
"language": "Språk",
"createRoom": "Del ei sanntids-samarbeidsøkt",
"duplicateSelection": "Dupliser",
"untitled": "",
"untitled": "Utan namn",
"name": "Namn",
"yourName": "Namnet ditt",
"madeWithExcalidraw": "Laga med Excalidraw",
"group": "Grupper utval",
"ungroup": "Avgrupper utval",
"collaborators": "Samarbeidarar",
"toggleGridMode": "Sla på/av rutenett",
"toggleStats": "",
"gridMode": "",
"addToLibrary": "Legg til i bibliotek",
"removeFromLibrary": "Fjern frå bibliotek",
"libraryLoadingMessage": "Laster bibliotek...",
"libraries": "",
"libraries": "Blad gjennom bibliotek",
"loadingScene": "Laster scene...",
"align": "",
"alignTop": "",
"alignBottom": "",
"alignLeft": "",
"alignRight": "",
"centerVertically": "",
"centerHorizontally": "",
"distributeHorizontally": "",
"distributeVertically": ""
"align": "Juster",
"alignTop": "Juster til topp",
"alignBottom": "Juster til botn",
"alignLeft": "Juster til venstre",
"alignRight": "Juster til høgre",
"centerVertically": "Midtstill vertikalt",
"centerHorizontally": "Midtstill horisontalt",
"distributeHorizontally": "Sprei horisontalt",
"distributeVertically": "Sprei vertikalt"
},
"buttons": {
"clearReset": "Tilbakestill lerretet",
@@ -100,7 +99,7 @@
"exportToSvg": "Eksporter til SVG",
"copyToClipboard": "Kopier til utklippstavla",
"copyPngToClipboard": "Kopier PNG til utklippstavla",
"scale": "",
"scale": "Skaler",
"save": "Lagre",
"saveAs": "Lagre som",
"load": "Opne",
@@ -118,15 +117,16 @@
"redo": "Gjer om",
"roomDialog": "Start sanntids-samarbeid",
"createNewRoom": "Lag nytt rom",
"toggleFullScreen": "Slå på/av fullskjerm",
"toggleDarkMode": "Skru av/på skumringsmodus",
"toggleZenMode": "Slå på/av zen-modus",
"fullScreen": "",
"darkMode": "",
"lightMode": "",
"zenMode": "",
"exitZenMode": "Avslutt zen-modus"
},
"alerts": {
"clearReset": "Dette vil tømme lerretet. Er du sikker?",
"couldNotCreateShareableLink": "Kunne ikkje lage delingslenke.",
"couldNotCreateShareableLinkTooBig": "",
"couldNotCreateShareableLinkTooBig": "Kunne ikkje opprette deleleg lenke: scena er for stor",
"couldNotLoadInvalidFile": "Kunne ikkje laste inn ugyldig fil",
"importBackendFailed": "Importering av backend feila.",
"cannotExportEmptyCanvas": "Kan ikkje eksportere eit tomt lerret.",
@@ -137,7 +137,7 @@
"errorLoadingLibrary": "Det oppstod ein feil under lastinga av tredjepartsbibliotek.",
"confirmAddLibrary": "Dette vil legge til {{numShapes}} form(er) i biblioteket ditt. Er du sikker?",
"imageDoesNotContainScene": "",
"cannotRestoreFromImage": ""
"cannotRestoreFromImage": "Scena kunne ikkje gjenopprettast frå denne biletfila"
},
"toolBar": {
"selection": "Vel",
@@ -161,6 +161,7 @@
"freeDraw": "Klikk og drag, slepp når du er ferdig",
"text": "Tips: du kan òg leggje til tekst ved å dobbeltklikke kor som helst med utvalgsverktyet",
"linearElementMulti": "Klikk på siste punkt eller trykk Escape eller Enter for å fullføre",
"lockAngle": "",
"resize": "Du kan halde fram med forholdet ved å trykke SHIFT medan du endrar storleik,\ntrykk ALT for å endre storleiken frå midten",
"rotate": "Du kan låse vinklane ved å halde SHIFT medan du roterer",
"lineEditor_info": "Dobbeltklikk eller trykk Enter for å redigere punkt",
@@ -168,9 +169,9 @@
"lineEditor_nothingSelected": "Vel eit punkt å flytte eller fjerne, eller hald Alt og klikk for å legge til nye punkt"
},
"canvasError": {
"cannotShowPreview": "",
"canvasTooBig": "",
"canvasTooBigTip": ""
"cannotShowPreview": "Kan ikkje vise førehandsvising",
"canvasTooBig": "Lerretet er mogleg for stort.",
"canvasTooBigTip": "Tips: prøv å flytte elementa som er lengst frå kvarandre, litt nærare kvarandre."
},
"errorSplash": {
"headingMain_pre": "Ein feil oppstod. Prøv ",
@@ -213,22 +214,22 @@
"textNewLine": "Legg til ny linje (tekst)",
"textFinish": "Fullfør redigering (tekst)",
"zoomToFit": "Zoom for å sjå alle elementa",
"zoomToSelection": "",
"zoomToSelection": "Zoom til utval",
"preventBinding": "Hindre pilkobling"
},
"encrypted": {
"tooltip": "Teikningane dine er ende-til-ende-krypterte slik at Excalidraw sine serverar aldri får sjå dei."
},
"stats": {
"angle": "",
"element": "",
"elements": "",
"height": "",
"scene": "",
"selected": "",
"storage": "",
"title": "",
"total": "",
"width": ""
"angle": "Vinkel",
"element": "Element",
"elements": "Element",
"height": "Høgde",
"scene": "Scene",
"selected": "Valde",
"storage": "Lagring",
"title": "Statistikk for nerdar",
"total": "Totalt",
"width": "Breidde"
}
}
+22 -21
View File
@@ -1,33 +1,34 @@
{
"ar-SA": 89,
"bg-BG": 61,
"ca-ES": 81,
"de-DE": 99,
"el-GR": 95,
"ar-SA": 86,
"bg-BG": 60,
"ca-ES": 78,
"de-DE": 100,
"el-GR": 96,
"en": 100,
"es-ES": 81,
"fa-IR": 89,
"es-ES": 99,
"fa-IR": 86,
"fi-FI": 100,
"fr-FR": 100,
"he-IL": 69,
"he-IL": 96,
"hi-IN": 82,
"hu-HU": 44,
"id-ID": 99,
"hu-HU": 92,
"id-ID": 100,
"it-IT": 100,
"ja-JP": 89,
"ko-KR": 68,
"my-MM": 96,
"ja-JP": 85,
"ko-KR": 67,
"my-MM": 93,
"nb-NO": 100,
"nl-NL": 80,
"nn-NO": 80,
"pl-PL": 79,
"pt-PT": 83,
"nl-NL": 100,
"nn-NO": 96,
"pl-PL": 95,
"pt-BR": 100,
"pt-PT": 100,
"ro-RO": 100,
"ru-RU": 81,
"ru-RU": 97,
"sk-SK": 100,
"sv-SE": 100,
"tr-TR": 81,
"uk-UA": 98,
"zh-CN": 95,
"tr-TR": 87,
"uk-UA": 99,
"zh-CN": 100,
"zh-TW": 99
}
+44 -43
View File
@@ -4,7 +4,7 @@
"selectAll": "Zaznacz wszystko",
"multiSelect": "Dodaj element do zaznaczenia",
"moveCanvas": "Przesuń obszar roboczy",
"cut": "",
"cut": "Wytnij",
"copy": "Kopiuj",
"copyAsPng": "Skopiuj do schowka jako plik PNG",
"copyAsSvg": "Skopiuj do schowka jako plik SVG",
@@ -29,17 +29,17 @@
"edges": "Krawędzie",
"sharp": "Ostry",
"round": "Zaokrąglij",
"arrowheads": "",
"arrowhead_none": "",
"arrowhead_arrow": "",
"arrowheads": "Groty",
"arrowhead_none": "Brak",
"arrowhead_arrow": "Strzałka",
"arrowhead_bar": "",
"arrowhead_dot": "",
"arrowhead_dot": "Kropka",
"fontSize": "Rozmiar tekstu",
"fontFamily": "Krój pisma",
"onlySelected": "Tylko wybrane",
"withBackground": "Z tłem dokumentu",
"exportEmbedScene": "",
"exportEmbedScene_details": "",
"withBackground": "",
"exportEmbedScene": "Osadź scenę w eksportowanym pliku",
"exportEmbedScene_details": "Dane sceny zostaną zapisane w eksportowanym pliku PNG/SVG tak, aby scena mogła zostać z niego przywrócona.\nZwiększy to rozmiar eksportowanego pliku.",
"addWatermark": "Dodaj \"Zrobione w Excalidraw\"",
"handDrawn": "Odręczny",
"normal": "Normalny",
@@ -60,7 +60,7 @@
"architect": "Dokładny",
"artist": "Artystyczny",
"cartoonist": "Rysunkowy",
"fileTitle": "",
"fileTitle": "Tytuł pliku",
"colorPicker": "Paleta kolorów",
"canvasBackground": "Kolor dokumentu",
"drawingCanvas": "Obszar roboczy",
@@ -69,29 +69,28 @@
"language": "Język",
"createRoom": "Udostępnij sesję współpracy na żywo",
"duplicateSelection": "Powiel",
"untitled": "",
"untitled": "Bez tytułu",
"name": "Nazwa",
"yourName": "Twoje imię",
"madeWithExcalidraw": "Zrobione w Excalidraw",
"group": "Zgrupuj wybrane",
"ungroup": "Rozgrupuj wybrane",
"collaborators": "Współtwórcy",
"toggleGridMode": "Włącz siatkę",
"toggleStats": "",
"gridMode": "Tryb siatki",
"addToLibrary": "Dodaj do biblioteki",
"removeFromLibrary": "Usuń z biblioteki",
"libraryLoadingMessage": "Wczytywanie biblioteki...",
"libraries": "",
"libraries": "Przeglądaj biblioteki",
"loadingScene": "Ładowanie sceny...",
"align": "",
"alignTop": "",
"alignBottom": "",
"alignLeft": "",
"alignRight": "",
"centerVertically": "",
"centerHorizontally": "",
"distributeHorizontally": "",
"distributeVertically": ""
"align": "Wyrównaj",
"alignTop": "Wyrównaj do góry",
"alignBottom": "Wyrównaj do dołu",
"alignLeft": "Wyrównaj do lewej",
"alignRight": "Wyrównaj do prawej",
"centerVertically": "Wyśrodkuj w pionie",
"centerHorizontally": "Wyśrodkuj w poziomie",
"distributeHorizontally": "Rozłóż poziomo",
"distributeVertically": "Rozłóż pionowo"
},
"buttons": {
"clearReset": "Wyczyść dokument i zresetuj kolor dokumentu",
@@ -118,15 +117,16 @@
"redo": "Przywróć",
"roomDialog": "Utwórz nową sesję współpracy na żywo",
"createNewRoom": "Utwórz nowy pokój",
"toggleFullScreen": "Włącz/wyłącz tryb pełnoekranowy",
"toggleDarkMode": "Włącz tryb ciemny",
"toggleZenMode": "Włącz tryb Zen",
"fullScreen": "",
"darkMode": "",
"lightMode": "",
"zenMode": "",
"exitZenMode": "Wyjdź z trybu Zen"
},
"alerts": {
"clearReset": "To spowoduje usunięcie wszystkiego z dokumentu. Czy chcesz kontynuować?",
"couldNotCreateShareableLink": "Wystąpił błąd przy generowaniu linka do udostępniania.",
"couldNotCreateShareableLinkTooBig": "",
"couldNotCreateShareableLinkTooBig": "Nie można utworzyć udostępnialnego linku: scena jest za duża",
"couldNotLoadInvalidFile": "Nie udało się otworzyć pliku. Wybrany plik jest nieprawidłowy.",
"importBackendFailed": "Wystąpił błąd podczas importowania pliku.",
"cannotExportEmptyCanvas": "Najpierw musisz coś narysować, aby zapisać dokument.",
@@ -134,10 +134,10 @@
"decryptFailed": "Nie udało się odszyfrować danych.",
"uploadedSecurly": "By zapewnić Ci prywatność, udostępnianie projektu jest zabezpieczone szyfrowaniem end-to-end, co oznacza, że poza tobą i osobą z którą podzielisz się linkiem, nikt nie ma dostępu do tego co udostępniasz.",
"loadSceneOverridePrompt": "Wczytanie zewnętrznego rysunku zastąpi istniejącą zawartość. Czy chcesz kontynuować?",
"errorLoadingLibrary": "",
"confirmAddLibrary": "",
"errorLoadingLibrary": "Wystąpił błąd podczas ładowania biblioteki stron trzecich.",
"confirmAddLibrary": "To doda {{numShapes}} kształtów do twojej biblioteki. Jesteś pewien?",
"imageDoesNotContainScene": "",
"cannotRestoreFromImage": ""
"cannotRestoreFromImage": "Scena nie mogła zostać przywrócona z pliku obrazu"
},
"toolBar": {
"selection": "Zaznaczenie",
@@ -161,6 +161,7 @@
"freeDraw": "Naciśnij i przeciągnij by rysować, puść kiedy skończysz",
"text": "Wskazówka: możesz również dodać tekst klikając dwukrotnie gdziekolwiek za pomocą narzędzia zaznaczania",
"linearElementMulti": "Aby zakończyć krzywą, ponownie kliknij w ostatni punkt, bądź naciśnij Esc albo Enter",
"lockAngle": "",
"resize": "Możesz zachować proporcję trzymająć wcisnięty SHIFT, przytrzymaj ALT by zmienić rozmiar względem środka",
"rotate": "Możesz obracać element w równych odstępach trzymając wciśnięty SHIFT",
"lineEditor_info": "Kliknij dwukrotnie lub naciśnij Enter, aby edytować punkty",
@@ -168,9 +169,9 @@
"lineEditor_nothingSelected": "Naciśnij w punkt by go edytować, przytrzymaj Alt i naciśnij by dodać nowy punkt"
},
"canvasError": {
"cannotShowPreview": "",
"canvasTooBig": "",
"canvasTooBigTip": ""
"cannotShowPreview": "Nie można pokazać podglądu",
"canvasTooBig": "Płótno może być za duże.",
"canvasTooBigTip": "Wskazówka: spróbuj nieco zbliżyć najdalej wysunięte elementy."
},
"errorSplash": {
"headingMain_pre": "Wystąpił błąd. Spróbuj ",
@@ -213,22 +214,22 @@
"textNewLine": "Dodaj nową linię (tekst)",
"textFinish": "Zakończ edycję (tekst)",
"zoomToFit": "Powiększ, aby wyświetlić wszystkie elementy",
"zoomToSelection": "",
"zoomToSelection": "Przybliż zaznaczenie",
"preventBinding": "Zablokuj przywiązanie strzałek do obiektu"
},
"encrypted": {
"tooltip": "Twoje rysunki są zabezpieczone szyfrowaniem end-to-end, tak więc nawet w Excalidraw nie jesteśmy w stanie zobaczyć tego co tworzysz."
},
"stats": {
"angle": "",
"element": "",
"elements": "",
"height": "",
"scene": "",
"selected": "",
"storage": "",
"title": "",
"total": "",
"width": ""
"angle": "Kąt",
"element": "Element",
"elements": "Elementy",
"height": "Wysokość",
"scene": "Scena",
"selected": "Zaznaczenie",
"storage": "Pamięć",
"title": "Statystyki dla nerdów",
"total": "Suma",
"width": "Szerokość"
}
}
+235
View File
@@ -0,0 +1,235 @@
{
"labels": {
"paste": "Colar",
"selectAll": "Selecionar tudo",
"multiSelect": "Adicionar elemento à seleção",
"moveCanvas": "Mover tela",
"cut": "Cortar",
"copy": "Copiar",
"copyAsPng": "Copiar para a área de transferência como PNG",
"copyAsSvg": "Copiar para a área de transferência como SVG",
"bringForward": "Trazer para a frente",
"sendToBack": "Enviar para o fundo",
"bringToFront": "Trazer para o primeiro plano",
"sendBackward": "Enviar para trás",
"delete": "Apagar",
"copyStyles": "Copiar os estilos",
"pasteStyles": "Colar os estilos",
"stroke": "Contorno",
"background": "Fundo",
"fill": "Preenchimento",
"strokeWidth": "Espessura do traço",
"strokeStyle": "Estilo de traço",
"strokeStyle_solid": "Sólido",
"strokeStyle_dashed": "Tracejado",
"strokeStyle_dotted": "Pontilhado",
"sloppiness": "Precisão do traço",
"opacity": "Opacidade",
"textAlign": "Alinhamento do texto",
"edges": "Arestas",
"sharp": "Pontudo",
"round": "Arredondado",
"arrowheads": "Pontas",
"arrowhead_none": "Nenhuma",
"arrowhead_arrow": "Flecha",
"arrowhead_bar": "Barra",
"arrowhead_dot": "Ponto",
"fontSize": "Tamanho da fonte",
"fontFamily": "Família da fonte",
"onlySelected": "Somente a seleção",
"withBackground": "Com fundo",
"exportEmbedScene": "Incorporar a cena no arquivo exportado",
"exportEmbedScene_details": "Os dados da cena serão salvos no arquivo PNG/SVG exportado para que a cena possa ser restaurada.\nIrá aumentar o tamanho do arquivo exportado.",
"addWatermark": "Adicionar \"Feito com Excalidraw\"",
"handDrawn": "Manuscrito",
"normal": "Normal",
"code": "Código",
"small": "Pequeno",
"medium": "Médio",
"large": "Grande",
"veryLarge": "Muito grande",
"solid": "Sólido",
"hachure": "Hachura",
"crossHatch": "Hachura cruzada",
"thin": "Fino",
"bold": "Espesso",
"left": "Esquerda",
"center": "Centralizar",
"right": "Direita",
"extraBold": "Muito espesso",
"architect": "Arquiteto",
"artist": "Artista",
"cartoonist": "Cartunista",
"fileTitle": "Título do arquivo",
"colorPicker": "Seletor de cores",
"canvasBackground": "Fundo da tela",
"drawingCanvas": "Tela de desenho",
"layers": "Camadas",
"actions": "Ações",
"language": "Idioma",
"createRoom": "Compartilhar uma sessão de colaboração ao vivo",
"duplicateSelection": "Duplicar",
"untitled": "Sem título",
"name": "Nome",
"yourName": "Seu nome",
"madeWithExcalidraw": "Feito com Excalidraw",
"group": "Agrupar seleção",
"ungroup": "Desagrupar seleção",
"collaborators": "Colaboradores",
"gridMode": "Modo grade",
"addToLibrary": "Adicionar à biblioteca",
"removeFromLibrary": "Remover da biblioteca",
"libraryLoadingMessage": "Carregando biblioteca...",
"libraries": "Procurar bibliotecas",
"loadingScene": "Carregando cena...",
"align": "Alinhamento",
"alignTop": "Alinhar ao topo",
"alignBottom": "Alinhar embaixo",
"alignLeft": "Alinhar à esquerda",
"alignRight": "Alinhar à direita",
"centerVertically": "Centralizar verticalmente",
"centerHorizontally": "Centralizar horizontalmente",
"distributeHorizontally": "Distribuir horizontalmente",
"distributeVertically": "Distribuir verticalmente"
},
"buttons": {
"clearReset": "Limpar o canvas e redefinir a cor de fundo",
"export": "Exportar",
"exportToPng": "Exportar em PNG",
"exportToSvg": "Exportar em SVG",
"copyToClipboard": "Copiar para o clipboard",
"copyPngToClipboard": "Copiar PNG para área de transferência",
"scale": "Escala",
"save": "Salvar",
"saveAs": "Salvar como",
"load": "Carregar",
"getShareableLink": "Obter um link de compartilhamento",
"close": "Fechar",
"selectLanguage": "Selecionar idioma",
"scrollBackToContent": "Voltar para o conteúdo",
"zoomIn": "Aumentar zoom",
"zoomOut": "Diminuir zoom",
"resetZoom": "Redefinir zoom",
"menu": "Menu",
"done": "Concluído",
"edit": "Editar",
"undo": "Desfazer",
"redo": "Refazer",
"roomDialog": "Iniciar colaboração ao vivo",
"createNewRoom": "Criar nova sala",
"fullScreen": "Tela cheia",
"darkMode": "Modo escuro",
"lightMode": "Modo claro",
"zenMode": "Modo Zen",
"exitZenMode": "Sair do modo zen"
},
"alerts": {
"clearReset": "Isto irá limpar toda a tela. Você tem certeza?",
"couldNotCreateShareableLink": "Não foi possível criar um link de compartilhamento.",
"couldNotCreateShareableLinkTooBig": "Não foi possível criar um link compartilhável: a cena é muito grande",
"couldNotLoadInvalidFile": "Não foi possível carregar o arquivo inválido",
"importBackendFailed": "A importação do servidor falhou.",
"cannotExportEmptyCanvas": "Não é possível exportar um canvas vazio.",
"couldNotCopyToClipboard": "Não foi possível copiar para a área de transferência. Experimente usando o navegador Chrome.",
"decryptFailed": "Não foi possível descriptografar os dados.",
"uploadedSecurly": "O upload foi protegido com criptografia de ponta a ponta, o que significa que o servidor do Excalidraw e terceiros não podem ler o conteúdo.",
"loadSceneOverridePrompt": "Carregar um desenho externo substituirá o seu conteúdo existente. Deseja continuar?",
"errorLoadingLibrary": "Houve um erro ao carregar a biblioteca de terceiros.",
"confirmAddLibrary": "Isso adicionará {{numShapes}} forma(s) à sua biblioteca. Tem certeza?",
"imageDoesNotContainScene": "A importação de imagens não é suportada no momento.\n\nVocê deseja importar uma cena? Esta imagem parece não conter dados de cena. Você ativou isto durante a exportação?",
"cannotRestoreFromImage": "Não foi possível restaurar a cena deste arquivo de imagem"
},
"toolBar": {
"selection": "Seleção",
"draw": "Desenho livre",
"rectangle": "Retângulo",
"diamond": "Losango",
"ellipse": "Elipse",
"arrow": "Flecha",
"line": "Linha",
"text": "Texto",
"library": "Biblioteca",
"lock": "Manter ativa a ferramenta selecionada após desenhar"
},
"headings": {
"canvasActions": "Ações da tela",
"selectedShapeActions": "Ações das formas selecionadas",
"shapes": "Formas"
},
"hints": {
"linearElement": "Clique para iniciar vários pontos, arraste para uma única linha",
"freeDraw": "Toque e arraste, solte quando terminar",
"text": "Dica: você também pode adicionar texto clicando duas vezes em qualquer lugar com a ferramenta de seleção",
"linearElementMulti": "Clique no último ponto ou pressione Escape ou Enter para terminar",
"lockAngle": "Você pode restringir o ângulo segurando o SHIFT",
"resize": "Você pode restringir proporções segurando SHIFT enquanto redimensiona,\nsegure ALT para redimensionar do centro",
"rotate": "Você pode restringir os ângulos segurando SHIFT enquanto gira",
"lineEditor_info": "Clique duas vezes ou pressione Enter para editar os pontos",
"lineEditor_pointSelected": "Pressione Deletar para remover o ponto, CtrlOuCmd+D para duplicar ou arraste para mover",
"lineEditor_nothingSelected": "Selecione um ponto para mover ou remover, ou segure Alt e clique para adicionar novos pontos"
},
"canvasError": {
"cannotShowPreview": "Não é possível mostrar pré-visualização",
"canvasTooBig": "A tela pode ser muito grande.",
"canvasTooBigTip": "Dica: tente aproximar um pouco os elementos mais distantes."
},
"errorSplash": {
"headingMain_pre": "Foi encontrado um erro. Tente ",
"headingMain_button": "recarregar a página.",
"clearCanvasMessage": "Se recarregar a página não funcionar, tente ",
"clearCanvasMessage_button": "limpando a tela.",
"clearCanvasCaveat": " Isso resultará em perda de trabalho ",
"trackedToSentry_pre": "O erro com o identificador ",
"trackedToSentry_post": " foi rastreado no nosso sistema.",
"openIssueMessage_pre": "Fomos muito cautelosos para não incluir suas informações de cena no erro. Se sua cena não for privada, por favor, considere seguir nosso ",
"openIssueMessage_button": "rastreador de bugs.",
"openIssueMessage_post": " Por favor, inclua informações abaixo, copiando e colando para a issue do GitHub.",
"sceneContent": "Conteúdo da cena:"
},
"roomDialog": {
"desc_intro": "Você pode convidar pessoas para sua cena atual para colaborar com você.",
"desc_privacy": "Não se preocupe, a sessão usa criptografia de ponta a ponta; portanto, o que você desenhar permanecerá privado. Nem mesmo nosso servidor poderá ver o que você cria.",
"button_startSession": "Iniciar sessão",
"button_stopSession": "Parar sessão",
"desc_inProgressIntro": "A sessão de colaboração ao vivo está agora em andamento.",
"desc_shareLink": "Compartilhe este link com qualquer pessoa com quem você queira colaborar:",
"desc_exitSession": "Interrompendo a sessão você irá se desconectar da sala, mas você poderá continuar trabalhando com a cena localmente. Observe que isso não afetará outras pessoas, e elas ainda poderão colaborar em suas versões."
},
"errorDialog": {
"title": "Erro"
},
"shortcutsDialog": {
"title": "Atalhos de teclado",
"shapes": "Formas",
"or": "ou",
"click": "clicar",
"drag": "arrastar",
"curvedArrow": "Seta curva",
"curvedLine": "Linha curva",
"editor": "Editor",
"view": "Visualizar",
"blog": "Leia o nosso blog",
"howto": "Siga os nossos guias",
"github": "Encontrou algum problema? Nos informe",
"textNewLine": "Adicionar nova linha (texto)",
"textFinish": "Finalizar edição (texto)",
"zoomToFit": "Ajustar para caber todos os elementos",
"zoomToSelection": "Ampliar a seleção",
"preventBinding": "Prevenir fixação de seta"
},
"encrypted": {
"tooltip": "Seus desenhos são criptografados de ponta a ponta, então os servidores do Excalidraw nunca os verão."
},
"stats": {
"angle": "Ângulo",
"element": "Elemento",
"elements": "Elementos",
"height": "Altura",
"scene": "Cena",
"selected": "Selecionado",
"storage": "Armazenamento",
"title": "Estatísticas para nerds",
"total": "Total",
"width": "Largura"
}
}
+39 -38
View File
@@ -4,7 +4,7 @@
"selectAll": "Selecionar tudo",
"multiSelect": "Adicionar elemento à seleção",
"moveCanvas": "Mover tela",
"cut": "",
"cut": "Cortar",
"copy": "Copiar",
"copyAsPng": "Copiar para a área de transferência como PNG",
"copyAsSvg": "Copiar para a área de transferência como SVG",
@@ -29,11 +29,11 @@
"edges": "Arestas",
"sharp": "Aguçado",
"round": "Redondo",
"arrowheads": "",
"arrowhead_none": "",
"arrowhead_arrow": "",
"arrowhead_bar": "",
"arrowhead_dot": "",
"arrowheads": "Pontas",
"arrowhead_none": "Nenhuma",
"arrowhead_arrow": "Seta",
"arrowhead_bar": "Barra",
"arrowhead_dot": "Ponto",
"fontSize": "Tamanho da fonte",
"fontFamily": "Família da fontes",
"onlySelected": "Somente a seleção",
@@ -60,7 +60,7 @@
"architect": "Arquitecto",
"artist": "Artista",
"cartoonist": "Caricaturista",
"fileTitle": "",
"fileTitle": "Título do ficheiro",
"colorPicker": "Seletor de cores",
"canvasBackground": "Fundo da tela",
"drawingCanvas": "Tela de desenho",
@@ -69,29 +69,28 @@
"language": "Idioma",
"createRoom": "Compartilhar uma sessão de colaboração ao vivo",
"duplicateSelection": "Duplicar",
"untitled": "",
"untitled": "Sem título",
"name": "Nome",
"yourName": "Seu nome",
"madeWithExcalidraw": "Feito com Excalidraw",
"group": "Agrupar seleção",
"ungroup": "Desagrupar seleção",
"collaborators": "Colaboradores",
"toggleGridMode": "Alternar modo de grade",
"toggleStats": "",
"gridMode": "Modo grade",
"addToLibrary": "Adicionar à biblioteca",
"removeFromLibrary": "Remover da biblioteca",
"libraryLoadingMessage": "Carregando biblioteca...",
"libraries": "",
"libraries": "Procurar bibliotecas",
"loadingScene": "Carregando cena...",
"align": "",
"alignTop": "",
"alignBottom": "",
"alignLeft": "",
"alignRight": "",
"centerVertically": "",
"centerHorizontally": "",
"distributeHorizontally": "",
"distributeVertically": ""
"align": "Alinhamento",
"alignTop": "Alinhar ao topo",
"alignBottom": "Alinhar ao fundo",
"alignLeft": "Alinhar à esquerda",
"alignRight": "Alinhar à direita",
"centerVertically": "Centralizar verticalmente",
"centerHorizontally": "Centralizar horizontalmente",
"distributeHorizontally": "Distribuir horizontalmente",
"distributeVertically": "Distribuir verticalmente"
},
"buttons": {
"clearReset": "Limpar o canvas e redefinir a cor de fundo",
@@ -118,9 +117,10 @@
"redo": "Refazer",
"roomDialog": "Iniciar colaboração ao vivo",
"createNewRoom": "Criar nova sala",
"toggleFullScreen": "Alternar tela cheia",
"toggleDarkMode": "Alternar modo escuro",
"toggleZenMode": "Alternar modo zen",
"fullScreen": "Tela cheia",
"darkMode": "Modo escuro",
"lightMode": "Modo claro",
"zenMode": "Modo Zen",
"exitZenMode": "Sair do modo zen"
},
"alerts": {
@@ -136,7 +136,7 @@
"loadSceneOverridePrompt": "Carregar um desenho externo substituirá o seu conteúdo existente. Deseja continuar?",
"errorLoadingLibrary": "Houve um erro ao carregar a biblioteca de terceiros.",
"confirmAddLibrary": "Isso adicionará {{numShapes}} forma(s) à sua biblioteca. Tem certeza?",
"imageDoesNotContainScene": "O arquivo de imagem não contém dados de cena. Você ativou durante a exportação?",
"imageDoesNotContainScene": "A importação de imagens não é suportada no momento.\n\nVocê deseja importar uma cena? Esta imagem parece não conter dados de cena. Você ativou isto durante a exportação?",
"cannotRestoreFromImage": "Não foi possível restaurar a cena deste arquivo de imagem"
},
"toolBar": {
@@ -161,6 +161,7 @@
"freeDraw": "Toque e arraste, solte quando terminar",
"text": "Dica: você também pode adicionar texto clicando duas vezes em qualquer lugar com a ferramenta de seleção",
"linearElementMulti": "Clique no último ponto ou pressione Escape ou Enter para terminar",
"lockAngle": "Você pode restringir o ângulo segurando SHIFT",
"resize": "Você pode restringir proporções segurando SHIFT enquanto redimensiona,\nsegure ALT para redimensionar do centro",
"rotate": "Você pode restringir os ângulos segurando SHIFT enquanto gira",
"lineEditor_info": "Clique duas vezes ou pressione Enter para editar os pontos",
@@ -168,9 +169,9 @@
"lineEditor_nothingSelected": "Selecione um ponto para mover ou remover, ou segure Alt e clique para adicionar novos pontos"
},
"canvasError": {
"cannotShowPreview": "",
"canvasTooBig": "",
"canvasTooBigTip": ""
"cannotShowPreview": "Não é possível mostrar pré-visualização",
"canvasTooBig": "A tela pode ser muito grande.",
"canvasTooBigTip": "Dica: tente aproximar um pouco os elementos mais distantes."
},
"errorSplash": {
"headingMain_pre": "Foi encontrado um erro. Tente ",
@@ -213,22 +214,22 @@
"textNewLine": "Adicionar nova linha (texto)",
"textFinish": "Finalizar edição (texto)",
"zoomToFit": "Ajustar para caber todos os elementos",
"zoomToSelection": "",
"zoomToSelection": "Ampliar a seleção",
"preventBinding": "Prevenir fixação de seta"
},
"encrypted": {
"tooltip": "Seus desenhos são criptografados de ponta a ponta, então os servidores do Excalidraw nunca os verão."
},
"stats": {
"angle": "",
"element": "",
"elements": "",
"height": "",
"scene": "",
"selected": "",
"storage": "",
"title": "",
"total": "",
"width": ""
"angle": "Ângulo",
"element": "Elemento",
"elements": "Elementos",
"height": "Altura",
"scene": "Cena",
"selected": "Selecionado",
"storage": "Armazenamento",
"title": "Estatísticas para nerds",
"total": "Total",
"width": "Largura"
}
}
+7 -6
View File
@@ -76,8 +76,7 @@
"group": "Grupare selecție",
"ungroup": "Degrupare selecție",
"collaborators": "Colaboratori",
"toggleGridMode": "Comută modul grilă",
"toggleStats": "Comută statisticile pentru pasionați",
"gridMode": "Mod grilă",
"addToLibrary": "Adăugare la bibliotecă",
"removeFromLibrary": "Eliminare din bibliotecă",
"libraryLoadingMessage": "Se încarcă biblioteca...",
@@ -118,9 +117,10 @@
"redo": "Refacere",
"roomDialog": "Colaborare în direct",
"createNewRoom": "Creare cameră nouă",
"toggleFullScreen": "Comută modul ecran complet",
"toggleDarkMode": "Comută modul întunecat",
"toggleZenMode": "Comută modul zen",
"fullScreen": "Ecran complet",
"darkMode": "Mod întunecat",
"lightMode": "Mod luminos",
"zenMode": "Mod zen",
"exitZenMode": "Ieșire din modul zen"
},
"alerts": {
@@ -136,7 +136,7 @@
"loadSceneOverridePrompt": "Încărcarea desenului extern va înlocui conținutul existent. Dorești să continui?",
"errorLoadingLibrary": "A apărut o eroare la încărcarea bibliotecii terțe.",
"confirmAddLibrary": "Această acțiune va adăuga {{numShapes}} formă(e) la biblioteca ta. Confirmi?",
"imageDoesNotContainScene": "Fișierul de imagine nu conține date de scenă. Ai activat această opțiune pe durata exportării?",
"imageDoesNotContainScene": "Importarea imaginilor nu este acceptată în acest moment.\n\nVoiai să imporți o scenă? Această imagine nu pare să conțină date de scenă. Ai activat această opțiune pe durata exportării?",
"cannotRestoreFromImage": "Scena nu a putut fi restaurată din acest fișier de imagine"
},
"toolBar": {
@@ -161,6 +161,7 @@
"freeDraw": "Dă clic pe pânză și glisează cursorul, apoi eliberează-l când ai terminat",
"text": "Sfat: poți adăuga text și dând dublu clic oriunde cu instrumentul de selecție",
"linearElementMulti": "Dă clic pe ultimul punct sau apasă tasta Escape sau tasta Enter pentru a termina",
"lockAngle": "Poți constrânge unghiul prin ținerea apăsată a tastei SHIFT",
"resize": "Poți constrânge proporțiile, ținând apăsată tasta SHIFT în timp ce redimensionezi,\nține apăsată tasta ALT pentru a redimensiona de la centru",
"rotate": "Poți constrânge unghiurile, ținând apăsată tasta SHIFT în timp ce rotești",
"lineEditor_info": "Dă dublu clic sau apasă tasta Enter pentru a edita punctele",
+48 -47
View File
@@ -2,9 +2,9 @@
"labels": {
"paste": "Вставить",
"selectAll": "Выбрать все",
"multiSelect": "Добавить элемент к выбору",
"multiSelect": "Добавить элемент в выделенный фрагмент",
"moveCanvas": "Переместить холст",
"cut": "",
"cut": "Вырезать",
"copy": "Копировать",
"copyAsPng": "Скопировать в буфер обмена как PNG",
"copyAsSvg": "Скопировать в буфер обмена как SVG",
@@ -29,17 +29,17 @@
"edges": "Края",
"sharp": "Острые",
"round": "Скругленные",
"arrowheads": "",
"arrowhead_none": "",
"arrowheads": "Стрелка",
"arrowhead_none": "Без стрелки",
"arrowhead_arrow": "Cтрелка",
"arrowhead_bar": "",
"arrowhead_bar": "Столбец",
"arrowhead_dot": "Точка",
"fontSize": "Размер шрифта",
"fontFamily": "Семейство шрифтов",
"onlySelected": "Только выбранные",
"withBackground": "С фоном",
"exportEmbedScene": "",
"exportEmbedScene_details": "",
"exportEmbedScene": "Встроить информацию о сцене в экспортируемый файл",
"exportEmbedScene_details": "Сцена будет сохранена в PNG/SVG файл так, чтобы всю сцену можно будет восстановить из этого файла. Это увеличит размер файла.",
"addWatermark": "Добавить \"Сделано с Excalidraw\"",
"handDrawn": "Нарисованный от руки",
"normal": "Обычный",
@@ -75,23 +75,22 @@
"madeWithExcalidraw": "Сделано в Excalidraw",
"group": "Сгруппировать выделение",
"ungroup": "Разделить выделение",
"collaborators": "Сотрудники",
"toggleGridMode": "Переключить режим сетки",
"toggleStats": "",
"collaborators": "Участники",
"gridMode": "",
"addToLibrary": "Добавить в библиотеку",
"removeFromLibrary": "Удалить из библиотеки",
"libraryLoadingMessage": "Загрузка библиотеки...",
"libraries": "",
"libraries": "Просмотреть библиотеки",
"loadingScene": "Загрузка сцены...",
"align": "",
"alignTop": "",
"alignBottom": "",
"alignLeft": "",
"alignRight": "",
"centerVertically": "",
"centerHorizontally": "",
"distributeHorizontally": "",
"distributeVertically": ""
"align": "Выровнять",
"alignTop": "Выровнять по верхнему краю",
"alignBottom": "Выровнять по нижнему краю",
"alignLeft": "Выровнять по левому краю",
"alignRight": "Выровнять по правому краю",
"centerVertically": "Центрировать по вертикали",
"centerHorizontally": "Центрировать по горизонтали",
"distributeHorizontally": "Распределить по горизонтали",
"distributeVertically": "Распределить по вертикали"
},
"buttons": {
"clearReset": "Очистить холст и сбросить цвет фона",
@@ -100,7 +99,7 @@
"exportToSvg": "Экспорт в SVG",
"copyToClipboard": "Скопировать в буфер обмена",
"copyPngToClipboard": "Скопировать PNG в буфер обмена",
"scale": "Шкала",
"scale": "Масштаб",
"save": "Сохранить",
"saveAs": "Сохранить как",
"load": "Загрузить",
@@ -118,26 +117,27 @@
"redo": "Шаг вперед",
"roomDialog": "Начать совместную работу",
"createNewRoom": "Создать новую комнату",
"toggleFullScreen": ереключить полноэкранный режим",
"toggleDarkMode": "Переключить тёмную тему",
"toggleZenMode": "Переключить режим концентрации внимания",
"fullScreen": олный экран",
"darkMode": "",
"lightMode": "",
"zenMode": "",
"exitZenMode": "Выключить режим концентрации внимания"
},
"alerts": {
"clearReset": "Это очистит весь холст. Вы уверены?",
"couldNotCreateShareableLink": "Не удалось создать общедоступную ссылку.",
"couldNotCreateShareableLinkTooBig": "",
"couldNotCreateShareableLinkTooBig": "Нельзя создать ссылку, чтобы поделиться. Сцена слишком большая",
"couldNotLoadInvalidFile": "Не удалось загрузить недопустимый файл",
"importBackendFailed": "Не удалось импортировать из бэкэнда.",
"cannotExportEmptyCanvas": "Не может экспортировать пустой холст.",
"couldNotCopyToClipboard": "Не удалось скопировать в буфер обмена. Попробуйте использовать веб-браузер Chrome.",
"decryptFailed": "Не удалось декодировать данные.",
"decryptFailed": "Не удалось расшифровать данные.",
"uploadedSecurly": "Загружаемые данные защищена сквозным шифрованием, что означает, что сервер Excalidraw и третьи стороны не могут прочитать содержимое.",
"loadSceneOverridePrompt": "",
"errorLoadingLibrary": "",
"confirmAddLibrary": "",
"loadSceneOverridePrompt": "Загрузка рисунка приведёт к замене имеющегося содержимого. Вы хотите продолжить?",
"errorLoadingLibrary": "Произошла ошибка при загрузке сторонней библиотеки.",
"confirmAddLibrary": "Будет добавлено {{numShapes}} фигур в вашу библиотеку. Продолжить?",
"imageDoesNotContainScene": "",
"cannotRestoreFromImage": ""
"cannotRestoreFromImage": "Сцена не может быть восстановлена из этого изображения"
},
"toolBar": {
"selection": "Выделение области",
@@ -159,18 +159,19 @@
"hints": {
"linearElement": "Нажмите, чтобы начать несколько точек, перетащите для одной линии",
"freeDraw": "Нажмите и перетаскивайте, отпустите по завершении",
"text": "",
"text": "Совет: при выбранном инструменте выделения дважды щёлкните в любом месте, чтобы добавить текст",
"linearElementMulti": "Кликните на последней точке или нажмите Escape или Enter чтобы закончить",
"lockAngle": "",
"resize": "Вы можете ограничить пропорции, удерживая SHIFT во время изменения размеров,\nудерживайте ALT чтобы изменить размер из центра",
"rotate": "Вы можете ограничить углы, удерживая SHIFT во время вращения",
"lineEditor_info": "Дважды кликните или нажмите Enter, чтобы редактировать точки",
"lineEditor_pointSelected": "",
"lineEditor_nothingSelected": ""
"lineEditor_pointSelected": "Нажмите Delete для удаления точки, Ctrl или Cmd + D для дублирования, перетащите для перемещения",
"lineEditor_nothingSelected": "Выберите точку для перемещения или удаления. Alt + клик чтобы добавить новые точки"
},
"canvasError": {
"cannotShowPreview": "",
"canvasTooBig": "",
"canvasTooBigTip": ""
"cannotShowPreview": "Не удается отобразить предпросмотр",
"canvasTooBig": "Сцена слишком большая.",
"canvasTooBigTip": "Совет: попробуйте сблизить элементы рисунка."
},
"errorSplash": {
"headingMain_pre": "Возникла ошибка. Попробуйте ",
@@ -188,11 +189,11 @@
"roomDialog": {
"desc_intro": "Вы можете пригласить людей в текущую сцену для совместной работы.",
"desc_privacy": "Не беспокойтесь, сессия использует сквозное шифрование, поэтому всё что вы нарисуете останется приватным. Ваша информация не будет доступна даже на наших серверах.",
"button_startSession": "Начать сессию",
"button_stopSession": "Закончить сессию",
"button_startSession": "Начать сеанс",
"button_stopSession": "Завершить сеанс",
"desc_inProgressIntro": "Совместная сессия теперь активна.",
"desc_shareLink": "Поделитесь этой ссылкой со всеми участниками:",
"desc_exitSession": ""
"desc_exitSession": "Завершив сеанс, вы выйдете из комнаты, но сможете продолжить работать с документом локально. Это не повлияет на работу других пользователей — они смогут продолжить совместную работу с их версией документа."
},
"errorDialog": {
"title": "Ошибка"
@@ -212,23 +213,23 @@
"github": "Нашли проблему? Отправьте",
"textNewLine": "Добавить новую строку (текст)",
"textFinish": "Закончить редактирование (текст)",
"zoomToFit": "",
"zoomToSelection": "",
"zoomToFit": "Отмастштабировать, чтобы поместились все элементы",
"zoomToSelection": "Перейти к выделенному",
"preventBinding": "Предотвратить привязку стрелок"
},
"encrypted": {
"tooltip": ""
"tooltip": "Ваши данные защищены сквозным (End-to-end) шифрованием. Серверы Excalidraw никогда не получат доступ к ним."
},
"stats": {
"angle": "Угол",
"element": "Элемент",
"elements": "Элементы",
"height": "Высота",
"scene": "",
"selected": "",
"storage": "",
"title": "",
"total": "",
"scene": "Сцены",
"selected": "Выбран",
"storage": "Хранилище",
"title": "Статистика для ботаников",
"total": "Всего",
"width": "Ширина"
}
}
+7 -6
View File
@@ -76,8 +76,7 @@
"group": "Zoskupiť",
"ungroup": "Zrušiť zoskupenie",
"collaborators": "Spolupracovníci",
"toggleGridMode": "Prepnúť mriežku",
"toggleStats": "Prepnúť štatistiky",
"gridMode": "Režim mriežky",
"addToLibrary": "Pridať do knižnice",
"removeFromLibrary": "Odstrániť z knižnice",
"libraryLoadingMessage": "Načítavanie knižnice...",
@@ -118,9 +117,10 @@
"redo": "Znova",
"roomDialog": "Začať živú spoluprácu",
"createNewRoom": "Vytvoriť novú miestnosť",
"toggleFullScreen": "Prepnúť režim celej obrazovky",
"toggleDarkMode": "Prepnúť tmavý režim",
"toggleZenMode": "Prepnúť režim zen",
"fullScreen": "Celá obrazovka",
"darkMode": "Tmavý režim",
"lightMode": "Svetlý režim",
"zenMode": "Režim zen",
"exitZenMode": "Zrušiť režim zen"
},
"alerts": {
@@ -136,7 +136,7 @@
"loadSceneOverridePrompt": "Nahratie externej kresby nahradí existujúci obsah. Prajete si pokračovať?",
"errorLoadingLibrary": "Nepodarilo sa načítať externú knižnicu.",
"confirmAddLibrary": "Týmto sa pridá {{numShapes}} tvar(ov) do vašej knižnice. Ste si istí?",
"imageDoesNotContainScene": "Obrázkový súbor neobsahuje údaje scény. Povolili ste ich pri exportovaní?",
"imageDoesNotContainScene": "Importovanie obrázku v tomto momente nie je možné.\n\nChceli ste importovať scénu? Tento obrázok neobsahuje žiadne údaje scény. Povolili ste túto možnosť počas exportovania?",
"cannotRestoreFromImage": "Nepodarilo sa obnoviť scénu z tohto obrázkového súboru"
},
"toolBar": {
@@ -161,6 +161,7 @@
"freeDraw": "Kliknite a ťahajte, pustite na ukončenie",
"text": "Tip: text môžete pridať aj dvojklikom kdekoľvek, ak je zvolený nástroj výber",
"linearElementMulti": "Kliknite na počiatočný bod alebo stlačte Escape alebo Enter na ukončenie",
"lockAngle": "Počas rotácie obmedzíte uhol podržaním SHIFT",
"resize": "Počas zmeny veľkosti zachováte proporcie podržaním SHIFT,\\npodržaním ALT meníte veľkosť so zachovaním stredu",
"rotate": "Počas rotácie obmedzíte uhol podržaním SHIFT",
"lineEditor_info": "Použite dvojklik alebo stlačte Enter na editáciu bodov",
+7 -6
View File
@@ -76,8 +76,7 @@
"group": "Gruppera markering",
"ungroup": "Avgruppera markering",
"collaborators": "Medarbetare",
"toggleGridMode": "Växla rutnätsläge",
"toggleStats": "Visa/dölj statistik för nördar",
"gridMode": "Rutnätsläge",
"addToLibrary": "Lägg till i biblioteket",
"removeFromLibrary": "Ta bort från bibliotek",
"libraryLoadingMessage": "Laddar bibliotek...",
@@ -118,9 +117,10 @@
"redo": "Gör om",
"roomDialog": "Starta live-samarbete",
"createNewRoom": "Skapa ett nytt rum",
"toggleFullScreen": "Växla fullskärmsläge",
"toggleDarkMode": "Växla mörkt läge",
"toggleZenMode": "Växla zen-läge",
"fullScreen": "Helskärm",
"darkMode": "Mörkt läge",
"lightMode": "Ljust läge",
"zenMode": "Zen-läge",
"exitZenMode": "Gå ur zen-läge"
},
"alerts": {
@@ -136,7 +136,7 @@
"loadSceneOverridePrompt": "Laddning av extern skiss kommer att ersätta ditt befintliga innehåll. Vill du fortsätta?",
"errorLoadingLibrary": "Fel vid inläsning av tredjeparts bibliotek.",
"confirmAddLibrary": "Detta kommer att lägga till {{numShapes}} form(er) till ditt bibliotek. Är du säker?",
"imageDoesNotContainScene": "Bildfilen innehåller inte skissdata. Har du aktiverat detta under export?",
"imageDoesNotContainScene": "Importering av bilder stöds inte just nu.\n\nVill du importera en skiss? Den här bilden verkar inte innehålla någon skissdata. Har du aktiverat detta under export?",
"cannotRestoreFromImage": "Skiss kunde inte återställas från denna bildfil"
},
"toolBar": {
@@ -161,6 +161,7 @@
"freeDraw": "Klicka och dra, släpp när du är klar",
"text": "Tips: du kan också lägga till text genom att dubbelklicka var som helst med markeringsverktyget",
"linearElementMulti": "Klicka på sista punkten eller tryck Escape eller Enter för att avsluta",
"lockAngle": "Du kan begränsa vinkeln genom att hålla SKIFT",
"resize": "Du kan behålla proportioner genom att hålla SHIFT medan du ändrar storlek,\nhåller du ALT ändras storlek relativt mitten",
"rotate": "Du kan begränsa vinklar genom att hålla SHIFT medan du roterar",
"lineEditor_info": "Dubbelklicka eller tryck på Enter för att redigera punkter",
+26 -25
View File
@@ -4,7 +4,7 @@
"selectAll": "Tümünü seç",
"multiSelect": "Seçime öge ekle",
"moveCanvas": "Tuvali taşı",
"cut": "",
"cut": "Kes",
"copy": "Kopyala",
"copyAsPng": "Panoya PNG olarak kopyala",
"copyAsSvg": "Panoya SVG olarak kopyala",
@@ -37,7 +37,7 @@
"fontSize": "Yazı tipi boyutu",
"fontFamily": "Yazı tipi ailesi",
"onlySelected": "Sadece seçilen",
"withBackground": "Arka Plan İle Beraber",
"withBackground": "",
"exportEmbedScene": "",
"exportEmbedScene_details": "",
"addWatermark": "\"Excalidraw ile yapıldı\" yazısını ekle",
@@ -60,7 +60,7 @@
"architect": "Mimar",
"artist": "Sanatçı",
"cartoonist": "Karikatürist",
"fileTitle": "",
"fileTitle": "Dosya adı",
"colorPicker": "Renk seçici",
"canvasBackground": "Tuval arka planı",
"drawingCanvas": "Çizim tuvali",
@@ -69,27 +69,26 @@
"language": "Dil",
"createRoom": "Ortak çalışma ortamını paylaş",
"duplicateSelection": "Çoğalt",
"untitled": "",
"untitled": "Adsız",
"name": "İsim",
"yourName": "İsminiz",
"madeWithExcalidraw": "Excalidraw ile yapıldı",
"group": "Seçimi grup yap",
"ungroup": "Seçilen grubu dağıt",
"collaborators": "Ortaklar",
"toggleGridMode": "Izgara modunu aç",
"toggleStats": "",
"gridMode": "",
"addToLibrary": "Kütüphaneye ekle",
"removeFromLibrary": "Kütüphaneden kaldır",
"libraryLoadingMessage": "Kütüphane yükleniyor...",
"libraries": "",
"loadingScene": "Çalışma alanı yükleniyor...",
"align": "",
"alignTop": "",
"alignBottom": "",
"alignLeft": "",
"alignRight": "",
"centerVertically": "",
"centerHorizontally": "",
"align": "Hizala",
"alignTop": "Yukarı hizala",
"alignBottom": "Aşağı hizala",
"alignLeft": "Sola yasla",
"alignRight": "Sağa yasla",
"centerVertically": "Dikeyde ortala",
"centerHorizontally": "Yatayda ortala",
"distributeHorizontally": "",
"distributeVertically": ""
},
@@ -118,9 +117,10 @@
"redo": "Yeniden yap",
"roomDialog": "Ortak çalışma ortamı yarat",
"createNewRoom": "Yeni oda oluştur",
"toggleFullScreen": "Tam ekranı aç/kapa",
"toggleDarkMode": "Karanlık modu aç/kapa",
"toggleZenMode": "Zen modunu aç/kapa",
"fullScreen": "",
"darkMode": "",
"lightMode": "",
"zenMode": "",
"exitZenMode": "Zen modundan çık"
},
"alerts": {
@@ -136,7 +136,7 @@
"loadSceneOverridePrompt": "Harici çizimler yüklemek mevcut olan içeriği değiştirecektir. Devam etmek istiyor musunuz?",
"errorLoadingLibrary": "Üçüncü taraf kitaplığı yüklerken bir hata oluştu.",
"confirmAddLibrary": "Bu, kitaplığınıza {{numShapes}} tane şekil ekleyecek. Emin misiniz?",
"imageDoesNotContainScene": "Görsel dosyası herhangi bir sahne verisi bulundurmuyor. Dışa aktarırken bunu etkinleştirdiniz mi?",
"imageDoesNotContainScene": "",
"cannotRestoreFromImage": "Bu görsel dosyasından sahne onarılamıyor"
},
"toolBar": {
@@ -161,6 +161,7 @@
"freeDraw": "Tıkla ve sürükle, bitirdiğinde serbest bırak",
"text": "İpucu: seçme aracıyla herhangi bir yere çift tıklayarak da yazı ekleyebilirsin",
"linearElementMulti": "Tamamlamak için son noktayı seçin veya Escape ve Enter'dan birine basın",
"lockAngle": "",
"resize": "Yeniden boyutlandırırken SHIFT'e basılı tutarak oranları kısıtlayabilirsiniz, merkezden yeniden boyutlandırmak için ALT'a basılı tutun",
"rotate": "Döndürürken SHIFT tuşuna basılı tutarak açıları koruyabilirsiniz",
"lineEditor_info": "Noktaları düzenlemek için çift-tıklayın veya Enter'a basın",
@@ -168,7 +169,7 @@
"lineEditor_nothingSelected": "Kaldırmak veya oynatmak için bir nokta seç, veya yeni noktalar eklemek için Alt'a basılı tut"
},
"canvasError": {
"cannotShowPreview": "",
"cannotShowPreview": "Önizleme gösterilemiyor",
"canvasTooBig": "",
"canvasTooBigTip": ""
},
@@ -220,15 +221,15 @@
"tooltip": "Çizimleriniz uçtan-uca şifrelenmiştir, Excalidraw'ın sunucuları bile onları göremez."
},
"stats": {
"angle": "",
"element": "",
"elements": "",
"height": "",
"angle": "Açı",
"element": "Bileşen",
"elements": "Bileşenler",
"height": "Yükseklik",
"scene": "",
"selected": "",
"storage": "",
"selected": "Seçili",
"storage": "Depolama",
"title": "",
"total": "",
"total": "Toplam",
"width": ""
}
}
+10 -9
View File
@@ -29,7 +29,7 @@
"edges": "Краї",
"sharp": "Гострі",
"round": "Круглі",
"arrowheads": "",
"arrowheads": "Закінчення стрілки",
"arrowhead_none": "Жоден",
"arrowhead_arrow": "Стрілка",
"arrowhead_bar": "Колона",
@@ -37,7 +37,7 @@
"fontSize": "Розмір шрифту",
"fontFamily": "Шрифт",
"onlySelected": "Тільки вибране",
"withBackground": "З тлом",
"withBackground": "З фоном",
"exportEmbedScene": "Вставити сцену в експортований файл",
"exportEmbedScene_details": "Дані сцени будуть збережені в експортований файл PNG/SVG. Ця сцена може бути відновленна з нього, однак це збільшить розмір експортованого файлу.",
"addWatermark": "Додати «Накреслене в Excalidraw»",
@@ -76,8 +76,7 @@
"group": "Групувати виділене",
"ungroup": "Розгрупувати виділене",
"collaborators": "Співавтори",
"toggleGridMode": "Режим сітки",
"toggleStats": "",
"gridMode": "Режим сітки",
"addToLibrary": "Додати до бібліотеки",
"removeFromLibrary": "Видалити з бібліотеки",
"libraryLoadingMessage": "Завантажити бібліотеку...",
@@ -118,9 +117,10 @@
"redo": "Повторити",
"roomDialog": "Відкрити сесію спільної роботи",
"createNewRoom": "Створити нову кімнату",
"toggleFullScreen": "Повноекранний режим",
"toggleDarkMode": "Переключити темний режим",
"toggleZenMode": "Дзен-режим",
"fullScreen": "Повноекранний режим",
"darkMode": "Темний режим",
"lightMode": "Світлий режим",
"zenMode": "Режим Дзен",
"exitZenMode": "Вийти з дзен-режиму"
},
"alerts": {
@@ -136,7 +136,7 @@
"loadSceneOverridePrompt": "Завантаження зовнішнього креслення замінить ваш наявний контент. Продовжити?",
"errorLoadingLibrary": "Помилка при завантаженні сторонньої бібліотеки.",
"confirmAddLibrary": "Це призведе до додавання {{numShapes}} фігур до вашої бібліотеки. Ви впевнені?",
"imageDoesNotContainScene": "Файл зображення не містить даних сцени. Ви увімкнули це під час експорту?",
"imageDoesNotContainScene": "Імпортування зображень на даний момент не підтримується.\n\nЧи хочете ви імпортувати сцену? Це зображення не містить ніяких даних сцен. Ви увімкнули це під час експорту?",
"cannotRestoreFromImage": "Сцена не може бути відновлена з цього файлу зображення"
},
"toolBar": {
@@ -161,6 +161,7 @@
"freeDraw": "Натисніть і потягніть, відпустіть коли завершите",
"text": "Порада: можна також додати текст, двічі клацнувши по будь-якому місці інструментом вибору",
"linearElementMulti": "Натисніть на останню точку, клацніть Esc або Enter щоб завершити",
"lockAngle": "",
"resize": "Ви можете зберегти пропорції, утримуючи SHIFT під час зміни розміру,\nутримуйте ALT для змінення розміру від центру",
"rotate": "Ви можете обмежити кути, утримуючи SHIFT під час обертання",
"lineEditor_info": "Двічі клацніть або натисніть Enter щоб редагувати точки",
@@ -227,7 +228,7 @@
"scene": "Сцена",
"selected": "Вибраний",
"storage": "Сховище",
"title": "",
"title": "Статистика",
"total": "Всього",
"width": "Ширина"
}
+16 -15
View File
@@ -4,7 +4,7 @@
"selectAll": "全部选中",
"multiSelect": "添加元素到选区",
"moveCanvas": "移动画布",
"cut": "",
"cut": "剪切",
"copy": "复制",
"copyAsPng": "复制为 PNG 到剪贴板",
"copyAsSvg": "复制为 SVG 到剪贴板",
@@ -29,15 +29,15 @@
"edges": "边角",
"sharp": "尖锐",
"round": "圆润",
"arrowheads": "",
"arrowhead_none": "",
"arrowhead_arrow": "",
"arrowhead_bar": "",
"arrowhead_dot": "",
"arrowheads": "箭头",
"arrowhead_none": "",
"arrowhead_arrow": "箭头",
"arrowhead_bar": "",
"arrowhead_dot": "圆点",
"fontSize": "字体大小",
"fontFamily": "字体",
"onlySelected": "仅被选中",
"withBackground": "添加背景",
"withBackground": "使用背景",
"exportEmbedScene": "将场景嵌入到导出的文件",
"exportEmbedScene_details": "场景数据将被保存到导出的 PNG/SVG 文件,以便恢复。\n将会增加导出的文件大小。",
"addWatermark": "添加 “使用 Excalidraw 创建” 水印",
@@ -76,12 +76,11 @@
"group": "组选",
"ungroup": "取消组选",
"collaborators": "协作者",
"toggleGridMode": "切换网格模式",
"toggleStats": "",
"gridMode": "网格模式",
"addToLibrary": "添加到库中",
"removeFromLibrary": "从库中移除",
"libraryLoadingMessage": "正在加载库...",
"libraries": "",
"libraries": "浏览库",
"loadingScene": "正在加载绘图...",
"align": "对齐",
"alignTop": "顶部对齐",
@@ -118,9 +117,10 @@
"redo": "重做",
"roomDialog": "开始实时协作",
"createNewRoom": "新建会议室",
"toggleFullScreen": "切换全屏显示",
"toggleDarkMode": "切换暗黑模式",
"toggleZenMode": "切换禅模式",
"fullScreen": "全屏",
"darkMode": "暗色主题",
"lightMode": "浅色模式",
"zenMode": "禅意模式",
"exitZenMode": "退出禅模式"
},
"alerts": {
@@ -136,7 +136,7 @@
"loadSceneOverridePrompt": "加载外部绘图将取代您现有的内容。您想要继续吗?",
"errorLoadingLibrary": "加载第三方库时出错。",
"confirmAddLibrary": "这将添加 {{numShapes}} 个形状到您的库。您确定吗?",
"imageDoesNotContainScene": "图像文件不包含场景数据。您是否在导出过程中启用了此选项",
"imageDoesNotContainScene": "当前不支持导入图片。\n\n您想要导入场景吗?此图像似乎不包含任何场景数据。您是否在导出过程中启用了这个数据",
"cannotRestoreFromImage": "无法从此图像文件恢复场景"
},
"toolBar": {
@@ -161,6 +161,7 @@
"freeDraw": "点击并拖动,完成后发布",
"text": "提示:您也可以使用选择工具双击任意位置来添加文字",
"linearElementMulti": "点击最后一个点或按下 Esc/Enter 来完成",
"lockAngle": "可以按住 Shift 来约束角度",
"resize": "您可以按住SHIFT来限制比例大小,\n按住ALT来调整中心大小",
"rotate": "旋转时可以按住 Shift 来约束角度",
"lineEditor_info": "双击或按回车键编辑",
@@ -227,7 +228,7 @@
"scene": "场景",
"selected": "选中",
"storage": "存储",
"title": "",
"title": "玩家统计",
"total": "总计",
"width": "宽度"
}
+7 -6
View File
@@ -76,8 +76,7 @@
"group": "建立群組",
"ungroup": "取消群組",
"collaborators": "協作者",
"toggleGridMode": "切換格線模式",
"toggleStats": "切換詳細統計",
"gridMode": "網格模式",
"addToLibrary": "加入資料庫",
"removeFromLibrary": "從資料庫中移除",
"libraryLoadingMessage": "資料庫讀取中…",
@@ -118,9 +117,10 @@
"redo": "重做",
"roomDialog": "開始即時協作",
"createNewRoom": "建立新協作會議室",
"toggleFullScreen": "切換全螢幕",
"toggleDarkMode": "切換深色模式",
"toggleZenMode": "切換專注模式",
"fullScreen": "全螢幕",
"darkMode": "深色模式",
"lightMode": "淺色模式",
"zenMode": "專注模式",
"exitZenMode": "離開專注模式"
},
"alerts": {
@@ -136,7 +136,7 @@
"loadSceneOverridePrompt": "讀取外部圖樣將取代目前的內容。是否要繼續?",
"errorLoadingLibrary": "載入第三方套件時出現錯誤。",
"confirmAddLibrary": "這將會將 {{numShapes}} 個圖形加入你的資料庫,你確定嗎?",
"imageDoesNotContainScene": "圖檔中未包含場景資料輸出檔案時是否有包含此資料",
"imageDoesNotContainScene": "目前尚不支援載入圖片。\n您是否要載入場景?此圖片中並無任何場景資料輸出時是否有選擇包含?",
"cannotRestoreFromImage": "無法由此檔案回復場景。"
},
"toolBar": {
@@ -161,6 +161,7 @@
"freeDraw": "點擊並拖曳來繪圖,放開即結束",
"text": "提示:亦可使用選取工具在任何地方雙擊來加入文字",
"linearElementMulti": "按下 Escape 或 Enter 以結束繪製",
"lockAngle": "按住 SHIFT 可限制旋轉角度",
"resize": "縮放時按住 Shift 可保持原比例縮放;\\n按住 Alt 可由中心點進行縮放",
"rotate": "旋轉時按住 Shift 可限制旋轉角度",
"lineEditor_info": "雙擊滑鼠左鍵或按 Enter 來編輯控制點",
+8
View File
@@ -16,6 +16,9 @@ Please add the latest change on the top under the correct section.
### Features
- Remove language picker, and add `langCode`, `renderFooter` [#2644](https://github.com/excalidraw/excalidraw/pull/2644):
- BREAKING: removed the language picker from UI. It is now the host app's responsibility to implement a language picker if desirable, using the newly added [`renderFooter`](https://github.com/excalidraw/excalidraw/blob/master/src/packages/excalidraw/README.md#renderFooter) prop. The reasoning is that the i18n should be controlled by the app itself, not by the nested Excalidraw component.
- Added [`langCode`](https://github.com/excalidraw/excalidraw/blob/master/src/packages/excalidraw/README.md#langCode) prop to control the UI language.
- Add support for `exportToBackend` prop to allow host apps to implement shareable links [#2612](https://github.com/excalidraw/excalidraw/pull/2612/files)
- Add zoom to selection [#2522](https://github.com/excalidraw/excalidraw/pull/2522)
- Insert Library items in the middle of the screen [#2527](https://github.com/excalidraw/excalidraw/pull/2527)
@@ -27,6 +30,7 @@ Please add the latest change on the top under the correct section.
### Fixes
- Fix initialization when browser tab not focused [#2677](https://github.com/excalidraw/excalidraw/pull/2677)
- Consistent case for export locale strings [#2622](https://github.com/excalidraw/excalidraw/pull/2622)
- Remove unnecessary console.error as it was polluting Sentry [#2637](https://github.com/excalidraw/excalidraw/pull/2637)
- Fix scroll-to-center on init for non-zero canvas offsets [#2445](https://github.com/excalidraw/excalidraw/pull/2445)
@@ -51,6 +55,10 @@ Please add the latest change on the top under the correct section.
- Bump ini from 1.3.5 to 1.3.7 in /src/packages/excalidraw [#2500](https://github.com/excalidraw/excalidraw/pull/2500)
### Docs
- Document some of the more exotic element props [#2673](https://github.com/excalidraw/excalidraw/pull/2673)
## 0.1.1
#### Fix
+20
View File
@@ -139,6 +139,8 @@ export default function App() {
| [`isCollaborating`](#isCollaborating) | `boolean` | | This implies if the app is in collaboration mode |
| [`onPointerUpdate`](#onPointerUpdate) | Function | | Callback triggered when mouse pointer is updated. |
| [`onExportToBackend`](#onExportToBackend) | Function | | Callback triggered when link button is clicked on export dialog |
| [`langCode`](#langCode) | string | `en` | Language code string |
| [`renderFooter `](#renderFooter) | Function | | Function that renders custom UI footer |
#### `width`
@@ -270,3 +272,21 @@ This callback is triggered when the shareable-link button is clicked in the expo
1. `exportedElements`: An array of [non deleted elements](https://github.com/excalidraw/excalidraw/blob/6e45cb95dbd7a8be1859c7055b06957298e3097c/src/element/types.ts#L76) which needs to be exported.
2. `appState`: [AppState](https://github.com/excalidraw/excalidraw/blob/4c90ea5667d29effe8ec4a115e49efc7c340cdb3/src/types.ts#L33) of the scene.
3. `canvas`: The `HTMLCanvasElement` of the scene.
#### `langCode`
Determines the language of the UI. It should be one of the [available language codes](https://github.com/excalidraw/excalidraw/blob/d337c8b15f6c1085287b12ecbe59c96e2c4e0ff4/src/i18n.ts#L14). Defaults to `en` (English).
We also export default language and supported languages which you can import as shown below.
```js
import { defaultLang, languages } from "@excalidraw/excalidraw";
```
| name | type |
| ----------- | -------------------------------------------------------------------------------------------------------------------- |
| defaultLang | string |
| languages | [Language []](https://github.com/excalidraw/excalidraw/blob/c35d983fef8a83ba842dd892c0f461111a3e8589/src/i18n.ts#L9) |
#### `renderFooter`
A function that renders (returns JSX) custom UI footer. For example, you can use this to render a language picker that was previously being rendered by Excalidraw itself (for now, you'll need to implement your own language picker).
+7 -1
View File
@@ -8,6 +8,7 @@ import "../../css/styles.scss";
import { ExcalidrawAPIRefValue, ExcalidrawProps } from "../../types";
import { IsMobileProvider } from "../../is-mobile";
import { defaultLang } from "../../i18n";
const Excalidraw = (props: ExcalidrawProps) => {
const {
@@ -23,6 +24,8 @@ const Excalidraw = (props: ExcalidrawProps) => {
isCollaborating,
onPointerUpdate,
onExportToBackend,
renderFooter,
langCode = defaultLang.code,
} = props;
useEffect(() => {
@@ -44,7 +47,7 @@ const Excalidraw = (props: ExcalidrawProps) => {
}, []);
return (
<InitializeApp>
<InitializeApp langCode={langCode}>
<IsMobileProvider>
<App
width={width}
@@ -59,6 +62,8 @@ const Excalidraw = (props: ExcalidrawProps) => {
isCollaborating={isCollaborating}
onPointerUpdate={onPointerUpdate}
onExportToBackend={onExportToBackend}
renderFooter={renderFooter}
langCode={langCode}
/>
</IsMobileProvider>
</InitializeApp>
@@ -94,3 +99,4 @@ export {
getSyncableElements,
getElementMap,
} from "../../element";
export { defaultLang, languages } from "../../i18n";
+75 -199
View File
@@ -1149,6 +1149,12 @@
"to-fast-properties": "^2.0.0"
}
},
"@discoveryjs/json-ext": {
"version": "0.5.2",
"resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.2.tgz",
"integrity": "sha512-HyYEUDeIj5rRQU2Hk5HTB2uHsbRQpF70nvMhVzi+VJR0X+xNEhjPui4/kBf3VeH/wqD28PT4sVOm8qqLjBrSZg==",
"dev": true
},
"@polka/url": {
"version": "1.0.0-next.11",
"resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.11.tgz",
@@ -1369,18 +1375,18 @@
}
},
"@webpack-cli/info": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-1.1.0.tgz",
"integrity": "sha512-uNWSdaYHc+f3LdIZNwhdhkjjLDDl3jP2+XBqAq9H8DjrJUvlOKdP8TNruy1yEaDfgpAIgbSAN7pye4FEHg9tYQ==",
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-1.2.1.tgz",
"integrity": "sha512-fLnDML5HZ5AEKzHul8xLAksoKN2cibu6MgonkUj8R9V7bbeVRkd1XbGEGWrAUNYHbX1jcqCsDEpBviE5StPMzQ==",
"dev": true,
"requires": {
"envinfo": "^7.7.3"
}
},
"@webpack-cli/serve": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-1.1.0.tgz",
"integrity": "sha512-7RfnMXCpJ/NThrhq4gYQYILB18xWyoQcBey81oIyVbmgbc6m5ZHHyFK+DyH7pLHJf0p14MxL4mTsoPAgBSTpIg==",
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-1.2.1.tgz",
"integrity": "sha512-Zj1z6AyS+vqV6Hfi7ngCjFGdHV5EwZNIHo6QfFTNe9PyW+zBU1zJ9BiOW1pmUEq950RC4+Dym6flyA/61/vhyw==",
"dev": true
},
"@xtuc/ieee754": {
@@ -1446,12 +1452,6 @@
"color-convert": "^1.9.0"
}
},
"array-back": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/array-back/-/array-back-4.0.1.tgz",
"integrity": "sha512-Z/JnaVEXv+A9xabHzN43FiiiWEE7gPCRXMrVmRm00tWbjZRul1iHm7ECzlyNq1p4a4ATXz+G9FJ3GqGOkOV3fg==",
"dev": true
},
"babel-code-frame": {
"version": "6.26.0",
"resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz",
@@ -1761,18 +1761,6 @@
"integrity": "sha512-puCDz0CzydiSYOrnXpz/PKd69zRrribezjtE9yd4zvytoRc8+RY/KJPvtPFKZS3E3wP6neGyMe0vOTlHO5L3Pw==",
"dev": true
},
"command-line-usage": {
"version": "6.1.1",
"resolved": "https://registry.npmjs.org/command-line-usage/-/command-line-usage-6.1.1.tgz",
"integrity": "sha512-F59pEuAR9o1SF/bD0dQBDluhpT4jJQNWUHEuVBqpDmCUo6gPjCi+m9fCWnWZVR/oG6cMTUms4h+3NPl74wGXvA==",
"dev": true,
"requires": {
"array-back": "^4.0.1",
"chalk": "^2.4.2",
"table-layout": "^1.0.1",
"typical": "^5.2.0"
}
},
"commander": {
"version": "2.20.3",
"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
@@ -1912,12 +1900,6 @@
"ms": "2.1.2"
}
},
"deep-extend": {
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz",
"integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==",
"dev": true
},
"define-properties": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz",
@@ -1945,15 +1927,6 @@
"integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==",
"dev": true
},
"end-of-stream": {
"version": "1.4.4",
"resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz",
"integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==",
"dev": true,
"requires": {
"once": "^1.4.0"
}
},
"enhanced-resolve": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-4.3.0.tgz",
@@ -1981,9 +1954,9 @@
"dev": true
},
"errno": {
"version": "0.1.7",
"resolved": "https://registry.npmjs.org/errno/-/errno-0.1.7.tgz",
"integrity": "sha512-MfrRBDWzIWifgq6tJj60gkAwtLNb6sQPlcFrSOflcP1aFmmruKQ2wRnze/8V6kgyz7H3FF8Npzv78mZ7XLLflg==",
"version": "0.1.8",
"resolved": "https://registry.npmjs.org/errno/-/errno-0.1.8.tgz",
"integrity": "sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==",
"dev": true,
"requires": {
"prr": "~1.0.1"
@@ -2047,19 +2020,19 @@
"dev": true
},
"execa": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/execa/-/execa-4.1.0.tgz",
"integrity": "sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==",
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/execa/-/execa-5.0.0.tgz",
"integrity": "sha512-ov6w/2LCiuyO4RLYGdpFGjkcs0wMTgGE8PrkTHikeUy5iJekXyPIKUjifk5CsE0pt7sMCrMZ3YNqoCj6idQOnQ==",
"dev": true,
"requires": {
"cross-spawn": "^7.0.0",
"get-stream": "^5.0.0",
"human-signals": "^1.1.1",
"cross-spawn": "^7.0.3",
"get-stream": "^6.0.0",
"human-signals": "^2.1.0",
"is-stream": "^2.0.0",
"merge-stream": "^2.0.0",
"npm-run-path": "^4.0.0",
"onetime": "^5.1.0",
"signal-exit": "^3.0.2",
"npm-run-path": "^4.0.1",
"onetime": "^5.1.2",
"signal-exit": "^3.0.3",
"strip-final-newline": "^2.0.0"
}
},
@@ -2075,6 +2048,12 @@
"integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==",
"dev": true
},
"fastest-levenshtein": {
"version": "1.0.12",
"resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.12.tgz",
"integrity": "sha512-On2N+BpYJ15xIC974QNVuYGMOlEVt4s0EOI3wwMqOmK1fdDY+FN/zltPV8vosq4ad4c/gJ1KHScUn/6AWIgiow==",
"dev": true
},
"file-loader": {
"version": "6.2.0",
"resolved": "https://registry.npmjs.org/file-loader/-/file-loader-6.2.0.tgz",
@@ -2163,13 +2142,10 @@
}
},
"get-stream": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz",
"integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==",
"dev": true,
"requires": {
"pump": "^3.0.0"
}
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.0.tgz",
"integrity": "sha512-A1B3Bh1UmL0bidM/YX2NsCOTnGJePL9rO/M+Mw3m9f2gUpfokS0hi5Eah0WSUEWZdZhIZtMjkIYS7mDfOqNHbg==",
"dev": true
},
"glob-to-regexp": {
"version": "0.4.1",
@@ -2229,9 +2205,9 @@
"dev": true
},
"human-signals": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz",
"integrity": "sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==",
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz",
"integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==",
"dev": true
},
"icss-utils": {
@@ -2248,51 +2224,6 @@
"requires": {
"pkg-dir": "^4.2.0",
"resolve-cwd": "^3.0.0"
},
"dependencies": {
"find-up": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
"integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
"dev": true,
"requires": {
"locate-path": "^5.0.0",
"path-exists": "^4.0.0"
}
},
"locate-path": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
"integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
"dev": true,
"requires": {
"p-locate": "^4.1.0"
}
},
"p-locate": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
"integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
"dev": true,
"requires": {
"p-limit": "^2.2.0"
}
},
"path-exists": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
"integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
"dev": true
},
"pkg-dir": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz",
"integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==",
"dev": true,
"requires": {
"find-up": "^4.0.0"
}
}
}
},
"indexes-of": {
@@ -2322,6 +2253,15 @@
"loose-envify": "^1.0.0"
}
},
"is-core-module": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.2.0.tgz",
"integrity": "sha512-XRAfAdyyY5F5cOXn7hYQDqh2Xmii+DEfIcQGxK/uNwMHhIkPWO0g8msXcbzLe+MpGoR951MlqM/2iIlU4vKDdQ==",
"dev": true,
"requires": {
"has": "^1.0.3"
}
},
"is-number": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
@@ -2413,12 +2353,6 @@
"integrity": "sha512-ZRbnvdg/NxqzC7L9Uyqzf4psi1OM4Cuc+sJAkQPjO6XkQIJTNbfK2Rsmbw8fx1p2mkZdp2FZYo2+LwXYY/uwIA==",
"dev": true
},
"leven": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz",
"integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==",
"dev": true
},
"loader-runner": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.1.0.tgz",
@@ -2530,18 +2464,18 @@
"dev": true
},
"mime-db": {
"version": "1.44.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.44.0.tgz",
"integrity": "sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg==",
"version": "1.45.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.45.0.tgz",
"integrity": "sha512-CkqLUxUk15hofLoLyljJSrukZi8mAtgd+yE5uO4tqRZsdsAJKv0O+rFMhVDRJgozy+yG6md5KwuXhD4ocIoP+w==",
"dev": true
},
"mime-types": {
"version": "2.1.27",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.27.tgz",
"integrity": "sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w==",
"version": "2.1.28",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.28.tgz",
"integrity": "sha512-0TO2yJ5YHYr7M2zzT7gDU1tbwHxEUWBCLt0lscSNpcdAfFyJOVEpRYNS7EXVcTLNj/25QO8gulHC5JtTzSE2UQ==",
"dev": true,
"requires": {
"mime-db": "1.44.0"
"mime-db": "1.45.0"
}
},
"mimic-fn": {
@@ -2642,15 +2576,6 @@
"object-keys": "^1.1.1"
}
},
"once": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
"integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
"dev": true,
"requires": {
"wrappy": "1"
}
},
"onetime": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz",
@@ -2807,16 +2732,6 @@
"integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY=",
"dev": true
},
"pump": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz",
"integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==",
"dev": true,
"requires": {
"end-of-stream": "^1.1.0",
"once": "^1.3.1"
}
},
"punycode": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
@@ -2856,12 +2771,6 @@
"resolve": "^1.9.0"
}
},
"reduce-flatten": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/reduce-flatten/-/reduce-flatten-2.0.0.tgz",
"integrity": "sha512-EJ4UNY/U1t2P/2k6oqotuX2Cc3T6nxJwsM0N0asT7dhrtH1ltUxDn4NalSYmPE2rCkVpcf/X6R0wDwcFpzhd4w==",
"dev": true
},
"regenerate": {
"version": "1.4.2",
"resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz",
@@ -2930,11 +2839,12 @@
}
},
"resolve": {
"version": "1.17.0",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz",
"integrity": "sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==",
"version": "1.19.0",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.19.0.tgz",
"integrity": "sha512-rArEXAgsBG4UgRGcynxWIWKFvh/XZCcS8UJdHhwy91zwAvCZIbcs+vAbflgBnNjYMs/i/i+/Ux6IZhML1yPvxg==",
"dev": true,
"requires": {
"is-core-module": "^2.1.0",
"path-parse": "^1.0.6"
}
},
@@ -3126,18 +3036,6 @@
"has-flag": "^3.0.0"
}
},
"table-layout": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/table-layout/-/table-layout-1.0.1.tgz",
"integrity": "sha512-dEquqYNJiGwY7iPfZ3wbXDI944iqanTSchrACLL2nOB+1r+h1Nzu2eH+DuPPvWvm5Ry7iAPeFlgEtP5bIp5U7Q==",
"dev": true,
"requires": {
"array-back": "^4.0.1",
"deep-extend": "~0.6.0",
"typical": "^5.2.0",
"wordwrapjs": "^4.0.0"
}
},
"tapable": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz",
@@ -3227,9 +3125,9 @@
"dev": true
},
"ts-loader": {
"version": "8.0.12",
"resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-8.0.12.tgz",
"integrity": "sha512-UIivVfGVJDdwwjgSrbtcL9Nf10c1BWnL1mxAQUVcnhNIn/P9W3nP5v60Z0aBMtc7ZrE11lMmU6+5jSgAXmGaYw==",
"version": "8.0.13",
"resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-8.0.13.tgz",
"integrity": "sha512-1o1nO6aqouA23d2nlcMSEyPMAWRhnYUU0EQUJSc60E0TUyBNX792RHFYUN1ZM29vhMUNayrsbj2UVdZwKhXCDA==",
"dev": true,
"requires": {
"chalk": "^2.3.0",
@@ -3253,12 +3151,6 @@
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==",
"dev": true
},
"typical": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/typical/-/typical-5.2.0.tgz",
"integrity": "sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg==",
"dev": true
},
"unicode-canonical-property-names-ecmascript": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz",
@@ -3325,9 +3217,9 @@
}
},
"webpack": {
"version": "5.11.0",
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.11.0.tgz",
"integrity": "sha512-ubWv7iP54RqAC/VjixgpnLLogCFbAfSOREcSWnnOlZEU8GICC5eKmJSu6YEnph2N2amKqY9rvxSwgyHxVqpaRw==",
"version": "5.11.1",
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.11.1.tgz",
"integrity": "sha512-tNUIdAmYJv+nupRs/U/gqmADm6fgrf5xE+rSlSsf2PgsGO7j2WG7ccU6AWNlOJlHFl+HnmXlBmHIkiLf+XA9mQ==",
"dev": true,
"requires": {
"@types/eslint-scope": "^3.7.0",
@@ -3357,13 +3249,13 @@
},
"dependencies": {
"enhanced-resolve": {
"version": "5.4.0",
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.4.0.tgz",
"integrity": "sha512-ZmqfWURB2lConOBM1JdCVfPyMRv5RdKWktLXO6123p97ovVm2CLBgw9t5MBj3jJWA6eHyOeIws9iJQoGFR4euQ==",
"version": "5.4.1",
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.4.1.tgz",
"integrity": "sha512-4GbyIMzYktTFoRSmkbgZ1LU+RXwf4AQ8Z+rSuuh1dC8plp0PPeaWvx6+G4hh4KnUJ48VoxKbNyA1QQQIUpXjYA==",
"dev": true,
"requires": {
"graceful-fs": "^4.2.4",
"tapable": "^2.0.0"
"tapable": "^2.2.0"
}
},
"find-up": {
@@ -3522,21 +3414,21 @@
}
},
"webpack-cli": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-4.2.0.tgz",
"integrity": "sha512-EIl3k88vaF4fSxWSgtAQR+VwicfLMTZ9amQtqS4o+TDPW9HGaEpbFBbAZ4A3ZOT5SOnMxNOzROsSTPiE8tBJPA==",
"version": "4.3.1",
"resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-4.3.1.tgz",
"integrity": "sha512-/F4+9QNZM/qKzzL9/06Am8NXIkGV+/NqQ62Dx7DSqudxxpAgBqYn6V7+zp+0Y7JuWksKUbczRY3wMTd+7Uj6OA==",
"dev": true,
"requires": {
"@webpack-cli/info": "^1.1.0",
"@webpack-cli/serve": "^1.1.0",
"@discoveryjs/json-ext": "^0.5.0",
"@webpack-cli/info": "^1.2.1",
"@webpack-cli/serve": "^1.2.1",
"colorette": "^1.2.1",
"command-line-usage": "^6.1.0",
"commander": "^6.2.0",
"enquirer": "^2.3.6",
"execa": "^4.1.0",
"execa": "^5.0.0",
"fastest-levenshtein": "^1.0.12",
"import-local": "^3.0.2",
"interpret": "^2.2.0",
"leven": "^3.1.0",
"rechoir": "^0.7.0",
"v8-compile-cache": "^2.2.0",
"webpack-merge": "^4.2.2"
@@ -3586,22 +3478,6 @@
"isexe": "^2.0.0"
}
},
"wordwrapjs": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/wordwrapjs/-/wordwrapjs-4.0.0.tgz",
"integrity": "sha512-Svqw723a3R34KvsMgpjFBYCgNOSdcW3mQFK4wIfhGQhtaFVOJmdYoXgi63ne3dTlWgatVcUc7t4HtQ/+bUVIzQ==",
"dev": true,
"requires": {
"reduce-flatten": "^2.0.0",
"typical": "^5.0.0"
}
},
"wrappy": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
"dev": true
},
"ws": {
"version": "7.4.1",
"resolved": "https://registry.npmjs.org/ws/-/ws-7.4.1.tgz",
+3 -3
View File
@@ -57,10 +57,10 @@
"mini-css-extract-plugin": "1.3.3",
"sass-loader": "10.1.0",
"terser-webpack-plugin": "5.0.3",
"ts-loader": "8.0.12",
"webpack": "5.11.0",
"ts-loader": "8.0.13",
"webpack": "5.11.1",
"webpack-bundle-analyzer": "4.3.0",
"webpack-cli": "4.2.0"
"webpack-cli": "4.3.1"
},
"bugs": "https://github.com/excalidraw/excalidraw/issues",
"repository": "https://github.com/excalidraw/excalidraw",
+3 -2
View File
@@ -6,6 +6,7 @@ import { getDefaultAppState } from "../appState";
import { AppState } from "../types";
import { ExcalidrawElement } from "../element/types";
import { getNonDeletedElements } from "../element";
import { SCENE_NAME_FALLBACK } from "../constants";
type ExportOpts = {
elements: readonly ExcalidrawElement[];
@@ -18,7 +19,7 @@ type ExportOpts = {
export const exportToCanvas = ({
elements,
appState = getDefaultAppState(),
appState = { ...getDefaultAppState(), name: SCENE_NAME_FALLBACK },
getDimensions = (width, height) => ({ width, height, scale: 1 }),
}: ExportOpts) => {
return _exportToCanvas(
@@ -74,7 +75,7 @@ export const exportToBlob = (
export const exportToSvg = ({
elements,
appState = getDefaultAppState(),
appState = { ...getDefaultAppState(), name: SCENE_NAME_FALLBACK },
exportPadding,
metadata,
}: ExportOpts & {
+65 -154
View File
@@ -1064,6 +1064,12 @@
"to-fast-properties": "^2.0.0"
}
},
"@discoveryjs/json-ext": {
"version": "0.5.2",
"resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.2.tgz",
"integrity": "sha512-HyYEUDeIj5rRQU2Hk5HTB2uHsbRQpF70nvMhVzi+VJR0X+xNEhjPui4/kBf3VeH/wqD28PT4sVOm8qqLjBrSZg==",
"dev": true
},
"@polka/url": {
"version": "1.0.0-next.11",
"resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.11.tgz",
@@ -1103,9 +1109,9 @@
"dev": true
},
"@types/node": {
"version": "14.14.14",
"resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.14.tgz",
"integrity": "sha512-UHnOPWVWV1z+VV8k6L1HhG7UbGBgIdghqF3l9Ny9ApPghbjICXkUJSd/b9gOgQfjM1r+37cipdw/HJ3F6ICEnQ==",
"version": "14.14.19",
"resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.19.tgz",
"integrity": "sha512-4nhBPStMK04rruRVtVc6cDqhu7S9GZai0fpXgPXrFpcPX6Xul8xnrjSdGB4KPBVYG/R5+fXWdCM8qBoiULWGPQ==",
"dev": true
},
"@webassemblyjs/ast": {
@@ -1284,18 +1290,18 @@
}
},
"@webpack-cli/info": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-1.1.0.tgz",
"integrity": "sha512-uNWSdaYHc+f3LdIZNwhdhkjjLDDl3jP2+XBqAq9H8DjrJUvlOKdP8TNruy1yEaDfgpAIgbSAN7pye4FEHg9tYQ==",
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-1.2.1.tgz",
"integrity": "sha512-fLnDML5HZ5AEKzHul8xLAksoKN2cibu6MgonkUj8R9V7bbeVRkd1XbGEGWrAUNYHbX1jcqCsDEpBviE5StPMzQ==",
"dev": true,
"requires": {
"envinfo": "^7.7.3"
}
},
"@webpack-cli/serve": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-1.1.0.tgz",
"integrity": "sha512-7RfnMXCpJ/NThrhq4gYQYILB18xWyoQcBey81oIyVbmgbc6m5ZHHyFK+DyH7pLHJf0p14MxL4mTsoPAgBSTpIg==",
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-1.2.1.tgz",
"integrity": "sha512-Zj1z6AyS+vqV6Hfi7ngCjFGdHV5EwZNIHo6QfFTNe9PyW+zBU1zJ9BiOW1pmUEq950RC4+Dym6flyA/61/vhyw==",
"dev": true
},
"@xtuc/ieee754": {
@@ -1361,12 +1367,6 @@
"color-convert": "^1.9.0"
}
},
"array-back": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/array-back/-/array-back-4.0.1.tgz",
"integrity": "sha512-Z/JnaVEXv+A9xabHzN43FiiiWEE7gPCRXMrVmRm00tWbjZRul1iHm7ECzlyNq1p4a4ATXz+G9FJ3GqGOkOV3fg==",
"dev": true
},
"babel-code-frame": {
"version": "6.26.0",
"resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz",
@@ -1670,18 +1670,6 @@
"integrity": "sha512-puCDz0CzydiSYOrnXpz/PKd69zRrribezjtE9yd4zvytoRc8+RY/KJPvtPFKZS3E3wP6neGyMe0vOTlHO5L3Pw==",
"dev": true
},
"command-line-usage": {
"version": "6.1.1",
"resolved": "https://registry.npmjs.org/command-line-usage/-/command-line-usage-6.1.1.tgz",
"integrity": "sha512-F59pEuAR9o1SF/bD0dQBDluhpT4jJQNWUHEuVBqpDmCUo6gPjCi+m9fCWnWZVR/oG6cMTUms4h+3NPl74wGXvA==",
"dev": true,
"requires": {
"array-back": "^4.0.1",
"chalk": "^2.4.2",
"table-layout": "^1.0.1",
"typical": "^5.2.0"
}
},
"commander": {
"version": "2.20.3",
"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
@@ -1762,12 +1750,6 @@
"ms": "2.1.2"
}
},
"deep-extend": {
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz",
"integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==",
"dev": true
},
"define-properties": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz",
@@ -1795,15 +1777,6 @@
"integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==",
"dev": true
},
"end-of-stream": {
"version": "1.4.4",
"resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz",
"integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==",
"dev": true,
"requires": {
"once": "^1.4.0"
}
},
"enhanced-resolve": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-4.3.0.tgz",
@@ -1831,9 +1804,9 @@
"dev": true
},
"errno": {
"version": "0.1.7",
"resolved": "https://registry.npmjs.org/errno/-/errno-0.1.7.tgz",
"integrity": "sha512-MfrRBDWzIWifgq6tJj60gkAwtLNb6sQPlcFrSOflcP1aFmmruKQ2wRnze/8V6kgyz7H3FF8Npzv78mZ7XLLflg==",
"version": "0.1.8",
"resolved": "https://registry.npmjs.org/errno/-/errno-0.1.8.tgz",
"integrity": "sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==",
"dev": true,
"requires": {
"prr": "~1.0.1"
@@ -1897,19 +1870,19 @@
"dev": true
},
"execa": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/execa/-/execa-4.1.0.tgz",
"integrity": "sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==",
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/execa/-/execa-5.0.0.tgz",
"integrity": "sha512-ov6w/2LCiuyO4RLYGdpFGjkcs0wMTgGE8PrkTHikeUy5iJekXyPIKUjifk5CsE0pt7sMCrMZ3YNqoCj6idQOnQ==",
"dev": true,
"requires": {
"cross-spawn": "^7.0.0",
"get-stream": "^5.0.0",
"human-signals": "^1.1.1",
"cross-spawn": "^7.0.3",
"get-stream": "^6.0.0",
"human-signals": "^2.1.0",
"is-stream": "^2.0.0",
"merge-stream": "^2.0.0",
"npm-run-path": "^4.0.0",
"onetime": "^5.1.0",
"signal-exit": "^3.0.2",
"npm-run-path": "^4.0.1",
"onetime": "^5.1.2",
"signal-exit": "^3.0.3",
"strip-final-newline": "^2.0.0"
}
},
@@ -1925,6 +1898,12 @@
"integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==",
"dev": true
},
"fastest-levenshtein": {
"version": "1.0.12",
"resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.12.tgz",
"integrity": "sha512-On2N+BpYJ15xIC974QNVuYGMOlEVt4s0EOI3wwMqOmK1fdDY+FN/zltPV8vosq4ad4c/gJ1KHScUn/6AWIgiow==",
"dev": true
},
"file-loader": {
"version": "6.2.0",
"resolved": "https://registry.npmjs.org/file-loader/-/file-loader-6.2.0.tgz",
@@ -2013,13 +1992,10 @@
}
},
"get-stream": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz",
"integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==",
"dev": true,
"requires": {
"pump": "^3.0.0"
}
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.0.tgz",
"integrity": "sha512-A1B3Bh1UmL0bidM/YX2NsCOTnGJePL9rO/M+Mw3m9f2gUpfokS0hi5Eah0WSUEWZdZhIZtMjkIYS7mDfOqNHbg==",
"dev": true
},
"glob-to-regexp": {
"version": "0.4.1",
@@ -2079,9 +2055,9 @@
"dev": true
},
"human-signals": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz",
"integrity": "sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==",
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz",
"integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==",
"dev": true
},
"import-local": {
@@ -2209,12 +2185,6 @@
"minimist": "^1.2.5"
}
},
"leven": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz",
"integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==",
"dev": true
},
"loader-runner": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.1.0.tgz",
@@ -2317,18 +2287,18 @@
"dev": true
},
"mime-db": {
"version": "1.44.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.44.0.tgz",
"integrity": "sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg==",
"version": "1.45.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.45.0.tgz",
"integrity": "sha512-CkqLUxUk15hofLoLyljJSrukZi8mAtgd+yE5uO4tqRZsdsAJKv0O+rFMhVDRJgozy+yG6md5KwuXhD4ocIoP+w==",
"dev": true
},
"mime-types": {
"version": "2.1.27",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.27.tgz",
"integrity": "sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w==",
"version": "2.1.28",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.28.tgz",
"integrity": "sha512-0TO2yJ5YHYr7M2zzT7gDU1tbwHxEUWBCLt0lscSNpcdAfFyJOVEpRYNS7EXVcTLNj/25QO8gulHC5JtTzSE2UQ==",
"dev": true,
"requires": {
"mime-db": "1.44.0"
"mime-db": "1.45.0"
}
},
"mimic-fn": {
@@ -2388,15 +2358,6 @@
"object-keys": "^1.1.1"
}
},
"once": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
"integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
"dev": true,
"requires": {
"wrappy": "1"
}
},
"onetime": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz",
@@ -2481,16 +2442,6 @@
"integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY=",
"dev": true
},
"pump": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz",
"integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==",
"dev": true,
"requires": {
"end-of-stream": "^1.1.0",
"once": "^1.3.1"
}
},
"punycode": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
@@ -2530,12 +2481,6 @@
"resolve": "^1.9.0"
}
},
"reduce-flatten": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/reduce-flatten/-/reduce-flatten-2.0.0.tgz",
"integrity": "sha512-EJ4UNY/U1t2P/2k6oqotuX2Cc3T6nxJwsM0N0asT7dhrtH1ltUxDn4NalSYmPE2rCkVpcf/X6R0wDwcFpzhd4w==",
"dev": true
},
"regenerate": {
"version": "1.4.2",
"resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz",
@@ -2755,18 +2700,6 @@
"has-flag": "^3.0.0"
}
},
"table-layout": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/table-layout/-/table-layout-1.0.1.tgz",
"integrity": "sha512-dEquqYNJiGwY7iPfZ3wbXDI944iqanTSchrACLL2nOB+1r+h1Nzu2eH+DuPPvWvm5Ry7iAPeFlgEtP5bIp5U7Q==",
"dev": true,
"requires": {
"array-back": "^4.0.1",
"deep-extend": "~0.6.0",
"typical": "^5.2.0",
"wordwrapjs": "^4.0.0"
}
},
"tapable": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz",
@@ -2856,9 +2789,9 @@
"dev": true
},
"ts-loader": {
"version": "8.0.12",
"resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-8.0.12.tgz",
"integrity": "sha512-UIivVfGVJDdwwjgSrbtcL9Nf10c1BWnL1mxAQUVcnhNIn/P9W3nP5v60Z0aBMtc7ZrE11lMmU6+5jSgAXmGaYw==",
"version": "8.0.13",
"resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-8.0.13.tgz",
"integrity": "sha512-1o1nO6aqouA23d2nlcMSEyPMAWRhnYUU0EQUJSc60E0TUyBNX792RHFYUN1ZM29vhMUNayrsbj2UVdZwKhXCDA==",
"dev": true,
"requires": {
"chalk": "^2.3.0",
@@ -2882,12 +2815,6 @@
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==",
"dev": true
},
"typical": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/typical/-/typical-5.2.0.tgz",
"integrity": "sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg==",
"dev": true
},
"unicode-canonical-property-names-ecmascript": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz",
@@ -2948,9 +2875,9 @@
}
},
"webpack": {
"version": "5.11.0",
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.11.0.tgz",
"integrity": "sha512-ubWv7iP54RqAC/VjixgpnLLogCFbAfSOREcSWnnOlZEU8GICC5eKmJSu6YEnph2N2amKqY9rvxSwgyHxVqpaRw==",
"version": "5.11.1",
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.11.1.tgz",
"integrity": "sha512-tNUIdAmYJv+nupRs/U/gqmADm6fgrf5xE+rSlSsf2PgsGO7j2WG7ccU6AWNlOJlHFl+HnmXlBmHIkiLf+XA9mQ==",
"dev": true,
"requires": {
"@types/eslint-scope": "^3.7.0",
@@ -2980,13 +2907,13 @@
},
"dependencies": {
"enhanced-resolve": {
"version": "5.4.0",
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.4.0.tgz",
"integrity": "sha512-ZmqfWURB2lConOBM1JdCVfPyMRv5RdKWktLXO6123p97ovVm2CLBgw9t5MBj3jJWA6eHyOeIws9iJQoGFR4euQ==",
"version": "5.4.1",
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.4.1.tgz",
"integrity": "sha512-4GbyIMzYktTFoRSmkbgZ1LU+RXwf4AQ8Z+rSuuh1dC8plp0PPeaWvx6+G4hh4KnUJ48VoxKbNyA1QQQIUpXjYA==",
"dev": true,
"requires": {
"graceful-fs": "^4.2.4",
"tapable": "^2.0.0"
"tapable": "^2.2.0"
}
},
"find-up": {
@@ -3129,21 +3056,21 @@
}
},
"webpack-cli": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-4.2.0.tgz",
"integrity": "sha512-EIl3k88vaF4fSxWSgtAQR+VwicfLMTZ9amQtqS4o+TDPW9HGaEpbFBbAZ4A3ZOT5SOnMxNOzROsSTPiE8tBJPA==",
"version": "4.3.1",
"resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-4.3.1.tgz",
"integrity": "sha512-/F4+9QNZM/qKzzL9/06Am8NXIkGV+/NqQ62Dx7DSqudxxpAgBqYn6V7+zp+0Y7JuWksKUbczRY3wMTd+7Uj6OA==",
"dev": true,
"requires": {
"@webpack-cli/info": "^1.1.0",
"@webpack-cli/serve": "^1.1.0",
"@discoveryjs/json-ext": "^0.5.0",
"@webpack-cli/info": "^1.2.1",
"@webpack-cli/serve": "^1.2.1",
"colorette": "^1.2.1",
"command-line-usage": "^6.1.0",
"commander": "^6.2.0",
"enquirer": "^2.3.6",
"execa": "^4.1.0",
"execa": "^5.0.0",
"fastest-levenshtein": "^1.0.12",
"import-local": "^3.0.2",
"interpret": "^2.2.0",
"leven": "^3.1.0",
"rechoir": "^0.7.0",
"v8-compile-cache": "^2.2.0",
"webpack-merge": "^4.2.2"
@@ -3193,22 +3120,6 @@
"isexe": "^2.0.0"
}
},
"wordwrapjs": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/wordwrapjs/-/wordwrapjs-4.0.0.tgz",
"integrity": "sha512-Svqw723a3R34KvsMgpjFBYCgNOSdcW3mQFK4wIfhGQhtaFVOJmdYoXgi63ne3dTlWgatVcUc7t4HtQ/+bUVIzQ==",
"dev": true,
"requires": {
"reduce-flatten": "^2.0.0",
"typical": "^5.0.0"
}
},
"wrappy": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
"dev": true
},
"ws": {
"version": "7.4.1",
"resolved": "https://registry.npmjs.org/ws/-/ws-7.4.1.tgz",
+3 -3
View File
@@ -45,10 +45,10 @@
"babel-plugin-transform-class-properties": "6.24.1",
"cross-env": "7.0.3",
"file-loader": "6.2.0",
"ts-loader": "8.0.12",
"webpack": "5.11.0",
"ts-loader": "8.0.13",
"webpack": "5.11.1",
"webpack-bundle-analyzer": "4.3.0",
"webpack-cli": "4.2.0"
"webpack-cli": "4.3.1"
},
"bugs": "https://github.com/excalidraw/excalidraw/issues",
"repository": "https://github.com/excalidraw/excalidraw",
File diff suppressed because it is too large Load Diff
+2 -2
View File
@@ -2,7 +2,7 @@ import React from "react";
import ReactDOM from "react-dom";
import { render } from "./test-utils";
import ExcalidrawApp from "../excalidraw-app";
import { setLanguage } from "../i18n";
import { defaultLang, setLanguage } from "../i18n";
import { UI, Pointer, Keyboard } from "./helpers/ui";
import { API } from "./helpers/api";
import { KEYS } from "../keys";
@@ -60,7 +60,7 @@ describe("aligning", () => {
ReactDOM.unmountComponentAtNode(document.getElementById("root")!);
mouse.reset();
await setLanguage("en.json");
await setLanguage(defaultLang);
await render(<ExcalidrawApp />);
});
+51 -5
View File
@@ -169,6 +169,12 @@ export class Pointer {
this.click(element.x, element.y);
this.reset();
}
doubleClickOn(element: ExcalidrawElement) {
this.reset();
this.doubleClick(element.x, element.y);
this.reset();
}
}
const mouse = new Pointer("mouse");
@@ -178,32 +184,72 @@ export class UI {
fireEvent.click(GlobalTestState.renderResult.getByToolName(toolName));
};
/**
* Creates an Excalidraw element, and returns a proxy that wraps it so that
* accessing props will return the latest ones from the object existing in
* the app's elements array. This is because across the app lifecycle we tend
* to recreate element objects and the returned reference will become stale.
*
* If you need to get the actual element, not the proxy, call `get()` method
* on the proxy object.
*/
static createElement<T extends ToolName>(
type: T,
{
x = 0,
y = 0,
position = 0,
x = position,
y = position,
size = 10,
width = size,
height = width,
}: {
position?: number;
x?: number;
y?: number;
size?: number;
width?: number;
height?: number;
} = {},
): T extends "arrow" | "line" | "draw"
): (T extends "arrow" | "line" | "draw"
? ExcalidrawLinearElement
: T extends "text"
? ExcalidrawTextElement
: ExcalidrawElement {
: ExcalidrawElement) & {
/** Returns the actual, current element from the elements array, instead
of the proxy */
get(): T extends "arrow" | "line" | "draw"
? ExcalidrawLinearElement
: T extends "text"
? ExcalidrawTextElement
: ExcalidrawElement;
} {
UI.clickTool(type);
mouse.reset();
mouse.down(x, y);
mouse.reset();
mouse.up(x + (width ?? height ?? size), y + (height ?? size));
return h.elements[h.elements.length - 1] as any;
const origElement = h.elements[h.elements.length - 1] as any;
return new Proxy(
{},
{
get(target, prop) {
const currentElement = h.elements.find(
(element) => element.id === origElement.id,
) as any;
if (prop === "get") {
if (currentElement.hasOwnProperty("get")) {
throw new Error(
"trying to get `get` test property, but ExcalidrawElement seems to define its own",
);
}
return () => currentElement;
}
return currentElement[prop];
},
},
) as any;
}
static group(elements: ExcalidrawElement[]) {
+3 -3
View File
@@ -69,9 +69,9 @@ describe("move element", () => {
// bind line to two rectangles
bindOrUnbindLinearElement(
line as NonDeleted<ExcalidrawLinearElement>,
rectA as ExcalidrawRectangleElement,
rectB as ExcalidrawRectangleElement,
line.get() as NonDeleted<ExcalidrawLinearElement>,
rectA.get() as ExcalidrawRectangleElement,
rectB.get() as ExcalidrawRectangleElement,
);
// select the second rectangles
+22 -41
View File
@@ -4,9 +4,8 @@ import ReactDOM from "react-dom";
import { copiedStyles } from "../actions/actionStyles";
import { ShortcutName } from "../actions/shortcuts";
import { ExcalidrawElement } from "../element/types";
import { setLanguage } from "../i18n";
import { CODES, KEYS } from "../keys";
import Excalidraw from "../packages/excalidraw/index";
import ExcalidrawApp from "../excalidraw-app";
import { reseed } from "../random";
import * as Renderer from "../renderer/renderScene";
import { setDateTimeForTests } from "../utils";
@@ -19,6 +18,7 @@ import {
screen,
waitFor,
} from "./test-utils";
import { defaultLang } from "../i18n";
const { h } = window;
@@ -75,8 +75,7 @@ beforeEach(async () => {
finger1.reset();
finger2.reset();
await setLanguage("en.json");
await render(<Excalidraw offsetLeft={0} offsetTop={0} />);
await render(<ExcalidrawApp />);
});
afterEach(() => {
@@ -439,7 +438,7 @@ describe("regression tests", () => {
await waitFor(() => expect(screen.queryByTitle(/thin/i)).toBeNull());
// reset language
fireEvent.change(document.querySelector(".dropdown-select__language")!, {
target: { value: "en" },
target: { value: defaultLang.code },
});
// switching back to English
await waitFor(() => expect(screen.queryByTitle(/thin/i)).not.toBeNull());
@@ -558,64 +557,46 @@ describe("regression tests", () => {
});
it("supports nested groups", () => {
const positions: number[][] = [];
UI.clickTool("rectangle");
mouse.down(10, 10);
mouse.up(10, 10);
positions.push(mouse.getPosition());
UI.clickTool("rectangle");
mouse.down(10, -10);
mouse.up(10, 10);
positions.push(mouse.getPosition());
UI.clickTool("rectangle");
mouse.down(10, -10);
mouse.up(10, 10);
positions.push(mouse.getPosition());
const rectA = UI.createElement("rectangle", { position: 0, size: 50 });
const rectB = UI.createElement("rectangle", { position: 100, size: 50 });
const rectC = UI.createElement("rectangle", { position: 200, size: 50 });
Keyboard.withModifierKeys({ ctrl: true }, () => {
Keyboard.keyPress(KEYS.A);
Keyboard.codePress(CODES.G);
});
mouse.doubleClick();
mouse.doubleClickOn(rectC);
Keyboard.withModifierKeys({ shift: true }, () => {
mouse.restorePosition(...positions[0]);
mouse.click();
mouse.clickOn(rectA);
});
Keyboard.withModifierKeys({ ctrl: true }, () => {
Keyboard.codePress(CODES.G);
});
const groupIds = h.elements[2].groupIds;
expect(groupIds.length).toBe(2);
expect(h.elements[1].groupIds).toEqual(groupIds);
expect(h.elements[0].groupIds).toEqual(groupIds.slice(1));
expect(rectC.groupIds.length).toBe(2);
expect(rectA.groupIds).toEqual(rectC.groupIds);
expect(rectB.groupIds).toEqual(rectA.groupIds.slice(1));
mouse.click(50, 50);
mouse.click(0, 100);
expect(API.getSelectedElements().length).toBe(0);
mouse.restorePosition(...positions[0]);
mouse.click();
mouse.clickOn(rectA);
expect(API.getSelectedElements().length).toBe(3);
expect(h.state.editingGroupId).toBe(null);
mouse.doubleClick();
mouse.doubleClickOn(rectA);
expect(API.getSelectedElements().length).toBe(2);
expect(h.state.editingGroupId).toBe(groupIds[1]);
expect(h.state.editingGroupId).toBe(rectA.groupIds[1]);
mouse.doubleClick();
mouse.doubleClickOn(rectA);
expect(API.getSelectedElements().length).toBe(1);
expect(h.state.editingGroupId).toBe(groupIds[0]);
expect(h.state.editingGroupId).toBe(rectA.groupIds[0]);
// click out of the group
mouse.restorePosition(...positions[1]);
mouse.click();
expect(API.getSelectedElements().length).toBe(0);
mouse.click();
// click outside current (sub)group
mouse.clickOn(rectB);
expect(API.getSelectedElements().length).toBe(3);
mouse.doubleClick();
mouse.doubleClickOn(rectB);
expect(API.getSelectedElements().length).toBe(1);
});
+15 -2
View File
@@ -9,6 +9,7 @@ import {
GroupId,
ExcalidrawBindableElement,
Arrowhead,
ChartType,
} from "./element/types";
import { SHAPES } from "./shapes";
import { Point as RoughPoint } from "roughjs/bin/geometry";
@@ -17,6 +18,8 @@ import { SuggestedBinding } from "./element/binding";
import { ImportedDataState } from "./data/types";
import { ExcalidrawImperativeAPI } from "./components/App";
import type { ResolvablePromise } from "./utils";
import { Spreadsheet } from "./charts";
import { Language } from "./i18n";
export type FlooredNumber = number & { _brand: "FlooredNumber" };
export type Point = Readonly<RoughPoint>;
@@ -67,8 +70,6 @@ export type AppState = {
viewBackgroundColor: string;
scrollX: FlooredNumber;
scrollY: FlooredNumber;
cursorX: number;
cursorY: number;
cursorButton: "up" | "down";
scrolledOutside: boolean;
name: string;
@@ -99,6 +100,16 @@ export type AppState = {
fileHandle: import("browser-nativefs").FileSystemHandle | null;
collaborators: Map<string, Collaborator>;
showStats: boolean;
currentChartType: ChartType;
pasteDialog:
| {
shown: false;
data: null;
}
| {
shown: true;
data: Spreadsheet;
};
};
export type NormalizedZoomValue = number & { _brand: "normalizedZoom" };
@@ -171,6 +182,8 @@ export interface ExcalidrawProps {
appState: AppState,
canvas: HTMLCanvasElement | null,
) => void;
renderFooter?: (isMobile: boolean) => JSX.Element;
langCode?: Language["code"];
}
export type SceneData = {
+5
View File
@@ -8,6 +8,7 @@ import { FontFamily, FontString } from "./element/types";
import { Zoom } from "./types";
import { unstable_batchedUpdates } from "react-dom";
import { isDarwin } from "./keys";
import { t } from "./i18n";
export const SVG_NS = "http://www.w3.org/2000/svg";
@@ -32,6 +33,10 @@ export const getDateTime = () => {
return `${year}-${month}-${day}-${hr}${min}`;
};
export const getNewSceneName = () => {
return `${t("labels.untitled")}-${getDateTime()}`;
};
export const capitalizeString = (str: string) =>
str.charAt(0).toUpperCase() + str.slice(1);