diff --git a/src/app/Store.ts b/src/app/Store.ts index 9ad31b07..08f3a021 100644 --- a/src/app/Store.ts +++ b/src/app/Store.ts @@ -12,6 +12,7 @@ export namespace Store { export const ID_HIGHLIGHTING = 'output_highlighting' export const ID_SOUNDS_VERSION = 'minecraft_sounds_version' export const ID_PROJECTS = 'misode_projects' + export const ID_BACKUPS = 'misode_generator_backups' export function getLanguage() { return localStorage.getItem(ID_LANGUAGE) ?? 'en' @@ -53,6 +54,11 @@ export namespace Store { return [DRAFT_PROJECT] } + export function getBackup(id: string): object | undefined { + const backups = JSON.parse(localStorage.getItem(ID_BACKUPS) ?? '{}') + return backups[id] + } + export function setLanguage(language: string | undefined) { if (language) localStorage.setItem(ID_LANGUAGE, language) } @@ -84,4 +90,14 @@ export namespace Store { export function setProjects(projects: Project[] | undefined) { if (projects) localStorage.setItem(ID_PROJECTS, JSON.stringify(projects)) } + + export function setBackup(id: string, data: object | undefined) { + const backups = JSON.parse(localStorage.getItem(ID_BACKUPS) ?? '{}') + if (data === undefined) { + delete backups[id] + } else { + backups[id] = data + } + localStorage.setItem(ID_BACKUPS, JSON.stringify(backups)) + } } diff --git a/src/app/hooks/useModel.ts b/src/app/hooks/useModel.ts index 996ea35e..4567deb8 100644 --- a/src/app/hooks/useModel.ts +++ b/src/app/hooks/useModel.ts @@ -1,7 +1,8 @@ import type { DataModel } from '@mcschema/core' +import type { Inputs } from 'preact/hooks' import { useEffect } from 'preact/hooks' -export function useModel(model: DataModel | undefined | null, invalidated: (model: DataModel) => unknown) { +export function useModel(model: DataModel | undefined | null, invalidated: (model: DataModel) => unknown, inputs?: Inputs) { const listener = { invalidated() { if (model) { @@ -15,5 +16,5 @@ export function useModel(model: DataModel | undefined | null, invalidated: (mode return () => { model?.removeListener(listener) } - }, [model]) + }, [model, ...inputs ?? []]) } diff --git a/src/app/pages/Generator.tsx b/src/app/pages/Generator.tsx index d21a3ab3..38c30b5a 100644 --- a/src/app/pages/Generator.tsx +++ b/src/app/pages/Generator.tsx @@ -1,6 +1,6 @@ import { DataModel, Path } from '@mcschema/core' import { getCurrentUrl, route } from 'preact-router' -import { useEffect, useErrorBoundary, useState } from 'preact/hooks' +import { useEffect, useErrorBoundary, useMemo, useState } from 'preact/hooks' import config from '../../config.json' import { Analytics } from '../Analytics' import { Ad, Btn, BtnMenu, ErrorPanel, HasPreview, Octicon, PreviewPanel, SearchList, SourcePanel, TextInput, Tree } from '../components' @@ -9,6 +9,7 @@ import { useActiveTimeout, useModel } from '../hooks' import { getOutput } from '../schema/transformOutput' import type { BlockStateRegistry, VersionId } from '../services' import { checkVersion, fetchPreset, getBlockStates, getCollections, getModel, getSnippet, shareSnippet, SHARE_KEY } from '../services' +import { Store } from '../Store' import { cleanUrl, deepEqual, getGenerator, getSearchParams, message, setSeachParams } from '../Utils' interface Props { @@ -74,6 +75,14 @@ export function Generator({}: Props) { model.reset(DataModel.wrapLists(snippet.data), false) } + const backup = useMemo(() => Store.getBackup(gen.id), [gen.id]) + + const loadBackup = () => { + if (backup !== undefined) { + model?.reset(DataModel.wrapLists(backup), false) + } + } + const [model, setModel] = useState(null) const [blockStates, setBlockStates] = useState(null) useEffect(() => { @@ -99,9 +108,10 @@ export function Generator({}: Props) { const [dirty, setDirty] = useState(false) useModel(model, () => { setSeachParams({ version: undefined, preset: undefined, [SHARE_KEY]: undefined }) + Store.setBackup(gen.id, DataModel.unwrapLists(model?.data)) setError(null) setDirty(true) - }) + }, [gen.id]) const [fileRename, setFileRename] = useState('') const [fileSaved, doSave] = useActiveTimeout() @@ -319,6 +329,7 @@ export function Generator({}: Props) { route('/project')} /> {file && } + {backup !== undefined && } f.type === gen.id).map(f => f.id)} onSelect={(id) => openFile(gen.id, id)} /> diff --git a/src/locales/en.json b/src/locales/en.json index 500b084a..3477a9c4 100644 --- a/src/locales/en.json +++ b/src/locales/en.json @@ -66,6 +66,7 @@ "recipe": "Recipe", "redo": "Redo", "reset": "Reset", + "restore_backup": "Restore last backup", "settings": "Settings", "settings.fields.description": "Customize advanced field settings", "settings.fields.path": "Context",