responsive-system 1.1.4 → 1.2.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/package.json +5 -1
- package/scripts/postinstall.js +8 -1
- package/src/App.css +42 -0
- package/src/App.tsx +29 -0
- package/src/assets/react.svg +1 -0
- package/src/components/LayoutSwitcher.tsx +62 -0
- package/src/components/ResponsiveDemo.tsx +282 -0
- package/src/components/layout/Footer.tsx +90 -0
- package/src/components/layout/Header.tsx +105 -0
- package/src/components/layout/Navigation.tsx +96 -0
- package/src/components/layout/Sidebar.tsx +108 -0
- package/src/components/layout/index.ts +4 -0
- package/src/config/layout.ts +61 -0
- package/src/constants/breakpoints.ts +48 -0
- package/src/context/NavigationContext.tsx +32 -0
- package/src/context/ResponsiveLayoutContext.tsx +37 -0
- package/src/context/SidebarContext.tsx +26 -0
- package/src/context/index.ts +4 -0
- package/src/hooks/index.ts +4 -0
- package/src/hooks/useLayout.ts +27 -0
- package/src/hooks/useResponsive.ts +189 -0
- package/src/hooks/useResponsiveLayout.ts +51 -0
- package/src/index.css +1 -0
- package/src/index.ts +100 -0
- package/src/layouts/DashboardLayout.tsx +76 -0
- package/src/layouts/DefaultLayout.tsx +30 -0
- package/src/layouts/MainLayout.tsx +38 -0
- package/src/layouts/MinimalLayout.tsx +20 -0
- package/src/layouts/SidebarLayout.tsx +36 -0
- package/src/layouts/index.ts +5 -0
- package/src/main.tsx +10 -0
- package/src/pages/ResponsiveTestPage.tsx +400 -0
- package/src/providers/ResponsiveLayoutProvider.tsx +92 -0
- package/src/providers/ResponsiveProvider.tsx +18 -0
- package/src/providers/index.ts +3 -0
- package/src/types/responsive.ts +64 -0
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
import { useState, useEffect, useCallback, useMemo } from 'react'
|
|
2
|
+
import type {
|
|
3
|
+
ResponsiveState,
|
|
4
|
+
Breakpoint
|
|
5
|
+
} from '../types/responsive'
|
|
6
|
+
import {
|
|
7
|
+
getCurrentBreakpoint,
|
|
8
|
+
getBreakpointIndex
|
|
9
|
+
} from '../constants/breakpoints'
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Debounce utility
|
|
13
|
+
*/
|
|
14
|
+
function debounce<T extends (...args: unknown[]) => void>(
|
|
15
|
+
func: T,
|
|
16
|
+
wait: number
|
|
17
|
+
): (...args: Parameters<T>) => void {
|
|
18
|
+
let timeout: ReturnType<typeof setTimeout> | null = null
|
|
19
|
+
return (...args: Parameters<T>) => {
|
|
20
|
+
if (timeout) clearTimeout(timeout)
|
|
21
|
+
timeout = setTimeout(() => func(...args), wait)
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Get orientation based on dimensions
|
|
27
|
+
*/
|
|
28
|
+
function getOrientation(width: number, height: number): 'landscape' | 'portrait' {
|
|
29
|
+
return width >= height ? 'landscape' : 'portrait'
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Hook principal useResponsive
|
|
34
|
+
* Provee información sobre el breakpoint actual y helpers para responsive
|
|
35
|
+
*/
|
|
36
|
+
export const useResponsive = (): ResponsiveState => {
|
|
37
|
+
const [dimensions, setDimensions] = useState({
|
|
38
|
+
width: typeof window !== 'undefined' ? window.innerWidth : 1024,
|
|
39
|
+
height: typeof window !== 'undefined' ? window.innerHeight : 768
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
// Función para actualizar dimensiones
|
|
43
|
+
const updateDimensions = useCallback(() => {
|
|
44
|
+
setDimensions({
|
|
45
|
+
width: window.innerWidth,
|
|
46
|
+
height: window.innerHeight
|
|
47
|
+
})
|
|
48
|
+
}, [])
|
|
49
|
+
|
|
50
|
+
// Debounced update para optimizar performance
|
|
51
|
+
const debouncedUpdateDimensions = useMemo(
|
|
52
|
+
() => debounce(updateDimensions, 100),
|
|
53
|
+
[updateDimensions]
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
// Effect para escuchar cambios de tamaño
|
|
57
|
+
useEffect(() => {
|
|
58
|
+
if (typeof window === 'undefined') return
|
|
59
|
+
|
|
60
|
+
window.addEventListener('resize', debouncedUpdateDimensions)
|
|
61
|
+
|
|
62
|
+
return () => {
|
|
63
|
+
window.removeEventListener('resize', debouncedUpdateDimensions)
|
|
64
|
+
}
|
|
65
|
+
}, [debouncedUpdateDimensions])
|
|
66
|
+
|
|
67
|
+
const { width, height } = dimensions
|
|
68
|
+
|
|
69
|
+
// Calcular breakpoint actual
|
|
70
|
+
const breakpoint = useMemo(() => getCurrentBreakpoint(width), [width])
|
|
71
|
+
|
|
72
|
+
// Calcular orientación
|
|
73
|
+
const orientation = useMemo(() => getOrientation(width, height), [width, height])
|
|
74
|
+
|
|
75
|
+
// Helpers booleanos por breakpoint específico
|
|
76
|
+
const isXs = breakpoint === 'xs'
|
|
77
|
+
const isSm = breakpoint === 'sm'
|
|
78
|
+
const isMd = breakpoint === 'md'
|
|
79
|
+
const isLg = breakpoint === 'lg'
|
|
80
|
+
const isXl = breakpoint === 'xl'
|
|
81
|
+
const is2Xl = breakpoint === '2xl'
|
|
82
|
+
const is3Xl = breakpoint === '3xl'
|
|
83
|
+
const is4Xl = breakpoint === '4xl'
|
|
84
|
+
const is5Xl = breakpoint === '5xl'
|
|
85
|
+
|
|
86
|
+
// Helpers booleanos agrupados
|
|
87
|
+
const isMobile = isXs || isSm
|
|
88
|
+
const isTablet = isMd
|
|
89
|
+
const isDesktop = isLg || isXl || is2Xl || is3Xl || is4Xl || is5Xl
|
|
90
|
+
const isSmall = isXs || isSm || isMd
|
|
91
|
+
const isLarge = isLg || isXl || is2Xl || is3Xl || is4Xl || is5Xl
|
|
92
|
+
const isUltraWide = is3Xl || is4Xl || is5Xl
|
|
93
|
+
const is4K = is4Xl || is5Xl
|
|
94
|
+
const is5K = is5Xl
|
|
95
|
+
|
|
96
|
+
// Helpers de orientación
|
|
97
|
+
const isPortrait = orientation === 'portrait'
|
|
98
|
+
const isLandscape = orientation === 'landscape'
|
|
99
|
+
|
|
100
|
+
// Funciones de comparación de breakpoints
|
|
101
|
+
const isBreakpointUp = useCallback((bp: Breakpoint): boolean => {
|
|
102
|
+
return getBreakpointIndex(breakpoint) >= getBreakpointIndex(bp)
|
|
103
|
+
}, [breakpoint])
|
|
104
|
+
|
|
105
|
+
const isBreakpointDown = useCallback((bp: Breakpoint): boolean => {
|
|
106
|
+
return getBreakpointIndex(breakpoint) <= getBreakpointIndex(bp)
|
|
107
|
+
}, [breakpoint])
|
|
108
|
+
|
|
109
|
+
const isBreakpointBetween = useCallback((min: Breakpoint, max: Breakpoint): boolean => {
|
|
110
|
+
const current = getBreakpointIndex(breakpoint)
|
|
111
|
+
return current >= getBreakpointIndex(min) && current <= getBreakpointIndex(max)
|
|
112
|
+
}, [breakpoint])
|
|
113
|
+
|
|
114
|
+
// Funciones de comparación de ancho
|
|
115
|
+
const isWidthUp = useCallback((minWidth: number): boolean => {
|
|
116
|
+
return width >= minWidth
|
|
117
|
+
}, [width])
|
|
118
|
+
|
|
119
|
+
const isWidthDown = useCallback((maxWidth: number): boolean => {
|
|
120
|
+
return width <= maxWidth
|
|
121
|
+
}, [width])
|
|
122
|
+
|
|
123
|
+
const isWidthBetween = useCallback((minWidth: number, maxWidth: number): boolean => {
|
|
124
|
+
return width >= minWidth && width <= maxWidth
|
|
125
|
+
}, [width])
|
|
126
|
+
|
|
127
|
+
// Funciones de comparación de altura
|
|
128
|
+
const isHeightUp = useCallback((minHeight: number): boolean => {
|
|
129
|
+
return height >= minHeight
|
|
130
|
+
}, [height])
|
|
131
|
+
|
|
132
|
+
const isHeightDown = useCallback((maxHeight: number): boolean => {
|
|
133
|
+
return height <= maxHeight
|
|
134
|
+
}, [height])
|
|
135
|
+
|
|
136
|
+
const isHeightBetween = useCallback((minHeight: number, maxHeight: number): boolean => {
|
|
137
|
+
return height >= minHeight && height <= maxHeight
|
|
138
|
+
}, [height])
|
|
139
|
+
|
|
140
|
+
// Debug mode
|
|
141
|
+
const debug = false
|
|
142
|
+
|
|
143
|
+
return {
|
|
144
|
+
// Estado básico
|
|
145
|
+
breakpoint,
|
|
146
|
+
width,
|
|
147
|
+
height,
|
|
148
|
+
orientation,
|
|
149
|
+
|
|
150
|
+
// Helpers booleanos específicos
|
|
151
|
+
isXs,
|
|
152
|
+
isSm,
|
|
153
|
+
isMd,
|
|
154
|
+
isLg,
|
|
155
|
+
isXl,
|
|
156
|
+
is2Xl,
|
|
157
|
+
is3Xl,
|
|
158
|
+
is4Xl,
|
|
159
|
+
is5Xl,
|
|
160
|
+
|
|
161
|
+
// Helpers booleanos agrupados
|
|
162
|
+
isMobile,
|
|
163
|
+
isTablet,
|
|
164
|
+
isDesktop,
|
|
165
|
+
isSmall,
|
|
166
|
+
isLarge,
|
|
167
|
+
isUltraWide,
|
|
168
|
+
is4K,
|
|
169
|
+
is5K,
|
|
170
|
+
|
|
171
|
+
// Helpers de orientación
|
|
172
|
+
isPortrait,
|
|
173
|
+
isLandscape,
|
|
174
|
+
|
|
175
|
+
// Funciones de comparación
|
|
176
|
+
isBreakpointUp,
|
|
177
|
+
isBreakpointDown,
|
|
178
|
+
isBreakpointBetween,
|
|
179
|
+
isWidthUp,
|
|
180
|
+
isWidthDown,
|
|
181
|
+
isWidthBetween,
|
|
182
|
+
isHeightUp,
|
|
183
|
+
isHeightDown,
|
|
184
|
+
isHeightBetween,
|
|
185
|
+
|
|
186
|
+
// Debug
|
|
187
|
+
debug
|
|
188
|
+
}
|
|
189
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { useResponsiveLayoutContext } from '../context'
|
|
2
|
+
|
|
3
|
+
export const useResponsiveLayout = () => {
|
|
4
|
+
const context = useResponsiveLayoutContext()
|
|
5
|
+
|
|
6
|
+
return {
|
|
7
|
+
// Todo el sistema responsivo original
|
|
8
|
+
...context.responsive,
|
|
9
|
+
|
|
10
|
+
// Sistema de layout
|
|
11
|
+
layout: {
|
|
12
|
+
current: context.layout.current,
|
|
13
|
+
config: context.layout.config,
|
|
14
|
+
setLayout: context.layout.setLayout,
|
|
15
|
+
},
|
|
16
|
+
|
|
17
|
+
// Utilidades de layout
|
|
18
|
+
layoutUtils: context.layoutUtils,
|
|
19
|
+
|
|
20
|
+
// Helpers específicos del layout
|
|
21
|
+
isDefaultLayout: () => context.layout.current === 'default',
|
|
22
|
+
isSidebarLayout: () => context.layout.current === 'sidebar',
|
|
23
|
+
isDashboardLayout: () => context.layout.current === 'dashboard',
|
|
24
|
+
isMinimalLayout: () => context.layout.current === 'minimal',
|
|
25
|
+
|
|
26
|
+
// Grid helpers que usan el sistema auto-escalable
|
|
27
|
+
grid: {
|
|
28
|
+
auto: (minWidth = 'md') => `grid-cols-auto-${minWidth}`,
|
|
29
|
+
responsive: (breakpoints: Record<string, number>) => {
|
|
30
|
+
const classes: string[] = []
|
|
31
|
+
Object.entries(breakpoints).forEach(([breakpoint, cols]) => {
|
|
32
|
+
if (breakpoint === 'base') {
|
|
33
|
+
classes.push(`grid-cols-${cols}`)
|
|
34
|
+
} else {
|
|
35
|
+
classes.push(`${breakpoint}:grid-cols-${cols}`)
|
|
36
|
+
}
|
|
37
|
+
})
|
|
38
|
+
return classes.join(' ')
|
|
39
|
+
},
|
|
40
|
+
fixed: (cols: number) => `grid-cols-${cols}`,
|
|
41
|
+
},
|
|
42
|
+
|
|
43
|
+
// Spacing helpers que escalan automáticamente
|
|
44
|
+
spacing: {
|
|
45
|
+
container: context.layoutUtils.getContainerClass(),
|
|
46
|
+
section: 'mb-6',
|
|
47
|
+
card: 'p-6',
|
|
48
|
+
gap: 'gap-4',
|
|
49
|
+
},
|
|
50
|
+
}
|
|
51
|
+
}
|
package/src/index.css
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
@import "tailwindcss";
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
// ========================================
|
|
2
|
+
// SISTEMA RESPONSIVE AUTO-SCALING + LAYOUTS
|
|
3
|
+
// ========================================
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* CÓMO USAR ESTE SISTEMA:
|
|
7
|
+
*
|
|
8
|
+
* 1. Instala el plugin en tailwind.config.js:
|
|
9
|
+
* import responsiveScalePlugin from './src/plugin/responsiveScalePlugin.js'
|
|
10
|
+
* plugins: [responsiveScalePlugin()]
|
|
11
|
+
*
|
|
12
|
+
* 2. Usa el ResponsiveLayoutProvider + MainLayout:
|
|
13
|
+
* <ResponsiveLayoutProvider defaultLayout="default">
|
|
14
|
+
* <MainLayout>
|
|
15
|
+
* <App />
|
|
16
|
+
* </MainLayout>
|
|
17
|
+
* </ResponsiveLayoutProvider>
|
|
18
|
+
*
|
|
19
|
+
* 3. Selección de layout (múltiples opciones):
|
|
20
|
+
* - Por prop: <MainLayout layout="dashboard">...</MainLayout>
|
|
21
|
+
* - Por contexto: const { setLayout } = useResponsiveLayout(); setLayout('sidebar')
|
|
22
|
+
* - Por defaultLayout: <ResponsiveLayoutProvider defaultLayout="dashboard">
|
|
23
|
+
*
|
|
24
|
+
* 4. Hook responsivo personalizado (opcional):
|
|
25
|
+
* <ResponsiveLayoutProvider useResponsiveHook={tuHookPersonalizado}>
|
|
26
|
+
* ...
|
|
27
|
+
* </ResponsiveLayoutProvider>
|
|
28
|
+
*
|
|
29
|
+
* 5. Usa Tailwind NORMAL en tus páginas:
|
|
30
|
+
* <div className="p-6 text-base">
|
|
31
|
+
* TODO escala automáticamente + layout consistente
|
|
32
|
+
* </div>
|
|
33
|
+
*
|
|
34
|
+
* 6. (Opcional) Usa hooks para casos avanzados:
|
|
35
|
+
* const { layout, responsive } = useResponsiveLayout()
|
|
36
|
+
*/
|
|
37
|
+
|
|
38
|
+
// ========================================
|
|
39
|
+
// EXPORTS PRINCIPALES
|
|
40
|
+
// ========================================
|
|
41
|
+
|
|
42
|
+
// Providers
|
|
43
|
+
export { ResponsiveLayoutProvider, ResponsiveProvider } from './providers'
|
|
44
|
+
|
|
45
|
+
// Layouts
|
|
46
|
+
export {
|
|
47
|
+
MainLayout,
|
|
48
|
+
DefaultLayout,
|
|
49
|
+
SidebarLayout,
|
|
50
|
+
DashboardLayout,
|
|
51
|
+
MinimalLayout
|
|
52
|
+
} from './layouts'
|
|
53
|
+
|
|
54
|
+
// Hooks
|
|
55
|
+
export { useResponsiveLayout, useLayout, useResponsive } from './hooks'
|
|
56
|
+
|
|
57
|
+
// Componentes de layout
|
|
58
|
+
export { Header, Sidebar, Footer, Navigation } from './components/layout'
|
|
59
|
+
|
|
60
|
+
// LayoutSwitcher
|
|
61
|
+
export { default as LayoutSwitcher } from './components/LayoutSwitcher'
|
|
62
|
+
|
|
63
|
+
// Context (para casos avanzados)
|
|
64
|
+
export {
|
|
65
|
+
useResponsiveLayoutContext,
|
|
66
|
+
SidebarProvider,
|
|
67
|
+
useSidebar,
|
|
68
|
+
NavigationProvider,
|
|
69
|
+
useNavigation
|
|
70
|
+
} from './context'
|
|
71
|
+
|
|
72
|
+
// Tipos TypeScript
|
|
73
|
+
export type {
|
|
74
|
+
Breakpoint,
|
|
75
|
+
Orientation,
|
|
76
|
+
ResponsiveState,
|
|
77
|
+
ResponsiveProviderProps
|
|
78
|
+
} from './types/responsive'
|
|
79
|
+
|
|
80
|
+
// Constantes (para casos avanzados)
|
|
81
|
+
export {
|
|
82
|
+
DEFAULT_BREAKPOINTS,
|
|
83
|
+
getCurrentBreakpoint,
|
|
84
|
+
getBreakpointIndex,
|
|
85
|
+
getBreakpointValue
|
|
86
|
+
} from './constants/breakpoints'
|
|
87
|
+
|
|
88
|
+
// Configuración de layouts
|
|
89
|
+
export { LAYOUT_CONFIG, DEFAULT_LAYOUT, AVAILABLE_LAYOUTS } from './config/layout'
|
|
90
|
+
export type { LayoutConfig } from './config/layout'
|
|
91
|
+
|
|
92
|
+
// Plugin de Tailwind (importar directamente en tailwind.config.js)
|
|
93
|
+
// import responsiveScalePlugin from './src/plugin/responsiveScalePlugin.js'
|
|
94
|
+
|
|
95
|
+
// ========================================
|
|
96
|
+
// EJEMPLOS (Solo para testing en este proyecto - NO exportados en npm)
|
|
97
|
+
// ========================================
|
|
98
|
+
|
|
99
|
+
// Los ejemplos no se exportan en el paquete npm
|
|
100
|
+
// Solo están disponibles durante el desarrollo local
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import { useResponsiveLayout } from '../hooks'
|
|
3
|
+
import { Sidebar, Footer } from '../components/layout'
|
|
4
|
+
import { SidebarProvider, useSidebar } from '../context'
|
|
5
|
+
|
|
6
|
+
interface DashboardLayoutProps {
|
|
7
|
+
children: React.ReactNode
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const DashboardLayoutContent: React.FC<{ children: React.ReactNode }> = ({ children }) => {
|
|
11
|
+
const { layoutUtils } = useResponsiveLayout()
|
|
12
|
+
const { setSidebarOpen } = useSidebar()
|
|
13
|
+
|
|
14
|
+
return (
|
|
15
|
+
<div className="min-h-screen bg-black flex flex-col">
|
|
16
|
+
{/* Navbar para móvil (igual que SidebarLayout) */}
|
|
17
|
+
<div className="sticky top-0 z-50">
|
|
18
|
+
<nav className="bg-gradient-to-r from-gray-900 via-black to-gray-900 border-b border-cyan-500/20 shadow-2xl relative">
|
|
19
|
+
<div className="w-full">
|
|
20
|
+
<div className="px-4 py-4">
|
|
21
|
+
<div className="flex items-center justify-between">
|
|
22
|
+
<div className="flex items-center space-x-2">
|
|
23
|
+
{/* Hamburger button para móvil - A LA IZQUIERDA */}
|
|
24
|
+
<button
|
|
25
|
+
onClick={() => setSidebarOpen(true)}
|
|
26
|
+
className="p-2 rounded-lg text-gray-300 hover:text-cyan-400 hover:bg-cyan-500/10 transition-colors"
|
|
27
|
+
>
|
|
28
|
+
<svg className="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
29
|
+
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M4 6h16M4 12h16M4 18h16" />
|
|
30
|
+
</svg>
|
|
31
|
+
</button>
|
|
32
|
+
|
|
33
|
+
<div className="flex items-center space-x-2">
|
|
34
|
+
<div className="w-1.5 h-1.5 bg-cyan-400 rounded-full shadow-lg shadow-cyan-400/50 animate-pulse"></div>
|
|
35
|
+
<h3 className="text-base font-black text-white tracking-tight">
|
|
36
|
+
Sistema Responsivo
|
|
37
|
+
</h3>
|
|
38
|
+
</div>
|
|
39
|
+
<div className="px-2 py-0.5 text-cyan-400 font-mono bg-black/50 border border-cyan-500/30 rounded text-xs font-bold tracking-widest">
|
|
40
|
+
DASHBOARD
|
|
41
|
+
</div>
|
|
42
|
+
</div>
|
|
43
|
+
</div>
|
|
44
|
+
</div>
|
|
45
|
+
</div>
|
|
46
|
+
</nav>
|
|
47
|
+
</div>
|
|
48
|
+
|
|
49
|
+
{/* Content area con sidebar */}
|
|
50
|
+
<div className="flex flex-1">
|
|
51
|
+
{/* Sidebar */}
|
|
52
|
+
<Sidebar />
|
|
53
|
+
|
|
54
|
+
{/* Main content */}
|
|
55
|
+
<main className="flex-1 overflow-auto">
|
|
56
|
+
<div className={layoutUtils.getContainerClass()}>
|
|
57
|
+
{children}
|
|
58
|
+
</div>
|
|
59
|
+
</main>
|
|
60
|
+
</div>
|
|
61
|
+
|
|
62
|
+
{/* Footer */}
|
|
63
|
+
<Footer />
|
|
64
|
+
</div>
|
|
65
|
+
)
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const DashboardLayout: React.FC<DashboardLayoutProps> = ({ children }) => {
|
|
69
|
+
return (
|
|
70
|
+
<SidebarProvider>
|
|
71
|
+
<DashboardLayoutContent>{children}</DashboardLayoutContent>
|
|
72
|
+
</SidebarProvider>
|
|
73
|
+
)
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export default DashboardLayout
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import { Navigation, Footer } from '../components/layout'
|
|
3
|
+
import { useResponsiveLayout } from '../hooks'
|
|
4
|
+
|
|
5
|
+
interface DefaultLayoutProps {
|
|
6
|
+
children: React.ReactNode
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
const DefaultLayout: React.FC<DefaultLayoutProps> = ({ children }) => {
|
|
10
|
+
const { layoutUtils } = useResponsiveLayout()
|
|
11
|
+
|
|
12
|
+
return (
|
|
13
|
+
<div className="min-h-screen bg-black flex flex-col">
|
|
14
|
+
{/* Navigation fijo arriba */}
|
|
15
|
+
<Navigation />
|
|
16
|
+
|
|
17
|
+
{/* Main content con padding-top para la navigation */}
|
|
18
|
+
<main className="flex-1">
|
|
19
|
+
<div className={layoutUtils.getContainerClass()}>
|
|
20
|
+
{children}
|
|
21
|
+
</div>
|
|
22
|
+
</main>
|
|
23
|
+
|
|
24
|
+
{/* Footer fijo abajo */}
|
|
25
|
+
<Footer />
|
|
26
|
+
</div>
|
|
27
|
+
)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export default DefaultLayout
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import { useResponsiveLayout } from '../hooks'
|
|
3
|
+
import {
|
|
4
|
+
DefaultLayout,
|
|
5
|
+
SidebarLayout,
|
|
6
|
+
DashboardLayout,
|
|
7
|
+
MinimalLayout
|
|
8
|
+
} from './index'
|
|
9
|
+
|
|
10
|
+
interface MainLayoutProps {
|
|
11
|
+
children: React.ReactNode
|
|
12
|
+
/**
|
|
13
|
+
* Layout específico a usar. Si se proporciona, sobrescribe el layout del contexto.
|
|
14
|
+
* Valores posibles: 'default', 'sidebar', 'dashboard', 'minimal'
|
|
15
|
+
*/
|
|
16
|
+
layout?: 'default' | 'sidebar' | 'dashboard' | 'minimal'
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const MainLayout: React.FC<MainLayoutProps> = ({ children, layout: layoutProp }) => {
|
|
20
|
+
const { layout } = useResponsiveLayout()
|
|
21
|
+
|
|
22
|
+
// Usar el layout del prop si se proporciona, sino usar el del contexto
|
|
23
|
+
const currentLayout = layoutProp || layout.current
|
|
24
|
+
|
|
25
|
+
// Seleccionar el layout apropiado basado en el estado del contexto o prop
|
|
26
|
+
const layouts = {
|
|
27
|
+
default: DefaultLayout,
|
|
28
|
+
sidebar: SidebarLayout,
|
|
29
|
+
dashboard: DashboardLayout,
|
|
30
|
+
minimal: MinimalLayout,
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const LayoutComponent = layouts[currentLayout as keyof typeof layouts] || DefaultLayout
|
|
34
|
+
|
|
35
|
+
return <LayoutComponent>{children}</LayoutComponent>
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export default MainLayout
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import { useResponsiveLayout } from '../hooks'
|
|
3
|
+
|
|
4
|
+
interface MinimalLayoutProps {
|
|
5
|
+
children: React.ReactNode
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
const MinimalLayout: React.FC<MinimalLayoutProps> = ({ children }) => {
|
|
9
|
+
const { layoutUtils } = useResponsiveLayout()
|
|
10
|
+
|
|
11
|
+
return (
|
|
12
|
+
<div className="min-h-screen bg-black">
|
|
13
|
+
<main className={layoutUtils.getContainerClass()}>
|
|
14
|
+
{children}
|
|
15
|
+
</main>
|
|
16
|
+
</div>
|
|
17
|
+
)
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export default MinimalLayout
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import { useResponsiveLayout } from '../hooks'
|
|
3
|
+
import { Sidebar } from '../components/layout'
|
|
4
|
+
import { SidebarProvider } from '../context'
|
|
5
|
+
|
|
6
|
+
interface SidebarLayoutProps {
|
|
7
|
+
children: React.ReactNode
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const SidebarLayoutContent: React.FC<{ children: React.ReactNode }> = ({ children }) => {
|
|
11
|
+
const { layoutUtils } = useResponsiveLayout()
|
|
12
|
+
|
|
13
|
+
return (
|
|
14
|
+
<div className="min-h-screen bg-black flex">
|
|
15
|
+
{/* Sidebar */}
|
|
16
|
+
<Sidebar />
|
|
17
|
+
|
|
18
|
+
{/* Main content */}
|
|
19
|
+
<main className="flex-1 overflow-auto">
|
|
20
|
+
<div className={layoutUtils.getContainerClass()}>
|
|
21
|
+
{children}
|
|
22
|
+
</div>
|
|
23
|
+
</main>
|
|
24
|
+
</div>
|
|
25
|
+
)
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const SidebarLayout: React.FC<SidebarLayoutProps> = ({ children }) => {
|
|
29
|
+
return (
|
|
30
|
+
<SidebarProvider>
|
|
31
|
+
<SidebarLayoutContent>{children}</SidebarLayoutContent>
|
|
32
|
+
</SidebarProvider>
|
|
33
|
+
)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export default SidebarLayout
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { default as MainLayout } from './MainLayout'
|
|
2
|
+
export { default as DefaultLayout } from './DefaultLayout'
|
|
3
|
+
export { default as SidebarLayout } from './SidebarLayout'
|
|
4
|
+
export { default as DashboardLayout } from './DashboardLayout'
|
|
5
|
+
export { default as MinimalLayout } from './MinimalLayout'
|
package/src/main.tsx
ADDED