Skip to article
Documentation

src/components/app-shell.tsx

Linked repository file from this build.

"use client";

import type { ReactNode } from "react";
import { isReviewWorkspace, PageSkeleton } from "./page-skeleton";
import { SiteNav, SiteToolbar } from "@/components/site-header";
import { useEffect, useLayoutEffect, useRef } from "react";
import { usePathname } from "next/navigation";
import { useReviewNavigation } from "@/features/reviews/provider";
import { useAppearance } from "@/components/appearance-provider";

/** Shared page frame; queue mode routes Home into Reviews with queues in navigation. */
export function AppShell({
  children,
  title,
  workspace = false,
}: {
  children: ReactNode;
  title: string;
  workspace?: boolean;
}) {
  const { appearance, ready } = useAppearance();
  const layout = ready ? appearance.layout : null;
  const { navigate, navigationTarget } = useReviewNavigation();
  const pathname = usePathname();
  const main = useRef<HTMLElement>(null);
  useLayoutEffect(() => {
    const element = main.current;
    if (element) element.style.setProperty("--page-scroll-offset", `${element.scrollTop}px`);
  }, [pathname, navigationTarget]);
  useEffect(() => {
    if (layout === "desk" && pathname === "/dashboard") void navigate("/reviews");
  }, [layout, pathname, navigate]);
  return (
    <div
      className="app-shell"
      data-workspace={
        (navigationTarget ? isReviewWorkspace(navigationTarget) : workspace) ? "" : undefined
      }
    >
      <SiteNav />
      <SiteToolbar title={title} />
      <main ref={main} className="app-main" aria-busy={navigationTarget ? true : undefined}>
        {navigationTarget && (
          <div className="page-transition-loading">
            <PageSkeleton pathname={navigationTarget} />
          </div>
        )}
        <div
          key={pathname}
          className="app-page-content"
          data-loading={navigationTarget ? "" : undefined}
          aria-hidden={navigationTarget ? true : undefined}
          inert={!!navigationTarget}
        >
          {children}
        </div>
      </main>
    </div>
  );
}