File
Blob: src/client/server/document.tsx
| 1 | import type { ReactNode } from "react"; |
| 2 | |
| 3 | import { highlightThemeHref } from "@/client/highlight-theme"; |
| 4 | import type { DocumentAssets } from "./assets"; |
| 5 | |
| 6 | type DocumentProps = { |
| 7 | title?: string; |
| 8 | assets: DocumentAssets; |
| 9 | needsHighlight?: boolean; |
| 10 | children: ReactNode; |
| 11 | }; |
| 12 | |
| 13 | const initialHighlightThemeHref = highlightThemeHref.dark || highlightThemeHref.light; |
| 14 | const themeBootstrap = `(function(){try{var saved=localStorage.getItem("theme");var theme=saved==="light"?"light":"dark";var root=document.documentElement;root.dataset.theme=theme;root.classList.toggle("dark",theme==="dark");var hljs=document.getElementById("hljs-theme");var darkHref="${highlightThemeHref.dark}";var lightHref="${highlightThemeHref.light}";if(hljs&&(darkHref||lightHref)){var nextHref=theme==="dark"?darkHref:lightHref;if(nextHref){hljs.setAttribute("href",nextHref);}else{hljs.removeAttribute("href");}}}catch(_err){document.documentElement.dataset.theme="dark";document.documentElement.classList.add("dark");}})();`; |
| 15 | const reactRefreshPreamble = `import RefreshRuntime from "/@react-refresh";RefreshRuntime.injectIntoGlobalHook(window);window.$RefreshReg$=()=>{};window.$RefreshSig$=()=>type=>type;window.__vite_plugin_react_preamble_installed__=true;`; |
| 16 | |
| 17 | export function Document({ title, assets, needsHighlight = false, children }: DocumentProps) { |
| 18 | const pageTitle = title || "git-on-cloudflare"; |
| 19 | |
| 20 | return ( |
| 21 | <html className="h-full" lang="en"> |
| 22 | <head> |
| 23 | <meta charSet="utf-8" /> |
| 24 | <meta name="viewport" content="width=device-width, initial-scale=1" /> |
| 25 | <meta name="color-scheme" content="light dark" /> |
| 26 | <title>{pageTitle}</title> |
| 27 | <link rel="preconnect" href="https://fonts.googleapis.com" /> |
| 28 | <link rel="preconnect" href="https://fonts.gstatic.com" crossOrigin="anonymous" /> |
| 29 | <link |
| 30 | href="https://fonts.googleapis.com/css2?family=Hanken+Grotesk:wght@400..700&family=JetBrains+Mono:wght@400;500&family=IBM+Plex+Serif:wght@600;700&display=swap" |
| 31 | rel="stylesheet" |
| 32 | /> |
| 33 | {needsHighlight && initialHighlightThemeHref ? ( |
| 34 | <link id="hljs-theme" rel="stylesheet" href={initialHighlightThemeHref} /> |
| 35 | ) : null} |
| 36 | {import.meta.env.DEV ? ( |
| 37 | <script type="module" dangerouslySetInnerHTML={{ __html: reactRefreshPreamble }} /> |
| 38 | ) : null} |
| 39 | <script dangerouslySetInnerHTML={{ __html: themeBootstrap }} /> |
| 40 | {assets.preloads.map((href) => ( |
| 41 | <link key={href} rel="modulepreload" href={href} /> |
| 42 | ))} |
| 43 | {assets.styles.map((href) => ( |
| 44 | <link key={href} rel="stylesheet" href={href} /> |
| 45 | ))} |
| 46 | </head> |
| 47 | <body className="min-h-screen text-zinc-900 dark:text-zinc-100"> |
| 48 | {children} |
| 49 | {assets.moduleScripts.map((src) => ( |
| 50 | <script key={src} type="module" src={src}></script> |
| 51 | ))} |
| 52 | </body> |
| 53 | </html> |
| 54 | ); |
| 55 | } |