72 lines
1.9 KiB
Vue
72 lines
1.9 KiB
Vue
<script setup lang="ts">
|
|
import { computed } from 'vue'
|
|
import { useRoute } from 'vue-router'
|
|
import { ChatDotRound, Picture, Clock, Setting } from '@element-plus/icons-vue'
|
|
import AtlasLogo from '@/components/AtlasLogo.vue'
|
|
|
|
const route = useRoute()
|
|
|
|
const navItems = [
|
|
{ path: '/chat', label: '对话', icon: ChatDotRound },
|
|
{ path: '/image', label: '生图', icon: Picture },
|
|
{ path: '/history', label: '历史', icon: Clock },
|
|
] as const
|
|
|
|
const pageTitle = computed(
|
|
() => navItems.find((i) => route.path === i.path || route.path.startsWith(`${i.path}/`))?.label ?? 'Atlas',
|
|
)
|
|
|
|
function isActive(path: string) {
|
|
return route.path === path || route.path.startsWith(`${path}/`)
|
|
}
|
|
</script>
|
|
|
|
<template>
|
|
<div class="layout">
|
|
<aside class="sidebar">
|
|
<div class="sidebar-brand">
|
|
<AtlasLogo :size="32" />
|
|
<div>
|
|
<span class="brand-name">Atlas</span>
|
|
<div class="brand-tagline">AI 创作台</div>
|
|
</div>
|
|
</div>
|
|
<div class="nav-group-label">创作</div>
|
|
<router-link
|
|
v-for="item in navItems"
|
|
:key="item.path"
|
|
:to="item.path"
|
|
class="nav-item"
|
|
:class="{ active: isActive(item.path) }"
|
|
>
|
|
<el-icon :size="16"><component :is="item.icon" /></el-icon>
|
|
{{ item.label }}
|
|
</router-link>
|
|
<div class="sidebar-footer">
|
|
<router-link to="/admin/providers" class="nav-item nav-item--muted">
|
|
<el-icon :size="16"><Setting /></el-icon>
|
|
管理端
|
|
</router-link>
|
|
</div>
|
|
</aside>
|
|
<div class="main-area">
|
|
<header class="topbar">
|
|
<span class="topbar-title">{{ pageTitle }}</span>
|
|
</header>
|
|
<main class="main-content">
|
|
<div class="page">
|
|
<router-view />
|
|
</div>
|
|
</main>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<style scoped>
|
|
.brand-tagline {
|
|
font-size: 0.75rem;
|
|
color: var(--muted-foreground);
|
|
margin-top: 2px;
|
|
}
|
|
</style>
|