94 lines
2.5 KiB
TypeScript
Executable File
94 lines
2.5 KiB
TypeScript
Executable File
import { XMarkIcon, BookOpenIcon } from "@heroicons/react/24/outline";
|
|
import {
|
|
ChevronDownIcon,
|
|
ClockIcon,
|
|
PlayCircleIcon,
|
|
} from "@heroicons/react/24/outline";
|
|
import { ChevronLeftIcon, ChevronRightIcon } from "@heroicons/react/24/outline";
|
|
import React, { useState, useRef, useContext } from "react";
|
|
import { SectionDto, TaxonomySlug } from "@nice/common";
|
|
import { SyllabusHeader } from "./SyllabusHeader";
|
|
import { SectionItem } from "./SectionItem";
|
|
import { CollapsedButton } from "./CollapsedButton";
|
|
import { CourseDetailContext } from "../CourseDetailContext";
|
|
import { api } from "@nice/client";
|
|
|
|
interface CourseSyllabusProps {
|
|
sections: SectionDto[];
|
|
onLectureClick?: (lectureId: string) => void;
|
|
isOpen: boolean;
|
|
onToggle: () => void;
|
|
}
|
|
|
|
export const CourseSyllabus: React.FC<CourseSyllabusProps> = ({
|
|
sections,
|
|
onLectureClick,
|
|
isOpen,
|
|
onToggle,
|
|
}) => {
|
|
const { isHeaderVisible } = useContext(CourseDetailContext);
|
|
const [expandedSections, setExpandedSections] = useState<string[]>(
|
|
sections.map((section) => section.id) // 默认展开所有章节
|
|
);
|
|
const sectionRefs = useRef<{ [key: string]: HTMLDivElement | null }>({});
|
|
|
|
const toggleSection = (sectionId: string) => {
|
|
setExpandedSections((prev) =>
|
|
prev.includes(sectionId)
|
|
? prev.filter((id) => id !== sectionId)
|
|
: [...prev, sectionId]
|
|
);
|
|
|
|
// 直接滚动,无需延迟
|
|
sectionRefs.current[sectionId]?.scrollIntoView({
|
|
behavior: "smooth",
|
|
block: "start",
|
|
});
|
|
};
|
|
return (
|
|
<>
|
|
{/* 收起按钮直接显示 */}
|
|
{!isOpen && (
|
|
<div className="fixed top-1/3 right-0 -translate-y-1/2 z-20">
|
|
<CollapsedButton onToggle={onToggle} />
|
|
</div>
|
|
)}
|
|
|
|
<div
|
|
style={{
|
|
width: isOpen ? "25%" : "0",
|
|
right: 0,
|
|
top: isHeaderVisible ? "64px" : "0",
|
|
}}
|
|
className="fixed top-0 bottom-0 z-20 bg-white shadow-xl">
|
|
{isOpen && (
|
|
<div className="h-full flex flex-col">
|
|
<SyllabusHeader onToggle={onToggle} />
|
|
|
|
<div className="flex-1 overflow-y-auto p-4">
|
|
<div className="space-y-4">
|
|
{sections.map((section, index) => (
|
|
<SectionItem
|
|
key={section.id}
|
|
ref={(el) =>
|
|
(sectionRefs.current[section.id] =
|
|
el)
|
|
}
|
|
index={index + 1}
|
|
section={section}
|
|
isExpanded={expandedSections.includes(
|
|
section.id
|
|
)}
|
|
onToggle={toggleSection}
|
|
onLectureClick={onLectureClick}
|
|
/>
|
|
))}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
)}
|
|
</div>
|
|
</>
|
|
);
|
|
};
|