├── .gitignore ├── .npmrc ├── .vscode └── settings.json ├── README.md ├── apps ├── docs │ ├── .gitignore │ ├── README.md │ ├── app │ │ ├── favicon.ico │ │ ├── fonts │ │ │ ├── GeistMonoVF.woff │ │ │ └── GeistVF.woff │ │ ├── globals.css │ │ ├── layout.tsx │ │ ├── page.module.css │ │ └── page.tsx │ ├── eslint.config.js │ ├── next.config.js │ ├── package.json │ ├── public │ │ ├── file-text.svg │ │ ├── globe.svg │ │ ├── next.svg │ │ ├── turborepo-dark.svg │ │ ├── turborepo-light.svg │ │ ├── vercel.svg │ │ └── window.svg │ └── tsconfig.json └── web │ ├── .gitignore │ ├── README.md │ ├── app │ ├── favicon.ico │ ├── fonts │ │ ├── GeistMonoVF.woff │ │ └── GeistVF.woff │ ├── globals.css │ ├── layout.tsx │ ├── page.module.css │ └── page.tsx │ ├── eslint.config.js │ ├── next.config.js │ ├── package.json │ ├── public │ ├── file-text.svg │ ├── globe.svg │ ├── next.svg │ ├── turborepo-dark.svg │ ├── turborepo-light.svg │ ├── vercel.svg │ └── window.svg │ └── tsconfig.json ├── package.json ├── packages ├── eslint-config │ ├── README.md │ ├── base.js │ ├── next.js │ ├── package.json │ └── react-internal.js ├── typescript-config │ ├── base.json │ ├── nextjs.json │ ├── package.json │ └── react-library.json └── ui │ ├── eslint.config.mjs │ ├── package.json │ ├── src │ ├── button.tsx │ ├── card.tsx │ └── code.tsx │ ├── tsconfig.json │ └── turbo │ └── generators │ ├── config.ts │ └── templates │ └── component.hbs ├── pnpm-lock.yaml ├── pnpm-workspace.yaml └── turbo.json /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # Dependencies 4 | node_modules 5 | .pnp 6 | .pnp.js 7 | 8 | # Local env files 9 | .env 10 | .env.local 11 | .env.development.local 12 | .env.test.local 13 | .env.production.local 14 | 15 | # Testing 16 | coverage 17 | 18 | # Turbo 19 | .turbo 20 | 21 | # Vercel 22 | .vercel 23 | 24 | # Build Outputs 25 | .next/ 26 | out/ 27 | build 28 | dist 29 | 30 | 31 | # Debug 32 | npm-debug.log* 33 | yarn-debug.log* 34 | yarn-error.log* 35 | 36 | # Misc 37 | .DS_Store 38 | *.pem 39 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emilwidlund/tactile/8e3a490ab1d3b02a813c078a12c52015be8286d9/.npmrc -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "eslint.workingDirectories": [ 3 | { 4 | "mode": "auto" 5 | } 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Turborepo starter 2 | 3 | This Turborepo starter is maintained by the Turborepo core team. 4 | 5 | ## Using this example 6 | 7 | Run the following command: 8 | 9 | ```sh 10 | npx create-turbo@latest 11 | ``` 12 | 13 | ## What's inside? 14 | 15 | This Turborepo includes the following packages/apps: 16 | 17 | ### Apps and Packages 18 | 19 | - `docs`: a [Next.js](https://nextjs.org/) app 20 | - `web`: another [Next.js](https://nextjs.org/) app 21 | - `@repo/ui`: a stub React component library shared by both `web` and `docs` applications 22 | - `@repo/eslint-config`: `eslint` configurations (includes `eslint-config-next` and `eslint-config-prettier`) 23 | - `@repo/typescript-config`: `tsconfig.json`s used throughout the monorepo 24 | 25 | Each package/app is 100% [TypeScript](https://www.typescriptlang.org/). 26 | 27 | ### Utilities 28 | 29 | This Turborepo has some additional tools already setup for you: 30 | 31 | - [TypeScript](https://www.typescriptlang.org/) for static type checking 32 | - [ESLint](https://eslint.org/) for code linting 33 | - [Prettier](https://prettier.io) for code formatting 34 | 35 | ### Build 36 | 37 | To build all apps and packages, run the following command: 38 | 39 | ``` 40 | cd my-turborepo 41 | pnpm build 42 | ``` 43 | 44 | ### Develop 45 | 46 | To develop all apps and packages, run the following command: 47 | 48 | ``` 49 | cd my-turborepo 50 | pnpm dev 51 | ``` 52 | 53 | ### Remote Caching 54 | 55 | > [!TIP] 56 | > Vercel Remote Cache is free for all plans. Get started today at [vercel.com](https://vercel.com/signup?/signup?utm_source=remote-cache-sdk&utm_campaign=free_remote_cache). 57 | 58 | Turborepo can use a technique known as [Remote Caching](https://turbo.build/repo/docs/core-concepts/remote-caching) to share cache artifacts across machines, enabling you to share build caches with your team and CI/CD pipelines. 59 | 60 | By default, Turborepo will cache locally. To enable Remote Caching you will need an account with Vercel. If you don't have an account you can [create one](https://vercel.com/signup?utm_source=turborepo-examples), then enter the following commands: 61 | 62 | ``` 63 | cd my-turborepo 64 | npx turbo login 65 | ``` 66 | 67 | This will authenticate the Turborepo CLI with your [Vercel account](https://vercel.com/docs/concepts/personal-accounts/overview). 68 | 69 | Next, you can link your Turborepo to your Remote Cache by running the following command from the root of your Turborepo: 70 | 71 | ``` 72 | npx turbo link 73 | ``` 74 | 75 | ## Useful Links 76 | 77 | Learn more about the power of Turborepo: 78 | 79 | - [Tasks](https://turbo.build/repo/docs/core-concepts/monorepos/running-tasks) 80 | - [Caching](https://turbo.build/repo/docs/core-concepts/caching) 81 | - [Remote Caching](https://turbo.build/repo/docs/core-concepts/remote-caching) 82 | - [Filtering](https://turbo.build/repo/docs/core-concepts/monorepos/filtering) 83 | - [Configuration Options](https://turbo.build/repo/docs/reference/configuration) 84 | - [CLI Usage](https://turbo.build/repo/docs/reference/command-line-reference) 85 | -------------------------------------------------------------------------------- /apps/docs/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | .yarn/install-state.gz 8 | 9 | # testing 10 | /coverage 11 | 12 | # next.js 13 | /.next/ 14 | /out/ 15 | 16 | # production 17 | /build 18 | 19 | # misc 20 | .DS_Store 21 | *.pem 22 | 23 | # debug 24 | npm-debug.log* 25 | yarn-debug.log* 26 | yarn-error.log* 27 | 28 | # env files (can opt-in for commiting if needed) 29 | .env* 30 | 31 | # vercel 32 | .vercel 33 | 34 | # typescript 35 | *.tsbuildinfo 36 | next-env.d.ts 37 | -------------------------------------------------------------------------------- /apps/docs/README.md: -------------------------------------------------------------------------------- 1 | This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-app`](https://nextjs.org/docs/app/api-reference/create-next-app). 2 | 3 | ## Getting Started 4 | 5 | First, run the development server: 6 | 7 | ```bash 8 | npm run dev 9 | # or 10 | yarn dev 11 | # or 12 | pnpm dev 13 | # or 14 | bun dev 15 | ``` 16 | 17 | Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. 18 | 19 | You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file. 20 | 21 | This project uses [`next/font`](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) to automatically optimize and load Inter, a custom Google Font. 22 | 23 | ## Learn More 24 | 25 | To learn more about Next.js, take a look at the following resources: 26 | 27 | - [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API. 28 | - [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial. 29 | 30 | You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js) - your feedback and contributions are welcome! 31 | 32 | ## Deploy on Vercel 33 | 34 | The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js. 35 | 36 | Check out our [Next.js deployment documentation](https://nextjs.org/docs/app/building-your-application/deploying) for more details. 37 | -------------------------------------------------------------------------------- /apps/docs/app/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emilwidlund/tactile/8e3a490ab1d3b02a813c078a12c52015be8286d9/apps/docs/app/favicon.ico -------------------------------------------------------------------------------- /apps/docs/app/fonts/GeistMonoVF.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emilwidlund/tactile/8e3a490ab1d3b02a813c078a12c52015be8286d9/apps/docs/app/fonts/GeistMonoVF.woff -------------------------------------------------------------------------------- /apps/docs/app/fonts/GeistVF.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emilwidlund/tactile/8e3a490ab1d3b02a813c078a12c52015be8286d9/apps/docs/app/fonts/GeistVF.woff -------------------------------------------------------------------------------- /apps/docs/app/globals.css: -------------------------------------------------------------------------------- 1 | :root { 2 | --background: #ffffff; 3 | --foreground: #171717; 4 | } 5 | 6 | @media (prefers-color-scheme: dark) { 7 | :root { 8 | --background: #0a0a0a; 9 | --foreground: #ededed; 10 | } 11 | } 12 | 13 | html, 14 | body { 15 | max-width: 100vw; 16 | overflow-x: hidden; 17 | } 18 | 19 | body { 20 | color: var(--foreground); 21 | background: var(--background); 22 | } 23 | 24 | * { 25 | box-sizing: border-box; 26 | padding: 0; 27 | margin: 0; 28 | } 29 | 30 | a { 31 | color: inherit; 32 | text-decoration: none; 33 | } 34 | 35 | .imgDark { 36 | display: none; 37 | } 38 | 39 | @media (prefers-color-scheme: dark) { 40 | html { 41 | color-scheme: dark; 42 | } 43 | 44 | .imgLight { 45 | display: none; 46 | } 47 | .imgDark { 48 | display: unset; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /apps/docs/app/layout.tsx: -------------------------------------------------------------------------------- 1 | import type { Metadata } from "next"; 2 | import localFont from "next/font/local"; 3 | import "./globals.css"; 4 | 5 | const geistSans = localFont({ 6 | src: "./fonts/GeistVF.woff", 7 | variable: "--font-geist-sans", 8 | }); 9 | const geistMono = localFont({ 10 | src: "./fonts/GeistMonoVF.woff", 11 | variable: "--font-geist-mono", 12 | }); 13 | 14 | export const metadata: Metadata = { 15 | title: "Create Next App", 16 | description: "Generated by create next app", 17 | }; 18 | 19 | export default function RootLayout({ 20 | children, 21 | }: Readonly<{ 22 | children: React.ReactNode; 23 | }>) { 24 | return ( 25 | 26 | 27 | {children} 28 | 29 | 30 | ); 31 | } 32 | -------------------------------------------------------------------------------- /apps/docs/app/page.module.css: -------------------------------------------------------------------------------- 1 | .page { 2 | --gray-rgb: 0, 0, 0; 3 | --gray-alpha-200: rgba(var(--gray-rgb), 0.08); 4 | --gray-alpha-100: rgba(var(--gray-rgb), 0.05); 5 | 6 | --button-primary-hover: #383838; 7 | --button-secondary-hover: #f2f2f2; 8 | 9 | display: grid; 10 | grid-template-rows: 20px 1fr 20px; 11 | align-items: center; 12 | justify-items: center; 13 | min-height: 100svh; 14 | padding: 80px; 15 | gap: 64px; 16 | font-synthesis: none; 17 | } 18 | 19 | @media (prefers-color-scheme: dark) { 20 | .page { 21 | --gray-rgb: 255, 255, 255; 22 | --gray-alpha-200: rgba(var(--gray-rgb), 0.145); 23 | --gray-alpha-100: rgba(var(--gray-rgb), 0.06); 24 | 25 | --button-primary-hover: #ccc; 26 | --button-secondary-hover: #1a1a1a; 27 | } 28 | } 29 | 30 | .main { 31 | display: flex; 32 | flex-direction: column; 33 | gap: 32px; 34 | grid-row-start: 2; 35 | } 36 | 37 | .main ol { 38 | font-family: var(--font-geist-mono); 39 | padding-left: 0; 40 | margin: 0; 41 | font-size: 14px; 42 | line-height: 24px; 43 | letter-spacing: -0.01em; 44 | list-style-position: inside; 45 | } 46 | 47 | .main li:not(:last-of-type) { 48 | margin-bottom: 8px; 49 | } 50 | 51 | .main code { 52 | font-family: inherit; 53 | background: var(--gray-alpha-100); 54 | padding: 2px 4px; 55 | border-radius: 4px; 56 | font-weight: 600; 57 | } 58 | 59 | .ctas { 60 | display: flex; 61 | gap: 16px; 62 | } 63 | 64 | .ctas a { 65 | appearance: none; 66 | border-radius: 128px; 67 | height: 48px; 68 | padding: 0 20px; 69 | border: none; 70 | font-family: var(--font-geist-sans); 71 | border: 1px solid transparent; 72 | transition: background 0.2s, color 0.2s, border-color 0.2s; 73 | cursor: pointer; 74 | display: flex; 75 | align-items: center; 76 | justify-content: center; 77 | font-size: 16px; 78 | line-height: 20px; 79 | font-weight: 500; 80 | } 81 | 82 | a.primary { 83 | background: var(--foreground); 84 | color: var(--background); 85 | gap: 8px; 86 | } 87 | 88 | a.secondary { 89 | border-color: var(--gray-alpha-200); 90 | min-width: 180px; 91 | } 92 | 93 | button.secondary { 94 | appearance: none; 95 | border-radius: 128px; 96 | height: 48px; 97 | padding: 0 20px; 98 | border: none; 99 | font-family: var(--font-geist-sans); 100 | border: 1px solid transparent; 101 | transition: background 0.2s, color 0.2s, border-color 0.2s; 102 | cursor: pointer; 103 | display: flex; 104 | align-items: center; 105 | justify-content: center; 106 | font-size: 16px; 107 | line-height: 20px; 108 | font-weight: 500; 109 | background: transparent; 110 | border-color: var(--gray-alpha-200); 111 | min-width: 180px; 112 | } 113 | 114 | .footer { 115 | font-family: var(--font-geist-sans); 116 | grid-row-start: 3; 117 | display: flex; 118 | gap: 24px; 119 | } 120 | 121 | .footer a { 122 | display: flex; 123 | align-items: center; 124 | gap: 8px; 125 | } 126 | 127 | .footer img { 128 | flex-shrink: 0; 129 | } 130 | 131 | /* Enable hover only on non-touch devices */ 132 | @media (hover: hover) and (pointer: fine) { 133 | a.primary:hover { 134 | background: var(--button-primary-hover); 135 | border-color: transparent; 136 | } 137 | 138 | a.secondary:hover { 139 | background: var(--button-secondary-hover); 140 | border-color: transparent; 141 | } 142 | 143 | .footer a:hover { 144 | text-decoration: underline; 145 | text-underline-offset: 4px; 146 | } 147 | } 148 | 149 | @media (max-width: 600px) { 150 | .page { 151 | padding: 32px; 152 | padding-bottom: 80px; 153 | } 154 | 155 | .main { 156 | align-items: center; 157 | } 158 | 159 | .main ol { 160 | text-align: center; 161 | } 162 | 163 | .ctas { 164 | flex-direction: column; 165 | } 166 | 167 | .ctas a { 168 | font-size: 14px; 169 | height: 40px; 170 | padding: 0 16px; 171 | } 172 | 173 | a.secondary { 174 | min-width: auto; 175 | } 176 | 177 | .footer { 178 | flex-wrap: wrap; 179 | align-items: center; 180 | justify-content: center; 181 | } 182 | } 183 | 184 | @media (prefers-color-scheme: dark) { 185 | .logo { 186 | filter: invert(); 187 | } 188 | } 189 | -------------------------------------------------------------------------------- /apps/docs/app/page.tsx: -------------------------------------------------------------------------------- 1 | import Image, { type ImageProps } from "next/image"; 2 | import { Button } from "@repo/ui/button"; 3 | import styles from "./page.module.css"; 4 | 5 | type Props = Omit & { 6 | srcLight: string; 7 | srcDark: string; 8 | }; 9 | 10 | const ThemeImage = (props: Props) => { 11 | const { srcLight, srcDark, ...rest } = props; 12 | 13 | return ( 14 | <> 15 | 16 | 17 | 18 | ); 19 | }; 20 | 21 | export default function Home() { 22 | return ( 23 |
24 |
25 | 34 |
    35 |
  1. 36 | Get started by editing apps/docs/app/page.tsx 37 |
  2. 38 |
  3. Save and see your changes instantly.
  4. 39 |
40 | 41 |
42 | 48 | Vercel logomark 55 | Deploy now 56 | 57 | 63 | Read our docs 64 | 65 |
66 | 69 |
70 | 100 |
101 | ); 102 | } 103 | -------------------------------------------------------------------------------- /apps/docs/eslint.config.js: -------------------------------------------------------------------------------- 1 | import { nextJsConfig } from "@repo/eslint-config/next-js"; 2 | 3 | /** @type {import("eslint").Linter.Config} */ 4 | export default nextJsConfig; 5 | -------------------------------------------------------------------------------- /apps/docs/next.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = {}; 3 | 4 | export default nextConfig; 5 | -------------------------------------------------------------------------------- /apps/docs/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "docs", 3 | "version": "0.1.0", 4 | "type": "module", 5 | "private": true, 6 | "scripts": { 7 | "dev": "next dev --turbopack --port 3001", 8 | "build": "next build", 9 | "start": "next start", 10 | "lint": "next lint --max-warnings 0", 11 | "check-types": "tsc --noEmit" 12 | }, 13 | "dependencies": { 14 | "@repo/ui": "workspace:*", 15 | "next": "^15.2.1", 16 | "react": "^19.0.0", 17 | "react-dom": "^19.0.0" 18 | }, 19 | "devDependencies": { 20 | "@repo/eslint-config": "workspace:*", 21 | "@repo/typescript-config": "workspace:*", 22 | "@types/node": "^22.13.9", 23 | "@types/react": "19.0.10", 24 | "@types/react-dom": "19.0.4", 25 | "eslint": "^9.22.0", 26 | "typescript": "5.8.2" 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /apps/docs/public/file-text.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /apps/docs/public/globe.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /apps/docs/public/next.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /apps/docs/public/turborepo-dark.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /apps/docs/public/turborepo-light.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /apps/docs/public/vercel.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /apps/docs/public/window.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /apps/docs/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@repo/typescript-config/nextjs.json", 3 | "compilerOptions": { 4 | "plugins": [ 5 | { 6 | "name": "next" 7 | } 8 | ] 9 | }, 10 | "include": [ 11 | "**/*.ts", 12 | "**/*.tsx", 13 | "next-env.d.ts", 14 | "next.config.js", 15 | ".next/types/**/*.ts" 16 | ], 17 | "exclude": [ 18 | "node_modules" 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /apps/web/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | .yarn/install-state.gz 8 | 9 | # testing 10 | /coverage 11 | 12 | # next.js 13 | /.next/ 14 | /out/ 15 | 16 | # production 17 | /build 18 | 19 | # misc 20 | .DS_Store 21 | *.pem 22 | 23 | # debug 24 | npm-debug.log* 25 | yarn-debug.log* 26 | yarn-error.log* 27 | 28 | # env files (can opt-in for commiting if needed) 29 | .env* 30 | 31 | # vercel 32 | .vercel 33 | 34 | # typescript 35 | *.tsbuildinfo 36 | next-env.d.ts 37 | -------------------------------------------------------------------------------- /apps/web/README.md: -------------------------------------------------------------------------------- 1 | This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-app`](https://nextjs.org/docs/app/api-reference/create-next-app). 2 | 3 | ## Getting Started 4 | 5 | First, run the development server: 6 | 7 | ```bash 8 | npm run dev 9 | # or 10 | yarn dev 11 | # or 12 | pnpm dev 13 | # or 14 | bun dev 15 | ``` 16 | 17 | Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. 18 | 19 | You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file. 20 | 21 | This project uses [`next/font`](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) to automatically optimize and load Inter, a custom Google Font. 22 | 23 | ## Learn More 24 | 25 | To learn more about Next.js, take a look at the following resources: 26 | 27 | - [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API. 28 | - [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial. 29 | 30 | You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js) - your feedback and contributions are welcome! 31 | 32 | ## Deploy on Vercel 33 | 34 | The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js. 35 | 36 | Check out our [Next.js deployment documentation](https://nextjs.org/docs/app/building-your-application/deploying) for more details. 37 | -------------------------------------------------------------------------------- /apps/web/app/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emilwidlund/tactile/8e3a490ab1d3b02a813c078a12c52015be8286d9/apps/web/app/favicon.ico -------------------------------------------------------------------------------- /apps/web/app/fonts/GeistMonoVF.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emilwidlund/tactile/8e3a490ab1d3b02a813c078a12c52015be8286d9/apps/web/app/fonts/GeistMonoVF.woff -------------------------------------------------------------------------------- /apps/web/app/fonts/GeistVF.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emilwidlund/tactile/8e3a490ab1d3b02a813c078a12c52015be8286d9/apps/web/app/fonts/GeistVF.woff -------------------------------------------------------------------------------- /apps/web/app/globals.css: -------------------------------------------------------------------------------- 1 | :root { 2 | --background: #ffffff; 3 | --foreground: #171717; 4 | } 5 | 6 | @media (prefers-color-scheme: dark) { 7 | :root { 8 | --background: #0a0a0a; 9 | --foreground: #ededed; 10 | } 11 | } 12 | 13 | html, 14 | body { 15 | max-width: 100vw; 16 | overflow-x: hidden; 17 | } 18 | 19 | body { 20 | color: var(--foreground); 21 | background: var(--background); 22 | } 23 | 24 | * { 25 | box-sizing: border-box; 26 | padding: 0; 27 | margin: 0; 28 | } 29 | 30 | a { 31 | color: inherit; 32 | text-decoration: none; 33 | } 34 | 35 | .imgDark { 36 | display: none; 37 | } 38 | 39 | @media (prefers-color-scheme: dark) { 40 | html { 41 | color-scheme: dark; 42 | } 43 | 44 | .imgLight { 45 | display: none; 46 | } 47 | .imgDark { 48 | display: unset; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /apps/web/app/layout.tsx: -------------------------------------------------------------------------------- 1 | import type { Metadata } from "next"; 2 | import localFont from "next/font/local"; 3 | import "./globals.css"; 4 | 5 | const geistSans = localFont({ 6 | src: "./fonts/GeistVF.woff", 7 | variable: "--font-geist-sans", 8 | }); 9 | const geistMono = localFont({ 10 | src: "./fonts/GeistMonoVF.woff", 11 | variable: "--font-geist-mono", 12 | }); 13 | 14 | export const metadata: Metadata = { 15 | title: "Create Next App", 16 | description: "Generated by create next app", 17 | }; 18 | 19 | export default function RootLayout({ 20 | children, 21 | }: Readonly<{ 22 | children: React.ReactNode; 23 | }>) { 24 | return ( 25 | 26 | 27 | {children} 28 | 29 | 30 | ); 31 | } 32 | -------------------------------------------------------------------------------- /apps/web/app/page.module.css: -------------------------------------------------------------------------------- 1 | .page { 2 | --gray-rgb: 0, 0, 0; 3 | --gray-alpha-200: rgba(var(--gray-rgb), 0.08); 4 | --gray-alpha-100: rgba(var(--gray-rgb), 0.05); 5 | 6 | --button-primary-hover: #383838; 7 | --button-secondary-hover: #f2f2f2; 8 | 9 | display: grid; 10 | grid-template-rows: 20px 1fr 20px; 11 | align-items: center; 12 | justify-items: center; 13 | min-height: 100svh; 14 | padding: 80px; 15 | gap: 64px; 16 | font-synthesis: none; 17 | } 18 | 19 | @media (prefers-color-scheme: dark) { 20 | .page { 21 | --gray-rgb: 255, 255, 255; 22 | --gray-alpha-200: rgba(var(--gray-rgb), 0.145); 23 | --gray-alpha-100: rgba(var(--gray-rgb), 0.06); 24 | 25 | --button-primary-hover: #ccc; 26 | --button-secondary-hover: #1a1a1a; 27 | } 28 | } 29 | 30 | .main { 31 | display: flex; 32 | flex-direction: column; 33 | gap: 32px; 34 | grid-row-start: 2; 35 | } 36 | 37 | .main ol { 38 | font-family: var(--font-geist-mono); 39 | padding-left: 0; 40 | margin: 0; 41 | font-size: 14px; 42 | line-height: 24px; 43 | letter-spacing: -0.01em; 44 | list-style-position: inside; 45 | } 46 | 47 | .main li:not(:last-of-type) { 48 | margin-bottom: 8px; 49 | } 50 | 51 | .main code { 52 | font-family: inherit; 53 | background: var(--gray-alpha-100); 54 | padding: 2px 4px; 55 | border-radius: 4px; 56 | font-weight: 600; 57 | } 58 | 59 | .ctas { 60 | display: flex; 61 | gap: 16px; 62 | } 63 | 64 | .ctas a { 65 | appearance: none; 66 | border-radius: 128px; 67 | height: 48px; 68 | padding: 0 20px; 69 | border: none; 70 | font-family: var(--font-geist-sans); 71 | border: 1px solid transparent; 72 | transition: background 0.2s, color 0.2s, border-color 0.2s; 73 | cursor: pointer; 74 | display: flex; 75 | align-items: center; 76 | justify-content: center; 77 | font-size: 16px; 78 | line-height: 20px; 79 | font-weight: 500; 80 | } 81 | 82 | a.primary { 83 | background: var(--foreground); 84 | color: var(--background); 85 | gap: 8px; 86 | } 87 | 88 | a.secondary { 89 | border-color: var(--gray-alpha-200); 90 | min-width: 180px; 91 | } 92 | 93 | button.secondary { 94 | appearance: none; 95 | border-radius: 128px; 96 | height: 48px; 97 | padding: 0 20px; 98 | border: none; 99 | font-family: var(--font-geist-sans); 100 | border: 1px solid transparent; 101 | transition: background 0.2s, color 0.2s, border-color 0.2s; 102 | cursor: pointer; 103 | display: flex; 104 | align-items: center; 105 | justify-content: center; 106 | font-size: 16px; 107 | line-height: 20px; 108 | font-weight: 500; 109 | background: transparent; 110 | border-color: var(--gray-alpha-200); 111 | min-width: 180px; 112 | } 113 | 114 | .footer { 115 | font-family: var(--font-geist-sans); 116 | grid-row-start: 3; 117 | display: flex; 118 | gap: 24px; 119 | } 120 | 121 | .footer a { 122 | display: flex; 123 | align-items: center; 124 | gap: 8px; 125 | } 126 | 127 | .footer img { 128 | flex-shrink: 0; 129 | } 130 | 131 | /* Enable hover only on non-touch devices */ 132 | @media (hover: hover) and (pointer: fine) { 133 | a.primary:hover { 134 | background: var(--button-primary-hover); 135 | border-color: transparent; 136 | } 137 | 138 | a.secondary:hover { 139 | background: var(--button-secondary-hover); 140 | border-color: transparent; 141 | } 142 | 143 | .footer a:hover { 144 | text-decoration: underline; 145 | text-underline-offset: 4px; 146 | } 147 | } 148 | 149 | @media (max-width: 600px) { 150 | .page { 151 | padding: 32px; 152 | padding-bottom: 80px; 153 | } 154 | 155 | .main { 156 | align-items: center; 157 | } 158 | 159 | .main ol { 160 | text-align: center; 161 | } 162 | 163 | .ctas { 164 | flex-direction: column; 165 | } 166 | 167 | .ctas a { 168 | font-size: 14px; 169 | height: 40px; 170 | padding: 0 16px; 171 | } 172 | 173 | a.secondary { 174 | min-width: auto; 175 | } 176 | 177 | .footer { 178 | flex-wrap: wrap; 179 | align-items: center; 180 | justify-content: center; 181 | } 182 | } 183 | 184 | @media (prefers-color-scheme: dark) { 185 | .logo { 186 | filter: invert(); 187 | } 188 | } 189 | -------------------------------------------------------------------------------- /apps/web/app/page.tsx: -------------------------------------------------------------------------------- 1 | import Image, { type ImageProps } from "next/image"; 2 | import { Button } from "@repo/ui/button"; 3 | import styles from "./page.module.css"; 4 | 5 | type Props = Omit & { 6 | srcLight: string; 7 | srcDark: string; 8 | }; 9 | 10 | const ThemeImage = (props: Props) => { 11 | const { srcLight, srcDark, ...rest } = props; 12 | 13 | return ( 14 | <> 15 | 16 | 17 | 18 | ); 19 | }; 20 | 21 | export default function Home() { 22 | return ( 23 |
24 |
25 | 34 |
    35 |
  1. 36 | Get started by editing apps/web/app/page.tsx 37 |
  2. 38 |
  3. Save and see your changes instantly.
  4. 39 |
40 | 41 | 66 | 69 |
70 | 100 |
101 | ); 102 | } 103 | -------------------------------------------------------------------------------- /apps/web/eslint.config.js: -------------------------------------------------------------------------------- 1 | import { nextJsConfig } from "@repo/eslint-config/next-js"; 2 | 3 | /** @type {import("eslint").Linter.Config} */ 4 | export default nextJsConfig; 5 | -------------------------------------------------------------------------------- /apps/web/next.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = {}; 3 | 4 | export default nextConfig; 5 | -------------------------------------------------------------------------------- /apps/web/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "web", 3 | "version": "0.1.0", 4 | "type": "module", 5 | "private": true, 6 | "scripts": { 7 | "dev": "next dev --turbopack --port 3000", 8 | "build": "next build", 9 | "start": "next start", 10 | "lint": "next lint --max-warnings 0", 11 | "check-types": "tsc --noEmit" 12 | }, 13 | "dependencies": { 14 | "@repo/ui": "workspace:*", 15 | "next": "^15.2.1", 16 | "react": "^19.0.0", 17 | "react-dom": "^19.0.0" 18 | }, 19 | "devDependencies": { 20 | "@repo/eslint-config": "workspace:*", 21 | "@repo/typescript-config": "workspace:*", 22 | "@types/node": "^22.13.9", 23 | "@types/react": "19.0.10", 24 | "@types/react-dom": "19.0.4", 25 | "eslint": "^9.22.0", 26 | "typescript": "5.8.2" 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /apps/web/public/file-text.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /apps/web/public/globe.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /apps/web/public/next.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /apps/web/public/turborepo-dark.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /apps/web/public/turborepo-light.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /apps/web/public/vercel.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /apps/web/public/window.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /apps/web/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@repo/typescript-config/nextjs.json", 3 | "compilerOptions": { 4 | "plugins": [ 5 | { 6 | "name": "next" 7 | } 8 | ] 9 | }, 10 | "include": [ 11 | "**/*.ts", 12 | "**/*.tsx", 13 | "next-env.d.ts", 14 | "next.config.js", 15 | ".next/types/**/*.ts" 16 | ], 17 | "exclude": [ 18 | "node_modules" 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tactile", 3 | "private": true, 4 | "scripts": { 5 | "build": "turbo run build", 6 | "dev": "turbo run dev", 7 | "lint": "turbo run lint", 8 | "format": "prettier --write \"**/*.{ts,tsx,md}\"", 9 | "check-types": "turbo run check-types" 10 | }, 11 | "devDependencies": { 12 | "prettier": "^3.5.3", 13 | "turbo": "^2.4.4", 14 | "typescript": "5.8.2" 15 | }, 16 | "packageManager": "pnpm@9.0.0", 17 | "engines": { 18 | "node": ">=18" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /packages/eslint-config/README.md: -------------------------------------------------------------------------------- 1 | # `@turbo/eslint-config` 2 | 3 | Collection of internal eslint configurations. 4 | -------------------------------------------------------------------------------- /packages/eslint-config/base.js: -------------------------------------------------------------------------------- 1 | import js from "@eslint/js"; 2 | import eslintConfigPrettier from "eslint-config-prettier"; 3 | import turboPlugin from "eslint-plugin-turbo"; 4 | import tseslint from "typescript-eslint"; 5 | import onlyWarn from "eslint-plugin-only-warn"; 6 | 7 | /** 8 | * A shared ESLint configuration for the repository. 9 | * 10 | * @type {import("eslint").Linter.Config[]} 11 | * */ 12 | export const config = [ 13 | js.configs.recommended, 14 | eslintConfigPrettier, 15 | ...tseslint.configs.recommended, 16 | { 17 | plugins: { 18 | turbo: turboPlugin, 19 | }, 20 | rules: { 21 | "turbo/no-undeclared-env-vars": "warn", 22 | }, 23 | }, 24 | { 25 | plugins: { 26 | onlyWarn, 27 | }, 28 | }, 29 | { 30 | ignores: ["dist/**"], 31 | }, 32 | ]; 33 | -------------------------------------------------------------------------------- /packages/eslint-config/next.js: -------------------------------------------------------------------------------- 1 | import js from "@eslint/js"; 2 | import eslintConfigPrettier from "eslint-config-prettier"; 3 | import tseslint from "typescript-eslint"; 4 | import pluginReactHooks from "eslint-plugin-react-hooks"; 5 | import pluginReact from "eslint-plugin-react"; 6 | import globals from "globals"; 7 | import pluginNext from "@next/eslint-plugin-next"; 8 | import { config as baseConfig } from "./base.js"; 9 | 10 | /** 11 | * A custom ESLint configuration for libraries that use Next.js. 12 | * 13 | * @type {import("eslint").Linter.Config[]} 14 | * */ 15 | export const nextJsConfig = [ 16 | ...baseConfig, 17 | js.configs.recommended, 18 | eslintConfigPrettier, 19 | ...tseslint.configs.recommended, 20 | { 21 | ...pluginReact.configs.flat.recommended, 22 | languageOptions: { 23 | ...pluginReact.configs.flat.recommended.languageOptions, 24 | globals: { 25 | ...globals.serviceworker, 26 | }, 27 | }, 28 | }, 29 | { 30 | plugins: { 31 | "@next/next": pluginNext, 32 | }, 33 | rules: { 34 | ...pluginNext.configs.recommended.rules, 35 | ...pluginNext.configs["core-web-vitals"].rules, 36 | }, 37 | }, 38 | { 39 | plugins: { 40 | "react-hooks": pluginReactHooks, 41 | }, 42 | settings: { react: { version: "detect" } }, 43 | rules: { 44 | ...pluginReactHooks.configs.recommended.rules, 45 | // React scope no longer necessary with new JSX transform. 46 | "react/react-in-jsx-scope": "off", 47 | }, 48 | }, 49 | ]; 50 | -------------------------------------------------------------------------------- /packages/eslint-config/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@repo/eslint-config", 3 | "version": "0.0.0", 4 | "type": "module", 5 | "private": true, 6 | "exports": { 7 | "./base": "./base.js", 8 | "./next-js": "./next.js", 9 | "./react-internal": "./react-internal.js" 10 | }, 11 | "devDependencies": { 12 | "@eslint/js": "^9.22.0", 13 | "@next/eslint-plugin-next": "^15.2.1", 14 | "eslint": "^9.22.0", 15 | "eslint-config-prettier": "^10.1.1", 16 | "eslint-plugin-only-warn": "^1.1.0", 17 | "eslint-plugin-react": "^7.37.4", 18 | "eslint-plugin-react-hooks": "^5.2.0", 19 | "eslint-plugin-turbo": "^2.4.4", 20 | "globals": "^16.0.0", 21 | "typescript": "^5.8.2", 22 | "typescript-eslint": "^8.26.0" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /packages/eslint-config/react-internal.js: -------------------------------------------------------------------------------- 1 | import js from "@eslint/js"; 2 | import eslintConfigPrettier from "eslint-config-prettier"; 3 | import tseslint from "typescript-eslint"; 4 | import pluginReactHooks from "eslint-plugin-react-hooks"; 5 | import pluginReact from "eslint-plugin-react"; 6 | import globals from "globals"; 7 | import { config as baseConfig } from "./base.js"; 8 | 9 | /** 10 | * A custom ESLint configuration for libraries that use React. 11 | * 12 | * @type {import("eslint").Linter.Config[]} */ 13 | export const config = [ 14 | ...baseConfig, 15 | js.configs.recommended, 16 | eslintConfigPrettier, 17 | ...tseslint.configs.recommended, 18 | pluginReact.configs.flat.recommended, 19 | { 20 | languageOptions: { 21 | ...pluginReact.configs.flat.recommended.languageOptions, 22 | globals: { 23 | ...globals.serviceworker, 24 | ...globals.browser, 25 | }, 26 | }, 27 | }, 28 | { 29 | plugins: { 30 | "react-hooks": pluginReactHooks, 31 | }, 32 | settings: { react: { version: "detect" } }, 33 | rules: { 34 | ...pluginReactHooks.configs.recommended.rules, 35 | // React scope no longer necessary with new JSX transform. 36 | "react/react-in-jsx-scope": "off", 37 | }, 38 | }, 39 | ]; 40 | -------------------------------------------------------------------------------- /packages/typescript-config/base.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/tsconfig", 3 | "compilerOptions": { 4 | "declaration": true, 5 | "declarationMap": true, 6 | "esModuleInterop": true, 7 | "incremental": false, 8 | "isolatedModules": true, 9 | "lib": ["es2022", "DOM", "DOM.Iterable"], 10 | "module": "NodeNext", 11 | "moduleDetection": "force", 12 | "moduleResolution": "NodeNext", 13 | "noUncheckedIndexedAccess": true, 14 | "resolveJsonModule": true, 15 | "skipLibCheck": true, 16 | "strict": true, 17 | "target": "ES2022" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /packages/typescript-config/nextjs.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/tsconfig", 3 | "extends": "./base.json", 4 | "compilerOptions": { 5 | "plugins": [{ "name": "next" }], 6 | "module": "ESNext", 7 | "moduleResolution": "Bundler", 8 | "allowJs": true, 9 | "jsx": "preserve", 10 | "noEmit": true 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /packages/typescript-config/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@repo/typescript-config", 3 | "version": "0.0.0", 4 | "private": true, 5 | "license": "MIT", 6 | "publishConfig": { 7 | "access": "public" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /packages/typescript-config/react-library.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/tsconfig", 3 | "extends": "./base.json", 4 | "compilerOptions": { 5 | "jsx": "react-jsx" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /packages/ui/eslint.config.mjs: -------------------------------------------------------------------------------- 1 | import { config } from "@repo/eslint-config/react-internal"; 2 | 3 | /** @type {import("eslint").Linter.Config} */ 4 | export default config; 5 | -------------------------------------------------------------------------------- /packages/ui/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@repo/ui", 3 | "version": "0.0.0", 4 | "private": true, 5 | "exports": { 6 | "./*": "./src/*.tsx" 7 | }, 8 | "scripts": { 9 | "lint": "eslint . --max-warnings 0", 10 | "generate:component": "turbo gen react-component", 11 | "check-types": "tsc --noEmit" 12 | }, 13 | "devDependencies": { 14 | "@repo/eslint-config": "workspace:*", 15 | "@repo/typescript-config": "workspace:*", 16 | "@turbo/gen": "^2.4.4", 17 | "@types/node": "^22.13.9", 18 | "@types/react": "19.0.10", 19 | "@types/react-dom": "19.0.4", 20 | "eslint": "^9.22.0", 21 | "typescript": "5.8.2" 22 | }, 23 | "dependencies": { 24 | "react": "^19.0.0", 25 | "react-dom": "^19.0.0" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /packages/ui/src/button.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import { ReactNode } from "react"; 4 | 5 | interface ButtonProps { 6 | children: ReactNode; 7 | className?: string; 8 | appName: string; 9 | } 10 | 11 | export const Button = ({ children, className, appName }: ButtonProps) => { 12 | return ( 13 | 19 | ); 20 | }; 21 | -------------------------------------------------------------------------------- /packages/ui/src/card.tsx: -------------------------------------------------------------------------------- 1 | import { type JSX } from "react"; 2 | 3 | export function Card({ 4 | className, 5 | title, 6 | children, 7 | href, 8 | }: { 9 | className?: string; 10 | title: string; 11 | children: React.ReactNode; 12 | href: string; 13 | }): JSX.Element { 14 | return ( 15 | 21 |

22 | {title} -> 23 |

24 |

{children}

25 |
26 | ); 27 | } 28 | -------------------------------------------------------------------------------- /packages/ui/src/code.tsx: -------------------------------------------------------------------------------- 1 | import { type JSX } from "react"; 2 | 3 | export function Code({ 4 | children, 5 | className, 6 | }: { 7 | children: React.ReactNode; 8 | className?: string; 9 | }): JSX.Element { 10 | return {children}; 11 | } 12 | -------------------------------------------------------------------------------- /packages/ui/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@repo/typescript-config/react-library.json", 3 | "compilerOptions": { 4 | "outDir": "dist" 5 | }, 6 | "include": ["src"], 7 | "exclude": ["node_modules", "dist"] 8 | } 9 | -------------------------------------------------------------------------------- /packages/ui/turbo/generators/config.ts: -------------------------------------------------------------------------------- 1 | import type { PlopTypes } from "@turbo/gen"; 2 | 3 | // Learn more about Turborepo Generators at https://turbo.build/repo/docs/core-concepts/monorepos/code-generation 4 | 5 | export default function generator(plop: PlopTypes.NodePlopAPI): void { 6 | // A simple generator to add a new React component to the internal UI library 7 | plop.setGenerator("react-component", { 8 | description: "Adds a new react component", 9 | prompts: [ 10 | { 11 | type: "input", 12 | name: "name", 13 | message: "What is the name of the component?", 14 | }, 15 | ], 16 | actions: [ 17 | { 18 | type: "add", 19 | path: "src/{{kebabCase name}}.tsx", 20 | templateFile: "templates/component.hbs", 21 | }, 22 | { 23 | type: "append", 24 | path: "package.json", 25 | pattern: /"exports": {(?)/g, 26 | template: ' "./{{kebabCase name}}": "./src/{{kebabCase name}}.tsx",', 27 | }, 28 | ], 29 | }); 30 | } 31 | -------------------------------------------------------------------------------- /packages/ui/turbo/generators/templates/component.hbs: -------------------------------------------------------------------------------- 1 | export const {{ pascalCase name }} = ({ children }: { children: React.ReactNode }) => { 2 | return ( 3 |
4 |

{{ pascalCase name }} Component

5 | {children} 6 |
7 | ); 8 | }; 9 | -------------------------------------------------------------------------------- /pnpm-workspace.yaml: -------------------------------------------------------------------------------- 1 | packages: 2 | - "apps/*" 3 | - "packages/*" 4 | -------------------------------------------------------------------------------- /turbo.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://turbo.build/schema.json", 3 | "ui": "tui", 4 | "tasks": { 5 | "build": { 6 | "dependsOn": ["^build"], 7 | "inputs": ["$TURBO_DEFAULT$", ".env*"], 8 | "outputs": [".next/**", "!.next/cache/**"] 9 | }, 10 | "lint": { 11 | "dependsOn": ["^lint"] 12 | }, 13 | "check-types": { 14 | "dependsOn": ["^check-types"] 15 | }, 16 | "dev": { 17 | "cache": false, 18 | "persistent": true 19 | } 20 | } 21 | } 22 | --------------------------------------------------------------------------------