Initial commit
This commit is contained in:
27
.eslintrc.cjs
Normal file
27
.eslintrc.cjs
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
/* eslint-env node */
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
root: true,
|
||||||
|
env: { browser: true, es2020: true },
|
||||||
|
extends: [
|
||||||
|
'eslint:recommended',
|
||||||
|
'plugin:@typescript-eslint/recommended',
|
||||||
|
'plugin:@typescript-eslint/recommended-requiring-type-checking',
|
||||||
|
'plugin:react-hooks/recommended',
|
||||||
|
],
|
||||||
|
parser: '@typescript-eslint/parser',
|
||||||
|
parserOptions: {
|
||||||
|
ecmaVersion: 'latest',
|
||||||
|
sourceType: 'module',
|
||||||
|
project: true,
|
||||||
|
tsconfigRootDir: __dirname,
|
||||||
|
},
|
||||||
|
plugins: ['react-refresh'],
|
||||||
|
rules: {
|
||||||
|
'react-refresh/only-export-components': [
|
||||||
|
'warn',
|
||||||
|
{ allowConstantExport: true },
|
||||||
|
],
|
||||||
|
'@typescript-eslint/no-non-null-assertion': 'off',
|
||||||
|
},
|
||||||
|
};
|
24
.gitignore
vendored
Normal file
24
.gitignore
vendored
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
# Logs
|
||||||
|
logs
|
||||||
|
*.log
|
||||||
|
npm-debug.log*
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
|
pnpm-debug.log*
|
||||||
|
lerna-debug.log*
|
||||||
|
|
||||||
|
node_modules
|
||||||
|
dist
|
||||||
|
dist-ssr
|
||||||
|
*.local
|
||||||
|
|
||||||
|
# Editor directories and files
|
||||||
|
.vscode/*
|
||||||
|
!.vscode/extensions.json
|
||||||
|
.idea
|
||||||
|
.DS_Store
|
||||||
|
*.suo
|
||||||
|
*.ntvs*
|
||||||
|
*.njsproj
|
||||||
|
*.sln
|
||||||
|
*.sw?
|
7
.prettierignore
Normal file
7
.prettierignore
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
**/.git
|
||||||
|
**/.svn
|
||||||
|
**/.hg
|
||||||
|
**/node_modules
|
||||||
|
/public
|
||||||
|
/dist
|
||||||
|
|
9
.prettierrc.js
Normal file
9
.prettierrc.js
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
/** @type {import("prettier").Options} */
|
||||||
|
const config = {
|
||||||
|
trailingComma: 'es5',
|
||||||
|
tabWidth: 2,
|
||||||
|
semi: true,
|
||||||
|
singleQuote: true,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default config;
|
13
index.html
Normal file
13
index.html
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<title>Excalidraw with WebRTC</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="root"></div>
|
||||||
|
<script type="module" src="/src/main.tsx"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
37
package.json
Normal file
37
package.json
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
{
|
||||||
|
"name": "excalidraw-p2p",
|
||||||
|
"private": true,
|
||||||
|
"version": "0.0.0",
|
||||||
|
"type": "module",
|
||||||
|
"scripts": {
|
||||||
|
"dev": "vite",
|
||||||
|
"build": "tsc && vite build",
|
||||||
|
"lint": "eslint src --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
|
||||||
|
"fmt": "prettier --write \"**/*.{ts,tsx,js,cjs,json,html,css}\"",
|
||||||
|
"preview": "vite preview"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@emotion/react": "^11.11.1",
|
||||||
|
"@emotion/styled": "^11.11.0",
|
||||||
|
"@excalidraw/excalidraw": "^0.15.2",
|
||||||
|
"@fontsource/roboto": "^5.0.5",
|
||||||
|
"@mui/icons-material": "^5.14.1",
|
||||||
|
"@mui/material": "^5.14.1",
|
||||||
|
"jotai": "^2.2.2",
|
||||||
|
"react": "^18.2.0",
|
||||||
|
"react-dom": "^18.2.0"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/react": "^18.2.14",
|
||||||
|
"@types/react-dom": "^18.2.6",
|
||||||
|
"@typescript-eslint/eslint-plugin": "^5.61.0",
|
||||||
|
"@typescript-eslint/parser": "^5.61.0",
|
||||||
|
"@vitejs/plugin-react-swc": "^3.3.2",
|
||||||
|
"eslint": "^8.44.0",
|
||||||
|
"eslint-plugin-react-hooks": "^4.6.0",
|
||||||
|
"eslint-plugin-react-refresh": "^0.4.1",
|
||||||
|
"prettier": "^3.0.0",
|
||||||
|
"typescript": "^5.0.2",
|
||||||
|
"vite": "^4.4.0"
|
||||||
|
}
|
||||||
|
}
|
2090
pnpm-lock.yaml
generated
Normal file
2090
pnpm-lock.yaml
generated
Normal file
File diff suppressed because it is too large
Load Diff
119
src/App.tsx
Normal file
119
src/App.tsx
Normal file
@ -0,0 +1,119 @@
|
|||||||
|
import { Excalidraw, Sidebar } from '@excalidraw/excalidraw';
|
||||||
|
import { Box, Button, Container } from '@mui/material';
|
||||||
|
import type {
|
||||||
|
ExcalidrawProps,
|
||||||
|
ExcalidrawImperativeAPI,
|
||||||
|
} from '@excalidraw/excalidraw/types/types';
|
||||||
|
import { FC, useState } from 'react';
|
||||||
|
|
||||||
|
const ExcalidrawContainer: FC<
|
||||||
|
ExcalidrawProps & { refCallback: (api: ExcalidrawImperativeAPI) => void }
|
||||||
|
> = (props) => {
|
||||||
|
return (
|
||||||
|
<Container>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
border: '1.5px solid',
|
||||||
|
width: '95vw',
|
||||||
|
height: '95vh',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Excalidraw {...props} ref={props.refCallback} />
|
||||||
|
</Box>
|
||||||
|
</Container>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
function App() {
|
||||||
|
// TODO: jotai premitives
|
||||||
|
const isCollaborating = false;
|
||||||
|
|
||||||
|
const [excalidrawAPI, setExcalidrawAPI] = useState<ExcalidrawImperativeAPI>();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Container
|
||||||
|
sx={{
|
||||||
|
display: 'grid',
|
||||||
|
height: '100%',
|
||||||
|
width: '100%',
|
||||||
|
placeContent: 'center',
|
||||||
|
overflow: 'hidden',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<ExcalidrawContainer
|
||||||
|
refCallback={(api) => setExcalidrawAPI(api)}
|
||||||
|
isCollaborating={isCollaborating}
|
||||||
|
autoFocus={true}
|
||||||
|
name="Excalidraw with WebRTC"
|
||||||
|
renderTopRightUI={() => {
|
||||||
|
return (
|
||||||
|
<Button
|
||||||
|
onClick={() => {
|
||||||
|
excalidrawAPI?.toggleMenu('customSidebar');
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Button
|
||||||
|
</Button>
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
renderSidebar={() => {
|
||||||
|
return (
|
||||||
|
<Sidebar dockable={true}>
|
||||||
|
<Sidebar.Header> Header </Sidebar.Header>
|
||||||
|
<Button>Button</Button>
|
||||||
|
</Sidebar>
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Container>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
export interface ExcalidrawProps {
|
||||||
|
// Render UI elements
|
||||||
|
renderTopRightUI?: (isMobile: boolean, appState: AppState) => JSX.Element | null;
|
||||||
|
renderSidebar?: () => JSX.Element | null;
|
||||||
|
|
||||||
|
onChange?: (elements: readonly ExcalidrawElement[], appState: AppState, files: BinaryFiles) => void;
|
||||||
|
initialData?: ExcalidrawInitialDataState | null | Promise<ExcalidrawInitialDataState | null>;
|
||||||
|
excalidrawRef?: ForwardRef<ExcalidrawAPIRefValue>;
|
||||||
|
isCollaborating?: boolean;
|
||||||
|
onPointerUpdate?: (payload: {
|
||||||
|
pointer: {
|
||||||
|
x: number;
|
||||||
|
y: number;
|
||||||
|
};
|
||||||
|
button: "down" | "up";
|
||||||
|
pointersMap: Gesture["pointers"];
|
||||||
|
}) => void;
|
||||||
|
onPaste?: (data: ClipboardData, event: ClipboardEvent | null) => Promise<boolean> | boolean;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
langCode?: Language["code"];
|
||||||
|
onPointerDown?: (activeTool: AppState["activeTool"], pointerDownState: PointerDownState) => void;
|
||||||
|
generateIdForFile?: (file: File) => string | Promise<string>;
|
||||||
|
UIOptions?: Partial<UIOptions>;
|
||||||
|
renderCustomStats?: (elements: readonly NonDeletedExcalidrawElement[], appState: AppState) => JSX.Element;
|
||||||
|
|
||||||
|
viewModeEnabled?: boolean;
|
||||||
|
zenModeEnabled?: boolean;
|
||||||
|
gridModeEnabled?: boolean;
|
||||||
|
libraryReturnUrl?: string;
|
||||||
|
name?: string;
|
||||||
|
theme?: Theme;
|
||||||
|
detectScroll?: boolean;
|
||||||
|
handleKeyboardGlobally?: boolean;
|
||||||
|
onLibraryChange?: (libraryItems: LibraryItems) => void | Promise<any>;
|
||||||
|
autoFocus?: boolean;
|
||||||
|
onLinkOpen?: (element: NonDeletedExcalidrawElement, event: CustomEvent<{
|
||||||
|
nativeEvent: MouseEvent | React.PointerEvent<HTMLCanvasElement>;
|
||||||
|
}>) => void;
|
||||||
|
onScrollChange?: (scrollX: number, scrollY: number) => void;
|
||||||
|
children?: React.ReactNode;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
export default App;
|
14
src/main.tsx
Normal file
14
src/main.tsx
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import ReactDOM from 'react-dom/client';
|
||||||
|
import App from './App.tsx';
|
||||||
|
|
||||||
|
import '@fontsource/roboto/300.css';
|
||||||
|
import '@fontsource/roboto/400.css';
|
||||||
|
import '@fontsource/roboto/500.css';
|
||||||
|
import '@fontsource/roboto/700.css';
|
||||||
|
|
||||||
|
ReactDOM.createRoot(document.getElementById('root')!).render(
|
||||||
|
<React.StrictMode>
|
||||||
|
<App />
|
||||||
|
</React.StrictMode>
|
||||||
|
);
|
1
src/vite-env.d.ts
vendored
Normal file
1
src/vite-env.d.ts
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
/// <reference types="vite/client" />
|
25
tsconfig.json
Normal file
25
tsconfig.json
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"target": "ES2020",
|
||||||
|
"useDefineForClassFields": true,
|
||||||
|
"lib": ["ES2020", "DOM", "DOM.Iterable"],
|
||||||
|
"module": "ESNext",
|
||||||
|
"skipLibCheck": true,
|
||||||
|
|
||||||
|
/* Bundler mode */
|
||||||
|
"moduleResolution": "bundler",
|
||||||
|
"allowImportingTsExtensions": true,
|
||||||
|
"resolveJsonModule": true,
|
||||||
|
"isolatedModules": true,
|
||||||
|
"noEmit": true,
|
||||||
|
"jsx": "react-jsx",
|
||||||
|
|
||||||
|
/* Linting */
|
||||||
|
"strict": true,
|
||||||
|
"noUnusedLocals": true,
|
||||||
|
"noUnusedParameters": true,
|
||||||
|
"noFallthroughCasesInSwitch": true
|
||||||
|
},
|
||||||
|
"include": ["src"],
|
||||||
|
"references": [{ "path": "./tsconfig.node.json" }]
|
||||||
|
}
|
10
tsconfig.node.json
Normal file
10
tsconfig.node.json
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"composite": true,
|
||||||
|
"skipLibCheck": true,
|
||||||
|
"module": "ESNext",
|
||||||
|
"moduleResolution": "bundler",
|
||||||
|
"allowSyntheticDefaultImports": true
|
||||||
|
},
|
||||||
|
"include": ["vite.config.ts"]
|
||||||
|
}
|
7
vite.config.ts
Normal file
7
vite.config.ts
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
import { defineConfig } from 'vite';
|
||||||
|
import react from '@vitejs/plugin-react-swc';
|
||||||
|
|
||||||
|
// https://vitejs.dev/config/
|
||||||
|
export default defineConfig({
|
||||||
|
plugins: [react()],
|
||||||
|
});
|
Reference in New Issue
Block a user