|
@@ -9,6 +9,8 @@ import nanoid from "nanoid";
|
|
|
|
|
|
const LOCAL_STORAGE_KEY = "excalidraw";
|
|
|
const LOCAL_STORAGE_KEY_STATE = "excalidraw-state";
|
|
|
+const BACKEND_POST = "https://json.excalidraw.com/api/v1/post/";
|
|
|
+const BACKEND_GET = "https://json.excalidraw.com/api/v1/";
|
|
|
|
|
|
// TODO: Defined globally, since file handles aren't yet serializable.
|
|
|
// Once `FileSystemFileHandle` can be serialized, make this
|
|
@@ -73,16 +75,23 @@ interface DataState {
|
|
|
appState: AppState;
|
|
|
}
|
|
|
|
|
|
-export async function saveAsJSON(
|
|
|
+export function serializeAsJSON(
|
|
|
elements: readonly ExcalidrawElement[],
|
|
|
- appState: AppState
|
|
|
-) {
|
|
|
- const serialized = JSON.stringify({
|
|
|
+ appState?: AppState
|
|
|
+): string {
|
|
|
+ return JSON.stringify({
|
|
|
version: 1,
|
|
|
source: window.location.origin,
|
|
|
elements: elements.map(({ shape, ...el }) => el),
|
|
|
- appState: appState
|
|
|
+ appState: appState || getDefaultAppState()
|
|
|
});
|
|
|
+}
|
|
|
+
|
|
|
+export async function saveAsJSON(
|
|
|
+ elements: readonly ExcalidrawElement[],
|
|
|
+ appState: AppState
|
|
|
+) {
|
|
|
+ const serialized = serializeAsJSON(elements, appState);
|
|
|
|
|
|
const name = `${appState.name}.json`;
|
|
|
if ("chooseFileSystemEntries" in window) {
|
|
@@ -166,6 +175,44 @@ export async function loadFromJSON() {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+export async function exportToBackend(elements: readonly ExcalidrawElement[]) {
|
|
|
+ const response = await fetch(BACKEND_POST, {
|
|
|
+ method: "POST",
|
|
|
+ headers: {
|
|
|
+ "Content-Type": "application/json"
|
|
|
+ },
|
|
|
+ body: serializeAsJSON(elements)
|
|
|
+ });
|
|
|
+ const json = await response.json();
|
|
|
+ if (json.hash) {
|
|
|
+ const url = new URL(window.location.href);
|
|
|
+ url.searchParams.append("json", json.hash);
|
|
|
+
|
|
|
+ await navigator.clipboard.writeText(url.toString());
|
|
|
+ window.alert("Copied shareable link " + url.toString() + " to clipboard");
|
|
|
+ } else {
|
|
|
+ window.alert("Couldn't create shareable link");
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+export async function importFromBackend(hash: string | null) {
|
|
|
+ let elements: readonly ExcalidrawElement[] = [];
|
|
|
+ let appState: AppState = getDefaultAppState();
|
|
|
+ const response = await fetch(`${BACKEND_GET}${hash}.json`).then(data =>
|
|
|
+ data.clone().json()
|
|
|
+ );
|
|
|
+ if (response != null) {
|
|
|
+ try {
|
|
|
+ elements = response.elements || elements;
|
|
|
+ appState = response.appState || appState;
|
|
|
+ } catch (error) {
|
|
|
+ window.alert("Importing from backend failed");
|
|
|
+ console.error(error);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return restore(elements, appState);
|
|
|
+}
|
|
|
+
|
|
|
export async function exportCanvas(
|
|
|
type: ExportType,
|
|
|
elements: readonly ExcalidrawElement[],
|
|
@@ -221,6 +268,8 @@ export async function exportCanvas(
|
|
|
} catch (err) {
|
|
|
window.alert("Couldn't copy to clipboard. Try using Chrome browser.");
|
|
|
}
|
|
|
+ } else if (type === "backend") {
|
|
|
+ exportToBackend(elements);
|
|
|
}
|
|
|
|
|
|
// clean up the DOM
|