Files
ttstd-infinite-canvas/web/src/components/layout/app-providers.tsx

58 lines
3.0 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import type { ReactNode } from "react";
import { lazy, Suspense, useLayoutEffect } from "react";
import { QueryClientProvider } from "@tanstack/react-query";
import { App, ConfigProvider } from "antd";
import zhCN from "antd/locale/zh_CN";
import { AuthSessionHydrator } from "@/components/auth/auth-session-hydrator";
import { FullScreenLoader } from "@/components/ui/aceternity/full-screen-loader";
import { getAntThemeConfig } from "@/lib/app-theme";
import { applySkinTheme } from "@/lib/skin-themes";
import { appQueryClient } from "@/lib/query-client";
import { isIsolatedDirectorRepro } from "@/lib/dev-repro";
import { useActiveTheme } from "@/stores/canvas/use-canvas-theme-store";
import { applyAppearanceMetadata, useAppearanceStore } from "@/stores/use-appearance-store";
import { useUserStore } from "@/stores/use-user-store";
const ClientRootInit = lazy(() => import("@/components/layout/client-root-init").then((module) => ({ default: module.ClientRootInit })));
function ClientRootBoundary({ children }: { children: ReactNode }) {
const authenticated = useUserStore((state) => Boolean(state.user));
if (!authenticated) return children;
return <Suspense fallback={<FullScreenLoader label="正在准备创作环境" detail="连接本地能力与模型配置" />}><ClientRootInit>{children}</ClientRootInit></Suspense>;
}
export function AppProviders({ children }: { children: ReactNode }) {
const theme = useActiveTheme();
const dark = theme === "dark";
const appearance = useAppearanceStore((state) => state.appearance);
useLayoutEffect(() => {
document.documentElement.classList.toggle("dark", dark);
document.documentElement.style.colorScheme = theme;
applySkinTheme(appearance.activeSkin, theme);
applyAppearanceMetadata(appearance);
}, [appearance, dark, theme]);
// DEV 复现台必须是同源本地确定性场景:AuthSessionHydrator 会打 /api/auth/session,
// ClientRootInit 会打 /api/model-catalog,没有后端时产生真实 502,与导演台无关却会污染判据。
// 与启动入口共用精确路径边界;生产构建中 import.meta.env.DEV 为 false,始终不启用隔离。
const isolateDevRepro = typeof window !== "undefined" && isIsolatedDirectorRepro(import.meta.env.DEV, window.location.pathname);
return (
<ConfigProvider locale={zhCN} theme={getAntThemeConfig(dark, appearance.activeSkin)} wave={{ disabled: true }}>
<App message={{ duration: 3, maxCount: 3 }} notification={{ duration: 4.5, maxCount: 3, placement: "topRight" }}>
<QueryClientProvider client={appQueryClient}>
{isolateDevRepro ? (
children
) : (
<AuthSessionHydrator>
<ClientRootBoundary>{children}</ClientRootBoundary>
</AuthSessionHydrator>
)}
</QueryClientProvider>
</App>
</ConfigProvider>
);
}