···1-import { isRouteErrorResponse, Link, useRouteError } from "@remix-run/react";
2import { useEffect } from "react";
3import { useTranslation } from "react-i18next";
045import { Card } from "~/components/card";
6import { Main, RootLayout } from "~/components/layout";
···01import { useEffect } from "react";
2import { useTranslation } from "react-i18next";
3+import { isRouteErrorResponse, Link, useRouteError } from "react-router";
45import { Card } from "~/components/card";
6import { Main, RootLayout } from "~/components/layout";
+1-1
app/components/layout.tsx
···1import { LanguageIcon } from "@heroicons/react/24/outline";
2-import { Form, Link } from "@remix-run/react";
3import { type ReactNode, useRef } from "react";
4import GitHubButton from "react-github-btn";
5import { useTranslation } from "react-i18next";
067import { cn } from "~/utils/cn";
8
···1import { LanguageIcon } from "@heroicons/react/24/outline";
02import { type ReactNode, useRef } from "react";
3import GitHubButton from "react-github-btn";
4import { useTranslation } from "react-i18next";
5+import { Form, Link } from "react-router";
67import { cn } from "~/utils/cn";
8
+2-2
app/components/logout-button.tsx
···1-import { Form, useSubmit } from "@remix-run/react";
2import { useTranslation } from "react-i18next";
034import { Button } from "./button";
5···11 event.preventDefault();
12 const ok = confirm(t("logout-button.confirm-message"));
13 if (ok) {
14- submit(event.currentTarget);
15 }
16 void umami.track("handle-logout", {
17 action: ok ? "confirm" : "cancel",
···01import { useTranslation } from "react-i18next";
2+import { Form, useSubmit } from "react-router";
34import { Button } from "./button";
5···11 event.preventDefault();
12 const ok = confirm(t("logout-button.confirm-message"));
13 if (ok) {
14+ void submit(event.currentTarget);
15 }
16 void umami.track("handle-logout", {
17 action: ok ? "confirm" : "cancel",
+2-2
app/entry.client.tsx
···1-import { RemixBrowser } from "@remix-run/react";
2import i18next from "i18next";
3import I18nextBrowserLanguageDetector from "i18next-browser-languagedetector";
4import { startTransition, StrictMode } from "react";
5import { hydrateRoot } from "react-dom/client";
6import { I18nextProvider, initReactI18next } from "react-i18next";
07import { getInitialNamespaces } from "remix-i18next/client";
89import { i18nConfig } from "./i18n/config";
···23 document,
24 <I18nextProvider i18n={i18next}>
25 <StrictMode>
26- <RemixBrowser />
27 </StrictMode>
28 </I18nextProvider>,
29 );
···01import i18next from "i18next";
2import I18nextBrowserLanguageDetector from "i18next-browser-languagedetector";
3import { startTransition, StrictMode } from "react";
4import { hydrateRoot } from "react-dom/client";
5import { I18nextProvider, initReactI18next } from "react-i18next";
6+import { HydratedRouter } from "react-router/dom";
7import { getInitialNamespaces } from "remix-i18next/client";
89import { i18nConfig } from "./i18n/config";
···23 document,
24 <I18nextProvider i18n={i18next}>
25 <StrictMode>
26+ <HydratedRouter />
27 </StrictMode>
28 </I18nextProvider>,
29 );
+18-18
app/entry.server.tsx
···78import { PassThrough } from "node:stream";
90000010import type {
11 ActionFunctionArgs,
12 AppLoadContext,
13 EntryContext,
14 LoaderFunctionArgs,
15-} from "@remix-run/node";
16-import { createReadableStreamFromReadable } from "@remix-run/node";
17-import { isRouteErrorResponse, RemixServer } from "@remix-run/react";
18-import { createInstance } from "i18next";
19-import { isbot } from "isbot";
20-import { renderToPipeableStream } from "react-dom/server";
21-import { I18nextProvider, initReactI18next } from "react-i18next";
2223import { i18nConfig } from "./i18n/config";
24import { i18nServer } from "./i18n/i18n";
···29 request: Request,
30 responseStatusCode: number,
31 responseHeaders: Headers,
32- remixContext: EntryContext,
33 // This is ignored so we can keep it in the template for visibility. Feel
34 // free to delete this parameter in your app if you're not using it!
35···40 request,
41 responseStatusCode,
42 responseHeaders,
43- remixContext,
44 )
45 : handleBrowserRequest(
46 request,
47 responseStatusCode,
48 responseHeaders,
49- remixContext,
50 );
51}
52···54 request: Request,
55 responseStatusCode: number,
56 responseHeaders: Headers,
57- remixContext: EntryContext,
58) {
59 const instance = createInstance();
60 const lng = await i18nServer.getLocale(request);
61- const ns = i18nServer.getRouteNamespaces(remixContext);
62 await instance.use(initReactI18next).init({
63 ...i18nConfig,
64 lng,
···68 let shellRendered = false;
69 const { pipe, abort } = renderToPipeableStream(
70 <I18nextProvider i18n={instance}>
71- <RemixServer
72- context={remixContext}
73 url={request.url}
74 abortDelay={ABORT_DELAY}
75 />
···115 request: Request,
116 responseStatusCode: number,
117 responseHeaders: Headers,
118- remixContext: EntryContext,
119) {
120 const instance = createInstance();
121 const lng = await i18nServer.getLocale(request);
122- const ns = i18nServer.getRouteNamespaces(remixContext);
123 await instance.use(initReactI18next).init({
124 ...i18nConfig,
125 lng,
···129 let shellRendered = false;
130 const { pipe, abort } = renderToPipeableStream(
131 <I18nextProvider i18n={instance}>
132- <RemixServer
133- context={remixContext}
134 url={request.url}
135 abortDelay={ABORT_DELAY}
136 />
···78import { PassThrough } from "node:stream";
910+import { createReadableStreamFromReadable } from "@react-router/node";
11+import { createInstance } from "i18next";
12+import { isbot } from "isbot";
13+import { renderToPipeableStream } from "react-dom/server";
14+import { I18nextProvider, initReactI18next } from "react-i18next";
15import type {
16 ActionFunctionArgs,
17 AppLoadContext,
18 EntryContext,
19 LoaderFunctionArgs,
20+} from "react-router";
21+import { isRouteErrorResponse, ServerRouter } from "react-router";
000002223import { i18nConfig } from "./i18n/config";
24import { i18nServer } from "./i18n/i18n";
···29 request: Request,
30 responseStatusCode: number,
31 responseHeaders: Headers,
32+ reactRouterContext: EntryContext,
33 // This is ignored so we can keep it in the template for visibility. Feel
34 // free to delete this parameter in your app if you're not using it!
35···40 request,
41 responseStatusCode,
42 responseHeaders,
43+ reactRouterContext,
44 )
45 : handleBrowserRequest(
46 request,
47 responseStatusCode,
48 responseHeaders,
49+ reactRouterContext,
50 );
51}
52···54 request: Request,
55 responseStatusCode: number,
56 responseHeaders: Headers,
57+ reactRouterContext: EntryContext,
58) {
59 const instance = createInstance();
60 const lng = await i18nServer.getLocale(request);
61+ const ns = i18nServer.getRouteNamespaces(reactRouterContext);
62 await instance.use(initReactI18next).init({
63 ...i18nConfig,
64 lng,
···68 let shellRendered = false;
69 const { pipe, abort } = renderToPipeableStream(
70 <I18nextProvider i18n={instance}>
71+ <ServerRouter
72+ context={reactRouterContext}
73 url={request.url}
74 abortDelay={ABORT_DELAY}
75 />
···115 request: Request,
116 responseStatusCode: number,
117 responseHeaders: Headers,
118+ reactRouterContext: EntryContext,
119) {
120 const instance = createInstance();
121 const lng = await i18nServer.getLocale(request);
122+ const ns = i18nServer.getRouteNamespaces(reactRouterContext);
123 await instance.use(initReactI18next).init({
124 ...i18nConfig,
125 lng,
···129 let shellRendered = false;
130 const { pipe, abort } = renderToPipeableStream(
131 <I18nextProvider i18n={instance}>
132+ <ServerRouter
133+ context={reactRouterContext}
134 url={request.url}
135 abortDelay={ABORT_DELAY}
136 />
+1-1
app/features/board/board-viewer.tsx
···1import { PencilSquareIcon } from "@heroicons/react/24/outline";
2-import { Form, useNavigation } from "@remix-run/react";
3import { useState } from "react";
4import { useTranslation } from "react-i18next";
056import { Button } from "~/components/button";
7import type { ValidBoard } from "~/models/board";
···1import { PencilSquareIcon } from "@heroicons/react/24/outline";
02import { useState } from "react";
3import { useTranslation } from "react-i18next";
4+import { Form, useNavigation } from "react-router";
56import { Button } from "~/components/button";
7import type { ValidBoard } from "~/models/board";
+1-1
app/features/board/card/profile-card.tsx
···1import { PencilSquareIcon, ShareIcon } from "@heroicons/react/24/outline";
2import { UserIcon } from "@heroicons/react/24/solid";
3import type { User } from "@prisma/client";
4-import { Link } from "@remix-run/react";
5import { useState } from "react";
6import { useTranslation } from "react-i18next";
078import { Button } from "~/components/button";
9import { Card } from "~/components/card";
···1import { PencilSquareIcon, ShareIcon } from "@heroicons/react/24/outline";
2import { UserIcon } from "@heroicons/react/24/solid";
3import type { User } from "@prisma/client";
04import { useState } from "react";
5import { useTranslation } from "react-i18next";
6+import { Link } from "react-router";
78import { Button } from "~/components/button";
9import { Card } from "~/components/card";
+1-1
app/features/board/form/card-form.tsx
···5} from "@conform-to/react";
6import Picker from "@emoji-mart/react";
7import { XMarkIcon } from "@heroicons/react/24/outline";
8-import { Form } from "@remix-run/react";
9import { useState } from "react";
10import { useTranslation } from "react-i18next";
01112import { Button } from "~/components/button";
13import { Input } from "~/components/input";
···5} from "@conform-to/react";
6import Picker from "@emoji-mart/react";
7import { XMarkIcon } from "@heroicons/react/24/outline";
08import { useState } from "react";
9import { useTranslation } from "react-i18next";
10+import { Form } from "react-router";
1112import { Button } from "~/components/button";
13import { Input } from "~/components/input";
+1-1
app/features/board/share-modal.tsx
···2 ClipboardDocumentCheckIcon,
3 ClipboardIcon,
4} from "@heroicons/react/24/outline";
5-import { useSearchParams } from "@remix-run/react";
6import { useEffect, useRef, useState } from "react";
7import { useTranslation } from "react-i18next";
089import { Button } from "~/components/button";
10import { BlueskyIcon } from "~/components/icons/bluesky";
···2 ClipboardDocumentCheckIcon,
3 ClipboardIcon,
4} from "@heroicons/react/24/outline";
05import { useEffect, useRef, useState } from "react";
6import { useTranslation } from "react-i18next";
7+import { useSearchParams } from "react-router";
89import { Button } from "~/components/button";
10import { BlueskyIcon } from "~/components/icons/bluesky";
+1-1
app/features/login/login-form.tsx
···1import { getFormProps, getInputProps, useForm } from "@conform-to/react";
2import { getZodConstraint, parseWithZod } from "@conform-to/zod";
3import { AtSymbolIcon } from "@heroicons/react/24/outline";
4-import { Form, useNavigation } from "@remix-run/react";
5import { useTranslation } from "react-i18next";
06import { z } from "zod";
78import { Button } from "~/components/button";
···1import { getFormProps, getInputProps, useForm } from "@conform-to/react";
2import { getZodConstraint, parseWithZod } from "@conform-to/zod";
3import { AtSymbolIcon } from "@heroicons/react/24/outline";
04import { useTranslation } from "react-i18next";
5+import { Form, useNavigation } from "react-router";
6import { z } from "zod";
78import { Button } from "~/components/button";
+1-1
app/features/toast/route.tsx
···1-import { useActionData } from "@remix-run/react";
2import { useEffect } from "react";
034import { useToast } from "~/atoms/toast/hooks";
5
···01import { useEffect } from "react";
2+import { useActionData } from "react-router";
34import { useToast } from "~/atoms/toast/hooks";
5
+1-1
app/i18n/i18n.ts
···1-import { createCookie } from "@remix-run/node";
2import { RemixI18Next } from "remix-i18next/server";
34import { i18nConfig } from "./config";
···1+import { createCookie } from "react-router";
2import { RemixI18Next } from "remix-i18next/server";
34import { i18nConfig } from "./config";