Agregar iconos locales de servicios y mejorar fallback de iconos
All checks were successful
build-and-deploy / build-and-deploy (push) Successful in 58s

This commit is contained in:
2025-10-17 05:46:30 -06:00
parent dc9d6ec959
commit bea01d3e5d
8 changed files with 104 additions and 4 deletions

View File

@@ -186,6 +186,13 @@ const getAppIconUrl = (app: Application): string | null => {
return null
}
// Intentar primero ícono local basado en slug
if (app.slug) {
const localIconPath = `/app-icons/${app.slug}.svg`
// Retornar path local - si falla se manejará en handleIconError
return localIconPath
}
// Si tiene meta_icon de Authentik, usarlo
if (app.icon) {
// Si es una URL completa
@@ -216,8 +223,47 @@ const handleIconError = (event: Event, app: Application) => {
const imgElement = event.target as HTMLImageElement
const currentSrc = imgElement.src
// Marcar como fallido
// Cascada de fallback para íconos:
// 1. Ícono local (/app-icons/${slug}.svg)
// 2. Meta_icon de Authentik
// 3. apple-touch-icon.png del dominio
// 4. favicon.ico del dominio
// 5. Ícono por defecto
// Si estábamos intentando el ícono local, intentar meta_icon o apple-touch-icon
if (currentSrc.includes('/app-icons/')) {
failedIcons.value.delete(app.pk) // Permitir siguiente intento
if (app.icon) {
// Tiene meta_icon de Authentik
if (app.icon.startsWith('http://') || app.icon.startsWith('https://')) {
imgElement.src = app.icon
} else {
try {
const url = new URL(app.launchUrl)
imgElement.src = `${url.origin}${app.icon.startsWith('/') ? '' : '/'}${app.icon}`
} catch {
// Si falla el parsing de URL, intentar apple-touch-icon
try {
const url = new URL(app.launchUrl)
imgElement.src = `${url.origin}/apple-touch-icon.png`
} catch {
failedIcons.value.add(app.pk)
}
}
}
return
}
// No tiene meta_icon, intentar apple-touch-icon
try {
const url = new URL(app.launchUrl)
imgElement.src = `${url.origin}/apple-touch-icon.png`
return
} catch {
failedIcons.value.add(app.pk)
}
}
// Si estábamos intentando apple-touch-icon, intentar favicon.ico
if (currentSrc.includes('apple-touch-icon')) {
@@ -227,11 +273,12 @@ const handleIconError = (event: Event, app: Application) => {
failedIcons.value.delete(app.pk) // Dar otra oportunidad
return
} catch {
// Si falla, el v-else mostrará el icono por defecto
failedIcons.value.add(app.pk)
}
}
// Ocultar la imagen para que se muestre el icono por defecto
// Marcar como fallido y ocultar imagen para mostrar ícono por defecto
failedIcons.value.add(app.pk)
imgElement.style.display = 'none'
}

View File

@@ -0,0 +1,11 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none">
<circle cx="6" cy="12" r="3" fill="#615EFF"/>
<circle cx="18" cy="12" r="3" fill="#FF5ED0"/>
<path d="M9 12h6" stroke="url(#airbyte-gradient)" stroke-width="2"/>
<defs>
<linearGradient id="airbyte-gradient" x1="9" y1="12" x2="15" y2="12" gradientUnits="userSpaceOnUse">
<stop stop-color="#615EFF"/>
<stop offset="1" stop-color="#FF5ED0"/>
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 475 B

View File

@@ -0,0 +1,8 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none">
<rect x="2" y="4" width="20" height="16" rx="2" fill="#4A5568"/>
<rect x="4" y="7" width="16" height="2" rx="1" fill="#68D391"/>
<rect x="4" y="11" width="16" height="2" rx="1" fill="#68D391"/>
<rect x="4" y="15" width="10" height="2" rx="1" fill="#68D391"/>
<circle cx="19" cy="8" r="1" fill="#F56565"/>
<circle cx="19" cy="12" r="1" fill="#48BB78"/>
</svg>

After

Width:  |  Height:  |  Size: 444 B

View File

@@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none">
<circle cx="12" cy="12" r="10" fill="#509EE3"/>
<path d="M8 10h8M8 12h8M8 14h5" stroke="#fff" stroke-width="2" stroke-linecap="round"/>
<circle cx="16" cy="8" r="2" fill="#fff"/>
</svg>

After

Width:  |  Height:  |  Size: 265 B

View File

@@ -0,0 +1,7 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none">
<rect x="3" y="3" width="18" height="18" rx="2" fill="#13BEF9"/>
<rect x="6" y="6" width="5" height="5" rx="1" fill="#fff"/>
<rect x="13" y="6" width="5" height="5" rx="1" fill="#fff"/>
<rect x="6" y="13" width="5" height="5" rx="1" fill="#fff"/>
<rect x="13" y="13" width="5" height="5" rx="1" fill="#fff"/>
</svg>

After

Width:  |  Height:  |  Size: 399 B

View File

@@ -0,0 +1,10 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none">
<path d="M13.277 21.738c-.412.599-1.356.587-1.75-.024L4.47 9.467c-.467-.722.166-1.656 1.057-1.56l10.935 1.183c.623.067.95.78.584 1.273l-3.77 5.375z" fill="#3ECF8E"/>
<path d="M10.723 2.262c.412-.599 1.356-.587 1.75.024l7.057 12.247c.467.722-.166 1.656-1.057 1.56L7.538 14.91c-.623-.067-.95-.78-.584-1.273l3.77-5.375z" fill="url(#supabase-gradient)" fill-opacity=".8"/>
<defs>
<linearGradient id="supabase-gradient" x1="11" y1="2" x2="11" y2="22" gradientUnits="userSpaceOnUse">
<stop stop-color="#3ECF8E"/>
<stop offset="1" stop-color="#3ECF8E" stop-opacity="0.6"/>
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 700 B

View File

@@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none">
<circle cx="12" cy="12" r="10" fill="#24A1C1"/>
<path d="M7 8h10l-5 8z" fill="#fff"/>
<path d="M12 8v8" stroke="#24A1C1" stroke-width="2"/>
</svg>

After

Width:  |  Height:  |  Size: 226 B

View File

@@ -0,0 +1,7 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none">
<circle cx="12" cy="12" r="10" fill="#E95420"/>
<circle cx="12" cy="5" r="2" fill="#fff"/>
<circle cx="18" cy="15" r="2" fill="#fff"/>
<circle cx="6" cy="15" r="2" fill="#fff"/>
<path d="M12 7v5m-4.5 3l4-2.5m0 0l4 2.5" stroke="#fff" stroke-width="1.5" stroke-linecap="round"/>
</svg>

After

Width:  |  Height:  |  Size: 367 B