__root.tsx (4.03 KB)
import interWoff2 from "@fontsource-variable/inter/files/inter-latin-wght-normal.woff2?url";
import interUrl from "@fontsource-variable/inter/index.css?url";
import type { QueryClient } from "@tanstack/react-query";
import {
  createRootRouteWithContext,
  HeadContent,
  Outlet,
  Scripts,
  useRouterState,
} from "@tanstack/react-router";
import { TanStackRouterDevtools } from "@tanstack/react-router-devtools";
import { LoaderIcon } from "lucide-react";
import { useEffect, useState } from "react";
import { getSessionOptions } from "@/api/session";
import { NotFoundComponent } from "@/components/404-components";
import { Toaster } from "@/components/ui/sonner";
import { cn } from "@/lib/utils";
import appCss from "../index.css?url";

export type RouterAppContext = {
  queryClient: QueryClient;
};

export const Route = createRootRouteWithContext<RouterAppContext>()({
  head: () => ({
    meta: [
      {
        charSet: "utf-8",
      },
      {
        name: "viewport",
        content: "width=device-width, initial-scale=1",
      },
      {
        title: "Gitflare",
      },
      {
        property: "og:title",
        content: "Gitflare",
      },
      {
        property: "og:description",
        content:
          "Gitflare is a fully open-source serverless git hosting platform. No VMs, No Containers, Just Durable Objects.",
      },
      {
        property: "og:image",
        content: "https://gitflare.mdhruvil.com/og.png",
      },
      {
        property: "og:url",
        content: "https://gitflare.mdhruvil.com",
      },
      {
        property: "og:type",
        content: "website",
      },
      {
        property: "twitter:card",
        content: "summary_large_image",
      },
      {
        property: "twitter:image",
        content: "https://gitflare.mdhruvil.com/og.png",
      },
    ],
    links: [
      {
        rel: "stylesheet",
        href: appCss,
      },
      {
        rel: "stylesheet",
        href: interUrl,
      },
      {
        rel: "preload",
        as: "font",
        href: interWoff2,
        type: "font/woff2",
        crossOrigin: "anonymous",
      },
      {
        rel: "icon",
        href: "/logo.svg",
        type: "image/svg+xml",
      },
    ],
  }),
  loader: async ({ context: { queryClient } }) => {
    queryClient.prefetchQuery(getSessionOptions);
  },
  notFoundComponent: NotFoundComponent,
  component: RootDocument,
});

function RootDocument() {
  const isLoading = useRouterState({
    select: (s) => s.status === "pending",
  });

  const [canShowLoading, setShowLoading] = useState(false);

  useEffect(() => {
    const timeout = setTimeout(() => {
      setShowLoading(true);
    }, 2000);

    return () => {
      clearTimeout(timeout);
    };
  }, []);

  return (
    <html className="dark" lang="en">
      <head>
        <HeadContent />
      </head>
      <body>
        {canShowLoading && (
          <div
            className={cn(
              "-translate-y-full pointer-events-none fixed top-0 left-0 z-30 h-75 w-full opacity-0 backdrop-blur-md transition-all delay-0 duration-300 dark:h-50 dark:rounded-[100%] dark:bg-white/10!",
              isLoading && "-translate-y-[50%] opacity-100 delay-500"
            )}
            style={{
              background:
                "radial-gradient(closest-side, rgba(0,10,40,0.2) 0%, rgba(0,0,0,0) 100%)",
              maskImage:
                "radial-gradient(ellipse 70% 75% at 50% 40%, black 60%, transparent 80%)",
              WebkitMaskImage:
                "radial-gradient(ellipse 70% 75% at 50% 40%, black 60%, transparent 80%)",
            }}
          >
            <div
              className={
                "-translate-x-1/2 absolute top-1/2 left-1/2 z-50 translate-y-7.5 rounded-lg bg-white/80 p-2 shadow-lg dark:bg-gray-700"
              }
            >
              <LoaderIcon className="animate-spin text-3xl" />
            </div>
          </div>
        )}
        <Outlet />
        <Toaster richColors />
        <TanStackRouterDevtools position="bottom-left" />
        <Scripts />
      </body>
    </html>
  );
}