2ff06ee7ae
Major Features:
- Internationalization (i18n) with auto-detection for ES/EN/PT
- Mobile-first responsive design for Studio and Experience
- Multi-model AI configuration (llama3.2:3b, qwen3.5:9b, gpt-oss:latest)
- Course language configuration (auto-detect or fixed per course)
Backend Changes:
- shared/common: ModelType enum for intelligent model selection
- LMS: log_ai_usage function migration (fix chat tutor 500 error)
- LMS/CMS: course language config fields (language_setting, fixed_language)
- LMS: /courses/{id}/language-config endpoint for language detection
Frontend Changes:
- Experience: Enhanced i18n with browser language detection
- Experience: Audio recording with HTTPS check and error handling
- Studio: Memory game with unique pair IDs and debug logging
- Studio: Expanded translations (250+ keys for ES, EN, PT)
- Both: Language selector in headers (mobile responsive)
Documentation:
- AI_MODELS_CONFIG.md: Multi-model configuration guide
- RESPONSIVIDAD_GUIA.md: Mobile-first design patterns
- I18N_RESPONSIVIDAD_IMPLEMENTACION.md: Implementation details
- DEBUG_AUDIO_RECORDING.md: Audio troubleshooting guide
- DEBUG_MEMORY_GAME.md: Memory game debugging steps
Bug Fixes:
- Fix chat tutor 500 error (missing log_ai_usage function)
- Fix audio recording (HTTPS check, browser compatibility)
- Fix memory game pair IDs (unique ID generation)
- Fix HotspotBlock TypeScript errors
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
6.2 KiB
6.2 KiB
Guía de Responsividad - OpenCCB
Principios Mobile-First
Breakpoints (Tailwind CSS)
/* Mobile: Default (0-639px) */
/* sm: 640px+ */
/* md: 768px+ */
/* lg: 1024px+ */
/* xl: 1280px+ */
/* 2xl: 1536px+ */
Jerarquía de Diseño
- Mobile (< 640px): Diseño de una sola columna, menú hamburguesa
- Tablet (640px - 1024px): 2 columnas, navegación visible
- Desktop (1024px+): Layout completo, todas las características
Componentes Responsivos
Layout Principal
// Mobile-first container
<div className="min-h-screen flex flex-col">
{/* Header responsivo */}
<header className="h-16 px-4 md:px-6">
{/* Logo y navegación */}
</header>
{/* Contenido principal */}
<main className="flex-1 px-4 md:px-6 py-4 md:py-8">
{children}
</main>
</div>
Navegación
Mobile:
- Menú hamburguesa (ícono)
- Sidebar deslizante desde la derecha
- Overlay con backdrop blur
- Items de navegación en columna
Desktop:
- Navegación horizontal visible
- Dropdowns al hacer hover/click
- Items en fila con espaciado
Tarjetas de Cursos
// Grid responsivo
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-4 md:gap-6">
{courses.map(course => (
<CourseCard key={course.id} course={course} />
))}
</div>
Tablas de Datos
Mobile:
- Scroll horizontal
- O tarjetas apiladas en lugar de tabla
Desktop:
- Tabla completa visible
<div className="overflow-x-auto">
<table className="min-w-full">
{/* tabla */}
</table>
</div>
Tipografía Fluida
// Títulos responsivos
<h1 className="text-2xl sm:text-3xl md:text-4xl lg:text-5xl font-bold">
Título
</h1>
// Texto de párrafo
<p className="text-sm md:text-base lg:text-lg">
Contenido
</p>
// Texto pequeño
<span className="text-xs md:text-sm">
Metadata
</span>
Espaciado Responsivo
// Padding responsivo
<div className="px-4 md:px-6 lg:px-8 py-4 md:py-6 lg:py-8">
{/* contenido */}
</div>
// Gap responsivo
<div className="flex flex-col md:flex-row gap-4 md:gap-6 lg:gap-8">
{/* items */}
</div>
Componentes Específicos
AppHeader (Experience)
Mobile (< 768px):
- Logo compacto
- Íconos de notificación y tema
- Botón de menú hamburguesa
- Sidebar deslizante con:
- Navegación completa
- Selector de idioma
- Toggle de tema
- Perfil de usuario
- Botón de logout
Desktop (≥ 768px):
- Logo completo
- Navegación horizontal visible
- Íconos de notificación, idioma, tema
- Perfil de usuario visible
- Botón de logout
Navbar (Studio)
Mobile (< 768px):
- Logo compacto
- Dropdowns colapsados
- Toggle de tema
- Selector de idioma
- Botón de menú hamburguesa
- Sidebar deslizante
Desktop (≥ 768px):
- Logo completo
- Dropdowns visibles
- Toggle de tema
- Selector de idioma
- Información de usuario visible
Reproductor de Lecciones
Mobile:
- Video en ancho completo
- Controles simplificados
- Pestañas colapsadas (acordeón)
- Navegación entre lecciones (botones)
Desktop:
- Video con tamaño fijo
- Sidebar con navegación de lecciones
- Pestañas visibles
- Panel de transcripción/resumen
Imágenes y Multimedia
// Imágenes responsivas
<Image
src={src}
alt={alt}
fill
sizes="(max-width: 640px) 100vw, (max-width: 1024px) 50vw, 25vw"
className="object-cover"
/>
// Video responsivo
<div className="aspect-video w-full">
<video controls className="w-full h-full">
{/* sources */}
</video>
</div>
Accesibilidad
Navegación por Teclado
- Todos los elementos interactivos deben ser focusables
- Orden de tab lógico
- Indicadores de focus visibles
Screen Readers
- Labels descriptivos en botones e íconos
aria-labelen íconos sin textoaria-expandeden elementos colapsablesaria-modalen diálogos
Contraste
- Relación de contraste mínima 4.5:1
- Texto grande: 3:1 mínimo
Pruebas de Responsividad
Dispositivos de Prueba
Chrome DevTools:
- iPhone SE (375x667)
- iPhone 12 Pro (390x844)
- iPad Air (820x1180)
- iPad Pro (1024x1366)
- Desktop (1920x1080)
Herramientas:
- Chrome DevTools Device Mode
- Firefox Responsive Design Mode
- BrowserStack (dispositivos reales)
Checklist de Pruebas
- Navegación funciona en mobile
- Menús desplegables accesibles
- Formularios usables en pantallas pequeñas
- Tablas con scroll horizontal o versión mobile
- Imágenes se escalan correctamente
- Texto legible sin zoom
- Botones táctiles (mínimo 44x44px)
- Sin overflow horizontal no intencional
- Layout no se rompe en tamaños extremos
Patrones Comunes
Mobile: Navegación Inferior
<nav className="fixed bottom-0 left-0 right-0 bg-white dark:bg-gray-900 border-t md:hidden">
<div className="flex justify-around items-center h-16">
{/* íconos de navegación */}
</div>
</nav>
Desktop: Sidebar Fija
<aside className="hidden md:block w-64 fixed left-0 top-16 bottom-0 overflow-y-auto">
{/* navegación lateral */}
</aside>
Tablas Responsivas
// Opción 1: Scroll horizontal
<div className="overflow-x-auto">
<table className="min-w-full divide-y divide-gray-200">
{/* tabla completa */}
</table>
</div>
// Opción 2: Tarjetas en mobile
<div className="block md:hidden">
{items.map(item => (
<Card key={item.id} item={item} />
))}
</div>
<div className="hidden md:block">
<table>
{/* tabla completa */}
</table>
</div>
Rendimiento
Lazy Loading
// Imágenes
<Image
src={src}
alt={alt}
loading="lazy"
width={400}
height={300}
/>
// Componentes pesados
const HeavyComponent = dynamic(() => import('./HeavyComponent'), {
loading: () => <p>Cargando...</p>,
ssr: false,
})
Code Splitting
// Carga diferida por ruta
const CourseDetail = dynamic(() => import('@/components/CourseDetail'))
Referencias
Última actualización: 2026-03-20 Versión: 1.0