add excalidraw_embed into base repo (#2040)
Co-authored-by: Lipis <lipiridis@gmail.com>
This commit is contained in:
parent
80cbe13167
commit
ab7073abdb
@ -3,3 +3,4 @@ build/
|
|||||||
package-lock.json
|
package-lock.json
|
||||||
.vscode/
|
.vscode/
|
||||||
firebase/
|
firebase/
|
||||||
|
dist/
|
||||||
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -13,3 +13,4 @@ yarn-debug.log*
|
|||||||
yarn-error.log*
|
yarn-error.log*
|
||||||
yarn.lock
|
yarn.lock
|
||||||
.idea
|
.idea
|
||||||
|
dist/
|
||||||
|
@ -1,13 +0,0 @@
|
|||||||
/* http://www.eaglefonts.com/fg-virgil-ttf-131249.htm */
|
|
||||||
@font-face {
|
|
||||||
font-family: "Virgil";
|
|
||||||
src: url("FG_Virgil.woff2");
|
|
||||||
font-display: swap;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* https://github.com/microsoft/cascadia-code */
|
|
||||||
@font-face {
|
|
||||||
font-family: "Cascadia";
|
|
||||||
src: url("Cascadia.woff2");
|
|
||||||
font-display: swap;
|
|
||||||
}
|
|
@ -60,8 +60,6 @@
|
|||||||
<!-- OG tags require absolute url for images -->
|
<!-- OG tags require absolute url for images -->
|
||||||
<meta name="twitter:image" content="https://excalidraw.com/og-image.png" />
|
<meta name="twitter:image" content="https://excalidraw.com/og-image.png" />
|
||||||
<link rel="shortcut icon" href="favicon.ico" type="image/x-icon" />
|
<link rel="shortcut icon" href="favicon.ico" type="image/x-icon" />
|
||||||
<link rel="stylesheet" href="fonts.css" type="text/css" />
|
|
||||||
<link rel="stylesheet" href="app.css" type="text/css" />
|
|
||||||
|
|
||||||
<link
|
<link
|
||||||
rel="preload"
|
rel="preload"
|
||||||
|
@ -278,12 +278,13 @@ class App extends React.Component<ExcalidrawProps, AppState> {
|
|||||||
super(props);
|
super(props);
|
||||||
const defaultAppState = getDefaultAppState();
|
const defaultAppState = getDefaultAppState();
|
||||||
|
|
||||||
const { width, height } = props;
|
const { width, height, user } = props;
|
||||||
this.state = {
|
this.state = {
|
||||||
...defaultAppState,
|
...defaultAppState,
|
||||||
isLoading: true,
|
isLoading: true,
|
||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
|
username: user?.name || "",
|
||||||
...this.getCanvasOffsets(),
|
...this.getCanvasOffsets(),
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -334,6 +335,9 @@ class App extends React.Component<ExcalidrawProps, AppState> {
|
|||||||
onRoomCreate={this.openPortal}
|
onRoomCreate={this.openPortal}
|
||||||
onRoomDestroy={this.closePortal}
|
onRoomDestroy={this.closePortal}
|
||||||
onUsernameChange={(username) => {
|
onUsernameChange={(username) => {
|
||||||
|
if (this.props.onUsernameChange) {
|
||||||
|
this.props.onUsernameChange(username);
|
||||||
|
}
|
||||||
saveUsernameToLocalStorage(username);
|
saveUsernameToLocalStorage(username);
|
||||||
this.setState({
|
this.setState({
|
||||||
username,
|
username,
|
||||||
@ -501,12 +505,12 @@ class App extends React.Component<ExcalidrawProps, AppState> {
|
|||||||
this.setState({ isLoading: true });
|
this.setState({ isLoading: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
let scene = await loadScene(null);
|
let scene = await loadScene(null, null, this.props.initialData);
|
||||||
|
|
||||||
let isCollaborationScene = !!getCollaborationLinkData(window.location.href);
|
let isCollaborationScene = !!getCollaborationLinkData(window.location.href);
|
||||||
const isExternalScene = !!(id || jsonMatch || isCollaborationScene);
|
const isExternalScene = !!(id || jsonMatch || isCollaborationScene);
|
||||||
|
|
||||||
if (isExternalScene) {
|
if (isExternalScene && !this.props.initialData) {
|
||||||
if (
|
if (
|
||||||
this.shouldForceLoadScene(scene) ||
|
this.shouldForceLoadScene(scene) ||
|
||||||
window.confirm(t("alerts.loadSceneOverridePrompt"))
|
window.confirm(t("alerts.loadSceneOverridePrompt"))
|
||||||
@ -715,7 +719,7 @@ class App extends React.Component<ExcalidrawProps, AppState> {
|
|||||||
|
|
||||||
componentDidUpdate(prevProps: ExcalidrawProps, prevState: AppState) {
|
componentDidUpdate(prevProps: ExcalidrawProps, prevState: AppState) {
|
||||||
const { width: prevWidth, height: prevHeight } = prevProps;
|
const { width: prevWidth, height: prevHeight } = prevProps;
|
||||||
const { width: currentWidth, height: currentHeight } = this.props;
|
const { width: currentWidth, height: currentHeight, onChange } = this.props;
|
||||||
if (prevWidth !== currentWidth || prevHeight !== currentHeight) {
|
if (prevWidth !== currentWidth || prevHeight !== currentHeight) {
|
||||||
this.setState({
|
this.setState({
|
||||||
width: currentWidth,
|
width: currentWidth,
|
||||||
@ -847,6 +851,10 @@ class App extends React.Component<ExcalidrawProps, AppState> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
history.record(this.state, this.scene.getElementsIncludingDeleted());
|
history.record(this.state, this.scene.getElementsIncludingDeleted());
|
||||||
|
|
||||||
|
if (onChange) {
|
||||||
|
onChange(this.scene.getElementsIncludingDeleted(), this.state);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy/paste
|
// Copy/paste
|
||||||
|
@ -1,3 +1,17 @@
|
|||||||
|
/* http://www.eaglefonts.com/fg-virgil-ttf-131249.htm */
|
||||||
|
@font-face {
|
||||||
|
font-family: "Virgil";
|
||||||
|
src: url("/FG_Virgil.woff2");
|
||||||
|
font-display: swap;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* https://github.com/microsoft/cascadia-code */
|
||||||
|
@font-face {
|
||||||
|
font-family: "Cascadia";
|
||||||
|
src: url("/Cascadia.woff2");
|
||||||
|
font-display: swap;
|
||||||
|
}
|
||||||
|
|
||||||
.visually-hidden {
|
.visually-hidden {
|
||||||
position: absolute !important;
|
position: absolute !important;
|
||||||
height: 1px;
|
height: 1px;
|
@ -19,6 +19,7 @@ import { serializeAsJSON } from "./json";
|
|||||||
import { ExportType } from "../scene/types";
|
import { ExportType } from "../scene/types";
|
||||||
import { restore } from "./restore";
|
import { restore } from "./restore";
|
||||||
import { restoreFromLocalStorage } from "./localStorage";
|
import { restoreFromLocalStorage } from "./localStorage";
|
||||||
|
import { DataState } from "./types";
|
||||||
|
|
||||||
export { loadFromBlob } from "./blob";
|
export { loadFromBlob } from "./blob";
|
||||||
export { saveAsJSON, loadFromJSON } from "./json";
|
export { saveAsJSON, loadFromJSON } from "./json";
|
||||||
@ -234,7 +235,7 @@ export const exportToBackend = async (
|
|||||||
|
|
||||||
export const importFromBackend = async (
|
export const importFromBackend = async (
|
||||||
id: string | null,
|
id: string | null,
|
||||||
privateKey: string | undefined,
|
privateKey?: string | null,
|
||||||
) => {
|
) => {
|
||||||
let elements: readonly ExcalidrawElement[] = [];
|
let elements: readonly ExcalidrawElement[] = [];
|
||||||
let appState = getDefaultAppState();
|
let appState = getDefaultAppState();
|
||||||
@ -364,14 +365,18 @@ export const exportCanvas = async (
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const loadScene = async (id: string | null, privateKey?: string) => {
|
export const loadScene = async (
|
||||||
|
id: string | null,
|
||||||
|
privateKey?: string | null,
|
||||||
|
initialData?: DataState,
|
||||||
|
) => {
|
||||||
let data;
|
let data;
|
||||||
if (id != null) {
|
if (id != null) {
|
||||||
// the private key is used to decrypt the content from the server, take
|
// the private key is used to decrypt the content from the server, take
|
||||||
// extra care not to leak it
|
// extra care not to leak it
|
||||||
data = await importFromBackend(id, privateKey);
|
data = await importFromBackend(id, privateKey);
|
||||||
} else {
|
} else {
|
||||||
data = restoreFromLocalStorage();
|
data = initialData || restoreFromLocalStorage();
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
2
src/excalidraw-embed/.gitignore
vendored
Normal file
2
src/excalidraw-embed/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
node_modules
|
||||||
|
dist
|
71
src/excalidraw-embed/index.tsx
Normal file
71
src/excalidraw-embed/index.tsx
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
import React, { useEffect } from "react";
|
||||||
|
|
||||||
|
import { InitializeApp } from "../components/InitializeApp";
|
||||||
|
import App from "../components/App";
|
||||||
|
|
||||||
|
import "../css/app.scss";
|
||||||
|
import "../css/styles.scss";
|
||||||
|
|
||||||
|
import { ExcalidrawProps } from "../types";
|
||||||
|
import { IsMobileProvider } from "../is-mobile";
|
||||||
|
|
||||||
|
const Excalidraw = React.memo(
|
||||||
|
(props: ExcalidrawProps) => {
|
||||||
|
const {
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
onChange,
|
||||||
|
initialData,
|
||||||
|
user,
|
||||||
|
onUsernameChange,
|
||||||
|
} = props;
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
// Block pinch-zooming on iOS outside of the content area
|
||||||
|
const handleTouchMove = (event: TouchEvent) => {
|
||||||
|
// @ts-ignore
|
||||||
|
if (typeof event.scale === "number" && event.scale !== 1) {
|
||||||
|
event.preventDefault();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
document.addEventListener("touchmove", handleTouchMove, {
|
||||||
|
passive: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
document.removeEventListener("touchmove", handleTouchMove);
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<InitializeApp>
|
||||||
|
<IsMobileProvider>
|
||||||
|
<App
|
||||||
|
width={width}
|
||||||
|
height={height}
|
||||||
|
onChange={onChange}
|
||||||
|
initialData={initialData}
|
||||||
|
user={user}
|
||||||
|
onUsernameChange={onUsernameChange}
|
||||||
|
/>
|
||||||
|
</IsMobileProvider>
|
||||||
|
</InitializeApp>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
(prevProps: ExcalidrawProps, nextProps: ExcalidrawProps) => {
|
||||||
|
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])
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
export default Excalidraw;
|
6384
src/excalidraw-embed/package-lock.json
generated
Normal file
6384
src/excalidraw-embed/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
66
src/excalidraw-embed/package.json
Normal file
66
src/excalidraw-embed/package.json
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
{
|
||||||
|
"name": "@excalidraw/excalidraw",
|
||||||
|
"version": "0.7.0",
|
||||||
|
"main": "dist/excalidraw.min.js",
|
||||||
|
"files": [
|
||||||
|
"dist/*"
|
||||||
|
],
|
||||||
|
"description": "Excalidraw as a React component",
|
||||||
|
"license": "MIT",
|
||||||
|
"keywords": [
|
||||||
|
"excalidraw",
|
||||||
|
"excalidraw-embed",
|
||||||
|
"react",
|
||||||
|
"npm",
|
||||||
|
"npm excalidraw"
|
||||||
|
],
|
||||||
|
"browserslist": {
|
||||||
|
"production": [
|
||||||
|
">0.2%",
|
||||||
|
"not dead",
|
||||||
|
"not ie <= 11",
|
||||||
|
"not op_mini all",
|
||||||
|
"not safari < 12",
|
||||||
|
"not kaios <= 2.5",
|
||||||
|
"not edge < 79",
|
||||||
|
"not chrome < 70",
|
||||||
|
"not and_uc < 13",
|
||||||
|
"not samsung < 10"
|
||||||
|
],
|
||||||
|
"development": [
|
||||||
|
"last 1 chrome version",
|
||||||
|
"last 1 firefox version",
|
||||||
|
"last 1 safari version"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": "16.13.1",
|
||||||
|
"react-dom": "16.13.1"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@babel/core": "7.9.0",
|
||||||
|
"@babel/plugin-transform-arrow-functions": "7.8.3",
|
||||||
|
"@babel/plugin-transform-async-to-generator": "7.8.3",
|
||||||
|
"@babel/plugin-transform-typescript": "7.9.4",
|
||||||
|
"@babel/preset-env": "7.9.5",
|
||||||
|
"@babel/preset-react": "7.9.4",
|
||||||
|
"@babel/preset-typescript": "7.9.0",
|
||||||
|
"babel-loader": "8.1.0",
|
||||||
|
"babel-plugin-transform-class-properties": "6.24.1",
|
||||||
|
"cross-env": "7.0.2",
|
||||||
|
"css-loader": "3.5.2",
|
||||||
|
"file-loader": "6.0.0",
|
||||||
|
"mini-css-extract-plugin": "0.8.0",
|
||||||
|
"sass-loader": "8.0.2",
|
||||||
|
"terser-webpack-plugin": "2.3.5",
|
||||||
|
"ts-loader": "7.0.0",
|
||||||
|
"webpack": "4.42.0",
|
||||||
|
"webpack-cli": "3.3.11"
|
||||||
|
},
|
||||||
|
"bugs": "https://github.com/excalidraw/excalidraw/issues",
|
||||||
|
"repository": "https://github.com/excalidraw/excalidraw",
|
||||||
|
"scripts": {
|
||||||
|
"build:umd": "cross-env NODE_ENV=production webpack --config webpack.prod.config.js",
|
||||||
|
"pack": "npm run build:umd && npm pack"
|
||||||
|
}
|
||||||
|
}
|
9
src/excalidraw-embed/tsconfig.prod.json
Normal file
9
src/excalidraw-embed/tsconfig.prod.json
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"target": "es5",
|
||||||
|
"module": "es2015",
|
||||||
|
"moduleResolution": "node",
|
||||||
|
"resolveJsonModule": true,
|
||||||
|
"jsx": "react"
|
||||||
|
}
|
||||||
|
}
|
99
src/excalidraw-embed/webpack.prod.config.js
Normal file
99
src/excalidraw-embed/webpack.prod.config.js
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
const path = require("path");
|
||||||
|
const webpack = require("webpack");
|
||||||
|
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
|
||||||
|
const TerserPlugin = require("terser-webpack-plugin");
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
mode: "production",
|
||||||
|
entry: {
|
||||||
|
"excalidraw.min": "./index.tsx",
|
||||||
|
},
|
||||||
|
output: {
|
||||||
|
path: path.resolve(__dirname, "dist"),
|
||||||
|
library: "Excalidraw",
|
||||||
|
libraryTarget: "umd",
|
||||||
|
filename: "[name].js",
|
||||||
|
},
|
||||||
|
resolve: {
|
||||||
|
extensions: [".js", ".ts", ".tsx", ".css", ".scss"],
|
||||||
|
},
|
||||||
|
module: {
|
||||||
|
rules: [
|
||||||
|
{
|
||||||
|
test: /\.(sa|sc|c)ss$/,
|
||||||
|
exclude: /node_modules/,
|
||||||
|
use: [
|
||||||
|
MiniCssExtractPlugin.loader,
|
||||||
|
{ loader: "css-loader" },
|
||||||
|
"sass-loader",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.(ts|tsx|js|jsx|mjs)$/,
|
||||||
|
exclude: /node_modules\/(?!(roughjs|socket.io-client|browser-nativefs)\/).*/,
|
||||||
|
use: [
|
||||||
|
{
|
||||||
|
loader: "ts-loader",
|
||||||
|
options: {
|
||||||
|
transpileOnly: true,
|
||||||
|
configFile: path.resolve(__dirname, "tsconfig.prod.json"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
loader: "babel-loader",
|
||||||
|
options: {
|
||||||
|
presets: [
|
||||||
|
"@babel/preset-env",
|
||||||
|
"@babel/preset-react",
|
||||||
|
"@babel/preset-typescript",
|
||||||
|
],
|
||||||
|
plugins: [
|
||||||
|
"@babel/plugin-proposal-object-rest-spread",
|
||||||
|
"@babel/plugin-transform-arrow-functions",
|
||||||
|
"transform-class-properties",
|
||||||
|
"@babel/plugin-transform-async-to-generator",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.(woff|woff2|eot|ttf|otf)$/,
|
||||||
|
use: [
|
||||||
|
{
|
||||||
|
loader: "file-loader",
|
||||||
|
options: {
|
||||||
|
name: "[name].[ext]",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
optimization: {
|
||||||
|
minimize: true,
|
||||||
|
minimizer: [
|
||||||
|
new TerserPlugin({
|
||||||
|
test: /\.js($|\?)/i,
|
||||||
|
}),
|
||||||
|
new webpack.optimize.LimitChunkCountPlugin({
|
||||||
|
maxChunks: 1,
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
},
|
||||||
|
plugins: [new MiniCssExtractPlugin({ filename: "[name].css" })],
|
||||||
|
externals: {
|
||||||
|
react: {
|
||||||
|
root: "React",
|
||||||
|
commonjs2: "react",
|
||||||
|
commonjs: "react",
|
||||||
|
amd: "react",
|
||||||
|
},
|
||||||
|
"react-dom": {
|
||||||
|
root: "ReactDOM",
|
||||||
|
commonjs2: "react-dom",
|
||||||
|
commonjs: "react-dom",
|
||||||
|
amd: "react-dom",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
65
src/i18n.ts
65
src/i18n.ts
@ -8,44 +8,41 @@ const COMPLETION_THRESHOLD_TO_EXCEED = 85;
|
|||||||
interface Language {
|
interface Language {
|
||||||
lng: string;
|
lng: string;
|
||||||
label: string;
|
label: string;
|
||||||
data: string;
|
|
||||||
rtl?: boolean;
|
rtl?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const allLanguages: Language[] = [
|
const allLanguages: Language[] = [
|
||||||
{ lng: "bg-BG", label: "Български", data: "bg-BG.json" },
|
{ lng: "bg-BG", label: "Български" },
|
||||||
{ lng: "de-DE", label: "Deutsch", data: "de-DE.json" },
|
{ lng: "de-DE", label: "Deutsch" },
|
||||||
{ lng: "es-ES", label: "Español", data: "es-ES.json" },
|
{ lng: "es-ES", label: "Español" },
|
||||||
{ lng: "ca-ES", label: "Catalan", data: "ca-ES.json" },
|
{ lng: "ca-ES", label: "Catalan" },
|
||||||
{ lng: "el-GR", label: "Ελληνικά", data: "el-GR.json" },
|
{ lng: "el-GR", label: "Ελληνικά" },
|
||||||
{ lng: "fr-FR", label: "Français", data: "fr-FR.json" },
|
{ lng: "fr-FR", label: "Français" },
|
||||||
{ lng: "id-ID", label: "Bahasa Indonesia", data: "id-ID.json" },
|
{ lng: "id-ID", label: "Bahasa Indonesia" },
|
||||||
{ lng: "it-IT", label: "Italiano", data: "it-IT.json" },
|
{ lng: "it-IT", label: "Italiano" },
|
||||||
{ lng: "hu-HU", label: "Magyar", data: "hu-HU.json" },
|
{ lng: "hu-HU", label: "Magyar" },
|
||||||
{ lng: "nl-NL", label: "Nederlands", data: "nl-NL.json" },
|
{ lng: "nl-NL", label: "Nederlands" },
|
||||||
{ lng: "nb-NO", label: "Norsk bokmål", data: "nb-NO.json" },
|
{ lng: "nb-NO", label: "Norsk bokmål" },
|
||||||
{ lng: "nn-NO", label: "Norsk nynorsk", data: "nn-NO.json" },
|
{ lng: "nn-NO", label: "Norsk nynorsk" },
|
||||||
{ lng: "pl-PL", label: "Polski", data: "pl-PL.json" },
|
{ lng: "pl-PL", label: "Polski" },
|
||||||
{ lng: "pt-PT", label: "Português", data: "pt-PT.json" },
|
{ lng: "pt-PT", label: "Português" },
|
||||||
{ lng: "ru-RU", label: "Русский", data: "ru-RU.json" },
|
{ lng: "ru-RU", label: "Русский" },
|
||||||
{ lng: "uk-UA", label: "Українська", data: "uk-UA.json" },
|
{ lng: "uk-UA", label: "Українська" },
|
||||||
{ lng: "fi-FI", label: "Suomi", data: "fi-FI.json" },
|
{ lng: "fi-FI", label: "Suomi" },
|
||||||
{ lng: "tr-TR", label: "Türkçe", data: "tr-TR.json" },
|
{ lng: "tr-TR", label: "Türkçe" },
|
||||||
{ lng: "ja-JP", label: "日本語", data: "ja-JP.json" },
|
{ lng: "ja-JP", label: "日本語" },
|
||||||
{ lng: "ko-KR", label: "한국어", data: "ko-KR.json" },
|
{ lng: "ko-KR", label: "한국어" },
|
||||||
{ lng: "zh-TW", label: "繁體中文", data: "zh-TW.json" },
|
{ lng: "zh-TW", label: "繁體中文" },
|
||||||
{ lng: "zh-CN", label: "简体中文", data: "zh-CN.json" },
|
{ lng: "zh-CN", label: "简体中文" },
|
||||||
{ lng: "ar-SA", label: "العربية", data: "ar-SA.json", rtl: true },
|
{ lng: "ar-SA", label: "العربية", rtl: true },
|
||||||
{ lng: "he-IL", label: "עברית", data: "he-IL.json", rtl: true },
|
{ lng: "he-IL", label: "עברית", rtl: true },
|
||||||
{ lng: "hi-IN", label: "हिन्दी", data: "hi-IN.json" },
|
{ lng: "hi-IN", label: "हिन्दी" },
|
||||||
{ lng: "ta-IN", label: "தமிழ்", data: "ta-IN.json" },
|
{ lng: "ta-IN", label: "தமிழ்" },
|
||||||
{ lng: "gl-ES", label: "Galego", data: "gl-ES.json" },
|
{ lng: "gl-ES", label: "Galego" },
|
||||||
{ lng: "vi-VN", label: "Tiếng Việt", data: "vi-VN.json" },
|
{ lng: "vi-VN", label: "Tiếng Việt" },
|
||||||
];
|
];
|
||||||
|
|
||||||
export const languages: Language[] = [
|
export const languages: Language[] = [{ lng: "en", label: "English" }]
|
||||||
{ lng: "en", label: "English", data: "en.json" },
|
|
||||||
]
|
|
||||||
.concat(
|
.concat(
|
||||||
allLanguages.sort((left, right) => (left.label > right.label ? 1 : -1)),
|
allLanguages.sort((left, right) => (left.label > right.label ? 1 : -1)),
|
||||||
)
|
)
|
||||||
@ -65,7 +62,7 @@ export const setLanguage = async (newLng: string | undefined) => {
|
|||||||
|
|
||||||
document.documentElement.dir = currentLanguage.rtl ? "rtl" : "ltr";
|
document.documentElement.dir = currentLanguage.rtl ? "rtl" : "ltr";
|
||||||
|
|
||||||
currentLanguageData = await import(`./locales/${currentLanguage.data}`);
|
currentLanguageData = await import(`./locales/${currentLanguage.lng}.json`);
|
||||||
|
|
||||||
languageDetector.cacheUserLanguage(currentLanguage.lng);
|
languageDetector.cacheUserLanguage(currentLanguage.lng);
|
||||||
};
|
};
|
||||||
@ -78,7 +75,7 @@ export const setLanguageFirstTime = async () => {
|
|||||||
|
|
||||||
document.documentElement.dir = currentLanguage.rtl ? "rtl" : "ltr";
|
document.documentElement.dir = currentLanguage.rtl ? "rtl" : "ltr";
|
||||||
|
|
||||||
currentLanguageData = await import(`./locales/${currentLanguage.data}`);
|
currentLanguageData = await import(`./locales/${currentLanguage.lng}.json`);
|
||||||
|
|
||||||
languageDetector.cacheUserLanguage(currentLanguage.lng);
|
languageDetector.cacheUserLanguage(currentLanguage.lng);
|
||||||
};
|
};
|
||||||
|
@ -5,12 +5,9 @@ import * as SentryIntegrations from "@sentry/integrations";
|
|||||||
|
|
||||||
import { EVENT } from "./constants";
|
import { EVENT } from "./constants";
|
||||||
import { TopErrorBoundary } from "./components/TopErrorBoundary";
|
import { TopErrorBoundary } from "./components/TopErrorBoundary";
|
||||||
import { InitializeApp } from "./components/InitializeApp";
|
import Excalidraw from "./excalidraw-embed/index";
|
||||||
import { IsMobileProvider } from "./is-mobile";
|
|
||||||
import App from "./components/App";
|
|
||||||
import { register as registerServiceWorker } from "./serviceWorker";
|
import { register as registerServiceWorker } from "./serviceWorker";
|
||||||
|
|
||||||
import "./css/styles.scss";
|
|
||||||
import { loadFromBlob } from "./data";
|
import { loadFromBlob } from "./data";
|
||||||
|
|
||||||
// On Apple mobile devices add the proprietary app icon and splashscreen markup.
|
// On Apple mobile devices add the proprietary app icon and splashscreen markup.
|
||||||
@ -63,18 +60,6 @@ Sentry.init({
|
|||||||
|
|
||||||
window.__EXCALIDRAW_SHA__ = REACT_APP_GIT_SHA;
|
window.__EXCALIDRAW_SHA__ = REACT_APP_GIT_SHA;
|
||||||
|
|
||||||
// Block pinch-zooming on iOS outside of the content area
|
|
||||||
document.addEventListener(
|
|
||||||
"touchmove",
|
|
||||||
(event) => {
|
|
||||||
// @ts-ignore
|
|
||||||
if (typeof event.scale === "number" && event.scale !== 1) {
|
|
||||||
event.preventDefault();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{ passive: false },
|
|
||||||
);
|
|
||||||
|
|
||||||
function ExcalidrawApp() {
|
function ExcalidrawApp() {
|
||||||
const [dimensions, setDimensions] = useState({
|
const [dimensions, setDimensions] = useState({
|
||||||
width: window.innerWidth,
|
width: window.innerWidth,
|
||||||
@ -97,11 +82,7 @@ function ExcalidrawApp() {
|
|||||||
const { width, height } = dimensions;
|
const { width, height } = dimensions;
|
||||||
return (
|
return (
|
||||||
<TopErrorBoundary>
|
<TopErrorBoundary>
|
||||||
<IsMobileProvider>
|
<Excalidraw width={width} height={height} />
|
||||||
<InitializeApp>
|
|
||||||
<App width={width} height={height} />
|
|
||||||
</InitializeApp>
|
|
||||||
</IsMobileProvider>
|
|
||||||
</TopErrorBoundary>
|
</TopErrorBoundary>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
10
src/types.ts
10
src/types.ts
@ -14,6 +14,7 @@ import { Point as RoughPoint } from "roughjs/bin/geometry";
|
|||||||
import { SocketUpdateDataSource } from "./data";
|
import { SocketUpdateDataSource } from "./data";
|
||||||
import { LinearElementEditor } from "./element/linearElementEditor";
|
import { LinearElementEditor } from "./element/linearElementEditor";
|
||||||
import { SuggestedBinding } from "./element/binding";
|
import { SuggestedBinding } from "./element/binding";
|
||||||
|
import { DataState } from "./data/types";
|
||||||
|
|
||||||
export type FlooredNumber = number & { _brand: "FlooredNumber" };
|
export type FlooredNumber = number & { _brand: "FlooredNumber" };
|
||||||
export type Point = Readonly<RoughPoint>;
|
export type Point = Readonly<RoughPoint>;
|
||||||
@ -122,4 +123,13 @@ export type LibraryItems = readonly LibraryItem[];
|
|||||||
export interface ExcalidrawProps {
|
export interface ExcalidrawProps {
|
||||||
width: number;
|
width: number;
|
||||||
height: number;
|
height: number;
|
||||||
|
onChange?: (
|
||||||
|
elements: readonly ExcalidrawElement[],
|
||||||
|
appState: AppState,
|
||||||
|
) => void;
|
||||||
|
initialData?: DataState;
|
||||||
|
user?: {
|
||||||
|
name?: string | null;
|
||||||
|
};
|
||||||
|
onUsernameChange?: (username: string) => void;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user