diff --git a/README.md b/README.md
index b31b932..be2b125 100644
--- a/README.md
+++ b/README.md
@@ -18,6 +18,7 @@ Licenses: see [LICENSES](./LICENSE).
- Autocomplete of imports
- Autocomplete of symbols / function calls (pseudo-parses file and its transitive imports)
- Responsive layout (but editing on iOS is still a pain, will address that soon). On small screens editor and viewer are stacked onto each other, while on larger screens they can be side-by-side
+- Installable as a PWA (then persists edits in localStorage instead of the hash fragment). On iOS just open the sharing panel and tap "Add to Home Screen".
## Roadmap
@@ -31,7 +32,7 @@ Licenses: see [LICENSES](./LICENSE).
- Better names for downloads (matching source)
- Model /home fs in shared state. have two clear paths: /libraries for builtins, and /home for user data. State pointing to /libraries paths needs not store the data except if there's overrides (flagged as modifications in the file picker)
- Drag and drop of files (SCAD, STL, etc) and Zip archives. For assets, auto insert the corresponding import.
-- Proper PWA w/ File opening / association to *.scad files
+- Fuller PWA support w/ link Sharing, File opening / association to *.scad files...
- Look into accessibility
- Setup [OPENSCADPATH](https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Libraries#Setting_OPENSCADPATH) env var w/ Emscripten to ensure examples that include assets / import local files will run fine.
- Bundle more examples (ask users to contribute)
diff --git a/src/components/App.tsx b/src/components/App.tsx
index ff699fd..357bb70 100644
--- a/src/components/App.tsx
+++ b/src/components/App.tsx
@@ -1,7 +1,7 @@
// Portions of this file are Copyright 2021 Google LLC, and licensed under GPL2+. See COPYING.
import React, { CSSProperties, useEffect, useState } from 'react';
-import {MultiLayoutComponentId, State} from '../state/app-state'
+import {MultiLayoutComponentId, State, StatePersister} from '../state/app-state'
import { Model } from '../state/model';
import EditorPanel from './EditorPanel';
import ViewerPanel from './ViewerPanel';
@@ -13,10 +13,10 @@ import PanelSwitcher from './PanelSwitcher';
// import "primereact/resources/primereact.min.css";
// import "primeicons/primeicons.css";
-export function App({initialState, fs}: {initialState: State, fs: FS}) {
+export function App({initialState, statePersister, fs}: {initialState: State, statePersister: StatePersister, fs: FS}) {
const [state, setState] = useState(initialState);
- const model = new Model(fs, state, setState);
+ const model = new Model(fs, state, setState, statePersister);
useEffect(() => model.init());
const zIndexOfPanelsDependingOnFocus = {
diff --git a/src/components/SettingsMenu.tsx b/src/components/SettingsMenu.tsx
index 89b646e..aff816e 100644
--- a/src/components/SettingsMenu.tsx
+++ b/src/components/SettingsMenu.tsx
@@ -5,6 +5,8 @@ import { Button } from 'primereact/button';
import { MenuItem } from 'primereact/menuitem';
import { Menu } from 'primereact/menu';
import { ModelContext } from './contexts';
+import { isInStandaloneMode } from '../utils';
+import { ConfirmDialog, confirmDialog } from 'primereact/confirmdialog';
export default function SettingsMenu({className, style}: {className?: string, style?: CSSProperties}) {
const model = useContext(ModelContext);
@@ -44,7 +46,34 @@ export default function SettingsMenu({className, style}: {className?: string, st
// disabled: true,
command: () => model.mutate(s => s.view.lineNumbers = !s.view.lineNumbers)
},
+ ...(isInStandaloneMode ? [
+ {
+ separator: true
+ },
+ {
+ label: 'Clear local storage',
+ icon: 'pi pi-list',
+ // disabled: true,
+ command: () => {
+ confirmDialog({
+ message: "This will clear all the edits you've made and files you've created in this playground " +
+ "and will reset it to factory defaults. " +
+ "Are you sure you wish to proceed? (you might lose your models!)",
+ header: 'Clear local storage',
+ icon: 'pi pi-exclamation-triangle',
+ accept: () => {
+ localStorage.clear();
+ location.reload();
+ },
+ acceptLabel: `Clear all files!`,
+ rejectLabel: 'Cancel'
+ });
+ },
+ },
+ ] : []),
] as MenuItem[]} popup ref={settingsMenu} />
+
+