Spreadsheet-UX op een echte relationele engine

main

Deze repository wordt als momentopname gepubliceerd: een clone bevat de volledige inhoud, maar geen commitgeschiedenis.

2.4 kB Ruw bestand
/**
 * 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();
}