99 lines
4.1 KiB
TypeScript
99 lines
4.1 KiB
TypeScript
'use client';
|
|
|
|
import Link from 'next/link';
|
|
import { useState, useEffect } from 'react';
|
|
import { ThemeToggle } from './ThemeToggle';
|
|
|
|
interface SidebarItem {
|
|
title: string;
|
|
slug: string;
|
|
children?: SidebarItem[];
|
|
}
|
|
|
|
interface SidebarProps {
|
|
sidebarData: SidebarItem[];
|
|
currentSlug?: string;
|
|
}
|
|
|
|
export function Sidebar({ sidebarData, currentSlug }: SidebarProps) {
|
|
// Use a map to track open state of each section (by slug)
|
|
const [openSections, setOpenSections] = useState<Record<string, boolean>>({});
|
|
|
|
useEffect(() => {
|
|
// Automatically open the section that contains the current slug
|
|
if (currentSlug) {
|
|
const parentSection = sidebarData.find(item =>
|
|
item.children?.some(child => child.slug === currentSlug)
|
|
);
|
|
if (parentSection) {
|
|
setOpenSections(prev => ({ ...prev, [parentSection.slug]: true }));
|
|
}
|
|
}
|
|
}, [currentSlug, sidebarData]);
|
|
|
|
const toggleSection = (slug: string) => {
|
|
setOpenSections(prev => ({ ...prev, [slug]: !prev[slug] }));
|
|
};
|
|
|
|
return (
|
|
<aside className="sidebar">
|
|
<div className="sidebar-header">
|
|
<Link href="/" className="sidebar-logo">
|
|
<div className="sidebar-logo-icon">🦞</div>
|
|
<div className="sidebar-logo-text">
|
|
<span className="sidebar-logo-title">OpenClaw</span>
|
|
<span className="sidebar-logo-subtitle">中文文档</span>
|
|
</div>
|
|
</Link>
|
|
<ThemeToggle />
|
|
</div>
|
|
<nav className="sidebar-nav">
|
|
{sidebarData.map(item => {
|
|
if (item.children && item.children.length > 0) {
|
|
const isOpen = !!openSections[item.slug];
|
|
const hasActiveChild = item.children.some(c => c.slug === currentSlug);
|
|
|
|
return (
|
|
<div key={item.slug} className="sidebar-section">
|
|
<div
|
|
className={`sidebar-section-title ${hasActiveChild ? 'active' : ''}`}
|
|
onClick={() => toggleSection(item.slug)}
|
|
>
|
|
{item.title}
|
|
<span className={`sidebar-section-arrow ${isOpen ? 'open' : ''}`}>
|
|
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
|
<path d="m9 18 6-6-6-6" />
|
|
</svg>
|
|
</span>
|
|
</div>
|
|
{isOpen && (
|
|
<div className="sidebar-section-children">
|
|
{item.children.map(child => (
|
|
<Link
|
|
key={child.slug}
|
|
href={child.slug}
|
|
className={`sidebar-link ${child.slug === currentSlug ? 'active' : ''}`}
|
|
>
|
|
{child.title}
|
|
</Link>
|
|
))}
|
|
</div>
|
|
)}
|
|
</div>
|
|
);
|
|
}
|
|
return (
|
|
<Link
|
|
key={item.slug}
|
|
href={item.slug}
|
|
className={`sidebar-root-link ${item.slug === currentSlug ? 'active' : ''}`}
|
|
>
|
|
{item.title}
|
|
</Link>
|
|
);
|
|
})}
|
|
</nav>
|
|
</aside>
|
|
);
|
|
}
|