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>
);
}