Compare commits
100 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 154f7bd8e5 | |||
| ba06565673 | |||
| 3780a155f4 | |||
| 6252b22b42 | |||
| bb612fd768 | |||
| 1bb3d71d22 | |||
| 3912e87b1d | |||
| 72f1134878 | |||
| 6e629383ea | |||
| 612e71e38b | |||
| 00ac804dd8 | |||
| 1f7f07fbfb | |||
| beffc290fd | |||
| 9b58efd363 | |||
| 23b672484b | |||
| 3a0a638a0d | |||
| 862c065e33 | |||
| 420703ba50 | |||
| 4d6ef81c83 | |||
| 88b980a8e0 | |||
| d85c1955b4 | |||
| a27e599798 | |||
| d25ed7bf88 | |||
| 28601b88bd | |||
| 1edfcc08d8 | |||
| 030814c254 | |||
| eb24e8ffe4 | |||
| 07e71a8071 | |||
| bf97414530 | |||
| f8c3c431da | |||
| ef792ad906 | |||
| 06a945aded | |||
| 0d2f72f87e | |||
| 3d1cbf444d | |||
| c77c9ce65a | |||
| f295ba98c5 | |||
| 91eb8834e8 | |||
| 418589e7ad | |||
| bd63dcbcc5 | |||
| 785a944ac2 | |||
| 32acde500e | |||
| 053353841a | |||
| 286642ffcf | |||
| 7090938ec1 | |||
| 6233bc52e3 | |||
| 7f8ee06710 | |||
| 3e200634e0 | |||
| 701b02d6df | |||
| 535b2b682e | |||
| 1a4a736d94 | |||
| bb207ef861 | |||
| 2fcbf8658f | |||
| 6a8c6e7f47 | |||
| f962503425 | |||
| 02fdc506ee | |||
| 2ba6088e97 | |||
| 4e421e6e9e | |||
| d213dbb42d | |||
| a5779dd5d8 | |||
| 628b4c1eec | |||
| 31333e597b | |||
| 872b340f1b | |||
| 83e8167adf | |||
| baea88942c | |||
| ae35037a3b | |||
| 4f31ae1e4b | |||
| 704ee30ae6 | |||
| 176baef9c2 | |||
| 3558f07fe0 | |||
| fd24c74ab1 | |||
| ae6892501d | |||
| 1e6adaf0b5 | |||
| 7ccd38a37f | |||
| e6ce9e0ea7 | |||
| c0e05445b1 | |||
| b44531d94a | |||
| 464c2cc05e | |||
| bd13c2ed48 | |||
| 2e58aaae66 | |||
| d4c14d484c | |||
| 06d1871640 | |||
| e7a59335e4 | |||
| 0dbef18044 | |||
| e16c2d592f | |||
| 1f4cf4610f | |||
| 1bee959660 | |||
| f609a4ac3a | |||
| eee9d1bc16 | |||
| ecdc2582e9 | |||
| 245e13a884 | |||
| 8a322b22ed | |||
| 3f784d76fc | |||
| ba5afe9139 | |||
| 9e6f351672 | |||
| fcd10a6a43 | |||
| 3bc18f6aed | |||
| 7c5481b877 | |||
| d17464fbaa | |||
| baf9da2b83 | |||
| 4bfcf105a5 |
+6
-6
@@ -1,10 +1,10 @@
|
||||
*
|
||||
!.env
|
||||
!.eslintrc.json
|
||||
!.npmrc
|
||||
!.prettierrc
|
||||
!package.json
|
||||
!public/
|
||||
!src/
|
||||
!.npmrc
|
||||
!.eslintrc.json
|
||||
!.prettierrc
|
||||
!package-lock.json
|
||||
!package.json
|
||||
!tsconfig.json
|
||||
!.env
|
||||
!yarn.lock
|
||||
|
||||
@@ -4,3 +4,4 @@ package-lock.json
|
||||
.vscode/
|
||||
firebase/
|
||||
dist/
|
||||
public/workbox
|
||||
|
||||
+2
-36
@@ -1,40 +1,6 @@
|
||||
{
|
||||
"extends": ["prettier", "react-app"],
|
||||
"plugins": ["prettier"],
|
||||
"extends": ["@excalidraw/eslint-config", "react-app"],
|
||||
"rules": {
|
||||
"@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"
|
||||
"import/no-anonymous-default-export": "off"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,36 +1,33 @@
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: npm
|
||||
directory: "/"
|
||||
directory: /
|
||||
schedule:
|
||||
interval: weekly
|
||||
day: sunday
|
||||
time: "01:00"
|
||||
open-pull-requests-limit: 99
|
||||
reviewers:
|
||||
- lipis
|
||||
assignees:
|
||||
- lipis
|
||||
|
||||
- package-ecosystem: npm
|
||||
directory: "/src/packages/excalidraw/"
|
||||
directory: /src/packages/excalidraw/
|
||||
schedule:
|
||||
interval: weekly
|
||||
day: sunday
|
||||
time: "01:00"
|
||||
open-pull-requests-limit: 99
|
||||
reviewers:
|
||||
- ad1992
|
||||
assignees:
|
||||
- ad1992
|
||||
|
||||
- package-ecosystem: npm
|
||||
directory: "/src/packages/utils/"
|
||||
directory: /src/packages/utils/
|
||||
schedule:
|
||||
interval: weekly
|
||||
day: sunday
|
||||
time: "01:00"
|
||||
open-pull-requests-limit: 99
|
||||
reviewers:
|
||||
- ad1992
|
||||
assignees:
|
||||
|
||||
@@ -6,9 +6,8 @@ on:
|
||||
- master
|
||||
|
||||
jobs:
|
||||
build:
|
||||
build-docker:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- uses: actions/checkout@v2
|
||||
- run: docker build -t excalidraw .
|
||||
|
||||
@@ -7,27 +7,23 @@ on:
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
packages:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
|
||||
- uses: actions/checkout@v2
|
||||
- name: Setup Node.js 14.x
|
||||
uses: actions/setup-node@v1
|
||||
uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: 14.x
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
npm ci
|
||||
npm ci --prefix src/packages/excalidraw
|
||||
npm ci --prefix src/packages/utils
|
||||
|
||||
yarn --frozen-lockfile
|
||||
yarn --cwd src/packages/excalidraw
|
||||
yarn --cwd src/packages/utils
|
||||
- name: Build @excalidraw/excalidraw
|
||||
run: |
|
||||
npm run pack --prefix src/packages/excalidraw
|
||||
|
||||
yarn --cwd src/packages/excalidraw run pack
|
||||
- name: Build @excalidraw/utils
|
||||
run: |
|
||||
npm run pack --prefix src/packages/utils
|
||||
yarn --cwd src/packages/utils run pack
|
||||
|
||||
@@ -9,7 +9,6 @@ on:
|
||||
jobs:
|
||||
cancel:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
timeout-minutes: 3
|
||||
steps:
|
||||
- uses: styfle/cancel-workflow-action@0.6.0
|
||||
|
||||
@@ -7,16 +7,16 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Setup Node.js 14.x
|
||||
uses: actions/setup-node@v1
|
||||
uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: 14.x
|
||||
|
||||
- name: Install and lint
|
||||
run: |
|
||||
npm ci
|
||||
npm run test:other
|
||||
npm run test:code
|
||||
npm run test:typecheck
|
||||
yarn --frozen-lockfile
|
||||
yarn test:other
|
||||
yarn test:code
|
||||
yarn test:typecheck
|
||||
|
||||
@@ -3,7 +3,7 @@ name: Build locales coverage
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- "l10n_master"
|
||||
- l10n_master
|
||||
|
||||
jobs:
|
||||
locales:
|
||||
@@ -15,13 +15,13 @@ jobs:
|
||||
token: ${{ secrets.PUSH_TRANSLATIONS_COVERAGE_PAT }}
|
||||
|
||||
- name: Setup Node.js 14.x
|
||||
uses: actions/setup-node@v1
|
||||
uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: 14.x
|
||||
|
||||
- name: Create report file
|
||||
run: |
|
||||
npm run locales-coverage
|
||||
yarn locales-coverage
|
||||
FILE_CHANGED=$(git diff src/locales/percentages.json)
|
||||
if [ ! -z "${FILE_CHANGED}" ]; then
|
||||
git config --global user.name 'Excalidraw Bot'
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
name: "Semantic PR title"
|
||||
name: Semantic PR title
|
||||
|
||||
on:
|
||||
pull_request_target:
|
||||
@@ -8,9 +8,8 @@ on:
|
||||
- synchronize
|
||||
|
||||
jobs:
|
||||
main:
|
||||
semantic:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: amannn/action-semantic-pull-request@v3.0.0
|
||||
env:
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
name: New Sentry Production Release
|
||||
name: New Sentry production release
|
||||
|
||||
on:
|
||||
push:
|
||||
@@ -6,28 +6,23 @@ on:
|
||||
- master
|
||||
|
||||
jobs:
|
||||
release:
|
||||
sentry:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v1.0.0
|
||||
|
||||
- uses: actions/checkout@v2
|
||||
- name: Setup Node.js 14.x
|
||||
uses: actions/setup-node@v1
|
||||
uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: 14.x
|
||||
|
||||
- name: Install and build
|
||||
run: |
|
||||
npm ci
|
||||
npm run build:app
|
||||
yarn --frozen-lockfile
|
||||
yarn build:app
|
||||
env:
|
||||
CI: true
|
||||
|
||||
- name: Install Sentry
|
||||
run: |
|
||||
curl -sL https://sentry.io/get-cli/ | bash
|
||||
|
||||
- name: Create new Sentry release
|
||||
run: |
|
||||
export SENTRY_RELEASE=$(sentry-cli releases propose-version)
|
||||
|
||||
@@ -5,16 +5,13 @@ on: pull_request
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
|
||||
- uses: actions/checkout@v2
|
||||
- name: Setup Node.js 14.x
|
||||
uses: actions/setup-node@v1
|
||||
uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: 14.x
|
||||
|
||||
- name: Install and test
|
||||
run: |
|
||||
npm ci
|
||||
npm run test:app
|
||||
yarn --frozen-lockfile
|
||||
yarn test:app
|
||||
|
||||
+1
-1
@@ -16,7 +16,7 @@ firebase
|
||||
logs
|
||||
node_modules
|
||||
npm-debug.log*
|
||||
package-lock.json
|
||||
static
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
yarn.lock
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
{
|
||||
"proseWrap": "never",
|
||||
"trailingComma": "all"
|
||||
}
|
||||
+3
-3
@@ -2,13 +2,13 @@ FROM node:14-alpine AS build
|
||||
|
||||
WORKDIR /opt/node_app
|
||||
|
||||
COPY package.json package-lock.json ./
|
||||
RUN npm i --no-optional
|
||||
COPY package.json yarn.lock ./
|
||||
RUN yarn --ignore-optional
|
||||
|
||||
ARG NODE_ENV=production
|
||||
|
||||
COPY . .
|
||||
RUN npm run build:app:docker
|
||||
RUN yarn build:app:docker
|
||||
|
||||
FROM nginx:1.17-alpine
|
||||
|
||||
|
||||
@@ -86,6 +86,12 @@ Try out [`@excalidraw/excalidraw`](https://www.npmjs.com/package/@excalidraw/exc
|
||||
|
||||
These instructions will get you a copy of the project up and running on your local machine for development and testing purposes.
|
||||
|
||||
#### Requirements
|
||||
|
||||
- [Node.js](https://nodejs.org/en/)
|
||||
- [Yarn](https://yarnpkg.com/getting-started/install)
|
||||
- [Git](https://git-scm.com/downloads)
|
||||
|
||||
#### Clone the repo
|
||||
|
||||
```bash
|
||||
@@ -94,14 +100,14 @@ git clone https://github.com/excalidraw/excalidraw.git
|
||||
|
||||
#### Commands
|
||||
|
||||
| Command | Description |
|
||||
| --------------------- | --------------------------------- |
|
||||
| `npm install` | Install the dependencies |
|
||||
| `npm start` | Run the project |
|
||||
| `npm run fix` | Reformat all files with Prettier |
|
||||
| `npm test` | Run tests |
|
||||
| `npm run test:update` | Update test snapshots |
|
||||
| `npm run test:code` | Test for formatting with Prettier |
|
||||
| Command | Description |
|
||||
| ------------------ | --------------------------------- |
|
||||
| `yarn` | Install the dependencies |
|
||||
| `yarn start` | Run the project |
|
||||
| `yarn fix` | Reformat all files with Prettier |
|
||||
| `yarn test` | Run tests |
|
||||
| `yarn test:update` | Update test snapshots |
|
||||
| `yarn test:code` | Test for formatting with Prettier |
|
||||
|
||||
#### Docker Compose
|
||||
|
||||
|
||||
+1
-1
@@ -18,7 +18,7 @@ services:
|
||||
volumes:
|
||||
- ./:/opt/node_app/app:delegated
|
||||
- ./package.json:/opt/node_app/package.json
|
||||
- ./package-lock.json:/opt/node_app/package-lock.json
|
||||
- ./yarn.lock:/opt/node_app/yarn.lock
|
||||
- notused:/opt/node_app/app/node_modules
|
||||
|
||||
volumes:
|
||||
|
||||
Generated
-23611
File diff suppressed because it is too large
Load Diff
+22
-19
@@ -19,21 +19,20 @@
|
||||
]
|
||||
},
|
||||
"dependencies": {
|
||||
"@sentry/browser": "6.1.0",
|
||||
"@sentry/integrations": "6.1.0",
|
||||
"@sentry/browser": "6.2.1",
|
||||
"@sentry/integrations": "6.2.1",
|
||||
"@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.35",
|
||||
"browser-fs-access": "0.13.1",
|
||||
"browser-fs-access": "0.14.1",
|
||||
"clsx": "1.1.1",
|
||||
"firebase": "8.2.7",
|
||||
"firebase": "8.2.10",
|
||||
"i18next-browser-languagedetector": "6.0.1",
|
||||
"lodash.throttle": "4.1.1",
|
||||
"nanoid": "3.1.20",
|
||||
"node-sass": "4.14.1",
|
||||
"open-color": "1.8.0",
|
||||
"pako": "1.0.11",
|
||||
"png-chunk-text": "1.0.0",
|
||||
@@ -43,18 +42,21 @@
|
||||
"pwacompat": "2.0.17",
|
||||
"react": "17.0.1",
|
||||
"react-dom": "17.0.1",
|
||||
"react-scripts": "4.0.2",
|
||||
"react-scripts": "4.0.3",
|
||||
"roughjs": "4.3.1",
|
||||
"sass": "1.32.8",
|
||||
"socket.io-client": "2.3.1",
|
||||
"typescript": "4.1.5"
|
||||
"typescript": "4.2.3"
|
||||
},
|
||||
"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": "7.2.0",
|
||||
"eslint-config-prettier": "8.1.0",
|
||||
"eslint-plugin-prettier": "3.3.1",
|
||||
"firebase-tools": "9.3.0",
|
||||
"firebase-tools": "9.5.0",
|
||||
"husky": "4.3.8",
|
||||
"jest-canvas-mock": "2.3.1",
|
||||
"lint-staged": "10.5.4",
|
||||
@@ -63,7 +65,7 @@
|
||||
"rewire": "5.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12.0.0"
|
||||
"node": ">=14.0.0"
|
||||
},
|
||||
"homepage": ".",
|
||||
"husky": {
|
||||
@@ -78,28 +80,29 @@
|
||||
"resetMocks": false
|
||||
},
|
||||
"name": "excalidraw",
|
||||
"prettier": "@excalidraw/prettier-config",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"build-node": "node ./scripts/build-node.js",
|
||||
"build:app:docker": "REACT_APP_DISABLE_SENTRY=true react-scripts build",
|
||||
"build:app": "REACT_APP_GIT_SHA=$VERCEL_GIT_COMMIT_SHA react-scripts build",
|
||||
"build:version": "node ./scripts/build-version.js",
|
||||
"build": "npm run build:app && npm run build:version",
|
||||
"build": "yarn build:app && yarn build:version",
|
||||
"eject": "react-scripts eject",
|
||||
"fix:code": "npm run test:code -- --fix",
|
||||
"fix:other": "npm run prettier -- --write",
|
||||
"fix": "npm run fix:other && npm run fix:code",
|
||||
"fix:code": "yarn test:code --fix",
|
||||
"fix:other": "yarn prettier --write",
|
||||
"fix": "yarn fix:other && yarn fix:code",
|
||||
"locales-coverage": "node scripts/build-locales-coverage.js",
|
||||
"locales-coverage:description": "node scripts/locales-coverage-description.js",
|
||||
"prettier": "prettier \"**/*.{css,scss,json,md,html,yml}\" --ignore-path=.eslintignore",
|
||||
"start": "react-scripts start",
|
||||
"test:all": "npm run test:typecheck && npm run test:code && npm run test:other && npm run test:app -- --watchAll=false",
|
||||
"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 --ignore-path .gitignore --ext .js,.ts,.tsx .",
|
||||
"test:code": "eslint --max-warnings=0 --ext .js,.ts,.tsx .",
|
||||
"test:debug": "react-scripts --inspect-brk test --runInBand --no-cache",
|
||||
"test:other": "npm run prettier -- --list-different",
|
||||
"test:other": "yarn prettier --list-different",
|
||||
"test:typecheck": "tsc",
|
||||
"test:update": "npm run test:app -- --updateSnapshot --watchAll=false",
|
||||
"test": "npm run test:app"
|
||||
"test:update": "yarn test:app --updateSnapshot --watchAll=false",
|
||||
"test": "yarn test:app"
|
||||
}
|
||||
}
|
||||
|
||||
Binary file not shown.
Binary file not shown.
+1
-1
@@ -1,7 +1,7 @@
|
||||
/* http://www.eaglefonts.com/fg-virgil-ttf-131249.htm */
|
||||
@font-face {
|
||||
font-family: "Virgil";
|
||||
src: url("FG_Virgil.woff2");
|
||||
src: url("Virgil.woff2");
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
|
||||
+4
-2
@@ -60,7 +60,7 @@
|
||||
|
||||
<link
|
||||
rel="preload"
|
||||
href="FG_Virgil.woff2"
|
||||
href="Virgil.woff2"
|
||||
as="font"
|
||||
type="font/woff2"
|
||||
crossorigin="anonymous"
|
||||
@@ -86,7 +86,9 @@
|
||||
/>
|
||||
|
||||
<link rel="stylesheet" href="fonts.css" type="text/css" />
|
||||
|
||||
<script>
|
||||
window.EXCALIDRAW_ASSET_PATH = "/";
|
||||
</script>
|
||||
<% if (process.env.REACT_APP_GOOGLE_ANALYTICS_ID) { %>
|
||||
<script
|
||||
async
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
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
|
||||
@@ -0,0 +1,2 @@
|
||||
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
|
||||
@@ -0,0 +1,2 @@
|
||||
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
@@ -0,0 +1,2 @@
|
||||
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
|
||||
@@ -0,0 +1,2 @@
|
||||
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
|
||||
@@ -0,0 +1,2 @@
|
||||
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
|
||||
@@ -0,0 +1,2 @@
|
||||
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
|
||||
@@ -0,0 +1,2 @@
|
||||
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
|
||||
@@ -0,0 +1,2 @@
|
||||
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
|
||||
@@ -0,0 +1,2 @@
|
||||
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
|
||||
@@ -0,0 +1,2 @@
|
||||
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
|
||||
@@ -0,0 +1,2 @@
|
||||
!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
|
||||
@@ -0,0 +1,2 @@
|
||||
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
|
||||
@@ -0,0 +1,2 @@
|
||||
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
|
||||
@@ -0,0 +1,2 @@
|
||||
!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
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
// In order to run:
|
||||
// npm install canvas # please do not check it in
|
||||
// npm run build-node
|
||||
// yarn build-node
|
||||
// node build/static/js/build-node.js
|
||||
// open test.png
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@ 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",
|
||||
@@ -60,6 +61,7 @@ const flags = {
|
||||
"nb-NO": "🇳🇴",
|
||||
"nl-NL": "🇳🇱",
|
||||
"nn-NO": "🇳🇴",
|
||||
"oc-FR": "🏳",
|
||||
"pa-IN": "🇮🇳",
|
||||
"pl-PL": "🇵🇱",
|
||||
"pt-BR": "🇧🇷",
|
||||
@@ -96,6 +98,7 @@ 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",
|
||||
|
||||
@@ -17,7 +17,7 @@ export const actionCopy = register({
|
||||
};
|
||||
},
|
||||
contextItemLabel: "labels.copy",
|
||||
keyTest: (event) => event[KEYS.CTRL_OR_CMD] && event.code === CODES.C,
|
||||
// Don't assign keyTest since its handled via copy event
|
||||
});
|
||||
|
||||
export const actionCut = register({
|
||||
@@ -94,7 +94,14 @@ export const actionCopyAsPng = register({
|
||||
return {
|
||||
appState: {
|
||||
...appState,
|
||||
toastMessage: t("toast.copyToClipboardAsPng"),
|
||||
toastMessage: t("toast.copyToClipboardAsPng", {
|
||||
exportSelection: selectedElements.length
|
||||
? t("toast.selection")
|
||||
: t("toast.canvas"),
|
||||
exportColorScheme: appState.exportWithDarkMode
|
||||
? t("buttons.darkMode")
|
||||
: t("buttons.lightMode"),
|
||||
}),
|
||||
},
|
||||
commitToHistory: false,
|
||||
};
|
||||
|
||||
@@ -5,6 +5,7 @@ import { ProjectName } from "../components/ProjectName";
|
||||
import { ToolButton } from "../components/ToolButton";
|
||||
import "../components/ToolIcon.scss";
|
||||
import { Tooltip } from "../components/Tooltip";
|
||||
import { DarkModeToggle, Appearence } from "../components/DarkModeToggle";
|
||||
import { loadFromJSON, saveAsJSON } from "../data";
|
||||
import { t } from "../i18n";
|
||||
import useIsMobile from "../is-mobile";
|
||||
@@ -204,3 +205,31 @@ export const actionLoadScene = register({
|
||||
/>
|
||||
),
|
||||
});
|
||||
|
||||
export const actionExportWithDarkMode = register({
|
||||
name: "exportWithDarkMode",
|
||||
perform: (_elements, appState, value) => {
|
||||
return {
|
||||
appState: { ...appState, exportWithDarkMode: value },
|
||||
commitToHistory: false,
|
||||
};
|
||||
},
|
||||
PanelComponent: ({ appState, updateData }) => (
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
justifyContent: "flex-end",
|
||||
marginTop: "-45px",
|
||||
marginBottom: "10px",
|
||||
}}
|
||||
>
|
||||
<DarkModeToggle
|
||||
value={appState.exportWithDarkMode ? "dark" : "light"}
|
||||
onChange={(appearance: Appearence) => {
|
||||
updateData(appearance === "dark");
|
||||
}}
|
||||
title={t("labels.toggleExportColorScheme")}
|
||||
/>
|
||||
</div>
|
||||
),
|
||||
});
|
||||
|
||||
@@ -18,7 +18,7 @@ import { isBindingElement } from "../element/typeChecks";
|
||||
|
||||
export const actionFinalize = register({
|
||||
name: "finalize",
|
||||
perform: (elements, appState) => {
|
||||
perform: (elements, appState, _, { canvas }) => {
|
||||
if (appState.editingLinearElement) {
|
||||
const {
|
||||
elementId,
|
||||
@@ -126,7 +126,7 @@ export const actionFinalize = register({
|
||||
(!appState.elementLocked && appState.elementType !== "draw") ||
|
||||
!multiPointElement
|
||||
) {
|
||||
resetCursor();
|
||||
resetCursor(canvas);
|
||||
}
|
||||
return {
|
||||
elements: newElements,
|
||||
|
||||
@@ -85,7 +85,8 @@ export type ActionName =
|
||||
| "alignHorizontallyCentered"
|
||||
| "distributeHorizontally"
|
||||
| "distributeVertically"
|
||||
| "viewMode";
|
||||
| "viewMode"
|
||||
| "exportWithDarkMode";
|
||||
|
||||
export interface Action {
|
||||
name: ActionName;
|
||||
|
||||
@@ -40,6 +40,7 @@ export const getDefaultAppState = (): Omit<
|
||||
errorMessage: null,
|
||||
exportBackground: true,
|
||||
exportEmbedScene: false,
|
||||
exportWithDarkMode: false,
|
||||
fileHandle: null,
|
||||
gridSize: null,
|
||||
height: window.innerHeight,
|
||||
@@ -118,6 +119,7 @@ const APP_STATE_STORAGE_CONF = (<
|
||||
errorMessage: { browser: false, export: false },
|
||||
exportBackground: { browser: true, export: false },
|
||||
exportEmbedScene: { browser: true, export: false },
|
||||
exportWithDarkMode: { browser: true, export: false },
|
||||
fileHandle: { browser: false, export: false },
|
||||
gridSize: { browser: true, export: true },
|
||||
height: { browser: false, export: false },
|
||||
|
||||
@@ -151,10 +151,12 @@ const LIBRARY_ICON = (
|
||||
);
|
||||
|
||||
export const ShapesSwitcher = ({
|
||||
canvas,
|
||||
elementType,
|
||||
setAppState,
|
||||
isLibraryOpen,
|
||||
}: {
|
||||
canvas: HTMLCanvasElement | null;
|
||||
elementType: ExcalidrawElement["type"];
|
||||
setAppState: React.Component<any, AppState>["setState"];
|
||||
isLibraryOpen: boolean;
|
||||
@@ -185,7 +187,7 @@ export const ShapesSwitcher = ({
|
||||
multiElement: null,
|
||||
selectedElementIds: {},
|
||||
});
|
||||
setCursorForShape(value);
|
||||
setCursorForShape(canvas, value);
|
||||
setAppState({});
|
||||
}}
|
||||
/>
|
||||
|
||||
+93
-64
@@ -172,6 +172,7 @@ import {
|
||||
ResolvablePromise,
|
||||
resolvablePromise,
|
||||
sceneCoordsToViewportCoords,
|
||||
setCursor,
|
||||
setCursorForShape,
|
||||
tupleToCoors,
|
||||
viewportCoordsToSceneCoords,
|
||||
@@ -413,8 +414,6 @@ class App extends React.Component<ExcalidrawProps, AppState> {
|
||||
zenModeEnabled,
|
||||
width: canvasDOMWidth,
|
||||
height: canvasDOMHeight,
|
||||
offsetTop,
|
||||
offsetLeft,
|
||||
viewModeEnabled,
|
||||
} = this.state;
|
||||
|
||||
@@ -432,8 +431,6 @@ class App extends React.Component<ExcalidrawProps, AppState> {
|
||||
style={{
|
||||
width: canvasDOMWidth,
|
||||
height: canvasDOMHeight,
|
||||
top: offsetTop,
|
||||
left: offsetLeft,
|
||||
}}
|
||||
>
|
||||
<LayerUI
|
||||
@@ -535,18 +532,22 @@ class App extends React.Component<ExcalidrawProps, AppState> {
|
||||
}
|
||||
|
||||
this.setState(
|
||||
(state) => ({
|
||||
...actionResult.appState,
|
||||
editingElement:
|
||||
editingElement || actionResult.appState?.editingElement || null,
|
||||
width: state.width,
|
||||
height: state.height,
|
||||
offsetTop: state.offsetTop,
|
||||
offsetLeft: state.offsetLeft,
|
||||
viewModeEnabled,
|
||||
zenModeEnabled,
|
||||
gridSize,
|
||||
}),
|
||||
(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,
|
||||
});
|
||||
},
|
||||
() => {
|
||||
if (actionResult.syncHistory) {
|
||||
history.setCurrentState(
|
||||
@@ -672,19 +673,24 @@ class App extends React.Component<ExcalidrawProps, AppState> {
|
||||
|
||||
scene.appState = {
|
||||
...scene.appState,
|
||||
...calculateScrollCenter(
|
||||
scene.elements,
|
||||
{
|
||||
...scene.appState,
|
||||
width: this.state.width,
|
||||
height: this.state.height,
|
||||
offsetTop: this.state.offsetTop,
|
||||
offsetLeft: this.state.offsetLeft,
|
||||
},
|
||||
null,
|
||||
),
|
||||
isLoading: false,
|
||||
};
|
||||
if (initialData?.scrollToCenter) {
|
||||
scene.appState = {
|
||||
...scene.appState,
|
||||
...calculateScrollCenter(
|
||||
scene.elements,
|
||||
{
|
||||
...scene.appState,
|
||||
width: this.state.width,
|
||||
height: this.state.height,
|
||||
offsetTop: this.state.offsetTop,
|
||||
offsetLeft: this.state.offsetLeft,
|
||||
},
|
||||
null,
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
this.resetHistory();
|
||||
this.syncActionResult({
|
||||
@@ -1002,7 +1008,13 @@ class App extends React.Component<ExcalidrawProps, AppState> {
|
||||
}
|
||||
|
||||
private onScroll = debounce(() => {
|
||||
this.setState({ ...this.getCanvasOffsets() });
|
||||
const { offsetTop, offsetLeft } = this.getCanvasOffsets();
|
||||
this.setState((state) => {
|
||||
if (state.offsetLeft === offsetLeft && state.offsetTop === offsetTop) {
|
||||
return null;
|
||||
}
|
||||
return { offsetTop, offsetLeft };
|
||||
});
|
||||
}, SCROLL_TIMEOUT);
|
||||
|
||||
// Copy/paste
|
||||
@@ -1016,6 +1028,13 @@ class App extends React.Component<ExcalidrawProps, AppState> {
|
||||
});
|
||||
|
||||
private onCopy = withBatchedUpdates((event: ClipboardEvent) => {
|
||||
const activeSelection = document.getSelection();
|
||||
if (
|
||||
activeSelection?.anchorNode &&
|
||||
!this.excalidrawContainerRef.current!.contains(activeSelection.anchorNode)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
if (isWritableElement(event.target)) {
|
||||
return;
|
||||
}
|
||||
@@ -1435,16 +1454,16 @@ class App extends React.Component<ExcalidrawProps, AppState> {
|
||||
}
|
||||
if (event.key === KEYS.SPACE && gesture.pointers.size === 0) {
|
||||
isHoldingSpace = true;
|
||||
document.documentElement.style.cursor = CURSOR_TYPE.GRABBING;
|
||||
setCursor(this.canvas, CURSOR_TYPE.GRABBING);
|
||||
}
|
||||
});
|
||||
|
||||
private onKeyUp = withBatchedUpdates((event: KeyboardEvent) => {
|
||||
if (event.key === KEYS.SPACE) {
|
||||
if (this.state.elementType === "selection") {
|
||||
resetCursor();
|
||||
resetCursor(this.canvas);
|
||||
} else {
|
||||
setCursorForShape(this.state.elementType);
|
||||
setCursorForShape(this.canvas, this.state.elementType);
|
||||
this.setState({
|
||||
selectedElementIds: {},
|
||||
selectedGroupIds: {},
|
||||
@@ -1470,7 +1489,7 @@ class App extends React.Component<ExcalidrawProps, AppState> {
|
||||
|
||||
private selectShapeTool(elementType: AppState["elementType"]) {
|
||||
if (!isHoldingSpace) {
|
||||
setCursorForShape(elementType);
|
||||
setCursorForShape(this.canvas, elementType);
|
||||
}
|
||||
if (isToolIcon(document.activeElement)) {
|
||||
document.activeElement.blur();
|
||||
@@ -1566,7 +1585,10 @@ class App extends React.Component<ExcalidrawProps, AppState> {
|
||||
},
|
||||
this.state,
|
||||
);
|
||||
return [viewportX, viewportY];
|
||||
return [
|
||||
viewportX - this.state.offsetLeft,
|
||||
viewportY - this.state.offsetTop,
|
||||
];
|
||||
},
|
||||
onChange: withBatchedUpdates((text) => {
|
||||
updateElement(text);
|
||||
@@ -1596,7 +1618,7 @@ class App extends React.Component<ExcalidrawProps, AppState> {
|
||||
editingElement: null,
|
||||
});
|
||||
if (this.state.elementLocked) {
|
||||
setCursorForShape(this.state.elementType);
|
||||
setCursorForShape(this.canvas, this.state.elementType);
|
||||
}
|
||||
}),
|
||||
element,
|
||||
@@ -1777,7 +1799,7 @@ class App extends React.Component<ExcalidrawProps, AppState> {
|
||||
return;
|
||||
}
|
||||
|
||||
resetCursor();
|
||||
resetCursor(this.canvas);
|
||||
|
||||
const { x: sceneX, y: sceneY } = viewportCoordsToSceneCoords(
|
||||
event,
|
||||
@@ -1809,7 +1831,7 @@ class App extends React.Component<ExcalidrawProps, AppState> {
|
||||
}
|
||||
}
|
||||
|
||||
resetCursor();
|
||||
resetCursor(this.canvas);
|
||||
|
||||
if (!event[KEYS.CTRL_OR_CMD]) {
|
||||
this.startTextEditing({
|
||||
@@ -1875,9 +1897,9 @@ class App extends React.Component<ExcalidrawProps, AppState> {
|
||||
const isOverScrollBar = isPointerOverScrollBars.isOverEither;
|
||||
if (!this.state.draggingElement && !this.state.multiElement) {
|
||||
if (isOverScrollBar) {
|
||||
resetCursor();
|
||||
resetCursor(this.canvas);
|
||||
} else {
|
||||
setCursorForShape(this.state.elementType);
|
||||
setCursorForShape(this.canvas, this.state.elementType);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1928,7 +1950,7 @@ class App extends React.Component<ExcalidrawProps, AppState> {
|
||||
const { points, lastCommittedPoint } = multiElement;
|
||||
const lastPoint = points[points.length - 1];
|
||||
|
||||
setCursorForShape(this.state.elementType);
|
||||
setCursorForShape(this.canvas, this.state.elementType);
|
||||
|
||||
if (lastPoint === lastCommittedPoint) {
|
||||
// if we haven't yet created a temp point and we're beyond commit-zone
|
||||
@@ -1945,7 +1967,7 @@ class App extends React.Component<ExcalidrawProps, AppState> {
|
||||
points: [...points, [scenePointerX - rx, scenePointerY - ry]],
|
||||
});
|
||||
} else {
|
||||
document.documentElement.style.cursor = CURSOR_TYPE.POINTER;
|
||||
setCursor(this.canvas, 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).
|
||||
}
|
||||
@@ -1959,13 +1981,13 @@ class App extends React.Component<ExcalidrawProps, AppState> {
|
||||
lastCommittedPoint[1],
|
||||
) < LINE_CONFIRM_THRESHOLD
|
||||
) {
|
||||
document.documentElement.style.cursor = CURSOR_TYPE.POINTER;
|
||||
setCursor(this.canvas, CURSOR_TYPE.POINTER);
|
||||
mutateElement(multiElement, {
|
||||
points: points.slice(0, -1),
|
||||
});
|
||||
} else {
|
||||
if (isPathALoop(points, this.state.zoom.value)) {
|
||||
document.documentElement.style.cursor = CURSOR_TYPE.POINTER;
|
||||
setCursor(this.canvas, CURSOR_TYPE.POINTER);
|
||||
}
|
||||
// update last uncommitted point
|
||||
mutateElement(multiElement, {
|
||||
@@ -2008,8 +2030,9 @@ class App extends React.Component<ExcalidrawProps, AppState> {
|
||||
elementWithTransformHandleType &&
|
||||
elementWithTransformHandleType.transformHandleType
|
||||
) {
|
||||
document.documentElement.style.cursor = getCursorForResizingElement(
|
||||
elementWithTransformHandleType,
|
||||
setCursor(
|
||||
this.canvas,
|
||||
getCursorForResizingElement(elementWithTransformHandleType),
|
||||
);
|
||||
return;
|
||||
}
|
||||
@@ -2022,9 +2045,12 @@ class App extends React.Component<ExcalidrawProps, AppState> {
|
||||
event.pointerType,
|
||||
);
|
||||
if (transformHandleType) {
|
||||
document.documentElement.style.cursor = getCursorForResizingElement({
|
||||
transformHandleType,
|
||||
});
|
||||
setCursor(
|
||||
this.canvas,
|
||||
getCursorForResizingElement({
|
||||
transformHandleType,
|
||||
}),
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -2034,11 +2060,12 @@ class App extends React.Component<ExcalidrawProps, AppState> {
|
||||
scenePointer.y,
|
||||
);
|
||||
if (this.state.elementType === "text") {
|
||||
document.documentElement.style.cursor = isTextElement(hitElement)
|
||||
? CURSOR_TYPE.TEXT
|
||||
: CURSOR_TYPE.CROSSHAIR;
|
||||
setCursor(
|
||||
this.canvas,
|
||||
isTextElement(hitElement) ? CURSOR_TYPE.TEXT : CURSOR_TYPE.CROSSHAIR,
|
||||
);
|
||||
} else if (isOverScrollBar) {
|
||||
document.documentElement.style.cursor = CURSOR_TYPE.AUTO;
|
||||
setCursor(this.canvas, CURSOR_TYPE.AUTO);
|
||||
} else if (
|
||||
hitElement ||
|
||||
this.isHittingCommonBoundingBoxOfSelectedElements(
|
||||
@@ -2046,9 +2073,9 @@ class App extends React.Component<ExcalidrawProps, AppState> {
|
||||
selectedElements,
|
||||
)
|
||||
) {
|
||||
document.documentElement.style.cursor = CURSOR_TYPE.MOVE;
|
||||
setCursor(this.canvas, CURSOR_TYPE.MOVE);
|
||||
} else {
|
||||
document.documentElement.style.cursor = CURSOR_TYPE.AUTO;
|
||||
setCursor(this.canvas, CURSOR_TYPE.AUTO);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -2221,7 +2248,7 @@ class App extends React.Component<ExcalidrawProps, AppState> {
|
||||
let nextPastePrevented = false;
|
||||
const isLinux = /Linux/.test(window.navigator.platform);
|
||||
|
||||
document.documentElement.style.cursor = CURSOR_TYPE.GRABBING;
|
||||
setCursor(this.canvas, CURSOR_TYPE.GRABBING);
|
||||
let { clientX: lastX, clientY: lastY } = event;
|
||||
const onPointerMove = withBatchedUpdates((event: PointerEvent) => {
|
||||
const deltaX = lastX - event.clientX;
|
||||
@@ -2273,7 +2300,7 @@ class App extends React.Component<ExcalidrawProps, AppState> {
|
||||
lastPointerUp = null;
|
||||
isPanning = false;
|
||||
if (!isHoldingSpace) {
|
||||
setCursorForShape(this.state.elementType);
|
||||
setCursorForShape(this.canvas, this.state.elementType);
|
||||
}
|
||||
this.setState({
|
||||
cursorButton: "up",
|
||||
@@ -2389,7 +2416,7 @@ class App extends React.Component<ExcalidrawProps, AppState> {
|
||||
|
||||
const onPointerUp = withBatchedUpdates(() => {
|
||||
isDraggingScrollBar = false;
|
||||
setCursorForShape(this.state.elementType);
|
||||
setCursorForShape(this.canvas, this.state.elementType);
|
||||
lastPointerUp = null;
|
||||
this.setState({
|
||||
cursorButton: "up",
|
||||
@@ -2452,9 +2479,12 @@ class App extends React.Component<ExcalidrawProps, AppState> {
|
||||
);
|
||||
}
|
||||
if (pointerDownState.resize.handleType) {
|
||||
document.documentElement.style.cursor = getCursorForResizingElement({
|
||||
transformHandleType: pointerDownState.resize.handleType,
|
||||
});
|
||||
setCursor(
|
||||
this.canvas,
|
||||
getCursorForResizingElement({
|
||||
transformHandleType: pointerDownState.resize.handleType,
|
||||
}),
|
||||
);
|
||||
pointerDownState.resize.isResizing = true;
|
||||
pointerDownState.resize.offset = tupleToCoors(
|
||||
getResizeOffsetXY(
|
||||
@@ -2619,7 +2649,7 @@ class App extends React.Component<ExcalidrawProps, AppState> {
|
||||
insertAtParentCenter: !event.altKey,
|
||||
});
|
||||
|
||||
resetCursor();
|
||||
resetCursor(this.canvas);
|
||||
if (!this.state.elementLocked) {
|
||||
this.setState({
|
||||
elementType: "selection",
|
||||
@@ -2676,7 +2706,7 @@ class App extends React.Component<ExcalidrawProps, AppState> {
|
||||
mutateElement(multiElement, {
|
||||
lastCommittedPoint: multiElement.points[multiElement.points.length - 1],
|
||||
});
|
||||
document.documentElement.style.cursor = CURSOR_TYPE.POINTER;
|
||||
setCursor(this.canvas, CURSOR_TYPE.POINTER);
|
||||
} else {
|
||||
const [gridX, gridY] = getGridPoint(
|
||||
pointerDownState.origin.x,
|
||||
@@ -3211,7 +3241,7 @@ class App extends React.Component<ExcalidrawProps, AppState> {
|
||||
}
|
||||
this.setState({ suggestedBindings: [], startBoundElement: null });
|
||||
if (!elementLocked && elementType !== "draw") {
|
||||
resetCursor();
|
||||
resetCursor(this.canvas);
|
||||
this.setState((prevState) => ({
|
||||
draggingElement: null,
|
||||
elementType: "selection",
|
||||
@@ -3382,7 +3412,7 @@ class App extends React.Component<ExcalidrawProps, AppState> {
|
||||
}
|
||||
|
||||
if (!elementLocked && elementType !== "draw") {
|
||||
resetCursor();
|
||||
resetCursor(this.canvas);
|
||||
this.setState({
|
||||
draggingElement: null,
|
||||
suggestedBindings: [],
|
||||
@@ -3540,7 +3570,6 @@ 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);
|
||||
|
||||
@@ -10,13 +10,18 @@ export type Appearence = "light" | "dark";
|
||||
export const DarkModeToggle = (props: {
|
||||
value: Appearence;
|
||||
onChange: (value: Appearence) => void;
|
||||
title?: string;
|
||||
}) => {
|
||||
const title = props.title
|
||||
? props.title
|
||||
: props.value === "dark"
|
||||
? t("buttons.lightMode")
|
||||
: t("buttons.darkMode");
|
||||
|
||||
return (
|
||||
<label
|
||||
className={`ToolIcon ToolIcon_type_floating ToolIcon_size_M`}
|
||||
title={
|
||||
props.value === "dark" ? t("buttons.lightMode") : t("buttons.darkMode")
|
||||
}
|
||||
title={title}
|
||||
>
|
||||
<input
|
||||
className="ToolIcon_type_checkbox ToolIcon_toggle_opaque"
|
||||
@@ -25,11 +30,7 @@ export const DarkModeToggle = (props: {
|
||||
props.onChange(event.target.checked ? "dark" : "light")
|
||||
}
|
||||
checked={props.value === "dark"}
|
||||
aria-label={
|
||||
props.value === "dark"
|
||||
? t("buttons.lightMode")
|
||||
: t("buttons.darkMode")
|
||||
}
|
||||
aria-label={title}
|
||||
/>
|
||||
<div className="ToolIcon__icon">
|
||||
{props.value === "light" ? ICONS.MOON : ICONS.SUN}
|
||||
|
||||
@@ -19,6 +19,9 @@ import { ToolButton } from "./ToolButton";
|
||||
const scales = [1, 2, 3];
|
||||
const defaultScale = scales.includes(devicePixelRatio) ? devicePixelRatio : 1;
|
||||
|
||||
const supportsContextFilters =
|
||||
"filter" in document.createElement("canvas").getContext("2d")!;
|
||||
|
||||
export const ErrorCanvasPreview = () => {
|
||||
return (
|
||||
<div>
|
||||
@@ -128,6 +131,8 @@ const ExportModal = ({
|
||||
return (
|
||||
<div className="ExportDialog">
|
||||
<div className="ExportDialog__preview" ref={previewRef} />
|
||||
{supportsContextFilters &&
|
||||
actionManager.renderAction("exportWithDarkMode")}
|
||||
<Stack.Col gap={2} align="center">
|
||||
<div className="ExportDialog__actions">
|
||||
<Stack.Row gap={2}>
|
||||
|
||||
@@ -516,6 +516,7 @@ const LayerUI = ({
|
||||
{heading}
|
||||
<Stack.Row gap={1}>
|
||||
<ShapesSwitcher
|
||||
canvas={canvas}
|
||||
elementType={appState.elementType}
|
||||
setAppState={setAppState}
|
||||
isLibraryOpen={appState.isLibraryOpen}
|
||||
@@ -703,6 +704,7 @@ 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])
|
||||
|
||||
@@ -57,6 +57,7 @@ export const MobileMenu = ({
|
||||
{heading}
|
||||
<Stack.Row gap={1}>
|
||||
<ShapesSwitcher
|
||||
canvas={canvas}
|
||||
elementType={appState.elementType}
|
||||
setAppState={setAppState}
|
||||
isLibraryOpen={appState.isLibraryOpen}
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
|
||||
.Toast__message {
|
||||
color: var(--popup-text-color);
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
|
||||
@keyframes fade-in {
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import React from "react";
|
||||
import * as Sentry from "@sentry/browser";
|
||||
import { resetCursor } from "../utils";
|
||||
import { t } from "../i18n";
|
||||
|
||||
interface TopErrorBoundaryState {
|
||||
@@ -24,7 +23,6 @@ export class TopErrorBoundary extends React.Component<
|
||||
}
|
||||
|
||||
componentDidCatch(error: Error, errorInfo: any) {
|
||||
resetCursor();
|
||||
const _localStorage: any = {};
|
||||
for (const [key, value] of Object.entries({ ...localStorage })) {
|
||||
try {
|
||||
|
||||
@@ -113,6 +113,16 @@ 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(
|
||||
|
||||
+4
-1
@@ -1,4 +1,5 @@
|
||||
import { FontFamily } from "./element/types";
|
||||
import cssVariables from "./css/variables.module.scss";
|
||||
|
||||
export const APP_NAME = "Excalidraw";
|
||||
|
||||
@@ -93,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 = 500;
|
||||
export const SCROLL_TIMEOUT = 100;
|
||||
|
||||
export const ZOOM_STEP = 0.1;
|
||||
|
||||
@@ -107,3 +108,5 @@ export const MODES = {
|
||||
ZEN: "zenMode",
|
||||
GRID: "gridMode",
|
||||
};
|
||||
|
||||
export const APPEARANCE_FILTER = cssVariables.appearanceFilter;
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
}
|
||||
|
||||
.excalidraw {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
color: var(--text-primary-color);
|
||||
display: flex;
|
||||
top: 0;
|
||||
@@ -573,3 +575,14 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.excalidraw-textEditorContainer {
|
||||
overflow: hidden;
|
||||
position: absolute;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
pointer-events: none;
|
||||
textarea {
|
||||
pointer-events: all;
|
||||
}
|
||||
}
|
||||
|
||||
+3
-4
@@ -1,6 +1,7 @@
|
||||
@import "open-color/open-color.scss";
|
||||
@import "./variables.module.scss";
|
||||
|
||||
:root {
|
||||
.excalidraw {
|
||||
--appearance-filter: none;
|
||||
--button-destructive-bg-color: #{$oc-red-1};
|
||||
--button-destructive-color: #{$oc-red-9};
|
||||
@@ -33,9 +34,7 @@
|
||||
--shadow-island: 0 1px 5px #{transparentize($oc-black, 0.85)};
|
||||
--space-factor: 0.25rem;
|
||||
--text-primary-color: #{$oc-gray-8};
|
||||
}
|
||||
|
||||
.excalidraw {
|
||||
&.Appearance_dark {
|
||||
background: $oc-black;
|
||||
|
||||
@@ -45,7 +44,7 @@
|
||||
}
|
||||
|
||||
&.Appearance_dark {
|
||||
--appearance-filter: invert(93%) hue-rotate(180deg);
|
||||
--appearance-filter: #{$appearance-filter};
|
||||
--button-destructive-bg-color: #5a0000;
|
||||
--button-destructive-color: #{$oc-red-3};
|
||||
--button-gray-1: #363636;
|
||||
|
||||
@@ -2,7 +2,9 @@
|
||||
|
||||
// keep up to date with is-mobile.tsx
|
||||
$is-mobile-query: "(max-width: 600px), (max-height: 500px) and (max-width: 1000px)";
|
||||
$appearance-filter: "invert(93%) hue-rotate(180deg)";
|
||||
|
||||
:export {
|
||||
isMobileQuery: unquote($is-mobile-query);
|
||||
appearanceFilter: unquote($appearance-filter);
|
||||
}
|
||||
|
||||
+4
-3
@@ -5,8 +5,9 @@ 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 { ImportedDataState, LibraryData } from "./types";
|
||||
import { LibraryData } from "./types";
|
||||
|
||||
const parseFileContents = async (blob: Blob | File) => {
|
||||
let contents: string;
|
||||
@@ -85,8 +86,8 @@ export const loadFromBlob = async (
|
||||
) => {
|
||||
const contents = await parseFileContents(blob);
|
||||
try {
|
||||
const data: ImportedDataState = JSON.parse(contents);
|
||||
if (data.type !== "excalidraw") {
|
||||
const data = JSON.parse(contents);
|
||||
if (!isValidExcalidrawData(data)) {
|
||||
throw new Error(t("alerts.couldNotLoadInvalidFile"));
|
||||
}
|
||||
const result = restore(
|
||||
|
||||
@@ -41,6 +41,7 @@ export const exportCanvas = async (
|
||||
if (type === "svg" || type === "clipboard-svg") {
|
||||
const tempSvg = exportToSvg(elements, {
|
||||
exportBackground,
|
||||
exportWithDarkMode: appState.exportWithDarkMode,
|
||||
viewBackgroundColor,
|
||||
exportPadding,
|
||||
scale,
|
||||
|
||||
@@ -6,6 +6,7 @@ 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[],
|
||||
@@ -53,6 +54,19 @@ export const loadFromJSON = async (localAppState: AppState) => {
|
||||
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" &&
|
||||
|
||||
@@ -15,6 +15,7 @@ export interface ImportedDataState {
|
||||
source?: string;
|
||||
elements?: DataState["elements"] | null;
|
||||
appState?: Partial<DataState["appState"]> | null;
|
||||
scrollToCenter?: boolean;
|
||||
}
|
||||
|
||||
export interface LibraryData {
|
||||
|
||||
@@ -182,9 +182,9 @@ const bindLinearElement = (
|
||||
} as PointBinding,
|
||||
});
|
||||
mutateElement(hoveredElement, {
|
||||
boundElementIds: [
|
||||
...new Set([...(hoveredElement.boundElementIds ?? []), linearElement.id]),
|
||||
],
|
||||
boundElementIds: Array.from(
|
||||
new Set([...(hoveredElement.boundElementIds ?? []), linearElement.id]),
|
||||
),
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@@ -21,7 +21,6 @@ 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 {
|
||||
@@ -105,13 +104,6 @@ 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") {
|
||||
|
||||
@@ -93,7 +93,7 @@ export const textWysiwyg = ({
|
||||
editable.wrap = "off";
|
||||
|
||||
Object.assign(editable.style, {
|
||||
position: "fixed",
|
||||
position: "relative",
|
||||
display: "inline-block",
|
||||
minHeight: "1em",
|
||||
backfaceVisibility: "hidden",
|
||||
|
||||
@@ -40,6 +40,7 @@ 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;
|
||||
@@ -188,6 +189,7 @@ class CollabWrapper extends PureComponent<Props, CollabState> {
|
||||
};
|
||||
|
||||
openPortal = async () => {
|
||||
trackEvent("share", "room creation");
|
||||
return this.initializeSocketClient(null);
|
||||
};
|
||||
|
||||
@@ -196,6 +198,7 @@ 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");
|
||||
}
|
||||
};
|
||||
|
||||
@@ -256,6 +259,7 @@ class CollabWrapper extends PureComponent<Props, CollabState> {
|
||||
if (elements) {
|
||||
scenePromise.resolve({
|
||||
elements,
|
||||
scrollToCenter: true,
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
@@ -307,7 +311,10 @@ class CollabWrapper extends PureComponent<Props, CollabState> {
|
||||
init: true,
|
||||
});
|
||||
// noop if already resolved via init from firebase
|
||||
scenePromise.resolve({ elements: reconciledElements });
|
||||
scenePromise.resolve({
|
||||
elements: reconciledElements,
|
||||
scrollToCenter: true,
|
||||
});
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ 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;
|
||||
@@ -32,6 +33,7 @@ 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,10 +1,17 @@
|
||||
import React, { useRef } from "react";
|
||||
import { copyTextToSystemClipboard } from "../../clipboard";
|
||||
import { Dialog } from "../../components/Dialog";
|
||||
import { clipboard, start, stop } from "../../components/icons";
|
||||
import {
|
||||
clipboard,
|
||||
start,
|
||||
stop,
|
||||
share,
|
||||
shareIOS,
|
||||
} from "../../components/icons";
|
||||
import { ToolButton } from "../../components/ToolButton";
|
||||
import { t } from "../../i18n";
|
||||
import "./RoomDialog.scss";
|
||||
import Stack from "../../components/Stack";
|
||||
|
||||
const RoomDialog = ({
|
||||
handleClose,
|
||||
@@ -24,6 +31,8 @@ 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 {
|
||||
@@ -36,6 +45,18 @@ 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();
|
||||
@@ -68,13 +89,24 @@ const RoomDialog = ({
|
||||
<p>{t("roomDialog.desc_inProgressIntro")}</p>
|
||||
<p>{t("roomDialog.desc_shareLink")}</p>
|
||||
<div className="RoomDialog-linkContainer">
|
||||
<ToolButton
|
||||
type="button"
|
||||
icon={clipboard}
|
||||
title={t("labels.copy")}
|
||||
aria-label={t("labels.copy")}
|
||||
onClick={copyRoomLink}
|
||||
/>
|
||||
<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>
|
||||
<input
|
||||
value={activeRoomLink}
|
||||
readOnly={true}
|
||||
|
||||
@@ -13,7 +13,8 @@ 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 { ImportedDataState } from "../data/types";
|
||||
import { loadFromBlob } from "../data/blob";
|
||||
import { DataState, ImportedDataState } from "../data/types";
|
||||
import {
|
||||
ExcalidrawElement,
|
||||
NonDeletedExcalidrawElement,
|
||||
@@ -69,16 +70,21 @@ const initializeScene = async (opts: {
|
||||
}): Promise<ImportedDataState | null> => {
|
||||
const searchParams = new URLSearchParams(window.location.search);
|
||||
const id = searchParams.get("id");
|
||||
const jsonMatch = window.location.hash.match(
|
||||
const jsonBackendMatch = window.location.hash.match(
|
||||
/^#json=([0-9]+),([a-zA-Z0-9_-]+)$/,
|
||||
);
|
||||
const externalUrlMatch = window.location.hash.match(/^#url=(.*)$/);
|
||||
|
||||
const initialData = importFromLocalStorage();
|
||||
|
||||
let scene = await loadScene(null, null, initialData);
|
||||
let scene: DataState & { scrollToCenter?: boolean } = await loadScene(
|
||||
null,
|
||||
null,
|
||||
initialData,
|
||||
);
|
||||
|
||||
let roomLinkData = getCollaborationLinkData(window.location.href);
|
||||
const isExternalScene = !!(id || jsonMatch || roomLinkData);
|
||||
const isExternalScene = !!(id || jsonBackendMatch || roomLinkData);
|
||||
if (isExternalScene) {
|
||||
if (
|
||||
// don't prompt if scene is empty
|
||||
@@ -91,9 +97,14 @@ const initializeScene = async (opts: {
|
||||
// Backwards compatibility with legacy url format
|
||||
if (id) {
|
||||
scene = await loadScene(id, null, initialData);
|
||||
} else if (jsonMatch) {
|
||||
scene = await loadScene(jsonMatch[1], jsonMatch[2], initialData);
|
||||
} else if (jsonBackendMatch) {
|
||||
scene = await loadScene(
|
||||
jsonBackendMatch[1],
|
||||
jsonBackendMatch[2],
|
||||
initialData,
|
||||
);
|
||||
}
|
||||
scene.scrollToCenter = true;
|
||||
if (!roomLinkData) {
|
||||
window.history.replaceState({}, APP_NAME, window.location.origin);
|
||||
}
|
||||
@@ -114,7 +125,28 @@ 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) {
|
||||
|
||||
Vendored
+1
@@ -12,6 +12,7 @@ interface Document {
|
||||
interface Window {
|
||||
ClipboardItem: any;
|
||||
__EXCALIDRAW_SHA__: string | undefined;
|
||||
EXCALIDRAW_ASSET_PATH: string | undefined;
|
||||
gtag: Function;
|
||||
}
|
||||
|
||||
|
||||
@@ -34,6 +34,7 @@ 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" },
|
||||
|
||||
+2
-2
@@ -54,8 +54,8 @@ const elements = [
|
||||
},
|
||||
];
|
||||
|
||||
registerFont("./public/FG_Virgil.ttf", { family: "Virgil" });
|
||||
registerFont("./public/Cascadia.ttf", { family: "Cascadia" });
|
||||
registerFont("./public/Virgil.woff2", { family: "Virgil" });
|
||||
registerFont("./public/Cascadia.woff2", { family: "Cascadia" });
|
||||
|
||||
const canvas = exportToCanvas(
|
||||
elements as any,
|
||||
|
||||
@@ -4,7 +4,6 @@ import ExcalidrawApp from "./excalidraw-app";
|
||||
|
||||
import "./excalidraw-app/pwa";
|
||||
import "./excalidraw-app/sentry";
|
||||
|
||||
window.__EXCALIDRAW_SHA__ = process.env.REACT_APP_GIT_SHA;
|
||||
|
||||
ReactDOM.render(<ExcalidrawApp />, document.getElementById("root"));
|
||||
|
||||
@@ -40,6 +40,7 @@ export const KEYS = {
|
||||
TAB: "Tab",
|
||||
|
||||
A: "a",
|
||||
C: "c",
|
||||
D: "d",
|
||||
E: "e",
|
||||
L: "l",
|
||||
|
||||
@@ -68,7 +68,7 @@
|
||||
"layers": "الطبقات",
|
||||
"actions": "الإجراءات",
|
||||
"language": "اللغة",
|
||||
"liveCollaboration": "",
|
||||
"liveCollaboration": "بدء المشاركة الحية",
|
||||
"duplicateSelection": "تكرار",
|
||||
"untitled": "غير معنون",
|
||||
"name": "الاسم",
|
||||
@@ -92,7 +92,8 @@
|
||||
"centerHorizontally": "توسيط أفقي",
|
||||
"distributeHorizontally": "التوزيع الأفقي",
|
||||
"distributeVertically": "التوزيع عمودياً",
|
||||
"viewMode": ""
|
||||
"viewMode": "",
|
||||
"toggleExportColorScheme": ""
|
||||
},
|
||||
"buttons": {
|
||||
"clearReset": "إعادة تعيين اللوحة",
|
||||
@@ -141,6 +142,7 @@
|
||||
"confirmAddLibrary": "هذا سيضيف {{numShapes}} شكل إلى مكتبتك. هل أنت متأكد؟",
|
||||
"imageDoesNotContainScene": "استيراد الصور غير مدعوم في الوقت الراهن.\n\nهل تريد استيراد مشهد؟ لا يبدو أن هذه الصورة تحتوي على أي بيانات مشهد. هل قمت بسماح هذا أثناء التصدير؟",
|
||||
"cannotRestoreFromImage": "تعذر استعادة المشهد من ملف الصورة",
|
||||
"invalidSceneUrl": "",
|
||||
"resetLibrary": ""
|
||||
},
|
||||
"toolBar": {
|
||||
@@ -246,6 +248,8 @@
|
||||
"copyToClipboard": "",
|
||||
"copyToClipboardAsPng": "",
|
||||
"fileSaved": "",
|
||||
"fileSavedToFilename": ""
|
||||
"fileSavedToFilename": "",
|
||||
"canvas": "",
|
||||
"selection": ""
|
||||
}
|
||||
}
|
||||
|
||||
@@ -92,7 +92,8 @@
|
||||
"centerHorizontally": "Центрирай хоризонтално",
|
||||
"distributeHorizontally": "Разпредели хоризонтално",
|
||||
"distributeVertically": "Разпредели вертикално",
|
||||
"viewMode": "Изглед"
|
||||
"viewMode": "Изглед",
|
||||
"toggleExportColorScheme": ""
|
||||
},
|
||||
"buttons": {
|
||||
"clearReset": "Нулиране на платно",
|
||||
@@ -141,6 +142,7 @@
|
||||
"confirmAddLibrary": "Ще се добавят {{numShapes}} фигура(и) във вашата библиотека. Сигурни ли сте?",
|
||||
"imageDoesNotContainScene": "Импортирането на картинки не се поддържва в момента.\n\nИскате да импортнете сцена? Тази картинка не съдържа данни от сцена. Разрешили ли сте последното при експортирането?",
|
||||
"cannotRestoreFromImage": "Не може да бъде възстановена сцена от този файл",
|
||||
"invalidSceneUrl": "",
|
||||
"resetLibrary": ""
|
||||
},
|
||||
"toolBar": {
|
||||
@@ -244,8 +246,10 @@
|
||||
"toast": {
|
||||
"copyStyles": "Копирани стилове.",
|
||||
"copyToClipboard": "Копирано в клипборда.",
|
||||
"copyToClipboardAsPng": "Копирано в клипборда като PNG.",
|
||||
"copyToClipboardAsPng": "",
|
||||
"fileSaved": "",
|
||||
"fileSavedToFilename": ""
|
||||
"fileSavedToFilename": "",
|
||||
"canvas": "",
|
||||
"selection": ""
|
||||
}
|
||||
}
|
||||
|
||||
+32
-28
@@ -68,7 +68,7 @@
|
||||
"layers": "Capes",
|
||||
"actions": "Accions",
|
||||
"language": "Llengua",
|
||||
"liveCollaboration": "",
|
||||
"liveCollaboration": "Col·laboració en directe",
|
||||
"duplicateSelection": "Duplicar",
|
||||
"untitled": "Sense títol",
|
||||
"name": "Nom",
|
||||
@@ -77,7 +77,7 @@
|
||||
"group": "Agrupar la selecció",
|
||||
"ungroup": "Desagrupar la selecció",
|
||||
"collaborators": "Col·laboradors",
|
||||
"showGrid": "",
|
||||
"showGrid": "Mostra la graella",
|
||||
"addToLibrary": "Afegir a la biblioteca",
|
||||
"removeFromLibrary": "Eliminar de la biblioteca",
|
||||
"libraryLoadingMessage": "Carregant la biblioteca…",
|
||||
@@ -92,7 +92,8 @@
|
||||
"centerHorizontally": "Centrar horitzontalment",
|
||||
"distributeHorizontally": "Distribuir horitzontalment",
|
||||
"distributeVertically": "Distribuir verticalment",
|
||||
"viewMode": ""
|
||||
"viewMode": "Mode de visualització",
|
||||
"toggleExportColorScheme": ""
|
||||
},
|
||||
"buttons": {
|
||||
"clearReset": "Netejar el llenç",
|
||||
@@ -117,7 +118,7 @@
|
||||
"edit": "Editar",
|
||||
"undo": "Desfer",
|
||||
"redo": "Refer",
|
||||
"resetLibrary": "",
|
||||
"resetLibrary": "Restablir biblioteca",
|
||||
"createNewRoom": "Crear sala nova",
|
||||
"fullScreen": "Pantalla completa",
|
||||
"darkMode": "Mode fosc",
|
||||
@@ -136,12 +137,13 @@
|
||||
"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": "",
|
||||
"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ó).",
|
||||
"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",
|
||||
"resetLibrary": ""
|
||||
"invalidSceneUrl": "",
|
||||
"resetLibrary": "Tot el llenç s'esborrarà. Estàs segur?"
|
||||
},
|
||||
"toolBar": {
|
||||
"selection": "Selecció",
|
||||
@@ -203,25 +205,25 @@
|
||||
"title": "Error"
|
||||
},
|
||||
"helpDialog": {
|
||||
"blog": "",
|
||||
"click": "",
|
||||
"curvedArrow": "",
|
||||
"curvedLine": "",
|
||||
"documentation": "",
|
||||
"drag": "",
|
||||
"editor": "",
|
||||
"github": "",
|
||||
"howto": "",
|
||||
"or": "",
|
||||
"preventBinding": "",
|
||||
"shapes": "",
|
||||
"shortcuts": "",
|
||||
"textFinish": "",
|
||||
"textNewLine": "",
|
||||
"title": "",
|
||||
"view": "",
|
||||
"zoomToFit": "",
|
||||
"zoomToSelection": ""
|
||||
"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ó"
|
||||
},
|
||||
"encrypted": {
|
||||
"tooltip": "Els vostres dibuixos estan xifrats de punta a punta de manera que els servidors d’Excalidraw no els veuran mai."
|
||||
@@ -236,8 +238,8 @@
|
||||
"storage": "Emmagatzematge",
|
||||
"title": "Estadístiques per nerds",
|
||||
"total": "Total",
|
||||
"version": "",
|
||||
"versionCopy": "",
|
||||
"version": "Versió",
|
||||
"versionCopy": "Feu clic per a copiar",
|
||||
"versionNotAvailable": "",
|
||||
"width": "Amplada"
|
||||
},
|
||||
@@ -246,6 +248,8 @@
|
||||
"copyToClipboard": "",
|
||||
"copyToClipboardAsPng": "",
|
||||
"fileSaved": "",
|
||||
"fileSavedToFilename": ""
|
||||
"fileSavedToFilename": "",
|
||||
"canvas": "",
|
||||
"selection": ""
|
||||
}
|
||||
}
|
||||
|
||||
@@ -92,7 +92,8 @@
|
||||
"centerHorizontally": "Horizontal zentrieren",
|
||||
"distributeHorizontally": "Horizontal verteilen",
|
||||
"distributeVertically": "Vertikal verteilen",
|
||||
"viewMode": "Ansichtsmodus"
|
||||
"viewMode": "Ansichtsmodus",
|
||||
"toggleExportColorScheme": "Farbschema für Export umschalten"
|
||||
},
|
||||
"buttons": {
|
||||
"clearReset": "Zeichenfläche löschen & Hintergrundfarbe zurücksetzen",
|
||||
@@ -141,6 +142,7 @@
|
||||
"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": {
|
||||
@@ -244,8 +246,10 @@
|
||||
"toast": {
|
||||
"copyStyles": "Formatierung kopiert.",
|
||||
"copyToClipboard": "In die Zwischenablage kopiert.",
|
||||
"copyToClipboardAsPng": "In die Zwischenablage als PNG kopiert.",
|
||||
"copyToClipboardAsPng": "{{exportSelection}} als PNG in die Zwischenablage kopiert\n({{exportColorScheme}})",
|
||||
"fileSaved": "Datei gespeichert.",
|
||||
"fileSavedToFilename": "Als {filename} gespeichert"
|
||||
"fileSavedToFilename": "Als {filename} gespeichert",
|
||||
"canvas": "Leinwand",
|
||||
"selection": "Auswahl"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -92,7 +92,8 @@
|
||||
"centerHorizontally": "Κέντρο οριζόντια",
|
||||
"distributeHorizontally": "Οριζόντια κατανομή",
|
||||
"distributeVertically": "Κατακόρυφη κατανομή",
|
||||
"viewMode": "Λειτουργία προβολής"
|
||||
"viewMode": "Λειτουργία προβολής",
|
||||
"toggleExportColorScheme": "Εναλλαγή εξαγωγής θέματος χρωμάτων"
|
||||
},
|
||||
"buttons": {
|
||||
"clearReset": "Επαναφορά του καμβά",
|
||||
@@ -141,6 +142,7 @@
|
||||
"confirmAddLibrary": "Αυτό θα προσθέσει {{numShapes}} σχήμα(τα) στη βιβλιοθήκη σας. Είστε σίγουροι;",
|
||||
"imageDoesNotContainScene": "Η εισαγωγή εικόνων δεν υποστηρίζεται αυτή τη στιγμή.\n\nΜήπως θέλετε να εισαγάγετε μια σκηνή; Αυτή η εικόνα δεν φαίνεται να περιέχει δεδομένα σκηνής. Έχετε ενεργοποιήσει αυτό κατά την εξαγωγή;",
|
||||
"cannotRestoreFromImage": "Η σκηνή δεν ήταν δυνατό να αποκατασταθεί από αυτό το αρχείο εικόνας",
|
||||
"invalidSceneUrl": "",
|
||||
"resetLibrary": "Αυτό θα καθαρίσει τη βιβλιοθήκη σας. Είστε σίγουροι;"
|
||||
},
|
||||
"toolBar": {
|
||||
@@ -244,8 +246,10 @@
|
||||
"toast": {
|
||||
"copyStyles": "Αντιγράφηκαν στυλ.",
|
||||
"copyToClipboard": "Αντιγράφηκε στο πρόχειρο.",
|
||||
"copyToClipboardAsPng": "Αντιγράφτηκε στο πρόχειρο ως PNG.",
|
||||
"copyToClipboardAsPng": "Αντιγράφηκε {{exportSelection}} στο πρόχειρο ως PNG\n({{exportColorScheme}})",
|
||||
"fileSaved": "Το αρχείο αποθηκεύτηκε.",
|
||||
"fileSavedToFilename": "Αποθηκεύτηκε στο {filename}"
|
||||
"fileSavedToFilename": "Αποθηκεύτηκε στο {filename}",
|
||||
"canvas": "καμβάς",
|
||||
"selection": "επιλογή"
|
||||
}
|
||||
}
|
||||
|
||||
+10
-4
@@ -92,7 +92,9 @@
|
||||
"centerHorizontally": "Center horizontally",
|
||||
"distributeHorizontally": "Distribute horizontally",
|
||||
"distributeVertically": "Distribute vertically",
|
||||
"viewMode": "View mode"
|
||||
"viewMode": "View mode",
|
||||
"toggleExportColorScheme": "Toggle export color scheme",
|
||||
"share": "Share"
|
||||
},
|
||||
"buttons": {
|
||||
"clearReset": "Reset the canvas",
|
||||
@@ -141,6 +143,7 @@
|
||||
"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": {
|
||||
@@ -197,7 +200,8 @@
|
||||
"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."
|
||||
"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"
|
||||
},
|
||||
"errorDialog": {
|
||||
"title": "Error"
|
||||
@@ -244,8 +248,10 @@
|
||||
"toast": {
|
||||
"copyStyles": "Copied styles.",
|
||||
"copyToClipboard": "Copied to clipboard.",
|
||||
"copyToClipboardAsPng": "Copied to clipboard as PNG.",
|
||||
"copyToClipboardAsPng": "Copied {{exportSelection}} to clipboard as PNG\n({{exportColorScheme}})",
|
||||
"fileSaved": "File saved.",
|
||||
"fileSavedToFilename": "Saved to {filename}"
|
||||
"fileSavedToFilename": "Saved to {filename}",
|
||||
"canvas": "canvas",
|
||||
"selection": "selection"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -92,7 +92,8 @@
|
||||
"centerHorizontally": "Centrar horizontalmente",
|
||||
"distributeHorizontally": "Distribuir horizontalmente",
|
||||
"distributeVertically": "Distribuir verticalmente",
|
||||
"viewMode": "Modo presentación"
|
||||
"viewMode": "Modo presentación",
|
||||
"toggleExportColorScheme": "Cambiar el esquema de colores de exportación"
|
||||
},
|
||||
"buttons": {
|
||||
"clearReset": "Limpiar lienzo y reiniciar el color de fondo",
|
||||
@@ -141,6 +142,7 @@
|
||||
"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": {
|
||||
@@ -244,8 +246,10 @@
|
||||
"toast": {
|
||||
"copyStyles": "Estilos copiados.",
|
||||
"copyToClipboard": "Copiado en el portapapeles.",
|
||||
"copyToClipboardAsPng": "Copiado al portapapeles como PNG.",
|
||||
"copyToClipboardAsPng": "Copiado {{exportSelection}} al portapapeles como PNG\n({{exportColorScheme}})",
|
||||
"fileSaved": "Archivo guardado.",
|
||||
"fileSavedToFilename": "Guardado en {filename}"
|
||||
"fileSavedToFilename": "Guardado en {filename}",
|
||||
"canvas": "lienzo",
|
||||
"selection": "selección"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -92,7 +92,8 @@
|
||||
"centerHorizontally": "وسط قرار دادن به صورت افقی",
|
||||
"distributeHorizontally": "توزیع کردن به صورت افقی",
|
||||
"distributeVertically": "توزیع کردن به صورت عمودی",
|
||||
"viewMode": ""
|
||||
"viewMode": "",
|
||||
"toggleExportColorScheme": ""
|
||||
},
|
||||
"buttons": {
|
||||
"clearReset": "پاکسازی بوم نقاشی",
|
||||
@@ -141,6 +142,7 @@
|
||||
"confirmAddLibrary": "{{numShapes}} از اشکال به کتابخانه شما اضافه خواهد شد. مطمئن هستید؟",
|
||||
"imageDoesNotContainScene": "وارد کردن تصویر در این لحظه امکان پذیر نمی باشد.\nآیا مایل به وارد کردن یک صحنه هستید؟ این تصویر به نظر می رسد که فاقد هرگونه اطلاعاتی مربوط به صحنه باشد. آیا این گزینه را در زمان وارد کردن تصویر فعال کرده اید؟",
|
||||
"cannotRestoreFromImage": "صحنه را نمی توان از این فایل تصویری بازیابی کرد",
|
||||
"invalidSceneUrl": "",
|
||||
"resetLibrary": ""
|
||||
},
|
||||
"toolBar": {
|
||||
@@ -244,8 +246,10 @@
|
||||
"toast": {
|
||||
"copyStyles": "کپی سبک.",
|
||||
"copyToClipboard": "",
|
||||
"copyToClipboardAsPng": "کپی در حافطه موقت به صورت PNG.",
|
||||
"copyToClipboardAsPng": "",
|
||||
"fileSaved": "",
|
||||
"fileSavedToFilename": ""
|
||||
"fileSavedToFilename": "",
|
||||
"canvas": "",
|
||||
"selection": ""
|
||||
}
|
||||
}
|
||||
|
||||
+32
-28
@@ -9,10 +9,10 @@
|
||||
"copy": "Kopioi",
|
||||
"copyAsPng": "Kopioi leikepöydälle PNG-tiedostona",
|
||||
"copyAsSvg": "Kopioi leikepöydälle SVG-tiedostona",
|
||||
"bringForward": "Siirrä eteenpäin",
|
||||
"bringForward": "Tuo eteenpäin",
|
||||
"sendToBack": "Vie taakse",
|
||||
"bringToFront": "Tuo eteen",
|
||||
"sendBackward": "Siirrä taaksepäin",
|
||||
"sendBackward": "Vie taaksepäin",
|
||||
"delete": "Poista",
|
||||
"copyStyles": "Kopioi tyyli",
|
||||
"pasteStyles": "Liitä tyyli",
|
||||
@@ -29,7 +29,7 @@
|
||||
"textAlign": "Tekstin tasaus",
|
||||
"edges": "Reunat",
|
||||
"sharp": "Terävä",
|
||||
"round": "Pyöreä",
|
||||
"round": "Pyöristetty",
|
||||
"arrowheads": "Nuolenkärjet",
|
||||
"arrowhead_none": "Ei mitään",
|
||||
"arrowhead_arrow": "Nuoli",
|
||||
@@ -92,7 +92,8 @@
|
||||
"centerHorizontally": "Keskitä vaakasuunnassa",
|
||||
"distributeHorizontally": "Jaa vaakasuunnassa",
|
||||
"distributeVertically": "Jaa pystysuunnassa",
|
||||
"viewMode": "Katselutila"
|
||||
"viewMode": "Katselutila",
|
||||
"toggleExportColorScheme": "Vaihda viennin väriteema"
|
||||
},
|
||||
"buttons": {
|
||||
"clearReset": "Tyhjennä piirtoalue",
|
||||
@@ -109,9 +110,9 @@
|
||||
"close": "Sulje",
|
||||
"selectLanguage": "Valitse kieli",
|
||||
"scrollBackToContent": "Näytä sisältö",
|
||||
"zoomIn": "Zoomaa sisään",
|
||||
"zoomOut": "Zoomaa ulos",
|
||||
"resetZoom": "Nollaa zoomaus",
|
||||
"zoomIn": "Lähennä",
|
||||
"zoomOut": "Loitonna",
|
||||
"resetZoom": "Nollaa suurennuksen taso",
|
||||
"menu": "Valikko",
|
||||
"done": "Valmis",
|
||||
"edit": "Muokkaa",
|
||||
@@ -128,20 +129,21 @@
|
||||
"alerts": {
|
||||
"clearReset": "Tämä tyhjentää koko piirtoalueen. Jatketaanko?",
|
||||
"couldNotCreateShareableLink": "Jaettavan linkin luominen epäonnistui.",
|
||||
"couldNotCreateShareableLinkTooBig": "Jaettavaa linkkiä ei voitu luoda: teos on liian suuri",
|
||||
"couldNotCreateShareableLinkTooBig": "Jaettavaa linkkiä ei voitu luoda: piirtoalue 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. 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?",
|
||||
"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?",
|
||||
"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",
|
||||
"resetLibrary": "Tämä tyhjentää kirjastosi. Oletko varma?"
|
||||
"invalidSceneUrl": "Teosta ei voitu tuoda annetusta URL-osoitteesta. Tallenne on vioittunut, tai osoitteessa ei ole Excalidraw JSON-dataa.",
|
||||
"resetLibrary": "Tämä tyhjentää kirjastosi. Jatketaanko?"
|
||||
},
|
||||
"toolBar": {
|
||||
"selection": "Valinta",
|
||||
@@ -164,13 +166,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": "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",
|
||||
"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",
|
||||
"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, CtrlOrCmd+D monistaaksesi, tai raahaa liikuttaaksesi",
|
||||
"lineEditor_nothingSelected": "Valitse liikutettava tai poistettava piste, tai pidä Alt pohjassa ja napauta lisätäksesi uusia 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ä"
|
||||
},
|
||||
"canvasError": {
|
||||
"cannotShowPreview": "Esikatselua ei voitu näyttää",
|
||||
@@ -180,19 +182,19 @@
|
||||
"errorSplash": {
|
||||
"headingMain_pre": "Tapahtui virhe. Yritä ",
|
||||
"headingMain_button": "sivun lataamista uudelleen.",
|
||||
"clearCanvasMessage": "Jos lataaminen uudelleen ei auta, yritä ",
|
||||
"clearCanvasMessage": "Mikäli sivun 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. Jos piirroksesi ei ole yksityinen, harkitsethan kertovasi meille ",
|
||||
"openIssueMessage_pre": "Olimme varovaisia emmekä sisällyttäneet tietoa piirroksestasi virheeseen. Mikäli 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 ei 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 eivät näe mitä keksit.",
|
||||
"button_startSession": "Aloita istunto",
|
||||
"button_stopSession": "Lopeta istunto",
|
||||
"desc_inProgressIntro": "Jaettu istunto on nyt käynnissä.",
|
||||
@@ -224,7 +226,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",
|
||||
@@ -234,7 +236,7 @@
|
||||
"scene": "Teos",
|
||||
"selected": "Valitut",
|
||||
"storage": "Tallennustila",
|
||||
"title": "Nörttien tilastot",
|
||||
"title": "Tilastoja nörteille",
|
||||
"total": "Yhteensä",
|
||||
"version": "Versio",
|
||||
"versionCopy": "Klikkaa kopioidaksesi",
|
||||
@@ -242,10 +244,12 @@
|
||||
"width": "Leveys"
|
||||
},
|
||||
"toast": {
|
||||
"copyStyles": "Tyylit kopioitu.",
|
||||
"copyToClipboard": "Kopioitu leikepöydälle.",
|
||||
"copyToClipboardAsPng": "Kopioitu leikepöydälle PNG-tiedostona.",
|
||||
"copyStyles": "Tyylit kopioitiin.",
|
||||
"copyToClipboard": "Kopioitiin leikepöydälle.",
|
||||
"copyToClipboardAsPng": "Kopioitiin {{exportSelection}} leikepöydälle PNG:nä\n({{exportColorScheme}})",
|
||||
"fileSaved": "Tiedosto tallennettu.",
|
||||
"fileSavedToFilename": "Tallennettu kohteeseen {filename}"
|
||||
"fileSavedToFilename": "Tallennettiin kohteeseen {filename}",
|
||||
"canvas": "piirtoalue",
|
||||
"selection": "valinta"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -92,7 +92,8 @@
|
||||
"centerHorizontally": "Centrer horizontalement",
|
||||
"distributeHorizontally": "Distribuer horizontalement",
|
||||
"distributeVertically": "Distribuer verticalement",
|
||||
"viewMode": "Mode présentation"
|
||||
"viewMode": "Mode présentation",
|
||||
"toggleExportColorScheme": "Activer/Désactiver l'export du thème de couleur"
|
||||
},
|
||||
"buttons": {
|
||||
"clearReset": "Réinitialiser le canevas",
|
||||
@@ -141,6 +142,7 @@
|
||||
"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": {
|
||||
@@ -244,8 +246,10 @@
|
||||
"toast": {
|
||||
"copyStyles": "Styles copiés.",
|
||||
"copyToClipboard": "Copié vers le presse-papiers.",
|
||||
"copyToClipboardAsPng": "Copié vers le presse-papier en PNG.",
|
||||
"copyToClipboardAsPng": "{{exportSelection}} copié dans le presse-papiers en PNG\n({{exportColorScheme}})",
|
||||
"fileSaved": "Fichier enregistré.",
|
||||
"fileSavedToFilename": "Enregistré sous {filename}"
|
||||
"fileSavedToFilename": "Enregistré sous {filename}",
|
||||
"canvas": "canevas",
|
||||
"selection": "sélection"
|
||||
}
|
||||
}
|
||||
|
||||
+25
-21
@@ -92,7 +92,8 @@
|
||||
"centerHorizontally": "מרכז אופקית",
|
||||
"distributeHorizontally": "חלוקה אופקית",
|
||||
"distributeVertically": "חלוקה אנכית",
|
||||
"viewMode": ""
|
||||
"viewMode": "מצב תצוגה",
|
||||
"toggleExportColorScheme": ""
|
||||
},
|
||||
"buttons": {
|
||||
"clearReset": "אפס את הלוח",
|
||||
@@ -117,7 +118,7 @@
|
||||
"edit": "ערוך",
|
||||
"undo": "בטל",
|
||||
"redo": "בצע מחדש",
|
||||
"resetLibrary": "",
|
||||
"resetLibrary": "איפוס ספריה",
|
||||
"createNewRoom": "צור חדר",
|
||||
"fullScreen": "מסך מלא",
|
||||
"darkMode": "מצב כהה",
|
||||
@@ -141,6 +142,7 @@
|
||||
"confirmAddLibrary": "הפעולה תוסיף {{numShapes}} צורה(ות) לספריה שלך. האם אתה בטוח?",
|
||||
"imageDoesNotContainScene": "אין תמיכה בייבוא תמונות כעת.\n\nהאם אתה רוצה לייבא תצוגה? התמונה הזאת אינה מכילה מידע על תצוגה. האם הפעלת את האפשרות הזאת בזמן הוצאת המידע?",
|
||||
"cannotRestoreFromImage": "לא הצלחנו לשחזר את התצוגה מקובץ התמונה",
|
||||
"invalidSceneUrl": "",
|
||||
"resetLibrary": ""
|
||||
},
|
||||
"toolBar": {
|
||||
@@ -203,25 +205,25 @@
|
||||
"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 לא יראו אותם לעולם."
|
||||
@@ -237,15 +239,17 @@
|
||||
"title": "סטטיסטיקות לחנונים",
|
||||
"total": "סה״כ",
|
||||
"version": "",
|
||||
"versionCopy": "",
|
||||
"versionCopy": "לחץ להעתקה",
|
||||
"versionNotAvailable": "",
|
||||
"width": "רוחב"
|
||||
},
|
||||
"toast": {
|
||||
"copyStyles": "",
|
||||
"copyStyles": "העתק סגנונות.",
|
||||
"copyToClipboard": "",
|
||||
"copyToClipboardAsPng": "",
|
||||
"fileSaved": "",
|
||||
"fileSavedToFilename": ""
|
||||
"fileSaved": "קובץ נשמר.",
|
||||
"fileSavedToFilename": "",
|
||||
"canvas": "",
|
||||
"selection": ""
|
||||
}
|
||||
}
|
||||
|
||||
@@ -92,7 +92,8 @@
|
||||
"centerHorizontally": "क्षैतिज केन्द्रित",
|
||||
"distributeHorizontally": "क्षैतिज रूप से वितरित करें",
|
||||
"distributeVertically": "खड़ी रूप से वितरित करें",
|
||||
"viewMode": ""
|
||||
"viewMode": "",
|
||||
"toggleExportColorScheme": ""
|
||||
},
|
||||
"buttons": {
|
||||
"clearReset": "कैनवास रीसेट करें",
|
||||
@@ -141,6 +142,7 @@
|
||||
"confirmAddLibrary": "लाइब्रेरी जोड़ें पुष्टि करें आकार संख्या",
|
||||
"imageDoesNotContainScene": "दृश्य में छवि नहीं है",
|
||||
"cannotRestoreFromImage": "छवि फ़ाइल बहाल दृश्य नहीं है",
|
||||
"invalidSceneUrl": "",
|
||||
"resetLibrary": ""
|
||||
},
|
||||
"toolBar": {
|
||||
@@ -244,8 +246,10 @@
|
||||
"toast": {
|
||||
"copyStyles": "काॅपी कीए स्टाइल",
|
||||
"copyToClipboard": "क्लिपबोर्ड में कॉपी कीए",
|
||||
"copyToClipboardAsPng": "क्लिपबोर्ड में PNG के रूप में कॉपी किए",
|
||||
"copyToClipboardAsPng": "",
|
||||
"fileSaved": "",
|
||||
"fileSavedToFilename": ""
|
||||
"fileSavedToFilename": "",
|
||||
"canvas": "",
|
||||
"selection": ""
|
||||
}
|
||||
}
|
||||
|
||||
@@ -92,7 +92,8 @@
|
||||
"centerHorizontally": "Vízszintesen középre igazított",
|
||||
"distributeHorizontally": "Vízszintes elosztás",
|
||||
"distributeVertically": "Függőleges elosztás",
|
||||
"viewMode": ""
|
||||
"viewMode": "",
|
||||
"toggleExportColorScheme": ""
|
||||
},
|
||||
"buttons": {
|
||||
"clearReset": "Vászon törlése",
|
||||
@@ -141,6 +142,7 @@
|
||||
"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": {
|
||||
@@ -246,6 +248,8 @@
|
||||
"copyToClipboard": "",
|
||||
"copyToClipboardAsPng": "",
|
||||
"fileSaved": "",
|
||||
"fileSavedToFilename": ""
|
||||
"fileSavedToFilename": "",
|
||||
"canvas": "",
|
||||
"selection": ""
|
||||
}
|
||||
}
|
||||
|
||||
+10
-6
@@ -68,7 +68,7 @@
|
||||
"layers": "Lapisan",
|
||||
"actions": "Aksi",
|
||||
"language": "Bahasa",
|
||||
"liveCollaboration": "",
|
||||
"liveCollaboration": "Kolaborasi langsung",
|
||||
"duplicateSelection": "Duplikat",
|
||||
"untitled": "Tanpa judul",
|
||||
"name": "Nama",
|
||||
@@ -92,7 +92,8 @@
|
||||
"centerHorizontally": "Pusatkan secara horizontal",
|
||||
"distributeHorizontally": "Distribusikan horizontal",
|
||||
"distributeVertically": "Distribusikan vertikal",
|
||||
"viewMode": "Mode tampilan"
|
||||
"viewMode": "Mode tampilan",
|
||||
"toggleExportColorScheme": "Ubah skema warna ekspor"
|
||||
},
|
||||
"buttons": {
|
||||
"clearReset": "Setel Ulang Kanvas",
|
||||
@@ -117,7 +118,7 @@
|
||||
"edit": "Edit",
|
||||
"undo": "Urungkan",
|
||||
"redo": "Ulangi",
|
||||
"resetLibrary": "",
|
||||
"resetLibrary": "Reset pustaka",
|
||||
"createNewRoom": "Buat ruang baru",
|
||||
"fullScreen": "Layar penuh",
|
||||
"darkMode": "Mode gelap",
|
||||
@@ -141,7 +142,8 @@
|
||||
"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",
|
||||
"resetLibrary": ""
|
||||
"invalidSceneUrl": "",
|
||||
"resetLibrary": "Ini akan menghapus pustaka Anda. Anda yakin?"
|
||||
},
|
||||
"toolBar": {
|
||||
"selection": "Pilihan",
|
||||
@@ -244,8 +246,10 @@
|
||||
"toast": {
|
||||
"copyStyles": "Gaya tersalin.",
|
||||
"copyToClipboard": "Tersalin ke papan klip.",
|
||||
"copyToClipboardAsPng": "Tersalin ke clipboard sebagai PNG.",
|
||||
"copyToClipboardAsPng": "Tersalin {{exportSelection}} ke clipboard sebagai PNG\n({{exportColorScheme}})",
|
||||
"fileSaved": "File tersimpan.",
|
||||
"fileSavedToFilename": "Disimpan ke {filename}"
|
||||
"fileSavedToFilename": "Disimpan ke {filename}",
|
||||
"canvas": "kanvas",
|
||||
"selection": "pilihan"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -92,7 +92,8 @@
|
||||
"centerHorizontally": "Centra orizzontalmente",
|
||||
"distributeHorizontally": "Distribuisci orizzontalmente",
|
||||
"distributeVertically": "Distribuisci verticalmente",
|
||||
"viewMode": "Modalità visualizzazione"
|
||||
"viewMode": "Modalità visualizzazione",
|
||||
"toggleExportColorScheme": "Cambia lo schema di colori in esportazione"
|
||||
},
|
||||
"buttons": {
|
||||
"clearReset": "Svuota la tela",
|
||||
@@ -141,6 +142,7 @@
|
||||
"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": {
|
||||
@@ -244,8 +246,10 @@
|
||||
"toast": {
|
||||
"copyStyles": "Stili copiati.",
|
||||
"copyToClipboard": "Copiato negli appunti.",
|
||||
"copyToClipboardAsPng": "Copiato negli appunti come PNG.",
|
||||
"copyToClipboardAsPng": "{{exportSelection}} copiato negli appunti come PNG\n({{exportColorScheme}})",
|
||||
"fileSaved": "File salvato.",
|
||||
"fileSavedToFilename": "Salvato in {filename}"
|
||||
"fileSavedToFilename": "Salvato in {filename}",
|
||||
"canvas": "tela",
|
||||
"selection": "selezione"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -92,7 +92,8 @@
|
||||
"centerHorizontally": "横方向に中央揃え",
|
||||
"distributeHorizontally": "水平方向に分散配置",
|
||||
"distributeVertically": "垂直方向に分散配置",
|
||||
"viewMode": "閲覧モード"
|
||||
"viewMode": "閲覧モード",
|
||||
"toggleExportColorScheme": ""
|
||||
},
|
||||
"buttons": {
|
||||
"clearReset": "キャンバスのリセット",
|
||||
@@ -141,6 +142,7 @@
|
||||
"confirmAddLibrary": "{{numShapes}} 個の図形をライブラリに追加します。よろしいですか?",
|
||||
"imageDoesNotContainScene": "現在、画像のインポートはサポートされていません。\n\nシーンをインポートしようとしましたか?この画像にはシーンデータが含まれていないようです。エクスポート中に有効にしていましたか?",
|
||||
"cannotRestoreFromImage": "このイメージファイルからシーンを復元できませんでした",
|
||||
"invalidSceneUrl": "",
|
||||
"resetLibrary": "ライブラリを消去します。本当によろしいですか?"
|
||||
},
|
||||
"toolBar": {
|
||||
@@ -244,8 +246,10 @@
|
||||
"toast": {
|
||||
"copyStyles": "スタイルをコピー",
|
||||
"copyToClipboard": "クリップボードにコピー",
|
||||
"copyToClipboardAsPng": "PNG形式でクリップボードにコピー",
|
||||
"copyToClipboardAsPng": "",
|
||||
"fileSaved": "ファイルを保存しました",
|
||||
"fileSavedToFilename": "{filename} に保存しました"
|
||||
"fileSavedToFilename": "{filename} に保存しました",
|
||||
"canvas": "",
|
||||
"selection": ""
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,7 +68,7 @@
|
||||
"layers": "Tissiyin",
|
||||
"actions": "Tigawin",
|
||||
"language": "Tutlayt",
|
||||
"liveCollaboration": "",
|
||||
"liveCollaboration": "Amɛiwen s srid",
|
||||
"duplicateSelection": "Sisleg",
|
||||
"untitled": "War azwel",
|
||||
"name": "Isem",
|
||||
@@ -92,7 +92,8 @@
|
||||
"centerHorizontally": "Di tlemmast s uglawi",
|
||||
"distributeHorizontally": "Freq s uglawi",
|
||||
"distributeVertically": "Freq s yibeddi",
|
||||
"viewMode": "Askar n tmuɣli"
|
||||
"viewMode": "Askar n tmuɣli",
|
||||
"toggleExportColorScheme": "Sermed/sens asifeḍ usentel n yini"
|
||||
},
|
||||
"buttons": {
|
||||
"clearReset": "Ales awennez n teɣzut n usuneɣ",
|
||||
@@ -117,7 +118,7 @@
|
||||
"edit": "Ẓreg",
|
||||
"undo": "Sefsex",
|
||||
"redo": "Err-d",
|
||||
"resetLibrary": "",
|
||||
"resetLibrary": "Ales awennez n temkarḍit",
|
||||
"createNewRoom": "Snulfu-d taxxamt tamaynutt",
|
||||
"fullScreen": "Agdil aččuran",
|
||||
"darkMode": "Askar imsulles",
|
||||
@@ -141,7 +142,8 @@
|
||||
"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",
|
||||
"resetLibrary": ""
|
||||
"invalidSceneUrl": "",
|
||||
"resetLibrary": "Ayagi ad isfeḍ tamkarḍit-inek•m. Tetḥeqqeḍ?"
|
||||
},
|
||||
"toolBar": {
|
||||
"selection": "Tafrayt",
|
||||
@@ -244,8 +246,10 @@
|
||||
"toast": {
|
||||
"copyStyles": "Iɣunab yettwaneɣlen.",
|
||||
"copyToClipboard": "Yettwaɣel ɣer tecfawit.",
|
||||
"copyToClipboardAsPng": "Yettwanɣel ɣer tecfawit am PNG.",
|
||||
"fileSaved": "",
|
||||
"fileSavedToFilename": ""
|
||||
"copyToClipboardAsPng": "{{exportSelection}} yettwanɣel ɣer tecfawit am PNG\n({{exportColorScheme}})",
|
||||
"fileSaved": "Afaylu yettwasekles.",
|
||||
"fileSavedToFilename": "Yettwasekles di {filename}",
|
||||
"canvas": "taɣzut n usuneɣ",
|
||||
"selection": "tafrayt"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -92,7 +92,8 @@
|
||||
"centerHorizontally": "수평으로 중앙 정렬",
|
||||
"distributeHorizontally": "수평으로 분배",
|
||||
"distributeVertically": "수직으로 분배",
|
||||
"viewMode": "보기 모드"
|
||||
"viewMode": "보기 모드",
|
||||
"toggleExportColorScheme": ""
|
||||
},
|
||||
"buttons": {
|
||||
"clearReset": "캔버스 초기화",
|
||||
@@ -141,6 +142,7 @@
|
||||
"confirmAddLibrary": "{{numShapes}}개의 모양이 라이브러리에 추가됩니다. 계속하시겠어요?",
|
||||
"imageDoesNotContainScene": "이미지에서 불러오기는 현재 지원되지 않습니다.\n\n화면을 불러오려고 하셨나요? 이미지에 화면 정보가 없는 것 같습니다. 내보낼 때 화면을 포함했나요?",
|
||||
"cannotRestoreFromImage": "이미지 파일에서 화면을 복구할 수 없었습니다",
|
||||
"invalidSceneUrl": "",
|
||||
"resetLibrary": ""
|
||||
},
|
||||
"toolBar": {
|
||||
@@ -244,8 +246,10 @@
|
||||
"toast": {
|
||||
"copyStyles": "스타일 복사.",
|
||||
"copyToClipboard": "클립보드로 복사.",
|
||||
"copyToClipboardAsPng": "클립보드로 PNG 이미지 복사.",
|
||||
"copyToClipboardAsPng": "",
|
||||
"fileSaved": "",
|
||||
"fileSavedToFilename": ""
|
||||
"fileSavedToFilename": "",
|
||||
"canvas": "",
|
||||
"selection": ""
|
||||
}
|
||||
}
|
||||
|
||||
@@ -92,7 +92,8 @@
|
||||
"centerHorizontally": "အလျားလိုက်အလယ်ညှိ",
|
||||
"distributeHorizontally": "အလျားလိုက်",
|
||||
"distributeVertically": "ထောင်လိုက်",
|
||||
"viewMode": ""
|
||||
"viewMode": "",
|
||||
"toggleExportColorScheme": ""
|
||||
},
|
||||
"buttons": {
|
||||
"clearReset": "ကားချပ်ရှင်းလင်း",
|
||||
@@ -141,6 +142,7 @@
|
||||
"confirmAddLibrary": "{{numShapes}} ခုသောပုံသဏ္ဌာန်အားမှတ်တမ်းတင်ပါမည်။ အတည်ပြုပါ။",
|
||||
"imageDoesNotContainScene": "",
|
||||
"cannotRestoreFromImage": "ဤပုံဖြင့်မြင်ကွင်းပြန်လည်မရယူနိုင်ပါ။",
|
||||
"invalidSceneUrl": "",
|
||||
"resetLibrary": ""
|
||||
},
|
||||
"toolBar": {
|
||||
@@ -246,6 +248,8 @@
|
||||
"copyToClipboard": "",
|
||||
"copyToClipboardAsPng": "",
|
||||
"fileSaved": "",
|
||||
"fileSavedToFilename": ""
|
||||
"fileSavedToFilename": "",
|
||||
"canvas": "",
|
||||
"selection": ""
|
||||
}
|
||||
}
|
||||
|
||||
@@ -92,7 +92,8 @@
|
||||
"centerHorizontally": "Midtstill horisontalt",
|
||||
"distributeHorizontally": "Distribuer horisontalt",
|
||||
"distributeVertically": "Distribuer vertikalt",
|
||||
"viewMode": "Visningsmodus"
|
||||
"viewMode": "Visningsmodus",
|
||||
"toggleExportColorScheme": "Veksle eksport av fargepalett"
|
||||
},
|
||||
"buttons": {
|
||||
"clearReset": "Tøm lerretet og tilbakestill bakgrunnsfargen",
|
||||
@@ -141,6 +142,7 @@
|
||||
"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": {
|
||||
@@ -244,8 +246,10 @@
|
||||
"toast": {
|
||||
"copyStyles": "Kopierte stiler.",
|
||||
"copyToClipboard": "Kopiert til utklippstavlen.",
|
||||
"copyToClipboardAsPng": "Kopiert til utklippstavlen som PNG.",
|
||||
"copyToClipboardAsPng": "Kopierte {{exportSelection}} til utklippstavlen som PNG\n({{exportColorScheme}})",
|
||||
"fileSaved": "Fil lagret.",
|
||||
"fileSavedToFilename": "Lagret til {filename}"
|
||||
"fileSavedToFilename": "Lagret til {filename}",
|
||||
"canvas": "lerret",
|
||||
"selection": "utvalg"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -92,7 +92,8 @@
|
||||
"centerHorizontally": "Horizontaal Centreren",
|
||||
"distributeHorizontally": "Horizontaal verspreiden",
|
||||
"distributeVertically": "Verticaal distribueren",
|
||||
"viewMode": "Weergavemodus"
|
||||
"viewMode": "Weergavemodus",
|
||||
"toggleExportColorScheme": "Kleurenschema exporteren aan/uit"
|
||||
},
|
||||
"buttons": {
|
||||
"clearReset": "Canvas opnieuw instellen",
|
||||
@@ -141,6 +142,7 @@
|
||||
"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": {
|
||||
@@ -244,8 +246,10 @@
|
||||
"toast": {
|
||||
"copyStyles": "Stijlen gekopieerd.",
|
||||
"copyToClipboard": "Gekopieerd naar het klembord.",
|
||||
"copyToClipboardAsPng": "Gekopieerd naar klembord als PNG.",
|
||||
"copyToClipboardAsPng": "{{exportSelection}} naar klembord gekopieerd als PNG\n({{exportColorScheme}})",
|
||||
"fileSaved": "Bestand opgeslagen.",
|
||||
"fileSavedToFilename": "Opgeslagen als {filename}"
|
||||
"fileSavedToFilename": "Opgeslagen als {filename}",
|
||||
"canvas": "canvas",
|
||||
"selection": "selectie"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -92,7 +92,8 @@
|
||||
"centerHorizontally": "Midtstill horisontalt",
|
||||
"distributeHorizontally": "Sprei horisontalt",
|
||||
"distributeVertically": "Sprei vertikalt",
|
||||
"viewMode": ""
|
||||
"viewMode": "",
|
||||
"toggleExportColorScheme": ""
|
||||
},
|
||||
"buttons": {
|
||||
"clearReset": "Tilbakestill lerretet",
|
||||
@@ -141,6 +142,7 @@
|
||||
"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": {
|
||||
@@ -246,6 +248,8 @@
|
||||
"copyToClipboard": "",
|
||||
"copyToClipboardAsPng": "",
|
||||
"fileSaved": "",
|
||||
"fileSavedToFilename": ""
|
||||
"fileSavedToFilename": "",
|
||||
"canvas": "",
|
||||
"selection": ""
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,255 @@
|
||||
{
|
||||
"labels": {
|
||||
"paste": "Pegar",
|
||||
"pasteCharts": "Pegar los grafics",
|
||||
"selectAll": "Tot seleccionar",
|
||||
"multiSelect": "Apondre un element a la seleccion",
|
||||
"moveCanvas": "Desplaçar lo canabàs",
|
||||
"cut": "Talhar",
|
||||
"copy": "Copiar",
|
||||
"copyAsPng": "Copiar al quichapapièrs coma PNG",
|
||||
"copyAsSvg": "Copiar al quichapapièrs coma SVG",
|
||||
"bringForward": "En avant",
|
||||
"sendToBack": "En arrièr",
|
||||
"bringToFront": "A l’endavant",
|
||||
"sendBackward": "Endarrièr",
|
||||
"delete": "Suprimir",
|
||||
"copyStyles": "Copiar los estiles",
|
||||
"pasteStyles": "Pegar los estils",
|
||||
"stroke": "Contorn",
|
||||
"background": "Rèireplan",
|
||||
"fill": "Empliment",
|
||||
"strokeWidth": "Largor del contorn",
|
||||
"strokeStyle": "Estil del contorn",
|
||||
"strokeStyle_solid": "Solide",
|
||||
"strokeStyle_dashed": "Tiret",
|
||||
"strokeStyle_dotted": "Puntilhat",
|
||||
"sloppiness": "Estil de traça",
|
||||
"opacity": "Opacitat",
|
||||
"textAlign": "Alinhament tèxt",
|
||||
"edges": "Angles",
|
||||
"sharp": "Ponchut",
|
||||
"round": "Arredonit",
|
||||
"arrowheads": "Cap de la flècha",
|
||||
"arrowhead_none": "Cap",
|
||||
"arrowhead_arrow": "Sageta",
|
||||
"arrowhead_bar": "Barra",
|
||||
"arrowhead_dot": "Ponch",
|
||||
"fontSize": "Talha poliça",
|
||||
"fontFamily": "Familha de poliça",
|
||||
"onlySelected": "Seleccion sonque",
|
||||
"withBackground": "Inclure rèireplan",
|
||||
"exportEmbedScene": "Integrar la scèna al fichièr d’expo",
|
||||
"exportEmbedScene_details": "Las donadas de scèna seràn enregistradas dins lo fichièr PNG/SVG exportat, per que la scèna pòsca èsser restaurada a partir d’aqueste fichièr.\nAumentarà la talha del fichièr exportat.",
|
||||
"addWatermark": "Apondre « Fabricat amb Excalidraw »",
|
||||
"handDrawn": "A la man levada",
|
||||
"normal": "Normala",
|
||||
"code": "Còdi",
|
||||
"small": "Pichona",
|
||||
"medium": "Mejana",
|
||||
"large": "Granda",
|
||||
"veryLarge": "Gradassa",
|
||||
"solid": "Solide",
|
||||
"hachure": "Raia",
|
||||
"crossHatch": "Raia crosada",
|
||||
"thin": "Fin",
|
||||
"bold": "Espés",
|
||||
"left": "Esquèrra",
|
||||
"center": "Centre",
|
||||
"right": "Drecha",
|
||||
"extraBold": "Espesàs",
|
||||
"architect": "Arquitècte",
|
||||
"artist": "Artista",
|
||||
"cartoonist": "Dessenhaire",
|
||||
"fileTitle": "Títol del fichièr",
|
||||
"colorPicker": "Selector de color",
|
||||
"canvasBackground": "Rèireplan del canabàs",
|
||||
"drawingCanvas": "Zòna de dessenh",
|
||||
"layers": "Calques",
|
||||
"actions": "Accions",
|
||||
"language": "Lenga",
|
||||
"liveCollaboration": "Collaboracion en dirèct",
|
||||
"duplicateSelection": "Duplicar",
|
||||
"untitled": "Sens títol",
|
||||
"name": "Nom",
|
||||
"yourName": "Vòstre nom",
|
||||
"madeWithExcalidraw": "Fabricat amb Excalidraw",
|
||||
"group": "Gropar la seleccion",
|
||||
"ungroup": "Desunir la seleccion",
|
||||
"collaborators": "Collaborators",
|
||||
"showGrid": "Afichar la gresilha",
|
||||
"addToLibrary": "Apondre a la bibliotèca",
|
||||
"removeFromLibrary": "Suprimir de la bibliotèca",
|
||||
"libraryLoadingMessage": "Cargament de la bibliotèca…",
|
||||
"libraries": "Percórrer las bibliotècas",
|
||||
"loadingScene": "Cargament de la scèna…",
|
||||
"align": "Alinhament",
|
||||
"alignTop": "Alinhar ennaut",
|
||||
"alignBottom": "Alinhar enbàs",
|
||||
"alignLeft": "Alinhar a esquèrra",
|
||||
"alignRight": "Alinhar a drecha",
|
||||
"centerVertically": "Centrar verticalament",
|
||||
"centerHorizontally": "Centrar orizontalament",
|
||||
"distributeHorizontally": "Distribuir orizontalament",
|
||||
"distributeVertically": "Distribuir verticalament",
|
||||
"viewMode": "Mòde de vista",
|
||||
"toggleExportColorScheme": "Alternar l’esquèma de color d’expòrt"
|
||||
},
|
||||
"buttons": {
|
||||
"clearReset": "Reïnicializar lo canabàs",
|
||||
"export": "Exportar",
|
||||
"exportToPng": "Export en PNG",
|
||||
"exportToSvg": "Export en SVG",
|
||||
"copyToClipboard": "Copiar al quichapapièrs",
|
||||
"copyPngToClipboard": "Copiar PNG al quichapapièrs",
|
||||
"scale": "Escala",
|
||||
"save": "Enregistrar",
|
||||
"saveAs": "Enregistrar jos",
|
||||
"load": "Cargar",
|
||||
"getShareableLink": "Obténer lo ligam de partatge",
|
||||
"close": "Tampar",
|
||||
"selectLanguage": "Causir una lenga",
|
||||
"scrollBackToContent": "Tornar al contengut",
|
||||
"zoomIn": "Zoom avant",
|
||||
"zoomOut": "Zoom arrièr",
|
||||
"resetZoom": "Tirar lo zoom",
|
||||
"menu": "Menú",
|
||||
"done": "Acabat",
|
||||
"edit": "Modificar",
|
||||
"undo": "Anullar",
|
||||
"redo": "Restablir",
|
||||
"resetLibrary": "Reïnicializar la bibliotèca",
|
||||
"createNewRoom": "Crear sala novèla",
|
||||
"fullScreen": "Ecran complèt",
|
||||
"darkMode": "Mòde escur",
|
||||
"lightMode": "Mòde clar",
|
||||
"zenMode": "Mòde escur",
|
||||
"exitZenMode": "Sortir del mòde zen"
|
||||
},
|
||||
"alerts": {
|
||||
"clearReset": "Aquò suprimirà lo canabàs complèt. O volètz vertadièrament ?",
|
||||
"couldNotCreateShareableLink": "Creacion impossibla del ligam de partatge.",
|
||||
"couldNotCreateShareableLinkTooBig": "Creacion impossibla del ligam de partatge : la scèna es tròp granda",
|
||||
"couldNotLoadInvalidFile": "Cargament impossible d’un fichièr invalid",
|
||||
"importBackendFailed": "Importacion fracassada.",
|
||||
"cannotExportEmptyCanvas": "Impossible d’exportar los canabasses voids.",
|
||||
"couldNotCopyToClipboard": "Còpia impossibla al quichapapièrs. Ensajatz d’utilizar lo navegador Chrome.",
|
||||
"decryptFailed": "Deschiframent impossible de las donadas.",
|
||||
"uploadedSecurly": "Lo telecargament es estat securizat amb un chiframent del cap a la fin, significa que los servidors d’Excalidraw o que quina tèrça part que siá pòdon pas legir lo contengut.",
|
||||
"loadSceneOverridePrompt": "Cargar un dessenh extèrn remplaçarà vòstre contengut existent. Volètz contunhar ?",
|
||||
"collabStopOverridePrompt": "Arrestar la session remplaçarà vòstre precedent dessenh gardat localament. O volètz vertadièrament ?\n\n(Se volètz gardar vòstre dessenh local, tampatz simplament l’onglet del navegador a la plaça)",
|
||||
"errorLoadingLibrary": "Una error s’es producha en cargant una bibliotèca tèrça.",
|
||||
"confirmAddLibrary": "Apondrà {{numShapes}} forma(s) a vòstra bibliotèca. Confirmatz ?",
|
||||
"imageDoesNotContainScene": "L’importacion d’imatge es pas encara presa en carga pel moment.\n\nVoliatz importar una scèna ? Aqueste imatge sembla pas conténer cap de donada de scèna. Aviatz activar aquò pendent l’export ?",
|
||||
"cannotRestoreFromImage": "Restauracion impossibla de la scèna a partir del fichièr imatge",
|
||||
"invalidSceneUrl": "Importacion impossibla de la scèna a partir de l’URL provesida. Es siá mal formatada o siá conten pas cap de donada JSON Excalidraw valida.",
|
||||
"resetLibrary": "Aquò suprimirà vòstra bibliotèca. Ne sètz vertadièrament ?"
|
||||
},
|
||||
"toolBar": {
|
||||
"selection": "Seleccion",
|
||||
"draw": "Dessenh liure",
|
||||
"rectangle": "Rectangle",
|
||||
"diamond": "Lausange",
|
||||
"ellipse": "Ellipsa",
|
||||
"arrow": "Sageta",
|
||||
"line": "Linha",
|
||||
"text": "Tèxt",
|
||||
"library": "Bibliotèca",
|
||||
"lock": "Mantenir activa l’aisina aprèp dessenhar"
|
||||
},
|
||||
"headings": {
|
||||
"canvasActions": "Accions del canabàs",
|
||||
"selectedShapeActions": "Accions per la forma seleccionada",
|
||||
"shapes": "Formas"
|
||||
},
|
||||
"hints": {
|
||||
"linearElement": "Clicatz per començar mantun punt, lisatz per una sola linha",
|
||||
"freeDraw": "Clicatz e lisatz, relargatz un còp acabat",
|
||||
"text": "Astúcia : podètz tanben apondre de tèxt en doble clicant ont que siá amb l’aisina de seleccion",
|
||||
"linearElementMulti": "Clicatz sul darrièr punt o quichatz Ecap o Entrada per acabar",
|
||||
"lockAngle": "Podètz restrénger l’angle en mantenent MAJ",
|
||||
"resize": "Podètz servar las proporcions en mantenent la tòca MAJ pendent lo redimensionament,\nmantenètz la tòca ALT per redimensionar a partir del centre",
|
||||
"rotate": "Podètz restrénger los angles en mantenent MAJ pendent la rotacion",
|
||||
"lineEditor_info": "Doble-clicatz o quichatz Entrada per modificar los punts",
|
||||
"lineEditor_pointSelected": "Quichatz Suprimir per suprimir lo punt, Ctrl o Cmd+D per lo duplicar, o fasètz lisar per lo desplaçar",
|
||||
"lineEditor_nothingSelected": "Seleccionatz un punt de desplaçar o suprimir, o mantenètz Alt e clicatz per apondre punts novèls"
|
||||
},
|
||||
"canvasError": {
|
||||
"cannotShowPreview": "Afichatge impossible de l’apercebut",
|
||||
"canvasTooBig": "Lo canabàs pòt èsser tròp grand.",
|
||||
"canvasTooBigTip": "Astúcia : ensajatz de sarrar los elements mai alonhats."
|
||||
},
|
||||
"errorSplash": {
|
||||
"headingMain_pre": "Una error s’es producha. Ensajatz ",
|
||||
"headingMain_button": "recargament de la pagina.",
|
||||
"clearCanvasMessage": "Se recargar fonciona pas, ensajatz ",
|
||||
"clearCanvasMessage_button": "d’escafar los canabasses.",
|
||||
"clearCanvasCaveat": " Menarà a una pèrda del trabalh ",
|
||||
"trackedToSentry_pre": "Error amb l’identificant ",
|
||||
"trackedToSentry_post": " es estada enregistrada sus nòstre sistèma.",
|
||||
"openIssueMessage_pre": "Èrem plan prudents per inclure pas d’informacions de la scèna vòstra sus l’error. Se vòstra scèna es pas privada, volgatz considerar de perseguir sus nòstre ",
|
||||
"openIssueMessage_button": "traçadors d’avarias.",
|
||||
"openIssueMessage_post": " Volgatz inclure las informacions çai-jos en las copiant e pegant a l’issue GitHub.",
|
||||
"sceneContent": "Contengut de la scèna :"
|
||||
},
|
||||
"roomDialog": {
|
||||
"desc_intro": "Podètz convidar lo monde a vòstra scèna actuala per participar amb vos.",
|
||||
"desc_privacy": "Vos en fagatz pas, la session utiliza lo chiframent del cap a la fin, çò que dessenetz demorarà privat. Mai nòstres servidors poiràn pas veire vòstra creacion.",
|
||||
"button_startSession": "Començar la session",
|
||||
"button_stopSession": "Arrestar la session",
|
||||
"desc_inProgressIntro": "La session de collaboracion es ara en cors.",
|
||||
"desc_shareLink": "Partejatz aqueste ligam amb lo monde amb qui volètz collaborar :",
|
||||
"desc_exitSession": "Arrestar la session vos desconnectarà de la sala, mas poiretz contunhar de trabalhar a la scèna, en local. Notatz qu’aquò afectarà pas los autres, e poiràn collaborar a lor version."
|
||||
},
|
||||
"errorDialog": {
|
||||
"title": "Error"
|
||||
},
|
||||
"helpDialog": {
|
||||
"blog": "Legir nòstre blog",
|
||||
"click": "clic",
|
||||
"curvedArrow": "Sageta corba",
|
||||
"curvedLine": "Linha corba",
|
||||
"documentation": "Documentacion",
|
||||
"drag": "lisar",
|
||||
"editor": "Editor",
|
||||
"github": "Problèma trobat ? Senhalatz-lo",
|
||||
"howto": "Seguissètz nòstras guidas",
|
||||
"or": "o",
|
||||
"preventBinding": "Empachar la fixacion de sagetas",
|
||||
"shapes": "Formas",
|
||||
"shortcuts": "Acorchis clavièr",
|
||||
"textFinish": "Terminar l’edicion (tèxt)",
|
||||
"textNewLine": "Apondre linha novèl (tèxt)",
|
||||
"title": "Ajuda",
|
||||
"view": "Vista",
|
||||
"zoomToFit": "Zoomar per veire totes los elements",
|
||||
"zoomToSelection": "Zoomar la seleccion"
|
||||
},
|
||||
"encrypted": {
|
||||
"tooltip": "Vòstres dessenhs son chifrats del cap a la fin en consequéncia los servidors d’Excalidraw los veiràn pas jamai."
|
||||
},
|
||||
"stats": {
|
||||
"angle": "Angle",
|
||||
"element": "Element",
|
||||
"elements": "Elements",
|
||||
"height": "Nautor",
|
||||
"scene": "Scèna",
|
||||
"selected": "Seleccionat",
|
||||
"storage": "Emmagazinatge",
|
||||
"title": "Estatisticas pels nerds",
|
||||
"total": "Total",
|
||||
"version": "Version",
|
||||
"versionCopy": "Clicar per copiar",
|
||||
"versionNotAvailable": "Version pas disponibla",
|
||||
"width": "Largor"
|
||||
},
|
||||
"toast": {
|
||||
"copyStyles": "Estiles copiats.",
|
||||
"copyToClipboard": "Copiats al quichapapièrs.",
|
||||
"copyToClipboardAsPng": "{{exportSelection}} copiat coma PNG ({{exportColorScheme}})",
|
||||
"fileSaved": "Fichièr enregistrat.",
|
||||
"fileSavedToFilename": "Enregistrat jos {filename}",
|
||||
"canvas": "canabàs",
|
||||
"selection": "seleccion"
|
||||
}
|
||||
}
|
||||
@@ -92,7 +92,8 @@
|
||||
"centerHorizontally": "ਖੜ੍ਹਵੇਂ ਵਿਚਕਾਰ ਕਰੋ",
|
||||
"distributeHorizontally": "ਖੜ੍ਹਵੇਂ ਇਕਸਾਰ ਵੰਡੋ",
|
||||
"distributeVertically": "ਲੇਟਵੇਂ ਇਕਸਾਰ ਵੰਡੋ",
|
||||
"viewMode": "ਦੇਖੋ ਮੋਡ"
|
||||
"viewMode": "ਦੇਖੋ ਮੋਡ",
|
||||
"toggleExportColorScheme": ""
|
||||
},
|
||||
"buttons": {
|
||||
"clearReset": "ਕੈਨਵਸ ਰੀਸੈੱਟ ਕਰੋ",
|
||||
@@ -141,6 +142,7 @@
|
||||
"confirmAddLibrary": "ਇਹ ਤੁਹਾਡੀ ਲਾਇਬ੍ਰੇਰੀ ਵਿੱਚ {{numShapes}} ਆਕ੍ਰਿਤੀ(ਆਂ) ਨੂੰ ਜੋੜ ਦੇਵੇਗਾ। ਕੀ ਤੁਸੀਂ ਪੱਕਾ ਇੰਝ ਕਰਨਾ ਚਾਹੁੰਦੇ ਹੋ?",
|
||||
"imageDoesNotContainScene": "ਫਿਲਹਾਲ ਤਸਵੀਰਾਂ ਨੂੰ ਆਯਾਤ ਕਰਨ ਦਾ ਸਮਰਥਨ ਨਹੀਂ ਕਰਦਾ।\n\nਕੀ ਤੁਸੀਂ ਦ੍ਰਿਸ਼ ਨੂੰ ਆਯਾਤ ਕਰਨਾ ਚਾਹੁੰਦੇ ਸੀ? ਇਸ ਤਸਵੀਰ ਵਿੱਚ ਦ੍ਰਿਸ਼ ਦਾ ਕੋਈ ਵੀ ਡਾਟਾ ਨਜ਼ਰ ਨਹੀਂ ਆ ਰਿਹਾ। ਕੀ ਨਿਰਯਾਤ ਦੌਰਾਨ ਤੁਸੀਂ ਇਹ ਸਮਰੱਥ ਕੀਤਾ ਸੀ?",
|
||||
"cannotRestoreFromImage": "ਇਸ ਤਸਵੀਰ ਫਾਈਲ ਤੋਂ ਦ੍ਰਿਸ਼ ਬਹਾਲ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਿਆ",
|
||||
"invalidSceneUrl": "",
|
||||
"resetLibrary": ""
|
||||
},
|
||||
"toolBar": {
|
||||
@@ -244,8 +246,10 @@
|
||||
"toast": {
|
||||
"copyStyles": "ਕਾਪੀ ਕੀਤੇ ਸਟਾਇਲ।",
|
||||
"copyToClipboard": "ਕਲਿੱਪਬੋਰਡ 'ਤੇ ਕਾਪੀ ਕੀਤਾ।",
|
||||
"copyToClipboardAsPng": "ਕਲਿੱਪਬੋਰਡ 'ਤੇ PNG ਵਜੋਂ ਕਾਪੀ ਕੀਤਾ।",
|
||||
"copyToClipboardAsPng": "",
|
||||
"fileSaved": "ਫਾਈਲ ਸਾਂਭੀ ਗਈ।",
|
||||
"fileSavedToFilename": "{filename} ਵਿੱਚ ਸਾਂਭੀ"
|
||||
"fileSavedToFilename": "{filename} ਵਿੱਚ ਸਾਂਭੀ",
|
||||
"canvas": "",
|
||||
"selection": ""
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user