Spaces:
Running
Running
Add country filter
Browse files- src/components/FilterBar.tsx +92 -37
- src/data/conferences.yml +92 -47
- src/pages/Index.tsx +180 -41
- src/types/conference.ts +18 -12
- src/utils/countryExtractor.ts +55 -0
src/components/FilterBar.tsx
CHANGED
@@ -1,13 +1,29 @@
|
|
1 |
import { useMemo } from "react";
|
2 |
import conferencesData from "@/data/conferences.yml";
|
3 |
-
import { X } from "lucide-react";
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
4 |
|
5 |
interface FilterBarProps {
|
6 |
selectedTags: Set<string>;
|
|
|
7 |
onTagSelect: (tags: Set<string>) => void;
|
|
|
8 |
}
|
9 |
|
10 |
-
const FilterBar = ({
|
|
|
|
|
|
|
|
|
|
|
11 |
const uniqueTags = useMemo(() => {
|
12 |
const tags = new Set<string>();
|
13 |
if (Array.isArray(conferencesData)) {
|
@@ -30,47 +46,86 @@ const FilterBar = ({ selectedTags = new Set(), onTagSelect }: FilterBarProps) =>
|
|
30 |
return selectedTags?.has(tagId) ?? false;
|
31 |
};
|
32 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
33 |
return (
|
34 |
-
<div className="
|
35 |
-
<div className="
|
36 |
-
<div className="flex flex-wrap gap-
|
37 |
-
|
38 |
-
<
|
39 |
-
|
40 |
-
|
41 |
-
|
42 |
-
|
43 |
-
|
44 |
-
|
45 |
-
|
46 |
-
|
47 |
-
|
48 |
-
|
49 |
-
|
50 |
-
|
51 |
-
|
52 |
-
|
53 |
-
|
54 |
-
|
55 |
-
|
56 |
-
|
57 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
58 |
>
|
59 |
-
|
60 |
-
</
|
61 |
-
)
|
62 |
|
63 |
-
{
|
|
|
64 |
<button
|
65 |
-
|
66 |
-
className="px-
|
67 |
-
|
68 |
-
flex items-center gap-2"
|
69 |
>
|
70 |
-
|
71 |
-
|
|
|
|
|
72 |
</button>
|
73 |
-
)}
|
74 |
</div>
|
75 |
</div>
|
76 |
</div>
|
|
|
1 |
import { useMemo } from "react";
|
2 |
import conferencesData from "@/data/conferences.yml";
|
3 |
+
import { X, ChevronRight, Filter } from "lucide-react";
|
4 |
+
import { getAllCountries } from "@/utils/countryExtractor";
|
5 |
+
import {
|
6 |
+
Popover,
|
7 |
+
PopoverContent,
|
8 |
+
PopoverTrigger,
|
9 |
+
} from "@/components/ui/popover";
|
10 |
+
import { Button } from "@/components/ui/button";
|
11 |
+
import { Checkbox } from "@/components/ui/checkbox";
|
12 |
+
import { Conference } from "@/types/conference";
|
13 |
|
14 |
interface FilterBarProps {
|
15 |
selectedTags: Set<string>;
|
16 |
+
selectedCountries: Set<string>;
|
17 |
onTagSelect: (tags: Set<string>) => void;
|
18 |
+
onCountrySelect: (countries: Set<string>) => void;
|
19 |
}
|
20 |
|
21 |
+
const FilterBar = ({
|
22 |
+
selectedTags = new Set(),
|
23 |
+
selectedCountries = new Set(),
|
24 |
+
onTagSelect,
|
25 |
+
onCountrySelect
|
26 |
+
}: FilterBarProps) => {
|
27 |
const uniqueTags = useMemo(() => {
|
28 |
const tags = new Set<string>();
|
29 |
if (Array.isArray(conferencesData)) {
|
|
|
46 |
return selectedTags?.has(tagId) ?? false;
|
47 |
};
|
48 |
|
49 |
+
const handleTagChange = (tagId: string) => {
|
50 |
+
const newSelectedTags = new Set(selectedTags);
|
51 |
+
if (newSelectedTags.has(tagId)) {
|
52 |
+
newSelectedTags.delete(tagId);
|
53 |
+
} else {
|
54 |
+
newSelectedTags.add(tagId);
|
55 |
+
}
|
56 |
+
onTagSelect(newSelectedTags);
|
57 |
+
};
|
58 |
+
|
59 |
+
const clearAllFilters = () => {
|
60 |
+
onTagSelect(new Set());
|
61 |
+
onCountrySelect(new Set());
|
62 |
+
};
|
63 |
+
|
64 |
return (
|
65 |
+
<div className="bg-white shadow rounded-lg p-4">
|
66 |
+
<div className="flex flex-col space-y-4">
|
67 |
+
<div className="flex flex-wrap items-center gap-2">
|
68 |
+
<Popover>
|
69 |
+
<PopoverTrigger asChild>
|
70 |
+
<Button variant="outline" size="sm" className="h-8 gap-1">
|
71 |
+
<Filter className="h-4 w-4" />
|
72 |
+
Filter by Tag
|
73 |
+
</Button>
|
74 |
+
</PopoverTrigger>
|
75 |
+
<PopoverContent className="w-80 p-4" align="start">
|
76 |
+
<div className="space-y-4">
|
77 |
+
<div>
|
78 |
+
<div className="flex items-center justify-between mb-4">
|
79 |
+
<h4 className="text-sm font-medium text-gray-800">Tags</h4>
|
80 |
+
<ChevronRight className="h-4 w-4 text-gray-500" />
|
81 |
+
</div>
|
82 |
+
<div className="max-h-60 overflow-y-auto space-y-2">
|
83 |
+
{uniqueTags.map(tag => (
|
84 |
+
<div key={tag.id} className="flex items-center space-x-2 hover:bg-gray-50 p-1 rounded">
|
85 |
+
<Checkbox
|
86 |
+
id={`tag-${tag.id}`}
|
87 |
+
checked={isTagSelected(tag.id)}
|
88 |
+
onCheckedChange={() => handleTagChange(tag.id)}
|
89 |
+
/>
|
90 |
+
<label
|
91 |
+
htmlFor={`tag-${tag.id}`}
|
92 |
+
className="text-sm font-medium text-gray-700 cursor-pointer w-full py-1"
|
93 |
+
>
|
94 |
+
{tag.label}
|
95 |
+
</label>
|
96 |
+
</div>
|
97 |
+
))}
|
98 |
+
</div>
|
99 |
+
</div>
|
100 |
+
</div>
|
101 |
+
</PopoverContent>
|
102 |
+
</Popover>
|
103 |
+
|
104 |
+
{/* Clear all filters button */}
|
105 |
+
{(selectedTags.size > 0 || selectedCountries.size > 0) && (
|
106 |
+
<Button
|
107 |
+
variant="ghost"
|
108 |
+
size="sm"
|
109 |
+
onClick={clearAllFilters}
|
110 |
+
className="text-neutral-500 hover:text-neutral-700"
|
111 |
>
|
112 |
+
Clear all
|
113 |
+
</Button>
|
114 |
+
)}
|
115 |
|
116 |
+
{/* Display selected tags */}
|
117 |
+
{Array.from(selectedTags).map(tag => (
|
118 |
<button
|
119 |
+
key={tag}
|
120 |
+
className="inline-flex items-center px-3 py-1 rounded-full text-sm bg-blue-100 text-blue-800 hover:bg-blue-200 font-medium"
|
121 |
+
onClick={() => handleTagChange(tag)}
|
|
|
122 |
>
|
123 |
+
{tag.split("-").map(word =>
|
124 |
+
word.charAt(0).toUpperCase() + word.slice(1)
|
125 |
+
).join(" ")}
|
126 |
+
<X className="ml-1 h-3 w-3" />
|
127 |
</button>
|
128 |
+
))}
|
129 |
</div>
|
130 |
</div>
|
131 |
</div>
|
src/data/conferences.yml
CHANGED
@@ -6,7 +6,8 @@
|
|
6 |
deadline: '2025-03-03 23:59:59'
|
7 |
abstract_deadline: '2025-02-26 23:59:59'
|
8 |
timezone: UTC-12
|
9 |
-
|
|
|
10 |
date: August 11-14, 2025
|
11 |
start: 2025-08-11
|
12 |
end: 2025-08-14
|
@@ -24,7 +25,8 @@
|
|
24 |
deadline: '2025-04-30 23:59:00'
|
25 |
abstract_deadline: '2025-04-23 23:59:00'
|
26 |
timezone: UTC-12
|
27 |
-
|
|
|
28 |
date: Sep 27-30, 2025
|
29 |
tags:
|
30 |
- machine-learning
|
@@ -41,7 +43,8 @@
|
|
41 |
link: https://2025.ieee-icra.org
|
42 |
deadline: '2024-07-15 12:00:00'
|
43 |
timezone: UTC-4
|
44 |
-
|
|
|
45 |
date: May 19-23, 2025
|
46 |
tags:
|
47 |
- machine-learning
|
@@ -58,7 +61,8 @@
|
|
58 |
link: https://wacv2025.thecvf.com/
|
59 |
deadline: '2024-07-15 23:59:59'
|
60 |
timezone: UTC-7
|
61 |
-
|
|
|
62 |
date: February 28 - March 4, 2025
|
63 |
tags:
|
64 |
- machine-learning
|
@@ -74,7 +78,8 @@
|
|
74 |
link: https://www.wsdm-conference.org/2025/
|
75 |
deadline: '2024-08-14 23:59:00'
|
76 |
timezone: UTC-12
|
77 |
-
|
|
|
78 |
venue: Hannover Congress Center, Hannover, Germany
|
79 |
date: March 10-14, 2025
|
80 |
start: 2025-03-10
|
@@ -82,6 +87,8 @@
|
|
82 |
tags:
|
83 |
- web-search
|
84 |
- data-mining
|
|
|
|
|
85 |
|
86 |
- title: AAAI
|
87 |
year: 2025
|
@@ -90,7 +97,8 @@
|
|
90 |
link: https://aaai.org/conference/aaai/aaai-25/
|
91 |
deadline: '2024-08-15 23:59:59'
|
92 |
timezone: UTC-12
|
93 |
-
|
|
|
94 |
date: February 25 - March 4, 2025
|
95 |
tags:
|
96 |
- data-mining
|
@@ -110,7 +118,8 @@
|
|
110 |
link: https://2025.ieeeicassp.org/
|
111 |
deadline: '2024-09-09 23:59:59'
|
112 |
timezone: UTC-12
|
113 |
-
|
|
|
114 |
venue: Hyderabad International Convention Center, Hyderabad, India
|
115 |
date: April 6-11, 2025
|
116 |
start: 2025-04-06
|
@@ -126,7 +135,8 @@
|
|
126 |
deadline: '2024-09-12 23:59:59'
|
127 |
abstract_deadline: '2024-09-05 23:59:59'
|
128 |
timezone: UTC-12
|
129 |
-
|
|
|
130 |
venue: Pacifico Yokohama Conference Center, Yokohama, Japan
|
131 |
date: April 26 - May 01, 2025
|
132 |
start: 2025-04-26
|
@@ -143,7 +153,8 @@
|
|
143 |
link: https://coling2025.org/
|
144 |
deadline: '2024-09-16 23:59:59'
|
145 |
timezone: UTC-12
|
146 |
-
|
|
|
147 |
date: Jan 19 - Jan 24, 2025
|
148 |
tags:
|
149 |
- natural-language-processing
|
@@ -161,7 +172,8 @@
|
|
161 |
link: https://algorithmiclearningtheory.org/alt2025/
|
162 |
deadline: '2024-10-01 09:59:59'
|
163 |
timezone: UTC+0
|
164 |
-
|
|
|
165 |
date: February 24-27, 2025
|
166 |
tags:
|
167 |
- machine-learning
|
@@ -175,7 +187,7 @@
|
|
175 |
link: https://iclr.cc/Conferences/2025
|
176 |
deadline: '2024-10-01 23:59:59'
|
177 |
timezone: UTC-12
|
178 |
-
|
179 |
date: April 24-28, 2025
|
180 |
tags:
|
181 |
- machine-learning
|
@@ -195,7 +207,8 @@
|
|
195 |
link: https://www.eg.org/wp/event/eurographics-2025/
|
196 |
deadline: '2024-10-03 23:59:59'
|
197 |
timezone: UTC+1
|
198 |
-
|
|
|
199 |
date: May 12 - 16, 2025
|
200 |
tags:
|
201 |
- computer-graphics
|
@@ -209,7 +222,8 @@
|
|
209 |
deadline: '2024-10-09 23:59:59'
|
210 |
abstract_deadline: '2024-10-02 23:59:59'
|
211 |
timezone: UTC-12
|
212 |
-
|
|
|
213 |
venue: IMT School for Advanced Studies Lucca, Lucca, Italy
|
214 |
date: April 6 - April 10, 2025
|
215 |
start: '2025-04-06'
|
@@ -225,7 +239,8 @@
|
|
225 |
link: https://aistats.org/aistats2025
|
226 |
deadline: '2024-10-10 23:59:59'
|
227 |
timezone: UTC-12
|
228 |
-
|
|
|
229 |
date: May 3-5, 2025
|
230 |
tags:
|
231 |
- machine-learning
|
@@ -244,7 +259,8 @@
|
|
244 |
link: https://2025.naacl.org/
|
245 |
deadline: '2024-10-15 23:59:59'
|
246 |
timezone: UTC-12
|
247 |
-
|
|
|
248 |
date: April 29-May 4, 2025
|
249 |
tags:
|
250 |
- natural-language-processing
|
@@ -259,7 +275,8 @@
|
|
259 |
link: https://aamas2025.org/
|
260 |
deadline: '2024-10-16 23:59:59'
|
261 |
timezone: UTC-12
|
262 |
-
|
|
|
263 |
date: May 19-23, 2025
|
264 |
tags:
|
265 |
- machine-learning
|
@@ -277,7 +294,8 @@
|
|
277 |
link: https://cvpr.thecvf.com/Conferences/2025/CallForPapers
|
278 |
deadline: '2024-11-14 23:59:00'
|
279 |
timezone: UTC-8
|
280 |
-
|
|
|
281 |
date: June 10-17, 2025
|
282 |
tags:
|
283 |
- computer-vision
|
@@ -297,7 +315,8 @@
|
|
297 |
link: https://www.esann.org/
|
298 |
deadline: '2024-11-20 00:00:00'
|
299 |
timezone: UTC-8
|
300 |
-
|
|
|
301 |
date: April 23 - April 25, 2025
|
302 |
tags: []
|
303 |
abstract_deadline: '2024-11-20 00:00:00'
|
@@ -310,7 +329,8 @@
|
|
310 |
link: https://cpal.cc/
|
311 |
deadline: '2024-11-25 23:59:59'
|
312 |
timezone: AoE
|
313 |
-
|
|
|
314 |
date: March 24-27, 2025
|
315 |
tags:
|
316 |
- machine-learning
|
@@ -323,7 +343,8 @@
|
|
323 |
link: https://www.cec2025.org/
|
324 |
deadline: '2025-01-15 23:59:59'
|
325 |
timezone: UTC-12
|
326 |
-
|
|
|
327 |
date: June 8-12, 2025
|
328 |
tags:
|
329 |
- machine-learning
|
@@ -336,7 +357,8 @@
|
|
336 |
link: https://s2025.siggraph.org/
|
337 |
deadline: '2025-01-16 23:59:59'
|
338 |
timezone: UTC-8
|
339 |
-
|
|
|
340 |
venue: Convention Centre, Vancouver, Canada
|
341 |
date: August 10-14, 2025
|
342 |
start: '2025-08-10'
|
@@ -351,7 +373,8 @@
|
|
351 |
link: https://2025.ijcai.org/
|
352 |
deadline: '2025-01-23 23:59:59'
|
353 |
timezone: UTC-12
|
354 |
-
|
|
|
355 |
date: August 16-22, 2025
|
356 |
tags:
|
357 |
- machine-learning
|
@@ -365,7 +388,8 @@
|
|
365 |
link: https://roboticsconference.org
|
366 |
deadline: '2025-01-24 23:59:00'
|
367 |
timezone: AoE
|
368 |
-
|
|
|
369 |
date: June 21-25, 2025
|
370 |
tags:
|
371 |
- machine-learning
|
@@ -379,7 +403,9 @@
|
|
379 |
link: https://icml.cc/Conferences/2025
|
380 |
deadline: '2025-01-30 23:59:59'
|
381 |
timezone: UTC-12
|
382 |
-
|
|
|
|
|
383 |
date: July 11-19, 2025
|
384 |
tags:
|
385 |
- machine-learning
|
@@ -395,7 +421,8 @@
|
|
395 |
link: https://2025.ijcnn.org/
|
396 |
deadline: '2025-02-05 23:59:59'
|
397 |
timezone: UTC-12
|
398 |
-
|
|
|
399 |
date: June 30 - July 5, 2025
|
400 |
tags:
|
401 |
- machine-learning
|
@@ -408,7 +435,8 @@
|
|
408 |
link: https://learningtheory.org/colt2025/
|
409 |
deadline: '2025-02-06 16:59:59'
|
410 |
timezone: UTC-5
|
411 |
-
|
|
|
412 |
date: June 30 - July 4, 2025
|
413 |
tags:
|
414 |
- machine-learning
|
@@ -421,7 +449,8 @@
|
|
421 |
link: https://www.auai.org/uai2025/
|
422 |
deadline: '2025-02-10 23:59:59'
|
423 |
timezone: AoE
|
424 |
-
|
|
|
425 |
date: July 21-25, 2025
|
426 |
tags:
|
427 |
- machine-learning
|
@@ -433,11 +462,12 @@
|
|
433 |
full_name: ACM SIGKDD Conference on Knowledge Discovery and Data Mining
|
434 |
deadline: '2025-02-10 23:59:59'
|
435 |
abstract_deadline: '2025-02-03 23:59:59'
|
436 |
-
start: '2025-08-03'
|
437 |
-
end: '2025-08-07'
|
438 |
timezone: AoE
|
439 |
-
|
|
|
440 |
date: August 3 - August 7, 2025
|
|
|
|
|
441 |
tags:
|
442 |
- data-mining
|
443 |
- machine-learning
|
@@ -453,7 +483,8 @@
|
|
453 |
link: https://2025.aclweb.org/
|
454 |
deadline: '2025-02-15 23:59:59'
|
455 |
timezone: UTC-12
|
456 |
-
|
|
|
457 |
date: July 27 - August 1, 2025
|
458 |
tags:
|
459 |
- natural-language-processing
|
@@ -470,7 +501,8 @@
|
|
470 |
deadline: 2025-02-20 23:59
|
471 |
abstract_deadline: 2025-02-01 23:59
|
472 |
timezone: Russia/Moscow
|
473 |
-
|
|
|
474 |
date: March, 24-28, 2025
|
475 |
start: 2025-03-24
|
476 |
end: 2025-03-28
|
@@ -490,8 +522,9 @@
|
|
490 |
deadline: '2025-02-28 23:59:59'
|
491 |
abstract_deadline: '2025-02-21 23:59:59'
|
492 |
timezone: UTC-12
|
|
|
|
|
493 |
date: August 5 - August 8, 2025
|
494 |
-
place: Edmonton, Canada
|
495 |
tags:
|
496 |
- machine-learning
|
497 |
- reinforcement-learning
|
@@ -504,7 +537,8 @@
|
|
504 |
link: http://www.iros25.org/
|
505 |
deadline: '2025-03-01 23:59:59'
|
506 |
timezone: UTC-8
|
507 |
-
|
|
|
508 |
date: October 19-25, 2025
|
509 |
tags:
|
510 |
- robotics
|
@@ -517,7 +551,8 @@
|
|
517 |
link: https://ksem2025.scimeeting.cn/
|
518 |
deadline: '2025-03-04 23:59:59'
|
519 |
timezone: UTC+0
|
520 |
-
|
|
|
521 |
date: August 4-6, 2025
|
522 |
tags:
|
523 |
- machine-learning
|
@@ -530,7 +565,8 @@
|
|
530 |
link: https://www.icdar2025.com/home
|
531 |
deadline: '2025-03-07 23:59:59'
|
532 |
timezone: UTC+0
|
533 |
-
|
|
|
534 |
date: September 17-21, 2025
|
535 |
tags:
|
536 |
- computer-vision
|
@@ -544,7 +580,8 @@
|
|
544 |
link: https://iccv.thecvf.com/Conferences/2025
|
545 |
deadline: '2025-03-08 09:59:59'
|
546 |
timezone: UTC+0
|
547 |
-
|
|
|
548 |
date: October 19-25, 2025
|
549 |
tags:
|
550 |
- machine-learning
|
@@ -563,7 +600,8 @@
|
|
563 |
deadline: 2025-03-15 23:59
|
564 |
abstract_deadline: 2025-03-15 23:59
|
565 |
timezone: UTC-12
|
566 |
-
|
|
|
567 |
date: September, 9-12, 2025
|
568 |
start: 2025-09-09
|
569 |
end: 2025-09-12
|
@@ -580,7 +618,8 @@
|
|
580 |
link: https://colmweb.org/cfp.html
|
581 |
deadline: '2025-03-27 23:59:59'
|
582 |
timezone: AoE
|
583 |
-
|
|
|
584 |
date: October 7-9, 2025
|
585 |
tags:
|
586 |
- natural-language-processing
|
@@ -592,10 +631,11 @@
|
|
592 |
year: 2025
|
593 |
id: ecai25
|
594 |
full_name: European Conference on Artificial Intelligence
|
595 |
-
link: https://ecai2025.
|
596 |
-
deadline: '2025-
|
597 |
timezone: UTC-12
|
598 |
-
|
|
|
599 |
date: October 25-30, 2025
|
600 |
tags:
|
601 |
- machine-learning
|
@@ -610,7 +650,8 @@
|
|
610 |
link: https://neurips.cc/
|
611 |
deadline: '2025-05-16 23:59:59'
|
612 |
timezone: UTC-8
|
613 |
-
|
|
|
614 |
venue: San Diego Convention Center, San Diego, USA
|
615 |
date: December 9-15, 2025
|
616 |
start: '2025-12-09'
|
@@ -625,7 +666,8 @@
|
|
625 |
link: https://2025.emnlp.org/
|
626 |
deadline: '2025-05-19 23:59:59'
|
627 |
timezone: UTC-12
|
628 |
-
|
|
|
629 |
date: November 5 - 9, 2025
|
630 |
start: '2025-11-05'
|
631 |
end: '2025-11-09'
|
@@ -641,7 +683,8 @@
|
|
641 |
link: https://conll.org/
|
642 |
deadline: 2025-03-15 12:00
|
643 |
timezone: UTC-12
|
644 |
-
|
|
|
645 |
date: July 31 - August 1, 2025
|
646 |
start: '2025-07-31'
|
647 |
end: '2025-08-01'
|
@@ -657,7 +700,8 @@
|
|
657 |
link: https://www3.cs.stonybrook.edu/~icdm2025/index.html
|
658 |
deadline: '2025-06-06 23:59:59'
|
659 |
timezone: AoE
|
660 |
-
|
|
|
661 |
date: November 12 - November 15, 2025
|
662 |
start: '2025-11-12'
|
663 |
end: '2025-11-15'
|
@@ -671,7 +715,8 @@
|
|
671 |
link: https://eccv.ecva.net/Conferences/2026
|
672 |
deadline: '2026-03-06 11:00:00'
|
673 |
timezone: UTC+0
|
|
|
|
|
674 |
date: September 8 - September 13, 2026
|
675 |
-
place: Malmö, Sweden
|
676 |
tags:
|
677 |
- computer-vision
|
|
|
6 |
deadline: '2025-03-03 23:59:59'
|
7 |
abstract_deadline: '2025-02-26 23:59:59'
|
8 |
timezone: UTC-12
|
9 |
+
city: Philadelphia
|
10 |
+
country: USA
|
11 |
date: August 11-14, 2025
|
12 |
start: 2025-08-11
|
13 |
end: 2025-08-14
|
|
|
25 |
deadline: '2025-04-30 23:59:00'
|
26 |
abstract_deadline: '2025-04-23 23:59:00'
|
27 |
timezone: UTC-12
|
28 |
+
city: Seoul
|
29 |
+
country: South Korea
|
30 |
date: Sep 27-30, 2025
|
31 |
tags:
|
32 |
- machine-learning
|
|
|
43 |
link: https://2025.ieee-icra.org
|
44 |
deadline: '2024-07-15 12:00:00'
|
45 |
timezone: UTC-4
|
46 |
+
city: Atlanta
|
47 |
+
country: USA
|
48 |
date: May 19-23, 2025
|
49 |
tags:
|
50 |
- machine-learning
|
|
|
61 |
link: https://wacv2025.thecvf.com/
|
62 |
deadline: '2024-07-15 23:59:59'
|
63 |
timezone: UTC-7
|
64 |
+
city: Tucson
|
65 |
+
country: USA
|
66 |
date: February 28 - March 4, 2025
|
67 |
tags:
|
68 |
- machine-learning
|
|
|
78 |
link: https://www.wsdm-conference.org/2025/
|
79 |
deadline: '2024-08-14 23:59:00'
|
80 |
timezone: UTC-12
|
81 |
+
city: Hannover
|
82 |
+
country: Germany
|
83 |
venue: Hannover Congress Center, Hannover, Germany
|
84 |
date: March 10-14, 2025
|
85 |
start: 2025-03-10
|
|
|
87 |
tags:
|
88 |
- web-search
|
89 |
- data-mining
|
90 |
+
abstract_deadline: '2024-08-07 23:59:00'
|
91 |
+
rankings: 'CCF: B, CORE: A*, THCPL: B'
|
92 |
|
93 |
- title: AAAI
|
94 |
year: 2025
|
|
|
97 |
link: https://aaai.org/conference/aaai/aaai-25/
|
98 |
deadline: '2024-08-15 23:59:59'
|
99 |
timezone: UTC-12
|
100 |
+
city: PHILADELPHIA
|
101 |
+
country: PENNSYLVANIA
|
102 |
date: February 25 - March 4, 2025
|
103 |
tags:
|
104 |
- data-mining
|
|
|
118 |
link: https://2025.ieeeicassp.org/
|
119 |
deadline: '2024-09-09 23:59:59'
|
120 |
timezone: UTC-12
|
121 |
+
city: Hyderabad
|
122 |
+
country: India
|
123 |
venue: Hyderabad International Convention Center, Hyderabad, India
|
124 |
date: April 6-11, 2025
|
125 |
start: 2025-04-06
|
|
|
135 |
deadline: '2024-09-12 23:59:59'
|
136 |
abstract_deadline: '2024-09-05 23:59:59'
|
137 |
timezone: UTC-12
|
138 |
+
city: Yokohama
|
139 |
+
country: Japan
|
140 |
venue: Pacifico Yokohama Conference Center, Yokohama, Japan
|
141 |
date: April 26 - May 01, 2025
|
142 |
start: 2025-04-26
|
|
|
153 |
link: https://coling2025.org/
|
154 |
deadline: '2024-09-16 23:59:59'
|
155 |
timezone: UTC-12
|
156 |
+
city: Abu Dhabi
|
157 |
+
country: UAE
|
158 |
date: Jan 19 - Jan 24, 2025
|
159 |
tags:
|
160 |
- natural-language-processing
|
|
|
172 |
link: https://algorithmiclearningtheory.org/alt2025/
|
173 |
deadline: '2024-10-01 09:59:59'
|
174 |
timezone: UTC+0
|
175 |
+
city: Milan
|
176 |
+
country: Italy
|
177 |
date: February 24-27, 2025
|
178 |
tags:
|
179 |
- machine-learning
|
|
|
187 |
link: https://iclr.cc/Conferences/2025
|
188 |
deadline: '2024-10-01 23:59:59'
|
189 |
timezone: UTC-12
|
190 |
+
city: Singapore
|
191 |
date: April 24-28, 2025
|
192 |
tags:
|
193 |
- machine-learning
|
|
|
207 |
link: https://www.eg.org/wp/event/eurographics-2025/
|
208 |
deadline: '2024-10-03 23:59:59'
|
209 |
timezone: UTC+1
|
210 |
+
city: London
|
211 |
+
country: UK
|
212 |
date: May 12 - 16, 2025
|
213 |
tags:
|
214 |
- computer-graphics
|
|
|
222 |
deadline: '2024-10-09 23:59:59'
|
223 |
abstract_deadline: '2024-10-02 23:59:59'
|
224 |
timezone: UTC-12
|
225 |
+
city: Lucca
|
226 |
+
country: Tuscany
|
227 |
venue: IMT School for Advanced Studies Lucca, Lucca, Italy
|
228 |
date: April 6 - April 10, 2025
|
229 |
start: '2025-04-06'
|
|
|
239 |
link: https://aistats.org/aistats2025
|
240 |
deadline: '2024-10-10 23:59:59'
|
241 |
timezone: UTC-12
|
242 |
+
city: Mai Khao
|
243 |
+
country: Thailand
|
244 |
date: May 3-5, 2025
|
245 |
tags:
|
246 |
- machine-learning
|
|
|
259 |
link: https://2025.naacl.org/
|
260 |
deadline: '2024-10-15 23:59:59'
|
261 |
timezone: UTC-12
|
262 |
+
city: Albuquerque
|
263 |
+
country: New Mexico
|
264 |
date: April 29-May 4, 2025
|
265 |
tags:
|
266 |
- natural-language-processing
|
|
|
275 |
link: https://aamas2025.org/
|
276 |
deadline: '2024-10-16 23:59:59'
|
277 |
timezone: UTC-12
|
278 |
+
city: Detroit
|
279 |
+
country: Michigan
|
280 |
date: May 19-23, 2025
|
281 |
tags:
|
282 |
- machine-learning
|
|
|
294 |
link: https://cvpr.thecvf.com/Conferences/2025/CallForPapers
|
295 |
deadline: '2024-11-14 23:59:00'
|
296 |
timezone: UTC-8
|
297 |
+
city: Nashville
|
298 |
+
country: Tennessee
|
299 |
date: June 10-17, 2025
|
300 |
tags:
|
301 |
- computer-vision
|
|
|
315 |
link: https://www.esann.org/
|
316 |
deadline: '2024-11-20 00:00:00'
|
317 |
timezone: UTC-8
|
318 |
+
city: Bruges
|
319 |
+
country: Belgium
|
320 |
date: April 23 - April 25, 2025
|
321 |
tags: []
|
322 |
abstract_deadline: '2024-11-20 00:00:00'
|
|
|
329 |
link: https://cpal.cc/
|
330 |
deadline: '2024-11-25 23:59:59'
|
331 |
timezone: AoE
|
332 |
+
city: California
|
333 |
+
country: USA
|
334 |
date: March 24-27, 2025
|
335 |
tags:
|
336 |
- machine-learning
|
|
|
343 |
link: https://www.cec2025.org/
|
344 |
deadline: '2025-01-15 23:59:59'
|
345 |
timezone: UTC-12
|
346 |
+
city: Hangzhou
|
347 |
+
country: China
|
348 |
date: June 8-12, 2025
|
349 |
tags:
|
350 |
- machine-learning
|
|
|
357 |
link: https://s2025.siggraph.org/
|
358 |
deadline: '2025-01-16 23:59:59'
|
359 |
timezone: UTC-8
|
360 |
+
city: Vancouver
|
361 |
+
country: Canada
|
362 |
venue: Convention Centre, Vancouver, Canada
|
363 |
date: August 10-14, 2025
|
364 |
start: '2025-08-10'
|
|
|
373 |
link: https://2025.ijcai.org/
|
374 |
deadline: '2025-01-23 23:59:59'
|
375 |
timezone: UTC-12
|
376 |
+
city: Montreal
|
377 |
+
country: Canada
|
378 |
date: August 16-22, 2025
|
379 |
tags:
|
380 |
- machine-learning
|
|
|
388 |
link: https://roboticsconference.org
|
389 |
deadline: '2025-01-24 23:59:00'
|
390 |
timezone: AoE
|
391 |
+
city: Los Angeles
|
392 |
+
country: USA
|
393 |
date: June 21-25, 2025
|
394 |
tags:
|
395 |
- machine-learning
|
|
|
403 |
link: https://icml.cc/Conferences/2025
|
404 |
deadline: '2025-01-30 23:59:59'
|
405 |
timezone: UTC-12
|
406 |
+
city: Vancouver
|
407 |
+
country: Canada
|
408 |
+
venue: Vancouver Convention Center
|
409 |
date: July 11-19, 2025
|
410 |
tags:
|
411 |
- machine-learning
|
|
|
421 |
link: https://2025.ijcnn.org/
|
422 |
deadline: '2025-02-05 23:59:59'
|
423 |
timezone: UTC-12
|
424 |
+
city: Rome
|
425 |
+
country: Italy
|
426 |
date: June 30 - July 5, 2025
|
427 |
tags:
|
428 |
- machine-learning
|
|
|
435 |
link: https://learningtheory.org/colt2025/
|
436 |
deadline: '2025-02-06 16:59:59'
|
437 |
timezone: UTC-5
|
438 |
+
city: Lyon
|
439 |
+
country: France
|
440 |
date: June 30 - July 4, 2025
|
441 |
tags:
|
442 |
- machine-learning
|
|
|
449 |
link: https://www.auai.org/uai2025/
|
450 |
deadline: '2025-02-10 23:59:59'
|
451 |
timezone: AoE
|
452 |
+
city: Rio de Janeiro
|
453 |
+
country: Brazil
|
454 |
date: July 21-25, 2025
|
455 |
tags:
|
456 |
- machine-learning
|
|
|
462 |
full_name: ACM SIGKDD Conference on Knowledge Discovery and Data Mining
|
463 |
deadline: '2025-02-10 23:59:59'
|
464 |
abstract_deadline: '2025-02-03 23:59:59'
|
|
|
|
|
465 |
timezone: AoE
|
466 |
+
city: Toronto
|
467 |
+
country: Canada
|
468 |
date: August 3 - August 7, 2025
|
469 |
+
start: '2025-08-03'
|
470 |
+
end: '2025-08-07'
|
471 |
tags:
|
472 |
- data-mining
|
473 |
- machine-learning
|
|
|
483 |
link: https://2025.aclweb.org/
|
484 |
deadline: '2025-02-15 23:59:59'
|
485 |
timezone: UTC-12
|
486 |
+
city: Vienna
|
487 |
+
country: Austria
|
488 |
date: July 27 - August 1, 2025
|
489 |
tags:
|
490 |
- natural-language-processing
|
|
|
501 |
deadline: 2025-02-20 23:59
|
502 |
abstract_deadline: 2025-02-01 23:59
|
503 |
timezone: Russia/Moscow
|
504 |
+
city: Sochi
|
505 |
+
country: Russia
|
506 |
date: March, 24-28, 2025
|
507 |
start: 2025-03-24
|
508 |
end: 2025-03-28
|
|
|
522 |
deadline: '2025-02-28 23:59:59'
|
523 |
abstract_deadline: '2025-02-21 23:59:59'
|
524 |
timezone: UTC-12
|
525 |
+
city: Edmonton
|
526 |
+
country: Canada
|
527 |
date: August 5 - August 8, 2025
|
|
|
528 |
tags:
|
529 |
- machine-learning
|
530 |
- reinforcement-learning
|
|
|
537 |
link: http://www.iros25.org/
|
538 |
deadline: '2025-03-01 23:59:59'
|
539 |
timezone: UTC-8
|
540 |
+
city: Hangzhou
|
541 |
+
country: China
|
542 |
date: October 19-25, 2025
|
543 |
tags:
|
544 |
- robotics
|
|
|
551 |
link: https://ksem2025.scimeeting.cn/
|
552 |
deadline: '2025-03-04 23:59:59'
|
553 |
timezone: UTC+0
|
554 |
+
city: Macao
|
555 |
+
country: China
|
556 |
date: August 4-6, 2025
|
557 |
tags:
|
558 |
- machine-learning
|
|
|
565 |
link: https://www.icdar2025.com/home
|
566 |
deadline: '2025-03-07 23:59:59'
|
567 |
timezone: UTC+0
|
568 |
+
city: Wuhan
|
569 |
+
country: China
|
570 |
date: September 17-21, 2025
|
571 |
tags:
|
572 |
- computer-vision
|
|
|
580 |
link: https://iccv.thecvf.com/Conferences/2025
|
581 |
deadline: '2025-03-08 09:59:59'
|
582 |
timezone: UTC+0
|
583 |
+
city: Honolulu
|
584 |
+
country: USA
|
585 |
date: October 19-25, 2025
|
586 |
tags:
|
587 |
- machine-learning
|
|
|
600 |
deadline: 2025-03-15 23:59
|
601 |
abstract_deadline: 2025-03-15 23:59
|
602 |
timezone: UTC-12
|
603 |
+
city: Kaunas
|
604 |
+
country: Lithuania
|
605 |
date: September, 9-12, 2025
|
606 |
start: 2025-09-09
|
607 |
end: 2025-09-12
|
|
|
618 |
link: https://colmweb.org/cfp.html
|
619 |
deadline: '2025-03-27 23:59:59'
|
620 |
timezone: AoE
|
621 |
+
city: Montreal
|
622 |
+
country: Canada
|
623 |
date: October 7-9, 2025
|
624 |
tags:
|
625 |
- natural-language-processing
|
|
|
631 |
year: 2025
|
632 |
id: ecai25
|
633 |
full_name: European Conference on Artificial Intelligence
|
634 |
+
link: https://www.ecai2025.eu/
|
635 |
+
deadline: '2025-03-30 23:59:59'
|
636 |
timezone: UTC-12
|
637 |
+
city: Bologna
|
638 |
+
country: Italy
|
639 |
date: October 25-30, 2025
|
640 |
tags:
|
641 |
- machine-learning
|
|
|
650 |
link: https://neurips.cc/
|
651 |
deadline: '2025-05-16 23:59:59'
|
652 |
timezone: UTC-8
|
653 |
+
city: San Diego
|
654 |
+
country: USA
|
655 |
venue: San Diego Convention Center, San Diego, USA
|
656 |
date: December 9-15, 2025
|
657 |
start: '2025-12-09'
|
|
|
666 |
link: https://2025.emnlp.org/
|
667 |
deadline: '2025-05-19 23:59:59'
|
668 |
timezone: UTC-12
|
669 |
+
city: Suzhou
|
670 |
+
country: China
|
671 |
date: November 5 - 9, 2025
|
672 |
start: '2025-11-05'
|
673 |
end: '2025-11-09'
|
|
|
683 |
link: https://conll.org/
|
684 |
deadline: 2025-03-15 12:00
|
685 |
timezone: UTC-12
|
686 |
+
city: Vienna
|
687 |
+
country: Austria
|
688 |
date: July 31 - August 1, 2025
|
689 |
start: '2025-07-31'
|
690 |
end: '2025-08-01'
|
|
|
700 |
link: https://www3.cs.stonybrook.edu/~icdm2025/index.html
|
701 |
deadline: '2025-06-06 23:59:59'
|
702 |
timezone: AoE
|
703 |
+
city: Washington DC
|
704 |
+
country: USA
|
705 |
date: November 12 - November 15, 2025
|
706 |
start: '2025-11-12'
|
707 |
end: '2025-11-15'
|
|
|
715 |
link: https://eccv.ecva.net/Conferences/2026
|
716 |
deadline: '2026-03-06 11:00:00'
|
717 |
timezone: UTC+0
|
718 |
+
city: Malmö
|
719 |
+
country: Sweden
|
720 |
date: September 8 - September 13, 2026
|
|
|
721 |
tags:
|
722 |
- computer-vision
|
src/pages/Index.tsx
CHANGED
@@ -6,12 +6,35 @@ import { Conference } from "@/types/conference";
|
|
6 |
import { useState, useMemo, useEffect } from "react";
|
7 |
import { Switch } from "@/components/ui/switch"
|
8 |
import { parseISO, isValid, isPast } from "date-fns";
|
|
|
|
|
|
|
|
|
|
|
|
|
9 |
|
10 |
const Index = () => {
|
11 |
const [selectedTags, setSelectedTags] = useState<Set<string>>(new Set());
|
|
|
12 |
const [searchQuery, setSearchQuery] = useState("");
|
13 |
const [showPastConferences, setShowPastConferences] = useState(false);
|
14 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
15 |
const filteredConferences = useMemo(() => {
|
16 |
if (!Array.isArray(conferencesData)) {
|
17 |
console.error("Conferences data is not an array:", conferencesData);
|
@@ -25,21 +48,27 @@ const Index = () => {
|
|
25 |
const isUpcoming = !deadlineDate || !isValid(deadlineDate) || !isPast(deadlineDate);
|
26 |
if (!showPastConferences && !isUpcoming) return false;
|
27 |
|
28 |
-
// Filter by tags
|
29 |
const matchesTags = selectedTags.size === 0 ||
|
30 |
(Array.isArray(conf.tags) && conf.tags.some(tag => selectedTags.has(tag)));
|
|
|
|
|
|
|
|
|
|
|
|
|
31 |
const matchesSearch = searchQuery === "" ||
|
32 |
conf.title.toLowerCase().includes(searchQuery.toLowerCase()) ||
|
33 |
(conf.full_name && conf.full_name.toLowerCase().includes(searchQuery.toLowerCase()));
|
34 |
|
35 |
-
return matchesTags && matchesSearch;
|
36 |
})
|
37 |
.sort((a: Conference, b: Conference) => {
|
38 |
const dateA = a.deadline && a.deadline !== 'TBD' ? parseISO(a.deadline).getTime() : Infinity;
|
39 |
const dateB = b.deadline && b.deadline !== 'TBD' ? parseISO(b.deadline).getTime() : Infinity;
|
40 |
return dateA - dateB;
|
41 |
});
|
42 |
-
}, [selectedTags, searchQuery, showPastConferences]);
|
43 |
|
44 |
// Update handleTagsChange to handle multiple tags
|
45 |
const handleTagsChange = (newTags: Set<string>) => {
|
@@ -50,36 +79,47 @@ const Index = () => {
|
|
50 |
} else {
|
51 |
searchParams.delete('tags');
|
52 |
}
|
53 |
-
|
54 |
-
window.history.pushState({}, '', newUrl);
|
55 |
};
|
56 |
|
57 |
-
|
58 |
-
|
59 |
-
|
60 |
-
|
61 |
-
|
62 |
-
|
63 |
-
|
64 |
-
|
65 |
-
|
66 |
-
|
67 |
-
|
68 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
69 |
|
70 |
-
|
|
|
|
|
|
|
|
|
71 |
|
72 |
-
// Check URL params on mount
|
73 |
-
const params = new URLSearchParams(window.location.search);
|
74 |
-
const tagsParam = params.get('tags');
|
75 |
if (tagsParam) {
|
76 |
-
|
|
|
77 |
}
|
78 |
-
|
79 |
-
|
80 |
-
|
81 |
-
|
82 |
-
|
|
|
83 |
|
84 |
if (!Array.isArray(conferencesData)) {
|
85 |
return <div>Loading conferences...</div>;
|
@@ -89,23 +129,122 @@ const Index = () => {
|
|
89 |
<div className="min-h-screen bg-neutral-light">
|
90 |
<Header
|
91 |
onSearch={setSearchQuery}
|
92 |
-
showEmptyMessage={
|
|
|
|
|
|
|
|
|
93 |
/>
|
94 |
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
95 |
<div className="space-y-4 py-4">
|
96 |
-
|
97 |
-
|
98 |
-
|
99 |
-
|
100 |
-
|
101 |
-
|
102 |
-
|
103 |
-
|
104 |
-
|
105 |
-
|
106 |
-
|
107 |
-
|
108 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
109 |
</div>
|
110 |
</div>
|
111 |
</div>
|
|
|
6 |
import { useState, useMemo, useEffect } from "react";
|
7 |
import { Switch } from "@/components/ui/switch"
|
8 |
import { parseISO, isValid, isPast } from "date-fns";
|
9 |
+
import { extractCountry } from "@/utils/countryExtractor";
|
10 |
+
import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover";
|
11 |
+
import { Button } from "@/components/ui/button";
|
12 |
+
import { Checkbox } from "@/components/ui/checkbox";
|
13 |
+
import { X, ChevronRight, Filter } from "lucide-react";
|
14 |
+
import { getAllCountries } from "@/utils/countryExtractor";
|
15 |
|
16 |
const Index = () => {
|
17 |
const [selectedTags, setSelectedTags] = useState<Set<string>>(new Set());
|
18 |
+
const [selectedCountries, setSelectedCountries] = useState<Set<string>>(new Set());
|
19 |
const [searchQuery, setSearchQuery] = useState("");
|
20 |
const [showPastConferences, setShowPastConferences] = useState(false);
|
21 |
|
22 |
+
// Category buttons configuration
|
23 |
+
const categoryButtons = [
|
24 |
+
{ id: "machine-learning", label: "Machine Learning" },
|
25 |
+
{ id: "lifelong-learning", label: "Lifelong Learning" },
|
26 |
+
{ id: "robotics", label: "Robotics" },
|
27 |
+
{ id: "computer-vision", label: "Computer Vision" },
|
28 |
+
{ id: "web-search", label: "Web Search" },
|
29 |
+
{ id: "data-mining", label: "Data Mining" },
|
30 |
+
{ id: "natural-language-processing", label: "Natural Language Processing" },
|
31 |
+
{ id: "signal-processing", label: "Signal Processing" },
|
32 |
+
{ id: "human-computer-interaction", label: "Human Computer Interaction" },
|
33 |
+
{ id: "computer-graphics", label: "Computer Graphics" },
|
34 |
+
{ id: "mathematics", label: "Mathematics" },
|
35 |
+
{ id: "reinforcement-learning", label: "Reinforcement Learning" },
|
36 |
+
];
|
37 |
+
|
38 |
const filteredConferences = useMemo(() => {
|
39 |
if (!Array.isArray(conferencesData)) {
|
40 |
console.error("Conferences data is not an array:", conferencesData);
|
|
|
48 |
const isUpcoming = !deadlineDate || !isValid(deadlineDate) || !isPast(deadlineDate);
|
49 |
if (!showPastConferences && !isUpcoming) return false;
|
50 |
|
51 |
+
// Filter by tags
|
52 |
const matchesTags = selectedTags.size === 0 ||
|
53 |
(Array.isArray(conf.tags) && conf.tags.some(tag => selectedTags.has(tag)));
|
54 |
+
|
55 |
+
// Filter by countries
|
56 |
+
const matchesCountry = selectedCountries.size === 0 ||
|
57 |
+
(conf.country && selectedCountries.has(conf.country));
|
58 |
+
|
59 |
+
// Filter by search query
|
60 |
const matchesSearch = searchQuery === "" ||
|
61 |
conf.title.toLowerCase().includes(searchQuery.toLowerCase()) ||
|
62 |
(conf.full_name && conf.full_name.toLowerCase().includes(searchQuery.toLowerCase()));
|
63 |
|
64 |
+
return matchesTags && matchesCountry && matchesSearch;
|
65 |
})
|
66 |
.sort((a: Conference, b: Conference) => {
|
67 |
const dateA = a.deadline && a.deadline !== 'TBD' ? parseISO(a.deadline).getTime() : Infinity;
|
68 |
const dateB = b.deadline && b.deadline !== 'TBD' ? parseISO(b.deadline).getTime() : Infinity;
|
69 |
return dateA - dateB;
|
70 |
});
|
71 |
+
}, [selectedTags, selectedCountries, searchQuery, showPastConferences]);
|
72 |
|
73 |
// Update handleTagsChange to handle multiple tags
|
74 |
const handleTagsChange = (newTags: Set<string>) => {
|
|
|
79 |
} else {
|
80 |
searchParams.delete('tags');
|
81 |
}
|
82 |
+
window.history.replaceState({}, '', `${window.location.pathname}?${searchParams}`);
|
|
|
83 |
};
|
84 |
|
85 |
+
const handleCountriesChange = (newCountries: Set<string>) => {
|
86 |
+
setSelectedCountries(newCountries);
|
87 |
+
const searchParams = new URLSearchParams(window.location.search);
|
88 |
+
if (newCountries.size > 0) {
|
89 |
+
searchParams.set('countries', Array.from(newCountries).join(','));
|
90 |
+
} else {
|
91 |
+
searchParams.delete('countries');
|
92 |
+
}
|
93 |
+
window.history.replaceState({}, '', `${window.location.pathname}?${searchParams}`);
|
94 |
+
};
|
95 |
+
|
96 |
+
// Toggle a single tag
|
97 |
+
const toggleTag = (tag: string) => {
|
98 |
+
const newTags = new Set(selectedTags);
|
99 |
+
if (newTags.has(tag)) {
|
100 |
+
newTags.delete(tag);
|
101 |
+
} else {
|
102 |
+
newTags.add(tag);
|
103 |
+
}
|
104 |
+
handleTagsChange(newTags);
|
105 |
+
};
|
106 |
|
107 |
+
// Load filters from URL on initial render
|
108 |
+
useEffect(() => {
|
109 |
+
const searchParams = new URLSearchParams(window.location.search);
|
110 |
+
const tagsParam = searchParams.get('tags');
|
111 |
+
const countriesParam = searchParams.get('countries');
|
112 |
|
|
|
|
|
|
|
113 |
if (tagsParam) {
|
114 |
+
const tags = tagsParam.split(',');
|
115 |
+
setSelectedTags(new Set(tags));
|
116 |
}
|
117 |
+
|
118 |
+
if (countriesParam) {
|
119 |
+
const countries = countriesParam.split(',');
|
120 |
+
setSelectedCountries(new Set(countries));
|
121 |
+
}
|
122 |
+
}, []);
|
123 |
|
124 |
if (!Array.isArray(conferencesData)) {
|
125 |
return <div>Loading conferences...</div>;
|
|
|
129 |
<div className="min-h-screen bg-neutral-light">
|
130 |
<Header
|
131 |
onSearch={setSearchQuery}
|
132 |
+
showEmptyMessage={
|
133 |
+
(selectedTags.size > 0 || selectedCountries.size > 0) &&
|
134 |
+
filteredConferences.length === 0 &&
|
135 |
+
!showPastConferences
|
136 |
+
}
|
137 |
/>
|
138 |
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
139 |
<div className="space-y-4 py-4">
|
140 |
+
{/* Category filter buttons */}
|
141 |
+
<div className="bg-white shadow rounded-lg p-4">
|
142 |
+
<div className="flex flex-wrap gap-2">
|
143 |
+
{categoryButtons.map(category => (
|
144 |
+
<button
|
145 |
+
key={category.id}
|
146 |
+
className={`px-4 py-2 rounded-md text-sm font-medium transition-colors ${
|
147 |
+
selectedTags.has(category.id)
|
148 |
+
? 'bg-blue-100 text-blue-800'
|
149 |
+
: 'bg-gray-100 text-gray-700 hover:bg-gray-200'
|
150 |
+
}`}
|
151 |
+
onClick={() => toggleTag(category.id)}
|
152 |
+
>
|
153 |
+
{category.label}
|
154 |
+
</button>
|
155 |
+
))}
|
156 |
+
</div>
|
157 |
+
</div>
|
158 |
+
|
159 |
+
{/* Controls row with past conferences toggle and country filter */}
|
160 |
+
<div className="flex flex-wrap items-center gap-4">
|
161 |
+
<div className="flex items-center gap-2 bg-white p-2 rounded-md shadow-sm">
|
162 |
+
<label htmlFor="show-past" className="text-sm text-neutral-600">
|
163 |
+
Show past conferences
|
164 |
+
</label>
|
165 |
+
<Switch
|
166 |
+
id="show-past"
|
167 |
+
checked={showPastConferences}
|
168 |
+
onCheckedChange={setShowPastConferences}
|
169 |
+
/>
|
170 |
+
</div>
|
171 |
+
|
172 |
+
<div className="flex items-center gap-2 bg-white p-2 rounded-md shadow-sm">
|
173 |
+
<Popover>
|
174 |
+
<PopoverTrigger asChild>
|
175 |
+
<Button variant="outline" size="sm" className="h-8 gap-1">
|
176 |
+
<Filter className="h-4 w-4" />
|
177 |
+
Filter by Country
|
178 |
+
</Button>
|
179 |
+
</PopoverTrigger>
|
180 |
+
<PopoverContent className="w-80 p-4 bg-white" align="start">
|
181 |
+
<div className="space-y-4">
|
182 |
+
<div>
|
183 |
+
<div className="flex items-center justify-between mb-4">
|
184 |
+
<h4 className="text-sm font-medium text-gray-800">Country</h4>
|
185 |
+
<ChevronRight className="h-4 w-4 text-gray-500" />
|
186 |
+
</div>
|
187 |
+
<div className="max-h-60 overflow-y-auto space-y-2 bg-white">
|
188 |
+
{getAllCountries(conferencesData as Conference[]).map(country => (
|
189 |
+
<div key={country} className="flex items-center space-x-2 hover:bg-gray-50 p-1 rounded">
|
190 |
+
<Checkbox
|
191 |
+
id={`country-${country}`}
|
192 |
+
checked={selectedCountries.has(country)}
|
193 |
+
onCheckedChange={() => {
|
194 |
+
const newCountries = new Set(selectedCountries);
|
195 |
+
if (newCountries.has(country)) {
|
196 |
+
newCountries.delete(country);
|
197 |
+
} else {
|
198 |
+
newCountries.add(country);
|
199 |
+
}
|
200 |
+
handleCountriesChange(newCountries);
|
201 |
+
}}
|
202 |
+
/>
|
203 |
+
<label
|
204 |
+
htmlFor={`country-${country}`}
|
205 |
+
className="text-sm font-medium text-gray-700 cursor-pointer w-full py-1"
|
206 |
+
>
|
207 |
+
{country}
|
208 |
+
</label>
|
209 |
+
</div>
|
210 |
+
))}
|
211 |
+
</div>
|
212 |
+
</div>
|
213 |
+
</div>
|
214 |
+
</PopoverContent>
|
215 |
+
</Popover>
|
216 |
+
|
217 |
+
{/* Display selected countries */}
|
218 |
+
{Array.from(selectedCountries).map(country => (
|
219 |
+
<button
|
220 |
+
key={country}
|
221 |
+
className="inline-flex items-center px-3 py-1 rounded-full text-sm bg-blue-100 text-blue-800 hover:bg-blue-200 font-medium"
|
222 |
+
onClick={() => {
|
223 |
+
const newCountries = new Set(selectedCountries);
|
224 |
+
newCountries.delete(country);
|
225 |
+
handleCountriesChange(newCountries);
|
226 |
+
}}
|
227 |
+
>
|
228 |
+
{country}
|
229 |
+
<X className="ml-1 h-3 w-3" />
|
230 |
+
</button>
|
231 |
+
))}
|
232 |
+
|
233 |
+
{/* Clear all filters button */}
|
234 |
+
{(selectedTags.size > 0 || selectedCountries.size > 0) && (
|
235 |
+
<Button
|
236 |
+
variant="ghost"
|
237 |
+
size="sm"
|
238 |
+
onClick={() => {
|
239 |
+
handleTagsChange(new Set());
|
240 |
+
handleCountriesChange(new Set());
|
241 |
+
}}
|
242 |
+
className="text-neutral-500 hover:text-neutral-700"
|
243 |
+
>
|
244 |
+
Clear all filters
|
245 |
+
</Button>
|
246 |
+
)}
|
247 |
+
</div>
|
248 |
</div>
|
249 |
</div>
|
250 |
</div>
|
src/types/conference.ts
CHANGED
@@ -1,24 +1,30 @@
|
|
1 |
export interface Conference {
|
2 |
-
title: string;
|
3 |
-
year: number;
|
4 |
id: string;
|
|
|
5 |
full_name?: string;
|
6 |
-
|
|
|
7 |
deadline: string;
|
8 |
-
timezone
|
9 |
-
place: string;
|
10 |
date: string;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
11 |
start?: string;
|
12 |
end?: string;
|
13 |
-
|
14 |
-
abstract_deadline?: string;
|
15 |
-
note?: string;
|
16 |
hindex?: number;
|
17 |
-
commitment_deadline?: string;
|
18 |
-
submission_deadline?: string;
|
19 |
-
timezone_submission?: string;
|
20 |
rebuttal_period_start?: string;
|
21 |
rebuttal_period_end?: string;
|
22 |
-
review_release_date?: string;
|
23 |
final_decision_date?: string;
|
|
|
|
|
|
|
|
|
|
|
|
|
24 |
}
|
|
|
1 |
export interface Conference {
|
|
|
|
|
2 |
id: string;
|
3 |
+
title: string;
|
4 |
full_name?: string;
|
5 |
+
year: number;
|
6 |
+
link?: string;
|
7 |
deadline: string;
|
8 |
+
timezone?: string;
|
|
|
9 |
date: string;
|
10 |
+
place?: string;
|
11 |
+
city?: string;
|
12 |
+
country?: string;
|
13 |
+
venue?: string;
|
14 |
+
tags?: string[];
|
15 |
+
note?: string;
|
16 |
+
abstract_deadline?: string;
|
17 |
start?: string;
|
18 |
end?: string;
|
19 |
+
rankings?: string;
|
|
|
|
|
20 |
hindex?: number;
|
|
|
|
|
|
|
21 |
rebuttal_period_start?: string;
|
22 |
rebuttal_period_end?: string;
|
|
|
23 |
final_decision_date?: string;
|
24 |
+
review_release_date?: string;
|
25 |
+
submission_deadline?: string;
|
26 |
+
timezone_submission?: string;
|
27 |
+
commitment_deadline?: string;
|
28 |
+
paperslink?: string;
|
29 |
+
pwclink?: string;
|
30 |
}
|
src/utils/countryExtractor.ts
ADDED
@@ -0,0 +1,55 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/**
|
2 |
+
* Extracts country from a conference place string
|
3 |
+
*/
|
4 |
+
export function extractCountry(place: string): string | null {
|
5 |
+
if (!place) return null;
|
6 |
+
|
7 |
+
// Extract the last part after the last comma, which is typically the country
|
8 |
+
const parts = place.split(',');
|
9 |
+
let country = parts[parts.length - 1].trim();
|
10 |
+
|
11 |
+
// Handle special cases like "USA" which might appear in different forms
|
12 |
+
if (['USA', 'U.S.A.', 'United States', 'United States of America'].includes(country)) {
|
13 |
+
return 'USA';
|
14 |
+
}
|
15 |
+
|
16 |
+
// Handle "UK" variations
|
17 |
+
if (['UK', 'U.K.', 'United Kingdom', 'England', 'Scotland', 'Wales'].includes(country)) {
|
18 |
+
return 'UK';
|
19 |
+
}
|
20 |
+
|
21 |
+
// For places without commas, try to extract known countries
|
22 |
+
if (parts.length === 1) {
|
23 |
+
const knownCountries = [
|
24 |
+
'USA', 'Canada', 'China', 'Japan', 'Germany', 'France', 'UK', 'Italy',
|
25 |
+
'Spain', 'Australia', 'Brazil', 'India', 'Singapore', 'South Korea',
|
26 |
+
'Netherlands', 'Sweden', 'Switzerland', 'Belgium', 'Austria', 'Portugal',
|
27 |
+
'UAE', 'Thailand', 'Hawaii', 'Russia', 'Lithuania'
|
28 |
+
];
|
29 |
+
|
30 |
+
for (const country of knownCountries) {
|
31 |
+
if (place.includes(country)) {
|
32 |
+
return country;
|
33 |
+
}
|
34 |
+
}
|
35 |
+
}
|
36 |
+
|
37 |
+
return country;
|
38 |
+
}
|
39 |
+
|
40 |
+
/**
|
41 |
+
* Gets all unique countries from conferences data
|
42 |
+
*/
|
43 |
+
export function getAllCountries(conferences: any[]): string[] {
|
44 |
+
if (!Array.isArray(conferences)) return [];
|
45 |
+
|
46 |
+
const countries = new Set<string>();
|
47 |
+
|
48 |
+
conferences.forEach(conf => {
|
49 |
+
if (conf.country) {
|
50 |
+
countries.add(conf.country);
|
51 |
+
}
|
52 |
+
});
|
53 |
+
|
54 |
+
return Array.from(countries).sort();
|
55 |
+
}
|