PWA: Interceptar enlaces para navegación en misma ventana
All checks were successful
build-and-deploy / build-and-deploy (push) Successful in 54s
All checks were successful
build-and-deploy / build-and-deploy (push) Successful in 54s
- Agregar capture_links al manifest para captura automática - Configurar clientsClaim y skipWaiting en workbox - Plugin de cliente para interceptar clics en enlaces - Interceptar window.open() para enlaces internos - Solo activo cuando la app corre como PWA instalada - Usar router de Nuxt para navegación interna fluida - Detectar display-mode standalone y window-controls-overlay
This commit is contained in:
81
nuxt4/app/plugins/pwa-link-handler.client.ts
Normal file
81
nuxt4/app/plugins/pwa-link-handler.client.ts
Normal file
@@ -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')
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user