diff --git a/.github/workflows/deploy-nestjs.yml b/.github/workflows/deploy-nestjs.yml new file mode 100644 index 0000000..510a6c7 --- /dev/null +++ b/.github/workflows/deploy-nestjs.yml @@ -0,0 +1,38 @@ +name: 🌥️ CI + +on: + workflow_dispatch: + +jobs: + deploy-nestjs: + name: 🐯 Deploy NestJS App + runs-on: ubuntu-latest + + steps: + - name: 🛎️ Checkout repo + uses: actions/checkout@v4 + + - name: Setup pnpm + uses: pnpm/action-setup@v2.4.0 + with: + version: 8 + + - name: Set up Node.js + uses: actions/setup-node@v3 + with: + node-version: 20 + cache: pnpm + + - name: 📥 Install Dependencies + run: pnpm install + + - name: 🏗️ Build + run: pnpm build + + - name: 🎈 Setup Fly + uses: superfly/flyctl-actions/setup-flyctl@v1.4 + + - name: 🚀 Deploy + run: flyctl deploy --config ./apps/nestjs/fly.toml --dockerfile ./apps/nestjs/Dockerfile --remote-only --build-arg COMMIT_SHA=${{ github.sha }} + env: + FLY_API_TOKEN: ${{ secrets.FLY_API_TOKEN }} diff --git a/.github/workflows/deploy-remix.yml b/.github/workflows/deploy-remix.yml new file mode 100644 index 0000000..a9b47dc --- /dev/null +++ b/.github/workflows/deploy-remix.yml @@ -0,0 +1,38 @@ +name: 🌥️ CI + +on: + workflow_dispatch: + +jobs: + deploy-remix: + name: 💿 Deploy Remix App + runs-on: ubuntu-latest + + steps: + - name: 🛎️ Checkout repo + uses: actions/checkout@v4 + + - name: Setup pnpm + uses: pnpm/action-setup@v2.4.0 + with: + version: 8 + + - name: Set up Node.js + uses: actions/setup-node@v3 + with: + node-version: 20 + cache: pnpm + + - name: 📥 Install Dependencies + run: pnpm install + + - name: 🏗️ Build + run: pnpm build + + - name: 🎈 Setup Fly + uses: superfly/flyctl-actions/setup-flyctl@v1.4 + + - name: 🚀 Deploy + run: flyctl deploy --config ./apps/remix/fly.toml --dockerfile ./apps/remix/Dockerfile --remote-only --build-arg COMMIT_SHA=${{ github.sha }} + env: + FLY_API_TOKEN: ${{ secrets.FLY_API_TOKEN }} diff --git a/README.md b/README.md index c6ae2d3..dc12fdf 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Pnpm Monorepo +# Pnpm + Turbo Monorepo ## TODO @@ -20,20 +20,21 @@ - [x] set unified path aliases for all apps and shared libs (done for `apps/`, because `libs/` probably don't need them anyway) - [x] add unused imports plugin to eslint - [x] research if it's worth using `turbo` - probably yes, to make it easier to run tasks that depend on each other -- [ ] use turbo repo and ensure the following works - - [x] lint, test, build, develop - - [ ] gh actions - - [ ] deployment +- [x] use turbo repo and ensure the following works: lint, test, build, develop, gh actions +- [ ] use turbo prune options to build docker images +- [x] add some examples for ui lib (use tailwindcss + shadcn/ui) - [ ] create diagram - [ ] setup renovate -## Deployments +## Links -| App | URL | -| ---------------- | --------------------------------------------------------- | -| NestJS | https://pnpm-monorepo-nestjs.fly.dev/ | -| Remix | https://pnpm-monorepo-remix.fly.dev/ | -| Docs (Storybook) | https://6562c63f0bbf6184dd3b3f1e-aulbjawzef.chromatic.com | +| App | URL | +| ---------------- | --------------------------------------------------------------- | +| NestJS | https://pnpm-monorepo-nestjs.fly.dev/ | +| Remix | https://pnpm-monorepo-remix.fly.dev/ | +| Docs (Storybook) | https://6562c63f0bbf6184dd3b3f1e-aulbjawzef.chromatic.com | +| MongoDB Project | https://cloud.mongodb.com/v2/65616305afb5120f9b3a3536#/overview | +| Fly.io Dashboard | https://fly.io/apps/ | ## Getting started @@ -50,6 +51,8 @@ pnpm install ### Database +If you want to use NestJS app, run MongoDB first. + ```sh docker compose up mongo ``` @@ -62,19 +65,30 @@ pnpm develop:nestjs ### Run Remix app +Runs Remix app and all its build dependencies, e.g. `ui` lib. Whenever you make changes to `ui` lib, it will be automatically rebuilt and Remix app will be reloaded. + ```sh pnpm develop:remix ``` +### Run Docs (Storybook) + +```sh +pnpm develop:docs +``` + ## References - https://pnpm.io/next/filtering - https://github.com/remix-run/indie-stack/tree/main - remix app example - https://github.com/sveltejs/kit/tree/master - svelte kit - pnpm monorepo - https://github.com/nestjs/nest/tree/master/sample - nestjs samples +- https://docs.nestjs.com/cli/overview - https://fly.io/docs/reference/configuration/#the-processes-section - fly.io config - https://github.com/vercel/turbo/tree/main/examples - turbo repo examples - https://github.com/storybookjs/storybook - https://storybook.js.org/tutorials/design-systems-for-developers/react/en/architecture/ - https://turbo.build/repo/docs/getting-started/existing-monorepo - https://github.com/vercel/style-guide/tree/canary +- https://ui.shadcn.com/docs +- https://tailwindcss.com/docs/installation diff --git a/apps/docs/stories/button.stories.tsx b/apps/docs/stories/button.stories.tsx index e710fd3..5646515 100644 --- a/apps/docs/stories/button.stories.tsx +++ b/apps/docs/stories/button.stories.tsx @@ -15,26 +15,40 @@ export default meta type Story = StoryObj -/* - *👇 Render functions are a framework specific feature to allow you control on how the component renders. - * See https://storybook.js.org/docs/react/api/csf - * to learn how to use render functions. - */ export const Primary: Story = { - render: props => ( - - ), - name: 'Button', + render: props => , args: { - children: 'Hello', type: 'button', }, } + +export const Secondary: Story = { + render: props => , + args: { + type: 'button', + variant: 'secondary', + }, +} + +export const Destructive: Story = { + render: props => , + args: { + type: 'button', + variant: 'destructive', + }, +} +export const Outline: Story = { + render: props => , + args: { + type: 'button', + variant: 'outline', + }, +} + +export const Ghost: Story = { + render: props => , + args: { + type: 'button', + variant: 'ghost', + }, +} diff --git a/apps/docs/stories/card.stories.tsx b/apps/docs/stories/card.stories.tsx index 956dfad..638a1bd 100644 --- a/apps/docs/stories/card.stories.tsx +++ b/apps/docs/stories/card.stories.tsx @@ -1,8 +1,8 @@ import { Card } from '@repo/ui' import type { Meta, StoryObj } from '@storybook/react' -const meta: Meta = { - component: Card, +const meta: Meta = { + component: Card.Root, } export default meta @@ -10,11 +10,19 @@ export default meta type Story = StoryObj export const Primary: Story = { - render: props => Hello, - name: 'Card', - args: { - children: 'Some card content!', - title: 'Card Title', - href: '#some-link', - }, + name: 'card', + render: () => ( + + + Card Title + Card Description + + +

Card Content

+
+ +

Card Footer

+
+
+ ), } diff --git a/apps/remix/app/root.tsx b/apps/remix/app/root.tsx index 040729f..b4b9b73 100644 --- a/apps/remix/app/root.tsx +++ b/apps/remix/app/root.tsx @@ -12,6 +12,8 @@ import uiStyles from '@repo/ui/styles.css' import tailwindStyles from '~/styles/tailwind.css' +console.log(uiStyles) + export const links: LinksFunction = () => [ { rel: 'stylesheet', href: tailwindStyles }, { rel: 'stylesheet', href: uiStyles }, @@ -27,7 +29,7 @@ export default function App() { - + diff --git a/apps/remix/app/routes/_index.tsx b/apps/remix/app/routes/_index.tsx index 5d67271..66280c4 100644 --- a/apps/remix/app/routes/_index.tsx +++ b/apps/remix/app/routes/_index.tsx @@ -1,6 +1,6 @@ import { json, type MetaFunction } from '@remix-run/node' import { useLoaderData } from '@remix-run/react' -import { Button, Card } from '@repo/ui' +import { Table, Button, Card, H1, H2, Paragraph } from '@repo/ui' import { catsApi } from '~/api/cats.api' @@ -25,17 +25,56 @@ export default function Index() { const { cats } = useLoaderData() return ( -
-

PNPM MONOREPO

-
-

Cats fetched from NestJS

-
{JSON.stringify(cats, null, 2)}
+
+

PNPM + TURBO MONOREPO

+ + This is a Remix app that uses UI components from `@repo/ui` and fetches + some data from NestJS API. + - - Imported from internal @repo/ui package - + + + Card Title + Card Description + + + This is an example Card component bootstrapped using `shadcn/ui` + package. + + + - +
+ + + + +
+ +

Cats fetched from NestJS

+ + Below should be a list of cats fetched from NestJS API. If nothing is + showing app, check if NestJS app is running. + + + + + + Name + Breed + Age + + + + {cats.map(cat => ( + + {cat.name} + {cat.breed} + {cat.age} + + ))} + +
) } diff --git a/apps/remix/app/styles/tailwind.css b/apps/remix/app/styles/tailwind.css index 4745595..b5c61c9 100644 --- a/apps/remix/app/styles/tailwind.css +++ b/apps/remix/app/styles/tailwind.css @@ -1,46 +1,3 @@ @tailwind base; @tailwind components; @tailwind utilities; - -/* Based on Kent's repo: https://github.com/kentcdodds/kentcdodds.com/tree/main */ -@layer utilities { - .bg-primary { - @apply bg-white dark:bg-gray-900; - } - - .bg-secondary { - @apply bg-gray-100 dark:bg-gray-800; - } - - .bg-alt { - @apply bg-gray-200 dark:bg-gray-700; - } - - .bg-inverse { - @apply bg-black dark:bg-white; - } - - .border-primary { - @apply border-gray-900 dark:border-white; - } - - .border-secondary { - @apply border-gray-200 dark:border-gray-600; - } - - .text-primary { - @apply text-black dark:text-white; - } - - .text-secondary { - @apply text-gray-500 dark:text-slate-500; - } - - .text-inverse { - @apply text-white dark:text-black; - } - - .text-prose { - @apply prose dark:prose-invert; - } -} diff --git a/libs/tailwind-config/package.json b/libs/tailwind-config/package.json index 2cce6e5..1051490 100644 --- a/libs/tailwind-config/package.json +++ b/libs/tailwind-config/package.json @@ -5,6 +5,7 @@ "devDependencies": { "@tailwindcss/forms": "^0.5.7", "@tailwindcss/typography": "^0.5.10", - "tailwindcss": "^3.3.5" + "tailwindcss": "^3.3.5", + "tailwindcss-animate": "^1.0.7" } } diff --git a/libs/tailwind-config/tailwind.config.ts b/libs/tailwind-config/tailwind.config.ts index 7521613..ed8fba0 100644 --- a/libs/tailwind-config/tailwind.config.ts +++ b/libs/tailwind-config/tailwind.config.ts @@ -1,21 +1,75 @@ import formsPlugin from '@tailwindcss/forms' import typographyPlugin from '@tailwindcss/typography' +import tailwindAnimatePlugin from 'tailwindcss-animate' import type { Config } from 'tailwindcss' -import tailwindColors from 'tailwindcss/colors' export default { content: ['./src/**/*.{js,ts,jsx,tsx,mdx}'], darkMode: 'class', theme: { + container: { + center: true, + padding: '2rem', + screens: { + '2xl': '1400px', + }, + }, extend: { colors: { - gray: tailwindColors.zinc, + border: 'hsl(var(--border))', + input: 'hsl(var(--input))', + ring: 'hsl(var(--ring))', + background: 'hsl(var(--background))', + foreground: 'hsl(var(--foreground))', + primary: { + DEFAULT: 'hsl(var(--primary))', + foreground: 'hsl(var(--primary-foreground))', + }, + secondary: { + DEFAULT: 'hsl(var(--secondary))', + foreground: 'hsl(var(--secondary-foreground))', + }, + destructive: { + DEFAULT: 'hsl(var(--destructive))', + foreground: 'hsl(var(--destructive-foreground))', + }, + muted: { + DEFAULT: 'hsl(var(--muted))', + foreground: 'hsl(var(--muted-foreground))', + }, + accent: { + DEFAULT: 'hsl(var(--accent))', + foreground: 'hsl(var(--accent-foreground))', + }, + popover: { + DEFAULT: 'hsl(var(--popover))', + foreground: 'hsl(var(--popover-foreground))', + }, + card: { + DEFAULT: 'hsl(var(--card))', + foreground: 'hsl(var(--card-foreground))', + }, + }, + borderRadius: { + lg: 'var(--radius)', + md: 'calc(var(--radius) - 2px)', + sm: 'calc(var(--radius) - 4px)', + }, + keyframes: { + 'accordion-down': { + from: { height: '0' }, + to: { height: 'var(--radix-accordion-content-height)' }, + }, + 'accordion-up': { + from: { height: 'var(--radix-accordion-content-height)' }, + to: { height: '0' }, + }, }, - backgroundImage: { - 'glow-conic': - 'conic-gradient(from 180deg at 50% 50%, #2a8af6 0deg, #a853ba 180deg, #e92a67 360deg)', + animation: { + 'accordion-down': 'accordion-down 0.2s ease-out', + 'accordion-up': 'accordion-up 0.2s ease-out', }, }, }, - plugins: [typographyPlugin, formsPlugin], + plugins: [formsPlugin, tailwindAnimatePlugin, typographyPlugin], } satisfies Config diff --git a/libs/ui/components.json b/libs/ui/components.json new file mode 100644 index 0000000..279cec5 --- /dev/null +++ b/libs/ui/components.json @@ -0,0 +1,16 @@ +{ + "$schema": "https://ui.shadcn.com/schema.json", + "style": "default", + "rsc": false, + "tsx": true, + "tailwind": { + "config": "tailwind.config.ts", + "css": "./src/styles.css", + "baseColor": "zinc", + "cssVariables": true + }, + "aliases": { + "components": "~/components", + "utils": "~/utils" + } +} diff --git a/libs/ui/package.json b/libs/ui/package.json index b8cdf2e..c4bdd7a 100644 --- a/libs/ui/package.json +++ b/libs/ui/package.json @@ -10,11 +10,6 @@ "require": "./dist/index.js", "types": "./dist/index.d.ts" }, - "./components/card": { - "import": "./dist/components/card.mjs", - "require": "./dist/components/card.js", - "types": "./dist/components/card.d.ts" - }, "./styles.css": "./dist/index.css" }, "scripts": { @@ -24,6 +19,13 @@ "develop": "tsup --watch", "typecheck": "tsc --noEmit" }, + "dependencies": { + "@radix-ui/react-slot": "^1.0.2", + "class-variance-authority": "^0.7.0", + "clsx": "^2.0.0", + "lucide-react": "^0.293.0", + "tailwind-merge": "^2.0.0" + }, "devDependencies": { "@repo/eslint-config": "workspace:*", "@repo/tailwind-config": "workspace:*", diff --git a/libs/ui/src/components/button.tsx b/libs/ui/src/components/button.tsx index 3ee5e02..b81c2b4 100644 --- a/libs/ui/src/components/button.tsx +++ b/libs/ui/src/components/button.tsx @@ -1,18 +1,56 @@ -export interface ButtonProps - extends React.ButtonHTMLAttributes { - children: React.ReactNode -} +import { Slot } from '@radix-ui/react-slot' +import { cva, type VariantProps } from 'class-variance-authority' +import * as React from 'react' + +import { cn } from '~/utils' -export const Button = ({ children, ...props }: ButtonProps) => { - return ( - - ) +const buttonVariants = cva( + 'inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50', + { + variants: { + variant: { + default: 'bg-primary text-primary-foreground hover:bg-primary/90', + destructive: + 'bg-destructive text-destructive-foreground hover:bg-destructive/90', + outline: + 'border border-input bg-background hover:bg-accent hover:text-accent-foreground', + secondary: + 'bg-secondary text-secondary-foreground hover:bg-secondary/80', + ghost: 'hover:bg-accent hover:text-accent-foreground', + link: 'text-primary underline-offset-4 hover:underline', + }, + size: { + default: 'h-10 px-4 py-2', + sm: 'h-9 rounded-md px-3', + lg: 'h-11 rounded-md px-8', + icon: 'h-10 w-10', + }, + }, + defaultVariants: { + variant: 'default', + size: 'default', + }, + }, +) + +export interface ButtonProps + extends React.ButtonHTMLAttributes, + VariantProps { + asChild?: boolean } +const Button = React.forwardRef( + ({ className, variant, size, asChild = false, ...props }, ref) => { + const Comp = asChild ? Slot : 'button' + return ( + + ) + }, +) Button.displayName = 'Button' + +export { Button, buttonVariants } diff --git a/libs/ui/src/components/card.tsx b/libs/ui/src/components/card.tsx index 279582e..fe34a91 100644 --- a/libs/ui/src/components/card.tsx +++ b/libs/ui/src/components/card.tsx @@ -1,28 +1,79 @@ import * as React from 'react' -export function Card({ - title, - children, - href, -}: { - title: string - children: React.ReactNode - href: string -}): JSX.Element { - return ( - -

- {title}{' '} - - -> - -

-

{children}

-
- ) -} +import { cn } from '~/utils' + +const Root = React.forwardRef< + HTMLDivElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +
+)) +Root.displayName = 'Root' + +const Header = React.forwardRef< + HTMLDivElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +
+)) +Header.displayName = 'Header' + +const Title = React.forwardRef< + HTMLParagraphElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +

+)) +Title.displayName = 'Title' + +const Description = React.forwardRef< + HTMLParagraphElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +

+)) +Description.displayName = 'Description' + +const Content = React.forwardRef< + HTMLDivElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +

+)) +Content.displayName = 'Content' + +const Footer = React.forwardRef< + HTMLDivElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +
+)) +Footer.displayName = 'Footer' + +export const Card = { Root, Header, Footer, Title, Description, Content } diff --git a/libs/ui/src/components/index.ts b/libs/ui/src/components/index.ts deleted file mode 100644 index e028193..0000000 --- a/libs/ui/src/components/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from './button' -export * from './card' diff --git a/libs/ui/src/components/table.tsx b/libs/ui/src/components/table.tsx new file mode 100644 index 0000000..0d4a333 --- /dev/null +++ b/libs/ui/src/components/table.tsx @@ -0,0 +1,117 @@ +import * as React from 'react' + +import { cn } from '~/utils' + +const Root = React.forwardRef< + HTMLTableElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +
+ + +)) +Root.displayName = 'Root' + +const Header = React.forwardRef< + HTMLTableSectionElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( + +)) +Header.displayName = 'Header' + +const Body = React.forwardRef< + HTMLTableSectionElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( + +)) +Body.displayName = 'Body' + +const Footer = React.forwardRef< + HTMLTableSectionElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( + tr]:last:border-b-0', + className, + )} + {...props} + /> +)) +Footer.displayName = 'Footer' + +const Row = React.forwardRef< + HTMLTableRowElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( + +)) +Row.displayName = 'Row' + +const Head = React.forwardRef< + HTMLTableCellElement, + React.ThHTMLAttributes +>(({ className, ...props }, ref) => ( +
+)) +Head.displayName = 'Head' + +const Cell = React.forwardRef< + HTMLTableCellElement, + React.TdHTMLAttributes +>(({ className, ...props }, ref) => ( + +)) +Cell.displayName = 'Cell' + +const Caption = React.forwardRef< + HTMLTableCaptionElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +
+)) +Caption.displayName = 'Caption' + +export const Table = { + Root, + Header, + Body, + Footer, + Row, + Head, + Cell, + Caption, +} diff --git a/libs/ui/src/components/typography.tsx b/libs/ui/src/components/typography.tsx new file mode 100644 index 0000000..9edaf5a --- /dev/null +++ b/libs/ui/src/components/typography.tsx @@ -0,0 +1,46 @@ +export function H1({ children }: { children: React.ReactNode }) { + return ( +

+ {children} +

+ ) +} + +export function H2({ children }: { children: React.ReactNode }) { + return ( +

+ {children} +

+ ) +} + +export function H3({ children }: { children: React.ReactNode }) { + return ( +

+ {children} +

+ ) +} + +export function H4({ children }: { children: React.ReactNode }) { + return ( +

+ {children} +

+ ) +} + +export function Paragraph({ children }: { children: React.ReactNode }) { + return ( +

+ {children} + his ways and repealed the joke tax. +

+ ) +} + +export function Blockquote({ children }: { children: React.ReactNode }) { + return ( +
{children}
+ ) +} diff --git a/libs/ui/src/index.tsx b/libs/ui/src/index.tsx index 1349b14..d3e89d6 100644 --- a/libs/ui/src/index.tsx +++ b/libs/ui/src/index.tsx @@ -4,3 +4,8 @@ import './styles.css' // components export * from './components/card' export * from './components/button' +export * from './components/table' +export * from './components/typography' + +// utils +export * from './utils' diff --git a/libs/ui/src/styles.css b/libs/ui/src/styles.css index 4745595..1beb227 100644 --- a/libs/ui/src/styles.css +++ b/libs/ui/src/styles.css @@ -2,45 +2,76 @@ @tailwind components; @tailwind utilities; -/* Based on Kent's repo: https://github.com/kentcdodds/kentcdodds.com/tree/main */ -@layer utilities { - .bg-primary { - @apply bg-white dark:bg-gray-900; - } +@layer base { + :root { + --background: 0 0% 100%; + --foreground: 240 10% 3.9%; - .bg-secondary { - @apply bg-gray-100 dark:bg-gray-800; - } + --card: 0 0% 100%; + --card-foreground: 240 10% 3.9%; - .bg-alt { - @apply bg-gray-200 dark:bg-gray-700; - } + --popover: 0 0% 100%; + --popover-foreground: 240 10% 3.9%; - .bg-inverse { - @apply bg-black dark:bg-white; - } + --primary: 240 5.9% 10%; + --primary-foreground: 0 0% 98%; - .border-primary { - @apply border-gray-900 dark:border-white; - } + --secondary: 240 4.8% 95.9%; + --secondary-foreground: 240 5.9% 10%; - .border-secondary { - @apply border-gray-200 dark:border-gray-600; - } + --muted: 240 4.8% 95.9%; + --muted-foreground: 240 3.8% 46.1%; - .text-primary { - @apply text-black dark:text-white; - } + --accent: 240 4.8% 95.9%; + --accent-foreground: 240 5.9% 10%; + + --destructive: 0 84.2% 60.2%; + --destructive-foreground: 0 0% 98%; - .text-secondary { - @apply text-gray-500 dark:text-slate-500; + --border: 240 5.9% 90%; + --input: 240 5.9% 90%; + --ring: 240 10% 3.9%; + + --radius: 0.5rem; } - .text-inverse { - @apply text-white dark:text-black; + .dark, + :root[class~='dark'] { + --background: 240 10% 3.9%; + --foreground: 0 0% 98%; + + --card: 240 10% 3.9%; + --card-foreground: 0 0% 98%; + + --popover: 240 10% 3.9%; + --popover-foreground: 0 0% 98%; + + --primary: 0 0% 98%; + --primary-foreground: 240 5.9% 10%; + + --secondary: 240 3.7% 15.9%; + --secondary-foreground: 0 0% 98%; + + --muted: 240 3.7% 15.9%; + --muted-foreground: 240 5% 64.9%; + + --accent: 240 3.7% 15.9%; + --accent-foreground: 0 0% 98%; + + --destructive: 0 62.8% 30.6%; + --destructive-foreground: 0 0% 98%; + + --border: 240 3.7% 15.9%; + --input: 240 3.7% 15.9%; + --ring: 240 4.9% 83.9%; } +} - .text-prose { - @apply prose dark:prose-invert; +@layer base { + * { + @apply border-border; + } + body { + @apply bg-background text-foreground; } } diff --git a/libs/ui/src/utils/index.ts b/libs/ui/src/utils/index.ts new file mode 100644 index 0000000..d32b0fe --- /dev/null +++ b/libs/ui/src/utils/index.ts @@ -0,0 +1,6 @@ +import { type ClassValue, clsx } from 'clsx' +import { twMerge } from 'tailwind-merge' + +export function cn(...inputs: ClassValue[]) { + return twMerge(clsx(inputs)) +} diff --git a/libs/ui/tsconfig.json b/libs/ui/tsconfig.json index 32d711c..63f2c5f 100644 --- a/libs/ui/tsconfig.json +++ b/libs/ui/tsconfig.json @@ -1,5 +1,12 @@ { "extends": "@repo/tsconfig/react-library.json", "include": ["."], - "exclude": ["dist", "build", "node_modules"] + "exclude": ["dist", "build", "node_modules"], + "compilerOptions": { + "outDir": "dist", + "baseUrl": ".", + "paths": { + "~/*": ["./src/*"] + } + } } diff --git a/libs/ui/tsup.config.ts b/libs/ui/tsup.config.ts index 72902a8..d719628 100644 --- a/libs/ui/tsup.config.ts +++ b/libs/ui/tsup.config.ts @@ -4,7 +4,7 @@ import { defineConfig } from 'tsup' export default defineConfig((options: Options) => ({ treeshake: true, splitting: true, - entry: ['src/**/*.tsx'], + entry: ['src/**/*.{ts,tsx}'], format: ['esm', 'cjs'], dts: true, minify: true, diff --git a/package.json b/package.json index 5d1c92e..4e3d92a 100644 --- a/package.json +++ b/package.json @@ -8,8 +8,8 @@ "deploy:nestjs": "fly deploy --config ./apps/nestjs/fly.toml --dockerfile ./apps/nestjs/Dockerfile", "deploy:remix": "fly deploy --config ./apps/remix/fly.toml --dockerfile ./apps/remix/Dockerfile", "develop:docs": "turbo run develop --filter docs", - "develop:nestjs": "turbo run develop --filter nestjs", - "develop:remix": "turbo run develop --filter remix", + "develop:nestjs": "turbo run develop --filter nestjs...", + "develop:remix": "turbo run develop --filter remix...", "develop:ui": "turbo run develop --filter ui", "develop": "turbo run develop", "format": "prettier --write .", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 62799bd..90be690 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -281,6 +281,9 @@ importers: tailwindcss: specifier: ^3.3.5 version: 3.3.5 + tailwindcss-animate: + specifier: ^1.0.7 + version: 1.0.7(tailwindcss@3.3.5) libs/tsconfig: {} @@ -297,6 +300,22 @@ importers: version: 5.3.2 libs/ui: + dependencies: + '@radix-ui/react-slot': + specifier: ^1.0.2 + version: 1.0.2(@types/react@18.2.38)(react@18.2.0) + class-variance-authority: + specifier: ^0.7.0 + version: 0.7.0 + clsx: + specifier: ^2.0.0 + version: 2.0.0 + lucide-react: + specifier: ^0.293.0 + version: 0.293.0(react@18.2.0) + tailwind-merge: + specifier: ^2.0.0 + version: 2.0.0 devDependencies: '@repo/eslint-config': specifier: workspace:* @@ -1776,7 +1795,6 @@ packages: engines: {node: '>=6.9.0'} dependencies: regenerator-runtime: 0.14.0 - dev: true /@babel/template@7.22.15: resolution: {integrity: sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==} @@ -3274,15 +3292,15 @@ packages: optional: true dependencies: '@babel/runtime': 7.23.4 - '@radix-ui/react-compose-refs': 1.0.1(react@18.2.0) + '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.38)(react@18.2.0) '@radix-ui/react-context': 1.0.1(react@18.2.0) '@radix-ui/react-primitive': 1.0.3(react-dom@18.2.0)(react@18.2.0) - '@radix-ui/react-slot': 1.0.2(react@18.2.0) + '@radix-ui/react-slot': 1.0.2(@types/react@18.2.38)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) dev: true - /@radix-ui/react-compose-refs@1.0.1(react@18.2.0): + /@radix-ui/react-compose-refs@1.0.1(@types/react@18.2.38)(react@18.2.0): resolution: {integrity: sha512-fDSBgd44FKHa1FRMU59qBMPFcl2PZE+2nmqunj+BWFyYYjnhIDWL2ItDs3rrbJDQOtzt5nIebLCQc4QRfz6LJw==} peerDependencies: '@types/react': '*' @@ -3292,8 +3310,8 @@ packages: optional: true dependencies: '@babel/runtime': 7.23.4 + '@types/react': 18.2.38 react: 18.2.0 - dev: true /@radix-ui/react-context@1.0.1(react@18.2.0): resolution: {integrity: sha512-ebbrdFoYTcuZ0v4wG5tedGnp9tzcV8awzsxYph7gXUyvnNLuTIcCk1q17JEbnVhXAKG9oX3KtchwiMIAYp9NLg==} @@ -3336,7 +3354,7 @@ packages: dependencies: '@babel/runtime': 7.23.4 '@radix-ui/primitive': 1.0.1 - '@radix-ui/react-compose-refs': 1.0.1(react@18.2.0) + '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.38)(react@18.2.0) '@radix-ui/react-primitive': 1.0.3(react-dom@18.2.0)(react@18.2.0) '@radix-ui/react-use-callback-ref': 1.0.1(react@18.2.0) '@radix-ui/react-use-escape-keydown': 1.0.3(react@18.2.0) @@ -3371,7 +3389,7 @@ packages: optional: true dependencies: '@babel/runtime': 7.23.4 - '@radix-ui/react-compose-refs': 1.0.1(react@18.2.0) + '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.38)(react@18.2.0) '@radix-ui/react-primitive': 1.0.3(react-dom@18.2.0)(react@18.2.0) '@radix-ui/react-use-callback-ref': 1.0.1(react@18.2.0) react: 18.2.0 @@ -3408,7 +3426,7 @@ packages: '@babel/runtime': 7.23.4 '@floating-ui/react-dom': 2.0.4(react-dom@18.2.0)(react@18.2.0) '@radix-ui/react-arrow': 1.0.3(react-dom@18.2.0)(react@18.2.0) - '@radix-ui/react-compose-refs': 1.0.1(react@18.2.0) + '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.38)(react@18.2.0) '@radix-ui/react-context': 1.0.1(react@18.2.0) '@radix-ui/react-primitive': 1.0.3(react-dom@18.2.0)(react@18.2.0) '@radix-ui/react-use-callback-ref': 1.0.1(react@18.2.0) @@ -3453,7 +3471,7 @@ packages: optional: true dependencies: '@babel/runtime': 7.23.4 - '@radix-ui/react-slot': 1.0.2(react@18.2.0) + '@radix-ui/react-slot': 1.0.2(@types/react@18.2.38)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) dev: true @@ -3474,7 +3492,7 @@ packages: '@babel/runtime': 7.23.4 '@radix-ui/primitive': 1.0.1 '@radix-ui/react-collection': 1.0.3(react-dom@18.2.0)(react@18.2.0) - '@radix-ui/react-compose-refs': 1.0.1(react@18.2.0) + '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.38)(react@18.2.0) '@radix-ui/react-context': 1.0.1(react@18.2.0) '@radix-ui/react-direction': 1.0.1(react@18.2.0) '@radix-ui/react-id': 1.0.1(react@18.2.0) @@ -3502,7 +3520,7 @@ packages: '@radix-ui/number': 1.0.1 '@radix-ui/primitive': 1.0.1 '@radix-ui/react-collection': 1.0.3(react-dom@18.2.0)(react@18.2.0) - '@radix-ui/react-compose-refs': 1.0.1(react@18.2.0) + '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.38)(react@18.2.0) '@radix-ui/react-context': 1.0.1(react@18.2.0) '@radix-ui/react-direction': 1.0.1(react@18.2.0) '@radix-ui/react-dismissable-layer': 1.0.4(react-dom@18.2.0)(react@18.2.0) @@ -3512,7 +3530,7 @@ packages: '@radix-ui/react-popper': 1.1.2(react-dom@18.2.0)(react@18.2.0) '@radix-ui/react-portal': 1.0.3(react-dom@18.2.0)(react@18.2.0) '@radix-ui/react-primitive': 1.0.3(react-dom@18.2.0)(react@18.2.0) - '@radix-ui/react-slot': 1.0.2(react@18.2.0) + '@radix-ui/react-slot': 1.0.2(@types/react@18.2.38)(react@18.2.0) '@radix-ui/react-use-callback-ref': 1.0.1(react@18.2.0) '@radix-ui/react-use-controllable-state': 1.0.1(react@18.2.0) '@radix-ui/react-use-layout-effect': 1.0.1(react@18.2.0) @@ -3543,7 +3561,7 @@ packages: react-dom: 18.2.0(react@18.2.0) dev: true - /@radix-ui/react-slot@1.0.2(react@18.2.0): + /@radix-ui/react-slot@1.0.2(@types/react@18.2.38)(react@18.2.0): resolution: {integrity: sha512-YeTpuq4deV+6DusvVUW4ivBgnkHwECUu0BiN43L5UCDFgdhsRUWAghhTF5MbvNTPzmiFOx90asDSUjWuCNapwg==} peerDependencies: '@types/react': '*' @@ -3553,9 +3571,9 @@ packages: optional: true dependencies: '@babel/runtime': 7.23.4 - '@radix-ui/react-compose-refs': 1.0.1(react@18.2.0) + '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.38)(react@18.2.0) + '@types/react': 18.2.38 react: 18.2.0 - dev: true /@radix-ui/react-toggle-group@1.0.4(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-Uaj/M/cMyiyT9Bx6fOZO0SAG4Cls0GptBWiBmBxofmDbNVnYYoyRWj/2M/6VCi/7qcXFWnHhRUfdfZFvvkuu8A==} @@ -5301,7 +5319,6 @@ packages: /@types/prop-types@15.7.11: resolution: {integrity: sha512-ga8y9v9uyeiLdpKddhxYQkxNDrfvuPrlFb0N1qnZZByvcElJaXthF1UhvCh9TLWJBEHeNtdnbysW7Y6Uq8CVng==} - dev: true /@types/qs@6.9.10: resolution: {integrity: sha512-3Gnx08Ns1sEoCrWssEgTSJs/rsT2vhGP+Ja9cnnk9k4ALxinORlQneLXFeFKOTJMOeZUFD1s7w+w2AphTpvzZw==} @@ -5323,7 +5340,6 @@ packages: '@types/prop-types': 15.7.11 '@types/scheduler': 0.16.8 csstype: 3.1.2 - dev: true /@types/resolve@1.20.6: resolution: {integrity: sha512-A4STmOXPhMUtHH+S6ymgE2GiBSMqf4oTvcQZMcHzokuTLVYzXTB8ttjcgxOVaAp2lGwEdzZ0J+cRbbeevQj1UQ==} @@ -5331,7 +5347,6 @@ packages: /@types/scheduler@0.16.8: resolution: {integrity: sha512-WZLiwShhwLRmeV6zH+GkbOFT6Z6VklCItrDioxUnv+u4Ll+8vKeFySoFyK/0ctcRpOmwAicELfmys1sDc/Rw+A==} - dev: true /@types/semver@7.5.6: resolution: {integrity: sha512-dn1l8LaMea/IjDoHNd9J52uBbInB796CDffS6VdIxvqYCPSG0V0DzHp76GpaWnlhg88uYyPbXCDIowa86ybd5A==} @@ -6852,6 +6867,12 @@ packages: resolution: {integrity: sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ==} dev: true + /class-variance-authority@0.7.0: + resolution: {integrity: sha512-jFI8IQw4hczaL4ALINxqLEXQbWcNjoSkloa4IaufXCJr6QawJyw7tuRysRsrE8w2p/4gGaxKIt/hX3qz/IbD1A==} + dependencies: + clsx: 2.0.0 + dev: false + /clean-regexp@1.0.0: resolution: {integrity: sha512-GfisEZEJvzKrmGWkvfhgzcz/BllN1USeqD2V6tg14OAOgaCD2Z/PUEuxnAZ/nPvmaHRG7a8y77p1T/IRQ4D1Hw==} engines: {node: '>=4'} @@ -6927,6 +6948,11 @@ packages: engines: {node: '>=0.8'} dev: true + /clsx@2.0.0: + resolution: {integrity: sha512-rQ1+kcj+ttHG0MKVGBUXwayCCF1oh39BF5COIpRzuCEv8Mwjv0XucrI2ExNTOn9IlLifGClWQcU9BrZORvtw6Q==} + engines: {node: '>=6'} + dev: false + /co@4.6.0: resolution: {integrity: sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==} engines: {iojs: '>= 1.0.0', node: '>= 0.12.0'} @@ -7155,7 +7181,6 @@ packages: /csstype@3.1.2: resolution: {integrity: sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==} - dev: true /damerau-levenshtein@1.0.8: resolution: {integrity: sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==} @@ -10639,6 +10664,14 @@ packages: engines: {node: '>=12'} dev: true + /lucide-react@0.293.0(react@18.2.0): + resolution: {integrity: sha512-g3AN0EYITCpAjNgLHrKrFWvIJzZy0Y9OPBaonyKw1cM+nZE6piOM+TiuQdYfha7oa76TMiDaWXQHE44CEqsrzw==} + peerDependencies: + react: ^16.5.1 || ^17.0.0 || ^18.0.0 + dependencies: + react: 18.2.0 + dev: false + /lz-string@1.5.0: resolution: {integrity: sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==} hasBin: true @@ -12772,7 +12805,6 @@ packages: /regenerator-runtime@0.14.0: resolution: {integrity: sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA==} - dev: true /regenerator-transform@0.15.2: resolution: {integrity: sha512-hfMp2BoF0qOk3uc5V20ALGDS2ddjQaLrdl7xrGXvAIow7qeWRM2VA2HuCHkUKk9slq3VwEwLNK3DFBqDfPGYtg==} @@ -13668,6 +13700,20 @@ packages: tslib: 2.6.2 dev: true + /tailwind-merge@2.0.0: + resolution: {integrity: sha512-WO8qghn9yhsldLSg80au+3/gY9E4hFxIvQ3qOmlpXnqpDKoMruKfi/56BbbMg6fHTQJ9QD3cc79PoWqlaQE4rw==} + dependencies: + '@babel/runtime': 7.23.4 + dev: false + + /tailwindcss-animate@1.0.7(tailwindcss@3.3.5): + resolution: {integrity: sha512-bl6mpH3T7I3UFxuvDEXLxy/VuFxBk5bbzplh7tXI68mwMokNYd1t9qPBHlnyTwfa4JGC4zP516I1hYYtQ/vspA==} + peerDependencies: + tailwindcss: '>=3.0.0 || insiders' + dependencies: + tailwindcss: 3.3.5 + dev: true + /tailwindcss@3.3.5: resolution: {integrity: sha512-5SEZU4J7pxZgSkv7FP1zY8i2TIAOooNZ1e/OGtxIEv6GltpoiXUqWvLy89+a10qYTB1N5Ifkuw9lqQkN9sscvA==} engines: {node: '>=14.0.0'}