From 0b07d281d85b490e55ca1dc62d6f97199eacf8bf Mon Sep 17 00:00:00 2001 From: Gabriele Petronella Date: Fri, 18 Oct 2024 11:16:48 +0200 Subject: [PATCH] Add react-router-monorepo template --- templates/.gitignore | 4 + templates/react-router-monorepo/.gitignore | 9 ++ .../.vscode/settings.json | 4 + .../react-router-monorepo/apps/app/README.md | 40 +++++++ .../apps/app/app/defaultMessages.ts | 56 ++++++++++ .../apps/app/app/entry.client.tsx | 44 ++++++++ .../apps/app/app/entry.server.tsx | 103 ++++++++++++++++++ .../apps/app/app/i18n.ts | 22 ++++ .../apps/app/app/i18next.server.ts | 25 +++++ .../apps/app/app/root.css | 3 + .../apps/app/app/root.tsx | 60 ++++++++++ .../apps/app/app/routes.ts | 3 + .../apps/app/app/routes/index.tsx | 20 ++++ .../apps/app/package.json | 40 +++++++ .../apps/app/public/favicon.ico | Bin 0 -> 15086 bytes .../apps/app/public/locales/en.json | 42 +++++++ .../apps/app/public/locales/it.json | 41 +++++++ .../apps/app/tsconfig.json | 33 ++++++ .../apps/app/vite.config.ts | 11 ++ .../libs/design-system/.gitignore | 1 + .../libs/design-system/package.json | 30 +++++ .../libs/design-system/src/index.tsx | 14 +++ .../libs/design-system/tsconfig.json | 19 ++++ .../libs/design-system/tsup.config.ts | 11 ++ templates/react-router-monorepo/nx.json | 17 +++ templates/react-router-monorepo/package.json | 12 ++ .../react-router-monorepo/pnpm-workspace.yaml | 3 + templates/react-router-monorepo/tsconfig.json | 1 + 28 files changed, 668 insertions(+) create mode 100644 templates/.gitignore create mode 100644 templates/react-router-monorepo/.gitignore create mode 100644 templates/react-router-monorepo/.vscode/settings.json create mode 100644 templates/react-router-monorepo/apps/app/README.md create mode 100644 templates/react-router-monorepo/apps/app/app/defaultMessages.ts create mode 100644 templates/react-router-monorepo/apps/app/app/entry.client.tsx create mode 100644 templates/react-router-monorepo/apps/app/app/entry.server.tsx create mode 100644 templates/react-router-monorepo/apps/app/app/i18n.ts create mode 100644 templates/react-router-monorepo/apps/app/app/i18next.server.ts create mode 100644 templates/react-router-monorepo/apps/app/app/root.css create mode 100644 templates/react-router-monorepo/apps/app/app/root.tsx create mode 100644 templates/react-router-monorepo/apps/app/app/routes.ts create mode 100644 templates/react-router-monorepo/apps/app/app/routes/index.tsx create mode 100644 templates/react-router-monorepo/apps/app/package.json create mode 100644 templates/react-router-monorepo/apps/app/public/favicon.ico create mode 100644 templates/react-router-monorepo/apps/app/public/locales/en.json create mode 100644 templates/react-router-monorepo/apps/app/public/locales/it.json create mode 100644 templates/react-router-monorepo/apps/app/tsconfig.json create mode 100644 templates/react-router-monorepo/apps/app/vite.config.ts create mode 100644 templates/react-router-monorepo/libs/design-system/.gitignore create mode 100644 templates/react-router-monorepo/libs/design-system/package.json create mode 100644 templates/react-router-monorepo/libs/design-system/src/index.tsx create mode 100644 templates/react-router-monorepo/libs/design-system/tsconfig.json create mode 100644 templates/react-router-monorepo/libs/design-system/tsup.config.ts create mode 100644 templates/react-router-monorepo/nx.json create mode 100644 templates/react-router-monorepo/package.json create mode 100644 templates/react-router-monorepo/pnpm-workspace.yaml create mode 100644 templates/react-router-monorepo/tsconfig.json diff --git a/templates/.gitignore b/templates/.gitignore new file mode 100644 index 000000000..00da837c3 --- /dev/null +++ b/templates/.gitignore @@ -0,0 +1,4 @@ +package-lock.json +yarn.lock +pnpm-lock.yaml +pnpm-lock.yml diff --git a/templates/react-router-monorepo/.gitignore b/templates/react-router-monorepo/.gitignore new file mode 100644 index 000000000..e41e7acf2 --- /dev/null +++ b/templates/react-router-monorepo/.gitignore @@ -0,0 +1,9 @@ +node_modules + +/.cache +/build +.env +.react-router + +.nx/cache +.nx/workspace-data diff --git a/templates/react-router-monorepo/.vscode/settings.json b/templates/react-router-monorepo/.vscode/settings.json new file mode 100644 index 000000000..fae8e3d8a --- /dev/null +++ b/templates/react-router-monorepo/.vscode/settings.json @@ -0,0 +1,4 @@ +{ + "typescript.tsdk": "node_modules/typescript/lib", + "typescript.enablePromptUseWorkspaceTsdk": true +} diff --git a/templates/react-router-monorepo/apps/app/README.md b/templates/react-router-monorepo/apps/app/README.md new file mode 100644 index 000000000..08a5fb414 --- /dev/null +++ b/templates/react-router-monorepo/apps/app/README.md @@ -0,0 +1,40 @@ +# Welcome to React Router! + +- 📖 [React Router docs](https://reactrouter.com/dev) + +## Development + +Run the dev server: + +```shellscript +npm run dev +``` + +## Deployment + +First, build your app for production: + +```sh +npm run build +``` + +Then run the app in production mode: + +```sh +npm start +``` + +Now you'll need to pick a host to deploy it to. + +### DIY + +If you're familiar with deploying Node applications, the built-in app server is production-ready. + +Make sure to deploy the output of `npm run build` + +- `build/server` +- `build/client` + +## Styling + +This template comes with [Tailwind CSS](https://tailwindcss.com/) already configured for a simple default starting experience. You can use whatever CSS framework you prefer. diff --git a/templates/react-router-monorepo/apps/app/app/defaultMessages.ts b/templates/react-router-monorepo/apps/app/app/defaultMessages.ts new file mode 100644 index 000000000..dd3f88762 --- /dev/null +++ b/templates/react-router-monorepo/apps/app/app/defaultMessages.ts @@ -0,0 +1,56 @@ +import { ComponentProps } from "react"; +import { BentoProvider } from "design-system"; +import { useTranslation } from "react-i18next"; + +export const useDefaultMessages = (): ComponentProps["defaultMessages"] => { + const { t } = useTranslation(); + + return { + Chip: { + dismissButtonLabel: t("common.chip.dismissButtonLabel", "Remove"), + }, + Banner: { + dismissButtonLabel: t("common.banner.dismissButtonLabel", "Close"), + }, + Modal: { + closeButtonLabel: t("common.modal.closeButtonLabel", "Close"), + }, + SelectField: { + noOptionsMessage: t("common.selectField.noOptionsMessage", "No options"), + multiOptionsSelected: (n) => { + const options = + n > 1 + ? t("common.selectField.optionsPlural", "options") + : t("common.selectField.optionsSingular", "option"); + return t("common.selectField.multiOptionsSelected", "{{n}} {{options}} selected", { + n, + options, + }); + }, + selectAllButtonLabel: t("common.selectField.selectAllButtonLabel", "Select all"), + clearAllButtonLabel: t("common.selectField.clearAllButtonLabel", "Clear all"), + }, + SearchBar: { + clearButtonLabel: t("common.searchBar.clearButtonLabel", "Clear"), + }, + Table: { + noResultsTitle: t("common.table.noResultsTitle", "No results found"), + noResultsDescription: t( + "common.table.noResultsDescription", + "Try adjusting your search filters to find what you're looking for." + ), + missingValue: t("common.table.missingValue", "-"), + }, + Loader: { + loadingMessage: t("common.loader.loadingMessage", "Loading..."), + }, + DateField: { + previousMonthLabel: t("common.dateField.previousMonthLabel", "Prev month"), + nextMonthLabel: t("common.dateField.nextMonthLabel", "Next month"), + }, + TextField: { + showPasswordLabel: t("common.textField.showPasswordLabel", "Show password"), + hidePasswordLabel: t("common.textField.hidePasswordLabel", "Hide password"), + }, + }; +}; diff --git a/templates/react-router-monorepo/apps/app/app/entry.client.tsx b/templates/react-router-monorepo/apps/app/app/entry.client.tsx new file mode 100644 index 000000000..cb79b329b --- /dev/null +++ b/templates/react-router-monorepo/apps/app/app/entry.client.tsx @@ -0,0 +1,44 @@ +import { startTransition, StrictMode } from "react"; +import { hydrateRoot } from "react-dom/client"; +import { HydratedRouter } from "react-router/dom"; +import i18n, { registerCustomFormats } from "./i18n"; +import i18next from "i18next"; +import { I18nextProvider, initReactI18next } from "react-i18next"; +import LanguageDetector from "i18next-browser-languagedetector"; +import Backend from "i18next-http-backend"; + +await i18next + .use(initReactI18next) // Tell i18next to use the react-i18next plugin + .use(LanguageDetector) // Setup a client-side language detector + .use(Backend) // Setup your backend + .init({ + ...i18n, // spread the configuration + // This function detects the namespaces your routes rendered while SSR use + ns: [], + backend: { loadPath: "/locales/{{lng}}.json" }, + detection: { + // Here only enable htmlTag detection, we'll detect the language only + // server-side with remix-i18next, by using the `` attribute + // we can communicate to the client the language detected server-side + order: ["htmlTag"], + // Because we only use htmlTag, there's no reason to cache the language + // on the browser, so we disable it + caches: [], + }, + }); + +registerCustomFormats(i18next); + +console.log(I18nextProvider); +console.log(i18next); + +startTransition(() => { + hydrateRoot( + document, + + + + + + ); +}); diff --git a/templates/react-router-monorepo/apps/app/app/entry.server.tsx b/templates/react-router-monorepo/apps/app/app/entry.server.tsx new file mode 100644 index 000000000..fbcd908d5 --- /dev/null +++ b/templates/react-router-monorepo/apps/app/app/entry.server.tsx @@ -0,0 +1,103 @@ +import { PassThrough } from "node:stream"; + +import type { AppLoadContext, EntryContext } from "react-router"; +import { createReadableStreamFromReadable } from "@react-router/node"; +import { ServerRouter } from "react-router"; +import { isbot } from "isbot"; +import type { RenderToPipeableStreamOptions } from "react-dom/server"; +import { renderToPipeableStream } from "react-dom/server"; +import { createInstance } from "i18next"; +import i18next from "./i18next.server"; +import { I18nextProvider, initReactI18next } from "react-i18next"; +import Backend from "i18next-fs-backend"; +import i18n, { registerCustomFormats } from "./i18n"; // your i18n configuration file +import * as path from "node:path"; + +const ABORT_DELAY = 5_000; + +// Override console.erro to suppress specific warnings +const originalConsoleError = console.error; +console.error = (msg, ...args) => { + if (typeof msg === "string" && msg.includes("useLayoutEffect")) { + return; + } + if (typeof msg === "string" && msg.includes("A props object containing")) { + return; + } + originalConsoleError(msg, ...args); +}; + +export default function handleRequest( + request: Request, + responseStatusCode: number, + responseHeaders: Headers, + routerContext: EntryContext, + loadContext: AppLoadContext +) { + return new Promise(async (resolve, reject) => { + let shellRendered = false; + let userAgent = request.headers.get("user-agent"); + + // Ensure requests from bots and SPA Mode renders wait for all content to load before responding + // https://react.dev/reference/react-dom/server/renderToPipeableStream#waiting-for-all-content-to-load-for-crawlers-and-static-generation + let readyOption: keyof RenderToPipeableStreamOptions = + (userAgent && isbot(userAgent)) || routerContext.isSpaMode ? "onAllReady" : "onShellReady"; + + let instance = createInstance(); + let lng = await i18next.getLocale(request); + // let ns = i18next.getRouteNamespaces(routerContext); + let ns = ["translation"] as string[]; + + await instance + .use(initReactI18next) // Tell our instance to use react-i18next + .use(Backend) // Setup our backend + .init({ + ...i18n, // spread the configuration + lng, // The locale we detected above + ns, // The namespaces the routes about to render wants to use + backend: { + loadPath: path.resolve("./public/locales/{{lng}}.json"), + }, + }); + + registerCustomFormats(instance); + + const { pipe, abort } = renderToPipeableStream( + + , + , + { + [readyOption]() { + shellRendered = true; + const body = new PassThrough(); + const stream = createReadableStreamFromReadable(body); + + responseHeaders.set("Content-Type", "text/html"); + + resolve( + new Response(stream, { + headers: responseHeaders, + status: responseStatusCode, + }) + ); + + pipe(body); + }, + onShellError(error: unknown) { + reject(error); + }, + onError(error: unknown) { + responseStatusCode = 500; + // Log streaming rendering errors from inside the shell. Don't log + // errors encountered during initial shell rendering since they'll + // reject and get logged in handleDocumentRequest. + if (shellRendered) { + console.error(error); + } + }, + } + ); + + setTimeout(abort, ABORT_DELAY); + }); +} diff --git a/templates/react-router-monorepo/apps/app/app/i18n.ts b/templates/react-router-monorepo/apps/app/app/i18n.ts new file mode 100644 index 000000000..69c11e934 --- /dev/null +++ b/templates/react-router-monorepo/apps/app/app/i18n.ts @@ -0,0 +1,22 @@ +import type { i18n, InitOptions } from "i18next"; +import type en from "../public/locales/en.json"; + +export default { + supportedLngs: ["en", "it"], + fallbackLng: "en", +} satisfies InitOptions; + +export function registerCustomFormats(i18n: i18n) { + i18n.services.formatter?.add("capitalize", (value: string) => { + return value.charAt(0).toUpperCase() + value.slice(1); + }); +} + +declare module "i18next" { + interface CustomTypeOptions { + defaultNS: "translation"; + resources: { + translation: typeof en; + }; + } +} diff --git a/templates/react-router-monorepo/apps/app/app/i18next.server.ts b/templates/react-router-monorepo/apps/app/app/i18next.server.ts new file mode 100644 index 000000000..9a876a91f --- /dev/null +++ b/templates/react-router-monorepo/apps/app/app/i18next.server.ts @@ -0,0 +1,25 @@ +import Backend from "i18next-fs-backend"; +import { resolve } from "node:path"; +import { RemixI18Next } from "remix-i18next/server"; +import i18n from "./i18n"; + +const i18next = new RemixI18Next({ + detection: { + supportedLanguages: i18n.supportedLngs, + fallbackLanguage: i18n.fallbackLng, + }, + // This is the configuration for i18next used + // when translating messages server-side only + i18next: { + ...i18n, + backend: { + loadPath: resolve("./public/locales/{{lng}}.json"), + }, + }, + // The i18next plugins you want RemixI18next to use for `i18n.getFixedT` inside loaders and actions. + // E.g. The Backend plugin for loading translations from the file system + // Tip: You could pass `resources` to the `i18next` configuration and avoid a backend here + plugins: [Backend], +}); + +export default i18next; diff --git a/templates/react-router-monorepo/apps/app/app/root.css b/templates/react-router-monorepo/apps/app/app/root.css new file mode 100644 index 000000000..ae8973b44 --- /dev/null +++ b/templates/react-router-monorepo/apps/app/app/root.css @@ -0,0 +1,3 @@ +body { + height: 100vh; +} diff --git a/templates/react-router-monorepo/apps/app/app/root.tsx b/templates/react-router-monorepo/apps/app/app/root.tsx new file mode 100644 index 000000000..8bba2d2c2 --- /dev/null +++ b/templates/react-router-monorepo/apps/app/app/root.tsx @@ -0,0 +1,60 @@ +import { + Link, + Links, + LinksFunction, + Meta, + Outlet, + Scripts, + ScrollRestoration, +} from "react-router"; +import "design-system/index.css"; +import { BentoProvider, Children } from "design-system"; +import "./root.css"; +import i18next from "./i18next.server"; +import type * as Route from "./+types.root"; +import { useChangeLanguage } from "remix-i18next/react"; +import { useTranslation } from "react-i18next"; +import { useDefaultMessages } from "./defaultMessages"; + +export const links: LinksFunction = () => []; + +export async function loader({ request }: Route.LoaderArgs) { + let locale = await i18next.getLocale(request); + return { locale }; +} + +export function Layout({ children }: { children: React.ReactNode }) { + const { i18n } = useTranslation(); + const defaultMessages = useDefaultMessages(); + return ( + + + + + + + + + { + if (href.startsWith("/")) { + return ; + } + return ; + }} + > + {children as Children} + + + + + + ); +} + +export default function App({ loaderData }: Route.ComponentProps) { + useChangeLanguage(loaderData.locale); + + return ; +} diff --git a/templates/react-router-monorepo/apps/app/app/routes.ts b/templates/react-router-monorepo/apps/app/app/routes.ts new file mode 100644 index 000000000..ac9a5d42e --- /dev/null +++ b/templates/react-router-monorepo/apps/app/app/routes.ts @@ -0,0 +1,3 @@ +import { type RouteConfig, index } from "@react-router/dev/routes"; + +export const routes: RouteConfig = [index("routes/index.tsx")]; diff --git a/templates/react-router-monorepo/apps/app/app/routes/index.tsx b/templates/react-router-monorepo/apps/app/app/routes/index.tsx new file mode 100644 index 000000000..ed5bdb80a --- /dev/null +++ b/templates/react-router-monorepo/apps/app/app/routes/index.tsx @@ -0,0 +1,20 @@ +import { Headline, Inline, Inset } from "design-system"; +import type * as Route from "./+types.index"; + +export function loader({ request }: Route.LoaderArgs) { + const url = new URL(request.url); + const message = url.searchParams.get("message"); + return { + message: message ?? "Hello, Bento!", + }; +} + +export default function Index({ loaderData }: Route.ComponentProps) { + return ( + + + {loaderData.message} + + + ); +} diff --git a/templates/react-router-monorepo/apps/app/package.json b/templates/react-router-monorepo/apps/app/package.json new file mode 100644 index 000000000..5eca5389f --- /dev/null +++ b/templates/react-router-monorepo/apps/app/package.json @@ -0,0 +1,40 @@ +{ + "name": "app", + "private": true, + "sideEffects": false, + "type": "module", + "scripts": { + "dev": "react-router dev", + "build": "react-router build", + "start": "react-router-serve ./build/server/index.js", + "typecheck": "react-router typegen && tsc", + "generate:types": "react-router typegen" + }, + "dependencies": { + "@react-router/node": "7.0.0-pre.1", + "@react-router/serve": "7.0.0-pre.1", + "design-system": "workspace:*", + "i18next": "^23.16.0", + "i18next-browser-languagedetector": "^8.0.0", + "i18next-fs-backend": "^2.3.2", + "i18next-http-backend": "^2.6.2", + "isbot": "^5.1.17", + "react": "^18.3.1", + "react-dom": "^18.3.1", + "react-i18next": "^15.0.3", + "react-router": "7.0.0-pre.1", + "remix-i18next": "^6.4.1" + }, + "devDependencies": { + "@react-router/dev": "7.0.0-pre.1", + "@types/react": "^18.3.9", + "@types/react-dom": "^18.3.0", + "typescript": "^5.6.2", + "vite": "^5.4.8", + "vite-plugin-checker": "^0.8.0", + "vite-tsconfig-paths": "^5.0.1" + }, + "engines": { + "node": ">=20.0.0" + } +} diff --git a/templates/react-router-monorepo/apps/app/public/favicon.ico b/templates/react-router-monorepo/apps/app/public/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..5dbdfcddcb14182535f6d32d1c900681321b1aa3 GIT binary patch literal 15086 zcmeI33v3ic7{|AFEmuJ-;v>ep_G*NPi6KM`qNryCe1PIJ8siIN1WZ(7qVa)RVtmC% z)Ch?tN+afMKm;5@rvorJk zcXnoOc4q51HBQnQH_jn!cAg&XI1?PlX>Kl^k8qq0;zkha`kY$Fxt#=KNJAE9CMdpW zqr4#g8`nTw191(+H4xW8Tmyru2I^3=J1G3emPxkPXA=3{vvuvse_WWSshqaqls^-m zgB7q8&Vk*aYRe?sn$n53dGH#%3y%^vxv{pL*-h0Z4bmb_(k6{FL7HWIz(V*HT#IcS z-wE{)+0x1U!RUPt3gB97%p}@oHxF4|6S*+Yw=_tLtxZ~`S=z6J?O^AfU>7qOX`JNBbV&8+bO0%@fhQitKIJ^O^ zpgIa__qD_y07t@DFlBJ)8SP_#^j{6jpaXt{U%=dx!qu=4u7^21lWEYHPPY5U3TcoQ zX_7W+lvZi>TapNk_X>k-KO%MC9iZp>1E`N34gHKd9tK&){jq2~7OsJ>!G0FzxQFw6G zm&Vb(2#-T|rM|n3>uAsG_hnbvUKFf3#ay@u4uTzia~NY%XgCHfx4^To4BDU@)HlV? z@EN=g^ymETa1sQK{kRwyE4Ax8?wT&GvaG@ASO}{&a17&^v`y z!oPdiSiia^oov(Z)QhG2&|FgE{M9_4hJROGbnj>#$~ZF$-G^|zPj*QApltKe?;u;uKHJ~-V!=VLkg7Kgct)l7u39f@%VG8e3f$N-B zAu3a4%ZGf)r+jPAYCSLt73m_J3}p>}6Tx0j(wg4vvKhP!DzgiWANiE;Ppvp}P2W@m z-VbYn+NXFF?6ngef5CfY6ZwKnWvNV4z6s^~yMXw2i5mv}jC$6$46g?G|CPAu{W5qF zDobS=zb2ILX9D827g*NtGe5w;>frjanY{f)hrBP_2ehBt1?`~ypvg_Ot4x1V+43P@Ve8>qd)9NX_jWdLo`Zfy zoeam9)@Dpym{4m@+LNxXBPjPKA7{3a&H+~xQvr>C_A;7=JrfK~$M2pCh>|xLz>W6SCs4qC|#V`)# z)0C|?$o>jzh<|-cpf

K7osU{Xp5PG4-K+L2G=)c3f&}H&M3wo7TlO_UJjQ-Oq&_ zjAc9=nNIYz{c3zxOiS5UfcE1}8#iI4@uy;$Q7>}u`j+OU0N<*Ezx$k{x_27+{s2Eg z`^=rhtIzCm!_UcJ?Db~Lh-=_))PT3{Q0{Mwdq;0>ZL%l3+;B&4!&xm#%HYAK|;b456Iv&&f$VQHf` z>$*K9w8T+paVwc7fLfMlhQ4)*zL_SG{~v4QR;IuX-(oRtYAhWOlh`NLoX0k$RUYMi z2Y!bqpdN}wz8q`-%>&Le@q|jFw92ErW-hma-le?S z-@OZt2EEUm4wLsuEMkt4zlyy29_3S50JAcQHTtgTC{P~%-mvCTzrjXOc|{}N`Cz`W zSj7CrXfa7lcsU0J(0uSX6G`54t^7}+OLM0n(|g4waOQ}bd3%!XLh?NX9|8G_|06Ie zD5F1)w5I~!et7lA{G^;uf7aqT`KE&2qx9|~O;s6t!gb`+zVLJyT2T)l*8l(j literal 0 HcmV?d00001 diff --git a/templates/react-router-monorepo/apps/app/public/locales/en.json b/templates/react-router-monorepo/apps/app/public/locales/en.json new file mode 100644 index 000000000..1bbb87a6c --- /dev/null +++ b/templates/react-router-monorepo/apps/app/public/locales/en.json @@ -0,0 +1,42 @@ +{ + "common": { + "search": "Search...", + + "chip": { + "dismissButtonLabel": "Remove" + }, + "banner": { + "dismissButtonLabel": "Close" + }, + "modal": { + "closeButtonLabel": "Close" + }, + "selectField": { + "noOptionsMessage": "No options", + "optionsPlural": "options", + "optionsSingular": "option", + "multiOptionsSelected": "{{n}} {{options}} selected", + "selectAllButtonLabel": "Select all", + "clearAllButtonLabel": "Clear all" + }, + "searchBar": { + "clearButtonLabel": "Clear" + }, + "table": { + "noResultsTitle": "No results found", + "noResultsDescription": "Try adjusting your search filters to find what you're looking for.", + "missingValue": "-" + }, + "loader": { + "loadingMessage": "Loading..." + }, + "dateField": { + "previousMonthLabel": "Prev month", + "nextMonthLabel": "Next month" + }, + "textField": { + "showPasswordLabel": "Show password", + "hidePasswordLabel": "Hide password" + } + } +} diff --git a/templates/react-router-monorepo/apps/app/public/locales/it.json b/templates/react-router-monorepo/apps/app/public/locales/it.json new file mode 100644 index 000000000..cefaea5c6 --- /dev/null +++ b/templates/react-router-monorepo/apps/app/public/locales/it.json @@ -0,0 +1,41 @@ +{ + "common": { + "search": "Cerca...", + "chip": { + "dismissButtonLabel": "Rimuovi" + }, + "banner": { + "dismissButtonLabel": "Chiudi" + }, + "modal": { + "closeButtonLabel": "Chiudi" + }, + "selectField": { + "noOptionsMessage": "Nessuna opzione", + "optionsPlural": "opzioni", + "optionsSingular": "opzione", + "multiOptionsSelected": "{{n}} {{options}} selezionate", + "selectAllButtonLabel": "Seleziona tutto", + "clearAllButtonLabel": "Cancella tutto" + }, + "searchBar": { + "clearButtonLabel": "Cancella" + }, + "table": { + "noResultsTitle": "Nessun risultato trovato", + "noResultsDescription": "Prova a modificare i filtri di ricerca per trovare ciò che stai cercando.", + "missingValue": "-" + }, + "loader": { + "loadingMessage": "Caricamento in corso..." + }, + "dateField": { + "previousMonthLabel": "Mese precedente", + "nextMonthLabel": "Mese successivo" + }, + "textField": { + "showPasswordLabel": "Mostra password", + "hidePasswordLabel": "Nascondi password" + } + } +} diff --git a/templates/react-router-monorepo/apps/app/tsconfig.json b/templates/react-router-monorepo/apps/app/tsconfig.json new file mode 100644 index 000000000..a6b9efb91 --- /dev/null +++ b/templates/react-router-monorepo/apps/app/tsconfig.json @@ -0,0 +1,33 @@ +{ + "include": [ + "**/*.ts", + "**/*.tsx", + "**/.server/**/*.ts", + "**/.server/**/*.tsx", + "**/.client/**/*.ts", + "**/.client/**/*.tsx", + "**/.react-router/types/**/*" + ], + "compilerOptions": { + "lib": ["DOM", "DOM.Iterable", "ES2022"], + "types": ["@react-router/node", "vite/client"], + "isolatedModules": true, + "esModuleInterop": true, + "jsx": "react-jsx", + "module": "ESNext", + "moduleResolution": "Bundler", + "resolveJsonModule": true, + "target": "ES2022", + "strict": true, + "allowJs": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true, + "baseUrl": ".", + "paths": { + "~/*": ["app/*"] + }, + "noEmit": true, + "rootDirs": [".", "./.react-router/types"], + "plugins": [{ "name": "@react-router/dev" }] + } +} diff --git a/templates/react-router-monorepo/apps/app/vite.config.ts b/templates/react-router-monorepo/apps/app/vite.config.ts new file mode 100644 index 000000000..cbc86668b --- /dev/null +++ b/templates/react-router-monorepo/apps/app/vite.config.ts @@ -0,0 +1,11 @@ +import { reactRouter } from "@react-router/dev/vite"; +import tsconfigPaths from "vite-tsconfig-paths"; +import { defineConfig } from "vite"; +import { checker } from "vite-plugin-checker"; + +export default defineConfig({ + plugins: [reactRouter({ ssr: true }), tsconfigPaths(), checker({ typescript: true })], + server: { + open: true, + }, +}); diff --git a/templates/react-router-monorepo/libs/design-system/.gitignore b/templates/react-router-monorepo/libs/design-system/.gitignore new file mode 100644 index 000000000..1521c8b76 --- /dev/null +++ b/templates/react-router-monorepo/libs/design-system/.gitignore @@ -0,0 +1 @@ +dist diff --git a/templates/react-router-monorepo/libs/design-system/package.json b/templates/react-router-monorepo/libs/design-system/package.json new file mode 100644 index 000000000..a276cec59 --- /dev/null +++ b/templates/react-router-monorepo/libs/design-system/package.json @@ -0,0 +1,30 @@ +{ + "name": "design-system", + "private": true, + "type": "module", + "exports": { + ".": "./dist/index.js", + "./index.css": "./dist/index.css" + }, + "scripts": { + "build": "tsup --minify --clean", + "dev": "tsup --watch", + "generate:types": "" + }, + "dependencies": { + "@buildo/bento-design-system": "^0.22.25", + "@phosphor-icons/react": "^2.1.7", + "@vanilla-extract/esbuild-plugin": "^2.3.11" + }, + "peerDependencies": { + "react": "^18.3.1", + "react-dom": "^18.3.1" + }, + "devDependencies": { + "@microsoft/api-extractor": "^7.47.9", + "tsup": "^8.3.0", + "typescript": "^5.6.0", + "react": "^18.3.1", + "react-dom": "^18.3.1" + } +} diff --git a/templates/react-router-monorepo/libs/design-system/src/index.tsx b/templates/react-router-monorepo/libs/design-system/src/index.tsx new file mode 100644 index 000000000..b947cd61f --- /dev/null +++ b/templates/react-router-monorepo/libs/design-system/src/index.tsx @@ -0,0 +1,14 @@ +import "@buildo/bento-design-system/index.css"; +import "@buildo/bento-design-system/defaultTheme.css"; +import { type Icon as PhosphorIcon } from "@phosphor-icons/react"; +import { Children, IconProps, svgIconProps } from "@buildo/bento-design-system"; + +export * from "@buildo/bento-design-system"; + +export function phosphorToBento(Icon: PhosphorIcon): (props: IconProps) => Children { + return (props: IconProps) => { + const { viewBox, ...svgProps } = svgIconProps(props); + // @ts-expect-error + return ; + }; +} diff --git a/templates/react-router-monorepo/libs/design-system/tsconfig.json b/templates/react-router-monorepo/libs/design-system/tsconfig.json new file mode 100644 index 000000000..ec1eb2192 --- /dev/null +++ b/templates/react-router-monorepo/libs/design-system/tsconfig.json @@ -0,0 +1,19 @@ +{ + "include": ["**/*.ts", "**/*.tsx"], + "compilerOptions": { + "lib": ["DOM", "DOM.Iterable", "ES2022"], + "isolatedModules": true, + "esModuleInterop": true, + "jsx": "react-jsx", + "module": "ESNext", + "moduleResolution": "Bundler", + "resolveJsonModule": true, + "target": "ES2022", + "strict": true, + "allowJs": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true, + "baseUrl": ".", + "noEmit": true + } +} diff --git a/templates/react-router-monorepo/libs/design-system/tsup.config.ts b/templates/react-router-monorepo/libs/design-system/tsup.config.ts new file mode 100644 index 000000000..d9bbeebb0 --- /dev/null +++ b/templates/react-router-monorepo/libs/design-system/tsup.config.ts @@ -0,0 +1,11 @@ +import { defineConfig } from "tsup"; +import { vanillaExtractPlugin } from "@vanilla-extract/esbuild-plugin"; + +export default defineConfig({ + entry: ["src/index.tsx"], + outDir: "dist", + esbuildPlugins: [vanillaExtractPlugin()], + dts: true, + format: ["esm"], + noExternal: ["@buildo/bento-design-system/index.css"], +}); diff --git a/templates/react-router-monorepo/nx.json b/templates/react-router-monorepo/nx.json new file mode 100644 index 000000000..fb1d817cb --- /dev/null +++ b/templates/react-router-monorepo/nx.json @@ -0,0 +1,17 @@ +{ + "$schema": "./node_modules/nx/schemas/nx-schema.json", + "targetDefaults": { + "dev": { + "dependsOn": ["generate:types", "^build"] + }, + "build": { + "dependsOn": ["^build"], + "outputs": ["{projectRoot}/dist"], + "cache": true + }, + "typecheck": { + "cache": true + } + }, + "defaultBase": "main" +} diff --git a/templates/react-router-monorepo/package.json b/templates/react-router-monorepo/package.json new file mode 100644 index 000000000..e43856cd2 --- /dev/null +++ b/templates/react-router-monorepo/package.json @@ -0,0 +1,12 @@ +{ + "private": true, + "scripts": { + "dev": "nx run app:dev", + "build": "nx run app:build", + "generate:types": "nx run app:generate:types" + }, + "devDependencies": { + "nx": "^20.0.0" + }, + "packageManager": "pnpm@9.7.0" +} diff --git a/templates/react-router-monorepo/pnpm-workspace.yaml b/templates/react-router-monorepo/pnpm-workspace.yaml new file mode 100644 index 000000000..0a26f3faf --- /dev/null +++ b/templates/react-router-monorepo/pnpm-workspace.yaml @@ -0,0 +1,3 @@ +packages: + - apps/* + - libs/* diff --git a/templates/react-router-monorepo/tsconfig.json b/templates/react-router-monorepo/tsconfig.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/templates/react-router-monorepo/tsconfig.json @@ -0,0 +1 @@ +{}