@@ -38,7 +38,8 @@ export function FeaturedTaskCarousel({
3838 ) ;
3939 }
4040
41- const activeTask = mergedTasks [ activeIndex ] ?? mergedTasks [ 0 ] ;
41+ const normalizedActiveIndex = activeIndex % mergedTasks . length ;
42+ const activeTask = mergedTasks [ normalizedActiveIndex ] ?? mergedTasks [ 0 ] ;
4243 const preview = activeTask . web_variant ;
4344 const drawerTask = mergedTasks . find ( ( task ) => task . repo === drawerRepo ) ?? null ;
4445
@@ -49,32 +50,45 @@ export function FeaturedTaskCarousel({
4950
5051 return (
5152 < >
52- < div className = "relative mx-auto w-full max-w-[590px]" >
53- < button
54- type = "button"
55- className = "tb-focus-ring absolute left-3 top-1/2 z-10 -translate-y-1/2 rounded-full border-2 border-[#25314d] bg-white p-3 shadow-[0_4px_0_#25314d] sm:left-0 sm:-translate-x-1/2"
56- onClick = { ( ) => goTo ( activeIndex - 1 ) }
57- aria-label = "Show previous featured task"
58- >
59- < IconChevronLeft className = "size-4" />
60- </ button >
61- < button
62- type = "button"
63- className = "tb-focus-ring absolute right-3 top-1/2 z-10 -translate-y-1/2 rounded-full border-2 border-[#25314d] bg-white p-3 shadow-[0_4px_0_#25314d] sm:right-0 sm:translate-x-1/2"
64- onClick = { ( ) => goTo ( activeIndex + 1 ) }
65- aria-label = "Show next featured task"
66- >
67- < IconChevronRight className = "size-4" />
68- </ button >
69- < div className = "tb-frame h-[410px] overflow-visible bg-[#fffdf9] px-6 py-7 sm:h-[450px] sm:px-8" >
70- < div className = "flex h-full flex-col" >
71- < div className = "flex flex-wrap justify-center gap-2" >
53+ < div className = "mx-auto w-full max-w-[620px]" >
54+ < div className = "tb-frame overflow-hidden bg-[#fffdf9] p-4 sm:p-6" >
55+ < div className = "flex flex-col gap-5" >
56+ < div className = "flex items-start justify-between gap-4" >
57+ < div className = "min-w-0" >
58+ < div className = "text-[11px] font-bold uppercase tracking-[0.24em] text-slate-500" >
59+ Featured Task
60+ </ div >
61+ </ div >
62+
63+ < div className = "flex shrink-0 items-center gap-2" >
64+ < button
65+ type = "button"
66+ className = "tb-focus-ring rounded-full border-2 border-[#25314d] bg-white p-2.5 shadow-[0_4px_0_#25314d] transition-transform hover:-translate-y-px disabled:translate-y-0 disabled:cursor-default disabled:opacity-50"
67+ onClick = { ( ) => goTo ( activeIndex - 1 ) }
68+ aria-label = "Show previous featured task"
69+ disabled = { mergedTasks . length < 2 }
70+ >
71+ < IconChevronLeft className = "size-4" />
72+ </ button >
73+ < button
74+ type = "button"
75+ className = "tb-focus-ring rounded-full border-2 border-[#25314d] bg-white p-2.5 shadow-[0_4px_0_#25314d] transition-transform hover:-translate-y-px disabled:translate-y-0 disabled:cursor-default disabled:opacity-50"
76+ onClick = { ( ) => goTo ( activeIndex + 1 ) }
77+ aria-label = "Show next featured task"
78+ disabled = { mergedTasks . length < 2 }
79+ >
80+ < IconChevronRight className = "size-4" />
81+ </ button >
82+ </ div >
83+ </ div >
84+
85+ < div className = "flex flex-wrap gap-2" >
7286 { mergedTasks . map ( ( task , index ) => (
7387 < button
7488 key = { task . repo }
7589 type = "button"
7690 className = {
77- index === activeIndex
91+ index === normalizedActiveIndex
7892 ? "tb-focus-ring rounded-full border-2 border-[#25314d] bg-[#d7ebf6] px-3 py-1.5 text-sm font-bold text-[#25314d] shadow-[0_4px_0_#25314d]"
7993 : "tb-focus-ring rounded-full border-2 border-[#25314d] bg-white px-3 py-1.5 text-sm font-bold text-[#25314d]"
8094 }
@@ -85,68 +99,49 @@ export function FeaturedTaskCarousel({
8599 ) ) }
86100 </ div >
87101
88- < div className = "mt-6 flex-1" >
89- < div className = "tb-frame-soft flex h-full flex-col bg-[#f8fcff] p-5 sm:p-6" >
90- < div className = "flex flex-wrap items-center gap-2 text-xs text-slate-600" >
91- < code className = "rounded-full border-2 border-[#25314d] bg-white px-2.5 py-1 font-mono text-[11px] font-semibold text-[#25314d]" >
92- { taskHandle ( activeTask ) }
93- </ code >
94- { activeTask . maturity ? < MaturityBadge maturity = { activeTask . maturity } /> : null }
95- { preview ? (
96- < span className = "rounded-full bg-[#ecffe5] px-3 py-1 text-[11px] font-bold text-[#25314d]" >
97- Preview ready
98- </ span >
99- ) : null }
100- < span className = "rounded-full bg-[#e2f3fb] px-3 py-1 text-[11px] font-bold text-[#25314d]" >
101- { formatShortDate ( activeTask . last_updated ) }
102+ < div className = "tb-frame-soft flex min-h-[320px] flex-col bg-[#f8fcff] p-5 sm:min-h-[360px] sm:p-6" >
103+ < div className = "flex flex-wrap items-center gap-2 text-xs text-slate-600" >
104+ < code className = "rounded-full border-2 border-[#25314d] bg-white px-2.5 py-1 font-mono text-[11px] font-semibold text-[#25314d]" >
105+ { taskHandle ( activeTask ) }
106+ </ code >
107+ { activeTask . maturity ? < MaturityBadge maturity = { activeTask . maturity } /> : null }
108+ { preview ? (
109+ < span className = "rounded-full bg-[#ecffe5] px-3 py-1 text-[11px] font-bold text-[#25314d]" >
110+ Preview ready
102111 </ span >
103- </ div >
112+ ) : null }
113+ < span className = "rounded-full bg-[#e2f3fb] px-3 py-1 text-[11px] font-bold text-[#25314d]" >
114+ { formatShortDate ( activeTask . last_updated ) }
115+ </ span >
116+ </ div >
104117
105- < div className = "mt-4 min-h-[6.1rem] font-heading text-3xl font-bold leading-tight text-[#25314d] sm:text-[2.65rem]" >
106- < span
107- style = { {
108- display : "-webkit-box" ,
109- WebkitLineClamp : 2 ,
110- WebkitBoxOrient : "vertical" ,
111- overflow : "hidden"
112- } }
113- >
114- { taskTitle ( activeTask ) }
115- </ span >
116- </ div >
118+ < div className = "mt-4 font-heading text-[2rem] font-bold leading-[1.02] text-[#25314d] sm:text-[2.45rem]" >
119+ { taskTitle ( activeTask ) }
120+ </ div >
121+
122+ < p className = "mt-3 max-w-[38ch] text-sm leading-7 text-slate-700 sm:text-base" >
123+ { activeTask . short_description }
124+ </ p >
117125
118- < p
119- className = "mt-3 min-h-[4.8rem] max-w-[36ch] text-sm leading-7 text-slate-700 sm:text-base"
120- style = { {
121- display : "-webkit-box" ,
122- WebkitLineClamp : 3 ,
123- WebkitBoxOrient : "vertical" ,
124- overflow : "hidden"
125- } }
126+ < div className = "mt-6 flex flex-wrap gap-3 sm:mt-auto" >
127+ < button
128+ type = "button"
129+ className = "tb-focus-ring tb-button-primary"
130+ onClick = { ( ) => setDrawerRepo ( activeTask . repo ) }
126131 >
127- { activeTask . short_description }
128- </ p >
129-
130- < div className = "mt-auto flex flex-wrap gap-3" >
131- < button
132- type = "button"
133- className = "tb-focus-ring tb-button-primary "
134- onClick = { ( ) => setDrawerRepo ( activeTask . repo ) }
132+ Expand details
133+ </ button >
134+ { preview ? (
135+ < a
136+ className = "tb-focus-ring tb- button-secondary bg-[#d7ebf6]"
137+ href = { preview . run_url }
138+ target = "_blank "
139+ rel = "noreferrer"
135140 >
136- Expand details
137- </ button >
138- { preview ? (
139- < a
140- className = "tb-focus-ring tb-button-secondary bg-[#d7ebf6]"
141- href = { preview . run_url }
142- target = "_blank"
143- rel = "noreferrer"
144- >
145- < IconPlay className = "size-4" />
146- Run Preview
147- </ a >
148- ) : null }
149- </ div >
141+ < IconPlay className = "size-4" />
142+ Run Preview
143+ </ a >
144+ ) : null }
150145 </ div >
151146 </ div >
152147 </ div >
0 commit comments