mirror of
https://github.com/AmruthPillai/Reactive-Resume.git
synced 2026-07-17 00:30:05 +10:00
146 lines
5.0 KiB
TypeScript
146 lines
5.0 KiB
TypeScript
import "@fontsource-variable/ibm-plex-sans";
|
|
import "@phosphor-icons/web/regular/style.css";
|
|
import type { QueryClient } from "@tanstack/react-query";
|
|
|
|
import { i18n } from "@lingui/core";
|
|
import { I18nProvider } from "@lingui/react";
|
|
import { IconContext } from "@phosphor-icons/react";
|
|
import { createRootRouteWithContext, HeadContent, Scripts } from "@tanstack/react-router";
|
|
import { MotionConfig } from "motion/react";
|
|
|
|
import type { AuthSession } from "@/integrations/auth/types";
|
|
import type { FeatureFlags } from "@/integrations/orpc/services/flags";
|
|
|
|
import { CommandPalette } from "@/components/command-palette";
|
|
import { BreakpointIndicator } from "@/components/layout/breakpoint-indicator";
|
|
import { ThemeProvider } from "@/components/theme/provider";
|
|
import { Toaster } from "@/components/ui/sonner";
|
|
import { TooltipProvider } from "@/components/ui/tooltip";
|
|
import { DialogManager } from "@/dialogs/manager";
|
|
import { ConfirmDialogProvider } from "@/hooks/use-confirm";
|
|
import { PromptDialogProvider } from "@/hooks/use-prompt";
|
|
import { getSession } from "@/integrations/auth/functions";
|
|
import { client, type orpc } from "@/integrations/orpc/client";
|
|
import { getLocale, isRTL, type Locale, loadLocale } from "@/utils/locale";
|
|
import { getTheme, type Theme } from "@/utils/theme";
|
|
|
|
import appCss from "../styles/globals.css?url";
|
|
|
|
type RouterContext = {
|
|
theme: Theme;
|
|
locale: Locale;
|
|
orpc: typeof orpc;
|
|
queryClient: QueryClient;
|
|
session: AuthSession | null;
|
|
flags: FeatureFlags;
|
|
};
|
|
|
|
const appName = "Reactive Resume";
|
|
const tagline = "A free and open-source resume builder";
|
|
const title = `${appName} — ${tagline}`;
|
|
const description =
|
|
"Reactive Resume is a free and open-source resume builder that simplifies the process of creating, updating, and sharing your resume.";
|
|
|
|
await loadLocale(await getLocale());
|
|
|
|
export const Route = createRootRouteWithContext<RouterContext>()({
|
|
shellComponent: RootDocument,
|
|
head: () => {
|
|
const appUrl = process.env.APP_URL ?? "https://rxresu.me/";
|
|
|
|
return {
|
|
links: [
|
|
{ rel: "stylesheet", href: appCss },
|
|
// Icons
|
|
{ rel: "icon", href: "/favicon.ico", type: "image/x-icon", sizes: "128x128" },
|
|
{ rel: "icon", href: "/favicon.svg", type: "image/svg+xml", sizes: "256x256 any" },
|
|
{ rel: "apple-touch-icon", href: "/apple-touch-icon-180x180.png", type: "image/png", sizes: "180x180 any" },
|
|
// Manifest
|
|
{ rel: "manifest", href: "/manifest.webmanifest", crossOrigin: "use-credentials" },
|
|
],
|
|
meta: [
|
|
{ title },
|
|
{ charSet: "UTF-8" },
|
|
{ name: "description", content: description },
|
|
{ name: "viewport", content: "width=device-width, initial-scale=1" },
|
|
// Twitter Tags
|
|
{ property: "twitter:image", content: `${appUrl}/opengraph/banner.jpg` },
|
|
{ property: "twitter:card", content: "summary_large_image" },
|
|
{ property: "twitter:title", content: title },
|
|
{ property: "twitter:description", content: description },
|
|
// OpenGraph Tags
|
|
{ property: "og:image", content: `${appUrl}/opengraph/banner.jpg` },
|
|
{ property: "og:site_name", content: appName },
|
|
{ property: "og:title", content: title },
|
|
{ property: "og:description", content: description },
|
|
{ property: "og:url", content: appUrl },
|
|
],
|
|
// Register service worker via script tag
|
|
scripts: [
|
|
{
|
|
children: `
|
|
if('serviceWorker' in navigator) {
|
|
window.addEventListener('load', () => {
|
|
navigator.serviceWorker.register('/sw.js', { scope: '/' })
|
|
})
|
|
}
|
|
`,
|
|
},
|
|
],
|
|
};
|
|
},
|
|
beforeLoad: async () => {
|
|
const [theme, locale, session, flags] = await Promise.all([
|
|
getTheme(),
|
|
getLocale(),
|
|
getSession(),
|
|
client.flags.get(),
|
|
]);
|
|
|
|
return { theme, locale, session, flags };
|
|
},
|
|
});
|
|
|
|
type Props = {
|
|
children: React.ReactNode;
|
|
};
|
|
|
|
function RootDocument({ children }: Props) {
|
|
const { theme, locale } = Route.useRouteContext();
|
|
const dir = isRTL(locale) ? "rtl" : "ltr";
|
|
|
|
return (
|
|
<html suppressHydrationWarning dir={dir} lang={locale} className={theme}>
|
|
<head>
|
|
<HeadContent />
|
|
</head>
|
|
|
|
<body>
|
|
<MotionConfig reducedMotion="user">
|
|
<I18nProvider i18n={i18n}>
|
|
<IconContext.Provider value={{ size: 16, weight: "regular" }}>
|
|
<ThemeProvider theme={theme}>
|
|
<TooltipProvider>
|
|
<ConfirmDialogProvider>
|
|
<PromptDialogProvider>
|
|
{children}
|
|
|
|
<DialogManager />
|
|
<CommandPalette />
|
|
<Toaster richColors position="bottom-right" />
|
|
|
|
{import.meta.env.DEV && <BreakpointIndicator />}
|
|
</PromptDialogProvider>
|
|
</ConfirmDialogProvider>
|
|
</TooltipProvider>
|
|
</ThemeProvider>
|
|
</IconContext.Provider>
|
|
</I18nProvider>
|
|
</MotionConfig>
|
|
|
|
<Scripts />
|
|
</body>
|
|
</html>
|
|
);
|
|
}
|