diff --git a/apps/web/app/(dashboard)/configuracion/page.tsx b/apps/web/app/(dashboard)/configuracion/page.tsx index cfd5835..090a2c5 100644 --- a/apps/web/app/(dashboard)/configuracion/page.tsx +++ b/apps/web/app/(dashboard)/configuracion/page.tsx @@ -5,13 +5,37 @@ import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/com import { useThemeStore } from '@/stores/theme-store'; import { useAuthStore } from '@/stores/auth-store'; import { themes, type ThemeName } from '@/themes'; -import { Check, Palette, User, Building } from 'lucide-react'; +import { Check, Palette, User, Building, Sidebar, PanelTop, Minimize2, Sparkles } from 'lucide-react'; -const themeOptions: { name: ThemeName; label: string; description: string }[] = [ - { name: 'light', label: 'Light', description: 'Tema claro profesional' }, - { name: 'vibrant', label: 'Vibrant', description: 'Colores vivos y modernos' }, - { name: 'corporate', label: 'Corporate', description: 'Diseño empresarial denso' }, - { name: 'dark', label: 'Dark', description: 'Modo oscuro con acentos neón' }, +const themeOptions: { name: ThemeName; label: string; description: string; layoutDesc: string; layoutIcon: typeof Sidebar }[] = [ + { + name: 'light', + label: 'Light', + description: 'Tema claro profesional', + layoutDesc: 'Sidebar estándar fijo', + layoutIcon: Sidebar, + }, + { + name: 'vibrant', + label: 'Vibrant', + description: 'Colores vivos y modernos', + layoutDesc: 'Navegación horizontal superior', + layoutIcon: PanelTop, + }, + { + name: 'corporate', + label: 'Corporate', + description: 'Diseño empresarial denso', + layoutDesc: 'Sidebar compacto (expande al hover)', + layoutIcon: Minimize2, + }, + { + name: 'dark', + label: 'Dark', + description: 'Modo oscuro con acentos neón', + layoutDesc: 'Sidebar flotante con efecto glass', + layoutIcon: Sparkles, + }, ]; export default function ConfiguracionPage() { @@ -71,41 +95,72 @@ export default function ConfiguracionPage() { - Tema Visual + Tema Visual y Layout - Elige el tema que mejor se adapte a tu preferencia + Cada tema incluye colores y distribución de elementos únicos -
- {themeOptions.map((option) => ( - - ))} + + {/* Theme Info */} +

{option.label}

+

+ {option.description} +

+ + {/* Layout Info */} +
+ + + {option.layoutDesc} + +
+ + ); + })}
diff --git a/apps/web/app/(dashboard)/layout.tsx b/apps/web/app/(dashboard)/layout.tsx index 97bbd3f..0f50c83 100644 --- a/apps/web/app/(dashboard)/layout.tsx +++ b/apps/web/app/(dashboard)/layout.tsx @@ -3,7 +3,13 @@ import { useEffect } from 'react'; import { useRouter } from 'next/navigation'; import { useAuthStore } from '@/stores/auth-store'; +import { useThemeStore } from '@/stores/theme-store'; +import { themes } from '@/themes'; import { Sidebar } from '@/components/layouts/sidebar'; +import { TopNav } from '@/components/layouts/topnav'; +import { SidebarCompact } from '@/components/layouts/sidebar-compact'; +import { SidebarFloating } from '@/components/layouts/sidebar-floating'; +import { cn } from '@/lib/utils'; export default function DashboardLayout({ children, @@ -12,6 +18,10 @@ export default function DashboardLayout({ }) { const router = useRouter(); const { isAuthenticated } = useAuthStore(); + const { theme } = useThemeStore(); + + const currentTheme = themes[theme]; + const layout = currentTheme.layout; useEffect(() => { if (!isAuthenticated) { @@ -23,10 +33,42 @@ export default function DashboardLayout({ return null; } + // Render layout based on theme + const renderNavigation = () => { + switch (layout) { + case 'topnav': + return ; + case 'sidebar-compact': + return ; + case 'sidebar-floating': + return ; + case 'sidebar-standard': + default: + return ; + } + }; + + const getContentClasses = () => { + switch (layout) { + case 'topnav': + return 'pt-16'; // Top padding for fixed top nav + case 'sidebar-compact': + return 'pl-16'; // Small left padding for compact sidebar + case 'sidebar-floating': + return 'pl-72 pr-4 py-4'; // Padding for floating sidebar + case 'sidebar-standard': + default: + return 'pl-64'; // Standard sidebar width + } + }; + return ( -
- -
+
+ {renderNavigation()} +
{children}
diff --git a/apps/web/components/layouts/sidebar-compact.tsx b/apps/web/components/layouts/sidebar-compact.tsx new file mode 100644 index 0000000..2174179 --- /dev/null +++ b/apps/web/components/layouts/sidebar-compact.tsx @@ -0,0 +1,130 @@ +'use client'; + +import Link from 'next/link'; +import { usePathname } from 'next/navigation'; +import { cn } from '@/lib/utils'; +import { + LayoutDashboard, + FileText, + Calculator, + Settings, + LogOut, + BarChart3, + Calendar, + Bell, + Users, +} from 'lucide-react'; +import { useAuthStore } from '@/stores/auth-store'; +import { logout } from '@/lib/api/auth'; +import { useRouter } from 'next/navigation'; +import { useState } from 'react'; + +const navigation = [ + { name: 'Dashboard', href: '/dashboard', icon: LayoutDashboard }, + { name: 'CFDI', href: '/cfdi', icon: FileText }, + { name: 'Impuestos', href: '/impuestos', icon: Calculator }, + { name: 'Reportes', href: '/reportes', icon: BarChart3 }, + { name: 'Calendario', href: '/calendario', icon: Calendar }, + { name: 'Alertas', href: '/alertas', icon: Bell }, + { name: 'Usuarios', href: '/usuarios', icon: Users }, + { name: 'Configuración', href: '/configuracion', icon: Settings }, +]; + +export function SidebarCompact() { + const pathname = usePathname(); + const router = useRouter(); + const { user, logout: clearAuth } = useAuthStore(); + const [expanded, setExpanded] = useState(false); + + const handleLogout = async () => { + try { + await logout(); + } catch { + // Ignore errors + } finally { + clearAuth(); + router.push('/login'); + } + }; + + return ( + + ); +} diff --git a/apps/web/components/layouts/sidebar-floating.tsx b/apps/web/components/layouts/sidebar-floating.tsx new file mode 100644 index 0000000..c83deae --- /dev/null +++ b/apps/web/components/layouts/sidebar-floating.tsx @@ -0,0 +1,111 @@ +'use client'; + +import Link from 'next/link'; +import { usePathname } from 'next/navigation'; +import { cn } from '@/lib/utils'; +import { + LayoutDashboard, + FileText, + Calculator, + Settings, + LogOut, + BarChart3, + Calendar, + Bell, + Users, +} from 'lucide-react'; +import { useAuthStore } from '@/stores/auth-store'; +import { logout } from '@/lib/api/auth'; +import { useRouter } from 'next/navigation'; + +const navigation = [ + { name: 'Dashboard', href: '/dashboard', icon: LayoutDashboard }, + { name: 'CFDI', href: '/cfdi', icon: FileText }, + { name: 'Impuestos', href: '/impuestos', icon: Calculator }, + { name: 'Reportes', href: '/reportes', icon: BarChart3 }, + { name: 'Calendario', href: '/calendario', icon: Calendar }, + { name: 'Alertas', href: '/alertas', icon: Bell }, + { name: 'Usuarios', href: '/usuarios', icon: Users }, + { name: 'Config', href: '/configuracion', icon: Settings }, +]; + +export function SidebarFloating() { + const pathname = usePathname(); + const router = useRouter(); + const { user, logout: clearAuth } = useAuthStore(); + + const handleLogout = async () => { + try { + await logout(); + } catch { + // Ignore errors + } finally { + clearAuth(); + router.push('/login'); + } + }; + + return ( + + ); +} diff --git a/apps/web/components/layouts/topnav.tsx b/apps/web/components/layouts/topnav.tsx new file mode 100644 index 0000000..845dbea --- /dev/null +++ b/apps/web/components/layouts/topnav.tsx @@ -0,0 +1,118 @@ +'use client'; + +import Link from 'next/link'; +import { usePathname } from 'next/navigation'; +import { cn } from '@/lib/utils'; +import { + LayoutDashboard, + FileText, + Calculator, + Settings, + LogOut, + BarChart3, + Calendar, + Bell, + Users, + ChevronDown, +} from 'lucide-react'; +import { useAuthStore } from '@/stores/auth-store'; +import { logout } from '@/lib/api/auth'; +import { useRouter } from 'next/navigation'; +import { useState } from 'react'; + +const navigation = [ + { name: 'Dashboard', href: '/dashboard', icon: LayoutDashboard }, + { name: 'CFDI', href: '/cfdi', icon: FileText }, + { name: 'Impuestos', href: '/impuestos', icon: Calculator }, + { name: 'Reportes', href: '/reportes', icon: BarChart3 }, + { name: 'Calendario', href: '/calendario', icon: Calendar }, + { name: 'Alertas', href: '/alertas', icon: Bell }, + { name: 'Usuarios', href: '/usuarios', icon: Users }, + { name: 'Config', href: '/configuracion', icon: Settings }, +]; + +export function TopNav() { + const pathname = usePathname(); + const router = useRouter(); + const { user, logout: clearAuth } = useAuthStore(); + const [userMenuOpen, setUserMenuOpen] = useState(false); + + const handleLogout = async () => { + try { + await logout(); + } catch { + // Ignore errors + } finally { + clearAuth(); + router.push('/login'); + } + }; + + return ( +
+
+ {/* Logo */} + +
+ H +
+ Horux360 + + + {/* Navigation */} + + + {/* User Menu */} +
+ + + {userMenuOpen && ( +
+
+

{user?.nombre}

+

{user?.email}

+
+ +
+ )} +
+
+
+ ); +} diff --git a/apps/web/themes/corporate.ts b/apps/web/themes/corporate.ts index 2c5e398..bd06306 100644 --- a/apps/web/themes/corporate.ts +++ b/apps/web/themes/corporate.ts @@ -1,7 +1,7 @@ export const corporateTheme = { name: 'corporate' as const, label: 'Corporate', - layout: 'multi-panel', + layout: 'sidebar-compact' as const, cssVars: { '--background': '210 20% 96%', '--foreground': '210 50% 10%', @@ -24,9 +24,4 @@ export const corporateTheme = { '--ring': '210 100% 25%', '--radius': '0.25rem', }, - sidebar: { - width: '200px', - collapsible: false, - }, - density: 'compact', }; diff --git a/apps/web/themes/dark.ts b/apps/web/themes/dark.ts index 90326d7..2806af8 100644 --- a/apps/web/themes/dark.ts +++ b/apps/web/themes/dark.ts @@ -1,7 +1,7 @@ export const darkTheme = { name: 'dark' as const, label: 'Dark', - layout: 'minimal-floating', + layout: 'sidebar-floating' as const, cssVars: { '--background': '0 0% 3.9%', '--foreground': '0 0% 98%', @@ -24,13 +24,4 @@ export const darkTheme = { '--ring': '187.2 85.7% 53.3%', '--radius': '0.75rem', }, - sidebar: { - width: '64px', - collapsible: false, - iconsOnly: true, - }, - effects: { - blur: '10px', - glow: '0 0 20px rgba(34,211,238,0.3)', - }, }; diff --git a/apps/web/themes/index.ts b/apps/web/themes/index.ts index 6bf60e4..d96f5eb 100644 --- a/apps/web/themes/index.ts +++ b/apps/web/themes/index.ts @@ -12,5 +12,6 @@ export const themes = { export type ThemeName = keyof typeof themes; export type Theme = (typeof themes)[ThemeName]; +export type LayoutType = 'sidebar-standard' | 'topnav' | 'sidebar-compact' | 'sidebar-floating'; export { lightTheme, vibrantTheme, corporateTheme, darkTheme }; diff --git a/apps/web/themes/light.ts b/apps/web/themes/light.ts index c8014e3..bdbe48c 100644 --- a/apps/web/themes/light.ts +++ b/apps/web/themes/light.ts @@ -1,7 +1,7 @@ export const lightTheme = { name: 'light' as const, label: 'Light', - layout: 'sidebar-fixed', + layout: 'sidebar-standard' as const, cssVars: { '--background': '0 0% 100%', '--foreground': '222.2 84% 4.9%', @@ -24,8 +24,4 @@ export const lightTheme = { '--ring': '221.2 83.2% 53.3%', '--radius': '0.5rem', }, - sidebar: { - width: '240px', - collapsible: false, - }, }; diff --git a/apps/web/themes/vibrant.ts b/apps/web/themes/vibrant.ts index 4fb2441..caad469 100644 --- a/apps/web/themes/vibrant.ts +++ b/apps/web/themes/vibrant.ts @@ -1,7 +1,7 @@ export const vibrantTheme = { name: 'vibrant' as const, label: 'Vibrant', - layout: 'sidebar-collapsible', + layout: 'topnav' as const, cssVars: { '--background': '270 50% 98%', '--foreground': '263.4 84% 6.7%', @@ -24,8 +24,4 @@ export const vibrantTheme = { '--ring': '262.1 83.3% 57.8%', '--radius': '1rem', }, - sidebar: { - width: '280px', - collapsible: true, - }, };