@ -7,6 +7,12 @@ import { CheckIcon } from '../ReactIcons/CheckIcon';
import { getPercentage } from '../../helper/number' ;
import { getPercentage } from '../../helper/number' ;
import { useIsMounted } from '../../hooks/use-is-mounted' ;
import { useIsMounted } from '../../hooks/use-is-mounted' ;
function LeftBorder() {
return (
< span className = "absolute left-[17px] top-0 h-full w-0.5 bg-gray-200" > < / span >
) ;
}
type ChapterProps = ChapterFileType & {
type ChapterProps = ChapterFileType & {
index : number ;
index : number ;
isActive? : boolean ;
isActive? : boolean ;
@ -76,31 +82,33 @@ export function Chapter(props: ChapterProps) {
< div >
< div >
< button
< button
className = { cn (
className = { cn (
'relative z-10 flex w-full items-center gap-2 border-b border-zinc-800 p-2 text-sm' ,
'relative z-10 flex w-full items-center gap-2 border-b px-2 py-4 text-base' ,
isActive && 'text-white' ,
{
'text-black' : true ,
} ,
) }
) }
onClick = { onChapterClick }
onClick = { onChapterClick }
>
>
< div className = "flex size-5 items-center justify-center rounded-full bg-zinc-70 0 text-xs text-white" >
< div className = "text-400 flex h-[21px] w-[21px] flex-shrink-0 items-center justify-center rounded-full bg-gray-400/7 0 text-xs text-white" >
{ index }
{ index }
< / div >
< / div >
< span className = "truncate text-left" > { title } < / span >
< span className = "truncate text-left" > { title } < / span >
{ /*Right check of completion*/ }
{ isChapterCompleted && lessons . length > 0 && (
{ isChapterCompleted && lessons . length > 0 && (
< CheckIcon additionalClasses = "h-4 w-4 ml-auto" / >
< CheckIcon additionalClasses = "h-4 w-4 ml-auto flex-shrink-0 " / >
) }
) }
{ /* active background indicator */ }
< div
< div
className = "absolute inset-0 -z-10 w-[var(--completed-percentage)] bg-zinc-800 transition-[width] duration-150 will-change-[width]"
className = "absolute inset-0 -z-10 bg-gray-100"
style = {
style = { {
{
width : ` ${ completedPercentage } % ` ,
'--completed-percentage' : ` ${ completedPercentage } % ` ,
} }
} as CSSProperties
}
/ >
/ >
< / button >
< / button >
{ isActive && (
{ isActive && (
< div className = "flex flex-col border-b border-zinc-800 " >
< div className = "flex flex-col border-b" >
{ lessons . length > 0 && (
{ lessons . length > 0 && (
< >
< >
< LessonList
< LessonList
@ -113,11 +121,11 @@ export function Chapter(props: ChapterProps) {
/ >
/ >
< div className = "relative" >
< div className = "relative" >
< label className = "relative z-10 my-2 ml-2 block max-w-max rounded-md bg-zinc-8 00 p-1 px-2 text-xs" >
< label className = "relative z-10 my-2 ml-2 block max-w-max rounded-md bg-gray-2 00 p-1 px-2 text-xs" >
Exercises
Exercises
< / label >
< / label >
< span className = "absolute left-[17px] top-0 h-full w-0.5 bg-zinc-700" > < / span >
< LeftBorder / >
< / div >
< / div >
< LessonList
< LessonList
@ -162,13 +170,14 @@ function LessonList(props: LessonListProps) {
return (
return (
< div >
< div >
{ lessons . map ( ( lesson ) = > {
{ lessons . map ( ( lesson , counter ) = > {
const isActive =
const isActive =
activeLessonId === lesson . id && chapterId === activeChapterId ;
activeLessonId === lesson . id && chapterId === activeChapterId ;
const isCompleted = completedLessonSet . has ( ` ${ chapterId } / ${ lesson . id } ` ) ;
const isCompleted = completedLessonSet . has ( ` ${ chapterId } / ${ lesson . id } ` ) ;
return (
return (
< Lesson
< Lesson
counter = { counter + 1 }
key = { lesson . id }
key = { lesson . id }
{ . . . lesson }
{ . . . lesson }
courseId = { activeCourseId }
courseId = { activeCourseId }
@ -186,6 +195,7 @@ type LessonProps = LessonFileType & {
isActive? : boolean ;
isActive? : boolean ;
isCompleted? : boolean ;
isCompleted? : boolean ;
courseId : string ;
courseId : string ;
counter : number ;
chapterId : string ;
chapterId : string ;
} ;
} ;
@ -196,6 +206,7 @@ export function Lesson(props: LessonProps) {
courseId ,
courseId ,
chapterId ,
chapterId ,
id : lessonId ,
id : lessonId ,
counter ,
isCompleted ,
isCompleted ,
} = props ;
} = props ;
const { title } = frontmatter ;
const { title } = frontmatter ;
@ -207,20 +218,36 @@ export function Lesson(props: LessonProps) {
return (
return (
< a
< a
className = { cn (
className = { cn (
'relative flex w-full items-center gap-2 p-2 text-sm text-zinc-600' ,
'relative flex w-full items-center gap-2 p-2 text-sm hover:bg-gray-100' ,
isActive && 'bg-zinc-800/50 text-white' ,
{
'bg-gray-100' : isActive ,
} ,
) }
) }
href = { href }
href = { href }
>
>
< div className = "relative z-10 flex size-5 items-center justify-center rounded-full bg-zinc-700 text-xs text-white" >
< div
{ isCompleted && < Check className = "h-3 w-3 stroke-[3]" / > }
className = { cn (
{ isLoading && isMounted && (
'relative z-10 flex size-5 flex-shrink-0 items-center justify-center rounded-full bg-gray-400/70 text-xs text-white' ,
< Loader2 className = "h-3 w-3 animate-spin stroke-[3] opacity-60" / >
) }
) }
>
{ counter }
< / div >
< / div >
< span className = "truncate text-left" > { title } < / span >
< span className = "flex-grow truncate text-left" > { title } < / span >
{ isCompleted && (
< div
className = { cn (
'relative z-10 flex size-5 flex-shrink-0 items-center justify-center rounded-full text-xs text-white' ,
{
'bg-black' : isCompleted ,
} ,
) }
>
< Check className = "h-3 w-3 stroke-[3] text-white" / >
< / div >
) }
< span className = "absolute left-[17px] top-0 h-full w-0.5 bg-zinc-700" > < / span >
{ ! isActive && < LeftBorder / > }
< / a >
< / a >
) ;
) ;
}
}