├── .eslintrc.js ├── .gitignore ├── .npmrc ├── README.md ├── apps ├── web │ ├── .eslintrc.cjs │ ├── .gitignore │ ├── README.md │ ├── index.html │ ├── package.json │ ├── postcss.config.js │ ├── public │ │ └── vite.svg │ ├── src │ │ ├── App.css │ │ ├── App.tsx │ │ ├── assets │ │ │ └── react.svg │ │ ├── index.css │ │ ├── main.tsx │ │ └── vite-env.d.ts │ ├── tailwind.config.js │ ├── tsconfig.json │ ├── tsconfig.node.json │ └── vite.config.ts └── workshop │ ├── .eslintrc.cjs │ ├── .gitignore │ ├── .storybook │ ├── main.js │ └── preview.js │ ├── README.md │ ├── index.html │ ├── package.json │ ├── postcss.config.js │ ├── public │ └── vite.svg │ ├── tailwind.config.js │ ├── tsconfig.json │ ├── tsconfig.node.json │ └── vite.config.ts ├── package.json ├── packages ├── config │ ├── .eslintrc.js │ ├── app.tsconfig.json │ ├── base.tsconfig.json │ ├── eslint │ │ └── base.js │ ├── index.js │ ├── package.json │ └── vite │ │ ├── index.ts │ │ └── relativeAliasResolver.ts ├── tsconfig │ ├── base.json │ ├── nextjs.json │ ├── package.json │ └── react-library.json └── ui │ ├── components.json │ ├── package.json │ ├── postcss.config.js │ ├── src │ ├── Button.stories.tsx │ ├── components │ │ └── ui │ │ │ └── button.tsx │ ├── index.tsx │ └── lib │ │ └── utils.ts │ ├── style │ ├── index.ts │ ├── postcss.config.js │ ├── styles.css │ └── tailwind.config.js │ ├── tailwind.config.js │ └── tsconfig.json ├── pnpm-lock.yaml ├── pnpm-workspace.yaml └── turbo.json /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | // This tells ESLint to load the config from the package `eslint-config-custom` 4 | extends: ["custom"], 5 | settings: { 6 | next: { 7 | rootDir: ["apps/*/"], 8 | }, 9 | }, 10 | }; 11 | -------------------------------------------------------------------------------- /.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 | # testing 9 | coverage 10 | 11 | # next.js 12 | .next/ 13 | out/ 14 | build 15 | 16 | # misc 17 | .DS_Store 18 | *.pem 19 | 20 | # debug 21 | npm-debug.log* 22 | yarn-debug.log* 23 | yarn-error.log* 24 | 25 | # local env files 26 | .env 27 | .env.local 28 | .env.development.local 29 | .env.test.local 30 | .env.production.local 31 | 32 | # turbo 33 | .turbo 34 | 35 | # vercel 36 | .vercel 37 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | auto-install-peers = true 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 🌱 Turborepo + TailwindCSS + Storybook 2 | 3 | ## What's inside? 4 | 5 | This Turborepo includes the following packages/apps: 6 | 7 | ### Apps and Packages 8 | 9 | - `workshop`: a Storybook app with the `ui` package imported 10 | - `docs`: a [Next.js](https://nextjs.org/) app with [Tailwind CSS](https://tailwindcss.com/) 11 | - `web`: another [Next.js](https://nextjs.org/) app with [Tailwind CSS](https://tailwindcss.com/) 12 | - `ui`: a stub React component library with [Tailwind CSS](https://tailwindcss.com/) shared by both `web` and `docs` applications with [shadcn-ui](https://github.com/shadcn/ui) already included. 13 | - `ui/eslint-config-custom`: `eslint` configurations (includes `eslint-config-next` and `eslint-config-prettier`) 14 | - `ui/tailwind-config`: reusable tailwind configuration 15 | - `ui/tsconfig`: `tsconfig.json`s used throughout the monorepo 16 | 17 | Each package/app is 100% [TypeScript](https://www.typescriptlang.org/). 18 | 19 | ### Building packages/ui 20 | 21 | This example is setup to build `packages/ui` and output the transpiled source and compiled styles to `dist/`. This was chosen to make sharing one `tailwind.config.js` as easy as possible, and to ensure only the CSS that is used by the current application and its dependencies is generated. 22 | 23 | Another option is to consume `packages/ui` directly from source without building. If using this option, you will need to update your `tailwind.config.js` to be aware of your package locations, so it can find all usages of the `tailwindcss` class names. 24 | 25 | For example, in [tailwind.config.js](packages/tailwind-config/tailwind.config.js): 26 | 27 | ```js 28 | content: [ 29 | // app content 30 | `src/**/*.{js,ts,jsx,tsx}`, 31 | // include packages if not transpiling 32 | "../../packages/**/*.{js,ts,jsx,tsx}", 33 | ], 34 | ``` 35 | 36 | ### Utilities 37 | 38 | This Turborepo has some additional tools already setup for you: 39 | 40 | - [Tailwind CSS](https://tailwindcss.com/) for styles 41 | - [TypeScript](https://www.typescriptlang.org/) for static type checking 42 | - [ESLint](https://eslint.org/) for code linting 43 | - [Prettier](https://prettier.io) for code formatting 44 | 45 | ## Using this example 46 | 47 | Run the following command: 48 | 49 | ```sh 50 | npx degit https://github.com/arevalolance/design-system-template.git design-system-template 51 | cd design-system-template 52 | pnpm install 53 | git init . && git add . && git commit -m "Init" 54 | ``` 55 | -------------------------------------------------------------------------------- /apps/web/.eslintrc.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: [require.resolve('config/eslint/web.js')], 3 | parserOptions: { 4 | tsconfigRootDir: __dirname, 5 | project: './tsconfig.json' 6 | }, 7 | }; -------------------------------------------------------------------------------- /apps/web/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /apps/web/README.md: -------------------------------------------------------------------------------- 1 | # React + TypeScript + Vite 2 | 3 | This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules. 4 | 5 | Currently, two official plugins are available: 6 | 7 | - [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/README.md) uses [Babel](https://babeljs.io/) for Fast Refresh 8 | - [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh 9 | 10 | ## Expanding the ESLint configuration 11 | 12 | If you are developing a production application, we recommend updating the configuration to enable type aware lint rules: 13 | 14 | - Configure the top-level `parserOptions` property like this: 15 | 16 | ```js 17 | parserOptions: { 18 | ecmaVersion: 'latest', 19 | sourceType: 'module', 20 | project: ['./tsconfig.json', './tsconfig.node.json'], 21 | tsconfigRootDir: __dirname, 22 | }, 23 | ``` 24 | 25 | - Replace `plugin:@typescript-eslint/recommended` to `plugin:@typescript-eslint/recommended-type-checked` or `plugin:@typescript-eslint/strict-type-checked` 26 | - Optionally add `plugin:@typescript-eslint/stylistic-type-checked` 27 | - Install [eslint-plugin-react](https://github.com/jsx-eslint/eslint-plugin-react) and add `plugin:react/recommended` & `plugin:react/jsx-runtime` to the `extends` list 28 | -------------------------------------------------------------------------------- /apps/web/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Vite + React + TS 8 | 9 | 10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /apps/web/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "web", 3 | "private": true, 4 | "version": "0.0.0", 5 | "scripts": { 6 | "dev": "vite", 7 | "build": "tsc && vite build", 8 | "lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0", 9 | "preview": "vite preview" 10 | }, 11 | "dependencies": { 12 | "react": "^18.2.0", 13 | "react-dom": "^18.2.0" 14 | }, 15 | "devDependencies": { 16 | "ui": "workspace:*", 17 | "@types/react": "^18.2.15", 18 | "@types/react-dom": "^18.2.7", 19 | "@typescript-eslint/eslint-plugin": "^6.0.0", 20 | "@typescript-eslint/parser": "^6.0.0", 21 | "@vitejs/plugin-react": "^4.0.3", 22 | "autoprefixer": "^10.4.14", 23 | "eslint": "^8.45.0", 24 | "eslint-plugin-react-hooks": "^4.6.0", 25 | "eslint-plugin-react-refresh": "^0.4.3", 26 | "postcss": "^8.4.27", 27 | "tailwindcss": "^3.3.3", 28 | "typescript": "^5.0.2", 29 | "vite": "^4.4.5" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /apps/web/postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = require("ui/postcss") -------------------------------------------------------------------------------- /apps/web/public/vite.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /apps/web/src/App.css: -------------------------------------------------------------------------------- 1 | #root { 2 | max-width: 1280px; 3 | margin: 0 auto; 4 | padding: 2rem; 5 | text-align: center; 6 | } 7 | 8 | .logo { 9 | height: 6em; 10 | padding: 1.5em; 11 | will-change: filter; 12 | transition: filter 300ms; 13 | } 14 | .logo:hover { 15 | filter: drop-shadow(0 0 2em #646cffaa); 16 | } 17 | .logo.react:hover { 18 | filter: drop-shadow(0 0 2em #61dafbaa); 19 | } 20 | 21 | @keyframes logo-spin { 22 | from { 23 | transform: rotate(0deg); 24 | } 25 | to { 26 | transform: rotate(360deg); 27 | } 28 | } 29 | 30 | @media (prefers-reduced-motion: no-preference) { 31 | a:nth-of-type(2) .logo { 32 | animation: logo-spin infinite 20s linear; 33 | } 34 | } 35 | 36 | .card { 37 | padding: 2em; 38 | } 39 | 40 | .read-the-docs { 41 | color: #888; 42 | } 43 | -------------------------------------------------------------------------------- /apps/web/src/App.tsx: -------------------------------------------------------------------------------- 1 | import { useState } from 'react' 2 | import reactLogo from './assets/react.svg' 3 | import viteLogo from '/vite.svg' 4 | import { Button } from "ui" 5 | 6 | function App() { 7 | const [count, setCount] = useState(0) 8 | 9 | return ( 10 | <> 11 |

Web

12 | 13 | 14 | ) 15 | } 16 | 17 | export default App 18 | -------------------------------------------------------------------------------- /apps/web/src/assets/react.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /apps/web/src/index.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | -------------------------------------------------------------------------------- /apps/web/src/main.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import ReactDOM from 'react-dom/client' 3 | import App from './App.tsx' 4 | import "ui/style" 5 | import "./index.css" 6 | 7 | ReactDOM.createRoot(document.getElementById('root')!).render( 8 | 9 | 10 | , 11 | ) 12 | -------------------------------------------------------------------------------- /apps/web/src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /apps/web/tailwind.config.js: -------------------------------------------------------------------------------- 1 | module.exports = require("ui/tailwind")("web") -------------------------------------------------------------------------------- /apps/web/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../packages/config/base.tsconfig.json", 3 | "compilerOptions": { 4 | "rootDir": "src", 5 | "declarationDir": "dist", 6 | "types": ["vite/client"] 7 | }, 8 | "include": ["src"] 9 | } 10 | -------------------------------------------------------------------------------- /apps/web/tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "composite": true, 4 | "skipLibCheck": true, 5 | "module": "ESNext", 6 | "moduleResolution": "bundler", 7 | "allowSyntheticDefaultImports": true 8 | }, 9 | "include": ["vite.config.ts"] 10 | } 11 | -------------------------------------------------------------------------------- /apps/web/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import react from '@vitejs/plugin-react' 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [react()], 7 | }) 8 | -------------------------------------------------------------------------------- /apps/workshop/.eslintrc.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: [require.resolve('config/eslint/web.js')], 3 | parserOptions: { 4 | tsconfigRootDir: __dirname, 5 | project: './tsconfig.json' 6 | }, 7 | }; -------------------------------------------------------------------------------- /apps/workshop/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | 26 | # build 27 | storybook-static -------------------------------------------------------------------------------- /apps/workshop/.storybook/main.js: -------------------------------------------------------------------------------- 1 | import { join, dirname } from "path"; 2 | 3 | /** 4 | * This function is used to resolve the absolute path of a package. 5 | * It is needed in projects that use Yarn PnP or are set up within a monorepo. 6 | */ 7 | function getAbsolutePath(value) { 8 | return dirname(require.resolve(join(value, "package.json"))); 9 | } 10 | 11 | /** @type { import('@storybook/react-vite').StorybookConfig } */ 12 | const config = { 13 | stories: [ 14 | { 15 | directory: '../../../packages/ui/src/**', 16 | titlePrefix: 'UI', 17 | files: '*.stories.*' 18 | }, 19 | ], 20 | addons: [ 21 | getAbsolutePath("@storybook/addon-links"), 22 | getAbsolutePath("@storybook/addon-essentials"), 23 | getAbsolutePath("@storybook/addon-onboarding"), 24 | getAbsolutePath("@storybook/addon-interactions"), 25 | ], 26 | framework: { 27 | name: "@storybook/react-vite", 28 | options: {}, 29 | }, 30 | docs: { 31 | autodocs: "tag", 32 | }, 33 | }; 34 | export default config; 35 | -------------------------------------------------------------------------------- /apps/workshop/.storybook/preview.js: -------------------------------------------------------------------------------- 1 | import "ui/style" 2 | 3 | /** @type { import('@storybook/react').Preview } */ 4 | const preview = { 5 | parameters: { 6 | actions: { argTypesRegex: "^on[A-Z].*" }, 7 | controls: { 8 | matchers: { 9 | color: /(background|color)$/i, 10 | date: /Date$/, 11 | }, 12 | }, 13 | }, 14 | }; 15 | 16 | export default preview; 17 | -------------------------------------------------------------------------------- /apps/workshop/README.md: -------------------------------------------------------------------------------- 1 | # React + TypeScript + Vite 2 | 3 | This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules. 4 | 5 | Currently, two official plugins are available: 6 | 7 | - [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/README.md) uses [Babel](https://babeljs.io/) for Fast Refresh 8 | - [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh 9 | 10 | ## Expanding the ESLint configuration 11 | 12 | If you are developing a production application, we recommend updating the configuration to enable type aware lint rules: 13 | 14 | - Configure the top-level `parserOptions` property like this: 15 | 16 | ```js 17 | parserOptions: { 18 | ecmaVersion: 'latest', 19 | sourceType: 'module', 20 | project: ['./tsconfig.json', './tsconfig.node.json'], 21 | tsconfigRootDir: __dirname, 22 | }, 23 | ``` 24 | 25 | - Replace `plugin:@typescript-eslint/recommended` to `plugin:@typescript-eslint/recommended-type-checked` or `plugin:@typescript-eslint/strict-type-checked` 26 | - Optionally add `plugin:@typescript-eslint/stylistic-type-checked` 27 | - Install [eslint-plugin-react](https://github.com/jsx-eslint/eslint-plugin-react) and add `plugin:react/recommended` & `plugin:react/jsx-runtime` to the `extends` list 28 | -------------------------------------------------------------------------------- /apps/workshop/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Vite + React + TS 8 | 9 | 10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /apps/workshop/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "workshop", 3 | "private": true, 4 | "version": "0.0.0", 5 | "scripts": { 6 | "dev": "storybook dev -p 6006", 7 | "build": "storybook build", 8 | "lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0", 9 | "preview": "vite preview", 10 | "storybook": "storybook dev -p 6006", 11 | "build-storybook": "storybook build" 12 | }, 13 | "dependencies": { 14 | "react": "^18.2.0", 15 | "react-dom": "^18.2.0", 16 | "ui": "workspace:*" 17 | }, 18 | "devDependencies": { 19 | "@storybook/addon-essentials": "^7.1.1", 20 | "@storybook/addon-interactions": "^7.1.1", 21 | "@storybook/addon-links": "^7.1.1", 22 | "@storybook/addon-onboarding": "^1.0.8", 23 | "@storybook/blocks": "^7.1.1", 24 | "@storybook/cli": "^7.1.1", 25 | "@storybook/react": "^7.1.1", 26 | "@storybook/react-vite": "^7.1.1", 27 | "@storybook/testing-library": "^0.2.0", 28 | "@types/react": "^18.2.15", 29 | "@types/react-dom": "^18.2.7", 30 | "@typescript-eslint/eslint-plugin": "^6.0.0", 31 | "@typescript-eslint/parser": "^6.0.0", 32 | "@vitejs/plugin-react": "^4.0.3", 33 | "autoprefixer": "^10.4.14", 34 | "eslint": "^8.45.0", 35 | "eslint-plugin-react-hooks": "^4.6.0", 36 | "eslint-plugin-react-refresh": "^0.4.3", 37 | "postcss": "^8.4.27", 38 | "prop-types": "^15.8.1", 39 | "storybook": "^7.1.1", 40 | "tailwindcss": "^3.3.3", 41 | "typescript": "^5.0.2", 42 | "vite": "^4.4.5" 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /apps/workshop/postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = require("ui/postcss") 2 | -------------------------------------------------------------------------------- /apps/workshop/public/vite.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /apps/workshop/tailwind.config.js: -------------------------------------------------------------------------------- 1 | module.exports = require("ui/tailwind")("workshop") -------------------------------------------------------------------------------- /apps/workshop/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ESNext", 4 | "useDefineForClassFields": true, 5 | "lib": ["DOM", "DOM.Iterable", "ESNext"], 6 | "allowJs": false, 7 | "skipLibCheck": true, 8 | "esModuleInterop": false, 9 | "allowSyntheticDefaultImports": true, 10 | "strict": true, 11 | "forceConsistentCasingInFileNames": true, 12 | "module": "ESNext", 13 | "moduleResolution": "Node", 14 | "resolveJsonModule": true, 15 | "isolatedModules": true, 16 | "noEmit": true, 17 | "jsx": "react-jsx" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /apps/workshop/tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "composite": true, 4 | "skipLibCheck": true, 5 | "module": "ESNext", 6 | "moduleResolution": "bundler", 7 | "allowSyntheticDefaultImports": true 8 | }, 9 | "include": ["vite.config.ts"] 10 | } 11 | -------------------------------------------------------------------------------- /apps/workshop/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import react from '@vitejs/plugin-react' 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [react()], 7 | }) 8 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "scripts": { 4 | "build": "turbo run build", 5 | "dev": "turbo run dev", 6 | "lint": "turbo run lint", 7 | "format": "prettier --write \"**/*.{ts,tsx,md}\"", 8 | "web": "pnpm --filter web --", 9 | "workshop": "pnpm --filter workshop --" 10 | }, 11 | "devDependencies": { 12 | "@turbo/gen": "^1.9.7", 13 | "eslint": "^7.32.0", 14 | "prettier": "^2.5.1", 15 | "turbo": "latest" 16 | }, 17 | "packageManager": "pnpm@8.6.10", 18 | "name": "design-system-template" 19 | } 20 | -------------------------------------------------------------------------------- /packages/config/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: [require.resolve('./eslint/base.js')] 3 | }; -------------------------------------------------------------------------------- /packages/config/app.tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./base.tsconfig.json", 3 | "compilerOptions": { 4 | "noEmit": true, 5 | "emitDeclarationOnly": false 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /packages/config/base.tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ESNext", 4 | "useDefineForClassFields": true, 5 | "module": "ESNext", 6 | "skipLibCheck": true, 7 | "esModuleInterop": true, 8 | 9 | "moduleResolution": "node", 10 | "allowImportingTsExtensions": true, 11 | "resolveJsonModule": true, 12 | "isolatedModules": true, 13 | "noEmit": true, 14 | "jsx": "react-jsx", 15 | 16 | "strict": true, 17 | "noUnusedLocals": true, 18 | "noUnusedParameters": true, 19 | "noFallthroughCasesInSwitch": true, 20 | "declaration": true 21 | }, 22 | "include": ["src"], 23 | "references": [{ "path": "./tsconfig.node.json" }] 24 | } 25 | -------------------------------------------------------------------------------- /packages/config/eslint/base.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | env: { browser: true, node: true }, 4 | extends: [ 5 | 'eslint:recommended', 6 | 'plugin:react/recommended', 7 | 'plugin:react-hooks/recommended', 8 | 'plugin:@typescript-eslint/recommended', 9 | 'turbo', 10 | 'prettier' 11 | ], 12 | ignorePatterns: ['dist', '.eslintrc.cjs'], 13 | parser: '@typescript-eslint/parser', 14 | parserOptions: { 15 | ecmaFeatures: { 16 | jsx: true 17 | }, 18 | ecmaVersion: 12, 19 | sourceType: 'module' 20 | }, 21 | plugins: ['react-refresh'], 22 | rules: { 23 | 'react-refresh/only-export-components': [ 24 | 'warn', 25 | { allowConstantExport: true }, 26 | ], 27 | }, 28 | } 29 | 30 | 31 | -------------------------------------------------------------------------------- /packages/config/index.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | vite: require('./vite') 3 | }; -------------------------------------------------------------------------------- /packages/config/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "config", 3 | "version": "0.0.0", 4 | "exports": { 5 | "./*": "./*", 6 | "./vite": "./vite" 7 | }, 8 | "scripts": { 9 | "lint": "eslint . --cache" 10 | }, 11 | "devDependencies": { 12 | "@types/node": "^20.4.5", 13 | "@typescript-eslint/eslint-plugin": "^5.59.6", 14 | "@typescript-eslint/parser": "^5.59.6", 15 | "eslint": "^8.41.0", 16 | "eslint-config-next": "13.3.0", 17 | "eslint-config-prettier": "^8.8.0", 18 | "eslint-config-turbo": "^1.9.8", 19 | "eslint-plugin-prettier": "^4.2.1", 20 | "eslint-plugin-react": "^7.32.2", 21 | "eslint-plugin-react-hooks": "^4.6.0", 22 | "eslint-plugin-tailwindcss": "^3.12.0", 23 | "eslint-utils": "^3.0.0", 24 | "regexpp": "^3.2.0", 25 | "vite-plugin-html": "^3.2.0", 26 | "vite-plugin-svgr": "^2.2.1" 27 | }, 28 | "dependencies": { 29 | "@vitejs/plugin-react": "^4.0.3", 30 | "vite": "^4.4.5", 31 | "vite-tsconfig-paths": "^4.2.0" 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /packages/config/vite/index.ts: -------------------------------------------------------------------------------- 1 | import path from 'path'; 2 | import { defineConfig } from 'vite'; 3 | import react from '@vitejs/plugin-react'; 4 | 5 | // https://vitejs.dev/config/ 6 | export default defineConfig({ 7 | plugins: [react()], 8 | resolve: { 9 | alias: { 10 | '@': path.resolve(__dirname, './src'), 11 | }, 12 | }, 13 | }); 14 | -------------------------------------------------------------------------------- /packages/config/vite/relativeAliasResolver.ts: -------------------------------------------------------------------------------- 1 | import fs from 'fs/promises'; 2 | import path from 'path'; 3 | import { Alias } from 'vite'; 4 | 5 | const pkgJsonCache = new Map(); 6 | 7 | const resolver: Alias = { 8 | find: /^(~\/.+)/, 9 | replacement: '$1', 10 | async customResolver(source, importer) { 11 | let root: null | string = null; 12 | 13 | const [_, sourcePath] = source.split('~/'); 14 | 15 | if (importer!.includes('/src/')) { 16 | const [pkg] = importer!.split('/src/'); 17 | 18 | root = `${pkg!}/src`; 19 | } else { 20 | let parent = importer!; 21 | 22 | while (parent !== '/') { 23 | parent = path.dirname(parent); 24 | 25 | let hasPkgJson = pkgJsonCache.get(parent); 26 | 27 | if (hasPkgJson === undefined) 28 | try { 29 | await fs.stat(`${parent}/package.json`); 30 | pkgJsonCache.set(parent, (hasPkgJson = true)); 31 | } catch { 32 | pkgJsonCache.set(parent, (hasPkgJson = false)); 33 | } 34 | 35 | if (hasPkgJson) { 36 | root = parent; 37 | break; 38 | } 39 | } 40 | 41 | if (root === null) 42 | throw new Error( 43 | `Failed to resolve import path ${source} in file ${importer}` 44 | ); 45 | } 46 | 47 | const absolutePath = `${root}/${sourcePath}`; 48 | 49 | const folderItems = await fs.readdir( 50 | path.join(absolutePath, '../') 51 | ); 52 | 53 | const item = folderItems.find((i) => 54 | i.startsWith(sourcePath.split('/').at(-1)!) 55 | )!; 56 | 57 | const fullPath = absolutePath + path.extname(item); 58 | 59 | const stats = await fs.stat(fullPath); 60 | 61 | if (stats.isDirectory()) { 62 | const directoryItems = await fs.readdir( 63 | absolutePath + path.extname(item) 64 | ); 65 | 66 | const indexFile = directoryItems.find((i) => 67 | i.startsWith('index') 68 | ); 69 | 70 | return `${absolutePath}/${indexFile}`; 71 | } else { 72 | return fullPath; 73 | } 74 | }, 75 | }; 76 | 77 | export default resolver; 78 | -------------------------------------------------------------------------------- /packages/tsconfig/base.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/tsconfig", 3 | "display": "Default", 4 | "compilerOptions": { 5 | "composite": false, 6 | "declaration": true, 7 | "declarationMap": true, 8 | "esModuleInterop": true, 9 | "forceConsistentCasingInFileNames": true, 10 | "inlineSources": false, 11 | "isolatedModules": true, 12 | "moduleResolution": "node", 13 | "noUnusedLocals": false, 14 | "noUnusedParameters": false, 15 | "preserveWatchOutput": true, 16 | "skipLibCheck": true, 17 | "strict": true 18 | }, 19 | "exclude": ["node_modules"] 20 | } 21 | -------------------------------------------------------------------------------- /packages/tsconfig/nextjs.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/tsconfig", 3 | "display": "Next.js", 4 | "extends": "./base.json", 5 | "compilerOptions": { 6 | "plugins": [{ "name": "next" }], 7 | "allowJs": true, 8 | "declaration": false, 9 | "declarationMap": false, 10 | "incremental": true, 11 | "jsx": "preserve", 12 | "lib": ["dom", "dom.iterable", "esnext"], 13 | "module": "esnext", 14 | "noEmit": true, 15 | "resolveJsonModule": true, 16 | "strict": false, 17 | "target": "es5" 18 | }, 19 | "include": ["src", "next-env.d.ts"], 20 | "exclude": ["node_modules"] 21 | } 22 | -------------------------------------------------------------------------------- /packages/tsconfig/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tsconfig", 3 | "version": "0.0.0", 4 | "private": true, 5 | "license": "MIT", 6 | "publishConfig": { 7 | "access": "public" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /packages/tsconfig/react-library.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/tsconfig", 3 | "display": "React Library", 4 | "extends": "./base.json", 5 | "compilerOptions": { 6 | "jsx": "react-jsx", 7 | "lib": ["ES2015", "DOM"], 8 | "module": "ESNext", 9 | "target": "es6" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /packages/ui/components.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://ui.shadcn.com/schema.json", 3 | "style": "new-york", 4 | "rsc": true, 5 | "tsx": true, 6 | "tailwind": { 7 | "config": "tailwind.config.js", 8 | "css": "style/styles.css", 9 | "baseColor": "slate", 10 | "cssVariables": true 11 | }, 12 | "aliases": { 13 | "components": "@/components", 14 | "utils": "@/lib/utils" 15 | } 16 | } -------------------------------------------------------------------------------- /packages/ui/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ui", 3 | "version": "0.0.0", 4 | "main": "./src/index.tsx", 5 | "types": "./src/index.tsx", 6 | "license": "MIT", 7 | "exports": { 8 | ".": "./src/index.tsx", 9 | "./tailwind": "./tailwind.config.js", 10 | "./postcss": "./postcss.config.js", 11 | "./style": "./style/styles.css" 12 | }, 13 | "scripts": { 14 | "lint": "eslint src --cache", 15 | "typecheck": "tsc -b", 16 | "build": "tsc" 17 | }, 18 | "devDependencies": { 19 | "@types/node": "^20.4.5", 20 | "@types/react": "^18.2.0", 21 | "@types/react-dom": "^18.2.0", 22 | "autoprefixer": "^10.4.14", 23 | "eslint": "^7.32.0", 24 | "postcss": "^8.4.27", 25 | "react": "^17.0.2", 26 | "tailwindcss": "^3.3.3", 27 | "tsconfig": "workspace:*", 28 | "typescript": "^4.5.2" 29 | }, 30 | "dependencies": { 31 | "@radix-ui/react-icons": "^1.3.0", 32 | "@radix-ui/react-slot": "^1.0.2", 33 | "@storybook/react": "^7.1.1", 34 | "class-variance-authority": "^0.7.0", 35 | "clsx": "^2.0.0", 36 | "tailwind-merge": "^1.14.0", 37 | "tailwindcss-animate": "^1.0.6" 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /packages/ui/postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = require("./style/postcss.config") -------------------------------------------------------------------------------- /packages/ui/src/Button.stories.tsx: -------------------------------------------------------------------------------- 1 | import { Button } from "./components/ui/button"; 2 | import { Meta, StoryFn } from "@storybook/react"; 3 | 4 | const meta: Meta = { 5 | title: "Button", 6 | component: Button, 7 | argTypes: {}, 8 | parameters: { 9 | backgrounds: { 10 | default: 'dark' 11 | } 12 | }, 13 | args: { 14 | children: 'Button' 15 | } 16 | } 17 | 18 | export default meta; 19 | 20 | const Template: StoryFn = (args: any) =>