You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
134 lines
5.6 KiB
134 lines
5.6 KiB
<template>
|
|
<nav class="sidebar">
|
|
<div class="sidebar-section">
|
|
<div class="sidebar-label">视图</div>
|
|
<a
|
|
v-for="item in views"
|
|
:key="item.key"
|
|
class="nav-item"
|
|
:class="{ active: currentView === item.key }"
|
|
@click="$emit('navigate', item.key)"
|
|
>
|
|
<span v-html="item.icon"></span>
|
|
{{ item.label }}
|
|
<span v-if="item.badge !== undefined" class="nav-badge">{{ item.badge }}</span>
|
|
</a>
|
|
</div>
|
|
|
|
<div class="sidebar-section" v-if="categories.length">
|
|
<div class="sidebar-label">分类</div>
|
|
<CategoryTreeNode
|
|
v-for="cat in categories"
|
|
:key="cat.id"
|
|
:category="cat"
|
|
:depth="0"
|
|
:current-id="currentCategoryId"
|
|
@select="$emit('navigate', 'category', $event)"
|
|
/>
|
|
</div>
|
|
|
|
<div class="sidebar-section" v-if="topTags.length">
|
|
<div class="sidebar-label">标签</div>
|
|
<a
|
|
v-for="tag in topTags"
|
|
:key="tag.id"
|
|
class="nav-item"
|
|
:class="{ active: currentTagId === tag.id }"
|
|
@click="$emit('navigate', 'tag', tag)"
|
|
>
|
|
<span class="tag-dot" :style="{ background: tag.color || 'var(--accent)' }"></span>
|
|
{{ tag.name }}
|
|
<span class="nav-badge">{{ tag.itemCount }}</span>
|
|
</a>
|
|
</div>
|
|
|
|
<div class="sidebar-section sidebar-bottom">
|
|
<div class="sidebar-label">系统</div>
|
|
<a
|
|
class="nav-item"
|
|
:class="{ active: currentView === 'settings' }"
|
|
@click="$emit('navigate', 'settings')"
|
|
>
|
|
<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><circle cx="12" cy="12" r="3"/><path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-4 0v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83-2.83l.06-.06A1.65 1.65 0 0 0 4.68 15a1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1 0-4h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 2.83-2.83l.06.06A1.65 1.65 0 0 0 9 4.68a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 2.83l-.06.06A1.65 1.65 0 0 0 19.4 9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1z"/></svg>
|
|
设置
|
|
</a>
|
|
</div>
|
|
</nav>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
const props = defineProps<{
|
|
currentView: string;
|
|
currentCategoryId?: number | null;
|
|
currentTagId?: number | null;
|
|
categories: any[];
|
|
topTags: any[];
|
|
inboxCount?: number;
|
|
allCount?: number;
|
|
articleCount?: number;
|
|
}>();
|
|
|
|
defineEmits<{
|
|
navigate: [type: string, payload?: any];
|
|
}>();
|
|
|
|
const views = computed(() => [
|
|
{ key: 'inbox', label: '收件箱', icon: '<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><path d="M22 12h-6l-2 3h-4l-2-3H2"/><path d="M5.45 5.11 2 12v6a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2v-6l-3.45-6.89A2 2 0 0 0 16.76 4H7.24a2 2 0 0 0-1.79 1.11z"/></svg>', badge: undefined },
|
|
{ key: 'all', label: '全部收藏', icon: '<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><rect x="3" y="3" width="7" height="7"/><rect x="14" y="3" width="7" height="7"/><rect x="14" y="14" width="7" height="7"/><rect x="3" y="14" width="7" height="7"/></svg>', badge: undefined },
|
|
{ key: 'recent', label: '最近收藏', icon: '<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><circle cx="12" cy="12" r="10"/><polyline points="12 6 12 12 16 14"/></svg>', badge: undefined },
|
|
{ key: 'starred', label: '已加星标', icon: '<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><polygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2"/></svg>', badge: undefined },
|
|
{ key: 'articles', label: '我的文章', icon: '<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/><line x1="16" y1="13" x2="8" y2="13"/><line x1="16" y1="17" x2="8" y2="17"/></svg>', badge: undefined },
|
|
]);
|
|
</script>
|
|
|
|
<style scoped>
|
|
.sidebar {
|
|
width: var(--sidebar-w);
|
|
background: var(--bg2);
|
|
border-right: 1px solid var(--border);
|
|
display: flex;
|
|
flex-direction: column;
|
|
overflow-y: auto;
|
|
flex-shrink: 0;
|
|
padding: 12px 0;
|
|
}
|
|
.sidebar::-webkit-scrollbar { width: 0; }
|
|
.sidebar-section { padding: 0 8px; margin-bottom: 20px; }
|
|
.sidebar-label {
|
|
font-size: 10px;
|
|
font-weight: 500;
|
|
letter-spacing: 0.1em;
|
|
text-transform: uppercase;
|
|
color: var(--text3);
|
|
padding: 0 8px;
|
|
margin-bottom: 4px;
|
|
}
|
|
.nav-item {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 8px;
|
|
padding: 7px 8px;
|
|
border-radius: 7px;
|
|
cursor: pointer;
|
|
color: var(--text2);
|
|
font-size: 13px;
|
|
transition: background 0.15s, color 0.15s;
|
|
position: relative;
|
|
text-decoration: none;
|
|
}
|
|
.nav-item:hover { background: var(--bg3); color: var(--text); }
|
|
.nav-item.active { background: var(--accent-bg); color: var(--accent); }
|
|
.nav-item :deep(svg) { flex-shrink: 0; }
|
|
.nav-badge {
|
|
margin-left: auto;
|
|
background: var(--bg4);
|
|
color: var(--text3);
|
|
font-size: 10px;
|
|
padding: 1px 6px;
|
|
border-radius: 10px;
|
|
font-family: var(--font-mono);
|
|
}
|
|
.nav-item.active .nav-badge { background: rgba(200, 169, 126, 0.2); color: var(--accent); }
|
|
.tag-dot { width: 7px; height: 7px; border-radius: 50%; flex-shrink: 0; }
|
|
.sidebar-bottom { margin-top: auto; padding-top: 12px; border-top: 1px solid var(--border); }
|
|
</style>
|
|
|