mirror of
https://github.com/aljazceru/claude-code-viewer.git
synced 2026-01-05 22:54:23 +01:00
fix not found page
This commit is contained in:
55
src/components/NotFound.tsx
Normal file
55
src/components/NotFound.tsx
Normal file
@@ -0,0 +1,55 @@
|
||||
import { Trans } from "@lingui/react";
|
||||
import { FileQuestion, Home } from "lucide-react";
|
||||
import type { FC, ReactNode } from "react";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import {
|
||||
Card,
|
||||
CardContent,
|
||||
CardDescription,
|
||||
CardHeader,
|
||||
CardTitle,
|
||||
} from "@/components/ui/card";
|
||||
|
||||
interface NotFoundProps {
|
||||
message?: ReactNode;
|
||||
description?: ReactNode;
|
||||
}
|
||||
|
||||
export const NotFound: FC<NotFoundProps> = ({
|
||||
message = <Trans id="notfound.default.title" message="Page Not Found" />,
|
||||
description = (
|
||||
<Trans
|
||||
id="notfound.default.description"
|
||||
message="The page you are looking for does not exist or has been moved."
|
||||
/>
|
||||
),
|
||||
}) => {
|
||||
return (
|
||||
<div className="flex min-h-screen items-center justify-center p-4">
|
||||
<Card className="w-full max-w-2xl">
|
||||
<CardHeader>
|
||||
<div className="flex items-center gap-3">
|
||||
<FileQuestion className="size-6 text-muted-foreground" />
|
||||
<div>
|
||||
<CardTitle>{message}</CardTitle>
|
||||
<CardDescription>{description}</CardDescription>
|
||||
</div>
|
||||
</div>
|
||||
</CardHeader>
|
||||
<CardContent className="space-y-4">
|
||||
<div className="flex gap-2">
|
||||
<Button
|
||||
onClick={() => {
|
||||
window.location.href = "/";
|
||||
}}
|
||||
variant="default"
|
||||
>
|
||||
<Home />
|
||||
<Trans id="notfound.button.go_home" message="Go to Home" />
|
||||
</Button>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -2,17 +2,13 @@ import { i18n } from "@lingui/core";
|
||||
import { I18nProvider } from "@lingui/react";
|
||||
import { type FC, type PropsWithChildren, useEffect } from "react";
|
||||
import { useConfig } from "../../app/hooks/useConfig";
|
||||
import { i18nMessages } from ".";
|
||||
|
||||
for (const { locale, messages } of i18nMessages) {
|
||||
i18n.load(locale, messages);
|
||||
}
|
||||
import { activateLocale } from ".";
|
||||
|
||||
export const LinguiClientProvider: FC<PropsWithChildren> = ({ children }) => {
|
||||
const { config } = useConfig();
|
||||
|
||||
useEffect(() => {
|
||||
i18n.activate(config.locale);
|
||||
void activateLocale(config.locale);
|
||||
}, [config.locale]);
|
||||
|
||||
return <I18nProvider i18n={i18n}>{children}</I18nProvider>;
|
||||
|
||||
@@ -1,20 +1,27 @@
|
||||
import type { Messages } from "@lingui/core";
|
||||
import { messages as enMessages } from "./locales/en/messages";
|
||||
import { messages as jaMessages } from "./locales/ja/messages";
|
||||
import { i18n } from "@lingui/core";
|
||||
import type { SupportedLocale } from "./schema";
|
||||
|
||||
export const locales: SupportedLocale[] = ["ja", "en"];
|
||||
|
||||
export const i18nMessages = [
|
||||
{
|
||||
locale: "ja",
|
||||
messages: jaMessages,
|
||||
},
|
||||
{
|
||||
locale: "en",
|
||||
messages: enMessages,
|
||||
},
|
||||
] as const satisfies Array<{
|
||||
locale: SupportedLocale;
|
||||
messages: Messages;
|
||||
}>;
|
||||
const importMessages = async (locale: SupportedLocale) => {
|
||||
switch (locale) {
|
||||
case "ja":
|
||||
return import("./locales/ja/messages");
|
||||
case "en":
|
||||
return import("./locales/en/messages");
|
||||
default:
|
||||
locale satisfies never;
|
||||
throw new Error(`Unsupported locale: ${locale}`);
|
||||
}
|
||||
};
|
||||
|
||||
const loadedLocales: SupportedLocale[] = [];
|
||||
export const activateLocale = async (locale: SupportedLocale) => {
|
||||
if (!loadedLocales.includes(locale)) {
|
||||
const { messages } = await importMessages(locale);
|
||||
i18n.load(locale, messages);
|
||||
loadedLocales.push(locale);
|
||||
}
|
||||
|
||||
i18n.activate(locale);
|
||||
};
|
||||
|
||||
@@ -1669,5 +1669,58 @@
|
||||
"comments": [],
|
||||
"origin": [["src/components/SettingsControls.tsx", 281]],
|
||||
"translation": "日本語"
|
||||
},
|
||||
"notfound.default.title": {
|
||||
"message": "Page Not Found",
|
||||
"placeholders": {},
|
||||
"comments": [],
|
||||
"origin": [["src/components/NotFound.tsx", 19]],
|
||||
"translation": "Page Not Found"
|
||||
},
|
||||
"notfound.default.description": {
|
||||
"message": "The page you are looking for does not exist or has been moved.",
|
||||
"placeholders": {},
|
||||
"comments": [],
|
||||
"origin": [["src/components/NotFound.tsx", 23]],
|
||||
"translation": "The page you are looking for does not exist or has been moved."
|
||||
},
|
||||
"notfound.button.go_home": {
|
||||
"message": "Go to Home",
|
||||
"placeholders": {},
|
||||
"comments": [],
|
||||
"origin": [["src/components/NotFound.tsx", 48]],
|
||||
"translation": "Go to Home"
|
||||
},
|
||||
"notfound.project.title": {
|
||||
"message": "Project Not Found",
|
||||
"placeholders": {},
|
||||
"comments": [],
|
||||
"origin": [["src/routes/projects/$projectId/latest/index.tsx", 15]],
|
||||
"translation": "Project Not Found"
|
||||
},
|
||||
"notfound.project.description": {
|
||||
"message": "The project you are looking for does not exist.",
|
||||
"placeholders": {},
|
||||
"comments": [],
|
||||
"origin": [["src/routes/projects/$projectId/latest/index.tsx", 19]],
|
||||
"translation": "The project you are looking for does not exist."
|
||||
},
|
||||
"notfound.session.title": {
|
||||
"message": "Session Not Found",
|
||||
"placeholders": {},
|
||||
"comments": [],
|
||||
"origin": [
|
||||
["src/routes/projects/$projectId/sessions/$sessionId/index.tsx", 13]
|
||||
],
|
||||
"translation": "Session Not Found"
|
||||
},
|
||||
"notfound.session.description": {
|
||||
"message": "The session you are looking for does not exist.",
|
||||
"placeholders": {},
|
||||
"comments": [],
|
||||
"origin": [
|
||||
["src/routes/projects/$projectId/sessions/$sessionId/index.tsx", 17]
|
||||
],
|
||||
"translation": "The session you are looking for does not exist."
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -1669,5 +1669,58 @@
|
||||
"comments": [],
|
||||
"origin": [["src/components/SettingsControls.tsx", 281]],
|
||||
"translation": "日本語"
|
||||
},
|
||||
"notfound.default.title": {
|
||||
"message": "Page Not Found",
|
||||
"placeholders": {},
|
||||
"comments": [],
|
||||
"origin": [["src/components/NotFound.tsx", 19]],
|
||||
"translation": "ページが見つかりません"
|
||||
},
|
||||
"notfound.default.description": {
|
||||
"message": "The page you are looking for does not exist or has been moved.",
|
||||
"placeholders": {},
|
||||
"comments": [],
|
||||
"origin": [["src/components/NotFound.tsx", 23]],
|
||||
"translation": "お探しのページは存在しないか、移動されました。"
|
||||
},
|
||||
"notfound.button.go_home": {
|
||||
"message": "Go to Home",
|
||||
"placeholders": {},
|
||||
"comments": [],
|
||||
"origin": [["src/components/NotFound.tsx", 48]],
|
||||
"translation": "ホームに戻る"
|
||||
},
|
||||
"notfound.project.title": {
|
||||
"message": "Project Not Found",
|
||||
"placeholders": {},
|
||||
"comments": [],
|
||||
"origin": [["src/routes/projects/$projectId/latest/index.tsx", 15]],
|
||||
"translation": "プロジェクトが見つかりません"
|
||||
},
|
||||
"notfound.project.description": {
|
||||
"message": "The project you are looking for does not exist.",
|
||||
"placeholders": {},
|
||||
"comments": [],
|
||||
"origin": [["src/routes/projects/$projectId/latest/index.tsx", 19]],
|
||||
"translation": "お探しのプロジェクトは存在しません。"
|
||||
},
|
||||
"notfound.session.title": {
|
||||
"message": "Session Not Found",
|
||||
"placeholders": {},
|
||||
"comments": [],
|
||||
"origin": [
|
||||
["src/routes/projects/$projectId/sessions/$sessionId/index.tsx", 13]
|
||||
],
|
||||
"translation": "セッションが見つかりません"
|
||||
},
|
||||
"notfound.session.description": {
|
||||
"message": "The session you are looking for does not exist.",
|
||||
"placeholders": {},
|
||||
"comments": [],
|
||||
"origin": [
|
||||
["src/routes/projects/$projectId/sessions/$sessionId/index.tsx", 17]
|
||||
],
|
||||
"translation": "お探しのセッションは存在しません。"
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -5,6 +5,7 @@ import ReactDOM from "react-dom/client";
|
||||
import { routeTree } from "./routeTree.gen";
|
||||
|
||||
import "./styles.css";
|
||||
import { NotFound } from "./components/NotFound";
|
||||
import { QueryClientProviderWrapper } from "./lib/api/QueryClientProviderWrapper";
|
||||
|
||||
const router = createRouter({
|
||||
@@ -14,6 +15,7 @@ const router = createRouter({
|
||||
scrollRestoration: true,
|
||||
defaultStructuralSharing: true,
|
||||
defaultPreloadStaleTime: 0,
|
||||
defaultNotFoundComponent: () => <NotFound />,
|
||||
});
|
||||
|
||||
declare module "@tanstack/react-router" {
|
||||
|
||||
@@ -1,12 +1,27 @@
|
||||
import { Trans } from "@lingui/react";
|
||||
import {
|
||||
createFileRoute,
|
||||
useLoaderData,
|
||||
useRouter,
|
||||
} from "@tanstack/react-router";
|
||||
import { NotFound } from "../../../../components/NotFound";
|
||||
import { honoClient } from "../../../../lib/api/client";
|
||||
|
||||
export const Route = createFileRoute("/projects/$projectId/latest/")({
|
||||
component: RouteComponent,
|
||||
notFoundComponent: () => (
|
||||
<NotFound
|
||||
message={
|
||||
<Trans id="notfound.project.title" message="Project Not Found" />
|
||||
}
|
||||
description={
|
||||
<Trans
|
||||
id="notfound.project.description"
|
||||
message="The project you are looking for does not exist."
|
||||
/>
|
||||
}
|
||||
/>
|
||||
),
|
||||
loader: async ({ params }) => {
|
||||
const { projectId } = params;
|
||||
const response = await honoClient.api.projects[":projectId"][
|
||||
|
||||
@@ -1,10 +1,25 @@
|
||||
import { Trans } from "@lingui/react";
|
||||
import { createFileRoute } from "@tanstack/react-router";
|
||||
import { SessionPageContent } from "../../../../../app/projects/[projectId]/sessions/[sessionId]/components/SessionPageContent";
|
||||
import { NotFound } from "../../../../../components/NotFound";
|
||||
|
||||
export const Route = createFileRoute(
|
||||
"/projects/$projectId/sessions/$sessionId/",
|
||||
)({
|
||||
component: RouteComponent,
|
||||
notFoundComponent: () => (
|
||||
<NotFound
|
||||
message={
|
||||
<Trans id="notfound.session.title" message="Session Not Found" />
|
||||
}
|
||||
description={
|
||||
<Trans
|
||||
id="notfound.session.description"
|
||||
message="The session you are looking for does not exist."
|
||||
/>
|
||||
}
|
||||
/>
|
||||
),
|
||||
});
|
||||
|
||||
function RouteComponent() {
|
||||
|
||||
Reference in New Issue
Block a user