119 lines
3.6 KiB
TypeScript
119 lines
3.6 KiB
TypeScript
'use client';
|
||
|
||
import { ChevronDown, ChevronRight, FileText, Plus } from 'lucide-react';
|
||
import { useState } from 'react';
|
||
import { cn } from '@/lib/utils';
|
||
import { Button } from '@/components/ui/button';
|
||
|
||
interface Lesson {
|
||
id: string;
|
||
title: string;
|
||
}
|
||
|
||
interface Chapter {
|
||
id: string;
|
||
title: string;
|
||
lessons: Lesson[];
|
||
}
|
||
|
||
interface Course {
|
||
id: string;
|
||
title: string;
|
||
chapters: Chapter[];
|
||
}
|
||
|
||
interface LessonSidebarProps {
|
||
course: Course;
|
||
activeLesson: string;
|
||
onSelectLesson: (lessonId: string) => void;
|
||
/** Скрыть кнопки «Добавить урок/главу» (режим просмотра) */
|
||
readOnly?: boolean;
|
||
}
|
||
|
||
export function LessonSidebar({
|
||
course,
|
||
activeLesson,
|
||
onSelectLesson,
|
||
readOnly = false,
|
||
}: LessonSidebarProps) {
|
||
const [expandedChapters, setExpandedChapters] = useState<string[]>(
|
||
course.chapters.map((ch) => ch.id)
|
||
);
|
||
|
||
const toggleChapter = (chapterId: string) => {
|
||
setExpandedChapters((prev) =>
|
||
prev.includes(chapterId)
|
||
? prev.filter((id) => id !== chapterId)
|
||
: [...prev, chapterId]
|
||
);
|
||
};
|
||
|
||
return (
|
||
<div className="h-full flex flex-col">
|
||
{/* Header */}
|
||
<div className="p-4 border-b">
|
||
<h2 className="font-semibold truncate">{course.title}</h2>
|
||
</div>
|
||
|
||
{/* Chapters list */}
|
||
<div className="flex-1 overflow-auto p-2">
|
||
{course.chapters.map((chapter) => {
|
||
const isExpanded = expandedChapters.includes(chapter.id);
|
||
return (
|
||
<div key={chapter.id} className="mb-2">
|
||
{/* Chapter header */}
|
||
<button
|
||
className="flex items-center gap-2 w-full rounded-md px-2 py-1.5 text-sm font-medium hover:bg-muted transition-colors"
|
||
onClick={() => toggleChapter(chapter.id)}
|
||
>
|
||
{isExpanded ? (
|
||
<ChevronDown className="h-4 w-4 shrink-0" />
|
||
) : (
|
||
<ChevronRight className="h-4 w-4 shrink-0" />
|
||
)}
|
||
<span className="truncate">{chapter.title}</span>
|
||
</button>
|
||
|
||
{/* Lessons */}
|
||
{isExpanded && (
|
||
<div className="ml-4 mt-1 space-y-1">
|
||
{chapter.lessons.map((lesson) => (
|
||
<button
|
||
key={lesson.id}
|
||
className={cn(
|
||
'flex items-center gap-2 w-full rounded-md px-2 py-1.5 text-sm transition-colors text-left',
|
||
activeLesson === lesson.id
|
||
? 'bg-primary text-primary-foreground'
|
||
: 'hover:bg-muted text-muted-foreground'
|
||
)}
|
||
onClick={() => onSelectLesson(lesson.id)}
|
||
>
|
||
<FileText className="h-4 w-4 shrink-0" />
|
||
<span className="truncate">{lesson.title}</span>
|
||
</button>
|
||
))}
|
||
{!readOnly && (
|
||
<button className="flex items-center gap-2 w-full rounded-md px-2 py-1.5 text-sm text-muted-foreground hover:bg-muted transition-colors">
|
||
<Plus className="h-4 w-4 shrink-0" />
|
||
<span>Добавить урок</span>
|
||
</button>
|
||
)}
|
||
</div>
|
||
)}
|
||
</div>
|
||
);
|
||
})}
|
||
</div>
|
||
|
||
{!readOnly && (
|
||
<div className="p-2 border-t">
|
||
<Button variant="ghost" size="sm" className="w-full justify-start">
|
||
<Plus className="mr-2 h-4 w-4" />
|
||
Добавить главу
|
||
</Button>
|
||
</div>
|
||
)}
|
||
</div>
|
||
);
|
||
}
|