Feat: Agregar estructura PWA Nuxt4 y configuración de desarrollo
Configuración PWA: - Agregar estructura completa de Nuxt4 para PWA - Configurar .env.example con variables de entorno - Preparar aplicación para instalación offline Configuración Claude Code: - Agregar .claude/ con settings y hooks - Configurar entorno de desarrollo con Claude CI/CD: - Agregar .gitea/workflows para Gitea Actions - Preparar pipeline de despliegue automático Docker: - Actualizar docker-compose.yml con servicios PWA - Configurar networking entre servicios Git: - Actualizar .gitignore para excluir archivos de build - Ignorar node_modules y archivos temporales
BIN
nuxt4/public/apple-touch-icon.png
Normal file
|
After Width: | Height: | Size: 45 KiB |
BIN
nuxt4/public/favicon.ico
Normal file
|
After Width: | Height: | Size: 4.2 KiB |
BIN
nuxt4/public/icon-128x128.png
Normal file
|
After Width: | Height: | Size: 24 KiB |
BIN
nuxt4/public/icon-144x144.png
Normal file
|
After Width: | Height: | Size: 28 KiB |
BIN
nuxt4/public/icon-152x152.png
Normal file
|
After Width: | Height: | Size: 31 KiB |
BIN
nuxt4/public/icon-192x192.png
Normal file
|
After Width: | Height: | Size: 46 KiB |
BIN
nuxt4/public/icon-256x256.png
Normal file
|
After Width: | Height: | Size: 75 KiB |
BIN
nuxt4/public/icon-384x384.png
Normal file
|
After Width: | Height: | Size: 161 KiB |
BIN
nuxt4/public/icon-512x512-maskable.png
Normal file
|
After Width: | Height: | Size: 19 KiB |
BIN
nuxt4/public/icon-512x512.png
Normal file
|
After Width: | Height: | Size: 274 KiB |
BIN
nuxt4/public/icon-72x72.png
Normal file
|
After Width: | Height: | Size: 9.6 KiB |
BIN
nuxt4/public/icon-96x96.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
35
nuxt4/public/icon-maskable.svg
Normal file
@@ -0,0 +1,35 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" fill="none">
|
||||
<!-- Background gradient para maskable (fondo completo sin transparencia) -->
|
||||
<defs>
|
||||
<linearGradient id="grad1" x1="0%" y1="0%" x2="100%" y2="100%">
|
||||
<stop offset="0%" style="stop-color:#00DC82;stop-opacity:1" />
|
||||
<stop offset="100%" style="stop-color:#00A155;stop-opacity:1" />
|
||||
</linearGradient>
|
||||
<linearGradient id="grad2" x1="0%" y1="0%" x2="100%" y2="100%">
|
||||
<stop offset="0%" style="stop-color:#4A90E2;stop-opacity:1" />
|
||||
<stop offset="100%" style="stop-color:#2E5C8A;stop-opacity:1" />
|
||||
</linearGradient>
|
||||
</defs>
|
||||
|
||||
<!-- Fondo completo (sin transparencia para evitar el blanco en Windows) -->
|
||||
<rect width="512" height="512" fill="url(#grad1)"/>
|
||||
|
||||
<!-- Contenido en el 80% central (safe zone para maskable icons) -->
|
||||
<g transform="translate(256, 256) scale(0.9) translate(-256, -256)">
|
||||
<!-- Shield shape (Authentik security) -->
|
||||
<path d="M256 80 L380 140 L380 280 Q380 360 256 420 Q132 360 132 280 L132 140 Z"
|
||||
fill="url(#grad2)" opacity="0.3"/>
|
||||
|
||||
<!-- Letter N (Nuxt) -->
|
||||
<path d="M180 200 L180 340 L220 340 L220 260 L292 340 L332 340 L332 200 L292 200 L292 280 L220 200 Z"
|
||||
fill="white" stroke="white" stroke-width="4"/>
|
||||
|
||||
<!-- Lock icon (Authentication) -->
|
||||
<g transform="translate(340, 180)">
|
||||
<rect x="-20" y="10" width="40" height="50" rx="5" fill="white" opacity="0.9"/>
|
||||
<path d="M -15 10 L -15 -5 Q -15 -20 0 -20 Q 15 -20 15 -5 L 15 10"
|
||||
stroke="white" stroke-width="6" fill="none" opacity="0.9"/>
|
||||
<circle cx="0" cy="30" r="5" fill="#00DC82"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.6 KiB |
32
nuxt4/public/icon.svg
Normal file
@@ -0,0 +1,32 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" fill="none">
|
||||
<!-- Background gradient -->
|
||||
<defs>
|
||||
<linearGradient id="grad1" x1="0%" y1="0%" x2="100%" y2="100%">
|
||||
<stop offset="0%" style="stop-color:#00DC82;stop-opacity:1" />
|
||||
<stop offset="100%" style="stop-color:#00A155;stop-opacity:1" />
|
||||
</linearGradient>
|
||||
<linearGradient id="grad2" x1="0%" y1="0%" x2="100%" y2="100%">
|
||||
<stop offset="0%" style="stop-color:#4A90E2;stop-opacity:1" />
|
||||
<stop offset="100%" style="stop-color:#2E5C8A;stop-opacity:1" />
|
||||
</linearGradient>
|
||||
</defs>
|
||||
|
||||
<!-- Background circle -->
|
||||
<circle cx="256" cy="256" r="240" fill="url(#grad1)"/>
|
||||
|
||||
<!-- Shield shape (Authentik security) -->
|
||||
<path d="M256 80 L380 140 L380 280 Q380 360 256 420 Q132 360 132 280 L132 140 Z"
|
||||
fill="url(#grad2)" opacity="0.3"/>
|
||||
|
||||
<!-- Letter N (Nuxt) -->
|
||||
<path d="M180 200 L180 340 L220 340 L220 260 L292 340 L332 340 L332 200 L292 200 L292 280 L220 200 Z"
|
||||
fill="white" stroke="white" stroke-width="4"/>
|
||||
|
||||
<!-- Lock icon (Authentication) -->
|
||||
<g transform="translate(340, 180)">
|
||||
<rect x="-20" y="10" width="40" height="50" rx="5" fill="white" opacity="0.9"/>
|
||||
<path d="M -15 10 L -15 -5 Q -15 -20 0 -20 Q 15 -20 15 -5 L 15 10"
|
||||
stroke="white" stroke-width="6" fill="none" opacity="0.9"/>
|
||||
<circle cx="0" cy="30" r="5" fill="url(#grad1)"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.4 KiB |
130
nuxt4/public/offline.html
Normal file
@@ -0,0 +1,130 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="es">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Modo Offline - Plantilla Nuxt + Authentik</title>
|
||||
<style>
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
min-height: 100vh;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.container {
|
||||
background: white;
|
||||
border-radius: 16px;
|
||||
padding: 48px 32px;
|
||||
max-width: 480px;
|
||||
width: 100%;
|
||||
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.icon {
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
margin: 0 auto 24px;
|
||||
background: #f3f4f6;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 40px;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 28px;
|
||||
color: #1f2937;
|
||||
margin-bottom: 16px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
p {
|
||||
font-size: 16px;
|
||||
color: #6b7280;
|
||||
line-height: 1.6;
|
||||
margin-bottom: 32px;
|
||||
}
|
||||
|
||||
.button {
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
color: white;
|
||||
border: none;
|
||||
padding: 14px 32px;
|
||||
border-radius: 8px;
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
transition: transform 0.2s, box-shadow 0.2s;
|
||||
box-shadow: 0 4px 12px rgba(102, 126, 234, 0.4);
|
||||
}
|
||||
|
||||
.button:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 6px 16px rgba(102, 126, 234, 0.5);
|
||||
}
|
||||
|
||||
.button:active {
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
.status {
|
||||
display: inline-block;
|
||||
margin-top: 24px;
|
||||
padding: 8px 16px;
|
||||
background: #fef3c7;
|
||||
color: #92400e;
|
||||
border-radius: 6px;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="icon">📡</div>
|
||||
<h1>Modo Offline</h1>
|
||||
<p>
|
||||
No tienes conexión a internet en este momento.
|
||||
</p>
|
||||
<p>
|
||||
<strong>Esta aplicación usa SSR (Server-Side Rendering) con autenticación Authentik</strong>, por lo que requiere conexión para cargar cuando se abre desde cero.
|
||||
</p>
|
||||
<p style="font-size: 14px; color: #9ca3af;">
|
||||
💡 <strong>Nota técnica:</strong> El modo offline completo solo funcionaría sin autenticación o sin SSR (SPA).
|
||||
Sin embargo, si ya tienes la app abierta y pierdes conexión, la interfaz seguirá funcionando con los datos cacheados.
|
||||
</p>
|
||||
<button class="button" onclick="window.location.reload()">
|
||||
Reintentar Conexión
|
||||
</button>
|
||||
<div class="status">
|
||||
⚠️ Sin conexión
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// Verificar conexión cada 3 segundos
|
||||
setInterval(() => {
|
||||
if (navigator.onLine) {
|
||||
window.location.href = '/';
|
||||
}
|
||||
}, 3000);
|
||||
|
||||
// Escuchar evento de conexión
|
||||
window.addEventListener('online', () => {
|
||||
window.location.href = '/';
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
2
nuxt4/public/robots.txt
Normal file
@@ -0,0 +1,2 @@
|
||||
User-Agent: *
|
||||
Disallow:
|
||||
BIN
nuxt4/public/screenshots/desktop-1.png
Normal file
|
After Width: | Height: | Size: 101 KiB |
BIN
nuxt4/public/screenshots/mobile-1.png
Normal file
|
After Width: | Height: | Size: 73 KiB |
BIN
nuxt4/public/screenshots/tablet-1.png
Normal file
|
After Width: | Height: | Size: 79 KiB |