Spreadsheet-UX op een echte relationele engine

main

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

2.3 kB Ruw bestand
import { renderToString } from 'react-dom/server';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import type { Locale, PublicConfig, VoiceAssignment } from '@wellformed/shared';
import { MarketingScreen } from './components/MarketingScreen';
import { I18nProvider } from './i18n';
import { messages } from './i18n/messages';
import { SessionProvider } from './state/session';
import { ToastProvider } from './state/toasts';

/**
 * The marketing page as a string, for the server to hand to whoever has no
 * JavaScript yet: crawlers on the first wave, and every visitor for the first
 * few hundred milliseconds.
 *
 * This renders the same component the browser will render, through the same
 * providers as main.tsx, so the two can never drift apart the way a
 * hand-written static twin would. What is different is only what render-time
 * knows: the locale comes from the URL or the Accept-Language header instead
 * of a navigator, the public config is handed in instead of fetched, and the
 * voice assignment was drawn by the caller — the server records the
 * impression, embeds the assignment beside this HTML, and the client adopts
 * it rather than drawing a second one.
 *
 * Built with `vite build --ssr` into its own bundle with every dependency
 * inlined, so the API server can import one file and needs no React of its
 * own. Effects never run in renderToString: nothing here fetches, beats, or
 * scrolls.
 */
export function renderMarketing(input: {
  locale: Locale;
  config: PublicConfig;
  voice: VoiceAssignment | null;
}): string {
  const queryClient = new QueryClient();
  queryClient.setQueryData(['publicConfig'], input.config);

  try {
    return renderToString(
      <QueryClientProvider client={queryClient}>
        <ToastProvider>
          <SessionProvider>
            <I18nProvider locale={input.locale}>
              <MarketingScreen ssrVoice={input.voice} />
            </I18nProvider>
          </SessionProvider>
        </ToastProvider>
      </QueryClientProvider>,
    );
  } finally {
    queryClient.clear();
  }
}

/** The head lines that go with it, from the same catalog as the page. */
export function marketingMeta(locale: Locale): { title: string; description: string } {
  return {
    title: messages['marketing.metaTitle'][locale],
    description: messages['marketing.metaDescription'][locale],
  };
}