Files
Memoh/apps/web/src/components/settings-sidebar/index.vue
T
2026-03-30 15:19:12 +08:00

140 lines
3.7 KiB
Vue

<template>
<aside>
<Sidebar collapsible="icon">
<SidebarHeader class="p-0 border-0">
<button
class="h-[53px] flex items-center gap-2.5 px-3.5 w-full border-b border-border text-foreground hover:bg-accent/50 transition-colors group-data-[collapsible=icon]:justify-center group-data-[collapsible=icon]:px-0"
@click="router.push(backToChatRoute)"
>
<ChevronLeft
class="size-3 shrink-0"
/>
<span class="text-xs font-semibold group-data-[collapsible=icon]:hidden">
{{ t('sidebar.settings') }}
</span>
</button>
</SidebarHeader>
<SidebarContent>
<SidebarGroup class="px-2 py-2.5">
<SidebarGroupContent>
<SidebarMenu class="gap-0.5">
<SidebarMenuItem
v-for="item in navItems"
:key="item.name"
>
<SidebarMenuButton
:tooltip="item.title"
:is-active="isItemActive(item.name)"
:aria-current="isItemActive(item.name) ? 'page' : undefined"
class="h-9 gap-2 relative before:absolute before:w-0.5 before:top-1.5 before:bottom-1.5 before:left-0 before:rounded-full data-[active=true]:before:bg-[#8B56E3]"
@click="router.push({ name: item.name })"
>
<component
:is="item.icon"
class="size-3.5 ml-1.5"
/>
<span class="text-xs font-medium">{{ item.title }}</span>
</SidebarMenuButton>
</SidebarMenuItem>
</SidebarMenu>
</SidebarGroupContent>
</SidebarGroup>
</SidebarContent>
</Sidebar>
</aside>
</template>
<script setup lang="ts">
import { computed, type Component } from 'vue'
import { storeToRefs } from 'pinia'
import { useRouter, useRoute } from 'vue-router'
import { useI18n } from 'vue-i18n'
import { ChevronLeft, Bot, Boxes, Globe, Brain, Volume2, Mail, AppWindow, ChartLine, User } from 'lucide-vue-next'
import { useChatSelectionStore } from '@/store/chat-selection'
import {
Sidebar,
SidebarContent,
SidebarGroup,
SidebarGroupContent,
SidebarHeader,
SidebarMenu,
SidebarMenuButton,
SidebarMenuItem,
} from '@memohai/ui'
const router = useRouter()
const route = useRoute()
const { t } = useI18n()
const selectionStore = useChatSelectionStore()
const { currentBotId, sessionId } = storeToRefs(selectionStore)
const backToChatRoute = computed(() => {
const botId = (currentBotId.value ?? '').trim()
const targetSessionId = (sessionId.value ?? '').trim()
if (!botId) return { name: 'home' as const }
return {
name: 'chat' as const,
params: {
botId,
sessionId: targetSessionId || undefined,
},
}
})
function isItemActive(name: string): boolean {
if (name === 'bots') {
return route.path.startsWith('/settings/bots')
}
return route.name === name
}
const navItems = computed<{ title: string; name: string; icon: Component }[]>(() => [
{
title: t('sidebar.bots'),
name: 'bots',
icon: Bot,
},
{
title: t('sidebar.providers'),
name: 'providers',
icon: Boxes,
},
{
title: t('sidebar.webSearch'),
name: 'web-search',
icon: Globe,
},
{
title: t('sidebar.memory'),
name: 'memory',
icon: Brain,
},
{
title: t('sidebar.speech'),
name: 'speech',
icon: Volume2,
},
{
title: t('sidebar.email'),
name: 'email',
icon: Mail,
},
{
title: t('sidebar.browser'),
name: 'browser',
icon: AppWindow,
},
{
title: t('sidebar.usage'),
name: 'usage',
icon: ChartLine,
},
{
title: t('sidebar.profile'),
name: 'profile',
icon: User,
},
])
</script>