Skip to content

Commit 2a1477d

Browse files
committed
Error boundary and 404 page added
1 parent deee689 commit 2a1477d

File tree

14 files changed

+178
-9
lines changed

14 files changed

+178
-9
lines changed

.vscode/settings.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,5 +39,8 @@
3939
"Readme*": "AUTHORS, Authors, BACKERS*, Backers*, CHANGELOG*, CITATION*, CODEOWNERS, CODE_OF_CONDUCT*, CONTRIBUTING*, CONTRIBUTORS, COPYING*, CREDITS, Changelog*, Citation*, Code_Of_Conduct*, Codeowners, Contributing*, Contributors, Copying*, Credits, GOVERNANCE.MD, Governance.md, HISTORY.MD, History.md, LICENSE*, License*, MAINTAINERS, Maintainers, README-*, README_*, RELEASE_NOTES*, ROADMAP.MD, Readme-*, Readme_*, Release_Notes*, Roadmap.md, SECURITY.MD, SPONSORS*, Security.md, Sponsors*, authors, backers*, changelog*, citation*, code_of_conduct*, codeowners, contributing*, contributors, copying*, credits, governance.md, history.md, license*, maintainers, readme-*, readme_*, release_notes*, roadmap.md, security.md, sponsors*",
4040
"README*": "AUTHORS, Authors, BACKERS*, Backers*, CHANGELOG*, CITATION*, CODEOWNERS, CODE_OF_CONDUCT*, CONTRIBUTING*, CONTRIBUTORS, COPYING*, CREDITS, Changelog*, Citation*, Code_Of_Conduct*, Codeowners, Contributing*, Contributors, Copying*, Credits, GOVERNANCE.MD, Governance.md, HISTORY.MD, History.md, LICENSE*, License*, MAINTAINERS, Maintainers, README-*, README_*, RELEASE_NOTES*, ROADMAP.MD, Readme-*, Readme_*, Release_Notes*, Roadmap.md, SECURITY.MD, SPONSORS*, Security.md, Sponsors*, authors, backers*, changelog*, citation*, code_of_conduct*, codeowners, contributing*, contributors, copying*, credits, governance.md, history.md, license*, maintainers, readme-*, readme_*, release_notes*, roadmap.md, security.md, sponsors*",
4141
"Dockerfile": "*.dockerfile, .devcontainer.*, .dockerignore, captain-definition, compose.*, docker-compose.*, dockerfile*"
42+
},
43+
"[typescriptreact]": {
44+
"editor.defaultFormatter": "biomejs.biome"
4245
}
4346
}

app/entry.client.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import i18next from "i18next"
22
import LanguageDetector from "i18next-browser-languagedetector"
3-
import Fetch from "i18next-fetch-backend"
3+
import Backend from "i18next-http-backend"
44
import { StrictMode, startTransition } from "react"
55
import { hydrateRoot } from "react-dom/client"
66
import { I18nextProvider, initReactI18next } from "react-i18next"
@@ -13,7 +13,7 @@ async function hydrate() {
1313
await i18next
1414
.use(initReactI18next) // Tell i18next to use the react-i18next plugin
1515
.use(LanguageDetector) // Setup a client-side language detector
16-
.use(Fetch) // Setup your backend
16+
.use(Backend) // Setup your backend
1717
.init({
1818
...i18n, // spread the configuration
1919
// This function detects the namespaces your routes rendered while SSR use

app/library/icon/icons/icon.svg

Lines changed: 1 addition & 1 deletion
Loading

app/library/icon/icons/types.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// This file is generated by icon spritesheet generator
22

33
export const iconNames = [
4-
"ShoppingCart",
4+
"Ghost",
55
] as const
66

77
export type IconName = typeof iconNames[number]

app/root.tsx

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { useTranslation } from "react-i18next"
2-
import { Links, Meta, Outlet, Scripts, ScrollRestoration } from "react-router"
2+
import { Links, Meta, Outlet, Scripts, ScrollRestoration, isRouteErrorResponse, useRouteError } from "react-router"
33
import type { LinksFunction } from "react-router"
44
import { useChangeLanguage } from "remix-i18next/react"
55
import type { Route } from "./+types/root"
@@ -49,3 +49,21 @@ export const Layout = ({ children }: { children: React.ReactNode }) => {
4949
</html>
5050
)
5151
}
52+
53+
export const ErrorBoundary = () => {
54+
const error = useRouteError()
55+
const { t } = useTranslation()
56+
57+
const errorStatusCode = isRouteErrorResponse(error) ? error.status : "500"
58+
59+
return (
60+
<div className="placeholder-index relative h-full min-h-screen w-screen flex items-center justify-center dark:bg-white sm:pb-16 sm:pt-8">
61+
<div className="relative mx-auto max-w-[90rem] sm:px-6 lg:px-8">
62+
<div className="relative min-h-72 flex flex-col justify-center sm:overflow-hidden sm:rounded-2xl p-1 md:p-4 lg:p-6">
63+
<h1 className="text-center w-full text-red-600 text-2xl pb-2">{t(`error.${errorStatusCode}.title`)}</h1>
64+
<p className="text-lg text-center w-full">{t(`error.${errorStatusCode}.description`)}</p>
65+
</div>
66+
</div>
67+
</div>
68+
)
69+
}

app/routes/$.tsx

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import { useTranslation } from "react-i18next"
2+
import { Link, useNavigate } from "react-router"
3+
import { Icon } from "~/library/icon/Icon"
4+
5+
export default function Route404() {
6+
const navigate = useNavigate()
7+
const { t } = useTranslation()
8+
9+
return (
10+
<div className="min-h-screen bg-gradient-to-b from-gray-50 to-gray-100 flex items-center justify-center p-4">
11+
<div className="max-w-2xl w-full text-center">
12+
<div className="mb-8 flex justify-center">
13+
<Icon name="Ghost" className="h-24 w-24 text-indigo-600 animate-float" />
14+
</div>
15+
16+
<h1 className="text-6xl font-bold text-gray-900 mb-4">404</h1>
17+
<h2 className="text-3xl font-semibold text-gray-800 mb-4">{t("error.404.title")}</h2>
18+
<p className="text-gray-600 mb-8 text-lg">{t("error.404.description")}</p>
19+
20+
<div className="flex flex-col sm:flex-row gap-4 justify-center">
21+
<button
22+
type="button"
23+
onClick={() => navigate(-1)}
24+
className="inline-flex cursor-pointer items-center justify-center px-6 py-3 border border-transparent text-base font-medium rounded-md text-indigo-700 bg-indigo-100 hover:bg-indigo-200 transition-colors duration-300"
25+
>
26+
{t("navigation.back")}
27+
</button>
28+
<Link
29+
to="/"
30+
className="inline-flex cursor-pointer items-center justify-center px-6 py-3 border border-transparent text-base font-medium rounded-md text-white bg-indigo-600 hover:bg-indigo-700 transition-colors duration-300"
31+
>
32+
{t("navigation.home")}
33+
</Link>
34+
</div>
35+
</div>
36+
</div>
37+
)
38+
}

app/tailwind.css

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,15 @@
22

33
@theme {
44
/* Your theme styles go here */
5+
--animate-float: float 3s ease-in-out infinite;
6+
7+
@keyframes float {
8+
0%,
9+
100% {
10+
transform: translateY(0);
11+
}
12+
50% {
13+
transform: translateY(-10px);
14+
}
15+
}
516
}

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
"hono": "4.6.12",
3434
"i18next": "24.2.1",
3535
"i18next-browser-languagedetector": "8.0.0",
36-
"i18next-fetch-backend": "6.0.0",
36+
"i18next-http-backend": "3.0.2",
3737
"isbot": "5.1.17",
3838
"pretty-cache-header": "1.0.0",
3939
"react": "19.0.0",

pnpm-lock.yaml

Lines changed: 52 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

resources/icons/ghost.svg

Lines changed: 1 addition & 0 deletions
Loading

0 commit comments

Comments
 (0)