diff --git a/apps/dashboard/src/components/layouts/not-found-screen.tsx b/apps/dashboard/src/components/layouts/not-found-screen.tsx new file mode 100644 index 0000000..26287ed --- /dev/null +++ b/apps/dashboard/src/components/layouts/not-found-screen.tsx @@ -0,0 +1,39 @@ +import { Button } from "@diffkit/ui/components/button"; +import { Logo } from "@diffkit/ui/components/logo"; +import { Link } from "@tanstack/react-router"; + +export function NotFoundScreen() { + return ( + + + + + + + 404 + + + Page not found + + + Check the URL or head back to your dashboard. + + + + + + Go to dashboard + + + + Sign in + + + + + + ); +} diff --git a/apps/dashboard/src/components/profile/pinned-repo-card.tsx b/apps/dashboard/src/components/profile/pinned-repo-card.tsx index 5f45a51..b5ce3de 100644 --- a/apps/dashboard/src/components/profile/pinned-repo-card.tsx +++ b/apps/dashboard/src/components/profile/pinned-repo-card.tsx @@ -1,12 +1,12 @@ import { GitForkIcon, StarIcon } from "@diffkit/icons"; +import { Link } from "@tanstack/react-router"; import type { PinnedRepo } from "#/lib/github.types"; export function PinnedRepoCard({ repo }: { repo: PinnedRepo }) { return ( - @@ -49,7 +49,7 @@ export function PinnedRepoCard({ repo }: { repo: PinnedRepo }) { )} - + ); } diff --git a/apps/dashboard/src/components/repo/repo-activity-cards.tsx b/apps/dashboard/src/components/repo/repo-activity-cards.tsx index c4466ea..03f3ba3 100644 --- a/apps/dashboard/src/components/repo/repo-activity-cards.tsx +++ b/apps/dashboard/src/components/repo/repo-activity-cards.tsx @@ -168,7 +168,7 @@ function ActivityCard({ function PullItem({ pr }: { pr: PullSummary }) { const { icon: StateIcon, color } = getPrStateConfig(pr); - const href = `/${pr.repository.owner}/${pr.repository.name}/pulls/${pr.number}`; + const href = `/${pr.repository.owner}/${pr.repository.name}/pull/${pr.number}`; return ( rootRouteImport, } as any) +const SplatRoute = SplatRouteImport.update({ + id: '/$', + path: '/$', + getParentRoute: () => rootRouteImport, +} as any) const ProtectedIndexRoute = ProtectedIndexRouteImport.update({ id: '/', path: '/', @@ -141,6 +147,7 @@ const ProtectedOwnerRepoIssuesIssueIdRoute = } as any) export interface FileRoutesByFullPath { + '/$': typeof SplatRoute '/': typeof ProtectedIndexRoute '/login': typeof LoginRoute '/privacy': typeof PrivacyRoute @@ -163,6 +170,7 @@ export interface FileRoutesByFullPath { '/$owner/$repo/review/$pullId': typeof ProtectedOwnerRepoReviewPullIdRoute } export interface FileRoutesByTo { + '/$': typeof SplatRoute '/login': typeof LoginRoute '/privacy': typeof PrivacyRoute '/setup': typeof SetupRoute @@ -185,6 +193,7 @@ export interface FileRoutesByTo { } export interface FileRoutesById { __root__: typeof rootRouteImport + '/$': typeof SplatRoute '/_protected': typeof ProtectedRouteWithChildren '/login': typeof LoginRoute '/privacy': typeof PrivacyRoute @@ -210,6 +219,7 @@ export interface FileRoutesById { export interface FileRouteTypes { fileRoutesByFullPath: FileRoutesByFullPath fullPaths: + | '/$' | '/' | '/login' | '/privacy' @@ -232,6 +242,7 @@ export interface FileRouteTypes { | '/$owner/$repo/review/$pullId' fileRoutesByTo: FileRoutesByTo to: + | '/$' | '/login' | '/privacy' | '/setup' @@ -253,6 +264,7 @@ export interface FileRouteTypes { | '/$owner/$repo/review/$pullId' id: | '__root__' + | '/$' | '/_protected' | '/login' | '/privacy' @@ -277,6 +289,7 @@ export interface FileRouteTypes { fileRoutesById: FileRoutesById } export interface RootRouteChildren { + SplatRoute: typeof SplatRoute ProtectedRoute: typeof ProtectedRouteWithChildren LoginRoute: typeof LoginRoute PrivacyRoute: typeof PrivacyRoute @@ -325,6 +338,13 @@ declare module '@tanstack/react-router' { preLoaderRoute: typeof ProtectedRouteImport parentRoute: typeof rootRouteImport } + '/$': { + id: '/$' + path: '/$' + fullPath: '/$' + preLoaderRoute: typeof SplatRouteImport + parentRoute: typeof rootRouteImport + } '/_protected/': { id: '/_protected/' path: '/' @@ -484,6 +504,7 @@ const ProtectedRouteWithChildren = ProtectedRoute._addFileChildren( ) const rootRouteChildren: RootRouteChildren = { + SplatRoute: SplatRoute, ProtectedRoute: ProtectedRouteWithChildren, LoginRoute: LoginRoute, PrivacyRoute: PrivacyRoute, diff --git a/apps/dashboard/src/router.tsx b/apps/dashboard/src/router.tsx index fe1c77d..c084434 100644 --- a/apps/dashboard/src/router.tsx +++ b/apps/dashboard/src/router.tsx @@ -1,6 +1,7 @@ import { createRouter as createTanStackRouter } from "@tanstack/react-router"; import { setupRouterSsrQueryIntegration } from "@tanstack/react-router-ssr-query"; import { DashboardErrorScreen } from "#/components/layouts/dashboard-error-screen"; +import { NotFoundScreen } from "#/components/layouts/not-found-screen"; import { AppQueryClientProvider, createAppQueryClient, @@ -19,6 +20,7 @@ export function getRouter() { defaultPreloadStaleTime: 0, defaultPendingMs: 0, defaultErrorComponent: DashboardErrorScreen, + defaultNotFoundComponent: NotFoundScreen, Wrap: ({ children }) => ( {children} diff --git a/apps/dashboard/src/routes/$.tsx b/apps/dashboard/src/routes/$.tsx new file mode 100644 index 0000000..ff43720 --- /dev/null +++ b/apps/dashboard/src/routes/$.tsx @@ -0,0 +1,18 @@ +import { createFileRoute, notFound } from "@tanstack/react-router"; +import { NotFoundScreen } from "#/components/layouts/not-found-screen"; +import { buildSeo, formatPageTitle } from "#/lib/seo"; + +export const Route = createFileRoute("/$")({ + beforeLoad: () => { + throw notFound(); + }, + head: ({ match }) => + buildSeo({ + path: match.pathname, + title: formatPageTitle("Page not found"), + description: "Check the URL or return to your dashboard.", + robots: "noindex", + includeCanonical: false, + }), + notFoundComponent: NotFoundScreen, +});
+ 404 +
+ Check the URL or head back to your dashboard. +