diff --git a/app/.gitignore b/app/.gitignore new file mode 100644 index 0000000..1521c8b --- /dev/null +++ b/app/.gitignore @@ -0,0 +1 @@ +dist diff --git a/app/web/package.json b/app/web/package.json index ab05c33..1b82c00 100644 --- a/app/web/package.json +++ b/app/web/package.json @@ -30,6 +30,7 @@ "monaco-editor-webpack-plugin": "^1.9.1", "netlify-identity-widget": "^1.9.1", "opencascade.js": "^0.1.15", + "pako": "^2.0.3", "prop-types": "^15.7.2", "react": "^17.0.1", "react-dom": "^17.0.1", @@ -44,10 +45,10 @@ "three": "^0.118.3" }, "devDependencies": { - "postcss": "^8.2.13", "autoprefixer": "^10.2.5", "html-webpack-plugin": "^4.5.0", "opentype.js": "^1.3.3", + "postcss": "^8.2.13", "postcss-loader": "4.0.2", "tailwindcss": "^2.1.2", "worker-loader": "^3.0.7" diff --git a/app/web/src/components/IdeToolbarNew/IdeToolbarNew.js b/app/web/src/components/IdeToolbarNew/IdeToolbarNew.js index dc12d73..3c5a2da 100644 --- a/app/web/src/components/IdeToolbarNew/IdeToolbarNew.js +++ b/app/web/src/components/IdeToolbarNew/IdeToolbarNew.js @@ -4,11 +4,13 @@ import { isBrowser } from '@redwoodjs/prerender/browserUtils' import { useIdeState, codeStorageKey } from 'src/helpers/hooks/useIdeState' import { copyTextToClipboard } from 'src/helpers/clipboard' import { requestRender } from 'src/helpers/hooks/useIdeState' +import { encode, decode } from 'src/helpers/compress' export const IdeContext = createContext() const IdeToolbarNew = ({ cadPackage }) => { const [state, thunkDispatch] = useIdeState() const scriptKey = 'encoded_script' + const scriptKeyV2 = 'encoded_script_v2' useEffect(() => { thunkDispatch({ type: 'initIde', @@ -19,9 +21,12 @@ const IdeToolbarNew = ({ cadPackage }) => { if (isBrowser) { hash = window.location.hash } - const [key, scriptBase64] = hash.slice(1).split('=') + const [key, encodedScript] = hash.slice(1).split('=') if (key === scriptKey) { - const script = atob(scriptBase64) + const script = atob(encodedScript) + thunkDispatch({ type: 'updateCode', payload: script }) + } else if (key === scriptKeyV2) { + const script = decode(encodedScript) thunkDispatch({ type: 'updateCode', payload: script }) } window.location.hash = '' @@ -43,8 +48,8 @@ const IdeToolbarNew = ({ cadPackage }) => { } function handleMakeLink() { if (isBrowser) { - const scriptBase64 = btoa(state.code) - window.location.hash = `encoded_script=${scriptBase64}` + const encodedScript = encode(state.code) + window.location.hash = `${scriptKeyV2}=${encodedScript}` copyTextToClipboard(window.location.href) } } diff --git a/app/web/src/helpers/compress.ts b/app/web/src/helpers/compress.ts new file mode 100644 index 0000000..9997d39 --- /dev/null +++ b/app/web/src/helpers/compress.ts @@ -0,0 +1,21 @@ +import { inflate, deflate } from 'pako' + +/* + some magic to get scripts to efficiently encoded into the URL. + We're using pako to compress the script, but this outputs to a 8bit array. Stringifying this array adds a lot of overhead, because "125" has three characters in it + Instead we're using the character codes to turn these a bit numbers into single characters + base64 is used as well because not all of the characters are allowed in a url (and b64 is better than encodeURIComponent) +*/ + +export const encode = (string: string): string => + btoa(String.fromCharCode.apply(null, deflate(string))) + +export const decode = (string: string): string => + inflate( + new Uint8Array( + atob(string) + .split('') + .map((character) => character.charCodeAt(0)) + ), + { to: 'string' } + ) diff --git a/app/yarn.lock b/app/yarn.lock index a4f2d4e..059eee6 100644 --- a/app/yarn.lock +++ b/app/yarn.lock @@ -11816,6 +11816,11 @@ p-try@^2.0.0: resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== +pako@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/pako/-/pako-2.0.3.tgz#cdf475e31b678565251406de9e759196a0ea7a43" + integrity sha512-WjR1hOeg+kki3ZIOjaf4b5WVcay1jaliKSYiEaB1XzwhMQZJxRdQRv0V31EKBYlxb4T7SK3hjfc/jxyU64BoSw== + pako@~1.0.5: version "1.0.11" resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.11.tgz#6c9599d340d54dfd3946380252a35705a6b992bf" @@ -13134,7 +13139,7 @@ react-docgen@^5.0.0: node-dir "^0.1.10" strip-indent "^3.0.0" -react-dom@17.0.1, react-dom@^17.0.1: +react-dom@^17.0.1: version "17.0.1" resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-17.0.1.tgz#1de2560474ec9f0e334285662ede52dbc5426fc6" integrity sha512-6eV150oJZ9U2t9svnsspTMrWNyHc6chX0KzDeAOXftRa8bNeOKTTfCJ7KorIwenkHd2xqVTBTCZd79yk/lx/Ug== @@ -13367,7 +13372,7 @@ react-use-measure@^2.0.3: dependencies: debounce "^1.2.0" -react@17.0.1, react@^17.0.1: +react@^17.0.1: version "17.0.1" resolved "https://registry.yarnpkg.com/react/-/react-17.0.1.tgz#6e0600416bd57574e3f86d92edba3d9008726127" integrity sha512-lG9c9UuMHdcAexXtigOZLX8exLWkW0Ku29qPRU8uhF2R9BN96dLCt0psvzPLlHc5OWkgymP3qwTRgbnw5BKx3w==