create-ej-app 3.1.0 → 3.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-ej-app",
3
- "version": "3.1.0",
3
+ "version": "3.2.0",
4
4
  "description": "Bootstrap a next.js app with my preferred setup",
5
5
  "main": "cli.js",
6
6
  "scripts": {
@@ -35,7 +35,7 @@
35
35
  "enquirer": "^2.4.1"
36
36
  },
37
37
  "devDependencies": {
38
- "@types/node": "^20.10.5",
38
+ "@types/node": "^20.10.6",
39
39
  "typescript": "^5.3.3"
40
40
  }
41
41
  }
@@ -7,7 +7,8 @@
7
7
  "config": "tailwind.config.ts",
8
8
  "css": "src/styles/globals.css",
9
9
  "baseColor": "neutral",
10
- "cssVariables": true
10
+ "cssVariables": true,
11
+ "prefix": ""
11
12
  },
12
13
  "aliases": {
13
14
  "components": "@/components",
@@ -9,9 +9,9 @@
9
9
  "dev": "next dev",
10
10
  "build": "next build",
11
11
  "start": "next start",
12
- "prisma:push": "prisma db push",
13
- "prisma:gen": "prisma generate",
14
- "prisma:studio": "prisma studio"
12
+ "db:push": "prisma db push",
13
+ "db:gen": "prisma generate",
14
+ "db:studio": "prisma studio"
15
15
  },
16
16
  "dependencies": {
17
17
  "@editorjs/checklist": "^1.6.0",
@@ -22,8 +22,8 @@
22
22
  "@editorjs/list": "^1.9.0",
23
23
  "@editorjs/quote": "^2.6.0",
24
24
  "@editorjs/table": "^2.3.0",
25
- "@ejekanshjain/cloud-storage": "^3.1.0",
26
- "@hookform/resolvers": "^3.3.2",
25
+ "@ejekanshjain/cloud-storage": "^3.2.0",
26
+ "@hookform/resolvers": "^3.3.3",
27
27
  "@next-auth/prisma-adapter": "^1.0.7",
28
28
  "@prisma/client": "^5.7.1",
29
29
  "@radix-ui/react-alert-dialog": "^1.0.5",
@@ -44,10 +44,10 @@
44
44
  "@types/lodash": "^4.14.202",
45
45
  "@types/node": "^20.10.5",
46
46
  "@types/nodemailer": "^6.4.14",
47
- "@types/react": "^18.2.45",
47
+ "@types/react": "^18.2.46",
48
48
  "@types/react-dom": "^18.2.18",
49
- "@typescript-eslint/eslint-plugin": "^6.15.0",
50
- "@typescript-eslint/parser": "^6.15.0",
49
+ "@typescript-eslint/eslint-plugin": "^6.16.0",
50
+ "@typescript-eslint/parser": "^6.16.0",
51
51
  "@vercel/analytics": "^1.1.1",
52
52
  "@vercel/speed-insights": "^1.0.2",
53
53
  "autoprefixer": "^10.4.16",
@@ -59,14 +59,14 @@
59
59
  "eslint": "^8.56.0",
60
60
  "eslint-config-next": "^14.0.4",
61
61
  "lodash": "^4.17.21",
62
- "lucide-react": "^0.302.0",
62
+ "lucide-react": "^0.303.0",
63
63
  "next": "^14.0.4",
64
64
  "next-auth": "^4.24.5",
65
65
  "next-themes": "^0.2.1",
66
66
  "nodemailer": "^6.9.7",
67
67
  "postcss": "^8.4.32",
68
68
  "prettier": "^3.1.1",
69
- "prettier-plugin-tailwindcss": "^0.5.9",
69
+ "prettier-plugin-tailwindcss": "^0.5.10",
70
70
  "prisma": "^5.7.1",
71
71
  "react": "^18.2.0",
72
72
  "react-dom": "^18.2.0",
@@ -1,3 +1,4 @@
1
+ import { cn } from '@/lib/cn'
1
2
  import {
2
3
  ArrowDown,
3
4
  ArrowRight,
@@ -53,6 +54,7 @@ export const Icons = {
53
54
  xmlns="http://www.w3.org/2000/svg"
54
55
  viewBox="0 0 30 30"
55
56
  {...props}
57
+ className={cn('fill-current', props.className)}
56
58
  >
57
59
  <path d="M 15.003906 3 C 8.3749062 3 3 8.373 3 15 C 3 21.627 8.3749062 27 15.003906 27 C 25.013906 27 27.269078 17.707 26.330078 13 L 25 13 L 22.732422 13 L 15 13 L 15 17 L 22.738281 17 C 21.848702 20.448251 18.725955 23 15 23 C 10.582 23 7 19.418 7 15 C 7 10.582 10.582 7 15 7 C 17.009 7 18.839141 7.74575 20.244141 8.96875 L 23.085938 6.1289062 C 20.951937 4.1849063 18.116906 3 15.003906 3 z"></path>
58
60
  </svg>
@@ -15,10 +15,10 @@ const AlertDialogPortal = AlertDialogPrimitive.Portal
15
15
  const AlertDialogOverlay = React.forwardRef<
16
16
  React.ElementRef<typeof AlertDialogPrimitive.Overlay>,
17
17
  React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Overlay>
18
- >(({ className, children, ...props }, ref) => (
18
+ >(({ className, ...props }, ref) => (
19
19
  <AlertDialogPrimitive.Overlay
20
20
  className={cn(
21
- 'fixed inset-0 z-50 bg-background/80 backdrop-blur-sm data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0',
21
+ 'fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0',
22
22
  className
23
23
  )}
24
24
  {...props}
@@ -36,7 +36,7 @@ const AlertDialogContent = React.forwardRef<
36
36
  <AlertDialogPrimitive.Content
37
37
  ref={ref}
38
38
  className={cn(
39
- 'fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg md:w-full',
39
+ 'fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg',
40
40
  className
41
41
  )}
42
42
  {...props}
@@ -1,6 +1,6 @@
1
1
  'use client'
2
2
 
3
- import { DialogProps } from '@radix-ui/react-dialog'
3
+ import { type DialogProps } from '@radix-ui/react-dialog'
4
4
  import { Command as CommandPrimitive } from 'cmdk'
5
5
  import { Search } from 'lucide-react'
6
6
  import * as React from 'react'
@@ -21,7 +21,7 @@ const DialogOverlay = React.forwardRef<
21
21
  <DialogPrimitive.Overlay
22
22
  ref={ref}
23
23
  className={cn(
24
- 'fixed inset-0 z-50 bg-background/80 backdrop-blur-sm data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0',
24
+ 'fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0',
25
25
  className
26
26
  )}
27
27
  {...props}
@@ -38,7 +38,7 @@ const DialogContent = React.forwardRef<
38
38
  <DialogPrimitive.Content
39
39
  ref={ref}
40
40
  className={cn(
41
- 'fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg md:w-full',
41
+ 'fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg',
42
42
  className
43
43
  )}
44
44
  {...props}
@@ -1,7 +1,7 @@
1
1
  'use client'
2
2
 
3
3
  import * as SelectPrimitive from '@radix-ui/react-select'
4
- import { Check, ChevronDown } from 'lucide-react'
4
+ import { Check, ChevronDown, ChevronUp } from 'lucide-react'
5
5
  import * as React from 'react'
6
6
 
7
7
  import { cn } from '@/lib/cn'
@@ -19,7 +19,7 @@ const SelectTrigger = React.forwardRef<
19
19
  <SelectPrimitive.Trigger
20
20
  ref={ref}
21
21
  className={cn(
22
- 'flex h-10 w-full items-center justify-between rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50',
22
+ 'flex h-10 w-full items-center justify-between rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1',
23
23
  className
24
24
  )}
25
25
  {...props}
@@ -32,6 +32,41 @@ const SelectTrigger = React.forwardRef<
32
32
  ))
33
33
  SelectTrigger.displayName = SelectPrimitive.Trigger.displayName
34
34
 
35
+ const SelectScrollUpButton = React.forwardRef<
36
+ React.ElementRef<typeof SelectPrimitive.ScrollUpButton>,
37
+ React.ComponentPropsWithoutRef<typeof SelectPrimitive.ScrollUpButton>
38
+ >(({ className, ...props }, ref) => (
39
+ <SelectPrimitive.ScrollUpButton
40
+ ref={ref}
41
+ className={cn(
42
+ 'flex cursor-default items-center justify-center py-1',
43
+ className
44
+ )}
45
+ {...props}
46
+ >
47
+ <ChevronUp className="h-4 w-4" />
48
+ </SelectPrimitive.ScrollUpButton>
49
+ ))
50
+ SelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName
51
+
52
+ const SelectScrollDownButton = React.forwardRef<
53
+ React.ElementRef<typeof SelectPrimitive.ScrollDownButton>,
54
+ React.ComponentPropsWithoutRef<typeof SelectPrimitive.ScrollDownButton>
55
+ >(({ className, ...props }, ref) => (
56
+ <SelectPrimitive.ScrollDownButton
57
+ ref={ref}
58
+ className={cn(
59
+ 'flex cursor-default items-center justify-center py-1',
60
+ className
61
+ )}
62
+ {...props}
63
+ >
64
+ <ChevronDown className="h-4 w-4" />
65
+ </SelectPrimitive.ScrollDownButton>
66
+ ))
67
+ SelectScrollDownButton.displayName =
68
+ SelectPrimitive.ScrollDownButton.displayName
69
+
35
70
  const SelectContent = React.forwardRef<
36
71
  React.ElementRef<typeof SelectPrimitive.Content>,
37
72
  React.ComponentPropsWithoutRef<typeof SelectPrimitive.Content>
@@ -40,7 +75,7 @@ const SelectContent = React.forwardRef<
40
75
  <SelectPrimitive.Content
41
76
  ref={ref}
42
77
  className={cn(
43
- 'relative z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2',
78
+ 'relative z-50 max-h-96 min-w-[8rem] overflow-hidden rounded-md border bg-popover text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2',
44
79
  position === 'popper' &&
45
80
  'data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1',
46
81
  className
@@ -48,6 +83,7 @@ const SelectContent = React.forwardRef<
48
83
  position={position}
49
84
  {...props}
50
85
  >
86
+ <SelectScrollUpButton />
51
87
  <SelectPrimitive.Viewport
52
88
  className={cn(
53
89
  'p-1',
@@ -57,6 +93,7 @@ const SelectContent = React.forwardRef<
57
93
  >
58
94
  {children}
59
95
  </SelectPrimitive.Viewport>
96
+ <SelectScrollDownButton />
60
97
  </SelectPrimitive.Content>
61
98
  </SelectPrimitive.Portal>
62
99
  ))
@@ -115,6 +152,8 @@ export {
115
152
  SelectGroup,
116
153
  SelectItem,
117
154
  SelectLabel,
155
+ SelectScrollDownButton,
156
+ SelectScrollUpButton,
118
157
  SelectSeparator,
119
158
  SelectTrigger,
120
159
  SelectValue
@@ -42,7 +42,10 @@ const TableFooter = React.forwardRef<
42
42
  >(({ className, ...props }, ref) => (
43
43
  <tfoot
44
44
  ref={ref}
45
- className={cn('bg-primary font-medium text-primary-foreground', className)}
45
+ className={cn(
46
+ 'border-t bg-muted/50 font-medium [&>tr]:last:border-b-0',
47
+ className
48
+ )}
46
49
  {...props}
47
50
  />
48
51
  ))
@@ -71,5 +71,8 @@ export const env = createEnv({
71
71
  * Run `build` or `dev` with `SKIP_ENV_VALIDATION` to skip env validation.
72
72
  * This is especially useful for Docker builds.
73
73
  */
74
- skipValidation: !!process.env.SKIP_ENV_VALIDATION
74
+ skipValidation: !!process.env.SKIP_ENV_VALIDATION,
75
+
76
+ // This makes empty strings be treated as undefined
77
+ emptyStringAsUndefined: true
75
78
  })
@@ -1,5 +1,5 @@
1
1
  import { PrismaAdapter } from '@next-auth/prisma-adapter'
2
- import { Permissions, UserType } from '@prisma/client'
2
+ import { Permissions, User as PrismaUser, UserType } from '@prisma/client'
3
3
  import {
4
4
  Session,
5
5
  getServerSession,
@@ -28,10 +28,7 @@ declare module 'next-auth' {
28
28
  } & DefaultSession['user']
29
29
  }
30
30
 
31
- interface User {
32
- type: UserType
33
- roleId?: string | null
34
- }
31
+ interface User extends PrismaUser {}
35
32
  }
36
33
 
37
34
  /**
@@ -1,8 +1,9 @@
1
1
  import type { Config } from 'tailwindcss'
2
2
 
3
- const tailwindConfig: Config = {
3
+ const config = {
4
4
  darkMode: ['class'],
5
5
  content: ['./src/**/*.{js,ts,jsx,tsx,mdx}'],
6
+ prefix: '',
6
7
  theme: {
7
8
  container: {
8
9
  center: true,
@@ -74,6 +75,6 @@ const tailwindConfig: Config = {
74
75
  }
75
76
  },
76
77
  plugins: [require('tailwindcss-animate'), require('@tailwindcss/typography')]
77
- }
78
+ } satisfies Config
78
79
 
79
- export default tailwindConfig
80
+ export default config
@@ -7,7 +7,8 @@
7
7
  "config": "tailwind.config.ts",
8
8
  "css": "src/styles/globals.css",
9
9
  "baseColor": "neutral",
10
- "cssVariables": true
10
+ "cssVariables": true,
11
+ "prefix": ""
11
12
  },
12
13
  "aliases": {
13
14
  "components": "@/components",
@@ -9,9 +9,9 @@
9
9
  "dev": "next dev",
10
10
  "build": "next build",
11
11
  "start": "next start",
12
- "prisma:push": "prisma db push",
13
- "prisma:gen": "prisma generate",
14
- "prisma:studio": "prisma studio"
12
+ "db:push": "prisma db push",
13
+ "db:gen": "prisma generate",
14
+ "db:studio": "prisma studio"
15
15
  },
16
16
  "dependencies": {
17
17
  "@editorjs/checklist": "^1.6.0",
@@ -22,8 +22,8 @@
22
22
  "@editorjs/list": "^1.9.0",
23
23
  "@editorjs/quote": "^2.6.0",
24
24
  "@editorjs/table": "^2.3.0",
25
- "@ejekanshjain/cloud-storage": "^3.1.0",
26
- "@hookform/resolvers": "^3.3.2",
25
+ "@ejekanshjain/cloud-storage": "^3.2.0",
26
+ "@hookform/resolvers": "^3.3.3",
27
27
  "@next-auth/prisma-adapter": "^1.0.7",
28
28
  "@prisma/client": "^5.7.1",
29
29
  "@radix-ui/react-alert-dialog": "^1.0.5",
@@ -44,10 +44,10 @@
44
44
  "@types/lodash": "^4.14.202",
45
45
  "@types/node": "^20.10.5",
46
46
  "@types/nodemailer": "^6.4.14",
47
- "@types/react": "^18.2.45",
47
+ "@types/react": "^18.2.46",
48
48
  "@types/react-dom": "^18.2.18",
49
- "@typescript-eslint/eslint-plugin": "^6.15.0",
50
- "@typescript-eslint/parser": "^6.15.0",
49
+ "@typescript-eslint/eslint-plugin": "^6.16.0",
50
+ "@typescript-eslint/parser": "^6.16.0",
51
51
  "@vercel/analytics": "^1.1.1",
52
52
  "@vercel/speed-insights": "^1.0.2",
53
53
  "autoprefixer": "^10.4.16",
@@ -59,14 +59,14 @@
59
59
  "eslint": "^8.56.0",
60
60
  "eslint-config-next": "^14.0.4",
61
61
  "lodash": "^4.17.21",
62
- "lucide-react": "^0.302.0",
62
+ "lucide-react": "^0.303.0",
63
63
  "next": "^14.0.4",
64
64
  "next-auth": "^4.24.5",
65
65
  "next-themes": "^0.2.1",
66
66
  "nodemailer": "^6.9.7",
67
67
  "postcss": "^8.4.32",
68
68
  "prettier": "^3.1.1",
69
- "prettier-plugin-tailwindcss": "^0.5.9",
69
+ "prettier-plugin-tailwindcss": "^0.5.10",
70
70
  "prisma": "^5.7.1",
71
71
  "react": "^18.2.0",
72
72
  "react-dom": "^18.2.0",
@@ -50,7 +50,6 @@ model User {
50
50
  email String? @unique
51
51
  emailVerified DateTime? @db.Timestamptz()
52
52
  image String?
53
- roleId String?
54
53
 
55
54
  createdAt DateTime @default(now()) @db.Timestamptz()
56
55
  updatedAt DateTime @default(now()) @updatedAt @db.Timestamptz()
@@ -1,3 +1,4 @@
1
+ import { cn } from '@/lib/cn'
1
2
  import {
2
3
  ArrowDown,
3
4
  ArrowRight,
@@ -53,6 +54,7 @@ export const Icons = {
53
54
  xmlns="http://www.w3.org/2000/svg"
54
55
  viewBox="0 0 30 30"
55
56
  {...props}
57
+ className={cn('fill-current', props.className)}
56
58
  >
57
59
  <path d="M 15.003906 3 C 8.3749062 3 3 8.373 3 15 C 3 21.627 8.3749062 27 15.003906 27 C 25.013906 27 27.269078 17.707 26.330078 13 L 25 13 L 22.732422 13 L 15 13 L 15 17 L 22.738281 17 C 21.848702 20.448251 18.725955 23 15 23 C 10.582 23 7 19.418 7 15 C 7 10.582 10.582 7 15 7 C 17.009 7 18.839141 7.74575 20.244141 8.96875 L 23.085938 6.1289062 C 20.951937 4.1849063 18.116906 3 15.003906 3 z"></path>
58
60
  </svg>
@@ -15,10 +15,10 @@ const AlertDialogPortal = AlertDialogPrimitive.Portal
15
15
  const AlertDialogOverlay = React.forwardRef<
16
16
  React.ElementRef<typeof AlertDialogPrimitive.Overlay>,
17
17
  React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Overlay>
18
- >(({ className, children, ...props }, ref) => (
18
+ >(({ className, ...props }, ref) => (
19
19
  <AlertDialogPrimitive.Overlay
20
20
  className={cn(
21
- 'fixed inset-0 z-50 bg-background/80 backdrop-blur-sm data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0',
21
+ 'fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0',
22
22
  className
23
23
  )}
24
24
  {...props}
@@ -36,7 +36,7 @@ const AlertDialogContent = React.forwardRef<
36
36
  <AlertDialogPrimitive.Content
37
37
  ref={ref}
38
38
  className={cn(
39
- 'fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg md:w-full',
39
+ 'fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg',
40
40
  className
41
41
  )}
42
42
  {...props}
@@ -1,6 +1,6 @@
1
1
  'use client'
2
2
 
3
- import { DialogProps } from '@radix-ui/react-dialog'
3
+ import { type DialogProps } from '@radix-ui/react-dialog'
4
4
  import { Command as CommandPrimitive } from 'cmdk'
5
5
  import { Search } from 'lucide-react'
6
6
  import * as React from 'react'
@@ -21,7 +21,7 @@ const DialogOverlay = React.forwardRef<
21
21
  <DialogPrimitive.Overlay
22
22
  ref={ref}
23
23
  className={cn(
24
- 'fixed inset-0 z-50 bg-background/80 backdrop-blur-sm data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0',
24
+ 'fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0',
25
25
  className
26
26
  )}
27
27
  {...props}
@@ -38,7 +38,7 @@ const DialogContent = React.forwardRef<
38
38
  <DialogPrimitive.Content
39
39
  ref={ref}
40
40
  className={cn(
41
- 'fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg md:w-full',
41
+ 'fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg',
42
42
  className
43
43
  )}
44
44
  {...props}
@@ -1,7 +1,7 @@
1
1
  'use client'
2
2
 
3
3
  import * as SelectPrimitive from '@radix-ui/react-select'
4
- import { Check, ChevronDown } from 'lucide-react'
4
+ import { Check, ChevronDown, ChevronUp } from 'lucide-react'
5
5
  import * as React from 'react'
6
6
 
7
7
  import { cn } from '@/lib/cn'
@@ -19,7 +19,7 @@ const SelectTrigger = React.forwardRef<
19
19
  <SelectPrimitive.Trigger
20
20
  ref={ref}
21
21
  className={cn(
22
- 'flex h-10 w-full items-center justify-between rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50',
22
+ 'flex h-10 w-full items-center justify-between rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1',
23
23
  className
24
24
  )}
25
25
  {...props}
@@ -32,6 +32,41 @@ const SelectTrigger = React.forwardRef<
32
32
  ))
33
33
  SelectTrigger.displayName = SelectPrimitive.Trigger.displayName
34
34
 
35
+ const SelectScrollUpButton = React.forwardRef<
36
+ React.ElementRef<typeof SelectPrimitive.ScrollUpButton>,
37
+ React.ComponentPropsWithoutRef<typeof SelectPrimitive.ScrollUpButton>
38
+ >(({ className, ...props }, ref) => (
39
+ <SelectPrimitive.ScrollUpButton
40
+ ref={ref}
41
+ className={cn(
42
+ 'flex cursor-default items-center justify-center py-1',
43
+ className
44
+ )}
45
+ {...props}
46
+ >
47
+ <ChevronUp className="h-4 w-4" />
48
+ </SelectPrimitive.ScrollUpButton>
49
+ ))
50
+ SelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName
51
+
52
+ const SelectScrollDownButton = React.forwardRef<
53
+ React.ElementRef<typeof SelectPrimitive.ScrollDownButton>,
54
+ React.ComponentPropsWithoutRef<typeof SelectPrimitive.ScrollDownButton>
55
+ >(({ className, ...props }, ref) => (
56
+ <SelectPrimitive.ScrollDownButton
57
+ ref={ref}
58
+ className={cn(
59
+ 'flex cursor-default items-center justify-center py-1',
60
+ className
61
+ )}
62
+ {...props}
63
+ >
64
+ <ChevronDown className="h-4 w-4" />
65
+ </SelectPrimitive.ScrollDownButton>
66
+ ))
67
+ SelectScrollDownButton.displayName =
68
+ SelectPrimitive.ScrollDownButton.displayName
69
+
35
70
  const SelectContent = React.forwardRef<
36
71
  React.ElementRef<typeof SelectPrimitive.Content>,
37
72
  React.ComponentPropsWithoutRef<typeof SelectPrimitive.Content>
@@ -40,7 +75,7 @@ const SelectContent = React.forwardRef<
40
75
  <SelectPrimitive.Content
41
76
  ref={ref}
42
77
  className={cn(
43
- 'relative z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2',
78
+ 'relative z-50 max-h-96 min-w-[8rem] overflow-hidden rounded-md border bg-popover text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2',
44
79
  position === 'popper' &&
45
80
  'data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1',
46
81
  className
@@ -48,6 +83,7 @@ const SelectContent = React.forwardRef<
48
83
  position={position}
49
84
  {...props}
50
85
  >
86
+ <SelectScrollUpButton />
51
87
  <SelectPrimitive.Viewport
52
88
  className={cn(
53
89
  'p-1',
@@ -57,6 +93,7 @@ const SelectContent = React.forwardRef<
57
93
  >
58
94
  {children}
59
95
  </SelectPrimitive.Viewport>
96
+ <SelectScrollDownButton />
60
97
  </SelectPrimitive.Content>
61
98
  </SelectPrimitive.Portal>
62
99
  ))
@@ -115,6 +152,8 @@ export {
115
152
  SelectGroup,
116
153
  SelectItem,
117
154
  SelectLabel,
155
+ SelectScrollDownButton,
156
+ SelectScrollUpButton,
118
157
  SelectSeparator,
119
158
  SelectTrigger,
120
159
  SelectValue
@@ -42,7 +42,10 @@ const TableFooter = React.forwardRef<
42
42
  >(({ className, ...props }, ref) => (
43
43
  <tfoot
44
44
  ref={ref}
45
- className={cn('bg-primary font-medium text-primary-foreground', className)}
45
+ className={cn(
46
+ 'border-t bg-muted/50 font-medium [&>tr]:last:border-b-0',
47
+ className
48
+ )}
46
49
  {...props}
47
50
  />
48
51
  ))
@@ -71,5 +71,8 @@ export const env = createEnv({
71
71
  * Run `build` or `dev` with `SKIP_ENV_VALIDATION` to skip env validation.
72
72
  * This is especially useful for Docker builds.
73
73
  */
74
- skipValidation: !!process.env.SKIP_ENV_VALIDATION
74
+ skipValidation: !!process.env.SKIP_ENV_VALIDATION,
75
+
76
+ // This makes empty strings be treated as undefined
77
+ emptyStringAsUndefined: true
75
78
  })
@@ -1,4 +1,5 @@
1
1
  import { PrismaAdapter } from '@next-auth/prisma-adapter'
2
+ import { User as PrismaUser } from '@prisma/client'
2
3
  import {
3
4
  getServerSession,
4
5
  type DefaultSession,
@@ -24,7 +25,7 @@ declare module 'next-auth' {
24
25
  } & DefaultSession['user']
25
26
  }
26
27
 
27
- interface User {}
28
+ interface User extends PrismaUser {}
28
29
  }
29
30
 
30
31
  /**
@@ -1,8 +1,9 @@
1
1
  import type { Config } from 'tailwindcss'
2
2
 
3
- const tailwindConfig: Config = {
3
+ const config = {
4
4
  darkMode: ['class'],
5
5
  content: ['./src/**/*.{js,ts,jsx,tsx,mdx}'],
6
+ prefix: '',
6
7
  theme: {
7
8
  container: {
8
9
  center: true,
@@ -74,6 +75,6 @@ const tailwindConfig: Config = {
74
75
  }
75
76
  },
76
77
  plugins: [require('tailwindcss-animate'), require('@tailwindcss/typography')]
77
- }
78
+ } satisfies Config
78
79
 
79
- export default tailwindConfig
80
+ export default config