Compare commits

..

21 Commits

Author SHA1 Message Date
Panayiotis Lipiridis 3bc80ea3a3 enum 2021-02-01 14:21:55 +02:00
Panayiotis Lipiridis 7ead1848da const 2021-02-01 14:20:05 +02:00
Panayiotis Lipiridis 7d00d2f9bb audit 2021-02-01 14:19:06 +02:00
Panayiotis Lipiridis 704986042d Fix 2021-02-01 14:14:00 +02:00
Panayiotis Lipiridis da45a0ecbb Merge branch 'cleanipp' of github.com:excalidraw/excalidraw into cleanipp
* 'cleanipp' of github.com:excalidraw/excalidraw:
2021-01-18 16:31:24 +02:00
Panayiotis Lipiridis fde1579884 merge 2021-01-18 16:31:07 +02:00
Lipis e4a0254c47 Merge branch 'master' into cleanipp 2021-01-16 22:37:08 +02:00
Panayiotis Lipiridis 5c7113cb72 sort 2021-01-15 20:26:54 +02:00
Panayiotis Lipiridis 1acd42a44c remove editor config 2021-01-15 19:17:59 +02:00
Panayiotis Lipiridis bf2566d65e Move contributing 2021-01-15 19:16:42 +02:00
Panayiotis Lipiridis 85e8e93d60 more 2021-01-15 18:35:36 +02:00
Panayiotis Lipiridis 1e7dfa692b minor 2021-01-15 18:34:06 +02:00
Panayiotis Lipiridis 1eb8920bc3 Merge branch 'master' of github.com:excalidraw/excalidraw into cleanipp
* 'master' of github.com:excalidraw/excalidraw: (37 commits)
  feat: Add toast (#2772)
  docs: Update readme with documentation (#2788)
  fix: allow text-selecting in dialogs & reset cursor (#2783)
  chore: Update translations from Crowdin (#2742)
  fix: broken Individuals link (#2782)
  refactor: Converting span to kbd tag (#2774)
  fix: don't render due to zoom after unmount (#2779)
  fix: Track the chart type correctly (#2773)
  chore(deps-dev): bump terser-webpack-plugin in /src/packages/excalidraw (#2750)
  chore(deps-dev): bump webpack in /src/packages/utils (#2768)
  fix: delay version logging & prevent duplicates (#2770)
  chore(deps-dev): bump webpack in /src/packages/excalidraw (#2769)
  chore(deps-dev): bump ts-loader in /src/packages/excalidraw (#2749)
  chore(deps-dev): bump ts-loader in /src/packages/utils (#2753)
  chore(deps): bump nanoid from 2.1.11 to 3.1.20 (#2581)
  feat: Track current version (#2731)
  chore(actions): Use cancel workflow action (#2763)
  chore(deps): bump @testing-library/react from 11.2.2 to 11.2.3 (#2755)
  chore(deps-dev): bump firebase-tools from 9.1.0 to 9.1.2 (#2761)
  chore(deps-dev): bump eslint-plugin-prettier from 3.3.0 to 3.3.1 (#2754)
  ...
2021-01-15 18:30:11 +02:00
Panayiotis Lipiridis abacd22c3f remove analytics.md 2021-01-03 20:40:26 +02:00
Panayiotis Lipiridis b05e0709b5 clean 2021-01-03 20:31:46 +02:00
Panayiotis Lipiridis 229aa84668 .excalidraw 2021-01-03 20:28:20 +02:00
Panayiotis Lipiridis 75148f6bac Merge 2021-01-03 20:27:54 +02:00
Panayiotis Lipiridis 154654bb9f 0px 2020-12-28 03:56:39 +02:00
Panayiotis Lipiridis dc2581a308 trans 2020-12-28 01:53:06 +02:00
Panayiotis Lipiridis 428752542d function 2020-12-28 01:26:38 +02:00
Panayiotis Lipiridis 2712a06ab8 refactor: Consistent variable names, remove duplicates/unused in css 2020-12-28 01:05:44 +02:00
89 changed files with 661 additions and 1400 deletions
-12
View File
@@ -1,12 +0,0 @@
# http://EditorConfig.org
# top-level EditorConfig file
root = true
[*]
charset = utf-8
end_of_line = lf
indent_size = 2
indent_style = space
insert_final_newline = true
trim_trailing_whitespace = true
+7
View File
@@ -21,5 +21,12 @@
} }
] ]
} }
],
"redirects": [
{
"source": "/([^.]+)",
"destination": "/",
"statusCode": 301
}
] ]
} }
+42 -58
View File
@@ -2663,86 +2663,70 @@
} }
}, },
"@sentry/browser": { "@sentry/browser": {
"version": "6.0.3", "version": "6.0.1",
"resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-6.0.3.tgz", "resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-6.0.1.tgz",
"integrity": "sha512-Ukxh83Twql4UmUgds9wPWllE62NG71cYvm5AM6daTojvM8wFR2jh7G6GiA0WYfgMb2fw6SlbevB2xb6RDG5DzQ==", "integrity": "sha512-iP8Bqxj4Ye8CXA4ja77buPZfXsKiZYUgHFzBQxVMihTHA8ZZLgBMPLQI6uFfHuJJW+1/yLzOf8BhvF2zknAebg==",
"requires": { "requires": {
"@sentry/core": "6.0.3", "@sentry/core": "6.0.1",
"@sentry/types": "6.0.3", "@sentry/types": "6.0.1",
"@sentry/utils": "6.0.3", "@sentry/utils": "6.0.1",
"tslib": "^1.9.3" "tslib": "^1.9.3"
} }
}, },
"@sentry/core": { "@sentry/core": {
"version": "6.0.3", "version": "6.0.1",
"resolved": "https://registry.npmjs.org/@sentry/core/-/core-6.0.3.tgz", "resolved": "https://registry.npmjs.org/@sentry/core/-/core-6.0.1.tgz",
"integrity": "sha512-UykB/4/98y2DkNvwTiL2ofFPuK3KDHc7rIRNsdj6dg6D+Cf7FRexgmWUUkZrpC/y+QBj0TPqkcFDcZAuQDa3Ag==", "integrity": "sha512-EoxgodyClasI8PA4GyU8Cp88W3R5ebpiLsE7fCcBcOU0DOBRkO8GAZ5IzfCDtYDJ50c9npivum5Oyj2wf8CXYw==",
"requires": { "requires": {
"@sentry/hub": "6.0.3", "@sentry/hub": "6.0.1",
"@sentry/minimal": "6.0.3", "@sentry/minimal": "6.0.1",
"@sentry/types": "6.0.3", "@sentry/types": "6.0.1",
"@sentry/utils": "6.0.3", "@sentry/utils": "6.0.1",
"tslib": "^1.9.3" "tslib": "^1.9.3"
} }
}, },
"@sentry/hub": { "@sentry/hub": {
"version": "6.0.3", "version": "6.0.1",
"resolved": "https://registry.npmjs.org/@sentry/hub/-/hub-6.0.3.tgz", "resolved": "https://registry.npmjs.org/@sentry/hub/-/hub-6.0.1.tgz",
"integrity": "sha512-BfV32tE09rjTWM9W0kk8gzxUC2k1h57Z5dNWJ35na79+LguNNtCcI6fHlFQ3PkJca6ITYof9FI8iQHUfsHFZnw==", "integrity": "sha512-pGckNdhKcr7qYVXgSgA/QVGArATcmQu54YFAR5xTnkWVHpAwNmh0fc4CJCc4JBwS/LXSU1Y0nYiLQduVfnv8Cg==",
"requires": { "requires": {
"@sentry/types": "6.0.3", "@sentry/types": "6.0.1",
"@sentry/utils": "6.0.3", "@sentry/utils": "6.0.1",
"tslib": "^1.9.3" "tslib": "^1.9.3"
} }
}, },
"@sentry/integrations": { "@sentry/integrations": {
"version": "6.0.3", "version": "6.0.1",
"resolved": "https://registry.npmjs.org/@sentry/integrations/-/integrations-6.0.3.tgz", "resolved": "https://registry.npmjs.org/@sentry/integrations/-/integrations-6.0.1.tgz",
"integrity": "sha512-SE/rQ+ttfoC6FlHDibB4e9lV95j78YkjQ6PvYNUe+zGkGIretCJREqgaS+W3qTNYvOdbUViuiiqtdfyvW9nM2g==", "integrity": "sha512-5HGwKW0otSVXSLAJ9ezqlux4AYdeX6ElzQgpm6roWEBXEWf/5OyD0n+M3+yHq4NdQXk2kkfL/0DCyNdy8zZX2Q==",
"requires": { "requires": {
"@sentry/types": "6.0.3", "@sentry/types": "6.0.1",
"@sentry/utils": "6.0.3", "@sentry/utils": "6.0.1",
"localforage": "^1.8.1", "localforage": "1.8.1",
"tslib": "^1.9.3" "tslib": "^1.9.3"
},
"dependencies": {
"@sentry/types": {
"version": "6.0.3",
"resolved": "https://registry.npmjs.org/@sentry/types/-/types-6.0.3.tgz",
"integrity": "sha512-266aBQbk9AGedhG2dzXshWbn23LYLElXqlI74DLku48UrU2v7TGKdyik/8/nfOfquCoRSp0GFGYHbItwU124XQ=="
},
"@sentry/utils": {
"version": "6.0.3",
"resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-6.0.3.tgz",
"integrity": "sha512-lvuBFvZHYs1zYwI8dkC8Z8ryb0aYnwPFUl1rbZiMwJpYI2Dgl1jpqqZWv9luux2rSRYOMid74uGedV708rvEgA==",
"requires": {
"@sentry/types": "6.0.3",
"tslib": "^1.9.3"
}
}
} }
}, },
"@sentry/minimal": { "@sentry/minimal": {
"version": "6.0.3", "version": "6.0.1",
"resolved": "https://registry.npmjs.org/@sentry/minimal/-/minimal-6.0.3.tgz", "resolved": "https://registry.npmjs.org/@sentry/minimal/-/minimal-6.0.1.tgz",
"integrity": "sha512-YsW+nw0SMyyb7UQdjZeKlZjxbGsJFpXNLh9iIp6fHKnoLTTv17YPm2ej9sOikDsQuVotaPg/xn/Qt5wySGHIxw==", "integrity": "sha512-TQ/M5A+OsxtQJ8dzHwrclxKXpJNdQeM1PUoYhff4BvsOXJScvZb7+Yn0OUEQXEc9pSMNt62tnQy4ct80iAMTHw==",
"requires": { "requires": {
"@sentry/hub": "6.0.3", "@sentry/hub": "6.0.1",
"@sentry/types": "6.0.3", "@sentry/types": "6.0.1",
"tslib": "^1.9.3" "tslib": "^1.9.3"
} }
}, },
"@sentry/types": { "@sentry/types": {
"version": "6.0.3", "version": "6.0.1",
"resolved": "https://registry.npmjs.org/@sentry/types/-/types-6.0.3.tgz", "resolved": "https://registry.npmjs.org/@sentry/types/-/types-6.0.1.tgz",
"integrity": "sha512-266aBQbk9AGedhG2dzXshWbn23LYLElXqlI74DLku48UrU2v7TGKdyik/8/nfOfquCoRSp0GFGYHbItwU124XQ==" "integrity": "sha512-cEoe19vtam75Tf6eWmaobfbeV8XwBdr5FJoSVTomzcSsEiP2FHGOEhlE7kVBigzeH5Lri0aibiW6BDi1hIqHdg=="
}, },
"@sentry/utils": { "@sentry/utils": {
"version": "6.0.3", "version": "6.0.1",
"resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-6.0.3.tgz", "resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-6.0.1.tgz",
"integrity": "sha512-lvuBFvZHYs1zYwI8dkC8Z8ryb0aYnwPFUl1rbZiMwJpYI2Dgl1jpqqZWv9luux2rSRYOMid74uGedV708rvEgA==", "integrity": "sha512-bjGuBYnG6fulZ8mLhPGBxttNu96DCN6d7Glw2sfLf4aurn1kjJ/58hP2c8dH0OqWO5e+rGYTsZ5Dr5kqVKNGTg==",
"requires": { "requires": {
"@sentry/types": "6.0.3", "@sentry/types": "6.0.1",
"tslib": "^1.9.3" "tslib": "^1.9.3"
} }
}, },
@@ -11106,9 +11090,9 @@
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
}, },
"ini": { "ini": {
"version": "1.3.5", "version": "1.3.8",
"resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz",
"integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==" "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew=="
}, },
"inquirer": { "inquirer": {
"version": "7.0.4", "version": "7.0.4",
@@ -14262,9 +14246,9 @@
} }
}, },
"localforage": { "localforage": {
"version": "1.9.0", "version": "1.8.1",
"resolved": "https://registry.npmjs.org/localforage/-/localforage-1.9.0.tgz", "resolved": "https://registry.npmjs.org/localforage/-/localforage-1.8.1.tgz",
"integrity": "sha512-rR1oyNrKulpe+VM9cYmcFn6tsHuokyVHFaCM3+osEmxaHTbEk8oQu6eGDfS6DQLWi/N67XRmB8ECG37OES368g==", "integrity": "sha512-azSSJJfc7h4bVpi0PGi+SmLQKJl2/8NErI+LhJsrORNikMZnhaQ7rv9fHj+ofwgSHrKRlsDCL/639a6nECIKuQ==",
"requires": { "requires": {
"lie": "3.1.1" "lie": "3.1.1"
} }
+16 -16
View File
@@ -1,5 +1,10 @@
{ {
"browserslist": { "browserslist": {
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
],
"production": [ "production": [
">0.2%", ">0.2%",
"not dead", "not dead",
@@ -11,16 +16,11 @@
"not chrome < 70", "not chrome < 70",
"not and_uc < 13", "not and_uc < 13",
"not samsung < 10" "not samsung < 10"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
] ]
}, },
"dependencies": { "dependencies": {
"@sentry/browser": "6.0.3", "@sentry/browser": "6.0.1",
"@sentry/integrations": "6.0.3", "@sentry/integrations": "6.0.1",
"@testing-library/jest-dom": "5.11.9", "@testing-library/jest-dom": "5.11.9",
"@testing-library/react": "11.2.3", "@testing-library/react": "11.2.3",
"@types/jest": "26.0.20", "@types/jest": "26.0.20",
@@ -71,34 +71,34 @@
} }
}, },
"jest": { "jest": {
"resetMocks": false,
"transformIgnorePatterns": [ "transformIgnorePatterns": [
"node_modules/(?!(roughjs|points-on-curve|path-data-parser|points-on-path|browser-fs-access)/)" "node_modules/(?!(roughjs|points-on-curve|path-data-parser|points-on-path|browser-fs-access)/)"
], ]
"resetMocks": false
}, },
"name": "excalidraw", "name": "excalidraw",
"private": true, "private": true,
"scripts": { "scripts": {
"build-node": "node ./scripts/build-node.js",
"build:app:docker": "REACT_APP_DISABLE_SENTRY=true react-scripts build",
"build:app": "REACT_APP_GIT_SHA=$VERCEL_GIT_COMMIT_SHA react-scripts build",
"build:version": "node ./scripts/build-version.js",
"build": "npm run build:app && npm run build:version", "build": "npm run build:app && npm run build:version",
"build-node": "node ./scripts/build-node.js",
"build:app": "REACT_APP_GIT_SHA=$VERCEL_GIT_COMMIT_SHA react-scripts build",
"build:app:docker": "REACT_APP_DISABLE_SENTRY=true react-scripts build",
"build:version": "node ./scripts/build-version.js",
"eject": "react-scripts eject", "eject": "react-scripts eject",
"fix": "npm run fix:other && npm run fix:code",
"fix:code": "npm run test:code -- --fix", "fix:code": "npm run test:code -- --fix",
"fix:other": "npm run prettier -- --write", "fix:other": "npm run prettier -- --write",
"fix": "npm run fix:other && npm run fix:code",
"locales-coverage": "node scripts/build-locales-coverage.js", "locales-coverage": "node scripts/build-locales-coverage.js",
"locales-coverage:description": "node scripts/locales-coverage-description.js", "locales-coverage:description": "node scripts/locales-coverage-description.js",
"prettier": "prettier \"**/*.{css,scss,json,md,html,yml}\" --ignore-path=.eslintignore", "prettier": "prettier \"**/*.{css,scss,json,md,html,yml}\" --ignore-path=.eslintignore",
"start": "react-scripts start", "start": "react-scripts start",
"test": "npm run test:app",
"test:all": "npm run test:typecheck && npm run test:code && npm run test:other && npm run test:app -- --watchAll=false", "test:all": "npm run test:typecheck && npm run test:code && npm run test:other && npm run test:app -- --watchAll=false",
"test:app": "react-scripts test --passWithNoTests", "test:app": "react-scripts test --passWithNoTests",
"test:code": "eslint --max-warnings=0 --ignore-path .gitignore --ext .js,.ts,.tsx .", "test:code": "eslint --max-warnings=0 --ignore-path .gitignore --ext .js,.ts,.tsx .",
"test:debug": "react-scripts --inspect-brk test --runInBand --no-cache", "test:debug": "react-scripts --inspect-brk test --runInBand --no-cache",
"test:other": "npm run prettier -- --list-different", "test:other": "npm run prettier -- --list-different",
"test:typecheck": "tsc", "test:typecheck": "tsc",
"test:update": "npm run test:app -- --updateSnapshot --watchAll=false", "test:update": "npm run test:app -- --updateSnapshot --watchAll=false"
"test": "npm run test:app"
} }
} }
+1 -4
View File
@@ -18,7 +18,6 @@ const crowdinMap = {
"id-ID": "en-id", "id-ID": "en-id",
"it-IT": "en-it", "it-IT": "en-it",
"ja-JP": "en-ja", "ja-JP": "en-ja",
"kab-KAB": "en-kab",
"ko-KR": "en-ko", "ko-KR": "en-ko",
"my-MM": "en-my", "my-MM": "en-my",
"nb-NO": "en-nb", "nb-NO": "en-nb",
@@ -41,7 +40,7 @@ const crowdinMap = {
const flags = { const flags = {
"ar-SA": "🇸🇦", "ar-SA": "🇸🇦",
"bg-BG": "🇧🇬", "bg-BG": "🇧🇬",
"ca-ES": "🏳", "ca-ES": "🇪🇸",
"de-DE": "🇩🇪", "de-DE": "🇩🇪",
"el-GR": "🇬🇷", "el-GR": "🇬🇷",
"es-ES": "🇪🇸", "es-ES": "🇪🇸",
@@ -54,7 +53,6 @@ const flags = {
"id-ID": "🇮🇩", "id-ID": "🇮🇩",
"it-IT": "🇮🇹", "it-IT": "🇮🇹",
"ja-JP": "🇯🇵", "ja-JP": "🇯🇵",
"kab-KAB": "🏳",
"ko-KR": "🇰🇷", "ko-KR": "🇰🇷",
"my-MM": "🇲🇲", "my-MM": "🇲🇲",
"nb-NO": "🇳🇴", "nb-NO": "🇳🇴",
@@ -90,7 +88,6 @@ const languages = {
"id-ID": "Bahasa Indonesia", "id-ID": "Bahasa Indonesia",
"it-IT": "Italiano", "it-IT": "Italiano",
"ja-JP": "日本語", "ja-JP": "日本語",
"kab-KAB": "Taqbaylit",
"ko-KR": "한국어", "ko-KR": "한국어",
"my-MM": "Burmese", "my-MM": "Burmese",
"nb-NO": "Norsk bokmål", "nb-NO": "Norsk bokmål",
+2 -2
View File
@@ -3,7 +3,7 @@ import { getDefaultAppState } from "../appState";
import { ColorPicker } from "../components/ColorPicker"; import { ColorPicker } from "../components/ColorPicker";
import { resetZoom, trash, zoomIn, zoomOut } from "../components/icons"; import { resetZoom, trash, zoomIn, zoomOut } from "../components/icons";
import { ToolButton } from "../components/ToolButton"; import { ToolButton } from "../components/ToolButton";
import { GRID_SIZE, ZOOM_STEP } from "../constants"; import { ZOOM_STEP } from "../constants";
import { getCommonBounds, getNonDeletedElements } from "../element"; import { getCommonBounds, getNonDeletedElements } from "../element";
import { newElementWith } from "../element/mutateElement"; import { newElementWith } from "../element/mutateElement";
import { ExcalidrawElement } from "../element/types"; import { ExcalidrawElement } from "../element/types";
@@ -52,7 +52,7 @@ export const actionClearCanvas = register({
elementLocked: appState.elementLocked, elementLocked: appState.elementLocked,
exportBackground: appState.exportBackground, exportBackground: appState.exportBackground,
exportEmbedScene: appState.exportEmbedScene, exportEmbedScene: appState.exportEmbedScene,
gridSize: appState.gridSize || GRID_SIZE, gridSize: appState.gridSize,
shouldAddWatermark: appState.shouldAddWatermark, shouldAddWatermark: appState.shouldAddWatermark,
showStats: appState.showStats, showStats: appState.showStats,
pasteDialog: appState.pasteDialog, pasteDialog: appState.pasteDialog,
+4 -5
View File
@@ -1,21 +1,20 @@
import { trackEvent } from "../analytics";
import { CODES, KEYS } from "../keys"; import { CODES, KEYS } from "../keys";
import { AppState } from "../types";
import { register } from "./register"; import { register } from "./register";
import { GRID_SIZE } from "../constants";
import { AppState } from "../types";
export const actionToggleGridMode = register({ export const actionToggleGridMode = register({
name: "gridMode", name: "gridMode",
perform(elements, appState) { perform(elements, appState) {
trackEvent("view", "mode", "grid");
return { return {
appState: { appState: {
...appState, ...appState,
showGrid: !appState.showGrid, gridSize: this.checked!(appState) ? null : GRID_SIZE,
}, },
commitToHistory: false, commitToHistory: false,
}; };
}, },
checked: (appState: AppState) => appState.showGrid, checked: (appState: AppState) => appState.gridSize !== null,
contextItemLabel: "labels.gridMode", contextItemLabel: "labels.gridMode",
keyTest: (event) => event[KEYS.CTRL_OR_CMD] && event.code === CODES.QUOTE, keyTest: (event) => event[KEYS.CTRL_OR_CMD] && event.code === CODES.QUOTE,
}); });
-22
View File
@@ -1,22 +0,0 @@
import { CODES, KEYS } from "../keys";
import { register } from "./register";
import { trackEvent } from "../analytics";
export const actionToggleViewMode = register({
name: "viewMode",
perform(elements, appState) {
trackEvent("view", "mode", "view");
return {
appState: {
...appState,
viewModeEnabled: !this.checked!(appState),
selectedElementIds: {},
},
commitToHistory: false,
};
},
checked: (appState) => appState.viewModeEnabled,
contextItemLabel: "labels.viewMode",
keyTest: (event) =>
!event[KEYS.CTRL_OR_CMD] && event.altKey && event.code === CODES.R,
});
-3
View File
@@ -1,12 +1,9 @@
import { CODES, KEYS } from "../keys"; import { CODES, KEYS } from "../keys";
import { register } from "./register"; import { register } from "./register";
import { trackEvent } from "../analytics";
export const actionToggleZenMode = register({ export const actionToggleZenMode = register({
name: "zenMode", name: "zenMode",
perform(elements, appState) { perform(elements, appState) {
trackEvent("view", "mode", "zen");
return { return {
appState: { appState: {
...appState, ...appState,
+2 -8
View File
@@ -7,11 +7,11 @@ import {
ActionResult, ActionResult,
} from "./types"; } from "./types";
import { ExcalidrawElement } from "../element/types"; import { ExcalidrawElement } from "../element/types";
import { AppState, ExcalidrawProps } from "../types"; import { AppState } from "../types";
// This is the <App> component, but for now we don't care about anything but its // This is the <App> component, but for now we don't care about anything but its
// `canvas` state. // `canvas` state.
type App = { canvas: HTMLCanvasElement | null; props: ExcalidrawProps }; type App = { canvas: HTMLCanvasElement | null };
export class ActionManager implements ActionsManagerInterface { export class ActionManager implements ActionsManagerInterface {
actions = {} as ActionsManagerInterface["actions"]; actions = {} as ActionsManagerInterface["actions"];
@@ -66,12 +66,6 @@ export class ActionManager implements ActionsManagerInterface {
if (data.length === 0) { if (data.length === 0) {
return false; return false;
} }
const { viewModeEnabled } = this.getAppState();
if (viewModeEnabled) {
if (data[0].name !== "viewMode") {
return false;
}
}
event.preventDefault(); event.preventDefault();
this.updater( this.updater(
+1 -3
View File
@@ -22,8 +22,7 @@ export type ShortcutName =
| "gridMode" | "gridMode"
| "zenMode" | "zenMode"
| "stats" | "stats"
| "addToLibrary" | "addToLibrary";
| "viewMode";
const shortcutMap: Record<ShortcutName, string[]> = { const shortcutMap: Record<ShortcutName, string[]> = {
cut: [getShortcutKey("CtrlOrCmd+X")], cut: [getShortcutKey("CtrlOrCmd+X")],
@@ -57,7 +56,6 @@ const shortcutMap: Record<ShortcutName, string[]> = {
zenMode: [getShortcutKey("Alt+Z")], zenMode: [getShortcutKey("Alt+Z")],
stats: [], stats: [],
addToLibrary: [], addToLibrary: [],
viewMode: [getShortcutKey("Alt+R")],
}; };
export const getShortcutFromShortcutName = (name: ShortcutName) => { export const getShortcutFromShortcutName = (name: ShortcutName) => {
+1 -2
View File
@@ -84,8 +84,7 @@ export type ActionName =
| "alignVerticallyCentered" | "alignVerticallyCentered"
| "alignHorizontallyCentered" | "alignHorizontallyCentered"
| "distributeHorizontally" | "distributeHorizontally"
| "distributeVertically" | "distributeVertically";
| "viewMode";
export interface Action { export interface Action {
name: ActionName; name: ActionName;
+1 -6
View File
@@ -3,7 +3,6 @@ import {
DEFAULT_FONT_FAMILY, DEFAULT_FONT_FAMILY,
DEFAULT_FONT_SIZE, DEFAULT_FONT_SIZE,
DEFAULT_TEXT_ALIGN, DEFAULT_TEXT_ALIGN,
GRID_SIZE,
} from "./constants"; } from "./constants";
import { t } from "./i18n"; import { t } from "./i18n";
import { AppState, NormalizedZoomValue } from "./types"; import { AppState, NormalizedZoomValue } from "./types";
@@ -42,7 +41,7 @@ export const getDefaultAppState = (): Omit<
exportBackground: true, exportBackground: true,
exportEmbedScene: false, exportEmbedScene: false,
fileHandle: null, fileHandle: null,
gridSize: GRID_SIZE, gridSize: null,
height: window.innerHeight, height: window.innerHeight,
isBindingEnabled: true, isBindingEnabled: true,
isLibraryOpen: false, isLibraryOpen: false,
@@ -64,7 +63,6 @@ export const getDefaultAppState = (): Omit<
selectionElement: null, selectionElement: null,
shouldAddWatermark: false, shouldAddWatermark: false,
shouldCacheIgnoreZoom: false, shouldCacheIgnoreZoom: false,
showGrid: false,
showHelpDialog: false, showHelpDialog: false,
showStats: false, showStats: false,
startBoundElement: null, startBoundElement: null,
@@ -74,7 +72,6 @@ export const getDefaultAppState = (): Omit<
width: window.innerWidth, width: window.innerWidth,
zenModeEnabled: false, zenModeEnabled: false,
zoom: { value: 1 as NormalizedZoomValue, translation: { x: 0, y: 0 } }, zoom: { value: 1 as NormalizedZoomValue, translation: { x: 0, y: 0 } },
viewModeEnabled: false,
}; };
}; };
@@ -122,7 +119,6 @@ const APP_STATE_STORAGE_CONF = (<
exportEmbedScene: { browser: true, export: false }, exportEmbedScene: { browser: true, export: false },
fileHandle: { browser: false, export: false }, fileHandle: { browser: false, export: false },
gridSize: { browser: true, export: true }, gridSize: { browser: true, export: true },
showGrid: { browser: true, export: false },
height: { browser: false, export: false }, height: { browser: false, export: false },
isBindingEnabled: { browser: false, export: false }, isBindingEnabled: { browser: false, export: false },
isLibraryOpen: { browser: false, export: false }, isLibraryOpen: { browser: false, export: false },
@@ -155,7 +151,6 @@ const APP_STATE_STORAGE_CONF = (<
width: { browser: false, export: false }, width: { browser: false, export: false },
zenModeEnabled: { browser: true, export: false }, zenModeEnabled: { browser: true, export: false },
zoom: { browser: true, export: false }, zoom: { browser: true, export: false },
viewModeEnabled: { browser: false, export: false },
}); });
const _clearAppStateForStorage = <ExportType extends "export" | "browser">( const _clearAppStateForStorage = <ExportType extends "export" | "browser">(
+58 -186
View File
@@ -2,8 +2,6 @@ import { Point, simplify } from "points-on-curve";
import React from "react"; import React from "react";
import { RoughCanvas } from "roughjs/bin/canvas"; import { RoughCanvas } from "roughjs/bin/canvas";
import rough from "roughjs/bin/rough"; import rough from "roughjs/bin/rough";
import clsx from "clsx";
import "../actions"; import "../actions";
import { import {
actionAddToLibrary, actionAddToLibrary,
@@ -177,11 +175,10 @@ import {
withBatchedUpdates, withBatchedUpdates,
} from "../utils"; } from "../utils";
import { isMobile } from "../is-mobile"; import { isMobile } from "../is-mobile";
import ContextMenu, { ContextMenuOption } from "./ContextMenu"; import ContextMenu from "./ContextMenu";
import LayerUI from "./LayerUI"; import LayerUI from "./LayerUI";
import { Stats } from "./Stats"; import { Stats } from "./Stats";
import { Toast } from "./Toast"; import { Toast } from "./Toast";
import { actionToggleViewMode } from "../actions/actionToggleViewMode";
const { history } = createHistory(); const { history } = createHistory();
@@ -298,7 +295,6 @@ class App extends React.Component<ExcalidrawProps, AppState> {
offsetLeft, offsetLeft,
offsetTop, offsetTop,
excalidrawRef, excalidrawRef,
viewModeEnabled = false,
} = props; } = props;
this.state = { this.state = {
...defaultAppState, ...defaultAppState,
@@ -306,7 +302,6 @@ class App extends React.Component<ExcalidrawProps, AppState> {
width, width,
height, height,
...this.getCanvasOffsets({ offsetLeft, offsetTop }), ...this.getCanvasOffsets({ offsetLeft, offsetTop }),
viewModeEnabled,
}; };
if (excalidrawRef) { if (excalidrawRef) {
const readyPromise = const readyPromise =
@@ -347,62 +342,6 @@ class App extends React.Component<ExcalidrawProps, AppState> {
this.actionManager.registerAction(createRedoAction(history)); this.actionManager.registerAction(createRedoAction(history));
} }
private renderCanvas() {
const canvasScale = window.devicePixelRatio;
const {
width: canvasDOMWidth,
height: canvasDOMHeight,
viewModeEnabled,
} = this.state;
const canvasWidth = canvasDOMWidth * canvasScale;
const canvasHeight = canvasDOMHeight * canvasScale;
if (viewModeEnabled) {
return (
<canvas
id="canvas"
style={{
width: canvasDOMWidth,
height: canvasDOMHeight,
cursor: "grabbing",
}}
width={canvasWidth}
height={canvasHeight}
ref={this.handleCanvasRef}
onContextMenu={this.handleCanvasContextMenu}
onPointerMove={this.handleCanvasPointerMove}
onPointerUp={this.removePointer}
onPointerCancel={this.removePointer}
onTouchMove={this.handleTouchMove}
onPointerDown={this.handleCanvasPointerDown}
>
{t("labels.drawingCanvas")}
</canvas>
);
}
return (
<canvas
id="canvas"
style={{
width: canvasDOMWidth,
height: canvasDOMHeight,
}}
width={canvasWidth}
height={canvasHeight}
ref={this.handleCanvasRef}
onContextMenu={this.handleCanvasContextMenu}
onPointerDown={this.handleCanvasPointerDown}
onDoubleClick={this.handleCanvasDoubleClick}
onPointerMove={this.handleCanvasPointerMove}
onPointerUp={this.removePointer}
onPointerCancel={this.removePointer}
onTouchMove={this.handleTouchMove}
onDrop={this.handleCanvasOnDrop}
>
{t("labels.drawingCanvas")}
</canvas>
);
}
public render() { public render() {
const { const {
zenModeEnabled, zenModeEnabled,
@@ -410,19 +349,20 @@ class App extends React.Component<ExcalidrawProps, AppState> {
height: canvasDOMHeight, height: canvasDOMHeight,
offsetTop, offsetTop,
offsetLeft, offsetLeft,
viewModeEnabled,
} = this.state; } = this.state;
const { onCollabButtonClick, onExportToBackend, renderFooter } = this.props; const { onCollabButtonClick, onExportToBackend, renderFooter } = this.props;
const canvasScale = window.devicePixelRatio;
const canvasWidth = canvasDOMWidth * canvasScale;
const canvasHeight = canvasDOMHeight * canvasScale;
const DEFAULT_PASTE_X = canvasDOMWidth / 2; const DEFAULT_PASTE_X = canvasDOMWidth / 2;
const DEFAULT_PASTE_Y = canvasDOMHeight / 2; const DEFAULT_PASTE_Y = canvasDOMHeight / 2;
return ( return (
<div <div
className={clsx("excalidraw", { className="excalidraw"
"excalidraw--view-mode": viewModeEnabled,
})}
ref={this.excalidrawContainerRef} ref={this.excalidrawContainerRef}
style={{ style={{
width: canvasDOMWidth, width: canvasDOMWidth,
@@ -452,11 +392,9 @@ class App extends React.Component<ExcalidrawProps, AppState> {
isCollaborating={this.props.isCollaborating || false} isCollaborating={this.props.isCollaborating || false}
onExportToBackend={onExportToBackend} onExportToBackend={onExportToBackend}
renderCustomFooter={renderFooter} renderCustomFooter={renderFooter}
viewModeEnabled={viewModeEnabled}
/> />
{this.state.showStats && ( {this.state.showStats && (
<Stats <Stats
setAppState={this.setAppState}
appState={this.state} appState={this.state}
elements={this.scene.getElements()} elements={this.scene.getElements()}
onClose={this.toggleStats} onClose={this.toggleStats}
@@ -468,7 +406,28 @@ class App extends React.Component<ExcalidrawProps, AppState> {
clearToast={this.clearToast} clearToast={this.clearToast}
/> />
)} )}
<main>{this.renderCanvas()}</main> <main>
<canvas
id="canvas"
style={{
width: canvasDOMWidth,
height: canvasDOMHeight,
}}
width={canvasWidth}
height={canvasHeight}
ref={this.handleCanvasRef}
onContextMenu={this.handleCanvasContextMenu}
onPointerDown={this.handleCanvasPointerDown}
onDoubleClick={this.handleCanvasDoubleClick}
onPointerMove={this.handleCanvasPointerMove}
onPointerUp={this.removePointer}
onPointerCancel={this.removePointer}
onTouchMove={this.handleTouchMove}
onDrop={this.handleCanvasOnDrop}
>
{t("labels.drawingCanvas")}
</canvas>
</main>
</div> </div>
); );
} }
@@ -508,13 +467,6 @@ class App extends React.Component<ExcalidrawProps, AppState> {
if (actionResult.commitToHistory) { if (actionResult.commitToHistory) {
history.resumeRecording(); history.resumeRecording();
} }
let viewModeEnabled = actionResult?.appState?.viewModeEnabled || false;
if (typeof this.props.viewModeEnabled !== "undefined") {
viewModeEnabled = this.props.viewModeEnabled;
}
this.setState( this.setState(
(state) => ({ (state) => ({
...actionResult.appState, ...actionResult.appState,
@@ -524,7 +476,6 @@ class App extends React.Component<ExcalidrawProps, AppState> {
height: state.height, height: state.height,
offsetTop: state.offsetTop, offsetTop: state.offsetTop,
offsetLeft: state.offsetLeft, offsetLeft: state.offsetLeft,
viewModeEnabled,
}), }),
() => { () => {
if (actionResult.syncHistory) { if (actionResult.syncHistory) {
@@ -707,6 +658,7 @@ class App extends React.Component<ExcalidrawProps, AppState> {
} }
this.scene.addCallback(this.onSceneUpdated); this.scene.addCallback(this.onSceneUpdated);
this.addEventListeners(); this.addEventListeners();
// optim to avoid extra render on init // optim to avoid extra render on init
@@ -773,16 +725,25 @@ class App extends React.Component<ExcalidrawProps, AppState> {
} }
private addEventListeners() { private addEventListeners() {
this.removeEventListeners();
document.addEventListener(EVENT.COPY, this.onCopy); document.addEventListener(EVENT.COPY, this.onCopy);
document.addEventListener(EVENT.PASTE, this.pasteFromClipboard);
document.addEventListener(EVENT.CUT, this.onCut);
document.addEventListener(EVENT.KEYDOWN, this.onKeyDown, false); document.addEventListener(EVENT.KEYDOWN, this.onKeyDown, false);
document.addEventListener(EVENT.KEYUP, this.onKeyUp, { passive: true }); document.addEventListener(EVENT.KEYUP, this.onKeyUp, { passive: true });
document.addEventListener( document.addEventListener(
EVENT.MOUSE_MOVE, EVENT.MOUSE_MOVE,
this.updateCurrentCursorPosition, this.updateCurrentCursorPosition,
); );
window.addEventListener(EVENT.RESIZE, this.onResize, false);
window.addEventListener(EVENT.UNLOAD, this.onUnload, false);
window.addEventListener(EVENT.BLUR, this.onBlur, false);
window.addEventListener(EVENT.DRAG_OVER, this.disableEvent, false);
window.addEventListener(EVENT.DROP, this.disableEvent, false);
// rerender text elements on font load to fix #637 && #1553 // rerender text elements on font load to fix #637 && #1553
document.fonts?.addEventListener?.("loadingdone", this.onFontLoaded); document.fonts?.addEventListener?.("loadingdone", this.onFontLoaded);
// Safari-only desktop pinch zoom // Safari-only desktop pinch zoom
document.addEventListener( document.addEventListener(
EVENT.GESTURE_START, EVENT.GESTURE_START,
@@ -799,18 +760,6 @@ class App extends React.Component<ExcalidrawProps, AppState> {
this.onGestureEnd as any, this.onGestureEnd as any,
false, false,
); );
if (this.state.viewModeEnabled) {
return;
}
document.addEventListener(EVENT.PASTE, this.pasteFromClipboard);
document.addEventListener(EVENT.CUT, this.onCut);
window.addEventListener(EVENT.RESIZE, this.onResize, false);
window.addEventListener(EVENT.UNLOAD, this.onUnload, false);
window.addEventListener(EVENT.BLUR, this.onBlur, false);
window.addEventListener(EVENT.DRAG_OVER, this.disableEvent, false);
window.addEventListener(EVENT.DROP, this.disableEvent, false);
} }
componentDidUpdate(prevProps: ExcalidrawProps, prevState: AppState) { componentDidUpdate(prevProps: ExcalidrawProps, prevState: AppState) {
@@ -833,17 +782,6 @@ class App extends React.Component<ExcalidrawProps, AppState> {
}); });
} }
if (prevProps.viewModeEnabled !== this.props.viewModeEnabled) {
this.setState(
{ viewModeEnabled: !!this.props.viewModeEnabled },
this.addEventListeners,
);
}
if (prevState.viewModeEnabled !== this.state.viewModeEnabled) {
this.addEventListeners();
}
document document
.querySelector(".excalidraw") .querySelector(".excalidraw")
?.classList.toggle("Appearance_dark", this.state.appearance === "dark"); ?.classList.toggle("Appearance_dark", this.state.appearance === "dark");
@@ -1088,12 +1026,7 @@ class App extends React.Component<ExcalidrawProps, AppState> {
const dy = y - elementsCenterY; const dy = y - elementsCenterY;
const groupIdMap = new Map(); const groupIdMap = new Map();
const [gridX, gridY] = getGridPoint( const [gridX, gridY] = getGridPoint(dx, dy, this.state.gridSize);
dx,
dy,
this.state.showGrid,
this.state.gridSize,
);
const oldIdToDuplicatedId = new Map(); const oldIdToDuplicatedId = new Map();
const newElements = clipboardElements.map((element) => { const newElements = clipboardElements.map((element) => {
@@ -1299,25 +1232,21 @@ class App extends React.Component<ExcalidrawProps, AppState> {
}); });
} }
if (this.actionManager.handleKeyDown(event)) {
return;
}
if (this.state.viewModeEnabled) {
return;
}
if (event[KEYS.CTRL_OR_CMD]) { if (event[KEYS.CTRL_OR_CMD]) {
this.setState({ isBindingEnabled: false }); this.setState({ isBindingEnabled: false });
} }
if (this.actionManager.handleKeyDown(event)) {
return;
}
if (event.code === CODES.NINE) { if (event.code === CODES.NINE) {
this.setState({ isLibraryOpen: !this.state.isLibraryOpen }); this.setState({ isLibraryOpen: !this.state.isLibraryOpen });
} }
if (isArrowKey(event.key)) { if (isArrowKey(event.key)) {
const step = const step =
(this.state.showGrid && (this.state.gridSize &&
(event.shiftKey ? ELEMENT_TRANSLATE_AMOUNT : this.state.gridSize)) || (event.shiftKey ? ELEMENT_TRANSLATE_AMOUNT : this.state.gridSize)) ||
(event.shiftKey (event.shiftKey
? ELEMENT_SHIFT_TRANSLATE_AMOUNT ? ELEMENT_SHIFT_TRANSLATE_AMOUNT
@@ -1859,7 +1788,6 @@ class App extends React.Component<ExcalidrawProps, AppState> {
scenePointerX, scenePointerX,
scenePointerY, scenePointerY,
this.state.editingLinearElement, this.state.editingLinearElement,
this.state.showGrid,
this.state.gridSize, this.state.gridSize,
); );
if (editingLinearElement !== this.state.editingLinearElement) { if (editingLinearElement !== this.state.editingLinearElement) {
@@ -2118,16 +2046,14 @@ class App extends React.Component<ExcalidrawProps, AppState> {
lastPointerUp = onPointerUp; lastPointerUp = onPointerUp;
if (!this.state.viewModeEnabled) { window.addEventListener(EVENT.POINTER_MOVE, onPointerMove);
window.addEventListener(EVENT.POINTER_MOVE, onPointerMove); window.addEventListener(EVENT.POINTER_UP, onPointerUp);
window.addEventListener(EVENT.POINTER_UP, onPointerUp); window.addEventListener(EVENT.KEYDOWN, onKeyDown);
window.addEventListener(EVENT.KEYDOWN, onKeyDown); window.addEventListener(EVENT.KEYUP, onKeyUp);
window.addEventListener(EVENT.KEYUP, onKeyUp); pointerDownState.eventListeners.onMove = onPointerMove;
pointerDownState.eventListeners.onMove = onPointerMove; pointerDownState.eventListeners.onUp = onPointerUp;
pointerDownState.eventListeners.onUp = onPointerUp; pointerDownState.eventListeners.onKeyUp = onKeyUp;
pointerDownState.eventListeners.onKeyUp = onKeyUp; pointerDownState.eventListeners.onKeyDown = onKeyDown;
pointerDownState.eventListeners.onKeyDown = onKeyDown;
}
}; };
private maybeOpenContextMenuAfterPointerDownOnTouchDevices = ( private maybeOpenContextMenuAfterPointerDownOnTouchDevices = (
@@ -2177,8 +2103,7 @@ class App extends React.Component<ExcalidrawProps, AppState> {
!( !(
gesture.pointers.size === 0 && gesture.pointers.size === 0 &&
(event.button === POINTER_BUTTON.WHEEL || (event.button === POINTER_BUTTON.WHEEL ||
(event.button === POINTER_BUTTON.MAIN && isHoldingSpace) || (event.button === POINTER_BUTTON.MAIN && isHoldingSpace))
this.state.viewModeEnabled)
) )
) { ) {
return false; return false;
@@ -2289,12 +2214,7 @@ class App extends React.Component<ExcalidrawProps, AppState> {
return { return {
origin, origin,
originInGrid: tupleToCoors( originInGrid: tupleToCoors(
getGridPoint( getGridPoint(origin.x, origin.y, this.state.gridSize),
origin.x,
origin.y,
this.state.showGrid,
this.state.gridSize,
),
), ),
scrollbars: isOverScrollBars( scrollbars: isOverScrollBars(
currentScrollBars, currentScrollBars,
@@ -2650,8 +2570,7 @@ class App extends React.Component<ExcalidrawProps, AppState> {
const [gridX, gridY] = getGridPoint( const [gridX, gridY] = getGridPoint(
pointerDownState.origin.x, pointerDownState.origin.x,
pointerDownState.origin.y, pointerDownState.origin.y,
elementType === "draw" ? false : this.state.showGrid, elementType === "draw" ? null : this.state.gridSize,
this.state.gridSize,
); );
/* If arrow is pre-arrowheads, it will have undefined for both start and end arrowheads. /* If arrow is pre-arrowheads, it will have undefined for both start and end arrowheads.
@@ -2713,7 +2632,6 @@ class App extends React.Component<ExcalidrawProps, AppState> {
const [gridX, gridY] = getGridPoint( const [gridX, gridY] = getGridPoint(
pointerDownState.origin.x, pointerDownState.origin.x,
pointerDownState.origin.y, pointerDownState.origin.y,
this.state.showGrid,
this.state.gridSize, this.state.gridSize,
); );
const element = newElement({ const element = newElement({
@@ -2803,7 +2721,6 @@ class App extends React.Component<ExcalidrawProps, AppState> {
const [gridX, gridY] = getGridPoint( const [gridX, gridY] = getGridPoint(
pointerCoords.x, pointerCoords.x,
pointerCoords.y, pointerCoords.y,
this.state.showGrid,
this.state.gridSize, this.state.gridSize,
); );
@@ -2876,7 +2793,6 @@ class App extends React.Component<ExcalidrawProps, AppState> {
const [dragX, dragY] = getGridPoint( const [dragX, dragY] = getGridPoint(
pointerCoords.x - pointerDownState.drag.offset.x, pointerCoords.x - pointerDownState.drag.offset.x,
pointerCoords.y - pointerDownState.drag.offset.y, pointerCoords.y - pointerDownState.drag.offset.y,
this.state.showGrid,
this.state.gridSize, this.state.gridSize,
); );
@@ -2929,7 +2845,6 @@ class App extends React.Component<ExcalidrawProps, AppState> {
const [originDragX, originDragY] = getGridPoint( const [originDragX, originDragY] = getGridPoint(
pointerDownState.origin.x - pointerDownState.drag.offset.x, pointerDownState.origin.x - pointerDownState.drag.offset.x,
pointerDownState.origin.y - pointerDownState.drag.offset.y, pointerDownState.origin.y - pointerDownState.drag.offset.y,
this.state.showGrid,
this.state.gridSize, this.state.gridSize,
); );
mutateElement(duplicatedElement, { mutateElement(duplicatedElement, {
@@ -3586,7 +3501,6 @@ class App extends React.Component<ExcalidrawProps, AppState> {
const [gridX, gridY] = getGridPoint( const [gridX, gridY] = getGridPoint(
pointerCoords.x, pointerCoords.x,
pointerCoords.y, pointerCoords.y,
this.state.showGrid,
this.state.gridSize, this.state.gridSize,
); );
dragNewElement( dragNewElement(
@@ -3625,7 +3539,6 @@ class App extends React.Component<ExcalidrawProps, AppState> {
const [resizeX, resizeY] = getGridPoint( const [resizeX, resizeY] = getGridPoint(
pointerCoords.x - pointerDownState.resize.offset.x, pointerCoords.x - pointerDownState.resize.offset.x,
pointerCoords.y - pointerDownState.resize.offset.y, pointerCoords.y - pointerDownState.resize.offset.y,
this.state.showGrid,
this.state.gridSize, this.state.gridSize,
); );
if ( if (
@@ -3677,36 +3590,7 @@ class App extends React.Component<ExcalidrawProps, AppState> {
const elements = this.scene.getElements(); const elements = this.scene.getElements();
const element = this.getElementAtPosition(x, y); const element = this.getElementAtPosition(x, y);
const options: ContextMenuOption[] = [];
if (probablySupportsClipboardBlob && elements.length > 0) {
options.push(actionCopyAsPng);
}
if (probablySupportsClipboardWriteText && elements.length > 0) {
options.push(actionCopyAsSvg);
}
if (!element) { if (!element) {
const viewModeOptions: ContextMenuOption[] = [
...options,
actionToggleStats,
];
if (typeof this.props.viewModeEnabled === "undefined") {
viewModeOptions.push(actionToggleViewMode);
}
ContextMenu.push({
options: viewModeOptions,
top: clientY,
left: clientX,
actionManager: this.actionManager,
appState: this.state,
});
if (this.state.viewModeEnabled) {
return;
}
ContextMenu.push({ ContextMenu.push({
options: [ options: [
_isMobile && _isMobile &&
@@ -3734,8 +3618,6 @@ class App extends React.Component<ExcalidrawProps, AppState> {
separator, separator,
actionToggleGridMode, actionToggleGridMode,
actionToggleZenMode, actionToggleZenMode,
typeof this.props.viewModeEnabled === "undefined" &&
actionToggleViewMode,
actionToggleStats, actionToggleStats,
], ],
top: clientY, top: clientY,
@@ -3750,17 +3632,6 @@ class App extends React.Component<ExcalidrawProps, AppState> {
this.setState({ selectedElementIds: { [element.id]: true } }); this.setState({ selectedElementIds: { [element.id]: true } });
} }
if (this.state.viewModeEnabled) {
ContextMenu.push({
options: [navigator.clipboard && actionCopy, ...options],
top: clientY,
left: clientX,
actionManager: this.actionManager,
appState: this.state,
});
return;
}
ContextMenu.push({ ContextMenu.push({
options: [ options: [
_isMobile && actionCut, _isMobile && actionCut,
@@ -3777,7 +3648,8 @@ class App extends React.Component<ExcalidrawProps, AppState> {
contextItemLabel: "labels.paste", contextItemLabel: "labels.paste",
}, },
_isMobile && separator, _isMobile && separator,
...options, probablySupportsClipboardBlob && actionCopyAsPng,
probablySupportsClipboardWriteText && actionCopyAsSvg,
separator, separator,
actionCopyStyles, actionCopyStyles,
actionPasteStyles, actionPasteStyles,
+2 -2
View File
@@ -14,11 +14,11 @@ export const ButtonIconCycle = <T extends any>({
}) => { }) => {
const current = options.find((op) => op.value === value); const current = options.find((op) => op.value === value);
function cycle() { const cycle = () => {
const index = options.indexOf(current!); const index = options.indexOf(current!);
const next = (index + 1) % options.length; const next = (index + 1) % options.length;
onChange(options[next].value); onChange(options[next].value);
} };
return ( return (
<label key={group} className={clsx({ active: current!.value !== null })}> <label key={group} className={clsx({ active: current!.value !== null })}>
+1 -1
View File
@@ -2,7 +2,7 @@
.excalidraw { .excalidraw {
.CollabButton.is-collaborating { .CollabButton.is-collaborating {
background-color: var(--button-special-active-background-color); background-color: var(--button-special-active-bg-color);
.ToolIcon__icon svg { .ToolIcon__icon svg {
color: var(--icon-green-fill-color); color: var(--icon-green-fill-color);
+20 -20
View File
@@ -2,9 +2,9 @@
.excalidraw { .excalidraw {
.color-picker { .color-picker {
background: var(--popup-background-color); background: var(--popup-bg-color);
border: 0px solid transparentize($oc-white, 0.75); border: 0 solid transparentize($oc-white, 0.75);
box-shadow: transparentize($oc-black, 0.75) 0px 1px 4px; box-shadow: transparentize($oc-black, 0.75) 0 1px 4px;
border-radius: 4px; border-radius: 4px;
position: absolute; position: absolute;
@@ -24,11 +24,11 @@
} }
.color-picker-triangle { .color-picker-triangle {
width: 0px; width: 0;
height: 0px; height: 0;
border-style: solid; border-style: solid;
border-width: 0px 9px 10px; border-width: 0 9px 10px;
border-color: transparent transparent var(--popup-background-color); border-color: transparent transparent var(--popup-bg-color);
position: absolute; position: absolute;
top: -10px; top: -10px;
@@ -84,12 +84,12 @@
.color-picker-transparent { .color-picker-transparent {
border-radius: 4px; border-radius: 4px;
box-shadow: transparentize($oc-black, 0.9) 0px 0px 0px 1px inset; box-shadow: transparentize($oc-black, 0.9) 0 0 0 1px inset;
position: absolute; position: absolute;
top: 0px; top: 0;
right: 0px; right: 0;
bottom: 0px; bottom: 0;
left: 0px; left: 0;
} }
.color-picker-transparent, .color-picker-transparent,
@@ -104,11 +104,11 @@
width: 1.875rem; width: 1.875rem;
:root[dir="ltr"] & { :root[dir="ltr"] & {
border-radius: 4px 0px 0px 4px; border-radius: 4px 0 0 4px;
} }
:root[dir="rtl"] & { :root[dir="rtl"] & {
border-radius: 0px 4px 4px 0px; border-radius: 0 4px 4px 0;
} }
color: var(--input-label-color); color: var(--input-label-color);
@@ -144,7 +144,7 @@
} }
.color-input-container:focus-within .color-picker-hash::after { .color-input-container:focus-within .color-picker-hash::after {
background: var(--input-background-color); background: var(--input-bg-color);
:root[dir="ltr"] & { :root[dir="ltr"] & {
right: -2px; right: -2px;
@@ -163,19 +163,19 @@
width: 12ch; /* length of `transparent` + 1 */ width: 12ch; /* length of `transparent` + 1 */
margin: 0; margin: 0;
font-size: 1rem; font-size: 1rem;
background-color: var(--input-background-color); background-color: var(--input-bg-color);
color: var(--text-color-primary); color: var(--text-color-primary);
border: 0px; border: 0;
outline: none; outline: none;
height: 1.75em; height: 1.75em;
box-shadow: var(--input-border-color) 0px 0px 0px 1px inset; box-shadow: var(--input-border-color) 0 0 0 1px inset;
:root[dir="ltr"] & { :root[dir="ltr"] & {
border-radius: 0px 4px 4px 0px; border-radius: 0 4px 4px 0;
} }
:root[dir="rtl"] & { :root[dir="rtl"] & {
border-radius: 4px 0px 0px 4px; border-radius: 4px 0 0 4px;
} }
float: left; float: left;
+4 -4
View File
@@ -4,13 +4,13 @@
.context-menu { .context-menu {
position: relative; position: relative;
border-radius: 4px; border-radius: 4px;
box-shadow: 0px 3px 10px transparentize($oc-black, 0.8); box-shadow: 0 3px 10px transparentize($oc-black, 0.8);
padding: 0; padding: 0;
list-style: none; list-style: none;
user-select: none; user-select: none;
margin: -0.25rem 0 0 0.125rem; margin: -0.25rem 0 0 0.125rem;
padding: 0.5rem 0; padding: 0.5rem 0;
background-color: var(--popup-secondary-background-color); background-color: var(--popup-secondary-bg-color);
border: 1px solid var(--button-gray-3); border: 1px solid var(--button-gray-3);
cursor: default; cursor: default;
} }
@@ -61,12 +61,12 @@
} }
.context-menu-option:hover { .context-menu-option:hover {
color: var(--popup-background-color); color: var(--popup-bg-color);
background-color: var(--select-highlight-color); background-color: var(--select-highlight-color);
&.dangerous { &.dangerous {
.context-menu-option__label { .context-menu-option__label {
color: var(--popup-background-color); color: var(--popup-bg-color);
} }
background-color: $oc-red-6; background-color: $oc-red-6;
} }
+1 -1
View File
@@ -13,7 +13,7 @@ import { Action } from "../actions/types";
import { ActionManager } from "../actions/manager"; import { ActionManager } from "../actions/manager";
import { AppState } from "../types"; import { AppState } from "../types";
export type ContextMenuOption = "separator" | Action; type ContextMenuOption = "separator" | Action;
type ContextMenuProps = { type ContextMenuProps = {
options: ContextMenuOption[]; options: ContextMenuOption[];
+1 -1
View File
@@ -45,7 +45,7 @@
position: sticky; position: sticky;
top: 0; top: 0;
padding: calc(var(--space-factor) * 2); padding: calc(var(--space-factor) * 2);
background: var(--bg-color-island); background: var(--island-bg-color);
font-size: 1.25em; font-size: 1.25em;
box-sizing: border-box; box-sizing: border-box;
-4
View File
@@ -227,10 +227,6 @@ export const HelpDialog = ({ onClose }: { onClose?: () => void }) => {
label={t("labels.gridMode")} label={t("labels.gridMode")}
shortcuts={[getShortcutKey("CtrlOrCmd+'")]} shortcuts={[getShortcutKey("CtrlOrCmd+'")]}
/> />
<Shortcut
label={t("labels.viewMode")}
shortcuts={[getShortcutKey("Alt+R")]}
/>
</ShortcutIsland> </ShortcutIsland>
</Column> </Column>
<Column> <Column>
+1 -1
View File
@@ -26,7 +26,7 @@ $wide-viewport-width: 1000px;
> span { > span {
padding: 0.2rem 0.4rem; padding: 0.2rem 0.4rem;
background-color: var(--overlay-background-color); background-color: var(--overlay-bg-color);
border-radius: 4px; border-radius: 4px;
} }
} }
+8 -8
View File
@@ -8,9 +8,9 @@
} }
.picker { .picker {
background: var(--popup-background-color); background: var(--popup-bg-color);
border: 0px solid transparentize($oc-white, 0.75); border: 0 solid transparentize($oc-white, 0.75);
box-shadow: transparentize($oc-black, 0.75) 0px 1px 4px; box-shadow: transparentize($oc-black, 0.75) 0 1px 4px;
border-radius: 4px; border-radius: 4px;
position: absolute; position: absolute;
} }
@@ -56,8 +56,8 @@
} }
.picker-triangle { .picker-triangle {
width: 0px; width: 0;
height: 0px; height: 0;
position: relative; position: relative;
top: -10px; top: -10px;
:root[dir="ltr"] & { :root[dir="ltr"] & {
@@ -73,7 +73,7 @@
content: ""; content: "";
position: absolute; position: absolute;
border-style: solid; border-style: solid;
border-width: 0px 9px 10px; border-width: 0 9px 10px;
border-color: transparent transparent transparentize($oc-black, 0.9); border-color: transparent transparent transparentize($oc-black, 0.9);
top: -1px; top: -1px;
} }
@@ -82,8 +82,8 @@
content: ""; content: "";
position: absolute; position: absolute;
border-style: solid; border-style: solid;
border-width: 0px 9px 10px; border-width: 0 9px 10px;
border-color: transparent transparent var(--popup-background-color); border-color: transparent transparent var(--popup-bg-color);
} }
} }
+1 -1
View File
@@ -1,7 +1,7 @@
.excalidraw { .excalidraw {
.Island { .Island {
--padding: 0; --padding: 0;
background-color: var(--bg-color-island); background-color: var(--island-bg-color);
backdrop-filter: saturate(100%) blur(10px); backdrop-filter: saturate(100%) blur(10px);
box-shadow: var(--shadow-island); box-shadow: var(--shadow-island);
border-radius: 4px; border-radius: 4px;
+2 -2
View File
@@ -71,7 +71,7 @@
&__footer { &__footer {
position: absolute; position: absolute;
z-index: 100; z-index: 100;
bottom: 0px; bottom: 0;
:root[dir="ltr"] & { :root[dir="ltr"] & {
right: 0; right: 0;
@@ -92,7 +92,7 @@
} }
:root[dir="ltr"] &.transition-right { :root[dir="ltr"] &.transition-right {
transform: translate(999px, 0px); transform: translate(999px, 0);
} }
:root[dir="rtl"] &.transition-left { :root[dir="rtl"] &.transition-left {
+43 -79
View File
@@ -61,7 +61,6 @@ interface LayerUIProps {
canvas: HTMLCanvasElement | null, canvas: HTMLCanvasElement | null,
) => void; ) => void;
renderCustomFooter?: (isMobile: boolean) => JSX.Element; renderCustomFooter?: (isMobile: boolean) => JSX.Element;
viewModeEnabled: boolean;
} }
const useOnClickOutside = ( const useOnClickOutside = (
@@ -300,7 +299,6 @@ const LayerUI = ({
isCollaborating, isCollaborating,
onExportToBackend, onExportToBackend,
renderCustomFooter, renderCustomFooter,
viewModeEnabled,
}: LayerUIProps) => { }: LayerUIProps) => {
const isMobile = useIsMobile(); const isMobile = useIsMobile();
@@ -360,28 +358,6 @@ const LayerUI = ({
); );
}; };
const renderViewModeCanvasActions = () => {
return (
<Section
heading="canvasActions"
className={clsx("zen-mode-transition", {
"transition-left": zenModeEnabled,
})}
>
{/* the zIndex ensures this menu has higher stacking order,
see https://github.com/excalidraw/excalidraw/pull/1445 */}
<Island padding={2} style={{ zIndex: 1 }}>
<Stack.Col gap={4}>
<Stack.Row gap={1} justifyContent="space-between">
{actionManager.renderAction("saveScene")}
{actionManager.renderAction("saveAsScene")}
{renderExportDialog()}
</Stack.Row>
</Stack.Col>
</Island>
</Section>
);
};
const renderCanvasActions = () => ( const renderCanvasActions = () => (
<Section <Section
heading="canvasActions" heading="canvasActions"
@@ -472,42 +448,38 @@ const LayerUI = ({
gap={4} gap={4}
className={clsx({ "disable-pointerEvents": zenModeEnabled })} className={clsx({ "disable-pointerEvents": zenModeEnabled })}
> >
{viewModeEnabled {renderCanvasActions()}
? renderViewModeCanvasActions()
: renderCanvasActions()}
{shouldRenderSelectedShapeActions && renderSelectedShapeActions()} {shouldRenderSelectedShapeActions && renderSelectedShapeActions()}
</Stack.Col> </Stack.Col>
{!viewModeEnabled && ( <Section heading="shapes">
<Section heading="shapes"> {(heading) => (
{(heading) => ( <Stack.Col gap={4} align="start">
<Stack.Col gap={4} align="start"> <Stack.Row gap={1}>
<Stack.Row gap={1}> <Island
<Island padding={1}
padding={1} className={clsx({ "zen-mode": zenModeEnabled })}
className={clsx({ "zen-mode": zenModeEnabled })} >
> <HintViewer appState={appState} elements={elements} />
<HintViewer appState={appState} elements={elements} /> {heading}
{heading} <Stack.Row gap={1}>
<Stack.Row gap={1}> <ShapesSwitcher
<ShapesSwitcher elementType={appState.elementType}
elementType={appState.elementType} setAppState={setAppState}
setAppState={setAppState} isLibraryOpen={appState.isLibraryOpen}
isLibraryOpen={appState.isLibraryOpen} />
/> </Stack.Row>
</Stack.Row> </Island>
</Island> <LockIcon
<LockIcon zenModeEnabled={zenModeEnabled}
zenModeEnabled={zenModeEnabled} checked={appState.elementLocked}
checked={appState.elementLocked} onChange={onLockToggle}
onChange={onLockToggle} title={t("toolBar.lock")}
title={t("toolBar.lock")} />
/> </Stack.Row>
</Stack.Row> {libraryMenu}
{libraryMenu} </Stack.Col>
</Stack.Col> )}
)} </Section>
</Section>
)}
<UserList <UserList
className={clsx("zen-mode-transition", { className={clsx("zen-mode-transition", {
"transition-right": zenModeEnabled, "transition-right": zenModeEnabled,
@@ -552,20 +524,6 @@ const LayerUI = ({
); );
}; };
const renderGitHubCorner = () => {
return (
<aside
className={clsx(
"layer-ui__wrapper__github-corner zen-mode-transition",
{
"transition-right": zenModeEnabled,
},
)}
>
<GitHubCorner appearance={appState.appearance} />
</aside>
);
};
const renderFooter = () => ( const renderFooter = () => (
<footer role="contentinfo" className="layer-ui__wrapper__footer"> <footer role="contentinfo" className="layer-ui__wrapper__footer">
<div <div
@@ -641,19 +599,25 @@ const LayerUI = ({
canvas={canvas} canvas={canvas}
isCollaborating={isCollaborating} isCollaborating={isCollaborating}
renderCustomFooter={renderCustomFooter} renderCustomFooter={renderCustomFooter}
viewModeEnabled={viewModeEnabled}
/> />
</> </>
) : ( ) : (
<div <div className="layer-ui__wrapper">
className={clsx("layer-ui__wrapper", {
"disable-pointerEvents": appState.cursorButton === "down",
})}
>
{dialogs} {dialogs}
{renderFixedSideContainer()} {renderFixedSideContainer()}
{renderBottomAppMenu()} {renderBottomAppMenu()}
{renderGitHubCorner()} {
<aside
className={clsx(
"layer-ui__wrapper__github-corner zen-mode-transition",
{
"transition-right": zenModeEnabled,
},
)}
>
<GitHubCorner appearance={appState.appearance} />
</aside>
}
{renderFooter()} {renderFooter()}
</div> </div>
); );
+116 -160
View File
@@ -29,7 +29,6 @@ type MobileMenuProps = {
canvas: HTMLCanvasElement | null; canvas: HTMLCanvasElement | null;
isCollaborating: boolean; isCollaborating: boolean;
renderCustomFooter?: (isMobile: boolean) => JSX.Element; renderCustomFooter?: (isMobile: boolean) => JSX.Element;
viewModeEnabled: boolean;
}; };
export const MobileMenu = ({ export const MobileMenu = ({
@@ -44,164 +43,121 @@ export const MobileMenu = ({
canvas, canvas,
isCollaborating, isCollaborating,
renderCustomFooter, renderCustomFooter,
viewModeEnabled, }: MobileMenuProps) => (
}: MobileMenuProps) => { <>
const renderFixedSideContainer = () => { <FixedSideContainer side="top">
return ( <Section heading="shapes">
<FixedSideContainer side="top"> {(heading) => (
<Section heading="shapes"> <Stack.Col gap={4} align="center">
{(heading) => ( <Stack.Row gap={1}>
<Stack.Col gap={4} align="center"> <Island padding={1}>
<Stack.Row gap={1}> {heading}
<Island padding={1}> <Stack.Row gap={1}>
{heading} <ShapesSwitcher
<Stack.Row gap={1}> elementType={appState.elementType}
<ShapesSwitcher setAppState={setAppState}
elementType={appState.elementType} isLibraryOpen={appState.isLibraryOpen}
setAppState={setAppState} />
isLibraryOpen={appState.isLibraryOpen} </Stack.Row>
/> </Island>
</Stack.Row> <LockIcon
</Island> checked={appState.elementLocked}
<LockIcon onChange={onLockToggle}
checked={appState.elementLocked} title={t("toolBar.lock")}
onChange={onLockToggle}
title={t("toolBar.lock")}
/>
</Stack.Row>
{libraryMenu}
</Stack.Col>
)}
</Section>
<HintViewer appState={appState} elements={elements} />
</FixedSideContainer>
);
};
const renderAppToolbar = () => {
if (viewModeEnabled) {
return (
<div className="App-toolbar-content">
{actionManager.renderAction("toggleCanvasMenu")}
</div>
);
}
return (
<div className="App-toolbar-content">
{actionManager.renderAction("toggleCanvasMenu")}
{actionManager.renderAction("toggleEditMenu")}
{actionManager.renderAction("undo")}
{actionManager.renderAction("redo")}
{actionManager.renderAction(
appState.multiElement ? "finalize" : "duplicateSelection",
)}
{actionManager.renderAction("deleteSelectedElements")}
</div>
);
};
const renderCanvasActions = () => {
if (viewModeEnabled) {
return (
<>
{actionManager.renderAction("saveScene")}
{actionManager.renderAction("saveAsScene")}
{exportButton}
</>
);
}
return (
<>
{actionManager.renderAction("loadScene")}
{actionManager.renderAction("saveScene")}
{actionManager.renderAction("saveAsScene")}
{exportButton}
{actionManager.renderAction("clearCanvas")}
{onCollabButtonClick && (
<CollabButton
isCollaborating={isCollaborating}
collaboratorCount={appState.collaborators.size}
onClick={onCollabButtonClick}
/>
)}
{
<BackgroundPickerAndDarkModeToggle
actionManager={actionManager}
appState={appState}
setAppState={setAppState}
/>
}
</>
);
};
return (
<>
{!viewModeEnabled && renderFixedSideContainer()}
<div
className="App-bottom-bar"
style={{
marginBottom: SCROLLBAR_WIDTH + SCROLLBAR_MARGIN * 2,
marginLeft: SCROLLBAR_WIDTH + SCROLLBAR_MARGIN * 2,
marginRight: SCROLLBAR_WIDTH + SCROLLBAR_MARGIN * 2,
}}
>
<Island padding={0}>
{appState.openMenu === "canvas" ? (
<Section className="App-mobile-menu" heading="canvasActions">
<div className="panelColumn">
<Stack.Col gap={4}>
{renderCanvasActions()}
{renderCustomFooter?.(true)}
<fieldset>
<legend>{t("labels.collaborators")}</legend>
<UserList mobile>
{Array.from(appState.collaborators)
// Collaborator is either not initialized or is actually the current user.
.filter(
([_, client]) => Object.keys(client).length !== 0,
)
.map(([clientId, client]) => (
<React.Fragment key={clientId}>
{actionManager.renderAction(
"goToCollaborator",
clientId,
)}
</React.Fragment>
))}
</UserList>
</fieldset>
</Stack.Col>
</div>
</Section>
) : appState.openMenu === "shape" &&
!viewModeEnabled &&
showSelectedShapeActions(appState, elements) ? (
<Section className="App-mobile-menu" heading="selectedShapeActions">
<SelectedShapeActions
appState={appState}
elements={elements}
renderAction={actionManager.renderAction}
elementType={appState.elementType}
/> />
</Section> </Stack.Row>
) : null} {libraryMenu}
<footer className="App-toolbar"> </Stack.Col>
{renderAppToolbar()} )}
{appState.scrolledOutside && !appState.openMenu && ( </Section>
<button <HintViewer appState={appState} elements={elements} />
className="scroll-back-to-content" </FixedSideContainer>
onClick={() => { <div
setAppState({ className="App-bottom-bar"
...calculateScrollCenter(elements, appState, canvas), style={{
}); marginBottom: SCROLLBAR_WIDTH + SCROLLBAR_MARGIN * 2,
}} marginLeft: SCROLLBAR_WIDTH + SCROLLBAR_MARGIN * 2,
> marginRight: SCROLLBAR_WIDTH + SCROLLBAR_MARGIN * 2,
{t("buttons.scrollBackToContent")} }}
</button> >
<Island padding={0}>
{appState.openMenu === "canvas" ? (
<Section className="App-mobile-menu" heading="canvasActions">
<div className="panelColumn">
<Stack.Col gap={4}>
{actionManager.renderAction("loadScene")}
{actionManager.renderAction("saveScene")}
{actionManager.renderAction("saveAsScene")}
{exportButton}
{actionManager.renderAction("clearCanvas")}
{onCollabButtonClick && (
<CollabButton
isCollaborating={isCollaborating}
collaboratorCount={appState.collaborators.size}
onClick={onCollabButtonClick}
/>
)}
<BackgroundPickerAndDarkModeToggle
actionManager={actionManager}
appState={appState}
setAppState={setAppState}
/>
{renderCustomFooter?.(true)}
<fieldset>
<legend>{t("labels.collaborators")}</legend>
<UserList mobile>
{Array.from(appState.collaborators)
// Collaborator is either not initialized or is actually the current user.
.filter(([_, client]) => Object.keys(client).length !== 0)
.map(([clientId, client]) => (
<React.Fragment key={clientId}>
{actionManager.renderAction(
"goToCollaborator",
clientId,
)}
</React.Fragment>
))}
</UserList>
</fieldset>
</Stack.Col>
</div>
</Section>
) : appState.openMenu === "shape" &&
showSelectedShapeActions(appState, elements) ? (
<Section className="App-mobile-menu" heading="selectedShapeActions">
<SelectedShapeActions
appState={appState}
elements={elements}
renderAction={actionManager.renderAction}
elementType={appState.elementType}
/>
</Section>
) : null}
<footer className="App-toolbar">
<div className="App-toolbar-content">
{actionManager.renderAction("toggleCanvasMenu")}
{actionManager.renderAction("toggleEditMenu")}
{actionManager.renderAction("undo")}
{actionManager.renderAction("redo")}
{actionManager.renderAction(
appState.multiElement ? "finalize" : "duplicateSelection",
)} )}
</footer> {actionManager.renderAction("deleteSelectedElements")}
</Island> </div>
</div> {appState.scrolledOutside && !appState.openMenu && (
</> <button
); className="scroll-back-to-content"
}; onClick={() => {
setAppState({
...calculateScrollCenter(elements, appState, canvas),
});
}}
>
{t("buttons.scrollBackToContent")}
</button>
)}
</footer>
</Island>
</div>
</>
);
+1 -1
View File
@@ -39,7 +39,7 @@
overflow-y: auto; overflow-y: auto;
// for modals, reset blurry bg // for modals, reset blurry bg
background: var(--bg-color-island); background: var(--island-bg-color);
backdrop-filter: none; backdrop-filter: none;
border: 1px solid var(--dialog-border); border: 1px solid var(--dialog-border);
+42 -40
View File
@@ -1,51 +1,53 @@
@import "../css/variables.module"; @import "../css/variables.module";
.Stats { .excalidraw {
position: fixed; .Stats {
top: 64px; position: fixed;
right: 12px; top: 64px;
font-size: 12px; right: 12px;
z-index: 999; font-size: 12px;
z-index: 999;
h3 { h3 {
margin: 0 24px 8px 0; margin: 0 24px 8px 0;
white-space: nowrap; white-space: nowrap;
} }
.close { .close {
float: right; float: right;
height: 16px; height: 16px;
width: 16px; width: 16px;
cursor: pointer; cursor: pointer;
svg { svg {
width: 100%;
height: 100%;
}
}
table {
width: 100%; width: 100%;
height: 100%; th {
border-bottom: 1px solid var(--input-border-color);
padding: 4px;
}
tr {
td:nth-child(2) {
min-width: 24px;
text-align: right;
}
}
} }
}
table { :root[dir="rtl"] & {
width: 100%; left: 12px;
th { right: initial;
border-bottom: 1px solid var(--input-border-color);
padding: 4px; h3 {
} margin: 0 0 8px 24px;
tr { }
td:nth-child(2) { .close {
min-width: 24px; float: left;
text-align: right;
} }
} }
} }
:root[dir="rtl"] & {
left: 12px;
right: initial;
h3 {
margin: 0 0 8px 24px;
}
.close {
float: left;
}
}
} }
-18
View File
@@ -24,7 +24,6 @@ const getStorageSizes = debounce((cb: (sizes: StorageSizes) => void) => {
}, 500); }, 500);
export const Stats = (props: { export const Stats = (props: {
setAppState: React.Component<any, AppState>["setState"];
appState: AppState; appState: AppState;
elements: readonly NonDeletedExcalidrawElement[]; elements: readonly NonDeletedExcalidrawElement[];
onClose: () => void; onClose: () => void;
@@ -47,12 +46,6 @@ export const Stats = (props: {
const selectedElements = getTargetElements(props.elements, props.appState); const selectedElements = getTargetElements(props.elements, props.appState);
const selectedBoundingBox = getCommonBounds(selectedElements); const selectedBoundingBox = getCommonBounds(selectedElements);
const onGridSizeChange = () => {
props.setAppState({
gridSize: ((props.appState.gridSize - 5) % 50) + 10,
});
};
if (isMobile && props.appState.openMenu) { if (isMobile && props.appState.openMenu) {
return null; return null;
} }
@@ -163,17 +156,6 @@ export const Stats = (props: {
</td> </td>
</tr> </tr>
)} )}
{props.appState.showGrid && (
<>
<tr>
<th colSpan={2}>{"Misc"}</th>
</tr>
<tr onClick={onGridSizeChange} style={{ cursor: "pointer" }}>
<td>{"Grid size"}</td>
<td>{props.appState.gridSize}</td>
</tr>
</>
)}
</tbody> </tbody>
</table> </table>
</Island> </Island>
+2 -2
View File
@@ -9,11 +9,11 @@
padding: 0.75rem; padding: 0.75rem;
white-space: nowrap; white-space: nowrap;
border-radius: var(--space-factor); border-radius: var(--space-factor);
background-color: var(--input-background-color); background-color: var(--input-bg-color);
&:not(:focus) { &:not(:focus) {
&:hover { &:hover {
background-color: var(--input-hover-background-color); background-color: var(--input-hover-bg-color);
} }
} }
+9 -1
View File
@@ -48,7 +48,15 @@
} }
} }
.Tooltip:hover .Tooltip__label { // the following 3 rules ensure that the tooltip doesn't show (nor affect
// the cursor) when you drag over when you draw on canvas, but at the same
// time it still works when clicking on the link/shield
body:active & .Tooltip:not(:hover) {
pointer-events: none;
}
body:not(:active) & .Tooltip:hover .Tooltip__label {
visibility: visible; visibility: visible;
} }
+24 -24
View File
@@ -2,50 +2,50 @@ import { FontFamily } from "./element/types";
export const APP_NAME = "Excalidraw"; export const APP_NAME = "Excalidraw";
export const DRAGGING_THRESHOLD = 10; // 10px export const DRAGGING_THRESHOLD = 10;
export const LINE_CONFIRM_THRESHOLD = 10; // 10px export const LINE_CONFIRM_THRESHOLD = 10;
export const ELEMENT_SHIFT_TRANSLATE_AMOUNT = 5; export const ELEMENT_SHIFT_TRANSLATE_AMOUNT = 5;
export const ELEMENT_TRANSLATE_AMOUNT = 1; export const ELEMENT_TRANSLATE_AMOUNT = 1;
export const TEXT_TO_CENTER_SNAP_THRESHOLD = 30; export const TEXT_TO_CENTER_SNAP_THRESHOLD = 30;
export const SHIFT_LOCKING_ANGLE = Math.PI / 12; export const SHIFT_LOCKING_ANGLE = Math.PI / 12;
export const CURSOR_TYPE = { export const CURSOR_TYPE = {
TEXT: "text", AUTO: "",
CROSSHAIR: "crosshair", CROSSHAIR: "crosshair",
GRABBING: "grabbing", GRABBING: "grabbing",
POINTER: "pointer",
MOVE: "move", MOVE: "move",
AUTO: "", POINTER: "pointer",
TEXT: "text",
}; };
export const POINTER_BUTTON = { export const POINTER_BUTTON = {
MAIN: 0, MAIN: 0,
WHEEL: 1,
SECONDARY: 2, SECONDARY: 2,
TOUCH: -1, TOUCH: -1,
WHEEL: 1,
}; };
export enum EVENT { export enum EVENT {
BEFORE_UNLOAD = "beforeunload",
BLUR = "blur",
COPY = "copy", COPY = "copy",
PASTE = "paste",
CUT = "cut", CUT = "cut",
DRAG_OVER = "dragover",
DROP = "drop",
GESTURE_CHANGE = "gesturechange",
GESTURE_END = "gestureend",
GESTURE_START = "gesturestart",
HASHCHANGE = "hashchange",
KEYDOWN = "keydown", KEYDOWN = "keydown",
KEYUP = "keyup", KEYUP = "keyup",
MOUSE_MOVE = "mousemove", MOUSE_MOVE = "mousemove",
RESIZE = "resize", PASTE = "paste",
UNLOAD = "unload",
BLUR = "blur",
DRAG_OVER = "dragover",
DROP = "drop",
GESTURE_END = "gestureend",
BEFORE_UNLOAD = "beforeunload",
GESTURE_START = "gesturestart",
GESTURE_CHANGE = "gesturechange",
POINTER_MOVE = "pointermove", POINTER_MOVE = "pointermove",
POINTER_UP = "pointerup", POINTER_UP = "pointerup",
RESIZE = "resize",
STATE_CHANGE = "statechange", STATE_CHANGE = "statechange",
WHEEL = "wheel",
TOUCH_START = "touchstart",
TOUCH_END = "touchend", TOUCH_END = "touchend",
HASHCHANGE = "hashchange", TOUCH_START = "touchstart",
UNLOAD = "unload",
WHEEL = "wheel",
} }
export const ENV = { export const ENV = {
@@ -66,11 +66,11 @@ export const FONT_FAMILY = {
export const WINDOWS_EMOJI_FALLBACK_FONT = "Segoe UI Emoji"; export const WINDOWS_EMOJI_FALLBACK_FONT = "Segoe UI Emoji";
export const DEFAULT_FONT_SIZE = 20;
export const DEFAULT_FONT_FAMILY: FontFamily = 1; export const DEFAULT_FONT_FAMILY: FontFamily = 1;
export const DEFAULT_FONT_SIZE = 20;
export const DEFAULT_TEXT_ALIGN = "left"; export const DEFAULT_TEXT_ALIGN = "left";
export const DEFAULT_VERTICAL_ALIGN = "top";
export const DEFAULT_VERSION = "{version}"; export const DEFAULT_VERSION = "{version}";
export const DEFAULT_VERTICAL_ALIGN = "top";
export const CANVAS_ONLY_ACTIONS = ["selectAll"]; export const CANVAS_ONLY_ACTIONS = ["selectAll"];
@@ -85,11 +85,11 @@ export const STORAGE_KEYS = {
LOCAL_STORAGE_LIBRARY: "excalidraw-library", LOCAL_STORAGE_LIBRARY: "excalidraw-library",
}; };
// time in milliseconds // Time in milliseconds
export const TAP_TWICE_TIMEOUT = 300; export const TAP_TWICE_TIMEOUT = 300;
export const TOUCH_CTX_MENU_TIMEOUT = 500;
export const TITLE_TIMEOUT = 10000; export const TITLE_TIMEOUT = 10000;
export const TOAST_TIMEOUT = 5000; export const TOAST_TIMEOUT = 5000;
export const VERSION_TIMEOUT = 30000; export const TOUCH_CTX_MENU_TIMEOUT = 500;
export const VERSION_TIMEOUT = 15000;
export const ZOOM_STEP = 0.1; export const ZOOM_STEP = 0.1;
+12 -19
View File
@@ -43,10 +43,10 @@
} }
.FixedSideContainer { .FixedSideContainer {
padding-top: var(--sat, 0px); padding-top: var(--sat, 0);
padding-right: var(--sar, 0px); padding-right: var(--sar, 0);
padding-bottom: var(--sab, 0px); padding-bottom: var(--sab, 0);
padding-left: var(--sal, 0px); padding-left: var(--sal, 0);
} }
.panelRow { .panelRow {
@@ -223,10 +223,10 @@
left: 0; left: 0;
right: 0; right: 0;
--bar-padding: calc(4 * var(--space-factor)); --bar-padding: calc(4 * var(--space-factor));
padding-top: #{"max(var(--bar-padding), var(--sat, 0px))"}; padding-top: #{"max(var(--bar-padding), var(--sat, 0))"};
padding-right: var(--sar, 0px); padding-right: var(--sar, 0);
padding-bottom: var(--sab, 0px); padding-bottom: var(--sab, 0);
padding-left: var(--sal, 0px); padding-left: var(--sal, 0);
z-index: 4; z-index: 4;
display: flex; display: flex;
align-items: flex-end; align-items: flex-end;
@@ -243,7 +243,7 @@
pointer-events: initial; pointer-events: initial;
.panelColumn { .panelColumn {
padding: 8px 8px 0px 8px; padding: 8px 8px 0 8px;
} }
} }
} }
@@ -282,7 +282,7 @@
pointer-events: none !important; pointer-events: none !important;
} }
.layer-ui__wrapper:not(.disable-pointerEvents) .App-menu_top > * { .App-menu_top > * {
pointer-events: all; pointer-events: all;
} }
@@ -323,7 +323,7 @@
} }
} }
.layer-ui__wrapper:not(.disable-pointerEvents) .App-menu_bottom > * { .App-menu_bottom > * {
pointer-events: all; pointer-events: all;
} }
@@ -447,7 +447,7 @@
display: none; display: none;
} }
.scroll-back-to-content { .scroll-back-to-content {
bottom: calc(80px + var(--sab, 0px)); bottom: calc(80px + var(--sab, 0));
z-index: -1; z-index: -1;
} }
} }
@@ -492,13 +492,6 @@
pointer-events: none !important; pointer-events: none !important;
} }
&.excalidraw--view-mode {
.App-menu {
display: flex;
justify-content: space-between;
}
}
@media print { @media print {
.App-bottom-bar, .App-bottom-bar,
.FixedSideContainer, .FixedSideContainer,
+40 -42
View File
@@ -1,43 +1,43 @@
@import "open-color/open-color.scss"; @import "open-color/open-color.scss";
:root { :root {
--bg-color-island: rgba(255, 255, 255, 0.9); --appearance-filter: none;
--popup-background-color: #{$oc-white}; --button-destructive-bg-color: #{$oc-red-1};
--space-factor: 0.25rem; --button-destructive-color: #{$oc-red-9};
--button-gray-1: #{$oc-gray-2}; --button-gray-1: #{$oc-gray-2};
--button-gray-2: #{$oc-gray-4}; --button-gray-2: #{$oc-gray-4};
--button-gray-3: #{$oc-gray-5}; --button-gray-3: #{$oc-gray-5};
--input-border-color: #{$oc-gray-3}; --button-special-active-bg-color: #{$oc-green-0};
--input-background-color: #{$oc-white}; --dialog-border: #{$oc-gray-6};
--input-hover-background-color: #{$oc-gray-1}; --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>');
--input-label-color: #{$oc-gray-7}; --focus-highlight-color: #{$oc-blue-2};
--icon-fill-color: #{$oc-black}; --icon-fill-color: #{$oc-black};
--icon-green-fill-color: #{$oc-green-9}; --icon-green-fill-color: #{$oc-green-9};
--input-bg-color: #{$oc-white};
--input-border-color: #{$oc-gray-3};
--input-hover-bg-color: #{$oc-gray-1};
--input-label-color: #{$oc-gray-7};
--island-bg-color: #{transparentize($oc-white, 0.12)};
--keybinding-color: #{$oc-gray-5}; --keybinding-color: #{$oc-gray-5};
--sat: env(safe-area-inset-top); --link-color: #{$oc-blue-7};
--overlay-bg-color: #{transparentize($oc-white, 0.12)};
--popup-bg-color: #{$oc-white};
--popup-secondary-bg-color: #{$oc-gray-1};
--popup-text-color: #{$oc-black};
--popup-text-inverted-color: #{$oc-white};
--sab: env(safe-area-inset-bottom); --sab: env(safe-area-inset-bottom);
--sal: env(safe-area-inset-left); --sal: env(safe-area-inset-left);
--sar: env(safe-area-inset-right); --sar: env(safe-area-inset-right);
--text-color-primary: #{$oc-gray-8}; --sat: env(safe-area-inset-top);
--shadow-island: 0 1px 5px #{transparentize($oc-black, 0.85)};
--overlay-background-color: #{transparentize($oc-white, 0.12)};
--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}; --select-highlight-color: #{$oc-blue-5};
--appearance-filter: none; --shadow-island: 0 1px 5px #{transparentize($oc-black, 0.85)};
--button-special-active-background-color: #{$oc-green-0}; --space-factor: 0.25rem;
--button-destructive-color: #{$oc-red-9}; --text-color-primary: #{$oc-gray-8};
--button-destructive-background-color: #{$oc-red-1};
--popup-secondary-background-color: #{$oc-gray-1};
--popup-text-color: #{$oc-black};
--popup-text-inverted-color: #{$oc-white};
--dialog-border: #{$oc-gray-6};
--link-color: #{$oc-blue-7};
} }
.excalidraw { .excalidraw {
&.Appearance_dark { &.Appearance_dark {
background: #000; background: $oc-black;
&.Appearance_dark-background-none { &.Appearance_dark-background-none {
background: none; background: none;
@@ -45,31 +45,29 @@
} }
&.Appearance_dark { &.Appearance_dark {
--text-color-primary: #{$oc-gray-4}; --appearance-filter: invert(93%) hue-rotate(180deg);
--bg-color-island: #1e1e1e; --button-destructive-bg-color: #5a0000;
--popup-background-color: #2c2c2c; --button-destructive-color: #{$oc-red-3};
--button-gray-1: #363636; --button-gray-1: #363636;
--button-gray-2: #272727; --button-gray-2: #272727;
--button-gray-3: #222; --button-gray-3: #222;
--input-border-color: #2e2e2e; --button-special-active-bg-color: #204624;
--input-background-color: #121212; --dialog-border: #{$oc-gray-9};
--input-hover-background-color: #181818;
--input-label-color: #{$oc-gray-2};
--icon-fill-color: #{$oc-gray-4};
--icon-green-fill-color: #{$oc-green-4};
--keybinding-color: #{$oc-gray-6};
--shadow-island: 0 1px 5px #{transparentize($oc-black, 0.7)};
--overlay-background-color: rgba(30, 30, 30, 0.88);
--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>'); --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}; --focus-highlight-color: #{$oc-blue-6};
--select-highlight-color: #{$oc-blue-4}; --icon-fill-color: #{$oc-gray-4};
--appearance-filter: invert(93%) hue-rotate(180deg); --icon-green-fill-color: #{$oc-green-4};
--button-special-active-background-color: #204624; --input-bg-color: #121212;
--button-destructive-color: #{$oc-red-3}; --input-border-color: #2e2e2e;
--button-destructive-background-color: #5a0000; --input-hover-bg-color: #181818;
--popup-secondary-background-color: #222; --input-label-color: #{$oc-gray-2};
--island-bg-color: #1e1e1e;
--keybinding-color: #{$oc-gray-6};
--overlay-bg-color: rgba(30, 30, 30, 0.88);
--popup-secondary-bg-color: #222;
--popup-text-color: #{$oc-gray-4}; --popup-text-color: #{$oc-gray-4};
--popup-text-inverted-color: #2c2c2c; --popup-text-inverted-color: #2c2c2c;
--dialog-border: #{$oc-gray-9}; --select-highlight-color: #{$oc-blue-4};
--shadow-island: 0 1px 5px #{transparentize($oc-black, 0.7)};
} }
} }
+1 -1
View File
@@ -1,6 +1,6 @@
@import "open-color/open-color.scss"; @import "open-color/open-color.scss";
// keep up to date with is-mobile.tsx // Keep up to date with is-mobile.tsx
$is-mobile-query: "(max-width: 600px), (max-height: 500px) and (max-width: 1000px)"; $is-mobile-query: "(max-width: 600px), (max-height: 500px) and (max-width: 1000px)";
:export { :export {
+3 -13
View File
@@ -102,7 +102,6 @@ export class LinearElementEditor {
element, element,
scenePointerX - editingLinearElement.pointerOffset.x, scenePointerX - editingLinearElement.pointerOffset.x,
scenePointerY - editingLinearElement.pointerOffset.y, scenePointerY - editingLinearElement.pointerOffset.y,
appState.showGrid,
appState.gridSize, appState.gridSize,
); );
LinearElementEditor.movePoint(element, activePointIndex, newPoint); LinearElementEditor.movePoint(element, activePointIndex, newPoint);
@@ -199,7 +198,6 @@ export class LinearElementEditor {
element, element,
scenePointer.x, scenePointer.x,
scenePointer.y, scenePointer.y,
appState.showGrid,
appState.gridSize, appState.gridSize,
), ),
], ],
@@ -284,8 +282,7 @@ export class LinearElementEditor {
scenePointerX: number, scenePointerX: number,
scenePointerY: number, scenePointerY: number,
editingLinearElement: LinearElementEditor, editingLinearElement: LinearElementEditor,
isGridOn: boolean, gridSize: number | null,
gridSize: number,
): LinearElementEditor { ): LinearElementEditor {
const { elementId, lastUncommittedPoint } = editingLinearElement; const { elementId, lastUncommittedPoint } = editingLinearElement;
const element = LinearElementEditor.getElement(elementId); const element = LinearElementEditor.getElement(elementId);
@@ -307,7 +304,6 @@ export class LinearElementEditor {
element, element,
scenePointerX - editingLinearElement.pointerOffset.x, scenePointerX - editingLinearElement.pointerOffset.x,
scenePointerY - editingLinearElement.pointerOffset.y, scenePointerY - editingLinearElement.pointerOffset.y,
isGridOn,
gridSize, gridSize,
); );
@@ -402,15 +398,9 @@ export class LinearElementEditor {
element: NonDeleted<ExcalidrawLinearElement>, element: NonDeleted<ExcalidrawLinearElement>,
scenePointerX: number, scenePointerX: number,
scenePointerY: number, scenePointerY: number,
isGridOn: boolean, gridSize: number | null,
gridSize: number,
): Point { ): Point {
const pointerOnGrid = getGridPoint( const pointerOnGrid = getGridPoint(scenePointerX, scenePointerY, gridSize);
scenePointerX,
scenePointerY,
isGridOn,
gridSize,
);
const [x1, y1, x2, y2] = getElementAbsoluteCoords(element); const [x1, y1, x2, y2] = getElementAbsoluteCoords(element);
const cx = (x1 + x2) / 2; const cx = (x1 + x2) / 2;
const cy = (y1 + y2) / 2; const cy = (y1 + y2) / 2;
+3 -4
View File
@@ -7,8 +7,7 @@ export const showSelectedShapeActions = (
elements: readonly NonDeletedExcalidrawElement[], elements: readonly NonDeletedExcalidrawElement[],
) => ) =>
Boolean( Boolean(
!appState.viewModeEnabled && appState.editingElement ||
(appState.editingElement || getSelectedElements(elements, appState).length ||
getSelectedElements(elements, appState).length || appState.elementType !== "selection",
appState.elementType !== "selection"),
); );
+2 -2
View File
@@ -35,7 +35,7 @@
} }
.RoomDialog-username { .RoomDialog-username {
background-color: var(--input-background-color); background-color: var(--input-bg-color);
border-color: var(--input-border-color); border-color: var(--input-border-color);
appearance: none; appearance: none;
min-width: 0; min-width: 0;
@@ -53,7 +53,7 @@
} }
.Modal .RoomDialog-stopSession { .Modal .RoomDialog-stopSession {
background-color: var(--button-destructive-background-color); background-color: var(--button-destructive-bg-color);
.ToolIcon__label, .ToolIcon__label,
.ToolIcon__icon svg { .ToolIcon__icon svg {
+2 -2
View File
@@ -188,7 +188,7 @@ const initializeScene = async (opts: {
return null; return null;
}; };
function ExcalidrawWrapper() { const ExcalidrawWrapper = () => {
// dimensions // dimensions
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
@@ -367,7 +367,7 @@ function ExcalidrawWrapper() {
)} )}
</> </>
); );
} };
export default function ExcalidrawApp() { export default function ExcalidrawApp() {
return ( return (
-1
View File
@@ -27,7 +27,6 @@ const allLanguages: Language[] = [
{ code: "id-ID", label: "Bahasa Indonesia" }, { code: "id-ID", label: "Bahasa Indonesia" },
{ code: "it-IT", label: "Italiano" }, { code: "it-IT", label: "Italiano" },
{ code: "ja-JP", label: "日本語" }, { code: "ja-JP", label: "日本語" },
{ code: "kab-KAB", label: "Taqbaylit" },
{ code: "ko-KR", label: "한국어" }, { code: "ko-KR", label: "한국어" },
{ code: "my-MM", label: "Burmese" }, { code: "my-MM", label: "Burmese" },
{ code: "nb-NO", label: "Norsk bokmål" }, { code: "nb-NO", label: "Norsk bokmål" },
-1
View File
@@ -21,7 +21,6 @@ export const CODES = {
V: "KeyV", V: "KeyV",
X: "KeyX", X: "KeyX",
Z: "KeyZ", Z: "KeyZ",
R: "KeyR",
} as const; } as const;
export const KEYS = { export const KEYS = {
+3 -4
View File
@@ -80,9 +80,9 @@
"gridMode": "وضع الشبكة", "gridMode": "وضع الشبكة",
"addToLibrary": "أضف إلى المكتبة", "addToLibrary": "أضف إلى المكتبة",
"removeFromLibrary": "حذف من المكتبة", "removeFromLibrary": "حذف من المكتبة",
"libraryLoadingMessage": "جارٍ تحميل المكتبة", "libraryLoadingMessage": "جارٍ تحميل المكتبة...",
"libraries": "تصفح المكتبات", "libraries": "تصفح المكتبات",
"loadingScene": "جاري تحميل المشهد", "loadingScene": "جاري تحميل المشهد...",
"align": "محاذاة", "align": "محاذاة",
"alignTop": "محاذاة إلى اﻷعلى", "alignTop": "محاذاة إلى اﻷعلى",
"alignBottom": "محاذاة إلى اﻷسفل", "alignBottom": "محاذاة إلى اﻷسفل",
@@ -91,8 +91,7 @@
"centerVertically": "توسيط عمودي", "centerVertically": "توسيط عمودي",
"centerHorizontally": "توسيط أفقي", "centerHorizontally": "توسيط أفقي",
"distributeHorizontally": "التوزيع الأفقي", "distributeHorizontally": "التوزيع الأفقي",
"distributeVertically": "التوزيع عمودياً", "distributeVertically": "التوزيع عمودياً"
"viewMode": ""
}, },
"buttons": { "buttons": {
"clearReset": "إعادة تعيين اللوحة", "clearReset": "إعادة تعيين اللوحة",
+3 -4
View File
@@ -80,9 +80,9 @@
"gridMode": "Решетъчен режим", "gridMode": "Решетъчен режим",
"addToLibrary": "Добавяне към библиотеката", "addToLibrary": "Добавяне към библиотеката",
"removeFromLibrary": "Премахване от библиотеката", "removeFromLibrary": "Премахване от библиотеката",
"libraryLoadingMessage": "Зареждане на библиотеката", "libraryLoadingMessage": "Зареждане на библиотеката...",
"libraries": "Разглеждане на библиотеките", "libraries": "Разглеждане на библиотеките",
"loadingScene": "Зареждане на сцена", "loadingScene": "Зареждане на сцена...",
"align": "Подравняване", "align": "Подравняване",
"alignTop": "Подравняване отгоре", "alignTop": "Подравняване отгоре",
"alignBottom": "Подравняване отдолу", "alignBottom": "Подравняване отдолу",
@@ -91,8 +91,7 @@
"centerVertically": "Центрирай вертикално", "centerVertically": "Центрирай вертикално",
"centerHorizontally": "Центрирай хоризонтално", "centerHorizontally": "Центрирай хоризонтално",
"distributeHorizontally": "Разпредели хоризонтално", "distributeHorizontally": "Разпредели хоризонтално",
"distributeVertically": "Разпредели вертикално", "distributeVertically": "Разпредели вертикално"
"viewMode": ""
}, },
"buttons": { "buttons": {
"clearReset": "Нулиране на платно", "clearReset": "Нулиране на платно",
+2 -3
View File
@@ -82,7 +82,7 @@
"removeFromLibrary": "Eliminar de la biblioteca", "removeFromLibrary": "Eliminar de la biblioteca",
"libraryLoadingMessage": "Carregant la biblioteca...", "libraryLoadingMessage": "Carregant la biblioteca...",
"libraries": "Explorar biblioteques", "libraries": "Explorar biblioteques",
"loadingScene": "Carregant escena", "loadingScene": "Carregant escena...",
"align": "Alinear", "align": "Alinear",
"alignTop": "Alinear a dalt", "alignTop": "Alinear a dalt",
"alignBottom": "Alinear a baix", "alignBottom": "Alinear a baix",
@@ -91,8 +91,7 @@
"centerVertically": "Centrar verticalment", "centerVertically": "Centrar verticalment",
"centerHorizontally": "Centrar horitzontalment", "centerHorizontally": "Centrar horitzontalment",
"distributeHorizontally": "Distribuir horitzontalment", "distributeHorizontally": "Distribuir horitzontalment",
"distributeVertically": "Distribuir verticalment", "distributeVertically": "Distribuir verticalment"
"viewMode": ""
}, },
"buttons": { "buttons": {
"clearReset": "Netejar el llenç", "clearReset": "Netejar el llenç",
+3 -4
View File
@@ -80,9 +80,9 @@
"gridMode": "Rastermodus", "gridMode": "Rastermodus",
"addToLibrary": "Zur Bibliothek hinzufügen", "addToLibrary": "Zur Bibliothek hinzufügen",
"removeFromLibrary": "Aus Bibliothek entfernen", "removeFromLibrary": "Aus Bibliothek entfernen",
"libraryLoadingMessage": "Lade Bibliothek", "libraryLoadingMessage": "Lade Bibliothek...",
"libraries": "Bibliotheken durchsuchen", "libraries": "Bibliotheken durchsuchen",
"loadingScene": "Lade Zeichnung", "loadingScene": "Lade Zeichnung...",
"align": "Ausrichten", "align": "Ausrichten",
"alignTop": "Obere Kanten", "alignTop": "Obere Kanten",
"alignBottom": "Untere Kanten", "alignBottom": "Untere Kanten",
@@ -91,8 +91,7 @@
"centerVertically": "Vertikal zentrieren", "centerVertically": "Vertikal zentrieren",
"centerHorizontally": "Horizontal zentrieren", "centerHorizontally": "Horizontal zentrieren",
"distributeHorizontally": "Horizontal verteilen", "distributeHorizontally": "Horizontal verteilen",
"distributeVertically": "Vertikal verteilen", "distributeVertically": "Vertikal verteilen"
"viewMode": "Ansichtsmodus"
}, },
"buttons": { "buttons": {
"clearReset": "Zeichenfläche löschen & Hintergrundfarbe zurücksetzen", "clearReset": "Zeichenfläche löschen & Hintergrundfarbe zurücksetzen",
+3 -4
View File
@@ -80,9 +80,9 @@
"gridMode": "Εμφάνιση σε πλέγμα", "gridMode": "Εμφάνιση σε πλέγμα",
"addToLibrary": "Προσθήκη στη βιβλιοθήκη", "addToLibrary": "Προσθήκη στη βιβλιοθήκη",
"removeFromLibrary": "Αφαίρεση από τη βιβλιοθήκη", "removeFromLibrary": "Αφαίρεση από τη βιβλιοθήκη",
"libraryLoadingMessage": "Φόρτωση βιβλιοθήκης", "libraryLoadingMessage": "Φόρτωση βιβλιοθήκης...",
"libraries": "Άλλες βιβλιοθήκες", "libraries": "Άλλες βιβλιοθήκες",
"loadingScene": "Φόρτωση σκηνής", "loadingScene": "Φόρτωση σκηνής...",
"align": "Στοίχιση", "align": "Στοίχιση",
"alignTop": "Στοίχιση πάνω", "alignTop": "Στοίχιση πάνω",
"alignBottom": "Στοίχιση κάτω", "alignBottom": "Στοίχιση κάτω",
@@ -91,8 +91,7 @@
"centerVertically": "Κέντρο κάθετα", "centerVertically": "Κέντρο κάθετα",
"centerHorizontally": "Κέντρο οριζόντια", "centerHorizontally": "Κέντρο οριζόντια",
"distributeHorizontally": "Οριζόντια κατανομή", "distributeHorizontally": "Οριζόντια κατανομή",
"distributeVertically": "Κατακόρυφη κατανομή", "distributeVertically": "Κατακόρυφη κατανομή"
"viewMode": "Λειτουργία προβολής"
}, },
"buttons": { "buttons": {
"clearReset": "Επαναφορά του καμβά", "clearReset": "Επαναφορά του καμβά",
+3 -4
View File
@@ -80,9 +80,9 @@
"gridMode": "Grid mode", "gridMode": "Grid mode",
"addToLibrary": "Add to library", "addToLibrary": "Add to library",
"removeFromLibrary": "Remove from library", "removeFromLibrary": "Remove from library",
"libraryLoadingMessage": "Loading library", "libraryLoadingMessage": "Loading library...",
"libraries": "Browse libraries", "libraries": "Browse libraries",
"loadingScene": "Loading scene", "loadingScene": "Loading scene...",
"align": "Align", "align": "Align",
"alignTop": "Align top", "alignTop": "Align top",
"alignBottom": "Align bottom", "alignBottom": "Align bottom",
@@ -91,8 +91,7 @@
"centerVertically": "Center vertically", "centerVertically": "Center vertically",
"centerHorizontally": "Center horizontally", "centerHorizontally": "Center horizontally",
"distributeHorizontally": "Distribute horizontally", "distributeHorizontally": "Distribute horizontally",
"distributeVertically": "Distribute vertically", "distributeVertically": "Distribute vertically"
"viewMode": "View mode"
}, },
"buttons": { "buttons": {
"clearReset": "Reset the canvas", "clearReset": "Reset the canvas",
+1 -2
View File
@@ -91,8 +91,7 @@
"centerVertically": "Centrar verticalmente", "centerVertically": "Centrar verticalmente",
"centerHorizontally": "Centrar horizontalmente", "centerHorizontally": "Centrar horizontalmente",
"distributeHorizontally": "Distribuir horizontalmente", "distributeHorizontally": "Distribuir horizontalmente",
"distributeVertically": "Distribuir verticalmente", "distributeVertically": "Distribuir verticalmente"
"viewMode": "Modo presentación"
}, },
"buttons": { "buttons": {
"clearReset": "Limpiar lienzo y reiniciar el color de fondo", "clearReset": "Limpiar lienzo y reiniciar el color de fondo",
+3 -4
View File
@@ -80,9 +80,9 @@
"gridMode": "حالت شبکه ای", "gridMode": "حالت شبکه ای",
"addToLibrary": "افزودن به کتابخانه", "addToLibrary": "افزودن به کتابخانه",
"removeFromLibrary": "حذف از کتابخانه", "removeFromLibrary": "حذف از کتابخانه",
"libraryLoadingMessage": "بارگذاری کتابخانه", "libraryLoadingMessage": "بارگذاری کتابخانه...",
"libraries": "مرور کردن کتابخانه ها", "libraries": "مرور کردن کتابخانه ها",
"loadingScene": "باگذاری صحنه", "loadingScene": "باگذاری صحنه...",
"align": "تراز", "align": "تراز",
"alignTop": "تراز به بالا", "alignTop": "تراز به بالا",
"alignBottom": "تراز به پایین", "alignBottom": "تراز به پایین",
@@ -91,8 +91,7 @@
"centerVertically": "وسط قرار دادن به صورت عمودی", "centerVertically": "وسط قرار دادن به صورت عمودی",
"centerHorizontally": "وسط قرار دادن به صورت افقی", "centerHorizontally": "وسط قرار دادن به صورت افقی",
"distributeHorizontally": "توزیع کردن به صورت افقی", "distributeHorizontally": "توزیع کردن به صورت افقی",
"distributeVertically": "توزیع کردن به صورت عمودی", "distributeVertically": "توزیع کردن به صورت عمودی"
"viewMode": ""
}, },
"buttons": { "buttons": {
"clearReset": "پاکسازی بوم نقاشی", "clearReset": "پاکسازی بوم نقاشی",
+3 -4
View File
@@ -80,9 +80,9 @@
"gridMode": "Ruudukkotila", "gridMode": "Ruudukkotila",
"addToLibrary": "Lisää kirjastoon", "addToLibrary": "Lisää kirjastoon",
"removeFromLibrary": "Poista kirjastosta", "removeFromLibrary": "Poista kirjastosta",
"libraryLoadingMessage": "Ladataan kirjastoa", "libraryLoadingMessage": "Ladataan kirjastoa...",
"libraries": "Selaa kirjastoja", "libraries": "Selaa kirjastoja",
"loadingScene": "Ladataan työtä", "loadingScene": "Ladataan työtä...",
"align": "Tasaa", "align": "Tasaa",
"alignTop": "Tasaa ylös", "alignTop": "Tasaa ylös",
"alignBottom": "Tasaa alas", "alignBottom": "Tasaa alas",
@@ -91,8 +91,7 @@
"centerVertically": "Keskitä pystysuunnassa", "centerVertically": "Keskitä pystysuunnassa",
"centerHorizontally": "Keskitä vaakasuunnassa", "centerHorizontally": "Keskitä vaakasuunnassa",
"distributeHorizontally": "Jaa vaakasuunnassa", "distributeHorizontally": "Jaa vaakasuunnassa",
"distributeVertically": "Jaa pystysuunnassa", "distributeVertically": "Jaa pystysuunnassa"
"viewMode": "Katselutila"
}, },
"buttons": { "buttons": {
"clearReset": "Tyhjennä piirtoalue", "clearReset": "Tyhjennä piirtoalue",
+2 -3
View File
@@ -91,8 +91,7 @@
"centerVertically": "Centrer verticalement", "centerVertically": "Centrer verticalement",
"centerHorizontally": "Centrer horizontalement", "centerHorizontally": "Centrer horizontalement",
"distributeHorizontally": "Distribuer horizontalement", "distributeHorizontally": "Distribuer horizontalement",
"distributeVertically": "Distribuer verticalement", "distributeVertically": "Distribuer verticalement"
"viewMode": "Mode présentation"
}, },
"buttons": { "buttons": {
"clearReset": "Réinitialiser le canevas", "clearReset": "Réinitialiser le canevas",
@@ -230,7 +229,7 @@
"elements": "Éléments", "elements": "Éléments",
"height": "Hauteur", "height": "Hauteur",
"scene": "Scène", "scene": "Scène",
"selected": "Sélection", "selected": "Sélection",
"storage": "Stockage", "storage": "Stockage",
"title": "Stats pour les nerds", "title": "Stats pour les nerds",
"total": "Total", "total": "Total",
+3 -4
View File
@@ -80,9 +80,9 @@
"gridMode": "מצב רשת", "gridMode": "מצב רשת",
"addToLibrary": "הוסף לספריה", "addToLibrary": "הוסף לספריה",
"removeFromLibrary": "הסר מספריה", "removeFromLibrary": "הסר מספריה",
"libraryLoadingMessage": "טוען ספריה", "libraryLoadingMessage": "טוען ספריה...",
"libraries": "דפדף בספריות", "libraries": "דפדף בספריות",
"loadingScene": "טוען תצוגה", "loadingScene": "טוען תצוגה...",
"align": "יישר", "align": "יישר",
"alignTop": "יישר למעלה", "alignTop": "יישר למעלה",
"alignBottom": "יישר למטה", "alignBottom": "יישר למטה",
@@ -91,8 +91,7 @@
"centerVertically": "מרכז אנכית", "centerVertically": "מרכז אנכית",
"centerHorizontally": "מרכז אופקית", "centerHorizontally": "מרכז אופקית",
"distributeHorizontally": "חלוקה אופקית", "distributeHorizontally": "חלוקה אופקית",
"distributeVertically": "חלוקה אנכית", "distributeVertically": "חלוקה אנכית"
"viewMode": ""
}, },
"buttons": { "buttons": {
"clearReset": "אפס את הלוח", "clearReset": "אפס את הלוח",
+1 -2
View File
@@ -91,8 +91,7 @@
"centerVertically": "लंबवत केन्द्रित", "centerVertically": "लंबवत केन्द्रित",
"centerHorizontally": "क्षैतिज केन्द्रित", "centerHorizontally": "क्षैतिज केन्द्रित",
"distributeHorizontally": "क्षैतिज रूप से वितरित करें", "distributeHorizontally": "क्षैतिज रूप से वितरित करें",
"distributeVertically": "खड़ी रूप से वितरित करें", "distributeVertically": "खड़ी रूप से वितरित करें"
"viewMode": ""
}, },
"buttons": { "buttons": {
"clearReset": "कैनवास रीसेट करें", "clearReset": "कैनवास रीसेट करें",
+3 -4
View File
@@ -80,9 +80,9 @@
"gridMode": "Hálómód", "gridMode": "Hálómód",
"addToLibrary": "Hozzáadás a könyvtárhoz", "addToLibrary": "Hozzáadás a könyvtárhoz",
"removeFromLibrary": "Eltávólítás a könyvtárból", "removeFromLibrary": "Eltávólítás a könyvtárból",
"libraryLoadingMessage": "Könyvtár betöltése", "libraryLoadingMessage": "Könyvtár betöltése...",
"libraries": "Könyvtárak böngészése", "libraries": "Könyvtárak böngészése",
"loadingScene": "Jelenet betöltése", "loadingScene": "Jelenet betöltése...",
"align": "Igazítás", "align": "Igazítás",
"alignTop": "Felülre igazítás", "alignTop": "Felülre igazítás",
"alignBottom": "Alulra igazítás", "alignBottom": "Alulra igazítás",
@@ -91,8 +91,7 @@
"centerVertically": "Függőlegesen középre igazított", "centerVertically": "Függőlegesen középre igazított",
"centerHorizontally": "Vízszintesen középre igazított", "centerHorizontally": "Vízszintesen középre igazított",
"distributeHorizontally": "Vízszintes elosztás", "distributeHorizontally": "Vízszintes elosztás",
"distributeVertically": "Függőleges elosztás", "distributeVertically": "Függőleges elosztás"
"viewMode": ""
}, },
"buttons": { "buttons": {
"clearReset": "Vászon törlése", "clearReset": "Vászon törlése",
+3 -4
View File
@@ -80,9 +80,9 @@
"gridMode": "Mode grid", "gridMode": "Mode grid",
"addToLibrary": "Tambahkan ke pustaka", "addToLibrary": "Tambahkan ke pustaka",
"removeFromLibrary": "Hapus dari pustaka", "removeFromLibrary": "Hapus dari pustaka",
"libraryLoadingMessage": "Memuat pustaka", "libraryLoadingMessage": "Memuat pustaka...",
"libraries": "Telusur pustaka", "libraries": "Telusur pustaka",
"loadingScene": "Memuat pemandangan", "loadingScene": "Memuat pemandangan...",
"align": "Perataan", "align": "Perataan",
"alignTop": "Rata atas", "alignTop": "Rata atas",
"alignBottom": "Rata bawah", "alignBottom": "Rata bawah",
@@ -91,8 +91,7 @@
"centerVertically": "Pusatkan secara vertikal", "centerVertically": "Pusatkan secara vertikal",
"centerHorizontally": "Pusatkan secara horizontal", "centerHorizontally": "Pusatkan secara horizontal",
"distributeHorizontally": "Distribusikan horizontal", "distributeHorizontally": "Distribusikan horizontal",
"distributeVertically": "Distribusikan vertikal", "distributeVertically": "Distribusikan vertikal"
"viewMode": "Mode tampilan"
}, },
"buttons": { "buttons": {
"clearReset": "Setel Ulang Kanvas", "clearReset": "Setel Ulang Kanvas",
+3 -4
View File
@@ -80,9 +80,9 @@
"gridMode": "Modalità griglia", "gridMode": "Modalità griglia",
"addToLibrary": "Aggiungi alla libreria", "addToLibrary": "Aggiungi alla libreria",
"removeFromLibrary": "Rimuovi dalla libreria", "removeFromLibrary": "Rimuovi dalla libreria",
"libraryLoadingMessage": "Caricamento della biblioteca", "libraryLoadingMessage": "Caricamento della biblioteca...",
"libraries": "Sfoglia librerie", "libraries": "Sfoglia librerie",
"loadingScene": "Caricamento della scena", "loadingScene": "Caricamento della scena...",
"align": "Allinea", "align": "Allinea",
"alignTop": "Allinea in alto", "alignTop": "Allinea in alto",
"alignBottom": "Allinea in basso", "alignBottom": "Allinea in basso",
@@ -91,8 +91,7 @@
"centerVertically": "Centra Verticalmente", "centerVertically": "Centra Verticalmente",
"centerHorizontally": "Centra orizzontalmente", "centerHorizontally": "Centra orizzontalmente",
"distributeHorizontally": "Distribuisci orizzontalmente", "distributeHorizontally": "Distribuisci orizzontalmente",
"distributeVertically": "Distribuisci verticalmente", "distributeVertically": "Distribuisci verticalmente"
"viewMode": "Modalità visualizzazione"
}, },
"buttons": { "buttons": {
"clearReset": "Svuota la tela", "clearReset": "Svuota la tela",
+3 -4
View File
@@ -80,9 +80,9 @@
"gridMode": "", "gridMode": "",
"addToLibrary": "ライブラリに追加", "addToLibrary": "ライブラリに追加",
"removeFromLibrary": "ライブラリから削除", "removeFromLibrary": "ライブラリから削除",
"libraryLoadingMessage": "ライブラリを読み込み中", "libraryLoadingMessage": "ライブラリを読み込み中...",
"libraries": "", "libraries": "",
"loadingScene": "シーンを読み込み中", "loadingScene": "シーンを読み込み中...",
"align": "整列", "align": "整列",
"alignTop": "上揃え", "alignTop": "上揃え",
"alignBottom": "下揃え", "alignBottom": "下揃え",
@@ -91,8 +91,7 @@
"centerVertically": "縦方向に中央揃え", "centerVertically": "縦方向に中央揃え",
"centerHorizontally": "横方向に中央揃え", "centerHorizontally": "横方向に中央揃え",
"distributeHorizontally": "", "distributeHorizontally": "",
"distributeVertically": "", "distributeVertically": ""
"viewMode": ""
}, },
"buttons": { "buttons": {
"clearReset": "キャンバスのリセット", "clearReset": "キャンバスのリセット",
-243
View File
@@ -1,243 +0,0 @@
{
"labels": {
"paste": "Senṭeḍ",
"pasteCharts": "Senṭeḍ udlifen",
"selectAll": "Fren akk",
"multiSelect": "Rnu aferdis ɣer tefrayt",
"moveCanvas": "Smutti taɣzut n usuneɣ",
"cut": "Gzem",
"copy": "Nɣel",
"copyAsPng": "Nɣel ɣer tecfawit am PNG",
"copyAsSvg": "Nɣel ɣer tecfawit am SVG",
"bringForward": "Awi ɣer sdat",
"sendToBack": "Awi s agilal",
"bringToFront": "Err ɣer deffir",
"sendBackward": "Awi ɣer deffir",
"delete": "Kkes",
"copyStyles": "Nɣel iɣunab",
"pasteStyles": "Senṭeḍ iɣunab",
"stroke": "Azizdew",
"background": "Agilal",
"fill": "Taččart",
"strokeWidth": "Tehri n yizirig",
"strokeStyle": "Aɣanib n tizirig",
"strokeStyle_solid": "Aččuran",
"strokeStyle_dashed": "S tjerriḍin",
"strokeStyle_dotted": "S tenqiḍin",
"sloppiness": "",
"opacity": "Tiḍullest",
"textAlign": "Areyyec n uḍris",
"edges": "Leryuf",
"sharp": "Yemsed",
"round": "Imdewer",
"arrowheads": "Ixfawen n tenccabt",
"arrowhead_none": "Ulac",
"arrowhead_arrow": "Taneccabt",
"arrowhead_bar": "Afeggag",
"arrowhead_dot": "Tanqiḍt",
"fontSize": "Tiddi n tsefsit",
"fontFamily": "Tawacult n tsefsiyin",
"onlySelected": "Tafrayt kan",
"withBackground": "S ugilal",
"exportEmbedScene": "Seddu asayes deg ufaylu yettwasifḍen",
"exportEmbedScene_details": "Asayes ad yettwasekles deg ufaylu n usifeḍ PNG/SVG akken akken ad yili wamek ara d-yettwarr seg-s usayes. Ayagi ad isimɣur tiddi n ufaylu n usifeḍ.",
"addWatermark": "Seddu \"Yettwaxdem s Excalidraw\"",
"handDrawn": "Asuneɣ s ufus",
"normal": "Amagnu",
"code": "Tangalt",
"small": "Meẓẓi",
"medium": "Alemmas",
"large": "Ameqran",
"veryLarge": "Meqqer aṭas",
"solid": "Aččuran",
"hachure": "Azerreg",
"crossHatch": "Azerreg anmidag",
"thin": "Arqaq",
"bold": "Azuran",
"left": "Azelmaḍ",
"center": "Talemmast",
"right": "Ayfus",
"extraBold": "Azuran aṭas",
"architect": "Amasdag",
"artist": "Anaẓur",
"cartoonist": "",
"fileTitle": "Azwel n ufaylu",
"colorPicker": "Amafran n yini",
"canvasBackground": "Agilal n teɣzut n usuneɣ",
"drawingCanvas": "Taɣzut n usuneɣ",
"layers": "Tissiyin",
"actions": "Tigawin",
"language": "Tutlayt",
"createRoom": "Bḍu tiɣimit n umɛawen s srid",
"duplicateSelection": "Sisleg",
"untitled": "War azwel",
"name": "Isem",
"yourName": "Isem-ik (im)",
"madeWithExcalidraw": "Yettwaxdem s Excalidraw",
"group": "Segrew tafrayt",
"ungroup": "Kkess asegrew i tefrayt",
"collaborators": "Imɛiwnen",
"gridMode": "Askar n uferrug",
"addToLibrary": "Rnu ɣer temkarḍit",
"removeFromLibrary": "Kkes si temkarḍit",
"libraryLoadingMessage": "Asali n temkarḍit…",
"libraries": "Snirem timkarḍiyin",
"loadingScene": "Asali n usayes…",
"align": "Reyyec",
"alignTop": "Areyyec uksawen",
"alignBottom": "Areyyec ukessar",
"alignLeft": "Reyyec s azelmaḍ",
"alignRight": "Areyyec s ayfus",
"centerVertically": "Di tlemmast s ibeddi",
"centerHorizontally": "Di tlemmast s uglawi",
"distributeHorizontally": "Freq s uglawi",
"distributeVertically": "Freq s yibeddi",
"viewMode": "Askar n tmuɣli"
},
"buttons": {
"clearReset": "Ales awennez n teɣzut n usuneɣ",
"export": "Sifeḍ",
"exportToPng": "Sifeḍ ɣer PNG",
"exportToSvg": "Sifeḍ ɣer SVG",
"copyToClipboard": "Nɣel ɣer tecfawit",
"copyPngToClipboard": "Nɣel PNG ɣer tecfawit",
"scale": "Taskala",
"save": "Sekles",
"saveAs": "Sekles am",
"load": "Sali-d",
"getShareableLink": "Awi-d aseɣwen n beṭṭu",
"close": "Mdel",
"selectLanguage": "Fren tutlayt",
"scrollBackToContent": "Uɣal s agbur",
"zoomIn": "Simɣur",
"zoomOut": "Simẓi",
"resetZoom": "Ales awennez n usemɣer",
"menu": "Umuɣ",
"done": "Ifukk",
"edit": "Ẓreg",
"undo": "Sefsex",
"redo": "Err-d",
"roomDialog": "Bdu amɛawen s srid",
"createNewRoom": "Snulfu-d taxxamt tamaynutt",
"fullScreen": "Agdil aččuran",
"darkMode": "Askar imsulles",
"lightMode": "Askar afaw",
"zenMode": "Askar Zen",
"exitZenMode": "Ffeɣ seg uskar Zen"
},
"alerts": {
"clearReset": "Ayagi ad isfeḍ akk taɣzut n usuneɣ. Tetḥeqqeḍ?",
"couldNotCreateShareableLink": "D awezɣi asnulfu n useɣwen n beṭṭu.",
"couldNotCreateShareableLinkTooBig": "D awezɣi asnulfu n useɣwen n beṭṭu. Asayes ɣezzif aṭas",
"couldNotLoadInvalidFile": "D awezɣi asali n ufaylu armeɣtu",
"importBackendFailed": "",
"cannotExportEmptyCanvas": "D awezɣi asifeḍ n teɣzut n usuneɣ tilemt.",
"couldNotCopyToClipboard": "D awezɣi anɣal ɣer tecfawit. Eɛreḍ ad tesqedceḍ iminig Chrome.",
"decryptFailed": "D awezɣi tukksa n uwgelhen i yisefka.",
"uploadedSecurly": "Asili yettwasɣelles s uwgelhen ixef s ixef, ayagi yebɣa ad d-yini belli aqeddac n Excalidraw akked medden ur zmiren ara ad ɣren agbur.",
"loadSceneOverridePrompt": "Asali n wunuɣ uffiɣ ad isemselsi agbur-inek (m) yellan. Tebɣiḍ ad tkemmeleḍ?",
"errorLoadingLibrary": "Teḍra-d tuccḍa deg usali n temkarḍit n wis kraḍ.",
"confirmAddLibrary": "Ayagi adirnu talɣa (win) {{numShapes}} ɣer temkarḍit-inek (m). Tetḥeqqeḍ?",
"imageDoesNotContainScene": "Taktert n tugniwin ur tettwadhel ara akka tura.\nTebɣiḍ ad tketreḍ asayes? Tugna-agi tettban-d ur tegbir ara isefka n usnas. Tesremdeḍ ayagi deg usifeḍ?",
"cannotRestoreFromImage": "Asayes ulamek ara d-yettwarr seg ufaylu-agi n tugna"
},
"toolBar": {
"selection": "Tafrayt",
"draw": "Unuɣ ilelli",
"rectangle": "Asrem",
"diamond": "Ameɣṛun",
"ellipse": "Taglayt",
"arrow": "Taneccabt",
"line": "Izirig",
"text": "Aḍris",
"library": "Tamkarḍit",
"lock": "Eǧǧ afecku n tefrayt yermed mbaɛd asuneɣ"
},
"headings": {
"canvasActions": "Tigawin n teɣzut n usuneɣ",
"selectedShapeActions": "Tigawin n talɣa yettwafernen",
"shapes": "Talɣiwin"
},
"hints": {
"linearElement": "Ssit akken ad tebduḍ aṭas n tenqiḍin, zuɣer i yiwen n yizirig",
"freeDraw": "Ssit yerna zuɣer, serreḥ ticki tfukeḍ",
"text": "Tixidest: tzemreḍ daɣen ad ternuḍ aḍris s usiti snat n tikkal anida tebɣiḍ s ufecku n tefrayt",
"linearElementMulti": "Ssit ɣef tenqiḍt taneggarut neɣ ssed taqeffalt Escape neɣ taqeffalt Kcem akken ad tfakkeḍ",
"lockAngle": "Tzemreḍ ad tḥettmeḍ tiɣmert s tuṭṭfa n tqeffalt SHIFT",
"resize": "Tzemreḍ ad tḥettemeḍ assaɣ s tuṭṭfa n tqeffalt SHIFT mi ara tettbeddileḍ tiddi,\nma teṭṭfeḍ ALT abeddel n tiddi ad yili si tlemmast",
"rotate": "Tzemreḍ ad tḥettemeḍ tiɣemmar s tuṭṭfa n SHIFT di tuzzya",
"lineEditor_info": "Ssit snat n tikkal neɣ ssed taqeffalt Kcem akken ad tẓergeḍ tinqiḍin",
"lineEditor_pointSelected": "Ssed taqeffalt kkes akken ad tekkseḍ tanqiḍt, CtrlOrCmd+D akken ad tsiselgeḍ, neɣ zuɣer akken ad tesmuttiḍ",
"lineEditor_nothingSelected": "Fren tanqiḍt ara tesmuttiḍ neɣ ara tekkseḍ, neɣ ṭṭef taqeffalt Alt akken ad ternuḍ tinqiḍin timaynutin"
},
"canvasError": {
"cannotShowPreview": "Ulamek abeqqeḍ n teskant",
"canvasTooBig": "Taɣzut n usuneɣ tezmer ad tili temeqqer aṭas.",
"canvasTooBigTip": "Tixidest: eɛreḍ ad tesqerbeḍ ciṭ iferdisen yembaɛaden."
},
"errorSplash": {
"headingMain_pre": "Teḍra-d tuccḍa. Eɛreḍ ",
"headingMain_button": "asali n usebter tikkelt-nniḍen.",
"clearCanvasMessage": "Ma yella tulsa n usali ur tefri ara ugur, eɛreḍ ",
"clearCanvasMessage_button": "asfaḍ n teɣzut n usuneɣ.",
"clearCanvasCaveat": " Ayagi ad d-iglu s usṛuḥu n umahil ",
"trackedToSentry_pre": "Tuccḍa akked umesmagi ",
"trackedToSentry_post": " tettwasekles deg unagraw-nneɣ.",
"openIssueMessage_pre": "",
"openIssueMessage_button": "afecku n weḍfar n yibugen.",
"openIssueMessage_post": " Ma ulac uɣilif seddu talɣut ukessar-agi s wenɣal akked usenṭeḍ di GitHub issue.",
"sceneContent": "Agbur n usayes:"
},
"roomDialog": {
"desc_intro": "Tzemreḍ ad d-teɛerḍeḍ medden ɣer usayes-inek (m) amiran akken ad ttekkin yid-k.",
"desc_privacy": "Ur tqelliq ara, tiɣimit tsseqdac awgelhen ixef s ixef, dɣa ayen ara tsunɣeḍ ad iqqim d amaẓlay. Ula d aqeddac-nneɣ ur yezmir ara ad iwali acu txeddemeḍ.",
"button_startSession": "Bdu tiɣimit",
"button_stopSession": "Ḥbes tiɣimit",
"desc_inProgressIntro": "Tiɣimit n umɛawen s srid tetteddu akka tura.",
"desc_shareLink": "Bḍu aseɣwen-agi akked medden ukud tebɣiḍ ad temɛawaneḍ:",
"desc_exitSession": "Aḥbas n tɣimit ad k (m) yesenser si texxamt, maca ad tizmireḍ ad tkemmeleḍ amahil s usayes, s wudem adigan. Ẓer belli ayagi ur yettḥaz ara imdanen-nniḍen, yerna ad izmiren ad kemmelen ad mɛawanen di tsuffeɣt-nnsen."
},
"errorDialog": {
"title": "Tuccḍa"
},
"helpDialog": {
"blog": "Ɣeṛ ablug-nneɣ",
"click": "ssit",
"curvedArrow": "Taneccabt izelgen",
"curvedLine": "Izirig izelgen",
"documentation": "Tasemlit",
"drag": "zuɣer",
"editor": "Amaẓrag",
"github": "Tufiḍ-d ugur? Azen-aɣ-d",
"howto": "Ḍfer imniren-nneɣ",
"or": "neɣ",
"preventBinding": "",
"shapes": "Talɣiwin",
"shortcuts": "Inegzumen n unasiw",
"textFinish": "Fak asiẓreg (aḍris)",
"textNewLine": "Rnu ajerriḍ amaynut (aḍris)",
"title": "Tallelt",
"view": "Tamuɣli",
"zoomToFit": "Simɣur akken ad twliḍ akk iferdisen",
"zoomToSelection": "Simɣur ɣer tefrayt"
},
"encrypted": {
"tooltip": "Unuɣen-inek (m) ttuwgelhnen seg yixef s ixef dɣa iqeddacen n Excalidraw werǧin ad ten-walin. "
},
"stats": {
"angle": "Tiɣmeṛt",
"element": "Aferdis",
"elements": "Iferdisen",
"height": "Tattayt",
"scene": "Asayes",
"selected": "Yettwafren",
"storage": "Aḥraz",
"title": "",
"total": "Aɣrud",
"width": "Tehri"
},
"toast": {
"copyStyles": "Iɣunab yettwaneɣlen.",
"copyToClipboardAsPng": "Yettwanɣel ɣer tecfawit am PNG."
}
}
+1 -2
View File
@@ -91,8 +91,7 @@
"centerVertically": "수직으로 중앙 정렬", "centerVertically": "수직으로 중앙 정렬",
"centerHorizontally": "수평으로 중앙 정렬", "centerHorizontally": "수평으로 중앙 정렬",
"distributeHorizontally": "수평으로 분배", "distributeHorizontally": "수평으로 분배",
"distributeVertically": "수직으로 분배", "distributeVertically": "수직으로 분배"
"viewMode": ""
}, },
"buttons": { "buttons": {
"clearReset": "캔버스 초기화", "clearReset": "캔버스 초기화",
+3 -4
View File
@@ -80,9 +80,9 @@
"gridMode": "", "gridMode": "",
"addToLibrary": "မှတ်တမ်းတင်", "addToLibrary": "မှတ်တမ်းတင်",
"removeFromLibrary": "မှတ်တမ်းမှထုတ်", "removeFromLibrary": "မှတ်တမ်းမှထုတ်",
"libraryLoadingMessage": "မှတ်တမ်းအား တင်သွင်းနေသည်", "libraryLoadingMessage": "မှတ်တမ်းအား တင်သွင်းနေသည်...",
"libraries": "စာကြည့်တိုက်တွင်ရှာဖွေပါ", "libraries": "စာကြည့်တိုက်တွင်ရှာဖွေပါ",
"loadingScene": "မြင်ကွင်းဖော်နေသည်", "loadingScene": "မြင်ကွင်းဖော်နေသည်...",
"align": "ချိန်ညှိ", "align": "ချိန်ညှိ",
"alignTop": "ထိပ်ညှိ", "alignTop": "ထိပ်ညှိ",
"alignBottom": "အခြေညှိ", "alignBottom": "အခြေညှိ",
@@ -91,8 +91,7 @@
"centerVertically": "ဒေါင်လိုက်အလယ်ညှိ", "centerVertically": "ဒေါင်လိုက်အလယ်ညှိ",
"centerHorizontally": "အလျားလိုက်အလယ်ညှိ", "centerHorizontally": "အလျားလိုက်အလယ်ညှိ",
"distributeHorizontally": "အလျားလိုက်", "distributeHorizontally": "အလျားလိုက်",
"distributeVertically": "ထောင်လိုက်", "distributeVertically": "ထောင်လိုက်"
"viewMode": ""
}, },
"buttons": { "buttons": {
"clearReset": "ကားချပ်ရှင်းလင်း", "clearReset": "ကားချပ်ရှင်းလင်း",
+3 -4
View File
@@ -80,9 +80,9 @@
"gridMode": "Rutevisning", "gridMode": "Rutevisning",
"addToLibrary": "Legg til i bibliotek", "addToLibrary": "Legg til i bibliotek",
"removeFromLibrary": "Fjern fra bibliotek", "removeFromLibrary": "Fjern fra bibliotek",
"libraryLoadingMessage": "Laster bibliotek", "libraryLoadingMessage": "Laster bibliotek...",
"libraries": "Bla gjennom biblioteker", "libraries": "Bla gjennom biblioteker",
"loadingScene": "Laster inn scene", "loadingScene": "Laster inn scene...",
"align": "Juster", "align": "Juster",
"alignTop": "Juster øverst", "alignTop": "Juster øverst",
"alignBottom": "Juster nederst", "alignBottom": "Juster nederst",
@@ -91,8 +91,7 @@
"centerVertically": "Midtstill vertikalt", "centerVertically": "Midtstill vertikalt",
"centerHorizontally": "Midtstill horisontalt", "centerHorizontally": "Midtstill horisontalt",
"distributeHorizontally": "Distribuer horisontalt", "distributeHorizontally": "Distribuer horisontalt",
"distributeVertically": "Distribuer vertikalt", "distributeVertically": "Distribuer vertikalt"
"viewMode": "Visningsmodus"
}, },
"buttons": { "buttons": {
"clearReset": "Tøm lerretet og tilbakestill bakgrunnsfargen", "clearReset": "Tøm lerretet og tilbakestill bakgrunnsfargen",
+1 -2
View File
@@ -91,8 +91,7 @@
"centerVertically": "Verticaal Centreren", "centerVertically": "Verticaal Centreren",
"centerHorizontally": "Horizontaal Centreren", "centerHorizontally": "Horizontaal Centreren",
"distributeHorizontally": "Horizontaal verspreiden", "distributeHorizontally": "Horizontaal verspreiden",
"distributeVertically": "Verticaal distribueren", "distributeVertically": "Verticaal distribueren"
"viewMode": "Weergavemodus"
}, },
"buttons": { "buttons": {
"clearReset": "Canvas opnieuw instellen", "clearReset": "Canvas opnieuw instellen",
+9 -10
View File
@@ -80,9 +80,9 @@
"gridMode": "Rutevisning", "gridMode": "Rutevisning",
"addToLibrary": "Legg til i bibliotek", "addToLibrary": "Legg til i bibliotek",
"removeFromLibrary": "Fjern frå bibliotek", "removeFromLibrary": "Fjern frå bibliotek",
"libraryLoadingMessage": "Laster bibliotek", "libraryLoadingMessage": "Laster bibliotek...",
"libraries": "Blad gjennom bibliotek", "libraries": "Blad gjennom bibliotek",
"loadingScene": "Laster scene", "loadingScene": "Laster scene...",
"align": "Juster", "align": "Juster",
"alignTop": "Juster til topp", "alignTop": "Juster til topp",
"alignBottom": "Juster til botn", "alignBottom": "Juster til botn",
@@ -91,8 +91,7 @@
"centerVertically": "Midtstill vertikalt", "centerVertically": "Midtstill vertikalt",
"centerHorizontally": "Midtstill horisontalt", "centerHorizontally": "Midtstill horisontalt",
"distributeHorizontally": "Sprei horisontalt", "distributeHorizontally": "Sprei horisontalt",
"distributeVertically": "Sprei vertikalt", "distributeVertically": "Sprei vertikalt"
"viewMode": ""
}, },
"buttons": { "buttons": {
"clearReset": "Tilbakestill lerretet", "clearReset": "Tilbakestill lerretet",
@@ -202,22 +201,22 @@
}, },
"helpDialog": { "helpDialog": {
"blog": "", "blog": "",
"click": "klikk", "click": "",
"curvedArrow": "", "curvedArrow": "",
"curvedLine": "", "curvedLine": "",
"documentation": "", "documentation": "",
"drag": "", "drag": "",
"editor": "Redigering", "editor": "",
"github": "", "github": "",
"howto": "", "howto": "",
"or": "eller", "or": "",
"preventBinding": "", "preventBinding": "",
"shapes": "Formar", "shapes": "",
"shortcuts": "", "shortcuts": "",
"textFinish": "", "textFinish": "",
"textNewLine": "", "textNewLine": "",
"title": "Hjelp", "title": "",
"view": "Vising", "view": "",
"zoomToFit": "", "zoomToFit": "",
"zoomToSelection": "" "zoomToSelection": ""
}, },
+1 -2
View File
@@ -91,8 +91,7 @@
"centerVertically": "ਲੇਟਵੇਂ ਵਿਚਕਾਰ ਕਰੋ", "centerVertically": "ਲੇਟਵੇਂ ਵਿਚਕਾਰ ਕਰੋ",
"centerHorizontally": "ਖੜ੍ਹਵੇਂ ਵਿਚਕਾਰ ਕਰੋ", "centerHorizontally": "ਖੜ੍ਹਵੇਂ ਵਿਚਕਾਰ ਕਰੋ",
"distributeHorizontally": "ਖੜ੍ਹਵੇਂ ਇਕਸਾਰ ਵੰਡੋ", "distributeHorizontally": "ਖੜ੍ਹਵੇਂ ਇਕਸਾਰ ਵੰਡੋ",
"distributeVertically": "ਲੇਟਵੇਂ ਇਕਸਾਰ ਵੰਡੋ", "distributeVertically": "ਲੇਟਵੇਂ ਇਕਸਾਰ ਵੰਡੋ"
"viewMode": ""
}, },
"buttons": { "buttons": {
"clearReset": "ਕੈਨਵਸ ਰੀਸੈੱਟ ਕਰੋ", "clearReset": "ਕੈਨਵਸ ਰੀਸੈੱਟ ਕਰੋ",
+14 -15
View File
@@ -1,7 +1,7 @@
{ {
"ar-SA": 89, "ar-SA": 90,
"bg-BG": 93, "bg-BG": 94,
"ca-ES": 89, "ca-ES": 90,
"de-DE": 100, "de-DE": 100,
"el-GR": 100, "el-GR": 100,
"en": 100, "en": 100,
@@ -9,28 +9,27 @@
"fa-IR": 98, "fa-IR": 98,
"fi-FI": 100, "fi-FI": 100,
"fr-FR": 100, "fr-FR": 100,
"he-IL": 89, "he-IL": 90,
"hi-IN": 89, "hi-IN": 90,
"hu-HU": 89, "hu-HU": 90,
"id-ID": 100, "id-ID": 100,
"it-IT": 100, "it-IT": 100,
"ja-JP": 81, "ja-JP": 81,
"kab-KAB": 97, "ko-KR": 90,
"ko-KR": 89,
"my-MM": 83, "my-MM": 83,
"nb-NO": 100, "nb-NO": 100,
"nl-NL": 100, "nl-NL": 100,
"nn-NO": 92, "nn-NO": 90,
"pa-IN": 99, "pa-IN": 100,
"pl-PL": 90, "pl-PL": 90,
"pt-BR": 100, "pt-BR": 100,
"pt-PT": 99, "pt-PT": 100,
"ro-RO": 100, "ro-RO": 100,
"ru-RU": 99, "ru-RU": 100,
"sk-SK": 100, "sk-SK": 100,
"sv-SE": 100, "sv-SE": 100,
"tr-TR": 89, "tr-TR": 90,
"uk-UA": 99, "uk-UA": 100,
"zh-CN": 99, "zh-CN": 100,
"zh-TW": 100 "zh-TW": 100
} }
+1 -2
View File
@@ -91,8 +91,7 @@
"centerVertically": "Wyśrodkuj w pionie", "centerVertically": "Wyśrodkuj w pionie",
"centerHorizontally": "Wyśrodkuj w poziomie", "centerHorizontally": "Wyśrodkuj w poziomie",
"distributeHorizontally": "Rozłóż poziomo", "distributeHorizontally": "Rozłóż poziomo",
"distributeVertically": "Rozłóż pionowo", "distributeVertically": "Rozłóż pionowo"
"viewMode": "Tryb widoku"
}, },
"buttons": { "buttons": {
"clearReset": "Wyczyść dokument i zresetuj kolor dokumentu", "clearReset": "Wyczyść dokument i zresetuj kolor dokumentu",
+1 -2
View File
@@ -91,8 +91,7 @@
"centerVertically": "Centralizar verticalmente", "centerVertically": "Centralizar verticalmente",
"centerHorizontally": "Centralizar horizontalmente", "centerHorizontally": "Centralizar horizontalmente",
"distributeHorizontally": "Distribuir horizontalmente", "distributeHorizontally": "Distribuir horizontalmente",
"distributeVertically": "Distribuir verticalmente", "distributeVertically": "Distribuir verticalmente"
"viewMode": "Modo de visualização"
}, },
"buttons": { "buttons": {
"clearReset": "Limpar o canvas e redefinir a cor de fundo", "clearReset": "Limpar o canvas e redefinir a cor de fundo",
+3 -4
View File
@@ -80,9 +80,9 @@
"gridMode": "Modo grade", "gridMode": "Modo grade",
"addToLibrary": "Adicionar à biblioteca", "addToLibrary": "Adicionar à biblioteca",
"removeFromLibrary": "Remover da biblioteca", "removeFromLibrary": "Remover da biblioteca",
"libraryLoadingMessage": "Carregando biblioteca", "libraryLoadingMessage": "Carregando biblioteca...",
"libraries": "Procurar bibliotecas", "libraries": "Procurar bibliotecas",
"loadingScene": "Carregando cena", "loadingScene": "Carregando cena...",
"align": "Alinhamento", "align": "Alinhamento",
"alignTop": "Alinhar ao topo", "alignTop": "Alinhar ao topo",
"alignBottom": "Alinhar ao fundo", "alignBottom": "Alinhar ao fundo",
@@ -91,8 +91,7 @@
"centerVertically": "Centralizar verticalmente", "centerVertically": "Centralizar verticalmente",
"centerHorizontally": "Centralizar horizontalmente", "centerHorizontally": "Centralizar horizontalmente",
"distributeHorizontally": "Distribuir horizontalmente", "distributeHorizontally": "Distribuir horizontalmente",
"distributeVertically": "Distribuir verticalmente", "distributeVertically": "Distribuir verticalmente"
"viewMode": ""
}, },
"buttons": { "buttons": {
"clearReset": "Limpar o canvas e redefinir a cor de fundo", "clearReset": "Limpar o canvas e redefinir a cor de fundo",
+3 -4
View File
@@ -80,9 +80,9 @@
"gridMode": "Mod grilă", "gridMode": "Mod grilă",
"addToLibrary": "Adăugare la bibliotecă", "addToLibrary": "Adăugare la bibliotecă",
"removeFromLibrary": "Eliminare din bibliotecă", "removeFromLibrary": "Eliminare din bibliotecă",
"libraryLoadingMessage": "Se încarcă biblioteca", "libraryLoadingMessage": "Se încarcă biblioteca...",
"libraries": "Răsfoiește bibliotecile", "libraries": "Răsfoiește bibliotecile",
"loadingScene": "Se încarcă scena", "loadingScene": "Se încarcă scena...",
"align": "Aliniere", "align": "Aliniere",
"alignTop": "Aliniere sus", "alignTop": "Aliniere sus",
"alignBottom": "Aliniere jos", "alignBottom": "Aliniere jos",
@@ -91,8 +91,7 @@
"centerVertically": "Centrare verticală", "centerVertically": "Centrare verticală",
"centerHorizontally": "Centrare orizontală", "centerHorizontally": "Centrare orizontală",
"distributeHorizontally": "Distribuie orizontal", "distributeHorizontally": "Distribuie orizontal",
"distributeVertically": "Distribuie vertical", "distributeVertically": "Distribuie vertical"
"viewMode": "Mod de vizualizare"
}, },
"buttons": { "buttons": {
"clearReset": "Resetare pânză", "clearReset": "Resetare pânză",
+3 -4
View File
@@ -80,9 +80,9 @@
"gridMode": "Сетка", "gridMode": "Сетка",
"addToLibrary": "Добавить в библиотеку", "addToLibrary": "Добавить в библиотеку",
"removeFromLibrary": "Удалить из библиотеки", "removeFromLibrary": "Удалить из библиотеки",
"libraryLoadingMessage": "Загрузка библиотеки", "libraryLoadingMessage": "Загрузка библиотеки...",
"libraries": "Просмотреть библиотеки", "libraries": "Просмотреть библиотеки",
"loadingScene": "Загрузка сцены", "loadingScene": "Загрузка сцены...",
"align": "Выровнять", "align": "Выровнять",
"alignTop": "Выровнять по верхнему краю", "alignTop": "Выровнять по верхнему краю",
"alignBottom": "Выровнять по нижнему краю", "alignBottom": "Выровнять по нижнему краю",
@@ -91,8 +91,7 @@
"centerVertically": "Центрировать по вертикали", "centerVertically": "Центрировать по вертикали",
"centerHorizontally": "Центрировать по горизонтали", "centerHorizontally": "Центрировать по горизонтали",
"distributeHorizontally": "Распределить по горизонтали", "distributeHorizontally": "Распределить по горизонтали",
"distributeVertically": "Распределить по вертикали", "distributeVertically": "Распределить по вертикали"
"viewMode": ""
}, },
"buttons": { "buttons": {
"clearReset": "Очистить холст и сбросить цвет фона", "clearReset": "Очистить холст и сбросить цвет фона",
+3 -4
View File
@@ -80,9 +80,9 @@
"gridMode": "Režim mriežky", "gridMode": "Režim mriežky",
"addToLibrary": "Pridať do knižnice", "addToLibrary": "Pridať do knižnice",
"removeFromLibrary": "Odstrániť z knižnice", "removeFromLibrary": "Odstrániť z knižnice",
"libraryLoadingMessage": "Načítavanie knižnice", "libraryLoadingMessage": "Načítavanie knižnice...",
"libraries": "Prehliadať knižnice", "libraries": "Prehliadať knižnice",
"loadingScene": "Načítavanie scény", "loadingScene": "Načítavanie scény...",
"align": "Zarovnanie", "align": "Zarovnanie",
"alignTop": "Zarovnať nahor", "alignTop": "Zarovnať nahor",
"alignBottom": "Zarovnať nadol", "alignBottom": "Zarovnať nadol",
@@ -91,8 +91,7 @@
"centerVertically": "Zarovnať zvislo na stred", "centerVertically": "Zarovnať zvislo na stred",
"centerHorizontally": "Zarovnať vodorovne na stred", "centerHorizontally": "Zarovnať vodorovne na stred",
"distributeHorizontally": "Rozmiestniť vodorovne", "distributeHorizontally": "Rozmiestniť vodorovne",
"distributeVertically": "Rozmiestniť zvisle", "distributeVertically": "Rozmiestniť zvisle"
"viewMode": "Režim zobrazenia"
}, },
"buttons": { "buttons": {
"clearReset": "Obnoviť plátno", "clearReset": "Obnoviť plátno",
+3 -4
View File
@@ -80,9 +80,9 @@
"gridMode": "Rutnätsläge", "gridMode": "Rutnätsläge",
"addToLibrary": "Lägg till i biblioteket", "addToLibrary": "Lägg till i biblioteket",
"removeFromLibrary": "Ta bort från bibliotek", "removeFromLibrary": "Ta bort från bibliotek",
"libraryLoadingMessage": "Laddar bibliotek", "libraryLoadingMessage": "Laddar bibliotek...",
"libraries": "Bläddra i bibliotek", "libraries": "Bläddra i bibliotek",
"loadingScene": "Laddar scen", "loadingScene": "Laddar scen...",
"align": "Justera", "align": "Justera",
"alignTop": "Justera överkant", "alignTop": "Justera överkant",
"alignBottom": "Justera underkant", "alignBottom": "Justera underkant",
@@ -91,8 +91,7 @@
"centerVertically": "Centrera vertikalt", "centerVertically": "Centrera vertikalt",
"centerHorizontally": "Centrera horisontellt", "centerHorizontally": "Centrera horisontellt",
"distributeHorizontally": "Fördela horisontellt", "distributeHorizontally": "Fördela horisontellt",
"distributeVertically": "Fördela vertikalt", "distributeVertically": "Fördela vertikalt"
"viewMode": "Visningsläge"
}, },
"buttons": { "buttons": {
"clearReset": "Återställ canvasen", "clearReset": "Återställ canvasen",
+2 -3
View File
@@ -82,7 +82,7 @@
"removeFromLibrary": "Kütüphaneden kaldır", "removeFromLibrary": "Kütüphaneden kaldır",
"libraryLoadingMessage": "Kütüphane yükleniyor...", "libraryLoadingMessage": "Kütüphane yükleniyor...",
"libraries": "Kütüphanelere gözat", "libraries": "Kütüphanelere gözat",
"loadingScene": "Çalışma alanı yükleniyor", "loadingScene": "Çalışma alanı yükleniyor...",
"align": "Hizala", "align": "Hizala",
"alignTop": "Yukarı hizala", "alignTop": "Yukarı hizala",
"alignBottom": "Aşağı hizala", "alignBottom": "Aşağı hizala",
@@ -91,8 +91,7 @@
"centerVertically": "Dikeyde ortala", "centerVertically": "Dikeyde ortala",
"centerHorizontally": "Yatayda ortala", "centerHorizontally": "Yatayda ortala",
"distributeHorizontally": "Yatay dağıt", "distributeHorizontally": "Yatay dağıt",
"distributeVertically": "Dikey dağıt", "distributeVertically": "Dikey dağıt"
"viewMode": ""
}, },
"buttons": { "buttons": {
"clearReset": "Tuvali sıfırla", "clearReset": "Tuvali sıfırla",
+3 -4
View File
@@ -80,9 +80,9 @@
"gridMode": "Режим сітки", "gridMode": "Режим сітки",
"addToLibrary": "Додати до бібліотеки", "addToLibrary": "Додати до бібліотеки",
"removeFromLibrary": "Видалити з бібліотеки", "removeFromLibrary": "Видалити з бібліотеки",
"libraryLoadingMessage": "Завантажити бібліотеку", "libraryLoadingMessage": "Завантажити бібліотеку...",
"libraries": "Огляд бібліотек", "libraries": "Огляд бібліотек",
"loadingScene": "Завантаження сцени", "loadingScene": "Завантаження сцени...",
"align": "Вирівнювання", "align": "Вирівнювання",
"alignTop": "Вирівняти по верхньому краю", "alignTop": "Вирівняти по верхньому краю",
"alignBottom": "Вирівняти по нижньому краю", "alignBottom": "Вирівняти по нижньому краю",
@@ -91,8 +91,7 @@
"centerVertically": "Центрувати по вертикалі", "centerVertically": "Центрувати по вертикалі",
"centerHorizontally": "Центрувати по горизонталі", "centerHorizontally": "Центрувати по горизонталі",
"distributeHorizontally": "Розподілити по горизонталі", "distributeHorizontally": "Розподілити по горизонталі",
"distributeVertically": "Розподілити вертикально", "distributeVertically": "Розподілити вертикально"
"viewMode": ""
}, },
"buttons": { "buttons": {
"clearReset": "Очистити полотно", "clearReset": "Очистити полотно",
+3 -4
View File
@@ -80,9 +80,9 @@
"gridMode": "网格模式", "gridMode": "网格模式",
"addToLibrary": "添加到库中", "addToLibrary": "添加到库中",
"removeFromLibrary": "从库中移除", "removeFromLibrary": "从库中移除",
"libraryLoadingMessage": "正在加载库", "libraryLoadingMessage": "正在加载库...",
"libraries": "浏览库", "libraries": "浏览库",
"loadingScene": "正在加载绘图", "loadingScene": "正在加载绘图...",
"align": "对齐", "align": "对齐",
"alignTop": "顶部对齐", "alignTop": "顶部对齐",
"alignBottom": "底端对齐", "alignBottom": "底端对齐",
@@ -91,8 +91,7 @@
"centerVertically": "垂直居中", "centerVertically": "垂直居中",
"centerHorizontally": "水平居中", "centerHorizontally": "水平居中",
"distributeHorizontally": "水平等距分布", "distributeHorizontally": "水平等距分布",
"distributeVertically": "垂直等距分布", "distributeVertically": "垂直等距分布"
"viewMode": ""
}, },
"buttons": { "buttons": {
"clearReset": "重置画布", "clearReset": "重置画布",
+1 -2
View File
@@ -91,8 +91,7 @@
"centerVertically": "垂直置中", "centerVertically": "垂直置中",
"centerHorizontally": "水平置中", "centerHorizontally": "水平置中",
"distributeHorizontally": "水平分布", "distributeHorizontally": "水平分布",
"distributeVertically": "垂直分布", "distributeVertically": "垂直分布"
"viewMode": "檢視模式"
}, },
"buttons": { "buttons": {
"clearReset": "重置 canvas", "clearReset": "重置 canvas",
+2 -3
View File
@@ -249,10 +249,9 @@ const doSegmentsIntersect = (p1: Point, q1: Point, p2: Point, q2: Point) => {
export const getGridPoint = ( export const getGridPoint = (
x: number, x: number,
y: number, y: number,
isGridOn: boolean, gridSize: number | null,
gridSize: number,
): [number, number] => { ): [number, number] => {
if (isGridOn) { if (gridSize) {
return [ return [
Math.round(x / gridSize) * gridSize, Math.round(x / gridSize) * gridSize,
Math.round(y / gridSize) * gridSize, Math.round(y / gridSize) * gridSize,
-5
View File
@@ -16,22 +16,17 @@ Please add the latest change on the top under the correct section.
## Excalidraw API ## Excalidraw API
### Features
- Add `viewModeEnabled` prop which enabled the view mode [#2840](https://github.com/excalidraw/excalidraw/pull/2840). When this prop is used, the view mode will not show up in context menu is so it is fully controlled by host.
- Expose `getAppState` on `excalidrawRef` [#2834](https://github.com/excalidraw/excalidraw/pull/2834). - Expose `getAppState` on `excalidrawRef` [#2834](https://github.com/excalidraw/excalidraw/pull/2834).
## Excalidraw Library ## Excalidraw Library
### Features ### Features
- Add view mode [#2840](https://github.com/excalidraw/excalidraw/pull/2840).
- Remove `copy`, `cut`, and `paste` actions from contextmenu [#2872](https://github.com/excalidraw/excalidraw/pull/2872) - Remove `copy`, `cut`, and `paste` actions from contextmenu [#2872](https://github.com/excalidraw/excalidraw/pull/2872)
- Support `Ctrl-Y` shortcut to redo on Windows [#2831](https://github.com/excalidraw/excalidraw/pull/2831). - Support `Ctrl-Y` shortcut to redo on Windows [#2831](https://github.com/excalidraw/excalidraw/pull/2831).
### Fixes ### Fixes
- Fix UI pointer-events not disabled when dragging on canvas [#2856](https://github.com/excalidraw/excalidraw/pull/2856).
- Fix remote pointers not accounting for offset [#2855](https://github.com/excalidraw/excalidraw/pull/2855). - Fix remote pointers not accounting for offset [#2855](https://github.com/excalidraw/excalidraw/pull/2855).
## 0.2.1 ## 0.2.1
-5
View File
@@ -138,7 +138,6 @@ export default function App() {
| [`onExportToBackend`](#onExportToBackend) | Function | | Callback triggered when link button is clicked on export dialog | | [`onExportToBackend`](#onExportToBackend) | Function | | Callback triggered when link button is clicked on export dialog |
| [`langCode`](#langCode) | string | `en` | Language code string | | [`langCode`](#langCode) | string | `en` | Language code string |
| [`renderFooter `](#renderFooter) | Function | | Function that renders custom UI footer | | [`renderFooter `](#renderFooter) | Function | | Function that renders custom UI footer |
| [`viewModeEnabled`](#viewModeEnabled) | boolean | false | This implies if the app is in view mode. |
### `Extra API's` ### `Extra API's`
@@ -331,7 +330,3 @@ import { defaultLang, languages } from "@excalidraw/excalidraw";
#### `renderFooter` #### `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). 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).
#### `viewModeEnabled`
This prop indicates if the app is in `view mode`. When this prop is used, the `view mode` will not show up in context menu is so it is fully controlled by host. Also the value of this prop if passed will be used over the value of `intialData.appState.viewModeEnabled`
+1 -6
View File
@@ -26,7 +26,6 @@ const Excalidraw = (props: ExcalidrawProps) => {
onExportToBackend, onExportToBackend,
renderFooter, renderFooter,
langCode = defaultLang.code, langCode = defaultLang.code,
viewModeEnabled,
} = props; } = props;
useEffect(() => { useEffect(() => {
@@ -65,7 +64,6 @@ const Excalidraw = (props: ExcalidrawProps) => {
onExportToBackend={onExportToBackend} onExportToBackend={onExportToBackend}
renderFooter={renderFooter} renderFooter={renderFooter}
langCode={langCode} langCode={langCode}
viewModeEnabled={viewModeEnabled}
/> />
</IsMobileProvider> </IsMobileProvider>
</InitializeApp> </InitializeApp>
@@ -83,6 +81,7 @@ const areEqual = (
const prevKeys = Object.keys(prevProps) as (keyof typeof prev)[]; const prevKeys = Object.keys(prevProps) as (keyof typeof prev)[];
const nextKeys = Object.keys(nextProps) as (keyof typeof next)[]; const nextKeys = Object.keys(nextProps) as (keyof typeof next)[];
return ( return (
prevUser?.name === nextUser?.name && prevUser?.name === nextUser?.name &&
prevKeys.length === nextKeys.length && prevKeys.length === nextKeys.length &&
@@ -90,10 +89,6 @@ const areEqual = (
); );
}; };
Excalidraw.defaultProps = {
lanCode: defaultLang.code,
};
const forwardedRefComp = forwardRef< const forwardedRefComp = forwardRef<
ExcalidrawAPIRefValue, ExcalidrawAPIRefValue,
PublicExcalidrawProps PublicExcalidrawProps
+1 -1
View File
@@ -74,7 +74,7 @@ const excalidrawDiagram = {
], ],
appState: { appState: {
viewBackgroundColor: "#ffffff", viewBackgroundColor: "#ffffff",
gridSize: 20, gridSize: null,
}, },
}; };
+3 -3
View File
@@ -349,12 +349,12 @@ const generateElementShape = (
if (element.type === "arrow") { if (element.type === "arrow") {
const { startArrowhead = null, endArrowhead = "arrow" } = element; const { startArrowhead = null, endArrowhead = "arrow" } = element;
function getArrowheadShapes( const getArrowheadShapes = (
element: ExcalidrawLinearElement, element: ExcalidrawLinearElement,
shape: Drawable[], shape: Drawable[],
position: "start" | "end", position: "start" | "end",
arrowhead: Arrowhead, arrowhead: Arrowhead,
) { ) => {
const arrowheadPoints = getArrowheadPoints( const arrowheadPoints = getArrowheadPoints(
element, element,
shape, shape,
@@ -392,7 +392,7 @@ const generateElementShape = (
generator.line(x3, y3, x2, y2, options), generator.line(x3, y3, x2, y2, options),
generator.line(x4, y4, x2, y2, options), generator.line(x4, y4, x2, y2, options),
]; ];
} };
if (startArrowhead !== null) { if (startArrowhead !== null) {
const shapes = getArrowheadShapes( const shapes = getArrowheadShapes(
+7 -9
View File
@@ -233,7 +233,7 @@ export const renderScene = (
context.scale(sceneState.zoom.value, sceneState.zoom.value); context.scale(sceneState.zoom.value, sceneState.zoom.value);
// Grid // Grid
if (renderGrid && appState.showGrid) { if (renderGrid && appState.gridSize) {
strokeGrid( strokeGrid(
context, context,
appState.gridSize, appState.gridSize,
@@ -373,14 +373,12 @@ export const renderScene = (
sceneState.zoom, sceneState.zoom,
"mouse", // when we render we don't know which pointer type so use mouse "mouse", // when we render we don't know which pointer type so use mouse
); );
if (!appState.viewModeEnabled) { renderTransformHandles(
renderTransformHandles( context,
context, sceneState,
sceneState, transformHandles,
transformHandles, locallySelectedElements[0].angle,
locallySelectedElements[0].angle, );
);
}
} else if (locallySelectedElements.length > 1 && !appState.isRotating) { } else if (locallySelectedElements.length > 1 && !appState.isRotating) {
const dashedLinePadding = 4 / sceneState.zoom.value; const dashedLinePadding = 4 / sceneState.zoom.value;
context.fillStyle = oc.white; context.fillStyle = oc.white;
File diff suppressed because it is too large Load Diff
-1
View File
@@ -623,7 +623,6 @@ describe("regression tests", () => {
"selectAll", "selectAll",
"gridMode", "gridMode",
"zenMode", "zenMode",
"viewMode",
"stats", "stats",
]; ];
+3 -3
View File
@@ -122,12 +122,12 @@ describe("resize rectangle ellipses and diamond elements", () => {
); );
}); });
function resize( const resize = (
element: ExcalidrawElement, element: ExcalidrawElement,
handleDir: TransformHandleDirection, handleDir: TransformHandleDirection,
mouseMove: [number, number], mouseMove: [number, number],
keyboardModifiers: KeyboardModifiers = {}, keyboardModifiers: KeyboardModifiers = {},
) { ) => {
mouse.select(element); mouse.select(element);
const handle = getTransformHandles(element, h.state.zoom, "mouse")[ const handle = getTransformHandles(element, h.state.zoom, "mouse")[
handleDir handleDir
@@ -140,4 +140,4 @@ function resize(
mouse.move(mouseMove[0], mouseMove[1]); mouse.move(mouseMove[0], mouseMove[1]);
mouse.up(); mouse.up();
}); });
} };
+1 -4
View File
@@ -84,9 +84,7 @@ export type AppState = {
toastMessage: string | null; toastMessage: string | null;
zenModeEnabled: boolean; zenModeEnabled: boolean;
appearance: "light" | "dark"; appearance: "light" | "dark";
gridSize: number; gridSize: number | null;
showGrid: boolean;
viewModeEnabled: boolean;
/** top-most selected groups (i.e. does not include nested groups) */ /** top-most selected groups (i.e. does not include nested groups) */
selectedGroupIds: { [groupId: string]: boolean }; selectedGroupIds: { [groupId: string]: boolean };
@@ -183,7 +181,6 @@ export interface ExcalidrawProps {
) => void; ) => void;
renderFooter?: (isMobile: boolean) => JSX.Element; renderFooter?: (isMobile: boolean) => JSX.Element;
langCode?: Language["code"]; langCode?: Language["code"];
viewModeEnabled?: boolean;
} }
export type SceneData = { export type SceneData = {