├── .nvmrc ├── .npmrc ├── src ├── components │ ├── Footer │ │ ├── index.tsx │ │ ├── Footer.tsx │ │ └── Footer.test.tsx │ ├── Header │ │ ├── index.tsx │ │ ├── Header.tsx │ │ └── Header.test.tsx │ ├── Navigation │ │ ├── index.tsx │ │ ├── Navigation.test.tsx │ │ └── Navigation.tsx │ └── ErrorBoundary │ │ ├── index.tsx │ │ ├── ErrorBoundary.tsx │ │ └── ErrorBoundary.test.tsx ├── styles │ └── tailwind.css ├── routes │ ├── api │ │ └── hello.tsx │ ├── index.tsx │ ├── about.tsx │ ├── sentryLoader.tsx │ ├── sentryFrontend.tsx │ └── sentryAction.tsx ├── tests │ ├── setup.ts │ ├── hello.test.tsx │ ├── _index.test.tsx │ └── about.test.tsx ├── utils │ ├── sentry.ts │ ├── errors.ts │ ├── sentry.test.ts │ └── errors.test.ts ├── routes.ts ├── entry.client.tsx ├── e2e │ └── example.spec.ts ├── root.tsx └── entry.server.tsx ├── env.d.ts ├── eslint.config.js ├── public ├── favicon.ico ├── github.png ├── twitter.png └── facebook.png ├── .env.example ├── plopfile.js ├── .prettierignore ├── .gitignore ├── vercel.json ├── .prettierrc ├── .all-contributorsrc ├── tsconfig.json ├── playwright.config.ts ├── license ├── .vscode └── tasks.json ├── readme.md ├── vite.config.ts ├── .github └── workflows │ └── ci.yml ├── package.json ├── contributing.md └── changelog.md /.nvmrc: -------------------------------------------------------------------------------- 1 | 22 2 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | legacy-peer-deps=true 2 | registry=https://registry.npmjs.org 3 | -------------------------------------------------------------------------------- /src/components/Footer/index.tsx: -------------------------------------------------------------------------------- 1 | export {default} from "./Footer.js" 2 | -------------------------------------------------------------------------------- /src/components/Header/index.tsx: -------------------------------------------------------------------------------- 1 | export {default} from "./Header.js" 2 | -------------------------------------------------------------------------------- /src/components/Navigation/index.tsx: -------------------------------------------------------------------------------- 1 | export {default} from "./Navigation.js" 2 | -------------------------------------------------------------------------------- /src/components/ErrorBoundary/index.tsx: -------------------------------------------------------------------------------- 1 | export {default} from "./ErrorBoundary.js" 2 | -------------------------------------------------------------------------------- /env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | -------------------------------------------------------------------------------- /eslint.config.js: -------------------------------------------------------------------------------- 1 | import config from "@bradgarropy/eslint-config" 2 | export default config 3 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bradgarropy/remix-starter/HEAD/public/favicon.ico -------------------------------------------------------------------------------- /public/github.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bradgarropy/remix-starter/HEAD/public/github.png -------------------------------------------------------------------------------- /public/twitter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bradgarropy/remix-starter/HEAD/public/twitter.png -------------------------------------------------------------------------------- /public/facebook.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bradgarropy/remix-starter/HEAD/public/facebook.png -------------------------------------------------------------------------------- /.env.example: -------------------------------------------------------------------------------- 1 | SENTRY_AUTH_TOKEN=sntrys_abc 2 | SENTRY_DSN=https://ingest.us.sentry.io 3 | SENTRY_ORG=bradgarropy 4 | SENTRY_PROJECT=remix-starter 5 | -------------------------------------------------------------------------------- /plopfile.js: -------------------------------------------------------------------------------- 1 | const config = async plop => { 2 | await plop.load("@bradgarropy/plop-generator-remix-route") 3 | } 4 | 5 | export default config 6 | -------------------------------------------------------------------------------- /src/styles/tailwind.css: -------------------------------------------------------------------------------- 1 | @import "tailwindcss"; 2 | 3 | nav > a.active { 4 | @apply underline decoration-purple-500 decoration-4 underline-offset-4; 5 | } 6 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | # dependencies 2 | /node_modules 3 | 4 | # build 5 | /.cache 6 | /build 7 | /public/build 8 | 9 | # test 10 | /coverage 11 | 12 | # secrets 13 | .env* 14 | -------------------------------------------------------------------------------- /src/routes/api/hello.tsx: -------------------------------------------------------------------------------- 1 | import {data} from "@remix-run/node" 2 | 3 | const loader = () => { 4 | return data({message: "world"}, {status: 200}) 5 | } 6 | 7 | export {loader} 8 | -------------------------------------------------------------------------------- /src/tests/setup.ts: -------------------------------------------------------------------------------- 1 | import "@testing-library/jest-dom/vitest" 2 | 3 | import {cleanup} from "@testing-library/react" 4 | import {afterEach} from "vitest" 5 | 6 | afterEach(() => { 7 | cleanup() 8 | }) 9 | -------------------------------------------------------------------------------- /src/utils/sentry.ts: -------------------------------------------------------------------------------- 1 | import pkg from "../../package.json" 2 | 3 | const createRelease = () => { 4 | const release = `${pkg.name}@${pkg.version}` 5 | return release 6 | } 7 | 8 | export {createRelease} 9 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # dependencies 2 | /node_modules 3 | 4 | # build 5 | /.cache 6 | /build 7 | /public/build 8 | 9 | # test 10 | /coverage 11 | /test-results 12 | /playwright-report 13 | 14 | # secrets 15 | .env 16 | 17 | # os 18 | .DS_Store 19 | -------------------------------------------------------------------------------- /src/components/Footer/Footer.tsx: -------------------------------------------------------------------------------- 1 | const Footer = () => { 2 | return ( 3 |
4 |

Footer

5 |
6 | ) 7 | } 8 | 9 | export default Footer 10 | -------------------------------------------------------------------------------- /src/routes/index.tsx: -------------------------------------------------------------------------------- 1 | const Route = () => { 2 | return ( 3 | <> 4 | 💿 remix starter | home 5 |

Home

6 | 7 | ) 8 | } 9 | 10 | export default Route 11 | -------------------------------------------------------------------------------- /vercel.json: -------------------------------------------------------------------------------- 1 | { 2 | "buildCommand": "npm run build", 3 | "cleanUrls": true, 4 | "devCommand": "npm run dev", 5 | "framework": "remix", 6 | "installCommand": "npm install", 7 | "redirects": [], 8 | "trailingSlash": false 9 | } 10 | -------------------------------------------------------------------------------- /src/routes/about.tsx: -------------------------------------------------------------------------------- 1 | const Route = () => { 2 | return ( 3 | <> 4 | 💿 remix starter | about 5 |

About

6 | 7 | ) 8 | } 9 | 10 | export default Route 11 | -------------------------------------------------------------------------------- /src/utils/errors.ts: -------------------------------------------------------------------------------- 1 | const createErrorStack = (error: Error) => { 2 | if (!error.stack) { 3 | return "" 4 | } 5 | 6 | const shortStack = error.stack.split("\n").slice(0, 10).join("\n") 7 | return shortStack 8 | } 9 | 10 | export {createErrorStack} 11 | -------------------------------------------------------------------------------- /src/tests/hello.test.tsx: -------------------------------------------------------------------------------- 1 | import {expect, test} from "vitest" 2 | 3 | import {loader} from "~/routes/api/hello" 4 | 5 | test("returns", async () => { 6 | const {data, init} = loader() 7 | 8 | expect(init).toMatchObject({status: 200}) 9 | expect(data).toEqual({message: "world"}) 10 | }) 11 | -------------------------------------------------------------------------------- /src/components/Footer/Footer.test.tsx: -------------------------------------------------------------------------------- 1 | import {render, screen} from "@testing-library/react" 2 | import {expect, test} from "vitest" 3 | 4 | import Footer from "~/components/Footer" 5 | 6 | test("renders", () => { 7 | render(