@create-lft-app/nextjs 1.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 (65) hide show
  1. package/bin/cli.d.ts +2 -0
  2. package/bin/cli.js +42 -0
  3. package/package.json +42 -0
  4. package/template/eslint.config.mjs +16 -0
  5. package/template/gitignore +36 -0
  6. package/template/next.config.ts +7 -0
  7. package/template/package.json +61 -0
  8. package/template/postcss.config.mjs +7 -0
  9. package/template/src/app/auth/login/page.tsx +153 -0
  10. package/template/src/app/dashboard/page.tsx +102 -0
  11. package/template/src/app/globals.css +249 -0
  12. package/template/src/app/layout.tsx +40 -0
  13. package/template/src/app/page.tsx +5 -0
  14. package/template/src/components/dashboard/widget.tsx +113 -0
  15. package/template/src/components/layout/admin-midday-sidebar.tsx +247 -0
  16. package/template/src/components/layout/admin-sidebar.tsx +146 -0
  17. package/template/src/components/layout/header.tsx +71 -0
  18. package/template/src/components/layout/main-content.tsx +28 -0
  19. package/template/src/components/layout/midday-sidebar.tsx +381 -0
  20. package/template/src/components/layout/nav-user.tsx +108 -0
  21. package/template/src/components/layout/page-header.tsx +95 -0
  22. package/template/src/components/layout/sidebar-context.tsx +33 -0
  23. package/template/src/components/layout/sidebar.tsx +194 -0
  24. package/template/src/components/layout/suspension-banner.tsx +21 -0
  25. package/template/src/components/ui/accordion.tsx +58 -0
  26. package/template/src/components/ui/alert-dialog.tsx +165 -0
  27. package/template/src/components/ui/alert.tsx +66 -0
  28. package/template/src/components/ui/avatar.tsx +55 -0
  29. package/template/src/components/ui/badge.tsx +50 -0
  30. package/template/src/components/ui/button.tsx +89 -0
  31. package/template/src/components/ui/calendar.tsx +220 -0
  32. package/template/src/components/ui/card.tsx +89 -0
  33. package/template/src/components/ui/checkbox.tsx +38 -0
  34. package/template/src/components/ui/collapsible.tsx +33 -0
  35. package/template/src/components/ui/command.tsx +196 -0
  36. package/template/src/components/ui/dialog.tsx +153 -0
  37. package/template/src/components/ui/dropdown-menu.tsx +280 -0
  38. package/template/src/components/ui/form.tsx +171 -0
  39. package/template/src/components/ui/icons.tsx +167 -0
  40. package/template/src/components/ui/input.tsx +28 -0
  41. package/template/src/components/ui/label.tsx +25 -0
  42. package/template/src/components/ui/popover.tsx +59 -0
  43. package/template/src/components/ui/progress.tsx +32 -0
  44. package/template/src/components/ui/radio-group.tsx +45 -0
  45. package/template/src/components/ui/scroll-area.tsx +63 -0
  46. package/template/src/components/ui/select.tsx +208 -0
  47. package/template/src/components/ui/separator.tsx +28 -0
  48. package/template/src/components/ui/sheet.tsx +146 -0
  49. package/template/src/components/ui/sidebar.tsx +726 -0
  50. package/template/src/components/ui/skeleton.tsx +15 -0
  51. package/template/src/components/ui/slider.tsx +58 -0
  52. package/template/src/components/ui/sonner.tsx +47 -0
  53. package/template/src/components/ui/spinner.tsx +27 -0
  54. package/template/src/components/ui/submit-button.tsx +47 -0
  55. package/template/src/components/ui/switch.tsx +31 -0
  56. package/template/src/components/ui/table.tsx +120 -0
  57. package/template/src/components/ui/tabs.tsx +75 -0
  58. package/template/src/components/ui/textarea.tsx +26 -0
  59. package/template/src/components/ui/tooltip.tsx +70 -0
  60. package/template/src/hooks/use-mobile.ts +21 -0
  61. package/template/src/lib/supabase/client.ts +8 -0
  62. package/template/src/lib/supabase/server.ts +36 -0
  63. package/template/src/lib/utils.ts +6 -0
  64. package/template/src/modules/auth/actions/auth-actions.ts +12 -0
  65. package/template/tsconfig.json +27 -0
package/bin/cli.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
package/bin/cli.js ADDED
@@ -0,0 +1,42 @@
1
+ #!/usr/bin/env node
2
+ import { program } from 'commander';
3
+ import path from 'path';
4
+ import fs from 'fs-extra';
5
+ import { fileURLToPath } from 'url';
6
+ const __filename = fileURLToPath(import.meta.url);
7
+ const __dirname = path.dirname(__filename);
8
+ program
9
+ .name('create-lft-nextjs')
10
+ .description('Crea un proyecto Next.js con el template LFT')
11
+ .version('1.0.0')
12
+ .argument('<project-name>', 'Nombre del proyecto')
13
+ .option('--cwd <path>', 'Directorio donde crear el proyecto', process.cwd())
14
+ .action(async (projectName, options) => {
15
+ const templateDir = path.join(__dirname, '..', 'template');
16
+ const targetDir = path.join(options.cwd, projectName);
17
+ // Verificar si el directorio ya existe
18
+ if (fs.existsSync(targetDir)) {
19
+ console.log(`El directorio ${projectName} ya existe`);
20
+ process.exit(1);
21
+ }
22
+ try {
23
+ // Copiar template
24
+ await fs.copy(templateDir, targetDir);
25
+ // Actualizar package.json con el nombre del proyecto
26
+ const pkgPath = path.join(targetDir, 'package.json');
27
+ const pkg = await fs.readJson(pkgPath);
28
+ pkg.name = projectName;
29
+ await fs.writeJson(pkgPath, pkg, { spaces: 2 });
30
+ // Renombrar gitignore
31
+ const gitignorePath = path.join(targetDir, 'gitignore');
32
+ if (fs.existsSync(gitignorePath)) {
33
+ await fs.rename(gitignorePath, path.join(targetDir, '.gitignore'));
34
+ }
35
+ console.log(`Proyecto ${projectName} creado exitosamente`);
36
+ }
37
+ catch (error) {
38
+ console.error('Error al crear el proyecto:', error);
39
+ process.exit(1);
40
+ }
41
+ });
42
+ program.parse();
package/package.json ADDED
@@ -0,0 +1,42 @@
1
+ {
2
+ "name": "@create-lft-app/nextjs",
3
+ "version": "1.0.0",
4
+ "description": "Next.js template para proyectos LFT con Midday Design System",
5
+ "type": "module",
6
+ "bin": {
7
+ "create-lft-nextjs": "./bin/cli.js"
8
+ },
9
+ "files": [
10
+ "bin",
11
+ "template"
12
+ ],
13
+ "scripts": {
14
+ "build": "tsc",
15
+ "prepublishOnly": "npm run build"
16
+ },
17
+ "keywords": [
18
+ "nextjs",
19
+ "template",
20
+ "lft",
21
+ "midday",
22
+ "dashboard"
23
+ ],
24
+ "author": "LFT",
25
+ "license": "MIT",
26
+ "repository": {
27
+ "type": "git",
28
+ "url": "https://github.com/Test-Boiler/create-lft-nextjs"
29
+ },
30
+ "publishConfig": {
31
+ "access": "public"
32
+ },
33
+ "devDependencies": {
34
+ "@types/fs-extra": "^11.0.0",
35
+ "@types/node": "^20.0.0",
36
+ "typescript": "^5.0.0"
37
+ },
38
+ "dependencies": {
39
+ "commander": "^12.0.0",
40
+ "fs-extra": "^11.0.0"
41
+ }
42
+ }
@@ -0,0 +1,16 @@
1
+ import { dirname } from "path";
2
+ import { fileURLToPath } from "url";
3
+ import { FlatCompat } from "@eslint/eslintrc";
4
+
5
+ const __filename = fileURLToPath(import.meta.url);
6
+ const __dirname = dirname(__filename);
7
+
8
+ const compat = new FlatCompat({
9
+ baseDirectory: __dirname,
10
+ });
11
+
12
+ const eslintConfig = [
13
+ ...compat.extends("next/core-web-vitals", "next/typescript"),
14
+ ];
15
+
16
+ export default eslintConfig;
@@ -0,0 +1,36 @@
1
+ # Dependencies
2
+ /node_modules
3
+ /.pnp
4
+ .pnp.js
5
+ .yarn/install-state.gz
6
+
7
+ # Testing
8
+ /coverage
9
+
10
+ # Next.js
11
+ /.next/
12
+ /out/
13
+
14
+ # Production
15
+ /build
16
+
17
+ # Misc
18
+ .DS_Store
19
+ *.pem
20
+
21
+ # Debug
22
+ npm-debug.log*
23
+ yarn-debug.log*
24
+ yarn-error.log*
25
+ .pnpm-debug.log*
26
+
27
+ # Local env files
28
+ .env*.local
29
+ .env
30
+
31
+ # Vercel
32
+ .vercel
33
+
34
+ # TypeScript
35
+ *.tsbuildinfo
36
+ next-env.d.ts
@@ -0,0 +1,7 @@
1
+ import type { NextConfig } from "next";
2
+
3
+ const nextConfig: NextConfig = {
4
+ /* config options here */
5
+ };
6
+
7
+ export default nextConfig;
@@ -0,0 +1,61 @@
1
+ {
2
+ "name": "lft-app",
3
+ "version": "0.1.0",
4
+ "private": true,
5
+ "scripts": {
6
+ "dev": "next dev --turbopack",
7
+ "build": "next build",
8
+ "start": "next start",
9
+ "lint": "next lint"
10
+ },
11
+ "dependencies": {
12
+ "next": "^16.0.0",
13
+ "react": "^19.0.0",
14
+ "react-dom": "^19.0.0",
15
+ "@radix-ui/react-accordion": "^1.2.0",
16
+ "@radix-ui/react-alert-dialog": "^1.1.0",
17
+ "@radix-ui/react-avatar": "^1.1.0",
18
+ "@radix-ui/react-checkbox": "^1.1.0",
19
+ "@radix-ui/react-collapsible": "^1.1.0",
20
+ "@radix-ui/react-dialog": "^1.1.0",
21
+ "@radix-ui/react-dropdown-menu": "^2.1.0",
22
+ "@radix-ui/react-label": "^2.1.0",
23
+ "@radix-ui/react-popover": "^1.1.0",
24
+ "@radix-ui/react-progress": "^1.1.0",
25
+ "@radix-ui/react-radio-group": "^1.2.0",
26
+ "@radix-ui/react-scroll-area": "^1.1.0",
27
+ "@radix-ui/react-select": "^2.1.0",
28
+ "@radix-ui/react-separator": "^1.1.0",
29
+ "@radix-ui/react-slider": "^1.2.0",
30
+ "@radix-ui/react-slot": "^1.1.0",
31
+ "@radix-ui/react-switch": "^1.1.0",
32
+ "@radix-ui/react-tabs": "^1.1.0",
33
+ "@radix-ui/react-tooltip": "^1.1.0",
34
+ "class-variance-authority": "^0.7.0",
35
+ "clsx": "^2.1.0",
36
+ "tailwind-merge": "^2.5.0",
37
+ "lucide-react": "^0.400.0",
38
+ "react-hook-form": "^7.50.0",
39
+ "@hookform/resolvers": "^3.9.0",
40
+ "cmdk": "^1.0.0",
41
+ "react-day-picker": "^9.0.0",
42
+ "date-fns": "^4.0.0",
43
+ "sonner": "^1.5.0",
44
+ "next-themes": "^0.4.0",
45
+ "tw-animate-css": "^1.2.0",
46
+ "zod": "^3.23.0",
47
+ "@supabase/supabase-js": "^2.45.0",
48
+ "@supabase/ssr": "^0.5.0"
49
+ },
50
+ "devDependencies": {
51
+ "@types/node": "^22.0.0",
52
+ "@types/react": "^19.0.0",
53
+ "@types/react-dom": "^19.0.0",
54
+ "typescript": "^5.7.0",
55
+ "eslint": "^9.0.0",
56
+ "eslint-config-next": "^16.0.0",
57
+ "tailwindcss": "^4.0.0",
58
+ "@tailwindcss/postcss": "^4.0.0",
59
+ "tailwindcss-animate": "^1.0.0"
60
+ }
61
+ }
@@ -0,0 +1,7 @@
1
+ const config = {
2
+ plugins: {
3
+ "@tailwindcss/postcss": {},
4
+ },
5
+ };
6
+
7
+ export default config;
@@ -0,0 +1,153 @@
1
+ "use client"
2
+
3
+ import { useState } from "react"
4
+ import { useRouter } from "next/navigation"
5
+ import Link from "next/link"
6
+ import { Card, CardHeader, CardTitle, CardDescription, CardContent, CardFooter } from "@/components/ui/card"
7
+ import { Input } from "@/components/ui/input"
8
+ import { Button } from "@/components/ui/button"
9
+ import { Label } from "@/components/ui/label"
10
+ import { Separator } from "@/components/ui/separator"
11
+ import { Spinner } from "@/components/ui/spinner"
12
+
13
+ export default function LoginPage() {
14
+ const router = useRouter()
15
+ const [isLoading, setIsLoading] = useState(false)
16
+ const [error, setError] = useState<string | null>(null)
17
+
18
+ const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
19
+ e.preventDefault()
20
+ setIsLoading(true)
21
+ setError(null)
22
+
23
+ const formData = new FormData(e.currentTarget)
24
+ const email = formData.get("email") as string
25
+ const password = formData.get("password") as string
26
+
27
+ try {
28
+ // TODO: Implementar autenticación con Supabase
29
+ // const { error } = await supabase.auth.signInWithPassword({ email, password })
30
+
31
+ // Simulación de login exitoso
32
+ await new Promise((resolve) => setTimeout(resolve, 1000))
33
+
34
+ router.push("/dashboard")
35
+ } catch (err) {
36
+ setError("Error al iniciar sesión. Verifica tus credenciales.")
37
+ } finally {
38
+ setIsLoading(false)
39
+ }
40
+ }
41
+
42
+ return (
43
+ <div className="min-h-screen flex items-center justify-center bg-background p-4">
44
+ <Card className="w-full max-w-md">
45
+ <CardHeader className="space-y-1 text-center">
46
+ <CardTitle className="text-2xl font-bold">Iniciar Sesión</CardTitle>
47
+ <CardDescription>
48
+ Ingresa tus credenciales para acceder al panel
49
+ </CardDescription>
50
+ </CardHeader>
51
+ <CardContent>
52
+ <form onSubmit={handleSubmit} className="space-y-4">
53
+ {error && (
54
+ <div className="p-3 text-sm text-destructive bg-destructive/10 border border-destructive/20 rounded-md">
55
+ {error}
56
+ </div>
57
+ )}
58
+
59
+ <div className="space-y-2">
60
+ <Label htmlFor="email">Email</Label>
61
+ <Input
62
+ id="email"
63
+ name="email"
64
+ type="email"
65
+ placeholder="tu@email.com"
66
+ required
67
+ disabled={isLoading}
68
+ autoComplete="email"
69
+ />
70
+ </div>
71
+
72
+ <div className="space-y-2">
73
+ <div className="flex items-center justify-between">
74
+ <Label htmlFor="password">Contraseña</Label>
75
+ <Link
76
+ href="/auth/forgot-password"
77
+ className="text-sm text-primary hover:underline"
78
+ >
79
+ ¿Olvidaste tu contraseña?
80
+ </Link>
81
+ </div>
82
+ <Input
83
+ id="password"
84
+ name="password"
85
+ type="password"
86
+ placeholder="••••••••"
87
+ required
88
+ disabled={isLoading}
89
+ autoComplete="current-password"
90
+ />
91
+ </div>
92
+
93
+ <Button type="submit" className="w-full" disabled={isLoading}>
94
+ {isLoading ? (
95
+ <>
96
+ <Spinner className="mr-2 h-4 w-4" />
97
+ Iniciando sesión...
98
+ </>
99
+ ) : (
100
+ "Iniciar Sesión"
101
+ )}
102
+ </Button>
103
+ </form>
104
+
105
+ <div className="relative my-6">
106
+ <Separator />
107
+ <span className="absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 bg-background px-2 text-xs text-muted-foreground">
108
+ O continuar con
109
+ </span>
110
+ </div>
111
+
112
+ <div className="grid grid-cols-2 gap-4">
113
+ <Button variant="outline" disabled={isLoading}>
114
+ <svg className="mr-2 h-4 w-4" viewBox="0 0 24 24">
115
+ <path
116
+ fill="currentColor"
117
+ d="M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92c-.26 1.37-1.04 2.53-2.21 3.31v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.09z"
118
+ />
119
+ <path
120
+ fill="currentColor"
121
+ d="M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z"
122
+ />
123
+ <path
124
+ fill="currentColor"
125
+ d="M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z"
126
+ />
127
+ <path
128
+ fill="currentColor"
129
+ d="M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z"
130
+ />
131
+ </svg>
132
+ Google
133
+ </Button>
134
+ <Button variant="outline" disabled={isLoading}>
135
+ <svg className="mr-2 h-4 w-4" fill="currentColor" viewBox="0 0 24 24">
136
+ <path d="M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z" />
137
+ </svg>
138
+ GitHub
139
+ </Button>
140
+ </div>
141
+ </CardContent>
142
+ <CardFooter className="flex justify-center">
143
+ <p className="text-sm text-muted-foreground">
144
+ ¿No tienes una cuenta?{" "}
145
+ <Link href="/auth/register" className="text-primary hover:underline">
146
+ Regístrate
147
+ </Link>
148
+ </p>
149
+ </CardFooter>
150
+ </Card>
151
+ </div>
152
+ )
153
+ }
@@ -0,0 +1,102 @@
1
+ import { Header } from "@/components/layout/header"
2
+ import { Widget, WidgetGrid } from "@/components/dashboard/widget"
3
+ import {
4
+ Users,
5
+ DollarSign,
6
+ Activity,
7
+ TrendingUp,
8
+ Building2,
9
+ FileText,
10
+ AlertCircle,
11
+ CheckCircle,
12
+ } from "lucide-react"
13
+
14
+ export default function DashboardPage() {
15
+ return (
16
+ <>
17
+ <Header title="Dashboard" />
18
+ <main className="flex-1 p-6">
19
+ <div className="space-y-6">
20
+ <div>
21
+ <h2 className="text-2xl font-bold tracking-tight">
22
+ Bienvenido de vuelta
23
+ </h2>
24
+ <p className="text-muted-foreground">
25
+ Aquí está el resumen de tu actividad
26
+ </p>
27
+ </div>
28
+
29
+ <WidgetGrid>
30
+ <Widget
31
+ title="Usuarios Activos"
32
+ icon={<Users className="h-4 w-4" />}
33
+ value="1,234"
34
+ subValue="usuarios registrados"
35
+ trend={{ value: 12.5, positive: true }}
36
+ href="/admin/users"
37
+ />
38
+ <Widget
39
+ title="Ingresos"
40
+ icon={<DollarSign className="h-4 w-4" />}
41
+ value="$45,231"
42
+ subValue="este mes"
43
+ trend={{ value: 8.2, positive: true }}
44
+ variant="success"
45
+ />
46
+ <Widget
47
+ title="Organizaciones"
48
+ icon={<Building2 className="h-4 w-4" />}
49
+ value="89"
50
+ subValue="organizaciones activas"
51
+ trend={{ value: 3.1, positive: true }}
52
+ href="/admin/organizations"
53
+ />
54
+ <Widget
55
+ title="Actividad"
56
+ icon={<Activity className="h-4 w-4" />}
57
+ value="2,345"
58
+ subValue="eventos hoy"
59
+ trend={{ value: 5.4, positive: true }}
60
+ />
61
+ </WidgetGrid>
62
+
63
+ <div className="grid grid-cols-1 md:grid-cols-2 gap-6">
64
+ <WidgetGrid>
65
+ <Widget
66
+ title="Documentos Pendientes"
67
+ icon={<FileText className="h-4 w-4" />}
68
+ value="23"
69
+ subValue="requieren revisión"
70
+ variant="warning"
71
+ />
72
+ <Widget
73
+ title="Alertas"
74
+ icon={<AlertCircle className="h-4 w-4" />}
75
+ value="5"
76
+ subValue="alertas activas"
77
+ variant="danger"
78
+ />
79
+ </WidgetGrid>
80
+
81
+ <WidgetGrid>
82
+ <Widget
83
+ title="Tareas Completadas"
84
+ icon={<CheckCircle className="h-4 w-4" />}
85
+ value="156"
86
+ subValue="esta semana"
87
+ variant="success"
88
+ />
89
+ <Widget
90
+ title="Crecimiento"
91
+ icon={<TrendingUp className="h-4 w-4" />}
92
+ value="+24%"
93
+ subValue="vs mes anterior"
94
+ trend={{ value: 24, positive: true }}
95
+ />
96
+ </WidgetGrid>
97
+ </div>
98
+ </div>
99
+ </main>
100
+ </>
101
+ )
102
+ }