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, ')')
}
}
})