kt-blog-web/src/components/blog/BlogSidebar.tsx

156 lines
5.8 KiB
TypeScript

import { SearchOutlined } from '@antdv-next/icons';
import { defineComponent, nextTick, type PropType, type Ref, ref } from 'vue';
import { RouterLink, useRouter } from 'vue-router';
import type { BlogArticle, BlogCategory, BlogTag } from '@/data/blog';
import { useBlogEventBus } from '@/hooks/useBlogEventBus';
import { useBlogTheme } from '@/hooks/useBlogTheme';
import { BlogButton, BlogInput } from './antdvComponents';
export default defineComponent({
name: 'BlogSidebar',
props: {
categories: {
type: Array as PropType<BlogCategory[]>,
required: true,
},
tags: {
type: Array as PropType<BlogTag[]>,
required: true,
},
articles: {
type: Array as PropType<BlogArticle[]>,
required: true,
},
part1Ref: {
type: Object as PropType<Ref<HTMLElement | null>>,
required: true,
},
part2Ref: {
type: Object as PropType<Ref<HTMLElement | null>>,
required: true,
},
},
setup(props) {
const router = useRouter();
const eventBus = useBlogEventBus();
const { siteConfig } = useBlogTheme();
const keyword = ref('');
const leftbarSearchOpen = ref(false);
const leftbarSearchInputRef = ref<any>(null);
/**
* @param target antdv-next Input 组件实例或原生 input 节点。
*/
const focusInput = (target: any) => {
target?.focus?.();
target?.input?.focus?.();
};
const submitSearch = () => {
const query = keyword.value.trim();
if (!query) {
return;
}
router.push({
name: 'BlogSearch',
query: { q: query },
});
};
return () => (
<aside class="kt-blog__sidebar" role="complementary">
<div ref={props.part1Ref} class="kt-blog__sidebar-panel kt-blog__sidebar-panel--menu kt-blog__card">
<div class="kt-blog__sidebar-banner kt-blog__card-body">
<span class="kt-blog__sidebar-banner-title">{siteConfig.value.title}</span>
</div>
<ul class="kt-blog__sidebar-menu">
{siteConfig.value.sidebarMenu.map((item, index) => (
<li key={item.label} class={['kt-blog__sidebar-menu-item', index === 0 && 'kt-blog__sidebar-menu-item--current']}>
{item.external ? (
<a href={item.href} rel="noopener noreferrer" target="_blank">
<i class="kt-blog__sidebar-menu-icon" data-icon={item.icon || 'fa-circle'} />
{item.label}
</a>
) : (
<RouterLink to={item.href}>
<i class="kt-blog__sidebar-menu-icon" data-icon={item.icon} />
{item.label}
</RouterLink>
)}
</li>
))}
</ul>
<div class={['kt-blog__sidebar-search kt-blog__card-body', leftbarSearchOpen.value && 'kt-blog__sidebar-search--open']}>
<BlogButton
class="kt-blog__sidebar-search-trigger kt-blog__button kt-blog__button--secondary kt-blog__button--small kt-blog__button--block"
onClick={() => {
leftbarSearchOpen.value = true;
nextTick(() => focusInput(leftbarSearchInputRef.value));
}}
>
<SearchOutlined />
</BlogButton>
<BlogInput
ref={leftbarSearchInputRef}
placeholder="搜索什么..."
class="kt-blog__sidebar-search-input kt-blog__input"
autocomplete="off"
v-model:value={keyword.value}
onBlur={() => {
leftbarSearchOpen.value = false;
}}
onKeydown={(event: KeyboardEvent) => {
if (event.key === 'Enter') {
event.preventDefault();
submitSearch();
}
}}
/>
</div>
</div>
<div ref={props.part2Ref} class="kt-blog__sidebar-panel kt-blog__sidebar-panel--overview kt-blog__card">
<div class="kt-blog__sidebar-overview kt-blog__card-body">
<div class="kt-blog__sidebar-overview-content">
<div class="kt-blog__sidebar-overview-panel kt-blog__sidebar-overview-panel--active">
<div class="kt-blog__sidebar-author-image">
<div class="kt-blog__sidebar-author-avatar" />
</div>
<h6 class="kt-blog__sidebar-author-name">{siteConfig.value.authorName}</h6>
<nav class="kt-blog__site-stats">
<div class="kt-blog__site-stats-item kt-blog__site-stats-item--posts">
<RouterLink to="/archives">
<span class="kt-blog__site-stats-count">{props.articles.length}</span>
<span class="kt-blog__site-stats-name"></span>
</RouterLink>
</div>
<div class="kt-blog__site-stats-item kt-blog__site-stats-item--categories">
<a
onClick={() => eventBus.emit('blog:taxonomy:open', 'categories')}
>
<span class="kt-blog__site-stats-count">{props.categories.length}</span>
<span class="kt-blog__site-stats-name"></span>
</a>
</div>
<div class="kt-blog__site-stats-item kt-blog__site-stats-item--tags">
<a onClick={() => eventBus.emit('blog:taxonomy:open', 'tags')}>
<span class="kt-blog__site-stats-count">{props.tags.length}</span>
<span class="kt-blog__site-stats-name"></span>
</a>
</div>
</nav>
</div>
</div>
</div>
</div>
</aside>
);
},
});