diff --git a/nuxt4/app/plugins/pwa-link-handler.client.ts b/nuxt4/app/plugins/pwa-link-handler.client.ts new file mode 100644 index 0000000..f2d88f2 --- /dev/null +++ b/nuxt4/app/plugins/pwa-link-handler.client.ts @@ -0,0 +1,81 @@ +/** + * Plugin para interceptar enlaces externos que apuntan a esta PWA + * y navegarlos dentro de la misma ventana en lugar de abrir nuevas ventanas/pestañas + */ +export default defineNuxtPlugin(() => { + if (import.meta.client && typeof window !== 'undefined') { + // Detectar si la app está corriendo como PWA instalada + const isPWA = window.matchMedia('(display-mode: standalone)').matches || + window.matchMedia('(display-mode: window-controls-overlay)').matches || + (window.navigator as any).standalone === true + + if (isPWA) { + // Obtener el origin de la aplicación + const appOrigin = window.location.origin + + // Interceptar clics en enlaces externos + document.addEventListener('click', (event) => { + const target = event.target as HTMLElement + + // Buscar el enlace más cercano (puede ser un elemento hijo del enlace) + const link = target.closest('a') + + if (!link) return + + const href = link.getAttribute('href') + if (!href) return + + try { + const url = new URL(href, window.location.origin) + + // Solo interceptar enlaces que apunten a este origin + if (url.origin === appOrigin) { + // Si el enlace tiene target="_blank", no interceptar + const linkTarget = link.getAttribute('target') + if (linkTarget === '_blank') return + + // Prevenir comportamiento por defecto + event.preventDefault() + + // Navegar usando el router de Nuxt si está dentro del scope + const router = useRouter() + const relativePath = url.pathname + url.search + url.hash + + // Usar el router de Nuxt para navegación interna + router.push(relativePath) + } + } catch (error) { + // Si no se puede parsear la URL, dejar que el navegador maneje el enlace + console.debug('Error parsing link URL:', error) + } + }, { capture: true }) + + // Interceptar window.open para links que apunten a esta app + const originalWindowOpen = window.open + window.open = function(url?: string | URL, target?: string, features?: string) { + if (!url) { + return originalWindowOpen.call(window, url, target, features) + } + + try { + const urlObj = typeof url === 'string' ? new URL(url, window.location.origin) : url + + // Si es un enlace a esta app y no tiene target especificado o es _self + if (urlObj.origin === appOrigin && (!target || target === '_self')) { + const router = useRouter() + const relativePath = urlObj.pathname + urlObj.search + urlObj.hash + router.push(relativePath) + return null + } + } catch (error) { + console.debug('Error parsing window.open URL:', error) + } + + // Para otros casos, usar el comportamiento original + return originalWindowOpen.call(window, url, target, features) + } + + console.log('✅ PWA link handler initialized - capturing internal links') + } + } +}) diff --git a/nuxt4/nuxt.config.ts b/nuxt4/nuxt.config.ts index 4a41d8c..b694c16 100644 --- a/nuxt4/nuxt.config.ts +++ b/nuxt4/nuxt.config.ts @@ -37,10 +37,12 @@ export default defineNuxtConfig({ theme_color: '#00DC82', background_color: '#ffffff', display: 'standalone', - display_override: ['window-controls-overlay'], + display_override: ['window-controls-overlay', 'standalone'], orientation: 'portrait', scope: '/', - start_url: '/', + start_url: '/?source=pwa', + // Capturar todos los enlaces que apunten a esta app + capture_links: 'existing-client-navigate', icons: [ { src: '/icon-192x192.png', @@ -83,6 +85,10 @@ export default defineNuxtConfig({ navigateFallbackDenylist: [/^\/api\//, /^\/authentik\//], globPatterns: ['**/*.{js,css,html,png,svg,ico,json}'], cleanupOutdatedCaches: true, + // Capturar todas las navegaciones dentro del scope + navigateFallbackAllowlist: [/^\//], + clientsClaim: true, + skipWaiting: true, runtimeCaching: [ { urlPattern: /^https:\/\/authentik\.nucleoriofrio\.com\/.*/i,