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

<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>