Spreadsheet-UX op een echte relationele engine
Deze repository wordt als momentopname gepubliceerd: een clone bevat de volledige inhoud, maar geen commitgeschiedenis.
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],
};
}