responsive-system 1.2.8 → 1.3.2

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "responsive-system",
3
- "version": "1.2.8",
3
+ "version": "1.3.2",
4
4
  "description": "Sistema de layout responsivo con auto-scaling para Tailwind CSS",
5
5
  "type": "module",
6
6
  "main": "./dist/responsive-system.cjs",
@@ -4,14 +4,18 @@
4
4
  * Script postinstall para automatizar la configuración inicial completa
5
5
  * - Instala React, TypeScript, Tailwind automáticamente
6
6
  * - Inicializa proyecto Vite si está vacío
7
- * - Configura Tailwind
8
- * - Crea página de ejemplo con layouts
7
+ * - Pregunta qué layout quiere (interactivo)
8
+ * - Copia solo los componentes necesarios
9
+ * - Copia el hook useResponsive como archivo local
10
+ * - Crea página de ejemplo en pages/
11
+ * - Configura App.tsx con el layout seleccionado
9
12
  */
10
13
 
11
14
  import fs from 'fs'
12
15
  import path from 'path'
13
16
  import { execSync } from 'child_process'
14
17
  import { fileURLToPath } from 'url'
18
+ import readline from 'readline'
15
19
 
16
20
  const __filename = fileURLToPath(import.meta.url)
17
21
  const __dirname = path.dirname(__filename)
@@ -19,10 +23,17 @@ const __dirname = path.dirname(__filename)
19
23
  const projectRoot = process.cwd()
20
24
  const packageJsonPath = path.join(projectRoot, 'package.json')
21
25
 
26
+ // Detectar si se ejecuta como postinstall o manualmente
27
+ const isPostinstall = process.env.npm_lifecycle_event === 'postinstall'
28
+ const isManual = process.argv[1].includes('postinstall.js') && !isPostinstall
29
+
22
30
  console.log('')
23
- console.log('📦 responsive-system: Iniciando postinstall...')
31
+ console.log('📦 responsive-system: Iniciando configuración...')
24
32
  console.log(` Directorio: ${projectRoot}`)
25
33
  console.log('')
34
+ console.log('💡 Si este es tu primer uso, este script configurará todo automáticamente.')
35
+ console.log(' Si ya tienes el proyecto configurado, puedes cancelar (Ctrl+C)')
36
+ console.log('')
26
37
 
27
38
  // Verificar si package.json existe
28
39
  if (!fs.existsSync(packageJsonPath)) {
@@ -46,27 +57,356 @@ const isProjectEmpty = !packageJson.dependencies ||
46
57
  // Verificar qué está instalado - SOLO en package.json (no en node_modules para evitar conflictos)
47
58
  const hasReactInPackageJson = (packageJson.dependencies && packageJson.dependencies.react) ||
48
59
  (packageJson.devDependencies && packageJson.devDependencies.react)
49
- // NO verificar node_modules porque puede estar como dependencia transitiva y causar conflictos
50
- const hasReact = hasReactInPackageJson
51
-
52
60
  const hasVite = packageJson.devDependencies && packageJson.devDependencies.vite
53
-
54
61
  const tailwindInDevDeps = packageJson.devDependencies && packageJson.devDependencies.tailwindcss
55
62
  const typescriptInDevDeps = packageJson.devDependencies && packageJson.devDependencies.typescript
56
63
 
57
64
  let needsUpdate = false
58
65
 
66
+ // Función para preguntar al usuario qué layout quiere
67
+ async function askLayout() {
68
+ if (isPostinstall && !isManual) {
69
+ // Si es postinstall automático, usar 'default' por defecto
70
+ console.log(' ℹ️ Usando layout "default" por defecto')
71
+ console.log(' 💡 Ejecuta "npx responsive-system-setup" para cambiar el layout')
72
+ return 'default'
73
+ }
74
+
75
+ // Si es ejecución manual, preguntar interactivamente
76
+ const rl = readline.createInterface({
77
+ input: process.stdin,
78
+ output: process.stdout
79
+ })
80
+
81
+ return new Promise((resolve) => {
82
+ console.log('')
83
+ console.log('🎨 Selecciona el layout que quieres usar:')
84
+ console.log(' 1. default - Navigation + Footer')
85
+ console.log(' 2. sidebar - Sidebar lateral')
86
+ console.log(' 3. dashboard - Sidebar + Footer')
87
+ console.log(' 4. minimal - Sin componentes (solo contenido)')
88
+ console.log('')
89
+
90
+ rl.question(' Ingresa el número (1-4) o el nombre del layout: ', (answer) => {
91
+ rl.close()
92
+
93
+ const normalized = answer.trim().toLowerCase()
94
+
95
+ if (normalized === '1' || normalized === 'default') {
96
+ resolve('default')
97
+ } else if (normalized === '2' || normalized === 'sidebar') {
98
+ resolve('sidebar')
99
+ } else if (normalized === '3' || normalized === 'dashboard') {
100
+ resolve('dashboard')
101
+ } else if (normalized === '4' || normalized === 'minimal') {
102
+ resolve('minimal')
103
+ } else {
104
+ console.log(' ⚠️ Opción inválida, usando "default"')
105
+ resolve('default')
106
+ }
107
+ })
108
+ })
109
+ }
110
+
111
+ // Función para copiar archivo desde el paquete al proyecto
112
+ function copyFileFromPackage(relativePath, targetPath, isComponent = false) {
113
+ const sourcePath = path.join(__dirname, '..', relativePath)
114
+ const destPath = path.join(projectRoot, targetPath)
115
+
116
+ if (!fs.existsSync(sourcePath)) {
117
+ console.error(` ❌ No se encontró: ${relativePath}`)
118
+ return false
119
+ }
120
+
121
+ // Crear directorio destino si no existe
122
+ const destDir = path.dirname(destPath)
123
+ if (!fs.existsSync(destDir)) {
124
+ fs.mkdirSync(destDir, { recursive: true })
125
+ }
126
+
127
+ let content = fs.readFileSync(sourcePath, 'utf8')
128
+
129
+ // Si es un componente, reemplazar importaciones relativas por importaciones del paquete
130
+ if (isComponent) {
131
+ // Reemplazar importaciones de hooks
132
+ content = content.replace(
133
+ /from ['"]\.\.\/\.\.\/hooks['"]/g,
134
+ "from 'responsive-system'"
135
+ )
136
+ // Reemplazar importaciones de context
137
+ content = content.replace(
138
+ /from ['"]\.\.\/\.\.\/context['"]/g,
139
+ "from 'responsive-system'"
140
+ )
141
+ // Reemplazar importaciones de componentes/layout
142
+ content = content.replace(
143
+ /from ['"]\.\.\/components\/layout['"]/g,
144
+ "from 'responsive-system'"
145
+ )
146
+ }
147
+
148
+ fs.writeFileSync(destPath, content)
149
+ return true
150
+ }
151
+
152
+ // Función para generar componentes genéricos según el layout seleccionado
153
+ function generateLayoutComponents(selectedLayout) {
154
+ const componentsDir = path.join(projectRoot, 'src', 'components', 'layout')
155
+
156
+ // Crear directorio si no existe
157
+ if (!fs.existsSync(componentsDir)) {
158
+ fs.mkdirSync(componentsDir, { recursive: true })
159
+ }
160
+
161
+ const componentsToGenerate = {
162
+ default: ['Navigation', 'Footer'],
163
+ sidebar: ['Sidebar'],
164
+ dashboard: ['Sidebar', 'Footer'],
165
+ minimal: []
166
+ }
167
+
168
+ const components = componentsToGenerate[selectedLayout] || []
169
+
170
+ if (components.length === 0) {
171
+ console.log(' ✅ Layout minimal: No se generan componentes')
172
+ return
173
+ }
174
+
175
+ console.log(` 📦 Generando componentes genéricos para layout "${selectedLayout}":`)
176
+
177
+ // Generar Navigation genérico
178
+ if (components.includes('Navigation')) {
179
+ const navigationContent = `import { useResponsiveLayout } from 'responsive-system'
180
+
181
+ const Navigation = () => {
182
+ const { isMobile, breakpoint } = useResponsiveLayout()
183
+
184
+ return (
185
+ <nav className="sticky top-0 z-50 bg-gray-900 border-b border-gray-800">
186
+ <div className="px-4 py-4">
187
+ <div className="flex items-center justify-between">
188
+ <div className="flex items-center space-x-3">
189
+ <div className="w-8 h-8 bg-blue-500 rounded-lg flex items-center justify-center">
190
+ <span className="text-white font-bold text-sm">LO</span>
191
+ </div>
192
+ <h1 className="text-white font-semibold text-lg">Tu Aplicación</h1>
193
+ </div>
194
+
195
+ {isMobile && (
196
+ <button className="p-2 text-gray-400 hover:text-white">
197
+ <svg className="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
198
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M4 6h16M4 12h16M4 18h16" />
199
+ </svg>
200
+ </button>
201
+ )}
202
+ </div>
203
+ </div>
204
+ </nav>
205
+ )
206
+ }
207
+
208
+ export default Navigation
209
+ `
210
+ fs.writeFileSync(path.join(componentsDir, 'Navigation.tsx'), navigationContent)
211
+ console.log(' ✅ Navigation.tsx (genérico)')
212
+ }
213
+
214
+ // Generar Footer genérico
215
+ if (components.includes('Footer')) {
216
+ const footerContent = `import { useResponsiveLayout } from 'responsive-system'
217
+
218
+ const Footer = () => {
219
+ const { breakpoint } = useResponsiveLayout()
220
+
221
+ return (
222
+ <footer className="bg-gray-900 border-t border-gray-800">
223
+ <div className="px-4 py-6">
224
+ <div className="max-w-7xl mx-auto">
225
+ <div className="grid grid-cols-1 md:grid-cols-3 gap-6">
226
+ <div>
227
+ <h3 className="text-white font-semibold mb-2">Tu Aplicación</h3>
228
+ <p className="text-gray-400 text-sm">
229
+ Descripción de tu aplicación aquí.
230
+ </p>
231
+ </div>
232
+
233
+ <div>
234
+ <h3 className="text-white font-semibold mb-2">Enlaces</h3>
235
+ <ul className="space-y-1 text-gray-400 text-sm">
236
+ <li><a href="#" className="hover:text-white">Inicio</a></li>
237
+ <li><a href="#" className="hover:text-white">Acerca</a></li>
238
+ <li><a href="#" className="hover:text-white">Contacto</a></li>
239
+ </ul>
240
+ </div>
241
+
242
+ <div>
243
+ <h3 className="text-white font-semibold mb-2">Info</h3>
244
+ <p className="text-gray-400 text-xs">
245
+ Breakpoint: <span className="text-blue-400">{breakpoint.toUpperCase()}</span>
246
+ </p>
247
+ </div>
248
+ </div>
249
+
250
+ <div className="border-t border-gray-800 mt-6 pt-4 text-center">
251
+ <p className="text-gray-500 text-xs">
252
+ © {new Date().getFullYear()} Tu Aplicación. Todos los derechos reservados.
253
+ </p>
254
+ </div>
255
+ </div>
256
+ </div>
257
+ </footer>
258
+ )
259
+ }
260
+
261
+ export default Footer
262
+ `
263
+ fs.writeFileSync(path.join(componentsDir, 'Footer.tsx'), footerContent)
264
+ console.log(' ✅ Footer.tsx (genérico)')
265
+ }
266
+
267
+ // Generar Sidebar genérico
268
+ if (components.includes('Sidebar')) {
269
+ const sidebarContent = `import { useResponsiveLayout } from 'responsive-system'
270
+ import { useSidebar } from 'responsive-system'
271
+
272
+ const Sidebar = () => {
273
+ const { isMobile, isTablet } = useResponsiveLayout()
274
+ const { sidebarOpen, setSidebarOpen } = useSidebar()
275
+
276
+ const menuItems = [
277
+ { id: 'home', label: 'Inicio' },
278
+ { id: 'about', label: 'Acerca' },
279
+ { id: 'contact', label: 'Contacto' },
280
+ ]
281
+
282
+ return (
283
+ <>
284
+ {/* Hamburger button para móvil */}
285
+ {isMobile && (
286
+ <button
287
+ onClick={() => setSidebarOpen(true)}
288
+ className="fixed top-4 left-4 z-50 p-2 rounded-lg text-gray-300 hover:text-white hover:bg-gray-800 bg-gray-900 border border-gray-700"
289
+ >
290
+ <svg className="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
291
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M4 6h16M4 12h16M4 18h16" />
292
+ </svg>
293
+ </button>
294
+ )}
295
+
296
+ {/* Sidebar desktop */}
297
+ <aside className={\`bg-gray-900 border-r border-gray-800 \${isMobile ? 'hidden' : 'w-64 flex-shrink-0'} \${isTablet ? 'w-56' : 'w-64'}\`}>
298
+ <div className="p-6 flex flex-col h-full">
299
+ <div className="flex items-center space-x-3 mb-8">
300
+ <div className="w-8 h-8 bg-blue-500 rounded-lg flex items-center justify-center">
301
+ <span className="text-white font-bold text-sm">LO</span>
302
+ </div>
303
+ <span className="text-white font-bold text-lg">Tu Aplicación</span>
304
+ </div>
305
+
306
+ <nav className="space-y-2">
307
+ {menuItems.map((item) => (
308
+ <button
309
+ key={item.id}
310
+ className="w-full flex items-center px-4 py-3 rounded-lg transition-all text-left text-gray-300 hover:text-white hover:bg-gray-800"
311
+ >
312
+ <span className="font-medium">{item.label}</span>
313
+ </button>
314
+ ))}
315
+ </nav>
316
+ </div>
317
+ </aside>
318
+
319
+ {/* Sidebar móvil desplegable */}
320
+ {isMobile && sidebarOpen && (
321
+ <div className="fixed inset-0 z-40 bg-black/50" onClick={() => setSidebarOpen(false)}>
322
+ <div className="fixed top-0 left-0 w-64 h-full bg-gray-900 border-r border-gray-800">
323
+ <div className="p-6 flex flex-col h-full pt-20">
324
+ <div className="flex items-center space-x-3 mb-8">
325
+ <div className="w-8 h-8 bg-blue-500 rounded-lg flex items-center justify-center">
326
+ <span className="text-white font-bold text-sm">LO</span>
327
+ </div>
328
+ <span className="text-white font-bold text-lg">Tu Aplicación</span>
329
+ </div>
330
+
331
+ <nav className="space-y-2">
332
+ {menuItems.map((item) => (
333
+ <button
334
+ key={item.id}
335
+ onClick={() => setSidebarOpen(false)}
336
+ className="w-full flex items-center px-4 py-3 rounded-lg transition-all text-left text-gray-300 hover:text-white hover:bg-gray-800"
337
+ >
338
+ <span className="font-medium">{item.label}</span>
339
+ </button>
340
+ ))}
341
+ </nav>
342
+ </div>
343
+ </div>
344
+ </div>
345
+ )}
346
+ </>
347
+ )
348
+ }
349
+
350
+ export default Sidebar
351
+ `
352
+ fs.writeFileSync(path.join(componentsDir, 'Sidebar.tsx'), sidebarContent)
353
+ console.log(' ✅ Sidebar.tsx (genérico)')
354
+ }
355
+
356
+ // Crear index.ts para exportar los componentes
357
+ const indexContent = components.map(c => `export { default as ${c} } from './${c}'`).join('\n')
358
+ fs.writeFileSync(path.join(componentsDir, 'index.ts'), indexContent)
359
+ console.log(' ✅ index.ts')
360
+ }
361
+
362
+ // Función para copiar el hook useResponsive y sus dependencias
363
+ function copyUseResponsiveHook() {
364
+ console.log(' 📦 Copiando hook useResponsive y dependencias...')
365
+
366
+ // Crear directorio hooks
367
+ const hooksDir = path.join(projectRoot, 'src', 'hooks')
368
+ if (!fs.existsSync(hooksDir)) {
369
+ fs.mkdirSync(hooksDir, { recursive: true })
370
+ }
371
+
372
+ // Copiar tipos
373
+ const typesDir = path.join(projectRoot, 'src', 'types')
374
+ if (!fs.existsSync(typesDir)) {
375
+ fs.mkdirSync(typesDir, { recursive: true })
376
+ }
377
+ copyFileFromPackage('src/types/responsive.ts', 'src/types/responsive.ts')
378
+ console.log(' ✅ types/responsive.ts')
379
+
380
+ // Copiar constantes
381
+ const constantsDir = path.join(projectRoot, 'src', 'constants')
382
+ if (!fs.existsSync(constantsDir)) {
383
+ fs.mkdirSync(constantsDir, { recursive: true })
384
+ }
385
+ copyFileFromPackage('src/constants/breakpoints.ts', 'src/constants/breakpoints.ts')
386
+ console.log(' ✅ constants/breakpoints.ts')
387
+
388
+ // Copiar hook useResponsive
389
+ copyFileFromPackage('src/hooks/useResponsive.ts', 'src/hooks/useResponsive.ts')
390
+ console.log(' ✅ hooks/useResponsive.ts')
391
+
392
+ // Crear index.ts para exportar el hook
393
+ const indexContent = `export { useResponsive } from './useResponsive'
394
+ export type { ResponsiveState, Breakpoint, Orientation } from '../types/responsive'
395
+ export { DEFAULT_BREAKPOINTS, getCurrentBreakpoint, getBreakpointIndex, getBreakpointValue } from '../constants/breakpoints'
396
+ `
397
+ fs.writeFileSync(path.join(hooksDir, 'index.ts'), indexContent)
398
+ console.log(' ✅ hooks/index.ts')
399
+ }
400
+
59
401
  // ESTRATEGIA: Modificar directamente el package.json primero, luego instalar
60
402
  console.log('📦 responsive-system: Verificando dependencias...')
61
403
 
62
404
  // Agregar React a dependencies SOLO si NO está en package.json
63
- // NO verificar node_modules para evitar múltiples copias de React
64
405
  if (!hasReactInPackageJson) {
65
406
  console.log(' ➕ Agregando React a dependencies...')
66
407
  if (!packageJson.dependencies) {
67
408
  packageJson.dependencies = {}
68
409
  }
69
- // Usar versión compatible con peerDependencies del paquete
70
410
  packageJson.dependencies['react'] = '^19.1.1'
71
411
  packageJson.dependencies['react-dom'] = '^19.1.1'
72
412
  needsUpdate = true
@@ -85,9 +425,9 @@ if (isProjectEmpty && !hasVite) {
85
425
  needsUpdate = true
86
426
  }
87
427
 
88
- // Agregar TypeScript y Tailwind a devDependencies
428
+ // Agregar Tailwind y sus dependencias a devDependencies
89
429
  if (!tailwindInDevDeps) {
90
- console.log(' ➕ Agregando Tailwind a devDependencies...')
430
+ console.log(' ➕ Agregando Tailwind y PostCSS a devDependencies...')
91
431
  if (!packageJson.devDependencies) {
92
432
  packageJson.devDependencies = {}
93
433
  }
@@ -98,6 +438,7 @@ if (!tailwindInDevDeps) {
98
438
  needsUpdate = true
99
439
  }
100
440
 
441
+ // Agregar TypeScript y sus tipos a devDependencies
101
442
  if (!typescriptInDevDeps) {
102
443
  console.log(' ➕ Agregando TypeScript a devDependencies...')
103
444
  if (!packageJson.devDependencies) {
@@ -139,21 +480,73 @@ if (needsUpdate) {
139
480
  console.log('✅ responsive-system: Todas las dependencias ya están en package.json')
140
481
  }
141
482
 
142
- // Si el proyecto está vacío, crear estructura base
483
+ // Si el proyecto está vacío, crear README básico PRIMERO
143
484
  if (isProjectEmpty) {
485
+ // Crear README básico INMEDIATAMENTE para que el usuario sepa qué hacer
486
+ const readmePath = path.join(projectRoot, 'README.md')
487
+ if (!fs.existsSync(readmePath)) {
488
+ const basicReadme = `# Tu Aplicación
489
+
490
+ ## 🚀 Configuración Inicial
491
+
492
+ Acabas de instalar **responsive-system**. Para completar la configuración, ejecuta:
493
+
494
+ \`\`\`bash
495
+ npx responsive-system-setup
496
+ \`\`\`
497
+
498
+ Este comando:
499
+ - ✅ Instalará React, TypeScript, Tailwind y Vite automáticamente
500
+ - ✅ Te permitirá seleccionar el layout que prefieras
501
+ - ✅ Creará la estructura base del proyecto
502
+ - ✅ Generará componentes genéricos y página de ejemplo
503
+
504
+ ## 📦 ¿Qué es responsive-system?
505
+
506
+ Sistema completo de layout responsive con auto-scaling para React + Tailwind CSS.
507
+
508
+ - Auto-scaling automático (texto, espaciado, sombras)
509
+ - Layouts pre-configurados (default, sidebar, dashboard, minimal)
510
+ - Hook \`useResponsive\` para configuración manual
511
+ - Sin media queries necesarias
512
+
513
+ ---
514
+
515
+ **Siguiente paso:** Ejecuta \`npx responsive-system-setup\` para comenzar 🚀
516
+ `
517
+ fs.writeFileSync(readmePath, basicReadme)
518
+ console.log(' ✅ README.md básico creado con instrucciones')
519
+ }
520
+
144
521
  console.log('')
145
522
  console.log('📦 responsive-system: Proyecto vacío detectado, creando estructura base...')
523
+ console.log('')
524
+ console.log('💡 IMPORTANTE: Si este es tu primer uso, este script configurará todo automáticamente.')
525
+ console.log(' Si ya tienes el proyecto configurado, puedes cancelar (Ctrl+C)')
526
+ console.log('')
527
+
528
+ // Preguntar qué layout quiere
529
+ const selectedLayout = await askLayout()
530
+ console.log(` ✅ Layout seleccionado: "${selectedLayout}"`)
531
+ console.log('')
146
532
 
147
533
  // Crear estructura de directorios
148
- const dirs = ['src', 'src/components', 'src/pages', 'public']
534
+ const dirs = ['src', 'src/components', 'src/components/layout', 'src/pages', 'src/hooks', 'src/types', 'src/constants', 'public']
149
535
  dirs.forEach(dir => {
150
536
  const dirPath = path.join(projectRoot, dir)
151
537
  if (!fs.existsSync(dirPath)) {
152
538
  fs.mkdirSync(dirPath, { recursive: true })
153
- console.log(` ✅ Creado: ${dir}/`)
154
539
  }
155
540
  })
156
541
 
542
+ // Generar componentes genéricos según layout seleccionado
543
+ generateLayoutComponents(selectedLayout)
544
+ console.log('')
545
+
546
+ // Copiar hook useResponsive
547
+ copyUseResponsiveHook()
548
+ console.log('')
549
+
157
550
  // Crear vite.config.ts
158
551
  const viteConfigPath = path.join(projectRoot, 'vite.config.ts')
159
552
  if (!fs.existsSync(viteConfigPath)) {
@@ -303,7 +696,7 @@ import './index.css'
303
696
 
304
697
  ReactDOM.createRoot(document.getElementById('root')!).render(
305
698
  <React.StrictMode>
306
- <ResponsiveLayoutProvider defaultLayout="default">
699
+ <ResponsiveLayoutProvider defaultLayout="${selectedLayout}">
307
700
  <MainLayout>
308
701
  <App />
309
702
  </MainLayout>
@@ -318,81 +711,114 @@ ReactDOM.createRoot(document.getElementById('root')!).render(
318
711
  // Crear src/index.css
319
712
  const indexCssPath = path.join(projectRoot, 'src', 'index.css')
320
713
  if (!fs.existsSync(indexCssPath)) {
321
- // Tailwind CSS v4 usa @import en lugar de @tailwind
322
714
  const indexCss = `@import "tailwindcss";
323
715
  `
324
716
  fs.writeFileSync(indexCssPath, indexCss)
325
717
  console.log(' ✅ Creado: src/index.css')
326
718
  }
327
719
 
328
- // Crear src/App.tsx con página de ejemplo
329
- const appTsxPath = path.join(projectRoot, 'src', 'App.tsx')
330
- if (!fs.existsSync(appTsxPath)) {
331
- const appTsx = `import { useResponsiveLayout, LayoutSwitcher } from 'responsive-system'
720
+ // Crear src/pages/HomePage.tsx con página de ejemplo simple
721
+ const homePagePath = path.join(projectRoot, 'src', 'pages', 'HomePage.tsx')
722
+ if (!fs.existsSync(homePagePath)) {
723
+ const homePage = `import { useResponsiveLayout } from 'responsive-system'
724
+ import { useResponsive } from '../hooks'
332
725
 
333
- function App() {
334
- const { breakpoint, isMobile, layout } = useResponsiveLayout()
726
+ function HomePage() {
727
+ const { breakpoint, isMobile } = useResponsiveLayout()
728
+ const responsive = useResponsive()
335
729
 
336
730
  return (
337
- <div className="min-h-screen bg-gray-50 p-6">
338
- <div className="max-w-7xl mx-auto space-y-6">
339
- {/* Header con información del sistema */}
340
- <div className="bg-white rounded-lg shadow-lg p-6">
341
- <h1 className="text-4xl font-bold mb-4">Responsive System Demo</h1>
342
- <div className="grid grid-cols-1 md:grid-cols-3 gap-4">
343
- <div className="p-4 bg-blue-50 rounded">
344
- <p className="text-sm text-gray-600">Breakpoint actual</p>
345
- <p className="text-2xl font-bold">{breakpoint}</p>
346
- </div>
347
- <div className="p-4 bg-green-50 rounded">
348
- <p className="text-sm text-gray-600">Layout actual</p>
349
- <p className="text-2xl font-bold capitalize">{layout.current}</p>
350
- </div>
351
- <div className="p-4 bg-purple-50 rounded">
352
- <p className="text-sm text-gray-600">Dispositivo</p>
353
- <p className="text-2xl font-bold">{isMobile ? 'Móvil' : 'Desktop'}</p>
354
- </div>
355
- </div>
731
+ <div className="min-h-screen bg-gray-50 py-8 px-4">
732
+ <div className="max-w-7xl mx-auto space-y-8">
733
+ {/* Hero Section */}
734
+ <div className="bg-white rounded-lg shadow-md p-8 text-center">
735
+ <h1 className="text-4xl font-bold text-gray-900 mb-4">
736
+ Bienvenido a tu Aplicación
737
+ </h1>
738
+ <p className="text-lg text-gray-600 max-w-2xl mx-auto">
739
+ Esta es una página de ejemplo que demuestra el sistema responsive con auto-scaling.
740
+ Todo el contenido se ajusta automáticamente según el tamaño de pantalla.
741
+ </p>
356
742
  </div>
357
743
 
358
- {/* Selector de layouts */}
359
- <div className="bg-white rounded-lg shadow-lg p-6">
360
- <h2 className="text-2xl font-bold mb-4">Cambiar Layout</h2>
361
- <LayoutSwitcher />
744
+ {/* Info Cards */}
745
+ <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6">
746
+ <div className="bg-blue-50 rounded-lg p-6 border border-blue-200">
747
+ <h3 className="text-sm font-semibold text-blue-900 mb-2">Breakpoint</h3>
748
+ <p className="text-2xl font-bold text-blue-700">{breakpoint.toUpperCase()}</p>
749
+ </div>
750
+ <div className="bg-green-50 rounded-lg p-6 border border-green-200">
751
+ <h3 className="text-sm font-semibold text-green-900 mb-2">Dispositivo</h3>
752
+ <p className="text-2xl font-bold text-green-700">{isMobile ? 'Móvil' : 'Desktop'}</p>
753
+ </div>
754
+ <div className="bg-purple-50 rounded-lg p-6 border border-purple-200">
755
+ <h3 className="text-sm font-semibold text-purple-900 mb-2">Ancho</h3>
756
+ <p className="text-2xl font-bold text-purple-700">{responsive.width}px</p>
757
+ </div>
758
+ <div className="bg-orange-50 rounded-lg p-6 border border-orange-200">
759
+ <h3 className="text-sm font-semibold text-orange-900 mb-2">Alto</h3>
760
+ <p className="text-2xl font-bold text-orange-700">{responsive.height}px</p>
761
+ </div>
362
762
  </div>
363
763
 
364
- {/* Cards de ejemplo */}
764
+ {/* Content Cards */}
365
765
  <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
366
766
  {[1, 2, 3, 4, 5, 6].map((i) => (
367
- <div key={i} className="bg-white rounded-lg shadow-lg p-6">
368
- <h3 className="text-xl font-bold mb-2">Card {i}</h3>
767
+ <div key={i} className="bg-white rounded-lg shadow-md p-6 hover:shadow-lg transition-shadow">
768
+ <div className="w-12 h-12 bg-blue-500 rounded-lg flex items-center justify-center mb-4">
769
+ <span className="text-white font-bold text-xl">{i}</span>
770
+ </div>
771
+ <h3 className="text-xl font-bold text-gray-900 mb-2">Card {i}</h3>
369
772
  <p className="text-gray-600">
370
- Este es un ejemplo de card que escala automáticamente según el tamaño de pantalla.
371
- Todo el texto, espaciado y sombras se ajustan automáticamente.
773
+ Este es un ejemplo de card. El texto, espaciado y sombras se ajustan automáticamente
774
+ según el tamaño de pantalla gracias al sistema de auto-scaling.
372
775
  </p>
373
776
  </div>
374
777
  ))}
375
778
  </div>
376
779
 
377
- {/* Información */}
378
- <div className="bg-white rounded-lg shadow-lg p-6">
379
- <h2 className="text-2xl font-bold mb-4">Cómo funciona</h2>
380
- <ul className="space-y-2 text-gray-700">
381
- <li>✅ <strong>Auto-scaling:</strong> Todo escala automáticamente (texto, espaciado, sombras)</li>
382
- <li>✅ <strong>Layouts:</strong> Cambia entre default, sidebar, dashboard y minimal</li>
383
- <li>✅ <strong>Responsive:</strong> Se adapta automáticamente a todos los tamaños de pantalla</li>
384
- <li>✅ <strong>Sin media queries:</strong> Usa el hook useResponsive para lógica condicional</li>
385
- </ul>
780
+ {/* Info Section */}
781
+ <div className="bg-white rounded-lg shadow-md p-8">
782
+ <h2 className="text-2xl font-bold text-gray-900 mb-4">Sistema Responsive</h2>
783
+ <div className="space-y-3 text-gray-700">
784
+ <p>
785
+ <strong className="text-gray-900">Auto-scaling activo:</strong> Todo el contenido escala
786
+ automáticamente según el breakpoint actual (texto, espaciado, sombras).
787
+ </p>
788
+ <p>
789
+ <strong className="text-gray-900">Hook useResponsive:</strong> Disponible en{' '}
790
+ <code className="bg-gray-100 px-2 py-1 rounded text-sm">src/hooks/useResponsive.ts</code>{' '}
791
+ para configuración manual cuando lo necesites.
792
+ </p>
793
+ <p>
794
+ <strong className="text-gray-900">Layout actual:</strong> <span className="capitalize">{selectedLayout}</span>
795
+ </p>
796
+ </div>
386
797
  </div>
387
798
  </div>
388
799
  </div>
389
800
  )
390
801
  }
391
802
 
803
+ export default HomePage
804
+ `
805
+ fs.writeFileSync(homePagePath, homePage)
806
+ console.log(' ✅ Creado: src/pages/HomePage.tsx (página de ejemplo simple)')
807
+ }
808
+
809
+ // Crear src/App.tsx que importa la página
810
+ const appTsxPath = path.join(projectRoot, 'src', 'App.tsx')
811
+ if (!fs.existsSync(appTsxPath)) {
812
+ const appTsx = `import HomePage from './pages/HomePage'
813
+
814
+ function App() {
815
+ return <HomePage />
816
+ }
817
+
392
818
  export default App
393
819
  `
394
820
  fs.writeFileSync(appTsxPath, appTsx)
395
- console.log(' ✅ Creado: src/App.tsx con página de ejemplo')
821
+ console.log(' ✅ Creado: src/App.tsx')
396
822
  }
397
823
 
398
824
  // Actualizar package.json con scripts
@@ -412,6 +838,106 @@ export default App
412
838
  fs.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2))
413
839
  console.log(' ✅ Actualizado: package.json con scripts')
414
840
 
841
+ // Actualizar README.md con información completa
842
+ // Si ya existe (el básico), lo reemplazamos con el completo
843
+ if (fs.existsSync(readmePath)) {
844
+ const readmeContent = `# Tu Aplicación
845
+
846
+ Proyecto inicializado con **responsive-system**.
847
+
848
+ ## 🚀 Inicio Rápido
849
+
850
+ Después de instalar el paquete, ejecuta el script de configuración:
851
+
852
+ \`\`\`bash
853
+ npx responsive-system-setup
854
+ \`\`\`
855
+
856
+ O si prefieres ejecutarlo directamente:
857
+
858
+ \`\`\`bash
859
+ node node_modules/responsive-system/scripts/postinstall.js
860
+ \`\`\`
861
+
862
+ Luego inicia el servidor de desarrollo:
863
+
864
+ \`\`\`bash
865
+ npm run dev
866
+ \`\`\`
867
+
868
+ Abre http://localhost:5173 en tu navegador.
869
+
870
+ ## 📁 Estructura del Proyecto
871
+
872
+ - \`src/pages/\` - Páginas de tu aplicación
873
+ - \`src/components/layout/\` - Componentes de layout (Navigation, Footer, Sidebar)
874
+ - \`src/hooks/useResponsive.ts\` - Hook para configuración responsive manual
875
+ - \`src/App.tsx\` - Componente principal
876
+ - \`src/main.tsx\` - Punto de entrada
877
+
878
+ ## 🎨 Layout Actual
879
+
880
+ Layout seleccionado: **${selectedLayout}**
881
+
882
+ - **default**: Navigation + Footer
883
+ - **sidebar**: Sidebar lateral
884
+ - **dashboard**: Sidebar + Footer
885
+ - **minimal**: Sin componentes (solo contenido)
886
+
887
+ ## 🔧 Personalización
888
+
889
+ ### Cambiar el Layout
890
+
891
+ Si quieres cambiar el layout después de la instalación:
892
+
893
+ \`\`\`bash
894
+ npx responsive-system-setup
895
+ \`\`\`
896
+
897
+ ### Usar el Hook useResponsive
898
+
899
+ El hook \`useResponsive\` está disponible localmente en \`src/hooks/useResponsive.ts\`:
900
+
901
+ \`\`\`typescript
902
+ import { useResponsive } from '../hooks'
903
+
904
+ function MyComponent() {
905
+ const { breakpoint, isMobile, isDesktop, width, height } = useResponsive()
906
+
907
+ // Tu lógica aquí
908
+ }
909
+ \`\`\`
910
+
911
+ ### Personalizar Componentes
912
+
913
+ Los componentes de layout están en \`src/components/layout/\` y puedes modificarlos según tus necesidades.
914
+
915
+ ## 📚 Documentación
916
+
917
+ - [responsive-system en npm](https://www.npmjs.com/package/responsive-system)
918
+ - Hook \`useResponsive\`: \`src/hooks/useResponsive.ts\`
919
+ - Tipos TypeScript: \`src/types/responsive.ts\`
920
+
921
+ ## ✅ Características
922
+
923
+ - ✅ Auto-scaling automático (texto, espaciado, sombras)
924
+ - ✅ Layout responsive que se adapta a todos los tamaños
925
+ - ✅ Hook \`useResponsive\` para configuración manual
926
+ - ✅ Componentes de layout personalizables
927
+ - ✅ Sin media queries necesarias
928
+
929
+ ---
930
+
931
+ **¡Listo para empezar a desarrollar!** 🎉
932
+ `
933
+ fs.writeFileSync(readmePath, readmeContent)
934
+ console.log(' ✅ Actualizado: README.md con instrucciones completas')
935
+ } else {
936
+ // Si no existe, crearlo completo
937
+ fs.writeFileSync(readmePath, readmeContent)
938
+ console.log(' ✅ Creado: README.md con instrucciones completas')
939
+ }
940
+
415
941
  console.log('')
416
942
  console.log('🎉 responsive-system: Proyecto inicializado correctamente!')
417
943
  console.log('')
@@ -419,8 +945,23 @@ export default App
419
945
  console.log(' 1. npm run dev')
420
946
  console.log(' 2. Abre http://localhost:5173')
421
947
  console.log('')
948
+ console.log(`Layout seleccionado: "${selectedLayout}"`)
949
+ console.log(' - Componentes generados en src/components/layout/')
950
+ console.log(' - Hook useResponsive disponible en src/hooks/useResponsive.ts')
951
+ console.log(' - Página de ejemplo en src/pages/HomePage.tsx')
952
+ console.log(' - README.md creado con instrucciones')
953
+ console.log('')
954
+ console.log('💡 Para cambiar el layout después, ejecuta: npx responsive-system-setup')
955
+ console.log('')
956
+ } else {
957
+ console.log('✅ responsive-system: Proyecto ya inicializado')
422
958
  }
423
959
 
424
960
  console.log('')
425
961
  console.log('✅ responsive-system: postinstall completado')
426
962
  console.log('')
963
+ console.log('📝 NOTA: Si instalaste el paquete pero este script no se ejecutó automáticamente,')
964
+ console.log(' ejecuta uno de estos comandos:')
965
+ console.log(' - npx responsive-system-setup')
966
+ console.log(' - node node_modules/responsive-system/scripts/postinstall.js')
967
+ console.log('')