Skip to content

Commit

Permalink
feat(playground): persist settings/code to url (#334)
Browse files Browse the repository at this point in the history
- Fix accidental re-applying hash
  • Loading branch information
benjie authored and ifiokjr committed Jul 15, 2020
1 parent 1a3f5ee commit 3f3fa9f
Show file tree
Hide file tree
Showing 3 changed files with 114 additions and 0 deletions.
2 changes: 2 additions & 0 deletions packages/@remirror/playground/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@
"@remirror/react": "^1.0.0-next.1",
"@types/babel__core": "^7.1.9",
"@types/babel__standalone": "^7.1.2",
"@types/lz-string": "^1.3.34",
"lz-string": "^1.4.4",
"monaco-editor": "^0.20.0",
"monaco-editor-webpack-plugin": "^1.9.0",
"regenerator-runtime": "^0.13.5",
Expand Down
99 changes: 99 additions & 0 deletions packages/@remirror/playground/src/playground.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import assert from 'assert';
import { compressToEncodedURIComponent, decompressFromEncodedURIComponent } from 'lz-string';
import React, { FC, useCallback, useEffect, useRef, useState } from 'react';

import CodeEditor from './code-editor';
Expand Down Expand Up @@ -188,6 +190,80 @@ export const Playground: FC = () => {
}, 2000);
}, [code]);

const windowHash = window.location.hash;
const ourHash = useRef('');
const [readyToSetUrlHash, setReadyToSetUrlHash] = useState(false);
useEffect(() => {
if (windowHash && ourHash.current !== windowHash) {
ourHash.current = windowHash;
const parts = windowHash.replace(/^#+/, '').split('&');
const part = parts.find((p) => p.startsWith('o/'));

if (part) {
try {
const state = decode(part.slice(2));
console.log('Restoring state');
console.dir(state);
assert(typeof state === 'object' && state, 'Expected state to be an object');
assert(typeof state.m === 'number', 'Expected mode to be a number');

if (state.m === 0) {
/* basic mode */
setAdvanced(false);
setOptions({ extensions: state.e, presets: state.p });

if (Array.isArray(state.a)) {
state.a.forEach((moduleName: string) => addModule(moduleName));
}
} else if (state.m === 1) {
/* advanced mode */
assert(typeof state.c === 'string', 'Expected code to be a string');
const code = state.c;
setAdvanced(true);
setValue(code);
}
} catch (error) {
console.error(part.slice(2));
console.error('Failed to parse above state; failed with following error:');
console.error(error);
}
}
}

setReadyToSetUrlHash(true);
}, [windowHash, addModule]);

useEffect(() => {
if (!readyToSetUrlHash) {
/* Premature, we may not have finished reading it yet */
return;
}

let state;

if (!advanced) {
state = {
m: 0,
a: Object.keys(modules).filter((n) => !REQUIRED_MODULES.includes(n)),
e: options.extensions,
p: options.presets,
};
} else {
state = {
m: 1,
c: value,
};
}

const encoded = encode(state);
const hash = `#o/${encoded}`;

if (hash !== ourHash.current) {
ourHash.current = hash;
window.location.hash = hash;
}
}, [advanced, value, options, modules, readyToSetUrlHash]);

return (
<Container>
<Main>
Expand Down Expand Up @@ -256,3 +332,26 @@ const copy = (text: string) => {
document.execCommand('copy');
textarea.remove();
};

/**
* Decodes a URL component string to POJO.
*/
function decode(data: string) {
const json = decompressFromEncodedURIComponent(data);

if (!json) {
throw new Error('Failed to decode');
}

const obj = JSON.parse(json);
return obj;
}

/**
* Encodes a POJO to a URL component string
*/
function encode(obj: object): string {
const json = JSON.stringify(obj);
const data = compressToEncodedURIComponent(json);
return data;
}
13 changes: 13 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 comment on commit 3f3fa9f

@github-actions
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎉 Published on https://remirror.io as production
🚀 Deployed on https://5f0f3353d3260794450f5494--remirror.netlify.app

Please sign in to comment.