11'use client'
22
3- import { useMemo } from "react"
3+ import { useMemo , useState } from "react"
44import Link from "next/link"
55import LessonCard from "@/components/LessonCard"
66import FilterControls from "@/components/FilterControls"
77import { useLessonFilters } from "@/hooks/useLessonFilters"
88import { TIMELINE_ERAS , groupLessonsByTimelineEra } from "@/lib/timeline"
9+ import type { TimelineEra } from "@/lib/types"
910
1011export default function TimelinePage ( ) {
1112 const {
@@ -25,6 +26,26 @@ export default function TimelinePage() {
2526 ( era ) => ( grouped . get ( era . id ) ?. length ?? 0 ) > 0
2627 )
2728
29+ const [ collapsed , setCollapsed ] = useState < Set < TimelineEra > > ( new Set ( ) )
30+
31+ function toggleEra ( id : TimelineEra ) {
32+ setCollapsed ( ( prev ) => {
33+ const next = new Set ( prev )
34+ if ( next . has ( id ) ) next . delete ( id )
35+ else next . add ( id )
36+ return next
37+ } )
38+ }
39+
40+ const allExpanded = collapsed . size === 0
41+ function toggleAll ( ) {
42+ if ( allExpanded ) {
43+ setCollapsed ( new Set ( visibleEras . map ( ( e ) => e . id ) ) )
44+ } else {
45+ setCollapsed ( new Set ( ) )
46+ }
47+ }
48+
2849 return (
2950 < div className = "space-y-8" >
3051
@@ -98,6 +119,16 @@ export default function TimelinePage() {
98119 </ div >
99120
100121 { /* ── Timeline ── */ }
122+ { hasResults && (
123+ < div className = "flex justify-end" >
124+ < button
125+ onClick = { toggleAll }
126+ className = "rounded-lg border border-[#d8ccb8] bg-white px-3 py-1.5 text-xs font-semibold text-[#7e622a] transition hover:bg-[#fbf7ee]"
127+ >
128+ { allExpanded ? 'Collapse All' : 'Expand All' }
129+ </ button >
130+ </ div >
131+ ) }
101132 { hasResults ? (
102133 < div className = "relative ml-3 border-l-2 border-[#d8ccb8] sm:ml-5" >
103134 { visibleEras . map ( ( era , visibleIndex ) => {
@@ -116,9 +147,20 @@ export default function TimelinePage() {
116147 </ div >
117148
118149 { /* Era header */ }
119- < div className = "rounded-2xl border border-[#d8ccb8] bg-white p-5 shadow-sm" >
120- < div className = "text-xs font-semibold uppercase tracking-widest text-[#7e622a]" >
121- { era . arcPhrase }
150+ < button
151+ onClick = { ( ) => toggleEra ( era . id ) }
152+ className = "w-full rounded-2xl border border-[#d8ccb8] bg-white p-5 shadow-sm text-left transition hover:border-[#c8a84b] cursor-pointer"
153+ >
154+ < div className = "flex items-center justify-between" >
155+ < div className = "text-xs font-semibold uppercase tracking-widest text-[#7e622a]" >
156+ { era . arcPhrase }
157+ </ div >
158+ < svg
159+ className = { `h-5 w-5 text-[#7e622a] transition-transform duration-200 ${ collapsed . has ( era . id ) ? '' : 'rotate-180' } ` }
160+ fill = "none" viewBox = "0 0 24 24" stroke = "currentColor" strokeWidth = { 2 }
161+ >
162+ < path strokeLinecap = "round" strokeLinejoin = "round" d = "M19 9l-7 7-7-7" />
163+ </ svg >
122164 </ div >
123165 < h2 className = "mt-1 text-2xl font-bold text-[#1b1a17]" >
124166 { era . title }
@@ -132,17 +174,21 @@ export default function TimelinePage() {
132174 { sorted . length } { sorted . length === 1 ? 'lesson' : 'lessons' }
133175 </ span >
134176 </ div >
135- < p className = "mt-3 max-w-3xl text-sm leading-relaxed text-[#4a4338]" >
136- { era . description }
137- </ p >
138- </ div >
177+ { ! collapsed . has ( era . id ) && (
178+ < p className = "mt-3 max-w-3xl text-sm leading-relaxed text-[#4a4338]" >
179+ { era . description }
180+ </ p >
181+ ) }
182+ </ button >
139183
140184 { /* Lesson cards */ }
141- < div className = "mt-4 grid gap-4 md:grid-cols-2 xl:grid-cols-3" >
142- { sorted . map ( ( lesson ) => (
143- < LessonCard key = { lesson . slug } lesson = { lesson } />
144- ) ) }
145- </ div >
185+ { ! collapsed . has ( era . id ) && (
186+ < div className = "mt-4 grid gap-4 md:grid-cols-2 xl:grid-cols-3" >
187+ { sorted . map ( ( lesson ) => (
188+ < LessonCard key = { lesson . slug } lesson = { lesson } />
189+ ) ) }
190+ </ div >
191+ ) }
146192 </ section >
147193 )
148194 } ) }
0 commit comments