Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 105f7fdaad |
@@ -4,4 +4,3 @@ package-lock.json
|
||||
.vscode/
|
||||
firebase/
|
||||
dist/
|
||||
public/workbox
|
||||
|
||||
+36
-2
@@ -1,6 +1,40 @@
|
||||
{
|
||||
"extends": ["@excalidraw/eslint-config", "react-app"],
|
||||
"extends": ["prettier", "react-app"],
|
||||
"plugins": ["prettier"],
|
||||
"rules": {
|
||||
"import/no-anonymous-default-export": "off"
|
||||
"@typescript-eslint/no-unused-vars": "warn",
|
||||
"curly": "warn",
|
||||
"dot-notation": "warn",
|
||||
"import/no-anonymous-default-export": "off",
|
||||
"no-console": [
|
||||
"warn",
|
||||
{
|
||||
"allow": ["warn", "error", "info"]
|
||||
}
|
||||
],
|
||||
"no-else-return": "warn",
|
||||
"no-lonely-if": "warn",
|
||||
"no-restricted-syntax": [
|
||||
"warn",
|
||||
{
|
||||
"message": "Use 't(...)' instead of literal text in JSX",
|
||||
"selector": "JSXText[value=/\\w/]"
|
||||
}
|
||||
],
|
||||
"no-unneeded-ternary": "warn",
|
||||
"no-unused-expressions": "warn",
|
||||
"no-useless-return": "warn",
|
||||
"no-var": "warn",
|
||||
"object-shorthand": "warn",
|
||||
"one-var": ["warn", "never"],
|
||||
"prefer-arrow-callback": "warn",
|
||||
"prefer-const": [
|
||||
"warn",
|
||||
{
|
||||
"destructuring": "all"
|
||||
}
|
||||
],
|
||||
"prefer-template": "warn",
|
||||
"prettier/prettier": "warn"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
<svg height="50" viewBox="0 0 257 50" xmlns="http://www.w3.org/2000/svg" fill-rule="evenodd" clip-rule="evenodd" stroke-linejoin="round" stroke-miterlimit="2">
|
||||
<path fill="#fff" d="M-7.977-9.253h288.95v78.13H-7.977z" />
|
||||
<path d="M67.626 32.315c-1.34 0-2.207 0-2.207-1.025 0-.236.079-.551.236-.946l4.02-8.907h12.929c1.34 0 2.128-.08 2.128.946 0 .315-.078.63-.236.946l-.788 1.734h5.439l1.104-2.444c.157-.394.157-.71.157-1.025 0-2.207-2.365-3.31-4.257-3.31H65.655l-5.754 12.691c-.158.394-.158.71-.158 1.025 0 2.365 1.97 3.547 4.73 3.547h20.26l1.26-3.232H67.627zm42.727-14.11H95.059l-6.937 17.342h5.518l5.519-14.032h8.435c1.34 0 2.05-.157 2.05.868 0 .315-.08.63-.237.946l-.789 1.734h5.518l1.104-2.444c.158-.394.158-.71.158-1.025 0-1.025-.552-1.892-1.734-2.522-.946-.473-2.208-.868-3.311-.868zm30.35 0h-21.285l-5.754 12.691c-.158.316-.158.63-.158 1.025 0 1.97 1.419 3.547 3.232 3.547h21.52l5.834-13.007c.158-.394.158-.71.158-1.024 0-2.05-1.734-3.233-3.547-3.233zm-6.701 14.19h-12.85c-1.34 0-1.97-.159-1.97-1.183 0-.316.079-.631.236-.946l4.178-8.908h12.929c1.26 0 1.891-.08 1.891.946 0 .315-.078.63-.236 1.025l-4.178 9.065zm13.953 3.152h28.695l7.41-17.264h-5.676l-6.149 14.032h-9.223l6.149-14.11h-5.676l-6.386 14.031h-6.306c-1.34 0-2.05-.157-2.05-1.182 0-.315.08-.63.237-.946l5.282-11.982h-5.519l-5.518 12.455c-1.103 3.39 2.207 4.966 4.73 4.966zm67.874-23.649l-5.913 1.577-1.97 4.73h-14.584c-3.548 0-6.7 1.576-8.278 4.73l-3.941 9.46c-.788 1.576.63 3.152 3.31 3.152h21.128l10.248-23.649zm-27.591 20.496c-1.183 0-1.735-.788-1.577-1.577l3.469-7.567c.788-1.813 2.68-1.892 4.414-1.892h11.825l-4.73 11.036h-13.401zm26.802 3.153l7.49-17.737-6.307 1.183-7.095 16.554h5.912zm8.435-19.944l1.656-3.705-6.228 1.261-1.577 3.705 6.15-1.26zm22.23 2.601h-20.417l-7.094 17.343h5.518l5.518-14.19h13.48c1.34 0 2.05-.078 2.05 1.026 0 .315-.08.63-.237.946l-5.518 12.297h5.518l5.834-13.007c.157-.315.157-.63.157-1.025 0-1.025-.552-1.892-1.734-2.522-.867-.473-1.892-.868-3.074-.868zm-192.82.868c-8.672-1.025-16.476.71-17.58 6.148 0 .237-.157 1.262-.157 1.42l1.419.157v2.207l-1.34-.157c.551 5.597 3.626 7.252 6.858 7.331h.236c1.42.079 2.917-.237 4.178-.788.08 0 .08-.08.08-.08v-.157c0-.079-.08-.079-.08-.157-.078 0-.078-.08-.157-.08-2.996.395-5.755-2.049-5.755-7.015 0-6.228 4.888-8.514 12.298-8.514.236.158.315-.237 0-.315zM36.803 30.344c.788 0 1.498.158 2.207.237.237 1.655 1.025 3.232 2.208 4.336-1.183-.158-2.208-.71-3.075-1.498a6.051 6.051 0 01-1.34-3.075zm2.68-5.439c0 .237-.157.552-.236.946h-1.025c-.552 0-1.025-.079-1.576-.158v-.157c.63-3.39 4.02-4.73 7.252-5.36a7.997 7.997 0 00-2.76 1.812c-.787.868-1.34 1.813-1.655 2.917z" fill="#2e3340" fill-rule="nonzero" />
|
||||
<path d="M56.274 14.105c-6.543-1.813-34.055-4.02-34.055 11.273.946.158 1.577.315 2.05.394-.079 1.183 0 2.444 0 3.626l-2.444-.394c0 8.83 6.464 11.667 11.588 11.667.868 0 1.656-.078 2.523-.157 2.128-.237 4.178-.867 5.991-1.892.079 0 .079-.08.079-.08v-.157c0-.079-.079-.079-.079-.157-.079 0-.079-.08-.157-.08-4.336.868-10.17-.315-10.17-10.563 0-13.637 19.156-12.77 24.753-13.007.08 0 .08-.079.08-.079v-.157c0-.08 0-.08-.08-.158 0-.079 0-.079-.079-.079zM33.414 39.41a9.362 9.362 0 01-6.78-2.286c-1.892-1.656-3.074-3.942-3.31-6.385 1.655.236 3.704.394 5.438.473a9.43 9.43 0 001.577 4.808c.946 1.42 2.207 2.602 3.705 3.39h-.63zM28.92 24.984l-2.601-.237-2.602-.315c0-7.962 12.77-11.036 18.683-10.484-5.912 1.34-13.086 4.099-13.48 11.036z" fill="#2e3340" fill-rule="nonzero" />
|
||||
<path d="M59.664 9.533c-7.962-2.68-17.027-4.02-25.462-3.941-12.22 0-27.67 3.626-28.064 16.081l3.31.788c-.393 1.577-.393 4.81-.393 4.81s-1.892-.553-2.917-.79c0 14.821 8.671 18.526 17.027 18.526 3.39 0 6.701-.552 9.854-1.734.08 0 .08-.08.08-.08v-.157c0-.079-.08-.079-.08-.157h-.157c-2.602 0-4.651.867-8.75-2.05-7.963-5.597-7.017-20.102 2.128-26.408 9.46-6.701 29.798-4.573 33.267-4.415h.157s.079 0 .079-.079v-.236l-.079-.158zm-36.42 34.292c-9.932 0-14.978-5.36-15.45-15.609 2.68.71 5.202 1.34 7.961 1.734-.157 4.02 1.262 7.962 4.02 11.037a12.488 12.488 0 005.046 2.916l-1.577-.078zM45.632 7.956c-12.06 0-26.014 1.42-28.773 14.584 0 0-7.41-1.182-9.066-1.576C9.843 4.409 38.38 5.67 49.89 7.956h-4.257z" fill="#2e3340" fill-rule="nonzero" />
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 4.1 KiB |
@@ -1,9 +0,0 @@
|
||||
<svg class="__sntry__ css-15xgryy e10nushx5" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 222 66" height="50" style="background-color: rgb(255, 255, 255);">
|
||||
<defs>
|
||||
<style type="text/css">
|
||||
@media (prefers-color-scheme: dark) {svg.__sntry__ { background-color: #584674 !important; }path.__sntry__ { fill: #ffffff !important; }}
|
||||
</style>
|
||||
</defs>
|
||||
<path d="M29,2.26a4.67,4.67,0,0,0-8,0L14.42,13.53A32.21,32.21,0,0,1,32.17,40.19H27.55A27.68,27.68,0,0,0,12.09,17.47L6,28a15.92,15.92,0,0,1,9.23,12.17H4.62A.76.76,0,0,1,4,39.06l2.94-5a10.74,10.74,0,0,0-3.36-1.9l-2.91,5a4.54,4.54,0,0,0,1.69,6.24A4.66,4.66,0,0,0,4.62,44H19.15a19.4,19.4,0,0,0-8-17.31l2.31-4A23.87,23.87,0,0,1,23.76,44H36.07a35.88,35.88,0,0,0-16.41-31.8l4.67-8a.77.77,0,0,1,1.05-.27c.53.29,20.29,34.77,20.66,35.17a.76.76,0,0,1-.68,1.13H40.6q.09,1.91,0,3.81h4.78A4.59,4.59,0,0,0,50,39.43a4.49,4.49,0,0,0-.62-2.28Z M124.32,28.28,109.56,9.22h-3.68V34.77h3.73V15.19l15.18,19.58h3.26V9.22h-3.73ZM87.15,23.54h13.23V20.22H87.14V12.53h14.93V9.21H83.34V34.77h18.92V31.45H87.14ZM71.59,20.3h0C66.44,19.06,65,18.08,65,15.7c0-2.14,1.89-3.59,4.71-3.59a12.06,12.06,0,0,1,7.07,2.55l2-2.83a14.1,14.1,0,0,0-9-3c-5.06,0-8.59,3-8.59,7.27,0,4.6,3,6.19,8.46,7.52C74.51,24.74,76,25.78,76,28.11s-2,3.77-5.09,3.77a12.34,12.34,0,0,1-8.3-3.26l-2.25,2.69a15.94,15.94,0,0,0,10.42,3.85c5.48,0,9-2.95,9-7.51C79.75,23.79,77.47,21.72,71.59,20.3ZM195.7,9.22l-7.69,12-7.64-12h-4.46L186,24.67V34.78h3.84V24.55L200,9.22Zm-64.63,3.46h8.37v22.1h3.84V12.68h8.37V9.22H131.08ZM169.41,24.8c3.86-1.07,6-3.77,6-7.63,0-4.91-3.59-8-9.38-8H154.67V34.76h3.8V25.58h6.45l6.48,9.2h4.44l-7-9.82Zm-10.95-2.5V12.6h7.17c3.74,0,5.88,1.77,5.88,4.84s-2.29,4.86-5.84,4.86Z" transform="translate(11, 11)" fill="#362d59" class="__sntry__">
|
||||
</path>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.7 KiB |
@@ -1,3 +0,0 @@
|
||||
<svg height="50" viewBox="0 0 164 50" xmlns="http://www.w3.org/2000/svg" style="background:#fff" fill-rule="evenodd" clip-rule="evenodd" stroke-linejoin="round" stroke-miterlimit="2">
|
||||
<path d="M78.21 15.587c-5.672 0-9.762 3.864-9.762 9.661s4.604 9.66 10.276 9.66c3.427 0 6.448-1.416 8.319-3.805l-3.931-2.372c-1.038 1.186-2.615 1.879-4.388 1.879-2.461 0-4.552-1.342-5.328-3.489h14.397c.113-.601.18-1.223.18-1.879 0-5.79-4.09-9.655-9.763-9.655zm-4.86 7.783c.642-2.142 2.399-3.489 4.855-3.489 2.461 0 4.219 1.347 4.855 3.489h-9.71zm60.187-7.783c-5.673 0-9.763 3.864-9.763 9.661s4.604 9.66 10.276 9.66c3.427 0 6.449-1.416 8.319-3.805l-3.931-2.372c-1.038 1.186-2.615 1.879-4.388 1.879-2.461 0-4.552-1.342-5.328-3.489h14.397c.113-.601.18-1.223.18-1.879 0-5.79-4.09-9.655-9.762-9.655zm-4.856 7.783c.642-2.142 2.4-3.489 4.856-3.489 2.46 0 4.218 1.347 4.855 3.489h-9.711zm-20.054 1.878c0 3.22 2.015 5.367 5.139 5.367 2.116 0 3.704-1.003 4.52-2.64l3.947 2.378c-1.634 2.843-4.696 4.556-8.467 4.556-5.678 0-9.763-3.864-9.763-9.661s4.09-9.66 9.763-9.66c3.77 0 6.828 1.712 8.467 4.556l-3.946 2.377c-.817-1.637-2.405-2.64-4.521-2.64-3.12 0-5.139 2.147-5.139 5.367zm42.378-15.565v24.69h-4.624V9.682h4.624zM24.73 7l18.985 34.35H5.744L24.73 7zm47.465 2.683L57.956 35.446 43.72 9.683h5.338l8.9 16.102 8.898-16.102h5.339zm30.268 6.44v5.202a5.634 5.634 0 00-1.644-.263c-2.985 0-5.138 2.147-5.138 5.367v7.943h-4.624V16.124h4.624v4.938c0-2.727 3.036-4.938 6.782-4.938z" fill-rule="nonzero" />
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.4 KiB |
@@ -33,7 +33,7 @@ jobs:
|
||||
- name: Construct comment body
|
||||
id: getCommentBody
|
||||
run: |
|
||||
body=$(npm run locales-coverage:description | grep '^[^>]')
|
||||
body=$(yarn locales-coverage:description | grep '^[^>]')
|
||||
body="${body//'%'/'%25'}"
|
||||
body="${body//$'\n'/'%0A'}"
|
||||
body="${body//$'\r'/'%0D'}"
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@
|
||||
### Option 1 - Manual
|
||||
|
||||
1. Fork and clone the repo
|
||||
1. Run `yarn` to install dependencies
|
||||
1. Run `npm install` to install dependencies
|
||||
1. Create a branch for your PR with `git checkout -b your-branch-name`
|
||||
|
||||
> To keep `master` branch pointing to remote repository and make pull requests from branches on your fork. To do this, run:
|
||||
|
||||
@@ -28,10 +28,6 @@ If you like the project, you can become a sponsor at [Open Collective](https://o
|
||||
|
||||
<a href="https://opencollective.com/excalidraw#category-CONTRIBUTE" target="_blank"><img src="https://opencollective.com/excalidraw/tiers/backers.svg?avatarHeight=32"/></a>
|
||||
|
||||
Last but not least, we're thankful to these companies for offering their services for free:
|
||||
|
||||
[](https://vercel.com) [](https://sentry.io) [](https://crowdin.com)
|
||||
|
||||
## Documentation
|
||||
|
||||
### Shortcuts
|
||||
|
||||
+9
-10
@@ -19,20 +19,20 @@
|
||||
]
|
||||
},
|
||||
"dependencies": {
|
||||
"@sentry/browser": "6.2.2",
|
||||
"@sentry/integrations": "6.2.1",
|
||||
"@sentry/browser": "6.2.0",
|
||||
"@sentry/integrations": "6.2.0",
|
||||
"@testing-library/jest-dom": "5.11.9",
|
||||
"@testing-library/react": "11.2.5",
|
||||
"@types/jest": "26.0.20",
|
||||
"@types/react": "17.0.2",
|
||||
"@types/react-dom": "17.0.1",
|
||||
"@types/socket.io-client": "1.4.36",
|
||||
"browser-fs-access": "0.14.2",
|
||||
"@types/socket.io-client": "1.4.35",
|
||||
"browser-fs-access": "0.14.0",
|
||||
"clsx": "1.1.1",
|
||||
"firebase": "8.2.10",
|
||||
"firebase": "8.2.9",
|
||||
"i18next-browser-languagedetector": "6.0.1",
|
||||
"lodash.throttle": "4.1.1",
|
||||
"nanoid": "3.1.21",
|
||||
"nanoid": "3.1.20",
|
||||
"open-color": "1.8.0",
|
||||
"pako": "1.0.11",
|
||||
"png-chunk-text": "1.0.0",
|
||||
@@ -46,17 +46,16 @@
|
||||
"roughjs": "4.3.1",
|
||||
"sass": "1.32.8",
|
||||
"socket.io-client": "2.3.1",
|
||||
"typescript": "4.2.3"
|
||||
"typescript": "4.1.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@excalidraw/eslint-config": "1.0.0",
|
||||
"@excalidraw/prettier-config": "1.0.2",
|
||||
"@types/lodash.throttle": "4.1.6",
|
||||
"@types/pako": "1.0.1",
|
||||
"@types/resize-observer-browser": "0.1.5",
|
||||
"eslint-config-prettier": "8.1.0",
|
||||
"eslint-plugin-prettier": "3.3.1",
|
||||
"firebase-tools": "9.6.1",
|
||||
"firebase-tools": "9.5.0",
|
||||
"husky": "4.3.8",
|
||||
"jest-canvas-mock": "2.3.1",
|
||||
"lint-staged": "10.5.4",
|
||||
@@ -98,7 +97,7 @@
|
||||
"start": "react-scripts start",
|
||||
"test:all": "yarn test:typecheck && yarn test:code && yarn test:other && yarn test:app --watchAll=false",
|
||||
"test:app": "react-scripts test --passWithNoTests",
|
||||
"test:code": "eslint --max-warnings=0 --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:other": "yarn prettier --list-different",
|
||||
"test:typecheck": "tsc",
|
||||
|
||||
Binary file not shown.
Binary file not shown.
+2
-1
@@ -112,7 +112,8 @@
|
||||
Roboto, Helvetica, Arial, sans-serif;
|
||||
font-family: var(--ui-font);
|
||||
-webkit-text-size-adjust: 100%;
|
||||
|
||||
-webkit-user-select: none;
|
||||
user-select: none;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
}
|
||||
|
||||
+1
-14
@@ -26,18 +26,5 @@
|
||||
}
|
||||
}
|
||||
],
|
||||
"capture_links": "new_client",
|
||||
"share_target": {
|
||||
"action": "/web-share-target",
|
||||
"method": "POST",
|
||||
"enctype": "multipart/form-data",
|
||||
"params": {
|
||||
"files": [
|
||||
{
|
||||
"name": "file",
|
||||
"accept": ["application/vnd.excalidraw+json", "application/json", ".excalidraw"]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
"capture_links": "new_client"
|
||||
}
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
this.workbox=this.workbox||{},this.workbox.backgroundSync=function(t,e,s){"use strict";try{self["workbox:background-sync:4.3.1"]&&_()}catch(t){}const i=3,n="workbox-background-sync",a="requests",r="queueName";class c{constructor(t){this.t=t,this.s=new s.DBWrapper(n,i,{onupgradeneeded:this.i})}async pushEntry(t){delete t.id,t.queueName=this.t,await this.s.add(a,t)}async unshiftEntry(t){const[e]=await this.s.getAllMatching(a,{count:1});e?t.id=e.id-1:delete t.id,t.queueName=this.t,await this.s.add(a,t)}async popEntry(){return this.h({direction:"prev"})}async shiftEntry(){return this.h({direction:"next"})}async getAll(){return await this.s.getAllMatching(a,{index:r,query:IDBKeyRange.only(this.t)})}async deleteEntry(t){await this.s.delete(a,t)}async h({direction:t}){const[e]=await this.s.getAllMatching(a,{direction:t,index:r,query:IDBKeyRange.only(this.t),count:1});if(e)return await this.deleteEntry(e.id),e}i(t){const e=t.target.result;t.oldVersion>0&&t.oldVersion<i&&e.objectStoreNames.contains(a)&&e.deleteObjectStore(a),e.createObjectStore(a,{autoIncrement:!0,keyPath:"id"}).createIndex(r,r,{unique:!1})}}const h=["method","referrer","referrerPolicy","mode","credentials","cache","redirect","integrity","keepalive"];class o{static async fromRequest(t){const e={url:t.url,headers:{}};"GET"!==t.method&&(e.body=await t.clone().arrayBuffer());for(const[s,i]of t.headers.entries())e.headers[s]=i;for(const s of h)void 0!==t[s]&&(e[s]=t[s]);return new o(e)}constructor(t){"navigate"===t.mode&&(t.mode="same-origin"),this.o=t}toObject(){const t=Object.assign({},this.o);return t.headers=Object.assign({},this.o.headers),t.body&&(t.body=t.body.slice(0)),t}toRequest(){return new Request(this.o.url,this.o)}clone(){return new o(this.toObject())}}const u="workbox-background-sync",y=10080,w=new Set;class d{constructor(t,{onSync:s,maxRetentionTime:i}={}){if(w.has(t))throw new e.WorkboxError("duplicate-queue-name",{name:t});w.add(t),this.u=t,this.l=s||this.replayRequests,this.q=i||y,this.m=new c(this.u),this.p()}get name(){return this.u}async pushRequest(t){await this.g(t,"push")}async unshiftRequest(t){await this.g(t,"unshift")}async popRequest(){return this.R("pop")}async shiftRequest(){return this.R("shift")}async getAll(){const t=await this.m.getAll(),e=Date.now(),s=[];for(const i of t){const t=60*this.q*1e3;e-i.timestamp>t?await this.m.deleteEntry(i.id):s.push(f(i))}return s}async g({request:t,metadata:e,timestamp:s=Date.now()},i){const n={requestData:(await o.fromRequest(t.clone())).toObject(),timestamp:s};e&&(n.metadata=e),await this.m[`${i}Entry`](n),this.k?this.D=!0:await this.registerSync()}async R(t){const e=Date.now(),s=await this.m[`${t}Entry`]();if(s){const i=60*this.q*1e3;return e-s.timestamp>i?this.R(t):f(s)}}async replayRequests(){let t;for(;t=await this.shiftRequest();)try{await fetch(t.request.clone())}catch(s){throw await this.unshiftRequest(t),new e.WorkboxError("queue-replay-failed",{name:this.u})}}async registerSync(){if("sync"in registration)try{await registration.sync.register(`${u}:${this.u}`)}catch(t){}}p(){"sync"in registration?self.addEventListener("sync",t=>{if(t.tag===`${u}:${this.u}`){const e=async()=>{let e;this.k=!0;try{await this.l({queue:this})}catch(t){throw e=t}finally{!this.D||e&&!t.lastChance||await this.registerSync(),this.k=!1,this.D=!1}};t.waitUntil(e())}}):this.l({queue:this})}static get _(){return w}}const f=t=>{const e={request:new o(t.requestData).toRequest(),timestamp:t.timestamp};return t.metadata&&(e.metadata=t.metadata),e};return t.Queue=d,t.Plugin=class{constructor(...t){this.v=new d(...t),this.fetchDidFail=this.fetchDidFail.bind(this)}async fetchDidFail({request:t}){await this.v.pushRequest({request:t})}},t}({},workbox.core._private,workbox.core._private);
|
||||
//# sourceMappingURL=workbox-background-sync.prod.js.map
|
||||
@@ -1,2 +0,0 @@
|
||||
this.workbox=this.workbox||{},this.workbox.broadcastUpdate=function(e,t){"use strict";try{self["workbox:broadcast-update:4.3.1"]&&_()}catch(e){}const s=(e,t,s)=>{return!s.some(s=>e.headers.has(s)&&t.headers.has(s))||s.every(s=>{const n=e.headers.has(s)===t.headers.has(s),a=e.headers.get(s)===t.headers.get(s);return n&&a})},n="workbox",a=1e4,i=["content-length","etag","last-modified"],o=async({channel:e,cacheName:t,url:s})=>{const n={type:"CACHE_UPDATED",meta:"workbox-broadcast-update",payload:{cacheName:t,updatedURL:s}};if(e)e.postMessage(n);else{const e=await clients.matchAll({type:"window"});for(const t of e)t.postMessage(n)}};class c{constructor({headersToCheck:e,channelName:t,deferNoticationTimeout:s}={}){this.t=e||i,this.s=t||n,this.i=s||a,this.o()}notifyIfUpdated({oldResponse:e,newResponse:t,url:n,cacheName:a,event:i}){if(!s(e,t,this.t)){const e=(async()=>{i&&i.request&&"navigate"===i.request.mode&&await this.h(i),await this.l({channel:this.u(),cacheName:a,url:n})})();if(i)try{i.waitUntil(e)}catch(e){}return e}}async l(e){await o(e)}u(){return"BroadcastChannel"in self&&!this.p&&(this.p=new BroadcastChannel(this.s)),this.p}h(e){if(!this.m.has(e)){const s=new t.Deferred;this.m.set(e,s);const n=setTimeout(()=>{s.resolve()},this.i);s.promise.then(()=>clearTimeout(n))}return this.m.get(e).promise}o(){this.m=new Map,self.addEventListener("message",e=>{if("WINDOW_READY"===e.data.type&&"workbox-window"===e.data.meta&&this.m.size>0){for(const e of this.m.values())e.resolve();this.m.clear()}})}}return e.BroadcastCacheUpdate=c,e.Plugin=class{constructor(e){this.l=new c(e)}cacheDidUpdate({cacheName:e,oldResponse:t,newResponse:s,request:n,event:a}){t&&this.l.notifyIfUpdated({cacheName:e,oldResponse:t,newResponse:s,event:a,url:n.url})}},e.broadcastUpdate=o,e.responsesAreSame=s,e}({},workbox.core._private);
|
||||
//# sourceMappingURL=workbox-broadcast-update.prod.js.map
|
||||
@@ -1,2 +0,0 @@
|
||||
this.workbox=this.workbox||{},this.workbox.cacheableResponse=function(t){"use strict";try{self["workbox:cacheable-response:4.3.1"]&&_()}catch(t){}class s{constructor(t={}){this.t=t.statuses,this.s=t.headers}isResponseCacheable(t){let s=!0;return this.t&&(s=this.t.includes(t.status)),this.s&&s&&(s=Object.keys(this.s).some(s=>t.headers.get(s)===this.s[s])),s}}return t.CacheableResponse=s,t.Plugin=class{constructor(t){this.i=new s(t)}cacheWillUpdate({response:t}){return this.i.isResponseCacheable(t)?t:null}},t}({});
|
||||
//# sourceMappingURL=workbox-cacheable-response.prod.js.map
|
||||
File diff suppressed because one or more lines are too long
@@ -1,2 +0,0 @@
|
||||
this.workbox=this.workbox||{},this.workbox.expiration=function(t,e,s,i,a,n){"use strict";try{self["workbox:expiration:4.3.1"]&&_()}catch(t){}const h="workbox-expiration",c="cache-entries",r=t=>{const e=new URL(t,location);return e.hash="",e.href};class o{constructor(t){this.t=t,this.s=new e.DBWrapper(h,1,{onupgradeneeded:t=>this.i(t)})}i(t){const e=t.target.result.createObjectStore(c,{keyPath:"id"});e.createIndex("cacheName","cacheName",{unique:!1}),e.createIndex("timestamp","timestamp",{unique:!1}),s.deleteDatabase(this.t)}async setTimestamp(t,e){t=r(t),await this.s.put(c,{url:t,timestamp:e,cacheName:this.t,id:this.h(t)})}async getTimestamp(t){return(await this.s.get(c,this.h(t))).timestamp}async expireEntries(t,e){const s=await this.s.transaction(c,"readwrite",(s,i)=>{const a=s.objectStore(c),n=[];let h=0;a.index("timestamp").openCursor(null,"prev").onsuccess=(({target:s})=>{const a=s.result;if(a){const s=a.value;s.cacheName===this.t&&(t&&s.timestamp<t||e&&h>=e?n.push(a.value):h++),a.continue()}else i(n)})}),i=[];for(const t of s)await this.s.delete(c,t.id),i.push(t.url);return i}h(t){return this.t+"|"+r(t)}}class u{constructor(t,e={}){this.o=!1,this.u=!1,this.l=e.maxEntries,this.p=e.maxAgeSeconds,this.t=t,this.m=new o(t)}async expireEntries(){if(this.o)return void(this.u=!0);this.o=!0;const t=this.p?Date.now()-1e3*this.p:void 0,e=await this.m.expireEntries(t,this.l),s=await caches.open(this.t);for(const t of e)await s.delete(t);this.o=!1,this.u&&(this.u=!1,this.expireEntries())}async updateTimestamp(t){await this.m.setTimestamp(t,Date.now())}async isURLExpired(t){return await this.m.getTimestamp(t)<Date.now()-1e3*this.p}async delete(){this.u=!1,await this.m.expireEntries(1/0)}}return t.CacheExpiration=u,t.Plugin=class{constructor(t={}){this.D=t,this.p=t.maxAgeSeconds,this.g=new Map,t.purgeOnQuotaError&&n.registerQuotaErrorCallback(()=>this.deleteCacheAndMetadata())}k(t){if(t===a.cacheNames.getRuntimeName())throw new i.WorkboxError("expire-custom-caches-only");let e=this.g.get(t);return e||(e=new u(t,this.D),this.g.set(t,e)),e}cachedResponseWillBeUsed({event:t,request:e,cacheName:s,cachedResponse:i}){if(!i)return null;let a=this.N(i);const n=this.k(s);n.expireEntries();const h=n.updateTimestamp(e.url);if(t)try{t.waitUntil(h)}catch(t){}return a?i:null}N(t){if(!this.p)return!0;const e=this._(t);return null===e||e>=Date.now()-1e3*this.p}_(t){if(!t.headers.has("date"))return null;const e=t.headers.get("date"),s=new Date(e).getTime();return isNaN(s)?null:s}async cacheDidUpdate({cacheName:t,request:e}){const s=this.k(t);await s.updateTimestamp(e.url),await s.expireEntries()}async deleteCacheAndMetadata(){for(const[t,e]of this.g)await caches.delete(t),await e.delete();this.g=new Map}},t}({},workbox.core._private,workbox.core._private,workbox.core._private,workbox.core._private,workbox.core);
|
||||
//# sourceMappingURL=workbox-expiration.prod.js.map
|
||||
@@ -1,2 +0,0 @@
|
||||
this.workbox=this.workbox||{},this.workbox.navigationPreload=function(t){"use strict";try{self["workbox:navigation-preload:4.3.1"]&&_()}catch(t){}function e(){return Boolean(self.registration&&self.registration.navigationPreload)}return t.disable=function(){e()&&self.addEventListener("activate",t=>{t.waitUntil(self.registration.navigationPreload.disable().then(()=>{}))})},t.enable=function(t){e()&&self.addEventListener("activate",e=>{e.waitUntil(self.registration.navigationPreload.enable().then(()=>{t&&self.registration.navigationPreload.setHeaderValue(t)}))})},t.isSupported=e,t}({});
|
||||
//# sourceMappingURL=workbox-navigation-preload.prod.js.map
|
||||
@@ -1,2 +0,0 @@
|
||||
this.workbox=this.workbox||{},this.workbox.googleAnalytics=function(e,t,o,n,a,c,w){"use strict";try{self["workbox:google-analytics:4.3.1"]&&_()}catch(e){}const r=/^\/(\w+\/)?collect/,s=e=>async({queue:t})=>{let o;for(;o=await t.shiftRequest();){const{request:n,timestamp:a}=o,c=new URL(n.url);try{const w="POST"===n.method?new URLSearchParams(await n.clone().text()):c.searchParams,r=a-(Number(w.get("qt"))||0),s=Date.now()-r;if(w.set("qt",s),e.parameterOverrides)for(const t of Object.keys(e.parameterOverrides)){const o=e.parameterOverrides[t];w.set(t,o)}"function"==typeof e.hitFilter&&e.hitFilter.call(null,w),await fetch(new Request(c.origin+c.pathname,{body:w.toString(),method:"POST",mode:"cors",credentials:"omit",headers:{"Content-Type":"text/plain"}}))}catch(e){throw await t.unshiftRequest(o),e}}},i=e=>{const t=({url:e})=>"www.google-analytics.com"===e.hostname&&r.test(e.pathname),o=new w.NetworkOnly({plugins:[e]});return[new n.Route(t,o,"GET"),new n.Route(t,o,"POST")]},l=e=>{const t=new c.NetworkFirst({cacheName:e});return new n.Route(({url:e})=>"www.google-analytics.com"===e.hostname&&"/analytics.js"===e.pathname,t,"GET")},m=e=>{const t=new c.NetworkFirst({cacheName:e});return new n.Route(({url:e})=>"www.googletagmanager.com"===e.hostname&&"/gtag/js"===e.pathname,t,"GET")},u=e=>{const t=new c.NetworkFirst({cacheName:e});return new n.Route(({url:e})=>"www.googletagmanager.com"===e.hostname&&"/gtm.js"===e.pathname,t,"GET")};return e.initialize=((e={})=>{const n=o.cacheNames.getGoogleAnalyticsName(e.cacheName),c=new t.Plugin("workbox-google-analytics",{maxRetentionTime:2880,onSync:s(e)}),w=[u(n),l(n),m(n),...i(c)],r=new a.Router;for(const e of w)r.registerRoute(e);r.addFetchListener()}),e}({},workbox.backgroundSync,workbox.core._private,workbox.routing,workbox.routing,workbox.strategies,workbox.strategies);
|
||||
//# sourceMappingURL=workbox-offline-ga.prod.js.map
|
||||
@@ -1,2 +0,0 @@
|
||||
this.workbox=this.workbox||{},this.workbox.precaching=function(t,e,n,s,c){"use strict";try{self["workbox:precaching:4.3.1"]&&_()}catch(t){}const o=[],i={get:()=>o,add(t){o.push(...t)}};const a="__WB_REVISION__";function r(t){if(!t)throw new c.WorkboxError("add-to-cache-list-unexpected-type",{entry:t});if("string"==typeof t){const e=new URL(t,location);return{cacheKey:e.href,url:e.href}}const{revision:e,url:n}=t;if(!n)throw new c.WorkboxError("add-to-cache-list-unexpected-type",{entry:t});if(!e){const t=new URL(n,location);return{cacheKey:t.href,url:t.href}}const s=new URL(n,location),o=new URL(n,location);return o.searchParams.set(a,e),{cacheKey:o.href,url:s.href}}class l{constructor(t){this.t=e.cacheNames.getPrecacheName(t),this.s=new Map}addToCacheList(t){for(const e of t){const{cacheKey:t,url:n}=r(e);if(this.s.has(n)&&this.s.get(n)!==t)throw new c.WorkboxError("add-to-cache-list-conflicting-entries",{firstEntry:this.s.get(n),secondEntry:t});this.s.set(n,t)}}async install({event:t,plugins:e}={}){const n=[],s=[],c=await caches.open(this.t),o=await c.keys(),i=new Set(o.map(t=>t.url));for(const t of this.s.values())i.has(t)?s.push(t):n.push(t);const a=n.map(n=>this.o({event:t,plugins:e,url:n}));return await Promise.all(a),{updatedURLs:n,notUpdatedURLs:s}}async activate(){const t=await caches.open(this.t),e=await t.keys(),n=new Set(this.s.values()),s=[];for(const c of e)n.has(c.url)||(await t.delete(c),s.push(c.url));return{deletedURLs:s}}async o({url:t,event:e,plugins:o}){const i=new Request(t,{credentials:"same-origin"});let a,r=await s.fetchWrapper.fetch({event:e,plugins:o,request:i});for(const t of o||[])"cacheWillUpdate"in t&&(a=t.cacheWillUpdate.bind(t));if(!(a?a({event:e,request:i,response:r}):r.status<400))throw new c.WorkboxError("bad-precaching-response",{url:t,status:r.status});r.redirected&&(r=await async function(t){const e=t.clone(),n="body"in e?Promise.resolve(e.body):e.blob(),s=await n;return new Response(s,{headers:e.headers,status:e.status,statusText:e.statusText})}(r)),await n.cacheWrapper.put({event:e,plugins:o,request:i,response:r,cacheName:this.t,matchOptions:{ignoreSearch:!0}})}getURLsToCacheKeys(){return this.s}getCachedURLs(){return[...this.s.keys()]}getCacheKeyForURL(t){const e=new URL(t,location);return this.s.get(e.href)}}let u;const h=()=>(u||(u=new l),u);const d=(t,e)=>{const n=h().getURLsToCacheKeys();for(const s of function*(t,{ignoreURLParametersMatching:e,directoryIndex:n,cleanURLs:s,urlManipulation:c}={}){const o=new URL(t,location);o.hash="",yield o.href;const i=function(t,e){for(const n of[...t.searchParams.keys()])e.some(t=>t.test(n))&&t.searchParams.delete(n);return t}(o,e);if(yield i.href,n&&i.pathname.endsWith("/")){const t=new URL(i);t.pathname+=n,yield t.href}if(s){const t=new URL(i);t.pathname+=".html",yield t.href}if(c){const t=c({url:o});for(const e of t)yield e.href}}(t,e)){const t=n.get(s);if(t)return t}};let w=!1;const f=t=>{w||((({ignoreURLParametersMatching:t=[/^utm_/],directoryIndex:n="index.html",cleanURLs:s=!0,urlManipulation:c=null}={})=>{const o=e.cacheNames.getPrecacheName();addEventListener("fetch",e=>{const i=d(e.request.url,{cleanURLs:s,directoryIndex:n,ignoreURLParametersMatching:t,urlManipulation:c});if(!i)return;let a=caches.open(o).then(t=>t.match(i)).then(t=>t||fetch(i));e.respondWith(a)})})(t),w=!0)},y=t=>{const e=h(),n=i.get();t.waitUntil(e.install({event:t,plugins:n}).catch(t=>{throw t}))},p=t=>{const e=h(),n=i.get();t.waitUntil(e.activate({event:t,plugins:n}))},L=t=>{h().addToCacheList(t),t.length>0&&(addEventListener("install",y),addEventListener("activate",p))};return t.addPlugins=(t=>{i.add(t)}),t.addRoute=f,t.cleanupOutdatedCaches=(()=>{addEventListener("activate",t=>{const n=e.cacheNames.getPrecacheName();t.waitUntil((async(t,e="-precache-")=>{const n=(await caches.keys()).filter(n=>n.includes(e)&&n.includes(self.registration.scope)&&n!==t);return await Promise.all(n.map(t=>caches.delete(t))),n})(n).then(t=>{}))})}),t.getCacheKeyForURL=(t=>{return h().getCacheKeyForURL(t)}),t.precache=L,t.precacheAndRoute=((t,e)=>{L(t),f(e)}),t.PrecacheController=l,t}({},workbox.core._private,workbox.core._private,workbox.core._private,workbox.core._private);
|
||||
//# sourceMappingURL=workbox-precaching.prod.js.map
|
||||
@@ -1,2 +0,0 @@
|
||||
this.workbox=this.workbox||{},this.workbox.rangeRequests=function(e,n){"use strict";try{self["workbox:range-requests:4.3.1"]&&_()}catch(e){}async function t(e,t){try{if(206===t.status)return t;const s=e.headers.get("range");if(!s)throw new n.WorkboxError("no-range-header");const a=function(e){const t=e.trim().toLowerCase();if(!t.startsWith("bytes="))throw new n.WorkboxError("unit-must-be-bytes",{normalizedRangeHeader:t});if(t.includes(","))throw new n.WorkboxError("single-range-only",{normalizedRangeHeader:t});const s=/(\d*)-(\d*)/.exec(t);if(null===s||!s[1]&&!s[2])throw new n.WorkboxError("invalid-range-values",{normalizedRangeHeader:t});return{start:""===s[1]?null:Number(s[1]),end:""===s[2]?null:Number(s[2])}}(s),r=await t.blob(),i=function(e,t,s){const a=e.size;if(s>a||t<0)throw new n.WorkboxError("range-not-satisfiable",{size:a,end:s,start:t});let r,i;return null===t?(r=a-s,i=a):null===s?(r=t,i=a):(r=t,i=s+1),{start:r,end:i}}(r,a.start,a.end),o=r.slice(i.start,i.end),u=o.size,l=new Response(o,{status:206,statusText:"Partial Content",headers:t.headers});return l.headers.set("Content-Length",u),l.headers.set("Content-Range",`bytes ${i.start}-${i.end-1}/`+r.size),l}catch(e){return new Response("",{status:416,statusText:"Range Not Satisfiable"})}}return e.createPartialResponse=t,e.Plugin=class{async cachedResponseWillBeUsed({request:e,cachedResponse:n}){return n&&e.headers.has("range")?await t(e,n):n}},e}({},workbox.core._private);
|
||||
//# sourceMappingURL=workbox-range-requests.prod.js.map
|
||||
@@ -1,2 +0,0 @@
|
||||
this.workbox=this.workbox||{},this.workbox.routing=function(t,e,r){"use strict";try{self["workbox:routing:4.3.1"]&&_()}catch(t){}const s="GET",n=t=>t&&"object"==typeof t?t:{handle:t};class o{constructor(t,e,r){this.handler=n(e),this.match=t,this.method=r||s}}class i extends o{constructor(t,{whitelist:e=[/./],blacklist:r=[]}={}){super(t=>this.t(t),t),this.s=e,this.o=r}t({url:t,request:e}){if("navigate"!==e.mode)return!1;const r=t.pathname+t.search;for(const t of this.o)if(t.test(r))return!1;return!!this.s.some(t=>t.test(r))}}class u extends o{constructor(t,e,r){super(({url:e})=>{const r=t.exec(e.href);return r?e.origin!==location.origin&&0!==r.index?null:r.slice(1):null},e,r)}}class c{constructor(){this.i=new Map}get routes(){return this.i}addFetchListener(){self.addEventListener("fetch",t=>{const{request:e}=t,r=this.handleRequest({request:e,event:t});r&&t.respondWith(r)})}addCacheListener(){self.addEventListener("message",async t=>{if(t.data&&"CACHE_URLS"===t.data.type){const{payload:e}=t.data,r=Promise.all(e.urlsToCache.map(t=>{"string"==typeof t&&(t=[t]);const e=new Request(...t);return this.handleRequest({request:e})}));t.waitUntil(r),t.ports&&t.ports[0]&&(await r,t.ports[0].postMessage(!0))}})}handleRequest({request:t,event:e}){const r=new URL(t.url,location);if(!r.protocol.startsWith("http"))return;let s,{params:n,route:o}=this.findMatchingRoute({url:r,request:t,event:e}),i=o&&o.handler;if(!i&&this.u&&(i=this.u),i){try{s=i.handle({url:r,request:t,event:e,params:n})}catch(t){s=Promise.reject(t)}return s&&this.h&&(s=s.catch(t=>this.h.handle({url:r,event:e,err:t}))),s}}findMatchingRoute({url:t,request:e,event:r}){const s=this.i.get(e.method)||[];for(const n of s){let s,o=n.match({url:t,request:e,event:r});if(o)return Array.isArray(o)&&o.length>0?s=o:o.constructor===Object&&Object.keys(o).length>0&&(s=o),{route:n,params:s}}return{}}setDefaultHandler(t){this.u=n(t)}setCatchHandler(t){this.h=n(t)}registerRoute(t){this.i.has(t.method)||this.i.set(t.method,[]),this.i.get(t.method).push(t)}unregisterRoute(t){if(!this.i.has(t.method))throw new r.WorkboxError("unregister-route-but-not-found-with-method",{method:t.method});const e=this.i.get(t.method).indexOf(t);if(!(e>-1))throw new r.WorkboxError("unregister-route-route-not-registered");this.i.get(t.method).splice(e,1)}}let a;const h=()=>(a||((a=new c).addFetchListener(),a.addCacheListener()),a);return t.NavigationRoute=i,t.RegExpRoute=u,t.registerNavigationRoute=((t,r={})=>{const s=e.cacheNames.getPrecacheName(r.cacheName),n=new i(async()=>{try{const e=await caches.match(t,{cacheName:s});if(e)return e;throw new Error(`The cache ${s} did not have an entry for `+`${t}.`)}catch(e){return fetch(t)}},{whitelist:r.whitelist,blacklist:r.blacklist});return h().registerRoute(n),n}),t.registerRoute=((t,e,s="GET")=>{let n;if("string"==typeof t){const r=new URL(t,location);n=new o(({url:t})=>t.href===r.href,e,s)}else if(t instanceof RegExp)n=new u(t,e,s);else if("function"==typeof t)n=new o(t,e,s);else{if(!(t instanceof o))throw new r.WorkboxError("unsupported-route-type",{moduleName:"workbox-routing",funcName:"registerRoute",paramName:"capture"});n=t}return h().registerRoute(n),n}),t.Route=o,t.Router=c,t.setCatchHandler=(t=>{h().setCatchHandler(t)}),t.setDefaultHandler=(t=>{h().setDefaultHandler(t)}),t}({},workbox.core._private,workbox.core._private);
|
||||
//# sourceMappingURL=workbox-routing.prod.js.map
|
||||
@@ -1,2 +0,0 @@
|
||||
this.workbox=this.workbox||{},this.workbox.strategies=function(e,t,s,n,r){"use strict";try{self["workbox:strategies:4.3.1"]&&_()}catch(e){}class i{constructor(e={}){this.t=t.cacheNames.getRuntimeName(e.cacheName),this.s=e.plugins||[],this.i=e.fetchOptions||null,this.h=e.matchOptions||null}async handle({event:e,request:t}){return this.makeRequest({event:e,request:t||e.request})}async makeRequest({event:e,request:t}){"string"==typeof t&&(t=new Request(t));let n,i=await s.cacheWrapper.match({cacheName:this.t,request:t,event:e,matchOptions:this.h,plugins:this.s});if(!i)try{i=await this.u(t,e)}catch(e){n=e}if(!i)throw new r.WorkboxError("no-response",{url:t.url,error:n});return i}async u(e,t){const r=await n.fetchWrapper.fetch({request:e,event:t,fetchOptions:this.i,plugins:this.s}),i=r.clone(),h=s.cacheWrapper.put({cacheName:this.t,request:e,response:i,event:t,plugins:this.s});if(t)try{t.waitUntil(h)}catch(e){}return r}}class h{constructor(e={}){this.t=t.cacheNames.getRuntimeName(e.cacheName),this.s=e.plugins||[],this.h=e.matchOptions||null}async handle({event:e,request:t}){return this.makeRequest({event:e,request:t||e.request})}async makeRequest({event:e,request:t}){"string"==typeof t&&(t=new Request(t));const n=await s.cacheWrapper.match({cacheName:this.t,request:t,event:e,matchOptions:this.h,plugins:this.s});if(!n)throw new r.WorkboxError("no-response",{url:t.url});return n}}const u={cacheWillUpdate:({response:e})=>200===e.status||0===e.status?e:null};class a{constructor(e={}){if(this.t=t.cacheNames.getRuntimeName(e.cacheName),e.plugins){let t=e.plugins.some(e=>!!e.cacheWillUpdate);this.s=t?e.plugins:[u,...e.plugins]}else this.s=[u];this.o=e.networkTimeoutSeconds,this.i=e.fetchOptions||null,this.h=e.matchOptions||null}async handle({event:e,request:t}){return this.makeRequest({event:e,request:t||e.request})}async makeRequest({event:e,request:t}){const s=[];"string"==typeof t&&(t=new Request(t));const n=[];let i;if(this.o){const{id:r,promise:h}=this.l({request:t,event:e,logs:s});i=r,n.push(h)}const h=this.q({timeoutId:i,request:t,event:e,logs:s});n.push(h);let u=await Promise.race(n);if(u||(u=await h),!u)throw new r.WorkboxError("no-response",{url:t.url});return u}l({request:e,logs:t,event:s}){let n;return{promise:new Promise(t=>{n=setTimeout(async()=>{t(await this.p({request:e,event:s}))},1e3*this.o)}),id:n}}async q({timeoutId:e,request:t,logs:r,event:i}){let h,u;try{u=await n.fetchWrapper.fetch({request:t,event:i,fetchOptions:this.i,plugins:this.s})}catch(e){h=e}if(e&&clearTimeout(e),h||!u)u=await this.p({request:t,event:i});else{const e=u.clone(),n=s.cacheWrapper.put({cacheName:this.t,request:t,response:e,event:i,plugins:this.s});if(i)try{i.waitUntil(n)}catch(e){}}return u}p({event:e,request:t}){return s.cacheWrapper.match({cacheName:this.t,request:t,event:e,matchOptions:this.h,plugins:this.s})}}class c{constructor(e={}){this.t=t.cacheNames.getRuntimeName(e.cacheName),this.s=e.plugins||[],this.i=e.fetchOptions||null}async handle({event:e,request:t}){return this.makeRequest({event:e,request:t||e.request})}async makeRequest({event:e,request:t}){let s,i;"string"==typeof t&&(t=new Request(t));try{i=await n.fetchWrapper.fetch({request:t,event:e,fetchOptions:this.i,plugins:this.s})}catch(e){s=e}if(!i)throw new r.WorkboxError("no-response",{url:t.url,error:s});return i}}class o{constructor(e={}){if(this.t=t.cacheNames.getRuntimeName(e.cacheName),this.s=e.plugins||[],e.plugins){let t=e.plugins.some(e=>!!e.cacheWillUpdate);this.s=t?e.plugins:[u,...e.plugins]}else this.s=[u];this.i=e.fetchOptions||null,this.h=e.matchOptions||null}async handle({event:e,request:t}){return this.makeRequest({event:e,request:t||e.request})}async makeRequest({event:e,request:t}){"string"==typeof t&&(t=new Request(t));const n=this.u({request:t,event:e});let i,h=await s.cacheWrapper.match({cacheName:this.t,request:t,event:e,matchOptions:this.h,plugins:this.s});if(h){if(e)try{e.waitUntil(n)}catch(i){}}else try{h=await n}catch(e){i=e}if(!h)throw new r.WorkboxError("no-response",{url:t.url,error:i});return h}async u({request:e,event:t}){const r=await n.fetchWrapper.fetch({request:e,event:t,fetchOptions:this.i,plugins:this.s}),i=s.cacheWrapper.put({cacheName:this.t,request:e,response:r.clone(),event:t,plugins:this.s});if(t)try{t.waitUntil(i)}catch(e){}return r}}const l={cacheFirst:i,cacheOnly:h,networkFirst:a,networkOnly:c,staleWhileRevalidate:o},q=e=>{const t=l[e];return e=>new t(e)},w=q("cacheFirst"),p=q("cacheOnly"),v=q("networkFirst"),y=q("networkOnly"),m=q("staleWhileRevalidate");return e.CacheFirst=i,e.CacheOnly=h,e.NetworkFirst=a,e.NetworkOnly=c,e.StaleWhileRevalidate=o,e.cacheFirst=w,e.cacheOnly=p,e.networkFirst=v,e.networkOnly=y,e.staleWhileRevalidate=m,e}({},workbox.core._private,workbox.core._private,workbox.core._private,workbox.core._private);
|
||||
//# sourceMappingURL=workbox-strategies.prod.js.map
|
||||
@@ -1,2 +0,0 @@
|
||||
this.workbox=this.workbox||{},this.workbox.streams=function(e){"use strict";try{self["workbox:streams:4.3.1"]&&_()}catch(e){}function n(e){const n=e.map(e=>Promise.resolve(e).then(e=>(function(e){return e.body&&e.body.getReader?e.body.getReader():e.getReader?e.getReader():new Response(e).body.getReader()})(e)));let t,r;const s=new Promise((e,n)=>{t=e,r=n});let o=0;return{done:s,stream:new ReadableStream({pull(e){return n[o].then(e=>e.read()).then(r=>{if(r.done)return++o>=n.length?(e.close(),void t()):this.pull(e);e.enqueue(r.value)}).catch(e=>{throw r(e),e})},cancel(){t()}})}}function t(e={}){const n=new Headers(e);return n.has("content-type")||n.set("content-type","text/html"),n}function r(e,r){const{done:s,stream:o}=n(e),a=t(r);return{done:s,response:new Response(o,{headers:a})}}let s=void 0;function o(){if(void 0===s)try{new ReadableStream({start(){}}),s=!0}catch(e){s=!1}return s}return e.concatenate=n,e.concatenateToResponse=r,e.isSupported=o,e.strategy=function(e,n){return async({event:s,url:a,params:c})=>{if(o()){const{done:t,response:o}=r(e.map(e=>e({event:s,url:a,params:c})),n);return s.waitUntil(t),o}const i=await Promise.all(e.map(e=>e({event:s,url:a,params:c})).map(async e=>{const n=await e;return n instanceof Response?n.blob():n})),u=t(n);return new Response(new Blob(i),{headers:u})}},e}({});
|
||||
//# sourceMappingURL=workbox-streams.prod.js.map
|
||||
@@ -1,2 +0,0 @@
|
||||
!function(){"use strict";try{self["workbox:sw:4.3.1"]&&_()}catch(t){}const t="https://storage.googleapis.com/workbox-cdn/releases/4.3.1",e={backgroundSync:"background-sync",broadcastUpdate:"broadcast-update",cacheableResponse:"cacheable-response",core:"core",expiration:"expiration",googleAnalytics:"offline-ga",navigationPreload:"navigation-preload",precaching:"precaching",rangeRequests:"range-requests",routing:"routing",strategies:"strategies",streams:"streams"};self.workbox=new class{constructor(){return this.v={},this.t={debug:"localhost"===self.location.hostname,modulePathPrefix:null,modulePathCb:null},this.s=this.t.debug?"dev":"prod",this.o=!1,new Proxy(this,{get(t,s){if(t[s])return t[s];const o=e[s];return o&&t.loadModule(`workbox-${o}`),t[s]}})}setConfig(t={}){if(this.o)throw new Error("Config must be set before accessing workbox.* modules");Object.assign(this.t,t),this.s=this.t.debug?"dev":"prod"}loadModule(t){const e=this.i(t);try{importScripts(e),this.o=!0}catch(s){throw console.error(`Unable to import module '${t}' from '${e}'.`),s}}i(e){if(this.t.modulePathCb)return this.t.modulePathCb(e,this.t.debug);let s=[t];const o=`${e}.${this.s}.js`,r=this.t.modulePathPrefix;return r&&""===(s=r.split("/"))[s.length-1]&&s.splice(s.length-1,1),s.push(o),s.join("/")}}}();
|
||||
//# sourceMappingURL=workbox-sw.js.map
|
||||
@@ -1,2 +0,0 @@
|
||||
try{self["workbox:window:4.3.1"]&&_()}catch(n){}var n=function(n,t){return new Promise(function(i){var e=new MessageChannel;e.port1.onmessage=function(n){return i(n.data)},n.postMessage(t,[e.port2])})};function t(n,t){for(var i=0;i<t.length;i++){var e=t[i];e.enumerable=e.enumerable||!1,e.configurable=!0,"value"in e&&(e.writable=!0),Object.defineProperty(n,e.key,e)}}function i(n){if(void 0===n)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return n}try{self["workbox:core:4.3.1"]&&_()}catch(n){}var e=function(){var n=this;this.promise=new Promise(function(t,i){n.resolve=t,n.reject=i})},r=function(n,t){return new URL(n,location).href===new URL(t,location).href},o=function(n,t){Object.assign(this,t,{type:n})};function u(n){return function(){for(var t=[],i=0;i<arguments.length;i++)t[i]=arguments[i];try{return Promise.resolve(n.apply(this,t))}catch(n){return Promise.reject(n)}}}function a(n,t,i){return i?t?t(n):n:(n&&n.then||(n=Promise.resolve(n)),t?n.then(t):n)}function s(){}var c=function(c){var f,h;function v(n,t){var r;return void 0===t&&(t={}),(r=c.call(this)||this).t=n,r.i=t,r.o=0,r.u=new e,r.s=new e,r.h=new e,r.v=r.v.bind(i(i(r))),r.l=r.l.bind(i(i(r))),r.g=r.g.bind(i(i(r))),r.m=r.m.bind(i(i(r))),r}h=c,(f=v).prototype=Object.create(h.prototype),f.prototype.constructor=f,f.__proto__=h;var l,w,g,d=v.prototype;return d.register=u(function(n){var t,i,e=this,u=(void 0===n?{}:n).immediate,c=void 0!==u&&u;return t=function(){return e.p=Boolean(navigator.serviceWorker.controller),e.P=e.R(),a(e.k(),function(n){e.B=n,e.P&&(e.O=e.P,e.s.resolve(e.P),e.h.resolve(e.P),e.j(e.P),e.P.addEventListener("statechange",e.l,{once:!0}));var t=e.B.waiting;return t&&r(t.scriptURL,e.t)&&(e.O=t,Promise.resolve().then(function(){e.dispatchEvent(new o("waiting",{sw:t,wasWaitingBeforeRegister:!0}))})),e.O&&e.u.resolve(e.O),e.B.addEventListener("updatefound",e.g),navigator.serviceWorker.addEventListener("controllerchange",e.m,{once:!0}),"BroadcastChannel"in self&&(e.C=new BroadcastChannel("workbox"),e.C.addEventListener("message",e.v)),navigator.serviceWorker.addEventListener("message",e.v),e.B})},(i=function(){if(!c&&"complete"!==document.readyState)return function(n,t){if(!t)return n&&n.then?n.then(s):Promise.resolve()}(new Promise(function(n){return addEventListener("load",n)}))}())&&i.then?i.then(t):t(i)}),d.getSW=u(function(){return this.O||this.u.promise}),d.messageSW=u(function(t){return a(this.getSW(),function(i){return n(i,t)})}),d.R=function(){var n=navigator.serviceWorker.controller;if(n&&r(n.scriptURL,this.t))return n},d.k=u(function(){var n=this;return function(n,t){try{var i=n()}catch(n){return t(n)}return i&&i.then?i.then(void 0,t):i}(function(){return a(navigator.serviceWorker.register(n.t,n.i),function(t){return n.L=performance.now(),t})},function(n){throw n})}),d.j=function(t){n(t,{type:"WINDOW_READY",meta:"workbox-window"})},d.g=function(){var n=this.B.installing;this.o>0||!r(n.scriptURL,this.t)||performance.now()>this.L+6e4?(this.W=n,this.B.removeEventListener("updatefound",this.g)):(this.O=n,this.u.resolve(n)),++this.o,n.addEventListener("statechange",this.l)},d.l=function(n){var t=this,i=n.target,e=i.state,r=i===this.W,u=r?"external":"",a={sw:i,originalEvent:n};!r&&this.p&&(a.isUpdate=!0),this.dispatchEvent(new o(u+e,a)),"installed"===e?this._=setTimeout(function(){"installed"===e&&t.B.waiting===i&&t.dispatchEvent(new o(u+"waiting",a))},200):"activating"===e&&(clearTimeout(this._),r||this.s.resolve(i))},d.m=function(n){var t=this.O;t===navigator.serviceWorker.controller&&(this.dispatchEvent(new o("controlling",{sw:t,originalEvent:n})),this.h.resolve(t))},d.v=function(n){var t=n.data;this.dispatchEvent(new o("message",{data:t,originalEvent:n}))},l=v,(w=[{key:"active",get:function(){return this.s.promise}},{key:"controlling",get:function(){return this.h.promise}}])&&t(l.prototype,w),g&&t(l,g),v}(function(){function n(){this.D={}}var t=n.prototype;return t.addEventListener=function(n,t){this.T(n).add(t)},t.removeEventListener=function(n,t){this.T(n).delete(t)},t.dispatchEvent=function(n){n.target=this,this.T(n.type).forEach(function(t){return t(n)})},t.T=function(n){return this.D[n]=this.D[n]||new Set},n}());export{c as Workbox,n as messageSW};
|
||||
//# sourceMappingURL=workbox-window.prod.es5.mjs.map
|
||||
@@ -1,2 +0,0 @@
|
||||
try{self["workbox:window:4.3.1"]&&_()}catch(t){}const t=(t,s)=>new Promise(i=>{let e=new MessageChannel;e.port1.onmessage=(t=>i(t.data)),t.postMessage(s,[e.port2])});try{self["workbox:core:4.3.1"]&&_()}catch(t){}class s{constructor(){this.promise=new Promise((t,s)=>{this.resolve=t,this.reject=s})}}class i{constructor(){this.t={}}addEventListener(t,s){this.s(t).add(s)}removeEventListener(t,s){this.s(t).delete(s)}dispatchEvent(t){t.target=this,this.s(t.type).forEach(s=>s(t))}s(t){return this.t[t]=this.t[t]||new Set}}const e=(t,s)=>new URL(t,location).href===new URL(s,location).href;class n{constructor(t,s){Object.assign(this,s,{type:t})}}const h=200,a=6e4;class o extends i{constructor(t,i={}){super(),this.i=t,this.h=i,this.o=0,this.l=new s,this.g=new s,this.u=new s,this.m=this.m.bind(this),this.v=this.v.bind(this),this.p=this.p.bind(this),this._=this._.bind(this)}async register({immediate:t=!1}={}){t||"complete"===document.readyState||await new Promise(t=>addEventListener("load",t)),this.C=Boolean(navigator.serviceWorker.controller),this.W=this.L(),this.S=await this.B(),this.W&&(this.R=this.W,this.g.resolve(this.W),this.u.resolve(this.W),this.P(this.W),this.W.addEventListener("statechange",this.v,{once:!0}));const s=this.S.waiting;return s&&e(s.scriptURL,this.i)&&(this.R=s,Promise.resolve().then(()=>{this.dispatchEvent(new n("waiting",{sw:s,wasWaitingBeforeRegister:!0}))})),this.R&&this.l.resolve(this.R),this.S.addEventListener("updatefound",this.p),navigator.serviceWorker.addEventListener("controllerchange",this._,{once:!0}),"BroadcastChannel"in self&&(this.T=new BroadcastChannel("workbox"),this.T.addEventListener("message",this.m)),navigator.serviceWorker.addEventListener("message",this.m),this.S}get active(){return this.g.promise}get controlling(){return this.u.promise}async getSW(){return this.R||this.l.promise}async messageSW(s){const i=await this.getSW();return t(i,s)}L(){const t=navigator.serviceWorker.controller;if(t&&e(t.scriptURL,this.i))return t}async B(){try{const t=await navigator.serviceWorker.register(this.i,this.h);return this.U=performance.now(),t}catch(t){throw t}}P(s){t(s,{type:"WINDOW_READY",meta:"workbox-window"})}p(){const t=this.S.installing;this.o>0||!e(t.scriptURL,this.i)||performance.now()>this.U+a?(this.k=t,this.S.removeEventListener("updatefound",this.p)):(this.R=t,this.l.resolve(t)),++this.o,t.addEventListener("statechange",this.v)}v(t){const s=t.target,{state:i}=s,e=s===this.k,a=e?"external":"",o={sw:s,originalEvent:t};!e&&this.C&&(o.isUpdate=!0),this.dispatchEvent(new n(a+i,o)),"installed"===i?this.D=setTimeout(()=>{"installed"===i&&this.S.waiting===s&&this.dispatchEvent(new n(a+"waiting",o))},h):"activating"===i&&(clearTimeout(this.D),e||this.g.resolve(s))}_(t){const s=this.R;s===navigator.serviceWorker.controller&&(this.dispatchEvent(new n("controlling",{sw:s,originalEvent:t})),this.u.resolve(s))}m(t){const{data:s}=t;this.dispatchEvent(new n("message",{data:s,originalEvent:t}))}}export{o as Workbox,t as messageSW};
|
||||
//# sourceMappingURL=workbox-window.prod.mjs.map
|
||||
@@ -1,2 +0,0 @@
|
||||
!function(n,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((n=n||self).workbox={})}(this,function(n){"use strict";try{self["workbox:window:4.3.1"]&&_()}catch(n){}var t=function(n,t){return new Promise(function(i){var e=new MessageChannel;e.port1.onmessage=function(n){return i(n.data)},n.postMessage(t,[e.port2])})};function i(n,t){for(var i=0;i<t.length;i++){var e=t[i];e.enumerable=e.enumerable||!1,e.configurable=!0,"value"in e&&(e.writable=!0),Object.defineProperty(n,e.key,e)}}function e(n){if(void 0===n)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return n}try{self["workbox:core:4.3.1"]&&_()}catch(n){}var r=function(){var n=this;this.promise=new Promise(function(t,i){n.resolve=t,n.reject=i})},o=function(n,t){return new URL(n,location).href===new URL(t,location).href},u=function(n,t){Object.assign(this,t,{type:n})};function s(n){return function(){for(var t=[],i=0;i<arguments.length;i++)t[i]=arguments[i];try{return Promise.resolve(n.apply(this,t))}catch(n){return Promise.reject(n)}}}function a(n,t,i){return i?t?t(n):n:(n&&n.then||(n=Promise.resolve(n)),t?n.then(t):n)}function c(){}var f=function(n){var f,h;function v(t,i){var o;return void 0===i&&(i={}),(o=n.call(this)||this).t=t,o.i=i,o.o=0,o.u=new r,o.s=new r,o.h=new r,o.v=o.v.bind(e(e(o))),o.l=o.l.bind(e(e(o))),o.g=o.g.bind(e(e(o))),o.m=o.m.bind(e(e(o))),o}h=n,(f=v).prototype=Object.create(h.prototype),f.prototype.constructor=f,f.__proto__=h;var l,w,d,g=v.prototype;return g.register=s(function(n){var t,i,e=this,r=(void 0===n?{}:n).immediate,s=void 0!==r&&r;return t=function(){return e.p=Boolean(navigator.serviceWorker.controller),e.P=e.j(),a(e.O(),function(n){e.R=n,e.P&&(e._=e.P,e.s.resolve(e.P),e.h.resolve(e.P),e.k(e.P),e.P.addEventListener("statechange",e.l,{once:!0}));var t=e.R.waiting;return t&&o(t.scriptURL,e.t)&&(e._=t,Promise.resolve().then(function(){e.dispatchEvent(new u("waiting",{sw:t,wasWaitingBeforeRegister:!0}))})),e._&&e.u.resolve(e._),e.R.addEventListener("updatefound",e.g),navigator.serviceWorker.addEventListener("controllerchange",e.m,{once:!0}),"BroadcastChannel"in self&&(e.B=new BroadcastChannel("workbox"),e.B.addEventListener("message",e.v)),navigator.serviceWorker.addEventListener("message",e.v),e.R})},(i=function(){if(!s&&"complete"!==document.readyState)return function(n,t){if(!t)return n&&n.then?n.then(c):Promise.resolve()}(new Promise(function(n){return addEventListener("load",n)}))}())&&i.then?i.then(t):t(i)}),g.getSW=s(function(){return this._||this.u.promise}),g.messageSW=s(function(n){return a(this.getSW(),function(i){return t(i,n)})}),g.j=function(){var n=navigator.serviceWorker.controller;if(n&&o(n.scriptURL,this.t))return n},g.O=s(function(){var n=this;return function(n,t){try{var i=n()}catch(n){return t(n)}return i&&i.then?i.then(void 0,t):i}(function(){return a(navigator.serviceWorker.register(n.t,n.i),function(t){return n.C=performance.now(),t})},function(n){throw n})}),g.k=function(n){t(n,{type:"WINDOW_READY",meta:"workbox-window"})},g.g=function(){var n=this.R.installing;this.o>0||!o(n.scriptURL,this.t)||performance.now()>this.C+6e4?(this.L=n,this.R.removeEventListener("updatefound",this.g)):(this._=n,this.u.resolve(n)),++this.o,n.addEventListener("statechange",this.l)},g.l=function(n){var t=this,i=n.target,e=i.state,r=i===this.L,o=r?"external":"",s={sw:i,originalEvent:n};!r&&this.p&&(s.isUpdate=!0),this.dispatchEvent(new u(o+e,s)),"installed"===e?this.W=setTimeout(function(){"installed"===e&&t.R.waiting===i&&t.dispatchEvent(new u(o+"waiting",s))},200):"activating"===e&&(clearTimeout(this.W),r||this.s.resolve(i))},g.m=function(n){var t=this._;t===navigator.serviceWorker.controller&&(this.dispatchEvent(new u("controlling",{sw:t,originalEvent:n})),this.h.resolve(t))},g.v=function(n){var t=n.data;this.dispatchEvent(new u("message",{data:t,originalEvent:n}))},l=v,(w=[{key:"active",get:function(){return this.s.promise}},{key:"controlling",get:function(){return this.h.promise}}])&&i(l.prototype,w),d&&i(l,d),v}(function(){function n(){this.D={}}var t=n.prototype;return t.addEventListener=function(n,t){this.M(n).add(t)},t.removeEventListener=function(n,t){this.M(n).delete(t)},t.dispatchEvent=function(n){n.target=this,this.M(n.type).forEach(function(t){return t(n)})},t.M=function(n){return this.D[n]=this.D[n]||new Set},n}());n.Workbox=f,n.messageSW=t,Object.defineProperty(n,"__esModule",{value:!0})});
|
||||
//# sourceMappingURL=workbox-window.prod.umd.js.map
|
||||
@@ -24,7 +24,6 @@ const crowdinMap = {
|
||||
"nb-NO": "en-nb",
|
||||
"nl-NL": "en-nl",
|
||||
"nn-NO": "en-nnno",
|
||||
"oc-FR": "en-oc",
|
||||
"pa-IN": "en-pain",
|
||||
"pl-PL": "en-pl",
|
||||
"pt-BR": "en-ptbr",
|
||||
@@ -61,7 +60,6 @@ const flags = {
|
||||
"nb-NO": "🇳🇴",
|
||||
"nl-NL": "🇳🇱",
|
||||
"nn-NO": "🇳🇴",
|
||||
"oc-FR": "🏳",
|
||||
"pa-IN": "🇮🇳",
|
||||
"pl-PL": "🇵🇱",
|
||||
"pt-BR": "🇧🇷",
|
||||
@@ -98,7 +96,6 @@ const languages = {
|
||||
"nb-NO": "Norsk bokmål",
|
||||
"nl-NL": "Nederlands",
|
||||
"nn-NO": "Norsk nynorsk",
|
||||
"oc-FR": "Occitan",
|
||||
"pa-IN": "ਪੰਜਾਬੀ",
|
||||
"pl-PL": "Polski",
|
||||
"pt-BR": "Português Brasileiro",
|
||||
|
||||
@@ -58,7 +58,7 @@ export const actionAlignTop = register({
|
||||
<ToolButton
|
||||
hidden={!enableActionGroup(elements, appState)}
|
||||
type="button"
|
||||
icon={<AlignTopIcon theme={appState.theme} />}
|
||||
icon={<AlignTopIcon appearance={appState.appearance} />}
|
||||
onClick={() => updateData(null)}
|
||||
title={`${t("labels.alignTop")} — ${getShortcutKey(
|
||||
"CtrlOrCmd+Shift+Up",
|
||||
@@ -87,7 +87,7 @@ export const actionAlignBottom = register({
|
||||
<ToolButton
|
||||
hidden={!enableActionGroup(elements, appState)}
|
||||
type="button"
|
||||
icon={<AlignBottomIcon theme={appState.theme} />}
|
||||
icon={<AlignBottomIcon appearance={appState.appearance} />}
|
||||
onClick={() => updateData(null)}
|
||||
title={`${t("labels.alignBottom")} — ${getShortcutKey(
|
||||
"CtrlOrCmd+Shift+Down",
|
||||
@@ -116,7 +116,7 @@ export const actionAlignLeft = register({
|
||||
<ToolButton
|
||||
hidden={!enableActionGroup(elements, appState)}
|
||||
type="button"
|
||||
icon={<AlignLeftIcon theme={appState.theme} />}
|
||||
icon={<AlignLeftIcon appearance={appState.appearance} />}
|
||||
onClick={() => updateData(null)}
|
||||
title={`${t("labels.alignLeft")} — ${getShortcutKey(
|
||||
"CtrlOrCmd+Shift+Left",
|
||||
@@ -145,7 +145,7 @@ export const actionAlignRight = register({
|
||||
<ToolButton
|
||||
hidden={!enableActionGroup(elements, appState)}
|
||||
type="button"
|
||||
icon={<AlignRightIcon theme={appState.theme} />}
|
||||
icon={<AlignRightIcon appearance={appState.appearance} />}
|
||||
onClick={() => updateData(null)}
|
||||
title={`${t("labels.alignRight")} — ${getShortcutKey(
|
||||
"CtrlOrCmd+Shift+Right",
|
||||
@@ -172,7 +172,7 @@ export const actionAlignVerticallyCentered = register({
|
||||
<ToolButton
|
||||
hidden={!enableActionGroup(elements, appState)}
|
||||
type="button"
|
||||
icon={<CenterVerticallyIcon theme={appState.theme} />}
|
||||
icon={<CenterVerticallyIcon appearance={appState.appearance} />}
|
||||
onClick={() => updateData(null)}
|
||||
title={t("labels.centerVertically")}
|
||||
aria-label={t("labels.centerVertically")}
|
||||
@@ -197,7 +197,7 @@ export const actionAlignHorizontallyCentered = register({
|
||||
<ToolButton
|
||||
hidden={!enableActionGroup(elements, appState)}
|
||||
type="button"
|
||||
icon={<CenterHorizontallyIcon theme={appState.theme} />}
|
||||
icon={<CenterHorizontallyIcon appearance={appState.appearance} />}
|
||||
onClick={() => updateData(null)}
|
||||
title={t("labels.centerHorizontally")}
|
||||
aria-label={t("labels.centerHorizontally")}
|
||||
|
||||
@@ -48,7 +48,7 @@ export const actionClearCanvas = register({
|
||||
),
|
||||
appState: {
|
||||
...getDefaultAppState(),
|
||||
theme: appState.theme,
|
||||
appearance: appState.appearance,
|
||||
elementLocked: appState.elementLocked,
|
||||
exportBackground: appState.exportBackground,
|
||||
exportEmbedScene: appState.exportEmbedScene,
|
||||
|
||||
@@ -17,8 +17,7 @@ export const actionCopy = register({
|
||||
};
|
||||
},
|
||||
contextItemLabel: "labels.copy",
|
||||
// don't supply a shortcut since we handle this conditionally via onCopy event
|
||||
keyTest: undefined,
|
||||
keyTest: (event) => event[KEYS.CTRL_OR_CMD] && event.code === CODES.C,
|
||||
});
|
||||
|
||||
export const actionCut = register({
|
||||
@@ -95,14 +94,7 @@ export const actionCopyAsPng = register({
|
||||
return {
|
||||
appState: {
|
||||
...appState,
|
||||
toastMessage: t("toast.copyToClipboardAsPng", {
|
||||
exportSelection: selectedElements.length
|
||||
? t("toast.selection")
|
||||
: t("toast.canvas"),
|
||||
exportColorScheme: appState.exportWithDarkMode
|
||||
? t("buttons.darkMode")
|
||||
: t("buttons.lightMode"),
|
||||
}),
|
||||
toastMessage: t("toast.copyToClipboardAsPng"),
|
||||
},
|
||||
commitToHistory: false,
|
||||
};
|
||||
|
||||
@@ -53,7 +53,7 @@ export const distributeHorizontally = register({
|
||||
<ToolButton
|
||||
hidden={!enableActionGroup(elements, appState)}
|
||||
type="button"
|
||||
icon={<DistributeHorizontallyIcon theme={appState.theme} />}
|
||||
icon={<DistributeHorizontallyIcon appearance={appState.appearance} />}
|
||||
onClick={() => updateData(null)}
|
||||
title={`${t("labels.distributeHorizontally")} — ${getShortcutKey(
|
||||
"Alt+H",
|
||||
@@ -81,7 +81,7 @@ export const distributeVertically = register({
|
||||
<ToolButton
|
||||
hidden={!enableActionGroup(elements, appState)}
|
||||
type="button"
|
||||
icon={<DistributeVerticallyIcon theme={appState.theme} />}
|
||||
icon={<DistributeVerticallyIcon appearance={appState.appearance} />}
|
||||
onClick={() => updateData(null)}
|
||||
title={`${t("labels.distributeVertically")} — ${getShortcutKey("Alt+V")}`}
|
||||
aria-label={t("labels.distributeVertically")}
|
||||
|
||||
@@ -18,12 +18,11 @@ export const actionChangeProjectName = register({
|
||||
trackEvent("change", "title");
|
||||
return { appState: { ...appState, name: value }, commitToHistory: false };
|
||||
},
|
||||
PanelComponent: ({ appState, updateData, appProps }) => (
|
||||
PanelComponent: ({ appState, updateData }) => (
|
||||
<ProjectName
|
||||
label={t("labels.fileTitle")}
|
||||
value={appState.name || "Unnamed"}
|
||||
onChange={(name: string) => updateData(name)}
|
||||
isNameEditable={typeof appProps.name === "undefined"}
|
||||
/>
|
||||
),
|
||||
});
|
||||
@@ -226,8 +225,8 @@ export const actionExportWithDarkMode = register({
|
||||
>
|
||||
<DarkModeToggle
|
||||
value={appState.exportWithDarkMode ? "dark" : "light"}
|
||||
onChange={(theme: Appearence) => {
|
||||
updateData(theme === "dark");
|
||||
onChange={(appearance: Appearence) => {
|
||||
updateData(appearance === "dark");
|
||||
}}
|
||||
title={t("labels.toggleExportColorScheme")}
|
||||
/>
|
||||
|
||||
@@ -18,7 +18,7 @@ import { isBindingElement } from "../element/typeChecks";
|
||||
|
||||
export const actionFinalize = register({
|
||||
name: "finalize",
|
||||
perform: (elements, appState, _, { canvas }) => {
|
||||
perform: (elements, appState) => {
|
||||
if (appState.editingLinearElement) {
|
||||
const {
|
||||
elementId,
|
||||
@@ -126,7 +126,7 @@ export const actionFinalize = register({
|
||||
(!appState.elementLocked && appState.elementType !== "draw") ||
|
||||
!multiPointElement
|
||||
) {
|
||||
resetCursor(canvas);
|
||||
resetCursor();
|
||||
}
|
||||
return {
|
||||
elements: newElements,
|
||||
|
||||
@@ -134,7 +134,7 @@ export const actionGroup = register({
|
||||
<ToolButton
|
||||
hidden={!enableActionGroup(elements, appState)}
|
||||
type="button"
|
||||
icon={<GroupIcon theme={appState.theme} />}
|
||||
icon={<GroupIcon appearance={appState.appearance} />}
|
||||
onClick={() => updateData(null)}
|
||||
title={`${t("labels.group")} — ${getShortcutKey("CtrlOrCmd+G")}`}
|
||||
aria-label={t("labels.group")}
|
||||
@@ -181,7 +181,7 @@ export const actionUngroup = register({
|
||||
<ToolButton
|
||||
type="button"
|
||||
hidden={getSelectedGroupIds(appState).length === 0}
|
||||
icon={<UngroupIcon theme={appState.theme} />}
|
||||
icon={<UngroupIcon appearance={appState.appearance} />}
|
||||
onClick={() => updateData(null)}
|
||||
title={`${t("labels.ungroup")} — ${getShortcutKey("CtrlOrCmd+Shift+G")}`}
|
||||
aria-label={t("labels.ungroup")}
|
||||
|
||||
@@ -169,17 +169,17 @@ export const actionChangeFillStyle = register({
|
||||
{
|
||||
value: "hachure",
|
||||
text: t("labels.hachure"),
|
||||
icon: <FillHachureIcon theme={appState.theme} />,
|
||||
icon: <FillHachureIcon appearance={appState.appearance} />,
|
||||
},
|
||||
{
|
||||
value: "cross-hatch",
|
||||
text: t("labels.crossHatch"),
|
||||
icon: <FillCrossHatchIcon theme={appState.theme} />,
|
||||
icon: <FillCrossHatchIcon appearance={appState.appearance} />,
|
||||
},
|
||||
{
|
||||
value: "solid",
|
||||
text: t("labels.solid"),
|
||||
icon: <FillSolidIcon theme={appState.theme} />,
|
||||
icon: <FillSolidIcon appearance={appState.appearance} />,
|
||||
},
|
||||
]}
|
||||
group="fill"
|
||||
@@ -219,17 +219,32 @@ export const actionChangeStrokeWidth = register({
|
||||
{
|
||||
value: 1,
|
||||
text: t("labels.thin"),
|
||||
icon: <StrokeWidthIcon theme={appState.theme} strokeWidth={2} />,
|
||||
icon: (
|
||||
<StrokeWidthIcon
|
||||
appearance={appState.appearance}
|
||||
strokeWidth={2}
|
||||
/>
|
||||
),
|
||||
},
|
||||
{
|
||||
value: 2,
|
||||
text: t("labels.bold"),
|
||||
icon: <StrokeWidthIcon theme={appState.theme} strokeWidth={6} />,
|
||||
icon: (
|
||||
<StrokeWidthIcon
|
||||
appearance={appState.appearance}
|
||||
strokeWidth={6}
|
||||
/>
|
||||
),
|
||||
},
|
||||
{
|
||||
value: 4,
|
||||
text: t("labels.extraBold"),
|
||||
icon: <StrokeWidthIcon theme={appState.theme} strokeWidth={10} />,
|
||||
icon: (
|
||||
<StrokeWidthIcon
|
||||
appearance={appState.appearance}
|
||||
strokeWidth={10}
|
||||
/>
|
||||
),
|
||||
},
|
||||
]}
|
||||
value={getFormValue(
|
||||
@@ -267,17 +282,17 @@ export const actionChangeSloppiness = register({
|
||||
{
|
||||
value: 0,
|
||||
text: t("labels.architect"),
|
||||
icon: <SloppinessArchitectIcon theme={appState.theme} />,
|
||||
icon: <SloppinessArchitectIcon appearance={appState.appearance} />,
|
||||
},
|
||||
{
|
||||
value: 1,
|
||||
text: t("labels.artist"),
|
||||
icon: <SloppinessArtistIcon theme={appState.theme} />,
|
||||
icon: <SloppinessArtistIcon appearance={appState.appearance} />,
|
||||
},
|
||||
{
|
||||
value: 2,
|
||||
text: t("labels.cartoonist"),
|
||||
icon: <SloppinessCartoonistIcon theme={appState.theme} />,
|
||||
icon: <SloppinessCartoonistIcon appearance={appState.appearance} />,
|
||||
},
|
||||
]}
|
||||
value={getFormValue(
|
||||
@@ -314,17 +329,17 @@ export const actionChangeStrokeStyle = register({
|
||||
{
|
||||
value: "solid",
|
||||
text: t("labels.strokeStyle_solid"),
|
||||
icon: <StrokeStyleSolidIcon theme={appState.theme} />,
|
||||
icon: <StrokeStyleSolidIcon appearance={appState.appearance} />,
|
||||
},
|
||||
{
|
||||
value: "dashed",
|
||||
text: t("labels.strokeStyle_dashed"),
|
||||
icon: <StrokeStyleDashedIcon theme={appState.theme} />,
|
||||
icon: <StrokeStyleDashedIcon appearance={appState.appearance} />,
|
||||
},
|
||||
{
|
||||
value: "dotted",
|
||||
text: t("labels.strokeStyle_dotted"),
|
||||
icon: <StrokeStyleDottedIcon theme={appState.theme} />,
|
||||
icon: <StrokeStyleDottedIcon appearance={appState.appearance} />,
|
||||
},
|
||||
]}
|
||||
value={getFormValue(
|
||||
@@ -565,12 +580,12 @@ export const actionChangeSharpness = register({
|
||||
{
|
||||
value: "sharp",
|
||||
text: t("labels.sharp"),
|
||||
icon: <EdgeSharpIcon theme={appState.theme} />,
|
||||
icon: <EdgeSharpIcon appearance={appState.appearance} />,
|
||||
},
|
||||
{
|
||||
value: "round",
|
||||
text: t("labels.round"),
|
||||
icon: <EdgeRoundIcon theme={appState.theme} />,
|
||||
icon: <EdgeRoundIcon appearance={appState.appearance} />,
|
||||
},
|
||||
]}
|
||||
value={getFormValue(
|
||||
@@ -638,27 +653,40 @@ export const actionChangeArrowhead = register({
|
||||
{
|
||||
value: null,
|
||||
text: t("labels.arrowhead_none"),
|
||||
icon: <ArrowheadNoneIcon theme={appState.theme} />,
|
||||
icon: <ArrowheadNoneIcon appearance={appState.appearance} />,
|
||||
keyBinding: "q",
|
||||
},
|
||||
{
|
||||
value: "arrow",
|
||||
text: t("labels.arrowhead_arrow"),
|
||||
icon: (
|
||||
<ArrowheadArrowIcon theme={appState.theme} flip={!isRTL} />
|
||||
<ArrowheadArrowIcon
|
||||
appearance={appState.appearance}
|
||||
flip={!isRTL}
|
||||
/>
|
||||
),
|
||||
keyBinding: "w",
|
||||
},
|
||||
{
|
||||
value: "bar",
|
||||
text: t("labels.arrowhead_bar"),
|
||||
icon: <ArrowheadBarIcon theme={appState.theme} flip={!isRTL} />,
|
||||
icon: (
|
||||
<ArrowheadBarIcon
|
||||
appearance={appState.appearance}
|
||||
flip={!isRTL}
|
||||
/>
|
||||
),
|
||||
keyBinding: "e",
|
||||
},
|
||||
{
|
||||
value: "dot",
|
||||
text: t("labels.arrowhead_dot"),
|
||||
icon: <ArrowheadDotIcon theme={appState.theme} flip={!isRTL} />,
|
||||
icon: (
|
||||
<ArrowheadDotIcon
|
||||
appearance={appState.appearance}
|
||||
flip={!isRTL}
|
||||
/>
|
||||
),
|
||||
keyBinding: "r",
|
||||
},
|
||||
]}
|
||||
@@ -681,27 +709,40 @@ export const actionChangeArrowhead = register({
|
||||
value: null,
|
||||
text: t("labels.arrowhead_none"),
|
||||
keyBinding: "q",
|
||||
icon: <ArrowheadNoneIcon theme={appState.theme} />,
|
||||
icon: <ArrowheadNoneIcon appearance={appState.appearance} />,
|
||||
},
|
||||
{
|
||||
value: "arrow",
|
||||
text: t("labels.arrowhead_arrow"),
|
||||
keyBinding: "w",
|
||||
icon: (
|
||||
<ArrowheadArrowIcon theme={appState.theme} flip={isRTL} />
|
||||
<ArrowheadArrowIcon
|
||||
appearance={appState.appearance}
|
||||
flip={isRTL}
|
||||
/>
|
||||
),
|
||||
},
|
||||
{
|
||||
value: "bar",
|
||||
text: t("labels.arrowhead_bar"),
|
||||
keyBinding: "e",
|
||||
icon: <ArrowheadBarIcon theme={appState.theme} flip={isRTL} />,
|
||||
icon: (
|
||||
<ArrowheadBarIcon
|
||||
appearance={appState.appearance}
|
||||
flip={isRTL}
|
||||
/>
|
||||
),
|
||||
},
|
||||
{
|
||||
value: "dot",
|
||||
text: t("labels.arrowhead_dot"),
|
||||
keyBinding: "r",
|
||||
icon: <ArrowheadDotIcon theme={appState.theme} flip={isRTL} />,
|
||||
icon: (
|
||||
<ArrowheadDotIcon
|
||||
appearance={appState.appearance}
|
||||
flip={isRTL}
|
||||
/>
|
||||
),
|
||||
},
|
||||
]}
|
||||
value={getFormValue<Arrowhead | null>(
|
||||
|
||||
@@ -38,7 +38,7 @@ export const actionSendBackward = register({
|
||||
onClick={() => updateData(null)}
|
||||
title={`${t("labels.sendBackward")} — ${getShortcutKey("CtrlOrCmd+[")}`}
|
||||
>
|
||||
<SendBackwardIcon theme={appState.theme} />
|
||||
<SendBackwardIcon appearance={appState.appearance} />
|
||||
</button>
|
||||
),
|
||||
});
|
||||
@@ -65,7 +65,7 @@ export const actionBringForward = register({
|
||||
onClick={() => updateData(null)}
|
||||
title={`${t("labels.bringForward")} — ${getShortcutKey("CtrlOrCmd+]")}`}
|
||||
>
|
||||
<BringForwardIcon theme={appState.theme} />
|
||||
<BringForwardIcon appearance={appState.appearance} />
|
||||
</button>
|
||||
),
|
||||
});
|
||||
@@ -99,7 +99,7 @@ export const actionSendToBack = register({
|
||||
: getShortcutKey("CtrlOrCmd+Shift+[")
|
||||
}`}
|
||||
>
|
||||
<SendToBackIcon theme={appState.theme} />
|
||||
<SendToBackIcon appearance={appState.appearance} />
|
||||
</button>
|
||||
),
|
||||
});
|
||||
@@ -133,7 +133,7 @@ export const actionBringToFront = register({
|
||||
: getShortcutKey("CtrlOrCmd+Shift+]")
|
||||
}`}
|
||||
>
|
||||
<BringToFrontIcon theme={appState.theme} />
|
||||
<BringToFrontIcon appearance={appState.appearance} />
|
||||
</button>
|
||||
),
|
||||
});
|
||||
|
||||
@@ -122,7 +122,6 @@ export class ActionManager implements ActionsManagerInterface {
|
||||
appState={this.getAppState()}
|
||||
updateData={updateData}
|
||||
id={id}
|
||||
appProps={this.app.props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import React from "react";
|
||||
import { ExcalidrawElement } from "../element/types";
|
||||
import { AppState, ExcalidrawProps } from "../types";
|
||||
import { AppState } from "../types";
|
||||
|
||||
/** if false, the action should be prevented */
|
||||
export type ActionResult =
|
||||
@@ -94,7 +94,6 @@ export interface Action {
|
||||
elements: readonly ExcalidrawElement[];
|
||||
appState: AppState;
|
||||
updateData: (formData?: any) => void;
|
||||
appProps: ExcalidrawProps;
|
||||
id?: string;
|
||||
}>;
|
||||
perform: ActionFn;
|
||||
|
||||
+2
-2
@@ -13,7 +13,7 @@ export const getDefaultAppState = (): Omit<
|
||||
"offsetTop" | "offsetLeft"
|
||||
> => {
|
||||
return {
|
||||
theme: "light",
|
||||
appearance: "light",
|
||||
collaborators: new Map(),
|
||||
currentChartType: "bar",
|
||||
currentItemBackgroundColor: "transparent",
|
||||
@@ -92,7 +92,7 @@ const APP_STATE_STORAGE_CONF = (<
|
||||
>(
|
||||
config: { [K in keyof T]: K extends keyof AppState ? T[K] : never },
|
||||
) => config)({
|
||||
theme: { browser: true, export: false },
|
||||
appearance: { browser: true, export: false },
|
||||
collaborators: { browser: false, export: false },
|
||||
currentChartType: { browser: true, export: false },
|
||||
currentItemBackgroundColor: { browser: true, export: false },
|
||||
|
||||
@@ -151,12 +151,10 @@ const LIBRARY_ICON = (
|
||||
);
|
||||
|
||||
export const ShapesSwitcher = ({
|
||||
canvas,
|
||||
elementType,
|
||||
setAppState,
|
||||
isLibraryOpen,
|
||||
}: {
|
||||
canvas: HTMLCanvasElement | null;
|
||||
elementType: ExcalidrawElement["type"];
|
||||
setAppState: React.Component<any, AppState>["setState"];
|
||||
isLibraryOpen: boolean;
|
||||
@@ -187,7 +185,7 @@ export const ShapesSwitcher = ({
|
||||
multiElement: null,
|
||||
selectedElementIds: {},
|
||||
});
|
||||
setCursorForShape(canvas, value);
|
||||
setCursorForShape(value);
|
||||
setAppState({});
|
||||
}}
|
||||
/>
|
||||
|
||||
+122
-187
@@ -172,7 +172,6 @@ import {
|
||||
ResolvablePromise,
|
||||
resolvablePromise,
|
||||
sceneCoordsToViewportCoords,
|
||||
setCursor,
|
||||
setCursorForShape,
|
||||
tupleToCoors,
|
||||
viewportCoordsToSceneCoords,
|
||||
@@ -271,10 +270,9 @@ export type ExcalidrawImperativeAPI = {
|
||||
history: {
|
||||
clear: InstanceType<typeof App>["resetHistory"];
|
||||
};
|
||||
setScrollToContent: InstanceType<typeof App>["setScrollToContent"];
|
||||
setScrollToCenter: InstanceType<typeof App>["setScrollToCenter"];
|
||||
getSceneElements: InstanceType<typeof App>["getSceneElements"];
|
||||
getAppState: () => InstanceType<typeof App>["state"];
|
||||
setCanvasOffsets: InstanceType<typeof App>["setCanvasOffsets"];
|
||||
readyPromise: ResolvablePromise<ExcalidrawImperativeAPI>;
|
||||
ready: true;
|
||||
};
|
||||
@@ -298,24 +296,22 @@ class App extends React.Component<ExcalidrawProps, AppState> {
|
||||
const {
|
||||
width = window.innerWidth,
|
||||
height = window.innerHeight,
|
||||
offsetLeft,
|
||||
offsetTop,
|
||||
excalidrawRef,
|
||||
viewModeEnabled = false,
|
||||
zenModeEnabled = false,
|
||||
gridModeEnabled = false,
|
||||
theme = defaultAppState.theme,
|
||||
name = defaultAppState.name,
|
||||
} = props;
|
||||
this.state = {
|
||||
...defaultAppState,
|
||||
theme,
|
||||
isLoading: true,
|
||||
width,
|
||||
height,
|
||||
...this.getCanvasOffsets(),
|
||||
...this.getCanvasOffsets({ offsetLeft, offsetTop }),
|
||||
viewModeEnabled,
|
||||
zenModeEnabled,
|
||||
gridSize: gridModeEnabled ? GRID_SIZE : null,
|
||||
name,
|
||||
};
|
||||
if (excalidrawRef) {
|
||||
const readyPromise =
|
||||
@@ -331,10 +327,9 @@ class App extends React.Component<ExcalidrawProps, AppState> {
|
||||
history: {
|
||||
clear: this.resetHistory,
|
||||
},
|
||||
setScrollToContent: this.setScrollToContent,
|
||||
setScrollToCenter: this.setScrollToCenter,
|
||||
getSceneElements: this.getSceneElements,
|
||||
getAppState: () => this.state,
|
||||
setCanvasOffsets: this.setCanvasOffsets,
|
||||
} as const;
|
||||
if (typeof excalidrawRef === "function") {
|
||||
excalidrawRef(api);
|
||||
@@ -418,6 +413,8 @@ class App extends React.Component<ExcalidrawProps, AppState> {
|
||||
zenModeEnabled,
|
||||
width: canvasDOMWidth,
|
||||
height: canvasDOMHeight,
|
||||
offsetTop,
|
||||
offsetLeft,
|
||||
viewModeEnabled,
|
||||
} = this.state;
|
||||
|
||||
@@ -435,6 +432,8 @@ class App extends React.Component<ExcalidrawProps, AppState> {
|
||||
style={{
|
||||
width: canvasDOMWidth,
|
||||
height: canvasDOMHeight,
|
||||
top: offsetTop,
|
||||
left: offsetLeft,
|
||||
}}
|
||||
>
|
||||
<LayerUI
|
||||
@@ -462,8 +461,6 @@ class App extends React.Component<ExcalidrawProps, AppState> {
|
||||
showExitZenModeBtn={
|
||||
typeof this.props?.zenModeEnabled === "undefined" && zenModeEnabled
|
||||
}
|
||||
showThemeBtn={typeof this.props?.theme === "undefined"}
|
||||
libraryReturnUrl={this.props.libraryReturnUrl}
|
||||
/>
|
||||
<div className="excalidraw-textEditorContainer" />
|
||||
{this.state.showStats && (
|
||||
@@ -524,8 +521,6 @@ class App extends React.Component<ExcalidrawProps, AppState> {
|
||||
let viewModeEnabled = actionResult?.appState?.viewModeEnabled || false;
|
||||
let zenModeEnabled = actionResult?.appState?.zenModeEnabled || false;
|
||||
let gridSize = actionResult?.appState?.gridSize || null;
|
||||
let theme = actionResult?.appState?.theme || "light";
|
||||
let name = actionResult?.appState?.name || this.state.name;
|
||||
|
||||
if (typeof this.props.viewModeEnabled !== "undefined") {
|
||||
viewModeEnabled = this.props.viewModeEnabled;
|
||||
@@ -539,33 +534,19 @@ class App extends React.Component<ExcalidrawProps, AppState> {
|
||||
gridSize = this.props.gridModeEnabled ? GRID_SIZE : null;
|
||||
}
|
||||
|
||||
if (typeof this.props.theme !== "undefined") {
|
||||
theme = this.props.theme;
|
||||
}
|
||||
|
||||
if (typeof this.props.name !== "undefined") {
|
||||
name = this.props.name;
|
||||
}
|
||||
|
||||
this.setState(
|
||||
(state) => {
|
||||
// using Object.assign instead of spread to fool TS 4.2.2+ into
|
||||
// regarding the resulting type as not containing undefined
|
||||
// (which the following expression will never contain)
|
||||
return Object.assign(actionResult.appState || {}, {
|
||||
editingElement:
|
||||
editingElement || actionResult.appState?.editingElement || null,
|
||||
width: state.width,
|
||||
height: state.height,
|
||||
offsetTop: state.offsetTop,
|
||||
offsetLeft: state.offsetLeft,
|
||||
viewModeEnabled,
|
||||
zenModeEnabled,
|
||||
gridSize,
|
||||
theme,
|
||||
name,
|
||||
});
|
||||
},
|
||||
(state) => ({
|
||||
...actionResult.appState,
|
||||
editingElement:
|
||||
editingElement || actionResult.appState?.editingElement || null,
|
||||
width: state.width,
|
||||
height: state.height,
|
||||
offsetTop: state.offsetTop,
|
||||
offsetLeft: state.offsetLeft,
|
||||
viewModeEnabled,
|
||||
zenModeEnabled,
|
||||
gridSize,
|
||||
}),
|
||||
() => {
|
||||
if (actionResult.syncHistory) {
|
||||
history.setCurrentState(
|
||||
@@ -606,7 +587,7 @@ class App extends React.Component<ExcalidrawProps, AppState> {
|
||||
private importLibraryFromUrl = async (url: string) => {
|
||||
window.history.replaceState({}, APP_NAME, window.location.origin);
|
||||
try {
|
||||
const request = await fetch(decodeURIComponent(url));
|
||||
const request = await fetch(url);
|
||||
const blob = await request.blob();
|
||||
const json = JSON.parse(await blob.text());
|
||||
if (!isValidLibrary(json)) {
|
||||
@@ -642,7 +623,7 @@ class App extends React.Component<ExcalidrawProps, AppState> {
|
||||
this.setState((state) => ({
|
||||
...getDefaultAppState(),
|
||||
isLoading: opts?.resetLoadingState ? false : state.isLoading,
|
||||
theme: this.state.theme,
|
||||
appearance: this.state.appearance,
|
||||
}));
|
||||
this.resetHistory();
|
||||
},
|
||||
@@ -693,7 +674,7 @@ class App extends React.Component<ExcalidrawProps, AppState> {
|
||||
...scene.appState,
|
||||
isLoading: false,
|
||||
};
|
||||
if (initialData?.scrollToContent) {
|
||||
if (initialData?.scrollToCenter) {
|
||||
scene.appState = {
|
||||
...scene.appState,
|
||||
...calculateScrollCenter(
|
||||
@@ -754,13 +735,14 @@ class App extends React.Component<ExcalidrawProps, AppState> {
|
||||
this.scene.addCallback(this.onSceneUpdated);
|
||||
this.addEventListeners();
|
||||
|
||||
const searchParams = new URLSearchParams(window.location.search.slice(1));
|
||||
|
||||
if (searchParams.has("web-share-target")) {
|
||||
// Obtain a file that was shared via the Web Share Target API.
|
||||
this.restoreFileFromShare();
|
||||
// optim to avoid extra render on init
|
||||
if (
|
||||
typeof this.props.offsetLeft === "number" &&
|
||||
typeof this.props.offsetTop === "number"
|
||||
) {
|
||||
this.initializeScene();
|
||||
} else {
|
||||
this.setState(this.getCanvasOffsets(), () => {
|
||||
this.setState(this.getCanvasOffsets(this.props), () => {
|
||||
this.initializeScene();
|
||||
});
|
||||
}
|
||||
@@ -865,12 +847,16 @@ class App extends React.Component<ExcalidrawProps, AppState> {
|
||||
|
||||
if (
|
||||
prevProps.width !== this.props.width ||
|
||||
prevProps.height !== this.props.height
|
||||
prevProps.height !== this.props.height ||
|
||||
(typeof this.props.offsetLeft === "number" &&
|
||||
prevProps.offsetLeft !== this.props.offsetLeft) ||
|
||||
(typeof this.props.offsetTop === "number" &&
|
||||
prevProps.offsetTop !== this.props.offsetTop)
|
||||
) {
|
||||
this.setState({
|
||||
width: this.props.width ?? window.innerWidth,
|
||||
height: this.props.height ?? window.innerHeight,
|
||||
...this.getCanvasOffsets(),
|
||||
...this.getCanvasOffsets(this.props),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -889,25 +875,14 @@ class App extends React.Component<ExcalidrawProps, AppState> {
|
||||
this.setState({ zenModeEnabled: !!this.props.zenModeEnabled });
|
||||
}
|
||||
|
||||
if (prevProps.theme !== this.props.theme && this.props.theme) {
|
||||
this.setState({ theme: this.props.theme });
|
||||
}
|
||||
|
||||
if (prevProps.gridModeEnabled !== this.props.gridModeEnabled) {
|
||||
this.setState({
|
||||
gridSize: this.props.gridModeEnabled ? GRID_SIZE : null,
|
||||
});
|
||||
}
|
||||
|
||||
if (this.props.name && prevProps.name !== this.props.name) {
|
||||
this.setState({
|
||||
name: this.props.name,
|
||||
});
|
||||
}
|
||||
|
||||
document
|
||||
.querySelector(".excalidraw")
|
||||
?.classList.toggle("theme--dark", this.state.theme === "dark");
|
||||
?.classList.toggle("Appearance_dark", this.state.appearance === "dark");
|
||||
|
||||
if (
|
||||
this.state.editingLinearElement &&
|
||||
@@ -1032,13 +1007,7 @@ class App extends React.Component<ExcalidrawProps, AppState> {
|
||||
}
|
||||
|
||||
private onScroll = debounce(() => {
|
||||
const { offsetTop, offsetLeft } = this.getCanvasOffsets();
|
||||
this.setState((state) => {
|
||||
if (state.offsetLeft === offsetLeft && state.offsetTop === offsetTop) {
|
||||
return null;
|
||||
}
|
||||
return { offsetTop, offsetLeft };
|
||||
});
|
||||
this.setState({ ...this.getCanvasOffsets() });
|
||||
}, SCROLL_TIMEOUT);
|
||||
|
||||
// Copy/paste
|
||||
@@ -1052,21 +1021,6 @@ class App extends React.Component<ExcalidrawProps, AppState> {
|
||||
});
|
||||
|
||||
private onCopy = withBatchedUpdates((event: ClipboardEvent) => {
|
||||
const activeSelection = document.getSelection();
|
||||
// if there's a selected text is outside the component, prevent our copy
|
||||
// action
|
||||
if (
|
||||
activeSelection?.anchorNode &&
|
||||
// it can happen that certain interactions will create a selection
|
||||
// outside (or potentially inside) the component without actually
|
||||
// selecting anything (i.e. the selection range is collapsed). Copying
|
||||
// in such case wouldn't copy anything to the clipboard anyway, so prevent
|
||||
// our copy handler only if the selection isn't collapsed
|
||||
!activeSelection.isCollapsed &&
|
||||
!this.excalidrawContainerRef.current!.contains(activeSelection.anchorNode)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
if (isWritableElement(event.target)) {
|
||||
return;
|
||||
}
|
||||
@@ -1118,6 +1072,7 @@ class App extends React.Component<ExcalidrawProps, AppState> {
|
||||
};
|
||||
|
||||
private onTapEnd = (event: TouchEvent) => {
|
||||
event.preventDefault();
|
||||
if (event.touches.length > 0) {
|
||||
this.setState({
|
||||
previousSelectedElementIds: {},
|
||||
@@ -1294,7 +1249,7 @@ class App extends React.Component<ExcalidrawProps, AppState> {
|
||||
this.actionManager.executeAction(actionToggleStats);
|
||||
};
|
||||
|
||||
setScrollToContent = (remoteElements: readonly ExcalidrawElement[]) => {
|
||||
setScrollToCenter = (remoteElements: readonly ExcalidrawElement[]) => {
|
||||
this.setState({
|
||||
...calculateScrollCenter(
|
||||
getNonDeletedElements(remoteElements),
|
||||
@@ -1308,22 +1263,6 @@ class App extends React.Component<ExcalidrawProps, AppState> {
|
||||
this.setState({ toastMessage: null });
|
||||
};
|
||||
|
||||
restoreFileFromShare = async () => {
|
||||
try {
|
||||
const webShareTargetCache = await caches.open("web-share-target");
|
||||
|
||||
const file = await webShareTargetCache.match("shared-file");
|
||||
if (file) {
|
||||
const blob = await file.blob();
|
||||
this.loadFileToCanvas(blob);
|
||||
await webShareTargetCache.delete("shared-file");
|
||||
window.history.replaceState(null, APP_NAME, window.location.pathname);
|
||||
}
|
||||
} catch (error) {
|
||||
this.setState({ errorMessage: error.message });
|
||||
}
|
||||
};
|
||||
|
||||
public updateScene = withBatchedUpdates((sceneData: SceneData) => {
|
||||
if (sceneData.commitToHistory) {
|
||||
history.resumeRecording();
|
||||
@@ -1501,16 +1440,16 @@ class App extends React.Component<ExcalidrawProps, AppState> {
|
||||
}
|
||||
if (event.key === KEYS.SPACE && gesture.pointers.size === 0) {
|
||||
isHoldingSpace = true;
|
||||
setCursor(this.canvas, CURSOR_TYPE.GRABBING);
|
||||
document.documentElement.style.cursor = CURSOR_TYPE.GRABBING;
|
||||
}
|
||||
});
|
||||
|
||||
private onKeyUp = withBatchedUpdates((event: KeyboardEvent) => {
|
||||
if (event.key === KEYS.SPACE) {
|
||||
if (this.state.elementType === "selection") {
|
||||
resetCursor(this.canvas);
|
||||
resetCursor();
|
||||
} else {
|
||||
setCursorForShape(this.canvas, this.state.elementType);
|
||||
setCursorForShape(this.state.elementType);
|
||||
this.setState({
|
||||
selectedElementIds: {},
|
||||
selectedGroupIds: {},
|
||||
@@ -1536,7 +1475,7 @@ class App extends React.Component<ExcalidrawProps, AppState> {
|
||||
|
||||
private selectShapeTool(elementType: AppState["elementType"]) {
|
||||
if (!isHoldingSpace) {
|
||||
setCursorForShape(this.canvas, elementType);
|
||||
setCursorForShape(elementType);
|
||||
}
|
||||
if (isToolIcon(document.activeElement)) {
|
||||
document.activeElement.blur();
|
||||
@@ -1632,10 +1571,7 @@ class App extends React.Component<ExcalidrawProps, AppState> {
|
||||
},
|
||||
this.state,
|
||||
);
|
||||
return [
|
||||
viewportX - this.state.offsetLeft,
|
||||
viewportY - this.state.offsetTop,
|
||||
];
|
||||
return [viewportX, viewportY];
|
||||
},
|
||||
onChange: withBatchedUpdates((text) => {
|
||||
updateElement(text);
|
||||
@@ -1643,12 +1579,10 @@ class App extends React.Component<ExcalidrawProps, AppState> {
|
||||
updateBoundElements(element);
|
||||
}
|
||||
}),
|
||||
onSubmit: withBatchedUpdates(({ text, viaKeyboard }) => {
|
||||
onSubmit: withBatchedUpdates((text) => {
|
||||
const isDeleted = !text.trim();
|
||||
updateElement(text, isDeleted);
|
||||
// select the created text element only if submitting via keyboard
|
||||
// (when submitting via click it should act as signal to deselect)
|
||||
if (!isDeleted && viaKeyboard) {
|
||||
if (!isDeleted) {
|
||||
this.setState((prevState) => ({
|
||||
selectedElementIds: {
|
||||
...prevState.selectedElementIds,
|
||||
@@ -1667,7 +1601,7 @@ class App extends React.Component<ExcalidrawProps, AppState> {
|
||||
editingElement: null,
|
||||
});
|
||||
if (this.state.elementLocked) {
|
||||
setCursorForShape(this.canvas, this.state.elementType);
|
||||
setCursorForShape(this.state.elementType);
|
||||
}
|
||||
}),
|
||||
element,
|
||||
@@ -1848,7 +1782,7 @@ class App extends React.Component<ExcalidrawProps, AppState> {
|
||||
return;
|
||||
}
|
||||
|
||||
resetCursor(this.canvas);
|
||||
resetCursor();
|
||||
|
||||
const { x: sceneX, y: sceneY } = viewportCoordsToSceneCoords(
|
||||
event,
|
||||
@@ -1880,7 +1814,7 @@ class App extends React.Component<ExcalidrawProps, AppState> {
|
||||
}
|
||||
}
|
||||
|
||||
resetCursor(this.canvas);
|
||||
resetCursor();
|
||||
|
||||
if (!event[KEYS.CTRL_OR_CMD]) {
|
||||
this.startTextEditing({
|
||||
@@ -1946,9 +1880,9 @@ class App extends React.Component<ExcalidrawProps, AppState> {
|
||||
const isOverScrollBar = isPointerOverScrollBars.isOverEither;
|
||||
if (!this.state.draggingElement && !this.state.multiElement) {
|
||||
if (isOverScrollBar) {
|
||||
resetCursor(this.canvas);
|
||||
resetCursor();
|
||||
} else {
|
||||
setCursorForShape(this.canvas, this.state.elementType);
|
||||
setCursorForShape(this.state.elementType);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1999,7 +1933,7 @@ class App extends React.Component<ExcalidrawProps, AppState> {
|
||||
const { points, lastCommittedPoint } = multiElement;
|
||||
const lastPoint = points[points.length - 1];
|
||||
|
||||
setCursorForShape(this.canvas, this.state.elementType);
|
||||
setCursorForShape(this.state.elementType);
|
||||
|
||||
if (lastPoint === lastCommittedPoint) {
|
||||
// if we haven't yet created a temp point and we're beyond commit-zone
|
||||
@@ -2016,7 +1950,7 @@ class App extends React.Component<ExcalidrawProps, AppState> {
|
||||
points: [...points, [scenePointerX - rx, scenePointerY - ry]],
|
||||
});
|
||||
} else {
|
||||
setCursor(this.canvas, CURSOR_TYPE.POINTER);
|
||||
document.documentElement.style.cursor = CURSOR_TYPE.POINTER;
|
||||
// in this branch, we're inside the commit zone, and no uncommitted
|
||||
// point exists. Thus do nothing (don't add/remove points).
|
||||
}
|
||||
@@ -2030,13 +1964,13 @@ class App extends React.Component<ExcalidrawProps, AppState> {
|
||||
lastCommittedPoint[1],
|
||||
) < LINE_CONFIRM_THRESHOLD
|
||||
) {
|
||||
setCursor(this.canvas, CURSOR_TYPE.POINTER);
|
||||
document.documentElement.style.cursor = CURSOR_TYPE.POINTER;
|
||||
mutateElement(multiElement, {
|
||||
points: points.slice(0, -1),
|
||||
});
|
||||
} else {
|
||||
if (isPathALoop(points, this.state.zoom.value)) {
|
||||
setCursor(this.canvas, CURSOR_TYPE.POINTER);
|
||||
document.documentElement.style.cursor = CURSOR_TYPE.POINTER;
|
||||
}
|
||||
// update last uncommitted point
|
||||
mutateElement(multiElement, {
|
||||
@@ -2079,9 +2013,8 @@ class App extends React.Component<ExcalidrawProps, AppState> {
|
||||
elementWithTransformHandleType &&
|
||||
elementWithTransformHandleType.transformHandleType
|
||||
) {
|
||||
setCursor(
|
||||
this.canvas,
|
||||
getCursorForResizingElement(elementWithTransformHandleType),
|
||||
document.documentElement.style.cursor = getCursorForResizingElement(
|
||||
elementWithTransformHandleType,
|
||||
);
|
||||
return;
|
||||
}
|
||||
@@ -2094,12 +2027,9 @@ class App extends React.Component<ExcalidrawProps, AppState> {
|
||||
event.pointerType,
|
||||
);
|
||||
if (transformHandleType) {
|
||||
setCursor(
|
||||
this.canvas,
|
||||
getCursorForResizingElement({
|
||||
transformHandleType,
|
||||
}),
|
||||
);
|
||||
document.documentElement.style.cursor = getCursorForResizingElement({
|
||||
transformHandleType,
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -2109,12 +2039,11 @@ class App extends React.Component<ExcalidrawProps, AppState> {
|
||||
scenePointer.y,
|
||||
);
|
||||
if (this.state.elementType === "text") {
|
||||
setCursor(
|
||||
this.canvas,
|
||||
isTextElement(hitElement) ? CURSOR_TYPE.TEXT : CURSOR_TYPE.CROSSHAIR,
|
||||
);
|
||||
document.documentElement.style.cursor = isTextElement(hitElement)
|
||||
? CURSOR_TYPE.TEXT
|
||||
: CURSOR_TYPE.CROSSHAIR;
|
||||
} else if (isOverScrollBar) {
|
||||
setCursor(this.canvas, CURSOR_TYPE.AUTO);
|
||||
document.documentElement.style.cursor = CURSOR_TYPE.AUTO;
|
||||
} else if (
|
||||
hitElement ||
|
||||
this.isHittingCommonBoundingBoxOfSelectedElements(
|
||||
@@ -2122,9 +2051,9 @@ class App extends React.Component<ExcalidrawProps, AppState> {
|
||||
selectedElements,
|
||||
)
|
||||
) {
|
||||
setCursor(this.canvas, CURSOR_TYPE.MOVE);
|
||||
document.documentElement.style.cursor = CURSOR_TYPE.MOVE;
|
||||
} else {
|
||||
setCursor(this.canvas, CURSOR_TYPE.AUTO);
|
||||
document.documentElement.style.cursor = CURSOR_TYPE.AUTO;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -2138,14 +2067,6 @@ class App extends React.Component<ExcalidrawProps, AppState> {
|
||||
) => {
|
||||
event.persist();
|
||||
|
||||
// remove any active selection when we start to interact with canvas
|
||||
// (mainly, we care about removing selection outside the component which
|
||||
// would prevent our copy handling otherwise)
|
||||
const selection = document.getSelection();
|
||||
if (selection?.anchorNode) {
|
||||
selection.removeAllRanges();
|
||||
}
|
||||
|
||||
this.maybeOpenContextMenuAfterPointerDownOnTouchDevices(event);
|
||||
this.maybeCleanupAfterMissingPointerUp(event);
|
||||
|
||||
@@ -2173,6 +2094,15 @@ class App extends React.Component<ExcalidrawProps, AppState> {
|
||||
|
||||
this.updateGestureOnPointerDown(event);
|
||||
|
||||
// fixes pointermove causing selection of UI texts #32
|
||||
event.preventDefault();
|
||||
// Preventing the event above disables default behavior
|
||||
// of defocusing potentially focused element, which is what we
|
||||
// want when clicking inside the canvas.
|
||||
if (document.activeElement instanceof HTMLElement) {
|
||||
document.activeElement.blur();
|
||||
}
|
||||
|
||||
// don't select while panning
|
||||
if (gesture.pointers.size > 1) {
|
||||
return;
|
||||
@@ -2296,7 +2226,7 @@ class App extends React.Component<ExcalidrawProps, AppState> {
|
||||
let nextPastePrevented = false;
|
||||
const isLinux = /Linux/.test(window.navigator.platform);
|
||||
|
||||
setCursor(this.canvas, CURSOR_TYPE.GRABBING);
|
||||
document.documentElement.style.cursor = CURSOR_TYPE.GRABBING;
|
||||
let { clientX: lastX, clientY: lastY } = event;
|
||||
const onPointerMove = withBatchedUpdates((event: PointerEvent) => {
|
||||
const deltaX = lastX - event.clientX;
|
||||
@@ -2348,7 +2278,7 @@ class App extends React.Component<ExcalidrawProps, AppState> {
|
||||
lastPointerUp = null;
|
||||
isPanning = false;
|
||||
if (!isHoldingSpace) {
|
||||
setCursorForShape(this.canvas, this.state.elementType);
|
||||
setCursorForShape(this.state.elementType);
|
||||
}
|
||||
this.setState({
|
||||
cursorButton: "up",
|
||||
@@ -2464,7 +2394,7 @@ class App extends React.Component<ExcalidrawProps, AppState> {
|
||||
|
||||
const onPointerUp = withBatchedUpdates(() => {
|
||||
isDraggingScrollBar = false;
|
||||
setCursorForShape(this.canvas, this.state.elementType);
|
||||
setCursorForShape(this.state.elementType);
|
||||
lastPointerUp = null;
|
||||
this.setState({
|
||||
cursorButton: "up",
|
||||
@@ -2527,12 +2457,9 @@ class App extends React.Component<ExcalidrawProps, AppState> {
|
||||
);
|
||||
}
|
||||
if (pointerDownState.resize.handleType) {
|
||||
setCursor(
|
||||
this.canvas,
|
||||
getCursorForResizingElement({
|
||||
transformHandleType: pointerDownState.resize.handleType,
|
||||
}),
|
||||
);
|
||||
document.documentElement.style.cursor = getCursorForResizingElement({
|
||||
transformHandleType: pointerDownState.resize.handleType,
|
||||
});
|
||||
pointerDownState.resize.isResizing = true;
|
||||
pointerDownState.resize.offset = tupleToCoors(
|
||||
getResizeOffsetXY(
|
||||
@@ -2697,7 +2624,7 @@ class App extends React.Component<ExcalidrawProps, AppState> {
|
||||
insertAtParentCenter: !event.altKey,
|
||||
});
|
||||
|
||||
resetCursor(this.canvas);
|
||||
resetCursor();
|
||||
if (!this.state.elementLocked) {
|
||||
this.setState({
|
||||
elementType: "selection",
|
||||
@@ -2754,7 +2681,7 @@ class App extends React.Component<ExcalidrawProps, AppState> {
|
||||
mutateElement(multiElement, {
|
||||
lastCommittedPoint: multiElement.points[multiElement.points.length - 1],
|
||||
});
|
||||
setCursor(this.canvas, CURSOR_TYPE.POINTER);
|
||||
document.documentElement.style.cursor = CURSOR_TYPE.POINTER;
|
||||
} else {
|
||||
const [gridX, gridY] = getGridPoint(
|
||||
pointerDownState.origin.x,
|
||||
@@ -3289,7 +3216,7 @@ class App extends React.Component<ExcalidrawProps, AppState> {
|
||||
}
|
||||
this.setState({ suggestedBindings: [], startBoundElement: null });
|
||||
if (!elementLocked && elementType !== "draw") {
|
||||
resetCursor(this.canvas);
|
||||
resetCursor();
|
||||
this.setState((prevState) => ({
|
||||
draggingElement: null,
|
||||
elementType: "selection",
|
||||
@@ -3460,7 +3387,7 @@ class App extends React.Component<ExcalidrawProps, AppState> {
|
||||
}
|
||||
|
||||
if (!elementLocked && elementType !== "draw") {
|
||||
resetCursor(this.canvas);
|
||||
resetCursor();
|
||||
this.setState({
|
||||
draggingElement: null,
|
||||
suggestedBindings: [],
|
||||
@@ -3618,12 +3545,26 @@ class App extends React.Component<ExcalidrawProps, AppState> {
|
||||
// This will only work as of Chrome 86,
|
||||
// but can be safely ignored on older releases.
|
||||
const item = event.dataTransfer.items[0];
|
||||
// TODO: Make this part of `AppState`.
|
||||
(file as any).handle = await (item as any).getAsFileSystemHandle();
|
||||
} catch (error) {
|
||||
console.warn(error.name, error.message);
|
||||
}
|
||||
}
|
||||
this.loadFileToCanvas(file);
|
||||
loadFromBlob(file, this.state)
|
||||
.then(({ elements, appState }) =>
|
||||
this.syncActionResult({
|
||||
elements,
|
||||
appState: {
|
||||
...(appState || this.state),
|
||||
isLoading: false,
|
||||
},
|
||||
commitToHistory: true,
|
||||
}),
|
||||
)
|
||||
.catch((error) => {
|
||||
this.setState({ isLoading: false, errorMessage: error.message });
|
||||
});
|
||||
} else if (
|
||||
file?.type === MIME_TYPES.excalidrawlib ||
|
||||
file?.name.endsWith(".excalidrawlib")
|
||||
@@ -3643,23 +3584,6 @@ class App extends React.Component<ExcalidrawProps, AppState> {
|
||||
}
|
||||
};
|
||||
|
||||
loadFileToCanvas = (file: Blob) => {
|
||||
loadFromBlob(file, this.state)
|
||||
.then(({ elements, appState }) =>
|
||||
this.syncActionResult({
|
||||
elements,
|
||||
appState: {
|
||||
...(appState || this.state),
|
||||
isLoading: false,
|
||||
},
|
||||
commitToHistory: true,
|
||||
}),
|
||||
)
|
||||
.catch((error) => {
|
||||
this.setState({ isLoading: false, errorMessage: error.message });
|
||||
});
|
||||
};
|
||||
|
||||
private handleCanvasContextMenu = (
|
||||
event: React.PointerEvent<HTMLCanvasElement>,
|
||||
) => {
|
||||
@@ -4040,22 +3964,33 @@ class App extends React.Component<ExcalidrawProps, AppState> {
|
||||
}
|
||||
}, 300);
|
||||
|
||||
public setCanvasOffsets = () => {
|
||||
this.setState({ ...this.getCanvasOffsets() });
|
||||
};
|
||||
|
||||
private getCanvasOffsets(): Pick<AppState, "offsetTop" | "offsetLeft"> {
|
||||
private getCanvasOffsets(offsets?: {
|
||||
offsetLeft?: number;
|
||||
offsetTop?: number;
|
||||
}): Pick<AppState, "offsetTop" | "offsetLeft"> {
|
||||
if (
|
||||
typeof offsets?.offsetLeft === "number" &&
|
||||
typeof offsets?.offsetTop === "number"
|
||||
) {
|
||||
return {
|
||||
offsetLeft: offsets.offsetLeft,
|
||||
offsetTop: offsets.offsetTop,
|
||||
};
|
||||
}
|
||||
if (this.excalidrawContainerRef?.current?.parentElement) {
|
||||
const parentElement = this.excalidrawContainerRef.current.parentElement;
|
||||
const { left, top } = parentElement.getBoundingClientRect();
|
||||
return {
|
||||
offsetLeft: left,
|
||||
offsetTop: top,
|
||||
offsetLeft:
|
||||
typeof offsets?.offsetLeft === "number" ? offsets.offsetLeft : left,
|
||||
offsetTop:
|
||||
typeof offsets?.offsetTop === "number" ? offsets.offsetTop : top,
|
||||
};
|
||||
}
|
||||
return {
|
||||
offsetLeft: 0,
|
||||
offsetTop: 0,
|
||||
offsetLeft:
|
||||
typeof offsets?.offsetLeft === "number" ? offsets.offsetLeft : 0,
|
||||
offsetTop: typeof offsets?.offsetTop === "number" ? offsets.offsetTop : 0,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -7,24 +7,20 @@ export const BackgroundPickerAndDarkModeToggle = ({
|
||||
appState,
|
||||
setAppState,
|
||||
actionManager,
|
||||
showThemeBtn,
|
||||
}: {
|
||||
actionManager: ActionManager;
|
||||
appState: AppState;
|
||||
setAppState: React.Component<any, AppState>["setState"];
|
||||
showThemeBtn: boolean;
|
||||
}) => (
|
||||
<div style={{ display: "flex" }}>
|
||||
{actionManager.renderAction("changeViewBackgroundColor")}
|
||||
{showThemeBtn && (
|
||||
<div style={{ marginInlineStart: "0.25rem" }}>
|
||||
<DarkModeToggle
|
||||
value={appState.theme}
|
||||
onChange={(theme) => {
|
||||
setAppState({ theme });
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
<div style={{ marginInlineStart: "0.25rem" }}>
|
||||
<DarkModeToggle
|
||||
value={appState.appearance}
|
||||
onChange={(appearance) => {
|
||||
setAppState({ appearance });
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -73,7 +73,7 @@
|
||||
box-sizing: border-box;
|
||||
border: 1px solid #ddd;
|
||||
background-color: currentColor !important;
|
||||
filter: var(--theme-filter);
|
||||
filter: var(--appearance-filter);
|
||||
|
||||
&:focus {
|
||||
/* TODO: only show the border when the color is too light to see as a shadow */
|
||||
@@ -192,7 +192,7 @@
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
background-color: transparent !important;
|
||||
filter: var(--theme-filter);
|
||||
filter: var(--appearance-filter);
|
||||
|
||||
&:after {
|
||||
content: "";
|
||||
@@ -239,7 +239,7 @@
|
||||
color: #d4d4d4;
|
||||
}
|
||||
|
||||
&.theme--dark {
|
||||
&.Appearance_dark {
|
||||
.color-picker-type-elementBackground .color-picker-keybinding {
|
||||
color: $oc-black;
|
||||
}
|
||||
|
||||
@@ -34,11 +34,11 @@ const ContextMenu = ({
|
||||
}: ContextMenuProps) => {
|
||||
const isDarkTheme = !!document
|
||||
.querySelector(".excalidraw")
|
||||
?.classList.contains("theme--dark");
|
||||
?.classList.contains("Appearance_dark");
|
||||
return (
|
||||
<div
|
||||
className={clsx("excalidraw", {
|
||||
"theme--dark theme--dark-background-none": isDarkTheme,
|
||||
"Appearance_dark Appearance_dark-background-none": isDarkTheme,
|
||||
})}
|
||||
>
|
||||
<Popover
|
||||
|
||||
@@ -20,8 +20,7 @@ export const DarkModeToggle = (props: {
|
||||
|
||||
return (
|
||||
<label
|
||||
className="ToolIcon ToolIcon_type_floating ToolIcon_size_M"
|
||||
data-testid="toggle-dark-mode"
|
||||
className={`ToolIcon ToolIcon_type_floating ToolIcon_size_M`}
|
||||
title={title}
|
||||
>
|
||||
<input
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
max-height: 25rem;
|
||||
}
|
||||
|
||||
&.theme--dark .ExportDialog__preview canvas {
|
||||
&.Appearance_dark .ExportDialog__preview canvas {
|
||||
filter: none;
|
||||
}
|
||||
|
||||
@@ -34,14 +34,6 @@
|
||||
|
||||
.TextInput {
|
||||
height: calc(1rem - 3px);
|
||||
|
||||
&--readonly {
|
||||
background: none;
|
||||
border: none;
|
||||
&:hover {
|
||||
background: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -257,7 +257,6 @@ export const ExportDialog = ({
|
||||
onClick={() => {
|
||||
setModalIsShown(true);
|
||||
}}
|
||||
data-testid="export-button"
|
||||
icon={exportFile}
|
||||
type="button"
|
||||
aria-label={t("buttons.export")}
|
||||
|
||||
@@ -3,7 +3,7 @@ import React from "react";
|
||||
|
||||
// https://github.com/tholman/github-corners
|
||||
export const GitHubCorner = React.memo(
|
||||
({ theme }: { theme: "light" | "dark" }) => (
|
||||
({ appearance }: { appearance: "light" | "dark" }) => (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="40"
|
||||
@@ -19,18 +19,18 @@ export const GitHubCorner = React.memo(
|
||||
>
|
||||
<path
|
||||
d="M0 0l115 115h15l12 27 108 108V0z"
|
||||
fill={theme === "light" ? oc.gray[6] : oc.gray[8]}
|
||||
fill={appearance === "light" ? oc.gray[6] : oc.gray[8]}
|
||||
/>
|
||||
<path
|
||||
className="octo-arm"
|
||||
d="M128 109c-15-9-9-19-9-19 3-7 2-11 2-11-1-7 3-2 3-2 4 5 2 11 2 11-3 10 5 15 9 16"
|
||||
style={{ transformOrigin: "130px 106px" }}
|
||||
fill={theme === "light" ? oc.white : oc.black}
|
||||
fill={appearance === "light" ? oc.white : oc.black}
|
||||
/>
|
||||
<path
|
||||
className="octo-body"
|
||||
d="M115 115s4 2 5 0l14-14c3-2 6-3 8-3-8-11-15-24 2-41 5-5 10-7 16-7 1-2 3-7 12-11 0 0 5 3 7 16 4 2 8 5 12 9s7 8 9 12c14 3 17 7 17 7-4 8-9 11-11 11 0 6-2 11-7 16-16 16-30 10-41 2 0 3-1 7-5 11l-12 11c-1 1 1 5 1 5z"
|
||||
fill={theme === "light" ? oc.white : oc.black}
|
||||
fill={appearance === "light" ? oc.white : oc.black}
|
||||
/>
|
||||
</a>
|
||||
</svg>
|
||||
|
||||
@@ -132,7 +132,7 @@
|
||||
color: #d4d4d4;
|
||||
}
|
||||
|
||||
&.theme--dark {
|
||||
&.Appearance_dark {
|
||||
.picker-type-elementBackground .picker-keybinding {
|
||||
color: $oc-black;
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ import { Language, t } from "../i18n";
|
||||
import useIsMobile from "../is-mobile";
|
||||
import { calculateScrollCenter, getSelectedElements } from "../scene";
|
||||
import { ExportType } from "../scene/types";
|
||||
import { AppState, ExcalidrawProps, LibraryItem, LibraryItems } from "../types";
|
||||
import { AppState, LibraryItem, LibraryItems } from "../types";
|
||||
import { muteFSAbortError } from "../utils";
|
||||
import { SelectedShapeActions, ShapesSwitcher, ZoomActions } from "./Actions";
|
||||
import { BackgroundPickerAndDarkModeToggle } from "./BackgroundPickerAndDarkModeToggle";
|
||||
@@ -53,7 +53,6 @@ interface LayerUIProps {
|
||||
onInsertElements: (elements: readonly NonDeletedExcalidrawElement[]) => void;
|
||||
zenModeEnabled: boolean;
|
||||
showExitZenModeBtn: boolean;
|
||||
showThemeBtn: boolean;
|
||||
toggleZenMode: () => void;
|
||||
langCode: Language["code"];
|
||||
isCollaborating: boolean;
|
||||
@@ -64,7 +63,6 @@ interface LayerUIProps {
|
||||
) => void;
|
||||
renderCustomFooter?: (isMobile: boolean) => JSX.Element;
|
||||
viewModeEnabled: boolean;
|
||||
libraryReturnUrl: ExcalidrawProps["libraryReturnUrl"];
|
||||
}
|
||||
|
||||
const useOnClickOutside = (
|
||||
@@ -103,7 +101,6 @@ const LibraryMenuItems = ({
|
||||
pendingElements,
|
||||
setAppState,
|
||||
setLibraryItems,
|
||||
libraryReturnUrl,
|
||||
}: {
|
||||
library: LibraryItems;
|
||||
pendingElements: LibraryItem;
|
||||
@@ -112,7 +109,6 @@ const LibraryMenuItems = ({
|
||||
onAddToLibrary: (elements: LibraryItem) => void;
|
||||
setAppState: React.Component<any, AppState>["setState"];
|
||||
setLibraryItems: (library: LibraryItems) => void;
|
||||
libraryReturnUrl: ExcalidrawProps["libraryReturnUrl"];
|
||||
}) => {
|
||||
const isMobile = useIsMobile();
|
||||
const numCells = library.length + (pendingElements.length > 0 ? 1 : 0);
|
||||
@@ -121,8 +117,6 @@ const LibraryMenuItems = ({
|
||||
const rows = [];
|
||||
let addedPendingElements = false;
|
||||
|
||||
const referrer = libraryReturnUrl || window.location.origin;
|
||||
|
||||
rows.push(
|
||||
<div className="layer-ui__library-header">
|
||||
<ToolButton
|
||||
@@ -172,10 +166,7 @@ const LibraryMenuItems = ({
|
||||
}}
|
||||
/>
|
||||
|
||||
<a
|
||||
href={`https://libraries.excalidraw.com?referrer=${referrer}`}
|
||||
target="_excalidraw_libraries"
|
||||
>
|
||||
<a href="https://libraries.excalidraw.com" target="_excalidraw_libraries">
|
||||
{t("labels.libraries")}
|
||||
</a>
|
||||
</div>,
|
||||
@@ -228,14 +219,12 @@ const LibraryMenu = ({
|
||||
pendingElements,
|
||||
onAddToLibrary,
|
||||
setAppState,
|
||||
libraryReturnUrl,
|
||||
}: {
|
||||
pendingElements: LibraryItem;
|
||||
onClickOutside: (event: MouseEvent) => void;
|
||||
onInsertShape: (elements: LibraryItem) => void;
|
||||
onAddToLibrary: () => void;
|
||||
setAppState: React.Component<any, AppState>["setState"];
|
||||
libraryReturnUrl: ExcalidrawProps["libraryReturnUrl"];
|
||||
}) => {
|
||||
const ref = useRef<HTMLDivElement | null>(null);
|
||||
useOnClickOutside(ref, (event) => {
|
||||
@@ -308,7 +297,6 @@ const LibraryMenu = ({
|
||||
pendingElements={pendingElements}
|
||||
setAppState={setAppState}
|
||||
setLibraryItems={setLibraryItems}
|
||||
libraryReturnUrl={libraryReturnUrl}
|
||||
/>
|
||||
)}
|
||||
</Island>
|
||||
@@ -326,13 +314,11 @@ const LayerUI = ({
|
||||
onInsertElements,
|
||||
zenModeEnabled,
|
||||
showExitZenModeBtn,
|
||||
showThemeBtn,
|
||||
toggleZenMode,
|
||||
isCollaborating,
|
||||
onExportToBackend,
|
||||
renderCustomFooter,
|
||||
viewModeEnabled,
|
||||
libraryReturnUrl,
|
||||
}: LayerUIProps) => {
|
||||
const isMobile = useIsMobile();
|
||||
|
||||
@@ -443,7 +429,6 @@ const LayerUI = ({
|
||||
actionManager={actionManager}
|
||||
appState={appState}
|
||||
setAppState={setAppState}
|
||||
showThemeBtn={showThemeBtn}
|
||||
/>
|
||||
</Stack.Col>
|
||||
</Island>
|
||||
@@ -497,7 +482,6 @@ const LayerUI = ({
|
||||
onInsertShape={onInsertElements}
|
||||
onAddToLibrary={deselectItems}
|
||||
setAppState={setAppState}
|
||||
libraryReturnUrl={libraryReturnUrl}
|
||||
/>
|
||||
) : null;
|
||||
|
||||
@@ -532,7 +516,6 @@ const LayerUI = ({
|
||||
{heading}
|
||||
<Stack.Row gap={1}>
|
||||
<ShapesSwitcher
|
||||
canvas={canvas}
|
||||
elementType={appState.elementType}
|
||||
setAppState={setAppState}
|
||||
isLibraryOpen={appState.isLibraryOpen}
|
||||
@@ -606,7 +589,7 @@ const LayerUI = ({
|
||||
},
|
||||
)}
|
||||
>
|
||||
<GitHubCorner theme={appState.theme} />
|
||||
<GitHubCorner appearance={appState.appearance} />
|
||||
</aside>
|
||||
);
|
||||
};
|
||||
@@ -674,7 +657,6 @@ const LayerUI = ({
|
||||
isCollaborating={isCollaborating}
|
||||
renderCustomFooter={renderCustomFooter}
|
||||
viewModeEnabled={viewModeEnabled}
|
||||
showThemeBtn={showThemeBtn}
|
||||
/>
|
||||
</>
|
||||
) : (
|
||||
@@ -721,7 +703,6 @@ const areEqual = (prev: LayerUIProps, next: LayerUIProps) => {
|
||||
|
||||
const keys = Object.keys(prevAppState) as (keyof Partial<AppState>)[];
|
||||
return (
|
||||
prev.renderCustomFooter === next.renderCustomFooter &&
|
||||
prev.langCode === next.langCode &&
|
||||
prev.elements === next.elements &&
|
||||
keys.every((key) => prevAppState[key] === nextAppState[key])
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
}
|
||||
|
||||
.library-unit__dragger > svg {
|
||||
filter: var(--theme-filter);
|
||||
filter: var(--appearance-filter);
|
||||
flex-grow: 1;
|
||||
max-height: 100%;
|
||||
max-width: 100%;
|
||||
|
||||
@@ -30,7 +30,6 @@ type MobileMenuProps = {
|
||||
isCollaborating: boolean;
|
||||
renderCustomFooter?: (isMobile: boolean) => JSX.Element;
|
||||
viewModeEnabled: boolean;
|
||||
showThemeBtn: boolean;
|
||||
};
|
||||
|
||||
export const MobileMenu = ({
|
||||
@@ -46,7 +45,6 @@ export const MobileMenu = ({
|
||||
isCollaborating,
|
||||
renderCustomFooter,
|
||||
viewModeEnabled,
|
||||
showThemeBtn,
|
||||
}: MobileMenuProps) => {
|
||||
const renderToolbar = () => {
|
||||
return (
|
||||
@@ -59,7 +57,6 @@ export const MobileMenu = ({
|
||||
{heading}
|
||||
<Stack.Row gap={1}>
|
||||
<ShapesSwitcher
|
||||
canvas={canvas}
|
||||
elementType={appState.elementType}
|
||||
setAppState={setAppState}
|
||||
isLibraryOpen={appState.isLibraryOpen}
|
||||
@@ -132,7 +129,6 @@ export const MobileMenu = ({
|
||||
actionManager={actionManager}
|
||||
appState={appState}
|
||||
setAppState={setAppState}
|
||||
showThemeBtn={showThemeBtn}
|
||||
/>
|
||||
}
|
||||
</>
|
||||
|
||||
@@ -50,7 +50,6 @@
|
||||
border: 1px solid var(--dialog-border-color);
|
||||
box-shadow: 0 2px 10px transparentize($oc-black, 0.75);
|
||||
border-radius: 6px;
|
||||
box-sizing: border-box;
|
||||
|
||||
@media #{$is-mobile-query} {
|
||||
max-width: 100%;
|
||||
|
||||
@@ -51,14 +51,14 @@ const useBodyRoot = () => {
|
||||
useLayoutEffect(() => {
|
||||
const isDarkTheme = !!document
|
||||
.querySelector(".excalidraw")
|
||||
?.classList.contains("theme--dark");
|
||||
?.classList.contains("Appearance_dark");
|
||||
const div = document.createElement("div");
|
||||
|
||||
div.classList.add("excalidraw", "excalidraw-modal-container");
|
||||
|
||||
if (isDarkTheme) {
|
||||
div.classList.add("theme--dark");
|
||||
div.classList.add("theme--dark-background-none");
|
||||
div.classList.add("Appearance_dark");
|
||||
div.classList.add("Appearance_dark-background-none");
|
||||
}
|
||||
document.body.appendChild(div);
|
||||
|
||||
|
||||
@@ -7,7 +7,6 @@ type Props = {
|
||||
value: string;
|
||||
onChange: (value: string) => void;
|
||||
label: string;
|
||||
isNameEditable: boolean;
|
||||
};
|
||||
|
||||
export class ProjectName extends Component<Props> {
|
||||
@@ -44,7 +43,7 @@ export class ProjectName extends Component<Props> {
|
||||
};
|
||||
|
||||
public render() {
|
||||
return this.props.isNameEditable ? (
|
||||
return (
|
||||
<span
|
||||
suppressContentEditableWarning
|
||||
ref={this.makeEditable}
|
||||
@@ -58,13 +57,6 @@ export class ProjectName extends Component<Props> {
|
||||
>
|
||||
{this.props.value}
|
||||
</span>
|
||||
) : (
|
||||
<span
|
||||
className="TextInput TextInput--readonly"
|
||||
aria-label={this.props.label}
|
||||
>
|
||||
{this.props.value}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
|
||||
.Toast__message {
|
||||
color: var(--popup-text-color);
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
|
||||
@keyframes fade-in {
|
||||
|
||||
@@ -58,7 +58,6 @@ export const ToolButton = React.forwardRef((props: ToolButtonProps, ref) => {
|
||||
"ToolIcon--selected": props.selected,
|
||||
},
|
||||
)}
|
||||
data-testid={props["data-testid"]}
|
||||
hidden={props.hidden}
|
||||
title={props.title}
|
||||
aria-label={props["aria-label"]}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import React from "react";
|
||||
import * as Sentry from "@sentry/browser";
|
||||
import { resetCursor } from "../utils";
|
||||
import { t } from "../i18n";
|
||||
|
||||
interface TopErrorBoundaryState {
|
||||
@@ -23,6 +24,7 @@ export class TopErrorBoundary extends React.Component<
|
||||
}
|
||||
|
||||
componentDidCatch(error: Error, errorInfo: any) {
|
||||
resetCursor();
|
||||
const _localStorage: any = {};
|
||||
for (const [key, value] of Object.entries({ ...localStorage })) {
|
||||
try {
|
||||
|
||||
+197
-182
@@ -11,12 +11,12 @@ import React from "react";
|
||||
import oc from "open-color";
|
||||
import clsx from "clsx";
|
||||
|
||||
const activeElementColor = (theme: "light" | "dark") =>
|
||||
theme === "light" ? oc.orange[4] : oc.orange[9];
|
||||
const iconFillColor = (theme: "light" | "dark") =>
|
||||
theme === "light" ? oc.black : oc.gray[4];
|
||||
const handlerColor = (theme: "light" | "dark") =>
|
||||
theme === "light" ? oc.white : "#1e1e1e";
|
||||
const activeElementColor = (appearance: "light" | "dark") =>
|
||||
appearance === "light" ? oc.orange[4] : oc.orange[9];
|
||||
const iconFillColor = (appearance: "light" | "dark") =>
|
||||
appearance === "light" ? oc.black : oc.gray[4];
|
||||
const handlerColor = (appearance: "light" | "dark") =>
|
||||
appearance === "light" ? oc.white : "#1e1e1e";
|
||||
|
||||
type Opts = {
|
||||
width?: number;
|
||||
@@ -113,16 +113,6 @@ export const questionCircle = createIcon(
|
||||
{ mirror: true },
|
||||
);
|
||||
|
||||
export const share = createIcon(
|
||||
"M18 16.08c-.76 0-1.44.3-1.96.77L8.91 12.7c.05-.23.09-.46.09-.7s-.04-.47-.09-.7l7.05-4.11c.54.5 1.25.81 2.04.81 1.66 0 3-1.34 3-3s-1.34-3-3-3-3 1.34-3 3c0 .24.04.47.09.7L8.04 9.81C7.5 9.31 6.79 9 6 9c-1.66 0-3 1.34-3 3s1.34 3 3 3c.79 0 1.5-.31 2.04-.81l7.12 4.16c-.05.21-.08.43-.08.65 0 1.61 1.31 2.92 2.92 2.92 1.61 0 2.92-1.31 2.92-2.92s-1.31-2.92-2.92-2.92z",
|
||||
{ width: 24, height: 24 },
|
||||
);
|
||||
|
||||
export const shareIOS = createIcon(
|
||||
"M16 5l-1.42 1.42-1.59-1.59V16h-1.98V4.83L9.42 6.42 8 5l4-4 4 4zm4 5v11c0 1.1-.9 2-2 2H6c-1.11 0-2-.9-2-2V10c0-1.11.89-2 2-2h3v2H6v11h12V10h-3V8h3c1.1 0 2 .89 2 2z",
|
||||
{ width: 24, height: 24 },
|
||||
);
|
||||
|
||||
// Icon imported form Storybook
|
||||
// Storybook is licensed under MIT https://github.com/storybookjs/storybook/blob/next/LICENSE
|
||||
export const resetZoom = createIcon(
|
||||
@@ -136,19 +126,19 @@ export const resetZoom = createIcon(
|
||||
);
|
||||
|
||||
export const BringForwardIcon = React.memo(
|
||||
({ theme }: { theme: "light" | "dark" }) =>
|
||||
({ appearance }: { appearance: "light" | "dark" }) =>
|
||||
createIcon(
|
||||
<>
|
||||
<path
|
||||
d="M22 9.556C22 8.696 21.303 8 20.444 8H16v8H8v4.444C8 21.304 8.697 22 9.556 22h10.888c.86 0 1.556-.697 1.556-1.556V9.556z"
|
||||
fill={iconFillColor(theme)}
|
||||
stroke={iconFillColor(theme)}
|
||||
fill={iconFillColor(appearance)}
|
||||
stroke={iconFillColor(appearance)}
|
||||
strokeWidth="2"
|
||||
/>
|
||||
<path
|
||||
d="M16 3.556C16 2.696 15.303 2 14.444 2H3.556C2.696 2 2 2.697 2 3.556v10.888C2 15.304 2.697 16 3.556 16h10.888c.86 0 1.556-.697 1.556-1.556V3.556z"
|
||||
fill={activeElementColor(theme)}
|
||||
stroke={activeElementColor(theme)}
|
||||
fill={activeElementColor(appearance)}
|
||||
stroke={activeElementColor(appearance)}
|
||||
strokeWidth="2"
|
||||
/>
|
||||
</>,
|
||||
@@ -157,19 +147,19 @@ export const BringForwardIcon = React.memo(
|
||||
);
|
||||
|
||||
export const SendBackwardIcon = React.memo(
|
||||
({ theme }: { theme: "light" | "dark" }) =>
|
||||
({ appearance }: { appearance: "light" | "dark" }) =>
|
||||
createIcon(
|
||||
<>
|
||||
<path
|
||||
d="M16 3.556C16 2.696 15.303 2 14.444 2H3.556C2.696 2 2 2.697 2 3.556v10.888C2 15.304 2.697 16 3.556 16h10.888c.86 0 1.556-.697 1.556-1.556V3.556z"
|
||||
fill={activeElementColor(theme)}
|
||||
stroke={activeElementColor(theme)}
|
||||
fill={activeElementColor(appearance)}
|
||||
stroke={activeElementColor(appearance)}
|
||||
strokeWidth="2"
|
||||
/>
|
||||
<path
|
||||
d="M22 9.556C22 8.696 21.303 8 20.444 8H9.556C8.696 8 8 8.697 8 9.556v10.888C8 21.304 8.697 22 9.556 22h10.888c.86 0 1.556-.697 1.556-1.556V9.556z"
|
||||
fill={iconFillColor(theme)}
|
||||
stroke={iconFillColor(theme)}
|
||||
fill={iconFillColor(appearance)}
|
||||
stroke={iconFillColor(appearance)}
|
||||
strokeWidth="2"
|
||||
/>
|
||||
</>,
|
||||
@@ -178,19 +168,19 @@ export const SendBackwardIcon = React.memo(
|
||||
);
|
||||
|
||||
export const BringToFrontIcon = React.memo(
|
||||
({ theme }: { theme: "light" | "dark" }) =>
|
||||
({ appearance }: { appearance: "light" | "dark" }) =>
|
||||
createIcon(
|
||||
<>
|
||||
<path
|
||||
d="M13 21a1 1 0 001 1h7a1 1 0 001-1v-7a1 1 0 00-1-1h-3v5h-5v3zM11 3a1 1 0 00-1-1H3a1 1 0 00-1 1v7a1 1 0 001 1h3V6h5V3z"
|
||||
fill={iconFillColor(theme)}
|
||||
stroke={iconFillColor(theme)}
|
||||
fill={iconFillColor(appearance)}
|
||||
stroke={iconFillColor(appearance)}
|
||||
strokeWidth="2"
|
||||
/>
|
||||
<path
|
||||
d="M18 7.333C18 6.597 17.403 6 16.667 6H7.333C6.597 6 6 6.597 6 7.333v9.334C6 17.403 6.597 18 7.333 18h9.334c.736 0 1.333-.597 1.333-1.333V7.333z"
|
||||
fill={activeElementColor(theme)}
|
||||
stroke={activeElementColor(theme)}
|
||||
fill={activeElementColor(appearance)}
|
||||
stroke={activeElementColor(appearance)}
|
||||
strokeWidth="2"
|
||||
/>
|
||||
</>,
|
||||
@@ -199,20 +189,20 @@ export const BringToFrontIcon = React.memo(
|
||||
);
|
||||
|
||||
export const SendToBackIcon = React.memo(
|
||||
({ theme }: { theme: "light" | "dark" }) =>
|
||||
({ appearance }: { appearance: "light" | "dark" }) =>
|
||||
createIcon(
|
||||
<>
|
||||
<path
|
||||
d="M18 7.333C18 6.597 17.403 6 16.667 6H7.333C6.597 6 6 6.597 6 7.333v9.334C6 17.403 6.597 18 7.333 18h9.334c.736 0 1.333-.597 1.333-1.333V7.333z"
|
||||
fill={activeElementColor(theme)}
|
||||
stroke={activeElementColor(theme)}
|
||||
fill={activeElementColor(appearance)}
|
||||
stroke={activeElementColor(appearance)}
|
||||
strokeLinejoin="round"
|
||||
strokeWidth="2"
|
||||
/>
|
||||
<path
|
||||
d="M11 3a1 1 0 00-1-1H3a1 1 0 00-1 1v7a1 1 0 001 1h8V3zM22 14a1 1 0 00-1-1h-7a1 1 0 00-1 1v7a1 1 0 001 1h8v-8z"
|
||||
fill={iconFillColor(theme)}
|
||||
stroke={iconFillColor(theme)}
|
||||
fill={iconFillColor(appearance)}
|
||||
stroke={iconFillColor(appearance)}
|
||||
strokeLinejoin="round"
|
||||
strokeWidth="2"
|
||||
/>
|
||||
@@ -228,20 +218,20 @@ export const SendToBackIcon = React.memo(
|
||||
// that would make them lie about their function.
|
||||
//
|
||||
export const AlignTopIcon = React.memo(
|
||||
({ theme }: { theme: "light" | "dark" }) =>
|
||||
({ appearance }: { appearance: "light" | "dark" }) =>
|
||||
createIcon(
|
||||
<>
|
||||
<path
|
||||
d="M 2,5 H 22"
|
||||
fill={iconFillColor(theme)}
|
||||
stroke={iconFillColor(theme)}
|
||||
fill={iconFillColor(appearance)}
|
||||
stroke={iconFillColor(appearance)}
|
||||
strokeWidth="2"
|
||||
strokeLinecap="round"
|
||||
/>
|
||||
<path
|
||||
d="M 6,7 C 5.446,7 5,7.446 5,8 v 9.999992 c 0,0.554 0.446,1 1,1 h 3.0000001 c 0.554,0 0.9999999,-0.446 0.9999999,-1 V 8 C 10,7.446 9.5540001,7 9.0000001,7 Z m 9,0 c -0.554,0 -1,0.446 -1,1 v 5.999992 c 0,0.554 0.446,1 1,1 h 3 c 0.554,0 1,-0.446 1,-1 V 8 C 19,7.446 18.554,7 18,7 Z"
|
||||
fill={activeElementColor(theme)}
|
||||
stroke={activeElementColor(theme)}
|
||||
fill={activeElementColor(appearance)}
|
||||
stroke={activeElementColor(appearance)}
|
||||
strokeWidth="2"
|
||||
/>
|
||||
</>,
|
||||
@@ -250,20 +240,20 @@ export const AlignTopIcon = React.memo(
|
||||
);
|
||||
|
||||
export const AlignBottomIcon = React.memo(
|
||||
({ theme }: { theme: "light" | "dark" }) =>
|
||||
({ appearance }: { appearance: "light" | "dark" }) =>
|
||||
createIcon(
|
||||
<>
|
||||
<path
|
||||
d="M 2,19 H 22"
|
||||
fill={iconFillColor(theme)}
|
||||
stroke={iconFillColor(theme)}
|
||||
fill={iconFillColor(appearance)}
|
||||
stroke={iconFillColor(appearance)}
|
||||
strokeWidth="2"
|
||||
strokeLinecap="round"
|
||||
/>
|
||||
<path
|
||||
d="m 6,16.999992 c -0.554,0 -1,-0.446 -1,-1 V 6 C 5,5.446 5.446,5 6,5 H 9.0000001 C 9.5540001,5 10,5.446 10,6 v 9.999992 c 0,0.554 -0.4459999,1 -0.9999999,1 z m 9,0 c -0.554,0 -1,-0.446 -1,-1 V 10 c 0,-0.554 0.446,-1 1,-1 h 3 c 0.554,0 1,0.446 1,1 v 5.999992 c 0,0.554 -0.446,1 -1,1 z"
|
||||
fill={activeElementColor(theme)}
|
||||
stroke={activeElementColor(theme)}
|
||||
fill={activeElementColor(appearance)}
|
||||
stroke={activeElementColor(appearance)}
|
||||
strokeWidth="2"
|
||||
/>
|
||||
</>,
|
||||
@@ -272,20 +262,20 @@ export const AlignBottomIcon = React.memo(
|
||||
);
|
||||
|
||||
export const AlignLeftIcon = React.memo(
|
||||
({ theme }: { theme: "light" | "dark" }) =>
|
||||
({ appearance }: { appearance: "light" | "dark" }) =>
|
||||
createIcon(
|
||||
<>
|
||||
<path
|
||||
d="M 5,2 V 22"
|
||||
fill={iconFillColor(theme)}
|
||||
stroke={iconFillColor(theme)}
|
||||
fill={iconFillColor(appearance)}
|
||||
stroke={iconFillColor(appearance)}
|
||||
strokeWidth="2"
|
||||
strokeLinecap="round"
|
||||
/>
|
||||
<path
|
||||
d="m 7.000004,5.999996 c 0,-0.554 0.446,-1 1,-1 h 9.999992 c 0.554,0 1,0.446 1,1 v 3.0000001 c 0,0.554 -0.446,0.9999999 -1,0.9999999 H 8.000004 c -0.554,0 -1,-0.4459999 -1,-0.9999999 z m 0,9 c 0,-0.554 0.446,-1 1,-1 h 5.999992 c 0.554,0 1,0.446 1,1 v 3 c 0,0.554 -0.446,1 -1,1 H 8.000004 c -0.554,0 -1,-0.446 -1,-1 z"
|
||||
fill={activeElementColor(theme)}
|
||||
stroke={activeElementColor(theme)}
|
||||
fill={activeElementColor(appearance)}
|
||||
stroke={activeElementColor(appearance)}
|
||||
strokeWidth="2"
|
||||
/>
|
||||
</>,
|
||||
@@ -294,20 +284,20 @@ export const AlignLeftIcon = React.memo(
|
||||
);
|
||||
|
||||
export const AlignRightIcon = React.memo(
|
||||
({ theme }: { theme: "light" | "dark" }) =>
|
||||
({ appearance }: { appearance: "light" | "dark" }) =>
|
||||
createIcon(
|
||||
<>
|
||||
<path
|
||||
d="M 19,2 V 22"
|
||||
fill={iconFillColor(theme)}
|
||||
stroke={iconFillColor(theme)}
|
||||
fill={iconFillColor(appearance)}
|
||||
stroke={iconFillColor(appearance)}
|
||||
strokeWidth="2"
|
||||
strokeLinecap="round"
|
||||
/>
|
||||
<path
|
||||
d="m 16.999996,5.999996 c 0,-0.554 -0.446,-1 -1,-1 H 6.000004 c -0.554,0 -1,0.446 -1,1 v 3.0000001 c 0,0.554 0.446,0.9999999 1,0.9999999 h 9.999992 c 0.554,0 1,-0.4459999 1,-0.9999999 z m 0,9 c 0,-0.554 -0.446,-1 -1,-1 h -5.999992 c -0.554,0 -1,0.446 -1,1 v 3 c 0,0.554 0.446,1 1,1 h 5.999992 c 0.554,0 1,-0.446 1,-1 z"
|
||||
fill={activeElementColor(theme)}
|
||||
stroke={activeElementColor(theme)}
|
||||
fill={activeElementColor(appearance)}
|
||||
stroke={activeElementColor(appearance)}
|
||||
strokeWidth="2"
|
||||
/>
|
||||
</>,
|
||||
@@ -316,20 +306,20 @@ export const AlignRightIcon = React.memo(
|
||||
);
|
||||
|
||||
export const DistributeHorizontallyIcon = React.memo(
|
||||
({ theme }: { theme: "light" | "dark" }) =>
|
||||
({ appearance }: { appearance: "light" | "dark" }) =>
|
||||
createIcon(
|
||||
<>
|
||||
<path d="M5 5V19Z" fill="black" />
|
||||
<path
|
||||
d="M19 5V19M5 5V19"
|
||||
stroke={iconFillColor(theme)}
|
||||
stroke={iconFillColor(appearance)}
|
||||
strokeWidth="2"
|
||||
strokeLinecap="round"
|
||||
/>
|
||||
<path
|
||||
d="M15 9C15.554 9 16 9.446 16 10V14C16 14.554 15.554 15 15 15H9C8.446 15 8 14.554 8 14V10C8 9.446 8.446 9 9 9H15Z"
|
||||
fill={activeElementColor(theme)}
|
||||
stroke={activeElementColor(theme)}
|
||||
fill={activeElementColor(appearance)}
|
||||
stroke={activeElementColor(appearance)}
|
||||
strokeWidth="2"
|
||||
/>
|
||||
</>,
|
||||
@@ -346,20 +336,20 @@ export const DistributeHorizontallyIcon = React.memo(
|
||||
></svg>;
|
||||
|
||||
export const DistributeVerticallyIcon = React.memo(
|
||||
({ theme }: { theme: "light" | "dark" }) =>
|
||||
({ appearance }: { appearance: "light" | "dark" }) =>
|
||||
createIcon(
|
||||
<>
|
||||
<path
|
||||
d="M5 5L19 5M5 19H19"
|
||||
fill={iconFillColor(theme)}
|
||||
stroke={iconFillColor(theme)}
|
||||
fill={iconFillColor(appearance)}
|
||||
stroke={iconFillColor(appearance)}
|
||||
strokeWidth="2"
|
||||
strokeLinecap="round"
|
||||
/>
|
||||
<path
|
||||
d="M15 9C15.554 9 16 9.446 16 10V14C16 14.554 15.554 15 15 15H9C8.446 15 8 14.554 8 14V10C8 9.446 8.446 9 9 9H15Z"
|
||||
fill={activeElementColor(theme)}
|
||||
stroke={activeElementColor(theme)}
|
||||
fill={activeElementColor(appearance)}
|
||||
stroke={activeElementColor(appearance)}
|
||||
strokeWidth="2"
|
||||
/>
|
||||
</>,
|
||||
@@ -368,19 +358,19 @@ export const DistributeVerticallyIcon = React.memo(
|
||||
);
|
||||
|
||||
export const CenterVerticallyIcon = React.memo(
|
||||
({ theme }: { theme: "light" | "dark" }) =>
|
||||
({ appearance }: { appearance: "light" | "dark" }) =>
|
||||
createIcon(
|
||||
<>
|
||||
<path
|
||||
d="m 5.000004,16.999996 c 0,0.554 0.446,1 1,1 h 3 c 0.554,0 1,-0.446 1,-1 v -10 c 0,-0.554 -0.446,-1 -1,-1 h -3 c -0.554,0 -1,0.446 -1,1 z m 9,-2 c 0,0.554 0.446,1 1,1 h 3 c 0.554,0 1,-0.446 1,-1 v -6 c 0,-0.554 -0.446,-1 -1,-1 h -3 c -0.554,0 -1,0.446 -1,1 z"
|
||||
fill={activeElementColor(theme)}
|
||||
stroke={activeElementColor(theme)}
|
||||
fill={activeElementColor(appearance)}
|
||||
stroke={activeElementColor(appearance)}
|
||||
strokeWidth="2"
|
||||
/>
|
||||
<path
|
||||
d="M 2,12 H 22"
|
||||
fill={iconFillColor(theme)}
|
||||
stroke={iconFillColor(theme)}
|
||||
fill={iconFillColor(appearance)}
|
||||
stroke={iconFillColor(appearance)}
|
||||
strokeWidth="2"
|
||||
strokeDasharray="1, 2.8"
|
||||
strokeLinecap="round"
|
||||
@@ -391,19 +381,19 @@ export const CenterVerticallyIcon = React.memo(
|
||||
);
|
||||
|
||||
export const CenterHorizontallyIcon = React.memo(
|
||||
({ theme }: { theme: "light" | "dark" }) =>
|
||||
({ appearance }: { appearance: "light" | "dark" }) =>
|
||||
createIcon(
|
||||
<>
|
||||
<path
|
||||
d="M 7 5 C 6.446 5 6 5.446 6 6 L 6 9 C 6 9.554 6.446 10 7 10 L 17 10 C 17.554 10 18 9.554 18 9 L 18 6 C 18 5.446 17.554 5 17 5 L 7 5 z M 9 14 C 8.446 14 8 14.446 8 15 L 8 18 C 8 18.554 8.446 19 9 19 L 15 19 C 15.554 19 16 18.554 16 18 L 16 15 C 16 14.446 15.554 14 15 14 L 9 14 z "
|
||||
fill={activeElementColor(theme)}
|
||||
stroke={activeElementColor(theme)}
|
||||
fill={activeElementColor(appearance)}
|
||||
stroke={activeElementColor(appearance)}
|
||||
strokeWidth="2"
|
||||
/>
|
||||
<path
|
||||
d="M 12,2 V 22"
|
||||
fill={iconFillColor(theme)}
|
||||
stroke={iconFillColor(theme)}
|
||||
fill={iconFillColor(appearance)}
|
||||
stroke={iconFillColor(appearance)}
|
||||
strokeWidth="2"
|
||||
strokeDasharray="1, 2.8"
|
||||
strokeLinecap="round"
|
||||
@@ -448,76 +438,20 @@ export const shield = createIcon(
|
||||
{ width: 24 },
|
||||
);
|
||||
|
||||
export const GroupIcon = React.memo(({ theme }: { theme: "light" | "dark" }) =>
|
||||
createIcon(
|
||||
<>
|
||||
<path d="M25 26H111V111H25" fill={iconFillColor(theme)} />
|
||||
<path
|
||||
d="M25 111C25 80.2068 25 49.4135 25 26M25 26C48.6174 26 72.2348 26 111 26H25ZM25 26C53.3671 26 81.7343 26 111 26H25ZM111 26C111 52.303 111 78.606 111 111V26ZM111 26C111 51.2947 111 76.5893 111 111V26ZM111 111C87.0792 111 63.1585 111 25 111H111ZM111 111C87.4646 111 63.9293 111 25 111H111ZM25 111C25 81.1514 25 51.3028 25 26V111Z"
|
||||
stroke={iconFillColor(theme)}
|
||||
strokeWidth="2"
|
||||
/>
|
||||
<path d="M100 100H160V160H100" fill={iconFillColor(theme)} />
|
||||
<path
|
||||
d="M100 160C100 144.106 100 128.211 100 100M100 100C117.706 100 135.412 100 160 100H100ZM100 100C114.214 100 128.428 100 160 100H100ZM160 100C160 120.184 160 140.369 160 160V100ZM160 100C160 113.219 160 126.437 160 160V100ZM160 160C145.534 160 131.068 160 100 160H160ZM160 160C143.467 160 126.934 160 100 160H160ZM100 160C100 143.661 100 127.321 100 100V160Z"
|
||||
stroke={iconFillColor(theme)}
|
||||
strokeWidth="2"
|
||||
/>
|
||||
<rect
|
||||
x="2.5"
|
||||
y="2.5"
|
||||
width="30"
|
||||
height="30"
|
||||
fill={handlerColor(theme)}
|
||||
stroke={iconFillColor(theme)}
|
||||
strokeWidth="6"
|
||||
/>
|
||||
<rect
|
||||
x="2.5"
|
||||
y="149.5"
|
||||
width="30"
|
||||
height="30"
|
||||
fill={handlerColor(theme)}
|
||||
stroke={iconFillColor(theme)}
|
||||
strokeWidth="6"
|
||||
/>
|
||||
<rect
|
||||
x="147.5"
|
||||
y="149.5"
|
||||
width="30"
|
||||
height="30"
|
||||
fill={handlerColor(theme)}
|
||||
stroke={iconFillColor(theme)}
|
||||
strokeWidth="6"
|
||||
/>
|
||||
<rect
|
||||
x="147.5"
|
||||
y="2.5"
|
||||
width="30"
|
||||
height="30"
|
||||
fill={handlerColor(theme)}
|
||||
stroke={iconFillColor(theme)}
|
||||
strokeWidth="6"
|
||||
/>
|
||||
</>,
|
||||
{ width: 182, height: 182, mirror: true },
|
||||
),
|
||||
);
|
||||
|
||||
export const UngroupIcon = React.memo(
|
||||
({ theme }: { theme: "light" | "dark" }) =>
|
||||
export const GroupIcon = React.memo(
|
||||
({ appearance }: { appearance: "light" | "dark" }) =>
|
||||
createIcon(
|
||||
<>
|
||||
<path d="M25 26H111V111H25" fill={iconFillColor(theme)} />
|
||||
<path d="M25 26H111V111H25" fill={iconFillColor(appearance)} />
|
||||
<path
|
||||
d="M25 111C25 80.2068 25 49.4135 25 26M25 26C48.6174 26 72.2348 26 111 26H25ZM25 26C53.3671 26 81.7343 26 111 26H25ZM111 26C111 52.303 111 78.606 111 111V26ZM111 26C111 51.2947 111 76.5893 111 111V26ZM111 111C87.0792 111 63.1585 111 25 111H111ZM111 111C87.4646 111 63.9293 111 25 111H111ZM25 111C25 81.1514 25 51.3028 25 26V111Z"
|
||||
stroke={iconFillColor(theme)}
|
||||
stroke={iconFillColor(appearance)}
|
||||
strokeWidth="2"
|
||||
/>
|
||||
<path d="M100 100H160V160H100" fill={iconFillColor(theme)} />
|
||||
<path d="M100 100H160V160H100" fill={iconFillColor(appearance)} />
|
||||
<path
|
||||
d="M100 160C100 144.106 100 128.211 100 100M100 100C117.706 100 135.412 100 160 100H100ZM100 100C114.214 100 128.428 100 160 100H100ZM160 100C160 120.184 160 140.369 160 160V100ZM160 100C160 113.219 160 126.437 160 160V100ZM160 160C145.534 160 131.068 160 100 160H160ZM160 160C143.467 160 126.934 160 100 160H160ZM100 160C100 143.661 100 127.321 100 100V160Z"
|
||||
stroke={iconFillColor(theme)}
|
||||
stroke={iconFillColor(appearance)}
|
||||
strokeWidth="2"
|
||||
/>
|
||||
<rect
|
||||
@@ -525,8 +459,65 @@ export const UngroupIcon = React.memo(
|
||||
y="2.5"
|
||||
width="30"
|
||||
height="30"
|
||||
fill={handlerColor(theme)}
|
||||
stroke={iconFillColor(theme)}
|
||||
fill={handlerColor(appearance)}
|
||||
stroke={iconFillColor(appearance)}
|
||||
strokeWidth="6"
|
||||
/>
|
||||
<rect
|
||||
x="2.5"
|
||||
y="149.5"
|
||||
width="30"
|
||||
height="30"
|
||||
fill={handlerColor(appearance)}
|
||||
stroke={iconFillColor(appearance)}
|
||||
strokeWidth="6"
|
||||
/>
|
||||
<rect
|
||||
x="147.5"
|
||||
y="149.5"
|
||||
width="30"
|
||||
height="30"
|
||||
fill={handlerColor(appearance)}
|
||||
stroke={iconFillColor(appearance)}
|
||||
strokeWidth="6"
|
||||
/>
|
||||
<rect
|
||||
x="147.5"
|
||||
y="2.5"
|
||||
width="30"
|
||||
height="30"
|
||||
fill={handlerColor(appearance)}
|
||||
stroke={iconFillColor(appearance)}
|
||||
strokeWidth="6"
|
||||
/>
|
||||
</>,
|
||||
{ width: 182, height: 182, mirror: true },
|
||||
),
|
||||
);
|
||||
|
||||
export const UngroupIcon = React.memo(
|
||||
({ appearance }: { appearance: "light" | "dark" }) =>
|
||||
createIcon(
|
||||
<>
|
||||
<path d="M25 26H111V111H25" fill={iconFillColor(appearance)} />
|
||||
<path
|
||||
d="M25 111C25 80.2068 25 49.4135 25 26M25 26C48.6174 26 72.2348 26 111 26H25ZM25 26C53.3671 26 81.7343 26 111 26H25ZM111 26C111 52.303 111 78.606 111 111V26ZM111 26C111 51.2947 111 76.5893 111 111V26ZM111 111C87.0792 111 63.1585 111 25 111H111ZM111 111C87.4646 111 63.9293 111 25 111H111ZM25 111C25 81.1514 25 51.3028 25 26V111Z"
|
||||
stroke={iconFillColor(appearance)}
|
||||
strokeWidth="2"
|
||||
/>
|
||||
<path d="M100 100H160V160H100" fill={iconFillColor(appearance)} />
|
||||
<path
|
||||
d="M100 160C100 144.106 100 128.211 100 100M100 100C117.706 100 135.412 100 160 100H100ZM100 100C114.214 100 128.428 100 160 100H100ZM160 100C160 120.184 160 140.369 160 160V100ZM160 100C160 113.219 160 126.437 160 160V100ZM160 160C145.534 160 131.068 160 100 160H160ZM160 160C143.467 160 126.934 160 100 160H160ZM100 160C100 143.661 100 127.321 100 100V160Z"
|
||||
stroke={iconFillColor(appearance)}
|
||||
strokeWidth="2"
|
||||
/>
|
||||
<rect
|
||||
x="2.5"
|
||||
y="2.5"
|
||||
width="30"
|
||||
height="30"
|
||||
fill={handlerColor(appearance)}
|
||||
stroke={iconFillColor(appearance)}
|
||||
strokeWidth="6"
|
||||
/>
|
||||
<rect
|
||||
@@ -534,8 +525,8 @@ export const UngroupIcon = React.memo(
|
||||
y="149.5"
|
||||
width="30"
|
||||
height="30"
|
||||
fill={handlerColor(theme)}
|
||||
stroke={iconFillColor(theme)}
|
||||
fill={handlerColor(appearance)}
|
||||
stroke={iconFillColor(appearance)}
|
||||
strokeWidth="6"
|
||||
/>
|
||||
<rect
|
||||
@@ -543,8 +534,8 @@ export const UngroupIcon = React.memo(
|
||||
y="149.5"
|
||||
width="30"
|
||||
height="30"
|
||||
fill={handlerColor(theme)}
|
||||
stroke={iconFillColor(theme)}
|
||||
fill={handlerColor(appearance)}
|
||||
stroke={iconFillColor(appearance)}
|
||||
strokeWidth="6"
|
||||
/>
|
||||
<rect
|
||||
@@ -552,8 +543,8 @@ export const UngroupIcon = React.memo(
|
||||
y="78.5"
|
||||
width="30"
|
||||
height="30"
|
||||
fill={handlerColor(theme)}
|
||||
stroke={iconFillColor(theme)}
|
||||
fill={handlerColor(appearance)}
|
||||
stroke={iconFillColor(appearance)}
|
||||
strokeWidth="6"
|
||||
/>
|
||||
<rect
|
||||
@@ -561,8 +552,8 @@ export const UngroupIcon = React.memo(
|
||||
y="2.5"
|
||||
width="30"
|
||||
height="30"
|
||||
fill={handlerColor(theme)}
|
||||
stroke={iconFillColor(theme)}
|
||||
fill={handlerColor(appearance)}
|
||||
stroke={iconFillColor(appearance)}
|
||||
strokeWidth="6"
|
||||
/>
|
||||
<rect
|
||||
@@ -570,8 +561,8 @@ export const UngroupIcon = React.memo(
|
||||
y="102.5"
|
||||
width="30"
|
||||
height="30"
|
||||
fill={handlerColor(theme)}
|
||||
stroke={iconFillColor(theme)}
|
||||
fill={handlerColor(appearance)}
|
||||
stroke={iconFillColor(appearance)}
|
||||
strokeWidth="6"
|
||||
/>
|
||||
</>,
|
||||
@@ -580,22 +571,22 @@ export const UngroupIcon = React.memo(
|
||||
);
|
||||
|
||||
export const FillHachureIcon = React.memo(
|
||||
({ theme }: { theme: "light" | "dark" }) =>
|
||||
({ appearance }: { appearance: "light" | "dark" }) =>
|
||||
createIcon(
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
clipRule="evenodd"
|
||||
d="M20.101 16H28.0934L36 8.95989V4H33.5779L20.101 16ZM30.5704 4L17.0935 16H9.10101L22.5779 4H30.5704ZM19.5704 4L6.09349 16H4V10.7475L11.5779 4H19.5704ZM8.57036 4H4V8.06952L8.57036 4ZM36 11.6378L31.101 16H36V11.6378ZM2 2V18H38V2H2Z"
|
||||
fill={iconFillColor(theme)}
|
||||
fill={iconFillColor(appearance)}
|
||||
/>,
|
||||
{ width: 40, height: 20 },
|
||||
),
|
||||
);
|
||||
|
||||
export const FillCrossHatchIcon = React.memo(
|
||||
({ theme }: { theme: "light" | "dark" }) =>
|
||||
({ appearance }: { appearance: "light" | "dark" }) =>
|
||||
createIcon(
|
||||
<g fill={iconFillColor(theme)} fillRule="evenodd" clipRule="evenodd">
|
||||
<g fill={iconFillColor(appearance)} fillRule="evenodd" clipRule="evenodd">
|
||||
<path d="M20.101 16H28.0934L36 8.95989V4H33.5779L20.101 16ZM30.5704 4L17.0935 16H9.10101L22.5779 4H30.5704ZM19.5704 4L6.09349 16H4V10.7475L11.5779 4H19.5704ZM8.57036 4H4V8.06952L8.57036 4ZM36 11.6378L31.101 16H36V11.6378ZM2 2V18H38V2H2Z" />
|
||||
<path d="M14.0001 18L3.00006 4.00002L4.5727 2.76438L15.5727 16.7644L14.0001 18ZM25.0001 18L14.0001 4.00002L15.5727 2.76438L26.5727 16.7644L25.0001 18ZM36.0001 18L25.0001 4.00002L26.5727 2.76438L37.5727 16.7644L36.0001 18Z" />
|
||||
</g>,
|
||||
@@ -604,19 +595,25 @@ export const FillCrossHatchIcon = React.memo(
|
||||
);
|
||||
|
||||
export const FillSolidIcon = React.memo(
|
||||
({ theme }: { theme: "light" | "dark" }) =>
|
||||
createIcon(<path d="M2 2H38V18H2V2Z" fill={iconFillColor(theme)} />, {
|
||||
({ appearance }: { appearance: "light" | "dark" }) =>
|
||||
createIcon(<path d="M2 2H38V18H2V2Z" fill={iconFillColor(appearance)} />, {
|
||||
width: 40,
|
||||
height: 20,
|
||||
}),
|
||||
);
|
||||
|
||||
export const StrokeWidthIcon = React.memo(
|
||||
({ theme, strokeWidth }: { theme: "light" | "dark"; strokeWidth: number }) =>
|
||||
({
|
||||
appearance,
|
||||
strokeWidth,
|
||||
}: {
|
||||
appearance: "light" | "dark";
|
||||
strokeWidth: number;
|
||||
}) =>
|
||||
createIcon(
|
||||
<path
|
||||
d="M6 10H34"
|
||||
stroke={iconFillColor(theme)}
|
||||
stroke={iconFillColor(appearance)}
|
||||
strokeWidth={strokeWidth}
|
||||
fill="none"
|
||||
/>,
|
||||
@@ -625,11 +622,11 @@ export const StrokeWidthIcon = React.memo(
|
||||
);
|
||||
|
||||
export const StrokeStyleSolidIcon = React.memo(
|
||||
({ theme }: { theme: "light" | "dark" }) =>
|
||||
({ appearance }: { appearance: "light" | "dark" }) =>
|
||||
createIcon(
|
||||
<path
|
||||
d="M6 10H34"
|
||||
stroke={iconFillColor(theme)}
|
||||
stroke={iconFillColor(appearance)}
|
||||
strokeWidth={2}
|
||||
fill="none"
|
||||
/>,
|
||||
@@ -641,11 +638,11 @@ export const StrokeStyleSolidIcon = React.memo(
|
||||
);
|
||||
|
||||
export const StrokeStyleDashedIcon = React.memo(
|
||||
({ theme }: { theme: "light" | "dark" }) =>
|
||||
({ appearance }: { appearance: "light" | "dark" }) =>
|
||||
createIcon(
|
||||
<path
|
||||
d="M6 10H34"
|
||||
stroke={iconFillColor(theme)}
|
||||
stroke={iconFillColor(appearance)}
|
||||
strokeWidth={2.5}
|
||||
strokeDasharray={"10, 8"}
|
||||
fill="none"
|
||||
@@ -655,11 +652,11 @@ export const StrokeStyleDashedIcon = React.memo(
|
||||
);
|
||||
|
||||
export const StrokeStyleDottedIcon = React.memo(
|
||||
({ theme }: { theme: "light" | "dark" }) =>
|
||||
({ appearance }: { appearance: "light" | "dark" }) =>
|
||||
createIcon(
|
||||
<path
|
||||
d="M6 10H34"
|
||||
stroke={iconFillColor(theme)}
|
||||
stroke={iconFillColor(appearance)}
|
||||
strokeWidth={2.5}
|
||||
strokeDasharray={"4, 4"}
|
||||
fill="none"
|
||||
@@ -669,11 +666,11 @@ export const StrokeStyleDottedIcon = React.memo(
|
||||
);
|
||||
|
||||
export const SloppinessArchitectIcon = React.memo(
|
||||
({ theme }: { theme: "light" | "dark" }) =>
|
||||
({ appearance }: { appearance: "light" | "dark" }) =>
|
||||
createIcon(
|
||||
<path
|
||||
d="M3.00098 16.1691C6.28774 13.9744 19.6399 2.8905 22.7215 3.00082C25.8041 3.11113 19.1158 15.5488 21.4962 16.8309C23.8757 18.1131 34.4155 11.7148 37.0001 10.6919"
|
||||
stroke={iconFillColor(theme)}
|
||||
stroke={iconFillColor(appearance)}
|
||||
strokeWidth={2}
|
||||
fill="none"
|
||||
/>,
|
||||
@@ -682,11 +679,11 @@ export const SloppinessArchitectIcon = React.memo(
|
||||
);
|
||||
|
||||
export const SloppinessArtistIcon = React.memo(
|
||||
({ theme }: { theme: "light" | "dark" }) =>
|
||||
({ appearance }: { appearance: "light" | "dark" }) =>
|
||||
createIcon(
|
||||
<path
|
||||
d="M3 17C6.68158 14.8752 16.1296 9.09849 22.0648 6.54922C28 3.99995 22.2896 13.3209 25 14C27.7104 14.6791 36.3757 9.6471 36.3757 9.6471M6.40706 15C13 11.1918 20.0468 1.51045 23.0234 3.0052C26 4.49995 20.457 12.8659 22.7285 16.4329C25 20 36.3757 13 36.3757 13"
|
||||
stroke={iconFillColor(theme)}
|
||||
stroke={iconFillColor(appearance)}
|
||||
strokeWidth={2}
|
||||
fill="none"
|
||||
/>,
|
||||
@@ -695,11 +692,11 @@ export const SloppinessArtistIcon = React.memo(
|
||||
);
|
||||
|
||||
export const SloppinessCartoonistIcon = React.memo(
|
||||
({ theme }: { theme: "light" | "dark" }) =>
|
||||
({ appearance }: { appearance: "light" | "dark" }) =>
|
||||
createIcon(
|
||||
<path
|
||||
d="M3 15.6468C6.93692 13.5378 22.5544 2.81528 26.6206 3.00242C30.6877 3.18956 25.6708 15.3346 27.4009 16.7705C29.1309 18.2055 35.4001 12.4762 37 11.6177M3.97143 10.4917C6.61158 9.24563 16.3706 2.61886 19.8104 3.01724C23.2522 3.41472 22.0773 12.2013 24.6181 12.8783C27.1598 13.5536 33.3179 8.04068 35.0571 7.07244"
|
||||
stroke={iconFillColor(theme)}
|
||||
stroke={iconFillColor(appearance)}
|
||||
strokeWidth={2}
|
||||
fill="none"
|
||||
/>,
|
||||
@@ -708,11 +705,11 @@ export const SloppinessCartoonistIcon = React.memo(
|
||||
);
|
||||
|
||||
export const EdgeSharpIcon = React.memo(
|
||||
({ theme }: { theme: "light" | "dark" }) =>
|
||||
({ appearance }: { appearance: "light" | "dark" }) =>
|
||||
createIcon(
|
||||
<path
|
||||
d="M10 17L10 5L35 5"
|
||||
stroke={iconFillColor(theme)}
|
||||
stroke={iconFillColor(appearance)}
|
||||
strokeWidth={2}
|
||||
fill="none"
|
||||
/>,
|
||||
@@ -721,11 +718,11 @@ export const EdgeSharpIcon = React.memo(
|
||||
);
|
||||
|
||||
export const EdgeRoundIcon = React.memo(
|
||||
({ theme }: { theme: "light" | "dark" }) =>
|
||||
({ appearance }: { appearance: "light" | "dark" }) =>
|
||||
createIcon(
|
||||
<path
|
||||
d="M10 17V15C10 8 13 5 21 5L33.5 5"
|
||||
stroke={iconFillColor(theme)}
|
||||
stroke={iconFillColor(appearance)}
|
||||
strokeWidth={2}
|
||||
fill="none"
|
||||
/>,
|
||||
@@ -734,11 +731,11 @@ export const EdgeRoundIcon = React.memo(
|
||||
);
|
||||
|
||||
export const ArrowheadNoneIcon = React.memo(
|
||||
({ theme }: { theme: "light" | "dark" }) =>
|
||||
({ appearance }: { appearance: "light" | "dark" }) =>
|
||||
createIcon(
|
||||
<path
|
||||
d="M6 10H34"
|
||||
stroke={iconFillColor(theme)}
|
||||
stroke={iconFillColor(appearance)}
|
||||
strokeWidth={2}
|
||||
fill="none"
|
||||
/>,
|
||||
@@ -750,11 +747,17 @@ export const ArrowheadNoneIcon = React.memo(
|
||||
);
|
||||
|
||||
export const ArrowheadArrowIcon = React.memo(
|
||||
({ theme, flip = false }: { theme: "light" | "dark"; flip?: boolean }) =>
|
||||
({
|
||||
appearance,
|
||||
flip = false,
|
||||
}: {
|
||||
appearance: "light" | "dark";
|
||||
flip?: boolean;
|
||||
}) =>
|
||||
createIcon(
|
||||
<g
|
||||
transform={flip ? "translate(40, 0) scale(-1, 1)" : ""}
|
||||
stroke={iconFillColor(theme)}
|
||||
stroke={iconFillColor(appearance)}
|
||||
strokeWidth={2}
|
||||
fill="none"
|
||||
>
|
||||
@@ -766,11 +769,17 @@ export const ArrowheadArrowIcon = React.memo(
|
||||
);
|
||||
|
||||
export const ArrowheadDotIcon = React.memo(
|
||||
({ theme, flip = false }: { theme: "light" | "dark"; flip?: boolean }) =>
|
||||
({
|
||||
appearance,
|
||||
flip = false,
|
||||
}: {
|
||||
appearance: "light" | "dark";
|
||||
flip?: boolean;
|
||||
}) =>
|
||||
createIcon(
|
||||
<g
|
||||
stroke={iconFillColor(theme)}
|
||||
fill={iconFillColor(theme)}
|
||||
stroke={iconFillColor(appearance)}
|
||||
fill={iconFillColor(appearance)}
|
||||
transform={flip ? "translate(40, 0) scale(-1, 1)" : ""}
|
||||
>
|
||||
<path d="M32 10L6 10" strokeWidth={2} />
|
||||
@@ -781,12 +790,18 @@ export const ArrowheadDotIcon = React.memo(
|
||||
);
|
||||
|
||||
export const ArrowheadBarIcon = React.memo(
|
||||
({ theme, flip = false }: { theme: "light" | "dark"; flip?: boolean }) =>
|
||||
({
|
||||
appearance,
|
||||
flip = false,
|
||||
}: {
|
||||
appearance: "light" | "dark";
|
||||
flip?: boolean;
|
||||
}) =>
|
||||
createIcon(
|
||||
<g transform={flip ? "translate(40, 0) scale(-1, 1)" : ""}>
|
||||
<path
|
||||
d="M34 10H5.99996M34 10L34 5M34 10L34 15"
|
||||
stroke={iconFillColor(theme)}
|
||||
stroke={iconFillColor(appearance)}
|
||||
strokeWidth={2}
|
||||
fill="none"
|
||||
/>
|
||||
|
||||
+2
-2
@@ -94,7 +94,7 @@ export const TOUCH_CTX_MENU_TIMEOUT = 500;
|
||||
export const TITLE_TIMEOUT = 10000;
|
||||
export const TOAST_TIMEOUT = 5000;
|
||||
export const VERSION_TIMEOUT = 30000;
|
||||
export const SCROLL_TIMEOUT = 100;
|
||||
export const SCROLL_TIMEOUT = 500;
|
||||
|
||||
export const ZOOM_STEP = 0.1;
|
||||
|
||||
@@ -109,4 +109,4 @@ export const MODES = {
|
||||
GRID: "gridMode",
|
||||
};
|
||||
|
||||
export const THEME_FILTER = cssVariables.themeFilter;
|
||||
export const APPEARANCE_FILTER = cssVariables.appearanceFilter;
|
||||
|
||||
+3
-11
@@ -8,8 +8,6 @@
|
||||
}
|
||||
|
||||
.excalidraw {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
color: var(--text-primary-color);
|
||||
display: flex;
|
||||
top: 0;
|
||||
@@ -17,13 +15,6 @@
|
||||
left: 0;
|
||||
right: 0;
|
||||
|
||||
// serves 2 purposes:
|
||||
// 1. prevent selecting text outside the component when double-clicking or
|
||||
// dragging inside it (e.g. on canvas)
|
||||
// 2. prevent selecting UI, both from the inside, and from outside the
|
||||
// component (e.g. if you select text in a sidebar)
|
||||
user-select: none;
|
||||
|
||||
a {
|
||||
font-weight: 500;
|
||||
text-decoration: none;
|
||||
@@ -36,6 +27,7 @@
|
||||
|
||||
canvas {
|
||||
touch-action: none;
|
||||
user-select: none;
|
||||
|
||||
// following props improve blurriness at certain devicePixelRatios.
|
||||
// AFAIK it doesn't affect export (in fact, export seems sharp either way).
|
||||
@@ -47,13 +39,13 @@
|
||||
z-index: var(--zIndex-canvas);
|
||||
}
|
||||
|
||||
&.theme--dark {
|
||||
&.Appearance_dark {
|
||||
// The percentage is inspired by
|
||||
// https://material.io/design/color/dark-theme.html#properties, which
|
||||
// recommends surface color of #121212, 93% yields #111111 for #FFF
|
||||
|
||||
canvas {
|
||||
filter: var(--theme-filter);
|
||||
filter: var(--appearance-filter);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+8
-6
@@ -1,8 +1,8 @@
|
||||
@import "open-color/open-color.scss";
|
||||
@import "./variables.module.scss";
|
||||
|
||||
.excalidraw {
|
||||
--theme-filter: none;
|
||||
:root {
|
||||
--appearance-filter: none;
|
||||
--button-destructive-bg-color: #{$oc-red-1};
|
||||
--button-destructive-color: #{$oc-red-9};
|
||||
--button-gray-1: #{$oc-gray-2};
|
||||
@@ -34,17 +34,19 @@
|
||||
--shadow-island: 0 1px 5px #{transparentize($oc-black, 0.85)};
|
||||
--space-factor: 0.25rem;
|
||||
--text-primary-color: #{$oc-gray-8};
|
||||
}
|
||||
|
||||
&.theme--dark {
|
||||
.excalidraw {
|
||||
&.Appearance_dark {
|
||||
background: $oc-black;
|
||||
|
||||
&.theme--dark-background-none {
|
||||
&.Appearance_dark-background-none {
|
||||
background: none;
|
||||
}
|
||||
}
|
||||
|
||||
&.theme--dark {
|
||||
--theme-filter: #{$theme-filter};
|
||||
&.Appearance_dark {
|
||||
--appearance-filter: #{$appearance-filter};
|
||||
--button-destructive-bg-color: #5a0000;
|
||||
--button-destructive-color: #{$oc-red-3};
|
||||
--button-gray-1: #363636;
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
|
||||
// keep up to date with is-mobile.tsx
|
||||
$is-mobile-query: "(max-width: 600px), (max-height: 500px) and (max-width: 1000px)";
|
||||
$theme-filter: "invert(93%) hue-rotate(180deg)";
|
||||
$appearance-filter: "invert(93%) hue-rotate(180deg)";
|
||||
|
||||
:export {
|
||||
isMobileQuery: unquote($is-mobile-query);
|
||||
themeFilter: unquote($theme-filter);
|
||||
appearanceFilter: unquote($appearance-filter);
|
||||
}
|
||||
|
||||
+4
-5
@@ -5,9 +5,8 @@ import { CanvasError } from "../errors";
|
||||
import { t } from "../i18n";
|
||||
import { calculateScrollCenter } from "../scene";
|
||||
import { AppState } from "../types";
|
||||
import { isValidExcalidrawData } from "./json";
|
||||
import { restore } from "./restore";
|
||||
import { LibraryData } from "./types";
|
||||
import { ImportedDataState, LibraryData } from "./types";
|
||||
|
||||
const parseFileContents = async (blob: Blob | File) => {
|
||||
let contents: string;
|
||||
@@ -86,15 +85,15 @@ export const loadFromBlob = async (
|
||||
) => {
|
||||
const contents = await parseFileContents(blob);
|
||||
try {
|
||||
const data = JSON.parse(contents);
|
||||
if (!isValidExcalidrawData(data)) {
|
||||
const data: ImportedDataState = JSON.parse(contents);
|
||||
if (data.type !== "excalidraw") {
|
||||
throw new Error(t("alerts.couldNotLoadInvalidFile"));
|
||||
}
|
||||
const result = restore(
|
||||
{
|
||||
elements: clearElementsForExport(data.elements || []),
|
||||
appState: {
|
||||
theme: localAppState?.theme,
|
||||
appearance: localAppState?.appearance,
|
||||
fileHandle:
|
||||
blob.handle &&
|
||||
["application/json", MIME_TYPES.excalidraw].includes(
|
||||
|
||||
+4
-30
@@ -6,7 +6,6 @@ import { ExcalidrawElement } from "../element/types";
|
||||
import { AppState } from "../types";
|
||||
import { loadFromBlob } from "./blob";
|
||||
import { Library } from "./library";
|
||||
import { ImportedDataState } from "./types";
|
||||
|
||||
export const serializeAsJSON = (
|
||||
elements: readonly ExcalidrawElement[],
|
||||
@@ -30,13 +29,13 @@ export const saveAsJSON = async (
|
||||
) => {
|
||||
const serialized = serializeAsJSON(elements, appState);
|
||||
const blob = new Blob([serialized], {
|
||||
type: MIME_TYPES.excalidraw,
|
||||
type: "application/json",
|
||||
});
|
||||
|
||||
const fileHandle = await fileSave(
|
||||
blob,
|
||||
{
|
||||
fileName: `${appState.name}.excalidraw`,
|
||||
fileName: appState.name,
|
||||
description: "Excalidraw file",
|
||||
extensions: [".excalidraw"],
|
||||
},
|
||||
@@ -48,34 +47,12 @@ export const saveAsJSON = async (
|
||||
export const loadFromJSON = async (localAppState: AppState) => {
|
||||
const blob = await fileOpen({
|
||||
description: "Excalidraw files",
|
||||
// ToDo: Be over-permissive until https://bugs.webkit.org/show_bug.cgi?id=34442
|
||||
// gets resolved. Else, iOS users cannot open `.excalidraw` files.
|
||||
/*
|
||||
extensions: [".json", ".excalidraw", ".png", ".svg"],
|
||||
mimeTypes: [
|
||||
MIME_TYPES.excalidraw,
|
||||
"application/json",
|
||||
"image/png",
|
||||
"image/svg+xml",
|
||||
],
|
||||
*/
|
||||
mimeTypes: ["application/json", "image/png", "image/svg+xml"],
|
||||
});
|
||||
return loadFromBlob(blob, localAppState);
|
||||
};
|
||||
|
||||
export const isValidExcalidrawData = (data?: {
|
||||
type?: any;
|
||||
elements?: any;
|
||||
appState?: any;
|
||||
}): data is ImportedDataState => {
|
||||
return (
|
||||
data?.type === "excalidraw" &&
|
||||
(!data.elements ||
|
||||
(Array.isArray(data.elements) &&
|
||||
(!data.appState || typeof data.appState === "object")))
|
||||
);
|
||||
};
|
||||
|
||||
export const isValidLibrary = (json: any) => {
|
||||
return (
|
||||
typeof json === "object" &&
|
||||
@@ -110,11 +87,8 @@ export const saveLibraryAsJSON = async () => {
|
||||
export const importLibraryFromJSON = async () => {
|
||||
const blob = await fileOpen({
|
||||
description: "Excalidraw library files",
|
||||
// ToDo: Be over-permissive until https://bugs.webkit.org/show_bug.cgi?id=34442
|
||||
// gets resolved. Else, iOS users cannot open `.excalidraw` files.
|
||||
/*
|
||||
extensions: [".json", ".excalidrawlib"],
|
||||
*/
|
||||
mimeTypes: ["application/json"],
|
||||
});
|
||||
Library.importLibrary(blob);
|
||||
};
|
||||
|
||||
+1
-1
@@ -15,7 +15,7 @@ export interface ImportedDataState {
|
||||
source?: string;
|
||||
elements?: DataState["elements"] | null;
|
||||
appState?: Partial<DataState["appState"]> | null;
|
||||
scrollToContent?: boolean;
|
||||
scrollToCenter?: boolean;
|
||||
}
|
||||
|
||||
export interface LibraryData {
|
||||
|
||||
@@ -182,9 +182,9 @@ const bindLinearElement = (
|
||||
} as PointBinding,
|
||||
});
|
||||
mutateElement(hoveredElement, {
|
||||
boundElementIds: Array.from(
|
||||
new Set([...(hoveredElement.boundElementIds ?? []), linearElement.id]),
|
||||
),
|
||||
boundElementIds: [
|
||||
...new Set([...(hoveredElement.boundElementIds ?? []), linearElement.id]),
|
||||
],
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@ import {
|
||||
import { isLinearElement, isTextElement } from "./typeChecks";
|
||||
import { mutateElement } from "./mutateElement";
|
||||
import { getPerfectElementSize } from "./sizeHelpers";
|
||||
import { getCursorForResizingElement } from "./resizeTest";
|
||||
import { measureText, getFontString } from "../utils";
|
||||
import { updateBoundElements } from "./binding";
|
||||
import {
|
||||
@@ -104,6 +105,13 @@ export const transformElements = (
|
||||
);
|
||||
}
|
||||
|
||||
// update cursor
|
||||
// FIXME it is not very nice to have this here
|
||||
document.documentElement.style.cursor = getCursorForResizingElement({
|
||||
element,
|
||||
transformHandleType,
|
||||
});
|
||||
|
||||
return true;
|
||||
} else if (selectedElements.length > 1) {
|
||||
if (transformHandleType === "rotation") {
|
||||
|
||||
+16
-44
@@ -21,18 +21,14 @@ const getTransform = (
|
||||
height: number,
|
||||
angle: number,
|
||||
appState: AppState,
|
||||
maxWidth: number,
|
||||
) => {
|
||||
const { zoom, offsetTop, offsetLeft } = appState;
|
||||
const degree = (180 * angle) / Math.PI;
|
||||
// offsets must be multiplied by 2 to account for the division by 2 of
|
||||
// the whole expression afterwards
|
||||
let translateX = ((width - offsetLeft * 2) * (zoom.value - 1)) / 2;
|
||||
const translateY = ((height - offsetTop * 2) * (zoom.value - 1)) / 2;
|
||||
if (width > maxWidth && zoom.value !== 1) {
|
||||
translateX = (maxWidth / 2) * (zoom.value - 1);
|
||||
}
|
||||
return `translate(${translateX}px, ${translateY}px) scale(${zoom.value}) rotate(${degree}deg)`;
|
||||
return `translate(${((width - offsetLeft * 2) * (zoom.value - 1)) / 2}px, ${
|
||||
((height - offsetTop * 2) * (zoom.value - 1)) / 2
|
||||
}px) scale(${zoom.value}) rotate(${degree}deg)`;
|
||||
};
|
||||
|
||||
export const textWysiwyg = ({
|
||||
@@ -47,7 +43,7 @@ export const textWysiwyg = ({
|
||||
id: ExcalidrawElement["id"];
|
||||
appState: AppState;
|
||||
onChange?: (text: string) => void;
|
||||
onSubmit: (data: { text: string; viaKeyboard: boolean }) => void;
|
||||
onSubmit: (text: string) => void;
|
||||
getViewportCoords: (x: number, y: number) => [number, number];
|
||||
element: ExcalidrawElement;
|
||||
canvas: HTMLCanvasElement | null;
|
||||
@@ -65,15 +61,6 @@ export const textWysiwyg = ({
|
||||
|
||||
const lines = updatedElement.text.replace(/\r\n?/g, "\n").split("\n");
|
||||
const lineHeight = updatedElement.height / lines.length;
|
||||
const maxWidth =
|
||||
(appState.offsetLeft + appState.width - viewportX - 8) /
|
||||
appState.zoom.value -
|
||||
// margin-right of parent if any
|
||||
Number(
|
||||
getComputedStyle(
|
||||
document.querySelector(".excalidraw")!.parentNode as Element,
|
||||
).marginRight.slice(0, -2),
|
||||
);
|
||||
|
||||
Object.assign(editable.style, {
|
||||
font: getFontString(updatedElement),
|
||||
@@ -88,13 +75,11 @@ export const textWysiwyg = ({
|
||||
updatedElement.height,
|
||||
angle,
|
||||
appState,
|
||||
maxWidth,
|
||||
),
|
||||
textAlign,
|
||||
color: updatedElement.strokeColor,
|
||||
opacity: updatedElement.opacity / 100,
|
||||
filter: "var(--theme-filter)",
|
||||
maxWidth: `${maxWidth}px`,
|
||||
filter: "var(--appearance-filter)",
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -108,7 +93,7 @@ export const textWysiwyg = ({
|
||||
editable.wrap = "off";
|
||||
|
||||
Object.assign(editable.style, {
|
||||
position: "absolute",
|
||||
position: "fixed",
|
||||
display: "inline-block",
|
||||
minHeight: "1em",
|
||||
backfaceVisibility: "hidden",
|
||||
@@ -136,14 +121,12 @@ export const textWysiwyg = ({
|
||||
editable.onkeydown = (event) => {
|
||||
if (event.key === KEYS.ESCAPE) {
|
||||
event.preventDefault();
|
||||
submittedViaKeyboard = true;
|
||||
handleSubmit();
|
||||
} else if (event.key === KEYS.ENTER && event[KEYS.CTRL_OR_CMD]) {
|
||||
event.preventDefault();
|
||||
if (event.isComposing || event.keyCode === 229) {
|
||||
return;
|
||||
}
|
||||
submittedViaKeyboard = true;
|
||||
handleSubmit();
|
||||
} else if (event.key === KEYS.ENTER && !event.altKey) {
|
||||
event.stopPropagation();
|
||||
@@ -155,14 +138,8 @@ export const textWysiwyg = ({
|
||||
event.stopPropagation();
|
||||
};
|
||||
|
||||
// using a state variable instead of passing it to the handleSubmit callback
|
||||
// so that we don't need to create separate a callback for event handlers
|
||||
let submittedViaKeyboard = false;
|
||||
const handleSubmit = () => {
|
||||
onSubmit({
|
||||
text: normalizeText(editable.value),
|
||||
viaKeyboard: submittedViaKeyboard,
|
||||
});
|
||||
onSubmit(normalizeText(editable.value));
|
||||
cleanup();
|
||||
};
|
||||
|
||||
@@ -183,7 +160,7 @@ export const textWysiwyg = ({
|
||||
window.removeEventListener("resize", updateWysiwygStyle);
|
||||
window.removeEventListener("wheel", stopEvent, true);
|
||||
window.removeEventListener("pointerdown", onPointerDown);
|
||||
window.removeEventListener("pointerup", bindBlurEvent);
|
||||
window.removeEventListener("pointerup", rebindBlur);
|
||||
window.removeEventListener("blur", handleSubmit);
|
||||
|
||||
unbindUpdate();
|
||||
@@ -191,12 +168,10 @@ export const textWysiwyg = ({
|
||||
editable.remove();
|
||||
};
|
||||
|
||||
const bindBlurEvent = () => {
|
||||
window.removeEventListener("pointerup", bindBlurEvent);
|
||||
// Deferred so that the pointerdown that initiates the wysiwyg doesn't
|
||||
// trigger the blur on ensuing pointerup.
|
||||
// Also to handle cases such as picking a color which would trigger a blur
|
||||
// in that same tick.
|
||||
const rebindBlur = () => {
|
||||
window.removeEventListener("pointerup", rebindBlur);
|
||||
// deferred to guard against focus traps on various UIs that steal focus
|
||||
// upon pointerUp
|
||||
setTimeout(() => {
|
||||
editable.onblur = handleSubmit;
|
||||
// case: clicking on the same property → no change → no update → no focus
|
||||
@@ -212,7 +187,7 @@ export const textWysiwyg = ({
|
||||
!isWritableElement(event.target)
|
||||
) {
|
||||
editable.onblur = null;
|
||||
window.addEventListener("pointerup", bindBlurEvent);
|
||||
window.addEventListener("pointerup", rebindBlur);
|
||||
// handle edge-case where pointerup doesn't fire e.g. due to user
|
||||
// alt-tabbing away
|
||||
window.addEventListener("blur", handleSubmit);
|
||||
@@ -225,14 +200,9 @@ export const textWysiwyg = ({
|
||||
editable.focus();
|
||||
});
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
let isDestroyed = false;
|
||||
|
||||
// select on init (focusing is done separately inside the bindBlurEvent()
|
||||
// because we need it to happen *after* the blur event from `pointerdown`)
|
||||
editable.select();
|
||||
bindBlurEvent();
|
||||
editable.onblur = handleSubmit;
|
||||
|
||||
// reposition wysiwyg in case of canvas is resized. Using ResizeObserver
|
||||
// is preferred so we catch changes from host, where window may not resize.
|
||||
@@ -254,4 +224,6 @@ export const textWysiwyg = ({
|
||||
document
|
||||
.querySelector(".excalidraw-textEditorContainer")!
|
||||
.appendChild(editable);
|
||||
editable.focus();
|
||||
editable.select();
|
||||
};
|
||||
|
||||
@@ -40,7 +40,6 @@ import { createInverseContext } from "../../createInverseContext";
|
||||
import { t } from "../../i18n";
|
||||
import { UserIdleState } from "./types";
|
||||
import { IDLE_THRESHOLD, ACTIVE_THRESHOLD } from "../../constants";
|
||||
import { trackEvent } from "../../analytics";
|
||||
|
||||
interface CollabState {
|
||||
modalIsShown: boolean;
|
||||
@@ -189,7 +188,6 @@ class CollabWrapper extends PureComponent<Props, CollabState> {
|
||||
};
|
||||
|
||||
openPortal = async () => {
|
||||
trackEvent("share", "room creation");
|
||||
return this.initializeSocketClient(null);
|
||||
};
|
||||
|
||||
@@ -198,7 +196,6 @@ class CollabWrapper extends PureComponent<Props, CollabState> {
|
||||
if (window.confirm(t("alerts.collabStopOverridePrompt"))) {
|
||||
window.history.pushState({}, APP_NAME, window.location.origin);
|
||||
this.destroySocketClient();
|
||||
trackEvent("share", "room closed");
|
||||
}
|
||||
};
|
||||
|
||||
@@ -259,7 +256,7 @@ class CollabWrapper extends PureComponent<Props, CollabState> {
|
||||
if (elements) {
|
||||
scenePromise.resolve({
|
||||
elements,
|
||||
scrollToContent: true,
|
||||
scrollToCenter: true,
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
@@ -313,7 +310,7 @@ class CollabWrapper extends PureComponent<Props, CollabState> {
|
||||
// noop if already resolved via init from firebase
|
||||
scenePromise.resolve({
|
||||
elements: reconciledElements,
|
||||
scrollToContent: true,
|
||||
scrollToCenter: true,
|
||||
});
|
||||
}
|
||||
break;
|
||||
@@ -454,7 +451,7 @@ class CollabWrapper extends PureComponent<Props, CollabState> {
|
||||
}: { init?: boolean; initFromSnapshot?: boolean } = {},
|
||||
) => {
|
||||
if (init || initFromSnapshot) {
|
||||
this.excalidrawAPI.setScrollToContent(elements);
|
||||
this.excalidrawAPI.setScrollToCenter(elements);
|
||||
}
|
||||
|
||||
this.excalidrawAPI.updateScene({
|
||||
|
||||
@@ -10,7 +10,6 @@ import { getSyncableElements } from "../../packages/excalidraw/index";
|
||||
import { ExcalidrawElement } from "../../element/types";
|
||||
import { BROADCAST, SCENE } from "../app_constants";
|
||||
import { UserIdleState } from "./types";
|
||||
import { trackEvent } from "../../analytics";
|
||||
|
||||
class Portal {
|
||||
collab: CollabWrapper;
|
||||
@@ -33,7 +32,6 @@ class Portal {
|
||||
this.socket.on("init-room", () => {
|
||||
if (this.socket) {
|
||||
this.socket.emit("join-room", this.roomId);
|
||||
trackEvent("share", "room joined");
|
||||
}
|
||||
});
|
||||
this.socket.on("new-user", async (_socketId: string) => {
|
||||
|
||||
@@ -1,17 +1,10 @@
|
||||
import React, { useRef } from "react";
|
||||
import { copyTextToSystemClipboard } from "../../clipboard";
|
||||
import { Dialog } from "../../components/Dialog";
|
||||
import {
|
||||
clipboard,
|
||||
start,
|
||||
stop,
|
||||
share,
|
||||
shareIOS,
|
||||
} from "../../components/icons";
|
||||
import { clipboard, start, stop } from "../../components/icons";
|
||||
import { ToolButton } from "../../components/ToolButton";
|
||||
import { t } from "../../i18n";
|
||||
import "./RoomDialog.scss";
|
||||
import Stack from "../../components/Stack";
|
||||
|
||||
const RoomDialog = ({
|
||||
handleClose,
|
||||
@@ -31,8 +24,6 @@ const RoomDialog = ({
|
||||
setErrorMessage: (message: string) => void;
|
||||
}) => {
|
||||
const roomLinkInput = useRef<HTMLInputElement>(null);
|
||||
const navigator = window.navigator as any;
|
||||
const isAppleBrowser = /Apple/.test(navigator.vendor);
|
||||
|
||||
const copyRoomLink = async () => {
|
||||
try {
|
||||
@@ -45,18 +36,6 @@ const RoomDialog = ({
|
||||
}
|
||||
};
|
||||
|
||||
const shareRoomLink = async () => {
|
||||
try {
|
||||
await navigator.share({
|
||||
title: t("roomDialog.shareTitle"),
|
||||
text: t("roomDialog.shareTitle"),
|
||||
url: activeRoomLink,
|
||||
});
|
||||
} catch (error) {
|
||||
// Just ignore.
|
||||
}
|
||||
};
|
||||
|
||||
const selectInput = (event: React.MouseEvent<HTMLInputElement>) => {
|
||||
if (event.target !== document.activeElement) {
|
||||
event.preventDefault();
|
||||
@@ -89,24 +68,13 @@ const RoomDialog = ({
|
||||
<p>{t("roomDialog.desc_inProgressIntro")}</p>
|
||||
<p>{t("roomDialog.desc_shareLink")}</p>
|
||||
<div className="RoomDialog-linkContainer">
|
||||
<Stack.Row gap={2}>
|
||||
{"share" in navigator ? (
|
||||
<ToolButton
|
||||
type="button"
|
||||
icon={isAppleBrowser ? shareIOS : share}
|
||||
title={t("labels.share")}
|
||||
aria-label={t("labels.share")}
|
||||
onClick={shareRoomLink}
|
||||
/>
|
||||
) : null}
|
||||
<ToolButton
|
||||
type="button"
|
||||
icon={clipboard}
|
||||
title={t("labels.copy")}
|
||||
aria-label={t("labels.copy")}
|
||||
onClick={copyRoomLink}
|
||||
/>
|
||||
</Stack.Row>
|
||||
<ToolButton
|
||||
type="button"
|
||||
icon={clipboard}
|
||||
title={t("labels.copy")}
|
||||
aria-label={t("labels.copy")}
|
||||
onClick={copyRoomLink}
|
||||
/>
|
||||
<input
|
||||
value={activeRoomLink}
|
||||
readOnly={true}
|
||||
|
||||
@@ -13,7 +13,6 @@ import { ExcalidrawImperativeAPI } from "../components/App";
|
||||
import { ErrorDialog } from "../components/ErrorDialog";
|
||||
import { TopErrorBoundary } from "../components/TopErrorBoundary";
|
||||
import { APP_NAME, EVENT, TITLE_TIMEOUT, VERSION_TIMEOUT } from "../constants";
|
||||
import { loadFromBlob } from "../data/blob";
|
||||
import { DataState, ImportedDataState } from "../data/types";
|
||||
import {
|
||||
ExcalidrawElement,
|
||||
@@ -70,21 +69,20 @@ const initializeScene = async (opts: {
|
||||
}): Promise<ImportedDataState | null> => {
|
||||
const searchParams = new URLSearchParams(window.location.search);
|
||||
const id = searchParams.get("id");
|
||||
const jsonBackendMatch = window.location.hash.match(
|
||||
const jsonMatch = window.location.hash.match(
|
||||
/^#json=([0-9]+),([a-zA-Z0-9_-]+)$/,
|
||||
);
|
||||
const externalUrlMatch = window.location.hash.match(/^#url=(.*)$/);
|
||||
|
||||
const initialData = importFromLocalStorage();
|
||||
|
||||
let scene: DataState & { scrollToContent?: boolean } = await loadScene(
|
||||
let scene: DataState & { scrollToCenter?: boolean } = await loadScene(
|
||||
null,
|
||||
null,
|
||||
initialData,
|
||||
);
|
||||
|
||||
let roomLinkData = getCollaborationLinkData(window.location.href);
|
||||
const isExternalScene = !!(id || jsonBackendMatch || roomLinkData);
|
||||
const isExternalScene = !!(id || jsonMatch || roomLinkData);
|
||||
if (isExternalScene) {
|
||||
if (
|
||||
// don't prompt if scene is empty
|
||||
@@ -97,14 +95,10 @@ const initializeScene = async (opts: {
|
||||
// Backwards compatibility with legacy url format
|
||||
if (id) {
|
||||
scene = await loadScene(id, null, initialData);
|
||||
} else if (jsonBackendMatch) {
|
||||
scene = await loadScene(
|
||||
jsonBackendMatch[1],
|
||||
jsonBackendMatch[2],
|
||||
initialData,
|
||||
);
|
||||
} else if (jsonMatch) {
|
||||
scene = await loadScene(jsonMatch[1], jsonMatch[2], initialData);
|
||||
}
|
||||
scene.scrollToContent = true;
|
||||
scene.scrollToCenter = true;
|
||||
if (!roomLinkData) {
|
||||
window.history.replaceState({}, APP_NAME, window.location.origin);
|
||||
}
|
||||
@@ -125,28 +119,7 @@ const initializeScene = async (opts: {
|
||||
roomLinkData = null;
|
||||
window.history.replaceState({}, APP_NAME, window.location.origin);
|
||||
}
|
||||
} else if (externalUrlMatch) {
|
||||
window.history.replaceState({}, APP_NAME, window.location.origin);
|
||||
|
||||
const url = externalUrlMatch[1];
|
||||
try {
|
||||
const request = await fetch(window.decodeURIComponent(url));
|
||||
const data = await loadFromBlob(await request.blob(), null);
|
||||
if (
|
||||
!scene.elements.length ||
|
||||
window.confirm(t("alerts.loadSceneOverridePrompt"))
|
||||
) {
|
||||
return data;
|
||||
}
|
||||
} catch (error) {
|
||||
return {
|
||||
appState: {
|
||||
errorMessage: t("alerts.invalidSceneUrl"),
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
if (roomLinkData) {
|
||||
return opts.collabAPI.initializeSocketClient(roomLinkData);
|
||||
} else if (scene) {
|
||||
|
||||
@@ -34,7 +34,6 @@ const allLanguages: Language[] = [
|
||||
{ code: "nb-NO", label: "Norsk bokmål" },
|
||||
{ code: "nl-NL", label: "Nederlands" },
|
||||
{ code: "nn-NO", label: "Norsk nynorsk" },
|
||||
{ code: "oc-FR", label: "Occitan" },
|
||||
{ code: "pa-IN", label: "ਪੰਜਾਬੀ" },
|
||||
{ code: "pl-PL", label: "Polski" },
|
||||
{ code: "pt-BR", label: "Português Brasileiro" },
|
||||
|
||||
+4
-10
@@ -68,7 +68,7 @@
|
||||
"layers": "الطبقات",
|
||||
"actions": "الإجراءات",
|
||||
"language": "اللغة",
|
||||
"liveCollaboration": "بدء المشاركة الحية",
|
||||
"liveCollaboration": "",
|
||||
"duplicateSelection": "تكرار",
|
||||
"untitled": "غير معنون",
|
||||
"name": "الاسم",
|
||||
@@ -92,9 +92,7 @@
|
||||
"centerHorizontally": "توسيط أفقي",
|
||||
"distributeHorizontally": "التوزيع الأفقي",
|
||||
"distributeVertically": "التوزيع عمودياً",
|
||||
"viewMode": "",
|
||||
"toggleExportColorScheme": "",
|
||||
"share": ""
|
||||
"viewMode": ""
|
||||
},
|
||||
"buttons": {
|
||||
"clearReset": "إعادة تعيين اللوحة",
|
||||
@@ -143,7 +141,6 @@
|
||||
"confirmAddLibrary": "هذا سيضيف {{numShapes}} شكل إلى مكتبتك. هل أنت متأكد؟",
|
||||
"imageDoesNotContainScene": "استيراد الصور غير مدعوم في الوقت الراهن.\n\nهل تريد استيراد مشهد؟ لا يبدو أن هذه الصورة تحتوي على أي بيانات مشهد. هل قمت بسماح هذا أثناء التصدير؟",
|
||||
"cannotRestoreFromImage": "تعذر استعادة المشهد من ملف الصورة",
|
||||
"invalidSceneUrl": "",
|
||||
"resetLibrary": ""
|
||||
},
|
||||
"toolBar": {
|
||||
@@ -200,8 +197,7 @@
|
||||
"button_stopSession": "إيقاف الجلسة",
|
||||
"desc_inProgressIntro": "تجري الآن المشاركة الحية.",
|
||||
"desc_shareLink": "شارك هذا الرابط مع أي شخص تريده أن يشاركك الجلسة:",
|
||||
"desc_exitSession": "إيقاف الجلسة سيؤدي إلى قطع الاتصال الخاص بك من الغرفة، ولكن ستتمكن من مواصلة العمل مع المشهد، محليا. لاحظ أن هذا لن يؤثر على الأشخاص الآخرين، و سيظلون قادرين على التعاون في إصدارهم.",
|
||||
"shareTitle": ""
|
||||
"desc_exitSession": "إيقاف الجلسة سيؤدي إلى قطع الاتصال الخاص بك من الغرفة، ولكن ستتمكن من مواصلة العمل مع المشهد، محليا. لاحظ أن هذا لن يؤثر على الأشخاص الآخرين، و سيظلون قادرين على التعاون في إصدارهم."
|
||||
},
|
||||
"errorDialog": {
|
||||
"title": "خطأ"
|
||||
@@ -250,8 +246,6 @@
|
||||
"copyToClipboard": "",
|
||||
"copyToClipboardAsPng": "",
|
||||
"fileSaved": "",
|
||||
"fileSavedToFilename": "",
|
||||
"canvas": "",
|
||||
"selection": ""
|
||||
"fileSavedToFilename": ""
|
||||
}
|
||||
}
|
||||
|
||||
+4
-10
@@ -92,9 +92,7 @@
|
||||
"centerHorizontally": "Центрирай хоризонтално",
|
||||
"distributeHorizontally": "Разпредели хоризонтално",
|
||||
"distributeVertically": "Разпредели вертикално",
|
||||
"viewMode": "Изглед",
|
||||
"toggleExportColorScheme": "",
|
||||
"share": ""
|
||||
"viewMode": "Изглед"
|
||||
},
|
||||
"buttons": {
|
||||
"clearReset": "Нулиране на платно",
|
||||
@@ -143,7 +141,6 @@
|
||||
"confirmAddLibrary": "Ще се добавят {{numShapes}} фигура(и) във вашата библиотека. Сигурни ли сте?",
|
||||
"imageDoesNotContainScene": "Импортирането на картинки не се поддържва в момента.\n\nИскате да импортнете сцена? Тази картинка не съдържа данни от сцена. Разрешили ли сте последното при експортирането?",
|
||||
"cannotRestoreFromImage": "Не може да бъде възстановена сцена от този файл",
|
||||
"invalidSceneUrl": "",
|
||||
"resetLibrary": ""
|
||||
},
|
||||
"toolBar": {
|
||||
@@ -200,8 +197,7 @@
|
||||
"button_stopSession": "Стоп на сесията",
|
||||
"desc_inProgressIntro": "Сесията за сътрудничество на живо е в ход.",
|
||||
"desc_shareLink": "Споделете тази връзка с всеки, с когото искате да си сътрудничите:",
|
||||
"desc_exitSession": "Спирането на сесията ще ви изключи от стаята, но ще можете да продължите да работите със сцената, локално. Имайте предвид, че това няма да засегне други хора и те все още ще могат да си сътрудничат с тяхната версия.",
|
||||
"shareTitle": ""
|
||||
"desc_exitSession": "Спирането на сесията ще ви изключи от стаята, но ще можете да продължите да работите със сцената, локално. Имайте предвид, че това няма да засегне други хора и те все още ще могат да си сътрудничат с тяхната версия."
|
||||
},
|
||||
"errorDialog": {
|
||||
"title": "Грешка"
|
||||
@@ -248,10 +244,8 @@
|
||||
"toast": {
|
||||
"copyStyles": "Копирани стилове.",
|
||||
"copyToClipboard": "Копирано в клипборда.",
|
||||
"copyToClipboardAsPng": "",
|
||||
"copyToClipboardAsPng": "Копирано в клипборда като PNG.",
|
||||
"fileSaved": "",
|
||||
"fileSavedToFilename": "",
|
||||
"canvas": "",
|
||||
"selection": ""
|
||||
"fileSavedToFilename": ""
|
||||
}
|
||||
}
|
||||
|
||||
+34
-40
@@ -68,7 +68,7 @@
|
||||
"layers": "Capes",
|
||||
"actions": "Accions",
|
||||
"language": "Llengua",
|
||||
"liveCollaboration": "Col·laboració en directe",
|
||||
"liveCollaboration": "",
|
||||
"duplicateSelection": "Duplicar",
|
||||
"untitled": "Sense títol",
|
||||
"name": "Nom",
|
||||
@@ -77,7 +77,7 @@
|
||||
"group": "Agrupar la selecció",
|
||||
"ungroup": "Desagrupar la selecció",
|
||||
"collaborators": "Col·laboradors",
|
||||
"showGrid": "Mostra la graella",
|
||||
"showGrid": "",
|
||||
"addToLibrary": "Afegir a la biblioteca",
|
||||
"removeFromLibrary": "Eliminar de la biblioteca",
|
||||
"libraryLoadingMessage": "Carregant la biblioteca…",
|
||||
@@ -92,9 +92,7 @@
|
||||
"centerHorizontally": "Centrar horitzontalment",
|
||||
"distributeHorizontally": "Distribuir horitzontalment",
|
||||
"distributeVertically": "Distribuir verticalment",
|
||||
"viewMode": "Mode de visualització",
|
||||
"toggleExportColorScheme": "Canvia l'esquema de colors de l'exportació",
|
||||
"share": "Compartir"
|
||||
"viewMode": ""
|
||||
},
|
||||
"buttons": {
|
||||
"clearReset": "Netejar el llenç",
|
||||
@@ -119,7 +117,7 @@
|
||||
"edit": "Editar",
|
||||
"undo": "Desfer",
|
||||
"redo": "Refer",
|
||||
"resetLibrary": "Restablir biblioteca",
|
||||
"resetLibrary": "",
|
||||
"createNewRoom": "Crear sala nova",
|
||||
"fullScreen": "Pantalla completa",
|
||||
"darkMode": "Mode fosc",
|
||||
@@ -138,13 +136,12 @@
|
||||
"decryptFailed": "No s'ha pogut desencriptar.",
|
||||
"uploadedSecurly": "La càrrega s'ha assegurat amb xifratge punta a punta, cosa que significa que el servidor Excalidraw i tercers no poden llegir el contingut.",
|
||||
"loadSceneOverridePrompt": "Si carregas aquest dibuix extern, substituirá el que tens. Vols continuar?",
|
||||
"collabStopOverridePrompt": "Aturar la sessió provocarà la sobreescriptura del dibuix previ, que hi ha desat en l'emmagatzematge local. N'esteu segur?\n\n(Si voleu conservar el dibuix local, tanqueu la pentanya del navegador en comptes d'aturar la sessió).",
|
||||
"collabStopOverridePrompt": "",
|
||||
"errorLoadingLibrary": "S'ha produït un error en carregar la biblioteca de tercers.",
|
||||
"confirmAddLibrary": "Això afegirà {{numShapes}} forma(es) a la vostra biblioteca. Estàs segur?",
|
||||
"imageDoesNotContainScene": "En aquest moment no s’admet la importació d’imatges.\n\nVolies importar una escena? Sembla que aquesta imatge no conté cap dada d’escena. Ho has activat durant l'exportació?",
|
||||
"cannotRestoreFromImage": "L’escena no s’ha pogut restaurar des d’aquest fitxer d’imatge",
|
||||
"invalidSceneUrl": "No s'ha pogut importar l'escena des de l'adreça URL proporcionada. Està malformada o no conté dades Excalidraw JSON vàlides.",
|
||||
"resetLibrary": "Tot el llenç s'esborrarà. Estàs segur?"
|
||||
"resetLibrary": ""
|
||||
},
|
||||
"toolBar": {
|
||||
"selection": "Selecció",
|
||||
@@ -200,32 +197,31 @@
|
||||
"button_stopSession": "Aturar sessió",
|
||||
"desc_inProgressIntro": "La sessió de col·laboració en directe està en marxa.",
|
||||
"desc_shareLink": "Comparteix aquest enllaç amb qualsevol persona amb qui vulguis col·laborar:",
|
||||
"desc_exitSession": "Si aturas la sessió, et desconectarás de la sala, però podrás continuar treballant amb el dibuix localment. Tingues en compte que això no afectarà a altres persones, i encara podran col·laborar en la seva versió.",
|
||||
"shareTitle": "Uniu-vos a una sessió de col·laboració en directe a Excalidraw"
|
||||
"desc_exitSession": "Si aturas la sessió, et desconectarás de la sala, però podrás continuar treballant amb el dibuix localment. Tingues en compte que això no afectarà a altres persones, i encara podran col·laborar en la seva versió."
|
||||
},
|
||||
"errorDialog": {
|
||||
"title": "Error"
|
||||
},
|
||||
"helpDialog": {
|
||||
"blog": "Llegiu el nostre blog",
|
||||
"click": "clic",
|
||||
"curvedArrow": "Fletxa corba",
|
||||
"curvedLine": "Línia corba",
|
||||
"documentation": "Documentació",
|
||||
"drag": "arrossega",
|
||||
"editor": "Editor",
|
||||
"github": "Hi heu trobat un problema? Informeu-ne",
|
||||
"howto": "Seguiu les nostres guies",
|
||||
"or": "o",
|
||||
"preventBinding": "Prevenir vinculació de la fletxa",
|
||||
"shapes": "Formes",
|
||||
"shortcuts": "Dreceres de teclat",
|
||||
"textFinish": "Acaba d'editar (text)",
|
||||
"textNewLine": "Afegeix línea nova (text)",
|
||||
"title": "Ajuda",
|
||||
"view": "Visualització",
|
||||
"zoomToFit": "Zoom per veure tots els elements",
|
||||
"zoomToSelection": "Zoom per veure la selecció"
|
||||
"blog": "",
|
||||
"click": "",
|
||||
"curvedArrow": "",
|
||||
"curvedLine": "",
|
||||
"documentation": "",
|
||||
"drag": "",
|
||||
"editor": "",
|
||||
"github": "",
|
||||
"howto": "",
|
||||
"or": "",
|
||||
"preventBinding": "",
|
||||
"shapes": "",
|
||||
"shortcuts": "",
|
||||
"textFinish": "",
|
||||
"textNewLine": "",
|
||||
"title": "",
|
||||
"view": "",
|
||||
"zoomToFit": "",
|
||||
"zoomToSelection": ""
|
||||
},
|
||||
"encrypted": {
|
||||
"tooltip": "Els vostres dibuixos estan xifrats de punta a punta de manera que els servidors d’Excalidraw no els veuran mai."
|
||||
@@ -240,18 +236,16 @@
|
||||
"storage": "Emmagatzematge",
|
||||
"title": "Estadístiques per nerds",
|
||||
"total": "Total",
|
||||
"version": "Versió",
|
||||
"versionCopy": "Feu clic per a copiar",
|
||||
"versionNotAvailable": "Versió no disponible",
|
||||
"version": "",
|
||||
"versionCopy": "",
|
||||
"versionNotAvailable": "",
|
||||
"width": "Amplada"
|
||||
},
|
||||
"toast": {
|
||||
"copyStyles": "S'han copiat els estils.",
|
||||
"copyToClipboard": "S'ha copiat al porta-retalls.",
|
||||
"copyToClipboardAsPng": "S'ha copiat {{exportSelection}} al porta-retalls en format PNG\n({{exportColorScheme}})",
|
||||
"fileSaved": "S'ha desat el fitxer.",
|
||||
"fileSavedToFilename": "S'ha desat a {filename}",
|
||||
"canvas": "el llenç",
|
||||
"selection": "la selecció"
|
||||
"copyStyles": "",
|
||||
"copyToClipboard": "",
|
||||
"copyToClipboardAsPng": "",
|
||||
"fileSaved": "",
|
||||
"fileSavedToFilename": ""
|
||||
}
|
||||
}
|
||||
|
||||
+4
-10
@@ -92,9 +92,7 @@
|
||||
"centerHorizontally": "Horizontal zentrieren",
|
||||
"distributeHorizontally": "Horizontal verteilen",
|
||||
"distributeVertically": "Vertikal verteilen",
|
||||
"viewMode": "Ansichtsmodus",
|
||||
"toggleExportColorScheme": "Farbschema für Export umschalten",
|
||||
"share": "Teilen"
|
||||
"viewMode": "Ansichtsmodus"
|
||||
},
|
||||
"buttons": {
|
||||
"clearReset": "Zeichenfläche löschen & Hintergrundfarbe zurücksetzen",
|
||||
@@ -143,7 +141,6 @@
|
||||
"confirmAddLibrary": "Dieses fügt {{numShapes}} Form(en) zu deiner Bibliothek hinzu. Bist du sicher?",
|
||||
"imageDoesNotContainScene": "Das Importieren von Bildern wird derzeit nicht unterstützt.\n\nMöchtest du eine Szene importieren? Dieses Bild scheint keine Zeichnungsdaten zu enthalten. Hast du dies beim Exportieren aktiviert?",
|
||||
"cannotRestoreFromImage": "Die Zeichnung konnte aus dieser Bilddatei nicht wiederhergestellt werden",
|
||||
"invalidSceneUrl": "Die Szene konnte nicht von der angegebenen URL importiert werden. Sie ist entweder fehlerhaft oder enthält keine gültigen Excalidraw JSON-Daten.",
|
||||
"resetLibrary": "Dieses löscht deine Bibliothek. Bist du sicher?"
|
||||
},
|
||||
"toolBar": {
|
||||
@@ -200,8 +197,7 @@
|
||||
"button_stopSession": "Sitzung beenden",
|
||||
"desc_inProgressIntro": "Die Live-Sitzung wird nun ausgeführt.",
|
||||
"desc_shareLink": "Teile diesen Link mit allen, mit denen du zusammenarbeiten möchtest:",
|
||||
"desc_exitSession": "Wenn du die Sitzung beendest, wird deine Verbindung zum Raum getrennt. Du kannst jedoch lokal weiter an der Zeichnung arbeiten. Beachte, dass dies keine Auswirkungen auf andere hat und diese weiterhin gemeinsam an ihrer Version arbeiten können.",
|
||||
"shareTitle": "An einer Live-Kollaborationssitzung auf Excalidraw teilnehmen"
|
||||
"desc_exitSession": "Wenn du die Sitzung beendest, wird deine Verbindung zum Raum getrennt. Du kannst jedoch lokal weiter an der Zeichnung arbeiten. Beachte, dass dies keine Auswirkungen auf andere hat und diese weiterhin gemeinsam an ihrer Version arbeiten können."
|
||||
},
|
||||
"errorDialog": {
|
||||
"title": "Fehler"
|
||||
@@ -248,10 +244,8 @@
|
||||
"toast": {
|
||||
"copyStyles": "Formatierung kopiert.",
|
||||
"copyToClipboard": "In die Zwischenablage kopiert.",
|
||||
"copyToClipboardAsPng": "{{exportSelection}} als PNG in die Zwischenablage kopiert\n({{exportColorScheme}})",
|
||||
"copyToClipboardAsPng": "In die Zwischenablage als PNG kopiert.",
|
||||
"fileSaved": "Datei gespeichert.",
|
||||
"fileSavedToFilename": "Als {filename} gespeichert",
|
||||
"canvas": "Leinwand",
|
||||
"selection": "Auswahl"
|
||||
"fileSavedToFilename": "Als {filename} gespeichert"
|
||||
}
|
||||
}
|
||||
|
||||
+4
-10
@@ -92,9 +92,7 @@
|
||||
"centerHorizontally": "Κέντρο οριζόντια",
|
||||
"distributeHorizontally": "Οριζόντια κατανομή",
|
||||
"distributeVertically": "Κατακόρυφη κατανομή",
|
||||
"viewMode": "Λειτουργία προβολής",
|
||||
"toggleExportColorScheme": "Εναλλαγή εξαγωγής θέματος χρωμάτων",
|
||||
"share": ""
|
||||
"viewMode": "Λειτουργία προβολής"
|
||||
},
|
||||
"buttons": {
|
||||
"clearReset": "Επαναφορά του καμβά",
|
||||
@@ -143,7 +141,6 @@
|
||||
"confirmAddLibrary": "Αυτό θα προσθέσει {{numShapes}} σχήμα(τα) στη βιβλιοθήκη σας. Είστε σίγουροι;",
|
||||
"imageDoesNotContainScene": "Η εισαγωγή εικόνων δεν υποστηρίζεται αυτή τη στιγμή.\n\nΜήπως θέλετε να εισαγάγετε μια σκηνή; Αυτή η εικόνα δεν φαίνεται να περιέχει δεδομένα σκηνής. Έχετε ενεργοποιήσει αυτό κατά την εξαγωγή;",
|
||||
"cannotRestoreFromImage": "Η σκηνή δεν ήταν δυνατό να αποκατασταθεί από αυτό το αρχείο εικόνας",
|
||||
"invalidSceneUrl": "",
|
||||
"resetLibrary": "Αυτό θα καθαρίσει τη βιβλιοθήκη σας. Είστε σίγουροι;"
|
||||
},
|
||||
"toolBar": {
|
||||
@@ -200,8 +197,7 @@
|
||||
"button_stopSession": "Τερματισμός Συνεδρίας",
|
||||
"desc_inProgressIntro": "Η ζωντανή συνεργασία με άλλους είναι σε ενεργή.",
|
||||
"desc_shareLink": "Μοιραστείτε τον σύνδεσμο με όποιον θέλετε να δουλέψετε μαζί:",
|
||||
"desc_exitSession": "Η διακοπή θα σας αποσυνδέσει από το δωμάτιο, αλλά θα μπορείτε να συνεχίσετε να δουλεύετε στον πίνακα, τοπικά. Σημειώσατε ότι αυτό δεν θα επηρεάσει τον πίνακα άλλων, και θα μπορούν ακόμα να συνεισφέρουν στην δική τους έκδοση.",
|
||||
"shareTitle": ""
|
||||
"desc_exitSession": "Η διακοπή θα σας αποσυνδέσει από το δωμάτιο, αλλά θα μπορείτε να συνεχίσετε να δουλεύετε στον πίνακα, τοπικά. Σημειώσατε ότι αυτό δεν θα επηρεάσει τον πίνακα άλλων, και θα μπορούν ακόμα να συνεισφέρουν στην δική τους έκδοση."
|
||||
},
|
||||
"errorDialog": {
|
||||
"title": "Σφάλμα"
|
||||
@@ -248,10 +244,8 @@
|
||||
"toast": {
|
||||
"copyStyles": "Αντιγράφηκαν στυλ.",
|
||||
"copyToClipboard": "Αντιγράφηκε στο πρόχειρο.",
|
||||
"copyToClipboardAsPng": "Αντιγράφηκε {{exportSelection}} στο πρόχειρο ως PNG\n({{exportColorScheme}})",
|
||||
"copyToClipboardAsPng": "Αντιγράφτηκε στο πρόχειρο ως PNG.",
|
||||
"fileSaved": "Το αρχείο αποθηκεύτηκε.",
|
||||
"fileSavedToFilename": "Αποθηκεύτηκε στο {filename}",
|
||||
"canvas": "καμβάς",
|
||||
"selection": "επιλογή"
|
||||
"fileSavedToFilename": "Αποθηκεύτηκε στο {filename}"
|
||||
}
|
||||
}
|
||||
|
||||
+4
-9
@@ -93,8 +93,7 @@
|
||||
"distributeHorizontally": "Distribute horizontally",
|
||||
"distributeVertically": "Distribute vertically",
|
||||
"viewMode": "View mode",
|
||||
"toggleExportColorScheme": "Toggle export color scheme",
|
||||
"share": "Share"
|
||||
"toggleExportColorScheme": "Toggle export color scheme"
|
||||
},
|
||||
"buttons": {
|
||||
"clearReset": "Reset the canvas",
|
||||
@@ -143,7 +142,6 @@
|
||||
"confirmAddLibrary": "This will add {{numShapes}} shape(s) to your library. Are you sure?",
|
||||
"imageDoesNotContainScene": "Importing images isn't supported at the moment.\n\nDid you want to import a scene? This image does not seem to contain any scene data. Have you enabled this during export?",
|
||||
"cannotRestoreFromImage": "Scene couldn't be restored from this image file",
|
||||
"invalidSceneUrl": "Couldn't import scene from the supplied URL. It's either malformed, or doesn't contain valid Excalidraw JSON data.",
|
||||
"resetLibrary": "This will clear your library. Are you sure?"
|
||||
},
|
||||
"toolBar": {
|
||||
@@ -200,8 +198,7 @@
|
||||
"button_stopSession": "Stop session",
|
||||
"desc_inProgressIntro": "Live-collaboration session is now in progress.",
|
||||
"desc_shareLink": "Share this link with anyone you want to collaborate with:",
|
||||
"desc_exitSession": "Stopping the session will disconnect you from the room, but you'll be able to continue working with the scene, locally. Note that this won't affect other people, and they'll still be able to collaborate on their version.",
|
||||
"shareTitle": "Join a live collaboration session on Excalidraw"
|
||||
"desc_exitSession": "Stopping the session will disconnect you from the room, but you'll be able to continue working with the scene, locally. Note that this won't affect other people, and they'll still be able to collaborate on their version."
|
||||
},
|
||||
"errorDialog": {
|
||||
"title": "Error"
|
||||
@@ -248,10 +245,8 @@
|
||||
"toast": {
|
||||
"copyStyles": "Copied styles.",
|
||||
"copyToClipboard": "Copied to clipboard.",
|
||||
"copyToClipboardAsPng": "Copied {{exportSelection}} to clipboard as PNG\n({{exportColorScheme}})",
|
||||
"copyToClipboardAsPng": "Copied to clipboard as PNG.",
|
||||
"fileSaved": "File saved.",
|
||||
"fileSavedToFilename": "Saved to {filename}",
|
||||
"canvas": "canvas",
|
||||
"selection": "selection"
|
||||
"fileSavedToFilename": "Saved to {filename}"
|
||||
}
|
||||
}
|
||||
|
||||
+4
-10
@@ -92,9 +92,7 @@
|
||||
"centerHorizontally": "Centrar horizontalmente",
|
||||
"distributeHorizontally": "Distribuir horizontalmente",
|
||||
"distributeVertically": "Distribuir verticalmente",
|
||||
"viewMode": "Modo presentación",
|
||||
"toggleExportColorScheme": "Cambiar el esquema de colores de exportación",
|
||||
"share": "Compartir"
|
||||
"viewMode": "Modo presentación"
|
||||
},
|
||||
"buttons": {
|
||||
"clearReset": "Limpiar lienzo y reiniciar el color de fondo",
|
||||
@@ -143,7 +141,6 @@
|
||||
"confirmAddLibrary": "Esto añadirá {{numShapes}} forma(s) a tu biblioteca. ¿Estás seguro?",
|
||||
"imageDoesNotContainScene": "La importación de imágenes no está homologada en este momento.\n\n¿Deseas importar una escena? Esta imagen no parece contener ningún dato de escena. ¿Lo has activado durante la exportación?",
|
||||
"cannotRestoreFromImage": "No se pudo restaurar la escena desde este archivo de imagen",
|
||||
"invalidSceneUrl": "No se ha podido importar la escena desde la URL proporcionada. Está mal formada, o no contiene datos de Excalidraw JSON válidos.",
|
||||
"resetLibrary": "Esto eliminará tu librería. ¿Estás seguro?"
|
||||
},
|
||||
"toolBar": {
|
||||
@@ -200,8 +197,7 @@
|
||||
"button_stopSession": "Detener sesión",
|
||||
"desc_inProgressIntro": "La sesión de colaboración en vivo está ahora en progreso.",
|
||||
"desc_shareLink": "Comparte este enlace con cualquier persona con quien quieras colaborar:",
|
||||
"desc_exitSession": "Detener la sesión te desconectará de la sala, pero podrás seguir trabajando con la escena en su computadora, esto es de modo local. Ten en cuenta que esto no afectará a otras personas, y que las mismas seguirán siendo capaces de colaborar en tu escena.",
|
||||
"shareTitle": "Únete a una sesión colaborativa en directo en Excalidraw"
|
||||
"desc_exitSession": "Detener la sesión te desconectará de la sala, pero podrás seguir trabajando con la escena en su computadora, esto es de modo local. Ten en cuenta que esto no afectará a otras personas, y que las mismas seguirán siendo capaces de colaborar en tu escena."
|
||||
},
|
||||
"errorDialog": {
|
||||
"title": "Error"
|
||||
@@ -248,10 +244,8 @@
|
||||
"toast": {
|
||||
"copyStyles": "Estilos copiados.",
|
||||
"copyToClipboard": "Copiado en el portapapeles.",
|
||||
"copyToClipboardAsPng": "Copiado {{exportSelection}} al portapapeles como PNG\n({{exportColorScheme}})",
|
||||
"copyToClipboardAsPng": "Copiado al portapapeles como PNG.",
|
||||
"fileSaved": "Archivo guardado.",
|
||||
"fileSavedToFilename": "Guardado en {filename}",
|
||||
"canvas": "lienzo",
|
||||
"selection": "selección"
|
||||
"fileSavedToFilename": "Guardado en {filename}"
|
||||
}
|
||||
}
|
||||
|
||||
+4
-10
@@ -92,9 +92,7 @@
|
||||
"centerHorizontally": "وسط قرار دادن به صورت افقی",
|
||||
"distributeHorizontally": "توزیع کردن به صورت افقی",
|
||||
"distributeVertically": "توزیع کردن به صورت عمودی",
|
||||
"viewMode": "",
|
||||
"toggleExportColorScheme": "",
|
||||
"share": ""
|
||||
"viewMode": ""
|
||||
},
|
||||
"buttons": {
|
||||
"clearReset": "پاکسازی بوم نقاشی",
|
||||
@@ -143,7 +141,6 @@
|
||||
"confirmAddLibrary": "{{numShapes}} از اشکال به کتابخانه شما اضافه خواهد شد. مطمئن هستید؟",
|
||||
"imageDoesNotContainScene": "وارد کردن تصویر در این لحظه امکان پذیر نمی باشد.\nآیا مایل به وارد کردن یک صحنه هستید؟ این تصویر به نظر می رسد که فاقد هرگونه اطلاعاتی مربوط به صحنه باشد. آیا این گزینه را در زمان وارد کردن تصویر فعال کرده اید؟",
|
||||
"cannotRestoreFromImage": "صحنه را نمی توان از این فایل تصویری بازیابی کرد",
|
||||
"invalidSceneUrl": "",
|
||||
"resetLibrary": ""
|
||||
},
|
||||
"toolBar": {
|
||||
@@ -200,8 +197,7 @@
|
||||
"button_stopSession": "پایان جلسه",
|
||||
"desc_inProgressIntro": "جلسه همکاری آنلاین در حال انجام است.",
|
||||
"desc_shareLink": "این لینک را با هر کسی که می خواهید با او همکاری کنید به اشتراک بگذارید:",
|
||||
"desc_exitSession": "با پایان دادن جلسه، شما از اتاق حذف میکند، اما می توانید به صورت محلی کار خود را با بوم ادامه دهید. توجه داشته باشید که این مورد بر سایر افراد تأثیر نمی گذارد و همچنان می توانند در نسخه خود همکاری کنند.",
|
||||
"shareTitle": ""
|
||||
"desc_exitSession": "با پایان دادن جلسه، شما از اتاق حذف میکند، اما می توانید به صورت محلی کار خود را با بوم ادامه دهید. توجه داشته باشید که این مورد بر سایر افراد تأثیر نمی گذارد و همچنان می توانند در نسخه خود همکاری کنند."
|
||||
},
|
||||
"errorDialog": {
|
||||
"title": "خطا"
|
||||
@@ -248,10 +244,8 @@
|
||||
"toast": {
|
||||
"copyStyles": "کپی سبک.",
|
||||
"copyToClipboard": "",
|
||||
"copyToClipboardAsPng": "",
|
||||
"copyToClipboardAsPng": "کپی در حافطه موقت به صورت PNG.",
|
||||
"fileSaved": "",
|
||||
"fileSavedToFilename": "",
|
||||
"canvas": "",
|
||||
"selection": ""
|
||||
"fileSavedToFilename": ""
|
||||
}
|
||||
}
|
||||
|
||||
+29
-35
@@ -9,10 +9,10 @@
|
||||
"copy": "Kopioi",
|
||||
"copyAsPng": "Kopioi leikepöydälle PNG-tiedostona",
|
||||
"copyAsSvg": "Kopioi leikepöydälle SVG-tiedostona",
|
||||
"bringForward": "Tuo eteenpäin",
|
||||
"bringForward": "Siirrä eteenpäin",
|
||||
"sendToBack": "Vie taakse",
|
||||
"bringToFront": "Tuo eteen",
|
||||
"sendBackward": "Vie taaksepäin",
|
||||
"sendBackward": "Siirrä taaksepäin",
|
||||
"delete": "Poista",
|
||||
"copyStyles": "Kopioi tyyli",
|
||||
"pasteStyles": "Liitä tyyli",
|
||||
@@ -29,7 +29,7 @@
|
||||
"textAlign": "Tekstin tasaus",
|
||||
"edges": "Reunat",
|
||||
"sharp": "Terävä",
|
||||
"round": "Pyöristetty",
|
||||
"round": "Pyöreä",
|
||||
"arrowheads": "Nuolenkärjet",
|
||||
"arrowhead_none": "Ei mitään",
|
||||
"arrowhead_arrow": "Nuoli",
|
||||
@@ -92,9 +92,7 @@
|
||||
"centerHorizontally": "Keskitä vaakasuunnassa",
|
||||
"distributeHorizontally": "Jaa vaakasuunnassa",
|
||||
"distributeVertically": "Jaa pystysuunnassa",
|
||||
"viewMode": "Katselutila",
|
||||
"toggleExportColorScheme": "Vaihda viennin väriteema",
|
||||
"share": "Jaa"
|
||||
"viewMode": "Katselutila"
|
||||
},
|
||||
"buttons": {
|
||||
"clearReset": "Tyhjennä piirtoalue",
|
||||
@@ -111,9 +109,9 @@
|
||||
"close": "Sulje",
|
||||
"selectLanguage": "Valitse kieli",
|
||||
"scrollBackToContent": "Näytä sisältö",
|
||||
"zoomIn": "Lähennä",
|
||||
"zoomOut": "Loitonna",
|
||||
"resetZoom": "Nollaa suurennuksen taso",
|
||||
"zoomIn": "Zoomaa sisään",
|
||||
"zoomOut": "Zoomaa ulos",
|
||||
"resetZoom": "Nollaa zoomaus",
|
||||
"menu": "Valikko",
|
||||
"done": "Valmis",
|
||||
"edit": "Muokkaa",
|
||||
@@ -130,21 +128,20 @@
|
||||
"alerts": {
|
||||
"clearReset": "Tämä tyhjentää koko piirtoalueen. Jatketaanko?",
|
||||
"couldNotCreateShareableLink": "Jaettavan linkin luominen epäonnistui.",
|
||||
"couldNotCreateShareableLinkTooBig": "Jaettavaa linkkiä ei voitu luoda: piirtoalue on liian suuri",
|
||||
"couldNotCreateShareableLinkTooBig": "Jaettavaa linkkiä ei voitu luoda: teos on liian suuri",
|
||||
"couldNotLoadInvalidFile": "Virheellistä tiedostoa ei voitu avata",
|
||||
"importBackendFailed": "Palvelimelta tuonti epäonnistui.",
|
||||
"cannotExportEmptyCanvas": "Tyhjää piirtoaluetta ei voi viedä.",
|
||||
"couldNotCopyToClipboard": "Leikepöydälle kopiointi epäonnistui. Kokeile Chrome-selainta.",
|
||||
"decryptFailed": "Salauksen purkaminen epäonnistui.",
|
||||
"uploadedSecurly": "Lähetys on turvattu päästä-päähän-salauksella. Excalidrawin palvelin ja kolmannet osapuolet eivät voi lukea sisältöä.",
|
||||
"loadSceneOverridePrompt": "Ulkopuolisen piirroksen lataaminen korvaa nykyisen sisältösi. Jatketaanko?",
|
||||
"collabStopOverridePrompt": "Istunnon lopettaminen korvaa aiemman, paikallisesti tallennetun piirustuksen. Jatketaanko?\n\n(Jos haluat säilyttää paikallisesti tallennetun piirustuksen, sulje selaimen välilehti lopettamisen sijaan.)",
|
||||
"errorLoadingLibrary": "Virhe ladattaessa kolmannen osapuolen kirjastoa.",
|
||||
"confirmAddLibrary": "Tämä lisää {{numShapes}} muotoa kirjastoosi. Jatketaanko?",
|
||||
"uploadedSecurly": "Lähetys on turvattu päästä päähän salauksella. Excalidrawin palvelin ja kolmannet osapuolet eivät voi lukea sisältöä.",
|
||||
"loadSceneOverridePrompt": "Ulkopuolisen piirroksen lataaminen korvaa nykyisen sisältösi. Haluatko jatkaa?",
|
||||
"collabStopOverridePrompt": "Istunnon lopettaminen korvaa aiemman, paikallisesti tallennetun piirustuksen. Oletko varma?\n\n(Jos haluat pitää paikallisen piirustuksen, sulje selaimen välilehti sen sijaan.)",
|
||||
"errorLoadingLibrary": "Kolmannen osapuolen kirjastoa ladattaessa tapahtui virhe.",
|
||||
"confirmAddLibrary": "Tämä lisää {{numShapes}} muotoa kirjastoosi. Oletko varma?",
|
||||
"imageDoesNotContainScene": "Kuvien lisääminen ei ole tällä hetkellä mahdollista.\n\nHaluatko tuoda piirroksen? Tämä kuva ei näytä sisältävän tarvittavia tietoja. Oletko ottanut piirrostietojen tallennuksen käyttöön viennin aikana?",
|
||||
"cannotRestoreFromImage": "Teosta ei voitu palauttaa tästä kuvatiedostosta",
|
||||
"invalidSceneUrl": "Teosta ei voitu tuoda annetusta URL-osoitteesta. Tallenne on vioittunut, tai osoitteessa ei ole Excalidraw JSON-dataa.",
|
||||
"resetLibrary": "Tämä tyhjentää kirjastosi. Jatketaanko?"
|
||||
"resetLibrary": "Tämä tyhjentää kirjastosi. Oletko varma?"
|
||||
},
|
||||
"toolBar": {
|
||||
"selection": "Valinta",
|
||||
@@ -167,13 +164,13 @@
|
||||
"linearElement": "Klikkaa piirtääksesi useampi piste, raahaa piirtääksesi yksittäinen viiva",
|
||||
"freeDraw": "Paina ja raahaa, päästä irti kun olet valmis",
|
||||
"text": "Vinkki: voit myös lisätä tekstiä kaksoisnapsauttamalla mihin tahansa valintatyökalulla",
|
||||
"linearElementMulti": "Lopeta klikkaamalla viimeistä pistettä, painamalla Escape- tai Enter-näppäintä",
|
||||
"lockAngle": "Voit rajoittaa kulmaa pitämällä SHIFT-näppäintä alaspainettuna",
|
||||
"resize": "Voit rajoittaa mittasuhteet pitämällä SHIFT-näppäintä alaspainettuna kun muutat kokoa, pidä ALT-näppäintä alaspainettuna muuttaaksesi kokoa keskipisteen suhteen",
|
||||
"linearElementMulti": "Klikkaa viimeistä pistettä, paina Escape tai paina Enter lopettaaksesi",
|
||||
"lockAngle": "Voit rajoittaa kulmaa pitämällä SHIFT pohjassa",
|
||||
"resize": "Voit rajoittaa mittasuhteet pitämällä SHIFT pohjassa kun muutat kokoa, pidä ALT pohjassa muuttaaksesi kokoa keskipisteen suhteen",
|
||||
"rotate": "Voit rajoittaa kulman pitämällä SHIFT pohjassa pyörittäessäsi",
|
||||
"lineEditor_info": "Kaksoisnapauta tai paina Enter muokataksesi pisteitä",
|
||||
"lineEditor_pointSelected": "Paina Delete poistaaksesi pisteen, Ctrl tai Cmd+D monistaaksesi, tai raahaa liikuttaaksesi",
|
||||
"lineEditor_nothingSelected": "Valitse liikutettava tai poistettava piste, tai pidä ALT-näppäintä alaspainettuna ja napsauta lisätäksesi uusia pisteitä"
|
||||
"lineEditor_pointSelected": "Paina Delete poistaaksesi pisteen, CtrlOrCmd+D monistaaksesi, tai raahaa liikuttaaksesi",
|
||||
"lineEditor_nothingSelected": "Valitse liikutettava tai poistettava piste, tai pidä Alt pohjassa ja napauta lisätäksesi uusia pisteitä"
|
||||
},
|
||||
"canvasError": {
|
||||
"cannotShowPreview": "Esikatselua ei voitu näyttää",
|
||||
@@ -183,25 +180,24 @@
|
||||
"errorSplash": {
|
||||
"headingMain_pre": "Tapahtui virhe. Yritä ",
|
||||
"headingMain_button": "sivun lataamista uudelleen.",
|
||||
"clearCanvasMessage": "Mikäli sivun lataaminen uudelleen ei auta, yritä ",
|
||||
"clearCanvasMessage": "Jos lataaminen uudelleen ei auta, yritä ",
|
||||
"clearCanvasMessage_button": "tyhjentää piirtoalue.",
|
||||
"clearCanvasCaveat": " Tämä johtaa työn menetykseen ",
|
||||
"trackedToSentry_pre": "Virhe tunnisteella ",
|
||||
"trackedToSentry_post": " tallennettiin järjestelmäämme.",
|
||||
"openIssueMessage_pre": "Olimme varovaisia emmekä sisällyttäneet tietoa piirroksestasi virheeseen. Mikäli piirroksesi ei ole yksityinen, harkitsethan kertovasi meille ",
|
||||
"openIssueMessage_pre": "Olimme varovaisia emmekä sisällyttäneet tietoa piirroksestasi virheeseen. Jos piirroksesi ei ole yksityinen, harkitsethan kertovasi meille ",
|
||||
"openIssueMessage_button": "virheenseurantajärjestelmässämme.",
|
||||
"openIssueMessage_post": " Sisällytä alla olevat tiedot kopioimalla ne GitHub-ongelmaan.",
|
||||
"sceneContent": "Piirroksen tiedot:"
|
||||
},
|
||||
"roomDialog": {
|
||||
"desc_intro": "Voit kutsua ihmisiä piirrokseesi tekemään yhteistyötä kanssasi.",
|
||||
"desc_privacy": "Älä huoli, istunto käyttää päästä-päähän-salausta, joten mitä tahansa piirrätkin, se pysyy salassa. Edes palvelimemme eivät näe mitä keksit.",
|
||||
"desc_privacy": "Älä huoli, istunto käyttää päästä päähän salausta, joten mitä tahansa piirrätkin, se pysyy salassa. Edes palvelimemme ei näe mitä keksit.",
|
||||
"button_startSession": "Aloita istunto",
|
||||
"button_stopSession": "Lopeta istunto",
|
||||
"desc_inProgressIntro": "Jaettu istunto on nyt käynnissä.",
|
||||
"desc_shareLink": "Jaa tämä linkki kenelle tahansa, jonka kanssa haluat tehdä yhteistyötä:",
|
||||
"desc_exitSession": "Istunnon pysäyttäminen katkaisee yhteyden huoneeseen, mutta voit vielä jatkaa työskentelyä paikallisesti. Huomaa, että tämä ei vaikuta muihin käyttäjiin ja he voivat jatkaa oman versionsa parissa työskentelyä.",
|
||||
"shareTitle": "Liity Excalidraw live-yhteistyöistuntoon"
|
||||
"desc_exitSession": "Istunnon pysäyttäminen katkaisee yhteyden huoneeseen, mutta voit vielä jatkaa työskentelyä paikallisesti. Huomaa, että tämä ei vaikuta muihin käyttäjiin ja he voivat jatkaa oman versionsa parissa työskentelyä."
|
||||
},
|
||||
"errorDialog": {
|
||||
"title": "Virhe"
|
||||
@@ -228,7 +224,7 @@
|
||||
"zoomToSelection": "Näytä valinta"
|
||||
},
|
||||
"encrypted": {
|
||||
"tooltip": "Piirroksesi ovat päästä-päähän-salattuja, joten Excalidrawin palvelimet eivät koskaan näe niitä."
|
||||
"tooltip": "Piirroksesi ovat päästä päähän salattuja, joten Excalidrawin palvelimet eivät koskaan näe niitä."
|
||||
},
|
||||
"stats": {
|
||||
"angle": "Kulma",
|
||||
@@ -238,7 +234,7 @@
|
||||
"scene": "Teos",
|
||||
"selected": "Valitut",
|
||||
"storage": "Tallennustila",
|
||||
"title": "Tilastoja nörteille",
|
||||
"title": "Nörttien tilastot",
|
||||
"total": "Yhteensä",
|
||||
"version": "Versio",
|
||||
"versionCopy": "Klikkaa kopioidaksesi",
|
||||
@@ -246,12 +242,10 @@
|
||||
"width": "Leveys"
|
||||
},
|
||||
"toast": {
|
||||
"copyStyles": "Tyylit kopioitiin.",
|
||||
"copyToClipboard": "Kopioitiin leikepöydälle.",
|
||||
"copyToClipboardAsPng": "Kopioitiin {{exportSelection}} leikepöydälle PNG:nä\n({{exportColorScheme}})",
|
||||
"copyStyles": "Tyylit kopioitu.",
|
||||
"copyToClipboard": "Kopioitu leikepöydälle.",
|
||||
"copyToClipboardAsPng": "Kopioitu leikepöydälle PNG-tiedostona.",
|
||||
"fileSaved": "Tiedosto tallennettu.",
|
||||
"fileSavedToFilename": "Tallennettiin kohteeseen {filename}",
|
||||
"canvas": "piirtoalue",
|
||||
"selection": "valinta"
|
||||
"fileSavedToFilename": "Tallennettu kohteeseen {filename}"
|
||||
}
|
||||
}
|
||||
|
||||
+4
-10
@@ -92,9 +92,7 @@
|
||||
"centerHorizontally": "Centrer horizontalement",
|
||||
"distributeHorizontally": "Distribuer horizontalement",
|
||||
"distributeVertically": "Distribuer verticalement",
|
||||
"viewMode": "Mode présentation",
|
||||
"toggleExportColorScheme": "Activer/Désactiver l'export du thème de couleur",
|
||||
"share": "Partager"
|
||||
"viewMode": "Mode présentation"
|
||||
},
|
||||
"buttons": {
|
||||
"clearReset": "Réinitialiser le canevas",
|
||||
@@ -143,7 +141,6 @@
|
||||
"confirmAddLibrary": "Cela va ajouter {{numShapes}} forme(s) à votre bibliothèque. Êtes-vous sûr·e ?",
|
||||
"imageDoesNotContainScene": "L'importation d'images n'est pas prise en charge pour le moment.\n\nVouliez-vous importer une scène ? Cette image ne semble pas contenir de données de scène. Avez-vous activé cette option lors de l'exportation ?",
|
||||
"cannotRestoreFromImage": "Impossible de restaurer la scène depuis ce fichier image",
|
||||
"invalidSceneUrl": "Impossible d'importer la scène depuis l'URL fournie. Elle est soit incorrecte, soit ne contient pas de données JSON Excalidraw valides.",
|
||||
"resetLibrary": "Cela va effacer votre bibliothèque. Êtes-vous sûr·e ?"
|
||||
},
|
||||
"toolBar": {
|
||||
@@ -200,8 +197,7 @@
|
||||
"button_stopSession": "Arrêter la session",
|
||||
"desc_inProgressIntro": "La session de collaboration en direct est maintenant en cours.",
|
||||
"desc_shareLink": "Partagez ce lien avec les personnes avec lesquelles vous souhaitez collaborer :",
|
||||
"desc_exitSession": "Arrêter la session vous déconnectera de la salle, mais vous pourrez continuer à travailler avec la scène, localement. Notez que cela n'affectera pas les autres personnes, et ils pourront toujours collaborer sur leur version.",
|
||||
"shareTitle": "Rejoindre une session de collaboration en direct sur Excalidraw"
|
||||
"desc_exitSession": "Arrêter la session vous déconnectera de la salle, mais vous pourrez continuer à travailler avec la scène, localement. Notez que cela n'affectera pas les autres personnes, et ils pourront toujours collaborer sur leur version."
|
||||
},
|
||||
"errorDialog": {
|
||||
"title": "Erreur"
|
||||
@@ -248,10 +244,8 @@
|
||||
"toast": {
|
||||
"copyStyles": "Styles copiés.",
|
||||
"copyToClipboard": "Copié vers le presse-papiers.",
|
||||
"copyToClipboardAsPng": "{{exportSelection}} copié dans le presse-papiers en PNG\n({{exportColorScheme}})",
|
||||
"copyToClipboardAsPng": "Copié vers le presse-papier en PNG.",
|
||||
"fileSaved": "Fichier enregistré.",
|
||||
"fileSavedToFilename": "Enregistré sous {filename}",
|
||||
"canvas": "canevas",
|
||||
"selection": "sélection"
|
||||
"fileSavedToFilename": "Enregistré sous {filename}"
|
||||
}
|
||||
}
|
||||
|
||||
+22
-28
@@ -92,9 +92,7 @@
|
||||
"centerHorizontally": "מרכז אופקית",
|
||||
"distributeHorizontally": "חלוקה אופקית",
|
||||
"distributeVertically": "חלוקה אנכית",
|
||||
"viewMode": "מצב תצוגה",
|
||||
"toggleExportColorScheme": "",
|
||||
"share": ""
|
||||
"viewMode": ""
|
||||
},
|
||||
"buttons": {
|
||||
"clearReset": "אפס את הלוח",
|
||||
@@ -119,7 +117,7 @@
|
||||
"edit": "ערוך",
|
||||
"undo": "בטל",
|
||||
"redo": "בצע מחדש",
|
||||
"resetLibrary": "איפוס ספריה",
|
||||
"resetLibrary": "",
|
||||
"createNewRoom": "צור חדר",
|
||||
"fullScreen": "מסך מלא",
|
||||
"darkMode": "מצב כהה",
|
||||
@@ -143,7 +141,6 @@
|
||||
"confirmAddLibrary": "הפעולה תוסיף {{numShapes}} צורה(ות) לספריה שלך. האם אתה בטוח?",
|
||||
"imageDoesNotContainScene": "אין תמיכה בייבוא תמונות כעת.\n\nהאם אתה רוצה לייבא תצוגה? התמונה הזאת אינה מכילה מידע על תצוגה. האם הפעלת את האפשרות הזאת בזמן הוצאת המידע?",
|
||||
"cannotRestoreFromImage": "לא הצלחנו לשחזר את התצוגה מקובץ התמונה",
|
||||
"invalidSceneUrl": "",
|
||||
"resetLibrary": ""
|
||||
},
|
||||
"toolBar": {
|
||||
@@ -200,32 +197,31 @@
|
||||
"button_stopSession": "הפסק שיתוף",
|
||||
"desc_inProgressIntro": "שיתוף חי כרגע בפעולה.",
|
||||
"desc_shareLink": "שתף את הקישור עם כל מי שאתה מעוניין לעבוד אתו:",
|
||||
"desc_exitSession": "עצירת השיתוף תנתק אותך מהחדר, אבל עדיין תוכל להמשיך לעבוד על הלוח, מקומית. שים לב שזה לא ישפיע על אנשים אחרים, והם עדיין יוכלו לשתף פעולה עם הגירסה שלהם.",
|
||||
"shareTitle": ""
|
||||
"desc_exitSession": "עצירת השיתוף תנתק אותך מהחדר, אבל עדיין תוכל להמשיך לעבוד על הלוח, מקומית. שים לב שזה לא ישפיע על אנשים אחרים, והם עדיין יוכלו לשתף פעולה עם הגירסה שלהם."
|
||||
},
|
||||
"errorDialog": {
|
||||
"title": "שגיאה"
|
||||
},
|
||||
"helpDialog": {
|
||||
"blog": "קרא את הבלוג שלנו",
|
||||
"click": "קליק",
|
||||
"blog": "",
|
||||
"click": "",
|
||||
"curvedArrow": "",
|
||||
"curvedLine": "",
|
||||
"documentation": "תיעוד",
|
||||
"drag": "לגרור",
|
||||
"editor": "עורך",
|
||||
"github": "מצאת בעיה? דווח",
|
||||
"howto": "עקוב אחר המדריכים שלנו",
|
||||
"or": "או",
|
||||
"documentation": "",
|
||||
"drag": "",
|
||||
"editor": "",
|
||||
"github": "",
|
||||
"howto": "",
|
||||
"or": "",
|
||||
"preventBinding": "",
|
||||
"shapes": "צורות",
|
||||
"shortcuts": "קיצורי מקלדת",
|
||||
"textFinish": "סיים עריכה (טקסט)",
|
||||
"textNewLine": "הוסף שורה חדשה (טקסט)",
|
||||
"title": "עזרה",
|
||||
"view": "תצוגה",
|
||||
"shapes": "",
|
||||
"shortcuts": "",
|
||||
"textFinish": "",
|
||||
"textNewLine": "",
|
||||
"title": "",
|
||||
"view": "",
|
||||
"zoomToFit": "",
|
||||
"zoomToSelection": "התמקד בבחירה"
|
||||
"zoomToSelection": ""
|
||||
},
|
||||
"encrypted": {
|
||||
"tooltip": "הרישומים שלך מוצפנים מקצה לקצה כך שהשרתים של Excalidraw לא יראו אותם לעולם."
|
||||
@@ -241,17 +237,15 @@
|
||||
"title": "סטטיסטיקות לחנונים",
|
||||
"total": "סה״כ",
|
||||
"version": "",
|
||||
"versionCopy": "לחץ להעתקה",
|
||||
"versionCopy": "",
|
||||
"versionNotAvailable": "",
|
||||
"width": "רוחב"
|
||||
},
|
||||
"toast": {
|
||||
"copyStyles": "העתק סגנונות.",
|
||||
"copyStyles": "",
|
||||
"copyToClipboard": "",
|
||||
"copyToClipboardAsPng": "",
|
||||
"fileSaved": "קובץ נשמר.",
|
||||
"fileSavedToFilename": "",
|
||||
"canvas": "",
|
||||
"selection": ""
|
||||
"fileSaved": "",
|
||||
"fileSavedToFilename": ""
|
||||
}
|
||||
}
|
||||
|
||||
+4
-10
@@ -92,9 +92,7 @@
|
||||
"centerHorizontally": "क्षैतिज केन्द्रित",
|
||||
"distributeHorizontally": "क्षैतिज रूप से वितरित करें",
|
||||
"distributeVertically": "खड़ी रूप से वितरित करें",
|
||||
"viewMode": "",
|
||||
"toggleExportColorScheme": "",
|
||||
"share": ""
|
||||
"viewMode": ""
|
||||
},
|
||||
"buttons": {
|
||||
"clearReset": "कैनवास रीसेट करें",
|
||||
@@ -143,7 +141,6 @@
|
||||
"confirmAddLibrary": "लाइब्रेरी जोड़ें पुष्टि करें आकार संख्या",
|
||||
"imageDoesNotContainScene": "दृश्य में छवि नहीं है",
|
||||
"cannotRestoreFromImage": "छवि फ़ाइल बहाल दृश्य नहीं है",
|
||||
"invalidSceneUrl": "",
|
||||
"resetLibrary": ""
|
||||
},
|
||||
"toolBar": {
|
||||
@@ -200,8 +197,7 @@
|
||||
"button_stopSession": "सत्र रुकें",
|
||||
"desc_inProgressIntro": "लाइव सहयोग सत्र अब जारी है।",
|
||||
"desc_shareLink": "इस लिंक को आप जिस किसी के साथ भी सहयोग करना चाहते हैं, उसके साथ साझा करें",
|
||||
"desc_exitSession": "सत्र रोकना आपको रूम से बाहर कर देगा, लेकिन आप स्थानीय स्तर पर दृश्य के साथ काम करना जारी रख पाएंगे। ध्यान दें कि यह अन्य लोगों को प्रभावित नहीं करेगा, और वे अभी भी अपने संस्करण पर सहयोग करने में सक्षम होंगे।",
|
||||
"shareTitle": ""
|
||||
"desc_exitSession": "सत्र रोकना आपको रूम से बाहर कर देगा, लेकिन आप स्थानीय स्तर पर दृश्य के साथ काम करना जारी रख पाएंगे। ध्यान दें कि यह अन्य लोगों को प्रभावित नहीं करेगा, और वे अभी भी अपने संस्करण पर सहयोग करने में सक्षम होंगे।"
|
||||
},
|
||||
"errorDialog": {
|
||||
"title": "गलती"
|
||||
@@ -248,10 +244,8 @@
|
||||
"toast": {
|
||||
"copyStyles": "काॅपी कीए स्टाइल",
|
||||
"copyToClipboard": "क्लिपबोर्ड में कॉपी कीए",
|
||||
"copyToClipboardAsPng": "",
|
||||
"copyToClipboardAsPng": "क्लिपबोर्ड में PNG के रूप में कॉपी किए",
|
||||
"fileSaved": "",
|
||||
"fileSavedToFilename": "",
|
||||
"canvas": "",
|
||||
"selection": ""
|
||||
"fileSavedToFilename": ""
|
||||
}
|
||||
}
|
||||
|
||||
@@ -92,9 +92,7 @@
|
||||
"centerHorizontally": "Vízszintesen középre igazított",
|
||||
"distributeHorizontally": "Vízszintes elosztás",
|
||||
"distributeVertically": "Függőleges elosztás",
|
||||
"viewMode": "",
|
||||
"toggleExportColorScheme": "",
|
||||
"share": ""
|
||||
"viewMode": ""
|
||||
},
|
||||
"buttons": {
|
||||
"clearReset": "Vászon törlése",
|
||||
@@ -143,7 +141,6 @@
|
||||
"confirmAddLibrary": "Ez a művelet {{numShapes}} formát fog hozzáadni a könyvtáradhoz. Biztos vagy benne?",
|
||||
"imageDoesNotContainScene": "Képek importálása egyelőre nem támogatott.\n\nEgy jelenetet szeretnél betölteni? Úgy tűnik ez a kép fájl nem tartalmazza a szükséges adatokat. Exportáláskor ezt egy külön opcióval lehet beállítani.",
|
||||
"cannotRestoreFromImage": "A jelenet visszaállítása nem sikerült ebből a kép fájlból",
|
||||
"invalidSceneUrl": "",
|
||||
"resetLibrary": ""
|
||||
},
|
||||
"toolBar": {
|
||||
@@ -200,8 +197,7 @@
|
||||
"button_stopSession": "Munkamenet leállítása",
|
||||
"desc_inProgressIntro": "Az élő együttműködési munkamenet folyamatban van.",
|
||||
"desc_shareLink": "Ossza meg ezt a linket bárkivel, akivel együtt szeretne működni:",
|
||||
"desc_exitSession": "Az munkamenet leállítása kilépteti önt a szobából, de folytathatja a munkát a saját gépén. Vegye figyelembe, hogy ez nem érinti más emberek munkáját és ők továbbra is együttműködhetnek a saját változatukon.",
|
||||
"shareTitle": ""
|
||||
"desc_exitSession": "Az munkamenet leállítása kilépteti önt a szobából, de folytathatja a munkát a saját gépén. Vegye figyelembe, hogy ez nem érinti más emberek munkáját és ők továbbra is együttműködhetnek a saját változatukon."
|
||||
},
|
||||
"errorDialog": {
|
||||
"title": "Hiba"
|
||||
@@ -250,8 +246,6 @@
|
||||
"copyToClipboard": "",
|
||||
"copyToClipboardAsPng": "",
|
||||
"fileSaved": "",
|
||||
"fileSavedToFilename": "",
|
||||
"canvas": "",
|
||||
"selection": ""
|
||||
"fileSavedToFilename": ""
|
||||
}
|
||||
}
|
||||
|
||||
+7
-13
@@ -68,7 +68,7 @@
|
||||
"layers": "Lapisan",
|
||||
"actions": "Aksi",
|
||||
"language": "Bahasa",
|
||||
"liveCollaboration": "Kolaborasi langsung",
|
||||
"liveCollaboration": "",
|
||||
"duplicateSelection": "Duplikat",
|
||||
"untitled": "Tanpa judul",
|
||||
"name": "Nama",
|
||||
@@ -92,9 +92,7 @@
|
||||
"centerHorizontally": "Pusatkan secara horizontal",
|
||||
"distributeHorizontally": "Distribusikan horizontal",
|
||||
"distributeVertically": "Distribusikan vertikal",
|
||||
"viewMode": "Mode tampilan",
|
||||
"toggleExportColorScheme": "Ubah skema warna ekspor",
|
||||
"share": "Bagikan"
|
||||
"viewMode": "Mode tampilan"
|
||||
},
|
||||
"buttons": {
|
||||
"clearReset": "Setel Ulang Kanvas",
|
||||
@@ -119,7 +117,7 @@
|
||||
"edit": "Edit",
|
||||
"undo": "Urungkan",
|
||||
"redo": "Ulangi",
|
||||
"resetLibrary": "Reset pustaka",
|
||||
"resetLibrary": "",
|
||||
"createNewRoom": "Buat ruang baru",
|
||||
"fullScreen": "Layar penuh",
|
||||
"darkMode": "Mode gelap",
|
||||
@@ -143,8 +141,7 @@
|
||||
"confirmAddLibrary": "Ini akan menambahkan {{numShapes}} bentuk ke pustaka Anda. Anda yakin?",
|
||||
"imageDoesNotContainScene": "Mengimpor gambar tidak didukung saat ini.\n\nApakah Anda ingin impor pemandangan? Gambar ini tidak berisi data pemandangan. Sudah ka Anda aktifkan ini ketika ekspor?",
|
||||
"cannotRestoreFromImage": "Pemandangan tidak dapat dipulihkan dari file gambar ini",
|
||||
"invalidSceneUrl": "",
|
||||
"resetLibrary": "Ini akan menghapus pustaka Anda. Anda yakin?"
|
||||
"resetLibrary": ""
|
||||
},
|
||||
"toolBar": {
|
||||
"selection": "Pilihan",
|
||||
@@ -200,8 +197,7 @@
|
||||
"button_stopSession": "Hentikan sesi",
|
||||
"desc_inProgressIntro": "Sesi kolaborasi sedang berlangsung sekarang.",
|
||||
"desc_shareLink": "Bagikan tautan ini dengan siapa pun yang Anda inginkan untuk kolaborasi bersama:",
|
||||
"desc_exitSession": "Menghentikan sesi akan memutuskan hubungan Anda dari ruangan, tetapi Anda dapat melanjutkan bekerja dengan pemandangan Anda secara lokal. Perhatikan bahwa ini tidak memengaruhi orang lain, dan mereka masih dapat berkolaborasi pada versi mereka.",
|
||||
"shareTitle": "Gabung sesi kolaborasi langsung di Excalidraw"
|
||||
"desc_exitSession": "Menghentikan sesi akan memutuskan hubungan Anda dari ruangan, tetapi Anda dapat melanjutkan bekerja dengan pemandangan Anda secara lokal. Perhatikan bahwa ini tidak memengaruhi orang lain, dan mereka masih dapat berkolaborasi pada versi mereka."
|
||||
},
|
||||
"errorDialog": {
|
||||
"title": "Kesalahan"
|
||||
@@ -248,10 +244,8 @@
|
||||
"toast": {
|
||||
"copyStyles": "Gaya tersalin.",
|
||||
"copyToClipboard": "Tersalin ke papan klip.",
|
||||
"copyToClipboardAsPng": "Tersalin {{exportSelection}} ke clipboard sebagai PNG\n({{exportColorScheme}})",
|
||||
"copyToClipboardAsPng": "Tersalin ke clipboard sebagai PNG.",
|
||||
"fileSaved": "File tersimpan.",
|
||||
"fileSavedToFilename": "Disimpan ke {filename}",
|
||||
"canvas": "kanvas",
|
||||
"selection": "pilihan"
|
||||
"fileSavedToFilename": "Disimpan ke {filename}"
|
||||
}
|
||||
}
|
||||
|
||||
+4
-10
@@ -92,9 +92,7 @@
|
||||
"centerHorizontally": "Centra orizzontalmente",
|
||||
"distributeHorizontally": "Distribuisci orizzontalmente",
|
||||
"distributeVertically": "Distribuisci verticalmente",
|
||||
"viewMode": "Modalità visualizzazione",
|
||||
"toggleExportColorScheme": "Cambia lo schema di colori in esportazione",
|
||||
"share": "Condividi"
|
||||
"viewMode": "Modalità visualizzazione"
|
||||
},
|
||||
"buttons": {
|
||||
"clearReset": "Svuota la tela",
|
||||
@@ -143,7 +141,6 @@
|
||||
"confirmAddLibrary": "Questo aggiungerà {{numShapes}} forma(e) alla tua libreria. Sei sicuro?",
|
||||
"imageDoesNotContainScene": "L'importazione di immagini al momento non è supportata.\n\nVuoi importare una scena? Questa immagine non sembra contenere alcun dato di scena. Hai abilitato questa opzione durante l'esportazione?",
|
||||
"cannotRestoreFromImage": "Impossibile ripristinare la scena da questo file immagine",
|
||||
"invalidSceneUrl": "Impossibile importare la scena dall'URL fornito. Potrebbe essere malformato o non contenere dati JSON Excalidraw validi.",
|
||||
"resetLibrary": "Questa azione cancellerà l'intera libreria. Sei sicuro?"
|
||||
},
|
||||
"toolBar": {
|
||||
@@ -200,8 +197,7 @@
|
||||
"button_stopSession": "Termina sessione",
|
||||
"desc_inProgressIntro": "La sessione di collaborazione è attualmente in corso.",
|
||||
"desc_shareLink": "Condividi questo link con chiunque desideri collaborare:",
|
||||
"desc_exitSession": "Interrompere la sessione scollegherà la tua stanza ma potrai continuare a lavorare con la scena, localmente. Tieni presente che questo non influirà sulle altre persone, e che saranno ancora in grado di collaborare alla loro versione.",
|
||||
"shareTitle": "Partecipa a una sessione di collaborazione live su Excalidraw"
|
||||
"desc_exitSession": "Interrompere la sessione scollegherà la tua stanza ma potrai continuare a lavorare con la scena, localmente. Tieni presente che questo non influirà sulle altre persone, e che saranno ancora in grado di collaborare alla loro versione."
|
||||
},
|
||||
"errorDialog": {
|
||||
"title": "Errore"
|
||||
@@ -248,10 +244,8 @@
|
||||
"toast": {
|
||||
"copyStyles": "Stili copiati.",
|
||||
"copyToClipboard": "Copiato negli appunti.",
|
||||
"copyToClipboardAsPng": "{{exportSelection}} copiato negli appunti come PNG\n({{exportColorScheme}})",
|
||||
"copyToClipboardAsPng": "Copiato negli appunti come PNG.",
|
||||
"fileSaved": "File salvato.",
|
||||
"fileSavedToFilename": "Salvato in {filename}",
|
||||
"canvas": "tela",
|
||||
"selection": "selezione"
|
||||
"fileSavedToFilename": "Salvato in {filename}"
|
||||
}
|
||||
}
|
||||
|
||||
+4
-10
@@ -92,9 +92,7 @@
|
||||
"centerHorizontally": "横方向に中央揃え",
|
||||
"distributeHorizontally": "水平方向に分散配置",
|
||||
"distributeVertically": "垂直方向に分散配置",
|
||||
"viewMode": "閲覧モード",
|
||||
"toggleExportColorScheme": "",
|
||||
"share": ""
|
||||
"viewMode": "閲覧モード"
|
||||
},
|
||||
"buttons": {
|
||||
"clearReset": "キャンバスのリセット",
|
||||
@@ -143,7 +141,6 @@
|
||||
"confirmAddLibrary": "{{numShapes}} 個の図形をライブラリに追加します。よろしいですか?",
|
||||
"imageDoesNotContainScene": "現在、画像のインポートはサポートされていません。\n\nシーンをインポートしようとしましたか?この画像にはシーンデータが含まれていないようです。エクスポート中に有効にしていましたか?",
|
||||
"cannotRestoreFromImage": "このイメージファイルからシーンを復元できませんでした",
|
||||
"invalidSceneUrl": "",
|
||||
"resetLibrary": "ライブラリを消去します。本当によろしいですか?"
|
||||
},
|
||||
"toolBar": {
|
||||
@@ -200,8 +197,7 @@
|
||||
"button_stopSession": "セッションを終了する",
|
||||
"desc_inProgressIntro": "共同編集セッションが有効になっています。",
|
||||
"desc_shareLink": "下記URLを共同編集したい人に共有してください:",
|
||||
"desc_exitSession": "セッションを終了すると部屋から切断されますが、手元の環境で編集を続けることができます。変更内容は他の人には反映されません。",
|
||||
"shareTitle": ""
|
||||
"desc_exitSession": "セッションを終了すると部屋から切断されますが、手元の環境で編集を続けることができます。変更内容は他の人には反映されません。"
|
||||
},
|
||||
"errorDialog": {
|
||||
"title": "エラー"
|
||||
@@ -248,10 +244,8 @@
|
||||
"toast": {
|
||||
"copyStyles": "スタイルをコピー",
|
||||
"copyToClipboard": "クリップボードにコピー",
|
||||
"copyToClipboardAsPng": "",
|
||||
"copyToClipboardAsPng": "PNG形式でクリップボードにコピー",
|
||||
"fileSaved": "ファイルを保存しました",
|
||||
"fileSavedToFilename": "{filename} に保存しました",
|
||||
"canvas": "",
|
||||
"selection": ""
|
||||
"fileSavedToFilename": "{filename} に保存しました"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,7 +68,7 @@
|
||||
"layers": "Tissiyin",
|
||||
"actions": "Tigawin",
|
||||
"language": "Tutlayt",
|
||||
"liveCollaboration": "Amɛiwen s srid",
|
||||
"liveCollaboration": "",
|
||||
"duplicateSelection": "Sisleg",
|
||||
"untitled": "War azwel",
|
||||
"name": "Isem",
|
||||
@@ -92,9 +92,7 @@
|
||||
"centerHorizontally": "Di tlemmast s uglawi",
|
||||
"distributeHorizontally": "Freq s uglawi",
|
||||
"distributeVertically": "Freq s yibeddi",
|
||||
"viewMode": "Askar n tmuɣli",
|
||||
"toggleExportColorScheme": "Sermed/sens asifeḍ usentel n yini",
|
||||
"share": "Bḍu"
|
||||
"viewMode": "Askar n tmuɣli"
|
||||
},
|
||||
"buttons": {
|
||||
"clearReset": "Ales awennez n teɣzut n usuneɣ",
|
||||
@@ -119,7 +117,7 @@
|
||||
"edit": "Ẓreg",
|
||||
"undo": "Sefsex",
|
||||
"redo": "Err-d",
|
||||
"resetLibrary": "Ales awennez n temkarḍit",
|
||||
"resetLibrary": "",
|
||||
"createNewRoom": "Snulfu-d taxxamt tamaynutt",
|
||||
"fullScreen": "Agdil aččuran",
|
||||
"darkMode": "Askar imsulles",
|
||||
@@ -143,8 +141,7 @@
|
||||
"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",
|
||||
"invalidSceneUrl": "Ulamek taktert n usayes seg URL i d-ittunefken. Ahat mačči d tameɣtut neɣ ur tegbir ara isefka JSON n Excalidraw.",
|
||||
"resetLibrary": "Ayagi ad isfeḍ tamkarḍit-inek•m. Tetḥeqqeḍ?"
|
||||
"resetLibrary": ""
|
||||
},
|
||||
"toolBar": {
|
||||
"selection": "Tafrayt",
|
||||
@@ -200,8 +197,7 @@
|
||||
"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.",
|
||||
"shareTitle": "Rnu ɣer tɣimit n umɛiwen s srid n Excalidraw"
|
||||
"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"
|
||||
@@ -248,10 +244,8 @@
|
||||
"toast": {
|
||||
"copyStyles": "Iɣunab yettwaneɣlen.",
|
||||
"copyToClipboard": "Yettwaɣel ɣer tecfawit.",
|
||||
"copyToClipboardAsPng": "{{exportSelection}} yettwanɣel ɣer tecfawit am PNG\n({{exportColorScheme}})",
|
||||
"fileSaved": "Afaylu yettwasekles.",
|
||||
"fileSavedToFilename": "Yettwasekles di {filename}",
|
||||
"canvas": "taɣzut n usuneɣ",
|
||||
"selection": "tafrayt"
|
||||
"copyToClipboardAsPng": "Yettwanɣel ɣer tecfawit am PNG.",
|
||||
"fileSaved": "",
|
||||
"fileSavedToFilename": ""
|
||||
}
|
||||
}
|
||||
|
||||
+4
-10
@@ -92,9 +92,7 @@
|
||||
"centerHorizontally": "수평으로 중앙 정렬",
|
||||
"distributeHorizontally": "수평으로 분배",
|
||||
"distributeVertically": "수직으로 분배",
|
||||
"viewMode": "보기 모드",
|
||||
"toggleExportColorScheme": "",
|
||||
"share": ""
|
||||
"viewMode": "보기 모드"
|
||||
},
|
||||
"buttons": {
|
||||
"clearReset": "캔버스 초기화",
|
||||
@@ -143,7 +141,6 @@
|
||||
"confirmAddLibrary": "{{numShapes}}개의 모양이 라이브러리에 추가됩니다. 계속하시겠어요?",
|
||||
"imageDoesNotContainScene": "이미지에서 불러오기는 현재 지원되지 않습니다.\n\n화면을 불러오려고 하셨나요? 이미지에 화면 정보가 없는 것 같습니다. 내보낼 때 화면을 포함했나요?",
|
||||
"cannotRestoreFromImage": "이미지 파일에서 화면을 복구할 수 없었습니다",
|
||||
"invalidSceneUrl": "",
|
||||
"resetLibrary": ""
|
||||
},
|
||||
"toolBar": {
|
||||
@@ -200,8 +197,7 @@
|
||||
"button_stopSession": "세션 중단",
|
||||
"desc_inProgressIntro": "실시간 협업 세션이 진행 중입니다.",
|
||||
"desc_shareLink": "공동 작업자에게 이 링크를 공유하세요.",
|
||||
"desc_exitSession": "세션을 중단하면 연결은 끊어지나 작업을 이어갈 수 있습니다. 이 작업은 다른 작업자에게 영향을 미치지 않으며 각자의 공동 작업은 계속 유지됩니다.",
|
||||
"shareTitle": ""
|
||||
"desc_exitSession": "세션을 중단하면 연결은 끊어지나 작업을 이어갈 수 있습니다. 이 작업은 다른 작업자에게 영향을 미치지 않으며 각자의 공동 작업은 계속 유지됩니다."
|
||||
},
|
||||
"errorDialog": {
|
||||
"title": "오류"
|
||||
@@ -248,10 +244,8 @@
|
||||
"toast": {
|
||||
"copyStyles": "스타일 복사.",
|
||||
"copyToClipboard": "클립보드로 복사.",
|
||||
"copyToClipboardAsPng": "",
|
||||
"copyToClipboardAsPng": "클립보드로 PNG 이미지 복사.",
|
||||
"fileSaved": "",
|
||||
"fileSavedToFilename": "",
|
||||
"canvas": "",
|
||||
"selection": ""
|
||||
"fileSavedToFilename": ""
|
||||
}
|
||||
}
|
||||
|
||||
@@ -92,9 +92,7 @@
|
||||
"centerHorizontally": "အလျားလိုက်အလယ်ညှိ",
|
||||
"distributeHorizontally": "အလျားလိုက်",
|
||||
"distributeVertically": "ထောင်လိုက်",
|
||||
"viewMode": "",
|
||||
"toggleExportColorScheme": "",
|
||||
"share": ""
|
||||
"viewMode": ""
|
||||
},
|
||||
"buttons": {
|
||||
"clearReset": "ကားချပ်ရှင်းလင်း",
|
||||
@@ -143,7 +141,6 @@
|
||||
"confirmAddLibrary": "{{numShapes}} ခုသောပုံသဏ္ဌာန်အားမှတ်တမ်းတင်ပါမည်။ အတည်ပြုပါ။",
|
||||
"imageDoesNotContainScene": "",
|
||||
"cannotRestoreFromImage": "ဤပုံဖြင့်မြင်ကွင်းပြန်လည်မရယူနိုင်ပါ။",
|
||||
"invalidSceneUrl": "",
|
||||
"resetLibrary": ""
|
||||
},
|
||||
"toolBar": {
|
||||
@@ -200,8 +197,7 @@
|
||||
"button_stopSession": "ပူးပေါင်းမှုအဆုံးသတ်",
|
||||
"desc_inProgressIntro": "တိုက်ရိုက်ပူးပေါင်းရေးဆွဲမှုများပြုလုပ်နေပါသည်။",
|
||||
"desc_shareLink": "ဤလင့်ခ်အား ပူးပေါင်းရေးဆွဲလိုသူများထံပေးပို့ပါ။ ။ ",
|
||||
"desc_exitSession": "ပူးပေါင်းမှုရပ်တန့်ပါက အဖွဲ့အတွင်းမှထွက်ခွာသွားမည်ဖြစ်သော်လည်း မိမိမြင်ကွင်းတွင်ဆက်လက်ရေးဆွဲနိုင်ပါမည်။ အဖွဲ့အတွင်းကျန်ရှိနေခဲ့သောအခြားပါဝင်သူများသည်လည်း ဆက်လက်ပူးပေါင်းရေးဆွဲနေနိုင်ပါလိမ့်မည်။",
|
||||
"shareTitle": ""
|
||||
"desc_exitSession": "ပူးပေါင်းမှုရပ်တန့်ပါက အဖွဲ့အတွင်းမှထွက်ခွာသွားမည်ဖြစ်သော်လည်း မိမိမြင်ကွင်းတွင်ဆက်လက်ရေးဆွဲနိုင်ပါမည်။ အဖွဲ့အတွင်းကျန်ရှိနေခဲ့သောအခြားပါဝင်သူများသည်လည်း ဆက်လက်ပူးပေါင်းရေးဆွဲနေနိုင်ပါလိမ့်မည်။"
|
||||
},
|
||||
"errorDialog": {
|
||||
"title": "ချို့ယွင်းချက်"
|
||||
@@ -250,8 +246,6 @@
|
||||
"copyToClipboard": "",
|
||||
"copyToClipboardAsPng": "",
|
||||
"fileSaved": "",
|
||||
"fileSavedToFilename": "",
|
||||
"canvas": "",
|
||||
"selection": ""
|
||||
"fileSavedToFilename": ""
|
||||
}
|
||||
}
|
||||
|
||||
+4
-10
@@ -92,9 +92,7 @@
|
||||
"centerHorizontally": "Midtstill horisontalt",
|
||||
"distributeHorizontally": "Distribuer horisontalt",
|
||||
"distributeVertically": "Distribuer vertikalt",
|
||||
"viewMode": "Visningsmodus",
|
||||
"toggleExportColorScheme": "Veksle eksport av fargepalett",
|
||||
"share": "Del"
|
||||
"viewMode": "Visningsmodus"
|
||||
},
|
||||
"buttons": {
|
||||
"clearReset": "Tøm lerretet og tilbakestill bakgrunnsfargen",
|
||||
@@ -143,7 +141,6 @@
|
||||
"confirmAddLibrary": "Dette vil legge til {{numShapes}} figur(er) i biblioteket ditt. Er du sikker?",
|
||||
"imageDoesNotContainScene": "Importering av bilder støttes ikke for øyeblikket.\n\nVil du importere en scene? Dette bildet ser ikke ut til å inneholde noen scene-data. Har du aktivert dette under eksporten?",
|
||||
"cannotRestoreFromImage": "Scenen kunne ikke gjenopprettes fra denne bildefilen",
|
||||
"invalidSceneUrl": "Kunne ikke importere scene fra den oppgitte URL-en. Den er enten ødelagt, eller inneholder ikke gyldig Excalidraw JSON-data.",
|
||||
"resetLibrary": "Dette vil tømme biblioteket ditt. Er du sikker?"
|
||||
},
|
||||
"toolBar": {
|
||||
@@ -200,8 +197,7 @@
|
||||
"button_stopSession": "Stopp sesjon",
|
||||
"desc_inProgressIntro": "Sanntids-samarbeidsøkt er nå i gang.",
|
||||
"desc_shareLink": "Del denne linken med de du vil samarbeide med:",
|
||||
"desc_exitSession": "Dersom du avslutter sesjonen blir du frakoblet rommet, men du kan fortsette å arbeide med scenen lokalt. Vær oppmerksom på at dette ikke vil påvirke andre personer, og de vil fortsatt ha mulighet til å samarbeide på deres versjon.",
|
||||
"shareTitle": "Bli med i en live samarbeidsøkt på Excalidraw"
|
||||
"desc_exitSession": "Dersom du avslutter sesjonen blir du frakoblet rommet, men du kan fortsette å arbeide med scenen lokalt. Vær oppmerksom på at dette ikke vil påvirke andre personer, og de vil fortsatt ha mulighet til å samarbeide på deres versjon."
|
||||
},
|
||||
"errorDialog": {
|
||||
"title": "Feil"
|
||||
@@ -248,10 +244,8 @@
|
||||
"toast": {
|
||||
"copyStyles": "Kopierte stiler.",
|
||||
"copyToClipboard": "Kopiert til utklippstavlen.",
|
||||
"copyToClipboardAsPng": "Kopierte {{exportSelection}} til utklippstavlen som PNG\n({{exportColorScheme}})",
|
||||
"copyToClipboardAsPng": "Kopiert til utklippstavlen som PNG.",
|
||||
"fileSaved": "Fil lagret.",
|
||||
"fileSavedToFilename": "Lagret til {filename}",
|
||||
"canvas": "lerret",
|
||||
"selection": "utvalg"
|
||||
"fileSavedToFilename": "Lagret til {filename}"
|
||||
}
|
||||
}
|
||||
|
||||
+4
-10
@@ -92,9 +92,7 @@
|
||||
"centerHorizontally": "Horizontaal Centreren",
|
||||
"distributeHorizontally": "Horizontaal verspreiden",
|
||||
"distributeVertically": "Verticaal distribueren",
|
||||
"viewMode": "Weergavemodus",
|
||||
"toggleExportColorScheme": "Kleurenschema exporteren aan/uit",
|
||||
"share": "Deel"
|
||||
"viewMode": "Weergavemodus"
|
||||
},
|
||||
"buttons": {
|
||||
"clearReset": "Canvas opnieuw instellen",
|
||||
@@ -143,7 +141,6 @@
|
||||
"confirmAddLibrary": "Hiermee worden {{numShapes}} vorm(n) aan uw bibliotheek toegevoegd. Ben je het zeker?",
|
||||
"imageDoesNotContainScene": "Afbeeldingen importeren wordt op dit moment niet ondersteund.\n\nWil je een scène importeren? Deze afbeelding lijkt geen scène gegevens te bevatten. Heb je dit geactiveerd tijdens het exporteren?",
|
||||
"cannotRestoreFromImage": "Scène kan niet worden hersteld vanuit dit afbeeldingsbestand",
|
||||
"invalidSceneUrl": "Kan scène niet importeren vanuit de opgegeven URL. Het is onjuist of bevat geen geldige Excalidraw JSON-gegevens.",
|
||||
"resetLibrary": "Dit zal je bibliotheek wissen. Weet je het zeker?"
|
||||
},
|
||||
"toolBar": {
|
||||
@@ -200,8 +197,7 @@
|
||||
"button_stopSession": "Sessie afbreken",
|
||||
"desc_inProgressIntro": "De live-samenwerkingssessie is nu gestart.",
|
||||
"desc_shareLink": "Deel deze link met iedereen waarmee je wil samenwerken:",
|
||||
"desc_exitSession": "Het stoppen van de sessie zal je loskoppelen van de kamer, maar je kunt lokaal doorwerken met de scène.\nPas op: dit heeft geen invloed op andere mensen en dat zij nog steeds in staat zullen zijn om samen te werken aan hun versie.",
|
||||
"shareTitle": "Neem deel aan een live samenwerkingssessie op Excalidraw"
|
||||
"desc_exitSession": "Het stoppen van de sessie zal je loskoppelen van de kamer, maar je kunt lokaal doorwerken met de scène.\nPas op: dit heeft geen invloed op andere mensen en dat zij nog steeds in staat zullen zijn om samen te werken aan hun versie."
|
||||
},
|
||||
"errorDialog": {
|
||||
"title": "Fout"
|
||||
@@ -248,10 +244,8 @@
|
||||
"toast": {
|
||||
"copyStyles": "Stijlen gekopieerd.",
|
||||
"copyToClipboard": "Gekopieerd naar het klembord.",
|
||||
"copyToClipboardAsPng": "{{exportSelection}} naar klembord gekopieerd als PNG\n({{exportColorScheme}})",
|
||||
"copyToClipboardAsPng": "Gekopieerd naar klembord als PNG.",
|
||||
"fileSaved": "Bestand opgeslagen.",
|
||||
"fileSavedToFilename": "Opgeslagen als {filename}",
|
||||
"canvas": "canvas",
|
||||
"selection": "selectie"
|
||||
"fileSavedToFilename": "Opgeslagen als {filename}"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -92,9 +92,7 @@
|
||||
"centerHorizontally": "Midtstill horisontalt",
|
||||
"distributeHorizontally": "Sprei horisontalt",
|
||||
"distributeVertically": "Sprei vertikalt",
|
||||
"viewMode": "",
|
||||
"toggleExportColorScheme": "",
|
||||
"share": ""
|
||||
"viewMode": ""
|
||||
},
|
||||
"buttons": {
|
||||
"clearReset": "Tilbakestill lerretet",
|
||||
@@ -143,7 +141,6 @@
|
||||
"confirmAddLibrary": "Dette vil legge til {{numShapes}} form(er) i biblioteket ditt. Er du sikker?",
|
||||
"imageDoesNotContainScene": "Importering av bilder støttes ikkje for p. t.\n\nVil du importere ein scene? Dette bildet ser ikkje ut til å inneholde noen scene-data. Har du aktivert dette under eksporten?",
|
||||
"cannotRestoreFromImage": "Scena kunne ikkje gjenopprettast frå denne biletfila",
|
||||
"invalidSceneUrl": "",
|
||||
"resetLibrary": ""
|
||||
},
|
||||
"toolBar": {
|
||||
@@ -200,8 +197,7 @@
|
||||
"button_stopSession": "Stopp økt",
|
||||
"desc_inProgressIntro": "Sanntids-samarbeidsøkt er no i gang.",
|
||||
"desc_shareLink": "Del denne lenka med dei du vil samarbeide med:",
|
||||
"desc_exitSession": "Dersom du avsluttar økta blir du kopla frå rommet, men du kan halde fram med å arbeide med scena lokalt. Ver merksam på at dette ikkje vil påverke andre personar, og desse vil framleis ha moglegheit til å samarbeide på deira eigen versjon.",
|
||||
"shareTitle": ""
|
||||
"desc_exitSession": "Dersom du avsluttar økta blir du kopla frå rommet, men du kan halde fram med å arbeide med scena lokalt. Ver merksam på at dette ikkje vil påverke andre personar, og desse vil framleis ha moglegheit til å samarbeide på deira eigen versjon."
|
||||
},
|
||||
"errorDialog": {
|
||||
"title": "Feil"
|
||||
@@ -250,8 +246,6 @@
|
||||
"copyToClipboard": "",
|
||||
"copyToClipboardAsPng": "",
|
||||
"fileSaved": "",
|
||||
"fileSavedToFilename": "",
|
||||
"canvas": "",
|
||||
"selection": ""
|
||||
"fileSavedToFilename": ""
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user