├── .DS_Store ├── .gitignore ├── .prettierrc ├── LICENSE ├── README.md ├── app ├── components │ └── Button.tsx ├── cookies.ts ├── entry.client.tsx ├── entry.server.tsx ├── root.tsx └── routes │ ├── index.tsx │ ├── pages.tsx │ └── pages │ └── $id.tsx ├── package-lock.json ├── package.json ├── public ├── .DS_Store └── favicon.ico ├── remix.config.js ├── remix.env.d.ts ├── stitches.config.ts └── tsconfig.json /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rossmoody/stitches-remix/73721b21db58744264bd8b2129d94d4b9f07f121/.DS_Store -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | 3 | /.cache 4 | /build 5 | /public/build 6 | .env 7 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "trailingComma": "es5", 3 | "tabWidth": 2, 4 | "semi": false, 5 | "singleQuote": true 6 | } 7 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Ross Moody 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Welcome to Remix! 2 | 3 | - [Remix Docs](https://remix.run/docs) 4 | 5 | ## Development 6 | 7 | From your terminal: 8 | 9 | ```sh 10 | npm run dev 11 | ``` 12 | 13 | This starts your app in development mode, rebuilding assets on file changes. 14 | 15 | ## Deployment 16 | 17 | First, build your app for production: 18 | 19 | ```sh 20 | npm run build 21 | ``` 22 | 23 | Then run the app in production mode: 24 | 25 | ```sh 26 | npm start 27 | ``` 28 | 29 | Now you'll need to pick a host to deploy it to. 30 | 31 | ### DIY 32 | 33 | If you're familiar with deploying node applications, the built-in Remix app server is production-ready. 34 | 35 | Make sure to deploy the output of `remix build` 36 | 37 | - `build/` 38 | - `public/build/` 39 | 40 | ### Using a Template 41 | 42 | When you ran `npx create-remix@latest` there were a few choices for hosting. You can run that again to create a new project, then copy over your `app/` folder to the new project that's pre-configured for your target server. 43 | 44 | ```sh 45 | cd .. 46 | # create a new project, and pick a pre-configured host 47 | npx create-remix@latest 48 | cd my-new-remix-app 49 | # remove the new project's app (not the old one!) 50 | rm -rf app 51 | # copy your app over 52 | cp -R ../my-old-remix-app/app app 53 | ``` 54 | -------------------------------------------------------------------------------- /app/components/Button.tsx: -------------------------------------------------------------------------------- 1 | import { styled, darkTheme } from '../../stitches.config' 2 | 3 | export const Button = styled('button', { 4 | padding: '24px', 5 | color: '$bgBody', 6 | backgroundColor: '$text', 7 | [`${darkTheme}`]: {}, 8 | }) 9 | 10 | // Need to pass dark theme into Button component or the dark 11 | // theme variables aren't compiled and added to :root. This isn't 12 | // normally necessary. 13 | -------------------------------------------------------------------------------- /app/cookies.ts: -------------------------------------------------------------------------------- 1 | import { createCookie } from 'remix' 2 | 3 | export let colorSchemeCookie = createCookie('color-scheme') 4 | 5 | export const getColorSchemeToken = async (request: Request) => 6 | await colorSchemeCookie.parse(request.headers.get('Cookie')) 7 | 8 | export const getColorScheme = async (request: Request) => { 9 | const userSelectedColorScheme = await getColorSchemeToken(request) 10 | const systemPreferredColorScheme = request.headers.get( 11 | 'Sec-CH-Prefers-Color-Scheme' 12 | ) 13 | 14 | return userSelectedColorScheme ?? systemPreferredColorScheme ?? 'light' 15 | } 16 | -------------------------------------------------------------------------------- /app/entry.client.tsx: -------------------------------------------------------------------------------- 1 | import { hydrate } from 'react-dom' 2 | import { RemixBrowser } from 'remix' 3 | 4 | hydrate(, document) 5 | -------------------------------------------------------------------------------- /app/entry.server.tsx: -------------------------------------------------------------------------------- 1 | import ReactDOMServer from 'react-dom/server' 2 | import { RemixServer, EntryContext } from 'remix' 3 | import { getCssText } from '../stitches.config' 4 | 5 | export default async function handleRequest( 6 | request: Request, 7 | responseStatusCode: number, 8 | responseHeaders: Headers, 9 | remixContext: EntryContext 10 | ) { 11 | const markup = ReactDOMServer.renderToString( 12 | 13 | ).replace(/<\/head>/, ``) 14 | 15 | return new Response('' + markup, { 16 | status: responseStatusCode, 17 | headers: { 18 | ...Object.fromEntries(responseHeaders), 19 | 'Content-Type': 'text/html', 20 | }, 21 | }) 22 | } 23 | -------------------------------------------------------------------------------- /app/root.tsx: -------------------------------------------------------------------------------- 1 | import { 2 | Links, 3 | LiveReload, 4 | LoaderFunction, 5 | Meta, 6 | Outlet, 7 | Scripts, 8 | ScrollRestoration, 9 | useLoaderData, 10 | HeadersFunction, 11 | MetaFunction, 12 | } from 'remix' 13 | import { getColorScheme } from './cookies' 14 | 15 | export const meta: MetaFunction = () => ({ 16 | title: 'Stitches Theme Example', 17 | }) 18 | 19 | export const headers: HeadersFunction = () => ({ 20 | 'Accept-CH': 'Sec-CH-Prefers-Color-Scheme', 21 | }) 22 | 23 | export const loader: LoaderFunction = async ({ request }) => ({ 24 | colorScheme: await getColorScheme(request), 25 | }) 26 | 27 | export default function App() { 28 | const { colorScheme } = useLoaderData() 29 | 30 | return ( 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | {process.env.NODE_ENV === 'development' && } 43 | 44 | 45 | ) 46 | } 47 | -------------------------------------------------------------------------------- /app/routes/index.tsx: -------------------------------------------------------------------------------- 1 | import { Button } from '~/components/Button' 2 | import { ActionFunction, Form, redirect, Link } from 'remix' 3 | import { colorSchemeCookie, getColorScheme } from '../cookies' 4 | 5 | export const action: ActionFunction = async ({ request }) => { 6 | const currentColorScheme = await getColorScheme(request) 7 | const newColorScheme = currentColorScheme === 'light' ? 'dark' : 'light' 8 | 9 | return redirect(request.url, { 10 | headers: { 11 | 'Set-Cookie': await colorSchemeCookie.serialize(newColorScheme), 12 | }, 13 | }) 14 | } 15 | 16 | export default function Index() { 17 | return ( 18 |
19 |

Home

20 |
21 | 22 |
23 |
    24 |
  • 25 | Go to /pages 26 |
  • 27 |
  • 28 | Go to /pages/hello 29 |
  • 30 |
  • 31 | Go to /pages/goodbye 32 |
  • 33 |
34 |
35 | ) 36 | } 37 | -------------------------------------------------------------------------------- /app/routes/pages.tsx: -------------------------------------------------------------------------------- 1 | import { Outlet, Link } from 'remix' 2 | 3 | export default function Pages() { 4 | return ( 5 |
6 |

Pages

7 |
    8 |
  • 9 | Go to /pages/hello 10 |
  • 11 |
  • 12 | Go to /pages/goodbye 13 |
  • 14 |
15 | 16 | 17 |
18 | ) 19 | } 20 | -------------------------------------------------------------------------------- /app/routes/pages/$id.tsx: -------------------------------------------------------------------------------- 1 | import { Link, useParams } from 'remix' 2 | 3 | export default function Hello() { 4 | const { id } = useParams() 5 | 6 | return ( 7 |
8 |

Pages {id}

9 |
    10 |
  • 11 | Go to home 12 |
  • 13 |
  • 14 | Go to /pages 15 |
  • 16 |
17 |
18 | ) 19 | } 20 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "name": "remix-app-template", 4 | "description": "", 5 | "license": "", 6 | "scripts": { 7 | "build": "remix build", 8 | "dev": "remix dev", 9 | "postinstall": "remix setup node", 10 | "start": "remix-serve build" 11 | }, 12 | "dependencies": { 13 | "@remix-run/react": "^1.1.1", 14 | "@remix-run/serve": "^1.1.1", 15 | "@stitches/react": "^1.2.6", 16 | "react": "^17.0.2", 17 | "react-dom": "^17.0.2", 18 | "remix": "^1.1.1" 19 | }, 20 | "devDependencies": { 21 | "@remix-run/dev": "^1.1.1", 22 | "@types/react": "^17.0.24", 23 | "@types/react-dom": "^17.0.9", 24 | "typescript": "^4.1.2" 25 | }, 26 | "engines": { 27 | "node": ">=14" 28 | }, 29 | "sideEffects": false 30 | } 31 | -------------------------------------------------------------------------------- /public/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rossmoody/stitches-remix/73721b21db58744264bd8b2129d94d4b9f07f121/public/.DS_Store -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rossmoody/stitches-remix/73721b21db58744264bd8b2129d94d4b9f07f121/public/favicon.ico -------------------------------------------------------------------------------- /remix.config.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @type {import('@remix-run/dev/config').AppConfig} 3 | */ 4 | module.exports = { 5 | appDirectory: "app", 6 | assetsBuildDirectory: "public/build", 7 | publicPath: "/build/", 8 | serverBuildDirectory: "build", 9 | devServerPort: 8002, 10 | ignoredRouteFiles: [".*"] 11 | }; 12 | -------------------------------------------------------------------------------- /remix.env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | -------------------------------------------------------------------------------- /stitches.config.ts: -------------------------------------------------------------------------------- 1 | import { createStitches } from "@stitches/react"; 2 | 3 | export const { styled, createTheme, globalCss, getCssText, theme } = 4 | createStitches({ 5 | theme: { 6 | colors: { 7 | text: "#191919", 8 | bgBody: "#f8f9fa", 9 | anchor: "DarkGoldenRod", 10 | }, 11 | }, 12 | }); 13 | 14 | export const darkTheme = createTheme("dark", { 15 | colors: { 16 | text: "#f8f9fa", 17 | bgBody: "#191919", 18 | anchor: "BlanchedAlmond", 19 | }, 20 | }); 21 | 22 | globalCss({ 23 | body: { 24 | color: "$text", 25 | backgroundColor: "$bgBody", 26 | }, 27 | 28 | a: { 29 | color: "$anchor", 30 | }, 31 | })(); 32 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": ["remix.env.d.ts", "**/*.ts", "**/*.tsx"], 3 | "compilerOptions": { 4 | "lib": ["DOM", "DOM.Iterable", "ES2019"], 5 | "isolatedModules": true, 6 | "esModuleInterop": true, 7 | "jsx": "react-jsx", 8 | "moduleResolution": "node", 9 | "resolveJsonModule": true, 10 | "target": "ES2019", 11 | "strict": true, 12 | "baseUrl": ".", 13 | "paths": { 14 | "~/*": ["./app/*"] 15 | }, 16 | 17 | // Remix takes care of building everything in `remix build`. 18 | "noEmit": true 19 | } 20 | } 21 | --------------------------------------------------------------------------------