├── .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) => ;
21 |
22 | export const Default: StoryFn = Template.bind({});
23 | Default.args = {
24 |
25 | };
26 |
27 | export const Secondary: StoryFn = Template.bind({});
28 | Secondary.args = {
29 | variant: "secondary"
30 | };
--------------------------------------------------------------------------------
/packages/ui/src/components/ui/button.tsx:
--------------------------------------------------------------------------------
1 | import * as React from "react"
2 | import { Slot } from "@radix-ui/react-slot"
3 | import { cva, type VariantProps } from "class-variance-authority"
4 |
5 | import { cn } from "../../lib/utils"
6 |
7 | const buttonVariants = cva(
8 | "inline-flex items-center justify-center rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50",
9 | {
10 | variants: {
11 | variant: {
12 | default:
13 | "bg-primary text-primary-foreground shadow hover:bg-primary/90",
14 | destructive:
15 | "bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90",
16 | outline:
17 | "border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground",
18 | secondary:
19 | "bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80",
20 | ghost: "hover:bg-accent hover:text-accent-foreground",
21 | link: "text-primary underline-offset-4 hover:underline",
22 | },
23 | size: {
24 | default: "h-9 px-4 py-2",
25 | sm: "h-8 rounded-md px-3 text-xs",
26 | lg: "h-10 rounded-md px-8",
27 | icon: "h-9 w-9",
28 | },
29 | },
30 | defaultVariants: {
31 | variant: "default",
32 | size: "default",
33 | },
34 | }
35 | )
36 |
37 | export interface ButtonProps
38 | extends React.ButtonHTMLAttributes,
39 | VariantProps {
40 | asChild?: boolean
41 | }
42 |
43 | const Button = React.forwardRef(
44 | ({ className, variant, size, asChild = false, ...props }, ref) => {
45 | const Comp = asChild ? Slot : "button"
46 | return (
47 |
52 | )
53 | }
54 | )
55 | Button.displayName = "Button"
56 |
57 | export { Button, buttonVariants }
58 |
--------------------------------------------------------------------------------
/packages/ui/src/index.tsx:
--------------------------------------------------------------------------------
1 | import * as React from "react";
2 |
3 | import "../style/styles.css"
4 |
5 | // component exports
6 | export * from "./components/ui/button";
7 |
--------------------------------------------------------------------------------
/packages/ui/src/lib/utils.ts:
--------------------------------------------------------------------------------
1 | import { type ClassValue, clsx } from "clsx"
2 | import { twMerge } from "tailwind-merge"
3 |
4 | export function cn(...inputs: ClassValue[]) {
5 | return twMerge(clsx(inputs))
6 | }
7 |
--------------------------------------------------------------------------------
/packages/ui/style/index.ts:
--------------------------------------------------------------------------------
1 | import './styles.css';
2 |
--------------------------------------------------------------------------------
/packages/ui/style/postcss.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | plugins: {
3 | tailwindcss: {},
4 | autoprefixer: {},
5 | }
6 | }
--------------------------------------------------------------------------------
/packages/ui/style/styles.css:
--------------------------------------------------------------------------------
1 | @tailwind base;
2 | @tailwind components;
3 | @tailwind utilities;
4 |
5 | @layer base {
6 | :root {
7 | --background: 0 0% 100%;
8 | --foreground: 222.2 84% 4.9%;
9 |
10 | --muted: 210 40% 96.1%;
11 | --muted-foreground: 215.4 16.3% 46.9%;
12 |
13 | --popover: 0 0% 100%;
14 | --popover-foreground: 222.2 84% 4.9%;
15 |
16 | --card: 0 0% 100%;
17 | --card-foreground: 222.2 84% 4.9%;
18 |
19 | --border: 214.3 31.8% 91.4%;
20 | --input: 214.3 31.8% 91.4%;
21 |
22 | --primary: 222.2 47.4% 11.2%;
23 | --primary-foreground: 210 40% 98%;
24 |
25 | --secondary: 210 40% 96.1%;
26 | --secondary-foreground: 222.2 47.4% 11.2%;
27 |
28 | --accent: 210 40% 96.1%;
29 | --accent-foreground: 222.2 47.4% 11.2%;
30 |
31 | --destructive: 0 84.2% 60.2%;
32 | --destructive-foreground: 210 40% 98%;
33 |
34 | --ring: 215 20.2% 65.1%;
35 |
36 | --radius: 0.5rem;
37 | }
38 |
39 | .dark {
40 | --background: 222.2 84% 4.9%;
41 | --foreground: 210 40% 98%;
42 |
43 | --muted: 217.2 32.6% 17.5%;
44 | --muted-foreground: 215 20.2% 65.1%;
45 |
46 | --popover: 222.2 84% 4.9%;
47 | --popover-foreground: 210 40% 98%;
48 |
49 | --card: 222.2 84% 4.9%;
50 | --card-foreground: 210 40% 98%;
51 |
52 | --border: 217.2 32.6% 17.5%;
53 | --input: 217.2 32.6% 17.5%;
54 |
55 | --primary: 210 40% 98%;
56 | --primary-foreground: 222.2 47.4% 11.2%;
57 |
58 | --secondary: 217.2 32.6% 17.5%;
59 | --secondary-foreground: 210 40% 98%;
60 |
61 | --accent: 217.2 32.6% 17.5%;
62 | --accent-foreground: 210 40% 98%;
63 |
64 | --destructive: 0 62.8% 30.6%;
65 | --destructive-foreground: 0 85.7% 97.3%;
66 |
67 | --ring: 217.2 32.6% 17.5%;
68 | }
69 | }
70 |
71 | /* @layer base {
72 | * {
73 | @apply border-border;
74 | }
75 | body {
76 | @apply bg-background text-foreground;
77 | }
78 | } */
79 |
--------------------------------------------------------------------------------
/packages/ui/style/tailwind.config.js:
--------------------------------------------------------------------------------
1 | module.exports = function (app, options) {
2 | let config = {
3 | content: [
4 | `../../apps/${app}/src/index.html`,
5 | `../../apps/${app}/src/**/*.{ts,tsx,html,stories.tsx}`,
6 | '../../packages/*/src/**/*.{ts,tsx,html,stories.tsx}',
7 | '../../interface/**/*.{ts,tsx,html,stories.tsx}'
8 | ],
9 | darkMode: ['class'],
10 | theme: {
11 | screens: {
12 | xs: '475px',
13 | sm: '650px',
14 | md: '868px',
15 | lg: '1024px',
16 | xl: '1280px',
17 | },
18 | fontSize: {
19 | 'tiny': '.65rem',
20 | 'xs': '.75rem',
21 | 'sm': '.80rem',
22 | 'base': '1rem',
23 | 'lg': '1.125rem',
24 | 'xl': '1.25rem',
25 | '2xl': '1.5rem',
26 | '3xl': '1.875rem',
27 | '4xl': '2.25rem',
28 | '5xl': '3rem',
29 | '6xl': '4rem',
30 | '7xl': '5rem'
31 | },
32 | container: {
33 | center: true,
34 | padding: "2rem",
35 | screens: {
36 | "2xl": "1400px",
37 | },
38 | },
39 | extend: {
40 | colors: {
41 | border: "hsl(var(--border))",
42 | input: "hsl(var(--input))",
43 | ring: "hsl(var(--ring))",
44 | background: "hsl(var(--background))",
45 | foreground: "hsl(var(--foreground))",
46 | primary: {
47 | DEFAULT: "hsl(var(--primary))",
48 | foreground: "hsl(var(--primary-foreground))",
49 | },
50 | secondary: {
51 | DEFAULT: "hsl(var(--secondary))",
52 | foreground: "hsl(var(--secondary-foreground))",
53 | },
54 | destructive: {
55 | DEFAULT: "hsl(var(--destructive))",
56 | foreground: "hsl(var(--destructive-foreground))",
57 | },
58 | muted: {
59 | DEFAULT: "hsl(var(--muted))",
60 | foreground: "hsl(var(--muted-foreground))",
61 | },
62 | accent: {
63 | DEFAULT: "hsl(var(--accent))",
64 | foreground: "hsl(var(--accent-foreground))",
65 | },
66 | popover: {
67 | DEFAULT: "hsl(var(--popover))",
68 | foreground: "hsl(var(--popover-foreground))",
69 | },
70 | card: {
71 | DEFAULT: "hsl(var(--card))",
72 | foreground: "hsl(var(--card-foreground))",
73 | },
74 | },
75 | borderRadius: {
76 | lg: "var(--radius)",
77 | md: "calc(var(--radius) - 2px)",
78 | sm: "calc(var(--radius) - 4px)",
79 | },
80 | keyframes: {
81 | "accordion-down": {
82 | from: { height: 0 },
83 | to: { height: "var(--radix-accordion-content-height)" },
84 | },
85 | "accordion-up": {
86 | from: { height: "var(--radix-accordion-content-height)" },
87 | to: { height: 0 },
88 | },
89 | },
90 | animation: {
91 | "accordion-down": "accordion-down 0.2s ease-out",
92 | "accordion-up": "accordion-up 0.2s ease-out",
93 | },
94 | },
95 | },
96 | plugins: [require("tailwindcss-animate")]
97 | };
98 | return config;
99 | };
--------------------------------------------------------------------------------
/packages/ui/tailwind.config.js:
--------------------------------------------------------------------------------
1 | module.exports = require("./style/tailwind.config")
--------------------------------------------------------------------------------
/packages/ui/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../packages/config/base.tsconfig.json",
3 | "include": ["src"],
4 | "exclude": ["dist", "build", "node_modules"],
5 | "compilerOptions": {
6 | "rootDir": "src",
7 | "baseUrl": ".",
8 | "paths": {
9 | "@/*": ["./src/*"]
10 | }
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/pnpm-workspace.yaml:
--------------------------------------------------------------------------------
1 | packages:
2 | - "apps/*"
3 | - "packages/*"
4 |
--------------------------------------------------------------------------------
/turbo.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://turbo.build/schema.json",
3 | "globalDependencies": ["**/.env.*local"],
4 | "pipeline": {
5 | "build": {
6 | "dependsOn": ["^build"],
7 | "outputs": [".next/**", "!.next/cache/**"]
8 | },
9 | "lint": {},
10 | "dev": {
11 | "cache": false,
12 | "persistent": true
13 | }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------