create-ej-app 3.1.0 → 4.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.
- package/cli.js +5 -1
- package/cli.ts +40 -33
- package/package.json +4 -4
- package/template/base/.env.example +10 -9
- package/template/base/.eslintrc.cjs +17 -15
- package/template/base/components.json +3 -2
- package/template/base/drizzle.config.ts +11 -0
- package/template/base/next.config.mjs +1 -12
- package/template/base/package.json +63 -56
- package/template/base/postcss.config.mjs +8 -0
- package/template/base/prettier.config.mjs +11 -0
- package/template/base/public/vercel.svg +1 -0
- package/template/base/src/app/(app)/dashboard/layout.tsx +14 -0
- package/template/base/src/app/(app)/dashboard/page.tsx +0 -7
- package/template/base/src/app/(app)/layout.tsx +55 -20
- package/template/base/src/app/(app)/roles/[id]/actions.ts +59 -0
- package/template/base/src/app/(app)/roles/[id]/page.tsx +46 -0
- package/template/base/src/app/(app)/roles/[id]/render.tsx +264 -0
- package/template/base/src/app/(app)/roles/[id]/validation.ts +22 -0
- package/template/base/src/app/(app)/roles/actions.ts +33 -0
- package/template/base/src/app/(app)/roles/page.tsx +52 -0
- package/template/base/src/app/(app)/roles/render.tsx +80 -0
- package/template/base/src/app/(app)/settings/actions.ts +11 -12
- package/template/base/src/app/(app)/settings/layout.tsx +14 -0
- package/template/base/src/app/(app)/settings/page.tsx +1 -10
- package/template/base/src/app/(app)/settings/render.tsx +11 -17
- package/template/base/src/app/(app)/settings/validation.ts +5 -0
- package/template/base/src/app/(app)/tasks/[id]/actions.ts +69 -124
- package/template/base/src/app/(app)/tasks/[id]/page.tsx +37 -3
- package/template/base/src/app/(app)/tasks/[id]/render.tsx +162 -93
- package/template/base/src/app/(app)/tasks/[id]/validation.ts +18 -0
- package/template/base/src/app/(app)/tasks/actions.ts +34 -64
- package/template/base/src/app/(app)/tasks/page.tsx +15 -9
- package/template/base/src/app/(app)/tasks/render.tsx +28 -6
- package/template/base/src/app/(app)/tasks/statusEnum.ts +3 -0
- package/template/base/src/app/(app)/users/[id]/actions.ts +47 -62
- package/template/base/src/app/(app)/users/[id]/page.tsx +15 -8
- package/template/base/src/app/(app)/users/[id]/render.tsx +119 -34
- package/template/base/src/app/(app)/users/[id]/validation.ts +18 -0
- package/template/base/src/app/(app)/users/actions.ts +28 -49
- package/template/base/src/app/(app)/users/page.tsx +22 -9
- package/template/base/src/app/(app)/users/render.tsx +47 -3
- package/template/base/src/app/(auth)/layout.tsx +7 -0
- package/template/base/src/app/(auth)/login/page.tsx +2 -2
- package/template/base/src/app/(auth)/login/render.tsx +146 -0
- package/template/base/src/app/(marketing)/layout.tsx +1 -1
- package/template/base/src/app/(marketing)/page.tsx +8 -7
- package/template/base/src/app/favicon.ico +0 -0
- package/template/base/src/app/layout.tsx +14 -17
- package/template/base/src/components/app-nav-command.tsx +18 -0
- package/template/base/src/components/data-table/data-table-column-header.tsx +2 -2
- package/template/base/src/components/icons.tsx +23 -5
- package/template/base/src/components/ui/alert-dialog.tsx +3 -3
- package/template/base/src/components/ui/command.tsx +2 -2
- package/template/base/src/components/ui/dialog.tsx +2 -2
- package/template/base/src/components/ui/select.tsx +42 -3
- package/template/base/src/components/ui/sonner.tsx +31 -0
- package/template/base/src/components/ui/table.tsx +4 -1
- package/template/base/src/components/user-avatar.tsx +4 -2
- package/template/base/src/data-access/resource.ts +85 -0
- package/template/base/src/data-access/role-permission.ts +45 -0
- package/template/base/src/data-access/role.ts +105 -0
- package/template/base/src/data-access/task.ts +141 -0
- package/template/base/src/data-access/user.ts +141 -0
- package/template/base/src/db/index.ts +14 -0
- package/template/base/src/db/schema.ts +287 -0
- package/template/base/src/env.mjs +13 -30
- package/template/base/src/hooks/use-lock-body.tsx +2 -1
- package/template/base/src/lib/auth.ts +32 -22
- package/template/base/src/lib/currentUser.ts +8 -0
- package/template/base/src/lib/s3Client.ts +156 -0
- package/template/base/src/lib/safe-action.ts +19 -0
- package/template/base/src/lib/sortOrderEnum.ts +2 -0
- package/template/base/src/use-case/role-permission.ts +19 -0
- package/template/base/src/use-case/role.ts +110 -0
- package/template/base/src/use-case/task.ts +166 -0
- package/template/base/src/use-case/user.ts +121 -0
- package/template/base/tailwind.config.ts +9 -7
- package/template/base/tsconfig.json +3 -2
- package/template/prisma/.env.example +16 -0
- package/template/prisma/.eslintrc.cjs +24 -0
- package/template/prisma/components.json +17 -0
- package/template/prisma/next.config.mjs +15 -0
- package/template/prisma/package.json +80 -0
- package/template/{base → prisma}/prisma/schema.prisma +0 -1
- package/template/prisma/public/next.svg +1 -0
- package/template/prisma/src/app/(app)/dashboard/page.tsx +19 -0
- package/template/prisma/src/app/(app)/layout.tsx +90 -0
- package/template/prisma/src/app/(app)/settings/actions.ts +18 -0
- package/template/prisma/src/app/(app)/settings/loading.tsx +28 -0
- package/template/prisma/src/app/(app)/settings/page.tsx +28 -0
- package/template/prisma/src/app/(app)/settings/render.tsx +113 -0
- package/template/prisma/src/app/(app)/tasks/[id]/actions.ts +147 -0
- package/template/prisma/src/app/(app)/tasks/[id]/page.tsx +25 -0
- package/template/prisma/src/app/(app)/tasks/[id]/render.tsx +413 -0
- package/template/prisma/src/app/(app)/tasks/actions.ts +69 -0
- package/template/prisma/src/app/(app)/tasks/page.tsx +53 -0
- package/template/prisma/src/app/(app)/tasks/render.tsx +107 -0
- package/template/prisma/src/app/(app)/users/[id]/actions.ts +83 -0
- package/template/prisma/src/app/(app)/users/[id]/page.tsx +32 -0
- package/template/prisma/src/app/(app)/users/[id]/render.tsx +240 -0
- package/template/prisma/src/app/(app)/users/actions.ts +55 -0
- package/template/prisma/src/app/(app)/users/page.tsx +49 -0
- package/template/prisma/src/app/(app)/users/render.tsx +80 -0
- package/template/prisma/src/app/(auth)/layout.tsx +20 -0
- package/template/prisma/src/app/(auth)/login/page.tsx +49 -0
- package/template/prisma/src/app/(marketing)/layout.tsx +42 -0
- package/template/prisma/src/app/(marketing)/page.tsx +96 -0
- package/template/prisma/src/app/api/auth/[...nextauth]/route.ts +7 -0
- package/template/prisma/src/app/favicon.ico +0 -0
- package/template/prisma/src/app/layout.tsx +34 -0
- package/template/prisma/src/components/app-nav-command.tsx +160 -0
- package/template/prisma/src/components/dark-mode-toggle.tsx +43 -0
- package/template/prisma/src/components/data-table/data-table-column-header.tsx +91 -0
- package/template/prisma/src/components/data-table/data-table-faceted-filter.tsx +149 -0
- package/template/prisma/src/components/data-table/data-table-loading.tsx +77 -0
- package/template/prisma/src/components/data-table/data-table-pagination.tsx +94 -0
- package/template/prisma/src/components/data-table/data-table-toolbar.tsx +78 -0
- package/template/prisma/src/components/data-table/data-table-types.ts +17 -0
- package/template/prisma/src/components/data-table/data-table-view-options.tsx +59 -0
- package/template/prisma/src/components/data-table/data-table.tsx +301 -0
- package/template/prisma/src/components/data-table/simple-data-table.tsx +109 -0
- package/template/prisma/src/components/empty-placeholder.tsx +78 -0
- package/template/prisma/src/components/heading.tsx +17 -0
- package/template/prisma/src/components/icons.tsx +85 -0
- package/template/prisma/src/components/main-nav.tsx +64 -0
- package/template/prisma/src/components/shell.tsx +13 -0
- package/template/prisma/src/components/side-nav.tsx +51 -0
- package/template/prisma/src/components/site-footer.tsx +31 -0
- package/template/prisma/src/components/system-info.tsx +36 -0
- package/template/prisma/src/components/ui/alert-dialog.tsx +141 -0
- package/template/prisma/src/components/ui/avatar.tsx +50 -0
- package/template/prisma/src/components/ui/badge.tsx +36 -0
- package/template/prisma/src/components/ui/button.tsx +56 -0
- package/template/prisma/src/components/ui/card.tsx +79 -0
- package/template/prisma/src/components/ui/checkbox.tsx +30 -0
- package/template/prisma/src/components/ui/command.tsx +155 -0
- package/template/prisma/src/components/ui/dialog.tsx +122 -0
- package/template/prisma/src/components/ui/dropdown-menu.tsx +200 -0
- package/template/prisma/src/components/ui/form.tsx +176 -0
- package/template/prisma/src/components/ui/input.tsx +25 -0
- package/template/prisma/src/components/ui/label.tsx +26 -0
- package/template/prisma/src/components/ui/popover.tsx +31 -0
- package/template/prisma/src/components/ui/select.tsx +160 -0
- package/template/prisma/src/components/ui/separator.tsx +31 -0
- package/template/prisma/src/components/ui/skeleton.tsx +15 -0
- package/template/prisma/src/components/ui/table.tsx +117 -0
- package/template/prisma/src/components/user-account-nav.tsx +60 -0
- package/template/prisma/src/components/user-avatar.tsx +25 -0
- package/template/prisma/src/env.mjs +78 -0
- package/template/prisma/src/hooks/use-debounce.ts +17 -0
- package/template/prisma/src/hooks/use-lock-body.tsx +12 -0
- package/template/prisma/src/lib/auth.ts +80 -0
- package/template/prisma/src/lib/cn.ts +4 -0
- package/template/prisma/src/lib/delay.ts +2 -0
- package/template/prisma/src/lib/formatDate.ts +11 -0
- package/template/prisma/src/lib/generateLabel.ts +5 -0
- package/template/prisma/src/lib/siteConfig.ts +4 -0
- package/template/prisma/src/styles/globals.css +76 -0
- package/template/prisma/tailwind.config.ts +80 -0
- package/template/prisma/tsconfig.json +46 -0
- package/template/{advanced → prisma-advanced}/components.json +2 -1
- package/template/{advanced → prisma-advanced}/package.json +10 -10
- package/template/{advanced → prisma-advanced}/src/components/icons.tsx +2 -0
- package/template/{advanced → prisma-advanced}/src/components/ui/alert-dialog.tsx +3 -3
- package/template/{advanced → prisma-advanced}/src/components/ui/command.tsx +1 -1
- package/template/{advanced → prisma-advanced}/src/components/ui/dialog.tsx +2 -2
- package/template/{advanced → prisma-advanced}/src/components/ui/select.tsx +42 -3
- package/template/{advanced → prisma-advanced}/src/components/ui/table.tsx +4 -1
- package/template/{advanced → prisma-advanced}/src/env.mjs +4 -1
- package/template/{advanced → prisma-advanced}/src/lib/auth.ts +2 -5
- package/template/{advanced → prisma-advanced}/tailwind.config.ts +4 -3
- /package/template/{advanced/src/styles → base/src/app}/globals.css +0 -0
- /package/template/{advanced/src/hooks/use-debounce.ts → base/src/hooks/use-debounce.tsx} +0 -0
- /package/template/{base → prisma}/postcss.config.cjs +0 -0
- /package/template/{base → prisma}/prettier.config.ts +0 -0
- /package/template/{base → prisma}/src/app/(auth)/login/user-auth-form.tsx +0 -0
- /package/template/{base → prisma}/src/app/api/upload/route.ts +0 -0
- /package/template/{advanced → prisma}/src/components/mobile-nav.tsx +0 -0
- /package/template/{base → prisma}/src/components/theme-provider.tsx +0 -0
- /package/template/{base → prisma}/src/components/ui/textarea.tsx +0 -0
- /package/template/{base → prisma}/src/components/ui/toast.tsx +0 -0
- /package/template/{base → prisma}/src/components/ui/toaster.tsx +0 -0
- /package/template/{base → prisma}/src/components/ui/use-toast.ts +0 -0
- /package/template/{base → prisma}/src/lib/db.ts +0 -0
- /package/template/{base → prisma}/src/lib/storageClient.ts +0 -0
- /package/template/{base → prisma}/src/styles/editor.css +0 -0
- /package/template/{base → prisma}/src/types/UnwrapPromise.ts +0 -0
- /package/template/{advanced → prisma-advanced}/.env.example +0 -0
- /package/template/{advanced → prisma-advanced}/.eslintrc.cjs +0 -0
- /package/template/{advanced → prisma-advanced}/next.config.mjs +0 -0
- /package/template/{advanced → prisma-advanced}/postcss.config.cjs +0 -0
- /package/template/{advanced → prisma-advanced}/prettier.config.ts +0 -0
- /package/template/{advanced → prisma-advanced}/prisma/schema.prisma +0 -0
- /package/template/{advanced → prisma-advanced}/public/next.svg +0 -0
- /package/template/{advanced → prisma-advanced}/src/app/(app)/dashboard/page.tsx +0 -0
- /package/template/{advanced → prisma-advanced}/src/app/(app)/layout.tsx +0 -0
- /package/template/{advanced → prisma-advanced}/src/app/(app)/roles/[id]/actions.ts +0 -0
- /package/template/{advanced → prisma-advanced}/src/app/(app)/roles/[id]/page.tsx +0 -0
- /package/template/{advanced → prisma-advanced}/src/app/(app)/roles/[id]/render.tsx +0 -0
- /package/template/{advanced → prisma-advanced}/src/app/(app)/roles/actions.ts +0 -0
- /package/template/{advanced → prisma-advanced}/src/app/(app)/roles/page.tsx +0 -0
- /package/template/{advanced → prisma-advanced}/src/app/(app)/roles/render.tsx +0 -0
- /package/template/{advanced → prisma-advanced}/src/app/(app)/settings/actions.ts +0 -0
- /package/template/{advanced → prisma-advanced}/src/app/(app)/settings/loading.tsx +0 -0
- /package/template/{advanced → prisma-advanced}/src/app/(app)/settings/page.tsx +0 -0
- /package/template/{advanced → prisma-advanced}/src/app/(app)/settings/render.tsx +0 -0
- /package/template/{advanced → prisma-advanced}/src/app/(app)/tasks/[id]/actions.ts +0 -0
- /package/template/{advanced → prisma-advanced}/src/app/(app)/tasks/[id]/page.tsx +0 -0
- /package/template/{advanced → prisma-advanced}/src/app/(app)/tasks/[id]/render.tsx +0 -0
- /package/template/{advanced → prisma-advanced}/src/app/(app)/tasks/actions.ts +0 -0
- /package/template/{advanced → prisma-advanced}/src/app/(app)/tasks/page.tsx +0 -0
- /package/template/{advanced → prisma-advanced}/src/app/(app)/tasks/render.tsx +0 -0
- /package/template/{advanced → prisma-advanced}/src/app/(app)/users/[id]/actions.ts +0 -0
- /package/template/{advanced → prisma-advanced}/src/app/(app)/users/[id]/page.tsx +0 -0
- /package/template/{advanced → prisma-advanced}/src/app/(app)/users/[id]/render.tsx +0 -0
- /package/template/{advanced → prisma-advanced}/src/app/(app)/users/actions.ts +0 -0
- /package/template/{advanced → prisma-advanced}/src/app/(app)/users/page.tsx +0 -0
- /package/template/{advanced → prisma-advanced}/src/app/(app)/users/render.tsx +0 -0
- /package/template/{advanced → prisma-advanced}/src/app/(auth)/layout.tsx +0 -0
- /package/template/{advanced → prisma-advanced}/src/app/(auth)/login/page.tsx +0 -0
- /package/template/{advanced → prisma-advanced}/src/app/(auth)/login/user-auth-form.tsx +0 -0
- /package/template/{advanced → prisma-advanced}/src/app/(marketing)/layout.tsx +0 -0
- /package/template/{advanced → prisma-advanced}/src/app/(marketing)/page.tsx +0 -0
- /package/template/{advanced → prisma-advanced}/src/app/api/auth/[...nextauth]/route.ts +0 -0
- /package/template/{advanced → prisma-advanced}/src/app/api/upload/route.ts +0 -0
- /package/template/{advanced → prisma-advanced}/src/app/favicon.ico +0 -0
- /package/template/{advanced → prisma-advanced}/src/app/layout.tsx +0 -0
- /package/template/{advanced → prisma-advanced}/src/components/app-nav-command.tsx +0 -0
- /package/template/{advanced → prisma-advanced}/src/components/dark-mode-toggle.tsx +0 -0
- /package/template/{advanced → prisma-advanced}/src/components/data-table/data-table-column-header.tsx +0 -0
- /package/template/{advanced → prisma-advanced}/src/components/data-table/data-table-faceted-filter.tsx +0 -0
- /package/template/{advanced → prisma-advanced}/src/components/data-table/data-table-loading.tsx +0 -0
- /package/template/{advanced → prisma-advanced}/src/components/data-table/data-table-pagination.tsx +0 -0
- /package/template/{advanced → prisma-advanced}/src/components/data-table/data-table-toolbar.tsx +0 -0
- /package/template/{advanced → prisma-advanced}/src/components/data-table/data-table-types.ts +0 -0
- /package/template/{advanced → prisma-advanced}/src/components/data-table/data-table-view-options.tsx +0 -0
- /package/template/{advanced → prisma-advanced}/src/components/data-table/data-table.tsx +0 -0
- /package/template/{advanced → prisma-advanced}/src/components/data-table/simple-data-table.tsx +0 -0
- /package/template/{advanced → prisma-advanced}/src/components/empty-placeholder.tsx +0 -0
- /package/template/{advanced → prisma-advanced}/src/components/heading.tsx +0 -0
- /package/template/{advanced → prisma-advanced}/src/components/main-nav.tsx +0 -0
- /package/template/{advanced → prisma-advanced}/src/components/shell.tsx +0 -0
- /package/template/{advanced → prisma-advanced}/src/components/side-nav.tsx +0 -0
- /package/template/{advanced → prisma-advanced}/src/components/site-footer.tsx +0 -0
- /package/template/{advanced → prisma-advanced}/src/components/system-info.tsx +0 -0
- /package/template/{advanced → prisma-advanced}/src/components/theme-provider.tsx +0 -0
- /package/template/{advanced → prisma-advanced}/src/components/ui/avatar.tsx +0 -0
- /package/template/{advanced → prisma-advanced}/src/components/ui/badge.tsx +0 -0
- /package/template/{advanced → prisma-advanced}/src/components/ui/button.tsx +0 -0
- /package/template/{advanced → prisma-advanced}/src/components/ui/card.tsx +0 -0
- /package/template/{advanced → prisma-advanced}/src/components/ui/checkbox.tsx +0 -0
- /package/template/{advanced → prisma-advanced}/src/components/ui/dropdown-menu.tsx +0 -0
- /package/template/{advanced → prisma-advanced}/src/components/ui/form.tsx +0 -0
- /package/template/{advanced → prisma-advanced}/src/components/ui/input.tsx +0 -0
- /package/template/{advanced → prisma-advanced}/src/components/ui/label.tsx +0 -0
- /package/template/{advanced → prisma-advanced}/src/components/ui/popover.tsx +0 -0
- /package/template/{advanced → prisma-advanced}/src/components/ui/separator.tsx +0 -0
- /package/template/{advanced → prisma-advanced}/src/components/ui/skeleton.tsx +0 -0
- /package/template/{advanced → prisma-advanced}/src/components/ui/textarea.tsx +0 -0
- /package/template/{advanced → prisma-advanced}/src/components/ui/toast.tsx +0 -0
- /package/template/{advanced → prisma-advanced}/src/components/ui/toaster.tsx +0 -0
- /package/template/{advanced → prisma-advanced}/src/components/ui/use-toast.ts +0 -0
- /package/template/{advanced → prisma-advanced}/src/components/user-account-nav.tsx +0 -0
- /package/template/{advanced → prisma-advanced}/src/components/user-avatar.tsx +0 -0
- /package/template/{base → prisma-advanced}/src/hooks/use-debounce.ts +0 -0
- /package/template/{advanced → prisma-advanced}/src/hooks/use-lock-body.tsx +0 -0
- /package/template/{advanced → prisma-advanced}/src/lib/cn.ts +0 -0
- /package/template/{advanced → prisma-advanced}/src/lib/db.ts +0 -0
- /package/template/{advanced → prisma-advanced}/src/lib/delay.ts +0 -0
- /package/template/{advanced → prisma-advanced}/src/lib/formatDate.ts +0 -0
- /package/template/{advanced → prisma-advanced}/src/lib/generateLabel.ts +0 -0
- /package/template/{advanced → prisma-advanced}/src/lib/siteConfig.ts +0 -0
- /package/template/{advanced → prisma-advanced}/src/lib/storageClient.ts +0 -0
- /package/template/{advanced → prisma-advanced}/src/styles/editor.css +0 -0
- /package/template/{base → prisma-advanced}/src/styles/globals.css +0 -0
- /package/template/{advanced → prisma-advanced}/src/types/UnwrapPromise.ts +0 -0
- /package/template/{advanced → prisma-advanced}/tsconfig.json +0 -0
|
@@ -0,0 +1,78 @@
|
|
|
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
|
+
|
|
76
|
+
// This makes empty strings be treated as undefined
|
|
77
|
+
emptyStringAsUndefined: true
|
|
78
|
+
})
|
|
@@ -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,80 @@
|
|
|
1
|
+
import { PrismaAdapter } from '@next-auth/prisma-adapter'
|
|
2
|
+
import { User as PrismaUser } from '@prisma/client'
|
|
3
|
+
import {
|
|
4
|
+
getServerSession,
|
|
5
|
+
type DefaultSession,
|
|
6
|
+
type NextAuthOptions
|
|
7
|
+
} from 'next-auth'
|
|
8
|
+
import EmailProvider from 'next-auth/providers/email'
|
|
9
|
+
import GitHubProvider from 'next-auth/providers/github'
|
|
10
|
+
import GoogleProvider from 'next-auth/providers/google'
|
|
11
|
+
|
|
12
|
+
import { env } from '@/env.mjs'
|
|
13
|
+
import { prisma } from '@/lib/db'
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Module augmentation for `next-auth` types. Allows us to add custom properties to the `session`
|
|
17
|
+
* object and keep type safety.
|
|
18
|
+
*
|
|
19
|
+
* @see https://next-auth.js.org/getting-started/typescript#module-augmentation
|
|
20
|
+
*/
|
|
21
|
+
declare module 'next-auth' {
|
|
22
|
+
interface Session extends DefaultSession {
|
|
23
|
+
user: {
|
|
24
|
+
id: string
|
|
25
|
+
} & DefaultSession['user']
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
interface User extends PrismaUser {}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Options for NextAuth.js used to configure adapters, providers, callbacks, etc.
|
|
33
|
+
*
|
|
34
|
+
* @see https://next-auth.js.org/configuration/options
|
|
35
|
+
*/
|
|
36
|
+
export const authOptions: NextAuthOptions = {
|
|
37
|
+
pages: {
|
|
38
|
+
signIn: '/login'
|
|
39
|
+
},
|
|
40
|
+
callbacks: {
|
|
41
|
+
session({ session, user }) {
|
|
42
|
+
return {
|
|
43
|
+
...session,
|
|
44
|
+
user: {
|
|
45
|
+
...session.user,
|
|
46
|
+
id: user.id
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
adapter: PrismaAdapter(prisma),
|
|
52
|
+
providers: [
|
|
53
|
+
EmailProvider({
|
|
54
|
+
server: {
|
|
55
|
+
host: env.EMAIL_SERVER_HOST,
|
|
56
|
+
port: env.EMAIL_SERVER_PORT,
|
|
57
|
+
auth: {
|
|
58
|
+
user: env.EMAIL_SERVER_USER,
|
|
59
|
+
pass: env.EMAIL_SERVER_PASSWORD
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
from: env.EMAIL_FROM
|
|
63
|
+
}),
|
|
64
|
+
GoogleProvider({
|
|
65
|
+
clientId: env.GOOGLE_ID,
|
|
66
|
+
clientSecret: env.GOOGLE_SECRET
|
|
67
|
+
}),
|
|
68
|
+
GitHubProvider({
|
|
69
|
+
clientId: env.GITHUB_ID,
|
|
70
|
+
clientSecret: env.GITHUB_SECRET
|
|
71
|
+
})
|
|
72
|
+
]
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Wrapper for `getServerSession` so that you don't need to import the `authOptions` in every file.
|
|
77
|
+
*
|
|
78
|
+
* @see https://next-auth.js.org/configuration/nextjs
|
|
79
|
+
*/
|
|
80
|
+
export const getAuthSession = () => getServerSession(authOptions)
|
|
@@ -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,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,80 @@
|
|
|
1
|
+
import type { Config } from 'tailwindcss'
|
|
2
|
+
|
|
3
|
+
const config = {
|
|
4
|
+
darkMode: ['class'],
|
|
5
|
+
content: ['./src/**/*.{js,ts,jsx,tsx,mdx}'],
|
|
6
|
+
prefix: '',
|
|
7
|
+
theme: {
|
|
8
|
+
container: {
|
|
9
|
+
center: true,
|
|
10
|
+
padding: '2rem',
|
|
11
|
+
screens: {
|
|
12
|
+
'2xl': '1400px'
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
extend: {
|
|
16
|
+
backgroundImage: {
|
|
17
|
+
'gradient-radial': 'radial-gradient(var(--tw-gradient-stops))',
|
|
18
|
+
'gradient-conic':
|
|
19
|
+
'conic-gradient(from 180deg at 50% 50%, var(--tw-gradient-stops))'
|
|
20
|
+
},
|
|
21
|
+
colors: {
|
|
22
|
+
border: 'hsl(var(--border))',
|
|
23
|
+
input: 'hsl(var(--input))',
|
|
24
|
+
ring: 'hsl(var(--ring))',
|
|
25
|
+
background: 'hsl(var(--background))',
|
|
26
|
+
foreground: 'hsl(var(--foreground))',
|
|
27
|
+
primary: {
|
|
28
|
+
DEFAULT: 'hsl(var(--primary))',
|
|
29
|
+
foreground: 'hsl(var(--primary-foreground))'
|
|
30
|
+
},
|
|
31
|
+
secondary: {
|
|
32
|
+
DEFAULT: 'hsl(var(--secondary))',
|
|
33
|
+
foreground: 'hsl(var(--secondary-foreground))'
|
|
34
|
+
},
|
|
35
|
+
destructive: {
|
|
36
|
+
DEFAULT: 'hsl(var(--destructive))',
|
|
37
|
+
foreground: 'hsl(var(--destructive-foreground))'
|
|
38
|
+
},
|
|
39
|
+
muted: {
|
|
40
|
+
DEFAULT: 'hsl(var(--muted))',
|
|
41
|
+
foreground: 'hsl(var(--muted-foreground))'
|
|
42
|
+
},
|
|
43
|
+
accent: {
|
|
44
|
+
DEFAULT: 'hsl(var(--accent))',
|
|
45
|
+
foreground: 'hsl(var(--accent-foreground))'
|
|
46
|
+
},
|
|
47
|
+
popover: {
|
|
48
|
+
DEFAULT: 'hsl(var(--popover))',
|
|
49
|
+
foreground: 'hsl(var(--popover-foreground))'
|
|
50
|
+
},
|
|
51
|
+
card: {
|
|
52
|
+
DEFAULT: 'hsl(var(--card))',
|
|
53
|
+
foreground: 'hsl(var(--card-foreground))'
|
|
54
|
+
}
|
|
55
|
+
},
|
|
56
|
+
borderRadius: {
|
|
57
|
+
lg: 'var(--radius)',
|
|
58
|
+
md: 'calc(var(--radius) - 2px)',
|
|
59
|
+
sm: 'calc(var(--radius) - 4px)'
|
|
60
|
+
},
|
|
61
|
+
keyframes: {
|
|
62
|
+
'accordion-down': {
|
|
63
|
+
from: { height: '0' },
|
|
64
|
+
to: { height: 'var(--radix-accordion-content-height)' }
|
|
65
|
+
},
|
|
66
|
+
'accordion-up': {
|
|
67
|
+
from: { height: 'var(--radix-accordion-content-height)' },
|
|
68
|
+
to: { height: '0' }
|
|
69
|
+
}
|
|
70
|
+
},
|
|
71
|
+
animation: {
|
|
72
|
+
'accordion-down': 'accordion-down 0.2s ease-out',
|
|
73
|
+
'accordion-up': 'accordion-up 0.2s ease-out'
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
},
|
|
77
|
+
plugins: [require('tailwindcss-animate'), require('@tailwindcss/typography')]
|
|
78
|
+
} satisfies Config
|
|
79
|
+
|
|
80
|
+
export default config
|
|
@@ -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
|
+
}
|
|
@@ -9,9 +9,9 @@
|
|
|
9
9
|
"dev": "next dev",
|
|
10
10
|
"build": "next build",
|
|
11
11
|
"start": "next start",
|
|
12
|
-
"
|
|
13
|
-
"
|
|
14
|
-
"
|
|
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.
|
|
26
|
-
"@hookform/resolvers": "^3.3.
|
|
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.
|
|
47
|
+
"@types/react": "^18.2.46",
|
|
48
48
|
"@types/react-dom": "^18.2.18",
|
|
49
|
-
"@typescript-eslint/eslint-plugin": "^6.
|
|
50
|
-
"@typescript-eslint/parser": "^6.
|
|
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.
|
|
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.
|
|
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,
|
|
18
|
+
>(({ className, ...props }, ref) => (
|
|
19
19
|
<AlertDialogPrimitive.Overlay
|
|
20
20
|
className={cn(
|
|
21
|
-
'fixed inset-0 z-50 bg-
|
|
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
|
|
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}
|
|
@@ -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-
|
|
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
|
|
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(
|
|
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
|
))
|