From 99062559c41bb631fbf1c33d11ab0c1dd18ee19c Mon Sep 17 00:00:00 2001 From: josedario87 Date: Fri, 17 Oct 2025 04:57:51 -0600 Subject: [PATCH] Desktop: Abrir app-items en nueva ventana para lanzar PWAs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Crear composable useDeviceType para detectar desktop/móvil - Modificar ApplicationsList para usar target='_blank' en desktop - Ajustar pwa-link-handler para permitir nuevas ventanas en desktop - En móvil mantener comportamiento original según openInNewTab --- .../app/components/auth/ApplicationsList.vue | 14 ++++++-- nuxt4/app/composables/useDeviceType.ts | 33 +++++++++++++++++++ nuxt4/app/plugins/pwa-link-handler.client.ts | 21 ++++++++++-- 3 files changed, 64 insertions(+), 4 deletions(-) create mode 100644 nuxt4/app/composables/useDeviceType.ts diff --git a/nuxt4/app/components/auth/ApplicationsList.vue b/nuxt4/app/components/auth/ApplicationsList.vue index c5ba146..4feca72 100644 --- a/nuxt4/app/components/auth/ApplicationsList.vue +++ b/nuxt4/app/components/auth/ApplicationsList.vue @@ -71,7 +71,7 @@ v-for="app in filteredApplications" :key="app.pk" :href="app.launchUrl" - :target="app.openInNewTab ? '_blank' : '_self'" + :target="shouldOpenInNewTab(app) ? '_blank' : '_self'" class="app-card" >
@@ -96,7 +96,7 @@ {{ app.name }} @@ -137,6 +137,9 @@ interface Application { openInNewTab: boolean } +// Detectar si estamos en desktop +const { isDesktop } = useDeviceType() + const { data: applicationsRaw, pending, error, refresh } = await useFetch('/api/authentik/applications', { default: () => [] }) @@ -304,6 +307,13 @@ const refreshInterval = setInterval(() => { refresh() }, 5 * 60 * 1000) +// Determinar si un enlace debe abrirse en nueva ventana +// En desktop, siempre abrir en nueva ventana para lanzar PWAs +// En móvil, respetar la configuración de la app +const shouldOpenInNewTab = (app: Application): boolean => { + return isDesktop.value || app.openInNewTab +} + // Limpiar interval cuando el componente se desmonte onUnmounted(() => { clearInterval(refreshInterval) diff --git a/nuxt4/app/composables/useDeviceType.ts b/nuxt4/app/composables/useDeviceType.ts new file mode 100644 index 0000000..9659797 --- /dev/null +++ b/nuxt4/app/composables/useDeviceType.ts @@ -0,0 +1,33 @@ +/** + * Composable para detectar el tipo de dispositivo (desktop o móvil) + * Usa matchMedia para detectar el tamaño de pantalla + */ +export const useDeviceType = () => { + const isDesktop = ref(false) + + if (import.meta.client && typeof window !== 'undefined') { + // Detectar si el dispositivo es desktop basado en el ancho de pantalla + // Usamos 1024px como punto de corte (típico para tablets/desktops) + const mediaQuery = window.matchMedia('(min-width: 1024px)') + + // Establecer valor inicial + isDesktop.value = mediaQuery.matches + + // Escuchar cambios en el tamaño de pantalla + const handleChange = (e: MediaQueryListEvent) => { + isDesktop.value = e.matches + } + + mediaQuery.addEventListener('change', handleChange) + + // Cleanup al desmontar + onUnmounted(() => { + mediaQuery.removeEventListener('change', handleChange) + }) + } + + return { + isDesktop: readonly(isDesktop), + isMobile: computed(() => !isDesktop.value) + } +} diff --git a/nuxt4/app/plugins/pwa-link-handler.client.ts b/nuxt4/app/plugins/pwa-link-handler.client.ts index f2d88f2..28d5f91 100644 --- a/nuxt4/app/plugins/pwa-link-handler.client.ts +++ b/nuxt4/app/plugins/pwa-link-handler.client.ts @@ -1,6 +1,8 @@ /** * 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 + * En desktop, permite que los enlaces con target="_blank" abran nuevas ventanas para + * lanzar PWAs correspondientes */ export default defineNuxtPlugin(() => { if (import.meta.client && typeof window !== 'undefined') { @@ -9,6 +11,9 @@ export default defineNuxtPlugin(() => { window.matchMedia('(display-mode: window-controls-overlay)').matches || (window.navigator as any).standalone === true + // Detectar si estamos en desktop + const isDesktop = window.matchMedia('(min-width: 1024px)').matches + if (isPWA) { // Obtener el origin de la aplicación const appOrigin = window.location.origin @@ -31,8 +36,12 @@ export default defineNuxtPlugin(() => { // Solo interceptar enlaces que apunten a este origin if (url.origin === appOrigin) { // Si el enlace tiene target="_blank", no interceptar + // Esto permite que en desktop los enlaces abran nuevas ventanas (PWAs) const linkTarget = link.getAttribute('target') - if (linkTarget === '_blank') return + if (linkTarget === '_blank') { + console.debug('Permitiendo apertura de nueva ventana para:', href) + return + } // Prevenir comportamiento por defecto event.preventDefault() @@ -51,6 +60,7 @@ export default defineNuxtPlugin(() => { }, { capture: true }) // Interceptar window.open para links que apunten a esta app + // En desktop, permitimos nuevas ventanas con target="_blank" const originalWindowOpen = window.open window.open = function(url?: string | URL, target?: string, features?: string) { if (!url) { @@ -61,12 +71,19 @@ export default defineNuxtPlugin(() => { 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 + // Y NO estamos en desktop con target _blank (para permitir lanzar PWAs) if (urlObj.origin === appOrigin && (!target || target === '_self')) { const router = useRouter() const relativePath = urlObj.pathname + urlObj.search + urlObj.hash router.push(relativePath) return null } + + // En desktop con target="_blank", permitir la apertura normal + if (isDesktop && target === '_blank') { + console.debug('Permitiendo window.open en desktop para:', url) + return originalWindowOpen.call(window, url, target, features) + } } catch (error) { console.debug('Error parsing window.open URL:', error) } @@ -75,7 +92,7 @@ export default defineNuxtPlugin(() => { return originalWindowOpen.call(window, url, target, features) } - console.log('✅ PWA link handler initialized - capturing internal links') + console.log('✅ PWA link handler initialized - capturing internal links (desktop mode:', isDesktop, ')') } } })