mirror of
https://github.com/fankes/komari-theme-purcarte.git
synced 2025-10-18 19:39:22 +08:00
120 lines
3.6 KiB
TypeScript
120 lines
3.6 KiB
TypeScript
import { StrictMode, useState, lazy, Suspense, useEffect } from "react";
|
|
import { createRoot } from "react-dom/client";
|
|
import { BrowserRouter as Router, Routes, Route } from "react-router-dom";
|
|
import "./index.css";
|
|
import "@radix-ui/themes/styles.css";
|
|
import { Theme } from "@radix-ui/themes";
|
|
import { Header } from "@/components/sections/Header";
|
|
import { ConfigProvider } from "@/config";
|
|
import { useThemeManager, useTheme } from "@/hooks/useTheme";
|
|
import { ThemeProvider } from "@/contexts/ThemeContext";
|
|
import { NodeDataProvider } from "@/contexts/NodeDataContext";
|
|
import { LiveDataProvider } from "@/contexts/LiveDataContext";
|
|
import { useNodeData } from "@/contexts/NodeDataContext";
|
|
import Footer from "@/components/sections/Footer";
|
|
import Loading from "./components/loading";
|
|
|
|
const HomePage = lazy(() => import("@/pages/Home"));
|
|
const InstancePage = lazy(() => import("@/pages/instance"));
|
|
const NotFoundPage = lazy(() => import("@/pages/NotFound"));
|
|
const PrivatePage = lazy(() => import("@/pages/Private"));
|
|
|
|
import { useConfigItem } from "@/config";
|
|
|
|
// 内部应用组件,在 ConfigProvider 内部使用配置
|
|
export const AppContent = () => {
|
|
const { nodes } = useNodeData();
|
|
const { appearance, color } = useTheme();
|
|
const [searchTerm, setSearchTerm] = useState("");
|
|
const enableVideoBackground = useConfigItem("enableVideoBackground");
|
|
const videoBackgroundUrl = useConfigItem("videoBackgroundUrl");
|
|
|
|
// 动态设置 HTML 根元素的 dark 类
|
|
useEffect(() => {
|
|
const htmlElement = document.documentElement;
|
|
if (appearance === "dark") {
|
|
htmlElement.classList.add("dark");
|
|
} else {
|
|
htmlElement.classList.remove("dark");
|
|
}
|
|
}, [appearance]);
|
|
|
|
return (
|
|
<>
|
|
{enableVideoBackground && videoBackgroundUrl && (
|
|
<video
|
|
src={videoBackgroundUrl as string}
|
|
autoPlay
|
|
loop
|
|
muted
|
|
playsInline
|
|
className="fixed right-0 bottom-0 min-w-full min-h-full w-auto h-auto -z-1 object-cover"></video>
|
|
)}
|
|
<Theme
|
|
appearance={appearance}
|
|
accentColor={color}
|
|
scaling="110%"
|
|
style={{ backgroundColor: "transparent" }}>
|
|
<div className="min-h-screen flex flex-col text-sm">
|
|
<Header searchTerm={searchTerm} setSearchTerm={setSearchTerm} />
|
|
<Suspense fallback={<Loading />}>
|
|
{nodes === "private" ? (
|
|
<PrivatePage />
|
|
) : (
|
|
<Routes>
|
|
<Route
|
|
path="/"
|
|
element={
|
|
<HomePage
|
|
searchTerm={searchTerm}
|
|
setSearchTerm={setSearchTerm}
|
|
/>
|
|
}
|
|
/>
|
|
<Route path="/instance/:uuid" element={<InstancePage />} />
|
|
<Route path="*" element={<NotFoundPage />} />
|
|
</Routes>
|
|
)}
|
|
</Suspense>
|
|
<Footer />
|
|
</div>
|
|
</Theme>
|
|
</>
|
|
);
|
|
};
|
|
|
|
const ThemedApp = () => {
|
|
const themeManager = useThemeManager();
|
|
return (
|
|
<ThemeProvider value={themeManager}>
|
|
<AppContent />
|
|
</ThemeProvider>
|
|
);
|
|
};
|
|
|
|
const App = () => {
|
|
const { publicSettings, loading } = useNodeData();
|
|
|
|
if (loading) {
|
|
return <Loading />;
|
|
}
|
|
|
|
return (
|
|
<ConfigProvider publicSettings={publicSettings}>
|
|
<ThemedApp />
|
|
</ConfigProvider>
|
|
);
|
|
};
|
|
|
|
createRoot(document.getElementById("root")!).render(
|
|
<StrictMode>
|
|
<NodeDataProvider>
|
|
<LiveDataProvider>
|
|
<Router>
|
|
<App />
|
|
</Router>
|
|
</LiveDataProvider>
|
|
</NodeDataProvider>
|
|
</StrictMode>
|
|
);
|