wip
This commit is contained in:
commit
d8f2407ddf
44 changed files with 10377 additions and 0 deletions
38
src/lib/use-project.ts
Normal file
38
src/lib/use-project.ts
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
import { useCallback, useEffect, useState } from 'react';
|
||||
import type { UrlState } from './types';
|
||||
import { decodeState, encodeState } from './url-state';
|
||||
|
||||
/** The fragment is the durable source of truth. No local storage or server state. */
|
||||
export function useProject() {
|
||||
const [loaded, setLoaded] = useState(() => decodeState(window.location.hash));
|
||||
useEffect(() => {
|
||||
const restore = () => setLoaded(decodeState(window.location.hash));
|
||||
window.addEventListener('hashchange', restore);
|
||||
window.addEventListener('popstate', restore);
|
||||
if (!window.location.hash) window.history.replaceState(null, '', encodeState(loaded.state));
|
||||
return () => {
|
||||
window.removeEventListener('hashchange', restore);
|
||||
window.removeEventListener('popstate', restore);
|
||||
};
|
||||
}, []);
|
||||
const update = useCallback((transform: (current: UrlState) => UrlState, milestone = false) => {
|
||||
setLoaded((current) => {
|
||||
const next = transform(current.state);
|
||||
try {
|
||||
const hash = encodeState(next);
|
||||
if (hash !== window.location.hash)
|
||||
window.history[milestone ? 'pushState' : 'replaceState'](null, '', hash);
|
||||
const canonical = decodeState(hash).state;
|
||||
if (next.project === current.state.project) canonical.project = current.state.project;
|
||||
return { state: canonical, error: null };
|
||||
} catch (error) {
|
||||
return {
|
||||
...current,
|
||||
error:
|
||||
error instanceof Error ? error.message : 'This project could not be saved in the URL.',
|
||||
};
|
||||
}
|
||||
});
|
||||
}, []);
|
||||
return { ...loaded, update };
|
||||
}
|
||||
Loading…
Reference in a new issue