-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 2b3a146
Showing
31 changed files
with
7,868 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
/** | ||
* This is intended to be a basic starting point for linting in your app. | ||
* It relies on recommended configs out of the box for simplicity, but you can | ||
* and should modify this configuration to best suit your team's needs. | ||
*/ | ||
|
||
/** @type {import('eslint').Linter.Config} */ | ||
module.exports = { | ||
root: true, | ||
parserOptions: { | ||
ecmaVersion: 'latest', | ||
sourceType: 'module', | ||
ecmaFeatures: { | ||
jsx: true, | ||
}, | ||
}, | ||
env: { | ||
browser: true, | ||
commonjs: true, | ||
es6: true, | ||
}, | ||
ignorePatterns: ['!**/.server', '!**/.client'], | ||
|
||
// Base config | ||
extends: ['eslint:recommended'], | ||
|
||
overrides: [ | ||
// React | ||
{ | ||
files: ['**/*.{js,jsx,ts,tsx}'], | ||
plugins: ['react', 'jsx-a11y'], | ||
extends: [ | ||
'plugin:react/recommended', | ||
'plugin:react/jsx-runtime', | ||
'plugin:react-hooks/recommended', | ||
'plugin:jsx-a11y/recommended', | ||
], | ||
settings: { | ||
react: { | ||
version: 'detect', | ||
}, | ||
formComponents: ['Form'], | ||
linkComponents: [ | ||
{ name: 'Link', linkAttribute: 'to' }, | ||
{ name: 'NavLink', linkAttribute: 'to' }, | ||
], | ||
'import/resolver': { | ||
typescript: {}, | ||
}, | ||
}, | ||
}, | ||
|
||
// Typescript | ||
{ | ||
files: ['**/*.{ts,tsx}'], | ||
plugins: ['@typescript-eslint', 'import'], | ||
parser: '@typescript-eslint/parser', | ||
settings: { | ||
'import/internal-regex': '^~/', | ||
'import/resolver': { | ||
node: { | ||
extensions: ['.ts', '.tsx'], | ||
}, | ||
typescript: { | ||
alwaysTryTypes: true, | ||
project: ['./frontend/tsconfig.json'], | ||
}, | ||
}, | ||
}, | ||
extends: [ | ||
'plugin:@typescript-eslint/recommended', | ||
'plugin:import/recommended', | ||
'plugin:import/typescript', | ||
], | ||
}, | ||
|
||
// Node | ||
{ | ||
files: ['.eslintrc.cjs'], | ||
env: { | ||
node: true, | ||
}, | ||
}, | ||
{ | ||
files: ['app/i18n/**/*', 'app/root.tsx'], // Exclude specific files | ||
rules: { | ||
'no-restricted-imports': 'off', // Disable the rule for these files | ||
}, | ||
}, | ||
], | ||
rules: { | ||
'no-restricted-imports': [ | ||
'error', | ||
{ | ||
paths: [ | ||
{ | ||
name: 'react-i18next', | ||
importNames: ['useTranslation', 'Trans'], | ||
message: | ||
'Use the custom typesafe `useTranslation` and `Trans` from `~/i18n/i18n` instead.', | ||
}, | ||
], | ||
}, | ||
], | ||
}, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
node_modules | ||
|
||
/.cache | ||
/build | ||
.env | ||
|
||
.DS_Store |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
{ | ||
"workspaceId": "4de503f3-f5e7-40fb-8175-0c498f1694ba", | ||
"defaultEnvironment": "", | ||
"gitBranchToEnvironmentMapping": null | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
# Ignore artifacts: | ||
build | ||
coverage | ||
|
||
# dependencies | ||
/node_modules | ||
/.pnp | ||
.pnp.js | ||
pnpm-lock.yaml | ||
|
||
# testing | ||
/coverage | ||
|
||
# production | ||
/build | ||
|
||
# misc | ||
.DS_Store | ||
*.pem | ||
|
||
# debug | ||
npm-debug.log* | ||
yarn-debug.log* | ||
yarn-error.log* | ||
.pnpm-debug.log* | ||
|
||
# local env files | ||
.env*.local | ||
|
||
# vercel | ||
.vercel | ||
|
||
# typescript | ||
*.tsbuildinfo | ||
next-env.d.ts | ||
|
||
# husky | ||
/.husky/ | ||
|
||
# Ignore autogenerated files | ||
.infisical.json | ||
components.json | ||
|
||
# Handlebars templates | ||
*.hbs |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
{ | ||
"printWidth": 80, | ||
"tabWidth": 2, | ||
"useTabs": false, | ||
"semi": true, | ||
"singleQuote": true, | ||
"quoteProps": "as-needed", | ||
"jsxSingleQuote": false, | ||
"trailingComma": "all", | ||
"bracketSpacing": true, | ||
"bracketSameLine": true, | ||
"arrowParens": "always", | ||
"endOfLine": "lf", | ||
"tailwindConfig": "./tailwind.config.ts", | ||
"tailwindAttributes": ["className"], | ||
"tailwindFunctions": ["cn", "tw", "clsx", "cva"], | ||
"plugins": ["prettier-plugin-organize-imports", "prettier-plugin-tailwindcss"] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
# Remix Template with TailwindCSS, Shadcn, Zodios, i18next, and More | ||
|
||
This repository provides a ready-to-use template for creating a Remix application with modern tooling, including TailwindCSS, Shadcn, environment variable validation with T3-oss, Zodios API client, i18next for localization, and more. | ||
|
||
## 🚀 Quick Start | ||
|
||
To create a new Remix project from this template, run the following command: | ||
|
||
```bash | ||
npx create-remix@latest --template <your-github-username>/<repo-name> | ||
``` | ||
|
||
This will set up a new Remix app with all the configurations and dependencies outlined below. | ||
|
||
### Running the App | ||
|
||
After setting up your project, navigate to the project folder and run the following command to install the dependencies: | ||
|
||
```bash | ||
pnpm install | ||
``` | ||
|
||
To start the development server: | ||
|
||
```bash | ||
pnpm dev | ||
``` | ||
|
||
This will run the app locally. Open [http://localhost:3000](http://localhost:3000) in your browser to view the app. | ||
|
||
## 🛠️ What's Included | ||
|
||
This template comes with the following features: | ||
|
||
- **Remix**: Uses Remix v1 routing with file-based routing. | ||
- **TailwindCSS**: A utility-first CSS framework for creating responsive, modern designs. | ||
- **Shadcn**: A component library providing pre-designed and customizable components. | ||
- **T3-Oss Env Validation**: T3-oss environment variable validation for managing your app's environment variables securely. | ||
- **Zodios**: An API client based on Zod to create and validate API requests seamlessly. | ||
- **i18next**: Localization framework for adding multi-language support to your app. | ||
- **Infisical**: Secure secret management for your app, storing API keys, DB credentials, and other sensitive information. | ||
- **Prettier**: Code formatting for consistent style across your project. | ||
- **ESLint**: Static analysis tool for identifying problematic patterns in JavaScript/TypeScript code. | ||
- **VSCode Settings**: Pre-configured VSCode settings for consistent development experience. | ||
|
||
## 📁 Special Folder and Filename Conventions | ||
|
||
In this project, files and folders with a double underscore (`__`) in their filename or folder name are treated as special. Specifically: | ||
|
||
- A file named `__guarded.tsx` in the `__guarded` folder is used as the layout for all routes within that folder. This is a key feature of the routing convention used in this template. This approach helps in grouping routes that share common layouts or behavior. | ||
|
||
Example: | ||
|
||
- `__guarded/__guarded.tsx` will act as a layout for every page inside the `__guarded` folder. | ||
|
||
## 🗂️ Folder Structure Example | ||
|
||
``` | ||
src/ | ||
├── routes/ | ||
│ ├── __guarded/ | ||
│ │ ├── index.tsx | ||
│ │ └── about.tsx | ||
│ └── __guarded.tsx | ||
├── tailwind.css | ||
└── ... | ||
``` | ||
|
||
In this case, the `__guarded.tsx` layout will be applied to `index.tsx`, `about.tsx`, or any other route placed inside the `__guarded` folder. | ||
|
||
## ⚙️ Additional Setup | ||
|
||
- **VSCode Settings**: Make sure to install the recommended VSCode extensions to ensure proper formatting and linting. | ||
- **Infisical**: | ||
|
||
Infisical is used to securely manage your environment variables, including API keys, database credentials, and other sensitive information. To initialize Infisical: | ||
|
||
1. **Create an Infisical Account**: | ||
- Go to [Infisical](https://app.infisical.com) and sign up for an account. | ||
2. **Create Infisical Project**: | ||
- You can go to [Infisical Dashboard](https://app.infisical.com) and create a new project. There you can add your environment variables, API keys, and other sensitive information. | ||
3. **Login to Infisical**: | ||
|
||
- Run the following command to log in to your Infisical account: | ||
```bash | ||
infisical login | ||
``` | ||
|
||
4. **Initialize Your Project**: | ||
- Once logged in, link your project to Infisical by running: | ||
```bash | ||
infisical init | ||
``` | ||
|
||
By following these steps, you can manage your sensitive environment variables securely in Infisical. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
import * as React from "react" | ||
import { Slot } from "@radix-ui/react-slot" | ||
import { cva, type VariantProps } from "class-variance-authority" | ||
|
||
import { cn } from "~/lib/utils" | ||
|
||
const buttonVariants = cva( | ||
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0", | ||
{ | ||
variants: { | ||
variant: { | ||
default: "bg-primary text-primary-foreground hover:bg-primary/90", | ||
destructive: | ||
"bg-destructive text-destructive-foreground hover:bg-destructive/90", | ||
outline: | ||
"border border-input bg-background hover:bg-accent hover:text-accent-foreground", | ||
secondary: | ||
"bg-secondary text-secondary-foreground hover:bg-secondary/80", | ||
ghost: "hover:bg-accent hover:text-accent-foreground", | ||
link: "text-primary underline-offset-4 hover:underline", | ||
}, | ||
size: { | ||
default: "h-10 px-4 py-2", | ||
sm: "h-9 rounded-md px-3", | ||
lg: "h-11 rounded-md px-8", | ||
icon: "h-10 w-10", | ||
}, | ||
}, | ||
defaultVariants: { | ||
variant: "default", | ||
size: "default", | ||
}, | ||
} | ||
) | ||
|
||
export interface ButtonProps | ||
extends React.ButtonHTMLAttributes<HTMLButtonElement>, | ||
VariantProps<typeof buttonVariants> { | ||
asChild?: boolean | ||
} | ||
|
||
const Button = React.forwardRef<HTMLButtonElement, ButtonProps>( | ||
({ className, variant, size, asChild = false, ...props }, ref) => { | ||
const Comp = asChild ? Slot : "button" | ||
return ( | ||
<Comp | ||
className={cn(buttonVariants({ variant, size, className }))} | ||
ref={ref} | ||
{...props} | ||
/> | ||
) | ||
} | ||
) | ||
Button.displayName = "Button" | ||
|
||
export { Button, buttonVariants } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
import { RemixBrowser } from '@remix-run/react'; | ||
import i18next from 'i18next'; | ||
import I18nextBrowserLanguageDetector from 'i18next-browser-languagedetector'; | ||
import Fetch from 'i18next-fetch-backend'; | ||
import { startTransition, StrictMode } from 'react'; | ||
import { hydrateRoot } from 'react-dom/client'; | ||
import { I18nextProvider, initReactI18next } from 'react-i18next'; | ||
import { getInitialNamespaces } from 'remix-i18next/client'; | ||
import { defaultNS, fallbackLng, supportedLngs } from './i18n/i18n'; | ||
|
||
async function main() { | ||
// eslint-disable-next-line import/no-named-as-default-member | ||
await i18next | ||
.use(initReactI18next) // Tell i18next to use the react-i18next plugin | ||
.use(Fetch) // Tell i18next to use the Fetch backend | ||
.use(I18nextBrowserLanguageDetector) // Setup a client-side language detector | ||
.init({ | ||
defaultNS, | ||
fallbackLng, | ||
supportedLngs, | ||
ns: getInitialNamespaces(), | ||
detection: { | ||
// Here only enable htmlTag detection, we'll detect the language only | ||
// server-side with remix-i18next, by using the `<html lang>` 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: [], | ||
}, | ||
backend: { | ||
// We will configure the backend to fetch the translations from the | ||
// resource route /api/locales and pass the lng and ns as search params | ||
loadPath: '/api/locales?lng={{lng}}&ns={{ns}}', | ||
}, | ||
}); | ||
|
||
startTransition(() => { | ||
hydrateRoot( | ||
document, | ||
<I18nextProvider i18n={i18next}> | ||
<StrictMode> | ||
<RemixBrowser /> | ||
</StrictMode> | ||
</I18nextProvider>, | ||
); | ||
}); | ||
} | ||
|
||
main().catch((error) => console.error(error)); |
Oops, something went wrong.