63 lines
1.9 KiB
TypeScript
63 lines
1.9 KiB
TypeScript
import { useMemo } from "react";
|
|
|
|
export type MenuProps = {
|
|
items: MenuItem[];
|
|
basename?: string;
|
|
};
|
|
export type MenuItem = {
|
|
id: string;
|
|
data: {
|
|
title: string;
|
|
tags: string[];
|
|
hideInMenu?: boolean;
|
|
}
|
|
}
|
|
export const Menu = (props: MenuProps) => {
|
|
const { items, basename = '' } = props;
|
|
const list = useMemo(() => {
|
|
return items.filter(item => !item.data?.hideInMenu).sort((a, b) => {
|
|
return (a.id).localeCompare(b.id)
|
|
});
|
|
}, [items]);
|
|
if (list.length === 0) {
|
|
return null;
|
|
}
|
|
const currentPath = typeof window !== 'undefined' ? window.location.pathname : '';
|
|
|
|
const isActive = (itemId: string) => {
|
|
return currentPath.includes(`/docs/${itemId}`);
|
|
};
|
|
|
|
return (
|
|
<nav className='flex-1 overflow-y-auto scrollbar bg-white border border-gray-200 rounded-lg shadow-sm'>
|
|
<div className="sticky top-0 bg-white border-b border-gray-200 px-4 py-3 rounded-t-lg">
|
|
<h2 className="text-sm font-semibold text-black">文档列表</h2>
|
|
</div>
|
|
<div className="p-2 space-y-0.5">
|
|
{list.map(item => (
|
|
<a
|
|
key={item.id}
|
|
href={`${basename}/docs/${item.id}/`}
|
|
className={`group block rounded-md transition-all duration-200 ease-in-out border-l-3 ${
|
|
isActive(item.id)
|
|
? 'bg-gray-100 border-l-4 border-black shadow-sm'
|
|
: 'border-transparent hover:bg-gray-50 hover:border-l-4 hover:border-gray-400'
|
|
}`}
|
|
>
|
|
<div className="px-3 py-2.5">
|
|
<h3 className={`text-sm font-medium transition-colors ${
|
|
isActive(item.id)
|
|
? 'text-black font-semibold'
|
|
: 'text-gray-700 group-hover:text-black'
|
|
}`}>
|
|
{item.data?.title}
|
|
</h3>
|
|
</div>
|
|
</a>
|
|
))}
|
|
</div>
|
|
</nav>
|
|
);
|
|
}
|
|
|