diff --git a/lib/page-with-shareable-state.tsx b/lib/page-with-shareable-state.tsx index 1003030..8ff1da5 100644 --- a/lib/page-with-shareable-state.tsx +++ b/lib/page-with-shareable-state.tsx @@ -45,6 +45,30 @@ export function createPageWithStateSearchParams( return search; } +const DeserializationErrorModal: React.FC = () => { + const [show, setShow] = useState(true); + + if (!show) return null; + + // TODO: This isn't accessible at all; it ought to trap keyboard focus, + // disappear when the user presses ESC, and so on. + + return ( +
+
+

+ Sorry, an error occurred when trying to load the composition on this + page. +

+

+ Either its data is corrupted, or displaying it is no longer supported. +

+ +
+
+ ); +}; + /** * Create a component that represents a page which exposes some * aspect of its state in the current URL, so that it can be @@ -84,13 +108,16 @@ export function createPageWithShareableState({ */ const [isInOnChange, setIsInOnChange] = useState(false); - /** The default state from th URL, which we'll pass into our component. */ + /** The default state from the URL, which we'll pass into our component. */ let defaults: T = defaultValue; + let didDeserializeThrow = false; + try { defaults = deserialize(state || ""); } catch (e) { console.log(`Error deserializing state: ${e}`); + didDeserializeThrow = true; } const onChange = useCallback( @@ -115,7 +142,12 @@ export function createPageWithShareableState({ } }, [isInOnChange, state, latestState, key]); - return ; + return ( + <> + {didDeserializeThrow && } + + + ); }; return PageWithShareableState; diff --git a/lib/page.css b/lib/page.css index 3af522b..0a63fcc 100644 --- a/lib/page.css +++ b/lib/page.css @@ -116,3 +116,37 @@ ul.navbar li:last-child { .error { color: red; } + +.page-error { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + display: flex; + align-items: center; + justify-content: center; + background-color: rgba(0, 0, 0, 0.75); +} + +.page-error div { + background: crimson; + color: white; + padding: 2em; + max-width: 50em; +} + +.page-error div p:first-child { + margin-top: 0; +} + +.page-error div p:last-child { + margin-bottom: 0; +} + +.page-error div button { + display: block; + width: 66%; + margin: 3em auto 0 auto; + text-align: center; +}