├── .dockerignore ├── .env.example ├── .eslintrc.cjs ├── .github ├── dependabot.yml └── workflows │ ├── deploy.production.yml │ ├── deploy.staging.yml │ ├── format.yml │ ├── lint.yml │ └── no-response.yml ├── .gitignore ├── .gitpod.Dockerfile ├── .gitpod.yml ├── .npmrc ├── .nvmrc ├── .prettierignore ├── Dockerfile ├── LICENSE.md ├── README.md ├── _redirects ├── app ├── actions │ └── color-scheme.ts ├── components │ ├── README.md │ ├── _playground │ │ ├── README.md │ │ ├── fake-menu.ts │ │ └── playground.tsx │ ├── color-scheme-toggle.tsx │ ├── details-popup.tsx │ ├── doc-error-boundary.tsx │ ├── doc-layout.tsx │ ├── docs-footer.tsx │ ├── docs-header │ │ ├── data.server.ts │ │ ├── docs-header.tsx │ │ └── use-header-data.ts │ ├── docs-menu │ │ ├── data.server.ts │ │ ├── menu-desktop.tsx │ │ ├── menu-mobile.tsx │ │ └── menu.tsx │ ├── on-this-page.tsx │ ├── package-select.tsx │ ├── popup-label.tsx │ ├── version-nav.tsx │ ├── version-select.tsx │ └── version-warning.tsx ├── hooks │ ├── README.md │ ├── use-delayed-value.ts │ ├── use-doc.ts │ └── use-navigation.ts ├── http.ts ├── icons.svg ├── modules │ ├── README.md │ ├── color-scheme │ │ ├── components.tsx │ │ ├── server.ts │ │ └── types.ts │ ├── details-menu │ │ └── index.tsx │ ├── docsearch.tsx │ ├── gh-docs │ │ └── .server │ │ │ ├── __fixture__ │ │ │ └── docs │ │ │ │ ├── components │ │ │ │ ├── index.md │ │ │ │ ├── link.md │ │ │ │ └── router.md │ │ │ │ ├── index.md │ │ │ │ └── pages │ │ │ │ ├── index.md │ │ │ │ ├── overview.md │ │ │ │ └── tutorial.md │ │ │ ├── branches.ts │ │ │ ├── compat-tokens.ts │ │ │ ├── docs.test.ts │ │ │ ├── docs.ts │ │ │ ├── github.ts │ │ │ ├── index.ts │ │ │ ├── md.ts │ │ │ ├── reference-docs.ts │ │ │ ├── repo-content.ts │ │ │ ├── repo-tarball.ts │ │ │ ├── tags.ts │ │ │ ├── tarball.test.ts │ │ │ └── tarball.ts │ ├── http-utils │ │ ├── ensure-secure.ts │ │ ├── is-host.ts │ │ └── remove-slashes.ts │ ├── redirects │ │ └── .server │ │ │ ├── __fixtures__ │ │ │ └── _redirects │ │ │ ├── check-url.test.ts │ │ │ ├── check-url.ts │ │ │ ├── get-redirects.ts │ │ │ └── index.ts │ ├── remix-seo │ │ ├── index.ts │ │ ├── seo.test.ts │ │ └── seo.ts │ └── stats │ │ └── index.tsx ├── pages │ ├── brand.tsx │ ├── doc.tsx │ ├── docs-home.tsx │ ├── docs-layout.tsx │ ├── healthcheck.tsx │ ├── redirect-major-version.tsx │ └── splash.tsx ├── root.tsx ├── routes.ts ├── seo.ts ├── styles │ ├── docs.css │ ├── docsearch.css │ └── tailwind.css └── ui │ ├── README.md │ ├── delegate-markdown-links.ts │ ├── meta.ts │ └── utils.ts ├── data ├── api-docs.json └── base16.json ├── fly.production.toml ├── fly.staging.toml ├── notes.md ├── package-lock.json ├── package.json ├── postcss.config.mjs ├── public ├── _brand │ ├── React Router Brand Assets.zip │ └── React Router Brand Assets │ │ ├── React Router Lockup │ │ ├── Dark.png │ │ ├── Dark.svg │ │ ├── Light.png │ │ ├── Light.svg │ │ └── One Color │ │ │ ├── Dark.png │ │ │ ├── Dark.svg │ │ │ ├── Light.png │ │ │ └── Light.svg │ │ ├── React Router Logo │ │ ├── Dark.png │ │ ├── Dark.svg │ │ ├── Light.png │ │ ├── Light.svg │ │ └── One Color │ │ │ ├── Dark.png │ │ │ ├── Dark.svg │ │ │ ├── Light.png │ │ │ └── Light.svg │ │ └── React Router Wordmark │ │ ├── Dark.png │ │ ├── Dark.svg │ │ ├── Light.png │ │ └── Light.svg ├── _docs │ ├── mode-icons.svg │ ├── tutorial │ │ ├── 01.webp │ │ ├── 02.webp │ │ ├── 03.webp │ │ ├── 04.webp │ │ ├── 05.webp │ │ ├── 06.webp │ │ ├── 07.webp │ │ ├── 08.webp │ │ ├── 09.webp │ │ ├── 10.webp │ │ ├── 11.webp │ │ ├── 12.webp │ │ ├── 13.webp │ │ ├── 14.webp │ │ ├── 15.webp │ │ ├── 16.webp │ │ ├── 17.webp │ │ ├── 18.webp │ │ ├── 19.webp │ │ ├── 20.webp │ │ ├── 21.webp │ │ ├── 22.webp │ │ ├── 23.webp │ │ ├── 24.webp │ │ ├── 25.webp │ │ ├── 26.webp │ │ └── 27.webp │ ├── tutorial_source_files │ │ ├── 01.png │ │ ├── 02.png │ │ ├── 03.png │ │ ├── 04.png │ │ ├── 05.png │ │ ├── 06.png │ │ ├── 07.png │ │ ├── 08.png │ │ ├── 09.png │ │ ├── 10.png │ │ ├── 11.png │ │ ├── 12.png │ │ ├── 13.png │ │ ├── 14.png │ │ ├── 15.png │ │ ├── 16.png │ │ ├── 17.png │ │ ├── 18.png │ │ ├── 19.png │ │ ├── 20.png │ │ ├── 21.png │ │ ├── 22.png │ │ ├── 23.png │ │ ├── 24.png │ │ ├── 25.png │ │ ├── 26.png │ │ └── 27.png │ └── v7_address_book_tutorial │ │ ├── 01.webp │ │ ├── 02.webp │ │ ├── 03.webp │ │ ├── 04.webp │ │ ├── 05.webp │ │ ├── 06.webp │ │ ├── 07.webp │ │ ├── 08.webp │ │ ├── 09.webp │ │ ├── 10.webp │ │ ├── 11.webp │ │ ├── 12.webp │ │ ├── 13.webp │ │ ├── 14.webp │ │ ├── 15.webp │ │ ├── 16.webp │ │ ├── 17.webp │ │ ├── 18.webp │ │ ├── 19.webp │ │ ├── 20.webp │ │ ├── 21.webp │ │ └── 22.webp ├── android-chrome-144x144.png ├── browserconfig.xml ├── favicon-dark.png ├── favicon-light.png ├── favicon.ico ├── font │ ├── inter-italic-latin-var.woff2 │ ├── inter-roman-latin-var.woff2 │ ├── source-code-pro-italic-var.woff2 │ └── source-code-pro-roman-var.woff2 ├── manifest.json ├── mstile-150x150.png ├── og-image.png └── splash │ ├── hero-3d-logo.dark.webp │ ├── hero-3d-logo.webp │ ├── shopify-badge.svg │ ├── v7-badge-1.svg │ └── v7-badge-2.svg ├── react-router.config.ts ├── server.js ├── server └── app.ts ├── start.sh ├── tailwind.config.ts ├── test ├── fixture.tar.gz └── setup-test-env.ts ├── tsconfig.json ├── vite.config.ts └── vitest.config.ts /.dockerignore: -------------------------------------------------------------------------------- 1 | /node_modules 2 | *.log 3 | .DS_Store 4 | .env 5 | /.cache 6 | /public/build 7 | /build 8 | -------------------------------------------------------------------------------- /.env.example: -------------------------------------------------------------------------------- 1 | # For the server 2 | SESSION_SECRET="anything-you-want" 3 | 4 | # GitHub repo to pull docs from 5 | SOURCE_REPO="remix-run/react-router" 6 | 7 | # A token to increase the rate limiting from 60/hr to 1000/hr 8 | GH_TOKEN="..." 9 | 10 | # For development, reading the docs from a local repo 11 | LOCAL_REPO_RELATIVE_PATH="../react-router" 12 | 13 | -------------------------------------------------------------------------------- /.eslintrc.cjs: -------------------------------------------------------------------------------- 1 | /** 2 | * @type {import('@types/eslint').Linter.BaseConfig} 3 | */ 4 | module.exports = { 5 | extends: [ 6 | "eslint:recommended", 7 | "plugin:@typescript-eslint/recommended", 8 | "plugin:react/recommended", 9 | "plugin:react-hooks/recommended", 10 | "prettier", 11 | ], 12 | env: { 13 | node: true, 14 | }, 15 | plugins: ["@typescript-eslint", "react"], 16 | settings: { 17 | react: { 18 | version: "detect", 19 | }, 20 | }, 21 | rules: { 22 | "no-unused-vars": "off", 23 | "no-inner-declarations": "off", 24 | "no-var": "off", 25 | "prefer-const": "off", 26 | "react/react-in-jsx-scope": "off", // Not needed in modern React 27 | "react/prop-types": "off", // We use TypeScript instead 28 | "react/no-unescaped-entities": "off", 29 | "@typescript-eslint/no-unused-vars": "warn", 30 | "@typescript-eslint/no-explicit-any": "off", 31 | "@typescript-eslint/no-non-null-assertion": "off", 32 | }, 33 | }; 34 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: github-actions 4 | directory: / 5 | schedule: 6 | interval: daily 7 | -------------------------------------------------------------------------------- /.github/workflows/deploy.production.yml: -------------------------------------------------------------------------------- 1 | name: 🚀 Deploy (production) 2 | on: 3 | push: 4 | branches: 5 | - main 6 | paths-ignore: 7 | - "README.md" 8 | 9 | concurrency: 10 | group: ${{ github.workflow }}-${{ github.ref }} 11 | cancel-in-progress: true 12 | 13 | env: 14 | FLY_API_TOKEN: ${{ secrets.FLY_API_TOKEN }} 15 | 16 | jobs: 17 | lint: 18 | name: ⬣ ESLint 19 | runs-on: ubuntu-latest 20 | steps: 21 | - name: ⬇️ Checkout repo 22 | uses: actions/checkout@v4 23 | 24 | - name: ⎔ Setup node 25 | uses: actions/setup-node@v4 26 | with: 27 | cache: npm 28 | cache-dependency-path: ./package-lock.json 29 | node-version: 22 30 | 31 | - name: 📥 Install deps 32 | run: npm install 33 | 34 | - name: 🔬 Lint 35 | run: npm run lint 36 | 37 | typecheck: 38 | name: ʦ TypeScript 39 | runs-on: ubuntu-latest 40 | steps: 41 | - name: ⬇️ Checkout repo 42 | uses: actions/checkout@v4 43 | 44 | - name: ⎔ Setup node 45 | uses: actions/setup-node@v4 46 | with: 47 | cache: npm 48 | cache-dependency-path: ./package-lock.json 49 | node-version: 22 50 | 51 | - name: 📥 Install deps 52 | run: npm install 53 | 54 | - name: 🔎 Type check 55 | run: npm run typecheck --if-present 56 | 57 | vitest: 58 | name: ⚡ Vitest 59 | runs-on: ubuntu-latest 60 | steps: 61 | - name: ⬇️ Checkout repo 62 | uses: actions/checkout@v4 63 | 64 | - name: ⎔ Setup node 65 | uses: actions/setup-node@v4 66 | with: 67 | cache: npm 68 | cache-dependency-path: ./package-lock.json 69 | node-version: 22 70 | 71 | - name: 📥 Install deps 72 | run: npm install 73 | 74 | - name: ⚡ Run vitest 75 | run: npm run test -- --coverage 76 | 77 | deploy: 78 | name: 🚀 Deploy 79 | runs-on: ubuntu-latest 80 | needs: [lint, typecheck, vitest] 81 | steps: 82 | - name: ⬇️ Checkout repo 83 | uses: actions/checkout@v4 84 | 85 | - name: 🎈 Setup Fly 86 | uses: superfly/flyctl-actions/setup-flyctl@1.5 87 | 88 | - name: 🚀 Deploy Production 89 | if: ${{ github.ref == 'refs/heads/main' }} 90 | run: flyctl deploy --remote-only --config ./fly.production.toml --build-arg COMMIT_SHA=${{ github.sha }} 91 | env: 92 | FLY_API_TOKEN: ${{ secrets.FLY_API_TOKEN }} 93 | 94 | purge: 95 | name: 🧹 Purge CDN 96 | runs-on: ubuntu-latest 97 | needs: [deploy] 98 | steps: 99 | - name: 🧹 Purge All 100 | run: | 101 | curl -D - -X POST --location "https://api.fastly.com/service/${{ secrets.FASTLY_SERVICE_ID }}/purge_all" -H "Accept: application/json" -H "Fastly-Key: ${{ secrets.FASTLY_API_TOKEN }}" -H "fastly-soft-purge: 1" 102 | -------------------------------------------------------------------------------- /.github/workflows/deploy.staging.yml: -------------------------------------------------------------------------------- 1 | name: 🚀 Deploy (staging) 2 | on: 3 | push: 4 | tags: 5 | - stage 6 | branches: 7 | - dev 8 | paths-ignore: 9 | - "README.md" 10 | 11 | concurrency: 12 | group: ${{ github.workflow }}-${{ github.ref }} 13 | cancel-in-progress: true 14 | 15 | env: 16 | FLY_API_TOKEN: ${{ secrets.FLY_API_TOKEN }} 17 | 18 | jobs: 19 | lint: 20 | name: ⬣ ESLint 21 | runs-on: ubuntu-latest 22 | steps: 23 | - name: ⬇️ Checkout repo 24 | uses: actions/checkout@v4 25 | 26 | - name: ⎔ Setup node 27 | uses: actions/setup-node@v4 28 | with: 29 | cache: npm 30 | cache-dependency-path: ./package-lock.json 31 | node-version: 22 32 | 33 | - name: 📥 Install deps 34 | run: npm install 35 | 36 | - name: 🔬 Lint 37 | run: npm run lint 38 | 39 | typecheck: 40 | name: ʦ TypeScript 41 | runs-on: ubuntu-latest 42 | steps: 43 | - name: ⬇️ Checkout repo 44 | uses: actions/checkout@v4 45 | 46 | - name: ⎔ Setup node 47 | uses: actions/setup-node@v4 48 | with: 49 | cache: npm 50 | cache-dependency-path: ./package-lock.json 51 | node-version: 22 52 | 53 | - name: 📥 Install deps 54 | run: npm install 55 | 56 | - name: 🔎 Type check 57 | run: npm run typecheck --if-present 58 | 59 | vitest: 60 | name: ⚡ Vitest 61 | runs-on: ubuntu-latest 62 | steps: 63 | - name: ⬇️ Checkout repo 64 | uses: actions/checkout@v4 65 | 66 | - name: ⎔ Setup node 67 | uses: actions/setup-node@v4 68 | with: 69 | cache: npm 70 | cache-dependency-path: ./package-lock.json 71 | node-version: 22 72 | 73 | - name: 📥 Install deps 74 | run: npm install 75 | 76 | - name: ⚡ Run vitest 77 | run: npm run test -- --coverage 78 | 79 | deploy: 80 | name: 🚀 Deploy 81 | runs-on: ubuntu-latest 82 | needs: [lint, typecheck, vitest] 83 | steps: 84 | - name: ⬇️ Checkout repo 85 | uses: actions/checkout@v4 86 | 87 | - name: 🎈 Setup Fly 88 | uses: superfly/flyctl-actions/setup-flyctl@1.5 89 | 90 | - name: 🚀 Deploy Staging 91 | run: flyctl deploy --remote-only --config ./fly.staging.toml --build-arg COMMIT_SHA=${{ github.sha }} --strategy bluegreen 92 | env: 93 | FLY_API_TOKEN: ${{ secrets.FLY_API_TOKEN }} 94 | -------------------------------------------------------------------------------- /.github/workflows/format.yml: -------------------------------------------------------------------------------- 1 | name: 👔 Format 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | 8 | concurrency: 9 | group: ${{ github.workflow }}-${{ github.ref }} 10 | cancel-in-progress: true 11 | 12 | jobs: 13 | format: 14 | if: github.repository == 'remix-run/react-router-website' 15 | runs-on: ubuntu-latest 16 | 17 | steps: 18 | - name: ⬇️ Checkout repo 19 | uses: actions/checkout@v4 20 | 21 | - name: ⎔ Setup node 22 | uses: actions/setup-node@v4 23 | with: 24 | cache: npm 25 | node-version: 22 26 | 27 | - name: 📥 Install deps 28 | run: npm ci 29 | 30 | - name: 👔 Format 31 | run: npm run format 32 | 33 | - name: 💪 Commit 34 | run: | 35 | git config --local user.email "github-actions[bot]@users.noreply.github.com" 36 | git config --local user.name "github-actions[bot]" 37 | 38 | git add . 39 | if [ -z "$(git status --porcelain)" ]; then 40 | echo "💿 no formatting changed" 41 | exit 0 42 | fi 43 | git commit -m "chore: format" 44 | git push 45 | echo "💿 pushed formatting changes https://github.com/$GITHUB_REPOSITORY/commit/$(git rev-parse HEAD)" 46 | -------------------------------------------------------------------------------- /.github/workflows/lint.yml: -------------------------------------------------------------------------------- 1 | name: ⬣ Lint 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | pull_request: 8 | 9 | concurrency: 10 | group: ${{ github.workflow }}-${{ github.ref }} 11 | cancel-in-progress: true 12 | 13 | jobs: 14 | lint: 15 | name: ⬣ Lint 16 | runs-on: ubuntu-latest 17 | steps: 18 | - name: ⬇️ Checkout repo 19 | uses: actions/checkout@v4 20 | 21 | - name: ⎔ Setup node 22 | uses: actions/setup-node@v4 23 | with: 24 | cache: npm 25 | node-version: 22 26 | 27 | - name: 📥 Install deps 28 | run: npm ci 29 | 30 | - name: 🔬 Lint 31 | run: npm run lint 32 | -------------------------------------------------------------------------------- /.github/workflows/no-response.yml: -------------------------------------------------------------------------------- 1 | name: 🥺 No Response 2 | 3 | on: 4 | schedule: 5 | # Schedule for five minutes after the hour, every hour 6 | - cron: "5 * * * *" 7 | 8 | permissions: 9 | issues: write 10 | pull-requests: write 11 | 12 | jobs: 13 | stale: 14 | if: github.repository == 'remix-run/react-router-website' 15 | runs-on: ubuntu-latest 16 | steps: 17 | - name: 🥺 Handle Ghosting 18 | uses: actions/stale@v9 19 | with: 20 | close-issue-message: > 21 | This issue has been automatically closed because we haven't received a 22 | response from the original author 🙈. This automation helps keep the issue 23 | tracker clean from issues that aren't actionable. Please reach out if you 24 | have more information for us! 🙂 25 | close-pr-message: > 26 | This PR has been automatically closed because we haven't received a 27 | response from the original author 🙈. This automation helps keep the issue 28 | tracker clean from PRs that aren't actionable. Please reach out if you 29 | want to resume the work on this PR! 🙂 30 | # don't automatically mark issues/PRs as stale 31 | days-before-stale: -1 32 | stale-issue-label: needs-response 33 | stale-pr-label: needs-response 34 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | 4 | /build 5 | /public/build 6 | .react-router 7 | .env 8 | 9 | /cypress/screenshots 10 | /cypress/videos 11 | /prisma/data.db 12 | /prisma/data.db-journal 13 | 14 | /.local.tgz 15 | app/modules/gh-docs/.server/__fixture__/tar.tgz 16 | 17 | *.code-workspace 18 | -------------------------------------------------------------------------------- /.gitpod.Dockerfile: -------------------------------------------------------------------------------- 1 | FROM gitpod/workspace-full 2 | 3 | # Install Fly 4 | RUN curl -L https://fly.io/install.sh | sh 5 | ENV FLYCTL_INSTALL="/home/gitpod/.fly" 6 | ENV PATH="$FLYCTL_INSTALL/bin:$PATH" 7 | 8 | # Install GitHub CLI 9 | RUN brew install gh 10 | -------------------------------------------------------------------------------- /.gitpod.yml: -------------------------------------------------------------------------------- 1 | # https://www.gitpod.io/docs/config-gitpod-file 2 | 3 | image: 4 | file: .gitpod.Dockerfile 5 | 6 | ports: 7 | - port: 3000 8 | onOpen: notify 9 | 10 | tasks: 11 | - name: Restore .env file 12 | command: | 13 | if [ -f .env ]; then 14 | # If this workspace already has a .env, don't override it 15 | # Local changes survive a workspace being opened and closed 16 | # but they will not persist between separate workspaces for the same repo 17 | 18 | echo "Found .env in workspace" 19 | else 20 | # There is no .env 21 | if [ ! -n "${ENV}" ]; then 22 | # There is no $ENV from a previous workspace 23 | # Default to the example .env 24 | echo "Setting example .env" 25 | 26 | cp .env.example .env 27 | else 28 | # After making changes to .env, run this line to persist it to $ENV 29 | # eval $(gp env -e ENV="$(base64 .env | tr -d '\n')") 30 | # 31 | # Environment variables set this way are shared between all your workspaces for this repo 32 | # The lines below will read $ENV and print a .env file 33 | 34 | echo "Restoring .env from Gitpod" 35 | 36 | echo "${ENV}" | base64 -d | tee .env > /dev/null 37 | fi 38 | fi 39 | 40 | - init: npm install 41 | command: npm run setup && npm run dev 42 | 43 | vscode: 44 | extensions: 45 | - ms-azuretools.vscode-docker 46 | - esbenp.prettier-vscode 47 | - dbaeumer.vscode-eslint 48 | - bradlc.vscode-tailwindcss 49 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | # Allows us to upgrade to React 19 -- remove when @docsearch/react updates 2 | legacy-peer-deps=true -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | 22 -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | 3 | /build 4 | /public/build 5 | .env 6 | _redirects 7 | 8 | /data -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:22-alpine AS development-dependencies-env 2 | COPY . /app 3 | WORKDIR /app 4 | RUN npm ci 5 | 6 | FROM node:22-alpine AS production-dependencies-env 7 | COPY ./package.json package-lock.json .npmrc /app/ 8 | WORKDIR /app 9 | RUN npm ci --omit=dev 10 | 11 | FROM node:22-alpine AS build-env 12 | COPY . /app/ 13 | COPY --from=development-dependencies-env /app/node_modules /app/node_modules 14 | WORKDIR /app 15 | RUN npm run build 16 | 17 | FROM node:22-alpine 18 | COPY ./package.json package-lock.json server.js /app/ 19 | 20 | 21 | ENV PORT="8080" 22 | ENV NODE_ENV="production" 23 | 24 | COPY --from=production-dependencies-env /app/node_modules /app/node_modules 25 | COPY --from=build-env /app/build /app/build 26 | COPY --from=build-env /app/start.sh /app/start.sh 27 | 28 | 29 | WORKDIR /app 30 | CMD ["npm", "run", "start"] -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) React Training LLC 2015-2021 4 | Copyright (c) Shopify Inc. 2022-2025 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # React Router Website! 2 | 3 | ## Contributing 4 | 5 | If you want to make a contribution 6 | 7 | - [Fork and clone](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/working-with-forks/fork-a-repo) this repo 8 | - Create a branch 9 | - Push any changes you make to your branch 10 | - Open up a PR in this Repo 11 | 12 | ## Setup 13 | 14 | First setup your `.env` file, use `.env.example` to know what to set. 15 | 16 | ```sh 17 | cp .env.example .env 18 | ``` 19 | 20 | Install dependencies 21 | 22 | ```sh 23 | npm i 24 | ``` 25 | 26 | ## Local Development 27 | 28 | Now you should be good to go: 29 | 30 | ```sh 31 | npm run dev 32 | ``` 33 | 34 | To preview local changes to the `docs` folder in the React Router repo, select "local" from the version dropdown menu on the site. Make sure you have the [react-router repo](https://github.com/remix-run/react-router) cloned locally and `LOCAL_REPO_RELATIVE_PATH` is pointed to the correct filepath. 35 | 36 | We leverage a number of LRUCache's to server-side cache various resources, such as processed markdown from GitHub, that expire at various times (usually after 5 minutes). If you want them to expire immediately for local development, set the `NO_CACHE` environment variable. 37 | 38 | ```sh 39 | NO_CACHE=1 npm run dev 40 | ``` 41 | 42 | Note that by default this assumes the relative path to your local copy of the React Router docs is `../react-router`. This can be configured via `LOCAL_REPO_RELATIVE_PATH` in your `.env` file. 43 | 44 | ## Preview 45 | 46 | To preview the production build locally: 47 | 48 | ```sh 49 | npm run build 50 | npm run preview 51 | ``` 52 | 53 | ## Deployment 54 | 55 | The production server is always in sync with `main` 56 | 57 | ```sh 58 | git push origin main 59 | open https://reactrouter.com 60 | ``` 61 | 62 | Pushing the "stage" tag will deploy to [staging](https://reactrouterdotcomstaging.fly.dev/). 63 | 64 | ```sh 65 | git checkout my/branch 66 | 67 | # moves the `stage` tag and pushes it, triggering a deploy 68 | npm run push:stage 69 | ``` 70 | 71 | When you're happy with it, merge your branch into `main` and push. 72 | 73 | ## CSS Notes 74 | 75 | You'll want the [tailwind VSCode plugin](https://marketplace.visualstudio.com/items?itemName=bradlc.vscode-tailwindcss) for sure, the hints are amazing. 76 | 77 | The color scheme has various shades but we also have a special "brand" rule for each of our brand colors so we don't have to know the specific number of that color like this: `
`. 78 | 79 | We want to use Tailwind's default classes as much as possible to avoid a large CSS file. A few things you can do to keep the styles shared: 80 | 81 | - Avoid changing anything but the theme in `tailwind.config.js`, no special classes, etc. 82 | - Avoid "inline rules" like `color-[#ccc]` as much as possible. 83 | - Silly HTML (like a wrapper div to add padding on a container) is better than one-off css rules. 84 | 85 | ## Algolia Search 86 | 87 | We use [DocSearch](https://docsearch.algolia.com/) by Algolia for our documentation's search. The site is automatically scraped and indexed weekly by the [Algolia Crawler](https://crawler.algolia.com/). 88 | 89 | If the doc search results ever seem outdated or incorrect be sure to check that the crawler isn't blocked. If it is, it might just need to be canceled and restarted to kick things off again. There is also an editor in the Crawler admin that lets you adjust the crawler's script if needed. 90 | -------------------------------------------------------------------------------- /app/actions/color-scheme.ts: -------------------------------------------------------------------------------- 1 | export { action } from "~/modules/color-scheme/server"; 2 | -------------------------------------------------------------------------------- /app/components/README.md: -------------------------------------------------------------------------------- 1 | These components are specific to this app 2 | -------------------------------------------------------------------------------- /app/components/_playground/README.md: -------------------------------------------------------------------------------- 1 | Visit `http://localhost:3000/__components` to render the playground. 2 | 3 | It's like bootleg storybook so you can build/tweak/play around with components in isolation 4 | -------------------------------------------------------------------------------- /app/components/_playground/playground.tsx: -------------------------------------------------------------------------------- 1 | import { Header } from "../docs-header/docs-header"; 2 | import { fakeMenu } from "./fake-menu"; 3 | 4 | export async function loader() { 5 | return { 6 | menu: fakeMenu, 7 | header: { 8 | branches: ["main", "dev", "local"], 9 | currentGitHubRef: "main", 10 | isLatest: true, 11 | latestVersion: "7.0.1", 12 | releaseBranch: "main", 13 | versions: ["6.26.1", "7.0.0"], 14 | lang: "en", 15 | hasAPIDocs: true, 16 | apiDocsRef: "dev", 17 | }, 18 | }; 19 | } 20 | 21 | export default function Playground() { 22 | return ( 23 | <> 24 |
25 | {/*