Compare commits
2 Commits
master
...
persist_fi
Author | SHA1 | Date | |
---|---|---|---|
|
f5f4ec7528 | ||
|
ba705a099a |
@ -31,6 +31,7 @@
|
||||
"clsx": "1.1.1",
|
||||
"firebase": "8.3.3",
|
||||
"i18next-browser-languagedetector": "6.1.0",
|
||||
"idb-keyval": "5.0.6",
|
||||
"lodash.throttle": "4.1.1",
|
||||
"nanoid": "3.1.22",
|
||||
"open-color": "1.8.0",
|
||||
|
@ -14,10 +14,11 @@ import { register } from "./register";
|
||||
import { supported as fsSupported } from "browser-fs-access";
|
||||
import { CheckboxItem } from "../components/CheckboxItem";
|
||||
import { getExportSize } from "../scene/export";
|
||||
import { DEFAULT_EXPORT_PADDING, EXPORT_SCALES } from "../constants";
|
||||
import { DEFAULT_EXPORT_PADDING, EXPORT_SCALES, IDB_KEYS } from "../constants";
|
||||
import { getSelectedElements, isSomeElementSelected } from "../scene";
|
||||
import { getNonDeletedElements } from "../element";
|
||||
import { ActiveFile } from "../components/ActiveFile";
|
||||
import * as idb from "idb-keyval";
|
||||
|
||||
export const actionChangeProjectName = register({
|
||||
name: "changeProjectName",
|
||||
@ -149,7 +150,22 @@ export const actionSaveToActiveFile = register({
|
||||
if (error?.name !== "AbortError") {
|
||||
console.error(error);
|
||||
}
|
||||
return { commitToHistory: false };
|
||||
|
||||
if (fileHandleExists && error.name === "AbortError") {
|
||||
try {
|
||||
await idb.del(IDB_KEYS.fileHandle);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
return {
|
||||
commitToHistory: false,
|
||||
appState: { ...appState, fileHandle: null },
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
commitToHistory: false,
|
||||
};
|
||||
}
|
||||
},
|
||||
keyTest: (event) =>
|
||||
@ -170,6 +186,13 @@ export const actionSaveFileToDisk = register({
|
||||
...appState,
|
||||
fileHandle: null,
|
||||
});
|
||||
try {
|
||||
if (fileHandle) {
|
||||
await idb.set(IDB_KEYS.fileHandle, fileHandle);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
return { commitToHistory: false, appState: { ...appState, fileHandle } };
|
||||
} catch (error) {
|
||||
if (error?.name !== "AbortError") {
|
||||
|
@ -52,6 +52,7 @@ import {
|
||||
ENV,
|
||||
EVENT,
|
||||
GRID_SIZE,
|
||||
IDB_KEYS,
|
||||
LINE_CONFIRM_THRESHOLD,
|
||||
MIME_TYPES,
|
||||
MQ_MAX_HEIGHT_LANDSCAPE,
|
||||
@ -194,6 +195,7 @@ import LayerUI from "./LayerUI";
|
||||
import { Stats } from "./Stats";
|
||||
import { Toast } from "./Toast";
|
||||
import { actionToggleViewMode } from "../actions/actionToggleViewMode";
|
||||
import * as idb from "idb-keyval";
|
||||
|
||||
const IsMobileContext = React.createContext(false);
|
||||
export const useIsMobile = () => useContext(IsMobileContext);
|
||||
@ -807,6 +809,15 @@ class App extends React.Component<AppProps, AppState> {
|
||||
} else {
|
||||
this.updateDOMRect(this.initializeScene);
|
||||
}
|
||||
|
||||
try {
|
||||
const fileHandle = await idb.get(IDB_KEYS.fileHandle);
|
||||
if (fileHandle) {
|
||||
this.setState({ fileHandle });
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
}
|
||||
|
||||
public componentWillUnmount() {
|
||||
|
@ -97,6 +97,10 @@ export const STORAGE_KEYS = {
|
||||
LOCAL_STORAGE_LIBRARY: "excalidraw-library",
|
||||
} as const;
|
||||
|
||||
export const IDB_KEYS = {
|
||||
fileHandle: "fileHandle",
|
||||
} as const;
|
||||
|
||||
// time in milliseconds
|
||||
export const TAP_TWICE_TIMEOUT = 300;
|
||||
export const TOUCH_CTX_MENU_TIMEOUT = 500;
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { fileOpen, fileSave } from "browser-fs-access";
|
||||
import { fileOpen, fileSave, FileSystemHandle } from "browser-fs-access";
|
||||
import { cleanAppStateForExport } from "../appState";
|
||||
import { EXPORT_DATA_TYPES, EXPORT_SOURCE, MIME_TYPES } from "../constants";
|
||||
import { clearElementsForExport } from "../element";
|
||||
@ -12,6 +12,7 @@ import {
|
||||
ExportedLibraryData,
|
||||
} from "./types";
|
||||
import Library from "./library";
|
||||
import { AbortError } from "../errors";
|
||||
|
||||
export const serializeAsJSON = (
|
||||
elements: readonly ExcalidrawElement[],
|
||||
@ -28,6 +29,26 @@ export const serializeAsJSON = (
|
||||
return JSON.stringify(data, null, 2);
|
||||
};
|
||||
|
||||
// adapted from https://web.dev/file-system-access
|
||||
const verifyPermission = async (fileHandle: FileSystemHandle) => {
|
||||
try {
|
||||
const options = { mode: "readwrite" } as any;
|
||||
// Check if permission was already granted. If so, return true.
|
||||
if ((await fileHandle.queryPermission(options)) === "granted") {
|
||||
return true;
|
||||
}
|
||||
// Request permission. If the user grants permission, return true.
|
||||
if ((await fileHandle.requestPermission(options)) === "granted") {
|
||||
return true;
|
||||
}
|
||||
// The user didn't grant permission, so return false.
|
||||
return false;
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
export const saveAsJSON = async (
|
||||
elements: readonly ExcalidrawElement[],
|
||||
appState: AppState,
|
||||
@ -37,6 +58,12 @@ export const saveAsJSON = async (
|
||||
type: MIME_TYPES.excalidraw,
|
||||
});
|
||||
|
||||
if (appState.fileHandle) {
|
||||
if (!(await verifyPermission(appState.fileHandle))) {
|
||||
throw new AbortError();
|
||||
}
|
||||
}
|
||||
|
||||
const fileHandle = await fileSave(
|
||||
blob,
|
||||
{
|
||||
|
@ -1,4 +1,5 @@
|
||||
type CANVAS_ERROR_NAMES = "CANVAS_ERROR" | "CANVAS_POSSIBLY_TOO_BIG";
|
||||
|
||||
export class CanvasError extends Error {
|
||||
constructor(
|
||||
message: string = "Couldn't export canvas.",
|
||||
@ -9,3 +10,11 @@ export class CanvasError extends Error {
|
||||
this.message = message;
|
||||
}
|
||||
}
|
||||
|
||||
export class AbortError extends Error {
|
||||
constructor(message: string = "Request aborted") {
|
||||
super();
|
||||
this.name = "AbortError";
|
||||
this.message = message;
|
||||
}
|
||||
}
|
||||
|
@ -6536,6 +6536,11 @@ icss-utils@^4.0.0, icss-utils@^4.1.1:
|
||||
dependencies:
|
||||
postcss "^7.0.14"
|
||||
|
||||
idb-keyval@5.0.6:
|
||||
version "5.0.6"
|
||||
resolved "https://registry.yarnpkg.com/idb-keyval/-/idb-keyval-5.0.6.tgz#62fe4a6703fb5ec86661f41330c94fda65e6d0e6"
|
||||
integrity sha512-6lJuVbwyo82mKSH6Wq2eHkt9LcbwHAelMIcMe0tP4p20Pod7tTxq9zf0ge2n/YDfMOpDryerfmmYyuQiaFaKOg==
|
||||
|
||||
idb@3.0.2:
|
||||
version "3.0.2"
|
||||
resolved "https://registry.npmjs.org/idb/-/idb-3.0.2.tgz"
|
||||
|
Loading…
x
Reference in New Issue
Block a user