Skip to content

Commit cb45e70

Browse files
committed
Enhance Speakers page with dynamic timeline and CFP status; add styles for timeline states and badges
Signed-off-by: Steve Yonkeu <yokwejuste@yahoo.com>
1 parent 274622e commit cb45e70

File tree

2 files changed

+107
-47
lines changed

2 files changed

+107
-47
lines changed

src/index.css

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1975,6 +1975,47 @@ img {
19751975
margin-bottom: var(--spacing-xs);
19761976
}
19771977

1978+
/* Timeline status states */
1979+
.timeline-past {
1980+
opacity: 0.5;
1981+
}
1982+
1983+
.timeline-past .timeline-content h4 {
1984+
text-decoration: line-through;
1985+
}
1986+
1987+
.timeline-past::before {
1988+
background: var(--color-green);
1989+
}
1990+
1991+
.timeline-active::before {
1992+
background: var(--color-green);
1993+
box-shadow: 0 0 0 4px rgba(0, 200, 83, 0.3);
1994+
animation: timeline-pulse 2s ease-in-out infinite;
1995+
}
1996+
1997+
@keyframes timeline-pulse {
1998+
0%, 100% { box-shadow: 0 0 0 4px rgba(0, 200, 83, 0.3); }
1999+
50% { box-shadow: 0 0 0 8px rgba(0, 200, 83, 0.1); }
2000+
}
2001+
2002+
.timeline-badge {
2003+
display: inline-block;
2004+
margin-left: var(--spacing-xs);
2005+
padding: 2px 8px;
2006+
font-size: 0.7rem;
2007+
font-weight: 700;
2008+
text-transform: uppercase;
2009+
border-radius: var(--radius-full);
2010+
background: var(--color-green);
2011+
color: white;
2012+
vertical-align: middle;
2013+
}
2014+
2015+
.timeline-badge-done {
2016+
background: var(--color-gray);
2017+
}
2018+
19782019
/* ===================================
19792020
Sponsor Page Specific Styles
19802021
=================================== */

src/pages/Speakers.jsx

Lines changed: 66 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,47 @@
1-
import React from 'react';
1+
import React, { useMemo } from 'react';
22
import useScrollAnimation from '../hooks/useScrollAnimation';
33

4+
const TIMELINE_MILESTONES = [
5+
{ date: new Date('2026-03-30'), label: 'March 30th, 2026', title: 'CFP and Call for Sponsors Opens', description: 'Start submitting your talk and workshop proposals via Sessionize.' },
6+
{ date: new Date('2026-05-15T23:59:00+01:00'), label: 'May 15th, 2026, 11:59 PM WAT', title: 'CFP Closes', description: "Last day to submit your proposals. Don't wait until the last minute!" },
7+
{ date: new Date('2026-05-30'), label: 'May 30th, 2026', title: 'Announcement of Speakers', description: 'Selected speakers will be announced. All submitters will receive notifications.' },
8+
{ date: new Date('2026-06-15'), label: 'June 15th, 2026', title: 'Schedule Published', description: 'The full conference schedule is posted on the PyCon Cameroon website.' },
9+
{ date: new Date('2026-09-19'), label: 'September 17th-19th, 2026', title: 'PyCon Cameroon 2026', description: 'The main event in Yaoundé, Cameroon!' },
10+
];
11+
12+
function getCfpStatus(now) {
13+
const cfpOpen = TIMELINE_MILESTONES[0].date;
14+
const cfpClose = TIMELINE_MILESTONES[1].date;
15+
if (now < cfpOpen) return 'upcoming';
16+
if (now <= cfpClose) return 'open';
17+
return 'closed';
18+
}
19+
20+
function getTimelineItemStatus(milestone, index, now) {
21+
const nextMilestone = TIMELINE_MILESTONES[index + 1];
22+
if (nextMilestone && now >= nextMilestone.date) return 'past';
23+
if (now >= milestone.date) return 'active';
24+
return 'upcoming';
25+
}
26+
427
const Speakers = () => {
528
useScrollAnimation();
629

30+
const now = useMemo(() => new Date(), []);
31+
const cfpStatus = getCfpStatus(now);
32+
33+
const bannerContent = {
34+
upcoming: { text: `📢 Call for Proposals will be OPEN on ${TIMELINE_MILESTONES[0].label}!`, alertClass: 'alert-success' },
35+
open: { text: '📢 Call for Proposals is NOW OPEN!', alertClass: 'alert-success' },
36+
closed: { text: '📢 Call for Proposals is now CLOSED. Thank you for your submissions!', alertClass: 'alert-warning' },
37+
}[cfpStatus];
38+
39+
const ctaText = {
40+
upcoming: `We can't wait to see your proposal. Submissions open ${TIMELINE_MILESTONES[0].label}!`,
41+
open: `We can't wait to see your proposal. Submit before ${TIMELINE_MILESTONES[1].label}!`,
42+
closed: 'The CFP is closed. Stay tuned for speaker announcements!',
43+
}[cfpStatus];
44+
745
return (
846
<>
947
{/* Page Header */}
@@ -28,13 +66,15 @@ const Speakers = () => {
2866
submit your proposal and we'll review it with care.
2967
</p>
3068

31-
<div className="alert alert-success" style={{ textAlign: 'left', margin: 'var(--spacing-lg) 0' }}>
32-
<strong>📢 Call for Proposals will be OPEN this March 01 2026!</strong><br />
69+
<div className={`alert ${bannerContent.alertClass}`} style={{ textAlign: 'left', margin: 'var(--spacing-lg) 0' }}>
70+
<strong>{bannerContent.text}</strong><br />
3371
We're inviting speakers of all experience levels and backgrounds to contribute
3472
to our conference program. Don't be shy – your unique perspective matters!
3573
</div>
3674

37-
<a href="https://sessionize.com/pycon-camerooon-2026" target="_blank" rel="noopener noreferrer" className="btn btn-primary btn-lg">Submit Your Proposal</a>
75+
{cfpStatus !== 'closed' && (
76+
<a href="https://sessionize.com/pycon-camerooon-2026" target="_blank" rel="noopener noreferrer" className="btn btn-primary btn-lg">Submit Your Proposal</a>
77+
)}
3878
</div>
3979
</div>
4080
</section>
@@ -69,45 +109,22 @@ const Speakers = () => {
69109
</h3>
70110

71111
<div className="timeline">
72-
<div className="timeline-item">
73-
<div className="timeline-date">March 30th, 2026</div>
74-
<div className="timeline-content">
75-
<h4>CFP and Call for Sponsors Opens</h4>
76-
<p>Start submitting your talk and workshop proposals via Sessionize.</p>
77-
</div>
78-
</div>
79-
80-
<div className="timeline-item">
81-
<div className="timeline-date">May 15th, 2026, 11:59 PM WAT</div>
82-
<div className="timeline-content">
83-
<h4>CFP Closes</h4>
84-
<p>Last day to submit your proposals. Don't wait until the last minute!</p>
85-
</div>
86-
</div>
87-
88-
<div className="timeline-item">
89-
<div className="timeline-date">May 30th, 2026</div>
90-
<div className="timeline-content">
91-
<h4>Announcement of Speakers</h4>
92-
<p>Selected speakers will be announced. All submitters will receive notifications.</p>
93-
</div>
94-
</div>
95-
96-
<div className="timeline-item">
97-
<div className="timeline-date">June 15th, 2026</div>
98-
<div className="timeline-content">
99-
<h4>Schedule Published</h4>
100-
<p>The full conference schedule is posted on the PyCon Cameroon website.</p>
101-
</div>
102-
</div>
103-
104-
<div className="timeline-item">
105-
<div className="timeline-date">September 17th-19th, 2026</div>
106-
<div className="timeline-content">
107-
<h4>PyCon Cameroon 2026</h4>
108-
<p>The main event in Yaoundé, Cameroon!</p>
109-
</div>
110-
</div>
112+
{TIMELINE_MILESTONES.map((milestone, index) => {
113+
const status = getTimelineItemStatus(milestone, index, now);
114+
return (
115+
<div className={`timeline-item timeline-${status}`} key={index}>
116+
<div className="timeline-date">
117+
{milestone.label}
118+
{status === 'active' && <span className="timeline-badge">Now</span>}
119+
{status === 'past' && <span className="timeline-badge timeline-badge-done">Done</span>}
120+
</div>
121+
<div className="timeline-content">
122+
<h4>{milestone.title}</h4>
123+
<p>{milestone.description}</p>
124+
</div>
125+
</div>
126+
);
127+
})}
111128
</div>
112129

113130
{/* Session Types */}
@@ -332,11 +349,13 @@ const Speakers = () => {
332349
<div className="container text-center">
333350
<h2 style={{ color: 'white', marginBottom: 'var(--spacing-sm)' }}>Ready to Share Your Knowledge?</h2>
334351
<p style={{ color: 'rgba(255,255,255,0.9)', fontSize: '1.25rem', marginBottom: 'var(--spacing-md)' }}>
335-
We can't wait to see your proposal. Submit before May 31st, 2026!
352+
{ctaText}
336353
</p>
337-
<a href="https://sessionize.com/pycon-camerooon-2026" target="_blank" rel="noopener noreferrer" className="btn btn-lg" style={{ background: 'white', color: 'var(--color-green)' }}>
338-
Submit Your Proposal Now
339-
</a>
354+
{cfpStatus !== 'closed' && (
355+
<a href="https://sessionize.com/pycon-camerooon-2026" target="_blank" rel="noopener noreferrer" className="btn btn-lg" style={{ background: 'white', color: 'var(--color-green)' }}>
356+
Submit Your Proposal Now
357+
</a>
358+
)}
340359
</div>
341360
</section>
342361
</>

0 commit comments

Comments
 (0)