diff --git a/packages/website/src/components/hooks/useHashState.ts b/packages/website/src/components/hooks/useHashState.ts index fa94232e89e..21538642891 100644 --- a/packages/website/src/components/hooks/useHashState.ts +++ b/packages/website/src/components/hooks/useHashState.ts @@ -2,6 +2,7 @@ import { toJsonConfig } from '@site/src/components/config/utils'; import * as lz from 'lzstring.ts'; import { useCallback, useEffect, useState } from 'react'; +import { hasOwnProperty } from '../lib/has-own-property'; import { shallowEqual } from '../lib/shallowEqual'; import type { ConfigModel } from '../types'; @@ -114,16 +115,69 @@ const writeStateToUrl = (newState: ConfigModel): string => { return ''; }; +const retrieveStateFromLocalStorage = (): Partial | undefined => { + try { + const configString = window.localStorage.getItem('config'); + if (!configString) { + return undefined; + } + + const config: unknown = JSON.parse(configString); + if (typeof config !== 'object' || !config) { + return undefined; + } + + const state: Partial = {}; + if (hasOwnProperty('ts', config)) { + const ts = config.ts; + if (typeof ts === 'string') { + state.ts = ts; + } + } + if (hasOwnProperty('jsx', config)) { + const jsx = config.jsx; + if (typeof jsx === 'boolean') { + state.jsx = jsx; + } + } + if (hasOwnProperty('showAST', config)) { + const showAST = config.showAST; + if (typeof showAST === 'boolean') { + state.showAST = showAST; + } else if (typeof showAST === 'string') { + state.showAST = readShowAST(showAST); + } + } + + return state; + } catch (e) { + // eslint-disable-next-line no-console + console.warn(e); + } + return undefined; +}; + +const writeStateToLocalStorage = (newState: ConfigModel): void => { + const config: Partial = { + ts: newState.ts, + jsx: newState.jsx, + showAST: newState.showAST, + }; + window.localStorage.setItem('config', JSON.stringify(config)); +}; + function useHashState( initialState: ConfigModel, ): [ConfigModel, (cfg: Partial) => void] { const [hash, setHash] = useState(window.location.hash.slice(1)); const [state, setState] = useState(() => ({ ...initialState, + ...retrieveStateFromLocalStorage(), ...parseStateFromUrl(window.location.hash.slice(1)), })); const [tmpState, setTmpState] = useState>(() => ({ ...initialState, + ...retrieveStateFromLocalStorage(), ...parseStateFromUrl(window.location.hash.slice(1)), })); @@ -141,6 +195,7 @@ function useHashState( useEffect(() => { const newState = { ...state, ...tmpState }; if (!shallowEqual(newState, state)) { + writeStateToLocalStorage(newState); const newHash = writeStateToUrl(newState); setState(newState); setHash(newHash); diff --git a/packages/website/src/components/lib/has-own-property.ts b/packages/website/src/components/lib/has-own-property.ts new file mode 100644 index 00000000000..eca42ee42fc --- /dev/null +++ b/packages/website/src/components/lib/has-own-property.ts @@ -0,0 +1,9 @@ +export function hasOwnProperty< + Container extends object, + Key extends PropertyKey, +>( + property: Key, + object: Container, +): object is Container & Record { + return property in object; +}