135 lines
4.5 KiB
TypeScript
135 lines
4.5 KiB
TypeScript
import { createRootRoute, createRoute, createRouter, lazyRouteComponent, redirect } from "@tanstack/react-router";
|
|
import type { ComponentType } from "react";
|
|
import { EmptyState } from "./components/console/empty-state.tsx";
|
|
import { Button } from "./components/ui/button.tsx";
|
|
import { parseUrlSearch, stringifyUrlSearch } from "./lib/router-compat.tsx";
|
|
import App from "./root.tsx";
|
|
|
|
type PageModule = { default: ComponentType; clientLoader?: (args: { request: Request }) => Promise<unknown> | unknown };
|
|
const modules = import.meta.glob<PageModule>("./routes/**/*.tsx");
|
|
|
|
async function loadPage(modulePath: string, href: string) {
|
|
const module = await modules[`./routes/${modulePath}.tsx`]?.();
|
|
if (!module) throw new Error(`路由模块不存在:${modulePath}`);
|
|
const result = await module.clientLoader?.({ request: new Request(new URL(href, window.location.origin)) });
|
|
if (result instanceof Response && result.status >= 300 && result.status < 400) {
|
|
const target = new URL(result.headers.get("Location") ?? "/console", window.location.origin);
|
|
throw redirect({
|
|
to: target.pathname,
|
|
search: parseUrlSearch(target.search),
|
|
hash: target.hash.slice(1),
|
|
replace: true,
|
|
} as never);
|
|
}
|
|
}
|
|
|
|
const rootRoute = createRootRoute({
|
|
component: App,
|
|
notFoundComponent: lazyRouteComponent(() => modules["./routes/not-found.tsx"]!()),
|
|
errorComponent: () => (
|
|
<main className="grid min-h-screen place-items-center bg-background px-4">
|
|
<EmptyState
|
|
title="页面加载失败"
|
|
description="刷新页面后重试。"
|
|
action={<Button onClick={() => window.location.reload()}>刷新页面</Button>}
|
|
/>
|
|
</main>
|
|
),
|
|
});
|
|
const indexRoute = createRoute({
|
|
getParentRoute: () => rootRoute,
|
|
path: "/",
|
|
beforeLoad: () => {
|
|
throw redirect({ to: "/console" } as never);
|
|
},
|
|
});
|
|
const loginRoute = createRoute({
|
|
getParentRoute: () => rootRoute,
|
|
path: "login",
|
|
component: lazyRouteComponent(() => modules["./routes/login.tsx"]!()),
|
|
});
|
|
const consoleRoute = createRoute({
|
|
getParentRoute: () => rootRoute,
|
|
path: "console",
|
|
component: lazyRouteComponent(() => modules["./routes/console/layout.tsx"]!()),
|
|
});
|
|
|
|
function page(path: string, modulePath: string) {
|
|
return createRoute({
|
|
getParentRoute: () => consoleRoute,
|
|
path,
|
|
component: lazyRouteComponent(() => modules[`./routes/console/${modulePath}.tsx`]!()),
|
|
beforeLoad: ({ location }) => loadPage(`console/${modulePath}`, location.href),
|
|
});
|
|
}
|
|
|
|
const agentRoute = createRoute({
|
|
getParentRoute: () => consoleRoute,
|
|
path: "agent",
|
|
component: lazyRouteComponent(() => modules["./routes/console/agent.tsx"]!()),
|
|
});
|
|
const agentIndexRoute = createRoute({
|
|
getParentRoute: () => agentRoute,
|
|
path: "/",
|
|
component: lazyRouteComponent(() => modules["./routes/console/agent._index.tsx"]!()),
|
|
});
|
|
const agentRunRoute = createRoute({
|
|
getParentRoute: () => agentRoute,
|
|
path: "$runId",
|
|
component: lazyRouteComponent(() => modules["./routes/console/agent.$runId.tsx"]!()),
|
|
});
|
|
|
|
const routeTree = rootRoute.addChildren([
|
|
indexRoute,
|
|
loginRoute,
|
|
consoleRoute.addChildren([
|
|
page("/", "home"),
|
|
page("inbox", "inbox"),
|
|
page("library", "library"),
|
|
page("library/$id", "library.$id"),
|
|
page("media/tmdb/$type/$id", "media.tmdb.$type.$id"),
|
|
page("identity", "identity"),
|
|
page("organize", "organize"),
|
|
page("organize/$id", "organize.$id"),
|
|
page("files", "files"),
|
|
page("files/trash", "files.trash"),
|
|
page("discover", "discover"),
|
|
page("subscriptions", "subscriptions"),
|
|
page("subscriptions/$id", "subscriptions.$id"),
|
|
page("preferences", "preferences"),
|
|
page("sites", "sites"),
|
|
page("sites/$siteId", "sites.$siteId"),
|
|
page("sources", "sources"),
|
|
page("rules", "rules"),
|
|
page("downloads", "downloads"),
|
|
page("downloads/plans", "downloads.plans"),
|
|
page("downloads/plans/$id", "downloads.plans"),
|
|
page("downloads/$id", "downloads.$id"),
|
|
page("tasks", "tasks"),
|
|
page("tasks/$id", "tasks.$id"),
|
|
agentRoute.addChildren([agentIndexRoute, agentRunRoute]),
|
|
page("engine", "engine"),
|
|
page("engine/$runId", "engine.$runId"),
|
|
page("audit", "audit"),
|
|
page("logs", "logs"),
|
|
page("settings", "settings"),
|
|
page("schedules", "schedules"),
|
|
page("search", "search"),
|
|
page("status", "status"),
|
|
]),
|
|
]);
|
|
|
|
export const router = createRouter({
|
|
routeTree,
|
|
parseSearch: parseUrlSearch,
|
|
stringifySearch: stringifyUrlSearch,
|
|
scrollRestoration: true,
|
|
defaultPreload: false,
|
|
});
|
|
|
|
declare module "@tanstack/react-router" {
|
|
interface Register {
|
|
router: typeof router;
|
|
}
|
|
}
|