mirror of
https://github.com/excalidraw/excalidraw
synced 2025-07-25 13:58:22 +08:00
Compare commits
2 Commits
aakansha-u
...
devolved-i
Author | SHA1 | Date | |
---|---|---|---|
b20fe944e7 | |||
1156ef6b96 |
@ -2,7 +2,6 @@
|
||||
"extends": ["prettier", "react-app"],
|
||||
"plugins": ["prettier"],
|
||||
"rules": {
|
||||
"@typescript-eslint/no-unused-vars": "warn",
|
||||
"curly": "warn",
|
||||
"dot-notation": "warn",
|
||||
"import/no-anonymous-default-export": "off",
|
||||
@ -23,6 +22,7 @@
|
||||
],
|
||||
"no-unneeded-ternary": "warn",
|
||||
"no-unused-expressions": "warn",
|
||||
"no-unused-vars": "warn",
|
||||
"no-useless-return": "warn",
|
||||
"no-var": "warn",
|
||||
"object-shorthand": "warn",
|
||||
|
@ -19,7 +19,7 @@
|
||||
### Option 2 - CodeSandbox
|
||||
|
||||
1. Go to https://codesandbox.io/s/github/excalidraw/excalidraw
|
||||
1. Connect your GitHub account
|
||||
1. Connect your Github account
|
||||
1. Go to Git tab on left side
|
||||
1. Tap on `Fork Sandbox`
|
||||
1. Write your code
|
||||
@ -35,6 +35,7 @@ Make sure the title starts with a semantic prefix:
|
||||
|
||||
- **feat**: A new feature
|
||||
- **fix**: A bug fix
|
||||
- **improvement**: An improvement to a current feature
|
||||
- **docs**: Documentation only changes
|
||||
- **style**: Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc)
|
||||
- **refactor**: A code change that neither fixes a bug nor adds a feature
|
||||
|
29
README.md
29
README.md
@ -2,7 +2,7 @@
|
||||
<a href="https://excalidraw.com">
|
||||
<img width="540" src="./public/og-image-sm.png" alt="Excalidraw logo: Sketch handrawn like diagrams." />
|
||||
</a>
|
||||
<h3>Virtual whiteboard for sketching hand-drawn like diagrams.<br>Collaborative and end-to-end encrypted.</h3>
|
||||
<h3>Virtual whiteboard for sketching hand-drawn like diagrams.<br>Collaborative and end to end encrypted.</h3>
|
||||
<p>
|
||||
<a href="https://twitter.com/Excalidraw">
|
||||
<img alt="Follow Excalidraw on Twitter" src="https://img.shields.io/twitter/follow/excalidraw.svg?label=follow+excalidraw&style=social&logo=twitter">
|
||||
@ -11,7 +11,6 @@
|
||||
<img src="https://badges.crowdin.net/excalidraw/localized.svg">
|
||||
</a>
|
||||
</p>
|
||||
<p>Ask questions or hang out on our <a target="_blank" href="https://discord.gg/UexuTaE">discord.gg/UexuTaE</a>.</p>
|
||||
</div>
|
||||
|
||||
## Try it now
|
||||
@ -20,14 +19,6 @@ Go to [excalidraw.com](https://excalidraw.com) to start sketching.
|
||||
|
||||
Read the latest news and updates on our [blog](https://blog.excalidraw.com). A good start is to see all the updates of [One Year of Excalidraw](https://blog.excalidraw.com/one-year-of-excalidraw/).
|
||||
|
||||
## Supporting Excalidraw
|
||||
|
||||
If you like the project, you can become a sponsor at [Open Collective](https://opencollective.com/excalidraw).
|
||||
|
||||
[<img src="https://opencollective.com/excalidraw/tiers/sponsors/0/avatar.svg?avatarHeight=120">](https://opencollective.com/excalidraw/tiers/sponsors/0/website) [<img src="https://opencollective.com/excalidraw/tiers/sponsors/1/avatar.svg?avatarHeight=120">](https://opencollective.com/excalidraw/tiers/sponsors/1/website) [<img src="https://opencollective.com/excalidraw/tiers/sponsors/2/avatar.svg?avatarHeight=120">](https://opencollective.com/excalidraw/tiers/sponsors/2/website) [<img src="https://opencollective.com/excalidraw/tiers/sponsors/3/avatar.svg?avatarHeight=120">](https://opencollective.com/excalidraw/tiers/sponsors/3/website) [<img src="https://opencollective.com/excalidraw/tiers/sponsors/4/avatar.svg?avatarHeight=120">](https://opencollective.com/excalidraw/tiers/sponsors/4/website) [<img src="https://opencollective.com/excalidraw/tiers/sponsors/5/avatar.svg?avatarHeight=120">](https://opencollective.com/excalidraw/tiers/sponsors/5/website) [<img src="https://opencollective.com/excalidraw/tiers/sponsors/6/avatar.svg?avatarHeight=120">](https://opencollective.com/excalidraw/tiers/sponsors/6/website) [<img src="https://opencollective.com/excalidraw/tiers/sponsors/7/avatar.svg?avatarHeight=120">](https://opencollective.com/excalidraw/tiers/sponsors/7/website) [<img src="https://opencollective.com/excalidraw/tiers/sponsors/8/avatar.svg?avatarHeight=120">](https://opencollective.com/excalidraw/tiers/sponsors/8/website) [<img src="https://opencollective.com/excalidraw/tiers/sponsors/9/avatar.svg?avatarHeight=120">](https://opencollective.com/excalidraw/tiers/sponsors/9/website) [<img src="https://opencollective.com/excalidraw/tiers/sponsors/10/avatar.svg?avatarHeight=120">](https://opencollective.com/excalidraw/tiers/sponsors/10/website)
|
||||
|
||||
<a href="https://opencollective.com/excalidraw#category-CONTRIBUTE" target="_blank"><img src="https://opencollective.com/excalidraw/tiers/backers.svg?avatarHeight=32"/></a>
|
||||
|
||||
## Documentation
|
||||
|
||||
### Shortcuts
|
||||
@ -50,7 +41,7 @@ Translations will be available on the app if they exceed a certain threshold of
|
||||
|
||||
### Create a collaboration session manually
|
||||
|
||||
In order to create a session manually, you just need to generate a link of this form:
|
||||
In order to create a session manually you just need to generate a link of this form:
|
||||
|
||||
```
|
||||
https://excalidraw.com/#room=[0-9a-f]{20},[a-zA-Z0-9_-]{22}
|
||||
@ -70,16 +61,12 @@ The second set of digits is the encryption key. The Excalidraw server doesn’t
|
||||
|
||||
Find a growing list of libraries containing assets for your drawings at [libraries.excalidraw.com](https://libraries.excalidraw.com).
|
||||
|
||||
## Embedding Excalidraw in your App?
|
||||
|
||||
Try out [`@excalidraw/excalidraw`](https://www.npmjs.com/package/@excalidraw/excalidraw). This package allows you to easily embed Excalidraw as a React component into your apps.
|
||||
|
||||
## Development
|
||||
## Developement
|
||||
|
||||
### Code Sandbox
|
||||
|
||||
- Go to https://codesandbox.io/s/github/excalidraw/excalidraw
|
||||
- You may need to sign in with GitHub and reload the page
|
||||
- You may need to sign in with Github and reload the page
|
||||
- You can start coding instantly, and even send PRs from there!
|
||||
|
||||
### Local Installation
|
||||
@ -105,15 +92,15 @@ git clone https://github.com/excalidraw/excalidraw.git
|
||||
|
||||
#### Docker Compose
|
||||
|
||||
You can use docker-compose to work on Excalidraw locally if you don't want to setup a Node.js env.
|
||||
You can use docker-compose to work on excalidraw locally if you don't want to setup a Node.js env.
|
||||
|
||||
```sh
|
||||
docker-compose up --build -d
|
||||
```
|
||||
|
||||
### Self-hosting
|
||||
### Self hosting
|
||||
|
||||
We publish a Docker image with the Excalidraw client at [excalidraw/excalidraw](https://hub.docker.com/r/excalidraw/excalidraw). You can use it to self-host your own client under your own domain, on Kubernetes, AWS ECS, etc.
|
||||
We publish a Docker image with the Excalidraw client at [excalidraw/excalidraw](https://hub.docker.com/r/excalidraw/excalidraw). You can use it to self host your own client under your own domain, on Kubernetes, AWS ECS, etc.
|
||||
|
||||
```sh
|
||||
docker build -t excalidraw/excalidraw .
|
||||
@ -124,7 +111,7 @@ The Docker image is free of analytics and other tracking libraries.
|
||||
|
||||
**At the moment, self-hosting your own instance doesn't support sharing or collaboration features.**
|
||||
|
||||
We are working towards providing a full-fledged solution for self-hosting your own Excalidraw.
|
||||
We are working towards providing a full-fledged solution for self hosting your own Excalidraw.
|
||||
|
||||
## Contributing
|
||||
|
||||
|
3012
package-lock.json
generated
3012
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
25
package.json
25
package.json
@ -19,17 +19,17 @@
|
||||
]
|
||||
},
|
||||
"dependencies": {
|
||||
"@sentry/browser": "6.1.0",
|
||||
"@sentry/integrations": "6.1.0",
|
||||
"@sentry/browser": "6.0.3",
|
||||
"@sentry/integrations": "6.0.3",
|
||||
"@testing-library/jest-dom": "5.11.9",
|
||||
"@testing-library/react": "11.2.5",
|
||||
"@testing-library/react": "11.2.3",
|
||||
"@types/jest": "26.0.20",
|
||||
"@types/react": "17.0.2",
|
||||
"@types/react-dom": "17.0.1",
|
||||
"@types/react": "17.0.0",
|
||||
"@types/react-dom": "17.0.0",
|
||||
"@types/socket.io-client": "1.4.35",
|
||||
"browser-fs-access": "0.13.1",
|
||||
"browser-fs-access": "0.13.0",
|
||||
"clsx": "1.1.1",
|
||||
"firebase": "8.2.7",
|
||||
"firebase": "8.2.5",
|
||||
"i18next-browser-languagedetector": "6.0.1",
|
||||
"lodash.throttle": "4.1.1",
|
||||
"nanoid": "3.1.20",
|
||||
@ -43,21 +43,20 @@
|
||||
"pwacompat": "2.0.17",
|
||||
"react": "17.0.1",
|
||||
"react-dom": "17.0.1",
|
||||
"react-scripts": "4.0.2",
|
||||
"react-scripts": "4.0.1",
|
||||
"roughjs": "4.3.1",
|
||||
"socket.io-client": "2.3.1",
|
||||
"typescript": "4.1.5"
|
||||
"typescript": "4.1.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@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-plugin-prettier": "3.3.1",
|
||||
"firebase-tools": "9.3.0",
|
||||
"firebase-tools": "9.2.2",
|
||||
"husky": "4.3.8",
|
||||
"jest-canvas-mock": "2.3.1",
|
||||
"lint-staged": "10.5.4",
|
||||
"jest-canvas-mock": "2.3.0",
|
||||
"lint-staged": "10.5.3",
|
||||
"pepjs": "0.5.3",
|
||||
"prettier": "2.2.1",
|
||||
"rewire": "5.0.0"
|
||||
|
@ -96,24 +96,9 @@ export const actionChangeShouldAddWatermark = register({
|
||||
export const actionSaveScene = register({
|
||||
name: "saveScene",
|
||||
perform: async (elements, appState, value) => {
|
||||
const fileHandleExists = !!appState.fileHandle;
|
||||
try {
|
||||
const { fileHandle } = await saveAsJSON(elements, appState);
|
||||
return {
|
||||
commitToHistory: false,
|
||||
appState: {
|
||||
...appState,
|
||||
fileHandle,
|
||||
toastMessage: fileHandleExists
|
||||
? fileHandle.name
|
||||
? t("toast.fileSavedToFilename").replace(
|
||||
"{filename}",
|
||||
`"${fileHandle.name}"`,
|
||||
)
|
||||
: t("toast.fileSaved")
|
||||
: null,
|
||||
},
|
||||
};
|
||||
return { commitToHistory: false, appState: { ...appState, fileHandle } };
|
||||
} catch (error) {
|
||||
if (error?.name !== "AbortError") {
|
||||
console.error(error);
|
||||
|
@ -83,7 +83,7 @@ export const actionFinalize = register({
|
||||
// If the multi point line closes the loop,
|
||||
// set the last point to first point.
|
||||
// This ensures that loop remains closed at different scales.
|
||||
const isLoop = isPathALoop(multiPointElement.points, appState.zoom.value);
|
||||
const isLoop = isPathALoop(multiPointElement.points);
|
||||
if (
|
||||
multiPointElement.type === "line" ||
|
||||
multiPointElement.type === "draw"
|
||||
|
@ -42,7 +42,7 @@ export const actionGoToCollaborator = register({
|
||||
return null;
|
||||
}
|
||||
|
||||
const { background, stroke } = getClientColors(clientId, appState);
|
||||
const { background, stroke } = getClientColors(clientId);
|
||||
const shortName = getClientInitials(collaborator.username);
|
||||
|
||||
return (
|
||||
|
@ -17,6 +17,6 @@ export const actionToggleGridMode = register({
|
||||
};
|
||||
},
|
||||
checked: (appState: AppState) => appState.gridSize !== null,
|
||||
contextItemLabel: "labels.showGrid",
|
||||
contextItemLabel: "labels.gridMode",
|
||||
keyTest: (event) => event[KEYS.CTRL_OR_CMD] && event.code === CODES.QUOTE,
|
||||
});
|
||||
|
@ -8,7 +8,6 @@ import {
|
||||
} from "./types";
|
||||
import { ExcalidrawElement } from "../element/types";
|
||||
import { AppState, ExcalidrawProps } from "../types";
|
||||
import { MODES } from "../constants";
|
||||
|
||||
// This is the <App> component, but for now we don't care about anything but its
|
||||
// `canvas` state.
|
||||
@ -69,7 +68,7 @@ export class ActionManager implements ActionsManagerInterface {
|
||||
}
|
||||
const { viewModeEnabled } = this.getAppState();
|
||||
if (viewModeEnabled) {
|
||||
if (!Object.values(MODES).includes(data[0].name)) {
|
||||
if (data[0].name !== "viewMode") {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -1,13 +1,6 @@
|
||||
import colors from "./colors";
|
||||
import { AppState } from "./types";
|
||||
|
||||
export const getClientColors = (clientId: string, appState: AppState) => {
|
||||
if (appState?.collaborators) {
|
||||
const currentUser = appState.collaborators.get(clientId);
|
||||
if (currentUser?.color) {
|
||||
return currentUser.color;
|
||||
}
|
||||
}
|
||||
export const getClientColors = (clientId: string) => {
|
||||
// Naive way of getting an integer out of the clientId
|
||||
const sum = clientId.split("").reduce((a, str) => a + str.charCodeAt(0), 0);
|
||||
|
||||
|
@ -4,6 +4,7 @@ import { RoughCanvas } from "roughjs/bin/canvas";
|
||||
import rough from "roughjs/bin/rough";
|
||||
import clsx from "clsx";
|
||||
|
||||
import "../actions";
|
||||
import {
|
||||
actionAddToLibrary,
|
||||
actionBringForward,
|
||||
@ -47,11 +48,9 @@ import {
|
||||
ELEMENT_TRANSLATE_AMOUNT,
|
||||
ENV,
|
||||
EVENT,
|
||||
GRID_SIZE,
|
||||
LINE_CONFIRM_THRESHOLD,
|
||||
MIME_TYPES,
|
||||
POINTER_BUTTON,
|
||||
SCROLL_TIMEOUT,
|
||||
TAP_TWICE_TIMEOUT,
|
||||
TEXT_TO_CENTER_SNAP_THRESHOLD,
|
||||
TOUCH_CTX_MENU_TIMEOUT,
|
||||
@ -300,8 +299,6 @@ class App extends React.Component<ExcalidrawProps, AppState> {
|
||||
offsetTop,
|
||||
excalidrawRef,
|
||||
viewModeEnabled = false,
|
||||
zenModeEnabled = false,
|
||||
gridModeEnabled = false,
|
||||
} = props;
|
||||
this.state = {
|
||||
...defaultAppState,
|
||||
@ -310,8 +307,6 @@ class App extends React.Component<ExcalidrawProps, AppState> {
|
||||
height,
|
||||
...this.getCanvasOffsets({ offsetLeft, offsetTop }),
|
||||
viewModeEnabled,
|
||||
zenModeEnabled,
|
||||
gridSize: gridModeEnabled ? GRID_SIZE : null,
|
||||
};
|
||||
if (excalidrawRef) {
|
||||
const readyPromise =
|
||||
@ -458,9 +453,6 @@ class App extends React.Component<ExcalidrawProps, AppState> {
|
||||
onExportToBackend={onExportToBackend}
|
||||
renderCustomFooter={renderFooter}
|
||||
viewModeEnabled={viewModeEnabled}
|
||||
showExitZenModeBtn={
|
||||
typeof this.props?.zenModeEnabled === "undefined" && zenModeEnabled
|
||||
}
|
||||
/>
|
||||
<div className="excalidraw-textEditorContainer" />
|
||||
{this.state.showStats && (
|
||||
@ -519,21 +511,11 @@ class App extends React.Component<ExcalidrawProps, AppState> {
|
||||
}
|
||||
|
||||
let viewModeEnabled = actionResult?.appState?.viewModeEnabled || false;
|
||||
let zenModeEnabled = actionResult?.appState?.zenModeEnabled || false;
|
||||
let gridSize = actionResult?.appState?.gridSize || null;
|
||||
|
||||
if (typeof this.props.viewModeEnabled !== "undefined") {
|
||||
viewModeEnabled = this.props.viewModeEnabled;
|
||||
}
|
||||
|
||||
if (typeof this.props.zenModeEnabled !== "undefined") {
|
||||
zenModeEnabled = this.props.zenModeEnabled;
|
||||
}
|
||||
|
||||
if (typeof this.props.gridModeEnabled !== "undefined") {
|
||||
gridSize = this.props.gridModeEnabled ? GRID_SIZE : null;
|
||||
}
|
||||
|
||||
this.setState(
|
||||
(state) => ({
|
||||
...actionResult.appState,
|
||||
@ -544,8 +526,6 @@ class App extends React.Component<ExcalidrawProps, AppState> {
|
||||
offsetTop: state.offsetTop,
|
||||
offsetLeft: state.offsetLeft,
|
||||
viewModeEnabled,
|
||||
zenModeEnabled,
|
||||
gridSize,
|
||||
}),
|
||||
() => {
|
||||
if (actionResult.syncHistory) {
|
||||
@ -826,7 +806,6 @@ class App extends React.Component<ExcalidrawProps, AppState> {
|
||||
|
||||
document.addEventListener(EVENT.PASTE, this.pasteFromClipboard);
|
||||
document.addEventListener(EVENT.CUT, this.onCut);
|
||||
document.addEventListener(EVENT.SCROLL, this.onScroll);
|
||||
|
||||
window.addEventListener(EVENT.RESIZE, this.onResize, false);
|
||||
window.addEventListener(EVENT.UNLOAD, this.onUnload, false);
|
||||
@ -866,15 +845,6 @@ class App extends React.Component<ExcalidrawProps, AppState> {
|
||||
this.addEventListeners();
|
||||
}
|
||||
|
||||
if (prevProps.zenModeEnabled !== this.props.zenModeEnabled) {
|
||||
this.setState({ zenModeEnabled: !!this.props.zenModeEnabled });
|
||||
}
|
||||
|
||||
if (prevProps.gridModeEnabled !== this.props.gridModeEnabled) {
|
||||
this.setState({
|
||||
gridSize: this.props.gridModeEnabled ? GRID_SIZE : null,
|
||||
});
|
||||
}
|
||||
document
|
||||
.querySelector(".excalidraw")
|
||||
?.classList.toggle("Appearance_dark", this.state.appearance === "dark");
|
||||
@ -1000,10 +970,6 @@ class App extends React.Component<ExcalidrawProps, AppState> {
|
||||
}
|
||||
}
|
||||
|
||||
private onScroll = debounce(() => {
|
||||
this.setState({ ...this.getCanvasOffsets() });
|
||||
}, SCROLL_TIMEOUT);
|
||||
|
||||
// Copy/paste
|
||||
|
||||
private onCut = withBatchedUpdates((event: ClipboardEvent) => {
|
||||
@ -1556,7 +1522,6 @@ class App extends React.Component<ExcalidrawProps, AppState> {
|
||||
textWysiwyg({
|
||||
id: element.id,
|
||||
appState: this.state,
|
||||
canvas: this.canvas,
|
||||
getViewportCoords: (x, y) => {
|
||||
const { x: viewportX, y: viewportY } = sceneCoordsToViewportCoords(
|
||||
{
|
||||
@ -1963,7 +1928,7 @@ class App extends React.Component<ExcalidrawProps, AppState> {
|
||||
points: points.slice(0, -1),
|
||||
});
|
||||
} else {
|
||||
if (isPathALoop(points, this.state.zoom.value)) {
|
||||
if (isPathALoop(points)) {
|
||||
document.documentElement.style.cursor = CURSOR_TYPE.POINTER;
|
||||
}
|
||||
// update last uncommitted point
|
||||
@ -2635,10 +2600,7 @@ class App extends React.Component<ExcalidrawProps, AppState> {
|
||||
const { multiElement } = this.state;
|
||||
|
||||
// finalize if completing a loop
|
||||
if (
|
||||
multiElement.type === "line" &&
|
||||
isPathALoop(multiElement.points, this.state.zoom.value)
|
||||
) {
|
||||
if (multiElement.type === "line" && isPathALoop(multiElement.points)) {
|
||||
mutateElement(multiElement, {
|
||||
lastCommittedPoint:
|
||||
multiElement.points[multiElement.points.length - 1],
|
||||
@ -3491,11 +3453,40 @@ class App extends React.Component<ExcalidrawProps, AppState> {
|
||||
}
|
||||
};
|
||||
|
||||
private handleCanvasImageDrop = async (
|
||||
event: React.DragEvent<HTMLCanvasElement>,
|
||||
file: File,
|
||||
) => {
|
||||
try {
|
||||
const shapes = await (
|
||||
await import(
|
||||
/* webpackChunkName: "pixelated-image" */ "../data/pixelated-image"
|
||||
)
|
||||
).pixelateImage(file, 20, 1200, event.clientX, event.clientY);
|
||||
|
||||
const nextElements = [
|
||||
...this.scene.getElementsIncludingDeleted(),
|
||||
...shapes,
|
||||
];
|
||||
|
||||
this.scene.replaceAllElements(nextElements);
|
||||
} catch (error) {
|
||||
return this.setState({
|
||||
isLoading: false,
|
||||
errorMessage: error.message,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
private handleCanvasOnDrop = async (
|
||||
event: React.DragEvent<HTMLCanvasElement>,
|
||||
) => {
|
||||
let imageFile: File | null = null;
|
||||
try {
|
||||
const file = event.dataTransfer.files[0];
|
||||
if (file?.type.indexOf("image/") === 0) {
|
||||
imageFile = file;
|
||||
}
|
||||
if (file?.type === "image/png" || file?.type === "image/svg+xml") {
|
||||
const { elements, appState } = await loadFromBlob(file, this.state);
|
||||
this.syncActionResult({
|
||||
@ -3507,8 +3498,13 @@ class App extends React.Component<ExcalidrawProps, AppState> {
|
||||
commitToHistory: true,
|
||||
});
|
||||
return;
|
||||
} else if (imageFile) {
|
||||
return await this.handleCanvasImageDrop(event, imageFile);
|
||||
}
|
||||
} catch (error) {
|
||||
if (imageFile) {
|
||||
return await this.handleCanvasImageDrop(event, imageFile);
|
||||
}
|
||||
return this.setState({
|
||||
isLoading: false,
|
||||
errorMessage: error.message,
|
||||
@ -3709,16 +3705,15 @@ class App extends React.Component<ExcalidrawProps, AppState> {
|
||||
options.push(actionCopyAsSvg);
|
||||
}
|
||||
if (!element) {
|
||||
const viewModeOptions = [
|
||||
const viewModeOptions: ContextMenuOption[] = [
|
||||
...options,
|
||||
typeof this.props.gridModeEnabled === "undefined" &&
|
||||
actionToggleGridMode,
|
||||
typeof this.props.zenModeEnabled === "undefined" && actionToggleZenMode,
|
||||
typeof this.props.viewModeEnabled === "undefined" &&
|
||||
actionToggleViewMode,
|
||||
actionToggleStats,
|
||||
];
|
||||
|
||||
if (typeof this.props.viewModeEnabled === "undefined") {
|
||||
viewModeOptions.push(actionToggleViewMode);
|
||||
}
|
||||
|
||||
ContextMenu.push({
|
||||
options: viewModeOptions,
|
||||
top: clientY,
|
||||
@ -3756,10 +3751,8 @@ class App extends React.Component<ExcalidrawProps, AppState> {
|
||||
separator,
|
||||
actionSelectAll,
|
||||
separator,
|
||||
typeof this.props.gridModeEnabled === "undefined" &&
|
||||
actionToggleGridMode,
|
||||
typeof this.props.zenModeEnabled === "undefined" &&
|
||||
actionToggleZenMode,
|
||||
actionToggleGridMode,
|
||||
actionToggleZenMode,
|
||||
typeof this.props.viewModeEnabled === "undefined" &&
|
||||
actionToggleViewMode,
|
||||
actionToggleStats,
|
||||
|
@ -2,10 +2,9 @@
|
||||
|
||||
.excalidraw {
|
||||
.CollabButton.is-collaborating {
|
||||
background-color: var(--button-special-active-bg-color);
|
||||
background-color: var(--button-special-active-background-color);
|
||||
|
||||
.ToolIcon__icon svg,
|
||||
.ToolIcon__label {
|
||||
.ToolIcon__icon svg {
|
||||
color: var(--icon-green-fill-color);
|
||||
}
|
||||
}
|
||||
|
@ -25,8 +25,8 @@ const CollabButton = ({
|
||||
onClick={onClick}
|
||||
icon={users}
|
||||
type="button"
|
||||
title={t("labels.liveCollaboration")}
|
||||
aria-label={t("labels.liveCollaboration")}
|
||||
title={t("buttons.roomDialog")}
|
||||
aria-label={t("buttons.roomDialog")}
|
||||
showAriaLabel={useIsMobile()}
|
||||
>
|
||||
{collaboratorCount > 0 && (
|
||||
|
@ -2,9 +2,9 @@
|
||||
|
||||
.excalidraw {
|
||||
.color-picker {
|
||||
background: var(--popup-bg-color);
|
||||
border: 0 solid transparentize($oc-white, 0.75);
|
||||
box-shadow: transparentize($oc-black, 0.75) 0 1px 4px;
|
||||
background: var(--popup-background-color);
|
||||
border: 0px solid transparentize($oc-white, 0.75);
|
||||
box-shadow: transparentize($oc-black, 0.75) 0px 1px 4px;
|
||||
border-radius: 4px;
|
||||
position: absolute;
|
||||
|
||||
@ -24,11 +24,11 @@
|
||||
}
|
||||
|
||||
.color-picker-triangle {
|
||||
width: 0;
|
||||
height: 0;
|
||||
width: 0px;
|
||||
height: 0px;
|
||||
border-style: solid;
|
||||
border-width: 0 9px 10px;
|
||||
border-color: transparent transparent var(--popup-bg-color);
|
||||
border-width: 0px 9px 10px;
|
||||
border-color: transparent transparent var(--popup-background-color);
|
||||
position: absolute;
|
||||
top: -10px;
|
||||
|
||||
@ -84,12 +84,12 @@
|
||||
|
||||
.color-picker-transparent {
|
||||
border-radius: 4px;
|
||||
box-shadow: transparentize($oc-black, 0.9) 0 0 0 1px inset;
|
||||
box-shadow: transparentize($oc-black, 0.9) 0px 0px 0px 1px inset;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
top: 0px;
|
||||
right: 0px;
|
||||
bottom: 0px;
|
||||
left: 0px;
|
||||
}
|
||||
|
||||
.color-picker-transparent,
|
||||
@ -104,11 +104,11 @@
|
||||
width: 1.875rem;
|
||||
|
||||
:root[dir="ltr"] & {
|
||||
border-radius: 4px 0 0 4px;
|
||||
border-radius: 4px 0px 0px 4px;
|
||||
}
|
||||
|
||||
:root[dir="rtl"] & {
|
||||
border-radius: 0 4px 4px 0;
|
||||
border-radius: 0px 4px 4px 0px;
|
||||
}
|
||||
|
||||
color: var(--input-label-color);
|
||||
@ -144,7 +144,7 @@
|
||||
}
|
||||
|
||||
.color-input-container:focus-within .color-picker-hash::after {
|
||||
background: var(--input-bg-color);
|
||||
background: var(--input-background-color);
|
||||
|
||||
:root[dir="ltr"] & {
|
||||
right: -2px;
|
||||
@ -163,19 +163,19 @@
|
||||
width: 12ch; /* length of `transparent` + 1 */
|
||||
margin: 0;
|
||||
font-size: 1rem;
|
||||
background-color: var(--input-bg-color);
|
||||
color: var(--text-primary-color);
|
||||
border: 0;
|
||||
background-color: var(--input-background-color);
|
||||
color: var(--text-color-primary);
|
||||
border: 0px;
|
||||
outline: none;
|
||||
height: 1.75em;
|
||||
box-shadow: var(--input-border-color) 0 0 0 1px inset;
|
||||
box-shadow: var(--input-border-color) 0px 0px 0px 1px inset;
|
||||
|
||||
:root[dir="ltr"] & {
|
||||
border-radius: 0 4px 4px 0;
|
||||
border-radius: 0px 4px 4px 0px;
|
||||
}
|
||||
|
||||
:root[dir="rtl"] & {
|
||||
border-radius: 4px 0 0 4px;
|
||||
border-radius: 4px 0px 0px 4px;
|
||||
}
|
||||
|
||||
float: left;
|
||||
@ -228,7 +228,7 @@
|
||||
}
|
||||
|
||||
.color-picker-type-elementBackground .color-picker-keybinding {
|
||||
color: $oc-white;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.color-picker-swatch[aria-label="transparent"] .color-picker-keybinding {
|
||||
@ -241,10 +241,10 @@
|
||||
|
||||
&.Appearance_dark {
|
||||
.color-picker-type-elementBackground .color-picker-keybinding {
|
||||
color: $oc-black;
|
||||
color: #000;
|
||||
}
|
||||
.color-picker-swatch[aria-label="transparent"] .color-picker-keybinding {
|
||||
color: $oc-black;
|
||||
color: #000;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4,13 +4,13 @@
|
||||
.context-menu {
|
||||
position: relative;
|
||||
border-radius: 4px;
|
||||
box-shadow: 0 3px 10px transparentize($oc-black, 0.8);
|
||||
box-shadow: 0px 3px 10px transparentize($oc-black, 0.8);
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
user-select: none;
|
||||
margin: -0.25rem 0 0 0.125rem;
|
||||
padding: 0.5rem 0;
|
||||
background-color: var(--popup-secondary-bg-color);
|
||||
background-color: var(--popup-secondary-background-color);
|
||||
border: 1px solid var(--button-gray-3);
|
||||
cursor: default;
|
||||
}
|
||||
@ -61,12 +61,12 @@
|
||||
}
|
||||
|
||||
.context-menu-option:hover {
|
||||
color: var(--popup-bg-color);
|
||||
color: var(--popup-background-color);
|
||||
background-color: var(--select-highlight-color);
|
||||
|
||||
&.dangerous {
|
||||
.context-menu-option__label {
|
||||
color: var(--popup-bg-color);
|
||||
color: var(--popup-background-color);
|
||||
}
|
||||
background-color: $oc-red-6;
|
||||
}
|
||||
|
@ -45,7 +45,7 @@
|
||||
position: sticky;
|
||||
top: 0;
|
||||
padding: calc(var(--space-factor) * 2);
|
||||
background: var(--island-bg-color);
|
||||
background: var(--bg-color-island);
|
||||
font-size: 1.25em;
|
||||
|
||||
box-sizing: border-box;
|
||||
|
@ -224,7 +224,7 @@ export const HelpDialog = ({ onClose }: { onClose?: () => void }) => {
|
||||
shortcuts={[getShortcutKey("Alt+Z")]}
|
||||
/>
|
||||
<Shortcut
|
||||
label={t("labels.showGrid")}
|
||||
label={t("labels.gridMode")}
|
||||
shortcuts={[getShortcutKey("CtrlOrCmd+'")]}
|
||||
/>
|
||||
<Shortcut
|
||||
|
@ -26,7 +26,7 @@ $wide-viewport-width: 1000px;
|
||||
|
||||
> span {
|
||||
padding: 0.2rem 0.4rem;
|
||||
background-color: var(--overlay-bg-color);
|
||||
background-color: var(--overlay-background-color);
|
||||
border-radius: 4px;
|
||||
}
|
||||
}
|
||||
|
@ -8,9 +8,9 @@
|
||||
}
|
||||
|
||||
.picker {
|
||||
background: var(--popup-bg-color);
|
||||
border: 0 solid transparentize($oc-white, 0.75);
|
||||
box-shadow: transparentize($oc-black, 0.75) 0 1px 4px;
|
||||
background: var(--popup-background-color);
|
||||
border: 0px solid transparentize($oc-white, 0.75);
|
||||
box-shadow: transparentize($oc-black, 0.75) 0px 1px 4px;
|
||||
border-radius: 4px;
|
||||
position: absolute;
|
||||
}
|
||||
@ -56,8 +56,8 @@
|
||||
}
|
||||
|
||||
.picker-triangle {
|
||||
width: 0;
|
||||
height: 0;
|
||||
width: 0px;
|
||||
height: 0px;
|
||||
position: relative;
|
||||
top: -10px;
|
||||
:root[dir="ltr"] & {
|
||||
@ -73,7 +73,7 @@
|
||||
content: "";
|
||||
position: absolute;
|
||||
border-style: solid;
|
||||
border-width: 0 9px 10px;
|
||||
border-width: 0px 9px 10px;
|
||||
border-color: transparent transparent transparentize($oc-black, 0.9);
|
||||
top: -1px;
|
||||
}
|
||||
@ -82,8 +82,8 @@
|
||||
content: "";
|
||||
position: absolute;
|
||||
border-style: solid;
|
||||
border-width: 0 9px 10px;
|
||||
border-color: transparent transparent var(--popup-bg-color);
|
||||
border-width: 0px 9px 10px;
|
||||
border-color: transparent transparent var(--popup-background-color);
|
||||
}
|
||||
}
|
||||
|
||||
@ -121,7 +121,7 @@
|
||||
}
|
||||
|
||||
.picker-type-elementBackground .picker-keybinding {
|
||||
color: $oc-white;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.picker-swatch[aria-label="transparent"] .picker-keybinding {
|
||||
@ -134,10 +134,10 @@
|
||||
|
||||
&.Appearance_dark {
|
||||
.picker-type-elementBackground .picker-keybinding {
|
||||
color: $oc-black;
|
||||
color: #000;
|
||||
}
|
||||
.picker-swatch[aria-label="transparent"] .picker-keybinding {
|
||||
color: $oc-black;
|
||||
color: #000;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,12 @@
|
||||
import React from "react";
|
||||
|
||||
import { LoadingMessage } from "./LoadingMessage";
|
||||
import { defaultLang, Language, languages, setLanguage } from "../i18n";
|
||||
import {
|
||||
defaultLang,
|
||||
Language,
|
||||
languages,
|
||||
setLanguageFirstTime,
|
||||
} from "../i18n";
|
||||
|
||||
interface Props {
|
||||
langCode: Language["code"];
|
||||
@ -18,7 +23,7 @@ export class InitializeApp extends React.Component<Props, State> {
|
||||
const currentLang =
|
||||
languages.find((lang) => lang.code === this.props.langCode) ||
|
||||
defaultLang;
|
||||
await setLanguage(currentLang);
|
||||
await setLanguageFirstTime(currentLang);
|
||||
this.setState({
|
||||
isLoading: false,
|
||||
});
|
||||
|
@ -1,7 +1,7 @@
|
||||
.excalidraw {
|
||||
.Island {
|
||||
--padding: 0;
|
||||
background-color: var(--island-bg-color);
|
||||
background-color: var(--bg-color-island);
|
||||
backdrop-filter: saturate(100%) blur(10px);
|
||||
box-shadow: var(--shadow-island);
|
||||
border-radius: 4px;
|
||||
|
@ -19,9 +19,9 @@
|
||||
}
|
||||
|
||||
a {
|
||||
margin-inline-start: auto;
|
||||
margin-left: auto;
|
||||
// 17px for scrollbar (needed for overlay scrollbars on Big Sur?) + 1px extra
|
||||
padding-inline-end: 18px;
|
||||
padding-right: 18px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
@ -73,7 +73,7 @@
|
||||
&__footer {
|
||||
position: absolute;
|
||||
z-index: 100;
|
||||
bottom: 0;
|
||||
bottom: 0px;
|
||||
|
||||
:root[dir="ltr"] & {
|
||||
right: 0;
|
||||
@ -94,7 +94,7 @@
|
||||
}
|
||||
|
||||
:root[dir="ltr"] &.transition-right {
|
||||
transform: translate(999px, 0);
|
||||
transform: translate(999px, 0px);
|
||||
}
|
||||
|
||||
:root[dir="rtl"] &.transition-left {
|
||||
|
@ -27,7 +27,7 @@ import { ExportCB, ExportDialog } from "./ExportDialog";
|
||||
import { FixedSideContainer } from "./FixedSideContainer";
|
||||
import { GitHubCorner } from "./GitHubCorner";
|
||||
import { HintViewer } from "./HintViewer";
|
||||
import { exportFile, load, shield, trash } from "./icons";
|
||||
import { exportFile, load, shield } from "./icons";
|
||||
import { Island } from "./Island";
|
||||
import "./LayerUI.scss";
|
||||
import { LibraryUnit } from "./LibraryUnit";
|
||||
@ -52,7 +52,6 @@ interface LayerUIProps {
|
||||
onLockToggle: () => void;
|
||||
onInsertElements: (elements: readonly NonDeletedExcalidrawElement[]) => void;
|
||||
zenModeEnabled: boolean;
|
||||
showExitZenModeBtn: boolean;
|
||||
toggleZenMode: () => void;
|
||||
langCode: Language["code"];
|
||||
isCollaborating: boolean;
|
||||
@ -100,7 +99,6 @@ const LibraryMenuItems = ({
|
||||
onInsertShape,
|
||||
pendingElements,
|
||||
setAppState,
|
||||
setLibraryItems,
|
||||
}: {
|
||||
library: LibraryItems;
|
||||
pendingElements: LibraryItem;
|
||||
@ -108,7 +106,6 @@ const LibraryMenuItems = ({
|
||||
onInsertShape: (elements: LibraryItem) => void;
|
||||
onAddToLibrary: (elements: LibraryItem) => void;
|
||||
setAppState: React.Component<any, AppState>["setState"];
|
||||
setLibraryItems: (library: LibraryItems) => void;
|
||||
}) => {
|
||||
const isMobile = useIsMobile();
|
||||
const numCells = library.length + (pendingElements.length > 0 ? 1 : 0);
|
||||
@ -152,19 +149,6 @@ const LibraryMenuItems = ({
|
||||
});
|
||||
}}
|
||||
/>
|
||||
<ToolButton
|
||||
key="reset"
|
||||
type="button"
|
||||
title={t("buttons.resetLibrary")}
|
||||
aria-label={t("buttons.resetLibrary")}
|
||||
icon={trash}
|
||||
onClick={() => {
|
||||
if (window.confirm(t("alerts.resetLibrary"))) {
|
||||
Library.resetLibrary();
|
||||
setLibraryItems([]);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
|
||||
<a href="https://libraries.excalidraw.com" target="_excalidraw_libraries">
|
||||
{t("labels.libraries")}
|
||||
@ -296,7 +280,6 @@ const LibraryMenu = ({
|
||||
onInsertShape={onInsertShape}
|
||||
pendingElements={pendingElements}
|
||||
setAppState={setAppState}
|
||||
setLibraryItems={setLibraryItems}
|
||||
/>
|
||||
)}
|
||||
</Island>
|
||||
@ -313,7 +296,6 @@ const LayerUI = ({
|
||||
onLockToggle,
|
||||
onInsertElements,
|
||||
zenModeEnabled,
|
||||
showExitZenModeBtn,
|
||||
toggleZenMode,
|
||||
isCollaborating,
|
||||
onExportToBackend,
|
||||
@ -442,15 +424,7 @@ const LayerUI = ({
|
||||
"transition-left": zenModeEnabled,
|
||||
})}
|
||||
>
|
||||
<Island
|
||||
className={CLASSES.SHAPE_ACTIONS_MENU}
|
||||
padding={2}
|
||||
style={{
|
||||
// we want to make sure this doesn't overflow so substracting 200
|
||||
// which is approximately height of zoom footer and top left menu items with some buffer
|
||||
maxHeight: `${appState.height - 200}px`,
|
||||
}}
|
||||
>
|
||||
<Island className={CLASSES.SHAPE_ACTIONS_MENU} padding={2}>
|
||||
<SelectedShapeActions
|
||||
appState={appState}
|
||||
elements={elements}
|
||||
@ -539,18 +513,17 @@ const LayerUI = ({
|
||||
"transition-right": zenModeEnabled,
|
||||
})}
|
||||
>
|
||||
{appState.collaborators.size > 0 &&
|
||||
Array.from(appState.collaborators)
|
||||
// Collaborator is either not initialized or is actually the current user.
|
||||
.filter(([_, client]) => Object.keys(client).length !== 0)
|
||||
.map(([clientId, client]) => (
|
||||
<Tooltip
|
||||
label={client.username || "Unknown user"}
|
||||
key={clientId}
|
||||
>
|
||||
{actionManager.renderAction("goToCollaborator", clientId)}
|
||||
</Tooltip>
|
||||
))}
|
||||
{Array.from(appState.collaborators)
|
||||
// Collaborator is either not initialized or is actually the current user.
|
||||
.filter(([_, client]) => Object.keys(client).length !== 0)
|
||||
.map(([clientId, client]) => (
|
||||
<Tooltip
|
||||
label={client.username || "Unknown user"}
|
||||
key={clientId}
|
||||
>
|
||||
{actionManager.renderAction("goToCollaborator", clientId)}
|
||||
</Tooltip>
|
||||
))}
|
||||
</UserList>
|
||||
</div>
|
||||
</FixedSideContainer>
|
||||
@ -605,12 +578,24 @@ const LayerUI = ({
|
||||
</div>
|
||||
<button
|
||||
className={clsx("disable-zen-mode", {
|
||||
"disable-zen-mode--visible": showExitZenModeBtn,
|
||||
"disable-zen-mode--visible": zenModeEnabled,
|
||||
})}
|
||||
onClick={toggleZenMode}
|
||||
>
|
||||
{t("buttons.exitZenMode")}
|
||||
</button>
|
||||
{appState.scrolledOutside && (
|
||||
<button
|
||||
className="scroll-back-to-content"
|
||||
onClick={() => {
|
||||
setAppState({
|
||||
...calculateScrollCenter(elements, appState, canvas),
|
||||
});
|
||||
}}
|
||||
>
|
||||
{t("buttons.scrollBackToContent")}
|
||||
</button>
|
||||
)}
|
||||
</footer>
|
||||
);
|
||||
|
||||
@ -673,18 +658,6 @@ const LayerUI = ({
|
||||
{renderBottomAppMenu()}
|
||||
{renderGitHubCorner()}
|
||||
{renderFooter()}
|
||||
{appState.scrolledOutside && (
|
||||
<button
|
||||
className="scroll-back-to-content"
|
||||
onClick={() => {
|
||||
setAppState({
|
||||
...calculateScrollCenter(elements, appState, canvas),
|
||||
});
|
||||
}}
|
||||
>
|
||||
{t("buttons.scrollBackToContent")}
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
@ -152,26 +152,24 @@ export const MobileMenu = ({
|
||||
<Stack.Col gap={4}>
|
||||
{renderCanvasActions()}
|
||||
{renderCustomFooter?.(true)}
|
||||
{appState.collaborators.size > 0 && (
|
||||
<fieldset>
|
||||
<legend>{t("labels.collaborators")}</legend>
|
||||
<UserList mobile>
|
||||
{Array.from(appState.collaborators)
|
||||
// Collaborator is either not initialized or is actually the current user.
|
||||
.filter(
|
||||
([_, client]) => Object.keys(client).length !== 0,
|
||||
)
|
||||
.map(([clientId, client]) => (
|
||||
<React.Fragment key={clientId}>
|
||||
{actionManager.renderAction(
|
||||
"goToCollaborator",
|
||||
clientId,
|
||||
)}
|
||||
</React.Fragment>
|
||||
))}
|
||||
</UserList>
|
||||
</fieldset>
|
||||
)}
|
||||
<fieldset>
|
||||
<legend>{t("labels.collaborators")}</legend>
|
||||
<UserList mobile>
|
||||
{Array.from(appState.collaborators)
|
||||
// Collaborator is either not initialized or is actually the current user.
|
||||
.filter(
|
||||
([_, client]) => Object.keys(client).length !== 0,
|
||||
)
|
||||
.map(([clientId, client]) => (
|
||||
<React.Fragment key={clientId}>
|
||||
{actionManager.renderAction(
|
||||
"goToCollaborator",
|
||||
clientId,
|
||||
)}
|
||||
</React.Fragment>
|
||||
))}
|
||||
</UserList>
|
||||
</fieldset>
|
||||
</Stack.Col>
|
||||
</div>
|
||||
</Section>
|
||||
|
@ -1,13 +1,8 @@
|
||||
@import "../css/variables.module";
|
||||
|
||||
.excalidraw {
|
||||
&.excalidraw-modal-container {
|
||||
position: absolute;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.Modal {
|
||||
position: absolute;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
@ -20,7 +15,7 @@
|
||||
}
|
||||
|
||||
.Modal__background {
|
||||
position: absolute;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
@ -44,10 +39,10 @@
|
||||
overflow-y: auto;
|
||||
|
||||
// for modals, reset blurry bg
|
||||
background: var(--island-bg-color);
|
||||
background: var(--bg-color-island);
|
||||
backdrop-filter: none;
|
||||
|
||||
border: 1px solid var(--dialog-border-color);
|
||||
border: 1px solid var(--dialog-border);
|
||||
box-shadow: 0 2px 10px transparentize($oc-black, 0.75);
|
||||
border-radius: 6px;
|
||||
|
||||
@ -87,7 +82,7 @@
|
||||
}
|
||||
|
||||
.Modal__content {
|
||||
position: absolute;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
|
@ -54,7 +54,7 @@ const useBodyRoot = () => {
|
||||
?.classList.contains("Appearance_dark");
|
||||
const div = document.createElement("div");
|
||||
|
||||
div.classList.add("excalidraw", "excalidraw-modal-container");
|
||||
div.classList.add("excalidraw");
|
||||
|
||||
if (isDarkTheme) {
|
||||
div.classList.add("Appearance_dark");
|
||||
|
@ -1,6 +1,14 @@
|
||||
.excalidraw {
|
||||
.popover {
|
||||
position: fixed;
|
||||
position: absolute;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.popover .cover {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
}
|
||||
}
|
||||
|
@ -1,53 +1,51 @@
|
||||
@import "../css/variables.module";
|
||||
|
||||
.excalidraw {
|
||||
.Stats {
|
||||
position: absolute;
|
||||
top: 64px;
|
||||
right: 12px;
|
||||
font-size: 12px;
|
||||
z-index: 999;
|
||||
.Stats {
|
||||
position: fixed;
|
||||
top: 64px;
|
||||
right: 12px;
|
||||
font-size: 12px;
|
||||
z-index: 999;
|
||||
|
||||
h3 {
|
||||
margin: 0 24px 8px 0;
|
||||
white-space: nowrap;
|
||||
}
|
||||
h3 {
|
||||
margin: 0 24px 8px 0;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.close {
|
||||
float: right;
|
||||
height: 16px;
|
||||
width: 16px;
|
||||
cursor: pointer;
|
||||
svg {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
table {
|
||||
.close {
|
||||
float: right;
|
||||
height: 16px;
|
||||
width: 16px;
|
||||
cursor: pointer;
|
||||
svg {
|
||||
width: 100%;
|
||||
th {
|
||||
border-bottom: 1px solid var(--input-border-color);
|
||||
padding: 4px;
|
||||
}
|
||||
tr {
|
||||
td:nth-child(2) {
|
||||
min-width: 24px;
|
||||
text-align: right;
|
||||
}
|
||||
}
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
:root[dir="rtl"] & {
|
||||
left: 12px;
|
||||
right: initial;
|
||||
|
||||
h3 {
|
||||
margin: 0 0 8px 24px;
|
||||
}
|
||||
.close {
|
||||
float: left;
|
||||
table {
|
||||
width: 100%;
|
||||
th {
|
||||
border-bottom: 1px solid var(--input-border-color);
|
||||
padding: 4px;
|
||||
}
|
||||
tr {
|
||||
td:nth-child(2) {
|
||||
min-width: 24px;
|
||||
text-align: right;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
:root[dir="rtl"] & {
|
||||
left: 12px;
|
||||
right: initial;
|
||||
|
||||
h3 {
|
||||
margin: 0 0 8px 24px;
|
||||
}
|
||||
.close {
|
||||
float: left;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,18 +2,18 @@
|
||||
|
||||
.excalidraw {
|
||||
.TextInput {
|
||||
color: var(--text-primary-color);
|
||||
color: var(--text-color-primary);
|
||||
display: inline-block;
|
||||
border: 1.5px solid var(--button-gray-1);
|
||||
line-height: 1;
|
||||
padding: 0.75rem;
|
||||
white-space: nowrap;
|
||||
border-radius: var(--space-factor);
|
||||
background-color: var(--input-bg-color);
|
||||
background-color: var(--input-background-color);
|
||||
|
||||
&:not(:focus) {
|
||||
&:hover {
|
||||
background-color: var(--input-hover-bg-color);
|
||||
background-color: var(--input-hover-background-color);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -11,7 +11,7 @@
|
||||
left: 50%;
|
||||
margin-left: -150px;
|
||||
padding: 4px 0;
|
||||
position: absolute;
|
||||
position: fixed;
|
||||
text-align: center;
|
||||
width: 300px;
|
||||
z-index: 999999;
|
||||
|
@ -2,8 +2,8 @@ import { FontFamily } from "./element/types";
|
||||
|
||||
export const APP_NAME = "Excalidraw";
|
||||
|
||||
export const DRAGGING_THRESHOLD = 10; // px
|
||||
export const LINE_CONFIRM_THRESHOLD = 8; // px
|
||||
export const DRAGGING_THRESHOLD = 10; // 10px
|
||||
export const LINE_CONFIRM_THRESHOLD = 10; // 10px
|
||||
export const ELEMENT_SHIFT_TRANSLATE_AMOUNT = 5;
|
||||
export const ELEMENT_TRANSLATE_AMOUNT = 1;
|
||||
export const TEXT_TO_CENTER_SNAP_THRESHOLD = 30;
|
||||
@ -47,7 +47,6 @@ export enum EVENT {
|
||||
TOUCH_END = "touchend",
|
||||
HASHCHANGE = "hashchange",
|
||||
VISIBILITY_CHANGE = "visibilitychange",
|
||||
SCROLL = "scroll",
|
||||
}
|
||||
|
||||
export const ENV = {
|
||||
@ -93,7 +92,6 @@ 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 ZOOM_STEP = 0.1;
|
||||
|
||||
@ -101,9 +99,3 @@ export const ZOOM_STEP = 0.1;
|
||||
export const IDLE_THRESHOLD = 60_000;
|
||||
// Report a user active each ACTIVE_THRESHOLD milliseconds
|
||||
export const ACTIVE_THRESHOLD = 3_000;
|
||||
|
||||
export const MODES = {
|
||||
VIEW: "viewMode",
|
||||
ZEN: "zenMode",
|
||||
GRID: "gridMode",
|
||||
};
|
||||
|
@ -8,8 +8,9 @@
|
||||
}
|
||||
|
||||
.excalidraw {
|
||||
color: var(--text-primary-color);
|
||||
color: var(--text-color-primary);
|
||||
display: flex;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
@ -50,10 +51,10 @@
|
||||
}
|
||||
|
||||
.FixedSideContainer {
|
||||
padding-top: var(--sat, 0);
|
||||
padding-right: var(--sar, 0);
|
||||
padding-bottom: var(--sab, 0);
|
||||
padding-left: var(--sal, 0);
|
||||
padding-top: var(--sat, 0px);
|
||||
padding-right: var(--sar, 0px);
|
||||
padding-bottom: var(--sab, 0px);
|
||||
padding-left: var(--sal, 0px);
|
||||
}
|
||||
|
||||
.panelRow {
|
||||
@ -71,7 +72,7 @@
|
||||
margin-top: 0.333rem;
|
||||
margin-bottom: 0.333rem;
|
||||
font-size: 0.75rem;
|
||||
color: var(--text-primary-color);
|
||||
color: var(--text-color-primary);
|
||||
font-weight: bold;
|
||||
display: block;
|
||||
}
|
||||
@ -226,8 +227,7 @@
|
||||
.App-top-bar {
|
||||
z-index: var(--zIndex-layerUI);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.App-bottom-bar {
|
||||
@ -237,10 +237,10 @@
|
||||
left: 0;
|
||||
right: 0;
|
||||
--bar-padding: calc(4 * var(--space-factor));
|
||||
padding-top: #{"max(var(--bar-padding), var(--sat,0))"};
|
||||
padding-right: var(--sar, 0);
|
||||
padding-bottom: var(--sab, 0);
|
||||
padding-left: var(--sal, 0);
|
||||
padding-top: #{"max(var(--bar-padding), var(--sat, 0px))"};
|
||||
padding-right: var(--sar, 0px);
|
||||
padding-bottom: var(--sab, 0px);
|
||||
padding-left: var(--sal, 0px);
|
||||
z-index: 4;
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
@ -257,7 +257,7 @@
|
||||
pointer-events: initial;
|
||||
|
||||
.panelColumn {
|
||||
padding: 8px 8px 0 8px;
|
||||
padding: 8px 8px 0px 8px;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -361,6 +361,7 @@
|
||||
|
||||
.App-menu__left {
|
||||
overflow-y: auto;
|
||||
max-height: calc(100vh - 236px);
|
||||
}
|
||||
|
||||
.dropdown-select {
|
||||
@ -432,7 +433,7 @@
|
||||
|
||||
.scroll-back-to-content {
|
||||
color: var(--popup-text-color);
|
||||
position: absolute;
|
||||
position: fixed;
|
||||
left: 50%;
|
||||
bottom: 30px;
|
||||
transform: translateX(-50%);
|
||||
@ -460,7 +461,7 @@
|
||||
display: none;
|
||||
}
|
||||
.scroll-back-to-content {
|
||||
bottom: calc(80px + var(--sab, 0));
|
||||
bottom: calc(80px + var(--sab, 0px));
|
||||
z-index: -1;
|
||||
}
|
||||
}
|
||||
|
@ -1,43 +1,43 @@
|
||||
@import "open-color/open-color.scss";
|
||||
|
||||
:root {
|
||||
--appearance-filter: none;
|
||||
--button-destructive-bg-color: #{$oc-red-1};
|
||||
--button-destructive-color: #{$oc-red-9};
|
||||
--bg-color-island: rgba(255, 255, 255, 0.9);
|
||||
--popup-background-color: #{$oc-white};
|
||||
--space-factor: 0.25rem;
|
||||
--button-gray-1: #{$oc-gray-2};
|
||||
--button-gray-2: #{$oc-gray-4};
|
||||
--button-gray-3: #{$oc-gray-5};
|
||||
--button-special-active-bg-color: #{$oc-green-0};
|
||||
--dialog-border-color: #{$oc-gray-6};
|
||||
--dropdown-icon: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="292.4" height="292.4" viewBox="0 0 292 292"><path d="M287 197L159 69c-4-3-8-5-13-5s-9 2-13 5L5 197c-3 4-5 8-5 13s2 9 5 13c4 4 8 5 13 5h256c5 0 9-1 13-5s5-8 5-13-1-9-5-13z"/></svg>');
|
||||
--focus-highlight-color: #{$oc-blue-2};
|
||||
--input-border-color: #{$oc-gray-3};
|
||||
--input-background-color: #{$oc-white};
|
||||
--input-hover-background-color: #{$oc-gray-1};
|
||||
--input-label-color: #{$oc-gray-7};
|
||||
--icon-fill-color: #{$oc-black};
|
||||
--icon-green-fill-color: #{$oc-green-9};
|
||||
--input-bg-color: #{$oc-white};
|
||||
--input-border-color: #{$oc-gray-3};
|
||||
--input-hover-bg-color: #{$oc-gray-1};
|
||||
--input-label-color: #{$oc-gray-7};
|
||||
--island-bg-color: rgba(255, 255, 255, 0.9);
|
||||
--keybinding-color: #{$oc-gray-5};
|
||||
--link-color: #{$oc-blue-7};
|
||||
--overlay-bg-color: #{transparentize($oc-white, 0.12)};
|
||||
--popup-bg-color: #{$oc-white};
|
||||
--popup-secondary-bg-color: #{$oc-gray-1};
|
||||
--popup-text-color: #{$oc-black};
|
||||
--popup-text-inverted-color: #{$oc-white};
|
||||
--sat: env(safe-area-inset-top);
|
||||
--sab: env(safe-area-inset-bottom);
|
||||
--sal: env(safe-area-inset-left);
|
||||
--sar: env(safe-area-inset-right);
|
||||
--sat: env(safe-area-inset-top);
|
||||
--select-highlight-color: #{$oc-blue-5};
|
||||
--text-color-primary: #{$oc-gray-8};
|
||||
--shadow-island: 0 1px 5px #{transparentize($oc-black, 0.85)};
|
||||
--space-factor: 0.25rem;
|
||||
--text-primary-color: #{$oc-gray-8};
|
||||
--overlay-background-color: #{transparentize($oc-white, 0.12)};
|
||||
--dropdown-icon: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="292.4" height="292.4" viewBox="0 0 292 292"><path d="M287 197L159 69c-4-3-8-5-13-5s-9 2-13 5L5 197c-3 4-5 8-5 13s2 9 5 13c4 4 8 5 13 5h256c5 0 9-1 13-5s5-8 5-13-1-9-5-13z"/></svg>');
|
||||
--focus-highlight-color: #{$oc-blue-2};
|
||||
--select-highlight-color: #{$oc-blue-5};
|
||||
--appearance-filter: none;
|
||||
--button-special-active-background-color: #{$oc-green-0};
|
||||
--button-destructive-color: #{$oc-red-9};
|
||||
--button-destructive-background-color: #{$oc-red-1};
|
||||
--popup-secondary-background-color: #{$oc-gray-1};
|
||||
--popup-text-color: #{$oc-black};
|
||||
--popup-text-inverted-color: #{$oc-white};
|
||||
--dialog-border: #{$oc-gray-6};
|
||||
--link-color: #{$oc-blue-7};
|
||||
}
|
||||
|
||||
.excalidraw {
|
||||
&.Appearance_dark {
|
||||
background: $oc-black;
|
||||
background: #000;
|
||||
|
||||
&.Appearance_dark-background-none {
|
||||
background: none;
|
||||
@ -45,31 +45,31 @@
|
||||
}
|
||||
|
||||
&.Appearance_dark {
|
||||
--appearance-filter: invert(93%) hue-rotate(180deg);
|
||||
--button-destructive-bg-color: #5a0000;
|
||||
--button-destructive-color: #{$oc-red-3};
|
||||
--text-color-primary: #{$oc-gray-4};
|
||||
--bg-color-island: #1e1e1e;
|
||||
--popup-background-color: #2c2c2c;
|
||||
--button-gray-1: #363636;
|
||||
--button-gray-2: #272727;
|
||||
--button-gray-3: #222;
|
||||
--button-special-active-bg-color: #204624;
|
||||
--dialog-border-color: #{$oc-gray-9};
|
||||
--dropdown-icon: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="292.4" height="292.4" viewBox="0 0 292 292"><path fill="%23ced4da" d="M287 197L159 69c-4-3-8-5-13-5s-9 2-13 5L5 197c-3 4-5 8-5 13s2 9 5 13c4 4 8 5 13 5h256c5 0 9-1 13-5s5-8 5-13-1-9-5-13z"/></svg>');
|
||||
--focus-highlight-color: #{$oc-blue-6};
|
||||
--input-border-color: #2e2e2e;
|
||||
--input-background-color: #121212;
|
||||
--input-hover-background-color: #181818;
|
||||
--input-label-color: #{$oc-gray-2};
|
||||
--icon-fill-color: #{$oc-gray-4};
|
||||
--icon-green-fill-color: #{$oc-green-4};
|
||||
--input-bg-color: #121212;
|
||||
--input-border-color: #2e2e2e;
|
||||
--input-hover-bg-color: #181818;
|
||||
--input-label-color: #{$oc-gray-2};
|
||||
--island-bg-color: #1e1e1e;
|
||||
--keybinding-color: #{$oc-gray-6};
|
||||
--overlay-bg-color: #{transparentize($oc-gray-8, 0.88)};
|
||||
--popup-bg-color: #2c2c2c;
|
||||
--popup-secondary-bg-color: #222;
|
||||
--shadow-island: 0 1px 5px #{transparentize($oc-black, 0.7)};
|
||||
--overlay-background-color: rgba(30, 30, 30, 0.88);
|
||||
--dropdown-icon: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="292.4" height="292.4" viewBox="0 0 292 292"><path fill="%23ced4da" d="M287 197L159 69c-4-3-8-5-13-5s-9 2-13 5L5 197c-3 4-5 8-5 13s2 9 5 13c4 4 8 5 13 5h256c5 0 9-1 13-5s5-8 5-13-1-9-5-13z"/></svg>');
|
||||
--focus-highlight-color: #{$oc-blue-6};
|
||||
--select-highlight-color: #{$oc-blue-4};
|
||||
--appearance-filter: invert(93%) hue-rotate(180deg);
|
||||
--button-special-active-background-color: #204624;
|
||||
--button-destructive-color: #{$oc-red-3};
|
||||
--button-destructive-background-color: #5a0000;
|
||||
--popup-secondary-background-color: #222;
|
||||
--popup-text-color: #{$oc-gray-4};
|
||||
--popup-text-inverted-color: #2c2c2c;
|
||||
--select-highlight-color: #{$oc-blue-4};
|
||||
--shadow-island: 0 1px 5px #{transparentize($oc-black, 0.7)};
|
||||
--text-primary-color: #{$oc-gray-4};
|
||||
--dialog-border: #{$oc-gray-9};
|
||||
}
|
||||
}
|
||||
|
106
src/data/pixelated-image.ts
Normal file
106
src/data/pixelated-image.ts
Normal file
@ -0,0 +1,106 @@
|
||||
import { ExcalidrawGenericElement, NonDeleted } from "../element/types";
|
||||
import { newElement } from "../element";
|
||||
import { DEFAULT_FONT_FAMILY, DEFAULT_FONT_SIZE } from "../constants";
|
||||
import { randomId } from "../random";
|
||||
|
||||
const loadImage = async (url: string): Promise<HTMLImageElement> => {
|
||||
const image = new Image();
|
||||
return new Promise<HTMLImageElement>((resolve, reject) => {
|
||||
image.onload = () => resolve(image);
|
||||
image.onerror = (err) =>
|
||||
reject(
|
||||
new Error(
|
||||
`Failed to load image: ${err ? err.toString : "unknown error"}`,
|
||||
),
|
||||
);
|
||||
image.onabort = () =>
|
||||
reject(new Error(`Failed to load image: image load aborted`));
|
||||
image.src = url;
|
||||
});
|
||||
};
|
||||
|
||||
const commonProps = {
|
||||
fillStyle: "solid",
|
||||
fontFamily: DEFAULT_FONT_FAMILY,
|
||||
fontSize: DEFAULT_FONT_SIZE,
|
||||
opacity: 100,
|
||||
roughness: 1,
|
||||
strokeColor: "transparent",
|
||||
strokeSharpness: "sharp",
|
||||
strokeStyle: "solid",
|
||||
strokeWidth: 1,
|
||||
verticalAlign: "middle",
|
||||
} as const;
|
||||
|
||||
export const pixelateImage = async (
|
||||
blob: Blob,
|
||||
cellSize: number,
|
||||
suggestedMaxShapeCount: number,
|
||||
x: number,
|
||||
y: number,
|
||||
) => {
|
||||
const url = URL.createObjectURL(blob);
|
||||
try {
|
||||
const image = await loadImage(url);
|
||||
|
||||
// initialize canvas for pixelation
|
||||
const { width, height } = image;
|
||||
let canvasWidth = Math.floor(width / cellSize);
|
||||
let canvasHeight = Math.floor(height / cellSize);
|
||||
const shapeCount = canvasHeight * canvasWidth;
|
||||
if (shapeCount > suggestedMaxShapeCount) {
|
||||
canvasWidth = Math.floor(
|
||||
canvasWidth * (suggestedMaxShapeCount / shapeCount),
|
||||
);
|
||||
canvasHeight = Math.floor(
|
||||
canvasHeight * (suggestedMaxShapeCount / shapeCount),
|
||||
);
|
||||
}
|
||||
const xOffset = x - (canvasWidth * cellSize) / 2;
|
||||
const yOffset = y - (canvasHeight * cellSize) / 2;
|
||||
|
||||
const canvas =
|
||||
"OffscreenCanvas" in window
|
||||
? new OffscreenCanvas(canvasWidth, canvasHeight)
|
||||
: document.createElement("canvas");
|
||||
canvas.width = canvasWidth;
|
||||
canvas.height = canvasHeight;
|
||||
|
||||
// Draw image on canvas
|
||||
const ctx = canvas.getContext("2d")!;
|
||||
ctx.drawImage(image, 0, 0, width, height, 0, 0, canvasWidth, canvasHeight);
|
||||
const imageData = ctx.getImageData(0, 0, canvasWidth, canvasHeight);
|
||||
const buffer = imageData.data;
|
||||
|
||||
const groupId = randomId();
|
||||
const shapes: NonDeleted<ExcalidrawGenericElement>[] = [];
|
||||
|
||||
for (let row = 0; row < canvasHeight; row++) {
|
||||
for (let col = 0; col < canvasWidth; col++) {
|
||||
const offset = row * canvasWidth * 4 + col * 4;
|
||||
const r = buffer[offset];
|
||||
const g = buffer[offset + 1];
|
||||
const b = buffer[offset + 2];
|
||||
const alpha = buffer[offset + 3];
|
||||
if (alpha) {
|
||||
const color = `rgba(${r}, ${g}, ${b}, ${alpha})`;
|
||||
const rectangle = newElement({
|
||||
backgroundColor: color,
|
||||
groupIds: [groupId],
|
||||
...commonProps,
|
||||
type: "rectangle",
|
||||
x: xOffset + col * cellSize,
|
||||
y: yOffset + row * cellSize,
|
||||
width: cellSize,
|
||||
height: cellSize,
|
||||
});
|
||||
shapes.push(rectangle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return shapes;
|
||||
} finally {
|
||||
URL.revokeObjectURL(url);
|
||||
}
|
||||
};
|
@ -141,7 +141,7 @@ export const restoreElements = (
|
||||
}, [] as ExcalidrawElement[]);
|
||||
};
|
||||
|
||||
export const restoreAppState = (
|
||||
const restoreAppState = (
|
||||
appState: ImportedDataState["appState"],
|
||||
localAppState: Partial<AppState> | null,
|
||||
): AppState => {
|
||||
|
@ -129,7 +129,7 @@ export class LinearElementEditor {
|
||||
isDragging &&
|
||||
(activePointIndex === 0 || activePointIndex === element.points.length - 1)
|
||||
) {
|
||||
if (isPathALoop(element.points, appState.zoom.value)) {
|
||||
if (isPathALoop(element.points)) {
|
||||
LinearElementEditor.movePoint(
|
||||
element,
|
||||
activePointIndex,
|
||||
|
@ -38,7 +38,6 @@ export const textWysiwyg = ({
|
||||
onSubmit,
|
||||
getViewportCoords,
|
||||
element,
|
||||
canvas,
|
||||
}: {
|
||||
id: ExcalidrawElement["id"];
|
||||
appState: AppState;
|
||||
@ -46,7 +45,6 @@ export const textWysiwyg = ({
|
||||
onSubmit: (text: string) => void;
|
||||
getViewportCoords: (x: number, y: number) => [number, number];
|
||||
element: ExcalidrawElement;
|
||||
canvas: HTMLCanvasElement | null;
|
||||
}) => {
|
||||
const updateWysiwygStyle = () => {
|
||||
const updatedElement = Scene.getScene(element)?.getElement(id);
|
||||
@ -153,10 +151,6 @@ export const textWysiwyg = ({
|
||||
editable.oninput = null;
|
||||
editable.onkeydown = null;
|
||||
|
||||
if (observer) {
|
||||
observer.disconnect();
|
||||
}
|
||||
|
||||
window.removeEventListener("resize", updateWysiwygStyle);
|
||||
window.removeEventListener("wheel", stopEvent, true);
|
||||
window.removeEventListener("pointerdown", onPointerDown);
|
||||
@ -203,19 +197,9 @@ export const textWysiwyg = ({
|
||||
let isDestroyed = false;
|
||||
|
||||
editable.onblur = handleSubmit;
|
||||
|
||||
// reposition wysiwyg in case of canvas is resized. Using ResizeObserver
|
||||
// is preferred so we catch changes from host, where window may not resize.
|
||||
let observer: ResizeObserver | null = null;
|
||||
if (canvas && "ResizeObserver" in window) {
|
||||
observer = new window.ResizeObserver(() => {
|
||||
updateWysiwygStyle();
|
||||
});
|
||||
observer.observe(canvas);
|
||||
} else {
|
||||
window.addEventListener("resize", updateWysiwygStyle);
|
||||
}
|
||||
|
||||
// reposition wysiwyg in case of window resize. Happens on mobile when
|
||||
// device keyboard is opened.
|
||||
window.addEventListener("resize", updateWysiwygStyle);
|
||||
window.addEventListener("pointerdown", onPointerDown);
|
||||
window.addEventListener("wheel", stopEvent, {
|
||||
passive: false,
|
||||
|
@ -7,7 +7,7 @@
|
||||
}
|
||||
|
||||
.RoomDialog-link {
|
||||
color: var(--text-primary-color);
|
||||
color: var(--text-color-primary);
|
||||
min-width: 0;
|
||||
flex: 1 1 auto;
|
||||
margin-inline-start: 1em;
|
||||
@ -32,29 +32,15 @@
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
@media #{$is-mobile-query} {
|
||||
flex-direction: column;
|
||||
align-items: stretch;
|
||||
}
|
||||
}
|
||||
|
||||
@media #{$is-mobile-query} {
|
||||
.RoomDialog-usernameLabel {
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
|
||||
.RoomDialog-username {
|
||||
background-color: var(--input-bg-color);
|
||||
background-color: var(--input-background-color);
|
||||
border-color: var(--input-border-color);
|
||||
appearance: none;
|
||||
min-width: 0;
|
||||
flex: 1 1 auto;
|
||||
margin-inline-start: 1em;
|
||||
@media #{$is-mobile-query} {
|
||||
margin-top: 0.5em;
|
||||
margin-inline-start: 0;
|
||||
}
|
||||
height: 2.5rem;
|
||||
font-size: 1em;
|
||||
line-height: 1.5;
|
||||
@ -67,7 +53,7 @@
|
||||
}
|
||||
|
||||
.Modal .RoomDialog-stopSession {
|
||||
background-color: var(--button-destructive-bg-color);
|
||||
background-color: var(--button-destructive-background-color);
|
||||
|
||||
.ToolIcon__label,
|
||||
.ToolIcon__icon svg {
|
||||
|
@ -119,11 +119,7 @@ const RoomDialog = ({
|
||||
);
|
||||
};
|
||||
return (
|
||||
<Dialog
|
||||
small
|
||||
onCloseRequest={handleClose}
|
||||
title={t("labels.liveCollaboration")}
|
||||
>
|
||||
<Dialog small onCloseRequest={handleClose} title={t("labels.createRoom")}>
|
||||
{renderRoomDialog()}
|
||||
</Dialog>
|
||||
);
|
||||
|
@ -80,14 +80,7 @@ const initializeScene = async (opts: {
|
||||
let roomLinkData = getCollaborationLinkData(window.location.href);
|
||||
const isExternalScene = !!(id || jsonMatch || roomLinkData);
|
||||
if (isExternalScene) {
|
||||
if (
|
||||
// don't prompt if scene is empty
|
||||
!scene.elements.length ||
|
||||
// don't prompt for collab scenes because we don't override local storage
|
||||
roomLinkData ||
|
||||
// otherwise, prompt whether user wants to override current scene
|
||||
window.confirm(t("alerts.loadSceneOverridePrompt"))
|
||||
) {
|
||||
if (roomLinkData || window.confirm(t("alerts.loadSceneOverridePrompt"))) {
|
||||
// Backwards compatibility with legacy url format
|
||||
if (id) {
|
||||
scene = await loadScene(id, null, initialData);
|
||||
@ -281,6 +274,7 @@ function ExcalidrawWrapper() {
|
||||
width={dimensions.width}
|
||||
height={dimensions.height}
|
||||
initialData={initialStatePromiseRef.current.promise}
|
||||
user={{ name: collabAPI?.username }}
|
||||
onCollabButtonClick={collabAPI?.onCollabButtonClick}
|
||||
isCollaborating={collabAPI?.isCollaborating()}
|
||||
onPointerUpdate={collabAPI?.onPointerUpdate}
|
||||
|
40
src/i18n.ts
40
src/i18n.ts
@ -1,6 +1,5 @@
|
||||
import fallbackLangData from "./locales/en.json";
|
||||
import percentages from "./locales/percentages.json";
|
||||
import { ENV } from "./constants";
|
||||
|
||||
const COMPLETION_THRESHOLD = 85;
|
||||
|
||||
@ -56,33 +55,25 @@ export const languages: Language[] = allLanguages
|
||||
COMPLETION_THRESHOLD,
|
||||
);
|
||||
|
||||
const TEST_LANG_CODE = "__test__";
|
||||
if (process.env.NODE_ENV === ENV.DEVELOPMENT) {
|
||||
languages.unshift(
|
||||
{ code: TEST_LANG_CODE, label: "test language" },
|
||||
{
|
||||
code: `${TEST_LANG_CODE}.rtl`,
|
||||
label: "\u{202a}test language (rtl)\u{202c}",
|
||||
rtl: true,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
let currentLang: Language = defaultLang;
|
||||
let currentLangData = {};
|
||||
|
||||
export const setLanguage = async (lang: Language) => {
|
||||
currentLang = lang;
|
||||
document.documentElement.dir = currentLang.rtl ? "rtl" : "ltr";
|
||||
document.documentElement.lang = currentLang.code;
|
||||
|
||||
if (lang.code.startsWith(TEST_LANG_CODE)) {
|
||||
currentLangData = {};
|
||||
} else {
|
||||
currentLangData = await import(
|
||||
/* webpackChunkName: "i18n-[request]" */ `./locales/${currentLang.code}.json`
|
||||
);
|
||||
}
|
||||
currentLangData = await import(
|
||||
/* webpackChunkName: "i18n-[request]" */ `./locales/${currentLang.code}.json`
|
||||
);
|
||||
};
|
||||
|
||||
export const setLanguageFirstTime = async (lang: Language) => {
|
||||
currentLang = lang;
|
||||
document.documentElement.dir = currentLang.rtl ? "rtl" : "ltr";
|
||||
|
||||
currentLangData = await import(
|
||||
/* webpackChunkName: "i18n-[request]" */ `./locales/${currentLang.code}.json`
|
||||
);
|
||||
};
|
||||
|
||||
export const getLanguage = () => currentLang;
|
||||
@ -102,13 +93,6 @@ const findPartsForData = (data: any, parts: string[]) => {
|
||||
};
|
||||
|
||||
export const t = (path: string, replacement?: { [key: string]: string }) => {
|
||||
if (currentLang.code.startsWith(TEST_LANG_CODE)) {
|
||||
const name = replacement
|
||||
? `${path}(${JSON.stringify(replacement).slice(1, -1)})`
|
||||
: path;
|
||||
return `\u{202a}[[${name}]]\u{202c}`;
|
||||
}
|
||||
|
||||
const parts = path.split(".");
|
||||
let translation =
|
||||
findPartsForData(currentLangData, parts) ||
|
||||
|
@ -68,7 +68,7 @@
|
||||
"layers": "الطبقات",
|
||||
"actions": "الإجراءات",
|
||||
"language": "اللغة",
|
||||
"liveCollaboration": "",
|
||||
"createRoom": "مشاركة الجلسة مباشرة",
|
||||
"duplicateSelection": "تكرار",
|
||||
"untitled": "غير معنون",
|
||||
"name": "الاسم",
|
||||
@ -77,7 +77,7 @@
|
||||
"group": "تحديد مجموعة",
|
||||
"ungroup": "إلغاء تحديد مجموعة",
|
||||
"collaborators": "المتعاونون",
|
||||
"showGrid": "",
|
||||
"gridMode": "وضع الشبكة",
|
||||
"addToLibrary": "أضف إلى المكتبة",
|
||||
"removeFromLibrary": "حذف من المكتبة",
|
||||
"libraryLoadingMessage": "جارٍ تحميل المكتبة…",
|
||||
@ -117,7 +117,7 @@
|
||||
"edit": "تعديل",
|
||||
"undo": "تراجع",
|
||||
"redo": "إعادة تنفيذ",
|
||||
"resetLibrary": "",
|
||||
"roomDialog": "بدء المشاركة الحية",
|
||||
"createNewRoom": "إنشاء غرفة جديدة",
|
||||
"fullScreen": "شاشة كاملة",
|
||||
"darkMode": "الوضع المظلم",
|
||||
@ -140,8 +140,7 @@
|
||||
"errorLoadingLibrary": "حصل خطأ أثناء تحميل مكتبة الطرف الثالث.",
|
||||
"confirmAddLibrary": "هذا سيضيف {{numShapes}} شكل إلى مكتبتك. هل أنت متأكد؟",
|
||||
"imageDoesNotContainScene": "استيراد الصور غير مدعوم في الوقت الراهن.\n\nهل تريد استيراد مشهد؟ لا يبدو أن هذه الصورة تحتوي على أي بيانات مشهد. هل قمت بسماح هذا أثناء التصدير؟",
|
||||
"cannotRestoreFromImage": "تعذر استعادة المشهد من ملف الصورة",
|
||||
"resetLibrary": ""
|
||||
"cannotRestoreFromImage": "تعذر استعادة المشهد من ملف الصورة"
|
||||
},
|
||||
"toolBar": {
|
||||
"selection": "تحديد",
|
||||
@ -244,8 +243,6 @@
|
||||
"toast": {
|
||||
"copyStyles": "",
|
||||
"copyToClipboard": "",
|
||||
"copyToClipboardAsPng": "",
|
||||
"fileSaved": "",
|
||||
"fileSavedToFilename": ""
|
||||
"copyToClipboardAsPng": ""
|
||||
}
|
||||
}
|
||||
|
@ -8,11 +8,11 @@
|
||||
"cut": "Изрежи",
|
||||
"copy": "Копирай",
|
||||
"copyAsPng": "Копиране в клипборда",
|
||||
"copyAsSvg": "Копирано в клипборда като SVG",
|
||||
"bringForward": "Преместване напред",
|
||||
"copyAsSvg": "Копиране в клипборда",
|
||||
"bringForward": "Преместване на~пред",
|
||||
"sendToBack": "Изнасяне назад",
|
||||
"bringToFront": "Изнасяне отпред",
|
||||
"sendBackward": "Изпрати отзад",
|
||||
"bringToFront": "~Изнасяне отпред",
|
||||
"sendBackward": "Изпрати назад",
|
||||
"delete": "Изтрий",
|
||||
"copyStyles": "Копирайте стилове",
|
||||
"pasteStyles": "Постави стилове",
|
||||
@ -68,7 +68,7 @@
|
||||
"layers": "Слоеве",
|
||||
"actions": "Действия",
|
||||
"language": "Език",
|
||||
"liveCollaboration": "",
|
||||
"createRoom": "Споделете сесия за сътрудничество на живо",
|
||||
"duplicateSelection": "Дублирай",
|
||||
"untitled": "Неозаглавено",
|
||||
"name": "Име",
|
||||
@ -77,7 +77,7 @@
|
||||
"group": "Групирай селекцията",
|
||||
"ungroup": "Спри групирането на селекцията",
|
||||
"collaborators": "Сътрудници",
|
||||
"showGrid": "Показване на мрежа",
|
||||
"gridMode": "Решетъчен режим",
|
||||
"addToLibrary": "Добавяне към библиотеката",
|
||||
"removeFromLibrary": "Премахване от библиотеката",
|
||||
"libraryLoadingMessage": "Зареждане на библиотеката…",
|
||||
@ -92,7 +92,7 @@
|
||||
"centerHorizontally": "Центрирай хоризонтално",
|
||||
"distributeHorizontally": "Разпредели хоризонтално",
|
||||
"distributeVertically": "Разпредели вертикално",
|
||||
"viewMode": "Изглед"
|
||||
"viewMode": ""
|
||||
},
|
||||
"buttons": {
|
||||
"clearReset": "Нулиране на платно",
|
||||
@ -117,7 +117,7 @@
|
||||
"edit": "Редактиране",
|
||||
"undo": "Отмяна",
|
||||
"redo": "Повтори",
|
||||
"resetLibrary": "",
|
||||
"roomDialog": "Започнете сътрудничество на живо",
|
||||
"createNewRoom": "Създай нова стая",
|
||||
"fullScreen": "На цял екран",
|
||||
"darkMode": "Тъмен режим",
|
||||
@ -136,12 +136,11 @@
|
||||
"decryptFailed": "Данните не можаха да се дешифрират.",
|
||||
"uploadedSecurly": "Качването е защитено с криптиране от край до край, което означава, че сървърът Excalidraw и трети страни не могат да четат съдържанието.",
|
||||
"loadSceneOverridePrompt": "Зареждането на външна рисунка ще презапише настоящото ви съдържание. Желаете ли да продължите?",
|
||||
"collabStopOverridePrompt": "Прекратяването на сесията ще презапише предишната, локално запазена, рисунка. Сигурни ли сте?\n\n(Ако искате да продължите с локалната рисунка, просто затворете таба на браузъра.)",
|
||||
"collabStopOverridePrompt": "",
|
||||
"errorLoadingLibrary": "Възникна грешка при зареждането на външна библиотека.",
|
||||
"confirmAddLibrary": "Ще се добавят {{numShapes}} фигура(и) във вашата библиотека. Сигурни ли сте?",
|
||||
"imageDoesNotContainScene": "Импортирането на картинки не се поддържва в момента.\n\nИскате да импортнете сцена? Тази картинка не съдържа данни от сцена. Разрешили ли сте последното при експортирането?",
|
||||
"cannotRestoreFromImage": "Не може да бъде възстановена сцена от този файл",
|
||||
"resetLibrary": ""
|
||||
"cannotRestoreFromImage": "Не може да бъде възстановена сцена от този файл"
|
||||
},
|
||||
"toolBar": {
|
||||
"selection": "Селекция",
|
||||
@ -203,24 +202,24 @@
|
||||
"title": "Грешка"
|
||||
},
|
||||
"helpDialog": {
|
||||
"blog": "Прочетете нашия блог",
|
||||
"blog": "",
|
||||
"click": "клик",
|
||||
"curvedArrow": "Извита стрелка",
|
||||
"curvedLine": "Извита линия",
|
||||
"documentation": "Документация",
|
||||
"curvedArrow": "",
|
||||
"curvedLine": "",
|
||||
"documentation": "",
|
||||
"drag": "плъзнете",
|
||||
"editor": "Редактор",
|
||||
"github": "Намерихте проблем? Изпратете",
|
||||
"howto": "Следвайте нашите ръководства",
|
||||
"github": "",
|
||||
"howto": "",
|
||||
"or": "или",
|
||||
"preventBinding": "Спри прилепяне на стрелките",
|
||||
"preventBinding": "",
|
||||
"shapes": "Фигури",
|
||||
"shortcuts": "Клавиши за бърз достъп",
|
||||
"textFinish": "Завършете редактирането (текст)",
|
||||
"textNewLine": "Добавяне на нов ред (текст)",
|
||||
"title": "Помощ",
|
||||
"textFinish": "",
|
||||
"textNewLine": "",
|
||||
"title": "",
|
||||
"view": "Преглед",
|
||||
"zoomToFit": "Приближи докато се виждат всички елементи",
|
||||
"zoomToFit": "",
|
||||
"zoomToSelection": "Приближи селекцията"
|
||||
},
|
||||
"encrypted": {
|
||||
@ -236,16 +235,14 @@
|
||||
"storage": "Съхранение на данни",
|
||||
"title": "Статистика за хакери",
|
||||
"total": "Общо",
|
||||
"version": "Версия",
|
||||
"versionCopy": "Настисни за да копираш",
|
||||
"versionNotAvailable": "Версията не е налична",
|
||||
"version": "",
|
||||
"versionCopy": "",
|
||||
"versionNotAvailable": "",
|
||||
"width": "Широчина"
|
||||
},
|
||||
"toast": {
|
||||
"copyStyles": "Копирани стилове.",
|
||||
"copyToClipboard": "Копирано в клипборда.",
|
||||
"copyToClipboardAsPng": "Копирано в клипборда като PNG.",
|
||||
"fileSaved": "",
|
||||
"fileSavedToFilename": ""
|
||||
"copyStyles": "",
|
||||
"copyToClipboard": "",
|
||||
"copyToClipboardAsPng": ""
|
||||
}
|
||||
}
|
||||
|
@ -68,7 +68,7 @@
|
||||
"layers": "Capes",
|
||||
"actions": "Accions",
|
||||
"language": "Llengua",
|
||||
"liveCollaboration": "",
|
||||
"createRoom": "Compartir una sessió de 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": "",
|
||||
"gridMode": "Mode quadrícula",
|
||||
"addToLibrary": "Afegir a la biblioteca",
|
||||
"removeFromLibrary": "Eliminar de la biblioteca",
|
||||
"libraryLoadingMessage": "Carregant la biblioteca…",
|
||||
@ -117,7 +117,7 @@
|
||||
"edit": "Editar",
|
||||
"undo": "Desfer",
|
||||
"redo": "Refer",
|
||||
"resetLibrary": "",
|
||||
"roomDialog": "Començar col·laboració en directe",
|
||||
"createNewRoom": "Crear sala nova",
|
||||
"fullScreen": "Pantalla completa",
|
||||
"darkMode": "Mode fosc",
|
||||
@ -140,8 +140,7 @@
|
||||
"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": ""
|
||||
"cannotRestoreFromImage": "L’escena no s’ha pogut restaurar des d’aquest fitxer d’imatge"
|
||||
},
|
||||
"toolBar": {
|
||||
"selection": "Selecció",
|
||||
@ -244,8 +243,6 @@
|
||||
"toast": {
|
||||
"copyStyles": "",
|
||||
"copyToClipboard": "",
|
||||
"copyToClipboardAsPng": "",
|
||||
"fileSaved": "",
|
||||
"fileSavedToFilename": ""
|
||||
"copyToClipboardAsPng": ""
|
||||
}
|
||||
}
|
||||
|
@ -68,7 +68,7 @@
|
||||
"layers": "Ebenen",
|
||||
"actions": "Aktionen",
|
||||
"language": "Sprache",
|
||||
"liveCollaboration": "Live-Zusammenarbeit",
|
||||
"createRoom": "Live-Kollaborationssitzung teilen",
|
||||
"duplicateSelection": "Duplizieren",
|
||||
"untitled": "Unbenannt",
|
||||
"name": "Name",
|
||||
@ -76,8 +76,8 @@
|
||||
"madeWithExcalidraw": "Made with Excalidraw",
|
||||
"group": "Auswahl gruppieren",
|
||||
"ungroup": "Gruppierung aufheben",
|
||||
"collaborators": "Kollaboratoren",
|
||||
"showGrid": "Raster anzeigen",
|
||||
"collaborators": "Mitarbeitende",
|
||||
"gridMode": "Rastermodus",
|
||||
"addToLibrary": "Zur Bibliothek hinzufügen",
|
||||
"removeFromLibrary": "Aus Bibliothek entfernen",
|
||||
"libraryLoadingMessage": "Lade Bibliothek…",
|
||||
@ -101,7 +101,7 @@
|
||||
"exportToSvg": "Als SVG exportieren",
|
||||
"copyToClipboard": "In Zwischenablage kopieren",
|
||||
"copyPngToClipboard": "PNG in die Zwischenablage kopieren",
|
||||
"scale": "Skalierung",
|
||||
"scale": "Skalieren",
|
||||
"save": "Speichern",
|
||||
"saveAs": "Speichern unter",
|
||||
"load": "Laden",
|
||||
@ -117,7 +117,7 @@
|
||||
"edit": "Bearbeiten",
|
||||
"undo": "Rückgängig machen",
|
||||
"redo": "Wiederholen",
|
||||
"resetLibrary": "Bibliothek zurücksetzen",
|
||||
"roomDialog": "Live-Kollaborationssitzung starten",
|
||||
"createNewRoom": "Neuen Raum erstellen",
|
||||
"fullScreen": "Vollbildanzeige",
|
||||
"darkMode": "Dunkles Design",
|
||||
@ -140,8 +140,7 @@
|
||||
"errorLoadingLibrary": "Beim Laden der Drittanbieter-Bibliothek ist ein Fehler aufgetreten.",
|
||||
"confirmAddLibrary": "Dieses fügt {{numShapes}} Form(en) zu deiner Bibliothek hinzu. Bist du sicher?",
|
||||
"imageDoesNotContainScene": "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",
|
||||
"resetLibrary": "Dieses löscht deine Bibliothek. Bist du sicher?"
|
||||
"cannotRestoreFromImage": "Die Zeichnung konnte aus dieser Bilddatei nicht wiederhergestellt werden"
|
||||
},
|
||||
"toolBar": {
|
||||
"selection": "Auswahl",
|
||||
@ -236,16 +235,14 @@
|
||||
"storage": "Speicher",
|
||||
"title": "Statistiken für Nerds",
|
||||
"total": "Gesamt",
|
||||
"version": "Version",
|
||||
"versionCopy": "Zum Kopieren klicken",
|
||||
"versionNotAvailable": "Version nicht verfügbar",
|
||||
"version": "",
|
||||
"versionCopy": "",
|
||||
"versionNotAvailable": "",
|
||||
"width": "Breite"
|
||||
},
|
||||
"toast": {
|
||||
"copyStyles": "Formatierung kopiert.",
|
||||
"copyToClipboard": "In die Zwischenablage kopiert.",
|
||||
"copyToClipboardAsPng": "In die Zwischenablage als PNG kopiert.",
|
||||
"fileSaved": "Datei gespeichert.",
|
||||
"fileSavedToFilename": "Als {filename} gespeichert"
|
||||
"copyToClipboard": "",
|
||||
"copyToClipboardAsPng": "In die Zwischenablage als PNG kopiert."
|
||||
}
|
||||
}
|
||||
|
@ -68,7 +68,7 @@
|
||||
"layers": "Στρώματα",
|
||||
"actions": "Ενέργειες",
|
||||
"language": "Γλώσσα",
|
||||
"liveCollaboration": "Ζωντανή συνεργασία",
|
||||
"createRoom": "Έναρξη ζωντανής συνεδρίας",
|
||||
"duplicateSelection": "Δημιουργία αντιγράφου",
|
||||
"untitled": "Χωρίς τίτλο",
|
||||
"name": "Όνομα",
|
||||
@ -77,7 +77,7 @@
|
||||
"group": "Δημιουργία ομάδας από επιλογή",
|
||||
"ungroup": "Κατάργηση ομάδας από επιλογή",
|
||||
"collaborators": "Συνεργάτες",
|
||||
"showGrid": "Προβολή πλέγματος",
|
||||
"gridMode": "Εμφάνιση σε πλέγμα",
|
||||
"addToLibrary": "Προσθήκη στη βιβλιοθήκη",
|
||||
"removeFromLibrary": "Αφαίρεση από τη βιβλιοθήκη",
|
||||
"libraryLoadingMessage": "Φόρτωση βιβλιοθήκης…",
|
||||
@ -117,13 +117,13 @@
|
||||
"edit": "Επεξεργασία",
|
||||
"undo": "Αναίρεση",
|
||||
"redo": "Επαναφορά",
|
||||
"resetLibrary": "Καθαρισμός βιβλιοθήκης",
|
||||
"roomDialog": "Έναρξη ζωντανής συνεργασίας",
|
||||
"createNewRoom": "Δημιουργία νέου χώρου",
|
||||
"fullScreen": "Πλήρης οθόνη",
|
||||
"darkMode": "Σκοτεινή λειτουργία",
|
||||
"lightMode": "Φωτεινή λειτουργία",
|
||||
"zenMode": "Λειτουργία Zεν",
|
||||
"exitZenMode": "Έξοδος από την λειτουργία Zen"
|
||||
"exitZenMode": "Έξοδος απο την λειτουργία Zen"
|
||||
},
|
||||
"alerts": {
|
||||
"clearReset": "Αυτό θα σβήσει ολόκληρο τον καμβά. Είσαι σίγουρος;",
|
||||
@ -136,12 +136,11 @@
|
||||
"decryptFailed": "Δεν ήταν δυνατή η αποκρυπτογράφηση δεδομένων.",
|
||||
"uploadedSecurly": "Η μεταφόρτωση έχει εξασφαλιστεί με κρυπτογράφηση από άκρο σε άκρο, πράγμα που σημαίνει ότι ο διακομιστής Excalidraw και τρίτα μέρη δεν μπορούν να διαβάσουν το περιεχόμενο.",
|
||||
"loadSceneOverridePrompt": "Η φόρτωση εξωτερικού σχεδίου θα αντικαταστήσει το υπάρχον περιεχόμενο. Επιθυμείτε να συνεχίσετε;",
|
||||
"collabStopOverridePrompt": "Η διακοπή της συνεδρίας θα αντικαταστήσει το προηγούμενο, τοπικά αποθηκευμένο σχέδιο. Είστε σίγουροι?\n\n(Αν θέλετε να διατηρήσετε το τοπικό σας σχέδιο, απλά κλείστε την καρτέλα του προγράμματος περιήγησης.)",
|
||||
"collabStopOverridePrompt": "",
|
||||
"errorLoadingLibrary": "Υπήρξε ένα σφάλμα κατά τη φόρτωση της βιβλιοθήκης τρίτου μέρους.",
|
||||
"confirmAddLibrary": "Αυτό θα προσθέσει {{numShapes}} σχήμα(τα) στη βιβλιοθήκη σας. Είστε σίγουροι;",
|
||||
"confirmAddLibrary": "Αυτό θα προσθέσει {{numShapes}} σχήμα(τα) στη βιβιλιοθήκη σας. Είστε σίγουροι;",
|
||||
"imageDoesNotContainScene": "Η εισαγωγή εικόνων δεν υποστηρίζεται αυτή τη στιγμή.\n\nΜήπως θέλετε να εισαγάγετε μια σκηνή; Αυτή η εικόνα δεν φαίνεται να περιέχει δεδομένα σκηνής. Έχετε ενεργοποιήσει αυτό κατά την εξαγωγή;",
|
||||
"cannotRestoreFromImage": "Η σκηνή δεν ήταν δυνατό να αποκατασταθεί από αυτό το αρχείο εικόνας",
|
||||
"resetLibrary": "Αυτό θα καθαρίσει τη βιβλιοθήκη σας. Είστε σίγουροι;"
|
||||
"cannotRestoreFromImage": "Η σκηνή δεν ήταν δυνατό να αποκατασταθεί από αυτό το αρχείο εικόνας"
|
||||
},
|
||||
"toolBar": {
|
||||
"selection": "Επιλογή",
|
||||
@ -162,7 +161,7 @@
|
||||
},
|
||||
"hints": {
|
||||
"linearElement": "Κάνε κλικ για να ξεκινήσεις πολλαπλά σημεία, σύρε για μια γραμμή",
|
||||
"freeDraw": "Κάντε κλικ και σύρτε, απελευθερώσατε όταν έχετε τελειώσει",
|
||||
"freeDraw": "Κάντε κλικ και σύρατε, απελευθερώσατε όταν έχετε τελειώσει",
|
||||
"text": "Tip: μπορείτε επίσης να προσθέστε κείμενο με διπλό-κλικ οπουδήποτε με το εργαλείο επιλογών",
|
||||
"linearElementMulti": "Κάνε κλικ στο τελευταίο σημείο ή πάτησε Escape ή Enter για να τελειώσεις",
|
||||
"lockAngle": "Μπορείτε να περιορίσετε τη γωνία κρατώντας πατημένο το SHIFT",
|
||||
@ -185,7 +184,7 @@
|
||||
"clearCanvasCaveat": " Αυτό θα προκαλέσει απώλεια της δουλειάς σου ",
|
||||
"trackedToSentry_pre": "Το σφάλμα με αναγνωριστικό ",
|
||||
"trackedToSentry_post": " παρακολουθήθηκε στο σύστημά μας.",
|
||||
"openIssueMessage_pre": "Ήμασταν πολύ προσεκτικοί για να μην συμπεριλάβουμε τις πληροφορίες της σκηνής σου στο σφάλμα. Αν η σκηνή σου δεν είναι ιδιωτική, παρακαλώ σκέψου να ακολουθήσεις το δικό μας ",
|
||||
"openIssueMessage_pre": "Ήμασταν πολύ προσεκτικοί για να μην συμπεριλάβουμε τις πληροφορίες της σκηνής σου στο σφάλμα. Αν η σκηνή σου δεν είναι ιδιωτική, παρακαλώ σκέψουν να ακολουθήσεις το δικό μας ",
|
||||
"openIssueMessage_button": "ανιχνευτής σφαλμάτων.",
|
||||
"openIssueMessage_post": " Παρακαλώ να συμπεριλάβετε τις παρακάτω πληροφορίες, αντιγράφοντας και επικολλώντας το ζήτημα στο GitHub.",
|
||||
"sceneContent": "Περιεχόμενο σκηνής:"
|
||||
@ -224,7 +223,7 @@
|
||||
"zoomToSelection": "Ζουμ στην επιλογή"
|
||||
},
|
||||
"encrypted": {
|
||||
"tooltip": "Τα σχέδιά σου είναι κρυπτογραφημένα από άκρο σε άκρο, έτσι δεν θα είναι ποτέ ορατά μέσα από τους διακομιστές του Excalidraw."
|
||||
"tooltip": "Τα σχέδιά σου είναι κρυπτογραφημένα από άκρο σε άκρο, έτσι δεν θα έιναι ποτέ ορατά μέσα από τους διακομιστές του Excalidraw."
|
||||
},
|
||||
"stats": {
|
||||
"angle": "Γωνία",
|
||||
@ -244,8 +243,6 @@
|
||||
"toast": {
|
||||
"copyStyles": "Αντιγράφηκαν στυλ.",
|
||||
"copyToClipboard": "Αντιγράφηκε στο πρόχειρο.",
|
||||
"copyToClipboardAsPng": "Αντιγράφτηκε στο πρόχειρο ως PNG.",
|
||||
"fileSaved": "Το αρχείο αποθηκεύτηκε.",
|
||||
"fileSavedToFilename": "Αποθηκεύτηκε στο {filename}"
|
||||
"copyToClipboardAsPng": "Αντιγράφτηκε στο πρόχειρο ως PNG."
|
||||
}
|
||||
}
|
||||
|
@ -68,7 +68,7 @@
|
||||
"layers": "Layers",
|
||||
"actions": "Actions",
|
||||
"language": "Language",
|
||||
"liveCollaboration": "Live collaboration",
|
||||
"createRoom": "Share a live-collaboration session",
|
||||
"duplicateSelection": "Duplicate",
|
||||
"untitled": "Untitled",
|
||||
"name": "Name",
|
||||
@ -77,7 +77,7 @@
|
||||
"group": "Group selection",
|
||||
"ungroup": "Ungroup selection",
|
||||
"collaborators": "Collaborators",
|
||||
"showGrid": "Show grid",
|
||||
"gridMode": "Grid mode",
|
||||
"addToLibrary": "Add to library",
|
||||
"removeFromLibrary": "Remove from library",
|
||||
"libraryLoadingMessage": "Loading library…",
|
||||
@ -117,7 +117,7 @@
|
||||
"edit": "Edit",
|
||||
"undo": "Undo",
|
||||
"redo": "Redo",
|
||||
"resetLibrary": "Reset library",
|
||||
"roomDialog": "Start live collaboration",
|
||||
"createNewRoom": "Create new room",
|
||||
"fullScreen": "Full screen",
|
||||
"darkMode": "Dark mode",
|
||||
@ -140,8 +140,7 @@
|
||||
"errorLoadingLibrary": "There was an error loading the third party library.",
|
||||
"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",
|
||||
"resetLibrary": "This will clear your library. Are you sure?"
|
||||
"cannotRestoreFromImage": "Scene couldn't be restored from this image file"
|
||||
},
|
||||
"toolBar": {
|
||||
"selection": "Selection",
|
||||
@ -244,8 +243,6 @@
|
||||
"toast": {
|
||||
"copyStyles": "Copied styles.",
|
||||
"copyToClipboard": "Copied to clipboard.",
|
||||
"copyToClipboardAsPng": "Copied to clipboard as PNG.",
|
||||
"fileSaved": "File saved.",
|
||||
"fileSavedToFilename": "Saved to {filename}"
|
||||
"copyToClipboardAsPng": "Copied to clipboard as PNG."
|
||||
}
|
||||
}
|
||||
|
@ -68,7 +68,7 @@
|
||||
"layers": "Capas",
|
||||
"actions": "Acciones",
|
||||
"language": "Idioma",
|
||||
"liveCollaboration": "Colaboración en directo",
|
||||
"createRoom": "Compartir una sesión de colaboración en vivo",
|
||||
"duplicateSelection": "Duplicar",
|
||||
"untitled": "Sin título",
|
||||
"name": "Nombre",
|
||||
@ -77,10 +77,10 @@
|
||||
"group": "Agrupar selección",
|
||||
"ungroup": "Desagrupar selección",
|
||||
"collaborators": "Colaboradores",
|
||||
"showGrid": "Mostrar cuadrícula",
|
||||
"gridMode": "Modo cuadrícula",
|
||||
"addToLibrary": "Añadir a la biblioteca",
|
||||
"removeFromLibrary": "Eliminar de la biblioteca",
|
||||
"libraryLoadingMessage": "Cargando librería…",
|
||||
"libraryLoadingMessage": "Cargando biblioteca…",
|
||||
"libraries": "Explorar bibliotecas",
|
||||
"loadingScene": "Cargando escena…",
|
||||
"align": "Alinear",
|
||||
@ -117,7 +117,7 @@
|
||||
"edit": "Editar",
|
||||
"undo": "Deshacer",
|
||||
"redo": "Rehacer",
|
||||
"resetLibrary": "Resetear librería",
|
||||
"roomDialog": "Iniciar colaboración en vivo",
|
||||
"createNewRoom": "Crear nueva sala",
|
||||
"fullScreen": "Pantalla completa",
|
||||
"darkMode": "Modo oscuro",
|
||||
@ -140,8 +140,7 @@
|
||||
"errorLoadingLibrary": "Se ha producido un error al cargar la biblioteca de terceros.",
|
||||
"confirmAddLibrary": "Esto añadirá {{numShapes}} forma(s) a tu biblioteca. ¿Estás seguro?",
|
||||
"imageDoesNotContainScene": "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",
|
||||
"resetLibrary": "Esto eliminará tu librería. ¿Estás seguro?"
|
||||
"cannotRestoreFromImage": "No se pudo restaurar la escena desde este archivo de imagen"
|
||||
},
|
||||
"toolBar": {
|
||||
"selection": "Selección",
|
||||
@ -236,16 +235,14 @@
|
||||
"storage": "Almacenamiento",
|
||||
"title": "Estadísticas para nerds",
|
||||
"total": "Total",
|
||||
"version": "Versión",
|
||||
"versionCopy": "Clic para copiar",
|
||||
"versionNotAvailable": "Versión no disponible",
|
||||
"version": "",
|
||||
"versionCopy": "",
|
||||
"versionNotAvailable": "",
|
||||
"width": "Ancho"
|
||||
},
|
||||
"toast": {
|
||||
"copyStyles": "Estilos copiados.",
|
||||
"copyToClipboard": "Copiado en el portapapeles.",
|
||||
"copyToClipboardAsPng": "Copiado al portapapeles como PNG.",
|
||||
"fileSaved": "Archivo guardado.",
|
||||
"fileSavedToFilename": "Guardado en {filename}"
|
||||
"copyToClipboard": "",
|
||||
"copyToClipboardAsPng": "Copiado al portapapeles como PNG."
|
||||
}
|
||||
}
|
||||
|
@ -68,7 +68,7 @@
|
||||
"layers": "لایه ها",
|
||||
"actions": "عملیات",
|
||||
"language": "زبان",
|
||||
"liveCollaboration": "",
|
||||
"createRoom": "اشتراک گذاری جلسه همکاری زنده",
|
||||
"duplicateSelection": "تکرار",
|
||||
"untitled": "بدون عنوان",
|
||||
"name": "نام",
|
||||
@ -77,7 +77,7 @@
|
||||
"group": "گروهبندی انتخابها",
|
||||
"ungroup": "حذف گروهبندی انتخابها",
|
||||
"collaborators": "همکاران",
|
||||
"showGrid": "",
|
||||
"gridMode": "حالت شبکه ای",
|
||||
"addToLibrary": "افزودن به کتابخانه",
|
||||
"removeFromLibrary": "حذف از کتابخانه",
|
||||
"libraryLoadingMessage": "بارگذاری کتابخانه…",
|
||||
@ -117,7 +117,7 @@
|
||||
"edit": "ویرایش",
|
||||
"undo": "بازگرد",
|
||||
"redo": "از سر",
|
||||
"resetLibrary": "",
|
||||
"roomDialog": "همکاری آنلاین را شروع کنید",
|
||||
"createNewRoom": "ایجاد یک اتاق جدید",
|
||||
"fullScreen": "تمامصفحه",
|
||||
"darkMode": "حالت تیره",
|
||||
@ -140,8 +140,7 @@
|
||||
"errorLoadingLibrary": "خطایی در بارگذاری کتابخانه ثالث وجود داشت.",
|
||||
"confirmAddLibrary": "{{numShapes}} از اشکال به کتابخانه شما اضافه خواهد شد. مطمئن هستید؟",
|
||||
"imageDoesNotContainScene": "وارد کردن تصویر در این لحظه امکان پذیر نمی باشد.\nآیا مایل به وارد کردن یک صحنه هستید؟ این تصویر به نظر می رسد که فاقد هرگونه اطلاعاتی مربوط به صحنه باشد. آیا این گزینه را در زمان وارد کردن تصویر فعال کرده اید؟",
|
||||
"cannotRestoreFromImage": "صحنه را نمی توان از این فایل تصویری بازیابی کرد",
|
||||
"resetLibrary": ""
|
||||
"cannotRestoreFromImage": "صحنه را نمی توان از این فایل تصویری بازیابی کرد"
|
||||
},
|
||||
"toolBar": {
|
||||
"selection": "گزینش",
|
||||
@ -244,8 +243,6 @@
|
||||
"toast": {
|
||||
"copyStyles": "کپی سبک.",
|
||||
"copyToClipboard": "",
|
||||
"copyToClipboardAsPng": "کپی در حافطه موقت به صورت PNG.",
|
||||
"fileSaved": "",
|
||||
"fileSavedToFilename": ""
|
||||
"copyToClipboardAsPng": "کپی در حافطه موقت به صورت PNG."
|
||||
}
|
||||
}
|
||||
|
@ -68,7 +68,7 @@
|
||||
"layers": "Tasot",
|
||||
"actions": "Toiminnot",
|
||||
"language": "Kieli",
|
||||
"liveCollaboration": "Live-yhteistyö",
|
||||
"createRoom": "Jaa yhteistyöistunto",
|
||||
"duplicateSelection": "Monista",
|
||||
"untitled": "Nimetön",
|
||||
"name": "Nimi",
|
||||
@ -77,7 +77,7 @@
|
||||
"group": "Ryhmitä valinta",
|
||||
"ungroup": "Pura valittu ryhmä",
|
||||
"collaborators": "Yhteistyökumppanit",
|
||||
"showGrid": "Näytä ruudukko",
|
||||
"gridMode": "Ruudukkotila",
|
||||
"addToLibrary": "Lisää kirjastoon",
|
||||
"removeFromLibrary": "Poista kirjastosta",
|
||||
"libraryLoadingMessage": "Ladataan kirjastoa…",
|
||||
@ -117,7 +117,7 @@
|
||||
"edit": "Muokkaa",
|
||||
"undo": "Kumoa",
|
||||
"redo": "Tee uudelleen",
|
||||
"resetLibrary": "Tyhjennä kirjasto",
|
||||
"roomDialog": "Aloita live-yhteistyö",
|
||||
"createNewRoom": "Luo huone",
|
||||
"fullScreen": "Koko näyttö",
|
||||
"darkMode": "Tumma tila",
|
||||
@ -140,8 +140,7 @@
|
||||
"errorLoadingLibrary": "Kolmannen osapuolen kirjastoa ladattaessa tapahtui virhe.",
|
||||
"confirmAddLibrary": "Tämä lisää {{numShapes}} muotoa kirjastoosi. Oletko varma?",
|
||||
"imageDoesNotContainScene": "Kuvien lisääminen ei ole tällä hetkellä mahdollista.\n\nHaluatko tuoda piirroksen? Tämä kuva ei näytä sisältävän tarvittavia tietoja. Oletko ottanut piirrostietojen tallennuksen käyttöön viennin aikana?",
|
||||
"cannotRestoreFromImage": "Teosta ei voitu palauttaa tästä kuvatiedostosta",
|
||||
"resetLibrary": "Tämä tyhjentää kirjastosi. Oletko varma?"
|
||||
"cannotRestoreFromImage": "Teosta ei voitu palauttaa tästä kuvatiedostosta"
|
||||
},
|
||||
"toolBar": {
|
||||
"selection": "Valinta",
|
||||
@ -236,16 +235,14 @@
|
||||
"storage": "Tallennustila",
|
||||
"title": "Nörttien tilastot",
|
||||
"total": "Yhteensä",
|
||||
"version": "Versio",
|
||||
"versionCopy": "Klikkaa kopioidaksesi",
|
||||
"versionNotAvailable": "Versio ei saatavilla",
|
||||
"version": "",
|
||||
"versionCopy": "",
|
||||
"versionNotAvailable": "",
|
||||
"width": "Leveys"
|
||||
},
|
||||
"toast": {
|
||||
"copyStyles": "Tyylit kopioitu.",
|
||||
"copyToClipboard": "Kopioitu leikepöydälle.",
|
||||
"copyToClipboardAsPng": "Kopioitu leikepöydälle PNG-tiedostona.",
|
||||
"fileSaved": "Tiedosto tallennettu.",
|
||||
"fileSavedToFilename": "Tallennettu kohteeseen {filename}"
|
||||
"copyToClipboard": "",
|
||||
"copyToClipboardAsPng": "Kopioitu leikepöydälle PNG-tiedostona."
|
||||
}
|
||||
}
|
||||
|
@ -68,7 +68,7 @@
|
||||
"layers": "Calques",
|
||||
"actions": "Actions",
|
||||
"language": "Langue",
|
||||
"liveCollaboration": "Collaboration en direct",
|
||||
"createRoom": "Partager une session de collaboration en direct",
|
||||
"duplicateSelection": "Dupliquer",
|
||||
"untitled": "Sans-titre",
|
||||
"name": "Nom",
|
||||
@ -77,7 +77,7 @@
|
||||
"group": "Grouper la sélection",
|
||||
"ungroup": "Dégrouper la sélection",
|
||||
"collaborators": "Collaborateurs",
|
||||
"showGrid": "Afficher la grille",
|
||||
"gridMode": "Mode grille",
|
||||
"addToLibrary": "Ajouter à la bibliothèque",
|
||||
"removeFromLibrary": "Supprimer de la bibliothèque",
|
||||
"libraryLoadingMessage": "Chargement de la bibliothèque…",
|
||||
@ -117,7 +117,7 @@
|
||||
"edit": "Modifier",
|
||||
"undo": "Annuler",
|
||||
"redo": "Rétablir",
|
||||
"resetLibrary": "Réinitialiser la bibliothèque",
|
||||
"roomDialog": "Démarrer la collaboration en direct",
|
||||
"createNewRoom": "Créer une nouvelle salle",
|
||||
"fullScreen": "Plein écran",
|
||||
"darkMode": "Mode sombre",
|
||||
@ -140,8 +140,7 @@
|
||||
"errorLoadingLibrary": "Une erreur s'est produite lors du chargement de la bibliothèque tierce.",
|
||||
"confirmAddLibrary": "Cela va ajouter {{numShapes}} forme(s) à votre bibliothèque. Êtes-vous sûr·e ?",
|
||||
"imageDoesNotContainScene": "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",
|
||||
"resetLibrary": "Cela va effacer votre bibliothèque. Êtes-vous sûr·e ?"
|
||||
"cannotRestoreFromImage": "Impossible de restaurer la scène depuis ce fichier image"
|
||||
},
|
||||
"toolBar": {
|
||||
"selection": "Sélection",
|
||||
@ -244,8 +243,6 @@
|
||||
"toast": {
|
||||
"copyStyles": "Styles copiés.",
|
||||
"copyToClipboard": "Copié vers le presse-papiers.",
|
||||
"copyToClipboardAsPng": "Copié vers le presse-papier en PNG.",
|
||||
"fileSaved": "Fichier enregistré.",
|
||||
"fileSavedToFilename": "Enregistré sous {filename}"
|
||||
"copyToClipboardAsPng": "Copié vers le presse-papier en PNG."
|
||||
}
|
||||
}
|
||||
|
@ -68,7 +68,7 @@
|
||||
"layers": "שכבות",
|
||||
"actions": "פעולות",
|
||||
"language": "שפה",
|
||||
"liveCollaboration": "",
|
||||
"createRoom": "התחל שיתוף פעולה חי",
|
||||
"duplicateSelection": "שכפל",
|
||||
"untitled": "ללא כותרת",
|
||||
"name": "שם",
|
||||
@ -77,7 +77,7 @@
|
||||
"group": "אחד לקבוצה",
|
||||
"ungroup": "פרק קבוצה",
|
||||
"collaborators": "שותפים",
|
||||
"showGrid": "",
|
||||
"gridMode": "מצב רשת",
|
||||
"addToLibrary": "הוסף לספריה",
|
||||
"removeFromLibrary": "הסר מספריה",
|
||||
"libraryLoadingMessage": "טוען ספריה…",
|
||||
@ -117,7 +117,7 @@
|
||||
"edit": "ערוך",
|
||||
"undo": "בטל",
|
||||
"redo": "בצע מחדש",
|
||||
"resetLibrary": "",
|
||||
"roomDialog": "התחל שיתוף חי",
|
||||
"createNewRoom": "צור חדר",
|
||||
"fullScreen": "מסך מלא",
|
||||
"darkMode": "מצב כהה",
|
||||
@ -140,8 +140,7 @@
|
||||
"errorLoadingLibrary": "קרתה שגיאה בטעינת הספריה החיצונית.",
|
||||
"confirmAddLibrary": "הפעולה תוסיף {{numShapes}} צורה(ות) לספריה שלך. האם אתה בטוח?",
|
||||
"imageDoesNotContainScene": "אין תמיכה בייבוא תמונות כעת.\n\nהאם אתה רוצה לייבא תצוגה? התמונה הזאת אינה מכילה מידע על תצוגה. האם הפעלת את האפשרות הזאת בזמן הוצאת המידע?",
|
||||
"cannotRestoreFromImage": "לא הצלחנו לשחזר את התצוגה מקובץ התמונה",
|
||||
"resetLibrary": ""
|
||||
"cannotRestoreFromImage": "לא הצלחנו לשחזר את התצוגה מקובץ התמונה"
|
||||
},
|
||||
"toolBar": {
|
||||
"selection": "בחירה",
|
||||
@ -244,8 +243,6 @@
|
||||
"toast": {
|
||||
"copyStyles": "",
|
||||
"copyToClipboard": "",
|
||||
"copyToClipboardAsPng": "",
|
||||
"fileSaved": "",
|
||||
"fileSavedToFilename": ""
|
||||
"copyToClipboardAsPng": ""
|
||||
}
|
||||
}
|
||||
|
@ -68,7 +68,7 @@
|
||||
"layers": "परतें",
|
||||
"actions": "कार्रवाई",
|
||||
"language": "भाषा",
|
||||
"liveCollaboration": "",
|
||||
"createRoom": "अधिवेशन",
|
||||
"duplicateSelection": "डुप्लिकेट",
|
||||
"untitled": "अशीर्षित",
|
||||
"name": "नाम",
|
||||
@ -77,7 +77,7 @@
|
||||
"group": "समूह चयन",
|
||||
"ungroup": "समूह चयन असमूहीकृत करें",
|
||||
"collaborators": "सहयोगी",
|
||||
"showGrid": "",
|
||||
"gridMode": "ग्रिड मॉड",
|
||||
"addToLibrary": "लाइब्रेरी से जोड़ें",
|
||||
"removeFromLibrary": "लाइब्रेरी से निकालें",
|
||||
"libraryLoadingMessage": "लाइब्रेरी खुल रही है",
|
||||
@ -117,7 +117,7 @@
|
||||
"edit": "संशोधन करें",
|
||||
"undo": "पूर्ववत् करें",
|
||||
"redo": "फिर से करें",
|
||||
"resetLibrary": "",
|
||||
"roomDialog": "लाइव सहयोग शुरू करें",
|
||||
"createNewRoom": "एक नया कमरा बनाएं",
|
||||
"fullScreen": "पूरी स्क्रीन",
|
||||
"darkMode": "डार्क मोड",
|
||||
@ -140,8 +140,7 @@
|
||||
"errorLoadingLibrary": "लाइब्रेरी लोड करने में त्रुटि",
|
||||
"confirmAddLibrary": "लाइब्रेरी जोड़ें पुष्टि करें आकार संख्या",
|
||||
"imageDoesNotContainScene": "दृश्य में छवि नहीं है",
|
||||
"cannotRestoreFromImage": "छवि फ़ाइल बहाल दृश्य नहीं है",
|
||||
"resetLibrary": ""
|
||||
"cannotRestoreFromImage": "छवि फ़ाइल बहाल दृश्य नहीं है"
|
||||
},
|
||||
"toolBar": {
|
||||
"selection": "चयन",
|
||||
@ -244,8 +243,6 @@
|
||||
"toast": {
|
||||
"copyStyles": "काॅपी कीए स्टाइल",
|
||||
"copyToClipboard": "क्लिपबोर्ड में कॉपी कीए",
|
||||
"copyToClipboardAsPng": "क्लिपबोर्ड में PNG के रूप में कॉपी किए",
|
||||
"fileSaved": "",
|
||||
"fileSavedToFilename": ""
|
||||
"copyToClipboardAsPng": "क्लिपबोर्ड में PNG के रूप में कॉपी किए"
|
||||
}
|
||||
}
|
||||
|
@ -68,7 +68,7 @@
|
||||
"layers": "Rétegek",
|
||||
"actions": "Műveletek",
|
||||
"language": "Nyelv",
|
||||
"liveCollaboration": "",
|
||||
"createRoom": "Élő együttmüködés megosztása",
|
||||
"duplicateSelection": "Duplikálás",
|
||||
"untitled": "Névtelen",
|
||||
"name": "Név",
|
||||
@ -77,7 +77,7 @@
|
||||
"group": "Csoportosítás",
|
||||
"ungroup": "Csoportbontás",
|
||||
"collaborators": "Közreműködők",
|
||||
"showGrid": "",
|
||||
"gridMode": "Hálómód",
|
||||
"addToLibrary": "Hozzáadás a könyvtárhoz",
|
||||
"removeFromLibrary": "Eltávólítás a könyvtárból",
|
||||
"libraryLoadingMessage": "Könyvtár betöltése…",
|
||||
@ -117,7 +117,7 @@
|
||||
"edit": "Szerkesztés",
|
||||
"undo": "Vissza",
|
||||
"redo": "Újra",
|
||||
"resetLibrary": "",
|
||||
"roomDialog": "Élő együttműködés indítása",
|
||||
"createNewRoom": "Új szoba létrehozása",
|
||||
"fullScreen": "Teljes képernyő",
|
||||
"darkMode": "Sötét mód",
|
||||
@ -140,8 +140,7 @@
|
||||
"errorLoadingLibrary": "Hibába ütközött a harmarmadik féltől származó könyvtár betöltése.",
|
||||
"confirmAddLibrary": "Ez a művelet {{numShapes}} formát fog hozzáadni a könyvtáradhoz. Biztos vagy benne?",
|
||||
"imageDoesNotContainScene": "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",
|
||||
"resetLibrary": ""
|
||||
"cannotRestoreFromImage": "A jelenet visszaállítása nem sikerült ebből a kép fájlból"
|
||||
},
|
||||
"toolBar": {
|
||||
"selection": "Kijelölés",
|
||||
@ -244,8 +243,6 @@
|
||||
"toast": {
|
||||
"copyStyles": "",
|
||||
"copyToClipboard": "",
|
||||
"copyToClipboardAsPng": "",
|
||||
"fileSaved": "",
|
||||
"fileSavedToFilename": ""
|
||||
"copyToClipboardAsPng": ""
|
||||
}
|
||||
}
|
||||
|
@ -68,7 +68,7 @@
|
||||
"layers": "Lapisan",
|
||||
"actions": "Aksi",
|
||||
"language": "Bahasa",
|
||||
"liveCollaboration": "",
|
||||
"createRoom": "Bagikan sesi kolaborasi langsung",
|
||||
"duplicateSelection": "Duplikat",
|
||||
"untitled": "Tanpa judul",
|
||||
"name": "Nama",
|
||||
@ -77,7 +77,7 @@
|
||||
"group": "Kelompokan pilihan",
|
||||
"ungroup": "Pisahkan pilihan",
|
||||
"collaborators": "Kolaborator",
|
||||
"showGrid": "Tampilkan grid",
|
||||
"gridMode": "Mode grid",
|
||||
"addToLibrary": "Tambahkan ke pustaka",
|
||||
"removeFromLibrary": "Hapus dari pustaka",
|
||||
"libraryLoadingMessage": "Memuat pustaka…",
|
||||
@ -117,7 +117,7 @@
|
||||
"edit": "Edit",
|
||||
"undo": "Urungkan",
|
||||
"redo": "Ulangi",
|
||||
"resetLibrary": "",
|
||||
"roomDialog": "Mulai kolaborasi langsung",
|
||||
"createNewRoom": "Buat ruang baru",
|
||||
"fullScreen": "Layar penuh",
|
||||
"darkMode": "Mode gelap",
|
||||
@ -136,12 +136,11 @@
|
||||
"decryptFailed": "Tidak dapat mengdekripsi data.",
|
||||
"uploadedSecurly": "Pengunggahan ini telah diamankan menggunakan enkripsi end-to-end, artinya server Excalidraw dan pihak ketiga tidak data membaca nya",
|
||||
"loadSceneOverridePrompt": "Memuat gambar external akan mengganti konten Anda yang ada. Apakah Anda ingin melanjutkan?",
|
||||
"collabStopOverridePrompt": "Menghentikan sesi akan menimpa gambar Anda yang tersimpan secara lokal. Anda yakin?\n\n(Jika Anda ingin menyimpan gambar lokal Anda, gantinya cukup tutup tab browser.)",
|
||||
"collabStopOverridePrompt": "",
|
||||
"errorLoadingLibrary": "Terdapat kesalahan dalam memuat pustaka pihak ketiga.",
|
||||
"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": ""
|
||||
"cannotRestoreFromImage": "Pemandangan tidak dapat dipulihkan dari file gambar ini"
|
||||
},
|
||||
"toolBar": {
|
||||
"selection": "Pilihan",
|
||||
@ -236,16 +235,14 @@
|
||||
"storage": "Penyimpanan",
|
||||
"title": "Statistik untuk nerd",
|
||||
"total": "Total",
|
||||
"version": "Versi",
|
||||
"versionCopy": "Klik untuk salin",
|
||||
"versionNotAvailable": "Versi tidak tersedia",
|
||||
"version": "",
|
||||
"versionCopy": "",
|
||||
"versionNotAvailable": "",
|
||||
"width": "Lebar"
|
||||
},
|
||||
"toast": {
|
||||
"copyStyles": "Gaya tersalin.",
|
||||
"copyToClipboard": "Tersalin ke papan klip.",
|
||||
"copyToClipboardAsPng": "Tersalin ke clipboard sebagai PNG.",
|
||||
"fileSaved": "File tersimpan.",
|
||||
"fileSavedToFilename": "Disimpan ke {filename}"
|
||||
"copyToClipboard": "",
|
||||
"copyToClipboardAsPng": "Tersalin ke clipboard sebagai PNG."
|
||||
}
|
||||
}
|
||||
|
@ -68,7 +68,7 @@
|
||||
"layers": "Livelli",
|
||||
"actions": "Azioni",
|
||||
"language": "Lingua",
|
||||
"liveCollaboration": "Collaborazione live",
|
||||
"createRoom": "Condividi una sessione di collaborazione in diretta",
|
||||
"duplicateSelection": "Duplica",
|
||||
"untitled": "Senza titolo",
|
||||
"name": "Nome",
|
||||
@ -77,7 +77,7 @@
|
||||
"group": "Crea gruppo da selezione",
|
||||
"ungroup": "Dividi gruppo da selezione",
|
||||
"collaborators": "Collaboratori",
|
||||
"showGrid": "Visualizza griglia",
|
||||
"gridMode": "Modalità griglia",
|
||||
"addToLibrary": "Aggiungi alla libreria",
|
||||
"removeFromLibrary": "Rimuovi dalla libreria",
|
||||
"libraryLoadingMessage": "Caricamento libreria…",
|
||||
@ -117,7 +117,7 @@
|
||||
"edit": "Modifica",
|
||||
"undo": "Annulla",
|
||||
"redo": "Ripeti",
|
||||
"resetLibrary": "Ripristina libreria",
|
||||
"roomDialog": "Inizia collaborazione in diretta",
|
||||
"createNewRoom": "Crea nuova stanza",
|
||||
"fullScreen": "Schermo intero",
|
||||
"darkMode": "Tema scuro",
|
||||
@ -140,8 +140,7 @@
|
||||
"errorLoadingLibrary": "Si è verificato un errore nel caricamento della libreria di terze parti.",
|
||||
"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",
|
||||
"resetLibrary": "Questa azione cancellerà l'intera libreria. Sei sicuro?"
|
||||
"cannotRestoreFromImage": "Impossibile ripristinare la scena da questo file immagine"
|
||||
},
|
||||
"toolBar": {
|
||||
"selection": "Selezione",
|
||||
@ -244,8 +243,6 @@
|
||||
"toast": {
|
||||
"copyStyles": "Stili copiati.",
|
||||
"copyToClipboard": "Copiato negli appunti.",
|
||||
"copyToClipboardAsPng": "Copiato negli appunti come PNG.",
|
||||
"fileSaved": "File salvato.",
|
||||
"fileSavedToFilename": "Salvato in {filename}"
|
||||
"copyToClipboardAsPng": "Copiato negli appunti come PNG."
|
||||
}
|
||||
}
|
||||
|
@ -1,11 +1,11 @@
|
||||
{
|
||||
"labels": {
|
||||
"paste": "貼り付け",
|
||||
"pasteCharts": "チャートの貼り付け",
|
||||
"pasteCharts": "",
|
||||
"selectAll": "すべて選択",
|
||||
"multiSelect": "複数選択",
|
||||
"moveCanvas": "キャンバスを移動",
|
||||
"cut": "切り取り",
|
||||
"cut": "",
|
||||
"copy": "コピー",
|
||||
"copyAsPng": "PNGとしてクリップボードへコピー",
|
||||
"copyAsSvg": "SVGとしてクリップボードへコピー",
|
||||
@ -38,7 +38,7 @@
|
||||
"fontSize": "フォントの大きさ",
|
||||
"fontFamily": "フォントの種類",
|
||||
"onlySelected": "選択中のみ",
|
||||
"withBackground": "背景を含める",
|
||||
"withBackground": "",
|
||||
"exportEmbedScene": "エクスポートされたファイルにシーンを埋め込みます",
|
||||
"exportEmbedScene_details": "シーンデータはエクスポートされたPNG/SVGファイルに保存され、シーンを復元することができます。\nエクスポートされたファイルのサイズは増加します。",
|
||||
"addWatermark": "\"Made with Excalidraw\"と表示",
|
||||
@ -68,20 +68,20 @@
|
||||
"layers": "レイヤー",
|
||||
"actions": "操作",
|
||||
"language": "言語",
|
||||
"liveCollaboration": "ライブ連携",
|
||||
"createRoom": "共同編集セッションの共有",
|
||||
"duplicateSelection": "複製",
|
||||
"untitled": "無題",
|
||||
"untitled": "",
|
||||
"name": "名前",
|
||||
"yourName": "あなたの名前",
|
||||
"madeWithExcalidraw": "Excalidrawで作成",
|
||||
"group": "図形のグループ化",
|
||||
"ungroup": "グループ化を解除",
|
||||
"collaborators": "共同編集者",
|
||||
"showGrid": "グリッドを表示",
|
||||
"gridMode": "",
|
||||
"addToLibrary": "ライブラリに追加",
|
||||
"removeFromLibrary": "ライブラリから削除",
|
||||
"libraryLoadingMessage": "ライブラリを読み込み中…",
|
||||
"libraries": "ライブラリを参照する",
|
||||
"libraries": "",
|
||||
"loadingScene": "シーンを読み込み中…",
|
||||
"align": "整列",
|
||||
"alignTop": "上揃え",
|
||||
@ -90,9 +90,9 @@
|
||||
"alignRight": "右揃え",
|
||||
"centerVertically": "縦方向に中央揃え",
|
||||
"centerHorizontally": "横方向に中央揃え",
|
||||
"distributeHorizontally": "水平方向に分散配置",
|
||||
"distributeVertically": "垂直方向に分散配置",
|
||||
"viewMode": "閲覧モード"
|
||||
"distributeHorizontally": "",
|
||||
"distributeVertically": "",
|
||||
"viewMode": ""
|
||||
},
|
||||
"buttons": {
|
||||
"clearReset": "キャンバスのリセット",
|
||||
@ -117,12 +117,12 @@
|
||||
"edit": "編集",
|
||||
"undo": "元に戻す",
|
||||
"redo": "やり直し",
|
||||
"resetLibrary": "ライブラリをリセット",
|
||||
"roomDialog": "共同編集を開始する",
|
||||
"createNewRoom": "新しい部屋を作成する",
|
||||
"fullScreen": "全画面表示",
|
||||
"darkMode": "ダークモード",
|
||||
"lightMode": "ライトモード",
|
||||
"zenMode": "Zenモード",
|
||||
"zenMode": "",
|
||||
"exitZenMode": "集中モードをやめる"
|
||||
},
|
||||
"alerts": {
|
||||
@ -136,12 +136,11 @@
|
||||
"decryptFailed": "データを復号できませんでした。",
|
||||
"uploadedSecurly": "データのアップロードはエンドツーエンド暗号化によって保護されています。Excalidrawサーバーと第三者はデータの内容を見ることができません。",
|
||||
"loadSceneOverridePrompt": "外部図面を読み込むと、既存のコンテンツが置き換わります。続行しますか?",
|
||||
"collabStopOverridePrompt": "セッションを停止すると、ローカルに保存されている図が上書きされます。 本当によろしいですか?\n\n(ローカルの図を保持したい場合は、セッションを停止せずにブラウザタブを閉じてください。)",
|
||||
"collabStopOverridePrompt": "",
|
||||
"errorLoadingLibrary": "サードパーティライブラリの読み込み中にエラーが発生しました。",
|
||||
"confirmAddLibrary": "{{numShapes}} 個の図形をライブラリに追加します。よろしいですか?",
|
||||
"imageDoesNotContainScene": "現在、画像のインポートはサポートされていません。\n\nシーンをインポートしようとしましたか?この画像にはシーンデータが含まれていないようです。エクスポート中に有効にしていましたか?",
|
||||
"cannotRestoreFromImage": "このイメージファイルからシーンを復元できませんでした",
|
||||
"resetLibrary": "ライブラリを消去します。本当によろしいですか?"
|
||||
"imageDoesNotContainScene": "",
|
||||
"cannotRestoreFromImage": "このイメージファイルからシーンを復元できませんでした"
|
||||
},
|
||||
"toolBar": {
|
||||
"selection": "選択",
|
||||
@ -165,7 +164,7 @@
|
||||
"freeDraw": "クリックしてドラッグします。離すと終了します",
|
||||
"text": "ヒント: 選択ツールを使用して任意の場所をダブルクリックしてテキストを追加することもできます",
|
||||
"linearElementMulti": "最後のポイントをクリックするか、エスケープまたはEnterを押して終了します",
|
||||
"lockAngle": "SHIFTを押したままにすると、角度を制限することができます",
|
||||
"lockAngle": "",
|
||||
"resize": "サイズを変更中にSHIFTを押しすと比率を制御できます。Altを押すと中央からサイズを変更できます。",
|
||||
"rotate": "回転中にSHIFT キーを押すと角度を制限することができます",
|
||||
"lineEditor_info": "ポイントを編集するには、ダブルクリックまたはEnterキーを押します",
|
||||
@ -203,49 +202,47 @@
|
||||
"title": "エラー"
|
||||
},
|
||||
"helpDialog": {
|
||||
"blog": "公式ブログを読む",
|
||||
"click": "クリック",
|
||||
"curvedArrow": "カーブした矢印",
|
||||
"curvedLine": "曲線",
|
||||
"documentation": "ドキュメント",
|
||||
"drag": "ドラッグ",
|
||||
"editor": "エディタ",
|
||||
"github": "不具合報告はこちら",
|
||||
"howto": "ヘルプ・マニュアル",
|
||||
"or": "または",
|
||||
"preventBinding": "矢印を結合しない",
|
||||
"shapes": "図形",
|
||||
"shortcuts": "キーボードショートカット",
|
||||
"textFinish": "編集を終了する (テキスト)",
|
||||
"textNewLine": "新しい行を追加 (テキスト)",
|
||||
"title": "ヘルプ",
|
||||
"view": "表示",
|
||||
"zoomToFit": "すべての要素が収まるようにズーム",
|
||||
"zoomToSelection": "選択要素にズーム"
|
||||
"blog": "",
|
||||
"click": "",
|
||||
"curvedArrow": "",
|
||||
"curvedLine": "",
|
||||
"documentation": "",
|
||||
"drag": "",
|
||||
"editor": "",
|
||||
"github": "",
|
||||
"howto": "",
|
||||
"or": "",
|
||||
"preventBinding": "",
|
||||
"shapes": "",
|
||||
"shortcuts": "",
|
||||
"textFinish": "",
|
||||
"textNewLine": "",
|
||||
"title": "",
|
||||
"view": "",
|
||||
"zoomToFit": "",
|
||||
"zoomToSelection": ""
|
||||
},
|
||||
"encrypted": {
|
||||
"tooltip": "描画内容はエンドツーエンド暗号化が施されており、Excalidrawサーバーが内容を見ることはできません。"
|
||||
},
|
||||
"stats": {
|
||||
"angle": "角度",
|
||||
"element": "要素",
|
||||
"elements": "要素",
|
||||
"angle": "",
|
||||
"element": "",
|
||||
"elements": "",
|
||||
"height": "高さ",
|
||||
"scene": "シーン",
|
||||
"selected": "選択済み",
|
||||
"storage": "ストレージ",
|
||||
"title": "マニア向け統計情報",
|
||||
"scene": "",
|
||||
"selected": "",
|
||||
"storage": "",
|
||||
"title": "",
|
||||
"total": "合計",
|
||||
"version": "バージョン",
|
||||
"versionCopy": "クリックしてコピー",
|
||||
"versionNotAvailable": "利用できないバージョン",
|
||||
"version": "",
|
||||
"versionCopy": "",
|
||||
"versionNotAvailable": "",
|
||||
"width": "幅"
|
||||
},
|
||||
"toast": {
|
||||
"copyStyles": "スタイルをコピー",
|
||||
"copyToClipboard": "クリップボードにコピー",
|
||||
"copyToClipboardAsPng": "PNG形式でクリップボードにコピー",
|
||||
"fileSaved": "ファイルを保存しました",
|
||||
"fileSavedToFilename": "{filename} に保存しました"
|
||||
"copyStyles": "",
|
||||
"copyToClipboard": "",
|
||||
"copyToClipboardAsPng": ""
|
||||
}
|
||||
}
|
||||
|
@ -24,7 +24,7 @@
|
||||
"strokeStyle_solid": "Aččuran",
|
||||
"strokeStyle_dashed": "S tjerriḍin",
|
||||
"strokeStyle_dotted": "S tenqiḍin",
|
||||
"sloppiness": "Astehzi",
|
||||
"sloppiness": "",
|
||||
"opacity": "Tiḍullest",
|
||||
"textAlign": "Areyyec n uḍris",
|
||||
"edges": "Leryuf",
|
||||
@ -68,7 +68,7 @@
|
||||
"layers": "Tissiyin",
|
||||
"actions": "Tigawin",
|
||||
"language": "Tutlayt",
|
||||
"liveCollaboration": "",
|
||||
"createRoom": "Bḍu tiɣimit n umɛawen s srid",
|
||||
"duplicateSelection": "Sisleg",
|
||||
"untitled": "War azwel",
|
||||
"name": "Isem",
|
||||
@ -77,7 +77,7 @@
|
||||
"group": "Segrew tafrayt",
|
||||
"ungroup": "Kkess asegrew i tefrayt",
|
||||
"collaborators": "Imɛiwnen",
|
||||
"showGrid": "Beqqeḍ aferrug",
|
||||
"gridMode": "Askar n uferrug",
|
||||
"addToLibrary": "Rnu ɣer temkarḍit",
|
||||
"removeFromLibrary": "Kkes si temkarḍit",
|
||||
"libraryLoadingMessage": "Asali n temkarḍit…",
|
||||
@ -117,7 +117,7 @@
|
||||
"edit": "Ẓreg",
|
||||
"undo": "Sefsex",
|
||||
"redo": "Err-d",
|
||||
"resetLibrary": "",
|
||||
"roomDialog": "Bdu amɛawen s srid",
|
||||
"createNewRoom": "Snulfu-d taxxamt tamaynutt",
|
||||
"fullScreen": "Agdil aččuran",
|
||||
"darkMode": "Askar imsulles",
|
||||
@ -130,18 +130,17 @@
|
||||
"couldNotCreateShareableLink": "D awezɣi asnulfu n useɣwen n beṭṭu.",
|
||||
"couldNotCreateShareableLinkTooBig": "D awezɣi asnulfu n useɣwen n beṭṭu. Asayes ɣezzif aṭas",
|
||||
"couldNotLoadInvalidFile": "D awezɣi asali n ufaylu armeɣtu",
|
||||
"importBackendFailed": "Takterḍ seg uɣawas n deffir ur teddi ara.",
|
||||
"importBackendFailed": "",
|
||||
"cannotExportEmptyCanvas": "D awezɣi asifeḍ n teɣzut n usuneɣ tilemt.",
|
||||
"couldNotCopyToClipboard": "D awezɣi anɣal ɣer tecfawit. Eɛreḍ ad tesqedceḍ iminig Chrome.",
|
||||
"decryptFailed": "D awezɣi tukksa n uwgelhen i yisefka.",
|
||||
"uploadedSecurly": "Asili yettwasɣelles s uwgelhen ixef s ixef, ayagi yebɣa ad d-yini belli aqeddac n Excalidraw akked medden ur zmiren ara ad ɣren agbur.",
|
||||
"loadSceneOverridePrompt": "Asali n wunuɣ uffiɣ ad isemselsi agbur-inek (m) yellan. Tebɣiḍ ad tkemmeleḍ?",
|
||||
"collabStopOverridePrompt": "Aḥbas n tɣimit ad yesefsex unuɣ-inek (m) yettwaḥerzen yakan s wudem adigan. Tetḥeqqeḍ?\n(Ma tebɣiḍ ad teǧǧeḍ unuɣ-inek (m) adigan, mdel iccer n yiminig, deg umḍiq.)",
|
||||
"collabStopOverridePrompt": "",
|
||||
"errorLoadingLibrary": "Teḍra-d tuccḍa deg usali n temkarḍit n wis kraḍ.",
|
||||
"confirmAddLibrary": "Ayagi adirnu talɣa (win) {{numShapes}} ɣer temkarḍit-inek (m). Tetḥeqqeḍ?",
|
||||
"imageDoesNotContainScene": "Taktert n tugniwin ur tettwadhel ara akka tura.\nTebɣiḍ ad tketreḍ asayes? Tugna-agi tettban-d ur tegbir ara isefka n usnas. Tesremdeḍ ayagi deg usifeḍ?",
|
||||
"cannotRestoreFromImage": "Asayes ulamek ara d-yettwarr seg ufaylu-agi n tugna",
|
||||
"resetLibrary": ""
|
||||
"cannotRestoreFromImage": "Asayes ulamek ara d-yettwarr seg ufaylu-agi n tugna"
|
||||
},
|
||||
"toolBar": {
|
||||
"selection": "Tafrayt",
|
||||
@ -185,7 +184,7 @@
|
||||
"clearCanvasCaveat": " Ayagi ad d-iglu s usṛuḥu n umahil ",
|
||||
"trackedToSentry_pre": "Tuccḍa akked umesmagi ",
|
||||
"trackedToSentry_post": " tettwasekles deg unagraw-nneɣ.",
|
||||
"openIssueMessage_pre": "Nḥuder aṭas akken ur nseddu ara talɣut n usayes-inek (m) di tuccḍa. Ma yella asayes-inek (m) mačči d amaẓlay, ttxil-k (m) xemmem ad ḍefreḍ ",
|
||||
"openIssueMessage_pre": "",
|
||||
"openIssueMessage_button": "afecku n weḍfar n yibugen.",
|
||||
"openIssueMessage_post": " Ma ulac uɣilif seddu talɣut ukessar-agi s wenɣal akked usenṭeḍ di GitHub issue.",
|
||||
"sceneContent": "Agbur n usayes:"
|
||||
@ -213,7 +212,7 @@
|
||||
"github": "Tufiḍ-d ugur? Azen-aɣ-d",
|
||||
"howto": "Ḍfer imniren-nneɣ",
|
||||
"or": "neɣ",
|
||||
"preventBinding": "Seḥbes tuqqna n tneccabin",
|
||||
"preventBinding": "",
|
||||
"shapes": "Talɣiwin",
|
||||
"shortcuts": "Inegzumen n unasiw",
|
||||
"textFinish": "Fak asiẓreg (aḍris)",
|
||||
@ -236,16 +235,14 @@
|
||||
"storage": "Aḥraz",
|
||||
"title": "",
|
||||
"total": "Aɣrud",
|
||||
"version": "Alqem",
|
||||
"versionCopy": "Sit ad tneɣleḍ",
|
||||
"versionNotAvailable": "Ur inuḥ ulqem",
|
||||
"version": "",
|
||||
"versionCopy": "",
|
||||
"versionNotAvailable": "",
|
||||
"width": "Tehri"
|
||||
},
|
||||
"toast": {
|
||||
"copyStyles": "Iɣunab yettwaneɣlen.",
|
||||
"copyToClipboard": "Yettwaɣel ɣer tecfawit.",
|
||||
"copyToClipboardAsPng": "Yettwanɣel ɣer tecfawit am PNG.",
|
||||
"fileSaved": "",
|
||||
"fileSavedToFilename": ""
|
||||
"copyToClipboard": "",
|
||||
"copyToClipboardAsPng": "Yettwanɣel ɣer tecfawit am PNG."
|
||||
}
|
||||
}
|
||||
|
@ -68,7 +68,7 @@
|
||||
"layers": "레이어",
|
||||
"actions": "동작",
|
||||
"language": "언어",
|
||||
"liveCollaboration": "",
|
||||
"createRoom": "실시간 협업 세션 공유",
|
||||
"duplicateSelection": "복제",
|
||||
"untitled": "제목 없음",
|
||||
"name": "이름",
|
||||
@ -77,7 +77,7 @@
|
||||
"group": "그룹 생성",
|
||||
"ungroup": "그룹 해제",
|
||||
"collaborators": "공동 작업자",
|
||||
"showGrid": "",
|
||||
"gridMode": "격자 방식",
|
||||
"addToLibrary": "라이브러리에 추가",
|
||||
"removeFromLibrary": "라이브러리에서 제거",
|
||||
"libraryLoadingMessage": "라이브러리 불러오는 중…",
|
||||
@ -92,7 +92,7 @@
|
||||
"centerHorizontally": "수평으로 중앙 정렬",
|
||||
"distributeHorizontally": "수평으로 분배",
|
||||
"distributeVertically": "수직으로 분배",
|
||||
"viewMode": "보기 모드"
|
||||
"viewMode": ""
|
||||
},
|
||||
"buttons": {
|
||||
"clearReset": "캔버스 초기화",
|
||||
@ -117,7 +117,7 @@
|
||||
"edit": "수정",
|
||||
"undo": "실행 취소",
|
||||
"redo": "다시 실행",
|
||||
"resetLibrary": "",
|
||||
"roomDialog": "실시간 협업 시작하기",
|
||||
"createNewRoom": "방 만들기",
|
||||
"fullScreen": "전체화면",
|
||||
"darkMode": "다크 모드",
|
||||
@ -136,12 +136,11 @@
|
||||
"decryptFailed": "데이터를 복호화하지 못했습니다.",
|
||||
"uploadedSecurly": "업로드는 종단 간 암호화로 보호되므로 Excalidraw 서버 및 타사가 콘텐츠를 읽을 수 없습니다.",
|
||||
"loadSceneOverridePrompt": "외부 파일을 불러 오면 기존 콘텐츠가 대체됩니다. 계속 진행할까요?",
|
||||
"collabStopOverridePrompt": "협업 세션을 종료하면 로컬 저장소에 있는 그림이 협업 세션의 그림으로 대체됩니다. 진행하겠습니까?\n\n(로컬 저장소에 있는 그림을 유지하려면 현재 브라우저 탭을 닫아주세요.)",
|
||||
"collabStopOverridePrompt": "",
|
||||
"errorLoadingLibrary": "외부 라이브러리를 불러오는 중에 문제가 발생했습니다.",
|
||||
"confirmAddLibrary": "{{numShapes}}개의 모양이 라이브러리에 추가됩니다. 계속하시겠어요?",
|
||||
"imageDoesNotContainScene": "이미지에서 불러오기는 현재 지원되지 않습니다.\n\n화면을 불러오려고 하셨나요? 이미지에 화면 정보가 없는 것 같습니다. 내보낼 때 화면을 포함했나요?",
|
||||
"cannotRestoreFromImage": "이미지 파일에서 화면을 복구할 수 없었습니다",
|
||||
"resetLibrary": ""
|
||||
"cannotRestoreFromImage": "이미지 파일에서 화면을 복구할 수 없었습니다"
|
||||
},
|
||||
"toolBar": {
|
||||
"selection": "선택",
|
||||
@ -203,25 +202,25 @@
|
||||
"title": "오류"
|
||||
},
|
||||
"helpDialog": {
|
||||
"blog": "블로그 읽어보기",
|
||||
"click": "클릭",
|
||||
"curvedArrow": "곡선 화살표",
|
||||
"curvedLine": "곡선",
|
||||
"documentation": "설명서",
|
||||
"drag": "드래그",
|
||||
"editor": "에디터",
|
||||
"github": "문제 제보하기",
|
||||
"howto": "가이드 참고하기",
|
||||
"or": "또는",
|
||||
"preventBinding": "화살표가 붙지 않게 하기",
|
||||
"shapes": "도형",
|
||||
"shortcuts": "키보드 단축키",
|
||||
"textFinish": "편집 완료 (텍스트)",
|
||||
"textNewLine": "줄바꿈 (텍스트)",
|
||||
"title": "도움말",
|
||||
"view": "보기",
|
||||
"zoomToFit": "모든 요소가 보이도록 확대/축소",
|
||||
"zoomToSelection": "선택 영역으로 확대/축소"
|
||||
"blog": "",
|
||||
"click": "",
|
||||
"curvedArrow": "",
|
||||
"curvedLine": "",
|
||||
"documentation": "",
|
||||
"drag": "",
|
||||
"editor": "",
|
||||
"github": "",
|
||||
"howto": "",
|
||||
"or": "",
|
||||
"preventBinding": "",
|
||||
"shapes": "",
|
||||
"shortcuts": "",
|
||||
"textFinish": "",
|
||||
"textNewLine": "",
|
||||
"title": "",
|
||||
"view": "",
|
||||
"zoomToFit": "",
|
||||
"zoomToSelection": ""
|
||||
},
|
||||
"encrypted": {
|
||||
"tooltip": "그림은 종단 간 암호화되므로 Excalidraw의 서버는 절대로 내용을 알 수 없습니다."
|
||||
@ -236,16 +235,14 @@
|
||||
"storage": "저장공간",
|
||||
"title": "덕후들을 위한 통계",
|
||||
"total": "합계",
|
||||
"version": "버전",
|
||||
"versionCopy": "복사하려면 클릭",
|
||||
"versionNotAvailable": "해당 버전 사용 불가능",
|
||||
"version": "",
|
||||
"versionCopy": "",
|
||||
"versionNotAvailable": "",
|
||||
"width": "너비"
|
||||
},
|
||||
"toast": {
|
||||
"copyStyles": "스타일 복사.",
|
||||
"copyToClipboard": "클립보드로 복사.",
|
||||
"copyToClipboardAsPng": "클립보드로 PNG 이미지 복사.",
|
||||
"fileSaved": "",
|
||||
"fileSavedToFilename": ""
|
||||
"copyStyles": "",
|
||||
"copyToClipboard": "",
|
||||
"copyToClipboardAsPng": ""
|
||||
}
|
||||
}
|
||||
|
@ -68,7 +68,7 @@
|
||||
"layers": "အလွှာများ",
|
||||
"actions": "လုပ်ဆောင်ချက်များ",
|
||||
"language": "ဘာသာစကား",
|
||||
"liveCollaboration": "",
|
||||
"createRoom": "တိုက်ရိုက်ပူးပေါင်းဆောင်ရွက်ရန်အဖွဲ့ဖွဲ့",
|
||||
"duplicateSelection": "ပွား",
|
||||
"untitled": "အမည်မရှိ",
|
||||
"name": "အမည်",
|
||||
@ -77,7 +77,7 @@
|
||||
"group": "အုပ်စုဖွဲ့",
|
||||
"ungroup": "အုပ်စုဖျက်သိမ်း",
|
||||
"collaborators": "ပူးပေါင်းပါဝင်သူများ",
|
||||
"showGrid": "",
|
||||
"gridMode": "",
|
||||
"addToLibrary": "မှတ်တမ်းတင်",
|
||||
"removeFromLibrary": "မှတ်တမ်းမှထုတ်",
|
||||
"libraryLoadingMessage": "မှတ်တမ်းအား တင်သွင်းနေသည်…",
|
||||
@ -117,7 +117,7 @@
|
||||
"edit": "ပြင်ဆင်",
|
||||
"undo": "ပြန်ထား",
|
||||
"redo": "ထပ်လုပ်",
|
||||
"resetLibrary": "",
|
||||
"roomDialog": "တိုက်ရိုက်ပူးပေါင်းမှုစတင်",
|
||||
"createNewRoom": "အခန်းသစ်ဖွဲ့",
|
||||
"fullScreen": "",
|
||||
"darkMode": "",
|
||||
@ -140,8 +140,7 @@
|
||||
"errorLoadingLibrary": "ပြင်ပမှမှတ်တမ်းအားတင်သွင်းရာတွင်အမှားအယွင်းရှိနေသည်။",
|
||||
"confirmAddLibrary": "{{numShapes}} ခုသောပုံသဏ္ဌာန်အားမှတ်တမ်းတင်ပါမည်။ အတည်ပြုပါ။",
|
||||
"imageDoesNotContainScene": "",
|
||||
"cannotRestoreFromImage": "ဤပုံဖြင့်မြင်ကွင်းပြန်လည်မရယူနိုင်ပါ။",
|
||||
"resetLibrary": ""
|
||||
"cannotRestoreFromImage": "ဤပုံဖြင့်မြင်ကွင်းပြန်လည်မရယူနိုင်ပါ။"
|
||||
},
|
||||
"toolBar": {
|
||||
"selection": "ရွေးချယ်",
|
||||
@ -244,8 +243,6 @@
|
||||
"toast": {
|
||||
"copyStyles": "",
|
||||
"copyToClipboard": "",
|
||||
"copyToClipboardAsPng": "",
|
||||
"fileSaved": "",
|
||||
"fileSavedToFilename": ""
|
||||
"copyToClipboardAsPng": ""
|
||||
}
|
||||
}
|
||||
|
@ -68,7 +68,7 @@
|
||||
"layers": "Lag",
|
||||
"actions": "Handlinger",
|
||||
"language": "Språk",
|
||||
"liveCollaboration": "Sanntids-samarbeid",
|
||||
"createRoom": "Del en sanntids-samarbeidsøkt",
|
||||
"duplicateSelection": "Dupliser",
|
||||
"untitled": "Uten navn",
|
||||
"name": "Navn",
|
||||
@ -77,7 +77,7 @@
|
||||
"group": "Gruppér utvalg",
|
||||
"ungroup": "Avgruppér utvalg",
|
||||
"collaborators": "Samarbeidspartnere",
|
||||
"showGrid": "Vis rutenett",
|
||||
"gridMode": "Rutevisning",
|
||||
"addToLibrary": "Legg til i bibliotek",
|
||||
"removeFromLibrary": "Fjern fra bibliotek",
|
||||
"libraryLoadingMessage": "Laster bibliotek…",
|
||||
@ -117,7 +117,7 @@
|
||||
"edit": "Rediger",
|
||||
"undo": "Angre",
|
||||
"redo": "Gjør om",
|
||||
"resetLibrary": "Nullstill bibliotek",
|
||||
"roomDialog": "Start sanntids-samarbeid",
|
||||
"createNewRoom": "Opprett et nytt rom",
|
||||
"fullScreen": "Fullskjerm",
|
||||
"darkMode": "Mørk modus",
|
||||
@ -140,8 +140,7 @@
|
||||
"errorLoadingLibrary": "Det oppstod en feil under lasting av tredjepartsbiblioteket.",
|
||||
"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",
|
||||
"resetLibrary": "Dette vil tømme biblioteket ditt. Er du sikker?"
|
||||
"cannotRestoreFromImage": "Scenen kunne ikke gjenopprettes fra denne bildefilen"
|
||||
},
|
||||
"toolBar": {
|
||||
"selection": "Velg",
|
||||
@ -244,8 +243,6 @@
|
||||
"toast": {
|
||||
"copyStyles": "Kopierte stiler.",
|
||||
"copyToClipboard": "Kopiert til utklippstavlen.",
|
||||
"copyToClipboardAsPng": "Kopiert til utklippstavlen som PNG.",
|
||||
"fileSaved": "Fil lagret.",
|
||||
"fileSavedToFilename": "Lagret til {filename}"
|
||||
"copyToClipboardAsPng": "Kopiert til utklippstavlen som PNG."
|
||||
}
|
||||
}
|
||||
|
@ -68,7 +68,7 @@
|
||||
"layers": "Lagen",
|
||||
"actions": "Acties",
|
||||
"language": "Taal",
|
||||
"liveCollaboration": "Live Samenwerking",
|
||||
"createRoom": "Deel een live-samenwerkingssessie",
|
||||
"duplicateSelection": "Dupliceer",
|
||||
"untitled": "Naamloos",
|
||||
"name": "Naam",
|
||||
@ -77,7 +77,7 @@
|
||||
"group": "Groeperen",
|
||||
"ungroup": "Groep opheffen",
|
||||
"collaborators": "Deelnemers",
|
||||
"showGrid": "Raster weergeven",
|
||||
"gridMode": "Rasterweergave",
|
||||
"addToLibrary": "Voeg toe aan bibliotheek",
|
||||
"removeFromLibrary": "Verwijder uit bibliotheek",
|
||||
"libraryLoadingMessage": "Bibliotheek laden…",
|
||||
@ -117,7 +117,7 @@
|
||||
"edit": "Bewerken",
|
||||
"undo": "Ongedaan maken",
|
||||
"redo": "Herstel ongedaan maken",
|
||||
"resetLibrary": "Bibliotheek Resetten",
|
||||
"roomDialog": "Live-samenwerkingssessie starten",
|
||||
"createNewRoom": "Creëer live-samenwerkingssessie",
|
||||
"fullScreen": "Volledig scherm",
|
||||
"darkMode": "Donkere modus",
|
||||
@ -140,8 +140,7 @@
|
||||
"errorLoadingLibrary": "Bij het laden van de externe bibliotheek is een fout opgetreden.",
|
||||
"confirmAddLibrary": "Hiermee worden {{numShapes}} vorm(n) aan uw bibliotheek toegevoegd. Ben je het zeker?",
|
||||
"imageDoesNotContainScene": "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",
|
||||
"resetLibrary": "Dit zal je bibliotheek wissen. Weet je het zeker?"
|
||||
"cannotRestoreFromImage": "Scène kan niet worden hersteld vanuit dit afbeeldingsbestand"
|
||||
},
|
||||
"toolBar": {
|
||||
"selection": "Selectie",
|
||||
@ -236,16 +235,14 @@
|
||||
"storage": "Opslag",
|
||||
"title": "Statistieken voor nerds",
|
||||
"total": "Totaal",
|
||||
"version": "Versie",
|
||||
"versionCopy": "Klik om te kopiëren",
|
||||
"versionNotAvailable": "Versie niet beschikbaar",
|
||||
"version": "",
|
||||
"versionCopy": "",
|
||||
"versionNotAvailable": "",
|
||||
"width": "Breedte"
|
||||
},
|
||||
"toast": {
|
||||
"copyStyles": "Stijlen gekopieerd.",
|
||||
"copyToClipboard": "Gekopieerd naar het klembord.",
|
||||
"copyToClipboardAsPng": "Gekopieerd naar klembord als PNG.",
|
||||
"fileSaved": "Bestand opgeslagen.",
|
||||
"fileSavedToFilename": "Opgeslagen als {filename}"
|
||||
"copyToClipboard": "",
|
||||
"copyToClipboardAsPng": "Gekopieerd naar klembord als PNG."
|
||||
}
|
||||
}
|
||||
|
@ -68,7 +68,7 @@
|
||||
"layers": "Lag",
|
||||
"actions": "Handlingar",
|
||||
"language": "Språk",
|
||||
"liveCollaboration": "",
|
||||
"createRoom": "Del ei sanntids-samarbeidsøkt",
|
||||
"duplicateSelection": "Dupliser",
|
||||
"untitled": "Utan namn",
|
||||
"name": "Namn",
|
||||
@ -77,7 +77,7 @@
|
||||
"group": "Grupper utval",
|
||||
"ungroup": "Avgrupper utval",
|
||||
"collaborators": "Samarbeidarar",
|
||||
"showGrid": "",
|
||||
"gridMode": "Rutevisning",
|
||||
"addToLibrary": "Legg til i bibliotek",
|
||||
"removeFromLibrary": "Fjern frå bibliotek",
|
||||
"libraryLoadingMessage": "Laster bibliotek…",
|
||||
@ -117,7 +117,7 @@
|
||||
"edit": "Rediger",
|
||||
"undo": "Angre",
|
||||
"redo": "Gjer om",
|
||||
"resetLibrary": "",
|
||||
"roomDialog": "Start sanntids-samarbeid",
|
||||
"createNewRoom": "Lag nytt rom",
|
||||
"fullScreen": "Fullskjerm",
|
||||
"darkMode": "Mørk modus",
|
||||
@ -140,8 +140,7 @@
|
||||
"errorLoadingLibrary": "Det oppstod ein feil under lastinga av tredjepartsbibliotek.",
|
||||
"confirmAddLibrary": "Dette vil legge til {{numShapes}} form(er) i biblioteket ditt. Er du sikker?",
|
||||
"imageDoesNotContainScene": "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",
|
||||
"resetLibrary": ""
|
||||
"cannotRestoreFromImage": "Scena kunne ikkje gjenopprettast frå denne biletfila"
|
||||
},
|
||||
"toolBar": {
|
||||
"selection": "Vel",
|
||||
@ -244,8 +243,6 @@
|
||||
"toast": {
|
||||
"copyStyles": "",
|
||||
"copyToClipboard": "",
|
||||
"copyToClipboardAsPng": "",
|
||||
"fileSaved": "",
|
||||
"fileSavedToFilename": ""
|
||||
"copyToClipboardAsPng": ""
|
||||
}
|
||||
}
|
||||
|
@ -68,7 +68,7 @@
|
||||
"layers": "ਪਰਤਾਂ",
|
||||
"actions": "ਕਾਰਵਾਈਆਂ",
|
||||
"language": "ਭਾਸ਼ਾ",
|
||||
"liveCollaboration": "",
|
||||
"createRoom": "ਲਾਇਵ ਸਹਿਯੋਗ ਇਜਲਾਸ ਸਾਂਝਾ ਕਰੋ",
|
||||
"duplicateSelection": "ਡੁਪਲੀਕੇਟ ਬਣਾਓ",
|
||||
"untitled": "ਬੇ-ਸਿਰਨਾਵਾਂ",
|
||||
"name": "ਨਾਂ",
|
||||
@ -77,7 +77,7 @@
|
||||
"group": "ਚੋਣ ਦਾ ਗਰੁੱਪ ਬਣਾਓ",
|
||||
"ungroup": "ਚੋਣ ਦਾ ਗਰੁੱਪ ਤੋੜੋ",
|
||||
"collaborators": "ਸਹਿਯੋਗੀ",
|
||||
"showGrid": "ਜਾਲੀ ਦਿਖਾਓ",
|
||||
"gridMode": "ਜਾਲੀਦਾਰ ਮੋਡ",
|
||||
"addToLibrary": "ਲਾਇਬ੍ਰੇਰੀ ਵਿੱਚ ਜੋੜੋ",
|
||||
"removeFromLibrary": "ਲਾਇਬ੍ਰੇਰੀ 'ਚੋਂ ਹਟਾਓ",
|
||||
"libraryLoadingMessage": "ਲਾਇਬ੍ਰੇਰੀ ਲੋਡ ਕੀਤੀ ਜਾ ਰਹੀ ਹੈ…",
|
||||
@ -117,7 +117,7 @@
|
||||
"edit": "ਸੋਧੋ",
|
||||
"undo": "ਅਣਕੀਤਾ ਕਰੋ",
|
||||
"redo": "ਮੁੜ-ਕਰੋ",
|
||||
"resetLibrary": "",
|
||||
"roomDialog": "ਲਾਇਵ ਸਹਿਯੋਗ ਸ਼ੁਰੂ ਕਰੋ",
|
||||
"createNewRoom": "ਨਵਾਂ ਕਮਰਾ ਬਣਾਓ",
|
||||
"fullScreen": "ਪੂਰੀ ਸਕਰੀਨ",
|
||||
"darkMode": "ਡਾਰਕ ਮੋਡ",
|
||||
@ -140,8 +140,7 @@
|
||||
"errorLoadingLibrary": "ਤੀਜੀ ਧਿਰ ਦੀ ਲਾਇਬ੍ਰੇਰੀ ਨੂੰ ਲੋਡ ਕਰਨ ਵਿੱਚ ਗਲਤੀ ਹੋਈ ਸੀ।",
|
||||
"confirmAddLibrary": "ਇਹ ਤੁਹਾਡੀ ਲਾਇਬ੍ਰੇਰੀ ਵਿੱਚ {{numShapes}} ਆਕ੍ਰਿਤੀ(ਆਂ) ਨੂੰ ਜੋੜ ਦੇਵੇਗਾ। ਕੀ ਤੁਸੀਂ ਪੱਕਾ ਇੰਝ ਕਰਨਾ ਚਾਹੁੰਦੇ ਹੋ?",
|
||||
"imageDoesNotContainScene": "ਫਿਲਹਾਲ ਤਸਵੀਰਾਂ ਨੂੰ ਆਯਾਤ ਕਰਨ ਦਾ ਸਮਰਥਨ ਨਹੀਂ ਕਰਦਾ।\n\nਕੀ ਤੁਸੀਂ ਦ੍ਰਿਸ਼ ਨੂੰ ਆਯਾਤ ਕਰਨਾ ਚਾਹੁੰਦੇ ਸੀ? ਇਸ ਤਸਵੀਰ ਵਿੱਚ ਦ੍ਰਿਸ਼ ਦਾ ਕੋਈ ਵੀ ਡਾਟਾ ਨਜ਼ਰ ਨਹੀਂ ਆ ਰਿਹਾ। ਕੀ ਨਿਰਯਾਤ ਦੌਰਾਨ ਤੁਸੀਂ ਇਹ ਸਮਰੱਥ ਕੀਤਾ ਸੀ?",
|
||||
"cannotRestoreFromImage": "ਇਸ ਤਸਵੀਰ ਫਾਈਲ ਤੋਂ ਦ੍ਰਿਸ਼ ਬਹਾਲ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਿਆ",
|
||||
"resetLibrary": ""
|
||||
"cannotRestoreFromImage": "ਇਸ ਤਸਵੀਰ ਫਾਈਲ ਤੋਂ ਦ੍ਰਿਸ਼ ਬਹਾਲ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਿਆ"
|
||||
},
|
||||
"toolBar": {
|
||||
"selection": "ਚੋਣਕਾਰ",
|
||||
@ -244,8 +243,6 @@
|
||||
"toast": {
|
||||
"copyStyles": "ਕਾਪੀ ਕੀਤੇ ਸਟਾਇਲ।",
|
||||
"copyToClipboard": "ਕਲਿੱਪਬੋਰਡ 'ਤੇ ਕਾਪੀ ਕੀਤਾ।",
|
||||
"copyToClipboardAsPng": "ਕਲਿੱਪਬੋਰਡ 'ਤੇ PNG ਵਜੋਂ ਕਾਪੀ ਕੀਤਾ।",
|
||||
"fileSaved": "ਫਾਈਲ ਸਾਂਭੀ ਗਈ।",
|
||||
"fileSavedToFilename": "{filename} ਵਿੱਚ ਸਾਂਭੀ"
|
||||
"copyToClipboardAsPng": "ਕਲਿੱਪਬੋਰਡ 'ਤੇ PNG ਵਜੋਂ ਕਾਪੀ ਕੀਤਾ।"
|
||||
}
|
||||
}
|
||||
|
@ -1,36 +1,36 @@
|
||||
{
|
||||
"ar-SA": 85,
|
||||
"bg-BG": 98,
|
||||
"ca-ES": 85,
|
||||
"de-DE": 100,
|
||||
"el-GR": 100,
|
||||
"ar-SA": 87,
|
||||
"bg-BG": 91,
|
||||
"ca-ES": 87,
|
||||
"de-DE": 98,
|
||||
"el-GR": 99,
|
||||
"en": 100,
|
||||
"es-ES": 100,
|
||||
"fa-IR": 93,
|
||||
"fi-FI": 100,
|
||||
"es-ES": 98,
|
||||
"fa-IR": 95,
|
||||
"fi-FI": 98,
|
||||
"fr-FR": 100,
|
||||
"he-IL": 85,
|
||||
"hi-IN": 96,
|
||||
"hu-HU": 85,
|
||||
"id-ID": 99,
|
||||
"he-IL": 87,
|
||||
"hi-IN": 98,
|
||||
"hu-HU": 87,
|
||||
"id-ID": 97,
|
||||
"it-IT": 100,
|
||||
"ja-JP": 100,
|
||||
"kab-KAB": 97,
|
||||
"ko-KR": 97,
|
||||
"my-MM": 79,
|
||||
"ja-JP": 79,
|
||||
"kab-KAB": 94,
|
||||
"ko-KR": 87,
|
||||
"my-MM": 81,
|
||||
"nb-NO": 100,
|
||||
"nl-NL": 99,
|
||||
"nn-NO": 87,
|
||||
"pa-IN": 99,
|
||||
"pl-PL": 85,
|
||||
"nl-NL": 97,
|
||||
"nn-NO": 90,
|
||||
"pa-IN": 100,
|
||||
"pl-PL": 88,
|
||||
"pt-BR": 100,
|
||||
"pt-PT": 94,
|
||||
"pt-PT": 97,
|
||||
"ro-RO": 100,
|
||||
"ru-RU": 100,
|
||||
"ru-RU": 97,
|
||||
"sk-SK": 100,
|
||||
"sv-SE": 100,
|
||||
"tr-TR": 85,
|
||||
"uk-UA": 99,
|
||||
"zh-CN": 95,
|
||||
"sv-SE": 98,
|
||||
"tr-TR": 87,
|
||||
"uk-UA": 97,
|
||||
"zh-CN": 98,
|
||||
"zh-TW": 100
|
||||
}
|
||||
|
@ -68,7 +68,7 @@
|
||||
"layers": "Warstwy",
|
||||
"actions": "Akcje",
|
||||
"language": "Język",
|
||||
"liveCollaboration": "",
|
||||
"createRoom": "Udostępnij sesję współpracy na żywo",
|
||||
"duplicateSelection": "Powiel",
|
||||
"untitled": "Bez tytułu",
|
||||
"name": "Nazwa",
|
||||
@ -77,7 +77,7 @@
|
||||
"group": "Zgrupuj wybrane",
|
||||
"ungroup": "Rozgrupuj wybrane",
|
||||
"collaborators": "Współtwórcy",
|
||||
"showGrid": "",
|
||||
"gridMode": "Tryb siatki",
|
||||
"addToLibrary": "Dodaj do biblioteki",
|
||||
"removeFromLibrary": "Usuń z biblioteki",
|
||||
"libraryLoadingMessage": "Ładowanie biblioteki…",
|
||||
@ -117,7 +117,7 @@
|
||||
"edit": "Edytuj",
|
||||
"undo": "Cofnij",
|
||||
"redo": "Przywróć",
|
||||
"resetLibrary": "",
|
||||
"roomDialog": "Utwórz nową sesję współpracy na żywo",
|
||||
"createNewRoom": "Utwórz nowy pokój",
|
||||
"fullScreen": "Pełny ekran",
|
||||
"darkMode": "Ciemny motyw",
|
||||
@ -140,8 +140,7 @@
|
||||
"errorLoadingLibrary": "Wystąpił błąd podczas ładowania zewnętrznej biblioteki.",
|
||||
"confirmAddLibrary": "To doda {{numShapes}} kształtów do twojej biblioteki. Jesteś pewien?",
|
||||
"imageDoesNotContainScene": "Importowanie zdjęć nie jest obecnie obsługiwane.\n\nCzy chciałeś zaimportować scenę? Ten obraz nie zawiera żadnych danych sceny. Czy włączyłeś to podczas eksportowania?",
|
||||
"cannotRestoreFromImage": "Scena nie mogła zostać przywrócona z pliku obrazu",
|
||||
"resetLibrary": ""
|
||||
"cannotRestoreFromImage": "Scena nie mogła zostać przywrócona z pliku obrazu"
|
||||
},
|
||||
"toolBar": {
|
||||
"selection": "Zaznaczenie",
|
||||
@ -244,8 +243,6 @@
|
||||
"toast": {
|
||||
"copyStyles": "",
|
||||
"copyToClipboard": "",
|
||||
"copyToClipboardAsPng": "",
|
||||
"fileSaved": "",
|
||||
"fileSavedToFilename": ""
|
||||
"copyToClipboardAsPng": ""
|
||||
}
|
||||
}
|
||||
|
@ -68,7 +68,7 @@
|
||||
"layers": "Camadas",
|
||||
"actions": "Ações",
|
||||
"language": "Idioma",
|
||||
"liveCollaboration": "Colaboração ao vivo",
|
||||
"createRoom": "Compartilhar uma sessão de colaboração ao vivo",
|
||||
"duplicateSelection": "Duplicar",
|
||||
"untitled": "Sem título",
|
||||
"name": "Nome",
|
||||
@ -77,7 +77,7 @@
|
||||
"group": "Agrupar seleção",
|
||||
"ungroup": "Desagrupar seleção",
|
||||
"collaborators": "Colaboradores",
|
||||
"showGrid": "Mostrar grade",
|
||||
"gridMode": "Modo grade",
|
||||
"addToLibrary": "Adicionar à biblioteca",
|
||||
"removeFromLibrary": "Remover da biblioteca",
|
||||
"libraryLoadingMessage": "Carregando biblioteca…",
|
||||
@ -117,7 +117,7 @@
|
||||
"edit": "Editar",
|
||||
"undo": "Desfazer",
|
||||
"redo": "Refazer",
|
||||
"resetLibrary": "Redefinir biblioteca",
|
||||
"roomDialog": "Iniciar colaboração ao vivo",
|
||||
"createNewRoom": "Criar nova sala",
|
||||
"fullScreen": "Tela cheia",
|
||||
"darkMode": "Modo escuro",
|
||||
@ -140,8 +140,7 @@
|
||||
"errorLoadingLibrary": "Houve um erro ao carregar a biblioteca de terceiros.",
|
||||
"confirmAddLibrary": "Isso adicionará {{numShapes}} forma(s) à sua biblioteca. Tem certeza?",
|
||||
"imageDoesNotContainScene": "A importação de imagens não é suportada no momento.\n\nVocê deseja importar uma cena? Esta imagem parece não conter dados de cena. Você ativou isto durante a exportação?",
|
||||
"cannotRestoreFromImage": "Não foi possível restaurar a cena deste arquivo de imagem",
|
||||
"resetLibrary": "Isto limpará a sua biblioteca. Você tem certeza?"
|
||||
"cannotRestoreFromImage": "Não foi possível restaurar a cena deste arquivo de imagem"
|
||||
},
|
||||
"toolBar": {
|
||||
"selection": "Seleção",
|
||||
@ -244,8 +243,6 @@
|
||||
"toast": {
|
||||
"copyStyles": "Estilos copiados.",
|
||||
"copyToClipboard": "Copiado para área de transferência.",
|
||||
"copyToClipboardAsPng": "Copiado para a área de transferência como PNG.",
|
||||
"fileSaved": "Arquivo salvo.",
|
||||
"fileSavedToFilename": "Salvo em {filename}"
|
||||
"copyToClipboardAsPng": "Copiado para a área de transferência como PNG."
|
||||
}
|
||||
}
|
||||
|
@ -68,7 +68,7 @@
|
||||
"layers": "Camadas",
|
||||
"actions": "Ações",
|
||||
"language": "Idioma",
|
||||
"liveCollaboration": "",
|
||||
"createRoom": "Compartilhar uma sessão de colaboração ao vivo",
|
||||
"duplicateSelection": "Duplicar",
|
||||
"untitled": "Sem título",
|
||||
"name": "Nome",
|
||||
@ -77,7 +77,7 @@
|
||||
"group": "Agrupar seleção",
|
||||
"ungroup": "Desagrupar seleção",
|
||||
"collaborators": "Colaboradores",
|
||||
"showGrid": "",
|
||||
"gridMode": "Modo grade",
|
||||
"addToLibrary": "Adicionar à biblioteca",
|
||||
"removeFromLibrary": "Remover da biblioteca",
|
||||
"libraryLoadingMessage": "Carregando biblioteca…",
|
||||
@ -117,7 +117,7 @@
|
||||
"edit": "Editar",
|
||||
"undo": "Desfazer",
|
||||
"redo": "Refazer",
|
||||
"resetLibrary": "",
|
||||
"roomDialog": "Iniciar colaboração ao vivo",
|
||||
"createNewRoom": "Criar nova sala",
|
||||
"fullScreen": "Tela cheia",
|
||||
"darkMode": "Modo escuro",
|
||||
@ -140,8 +140,7 @@
|
||||
"errorLoadingLibrary": "Houve um erro ao carregar a biblioteca de terceiros.",
|
||||
"confirmAddLibrary": "Isso adicionará {{numShapes}} forma(s) à sua biblioteca. Tem certeza?",
|
||||
"imageDoesNotContainScene": "A importação de imagens não é suportada no momento.\n\nVocê deseja importar uma cena? Esta imagem parece não conter dados de cena. Você ativou isto durante a exportação?",
|
||||
"cannotRestoreFromImage": "Não foi possível restaurar a cena deste arquivo de imagem",
|
||||
"resetLibrary": ""
|
||||
"cannotRestoreFromImage": "Não foi possível restaurar a cena deste arquivo de imagem"
|
||||
},
|
||||
"toolBar": {
|
||||
"selection": "Seleção",
|
||||
@ -244,8 +243,6 @@
|
||||
"toast": {
|
||||
"copyStyles": "Estilos copiados.",
|
||||
"copyToClipboard": "",
|
||||
"copyToClipboardAsPng": "Copiado para o clipboard como PNG.",
|
||||
"fileSaved": "",
|
||||
"fileSavedToFilename": ""
|
||||
"copyToClipboardAsPng": "Copiado para o clipboard como PNG."
|
||||
}
|
||||
}
|
||||
|
@ -68,7 +68,7 @@
|
||||
"layers": "Straturi",
|
||||
"actions": "Acțiuni",
|
||||
"language": "Limbă",
|
||||
"liveCollaboration": "Colaborare în direct",
|
||||
"createRoom": "Invită la o sesiune de colaborare în direct",
|
||||
"duplicateSelection": "Duplicare",
|
||||
"untitled": "Nedenumit",
|
||||
"name": "Nume",
|
||||
@ -77,7 +77,7 @@
|
||||
"group": "Grupare selecție",
|
||||
"ungroup": "Degrupare selecție",
|
||||
"collaborators": "Colaboratori",
|
||||
"showGrid": "Afișare grilă",
|
||||
"gridMode": "Mod grilă",
|
||||
"addToLibrary": "Adăugare la bibliotecă",
|
||||
"removeFromLibrary": "Eliminare din bibliotecă",
|
||||
"libraryLoadingMessage": "Se încarcă biblioteca…",
|
||||
@ -117,7 +117,7 @@
|
||||
"edit": "Edit",
|
||||
"undo": "Anulare",
|
||||
"redo": "Refacere",
|
||||
"resetLibrary": "Resetare bibliotecă",
|
||||
"roomDialog": "Colaborare în direct",
|
||||
"createNewRoom": "Creare cameră nouă",
|
||||
"fullScreen": "Ecran complet",
|
||||
"darkMode": "Mod întunecat",
|
||||
@ -140,8 +140,7 @@
|
||||
"errorLoadingLibrary": "A apărut o eroare la încărcarea bibliotecii terțe.",
|
||||
"confirmAddLibrary": "Această acțiune va adăuga {{numShapes}} formă(e) la biblioteca ta. Confirmi?",
|
||||
"imageDoesNotContainScene": "Importarea imaginilor nu este acceptată în acest moment.\n\nVoiai să imporți o scenă? Această imagine nu pare să conțină date de scenă. Ai activat această opțiune pe durata exportării?",
|
||||
"cannotRestoreFromImage": "Scena nu a putut fi restaurată din acest fișier de imagine",
|
||||
"resetLibrary": "Această opțiune va elimina conținutul din bibliotecă. Confirmi?"
|
||||
"cannotRestoreFromImage": "Scena nu a putut fi restaurată din acest fișier de imagine"
|
||||
},
|
||||
"toolBar": {
|
||||
"selection": "Selecție",
|
||||
@ -244,8 +243,6 @@
|
||||
"toast": {
|
||||
"copyStyles": "Stiluri copiate.",
|
||||
"copyToClipboard": "Copiat în memoria temporară.",
|
||||
"copyToClipboardAsPng": "Copiat în memoria temporară ca PNG.",
|
||||
"fileSaved": "Fișier salvat.",
|
||||
"fileSavedToFilename": "Salvat în {filename}"
|
||||
"copyToClipboardAsPng": "Copiat în memoria temporară ca PNG."
|
||||
}
|
||||
}
|
||||
|
@ -68,7 +68,7 @@
|
||||
"layers": "Слои",
|
||||
"actions": "Действия",
|
||||
"language": "Язык",
|
||||
"liveCollaboration": "Совместное взаимодействие",
|
||||
"createRoom": "Начать сеанс совместной работы",
|
||||
"duplicateSelection": "Дубликат",
|
||||
"untitled": "Безымянный",
|
||||
"name": "Имя",
|
||||
@ -77,7 +77,7 @@
|
||||
"group": "Сгруппировать выделение",
|
||||
"ungroup": "Разделить выделение",
|
||||
"collaborators": "Участники",
|
||||
"showGrid": "Показать сетку",
|
||||
"gridMode": "Сетка",
|
||||
"addToLibrary": "Добавить в библиотеку",
|
||||
"removeFromLibrary": "Удалить из библиотеки",
|
||||
"libraryLoadingMessage": "Загрузка библиотеки…",
|
||||
@ -117,7 +117,7 @@
|
||||
"edit": "Изменить",
|
||||
"undo": "Шаг назад",
|
||||
"redo": "Шаг вперед",
|
||||
"resetLibrary": "Сброс библиотеки",
|
||||
"roomDialog": "Начать совместную работу",
|
||||
"createNewRoom": "Создать новую комнату",
|
||||
"fullScreen": "Полный экран",
|
||||
"darkMode": "Темная тема",
|
||||
@ -136,12 +136,11 @@
|
||||
"decryptFailed": "Не удалось расшифровать данные.",
|
||||
"uploadedSecurly": "Загружаемые данные защищена сквозным шифрованием, что означает, что сервер Excalidraw и третьи стороны не могут прочитать содержимое.",
|
||||
"loadSceneOverridePrompt": "Загрузка рисунка приведёт к замене имеющегося содержимого. Вы хотите продолжить?",
|
||||
"collabStopOverridePrompt": "Остановка сессии перезапишет ваш предыдущий, локально сохранённый рисунок. Вы уверены? \n\n(Если вы хотите оставить ваш локальный рисунок, просто закройте вкладку браузера)",
|
||||
"collabStopOverridePrompt": "",
|
||||
"errorLoadingLibrary": "Произошла ошибка при загрузке сторонней библиотеки.",
|
||||
"confirmAddLibrary": "Будет добавлено {{numShapes}} фигур в вашу библиотеку. Продолжить?",
|
||||
"imageDoesNotContainScene": "Импорт изображений не поддерживается в данный момент.\n\nХотите импортировать сцену? Данное изображение не содержит данных о сцене. Было ли включено это во время экспорта?",
|
||||
"cannotRestoreFromImage": "Сцена не может быть восстановлена из этого изображения",
|
||||
"resetLibrary": "Это очистит вашу библиотеку. Вы уверены?"
|
||||
"cannotRestoreFromImage": "Сцена не может быть восстановлена из этого изображения"
|
||||
},
|
||||
"toolBar": {
|
||||
"selection": "Выделение области",
|
||||
@ -236,16 +235,14 @@
|
||||
"storage": "Хранилище",
|
||||
"title": "Статистика для ботаников",
|
||||
"total": "Всего",
|
||||
"version": "Версия",
|
||||
"versionCopy": "Копировать",
|
||||
"versionNotAvailable": "Версия не доступна",
|
||||
"version": "",
|
||||
"versionCopy": "",
|
||||
"versionNotAvailable": "",
|
||||
"width": "Ширина"
|
||||
},
|
||||
"toast": {
|
||||
"copyStyles": "Скопированы стили.",
|
||||
"copyToClipboard": "Скопировано в буфер обмена.",
|
||||
"copyToClipboardAsPng": "Скопировано в буфер обмена в формате PNG.",
|
||||
"fileSaved": "Файл сохранён.",
|
||||
"fileSavedToFilename": "Сохранено в {filename}"
|
||||
"copyToClipboard": "",
|
||||
"copyToClipboardAsPng": "Скопировано в буфер обмена в формате PNG."
|
||||
}
|
||||
}
|
||||
|
@ -68,7 +68,7 @@
|
||||
"layers": "Vrstvy",
|
||||
"actions": "Akcie",
|
||||
"language": "Jazyk",
|
||||
"liveCollaboration": "Živá spolupráca",
|
||||
"createRoom": "Zdieľajte živú spoluprácu",
|
||||
"duplicateSelection": "Duplikovať",
|
||||
"untitled": "Bez názvu",
|
||||
"name": "Meno",
|
||||
@ -77,7 +77,7 @@
|
||||
"group": "Zoskupiť",
|
||||
"ungroup": "Zrušiť zoskupenie",
|
||||
"collaborators": "Spolupracovníci",
|
||||
"showGrid": "Zobraziť mriežku",
|
||||
"gridMode": "Režim mriežky",
|
||||
"addToLibrary": "Pridať do knižnice",
|
||||
"removeFromLibrary": "Odstrániť z knižnice",
|
||||
"libraryLoadingMessage": "Načítavanie knižnice…",
|
||||
@ -117,7 +117,7 @@
|
||||
"edit": "Upraviť",
|
||||
"undo": "Späť",
|
||||
"redo": "Znova",
|
||||
"resetLibrary": "Obnoviť knižnicu",
|
||||
"roomDialog": "Začať živú spoluprácu",
|
||||
"createNewRoom": "Vytvoriť novú miestnosť",
|
||||
"fullScreen": "Celá obrazovka",
|
||||
"darkMode": "Tmavý režim",
|
||||
@ -140,8 +140,7 @@
|
||||
"errorLoadingLibrary": "Nepodarilo sa načítať externú knižnicu.",
|
||||
"confirmAddLibrary": "Týmto sa pridá {{numShapes}} tvar(ov) do vašej knižnice. Ste si istí?",
|
||||
"imageDoesNotContainScene": "Importovanie obrázku v tomto momente nie je možné.\n\nChceli ste importovať scénu? Tento obrázok neobsahuje žiadne údaje scény. Povolili ste túto možnosť počas exportovania?",
|
||||
"cannotRestoreFromImage": "Nepodarilo sa obnoviť scénu z tohto obrázkového súboru",
|
||||
"resetLibrary": "Týmto vyprázdnite vašu knižnicu. Ste si istý?"
|
||||
"cannotRestoreFromImage": "Nepodarilo sa obnoviť scénu z tohto obrázkového súboru"
|
||||
},
|
||||
"toolBar": {
|
||||
"selection": "Výber",
|
||||
@ -244,8 +243,6 @@
|
||||
"toast": {
|
||||
"copyStyles": "Štýly skopírované.",
|
||||
"copyToClipboard": "Skopírované do schránky.",
|
||||
"copyToClipboardAsPng": "Skopírované do schránky ako PNG.",
|
||||
"fileSaved": "Súbor uložený.",
|
||||
"fileSavedToFilename": "Uložený ako {filename}"
|
||||
"copyToClipboardAsPng": "Skopírované do schránky ako PNG."
|
||||
}
|
||||
}
|
||||
|
@ -68,7 +68,7 @@
|
||||
"layers": "Lager",
|
||||
"actions": "Åtgärder",
|
||||
"language": "Språk",
|
||||
"liveCollaboration": "Samarbeta live",
|
||||
"createRoom": "Dela en live-samarbetssession",
|
||||
"duplicateSelection": "Duplicera",
|
||||
"untitled": "Namnlös",
|
||||
"name": "Namn",
|
||||
@ -77,7 +77,7 @@
|
||||
"group": "Gruppera markering",
|
||||
"ungroup": "Avgruppera markering",
|
||||
"collaborators": "Medarbetare",
|
||||
"showGrid": "Visa rutnät",
|
||||
"gridMode": "Rutnätsläge",
|
||||
"addToLibrary": "Lägg till i biblioteket",
|
||||
"removeFromLibrary": "Ta bort från bibliotek",
|
||||
"libraryLoadingMessage": "Laddar bibliotek…",
|
||||
@ -117,7 +117,7 @@
|
||||
"edit": "Redigera",
|
||||
"undo": "Ångra",
|
||||
"redo": "Gör om",
|
||||
"resetLibrary": "Återställ bibliotek",
|
||||
"roomDialog": "Starta live-samarbete",
|
||||
"createNewRoom": "Skapa ett nytt rum",
|
||||
"fullScreen": "Helskärm",
|
||||
"darkMode": "Mörkt läge",
|
||||
@ -140,8 +140,7 @@
|
||||
"errorLoadingLibrary": "Fel vid inläsning av tredjeparts bibliotek.",
|
||||
"confirmAddLibrary": "Detta kommer att lägga till {{numShapes}} form(er) till ditt bibliotek. Är du säker?",
|
||||
"imageDoesNotContainScene": "Importering av bilder stöds inte just nu.\n\nVill du importera en skiss? Den här bilden verkar inte innehålla någon skissdata. Har du aktiverat detta under export?",
|
||||
"cannotRestoreFromImage": "Skiss kunde inte återställas från denna bildfil",
|
||||
"resetLibrary": "Detta kommer att rensa ditt bibliotek. Är du säker?"
|
||||
"cannotRestoreFromImage": "Skiss kunde inte återställas från denna bildfil"
|
||||
},
|
||||
"toolBar": {
|
||||
"selection": "Markering",
|
||||
@ -236,16 +235,14 @@
|
||||
"storage": "Lagring",
|
||||
"title": "Statistik för nördar",
|
||||
"total": "Totalt",
|
||||
"version": "Version",
|
||||
"versionCopy": "Klicka för att kopiera",
|
||||
"versionNotAvailable": "Versionen är inte tillgänglig",
|
||||
"version": "",
|
||||
"versionCopy": "",
|
||||
"versionNotAvailable": "",
|
||||
"width": "Bredd"
|
||||
},
|
||||
"toast": {
|
||||
"copyStyles": "Kopierade stilar.",
|
||||
"copyToClipboard": "Kopierad till urklipp.",
|
||||
"copyToClipboardAsPng": "Kopierat till urklipp som PNG.",
|
||||
"fileSaved": "Fil sparad.",
|
||||
"fileSavedToFilename": "Sparad till {filename}"
|
||||
"copyToClipboard": "",
|
||||
"copyToClipboardAsPng": "Kopierat till urklipp som PNG."
|
||||
}
|
||||
}
|
||||
|
@ -68,7 +68,7 @@
|
||||
"layers": "Katmanlar",
|
||||
"actions": "Eylemler",
|
||||
"language": "Dil",
|
||||
"liveCollaboration": "",
|
||||
"createRoom": "Ortak çalışma ortamını paylaş",
|
||||
"duplicateSelection": "Çoğalt",
|
||||
"untitled": "Adsız",
|
||||
"name": "İsim",
|
||||
@ -77,7 +77,7 @@
|
||||
"group": "Seçimi grup yap",
|
||||
"ungroup": "Seçilen grubu dağıt",
|
||||
"collaborators": "Ortaklar",
|
||||
"showGrid": "",
|
||||
"gridMode": "Izgara modu",
|
||||
"addToLibrary": "Kütüphaneye ekle",
|
||||
"removeFromLibrary": "Kütüphaneden kaldır",
|
||||
"libraryLoadingMessage": "Kütüphane yükleniyor…",
|
||||
@ -117,7 +117,7 @@
|
||||
"edit": "Düzenle",
|
||||
"undo": "Geri Al",
|
||||
"redo": "Yeniden yap",
|
||||
"resetLibrary": "",
|
||||
"roomDialog": "Ortak çalışma ortamı yarat",
|
||||
"createNewRoom": "Yeni oda oluştur",
|
||||
"fullScreen": "Tam ekran",
|
||||
"darkMode": "Koyu tema",
|
||||
@ -140,8 +140,7 @@
|
||||
"errorLoadingLibrary": "Üçüncü taraf kitaplığı yüklerken bir hata oluştu.",
|
||||
"confirmAddLibrary": "Bu, kitaplığınıza {{numShapes}} tane şekil ekleyecek. Emin misiniz?",
|
||||
"imageDoesNotContainScene": "Resim ekleme şuan için desteklenmiyor.\nBir sahneyi içeri aktarmak mı istediniz? Bu dosya herhangi bir sahne içeriyor gibi durmuyor. Çıktı alırken sahneyi dahil ettiniz mi?",
|
||||
"cannotRestoreFromImage": "Sahne bu dosyadan oluşturulamıyor",
|
||||
"resetLibrary": ""
|
||||
"cannotRestoreFromImage": "Sahne bu dosyadan oluşturulamıyor"
|
||||
},
|
||||
"toolBar": {
|
||||
"selection": "Seçme",
|
||||
@ -244,8 +243,6 @@
|
||||
"toast": {
|
||||
"copyStyles": "",
|
||||
"copyToClipboard": "",
|
||||
"copyToClipboardAsPng": "",
|
||||
"fileSaved": "",
|
||||
"fileSavedToFilename": ""
|
||||
"copyToClipboardAsPng": ""
|
||||
}
|
||||
}
|
||||
|
@ -68,7 +68,7 @@
|
||||
"layers": "Шари",
|
||||
"actions": "Дії",
|
||||
"language": "Мова",
|
||||
"liveCollaboration": "",
|
||||
"createRoom": "Поділитися сесією для спільної роботи",
|
||||
"duplicateSelection": "Дублювати",
|
||||
"untitled": "Без назви",
|
||||
"name": "Ім’я",
|
||||
@ -77,7 +77,7 @@
|
||||
"group": "Групувати виділене",
|
||||
"ungroup": "Розгрупувати виділене",
|
||||
"collaborators": "Співавтори",
|
||||
"showGrid": "Показати сітку",
|
||||
"gridMode": "Режим сітки",
|
||||
"addToLibrary": "Додати до бібліотеки",
|
||||
"removeFromLibrary": "Видалити з бібліотеки",
|
||||
"libraryLoadingMessage": "Завантажити бібліотеку…",
|
||||
@ -92,7 +92,7 @@
|
||||
"centerHorizontally": "Центрувати по горизонталі",
|
||||
"distributeHorizontally": "Розподілити по горизонталі",
|
||||
"distributeVertically": "Розподілити вертикально",
|
||||
"viewMode": "Режим перегляду"
|
||||
"viewMode": ""
|
||||
},
|
||||
"buttons": {
|
||||
"clearReset": "Очистити полотно",
|
||||
@ -117,7 +117,7 @@
|
||||
"edit": "Редагувати",
|
||||
"undo": "Відмінити",
|
||||
"redo": "Повторити",
|
||||
"resetLibrary": "",
|
||||
"roomDialog": "Відкрити сесію спільної роботи",
|
||||
"createNewRoom": "Створити нову кімнату",
|
||||
"fullScreen": "Повноекранний режим",
|
||||
"darkMode": "Темний режим",
|
||||
@ -136,12 +136,11 @@
|
||||
"decryptFailed": "Не вдалося розшифрувати дані.",
|
||||
"uploadedSecurly": "Це завантаження було захищене наскрізним шифруванням, а це означає що сервер Excalidraw та інші не зможуть прочитати вміст.",
|
||||
"loadSceneOverridePrompt": "Завантаження зовнішнього креслення замінить ваш наявний контент. Продовжити?",
|
||||
"collabStopOverridePrompt": "Зупинка сесії перезапише ваш попередній, локально збережений малюнок. Ви впевнені?\n\n(Якщо ви хочете зберегти локальний малюнок, просто закрийте замість нього вкладку браузера.)",
|
||||
"collabStopOverridePrompt": "",
|
||||
"errorLoadingLibrary": "Помилка при завантаженні сторонньої бібліотеки.",
|
||||
"confirmAddLibrary": "Це призведе до додавання {{numShapes}} фігур до вашої бібліотеки. Ви впевнені?",
|
||||
"imageDoesNotContainScene": "Імпортування зображень на даний момент не підтримується.\n\nЧи хочете ви імпортувати сцену? Це зображення не містить ніяких даних сцен. Ви увімкнули це під час експорту?",
|
||||
"cannotRestoreFromImage": "Сцена не може бути відновлена з цього файлу зображення",
|
||||
"resetLibrary": ""
|
||||
"cannotRestoreFromImage": "Сцена не може бути відновлена з цього файлу зображення"
|
||||
},
|
||||
"toolBar": {
|
||||
"selection": "Виділення",
|
||||
@ -236,16 +235,14 @@
|
||||
"storage": "Сховище",
|
||||
"title": "Статистика",
|
||||
"total": "Всього",
|
||||
"version": "Версія",
|
||||
"versionCopy": "Натисніть, щоб скопіювати",
|
||||
"versionNotAvailable": "Версія недоступна",
|
||||
"version": "",
|
||||
"versionCopy": "",
|
||||
"versionNotAvailable": "",
|
||||
"width": "Ширина"
|
||||
},
|
||||
"toast": {
|
||||
"copyStyles": "Скопійовані стилі.",
|
||||
"copyToClipboard": "Скопіювати до буферу обміну.",
|
||||
"copyToClipboardAsPng": "Скопійовано в буфер обміну як PNG.",
|
||||
"fileSaved": "Файл збережено.",
|
||||
"fileSavedToFilename": "Збережено в {filename}"
|
||||
"copyToClipboard": "",
|
||||
"copyToClipboardAsPng": "Скопійовано в буфер обміну як PNG."
|
||||
}
|
||||
}
|
||||
|
@ -68,7 +68,7 @@
|
||||
"layers": "图层",
|
||||
"actions": "操作",
|
||||
"language": "语言",
|
||||
"liveCollaboration": "",
|
||||
"createRoom": "分享实时协作会议",
|
||||
"duplicateSelection": "复制",
|
||||
"untitled": "无标题",
|
||||
"name": "名字",
|
||||
@ -77,7 +77,7 @@
|
||||
"group": "组选",
|
||||
"ungroup": "取消组选",
|
||||
"collaborators": "协作者",
|
||||
"showGrid": "",
|
||||
"gridMode": "网格模式",
|
||||
"addToLibrary": "添加到库中",
|
||||
"removeFromLibrary": "从库中移除",
|
||||
"libraryLoadingMessage": "正在加载库…",
|
||||
@ -117,7 +117,7 @@
|
||||
"edit": "编辑",
|
||||
"undo": "撤销",
|
||||
"redo": "重做",
|
||||
"resetLibrary": "",
|
||||
"roomDialog": "开始实时协作",
|
||||
"createNewRoom": "新建会议室",
|
||||
"fullScreen": "全屏",
|
||||
"darkMode": "暗色主题",
|
||||
@ -140,8 +140,7 @@
|
||||
"errorLoadingLibrary": "加载第三方库时出错。",
|
||||
"confirmAddLibrary": "这将添加 {{numShapes}} 个形状到您的库。您确定吗?",
|
||||
"imageDoesNotContainScene": "当前不支持导入图片。\n\n您想要导入画布数据吗?此图像似乎不包含任何画布数据。您是否在导出过程中启用了嵌入画布的选项?",
|
||||
"cannotRestoreFromImage": "无法从此图像文件恢复画布",
|
||||
"resetLibrary": ""
|
||||
"cannotRestoreFromImage": "无法从此图像文件恢复画布"
|
||||
},
|
||||
"toolBar": {
|
||||
"selection": "选择",
|
||||
@ -244,8 +243,6 @@
|
||||
"toast": {
|
||||
"copyStyles": "复制样式",
|
||||
"copyToClipboard": "",
|
||||
"copyToClipboardAsPng": "复制为 PNG 到剪贴板",
|
||||
"fileSaved": "",
|
||||
"fileSavedToFilename": ""
|
||||
"copyToClipboardAsPng": "复制为 PNG 到剪贴板"
|
||||
}
|
||||
}
|
||||
|
@ -68,7 +68,7 @@
|
||||
"layers": "圖層",
|
||||
"actions": "動作",
|
||||
"language": "語言",
|
||||
"liveCollaboration": "即時協作",
|
||||
"createRoom": "建立新協作會議室",
|
||||
"duplicateSelection": "複製",
|
||||
"untitled": "無標題",
|
||||
"name": "名稱",
|
||||
@ -77,7 +77,7 @@
|
||||
"group": "建立群組",
|
||||
"ungroup": "取消群組",
|
||||
"collaborators": "協作者",
|
||||
"showGrid": "顯示格線",
|
||||
"gridMode": "網格模式",
|
||||
"addToLibrary": "加入資料庫",
|
||||
"removeFromLibrary": "從資料庫中移除",
|
||||
"libraryLoadingMessage": "資料庫讀取中…",
|
||||
@ -117,7 +117,7 @@
|
||||
"edit": "編輯",
|
||||
"undo": "復原",
|
||||
"redo": "重做",
|
||||
"resetLibrary": "重設資料庫",
|
||||
"roomDialog": "開始即時協作",
|
||||
"createNewRoom": "建立新協作會議室",
|
||||
"fullScreen": "全螢幕",
|
||||
"darkMode": "深色模式",
|
||||
@ -140,8 +140,7 @@
|
||||
"errorLoadingLibrary": "載入第三方套件時出現錯誤。",
|
||||
"confirmAddLibrary": "這將會將 {{numShapes}} 個圖形加入你的資料庫,你確定嗎?",
|
||||
"imageDoesNotContainScene": "目前尚不支援載入圖片。\n您是否要載入場景?此圖片中並無任何場景資料,輸出時是否有選擇包含?",
|
||||
"cannotRestoreFromImage": "無法由此檔案回復場景。",
|
||||
"resetLibrary": "這會清除您的資料庫,是否確定?"
|
||||
"cannotRestoreFromImage": "無法由此檔案回復場景。"
|
||||
},
|
||||
"toolBar": {
|
||||
"selection": "選取",
|
||||
@ -244,8 +243,6 @@
|
||||
"toast": {
|
||||
"copyStyles": "已複製樣式",
|
||||
"copyToClipboard": "複製至剪貼簿。",
|
||||
"copyToClipboardAsPng": "已複製 PNG 至剪貼簿",
|
||||
"fileSaved": "已儲存檔案。",
|
||||
"fileSavedToFilename": "儲存為 {filename}"
|
||||
"copyToClipboardAsPng": "已複製 PNG 至剪貼簿"
|
||||
}
|
||||
}
|
||||
|
15
src/math.ts
15
src/math.ts
@ -1,4 +1,4 @@
|
||||
import { NormalizedZoomValue, Point, Zoom } from "./types";
|
||||
import { Point } from "./types";
|
||||
import { LINE_CONFIRM_THRESHOLD } from "./constants";
|
||||
import { ExcalidrawLinearElement } from "./element/types";
|
||||
|
||||
@ -147,16 +147,13 @@ export const centerPoint = (a: Point, b: Point): Point => {
|
||||
// to be considered a loop
|
||||
export const isPathALoop = (
|
||||
points: ExcalidrawLinearElement["points"],
|
||||
/** supply if you want the loop detection to account for current zoom */
|
||||
zoomValue: Zoom["value"] = 1 as NormalizedZoomValue,
|
||||
): boolean => {
|
||||
if (points.length >= 3) {
|
||||
const [first, last] = [points[0], points[points.length - 1]];
|
||||
const distance = distance2d(first[0], first[1], last[0], last[1]);
|
||||
|
||||
// Adjusting LINE_CONFIRM_THRESHOLD to current zoom so that when zoomed in
|
||||
// really close we make the threshold smaller, and vice versa.
|
||||
return distance <= LINE_CONFIRM_THRESHOLD / zoomValue;
|
||||
const [firstPoint, lastPoint] = [points[0], points[points.length - 1]];
|
||||
return (
|
||||
distance2d(firstPoint[0], firstPoint[1], lastPoint[0], lastPoint[1]) <=
|
||||
LINE_CONFIRM_THRESHOLD
|
||||
);
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
@ -18,97 +18,22 @@ Please add the latest change on the top under the correct section.
|
||||
|
||||
### Features
|
||||
|
||||
- Export [`restore`](https://github.com/excalidraw/excalidraw/blob/master/src/data/restore.ts#L182), [`restoreAppState`](https://github.com/excalidraw/excalidraw/blob/master/src/data/restore.ts#L144) and [`restoreElements`](https://github.com/excalidraw/excalidraw/blob/master/src/data/restore.ts#L128) to host
|
||||
|
||||
### Fixes
|
||||
|
||||
- Show user state only when [userState](https://github.com/excalidraw/excalidraw/blob/master/src/types.ts#L35) is passed on remote pointers during collaboration [#3050](https://github.com/excalidraw/excalidraw/pull/3050)
|
||||
|
||||
## 0.3.1
|
||||
|
||||
## Excalidraw API
|
||||
|
||||
### Fixes
|
||||
|
||||
- Support Excalidraw inside scrollable container [#3018](https://github.com/excalidraw/excalidraw/pull/3018)
|
||||
|
||||
## Excalidraw Library
|
||||
|
||||
### Fixes
|
||||
|
||||
- Allow to toggle between modes when view only mode to make UI consistent [#3009](https://github.com/excalidraw/excalidraw/pull/3009)
|
||||
|
||||
## 0.3.0
|
||||
|
||||
## Excalidraw API
|
||||
|
||||
### Features
|
||||
|
||||
- Allow host to pass [color](https://github.com/excalidraw/excalidraw/blob/master/src/types.ts#L36) for [collaborator](https://github.com/excalidraw/excalidraw/blob/master/src/types.ts#L27) [#2943](https://github.com/excalidraw/excalidraw/pull/2943). The unused prop `user` is now removed.
|
||||
- Add `zenModeEnabled` and `gridModeEnabled` prop which enables zen mode and grid mode respectively [#2901](https://github.com/excalidraw/excalidraw/pull/2901). When this prop is used, the zen mode / grid mode will be fully controlled by the host app.
|
||||
- Allow host to pass [userState](https://github.com/excalidraw/excalidraw/blob/6967d8c9851c65bb8873e2f97387749976bbe326/src/types.ts#L35) for [collaborator](https://github.com/excalidraw/excalidraw/blob/master/src/types.ts#L27) to show the current user state [#2877](https://github.com/excalidraw/excalidraw/pull/2877).
|
||||
- Add `viewModeEnabled` prop which enabled the view mode [#2840](https://github.com/excalidraw/excalidraw/pull/2840). When this prop is used, the view mode will not show up in context menu is so it is fully controlled by host.
|
||||
- Expose `getAppState` on `excalidrawRef` [#2834](https://github.com/excalidraw/excalidraw/pull/2834).
|
||||
|
||||
### Build
|
||||
|
||||
- Remove publicPath so host can use `__webpack_public_path__` to host the assets[#2835](https://github.com/excalidraw/excalidraw/pull/2835)
|
||||
|
||||
## Excalidraw Library
|
||||
|
||||
### Features
|
||||
|
||||
- Add the ability to clear library [#2997](https://github.com/excalidraw/excalidraw/pull/2997)
|
||||
- Updates to Collaboration and RTL UX [#2994](https://github.com/excalidraw/excalidraw/pull/2994)
|
||||
- Show toast when saving to existing file [#2988](https://github.com/excalidraw/excalidraw/pull/2988)
|
||||
- Support supplying custom scale when exporting canvas [#2904](https://github.com/excalidraw/excalidraw/pull/2904)
|
||||
- Show version in the stats dialog [#2908](https://github.com/excalidraw/excalidraw/pull/2908)
|
||||
- Add idle detection to collaboration feature [#2877](https://github.com/excalidraw/excalidraw/pull/2877)
|
||||
- Add view mode in Excalidraw [#2840](https://github.com/excalidraw/excalidraw/pull/2840)
|
||||
- Increase max zoom [#2881](https://github.com/excalidraw/excalidraw/pull/2881)
|
||||
- Remove copy & paste from context menu on desktop [#2872](https://github.com/excalidraw/excalidraw/pull/2872)
|
||||
- Add separators on context menu [#2659](https://github.com/excalidraw/excalidraw/pull/2659)
|
||||
- Add ctrl-y to redo [#2831](https://github.com/excalidraw/excalidraw/pull/2831)
|
||||
- Add view mode [#2840](https://github.com/excalidraw/excalidraw/pull/2840).
|
||||
- Remove `copy`, `cut`, and `paste` actions from contextmenu [#2872](https://github.com/excalidraw/excalidraw/pull/2872)
|
||||
- Support `Ctrl-Y` shortcut to redo on Windows [#2831](https://github.com/excalidraw/excalidraw/pull/2831).
|
||||
|
||||
### Fixes
|
||||
|
||||
- Refresh wysiwyg position on canvas resize [#3008](https://github.com/excalidraw/excalidraw/pull/3008)
|
||||
- Update the `lang` attribute with the current lang. [#2995](https://github.com/excalidraw/excalidraw/pull/2995)
|
||||
- Rename 'Grid mode' to 'Show grid' [#2944](https://github.com/excalidraw/excalidraw/pull/2944)
|
||||
- Deal with users on systems that don't handle emoji [#2941](https://github.com/excalidraw/excalidraw/pull/2941)
|
||||
- Mobile toolbar tooltip regression [#2939](https://github.com/excalidraw/excalidraw/pull/2939)
|
||||
- Hide collaborator list on mobile if empty [#2938](https://github.com/excalidraw/excalidraw/pull/2938)
|
||||
- Toolbar unnecessarily eats too much width [#2924](https://github.com/excalidraw/excalidraw/pull/2924)
|
||||
- Mistakenly hardcoding scale [#2925](https://github.com/excalidraw/excalidraw/pull/2925)
|
||||
- Text editor not visible in dark mode [#2920](https://github.com/excalidraw/excalidraw/pull/2920)
|
||||
- Incorrect z-index of text editor [#2914](https://github.com/excalidraw/excalidraw/pull/2914)
|
||||
- Make scrollbars draggable when offsets are set [#2916](https://github.com/excalidraw/excalidraw/pull/2916)
|
||||
- Pointer-events being disabled on free-draw [#2912](https://github.com/excalidraw/excalidraw/pull/2912)
|
||||
- Track zenmode and grid mode usage [#2900](https://github.com/excalidraw/excalidraw/pull/2900)
|
||||
- Disable UI pointer-events on canvas drag [#2856](https://github.com/excalidraw/excalidraw/pull/2856)
|
||||
- Stop flooring scroll positions [#2883](https://github.com/excalidraw/excalidraw/pull/2883)
|
||||
- Apply initialData appState for zenmode and grid stats and refactor check param for actions [#2871](https://github.com/excalidraw/excalidraw/pull/2871)
|
||||
- Show correct state of Nerd stats in context menu when nerd stats dialog closed [#2874](https://github.com/excalidraw/excalidraw/pull/2874)
|
||||
- Remote pointers not accounting for offset [#2855](https://github.com/excalidraw/excalidraw/pull/2855)
|
||||
- Toggle help dialog when "shift+?" is pressed [#2828](https://github.com/excalidraw/excalidraw/pull/2828)
|
||||
- Add safe check for process so Excalidraw can be loaded via script [#2824](https://github.com/excalidraw/excalidraw/pull/2824)
|
||||
- Fix UI pointer-events not disabled when dragging on canvas [#2856](https://github.com/excalidraw/excalidraw/pull/2856).
|
||||
- Fix remote pointers not accounting for offset [#2855](https://github.com/excalidraw/excalidraw/pull/2855).
|
||||
|
||||
### Refactor
|
||||
|
||||
- Remove duplicate key handling [#2878](https://github.com/excalidraw/excalidraw/pull/2878)
|
||||
- Reuse scss variables in js for SSOT [#2867](https://github.com/excalidraw/excalidraw/pull/2867)
|
||||
- Rename browser-nativefs to browser-fs-access [#2862](https://github.com/excalidraw/excalidraw/pull/2862)
|
||||
- Rewrite collabWrapper to remove TDZs and simplify [#2834](https://github.com/excalidraw/excalidraw/pull/2834)
|
||||
|
||||
### Chore
|
||||
|
||||
- Use `Sentence case` for `Live collaboration`
|
||||
|
||||
## 0.2.1
|
||||
|
||||
## Excalidraw API
|
||||
|
@ -18,15 +18,7 @@ yarn add react react-dom @excalidraw/excalidraw
|
||||
|
||||
After installation you will see a folder `excalidraw-assets` in `dist` directory which contains the assets needed for this app.
|
||||
|
||||
Move the folder `excalidraw-assets` to the path where your assets are served.
|
||||
|
||||
By default it will try to load the files from `{rootUrl}/excalidraw-assets/`
|
||||
|
||||
With **Webpack**, if you want to load the files from different path you can use <pre><a href="https://webpack.js.org/guides/public-path/#on-the-fly">`__webpack_public_path__`</a></pre>.
|
||||
|
||||
With **create-react-app**, the assets can be served from `public/static/js/excalidraw-assets`since CRA tries to load the assets from `{rootUrl}/static/js` path by default.
|
||||
|
||||
You can update the value of `PUBLIC_URL` if you want to serve it from a different URL.
|
||||
Move the folder `excalidraw-assets` to the path where your assets are served. In the example its served from `public/excalidraw-assets`
|
||||
|
||||
### Demo
|
||||
|
||||
@ -34,43 +26,31 @@ You can update the value of `PUBLIC_URL` if you want to serve it from a differen
|
||||
|
||||
### Usage
|
||||
|
||||
1. If you are using a Web bundler (for instance, Webpack), you can import it as an ES6 module as shown below
|
||||
|
||||
```js
|
||||
import React, { useEffect, useState, useRef } from "react";
|
||||
import React, { useEffect, useState, createRef } from "react";
|
||||
import Excalidraw from "@excalidraw/excalidraw";
|
||||
import InitialData from "./initialData";
|
||||
|
||||
import "./styles.scss";
|
||||
import "./styles.css";
|
||||
|
||||
export default function App() {
|
||||
const excalidrawRef = useRef(null);
|
||||
const excalidrawWrapperRef = useRef(null);
|
||||
const excalidrawRef = createRef();
|
||||
|
||||
const [dimensions, setDimensions] = useState({
|
||||
width: undefined,
|
||||
height: undefined,
|
||||
width: window.innerWidth,
|
||||
height: window.innerHeight,
|
||||
});
|
||||
|
||||
const [viewModeEnabled, setViewModeEnabled] = useState(false);
|
||||
const [zenModeEnabled, setZenModeEnabled] = useState(false);
|
||||
const [gridModeEnabled, setGridModeEnabled] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
setDimensions({
|
||||
width: excalidrawWrapperRef.current.getBoundingClientRect().width,
|
||||
height: excalidrawWrapperRef.current.getBoundingClientRect().height,
|
||||
});
|
||||
const onResize = () => {
|
||||
setDimensions({
|
||||
width: excalidrawWrapperRef.current.getBoundingClientRect().width,
|
||||
height: excalidrawWrapperRef.current.getBoundingClientRect().height,
|
||||
width: window.innerWidth,
|
||||
height: window.innerHeight,
|
||||
});
|
||||
};
|
||||
|
||||
window.addEventListener("resize", onResize);
|
||||
|
||||
return () => window.removeEventListener("resize", onResize);
|
||||
}, [excalidrawWrapperRef]);
|
||||
}, []);
|
||||
|
||||
const updateScene = () => {
|
||||
const sceneData = {
|
||||
@ -106,60 +86,31 @@ export default function App() {
|
||||
|
||||
return (
|
||||
<div className="App">
|
||||
<h1> Excalidraw Example</h1>
|
||||
<div className="button-wrapper">
|
||||
<button className="update-scene" onClick={updateScene}>
|
||||
Update Scene
|
||||
</button>
|
||||
<button
|
||||
className="reset-scene"
|
||||
onClick={() => {
|
||||
excalidrawRef.current.resetScene();
|
||||
}}
|
||||
>
|
||||
Reset Scene
|
||||
</button>
|
||||
<label>
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={viewModeEnabled}
|
||||
onChange={() => setViewModeEnabled(!viewModeEnabled)}
|
||||
/>
|
||||
View mode
|
||||
</label>
|
||||
<label>
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={zenModeEnabled}
|
||||
onChange={() => setZenModeEnabled(!zenModeEnabled)}
|
||||
/>
|
||||
Zen mode
|
||||
</label>
|
||||
<label>
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={gridModeEnabled}
|
||||
onChange={() => setGridModeEnabled(!gridModeEnabled)}
|
||||
/>
|
||||
Grid mode
|
||||
</label>
|
||||
</div>
|
||||
<div className="excalidraw-wrapper" ref={excalidrawWrapperRef}>
|
||||
<button className="update-scene" onClick={updateScene}>
|
||||
Update Scene
|
||||
</button>
|
||||
<button
|
||||
className="reset-scene"
|
||||
onClick={() => {
|
||||
excalidrawRef.current.resetScene();
|
||||
}}
|
||||
>
|
||||
Reset Scene
|
||||
</button>
|
||||
<div className="excalidraw-wrapper">
|
||||
<Excalidraw
|
||||
ref={excalidrawRef}
|
||||
width={dimensions.width}
|
||||
height={dimensions.height}
|
||||
initialData={InitialData}
|
||||
onChange={(elements, state) =>
|
||||
console.log("Elements :", elements, "State : ", state)
|
||||
}
|
||||
onPointerUpdate={(payload) => console.log(payload)}
|
||||
onCollabButtonClick={() =>
|
||||
window.alert("You clicked on collab button")
|
||||
}
|
||||
viewModeEnabled={viewModeEnabled}
|
||||
zenModeEnabled={zenModeEnabled}
|
||||
gridModeEnabled={gridModeEnabled}
|
||||
onChange={(elements, state) => {
|
||||
console.log("Latest elements:", elements, "Latest state:", state);
|
||||
}}
|
||||
user={{ name: "Excalidraw User" }}
|
||||
onPointerUpdate={(pointerData) => console.log(pointerData)}
|
||||
onCollabButtonClick={() => {
|
||||
window.alert("You clicked on collab button");
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@ -169,68 +120,6 @@ export default function App() {
|
||||
|
||||
[](https://codesandbox.io/s/excalidraw-ehlz3?fontsize=14&hidenavigation=1&theme=dark)
|
||||
|
||||
2. To use it in a browser directly:
|
||||
|
||||
You will need to make sure `react`, `react-dom` is available as shown below.
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Excalidraw in browser</title>
|
||||
<meta charset="UTF-8" />
|
||||
<script src="https://unpkg.com/react@16.14.0/umd/react.development.js"></script>
|
||||
<script src="https://unpkg.com/react-dom@16.13.1/umd/react-dom.development.js"></script>
|
||||
<script
|
||||
type="text/javascript"
|
||||
src="https://unpkg.com/@excalidraw/excalidraw@0.2.2/dist/excalidraw.min.js"
|
||||
></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="container">
|
||||
<h4>Excalidraw Embed Example</h4>
|
||||
<div id="app"></div>
|
||||
</div>
|
||||
|
||||
<script type="text/javascript" src="src/index.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
```js
|
||||
import "./styles.css";
|
||||
|
||||
const excalidrawWrapper = document.getElementById("app");
|
||||
|
||||
const props = {
|
||||
onChange: (data, appState) => {
|
||||
console.log(data, appState);
|
||||
},
|
||||
};
|
||||
|
||||
/*eslint-disable */
|
||||
ReactDOM.render(
|
||||
React.createElement(Excalidraw.default, props),
|
||||
excalidrawWrapper,
|
||||
);
|
||||
```
|
||||
|
||||
[](https://codesandbox.io/s/excalidraw-in-browser-tlqom?fontsize=14&hidenavigation=1&theme=dark)
|
||||
|
||||
Since Excalidraw doesn't support server side rendering yet so you will have to make sure the component is rendered once host is mounted.
|
||||
|
||||
```js
|
||||
import { useState, useEffect } from "react";
|
||||
export default function IndexPage() {
|
||||
const [Comp, setComp] = useState(null);
|
||||
useEffect(() => {
|
||||
import("@excalidraw/excalidraw").then((comp) => setComp(comp.default));
|
||||
});
|
||||
return <>{Comp && <Comp />}</>;
|
||||
}
|
||||
```
|
||||
|
||||
### Props
|
||||
|
||||
| Name | Type | Default | Description |
|
||||
@ -241,6 +130,7 @@ export default function IndexPage() {
|
||||
| [`offsetTop`](#offsetTop) | Number | `0` | top position relative to which Excalidraw should render |
|
||||
| [`onChange`](#onChange) | Function | | This callback is triggered whenever the component updates due to any change. This callback will receive the excalidraw elements and the current app state. |
|
||||
| [`initialData`](#initialData) | <pre>{elements?: <a href="https://github.com/excalidraw/excalidraw/blob/master/src/element/types.ts#L78">ExcalidrawElement[]</a>, appState?: <a href="https://github.com/excalidraw/excalidraw/blob/master/src/types.ts#L37">AppState<a> } </pre> | null | The initial data with which app loads. |
|
||||
| [`user`](#user) | `{ name?: string }` | | User details. The name refers to the name of the user to be shown |
|
||||
| [`excalidrawRef`](#excalidrawRef) | [`createRef`](https://reactjs.org/docs/refs-and-the-dom.html#creating-refs) or [`callbackRef`](https://reactjs.org/docs/refs-and-the-dom.html#callback-refs) or <pre>{ current: { readyPromise: <a href="https://github.com/excalidraw/excalidraw/blob/master/src/utils.ts#L317">resolvablePromise</a> } }</pre> | | Ref to be passed to Excalidraw |
|
||||
| [`onCollabButtonClick`](#onCollabButtonClick) | Function | | Callback to be triggered when the collab button is clicked |
|
||||
| [`isCollaborating`](#isCollaborating) | `boolean` | | This implies if the app is in collaboration mode |
|
||||
@ -248,9 +138,52 @@ export default function IndexPage() {
|
||||
| [`onExportToBackend`](#onExportToBackend) | Function | | Callback triggered when link button is clicked on export dialog |
|
||||
| [`langCode`](#langCode) | string | `en` | Language code string |
|
||||
| [`renderFooter `](#renderFooter) | Function | | Function that renders custom UI footer |
|
||||
| [`viewModeEnabled`](#viewModeEnabled) | boolean | | This implies if the app is in view mode. |
|
||||
| [`zenModeEnabled`](#zenModeEnabled) | boolean | | This implies if the zen mode is enabled |
|
||||
| [`gridModeEnabled`](#gridModeEnabled) | boolean | | This implies if the grid mode is enabled |
|
||||
| [`viewModeEnabled`](#viewModeEnabled) | boolean | false | This implies if the app is in view mode. |
|
||||
|
||||
### `Extra API's`
|
||||
|
||||
#### `getSceneVersion`
|
||||
|
||||
**How to use**
|
||||
|
||||
<pre>
|
||||
import { getSceneVersion } from "@excalidraw/excalidraw";
|
||||
getSceneVersion(elements: <a href="https://github.com/excalidraw/excalidraw/blob/master/src/element/types.ts#L78">ExcalidrawElement[]</a>)
|
||||
</pre>
|
||||
|
||||
This function returns the current scene version.
|
||||
|
||||
#### `getSyncableElements`
|
||||
|
||||
**_Signature_**
|
||||
|
||||
<pre>
|
||||
getSyncableElements(elements: <a href="https://github.com/excalidraw/excalidraw/blob/master/src/element/types.ts#L78">ExcalidrawElement[]</a>):<a href="https://github.com/excalidraw/excalidraw/blob/master/src/element/types.ts#L78">ExcalidrawElement[]</a>
|
||||
</pre>
|
||||
|
||||
**How to use**
|
||||
|
||||
```js
|
||||
import { getSyncableElements } from "@excalidraw/excalidraw";
|
||||
```
|
||||
|
||||
This function returns all the deleted elements of the scene.
|
||||
|
||||
### `getElementMap`
|
||||
|
||||
**_Signature_**
|
||||
|
||||
<pre>
|
||||
getElementsMap(elements: <a href="https://github.com/excalidraw/excalidraw/blob/master/src/element/types.ts#L78">ExcalidrawElement[]</a>): {[id: string]: <a href="https://github.com/excalidraw/excalidraw/blob/master/src/element/types.ts#L78">ExcalidrawElement</a>}
|
||||
</pre>
|
||||
|
||||
**How to use**
|
||||
|
||||
```js
|
||||
import { getElementsMap } from "@excalidraw/excalidraw";
|
||||
```
|
||||
|
||||
This function returns an object where each element is mapped to its id.
|
||||
|
||||
#### `width`
|
||||
|
||||
@ -322,6 +255,10 @@ This helps to load Excalidraw with `initialData`. It must be an object or a [pro
|
||||
|
||||
You might want to use this when you want to load excalidraw with some initial elements and app state.
|
||||
|
||||
#### `user`
|
||||
|
||||
This is the user name which shows during collaboration. Defaults to `{name: ''}`.
|
||||
|
||||
#### `excalidrawRef`
|
||||
|
||||
You can pass a `ref` when you want to access some excalidraw APIs. We expose the below APIs:
|
||||
@ -330,7 +267,7 @@ You can pass a `ref` when you want to access some excalidraw APIs. We expose the
|
||||
| --- | --- | --- |
|
||||
| ready | `boolean` | This is set to true once Excalidraw is rendered |
|
||||
| readyPromise | [resolvablePromise](https://github.com/excalidraw/excalidraw/blob/master/src/utils.ts#L317) | This promise will be resolved with the api once excalidraw has rendered. This will be helpful when you want do some action on the host app once this promise resolves. For this to work you will have to pass ref as shown [here](#readyPromise) |
|
||||
| updateScene | <pre>(<a href="https://github.com/excalidraw/excalidraw/blob/master/src/types.ts#L192">sceneData</a>)) => void </pre> | updates the scene with the sceneData |
|
||||
| updateScene | <pre>(<a href="https://github.com/excalidraw/excalidraw/blob/master/src/types.ts#L189">sceneData</a>)) => void </pre> | updates the scene with the sceneData |
|
||||
| resetScene | `({ resetLoadingState: boolean }) => void` | Resets the scene. If `resetLoadingState` is passed as true then it will also force set the loading state to false. |
|
||||
| getSceneElementsIncludingDeleted | <pre> () => <a href="https://github.com/excalidraw/excalidraw/blob/master/src/element/types.ts#L78">ExcalidrawElement[]</a></pre> | Returns all the elements including the deleted in the scene |
|
||||
| getSceneElements | <pre> () => <a href="https://github.com/excalidraw/excalidraw/blob/master/src/element/types.ts#L78">ExcalidrawElement[]</a></pre> | Returns all the elements excluding the deleted in the scene |
|
||||
@ -397,107 +334,4 @@ A function that renders (returns JSX) custom UI footer. For example, you can use
|
||||
|
||||
#### `viewModeEnabled`
|
||||
|
||||
This prop indicates whether the app is in `view mode`. When supplied, the value takes precedence over `intialData.appState.viewModeEnabled`, the `view mode` will be fully controlled by the host app, and users won't be able to toggle it from within the app.
|
||||
|
||||
#### `zenModeEnabled`
|
||||
|
||||
This prop indicates whether the app is in `zen mode`. When supplied, the value takes precedence over `intialData.appState.zenModeEnabled`, the `zen mode` will be fully controlled by the host app, and users won't be able to toggle it from within the app.
|
||||
|
||||
#### `gridModeEnabled`
|
||||
|
||||
This prop indicates whether the shows the grid. When supplied, the value takes precedence over `intialData.appState.gridModeEnabled`, the grid will be fully controlled by the host app, and users won't be able to toggle it from within the app.
|
||||
|
||||
### Extra API's
|
||||
|
||||
#### `getSceneVersion`
|
||||
|
||||
**How to use**
|
||||
|
||||
<pre>
|
||||
import { getSceneVersion } from "@excalidraw/excalidraw";
|
||||
getSceneVersion(elements: <a href="https://github.com/excalidraw/excalidraw/blob/master/src/element/types.ts#L78">ExcalidrawElement[]</a>)
|
||||
</pre>
|
||||
|
||||
This function returns the current scene version.
|
||||
|
||||
#### `getSyncableElements`
|
||||
|
||||
**_Signature_**
|
||||
|
||||
<pre>
|
||||
getSyncableElements(elements: <a href="https://github.com/excalidraw/excalidraw/blob/master/src/element/types.ts#L78">ExcalidrawElement[]</a>):<a href="https://github.com/excalidraw/excalidraw/blob/master/src/element/types.ts#L78">ExcalidrawElement[]</a>
|
||||
</pre>
|
||||
|
||||
**How to use**
|
||||
|
||||
```js
|
||||
import { getSyncableElements } from "@excalidraw/excalidraw";
|
||||
```
|
||||
|
||||
This function returns all the deleted elements of the scene.
|
||||
|
||||
#### `getElementMap`
|
||||
|
||||
**_Signature_**
|
||||
|
||||
<pre>
|
||||
getElementsMap(elements: <a href="https://github.com/excalidraw/excalidraw/blob/master/src/element/types.ts#L78">ExcalidrawElement[]</a>): {[id: string]: <a href="https://github.com/excalidraw/excalidraw/blob/master/src/element/types.ts#L78">ExcalidrawElement</a>}
|
||||
</pre>
|
||||
|
||||
**How to use**
|
||||
|
||||
```js
|
||||
import { getElementsMap } from "@excalidraw/excalidraw";
|
||||
```
|
||||
|
||||
This function returns an object where each element is mapped to its id.
|
||||
|
||||
**_The below api's will be available in [next version](https://github.com/excalidraw/excalidraw/blob/master/src/packages/excalidraw/CHANGELOG.md#unreleased)_**
|
||||
|
||||
#### `restoreAppState`
|
||||
|
||||
**_Signature_**
|
||||
|
||||
<pre>
|
||||
restoreAppState(appState: <a href="https://github.com/excalidraw/excalidraw/blob/master/src/data/types.ts#L17">ImportedDataState["appState"]</a>, localAppState: Partial<<a href="https://github.com/excalidraw/excalidraw/blob/master/src/types.ts#L37">AppState</a>> | null): <a href="https://github.com/excalidraw/excalidraw/blob/master/src/types.ts#L37">AppState</a>
|
||||
</pre>
|
||||
|
||||
**_How to use_**
|
||||
|
||||
```js
|
||||
import { restoreAppState } from "@excalidraw/excalidraw";
|
||||
```
|
||||
|
||||
This function will make sure all the keys have appropriate values in [appState](https://github.com/excalidraw/excalidraw/blob/master/src/types.ts#L37) and if any key is missing, it will be set to default value. If you pass `localAppState`, `localAppState` value will be preferred over the `appState` passed in params.
|
||||
|
||||
#### `restoreElements`
|
||||
|
||||
**_Signature_**
|
||||
|
||||
<pre>
|
||||
restoreElements(elements: <a href="https://github.com/excalidraw/excalidraw/blob/master/src/data/types.ts#L16">ImportedDataState["elements"]</a>): <a href="https://github.com/excalidraw/excalidraw/blob/master/src/element/types.ts#L78">ExcalidrawElement[]</a>
|
||||
</pre>
|
||||
|
||||
**_How to use_**
|
||||
|
||||
```js
|
||||
import { restoreElements } from "@excalidraw/excalidraw";
|
||||
```
|
||||
|
||||
This function will make sure all properties of element is correctly set and if any attribute is missing, it will be set to default value.
|
||||
|
||||
#### `restore`
|
||||
|
||||
**_Signature_**
|
||||
|
||||
<pre>
|
||||
restoreElements(data: <a href="https://github.com/excalidraw/excalidraw/blob/master/src/data/types.ts#L12">ImportedDataState</a>): <a href="https://github.com/excalidraw/excalidraw/blob/master/src/data/types.ts#L4">DataState</a>
|
||||
</pre>
|
||||
|
||||
**_How to use_**
|
||||
|
||||
```js
|
||||
import { restore } from "@excalidraw/excalidraw";
|
||||
```
|
||||
|
||||
This function makes sure elements and state is set to appropriate values and set to default value if not present. It is combination of [restoreElements](#restoreElements) and [restoreAppState](#restoreAppState)
|
||||
This prop indicates if the app is in `view mode`. When this prop is used, the `view mode` will not show up in context menu is so it is fully controlled by host. Also the value of this prop if passed will be used over the value of `intialData.appState.viewModeEnabled`
|
||||
|
@ -18,6 +18,7 @@ const Excalidraw = (props: ExcalidrawProps) => {
|
||||
offsetTop,
|
||||
onChange,
|
||||
initialData,
|
||||
user,
|
||||
excalidrawRef,
|
||||
onCollabButtonClick,
|
||||
isCollaborating,
|
||||
@ -26,8 +27,6 @@ const Excalidraw = (props: ExcalidrawProps) => {
|
||||
renderFooter,
|
||||
langCode = defaultLang.code,
|
||||
viewModeEnabled,
|
||||
zenModeEnabled,
|
||||
gridModeEnabled,
|
||||
} = props;
|
||||
|
||||
useEffect(() => {
|
||||
@ -58,6 +57,7 @@ const Excalidraw = (props: ExcalidrawProps) => {
|
||||
offsetTop={offsetTop}
|
||||
onChange={onChange}
|
||||
initialData={initialData}
|
||||
user={user}
|
||||
excalidrawRef={excalidrawRef}
|
||||
onCollabButtonClick={onCollabButtonClick}
|
||||
isCollaborating={isCollaborating}
|
||||
@ -66,8 +66,6 @@ const Excalidraw = (props: ExcalidrawProps) => {
|
||||
renderFooter={renderFooter}
|
||||
langCode={langCode}
|
||||
viewModeEnabled={viewModeEnabled}
|
||||
zenModeEnabled={zenModeEnabled}
|
||||
gridModeEnabled={gridModeEnabled}
|
||||
/>
|
||||
</IsMobileProvider>
|
||||
</InitializeApp>
|
||||
@ -80,12 +78,13 @@ const areEqual = (
|
||||
prevProps: PublicExcalidrawProps,
|
||||
nextProps: PublicExcalidrawProps,
|
||||
) => {
|
||||
const { initialData: prevInitialData, ...prev } = prevProps;
|
||||
const { initialData: nextInitialData, ...next } = nextProps;
|
||||
const { initialData: prevInitialData, user: prevUser, ...prev } = prevProps;
|
||||
const { initialData: nextInitialData, user: nextUser, ...next } = nextProps;
|
||||
|
||||
const prevKeys = Object.keys(prevProps) as (keyof typeof prev)[];
|
||||
const nextKeys = Object.keys(nextProps) as (keyof typeof next)[];
|
||||
return (
|
||||
prevUser?.name === nextUser?.name &&
|
||||
prevKeys.length === nextKeys.length &&
|
||||
prevKeys.every((key) => prev[key] === next[key])
|
||||
);
|
||||
@ -106,4 +105,3 @@ export {
|
||||
getElementMap,
|
||||
} from "../../element";
|
||||
export { defaultLang, languages } from "../../i18n";
|
||||
export { restore, restoreAppState, restoreElements } from "../../data/restore";
|
||||
|
2162
src/packages/excalidraw/package-lock.json
generated
2162
src/packages/excalidraw/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "aakansha-excalidraw",
|
||||
"version": "0.4.3",
|
||||
"name": "@excalidraw/excalidraw",
|
||||
"version": "0.2.1",
|
||||
"main": "dist/excalidraw.min.js",
|
||||
"files": [
|
||||
"dist/*"
|
||||
@ -41,26 +41,26 @@
|
||||
"react-dom": "^17.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "7.12.16",
|
||||
"@babel/plugin-transform-arrow-functions": "7.12.13",
|
||||
"@babel/plugin-transform-async-to-generator": "7.12.13",
|
||||
"@babel/plugin-transform-runtime": "7.12.15",
|
||||
"@babel/plugin-transform-typescript": "7.12.16",
|
||||
"@babel/preset-env": "7.12.16",
|
||||
"@babel/preset-react": "7.12.13",
|
||||
"@babel/preset-typescript": "7.12.16",
|
||||
"@babel/core": "7.12.10",
|
||||
"@babel/plugin-transform-arrow-functions": "7.12.1",
|
||||
"@babel/plugin-transform-async-to-generator": "7.12.1",
|
||||
"@babel/plugin-transform-runtime": "7.12.10",
|
||||
"@babel/plugin-transform-typescript": "7.12.1",
|
||||
"@babel/preset-env": "7.12.11",
|
||||
"@babel/preset-react": "7.12.10",
|
||||
"@babel/preset-typescript": "7.12.7",
|
||||
"babel-loader": "8.2.2",
|
||||
"babel-plugin-transform-class-properties": "6.24.1",
|
||||
"cross-env": "7.0.3",
|
||||
"css-loader": "5.0.2",
|
||||
"css-loader": "5.0.1",
|
||||
"file-loader": "6.2.0",
|
||||
"mini-css-extract-plugin": "1.3.6",
|
||||
"sass-loader": "11.0.1",
|
||||
"mini-css-extract-plugin": "1.3.5",
|
||||
"sass-loader": "10.1.1",
|
||||
"terser-webpack-plugin": "5.1.1",
|
||||
"ts-loader": "8.0.17",
|
||||
"webpack": "5.21.2",
|
||||
"ts-loader": "8.0.14",
|
||||
"webpack": "5.19.0",
|
||||
"webpack-bundle-analyzer": "4.4.0",
|
||||
"webpack-cli": "4.5.0"
|
||||
"webpack-cli": "4.4.0"
|
||||
},
|
||||
"bugs": "https://github.com/excalidraw/excalidraw/issues",
|
||||
"repository": "https://github.com/excalidraw/excalidraw",
|
||||
|
@ -13,8 +13,8 @@ module.exports = {
|
||||
library: "Excalidraw",
|
||||
libraryTarget: "umd",
|
||||
filename: "[name].js",
|
||||
publicPath: "/",
|
||||
chunkFilename: "excalidraw-assets/[name].js",
|
||||
publicPath: "https://unpkg.com/aakansha-excalidraw@0.4.3/dist/",
|
||||
},
|
||||
resolve: {
|
||||
extensions: [".js", ".ts", ".tsx", ".css", ".scss"],
|
||||
|
1376
src/packages/utils/package-lock.json
generated
1376
src/packages/utils/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -34,21 +34,21 @@
|
||||
]
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "7.12.16",
|
||||
"@babel/plugin-transform-arrow-functions": "7.12.13",
|
||||
"@babel/plugin-transform-async-to-generator": "7.12.13",
|
||||
"@babel/core": "7.12.10",
|
||||
"@babel/plugin-transform-arrow-functions": "7.12.1",
|
||||
"@babel/plugin-transform-async-to-generator": "7.12.1",
|
||||
"@babel/plugin-transform-runtime": "^7.12.10",
|
||||
"@babel/plugin-transform-typescript": "7.12.16",
|
||||
"@babel/preset-env": "7.12.16",
|
||||
"@babel/preset-typescript": "7.12.16",
|
||||
"@babel/plugin-transform-typescript": "7.12.1",
|
||||
"@babel/preset-env": "7.12.11",
|
||||
"@babel/preset-typescript": "7.12.7",
|
||||
"babel-loader": "8.2.2",
|
||||
"babel-plugin-transform-class-properties": "6.24.1",
|
||||
"cross-env": "7.0.3",
|
||||
"file-loader": "6.2.0",
|
||||
"ts-loader": "8.0.17",
|
||||
"webpack": "5.21.2",
|
||||
"ts-loader": "8.0.14",
|
||||
"webpack": "5.19.0",
|
||||
"webpack-bundle-analyzer": "4.4.0",
|
||||
"webpack-cli": "4.5.0"
|
||||
"webpack-cli": "4.4.0"
|
||||
},
|
||||
"bugs": "https://github.com/excalidraw/excalidraw/issues",
|
||||
"repository": "https://github.com/excalidraw/excalidraw",
|
||||
|
@ -47,11 +47,9 @@ import {
|
||||
TransformHandles,
|
||||
TransformHandleType,
|
||||
} from "../element/transformHandles";
|
||||
import { viewportCoordsToSceneCoords, supportsEmoji } from "../utils";
|
||||
import { viewportCoordsToSceneCoords } from "../utils";
|
||||
import { UserIdleState } from "../excalidraw-app/collab/types";
|
||||
|
||||
const hasEmojiSupport = supportsEmoji();
|
||||
|
||||
const strokeRectWithRotation = (
|
||||
context: CanvasRenderingContext2D,
|
||||
x: number,
|
||||
@ -313,7 +311,7 @@ export const renderScene = (
|
||||
if (sceneState.remoteSelectedElementIds[element.id]) {
|
||||
selectionColors.push(
|
||||
...sceneState.remoteSelectedElementIds[element.id].map((socketId) => {
|
||||
const { background } = getClientColors(socketId, appState);
|
||||
const { background } = getClientColors(socketId);
|
||||
return background;
|
||||
}),
|
||||
);
|
||||
@ -441,7 +439,7 @@ export const renderScene = (
|
||||
y = Math.max(y, 0);
|
||||
y = Math.min(y, normalizedCanvasHeight - height);
|
||||
|
||||
const { background, stroke } = getClientColors(clientId, appState);
|
||||
const { background, stroke } = getClientColors(clientId);
|
||||
|
||||
const strokeStyle = context.strokeStyle;
|
||||
const fillStyle = context.fillStyle;
|
||||
@ -451,7 +449,7 @@ export const renderScene = (
|
||||
|
||||
const userState = sceneState.remotePointerUserStates[clientId];
|
||||
if (isOutOfBounds || userState === UserIdleState.AWAY) {
|
||||
context.globalAlpha = 0.48;
|
||||
context.globalAlpha = 0.2;
|
||||
}
|
||||
|
||||
if (
|
||||
@ -483,19 +481,13 @@ export const renderScene = (
|
||||
context.stroke();
|
||||
|
||||
const username = sceneState.remotePointerUsernames[clientId];
|
||||
|
||||
let idleState = "";
|
||||
if (userState === UserIdleState.AWAY) {
|
||||
idleState = hasEmojiSupport ? "⚫️" : ` (${UserIdleState.AWAY})`;
|
||||
} else if (userState === UserIdleState.IDLE) {
|
||||
idleState = hasEmojiSupport ? "💤" : ` (${UserIdleState.IDLE})`;
|
||||
} else if (userState === UserIdleState.ACTIVE) {
|
||||
idleState = hasEmojiSupport ? "🟢" : "";
|
||||
}
|
||||
|
||||
const usernameAndIdleState = `${
|
||||
username ? `${username} ` : ""
|
||||
}${idleState}`;
|
||||
const usernameAndIdleState = `${username ? `${username} ` : ""}${
|
||||
userState === UserIdleState.AWAY
|
||||
? "⚫️"
|
||||
: userState === UserIdleState.IDLE
|
||||
? "💤"
|
||||
: "🟢"
|
||||
}`;
|
||||
|
||||
if (!isOutOfBounds && usernameAndIdleState) {
|
||||
const offsetX = x + width;
|
||||
|
@ -1,89 +0,0 @@
|
||||
import React from "react";
|
||||
import { fireEvent, GlobalTestState, render } from "./test-utils";
|
||||
import Excalidraw from "../packages/excalidraw/index";
|
||||
import { queryByText } from "@testing-library/react";
|
||||
import { GRID_SIZE } from "../constants";
|
||||
|
||||
const { h } = window;
|
||||
|
||||
describe("<Excalidraw/>", () => {
|
||||
describe("Test zenModeEnabled prop", () => {
|
||||
it('should show exit zen mode button when zen mode is set and zen mode option in context menu when zenModeEnabled is "undefined"', async () => {
|
||||
const { container } = await render(<Excalidraw />);
|
||||
expect(
|
||||
container.getElementsByClassName("disable-zen-mode--visible").length,
|
||||
).toBe(0);
|
||||
expect(h.state.zenModeEnabled).toBe(false);
|
||||
|
||||
fireEvent.contextMenu(GlobalTestState.canvas, {
|
||||
button: 2,
|
||||
clientX: 1,
|
||||
clientY: 1,
|
||||
});
|
||||
const contextMenu = document.querySelector(".context-menu");
|
||||
fireEvent.click(queryByText(contextMenu as HTMLElement, "Zen mode")!);
|
||||
expect(h.state.zenModeEnabled).toBe(true);
|
||||
expect(
|
||||
container.getElementsByClassName("disable-zen-mode--visible").length,
|
||||
).toBe(1);
|
||||
});
|
||||
|
||||
it("should not show exit zen mode button and zen mode option in context menu when zenModeEnabled is set", async () => {
|
||||
const { container } = await render(<Excalidraw zenModeEnabled={true} />);
|
||||
expect(
|
||||
container.getElementsByClassName("disable-zen-mode--visible").length,
|
||||
).toBe(0);
|
||||
expect(h.state.zenModeEnabled).toBe(true);
|
||||
|
||||
fireEvent.contextMenu(GlobalTestState.canvas, {
|
||||
button: 2,
|
||||
clientX: 1,
|
||||
clientY: 1,
|
||||
});
|
||||
const contextMenu = document.querySelector(".context-menu");
|
||||
expect(queryByText(contextMenu as HTMLElement, "Zen mode")).toBe(null);
|
||||
expect(h.state.zenModeEnabled).toBe(true);
|
||||
expect(
|
||||
container.getElementsByClassName("disable-zen-mode--visible").length,
|
||||
).toBe(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe("Test gridModeEnabled prop", () => {
|
||||
it('should show grid mode in context menu when gridModeEnabled is "undefined"', async () => {
|
||||
const { container } = await render(<Excalidraw />);
|
||||
expect(h.state.gridSize).toBe(null);
|
||||
|
||||
expect(
|
||||
container.getElementsByClassName("disable-zen-mode--visible").length,
|
||||
).toBe(0);
|
||||
fireEvent.contextMenu(GlobalTestState.canvas, {
|
||||
button: 2,
|
||||
clientX: 1,
|
||||
clientY: 1,
|
||||
});
|
||||
const contextMenu = document.querySelector(".context-menu");
|
||||
fireEvent.click(queryByText(contextMenu as HTMLElement, "Show grid")!);
|
||||
expect(h.state.gridSize).toBe(GRID_SIZE);
|
||||
});
|
||||
|
||||
it('should not show grid mode in context menu when gridModeEnabled is not "undefined"', async () => {
|
||||
const { container } = await render(
|
||||
<Excalidraw gridModeEnabled={false} />,
|
||||
);
|
||||
expect(h.state.gridSize).toBe(null);
|
||||
|
||||
expect(
|
||||
container.getElementsByClassName("disable-zen-mode--visible").length,
|
||||
).toBe(0);
|
||||
fireEvent.contextMenu(GlobalTestState.canvas, {
|
||||
button: 2,
|
||||
clientX: 1,
|
||||
clientY: 1,
|
||||
});
|
||||
const contextMenu = document.querySelector(".context-menu");
|
||||
expect(queryByText(contextMenu as HTMLElement, "Show grid")).toBe(null);
|
||||
expect(h.state.gridSize).toBe(null);
|
||||
});
|
||||
});
|
||||
});
|
@ -33,10 +33,6 @@ export type Collaborator = {
|
||||
selectedElementIds?: AppState["selectedElementIds"];
|
||||
username?: string | null;
|
||||
userState?: UserIdleState;
|
||||
color?: {
|
||||
background: string;
|
||||
stroke: string;
|
||||
};
|
||||
};
|
||||
|
||||
export type AppState = {
|
||||
@ -170,6 +166,9 @@ export interface ExcalidrawProps {
|
||||
appState: AppState,
|
||||
) => void;
|
||||
initialData?: ImportedDataState | null | Promise<ImportedDataState | null>;
|
||||
user?: {
|
||||
name?: string | null;
|
||||
};
|
||||
excalidrawRef?: ForwardRef<ExcalidrawAPIRefValue>;
|
||||
onCollabButtonClick?: () => void;
|
||||
isCollaborating?: boolean;
|
||||
@ -186,8 +185,6 @@ export interface ExcalidrawProps {
|
||||
renderFooter?: (isMobile: boolean) => JSX.Element;
|
||||
langCode?: Language["code"];
|
||||
viewModeEnabled?: boolean;
|
||||
zenModeEnabled?: boolean;
|
||||
gridModeEnabled?: boolean;
|
||||
}
|
||||
|
||||
export type SceneData = {
|
||||
|
17
src/utils.ts
17
src/utils.ts
@ -369,20 +369,3 @@ export const getVersion = () => {
|
||||
DEFAULT_VERSION
|
||||
);
|
||||
};
|
||||
|
||||
// Adapted from https://github.com/Modernizr/Modernizr/blob/master/feature-detects/emoji.js
|
||||
export const supportsEmoji = () => {
|
||||
const canvas = document.createElement("canvas");
|
||||
const ctx = canvas.getContext("2d");
|
||||
if (!ctx) {
|
||||
return false;
|
||||
}
|
||||
const offset = 12;
|
||||
ctx.fillStyle = "#f00";
|
||||
ctx.textBaseline = "top";
|
||||
ctx.font = "32px Arial";
|
||||
// Modernizr used 🐨, but it is sort of supported on Windows 7.
|
||||
// Luckily 😀 isn't supported.
|
||||
ctx.fillText("😀", 0, 0);
|
||||
return ctx.getImageData(offset, offset, 1, 1).data[0] !== 0;
|
||||
};
|
||||
|
Reference in New Issue
Block a user