84 lines
3.5 KiB
Vue
84 lines
3.5 KiB
Vue
<script setup lang="ts">
|
|
import { providerIcons } from '~/utils/model-mapping';
|
|
|
|
const route = useRoute();
|
|
const { providers } = await useModels();
|
|
const { isAdmin } = useAuth();
|
|
|
|
const ADMIN_GROUP = {
|
|
label: 'Instance',
|
|
adminOnly: true,
|
|
items: [
|
|
{ to: '/settings/instance/users', name: 'Users', icon: 'i-mynaui-users' },
|
|
{ to: '/settings/instance', name: 'Instance', icon: 'i-tabler-server' },
|
|
],
|
|
};
|
|
|
|
const BASE_GROUPS = [
|
|
{
|
|
label: 'Account',
|
|
adminOnly: false,
|
|
items: [
|
|
{ to: '/settings/profile', name: 'Profile', icon: 'i-mynaui-user' },
|
|
{ to: '/settings/security', name: 'Security', icon: 'i-mynaui-shield' },
|
|
],
|
|
},
|
|
{
|
|
label: 'App',
|
|
adminOnly: false,
|
|
items: [
|
|
{ to: '/settings/general', name: 'General', icon: 'i-mynaui-cog-four' },
|
|
{ to: '/settings/appearance', name: 'Appearance', icon: 'i-tabler-palette' },
|
|
{ to: '/settings/providers', name: 'AI Providers', icon: 'i-mynaui-api' },
|
|
{ to: '/settings/assistants', name: 'System Assistants', icon: 'i-mynaui-sparkles' },
|
|
],
|
|
},
|
|
];
|
|
|
|
const groups = computed(() => isAdmin.value ? [...BASE_GROUPS, ADMIN_GROUP] : BASE_GROUPS);
|
|
|
|
const inProviders = computed(() => route.path.startsWith('/settings/providers'));
|
|
|
|
// enabled providers first, same order the provider list uses
|
|
const sortedProviders = computed(() => [
|
|
...providers.value.filter(p => p.enabled),
|
|
...providers.value.filter(p => !p.enabled),
|
|
]);
|
|
</script>
|
|
|
|
<template>
|
|
<nav aria-label="Settings" class="flex flex-col gap-1 overflow-auto">
|
|
<template v-for="group in groups" :key="group.label">
|
|
<div
|
|
class="flex items-center justify-between px-2 pt-3 pb-0.5 text-sm md:text-xs font-medium uppercase tracking-wider">
|
|
{{ group.label }}
|
|
<span v-if="group.adminOnly"
|
|
class="px-1.5 py-0.25 rounded border border-[var(--color-border-active)] text-[10px] tracking-wide">
|
|
Admin only
|
|
</span>
|
|
</div>
|
|
|
|
<template v-for="item in group.items" :key="item.to">
|
|
<SidenavItem :to="item.to" :name="item.name" :icon="item.icon" :active="route.path === item.to" />
|
|
|
|
<!-- the providers are listed under their section while it is open -->
|
|
<div v-if="item.to === '/settings/providers' && inProviders" class="flex flex-col gap-1 pl-4">
|
|
<NuxtLink v-for="p in sortedProviders" :key="p.id" :to="`/settings/providers/${p.id}`" :class="[
|
|
'case-capital decoration-none flex items-center gap-2 shrink-0 px-2 h-9 rounded-lg transition-colors',
|
|
route.path === `/settings/providers/${p.id}`
|
|
? 'text-[var(--text-primary)] bg-[var(--color-hover)]'
|
|
: 'text-[var(--text-secondary)] @hover:bg-[var(--color-hover)] focus-visible:bg-[var(--color-hover)]',
|
|
p.enabled ? '' : 'opacity-50',
|
|
]">
|
|
<component v-if="providerIcons[p.type]" :color="true" :is="providerIcons[p.type]"
|
|
class="h-6 w-6 md:w-4 md:h-4 flex-shrink-0 text-[var(--text-primary)]" />
|
|
<span class="md:text-sm font-medium overflow-hidden text-ellipsis whitespace-nowrap">
|
|
{{ p.name }}
|
|
</span>
|
|
</NuxtLink>
|
|
</div>
|
|
</template>
|
|
</template>
|
|
</nav>
|
|
</template>
|