new funcionality

This commit is contained in:
2026-07-27 17:20:02 +02:00
parent c2b5291a74
commit c5ce8a7a36
101 changed files with 6889 additions and 176 deletions

View File

@@ -5,6 +5,7 @@ import { useI18n } from 'vue-i18n';
import axios from 'axios';
import { useAuthStore } from './stores/auth';
import { useTheme } from './composables/useTheme';
import AppLogo from './components/AppLogo.vue';
const auth = useAuthStore();
const route = useRoute();
@@ -40,56 +41,58 @@ const navLinks = computed<NavLink[]>(() => [
{ to: '/clients', name: 'clients', label: t('nav.clients') },
{ to: '/tokens', name: 'tokens', label: t('nav.tokens') },
{ to: '/authorized-apps', name: 'authorized-apps', label: t('nav.authorizedApps') },
{ to: '/security', name: 'security', label: t('nav.security') },
...(auth.isAdmin ? [{ to: '/admin/users', name: 'admin-users', label: t('nav.users') }] : []),
...(auth.isAdmin ? [{ to: '/admin/analytics', name: 'admin-analytics', label: t('nav.analytics') }] : []),
...(auth.isAdmin ? [{ to: '/admin/audit-log', name: 'admin-audit-log', label: t('nav.auditLog') }] : []),
]);
</script>
<template>
<div class="app-shell">
<nav v-if="showNav" class="app-nav">
<nav v-if="showNav" class="app-nav no-print">
<div class="app-nav__inner">
<div class="app-nav__section">
<div class="app-nav__top">
<router-link to="/" class="app-nav__brand">
<span class="app-nav__logo">O2</span>
<AppLogo class="app-nav__logo" />
<span class="app-nav__brand-name">OAuth2 Server</span>
</router-link>
<div class="app-nav__links">
<router-link
v-for="link in navLinks"
:key="link.name"
:to="link.to"
class="app-nav__link"
active-class="app-nav__link--active"
>
{{ link.label }}
</router-link>
<a href="/api/documentation" class="app-nav__link">{{ t('nav.apiDocs') }}</a>
<div class="app-nav__controls">
<select :value="currentLocale" @change="onLocaleChange" class="pill-select">
<option value="es">ES</option>
<option value="en">EN</option>
<option value="ca">CA</option>
</select>
<button @click="toggleTheme" type="button" class="app-nav__theme-toggle"
:aria-label="isDark ? 'Light mode' : 'Dark mode'">
<svg v-if="isDark" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor">
<path fill-rule="evenodd" d="M12 2.25a.75.75 0 01.75.75v2a.75.75 0 01-1.5 0V3a.75.75 0 01.75-.75zM7.5 12a4.5 4.5 0 119 0 4.5 4.5 0 01-9 0zM18.894 6.166a.75.75 0 00-1.06-1.06l-1.415 1.414a.75.75 0 101.06 1.06l1.415-1.414zM21.75 12a.75.75 0 01-.75.75h-2a.75.75 0 010-1.5h2a.75.75 0 01.75.75zM17.834 18.894a.75.75 0 001.06-1.06l-1.414-1.415a.75.75 0 10-1.06 1.06l1.414 1.415zM12 18a.75.75 0 01.75.75v2a.75.75 0 01-1.5 0v-2A.75.75 0 0112 18zM7.758 17.303a.75.75 0 00-1.061-1.06l-1.414 1.414a.75.75 0 001.06 1.06l1.415-1.414zM6 12a.75.75 0 01-.75.75h-2a.75.75 0 010-1.5h2A.75.75 0 016 12zM6.697 7.757a.75.75 0 001.06-1.06L6.343 5.283a.75.75 0 10-1.06 1.06l1.414 1.414z" clip-rule="evenodd" />
</svg>
<svg v-else xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor">
<path fill-rule="evenodd" d="M9.528 1.718a.75.75 0 01.162.819A8.97 8.97 0 009 6a9 9 0 009 9 8.97 8.97 0 003.463-.69.75.75 0 01.981.98 10.503 10.503 0 01-9.694 6.46c-5.799 0-10.5-4.7-10.5-10.5 0-4.368 2.667-8.112 6.46-9.694a.75.75 0 01.818.162z" clip-rule="evenodd" />
</svg>
</button>
<span class="app-nav__user">{{ auth.user?.email }}</span>
<button @click="logout" class="btn btn--invert">
{{ t('nav.logout') }}
</button>
</div>
</div>
<div class="app-nav__controls">
<select :value="currentLocale" @change="onLocaleChange" class="pill-select">
<option value="es">ES</option>
<option value="en">EN</option>
<option value="ca">CA</option>
</select>
<button @click="toggleTheme" type="button" class="app-nav__theme-toggle"
:aria-label="isDark ? 'Light mode' : 'Dark mode'">
<svg v-if="isDark" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor">
<path fill-rule="evenodd" d="M12 2.25a.75.75 0 01.75.75v2a.75.75 0 01-1.5 0V3a.75.75 0 01.75-.75zM7.5 12a4.5 4.5 0 119 0 4.5 4.5 0 01-9 0zM18.894 6.166a.75.75 0 00-1.06-1.06l-1.415 1.414a.75.75 0 101.06 1.06l1.415-1.414zM21.75 12a.75.75 0 01-.75.75h-2a.75.75 0 010-1.5h2a.75.75 0 01.75.75zM17.834 18.894a.75.75 0 001.06-1.06l-1.414-1.415a.75.75 0 10-1.06 1.06l1.414 1.415zM12 18a.75.75 0 01.75.75v2a.75.75 0 01-1.5 0v-2A.75.75 0 0112 18zM7.758 17.303a.75.75 0 00-1.061-1.06l-1.414 1.414a.75.75 0 001.06 1.06l1.415-1.414zM6 12a.75.75 0 01-.75.75h-2a.75.75 0 010-1.5h2A.75.75 0 016 12zM6.697 7.757a.75.75 0 001.06-1.06L6.343 5.283a.75.75 0 10-1.06 1.06l1.414 1.414z" clip-rule="evenodd" />
</svg>
<svg v-else xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor">
<path fill-rule="evenodd" d="M9.528 1.718a.75.75 0 01.162.819A8.97 8.97 0 009 6a9 9 0 009 9 8.97 8.97 0 003.463-.69.75.75 0 01.981.98 10.503 10.503 0 01-9.694 6.46c-5.799 0-10.5-4.7-10.5-10.5 0-4.368 2.667-8.112 6.46-9.694a.75.75 0 01.818.162z" clip-rule="evenodd" />
</svg>
</button>
<span class="app-nav__user">{{ auth.user?.email }}</span>
<button @click="logout" class="btn btn--invert">
{{ t('nav.logout') }}
</button>
<div class="app-nav__links">
<router-link
v-for="link in navLinks"
:key="link.name"
:to="link.to"
class="app-nav__link"
active-class="app-nav__link--active"
>
{{ link.label }}
</router-link>
<a href="/api/documentation" class="app-nav__link">{{ t('nav.apiDocs') }}</a>
</div>
</div>
</nav>