@create-lft-app/cli 1.0.13 → 1.1.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/dist/bin/cli.js +17 -156
- package/dist/bin/cli.js.map +1 -1
- package/dist/src/index.js +15 -154
- package/dist/src/index.js.map +1 -1
- package/package.json +1 -1
- package/templates/app/auth/login/page.tsx +0 -153
- package/templates/app/dashboard/page.tsx +0 -102
- package/templates/app/globals.css +0 -68
- package/templates/app/layout.tsx +0 -40
- package/templates/app/page.tsx +0 -5
- package/templates/components/dashboard/widget.tsx +0 -113
- package/templates/components/layout/admin-midday-sidebar.tsx +0 -247
- package/templates/components/layout/admin-sidebar.tsx +0 -146
- package/templates/components/layout/header.tsx +0 -71
- package/templates/components/layout/main-content.tsx +0 -28
- package/templates/components/layout/midday-sidebar.tsx +0 -381
- package/templates/components/layout/nav-user.tsx +0 -108
- package/templates/components/layout/page-header.tsx +0 -95
- package/templates/components/layout/sidebar-context.tsx +0 -33
- package/templates/components/layout/sidebar.tsx +0 -194
- package/templates/components/layout/suspension-banner.tsx +0 -21
- package/templates/components/ui/accordion.tsx +0 -58
- package/templates/components/ui/alert-dialog.tsx +0 -165
- package/templates/components/ui/alert.tsx +0 -66
- package/templates/components/ui/avatar.tsx +0 -55
- package/templates/components/ui/badge.tsx +0 -50
- package/templates/components/ui/button.tsx +0 -89
- package/templates/components/ui/calendar.tsx +0 -220
- package/templates/components/ui/card.tsx +0 -89
- package/templates/components/ui/checkbox.tsx +0 -38
- package/templates/components/ui/collapsible.tsx +0 -33
- package/templates/components/ui/command.tsx +0 -196
- package/templates/components/ui/dialog.tsx +0 -153
- package/templates/components/ui/dropdown-menu.tsx +0 -280
- package/templates/components/ui/form.tsx +0 -171
- package/templates/components/ui/icons.tsx +0 -167
- package/templates/components/ui/input.tsx +0 -28
- package/templates/components/ui/label.tsx +0 -25
- package/templates/components/ui/popover.tsx +0 -59
- package/templates/components/ui/progress.tsx +0 -32
- package/templates/components/ui/radio-group.tsx +0 -45
- package/templates/components/ui/scroll-area.tsx +0 -63
- package/templates/components/ui/select.tsx +0 -208
- package/templates/components/ui/separator.tsx +0 -28
- package/templates/components/ui/sheet.tsx +0 -146
- package/templates/components/ui/sidebar.tsx +0 -726
- package/templates/components/ui/skeleton.tsx +0 -15
- package/templates/components/ui/slider.tsx +0 -58
- package/templates/components/ui/sonner.tsx +0 -47
- package/templates/components/ui/spinner.tsx +0 -27
- package/templates/components/ui/submit-button.tsx +0 -47
- package/templates/components/ui/switch.tsx +0 -31
- package/templates/components/ui/table.tsx +0 -120
- package/templates/components/ui/tabs.tsx +0 -75
- package/templates/components/ui/textarea.tsx +0 -26
- package/templates/components/ui/tooltip.tsx +0 -70
- package/templates/hooks/use-mobile.ts +0 -21
- package/templates/lib/supabase/client.ts +0 -8
- package/templates/lib/supabase/server.ts +0 -29
- package/templates/lib/utils.ts +0 -6
- package/templates/modules/auth/actions/auth-actions.ts +0 -12
|
@@ -1,102 +0,0 @@
|
|
|
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
|
-
}
|
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
/* LFT Custom Styles */
|
|
2
|
-
|
|
3
|
-
/* Sidebar custom colors */
|
|
4
|
-
:root {
|
|
5
|
-
--sidebar-background: 0 0% 98%;
|
|
6
|
-
--sidebar-foreground: 240 5.3% 26.1%;
|
|
7
|
-
--sidebar-primary: 240 5.9% 10%;
|
|
8
|
-
--sidebar-primary-foreground: 0 0% 98%;
|
|
9
|
-
--sidebar-accent: 240 4.8% 95.9%;
|
|
10
|
-
--sidebar-accent-foreground: 240 5.9% 10%;
|
|
11
|
-
--sidebar-border: 220 13% 91%;
|
|
12
|
-
--sidebar-ring: 217.2 91.2% 59.8%;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
.dark {
|
|
16
|
-
--sidebar-background: 240 5.9% 10%;
|
|
17
|
-
--sidebar-foreground: 240 4.8% 95.9%;
|
|
18
|
-
--sidebar-primary: 0 0% 98%;
|
|
19
|
-
--sidebar-primary-foreground: 240 5.9% 10%;
|
|
20
|
-
--sidebar-accent: 240 3.7% 15.9%;
|
|
21
|
-
--sidebar-accent-foreground: 240 4.8% 95.9%;
|
|
22
|
-
--sidebar-border: 240 3.7% 15.9%;
|
|
23
|
-
--sidebar-ring: 217.2 91.2% 59.8%;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
/* Scrollbar styling */
|
|
27
|
-
::-webkit-scrollbar {
|
|
28
|
-
width: 8px;
|
|
29
|
-
height: 8px;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
::-webkit-scrollbar-track {
|
|
33
|
-
background: transparent;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
::-webkit-scrollbar-thumb {
|
|
37
|
-
background: hsl(var(--muted-foreground) / 0.3);
|
|
38
|
-
border-radius: 4px;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
::-webkit-scrollbar-thumb:hover {
|
|
42
|
-
background: hsl(var(--muted-foreground) / 0.5);
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
/* Focus visible improvements */
|
|
46
|
-
*:focus-visible {
|
|
47
|
-
outline: 2px solid hsl(var(--ring));
|
|
48
|
-
outline-offset: 2px;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
/* Smooth transitions */
|
|
52
|
-
* {
|
|
53
|
-
transition-property: background-color, border-color, color, fill, stroke;
|
|
54
|
-
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
|
|
55
|
-
transition-duration: 150ms;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
/* Widget animations */
|
|
59
|
-
.widget-enter {
|
|
60
|
-
opacity: 0;
|
|
61
|
-
transform: translateY(10px);
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
.widget-enter-active {
|
|
65
|
-
opacity: 1;
|
|
66
|
-
transform: translateY(0);
|
|
67
|
-
transition: opacity 300ms, transform 300ms;
|
|
68
|
-
}
|
package/templates/app/layout.tsx
DELETED
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
import type { Metadata } from "next"
|
|
2
|
-
import { Inter } from "next/font/google"
|
|
3
|
-
import "./globals.css"
|
|
4
|
-
import { SidebarProvider, SidebarInset } from "@/components/ui/sidebar"
|
|
5
|
-
import { AdminSidebar } from "@/components/layout/admin-sidebar"
|
|
6
|
-
import { Toaster } from "@/components/ui/sonner"
|
|
7
|
-
|
|
8
|
-
const inter = Inter({ subsets: ["latin"] })
|
|
9
|
-
|
|
10
|
-
export const metadata: Metadata = {
|
|
11
|
-
title: "Dashboard - LFT App",
|
|
12
|
-
description: "Panel de administración creado con create-lft-app",
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export default function RootLayout({
|
|
16
|
-
children,
|
|
17
|
-
}: {
|
|
18
|
-
children: React.ReactNode
|
|
19
|
-
}) {
|
|
20
|
-
// Usuario de ejemplo - en producción esto vendría de Supabase Auth
|
|
21
|
-
const user = {
|
|
22
|
-
email: "admin@ejemplo.com",
|
|
23
|
-
full_name: "Admin Usuario",
|
|
24
|
-
role: "Super Admin",
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
return (
|
|
28
|
-
<html lang="es" suppressHydrationWarning>
|
|
29
|
-
<body className={inter.className}>
|
|
30
|
-
<SidebarProvider>
|
|
31
|
-
<AdminSidebar user={user} />
|
|
32
|
-
<SidebarInset>
|
|
33
|
-
{children}
|
|
34
|
-
</SidebarInset>
|
|
35
|
-
</SidebarProvider>
|
|
36
|
-
<Toaster />
|
|
37
|
-
</body>
|
|
38
|
-
</html>
|
|
39
|
-
)
|
|
40
|
-
}
|
package/templates/app/page.tsx
DELETED
|
@@ -1,113 +0,0 @@
|
|
|
1
|
-
'use client'
|
|
2
|
-
|
|
3
|
-
import { cn } from '@/lib/utils'
|
|
4
|
-
import Link from 'next/link'
|
|
5
|
-
|
|
6
|
-
interface WidgetProps {
|
|
7
|
-
title: string
|
|
8
|
-
icon: React.ReactNode
|
|
9
|
-
description?: string
|
|
10
|
-
value: string | number
|
|
11
|
-
subValue?: string
|
|
12
|
-
href?: string
|
|
13
|
-
trend?: {
|
|
14
|
-
value: number
|
|
15
|
-
positive?: boolean
|
|
16
|
-
}
|
|
17
|
-
variant?: 'default' | 'warning' | 'danger' | 'success'
|
|
18
|
-
children?: React.ReactNode
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
export function Widget({
|
|
22
|
-
title,
|
|
23
|
-
icon,
|
|
24
|
-
description,
|
|
25
|
-
value,
|
|
26
|
-
subValue,
|
|
27
|
-
href,
|
|
28
|
-
trend,
|
|
29
|
-
variant = 'default',
|
|
30
|
-
children,
|
|
31
|
-
}: WidgetProps) {
|
|
32
|
-
const content = (
|
|
33
|
-
<div
|
|
34
|
-
className={cn(
|
|
35
|
-
'bg-background border border-border p-4 h-[180px] flex flex-col justify-between transition-all duration-200',
|
|
36
|
-
href && 'cursor-pointer hover:bg-accent/50 hover:border-border/80',
|
|
37
|
-
)}
|
|
38
|
-
>
|
|
39
|
-
<div>
|
|
40
|
-
<div className="flex items-center gap-2 mb-3">
|
|
41
|
-
<span className="text-[#606060]">{icon}</span>
|
|
42
|
-
<h3 className="text-xs text-[#606060] font-medium uppercase tracking-wide">{title}</h3>
|
|
43
|
-
</div>
|
|
44
|
-
|
|
45
|
-
{description && (
|
|
46
|
-
<p className="text-sm text-[#878787]">{description}</p>
|
|
47
|
-
)}
|
|
48
|
-
</div>
|
|
49
|
-
|
|
50
|
-
<div>
|
|
51
|
-
{children ? (
|
|
52
|
-
children
|
|
53
|
-
) : (
|
|
54
|
-
<div className="flex flex-col gap-1">
|
|
55
|
-
<div className="flex items-baseline gap-2">
|
|
56
|
-
<span
|
|
57
|
-
className={cn(
|
|
58
|
-
'text-3xl font-medium tabular-nums',
|
|
59
|
-
variant === 'danger' && 'text-destructive',
|
|
60
|
-
variant === 'warning' && 'text-yellow-500',
|
|
61
|
-
variant === 'success' && 'text-green-500',
|
|
62
|
-
)}
|
|
63
|
-
>
|
|
64
|
-
{value}
|
|
65
|
-
</span>
|
|
66
|
-
{trend && (
|
|
67
|
-
<span
|
|
68
|
-
className={cn(
|
|
69
|
-
'text-xs',
|
|
70
|
-
trend.positive ? 'text-green-500' : 'text-destructive'
|
|
71
|
-
)}
|
|
72
|
-
>
|
|
73
|
-
{trend.positive ? '+' : ''}{trend.value}%
|
|
74
|
-
</span>
|
|
75
|
-
)}
|
|
76
|
-
</div>
|
|
77
|
-
{subValue && (
|
|
78
|
-
<span className="text-xs text-[#878787]">{subValue}</span>
|
|
79
|
-
)}
|
|
80
|
-
</div>
|
|
81
|
-
)}
|
|
82
|
-
|
|
83
|
-
{href && (
|
|
84
|
-
<span className="text-xs text-[#878787] group-hover:text-foreground transition-colors mt-2 block">
|
|
85
|
-
Ver más →
|
|
86
|
-
</span>
|
|
87
|
-
)}
|
|
88
|
-
</div>
|
|
89
|
-
</div>
|
|
90
|
-
)
|
|
91
|
-
|
|
92
|
-
if (href) {
|
|
93
|
-
return (
|
|
94
|
-
<Link href={href} className="group">
|
|
95
|
-
{content}
|
|
96
|
-
</Link>
|
|
97
|
-
)
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
return content
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
interface WidgetGridProps {
|
|
104
|
-
children: React.ReactNode
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
export function WidgetGrid({ children }: WidgetGridProps) {
|
|
108
|
-
return (
|
|
109
|
-
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4">
|
|
110
|
-
{children}
|
|
111
|
-
</div>
|
|
112
|
-
)
|
|
113
|
-
}
|
|
@@ -1,247 +0,0 @@
|
|
|
1
|
-
'use client'
|
|
2
|
-
|
|
3
|
-
import Link from 'next/link'
|
|
4
|
-
import { usePathname } from 'next/navigation'
|
|
5
|
-
import { useState, useRef, useEffect } from 'react'
|
|
6
|
-
import { cn } from '@/lib/utils'
|
|
7
|
-
import {
|
|
8
|
-
LayoutDashboard,
|
|
9
|
-
Building2,
|
|
10
|
-
Users,
|
|
11
|
-
CreditCard,
|
|
12
|
-
Settings,
|
|
13
|
-
Shield,
|
|
14
|
-
Clock,
|
|
15
|
-
ChevronLeft,
|
|
16
|
-
LogOut,
|
|
17
|
-
} from 'lucide-react'
|
|
18
|
-
import {
|
|
19
|
-
DropdownMenu,
|
|
20
|
-
DropdownMenuContent,
|
|
21
|
-
DropdownMenuItem,
|
|
22
|
-
DropdownMenuSeparator,
|
|
23
|
-
DropdownMenuTrigger,
|
|
24
|
-
} from '@/components/ui/dropdown-menu'
|
|
25
|
-
import { logout } from '@/modules/auth/actions/auth-actions'
|
|
26
|
-
|
|
27
|
-
type NavItem = {
|
|
28
|
-
path: string
|
|
29
|
-
name: string
|
|
30
|
-
icon: React.ComponentType<{ className?: string }>
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
const adminNavItems: NavItem[] = [
|
|
34
|
-
{ path: '/admin', name: 'Dashboard', icon: LayoutDashboard },
|
|
35
|
-
{ path: '/admin/organizations', name: 'Organizaciones', icon: Building2 },
|
|
36
|
-
{ path: '/admin/users', name: 'Usuarios', icon: Users },
|
|
37
|
-
{ path: '/admin/subscriptions', name: 'Suscripciones', icon: CreditCard },
|
|
38
|
-
]
|
|
39
|
-
|
|
40
|
-
const systemNavItems: NavItem[] = [
|
|
41
|
-
{ path: '/admin/jobs', name: 'Jobs', icon: Clock },
|
|
42
|
-
{ path: '/admin/settings', name: 'Configuración', icon: Settings },
|
|
43
|
-
]
|
|
44
|
-
|
|
45
|
-
interface AdminMiddaySidebarProps {
|
|
46
|
-
user: {
|
|
47
|
-
email: string
|
|
48
|
-
full_name: string | null
|
|
49
|
-
role: string
|
|
50
|
-
} | null
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
export function AdminMiddaySidebar({ user }: AdminMiddaySidebarProps) {
|
|
54
|
-
const pathname = usePathname()
|
|
55
|
-
const [isExpanded, setIsExpanded] = useState(false)
|
|
56
|
-
const sidebarRef = useRef<HTMLElement>(null)
|
|
57
|
-
const timeoutRef = useRef<NodeJS.Timeout | null>(null)
|
|
58
|
-
|
|
59
|
-
const handleMouseEnter = () => {
|
|
60
|
-
if (timeoutRef.current) clearTimeout(timeoutRef.current)
|
|
61
|
-
setIsExpanded(true)
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
const handleMouseLeave = () => {
|
|
65
|
-
timeoutRef.current = setTimeout(() => setIsExpanded(false), 100)
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
useEffect(() => {
|
|
69
|
-
return () => {
|
|
70
|
-
if (timeoutRef.current) clearTimeout(timeoutRef.current)
|
|
71
|
-
}
|
|
72
|
-
}, [])
|
|
73
|
-
|
|
74
|
-
const isActive = (path: string) => {
|
|
75
|
-
if (path === '/admin') return pathname === '/admin'
|
|
76
|
-
return pathname.startsWith(path)
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
const initials = user?.full_name
|
|
80
|
-
?.split(' ')
|
|
81
|
-
.map((n) => n[0])
|
|
82
|
-
.join('')
|
|
83
|
-
.toUpperCase()
|
|
84
|
-
.slice(0, 2) || 'SA'
|
|
85
|
-
|
|
86
|
-
return (
|
|
87
|
-
<aside
|
|
88
|
-
ref={sidebarRef}
|
|
89
|
-
className={cn(
|
|
90
|
-
'h-screen flex-shrink-0 flex-col justify-between fixed top-0 left-0 hidden md:flex z-50',
|
|
91
|
-
'bg-background border-r border-border',
|
|
92
|
-
'transition-[width] duration-200 ease-[cubic-bezier(0.4,0,0.2,1)]',
|
|
93
|
-
isExpanded ? 'w-[240px]' : 'w-[70px]'
|
|
94
|
-
)}
|
|
95
|
-
onMouseEnter={handleMouseEnter}
|
|
96
|
-
onMouseLeave={handleMouseLeave}
|
|
97
|
-
>
|
|
98
|
-
{/* Logo */}
|
|
99
|
-
<div className="h-[70px] flex items-center border-b border-border px-4">
|
|
100
|
-
<Link href="/admin" className="flex items-center gap-3">
|
|
101
|
-
<div className="flex h-8 w-8 items-center justify-center rounded-md bg-red-500 text-white flex-shrink-0">
|
|
102
|
-
<Shield className="h-4 w-4" />
|
|
103
|
-
</div>
|
|
104
|
-
<span
|
|
105
|
-
className={cn(
|
|
106
|
-
'font-semibold text-sm whitespace-nowrap transition-opacity duration-200',
|
|
107
|
-
isExpanded ? 'opacity-100' : 'opacity-0 w-0'
|
|
108
|
-
)}
|
|
109
|
-
>
|
|
110
|
-
Super Admin
|
|
111
|
-
</span>
|
|
112
|
-
</Link>
|
|
113
|
-
</div>
|
|
114
|
-
|
|
115
|
-
{/* Navigation */}
|
|
116
|
-
<nav className="flex-1 overflow-y-auto py-4">
|
|
117
|
-
{/* Main Nav */}
|
|
118
|
-
<div className="mb-6">
|
|
119
|
-
{isExpanded && (
|
|
120
|
-
<p className="px-4 mb-2 text-[10px] font-medium text-[#878787] uppercase tracking-wider">
|
|
121
|
-
Gestión
|
|
122
|
-
</p>
|
|
123
|
-
)}
|
|
124
|
-
<ul className="space-y-1 px-2">
|
|
125
|
-
{adminNavItems.map((item) => {
|
|
126
|
-
const Icon = item.icon
|
|
127
|
-
const active = isActive(item.path)
|
|
128
|
-
|
|
129
|
-
return (
|
|
130
|
-
<li key={item.path}>
|
|
131
|
-
<Link
|
|
132
|
-
href={item.path}
|
|
133
|
-
className={cn(
|
|
134
|
-
'flex items-center gap-3 rounded-md px-3 py-2 text-sm transition-colors',
|
|
135
|
-
active
|
|
136
|
-
? 'bg-accent text-foreground'
|
|
137
|
-
: 'text-[#878787] hover:bg-accent/50 hover:text-foreground'
|
|
138
|
-
)}
|
|
139
|
-
>
|
|
140
|
-
<Icon className="h-4 w-4 flex-shrink-0" />
|
|
141
|
-
{isExpanded && (
|
|
142
|
-
<span className="whitespace-nowrap">
|
|
143
|
-
{item.name}
|
|
144
|
-
</span>
|
|
145
|
-
)}
|
|
146
|
-
</Link>
|
|
147
|
-
</li>
|
|
148
|
-
)
|
|
149
|
-
})}
|
|
150
|
-
</ul>
|
|
151
|
-
</div>
|
|
152
|
-
|
|
153
|
-
{/* System Nav */}
|
|
154
|
-
<div>
|
|
155
|
-
{isExpanded && (
|
|
156
|
-
<p className="px-4 mb-2 text-[10px] font-medium text-[#878787] uppercase tracking-wider">
|
|
157
|
-
Sistema
|
|
158
|
-
</p>
|
|
159
|
-
)}
|
|
160
|
-
<ul className="space-y-1 px-2">
|
|
161
|
-
{systemNavItems.map((item) => {
|
|
162
|
-
const Icon = item.icon
|
|
163
|
-
const active = isActive(item.path)
|
|
164
|
-
|
|
165
|
-
return (
|
|
166
|
-
<li key={item.path}>
|
|
167
|
-
<Link
|
|
168
|
-
href={item.path}
|
|
169
|
-
className={cn(
|
|
170
|
-
'flex items-center gap-3 rounded-md px-3 py-2 text-sm transition-colors',
|
|
171
|
-
active
|
|
172
|
-
? 'bg-accent text-foreground'
|
|
173
|
-
: 'text-[#878787] hover:bg-accent/50 hover:text-foreground'
|
|
174
|
-
)}
|
|
175
|
-
>
|
|
176
|
-
<Icon className="h-4 w-4 flex-shrink-0" />
|
|
177
|
-
{isExpanded && (
|
|
178
|
-
<span className="whitespace-nowrap">
|
|
179
|
-
{item.name}
|
|
180
|
-
</span>
|
|
181
|
-
)}
|
|
182
|
-
</Link>
|
|
183
|
-
</li>
|
|
184
|
-
)
|
|
185
|
-
})}
|
|
186
|
-
</ul>
|
|
187
|
-
</div>
|
|
188
|
-
</nav>
|
|
189
|
-
|
|
190
|
-
{/* Back to Dashboard & User */}
|
|
191
|
-
<div className="border-t border-border">
|
|
192
|
-
{/* Back Link */}
|
|
193
|
-
<Link
|
|
194
|
-
href="/"
|
|
195
|
-
className="flex items-center gap-3 px-4 py-3 text-sm text-[#878787] hover:text-foreground hover:bg-accent/50 transition-colors"
|
|
196
|
-
>
|
|
197
|
-
<ChevronLeft className="h-4 w-4 flex-shrink-0" />
|
|
198
|
-
<span
|
|
199
|
-
className={cn(
|
|
200
|
-
'whitespace-nowrap transition-opacity duration-200',
|
|
201
|
-
isExpanded ? 'opacity-100' : 'opacity-0 w-0'
|
|
202
|
-
)}
|
|
203
|
-
>
|
|
204
|
-
Volver al Dashboard
|
|
205
|
-
</span>
|
|
206
|
-
</Link>
|
|
207
|
-
|
|
208
|
-
{/* User Menu */}
|
|
209
|
-
<DropdownMenu>
|
|
210
|
-
<DropdownMenuTrigger asChild>
|
|
211
|
-
<button className="flex items-center gap-3 w-full px-4 py-3 hover:bg-accent/50 transition-colors">
|
|
212
|
-
<div className="flex h-8 w-8 items-center justify-center rounded-full bg-red-500/10 text-red-500 text-xs font-medium flex-shrink-0">
|
|
213
|
-
{initials}
|
|
214
|
-
</div>
|
|
215
|
-
<div
|
|
216
|
-
className={cn(
|
|
217
|
-
'flex flex-col items-start text-left transition-opacity duration-200',
|
|
218
|
-
isExpanded ? 'opacity-100' : 'opacity-0 w-0'
|
|
219
|
-
)}
|
|
220
|
-
>
|
|
221
|
-
<span className="text-sm font-medium truncate max-w-[160px]">
|
|
222
|
-
{user?.full_name || 'Super Admin'}
|
|
223
|
-
</span>
|
|
224
|
-
<span className="text-xs text-[#878787] truncate max-w-[160px]">
|
|
225
|
-
{user?.email}
|
|
226
|
-
</span>
|
|
227
|
-
</div>
|
|
228
|
-
</button>
|
|
229
|
-
</DropdownMenuTrigger>
|
|
230
|
-
<DropdownMenuContent align="end" className="w-56">
|
|
231
|
-
<div className="px-2 py-1.5">
|
|
232
|
-
<p className="text-sm font-medium">{user?.full_name}</p>
|
|
233
|
-
<p className="text-xs text-[#878787]">{user?.email}</p>
|
|
234
|
-
</div>
|
|
235
|
-
<DropdownMenuSeparator />
|
|
236
|
-
<DropdownMenuItem asChild>
|
|
237
|
-
<button onClick={() => logout()} className="w-full cursor-pointer">
|
|
238
|
-
<LogOut className="h-4 w-4 mr-2" />
|
|
239
|
-
Cerrar sesión
|
|
240
|
-
</button>
|
|
241
|
-
</DropdownMenuItem>
|
|
242
|
-
</DropdownMenuContent>
|
|
243
|
-
</DropdownMenu>
|
|
244
|
-
</div>
|
|
245
|
-
</aside>
|
|
246
|
-
)
|
|
247
|
-
}
|