build: Added example folder for testing @excalidraw/excalidraw in local (#4488)
* build: Added example folder for testing @excalidraw/excalidraw in local * remove unnecessary files * use scss * update docs * newline * remove index * remove yarn * use the bundled excalidraw.development.js for better testing and font will also be available * remove src folder from examplepull/4482/head
parent
f463c047c0
commit
04f852a40a
@ -0,0 +1,249 @@
|
||||
import { useEffect, useState, useRef } from "react";
|
||||
|
||||
import InitialData from "./initialData";
|
||||
import Sidebar from "./sidebar/Sidebar";
|
||||
|
||||
import "./App.scss";
|
||||
import initialData from "./initialData";
|
||||
|
||||
// This is so that we use the bundled excalidraw.developement.js file instead
|
||||
// of the actual source code
|
||||
const { exportToCanvas, exportToSvg, exportToBlob } = window.Excalidraw;
|
||||
const Excalidraw = window.Excalidraw.default;
|
||||
|
||||
const renderTopRightUI = () => {
|
||||
return (
|
||||
<button onClick={() => alert("This is dummy top right UI")}>
|
||||
{" "}
|
||||
Click me{" "}
|
||||
</button>
|
||||
);
|
||||
};
|
||||
|
||||
const renderFooter = () => {
|
||||
return (
|
||||
<button onClick={() => alert("This is dummy footer")}>
|
||||
{" "}
|
||||
custom footer{" "}
|
||||
</button>
|
||||
);
|
||||
};
|
||||
|
||||
export default function App() {
|
||||
const excalidrawRef = useRef(null);
|
||||
|
||||
const [viewModeEnabled, setViewModeEnabled] = useState(false);
|
||||
const [zenModeEnabled, setZenModeEnabled] = useState(false);
|
||||
const [gridModeEnabled, setGridModeEnabled] = useState(false);
|
||||
const [blobUrl, setBlobUrl] = useState(null);
|
||||
const [canvasUrl, setCanvasUrl] = useState(null);
|
||||
const [exportWithDarkMode, setExportWithDarkMode] = useState(false);
|
||||
const [shouldAddWatermark, setShouldAddWatermark] = useState(false);
|
||||
const [theme, setTheme] = useState("light");
|
||||
|
||||
useEffect(() => {
|
||||
const onHashChange = () => {
|
||||
const hash = new URLSearchParams(window.location.hash.slice(1));
|
||||
const libraryUrl = hash.get("addLibrary");
|
||||
if (libraryUrl) {
|
||||
excalidrawRef.current.importLibrary(libraryUrl, hash.get("token"));
|
||||
}
|
||||
};
|
||||
window.addEventListener("hashchange", onHashChange, false);
|
||||
return () => {
|
||||
window.removeEventListener("hashchange", onHashChange);
|
||||
};
|
||||
}, []);
|
||||
|
||||
const updateScene = () => {
|
||||
const sceneData = {
|
||||
elements: [
|
||||
{
|
||||
type: "rectangle",
|
||||
version: 141,
|
||||
versionNonce: 361174001,
|
||||
isDeleted: false,
|
||||
id: "oDVXy8D6rom3H1-LLH2-f",
|
||||
fillStyle: "hachure",
|
||||
strokeWidth: 1,
|
||||
strokeStyle: "solid",
|
||||
roughness: 1,
|
||||
opacity: 100,
|
||||
angle: 0,
|
||||
x: 100.50390625,
|
||||
y: 93.67578125,
|
||||
strokeColor: "#c92a2a",
|
||||
backgroundColor: "transparent",
|
||||
width: 186.47265625,
|
||||
height: 141.9765625,
|
||||
seed: 1968410350,
|
||||
groupIds: [],
|
||||
},
|
||||
],
|
||||
appState: {
|
||||
viewBackgroundColor: "#edf2ff",
|
||||
},
|
||||
};
|
||||
excalidrawRef.current.updateScene(sceneData);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="App">
|
||||
<h1> Excalidraw Example</h1>
|
||||
<Sidebar>
|
||||
<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>
|
||||
<label>
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={theme === "dark"}
|
||||
onChange={() => {
|
||||
let newTheme = "light";
|
||||
if (theme === "light") {
|
||||
newTheme = "dark";
|
||||
}
|
||||
setTheme(newTheme);
|
||||
}}
|
||||
/>
|
||||
Switch to Dark Theme
|
||||
</label>
|
||||
</div>
|
||||
<div className="excalidraw-wrapper">
|
||||
<Excalidraw
|
||||
ref={excalidrawRef}
|
||||
initialData={InitialData}
|
||||
onChange={(elements, state) =>
|
||||
console.info("Elements :", elements, "State : ", state)
|
||||
}
|
||||
onPointerUpdate={(payload) => console.info(payload)}
|
||||
onCollabButtonClick={() =>
|
||||
window.alert("You clicked on collab button")
|
||||
}
|
||||
viewModeEnabled={viewModeEnabled}
|
||||
zenModeEnabled={zenModeEnabled}
|
||||
gridModeEnabled={gridModeEnabled}
|
||||
theme={theme}
|
||||
name="Custom name of drawing"
|
||||
UIOptions={{ canvasActions: { loadScene: false } }}
|
||||
renderTopRightUI={renderTopRightUI}
|
||||
renderFooter={renderFooter}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="export-wrapper button-wrapper">
|
||||
<label className="export-wrapper__checkbox">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={exportWithDarkMode}
|
||||
onChange={() => setExportWithDarkMode(!exportWithDarkMode)}
|
||||
/>
|
||||
Export with dark mode
|
||||
</label>
|
||||
<label className="export-wrapper__checkbox">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={shouldAddWatermark}
|
||||
onChange={() => setShouldAddWatermark(!shouldAddWatermark)}
|
||||
/>
|
||||
Add Watermark
|
||||
</label>
|
||||
<button
|
||||
onClick={async () => {
|
||||
const svg = await exportToSvg({
|
||||
elements: excalidrawRef.current.getSceneElements(),
|
||||
appState: {
|
||||
...initialData.appState,
|
||||
exportWithDarkMode,
|
||||
shouldAddWatermark,
|
||||
width: 300,
|
||||
height: 100,
|
||||
},
|
||||
embedScene: true,
|
||||
});
|
||||
document.querySelector(".export-svg").innerHTML = svg.outerHTML;
|
||||
}}
|
||||
>
|
||||
Export to SVG
|
||||
</button>
|
||||
<div className="export export-svg"></div>
|
||||
|
||||
<button
|
||||
onClick={async () => {
|
||||
const blob = await exportToBlob({
|
||||
elements: excalidrawRef.current.getSceneElements(),
|
||||
mimeType: "image/png",
|
||||
appState: {
|
||||
...initialData.appState,
|
||||
exportWithDarkMode,
|
||||
shouldAddWatermark,
|
||||
},
|
||||
});
|
||||
setBlobUrl(window.URL.createObjectURL(blob));
|
||||
}}
|
||||
>
|
||||
Export to Blob
|
||||
</button>
|
||||
<div className="export export-blob">
|
||||
<img src={blobUrl} alt="" />
|
||||
</div>
|
||||
|
||||
<button
|
||||
onClick={() => {
|
||||
const canvas = exportToCanvas({
|
||||
elements: excalidrawRef.current.getSceneElements(),
|
||||
appState: {
|
||||
...initialData.appState,
|
||||
exportWithDarkMode,
|
||||
shouldAddWatermark,
|
||||
},
|
||||
});
|
||||
const ctx = canvas.getContext("2d");
|
||||
ctx.font = "30px Virgil";
|
||||
ctx.strokeText("My custom text", 50, 60);
|
||||
setCanvasUrl(canvas.toDataURL());
|
||||
}}
|
||||
>
|
||||
Export to Canvas
|
||||
</button>
|
||||
<div className="export export-canvas">
|
||||
<img src={canvasUrl} alt="" />
|
||||
</div>
|
||||
</div>
|
||||
</Sidebar>
|
||||
</div>
|
||||
);
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
.App {
|
||||
font-family: sans-serif;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.button-wrapper button {
|
||||
z-index: 1;
|
||||
height: 40px;
|
||||
max-width: 200px;
|
||||
margin: 10px;
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
.excalidraw .App-menu_top .buttonList {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.excalidraw-wrapper {
|
||||
height: 800px;
|
||||
margin: 50px;
|
||||
}
|
||||
|
||||
:root[dir="ltr"]
|
||||
.excalidraw
|
||||
.layer-ui__wrapper
|
||||
.zen-mode-transition.App-menu_bottom--transition-left {
|
||||
transform: none;
|
||||
}
|
||||
|
||||
.excalidraw .panelColumn {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.export-wrapper {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
margin: 50px;
|
||||
|
||||
&__checkbox {
|
||||
display: flex;
|
||||
}
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta
|
||||
name="viewport"
|
||||
content="width=device-width, initial-scale=1, shrink-to-fit=no"
|
||||
/>
|
||||
<meta name="theme-color" content="#000000" />
|
||||
|
||||
<title>React App</title>
|
||||
<script>
|
||||
window.name = "codesandbox";
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<noscript> You need to enable JavaScript to run this app. </noscript>
|
||||
<div id="root"></div>
|
||||
<script src="https://unpkg.com/react@17.0.2/umd/react.development.js"></script>
|
||||
<script src="https://unpkg.com/react-dom@17.0.2/umd/react-dom.development.js"></script>
|
||||
|
||||
<!-- This is so that we use the bundled excalidraw.developement.js file instead
|
||||
of the actual source code -->
|
||||
<script src="./excalidraw.development.js"></script>
|
||||
|
||||
<script src="./bundle.js"></script>
|
||||
</body>
|
||||
</html>
|
@ -0,0 +1,12 @@
|
||||
import React from "react";
|
||||
import ReactDOM from "react-dom";
|
||||
|
||||
import App from "./App";
|
||||
|
||||
const rootElement = document.getElementById("root");
|
||||
ReactDOM.render(
|
||||
<React.StrictMode>
|
||||
<App />
|
||||
</React.StrictMode>,
|
||||
rootElement,
|
||||
);
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,30 @@
|
||||
import { useState } from "react";
|
||||
import "./Sidebar.scss";
|
||||
export default function Sidebar(props) {
|
||||
const [open, setOpen] = useState(false);
|
||||
|
||||
return (
|
||||
<>
|
||||
<div id="mySidebar" className={`sidebar ${open ? "open" : ""}`}>
|
||||
<button className="closebtn" onClick={() => setOpen(false)}>
|
||||
x
|
||||
</button>
|
||||
<div className="sidebar-links">
|
||||
<button>Dummy Home</button>
|
||||
<button>Dummy About</button>{" "}
|
||||
</div>
|
||||
</div>
|
||||
<div className={`${open ? "sidebar-open" : ""}`}>
|
||||
<button
|
||||
className="openbtn"
|
||||
onClick={() => {
|
||||
setOpen(!open);
|
||||
}}
|
||||
>
|
||||
Open Sidebar
|
||||
</button>
|
||||
{props.children}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
@ -0,0 +1,66 @@
|
||||
.sidebar {
|
||||
height: 100%;
|
||||
width: 0;
|
||||
position: absolute;
|
||||
z-index: 1;
|
||||
top: 0;
|
||||
left: 0;
|
||||
background-color: #111;
|
||||
overflow-x: hidden;
|
||||
transition: 0.5s;
|
||||
padding-top: 60px;
|
||||
|
||||
&.open {
|
||||
width: 300px;
|
||||
}
|
||||
|
||||
&-links {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 20px;
|
||||
|
||||
button {
|
||||
padding: 10px;
|
||||
margin: 10px;
|
||||
background: #faa2c1;
|
||||
color: #fff;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.sidebar a {
|
||||
padding: 8px 8px 8px 32px;
|
||||
text-decoration: none;
|
||||
font-size: 25px;
|
||||
color: #818181;
|
||||
display: block;
|
||||
transition: 0.3s;
|
||||
}
|
||||
|
||||
.sidebar a:hover {
|
||||
color: #f1f1f1;
|
||||
}
|
||||
|
||||
.sidebar .closebtn {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
font-size: 36px;
|
||||
margin-left: 50px;
|
||||
}
|
||||
|
||||
.openbtn {
|
||||
font-size: 20px;
|
||||
cursor: pointer;
|
||||
background-color: #111;
|
||||
color: white;
|
||||
padding: 10px 15px;
|
||||
border: none;
|
||||
display: flex;
|
||||
margin-left: 50px;
|
||||
}
|
||||
.sidebar-open {
|
||||
margin-left: 300px;
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
const path = require("path");
|
||||
const { merge } = require("webpack-merge");
|
||||
|
||||
const devConfig = require("./webpack.dev.config");
|
||||
|
||||
const devServerConfig = {
|
||||
entry: {
|
||||
bundle: "./example/index.js",
|
||||
},
|
||||
// Server Configuration options
|
||||
devServer: {
|
||||
port: 3001,
|
||||
host: "localhost",
|
||||
hot: true,
|
||||
compress: true,
|
||||
static: {
|
||||
directory: path.join(__dirname, "example"),
|
||||
},
|
||||
client: {
|
||||
progress: true,
|
||||
logging: "info",
|
||||
overlay: true, //Shows a full-screen overlay in the browser when there are compiler errors or warnings.
|
||||
},
|
||||
open: ["./"],
|
||||
},
|
||||
};
|
||||
|
||||
module.exports = merge(devServerConfig, devConfig);
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue