Spreadsheet-UX op een echte relationele engine
Deze repository wordt als momentopname gepubliceerd: een clone bevat de volledige inhoud, maar geen commitgeschiedenis.
/**
* Where the browser is, in the four shapes Wellformed cares about.
*
* There is no router library and no client-side history here on purpose.
* A workspace is addressed by its path, and switching between workspaces is a
* real navigation: that way two tabs can hold two workspaces, links name the
* workspace they point at, and no cached query can survive into a workspace it
* was never fetched from. The grid's own state (table, view, filters) is not
* in the URL — it never was — so nothing else needs history at all.
*/
export type Route =
| { kind: 'workspace'; slug: string }
| { kind: 'signup' }
| { kind: 'signin' }
| { kind: 'invite'; token: string }
| { kind: 'forgot' }
| { kind: 'reset'; token: string }
| { kind: 'verify'; token: string }
| { kind: 'pricing' }
| { kind: 'home'; locale?: 'en' | 'nl' };
export function readRoute(pathname: string = window.location.pathname): Route {
const parts = pathname.split('/').filter(Boolean);
if (parts[0] === 'w' && parts[1]) return { kind: 'workspace', slug: decodeURIComponent(parts[1]) };
// The landing page, pinned to one language. `/` adapts to the browser; these
// exist so each language has a stable address search engines can index and
// hreflang can point at.
if (parts[0] === 'en' && !parts[1]) return { kind: 'home', locale: 'en' };
if (parts[0] === 'nl' && !parts[1]) return { kind: 'home', locale: 'nl' };
if (parts[0] === 'signup') return { kind: 'signup' };
if (parts[0] === 'signin' || parts[0] === 'login') return { kind: 'signin' };
if (parts[0] === 'invite' && parts[1]) return { kind: 'invite', token: decodeURIComponent(parts[1]) };
if (parts[0] === 'forgot') return { kind: 'forgot' };
if (parts[0] === 'reset' && parts[1]) return { kind: 'reset', token: decodeURIComponent(parts[1]) };
if (parts[0] === 'verify' && parts[1]) return { kind: 'verify', token: decodeURIComponent(parts[1]) };
if (parts[0] === 'pricing') return { kind: 'pricing' };
return { kind: 'home' };
}
export function workspacePath(slug: string): string {
return `/w/${encodeURIComponent(slug)}`;
}
/** A full navigation, deliberately — see the note at the top of this file. */
export function goTo(path: string): void {
window.location.assign(path);
}
/** Make a server-issued path (an invite link) absolute for copying and sharing. */
export function absolute(path: string): string {
return new URL(path, window.location.origin).toString();
}