Mejoras finales: filtro hardcoded, orientación y contador
All checks were successful
build-and-deploy / build-and-deploy (push) Successful in 54s

- Filtrar app "perfil" de la lista (hardcoded por slug y nombre)
- Búsqueda en tiempo real con v-model (sin debounce)
- Orientación "any" para respetar dispositivo móvil
- Contador de apps con glassmorphism personalizado
- Estilos matching chips y badges de la app
- Soporte completo modo día/noche para contador
This commit is contained in:
2025-10-16 23:56:48 -06:00
parent 4c6cc7ec75
commit e535f8d937
2 changed files with 47 additions and 4 deletions

View File

@@ -6,9 +6,9 @@
<UIcon name="i-heroicons-squares-2x2" class="w-6 h-6" />
Mis Aplicaciones
</h2>
<UBadge v-if="filteredApplications.length > 0" color="primary" variant="soft" size="lg">
<span v-if="filteredApplications.length > 0" class="app-counter">
{{ filteredApplications.length }}
</UBadge>
</span>
</div>
<!-- Campo de búsqueda -->
@@ -137,10 +137,21 @@ interface Application {
openInNewTab: boolean
}
const { data: applications, pending, error, refresh } = await useFetch<Application[]>('/api/authentik/applications', {
const { data: applicationsRaw, pending, error, refresh } = await useFetch<Application[]>('/api/authentik/applications', {
default: () => []
})
// Filtrar esta app (perfil) de la lista de manera hardcodeada
const applications = computed(() => {
return applicationsRaw.value.filter(app => {
// Filtrar por slug o nombre que contenga "perfil"
const isPerfil = app.slug === 'perfil' ||
app.slug === 'perfil-nucleo' ||
app.name.toLowerCase().includes('perfil nucleo')
return !isPerfil
})
})
// Cookie para persistir filtros seleccionados
const filtersCookie = useCookie<string[]>('app-filters', {
maxAge: 60 * 60 * 24 * 365, // 1 año
@@ -327,6 +338,27 @@ onUnmounted(() => {
margin: 0;
}
.app-counter {
display: inline-flex;
align-items: center;
justify-content: center;
min-width: 2.5rem;
height: 2.5rem;
padding: 0 0.75rem;
font-size: 1.125rem;
font-weight: 700;
border-radius: 0.875rem;
background: rgba(var(--color-primary-500), 0.15);
backdrop-filter: blur(10px) saturate(150%);
border: 1px solid rgba(var(--color-primary-500), 0.3);
color: rgb(var(--color-primary-500));
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
box-shadow:
0 2px 8px 0 rgba(var(--color-primary-500), 0.2),
inset 0 1px 1px 0 rgba(255, 255, 255, 0.3),
inset 0 -1px 2px 0 rgba(var(--color-primary-500), 0.1);
}
.search-section {
margin-bottom: 1.5rem;
}
@@ -623,6 +655,17 @@ onUnmounted(() => {
color: var(--color-gray-100) !important;
}
.dark .app-counter {
background: rgba(var(--color-primary-500), 0.25) !important;
border-color: rgba(var(--color-primary-500), 0.5) !important;
color: rgb(var(--color-primary-400)) !important;
box-shadow:
0 2px 8px 0 rgba(var(--color-primary-500), 0.4),
0 0 0 1px rgba(var(--color-primary-500), 0.3),
inset 0 1px 1px 0 rgba(255, 255, 255, 0.08),
inset 0 -1px 2px 0 rgba(var(--color-primary-500), 0.2) !important;
}
.dark .app-card {
background: rgba(0, 0, 0, 0.65) !important;
border: 1px solid rgba(255, 255, 255, 0.1) !important;