create-apppaaaul 2.0.15 → 2.0.17

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 (47) hide show
  1. package/dist/index.js +2 -4
  2. package/dist/index.js.map +1 -1
  3. package/dist/templates/nextjs-ts-clean/project/%%.gitignore +43 -0
  4. package/dist/templates/nextjs-ts-clean/project/eslint.config.mjs +137 -114
  5. package/dist/templates/nextjs-ts-clean/project/package.json +15 -15
  6. package/dist/templates/nextjs-ts-clean/project/src/scripts/dev-rebase.js +12 -2
  7. package/dist/templates/nextjs-ts-landing-prisma/project/%%.gitignore +46 -0
  8. package/dist/templates/nextjs-ts-landing-prisma/project/.env.test +26 -0
  9. package/dist/templates/nextjs-ts-landing-prisma/project/eslint.config.mjs +137 -114
  10. package/dist/templates/nextjs-ts-landing-prisma/project/package.json +34 -26
  11. package/dist/templates/nextjs-ts-landing-prisma/project/prisma/schema.prisma +74 -14
  12. package/dist/templates/nextjs-ts-landing-prisma/project/src/app/api/auth/[...all]/route.ts +5 -0
  13. package/dist/templates/nextjs-ts-landing-prisma/project/src/app/not-found.tsx +118 -0
  14. package/dist/templates/nextjs-ts-landing-prisma/project/src/lib/auth-client.ts +9 -0
  15. package/dist/templates/nextjs-ts-landing-prisma/project/src/lib/auth-utils.ts +197 -0
  16. package/dist/templates/nextjs-ts-landing-prisma/project/src/lib/auth.ts +49 -0
  17. package/dist/templates/nextjs-ts-landing-prisma/project/src/lib/cloudflare-r2.ts +124 -0
  18. package/dist/templates/nextjs-ts-landing-prisma/project/src/lib/db.ts +24 -5
  19. package/dist/templates/nextjs-ts-landing-prisma/project/src/lib/env.ts +44 -0
  20. package/dist/templates/nextjs-ts-landing-prisma/project/src/middleware.ts +105 -0
  21. package/dist/templates/nextjs-ts-landing-prisma/project/src/scripts/db-seed.ts +16 -0
  22. package/dist/templates/nextjs-ts-landing-prisma/project/src/scripts/dev-rebase.js +12 -2
  23. package/package.json +1 -1
  24. package/dist/templates/nextjs-ts-landing-drizzle/project/README.md +0 -15
  25. package/dist/templates/nextjs-ts-landing-drizzle/project/components.json +0 -21
  26. package/dist/templates/nextjs-ts-landing-drizzle/project/drizzle.config.ts +0 -11
  27. package/dist/templates/nextjs-ts-landing-drizzle/project/eslint.config.mjs +0 -183
  28. package/dist/templates/nextjs-ts-landing-drizzle/project/next.config.mjs +0 -10
  29. package/dist/templates/nextjs-ts-landing-drizzle/project/package.json +0 -61
  30. package/dist/templates/nextjs-ts-landing-drizzle/project/postcss.config.js +0 -3
  31. package/dist/templates/nextjs-ts-landing-drizzle/project/public/next.svg +0 -1
  32. package/dist/templates/nextjs-ts-landing-drizzle/project/public/vercel.svg +0 -1
  33. package/dist/templates/nextjs-ts-landing-drizzle/project/src/app/api/auth/[...nextauth]/route.ts +0 -3
  34. package/dist/templates/nextjs-ts-landing-drizzle/project/src/app/favicon.ico +0 -0
  35. package/dist/templates/nextjs-ts-landing-drizzle/project/src/app/globals.css +0 -161
  36. package/dist/templates/nextjs-ts-landing-drizzle/project/src/app/layout.tsx +0 -25
  37. package/dist/templates/nextjs-ts-landing-drizzle/project/src/app/page.tsx +0 -5
  38. package/dist/templates/nextjs-ts-landing-drizzle/project/src/auth.ts +0 -79
  39. package/dist/templates/nextjs-ts-landing-drizzle/project/src/components/ui/button.tsx +0 -49
  40. package/dist/templates/nextjs-ts-landing-drizzle/project/src/db/index.ts +0 -25
  41. package/dist/templates/nextjs-ts-landing-drizzle/project/src/db/schema.ts +0 -93
  42. package/dist/templates/nextjs-ts-landing-drizzle/project/src/lib/utils.ts +0 -6
  43. package/dist/templates/nextjs-ts-landing-drizzle/project/src/scripts/dev-rebase.js +0 -32
  44. package/dist/templates/nextjs-ts-landing-drizzle/project/tailwind.config.ts +0 -80
  45. package/dist/templates/nextjs-ts-landing-drizzle/project/tsconfig.json +0 -27
  46. package/dist/templates/nextjs-ts-landing-prisma/project/src/app/api/auth/[...nextauth]/route.ts +0 -3
  47. package/dist/templates/nextjs-ts-landing-prisma/project/src/auth.ts +0 -31
@@ -1,67 +1,90 @@
1
- import globals from "globals";
1
+ import { FlatCompat } from "@eslint/eslintrc";
2
+ import { defineConfig } from "eslint/config";
2
3
  import tseslint from "typescript-eslint";
3
- import eslintPluginReact from "eslint-plugin-react";
4
- import eslintPluginReactHooks from "eslint-plugin-react-hooks";
5
- import {fixupPluginRules} from "@eslint/compat";
6
- import eslintPluginPrettier from "eslint-plugin-prettier/recommended";
4
+ import eslintJs from "@eslint/js";
5
+ import eslintReact from "@eslint-react/eslint-plugin";
6
+ import eslintPluginPrettierRecommended from "eslint-plugin-prettier/recommended";
7
7
  import eslintPluginImport from "eslint-plugin-import";
8
8
  import eslintPluginReactCompiler from "eslint-plugin-react-compiler";
9
- import eslintPluginNext from "@next/eslint-plugin-next";
10
9
  import eslintPluginJsxA11y from "eslint-plugin-jsx-a11y";
10
+ import eslintPluginReact from "eslint-plugin-react";
11
+ import eslintPluginStylistic from "@stylistic/eslint-plugin";
11
12
 
12
- export default [
13
- // Ignores configuration
13
+ const compat = new FlatCompat({
14
+ baseDirectory: import.meta.dirname,
15
+ });
16
+
17
+ const languageLintingConfig = tseslint.config(
14
18
  {
15
- ignores: ["node_modules", ".next", "out", "coverage", ".idea"],
19
+ files: ["**/*.{ts,tsx,js,mjs,cjs}"],
20
+ languageOptions: {
21
+ parser: tseslint.parser,
22
+ parserOptions: {
23
+ projectService: {
24
+ allowDefaultProject: ["*.js", "*.mjs", "*.cjs"],
25
+ },
26
+ tsconfigRootDir: import.meta.dirname,
27
+ },
28
+ },
16
29
  },
17
- // General configuration
30
+ eslintJs.configs.recommended,
31
+ tseslint.configs.strictTypeChecked,
32
+ tseslint.configs.stylisticTypeChecked,
33
+ eslintPluginStylistic.configs.recommended,
18
34
  {
19
35
  rules: {
20
- "padding-line-between-statements": [
36
+ "no-console": ["warn", { allow: ["error"] }],
37
+ "@stylistic/padding-line-between-statements": [
21
38
  "warn",
22
- {blankLine: "always", prev: "*", next: ["return", "export"]},
23
- {blankLine: "always", prev: ["const", "let", "var"], next: "*"},
24
- {blankLine: "any", prev: ["const", "let", "var"], next: ["const", "let", "var"]},
39
+ { blankLine: "always", prev: "*", next: ["return", "export"] },
40
+ { blankLine: "always", prev: ["const", "let", "var"], next: "*" },
41
+ {
42
+ blankLine: "any",
43
+ prev: ["const", "let", "var"],
44
+ next: ["const", "let", "var"],
45
+ },
25
46
  ],
26
- "no-console": ["warn", {allow: ["error"]}],
47
+ "@typescript-eslint/no-unused-vars": [
48
+ "warn",
49
+ {
50
+ args: "after-used",
51
+ ignoreRestSiblings: false,
52
+ argsIgnorePattern: "^_.*?$",
53
+ caughtErrorsIgnorePattern: "^_.*?$",
54
+ },
55
+ ],
56
+ "@typescript-eslint/no-unsafe-member-access": "off",
57
+ "@typescript-eslint/no-confusing-void-expression": "off",
58
+ "@typescript-eslint/ban-ts-comment": "off",
59
+ "@typescript-eslint/no-explicit-any": "off",
60
+ "@typescript-eslint/no-inferrable-types": "off",
61
+ // Optionals
62
+ // "@typescript-eslint/no-floating-promises": "off",
63
+ // "@typescript-eslint/no-non-null-assertion": "off",
27
64
  },
28
65
  },
29
- // React configuration
66
+ );
67
+
68
+ const reactLintingConfig = defineConfig([
30
69
  {
31
- plugins: {
32
- react: fixupPluginRules(eslintPluginReact),
33
- "react-hooks": fixupPluginRules(eslintPluginReactHooks),
34
- "react-compiler": fixupPluginRules(eslintPluginReactCompiler),
35
- "jsx-a11y": fixupPluginRules(eslintPluginJsxA11y),
36
- },
37
- languageOptions: {
38
- parserOptions: {
39
- ecmaFeatures: {
40
- jsx: true,
41
- },
42
- },
43
- globals: {
44
- ...globals.browser,
45
- ...globals.serviceworker,
46
- },
47
- },
70
+ files: ["**/*.{tsx,jsx}"],
48
71
  settings: {
49
72
  react: {
50
73
  version: "detect",
51
74
  },
52
75
  },
76
+ },
77
+ eslintPluginReact.configs.flat.recommended,
78
+ eslintPluginReact.configs.flat["jsx-runtime"],
79
+ eslintReact.configs["recommended-type-checked"],
80
+ eslintPluginReactCompiler.configs.recommended,
81
+ {
53
82
  rules: {
54
- ...eslintPluginReact.configs.recommended.rules,
55
- ...eslintPluginJsxA11y.configs.recommended.rules,
56
- ...eslintPluginReactHooks.configs.recommended.rules,
57
- "react/jsx-boolean-value": ["error", "never"],
58
- "react/jsx-curly-brace-presence": ["error", {props: "never", children: "never"}],
59
- "react/jsx-no-useless-fragment": "error",
60
- "react/prop-types": "off",
61
- "react/jsx-uses-react": "off",
83
+ "@eslint-react/no-useless-fragment": "error",
84
+ "@eslint-react/no-missing-key": "warn",
62
85
  "react/no-array-index-key": "off",
63
- "react/react-in-jsx-scope": "off",
64
86
  "react/self-closing-comp": "warn",
87
+ "react/jsx-curly-brace-presence": ["error", { props: "never", children: "never" }],
65
88
  "react/jsx-sort-props": [
66
89
  "warn",
67
90
  {
@@ -71,73 +94,56 @@ export default [
71
94
  reservedFirst: true,
72
95
  },
73
96
  ],
74
- "react-compiler/react-compiler": "error",
75
- "react/jsx-no-leaked-render": "off",
76
- "jsx-a11y/no-static-element-interactions": "off",
97
+ },
98
+ },
99
+ ]);
100
+
101
+ const reactA11yLintingConfig = defineConfig([
102
+ {
103
+ files: ["**/*.{tsx,jsx}"],
104
+ },
105
+ eslintPluginJsxA11y.flatConfigs.recommended,
106
+ {
107
+ rules: {
77
108
  "jsx-a11y/click-events-have-key-events": "off",
78
- "jsx-a11y/html-has-lang": "off",
79
109
  },
80
110
  },
81
- // TypeScript configuration
82
- ...[
83
- ...tseslint.configs.recommended,
84
- {
85
- rules: {
86
- "@typescript-eslint/ban-ts-comment": "off",
87
- "@typescript-eslint/no-empty-object-type": "error",
88
- "@typescript-eslint/no-unsafe-function-type": "error",
89
- "@typescript-eslint/no-wrapper-object-types": "error",
90
- "@typescript-eslint/no-empty-function": "off",
91
- "@typescript-eslint/no-explicit-any": "off",
92
- "@typescript-eslint/no-inferrable-types": "off",
93
- "@typescript-eslint/no-namespace": "off",
94
- "@typescript-eslint/no-non-null-assertion": "off",
95
- "@typescript-eslint/no-shadow": "off",
96
- "@typescript-eslint/explicit-function-return-type": "off",
97
- "@typescript-eslint/require-await": "off",
98
- "@typescript-eslint/no-floating-promises": "off",
99
- "@typescript-eslint/no-confusing-void-expression": "off",
100
- "@typescript-eslint/no-unused-vars": [
101
- "warn",
102
- {
103
- args: "after-used",
104
- ignoreRestSiblings: false,
105
- argsIgnorePattern: "^_.*?$",
106
- caughtErrorsIgnorePattern: "^_.*?$",
107
- },
108
- ],
109
- },
111
+ ]);
112
+
113
+ const nextLintingConfig = defineConfig([
114
+ {
115
+ files: ["**/*.{tsx,jsx}"],
116
+ },
117
+ compat.extends("plugin:@next/next/recommended"),
118
+ {
119
+ rules: {
120
+ "@next/next/no-img-element": "off",
110
121
  },
111
- ],
112
- // Prettier configuration
113
- ...[
114
- eslintPluginPrettier,
115
- {
116
- rules: {
117
- "prettier/prettier": [
118
- "warn",
119
- {
120
- printWidth: 100,
121
- trailingComma: "all",
122
- tabWidth: 2,
123
- semi: true,
124
- singleQuote: false,
125
- bracketSpacing: true,
126
- arrowParens: "always",
127
- endOfLine: "auto",
128
- plugins: ["prettier-plugin-tailwindcss"],
129
- },
130
- ],
122
+ },
123
+ ]);
124
+
125
+ const importLintingConfig = defineConfig([
126
+ {
127
+ files: ["**/*.{ts,tsx,js,mjs,cjs}"],
128
+ },
129
+ {
130
+ settings: {
131
+ "import/resolver": {
132
+ typescript: true,
133
+ node: true,
131
134
  },
132
135
  },
133
- ],
134
- // Import configuration
136
+ },
137
+ eslintPluginImport.flatConfigs.recommended,
138
+ eslintPluginImport.flatConfigs.typescript,
135
139
  {
136
- plugins: {
137
- import: fixupPluginRules(eslintPluginImport),
138
- },
139
140
  rules: {
140
141
  "import/no-default-export": "off",
142
+ "import/no-named-as-default-member": "off",
143
+ "import/named": "off",
144
+ "import/namespace": "off",
145
+ "import/default": "off",
146
+ "import/no-unresolved": "off",
141
147
  "import/order": [
142
148
  "warn",
143
149
  {
@@ -163,21 +169,38 @@ export default [
163
169
  ],
164
170
  },
165
171
  },
166
- // Next configuration
172
+ ]);
173
+
174
+ const prettierLintingConfig = defineConfig([
175
+ {
176
+ files: ["**/*.{ts,tsx,js,mjs,cjs}"],
177
+ },
178
+ eslintPluginPrettierRecommended,
167
179
  {
168
- plugins: {
169
- "@next/next": fixupPluginRules(eslintPluginNext),
170
- },
171
- languageOptions: {
172
- globals: {
173
- ...globals.node,
174
- ...globals.browser,
175
- },
176
- },
177
180
  rules: {
178
- ...eslintPluginNext.configs.recommended.rules,
179
- "@next/next/no-img-element": "off",
180
- "@next/next/no-html-link-for-pages": "off",
181
+ "prettier/prettier": [
182
+ "warn",
183
+ {
184
+ printWidth: 100,
185
+ trailingComma: "all",
186
+ tabWidth: 2,
187
+ semi: true,
188
+ singleQuote: false,
189
+ bracketSpacing: true,
190
+ arrowParens: "always",
191
+ endOfLine: "auto",
192
+ plugins: ["prettier-plugin-tailwindcss"],
193
+ },
194
+ ],
181
195
  },
182
196
  },
183
- ];
197
+ ]);
198
+
199
+ export default defineConfig([
200
+ languageLintingConfig,
201
+ reactLintingConfig,
202
+ reactA11yLintingConfig,
203
+ nextLintingConfig,
204
+ importLintingConfig,
205
+ prettierLintingConfig,
206
+ ]);
@@ -6,56 +6,64 @@
6
6
  "dev": "next dev --turbopack",
7
7
  "build": "next build",
8
8
  "start": "next start",
9
+ "postinstall": "npx prisma generate",
9
10
  "lint": "next lint",
10
11
  "db:push": "npx prisma generate &&npx prisma db push",
11
- "prod": "pnpm test && pnpm lint && pnpm build && git checkout main && git pull origin main && git merge dev && pnpm version patch && git push origin main && git checkout dev && echo ✅ Deploy completado",
12
+ "db:seed": "tsx src/scripts/db-seed.ts",
13
+ "db:studio": "npx prisma studio",
14
+ "prod": "pnpm build && git checkout main && git pull origin main && git merge dev && pnpm version patch && git push origin main && git checkout dev && echo ✅ Deploy completado",
12
15
  "dev-rebase": "node src/scripts/dev-rebase.js"
13
- },
16
+ },
14
17
  "dependencies": {
15
- "@auth/prisma-adapter": "^2.10.0",
16
- "@prisma/client": "^6.16.0",
18
+ "@auth/prisma-adapter": "^2.11.0",
19
+ "@aws-sdk/client-s3": "^3.916.0",
20
+ "@aws-sdk/s3-request-presigner": "^3.916.0",
21
+ "@prisma/client": "^6.18.0",
17
22
  "@radix-ui/react-slot": "^1.2.3",
18
- "@tailwindcss/postcss": "^4.1.13",
23
+ "@react-email/render": "^1.4.0",
24
+ "@tailwindcss/postcss": "^4.1.16",
19
25
  "autoprefixer": "^10.4.21",
20
26
  "bcryptjs": "^3.0.2",
27
+ "better-auth": "^1.3.29",
21
28
  "class-variance-authority": "^0.7.1",
22
29
  "clsx": "^2.1.1",
23
- "dotenv": "^17.2.2",
24
- "lucide-react": "^0.544.0",
25
- "next": "^15.5.3",
26
- "next-auth": "5.0.0-beta.29",
30
+ "dotenv": "^17.2.3",
31
+ "lucide-react": "^0.547.0",
32
+ "motion": "^12.23.24",
33
+ "next": "^16.0.0",
27
34
  "postcss": "^8.5.6",
28
35
  "postgres": "^3.4.7",
29
- "react": "^19.1.1",
30
- "react-dom": "^19.1.1",
36
+ "react": "^19.2.0",
37
+ "react-dom": "^19.2.0",
38
+ "resend": "^6.2.2",
31
39
  "sonner": "^2.0.7",
32
40
  "tailwind-merge": "^3.3.1",
33
- "tailwindcss": "^4.1.13",
41
+ "tailwindcss": "^4.1.16",
34
42
  "tailwindcss-animate": "^1.0.7",
35
- "zod": "^4.1.7"
43
+ "zod": "^4.1.12"
36
44
  },
37
45
  "devDependencies": {
38
- "@eslint/compat": "^1.3.2",
39
- "@next/eslint-plugin-next": "15.5.3",
40
- "@types/node": "^24.3.1",
41
- "@types/react": "^19.1.12",
42
- "@types/react-dom": "^19.1.9",
46
+ "@eslint/compat": "^1.4.0",
47
+ "@next/eslint-plugin-next": "16.0.0",
48
+ "@types/node": "^24.9.1",
49
+ "@types/react": "^19.2.2",
50
+ "@types/react-dom": "^19.2.2",
43
51
  "babel-plugin-react-compiler": "19.0.0-beta-e1e972c-20250221",
44
- "eslint": "^9.35.0",
45
- "eslint-config-next": "^15.5.3",
52
+ "eslint": "^9.38.0",
53
+ "eslint-config-next": "^16.0.0",
46
54
  "eslint-config-prettier": "^10.1.8",
47
55
  "eslint-plugin-import": "^2.32.0",
48
56
  "eslint-plugin-jsx-a11y": "^6.10.2",
49
57
  "eslint-plugin-prettier": "^5.5.4",
50
58
  "eslint-plugin-react": "^7.37.5",
51
59
  "eslint-plugin-react-compiler": "0.0.0-experimental-c8b3f72-20240517",
52
- "eslint-plugin-react-hooks": "^5.2.0",
60
+ "eslint-plugin-react-hooks": "^7.0.0",
53
61
  "globals": "^16.4.0",
54
62
  "prettier": "^3.6.2",
55
- "prettier-plugin-tailwindcss": "^0.6.14",
56
- "prisma": "^6.16.0",
57
- "tsx": "^4.20.5",
58
- "typescript": "^5.9.2",
59
- "typescript-eslint": "^8.43.0"
63
+ "prettier-plugin-tailwindcss": "^0.7.1",
64
+ "prisma": "^6.18.0",
65
+ "tsx": "^4.20.6",
66
+ "typescript": "^5.9.3",
67
+ "typescript-eslint": "^8.46.2"
60
68
  }
61
69
  }
@@ -1,25 +1,85 @@
1
- datasource db {
2
- provider = "postgresql"
3
- url = env("DATABASE_URL")
1
+
2
+ generator client {
3
+ provider = "prisma-client-js"
4
4
  }
5
5
 
6
- generator client {
7
- provider = "prisma-client-js"
8
- output = "./generated"
6
+ datasource db {
7
+ provider = "postgresql"
8
+ url = env("DATABASE_URL")
9
9
  }
10
10
 
11
- model Post {
11
+ model Post {
12
12
  id Int @id @default(autoincrement())
13
13
  title String
14
14
  content String?
15
15
  published Boolean @default(false)
16
16
  author User? @relation(fields: [authorId], references: [id])
17
- authorId Int?
17
+ authorId Int?
18
+ }
19
+
20
+ model User {
21
+ id Int @id @default(autoincrement())
22
+ email String @unique
23
+ name String?
24
+ posts Post[]
25
+ emailVerified Boolean @default(false)
26
+ image String?
27
+ createdAt DateTime @default(now())
28
+ updatedAt DateTime @default(now()) @updatedAt
29
+ role String
30
+ banned Boolean? @default(false)
31
+ banReason String?
32
+ banExpires DateTime?
33
+ lastName String?
34
+ username String?
35
+ sessions Session[]
36
+ accounts Account[]
37
+
38
+ @@map("user")
18
39
  }
40
+
41
+ model Session {
42
+ id String @id
43
+ expiresAt DateTime
44
+ token String
45
+ createdAt DateTime @default(now())
46
+ updatedAt DateTime @updatedAt
47
+ ipAddress String?
48
+ userAgent String?
49
+ userId String
50
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
51
+ impersonatedBy String?
19
52
 
20
- model User {
21
- id Int @id @default(autoincrement())
22
- email String @unique
23
- name String?
24
- posts Post[]
25
- }
53
+ @@unique([token])
54
+ @@map("session")
55
+ }
56
+
57
+ model Account {
58
+ id String @id
59
+ accountId String
60
+ providerId String
61
+ userId String
62
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
63
+ accessToken String?
64
+ refreshToken String?
65
+ idToken String?
66
+ accessTokenExpiresAt DateTime?
67
+ refreshTokenExpiresAt DateTime?
68
+ scope String?
69
+ password String?
70
+ createdAt DateTime @default(now())
71
+ updatedAt DateTime @updatedAt
72
+
73
+ @@map("account")
74
+ }
75
+
76
+ model Verification {
77
+ id String @id
78
+ identifier String
79
+ value String
80
+ expiresAt DateTime
81
+ createdAt DateTime @default(now())
82
+ updatedAt DateTime @default(now()) @updatedAt
83
+
84
+ @@map("verification")
85
+ }
@@ -0,0 +1,5 @@
1
+ import { toNextJsHandler } from "better-auth/next-js";
2
+
3
+ import { auth } from "@/lib/auth";
4
+
5
+ export const { POST, GET } = toNextJsHandler(auth);
@@ -0,0 +1,118 @@
1
+ "use client";
2
+
3
+ import Link from "next/link";
4
+ import { Brain, Home, Search, ArrowLeft } from "lucide-react";
5
+ import { motion } from "motion/react";
6
+
7
+ import { Button } from "@/components/ui/button";
8
+
9
+ export default function NotFound() {
10
+ return (
11
+ <div className="bg-background relative flex min-h-screen flex-col items-center justify-center gap-8 overflow-hidden p-6">
12
+ {/* Contenido principal */}
13
+ <div className="relative z-10 flex w-full max-w-2xl flex-col items-center gap-8 text-center">
14
+ {/* Logo y marca */}
15
+ <motion.div
16
+ animate={{ scale: [1, 1.1, 1] }}
17
+ className="flex items-center gap-3 text-2xl font-bold"
18
+ transition={{ duration: 2, repeat: Infinity, ease: "easeInOut" }}
19
+ >
20
+ <div className="from-primary to-accent text-primary-foreground flex size-12 items-center justify-center rounded-xl bg-gradient-to-br shadow-lg">
21
+ <Brain className="size-7" />
22
+ </div>
23
+ <span className="from-foreground to-primary bg-gradient-to-r bg-clip-text text-transparent">
24
+ Nuvace
25
+ </span>
26
+ </motion.div>
27
+
28
+ {/* Número 404 animado */}
29
+ <motion.div
30
+ animate={{
31
+ rotateY: [0, 180, 360],
32
+ scale: [1, 1.05, 1],
33
+ }}
34
+ className="relative"
35
+ transition={{
36
+ duration: 3,
37
+ repeat: Infinity,
38
+ ease: "easeInOut",
39
+ }}
40
+ >
41
+ <h1 className="text-8xl font-black tracking-tighter sm:text-9xl">
42
+ <span className="from-primary to-accent bg-gradient-to-r bg-clip-text text-transparent">
43
+ 404
44
+ </span>
45
+ </h1>
46
+ </motion.div>
47
+
48
+ {/* Mensaje principal */}
49
+ <div className="space-y-4">
50
+ <h2 className="text-foreground text-2xl font-bold sm:text-3xl">
51
+ ¡Ups! Esta página no existe
52
+ </h2>
53
+ <p className="text-muted-foreground max-w-md text-lg">
54
+ La página que buscas no se encuentra disponible. Es posible que haya sido movida o
55
+ eliminada.
56
+ </p>
57
+ </div>
58
+
59
+ {/* Botones de acción */}
60
+ <div className="flex w-full max-w-sm flex-col gap-4 sm:flex-row">
61
+ <Button asChild className="flex-1 gap-2" size="lg">
62
+ <Link href="/">
63
+ <Home className="size-4" />
64
+ Ir al inicio
65
+ </Link>
66
+ </Button>
67
+ </div>
68
+
69
+ {/* Enlace para volver atrás */}
70
+ <Button
71
+ className="text-muted-foreground hover:text-foreground gap-2"
72
+ variant="ghost"
73
+ onClick={() => window.history.back()}
74
+ >
75
+ <ArrowLeft className="size-4" />
76
+ Volver atrás
77
+ </Button>
78
+
79
+ {/* Información adicional */}
80
+ <div className="border-muted/20 bg-muted/10 mt-8 rounded-lg border p-6 backdrop-blur-sm">
81
+ <p className="text-muted-foreground text-sm">
82
+ Si crees que esto es un error, por favor{" "}
83
+ <Link className="text-primary font-medium hover:underline" href="/panel/resumen">
84
+ contacta con soporte
85
+ </Link>{" "}
86
+ para que podamos ayudarte.
87
+ </p>
88
+ </div>
89
+ </div>
90
+
91
+ {/* Partículas flotantes adicionales para el efecto 404 */}
92
+ <div className="pointer-events-none fixed inset-0">
93
+ {[...Array(5)].map((_, i) => (
94
+ <motion.div
95
+ key={i}
96
+ animate={{
97
+ x: [0, 200, 0],
98
+ y: [0, -200, 0],
99
+ opacity: [0.3, 0.7, 0.3],
100
+ scale: [0.5, 1, 0.5],
101
+ }}
102
+ className="bg-accent absolute h-2 w-2 rounded-full"
103
+ style={{
104
+ left: `${20 + i * 15}%`,
105
+ top: `${30 + i * 10}%`,
106
+ }}
107
+ transition={{
108
+ duration: 5 + i * 0.5,
109
+ ease: "easeInOut",
110
+ repeat: Infinity,
111
+ delay: i * 0.3,
112
+ }}
113
+ />
114
+ ))}
115
+ </div>
116
+ </div>
117
+ );
118
+ }
@@ -0,0 +1,9 @@
1
+ import { createAuthClient } from "better-auth/react";
2
+ import { emailOTPClient, adminClient } from "better-auth/client/plugins";
3
+
4
+ export const authClient = createAuthClient({
5
+ baseURL: process.env.BETTER_AUTH_URL,
6
+ plugins: [emailOTPClient(), adminClient()],
7
+ });
8
+
9
+ export const { signIn, signUp, signOut, useSession } = authClient;