create-ej-app 1.0.0 → 2.0.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.
Files changed (198) hide show
  1. package/cli.js +21 -3
  2. package/package.json +1 -1
  3. package/template/{.env.example → advanced/.env.example} +4 -0
  4. package/template/{components.json → advanced/components.json} +1 -1
  5. package/template/{package.json → advanced/package.json} +11 -0
  6. package/template/{prisma → advanced/prisma}/schema.prisma +18 -1
  7. package/template/{src → advanced/src}/app/(app)/tasks/[id]/actions.ts +46 -4
  8. package/template/{src → advanced/src}/app/(app)/tasks/[id]/render.tsx +136 -25
  9. package/template/{src → advanced/src}/app/(app)/tasks/actions.ts +0 -6
  10. package/template/{src → advanced/src}/app/(app)/tasks/page.tsx +0 -3
  11. package/template/{src → advanced/src}/app/(app)/tasks/render.tsx +0 -10
  12. package/template/advanced/src/app/api/upload/route.ts +45 -0
  13. package/template/{src → advanced/src}/app/layout.tsx +1 -1
  14. package/template/{src → advanced/src}/env.mjs +10 -2
  15. package/template/advanced/src/styles/editor.css +61 -0
  16. package/template/{tailwind.config.ts → advanced/tailwind.config.ts} +1 -1
  17. package/template/base/.env.example +16 -0
  18. package/template/base/.eslintrc.cjs +24 -0
  19. package/template/base/components.json +16 -0
  20. package/template/base/next.config.mjs +18 -0
  21. package/template/base/package.json +79 -0
  22. package/template/base/postcss.config.cjs +6 -0
  23. package/template/base/prettier.config.ts +11 -0
  24. package/template/base/prisma/schema.prisma +115 -0
  25. package/template/base/public/next.svg +1 -0
  26. package/template/base/src/app/(app)/dashboard/page.tsx +19 -0
  27. package/template/base/src/app/(app)/layout.tsx +90 -0
  28. package/template/base/src/app/(app)/settings/actions.ts +18 -0
  29. package/template/base/src/app/(app)/settings/loading.tsx +28 -0
  30. package/template/base/src/app/(app)/settings/page.tsx +28 -0
  31. package/template/base/src/app/(app)/settings/render.tsx +113 -0
  32. package/template/base/src/app/(app)/tasks/[id]/actions.ts +149 -0
  33. package/template/base/src/app/(app)/tasks/[id]/page.tsx +25 -0
  34. package/template/base/src/app/(app)/tasks/[id]/render.tsx +413 -0
  35. package/template/base/src/app/(app)/tasks/actions.ts +69 -0
  36. package/template/base/src/app/(app)/tasks/page.tsx +53 -0
  37. package/template/base/src/app/(app)/tasks/render.tsx +107 -0
  38. package/template/base/src/app/(app)/users/[id]/actions.ts +83 -0
  39. package/template/base/src/app/(app)/users/[id]/page.tsx +32 -0
  40. package/template/base/src/app/(app)/users/[id]/render.tsx +240 -0
  41. package/template/base/src/app/(app)/users/actions.ts +55 -0
  42. package/template/base/src/app/(app)/users/page.tsx +49 -0
  43. package/template/base/src/app/(app)/users/render.tsx +80 -0
  44. package/template/base/src/app/(auth)/layout.tsx +20 -0
  45. package/template/base/src/app/(auth)/login/page.tsx +49 -0
  46. package/template/base/src/app/(auth)/login/user-auth-form.tsx +152 -0
  47. package/template/base/src/app/(marketing)/layout.tsx +42 -0
  48. package/template/base/src/app/(marketing)/page.tsx +96 -0
  49. package/template/base/src/app/api/auth/[...nextauth]/route.ts +7 -0
  50. package/template/base/src/app/api/upload/route.ts +45 -0
  51. package/template/base/src/app/favicon.ico +0 -0
  52. package/template/base/src/app/layout.tsx +32 -0
  53. package/template/base/src/components/app-nav-command.tsx +160 -0
  54. package/template/base/src/components/dark-mode-toggle.tsx +43 -0
  55. package/template/base/src/components/data-table/data-table-column-header.tsx +91 -0
  56. package/template/base/src/components/data-table/data-table-faceted-filter.tsx +149 -0
  57. package/template/base/src/components/data-table/data-table-loading.tsx +77 -0
  58. package/template/base/src/components/data-table/data-table-pagination.tsx +94 -0
  59. package/template/base/src/components/data-table/data-table-toolbar.tsx +78 -0
  60. package/template/base/src/components/data-table/data-table-types.ts +17 -0
  61. package/template/base/src/components/data-table/data-table-view-options.tsx +59 -0
  62. package/template/base/src/components/data-table/data-table.tsx +301 -0
  63. package/template/base/src/components/data-table/simple-data-table.tsx +109 -0
  64. package/template/base/src/components/empty-placeholder.tsx +78 -0
  65. package/template/base/src/components/heading.tsx +17 -0
  66. package/template/base/src/components/icons.tsx +83 -0
  67. package/template/base/src/components/main-nav.tsx +64 -0
  68. package/template/base/src/components/mobile-nav.tsx +50 -0
  69. package/template/base/src/components/shell.tsx +13 -0
  70. package/template/base/src/components/side-nav.tsx +51 -0
  71. package/template/base/src/components/site-footer.tsx +31 -0
  72. package/template/base/src/components/system-info.tsx +36 -0
  73. package/template/base/src/components/theme-provider.tsx +13 -0
  74. package/template/base/src/components/ui/alert-dialog.tsx +145 -0
  75. package/template/base/src/components/ui/avatar.tsx +50 -0
  76. package/template/base/src/components/ui/badge.tsx +36 -0
  77. package/template/base/src/components/ui/button.tsx +56 -0
  78. package/template/base/src/components/ui/card.tsx +79 -0
  79. package/template/base/src/components/ui/checkbox.tsx +30 -0
  80. package/template/base/src/components/ui/command.tsx +155 -0
  81. package/template/base/src/components/ui/dialog.tsx +123 -0
  82. package/template/base/src/components/ui/dropdown-menu.tsx +200 -0
  83. package/template/base/src/components/ui/form.tsx +176 -0
  84. package/template/base/src/components/ui/input.tsx +25 -0
  85. package/template/base/src/components/ui/label.tsx +26 -0
  86. package/template/base/src/components/ui/popover.tsx +31 -0
  87. package/template/base/src/components/ui/select.tsx +121 -0
  88. package/template/base/src/components/ui/separator.tsx +31 -0
  89. package/template/base/src/components/ui/skeleton.tsx +15 -0
  90. package/template/base/src/components/ui/table.tsx +114 -0
  91. package/template/base/src/components/ui/textarea.tsx +24 -0
  92. package/template/base/src/components/ui/toast.tsx +127 -0
  93. package/template/base/src/components/ui/toaster.tsx +35 -0
  94. package/template/base/src/components/ui/use-toast.ts +189 -0
  95. package/template/base/src/components/user-account-nav.tsx +60 -0
  96. package/template/base/src/components/user-avatar.tsx +25 -0
  97. package/template/base/src/env.mjs +75 -0
  98. package/template/base/src/hooks/use-debounce.ts +17 -0
  99. package/template/base/src/hooks/use-lock-body.tsx +12 -0
  100. package/template/base/src/lib/auth.ts +79 -0
  101. package/template/base/src/lib/cn.ts +4 -0
  102. package/template/base/src/lib/db.ts +20 -0
  103. package/template/base/src/lib/delay.ts +2 -0
  104. package/template/base/src/lib/formatDate.ts +11 -0
  105. package/template/base/src/lib/generateLabel.ts +5 -0
  106. package/template/base/src/lib/siteConfig.ts +4 -0
  107. package/template/base/src/styles/editor.css +61 -0
  108. package/template/base/src/styles/globals.css +76 -0
  109. package/template/base/src/types/UnwrapPromise.ts +1 -0
  110. package/template/base/tailwind.config.ts +79 -0
  111. package/template/base/tsconfig.json +46 -0
  112. /package/template/{.eslintrc.cjs → advanced/.eslintrc.cjs} +0 -0
  113. /package/template/{next.config.mjs → advanced/next.config.mjs} +0 -0
  114. /package/template/{postcss.config.cjs → advanced/postcss.config.cjs} +0 -0
  115. /package/template/{prettier.config.ts → advanced/prettier.config.ts} +0 -0
  116. /package/template/{public → advanced/public}/next.svg +0 -0
  117. /package/template/{src → advanced/src}/app/(app)/dashboard/page.tsx +0 -0
  118. /package/template/{src → advanced/src}/app/(app)/layout.tsx +0 -0
  119. /package/template/{src → advanced/src}/app/(app)/roles/[id]/actions.ts +0 -0
  120. /package/template/{src → advanced/src}/app/(app)/roles/[id]/page.tsx +0 -0
  121. /package/template/{src → advanced/src}/app/(app)/roles/[id]/render.tsx +0 -0
  122. /package/template/{src → advanced/src}/app/(app)/roles/actions.ts +0 -0
  123. /package/template/{src → advanced/src}/app/(app)/roles/page.tsx +0 -0
  124. /package/template/{src → advanced/src}/app/(app)/roles/render.tsx +0 -0
  125. /package/template/{src → advanced/src}/app/(app)/settings/actions.ts +0 -0
  126. /package/template/{src → advanced/src}/app/(app)/settings/loading.tsx +0 -0
  127. /package/template/{src → advanced/src}/app/(app)/settings/page.tsx +0 -0
  128. /package/template/{src → advanced/src}/app/(app)/settings/render.tsx +0 -0
  129. /package/template/{src → advanced/src}/app/(app)/tasks/[id]/page.tsx +0 -0
  130. /package/template/{src → advanced/src}/app/(app)/users/[id]/actions.ts +0 -0
  131. /package/template/{src → advanced/src}/app/(app)/users/[id]/page.tsx +0 -0
  132. /package/template/{src → advanced/src}/app/(app)/users/[id]/render.tsx +0 -0
  133. /package/template/{src → advanced/src}/app/(app)/users/actions.ts +0 -0
  134. /package/template/{src → advanced/src}/app/(app)/users/page.tsx +0 -0
  135. /package/template/{src → advanced/src}/app/(app)/users/render.tsx +0 -0
  136. /package/template/{src → advanced/src}/app/(auth)/layout.tsx +0 -0
  137. /package/template/{src → advanced/src}/app/(auth)/login/page.tsx +0 -0
  138. /package/template/{src → advanced/src}/app/(auth)/login/user-auth-form.tsx +0 -0
  139. /package/template/{src → advanced/src}/app/(marketing)/layout.tsx +0 -0
  140. /package/template/{src → advanced/src}/app/(marketing)/page.tsx +0 -0
  141. /package/template/{src → advanced/src}/app/api/auth/[...nextauth]/route.ts +0 -0
  142. /package/template/{src → advanced/src}/app/favicon.ico +0 -0
  143. /package/template/{src → advanced/src}/components/app-nav-command.tsx +0 -0
  144. /package/template/{src → advanced/src}/components/dark-mode-toggle.tsx +0 -0
  145. /package/template/{src → advanced/src}/components/data-table/data-table-column-header.tsx +0 -0
  146. /package/template/{src → advanced/src}/components/data-table/data-table-faceted-filter.tsx +0 -0
  147. /package/template/{src → advanced/src}/components/data-table/data-table-loading.tsx +0 -0
  148. /package/template/{src → advanced/src}/components/data-table/data-table-pagination.tsx +0 -0
  149. /package/template/{src → advanced/src}/components/data-table/data-table-toolbar.tsx +0 -0
  150. /package/template/{src → advanced/src}/components/data-table/data-table-types.ts +0 -0
  151. /package/template/{src → advanced/src}/components/data-table/data-table-view-options.tsx +0 -0
  152. /package/template/{src → advanced/src}/components/data-table/data-table.tsx +0 -0
  153. /package/template/{src → advanced/src}/components/data-table/simple-data-table.tsx +0 -0
  154. /package/template/{src → advanced/src}/components/empty-placeholder.tsx +0 -0
  155. /package/template/{src → advanced/src}/components/heading.tsx +0 -0
  156. /package/template/{src → advanced/src}/components/icons.tsx +0 -0
  157. /package/template/{src → advanced/src}/components/main-nav.tsx +0 -0
  158. /package/template/{src → advanced/src}/components/mobile-nav.tsx +0 -0
  159. /package/template/{src → advanced/src}/components/shell.tsx +0 -0
  160. /package/template/{src → advanced/src}/components/side-nav.tsx +0 -0
  161. /package/template/{src → advanced/src}/components/site-footer.tsx +0 -0
  162. /package/template/{src → advanced/src}/components/system-info.tsx +0 -0
  163. /package/template/{src → advanced/src}/components/theme-provider.tsx +0 -0
  164. /package/template/{src → advanced/src}/components/ui/alert-dialog.tsx +0 -0
  165. /package/template/{src → advanced/src}/components/ui/avatar.tsx +0 -0
  166. /package/template/{src → advanced/src}/components/ui/badge.tsx +0 -0
  167. /package/template/{src → advanced/src}/components/ui/button.tsx +0 -0
  168. /package/template/{src → advanced/src}/components/ui/card.tsx +0 -0
  169. /package/template/{src → advanced/src}/components/ui/checkbox.tsx +0 -0
  170. /package/template/{src → advanced/src}/components/ui/command.tsx +0 -0
  171. /package/template/{src → advanced/src}/components/ui/dialog.tsx +0 -0
  172. /package/template/{src → advanced/src}/components/ui/dropdown-menu.tsx +0 -0
  173. /package/template/{src → advanced/src}/components/ui/form.tsx +0 -0
  174. /package/template/{src → advanced/src}/components/ui/input.tsx +0 -0
  175. /package/template/{src → advanced/src}/components/ui/label.tsx +0 -0
  176. /package/template/{src → advanced/src}/components/ui/popover.tsx +0 -0
  177. /package/template/{src → advanced/src}/components/ui/select.tsx +0 -0
  178. /package/template/{src → advanced/src}/components/ui/separator.tsx +0 -0
  179. /package/template/{src → advanced/src}/components/ui/skeleton.tsx +0 -0
  180. /package/template/{src → advanced/src}/components/ui/table.tsx +0 -0
  181. /package/template/{src → advanced/src}/components/ui/textarea.tsx +0 -0
  182. /package/template/{src → advanced/src}/components/ui/toast.tsx +0 -0
  183. /package/template/{src → advanced/src}/components/ui/toaster.tsx +0 -0
  184. /package/template/{src → advanced/src}/components/ui/use-toast.ts +0 -0
  185. /package/template/{src → advanced/src}/components/user-account-nav.tsx +0 -0
  186. /package/template/{src → advanced/src}/components/user-avatar.tsx +0 -0
  187. /package/template/{src → advanced/src}/hooks/use-debounce.ts +0 -0
  188. /package/template/{src → advanced/src}/hooks/use-lock-body.tsx +0 -0
  189. /package/template/{src → advanced/src}/lib/auth.ts +0 -0
  190. /package/template/{src → advanced/src}/lib/cn.ts +0 -0
  191. /package/template/{src → advanced/src}/lib/db.ts +0 -0
  192. /package/template/{src → advanced/src}/lib/delay.ts +0 -0
  193. /package/template/{src → advanced/src}/lib/formatDate.ts +0 -0
  194. /package/template/{src → advanced/src}/lib/generateLabel.ts +0 -0
  195. /package/template/{src → advanced/src}/lib/siteConfig.ts +0 -0
  196. /package/template/{src/app → advanced/src/styles}/globals.css +0 -0
  197. /package/template/{src → advanced/src}/types/UnwrapPromise.ts +0 -0
  198. /package/template/{tsconfig.json → advanced/tsconfig.json} +0 -0
@@ -0,0 +1,60 @@
1
+ 'use client'
2
+
3
+ import { User } from 'next-auth'
4
+ import { signOut } from 'next-auth/react'
5
+ import Link from 'next/link'
6
+ import { FC, HTMLAttributes } from 'react'
7
+
8
+ import {
9
+ DropdownMenu,
10
+ DropdownMenuContent,
11
+ DropdownMenuItem,
12
+ DropdownMenuSeparator,
13
+ DropdownMenuTrigger
14
+ } from '@/components/ui/dropdown-menu'
15
+ import { UserAvatar } from '@/components/user-avatar'
16
+
17
+ interface UserAccountNavProps extends HTMLAttributes<HTMLDivElement> {
18
+ user: Pick<User, 'name' | 'image' | 'email'>
19
+ }
20
+
21
+ export const UserAccountNav: FC<UserAccountNavProps> = ({ user }) => {
22
+ return (
23
+ <DropdownMenu>
24
+ <DropdownMenuTrigger>
25
+ <UserAvatar
26
+ user={{ name: user.name || null, image: user.image || null }}
27
+ className="h-8 w-8"
28
+ />
29
+ </DropdownMenuTrigger>
30
+ <DropdownMenuContent align="end">
31
+ <div className="flex items-center justify-start gap-2 p-2">
32
+ <div className="flex flex-col space-y-1 leading-none">
33
+ {user.name && <p className="font-medium">{user.name}</p>}
34
+ {user.email && (
35
+ <p className="w-[200px] truncate text-sm text-muted-foreground">
36
+ {user.email}
37
+ </p>
38
+ )}
39
+ </div>
40
+ </div>
41
+ <DropdownMenuSeparator />
42
+ <DropdownMenuItem asChild>
43
+ <Link href="/settings">Settings</Link>
44
+ </DropdownMenuItem>
45
+ <DropdownMenuSeparator />
46
+ <DropdownMenuItem
47
+ className="cursor-pointer"
48
+ onSelect={event => {
49
+ event.preventDefault()
50
+ signOut({
51
+ callbackUrl: `${window.location.origin}/login`
52
+ })
53
+ }}
54
+ >
55
+ Sign out
56
+ </DropdownMenuItem>
57
+ </DropdownMenuContent>
58
+ </DropdownMenu>
59
+ )
60
+ }
@@ -0,0 +1,25 @@
1
+ import { User } from '@prisma/client'
2
+ import { AvatarProps } from '@radix-ui/react-avatar'
3
+ import { FC } from 'react'
4
+
5
+ import { Icons } from '@/components/icons'
6
+ import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar'
7
+
8
+ interface UserAvatarProps extends AvatarProps {
9
+ user: Pick<User, 'image' | 'name'>
10
+ }
11
+
12
+ export const UserAvatar: FC<UserAvatarProps> = ({ user, ...props }) => {
13
+ return (
14
+ <Avatar {...props}>
15
+ {user.image ? (
16
+ <AvatarImage alt="Picture" src={user.image} />
17
+ ) : (
18
+ <AvatarFallback>
19
+ <span className="sr-only">{user.name}</span>
20
+ <Icons.user className="h-4 w-4" />
21
+ </AvatarFallback>
22
+ )}
23
+ </Avatar>
24
+ )
25
+ }
@@ -0,0 +1,75 @@
1
+ import { createEnv } from '@t3-oss/env-nextjs'
2
+ import { z } from 'zod'
3
+
4
+ export const env = createEnv({
5
+ /**
6
+ * Specify your server-side environment variables schema here. This way you can ensure the app
7
+ * isn't built with invalid env vars.
8
+ */
9
+ server: {
10
+ NODE_ENV: z.enum(['development', 'test', 'production']),
11
+ DATABASE_URL: z.string().url(),
12
+ NEXTAUTH_SECRET:
13
+ process.env.NODE_ENV === 'production'
14
+ ? z.string().min(1)
15
+ : z.string().min(1).optional(),
16
+ NEXTAUTH_URL: z.preprocess(
17
+ // This makes Vercel deployments not fail if you don't set NEXTAUTH_URL
18
+ // Since NextAuth.js automatically uses the VERCEL_URL if present.
19
+ str => process.env.VERCEL_URL ?? str,
20
+ // VERCEL_URL doesn't include `https` so it cant be validated as a URL
21
+ process.env.VERCEL ? z.string().min(1) : z.string().url()
22
+ ),
23
+ EMAIL_SERVER_HOST: z.string().min(1),
24
+ EMAIL_SERVER_PORT: z.number(),
25
+ EMAIL_SERVER_USER: z.string().min(1),
26
+ EMAIL_SERVER_PASSWORD: z.string().min(1),
27
+ EMAIL_FROM: z.string().email(),
28
+ GOOGLE_ID: z.string().min(1),
29
+ GOOGLE_SECRET: z.string().min(1),
30
+ GITHUB_ID: z.string().min(1),
31
+ GITHUB_SECRET: z.string().min(1),
32
+ FIREBASE_PROJECT_ID: z.string().min(1),
33
+ FIREBASE_PRIVATE_KEY: z.string().min(1),
34
+ FIREBASE_CLIENT_EMAIL: z.string().min(1),
35
+ FIREBASE_STORAGE_BUCKET: z.string().min(1)
36
+ },
37
+
38
+ /**
39
+ * Specify your client-side environment variables schema here. This way you can ensure the app
40
+ * isn't built with invalid env vars. To expose them to the client, prefix them with
41
+ * `NEXT_PUBLIC_`.
42
+ */
43
+ client: {
44
+ // NEXT_PUBLIC_CLIENTVAR: z.string().min(1),
45
+ },
46
+
47
+ /**
48
+ * You can't destruct `process.env` as a regular object in the Next.js edge runtimes (e.g.
49
+ * middlewares) or client-side so we need to destruct manually.
50
+ */
51
+ runtimeEnv: {
52
+ NODE_ENV: process.env.NODE_ENV,
53
+ DATABASE_URL: process.env.DATABASE_URL,
54
+ NEXTAUTH_SECRET: process.env.NEXTAUTH_SECRET,
55
+ NEXTAUTH_URL: process.env.NEXTAUTH_URL,
56
+ EMAIL_SERVER_HOST: process.env.EMAIL_SERVER_HOST,
57
+ EMAIL_SERVER_PORT: parseInt(process.env.EMAIL_SERVER_PORT || ''),
58
+ EMAIL_SERVER_USER: process.env.EMAIL_SERVER_USER,
59
+ EMAIL_SERVER_PASSWORD: process.env.EMAIL_SERVER_PASSWORD,
60
+ EMAIL_FROM: process.env.EMAIL_FROM,
61
+ GOOGLE_ID: process.env.GOOGLE_ID,
62
+ GOOGLE_SECRET: process.env.GOOGLE_SECRET,
63
+ GITHUB_ID: process.env.GITHUB_ID,
64
+ GITHUB_SECRET: process.env.GITHUB_SECRET,
65
+ FIREBASE_PROJECT_ID: process.env.FIREBASE_PROJECT_ID,
66
+ FIREBASE_PRIVATE_KEY: process.env.FIREBASE_PRIVATE_KEY,
67
+ FIREBASE_CLIENT_EMAIL: process.env.FIREBASE_CLIENT_EMAIL,
68
+ FIREBASE_STORAGE_BUCKET: process.env.FIREBASE_STORAGE_BUCKET
69
+ },
70
+ /**
71
+ * Run `build` or `dev` with `SKIP_ENV_VALIDATION` to skip env validation.
72
+ * This is especially useful for Docker builds.
73
+ */
74
+ skipValidation: !!process.env.SKIP_ENV_VALIDATION
75
+ })
@@ -0,0 +1,17 @@
1
+ 'use client'
2
+
3
+ import { useEffect, useState } from 'react'
4
+
5
+ export function useDebounce<T>(value: T, delay?: number): T {
6
+ const [debouncedValue, setDebouncedValue] = useState<T>(value)
7
+
8
+ useEffect(() => {
9
+ const timer = setTimeout(() => setDebouncedValue(value), delay || 500)
10
+
11
+ return () => {
12
+ clearTimeout(timer)
13
+ }
14
+ }, [value, delay])
15
+
16
+ return debouncedValue
17
+ }
@@ -0,0 +1,12 @@
1
+ import { useLayoutEffect } from 'react'
2
+
3
+ // @see https://usehooks.com/useLockBodyScroll.
4
+ export function useLockBody() {
5
+ useLayoutEffect((): (() => void) => {
6
+ const originalStyle: string = window.getComputedStyle(
7
+ document.body
8
+ ).overflow
9
+ document.body.style.overflow = 'hidden'
10
+ return () => (document.body.style.overflow = originalStyle)
11
+ }, [])
12
+ }
@@ -0,0 +1,79 @@
1
+ import { PrismaAdapter } from '@next-auth/prisma-adapter'
2
+ import {
3
+ getServerSession,
4
+ type DefaultSession,
5
+ type NextAuthOptions
6
+ } from 'next-auth'
7
+ import EmailProvider from 'next-auth/providers/email'
8
+ import GitHubProvider from 'next-auth/providers/github'
9
+ import GoogleProvider from 'next-auth/providers/google'
10
+
11
+ import { env } from '@/env.mjs'
12
+ import { prisma } from '@/lib/db'
13
+
14
+ /**
15
+ * Module augmentation for `next-auth` types. Allows us to add custom properties to the `session`
16
+ * object and keep type safety.
17
+ *
18
+ * @see https://next-auth.js.org/getting-started/typescript#module-augmentation
19
+ */
20
+ declare module 'next-auth' {
21
+ interface Session extends DefaultSession {
22
+ user: {
23
+ id: string
24
+ } & DefaultSession['user']
25
+ }
26
+
27
+ interface User {}
28
+ }
29
+
30
+ /**
31
+ * Options for NextAuth.js used to configure adapters, providers, callbacks, etc.
32
+ *
33
+ * @see https://next-auth.js.org/configuration/options
34
+ */
35
+ export const authOptions: NextAuthOptions = {
36
+ pages: {
37
+ signIn: '/login'
38
+ },
39
+ callbacks: {
40
+ session({ session, user }) {
41
+ return {
42
+ ...session,
43
+ user: {
44
+ ...session.user,
45
+ id: user.id
46
+ }
47
+ }
48
+ }
49
+ },
50
+ adapter: PrismaAdapter(prisma),
51
+ providers: [
52
+ EmailProvider({
53
+ server: {
54
+ host: env.EMAIL_SERVER_HOST,
55
+ port: env.EMAIL_SERVER_PORT,
56
+ auth: {
57
+ user: env.EMAIL_SERVER_USER,
58
+ pass: env.EMAIL_SERVER_PASSWORD
59
+ }
60
+ },
61
+ from: env.EMAIL_FROM
62
+ }),
63
+ GoogleProvider({
64
+ clientId: env.GOOGLE_ID,
65
+ clientSecret: env.GOOGLE_SECRET
66
+ }),
67
+ GitHubProvider({
68
+ clientId: env.GITHUB_ID,
69
+ clientSecret: env.GITHUB_SECRET
70
+ })
71
+ ]
72
+ }
73
+
74
+ /**
75
+ * Wrapper for `getServerSession` so that you don't need to import the `authOptions` in every file.
76
+ *
77
+ * @see https://next-auth.js.org/configuration/nextjs
78
+ */
79
+ export const getAuthSession = () => getServerSession(authOptions)
@@ -0,0 +1,4 @@
1
+ import { clsx, type ClassValue } from 'clsx'
2
+ import { twMerge } from 'tailwind-merge'
3
+
4
+ export const cn = (...inputs: ClassValue[]) => twMerge(clsx(inputs))
@@ -0,0 +1,20 @@
1
+ import { PrismaClient } from '@prisma/client'
2
+
3
+ import { env } from '@/env.mjs'
4
+
5
+ const globalForPrisma = globalThis as unknown as {
6
+ prisma: PrismaClient | undefined
7
+ }
8
+
9
+ export const prisma =
10
+ globalForPrisma.prisma ||
11
+ new PrismaClient({
12
+ log:
13
+ env.NODE_ENV === 'development'
14
+ ? [
15
+ // 'info', 'query', 'error', 'warn'
16
+ ]
17
+ : ['error']
18
+ })
19
+
20
+ if (env.NODE_ENV !== 'production') globalForPrisma.prisma = prisma
@@ -0,0 +1,2 @@
1
+ export const delay = (ms: number) =>
2
+ new Promise(resolve => setTimeout(resolve, ms))
@@ -0,0 +1,11 @@
1
+ import dayjs from 'dayjs'
2
+ import relativeTime from 'dayjs/plugin/relativeTime'
3
+
4
+ dayjs.extend(relativeTime)
5
+
6
+ export const formatDate = (date: Date) => dayjs(date).format('DD/MM/YYYY')
7
+
8
+ export const formatDateTime = (date: Date) =>
9
+ dayjs(date).format('DD/MM/YYYY hh:mm:ss A')
10
+
11
+ export const timesAgo = (date: Date) => dayjs(date).fromNow()
@@ -0,0 +1,5 @@
1
+ export const generateLabel = (str: string) =>
2
+ str
3
+ .replaceAll('_', ' ')
4
+ .replaceAll(/([A-Z])/g, ' $1')
5
+ .trim()
@@ -0,0 +1,4 @@
1
+ export const siteConfig = {
2
+ name: 'Project Name',
3
+ description: 'Project Description'
4
+ }
@@ -0,0 +1,61 @@
1
+ .dark .ce-block--selected .ce-block__content,
2
+ .dark .ce-inline-toolbar,
3
+ .dark .codex-editor--narrow .ce-toolbox,
4
+ .dark .ce-conversion-toolbar,
5
+ .dark .ce-settings,
6
+ .dark .ce-settings__button,
7
+ .dark .ce-toolbar__settings-btn,
8
+ .dark .cdx-button,
9
+ .dark .ce-popover,
10
+ .dark .ce-toolbar__plus:hover {
11
+ background: theme('colors.popover.DEFAULT');
12
+ color: inherit;
13
+ border-color: theme('colors.border');
14
+ }
15
+
16
+ .dark .ce-inline-tool,
17
+ .dark .ce-conversion-toolbar__label,
18
+ .dark .ce-toolbox__button,
19
+ .dark .cdx-settings-button,
20
+ .dark .ce-toolbar__plus {
21
+ color: inherit;
22
+ }
23
+
24
+ .dark .ce-popover__item-icon,
25
+ .dark .ce-conversion-tool__icon {
26
+ background-color: theme('colors.muted.DEFAULT');
27
+ box-shadow: none;
28
+ }
29
+
30
+ .dark .cdx-search-field {
31
+ border-color: theme('colors.border');
32
+ background: theme('colors.input');
33
+ color: inherit;
34
+ }
35
+
36
+ .dark ::selection {
37
+ background: theme('colors.accent.DEFAULT');
38
+ }
39
+
40
+ .dark .cdx-settings-button:hover,
41
+ .dark .ce-settings__button:hover,
42
+ .dark .ce-toolbox__button--active,
43
+ .dark .ce-toolbox__button:hover,
44
+ .dark .cdx-button:hover,
45
+ .dark .ce-inline-toolbar__dropdown:hover,
46
+ .dark .ce-inline-tool:hover,
47
+ .dark .ce-popover__item:hover,
48
+ .dark .ce-conversion-tool:hover,
49
+ .dark .ce-toolbar__settings-btn:hover {
50
+ background-color: theme('colors.accent.DEFAULT');
51
+ color: theme('colors.accent.foreground');
52
+ }
53
+
54
+ .dark .cdx-notify--error {
55
+ background: theme('colors.destructive.DEFAULT') !important;
56
+ }
57
+
58
+ .dark .cdx-notify__cross::after,
59
+ .dark .cdx-notify__cross::before {
60
+ background: white;
61
+ }
@@ -0,0 +1,76 @@
1
+ @tailwind base;
2
+ @tailwind components;
3
+ @tailwind utilities;
4
+
5
+ @layer base {
6
+ :root {
7
+ --background: 0 0% 100%;
8
+ --foreground: 0 0% 3.9%;
9
+
10
+ --card: 0 0% 100%;
11
+ --card-foreground: 0 0% 3.9%;
12
+
13
+ --popover: 0 0% 100%;
14
+ --popover-foreground: 0 0% 3.9%;
15
+
16
+ --primary: 0 0% 9%;
17
+ --primary-foreground: 0 0% 98%;
18
+
19
+ --secondary: 0 0% 96.1%;
20
+ --secondary-foreground: 0 0% 9%;
21
+
22
+ --muted: 0 0% 96.1%;
23
+ --muted-foreground: 0 0% 45.1%;
24
+
25
+ --accent: 0 0% 96.1%;
26
+ --accent-foreground: 0 0% 9%;
27
+
28
+ --destructive: 0 84.2% 60.2%;
29
+ --destructive-foreground: 0 0% 98%;
30
+
31
+ --border: 0 0% 89.8%;
32
+ --input: 0 0% 89.8%;
33
+ --ring: 0 0% 3.9%;
34
+
35
+ --radius: 0.5rem;
36
+ }
37
+
38
+ .dark {
39
+ --background: 0 0% 3.9%;
40
+ --foreground: 0 0% 98%;
41
+
42
+ --card: 0 0% 3.9%;
43
+ --card-foreground: 0 0% 98%;
44
+
45
+ --popover: 0 0% 3.9%;
46
+ --popover-foreground: 0 0% 98%;
47
+
48
+ --primary: 0 0% 98%;
49
+ --primary-foreground: 0 0% 9%;
50
+
51
+ --secondary: 0 0% 14.9%;
52
+ --secondary-foreground: 0 0% 98%;
53
+
54
+ --muted: 0 0% 14.9%;
55
+ --muted-foreground: 0 0% 63.9%;
56
+
57
+ --accent: 0 0% 14.9%;
58
+ --accent-foreground: 0 0% 98%;
59
+
60
+ --destructive: 0 62.8% 30.6%;
61
+ --destructive-foreground: 0 0% 98%;
62
+
63
+ --border: 0 0% 14.9%;
64
+ --input: 0 0% 14.9%;
65
+ --ring: 0 0% 83.1%;
66
+ }
67
+ }
68
+
69
+ @layer base {
70
+ * {
71
+ @apply border-border;
72
+ }
73
+ body {
74
+ @apply bg-background text-foreground;
75
+ }
76
+ }
@@ -0,0 +1 @@
1
+ export type UnwrapPromise<T> = T extends Promise<infer U> ? U : T
@@ -0,0 +1,79 @@
1
+ import type { Config } from 'tailwindcss'
2
+
3
+ const tailwindConfig: Config = {
4
+ darkMode: ['class'],
5
+ content: ['./src/**/*.{js,ts,jsx,tsx,mdx}'],
6
+ theme: {
7
+ container: {
8
+ center: true,
9
+ padding: '2rem',
10
+ screens: {
11
+ '2xl': '1400px'
12
+ }
13
+ },
14
+ extend: {
15
+ backgroundImage: {
16
+ 'gradient-radial': 'radial-gradient(var(--tw-gradient-stops))',
17
+ 'gradient-conic':
18
+ 'conic-gradient(from 180deg at 50% 50%, var(--tw-gradient-stops))'
19
+ },
20
+ colors: {
21
+ border: 'hsl(var(--border))',
22
+ input: 'hsl(var(--input))',
23
+ ring: 'hsl(var(--ring))',
24
+ background: 'hsl(var(--background))',
25
+ foreground: 'hsl(var(--foreground))',
26
+ primary: {
27
+ DEFAULT: 'hsl(var(--primary))',
28
+ foreground: 'hsl(var(--primary-foreground))'
29
+ },
30
+ secondary: {
31
+ DEFAULT: 'hsl(var(--secondary))',
32
+ foreground: 'hsl(var(--secondary-foreground))'
33
+ },
34
+ destructive: {
35
+ DEFAULT: 'hsl(var(--destructive))',
36
+ foreground: 'hsl(var(--destructive-foreground))'
37
+ },
38
+ muted: {
39
+ DEFAULT: 'hsl(var(--muted))',
40
+ foreground: 'hsl(var(--muted-foreground))'
41
+ },
42
+ accent: {
43
+ DEFAULT: 'hsl(var(--accent))',
44
+ foreground: 'hsl(var(--accent-foreground))'
45
+ },
46
+ popover: {
47
+ DEFAULT: 'hsl(var(--popover))',
48
+ foreground: 'hsl(var(--popover-foreground))'
49
+ },
50
+ card: {
51
+ DEFAULT: 'hsl(var(--card))',
52
+ foreground: 'hsl(var(--card-foreground))'
53
+ }
54
+ },
55
+ borderRadius: {
56
+ lg: 'var(--radius)',
57
+ md: 'calc(var(--radius) - 2px)',
58
+ sm: 'calc(var(--radius) - 4px)'
59
+ },
60
+ keyframes: {
61
+ 'accordion-down': {
62
+ from: { height: '0' },
63
+ to: { height: 'var(--radix-accordion-content-height)' }
64
+ },
65
+ 'accordion-up': {
66
+ from: { height: 'var(--radix-accordion-content-height)' },
67
+ to: { height: '0' }
68
+ }
69
+ },
70
+ animation: {
71
+ 'accordion-down': 'accordion-down 0.2s ease-out',
72
+ 'accordion-up': 'accordion-up 0.2s ease-out'
73
+ }
74
+ }
75
+ },
76
+ plugins: [require('tailwindcss-animate'), require('@tailwindcss/typography')]
77
+ }
78
+
79
+ module.exports = tailwindConfig
@@ -0,0 +1,46 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2017",
4
+ "lib": ["DOM", "DOM.Iterable", "ESNext"],
5
+ "allowJs": true,
6
+ "checkJs": true,
7
+ "skipLibCheck": true,
8
+ "strict": true,
9
+ "noImplicitAny": true,
10
+ "strictNullChecks": true,
11
+ "strictFunctionTypes": true,
12
+ "noImplicitThis": true,
13
+ "noUncheckedIndexedAccess": true,
14
+ "noUnusedLocals": true,
15
+ "noUnusedParameters": true,
16
+ "noImplicitReturns": true,
17
+ "noFallthroughCasesInSwitch": true,
18
+ "forceConsistentCasingInFileNames": true,
19
+ "noEmit": true,
20
+ "esModuleInterop": true,
21
+ "module": "ESNext",
22
+ "moduleResolution": "Bundler",
23
+ "resolveJsonModule": true,
24
+ "isolatedModules": true,
25
+ "jsx": "preserve",
26
+ "incremental": true,
27
+ "plugins": [
28
+ {
29
+ "name": "next"
30
+ }
31
+ ],
32
+ "paths": {
33
+ "@/*": ["./src/*"]
34
+ }
35
+ },
36
+ "include": [
37
+ ".eslintrc.cjs",
38
+ "next-env.d.ts",
39
+ "**/*.ts",
40
+ "**/*.tsx",
41
+ "**/*.cjs",
42
+ "**/*.mjs",
43
+ ".next/types/**/*.ts"
44
+ ],
45
+ "exclude": ["node_modules"]
46
+ }
File without changes