Spaces:
Running
Running
Fix date parsing
Browse files- src/components/ConferenceCalendar.tsx +37 -25
- src/data/conferences.yml +36 -10
- src/pages/Calendar.tsx +52 -76
src/components/ConferenceCalendar.tsx
CHANGED
@@ -20,46 +20,53 @@ const ConferenceCalendar = ({ conferences }: ConferenceCalendarProps) => {
|
|
20 |
// Convert conference dates to calendar events
|
21 |
const conferenceEvents = conferences.map(conf => {
|
22 |
let startDate: Date | null = null;
|
|
|
23 |
|
24 |
try {
|
25 |
-
//
|
26 |
-
if (conf.start) {
|
27 |
startDate = parseISO(conf.start);
|
|
|
28 |
}
|
29 |
-
// If no start
|
30 |
else if (conf.date) {
|
31 |
-
|
32 |
-
const dateStr = conf.date.split('–')[0].split('-')[0].trim(); // Get first date in range
|
33 |
|
34 |
-
// Try different date formats
|
35 |
try {
|
36 |
-
// Try
|
37 |
-
startDate = parse(
|
38 |
-
|
39 |
-
|
40 |
-
|
41 |
-
|
42 |
-
|
43 |
-
|
44 |
-
|
|
|
|
|
|
|
|
|
45 |
}
|
|
|
|
|
46 |
}
|
47 |
}
|
48 |
|
49 |
-
// Only return event if we successfully parsed
|
50 |
-
if (startDate && isValidDate(startDate)) {
|
51 |
return {
|
52 |
-
|
|
|
53 |
title: conf.title,
|
54 |
conference: conf
|
55 |
};
|
56 |
}
|
57 |
return null;
|
58 |
} catch (error) {
|
59 |
-
console.warn(`Failed to parse
|
60 |
return null;
|
61 |
}
|
62 |
-
}).filter(event => event !== null);
|
63 |
|
64 |
// Helper function to check if date is valid
|
65 |
function isValidDate(date: Date) {
|
@@ -70,16 +77,21 @@ const ConferenceCalendar = ({ conferences }: ConferenceCalendarProps) => {
|
|
70 |
const getEventsForDate = (date: Date) => {
|
71 |
if (!date || !isValidDate(date)) return [];
|
72 |
return conferenceEvents.filter(event =>
|
73 |
-
event && event.
|
74 |
-
|
75 |
);
|
76 |
};
|
77 |
|
78 |
// Get events for the current month
|
79 |
const getEventsForMonth = (date: Date) => {
|
|
|
|
|
|
|
80 |
return conferenceEvents.filter(event =>
|
81 |
-
event && event.
|
82 |
-
|
|
|
|
|
83 |
);
|
84 |
};
|
85 |
|
@@ -93,7 +105,7 @@ const ConferenceCalendar = ({ conferences }: ConferenceCalendarProps) => {
|
|
93 |
<ul className="mt-2 space-y-1">
|
94 |
{getEventsForMonth(currentMonth).map((event, index) => (
|
95 |
<li key={index} className="text-sm">
|
96 |
-
{event.title} ({format(event.
|
97 |
</li>
|
98 |
))}
|
99 |
</ul>
|
|
|
20 |
// Convert conference dates to calendar events
|
21 |
const conferenceEvents = conferences.map(conf => {
|
22 |
let startDate: Date | null = null;
|
23 |
+
let endDate: Date | null = null;
|
24 |
|
25 |
try {
|
26 |
+
// Parse both start and end dates
|
27 |
+
if (conf.start && conf.end) {
|
28 |
startDate = parseISO(conf.start);
|
29 |
+
endDate = parseISO(conf.end);
|
30 |
}
|
31 |
+
// If no start/end fields, try to parse from date field
|
32 |
else if (conf.date) {
|
33 |
+
const [startStr, endStr] = conf.date.split(/[-–]/).map(d => d.trim());
|
|
|
34 |
|
|
|
35 |
try {
|
36 |
+
// Try parsing start date
|
37 |
+
startDate = parse(startStr, 'MMM d, yyyy', new Date()) ||
|
38 |
+
parse(startStr, 'MMMM d, yyyy', new Date()) ||
|
39 |
+
parseISO(startStr);
|
40 |
+
|
41 |
+
// Try parsing end date if it exists
|
42 |
+
if (endStr) {
|
43 |
+
endDate = parse(endStr, 'MMM d, yyyy', new Date()) ||
|
44 |
+
parse(endStr, 'MMMM d, yyyy', new Date()) ||
|
45 |
+
parseISO(endStr);
|
46 |
+
} else {
|
47 |
+
// If no end date, use start date
|
48 |
+
endDate = startDate;
|
49 |
}
|
50 |
+
} catch (error) {
|
51 |
+
console.warn(`Failed to parse date range for conference ${conf.title}:`, error);
|
52 |
}
|
53 |
}
|
54 |
|
55 |
+
// Only return event if we successfully parsed both dates
|
56 |
+
if (startDate && endDate && isValidDate(startDate) && isValidDate(endDate)) {
|
57 |
return {
|
58 |
+
startDate,
|
59 |
+
endDate,
|
60 |
title: conf.title,
|
61 |
conference: conf
|
62 |
};
|
63 |
}
|
64 |
return null;
|
65 |
} catch (error) {
|
66 |
+
console.warn(`Failed to parse dates for conference ${conf.title}:`, error);
|
67 |
return null;
|
68 |
}
|
69 |
+
}).filter(event => event !== null);
|
70 |
|
71 |
// Helper function to check if date is valid
|
72 |
function isValidDate(date: Date) {
|
|
|
77 |
const getEventsForDate = (date: Date) => {
|
78 |
if (!date || !isValidDate(date)) return [];
|
79 |
return conferenceEvents.filter(event =>
|
80 |
+
event && event.startDate && event.endDate &&
|
81 |
+
date >= event.startDate && date <= event.endDate
|
82 |
);
|
83 |
};
|
84 |
|
85 |
// Get events for the current month
|
86 |
const getEventsForMonth = (date: Date) => {
|
87 |
+
const monthStart = startOfMonth(date);
|
88 |
+
const nextMonthStart = new Date(date.getFullYear(), date.getMonth() + 1, 1);
|
89 |
+
|
90 |
return conferenceEvents.filter(event =>
|
91 |
+
event && event.startDate && event.endDate &&
|
92 |
+
((event.startDate >= monthStart && event.startDate < nextMonthStart) ||
|
93 |
+
(event.endDate >= monthStart && event.endDate < nextMonthStart) ||
|
94 |
+
(event.startDate <= monthStart && event.endDate >= nextMonthStart))
|
95 |
);
|
96 |
};
|
97 |
|
|
|
105 |
<ul className="mt-2 space-y-1">
|
106 |
{getEventsForMonth(currentMonth).map((event, index) => (
|
107 |
<li key={index} className="text-sm">
|
108 |
+
{event.title} ({format(event.startDate, 'MMM d')}-{format(event.endDate, 'MMM d')}) - {event.conference.place}
|
109 |
</li>
|
110 |
))}
|
111 |
</ul>
|
src/data/conferences.yml
CHANGED
@@ -58,7 +58,7 @@
|
|
58 |
timezone: UTC-12
|
59 |
place: Hyderabad, India
|
60 |
date: April 6-11, 2025
|
61 |
-
start: 2025-04-
|
62 |
end: 2025-04-11
|
63 |
tags:
|
64 |
- signal-processing
|
@@ -119,6 +119,8 @@
|
|
119 |
timezone: UTC+0
|
120 |
place: Milan, Italy
|
121 |
date: February 24-27, 2025
|
|
|
|
|
122 |
tags:
|
123 |
- machine-learning
|
124 |
|
@@ -207,6 +209,7 @@
|
|
207 |
- title: CVPR
|
208 |
year: 2025
|
209 |
id: cvpr25
|
|
|
210 |
link: https://cvpr.thecvf.com/Conferences/2025
|
211 |
deadline: '2024-11-15 06:59:59'
|
212 |
abstract_deadline: '2024-11-08 06:59:59'
|
@@ -223,15 +226,14 @@
|
|
223 |
- title: ESANN
|
224 |
year: 2025
|
225 |
id: esann25
|
226 |
-
full_name: European Symposium on Artificial Neural Networks, Computational Intelligence
|
227 |
-
and Machine Learning
|
228 |
link: https://www.esann.org/
|
229 |
deadline: '2024-11-20 00:00:00'
|
230 |
timezone: UTC-8
|
231 |
place: Bruges, Belgium
|
232 |
-
date: April 23
|
233 |
-
|
234 |
-
|
235 |
abstract_deadline: '2024-11-20 00:00:00'
|
236 |
note: 'Rankings: CCF: N, CORE: B, THCPL: N'
|
237 |
|
@@ -244,6 +246,8 @@
|
|
244 |
timezone: AoE
|
245 |
place: California, USA
|
246 |
date: March 24-27, 2025
|
|
|
|
|
247 |
tags:
|
248 |
- machine-learning
|
249 |
note: 'Rankings: CCF: N, CORE: N, THCPL: N'
|
@@ -257,6 +261,8 @@
|
|
257 |
timezone: UTC-12
|
258 |
place: Hangzhou, China
|
259 |
date: June 8-12, 2025
|
|
|
|
|
260 |
tags:
|
261 |
- machine-learning
|
262 |
|
@@ -267,8 +273,10 @@
|
|
267 |
link: https://2025.ijcai.org/
|
268 |
deadline: '2025-01-23 23:59:59'
|
269 |
timezone: UTC-12
|
270 |
-
place: Montreal, Canada
|
271 |
date: August 16-22, 2025
|
|
|
|
|
272 |
tags:
|
273 |
- machine-learning
|
274 |
abstract_deadline: '2025-01-16 23:59:59'
|
@@ -282,6 +290,8 @@
|
|
282 |
timezone: AoE
|
283 |
place: Los Angeles, California, USA
|
284 |
date: June 21-25, 2025
|
|
|
|
|
285 |
tags:
|
286 |
- machine-learning
|
287 |
abstract_deadline: '2025-01-17 23:59:00'
|
@@ -295,6 +305,8 @@
|
|
295 |
timezone: UTC-12
|
296 |
place: Vancouver Convention Center, Vancouver, Canada
|
297 |
date: July 11-19, 2025
|
|
|
|
|
298 |
tags:
|
299 |
- machine-learning
|
300 |
abstract_deadline: '2025-01-23 23:59:59'
|
@@ -308,6 +320,8 @@
|
|
308 |
timezone: UTC-12
|
309 |
place: Rome, Italy
|
310 |
date: June 30 - July 5, 2025
|
|
|
|
|
311 |
tags:
|
312 |
- machine-learning
|
313 |
|
@@ -320,6 +334,8 @@
|
|
320 |
timezone: UTC-5
|
321 |
place: Lyon, France
|
322 |
date: June 30 - July 4, 2025
|
|
|
|
|
323 |
tags:
|
324 |
- machine-learning
|
325 |
|
@@ -414,6 +430,8 @@
|
|
414 |
timezone: AoE
|
415 |
place: Palais des Congrès Montreal, Canada
|
416 |
date: October 7-9, 2025
|
|
|
|
|
417 |
tags:
|
418 |
- natural-language-processing
|
419 |
abstract_deadline: '2025-03-20 23:59:59'
|
@@ -427,6 +445,8 @@
|
|
427 |
timezone: UTC-12
|
428 |
place: Bologna, Italy
|
429 |
date: October 25-30, 2025
|
|
|
|
|
430 |
tags:
|
431 |
- machine-learning
|
432 |
abstract_deadline: '2025-04-29 23:59:59'
|
@@ -439,7 +459,9 @@
|
|
439 |
deadline: '2025-05-19 23:59:59'
|
440 |
timezone: UTC-12
|
441 |
place: Suzhou, China
|
442 |
-
date: November 5
|
|
|
|
|
443 |
tags:
|
444 |
- natural-language-processing
|
445 |
|
@@ -452,6 +474,8 @@
|
|
452 |
timezone: UTC+1
|
453 |
place: Vienna, Austria
|
454 |
date: Jun 1-5, 2026
|
|
|
|
|
455 |
tags:
|
456 |
- machine-learning
|
457 |
- robotics
|
@@ -461,9 +485,11 @@
|
|
461 |
id: neurips25
|
462 |
full_name: Conference on Neural Information Processing Systems
|
463 |
link: https://neurips.cc/
|
464 |
-
deadline:
|
465 |
timezone: UTC-8
|
466 |
place: San Diego, US
|
467 |
-
date:
|
|
|
|
|
468 |
tags:
|
469 |
- machine-learning
|
|
|
58 |
timezone: UTC-12
|
59 |
place: Hyderabad, India
|
60 |
date: April 6-11, 2025
|
61 |
+
start: 2025-04-06
|
62 |
end: 2025-04-11
|
63 |
tags:
|
64 |
- signal-processing
|
|
|
119 |
timezone: UTC+0
|
120 |
place: Milan, Italy
|
121 |
date: February 24-27, 2025
|
122 |
+
start: 2025-02-24
|
123 |
+
end: 2025-02-27
|
124 |
tags:
|
125 |
- machine-learning
|
126 |
|
|
|
209 |
- title: CVPR
|
210 |
year: 2025
|
211 |
id: cvpr25
|
212 |
+
full_name: IEEE/CVF Conference on Computer Vision and Pattern Recognition
|
213 |
link: https://cvpr.thecvf.com/Conferences/2025
|
214 |
deadline: '2024-11-15 06:59:59'
|
215 |
abstract_deadline: '2024-11-08 06:59:59'
|
|
|
226 |
- title: ESANN
|
227 |
year: 2025
|
228 |
id: esann25
|
229 |
+
full_name: European Symposium on Artificial Neural Networks, Computational Intelligence and Machine Learning
|
|
|
230 |
link: https://www.esann.org/
|
231 |
deadline: '2024-11-20 00:00:00'
|
232 |
timezone: UTC-8
|
233 |
place: Bruges, Belgium
|
234 |
+
date: April 23-25, 2025
|
235 |
+
start: 2025-04-23
|
236 |
+
end: 2025-04-25
|
237 |
abstract_deadline: '2024-11-20 00:00:00'
|
238 |
note: 'Rankings: CCF: N, CORE: B, THCPL: N'
|
239 |
|
|
|
246 |
timezone: AoE
|
247 |
place: California, USA
|
248 |
date: March 24-27, 2025
|
249 |
+
start: 2025-03-24
|
250 |
+
end: 2025-03-27
|
251 |
tags:
|
252 |
- machine-learning
|
253 |
note: 'Rankings: CCF: N, CORE: N, THCPL: N'
|
|
|
261 |
timezone: UTC-12
|
262 |
place: Hangzhou, China
|
263 |
date: June 8-12, 2025
|
264 |
+
start: 2025-06-08
|
265 |
+
end: 2025-06-12
|
266 |
tags:
|
267 |
- machine-learning
|
268 |
|
|
|
273 |
link: https://2025.ijcai.org/
|
274 |
deadline: '2025-01-23 23:59:59'
|
275 |
timezone: UTC-12
|
276 |
+
place: Montreal, Canada
|
277 |
date: August 16-22, 2025
|
278 |
+
start: 2025-08-16
|
279 |
+
end: 2025-08-22
|
280 |
tags:
|
281 |
- machine-learning
|
282 |
abstract_deadline: '2025-01-16 23:59:59'
|
|
|
290 |
timezone: AoE
|
291 |
place: Los Angeles, California, USA
|
292 |
date: June 21-25, 2025
|
293 |
+
start: 2025-06-21
|
294 |
+
end: 2025-06-25
|
295 |
tags:
|
296 |
- machine-learning
|
297 |
abstract_deadline: '2025-01-17 23:59:00'
|
|
|
305 |
timezone: UTC-12
|
306 |
place: Vancouver Convention Center, Vancouver, Canada
|
307 |
date: July 11-19, 2025
|
308 |
+
start: 2025-07-11
|
309 |
+
end: 2025-07-19
|
310 |
tags:
|
311 |
- machine-learning
|
312 |
abstract_deadline: '2025-01-23 23:59:59'
|
|
|
320 |
timezone: UTC-12
|
321 |
place: Rome, Italy
|
322 |
date: June 30 - July 5, 2025
|
323 |
+
start: 2025-06-30
|
324 |
+
end: 2025-07-05
|
325 |
tags:
|
326 |
- machine-learning
|
327 |
|
|
|
334 |
timezone: UTC-5
|
335 |
place: Lyon, France
|
336 |
date: June 30 - July 4, 2025
|
337 |
+
start: 2025-06-30
|
338 |
+
end: 2025-07-04
|
339 |
tags:
|
340 |
- machine-learning
|
341 |
|
|
|
430 |
timezone: AoE
|
431 |
place: Palais des Congrès Montreal, Canada
|
432 |
date: October 7-9, 2025
|
433 |
+
start: 2025-10-07
|
434 |
+
end: 2025-10-09
|
435 |
tags:
|
436 |
- natural-language-processing
|
437 |
abstract_deadline: '2025-03-20 23:59:59'
|
|
|
445 |
timezone: UTC-12
|
446 |
place: Bologna, Italy
|
447 |
date: October 25-30, 2025
|
448 |
+
start: 2025-10-25
|
449 |
+
end: 2025-10-30
|
450 |
tags:
|
451 |
- machine-learning
|
452 |
abstract_deadline: '2025-04-29 23:59:59'
|
|
|
459 |
deadline: '2025-05-19 23:59:59'
|
460 |
timezone: UTC-12
|
461 |
place: Suzhou, China
|
462 |
+
date: November 5-9, 2025
|
463 |
+
start: 2025-11-05
|
464 |
+
end: 2025-11-09
|
465 |
tags:
|
466 |
- natural-language-processing
|
467 |
|
|
|
474 |
timezone: UTC+1
|
475 |
place: Vienna, Austria
|
476 |
date: Jun 1-5, 2026
|
477 |
+
start: 2026-06-01
|
478 |
+
end: 2026-06-05
|
479 |
tags:
|
480 |
- machine-learning
|
481 |
- robotics
|
|
|
485 |
id: neurips25
|
486 |
full_name: Conference on Neural Information Processing Systems
|
487 |
link: https://neurips.cc/
|
488 |
+
deadline: '2025-05-16 23:59:59'
|
489 |
timezone: UTC-8
|
490 |
place: San Diego, US
|
491 |
+
date: December 9-15, 2025
|
492 |
+
start: 2025-12-09
|
493 |
+
end: 2025-12-15
|
494 |
tags:
|
495 |
- machine-learning
|
src/pages/Calendar.tsx
CHANGED
@@ -55,6 +55,9 @@ const CalendarPage = () => {
|
|
55 |
const safeParseISO = (dateString: string | undefined | number): Date | null => {
|
56 |
if (!dateString) return null;
|
57 |
if (dateString === 'TBD') return null;
|
|
|
|
|
|
|
58 |
|
59 |
try {
|
60 |
if (typeof dateString === 'object') {
|
@@ -114,35 +117,23 @@ const CalendarPage = () => {
|
|
114 |
};
|
115 |
|
116 |
const getDayEvents = (date: Date) => {
|
117 |
-
|
118 |
-
const matchesSearch = searchQuery === "" ||
|
119 |
-
conf.title.toLowerCase().includes(searchQuery.toLowerCase()) ||
|
120 |
-
(conf.full_name && conf.full_name.toLowerCase().includes(searchQuery.toLowerCase()));
|
121 |
-
|
122 |
-
const matchesTag = selectedTag === "All" || (Array.isArray(conf.tags) && conf.tags.includes(selectedTag));
|
123 |
-
|
124 |
-
if (!matchesSearch || !matchesTag) {
|
125 |
-
return acc;
|
126 |
-
}
|
127 |
-
|
128 |
const deadlineDate = safeParseISO(conf.deadline);
|
|
|
|
|
|
|
|
|
129 |
const startDate = safeParseISO(conf.start);
|
130 |
const endDate = safeParseISO(conf.end);
|
|
|
|
|
|
|
|
|
131 |
|
132 |
-
|
133 |
-
|
134 |
-
|
135 |
-
|
136 |
-
if (startDate && endDate) {
|
137 |
-
if (date >= startDate && date <= endDate) {
|
138 |
-
acc.conferences.push(conf);
|
139 |
-
}
|
140 |
-
} else if (startDate && isSameDay(startDate, date)) {
|
141 |
-
acc.conferences.push(conf);
|
142 |
-
}
|
143 |
-
|
144 |
-
return acc;
|
145 |
-
}, { deadlines: [], conferences: [] } as { deadlines: Conference[], conferences: Conference[] });
|
146 |
};
|
147 |
|
148 |
const renderEventPreview = (events: { deadlines: Conference[], conferences: Conference[] }) => {
|
@@ -176,49 +167,34 @@ const CalendarPage = () => {
|
|
176 |
|
177 |
// Update the getConferenceLineStyle function
|
178 |
const getConferenceLineStyle = (date: Date) => {
|
179 |
-
|
180 |
-
|
181 |
-
|
182 |
-
|
183 |
-
|
184 |
-
|
185 |
-
|
186 |
-
|
187 |
-
const
|
188 |
-
prevDate.setDate(date.getDate() - 1);
|
189 |
-
const nextDate = new Date(date);
|
190 |
-
nextDate.setDate(date.getDate() + 1);
|
191 |
|
192 |
-
|
193 |
-
|
194 |
-
|
195 |
-
let lineStyle = "h-1";
|
196 |
|
197 |
-
|
198 |
-
|
199 |
-
|
200 |
-
}
|
201 |
-
|
202 |
-
|
203 |
-
} else if (hasNextDay) {
|
204 |
-
// Start of a sequence
|
205 |
-
lineStyle += " w-[calc(100%+0.5rem)] right-0";
|
206 |
-
} else {
|
207 |
-
// Single day
|
208 |
-
lineStyle += " w-full";
|
209 |
}
|
210 |
-
|
211 |
-
// Get the color based on the first tag or default to purple
|
212 |
-
const color = conf.tags?.[0] ? categoryColors[conf.tags[0]] : "bg-purple-500";
|
213 |
|
214 |
-
|
215 |
-
|
216 |
-
|
217 |
-
}
|
218 |
-
}
|
219 |
-
|
220 |
-
|
221 |
-
return styles;
|
222 |
};
|
223 |
|
224 |
// Update the renderDayContent function
|
@@ -233,25 +209,25 @@ const CalendarPage = () => {
|
|
233 |
const hasDeadline = dayEvents.deadlines.length > 0;
|
234 |
|
235 |
return (
|
236 |
-
<div className="relative w-full h-full flex flex-col
|
237 |
-
{/* Day number at the top */}
|
238 |
-
<div className="
|
239 |
<span>{format(date, 'd')}</span>
|
240 |
</div>
|
241 |
|
242 |
{/* Event indicator lines at the bottom */}
|
243 |
-
<div className="absolute bottom-
|
244 |
-
{/*
|
245 |
-
{hasDeadline && (
|
246 |
-
<div className="h-1 w-full bg-red-500" />
|
247 |
-
)}
|
248 |
-
{/* Conference lines at the bottom */}
|
249 |
{conferenceStyles.map((style, index) => (
|
250 |
<div
|
251 |
key={`conf-${index}`}
|
252 |
-
className={
|
253 |
/>
|
254 |
))}
|
|
|
|
|
|
|
|
|
255 |
</div>
|
256 |
|
257 |
{/* Tooltip trigger */}
|
@@ -380,8 +356,8 @@ const CalendarPage = () => {
|
|
380 |
head_row: "flex",
|
381 |
head_cell: "text-muted-foreground rounded-md w-10 font-normal text-[0.8rem]",
|
382 |
row: "flex w-full mt-2",
|
383 |
-
cell: "h-
|
384 |
-
day: "h-
|
385 |
day_today: "bg-neutral-100 text-primary font-semibold",
|
386 |
day_outside: "hidden",
|
387 |
nav: "space-x-1 flex items-center",
|
|
|
55 |
const safeParseISO = (dateString: string | undefined | number): Date | null => {
|
56 |
if (!dateString) return null;
|
57 |
if (dateString === 'TBD') return null;
|
58 |
+
|
59 |
+
// If it's already a Date object, return it
|
60 |
+
if (dateString instanceof Date) return dateString;
|
61 |
|
62 |
try {
|
63 |
if (typeof dateString === 'object') {
|
|
|
117 |
};
|
118 |
|
119 |
const getDayEvents = (date: Date) => {
|
120 |
+
const deadlines = conferencesData.filter(conf => {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
121 |
const deadlineDate = safeParseISO(conf.deadline);
|
122 |
+
return deadlineDate && isSameDay(deadlineDate, date);
|
123 |
+
});
|
124 |
+
|
125 |
+
const conferences = conferencesData.filter(conf => {
|
126 |
const startDate = safeParseISO(conf.start);
|
127 |
const endDate = safeParseISO(conf.end);
|
128 |
+
return startDate && endDate &&
|
129 |
+
date >= startDate &&
|
130 |
+
date <= endDate;
|
131 |
+
});
|
132 |
|
133 |
+
return {
|
134 |
+
deadlines,
|
135 |
+
conferences
|
136 |
+
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
137 |
};
|
138 |
|
139 |
const renderEventPreview = (events: { deadlines: Conference[], conferences: Conference[] }) => {
|
|
|
167 |
|
168 |
// Update the getConferenceLineStyle function
|
169 |
const getConferenceLineStyle = (date: Date) => {
|
170 |
+
return conferencesData
|
171 |
+
.filter(conf => {
|
172 |
+
const startDate = safeParseISO(conf.start);
|
173 |
+
const endDate = safeParseISO(conf.end);
|
174 |
+
return startDate && endDate && date >= startDate && date <= endDate;
|
175 |
+
})
|
176 |
+
.map(conf => {
|
177 |
+
const startDate = safeParseISO(conf.start);
|
178 |
+
const endDate = safeParseISO(conf.end);
|
|
|
|
|
|
|
179 |
|
180 |
+
if (!startDate || !endDate) return null;
|
181 |
+
|
182 |
+
let style = "w-[calc(100%+1rem)] -left-2 relative";
|
|
|
183 |
|
184 |
+
// Add specific styles for start, middle, and end days
|
185 |
+
if (isSameDay(date, startDate)) {
|
186 |
+
style += " rounded-l-sm";
|
187 |
+
}
|
188 |
+
if (isSameDay(date, endDate)) {
|
189 |
+
style += " rounded-r-sm";
|
|
|
|
|
|
|
|
|
|
|
|
|
190 |
}
|
|
|
|
|
|
|
191 |
|
192 |
+
// Get the color based on the first tag
|
193 |
+
const color = conf.tags && conf.tags[0] ? categoryColors[conf.tags[0]] : "bg-gray-500";
|
194 |
+
|
195 |
+
return { style, color };
|
196 |
+
})
|
197 |
+
.filter(Boolean);
|
|
|
|
|
198 |
};
|
199 |
|
200 |
// Update the renderDayContent function
|
|
|
209 |
const hasDeadline = dayEvents.deadlines.length > 0;
|
210 |
|
211 |
return (
|
212 |
+
<div className="relative w-full h-full flex flex-col">
|
213 |
+
{/* Day number at the top with more space */}
|
214 |
+
<div className="h-12 flex items-center justify-center">
|
215 |
<span>{format(date, 'd')}</span>
|
216 |
</div>
|
217 |
|
218 |
{/* Event indicator lines at the bottom */}
|
219 |
+
<div className="absolute bottom-2 left-0 right-0 flex flex-col-reverse gap-[2px]">
|
220 |
+
{/* Conference lines at the bottom (rendered first) */}
|
|
|
|
|
|
|
|
|
221 |
{conferenceStyles.map((style, index) => (
|
222 |
<div
|
223 |
key={`conf-${index}`}
|
224 |
+
className={`h-[3px] ${style.style} ${style.color}`}
|
225 |
/>
|
226 |
))}
|
227 |
+
{/* Deadline lines on top */}
|
228 |
+
{hasDeadline && (
|
229 |
+
<div className="h-[3px] w-[calc(100%+1rem)] -left-2 relative bg-red-500" />
|
230 |
+
)}
|
231 |
</div>
|
232 |
|
233 |
{/* Tooltip trigger */}
|
|
|
356 |
head_row: "flex",
|
357 |
head_cell: "text-muted-foreground rounded-md w-10 font-normal text-[0.8rem]",
|
358 |
row: "flex w-full mt-2",
|
359 |
+
cell: "h-16 w-10 text-center text-sm p-0 relative focus-within:relative focus-within:z-20 hover:bg-neutral-50",
|
360 |
+
day: "h-16 w-10 p-0 font-normal hover:bg-neutral-100 rounded-lg transition-colors",
|
361 |
day_today: "bg-neutral-100 text-primary font-semibold",
|
362 |
day_outside: "hidden",
|
363 |
nav: "space-x-1 flex items-center",
|