tfrere commited on
Commit
4b0f375
·
1 Parent(s): 5048cfd

update color filter

Browse files
client/src/components/LeaderboardCard.jsx CHANGED
@@ -12,6 +12,7 @@ const LeaderboardCard = ({ leaderboard }) => {
12
  consolidated_notes,
13
  organization,
14
  last_modified,
 
15
  } = leaderboard;
16
 
17
  const { getHighlightedText, searchQuery } = useLeaderboard();
@@ -51,6 +52,12 @@ const LeaderboardCard = ({ leaderboard }) => {
51
  // Séparer les emojis s'il y en a plusieurs
52
  const emojis = card_data.emoji?.trim().split(/\s+/) || ["🎯"];
53
 
 
 
 
 
 
 
54
  return (
55
  <Box
56
  component="a"
@@ -244,13 +251,12 @@ const LeaderboardCard = ({ leaderboard }) => {
244
  ))}
245
  </Box>
246
  </Box>
247
- {(card_data.short_description || consolidated_notes) && (
248
  <Typography
249
  variant="body2"
250
  sx={{
251
- color: "white",
252
- opacity: 0.8,
253
- fontSize: "0.875rem",
254
  overflow: "hidden",
255
  textOverflow: "ellipsis",
256
  display: "-webkit-box",
@@ -260,7 +266,7 @@ const LeaderboardCard = ({ leaderboard }) => {
260
  "drop-shadow(0 10px 8px rgb(0 0 0 / .04)) drop-shadow(0 4px 3px rgb(0 0 0 / .1))",
261
  }}
262
  >
263
- {card_data.short_description || consolidated_notes}
264
  </Typography>
265
  )}
266
  </CardContent>
 
12
  consolidated_notes,
13
  organization,
14
  last_modified,
15
+ editor_short_description,
16
  } = leaderboard;
17
 
18
  const { getHighlightedText, searchQuery } = useLeaderboard();
 
52
  // Séparer les emojis s'il y en a plusieurs
53
  const emojis = card_data.emoji?.trim().split(/\s+/) || ["🎯"];
54
 
55
+ // Obtenir la description à afficher
56
+ const displayDescription =
57
+ card_data.short_description ||
58
+ editor_short_description ||
59
+ consolidated_notes;
60
+
61
  return (
62
  <Box
63
  component="a"
 
251
  ))}
252
  </Box>
253
  </Box>
254
+ {displayDescription && (
255
  <Typography
256
  variant="body2"
257
  sx={{
258
+ mt: 1,
259
+ opacity: 0.9,
 
260
  overflow: "hidden",
261
  textOverflow: "ellipsis",
262
  display: "-webkit-box",
 
266
  "drop-shadow(0 10px 8px rgb(0 0 0 / .04)) drop-shadow(0 4px 3px rgb(0 0 0 / .1))",
267
  }}
268
  >
269
+ {displayDescription}
270
  </Typography>
271
  )}
272
  </CardContent>
client/src/components/LeaderboardFilters/LeaderboardFilters.jsx CHANGED
@@ -1,29 +1,25 @@
1
  import React, { useState, useMemo } from "react";
2
- import {
3
- Box,
4
- Stack,
5
- Button,
6
- FormControlLabel,
7
- Switch,
8
- TextField,
9
- InputAdornment,
10
- Typography,
11
- Divider,
12
- } from "@mui/material";
13
- import SearchIcon from "@mui/icons-material/Search";
14
  import { useLeaderboard } from "../../context/LeaderboardContext";
15
  import { useDebounce } from "../../hooks/useDebounce";
16
  import { alpha } from "@mui/material/styles";
17
- import { useMediaQuery } from "@mui/material";
18
 
19
  // Helper function to get the category group of a section
20
  const getSectionGroup = (id) => {
21
  const groups = {
22
- modalities: ["agentic", "vision", "audio"],
23
- capabilities: ["code", "math", "rag"],
24
- languages: ["language"],
25
- domains: ["financial", "medical", "legal", "biology"],
26
- evaluation: ["safety"],
 
 
 
 
 
 
 
27
  misc: ["uncategorized"],
28
  };
29
 
@@ -35,16 +31,40 @@ const getSectionGroup = (id) => {
35
  return "misc";
36
  };
37
 
38
- const LeaderboardFilters = ({ allSections }) => {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
39
  const {
40
  setSearchQuery,
41
  arenaOnly,
42
  setArenaOnly,
43
- totalLeaderboards,
44
- filteredCount,
45
  filterLeaderboards,
46
- filterLeaderboardsForCount,
47
- leaderboards,
48
  selectedCategory,
49
  setSelectedCategory,
50
  searchQuery,
@@ -66,33 +86,34 @@ const LeaderboardFilters = ({ allSections }) => {
66
 
67
  // Update total arena count
68
  React.useEffect(() => {
69
- // Si une catégorie est sélectionnée, on compte les arena dans cette catégorie
70
  const boardsToCount = selectedCategory
71
  ? allSections.find((section) => section.id === selectedCategory)?.data ||
72
  []
73
- : allSections.reduce((acc, section) => [...acc, ...section.data], []);
 
 
 
74
 
75
  const arenaCount = boardsToCount.filter((board) =>
76
  board.tags?.includes("judge:humans")
77
  ).length;
78
  setTotalArenaCount(arenaCount);
79
- }, [leaderboards, selectedCategory, allSections]);
80
-
81
- // Check if any filter is active
82
- const isFilterActive = debouncedSearch || arenaOnly;
83
 
84
  // Calculer le nombre total en fonction de la catégorie sélectionnée
85
  const totalCount = useMemo(() => {
 
 
86
  if (selectedCategory) {
87
  const categorySection = allSections.find(
88
  (section) => section.id === selectedCategory
89
  );
90
- return categorySection ? categorySection.data.length : 0;
91
  }
92
- // Quand aucune catégorie n'est sélectionnée, on compte les leaderboards uniques
93
  const uniqueIds = new Set();
94
  allSections.forEach((section) => {
95
- section.data.forEach((board) => {
96
  if (board.approval_status === "approved") {
97
  uniqueIds.add(board.id);
98
  }
@@ -103,8 +124,9 @@ const LeaderboardFilters = ({ allSections }) => {
103
 
104
  // Calculer le nombre filtré en prenant en compte tous les filtres
105
  const currentFilteredCount = useMemo(() => {
106
- // Si on a uniquement le filtre arena actif (pas de recherche ni de catégorie)
107
- if (arenaOnly && !debouncedSearch && !selectedCategory) {
 
108
  return totalArenaCount;
109
  }
110
 
@@ -112,14 +134,13 @@ const LeaderboardFilters = ({ allSections }) => {
112
  const categorySection = allSections.find(
113
  (section) => section.id === selectedCategory
114
  );
115
- if (!categorySection) return 0;
116
  return filterLeaderboards(categorySection.data).length;
117
  }
118
 
119
- // Quand aucune catégorie n'est sélectionnée, on utilise un Set pour éviter les doublons
120
  const uniqueFilteredIds = new Set();
121
  allSections.forEach((section) => {
122
- const filteredBoards = filterLeaderboards(section.data);
123
  filteredBoards.forEach((board) => {
124
  if (board.approval_status === "approved") {
125
  uniqueFilteredIds.add(board.id);
@@ -132,7 +153,7 @@ const LeaderboardFilters = ({ allSections }) => {
132
  allSections,
133
  filterLeaderboards,
134
  arenaOnly,
135
- debouncedSearch,
136
  totalArenaCount,
137
  ]);
138
 
@@ -145,7 +166,7 @@ const LeaderboardFilters = ({ allSections }) => {
145
  sx={{
146
  width: {
147
  xs: "100%",
148
- md: "60%",
149
  },
150
  }}
151
  >
@@ -157,8 +178,8 @@ const LeaderboardFilters = ({ allSections }) => {
157
  justifyContent="center"
158
  sx={{ pb: 2 }}
159
  >
160
- {allSections.map(({ id, title, data }, index) => {
161
- const filteredCount = filterLeaderboardsForCount(data).length;
162
  const currentGroup = getSectionGroup(id);
163
  const prevGroup =
164
  index > 0 ? getSectionGroup(allSections[index - 1].id) : null;
@@ -171,33 +192,44 @@ const LeaderboardFilters = ({ allSections }) => {
171
  )}
172
  <Button
173
  onClick={() => {
174
- if (selectedCategory === id || filteredCount > 0) {
175
  setSelectedCategory(selectedCategory === id ? null : id);
176
  }
177
  }}
178
  variant={selectedCategory === id ? "contained" : "outlined"}
179
  size="small"
180
- disabled={filteredCount === 0 && selectedCategory !== id}
181
  sx={{
182
  textTransform: "none",
183
  cursor:
184
- filteredCount === 0 && selectedCategory !== id
185
  ? "default"
186
  : "pointer",
187
  mb: 1,
188
- backgroundColor: (theme) =>
189
- selectedCategory === id
190
- ? undefined
191
- : theme.palette.mode === "dark"
 
192
  ? "background.paper"
193
- : "white",
 
 
 
 
 
 
 
 
 
 
194
  "&:hover": {
195
- backgroundColor: (theme) =>
196
- selectedCategory === id
197
- ? undefined
198
- : theme.palette.mode === "dark"
199
- ? "background.paper"
200
- : "white",
201
  },
202
  "& .MuiTouchRipple-root": {
203
  transition: "none",
@@ -228,7 +260,7 @@ const LeaderboardFilters = ({ allSections }) => {
228
  ),
229
  })}
230
  />
231
- {filteredCount}
232
  </Box>
233
  </Button>
234
  </React.Fragment>
@@ -238,121 +270,16 @@ const LeaderboardFilters = ({ allSections }) => {
238
  </Box>
239
 
240
  {/* Search bar */}
241
- <Box sx={{ width: "100%" }}>
242
- <TextField
243
- size="large"
244
- placeholder={
245
- isMobile
246
- ? "Search by name or tags..."
247
- : "Search by name or use domain:, language:, eval:, judge:, test:, modality:, submission:"
248
- }
249
- value={inputValue}
250
- onChange={(e) => setInputValue(e.target.value)}
251
- fullWidth
252
- sx={{
253
- backgroundColor: (theme) =>
254
- theme.palette.mode === "dark" ? "background.paper" : "white",
255
- "& .MuiOutlinedInput-root": {
256
- borderRadius: 1,
257
- fontSize: "0.875rem",
258
- backgroundColor: (theme) =>
259
- theme.palette.mode === "dark" ? "background.paper" : "white",
260
- },
261
- }}
262
- InputProps={{
263
- startAdornment: (
264
- <InputAdornment position="start">
265
- <SearchIcon
266
- sx={{ fontSize: "1.25rem", color: "text.secondary" }}
267
- />
268
- </InputAdornment>
269
- ),
270
- endAdornment: (
271
- <InputAdornment position="end">
272
- <Stack direction="row" spacing={2} alignItems="center">
273
- <Box sx={{ display: "flex", alignItems: "center" }}>
274
- <Typography
275
- variant="body2"
276
- sx={{
277
- color: debouncedSearch
278
- ? "primary.main"
279
- : "text.secondary",
280
- fontWeight: 500,
281
- }}
282
- >
283
- {currentFilteredCount}
284
- </Typography>
285
- <Box
286
- sx={{
287
- display: "flex",
288
- alignItems: "center",
289
- color: arenaOnly ? "secondary.main" : "text.secondary",
290
- }}
291
- >
292
- <Typography
293
- variant="body2"
294
- sx={{
295
- fontWeight: 500,
296
- mx: 0.5,
297
- }}
298
- >
299
- /
300
- </Typography>
301
- <Typography
302
- variant="body2"
303
- sx={{
304
- fontWeight: 500,
305
- }}
306
- >
307
- {arenaOnly ? totalArenaCount : totalCount}
308
- </Typography>
309
- </Box>
310
- <Typography
311
- variant="body2"
312
- sx={{
313
- color: "text.secondary",
314
- fontWeight: 400,
315
- ml: 0.5,
316
- }}
317
- >
318
- leaderboards
319
- </Typography>
320
- </Box>
321
-
322
- <Divider orientation="vertical" flexItem />
323
- <FormControlLabel
324
- control={
325
- <Switch
326
- checked={arenaOnly}
327
- onChange={(e) => setArenaOnly(e.target.checked)}
328
- size="small"
329
- color="secondary"
330
- sx={{
331
- "&.Mui-checked": {
332
- color: "secondary.light",
333
- "& .MuiSwitch-track": {
334
- backgroundColor: "secondary.light",
335
- },
336
- },
337
- }}
338
- />
339
- }
340
- label={isMobile ? "Arena only" : "Show arena only"}
341
- sx={{
342
- userSelect: "none!important",
343
- mr: 0,
344
- "& .MuiFormControlLabel-label": {
345
- color: arenaOnly ? "secondary.light" : "inherit",
346
- userSelect: arenaOnly ? "none" : "auto",
347
- },
348
- }}
349
- />
350
- </Stack>
351
- </InputAdornment>
352
- ),
353
- }}
354
- />
355
- </Box>
356
  </Stack>
357
  );
358
  };
 
1
  import React, { useState, useMemo } from "react";
2
+ import { Box, Stack, Button, useMediaQuery } from "@mui/material";
 
 
 
 
 
 
 
 
 
 
 
3
  import { useLeaderboard } from "../../context/LeaderboardContext";
4
  import { useDebounce } from "../../hooks/useDebounce";
5
  import { alpha } from "@mui/material/styles";
6
+ import SearchBar from "./SearchBar";
7
 
8
  // Helper function to get the category group of a section
9
  const getSectionGroup = (id) => {
10
  const groups = {
11
+ science: ["code", "math", "biology", "chemistry", "physics"],
12
+ modalities: ["text", "image", "video", "audio", "threeD", "embeddings"],
13
+ llm_capabilities: [
14
+ "rag",
15
+ "reasoning",
16
+ "agentic",
17
+ "safety",
18
+ "performance",
19
+ "hallucination",
20
+ ],
21
+ domain_specific: ["medical", "financial", "legal", "commercial"],
22
+ language_related: ["language", "translation"],
23
  misc: ["uncategorized"],
24
  };
25
 
 
31
  return "misc";
32
  };
33
 
34
+ // Colors for each group
35
+ const groupColors = {
36
+ science: {
37
+ main: "#2196F3",
38
+ light: "#E3F2FD",
39
+ },
40
+ modalities: {
41
+ main: "#9C27B0",
42
+ light: "#F3E5F5",
43
+ },
44
+ llm_capabilities: {
45
+ main: "#4CAF50",
46
+ light: "#E8F5E9",
47
+ },
48
+ domain_specific: {
49
+ main: "#FF9800",
50
+ light: "#FFF3E0",
51
+ },
52
+ language_related: {
53
+ main: "#F44336",
54
+ light: "#FFEBEE",
55
+ },
56
+ misc: {
57
+ main: "#607D8B",
58
+ light: "#ECEFF1",
59
+ },
60
+ };
61
+
62
+ const LeaderboardFilters = ({ allSections = [] }) => {
63
  const {
64
  setSearchQuery,
65
  arenaOnly,
66
  setArenaOnly,
 
 
67
  filterLeaderboards,
 
 
68
  selectedCategory,
69
  setSelectedCategory,
70
  searchQuery,
 
86
 
87
  // Update total arena count
88
  React.useEffect(() => {
 
89
  const boardsToCount = selectedCategory
90
  ? allSections.find((section) => section.id === selectedCategory)?.data ||
91
  []
92
+ : allSections.reduce(
93
+ (acc, section) => [...acc, ...(section.data || [])],
94
+ []
95
+ );
96
 
97
  const arenaCount = boardsToCount.filter((board) =>
98
  board.tags?.includes("judge:humans")
99
  ).length;
100
  setTotalArenaCount(arenaCount);
101
+ }, [selectedCategory, allSections]);
 
 
 
102
 
103
  // Calculer le nombre total en fonction de la catégorie sélectionnée
104
  const totalCount = useMemo(() => {
105
+ if (!allSections) return 0;
106
+
107
  if (selectedCategory) {
108
  const categorySection = allSections.find(
109
  (section) => section.id === selectedCategory
110
  );
111
+ return categorySection?.data?.length || 0;
112
  }
113
+
114
  const uniqueIds = new Set();
115
  allSections.forEach((section) => {
116
+ (section.data || []).forEach((board) => {
117
  if (board.approval_status === "approved") {
118
  uniqueIds.add(board.id);
119
  }
 
124
 
125
  // Calculer le nombre filtré en prenant en compte tous les filtres
126
  const currentFilteredCount = useMemo(() => {
127
+ if (!allSections) return 0;
128
+
129
+ if (arenaOnly && !searchQuery && !selectedCategory) {
130
  return totalArenaCount;
131
  }
132
 
 
134
  const categorySection = allSections.find(
135
  (section) => section.id === selectedCategory
136
  );
137
+ if (!categorySection?.data) return 0;
138
  return filterLeaderboards(categorySection.data).length;
139
  }
140
 
 
141
  const uniqueFilteredIds = new Set();
142
  allSections.forEach((section) => {
143
+ const filteredBoards = filterLeaderboards(section.data || []);
144
  filteredBoards.forEach((board) => {
145
  if (board.approval_status === "approved") {
146
  uniqueFilteredIds.add(board.id);
 
153
  allSections,
154
  filterLeaderboards,
155
  arenaOnly,
156
+ searchQuery,
157
  totalArenaCount,
158
  ]);
159
 
 
166
  sx={{
167
  width: {
168
  xs: "100%",
169
+ md: "68%",
170
  },
171
  }}
172
  >
 
178
  justifyContent="center"
179
  sx={{ pb: 2 }}
180
  >
181
+ {(allSections || []).map(({ id, title, data = [] }, index) => {
182
+ const count = data.length;
183
  const currentGroup = getSectionGroup(id);
184
  const prevGroup =
185
  index > 0 ? getSectionGroup(allSections[index - 1].id) : null;
 
192
  )}
193
  <Button
194
  onClick={() => {
195
+ if (selectedCategory === id || count > 0) {
196
  setSelectedCategory(selectedCategory === id ? null : id);
197
  }
198
  }}
199
  variant={selectedCategory === id ? "contained" : "outlined"}
200
  size="small"
201
+ disabled={count === 0 && selectedCategory !== id}
202
  sx={{
203
  textTransform: "none",
204
  cursor:
205
+ count === 0 && selectedCategory !== id
206
  ? "default"
207
  : "pointer",
208
  mb: 1,
209
+ backgroundColor: (theme) => {
210
+ if (selectedCategory === id) {
211
+ return groupColors[currentGroup]?.main;
212
+ }
213
+ return theme.palette.mode === "dark"
214
  ? "background.paper"
215
+ : groupColors[currentGroup]?.light;
216
+ },
217
+ color: (theme) => {
218
+ if (selectedCategory === id) {
219
+ return "white";
220
+ }
221
+ return groupColors[currentGroup]?.main;
222
+ },
223
+ borderColor: (theme) => {
224
+ return groupColors[currentGroup]?.main;
225
+ },
226
  "&:hover": {
227
+ backgroundColor: (theme) => {
228
+ if (selectedCategory === id) {
229
+ return groupColors[currentGroup]?.main;
230
+ }
231
+ return groupColors[currentGroup]?.light;
232
+ },
233
  },
234
  "& .MuiTouchRipple-root": {
235
  transition: "none",
 
260
  ),
261
  })}
262
  />
263
+ {count}
264
  </Box>
265
  </Button>
266
  </React.Fragment>
 
270
  </Box>
271
 
272
  {/* Search bar */}
273
+ <SearchBar
274
+ searchQuery={searchQuery}
275
+ setSearchQuery={setSearchQuery}
276
+ arenaOnly={arenaOnly}
277
+ setArenaOnly={setArenaOnly}
278
+ currentFilteredCount={currentFilteredCount}
279
+ totalCount={totalCount}
280
+ totalArenaCount={totalArenaCount}
281
+ isMobile={isMobile}
282
+ />
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
283
  </Stack>
284
  );
285
  };
client/src/components/LeaderboardFilters/SearchBar.jsx ADDED
@@ -0,0 +1,169 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import React, { useState } from "react";
2
+ import PropTypes from "prop-types";
3
+ import {
4
+ Box,
5
+ Stack,
6
+ TextField,
7
+ InputAdornment,
8
+ Typography,
9
+ Divider,
10
+ FormControlLabel,
11
+ Switch,
12
+ } from "@mui/material";
13
+ import SearchIcon from "@mui/icons-material/Search";
14
+ import { useDebounce } from "../../hooks/useDebounce";
15
+
16
+ const SearchBar = ({
17
+ searchQuery,
18
+ setSearchQuery,
19
+ arenaOnly,
20
+ setArenaOnly,
21
+ currentFilteredCount,
22
+ totalCount,
23
+ totalArenaCount,
24
+ isMobile,
25
+ }) => {
26
+ const [inputValue, setInputValue] = useState(searchQuery || "");
27
+ const debouncedSearch = useDebounce(inputValue, 200);
28
+
29
+ // Update the search query after debounce
30
+ React.useEffect(() => {
31
+ setSearchQuery(debouncedSearch);
32
+ }, [debouncedSearch, setSearchQuery]);
33
+
34
+ // Update input value when searchQuery changes externally
35
+ React.useEffect(() => {
36
+ setInputValue(searchQuery || "");
37
+ }, [searchQuery]);
38
+
39
+ return (
40
+ <Box sx={{ width: "100%" }}>
41
+ <TextField
42
+ size="large"
43
+ placeholder={
44
+ isMobile
45
+ ? "Search by name or tags..."
46
+ : "Search by name or use domain:, language:, eval:, judge:, test:, modality:, submission:"
47
+ }
48
+ value={inputValue}
49
+ onChange={(e) => setInputValue(e.target.value)}
50
+ fullWidth
51
+ sx={{
52
+ backgroundColor: (theme) =>
53
+ theme.palette.mode === "dark" ? "background.paper" : "white",
54
+ "& .MuiOutlinedInput-root": {
55
+ borderRadius: 1,
56
+ fontSize: "0.875rem",
57
+ backgroundColor: (theme) =>
58
+ theme.palette.mode === "dark" ? "background.paper" : "white",
59
+ },
60
+ }}
61
+ InputProps={{
62
+ startAdornment: (
63
+ <InputAdornment position="start">
64
+ <SearchIcon
65
+ sx={{ fontSize: "1.25rem", color: "text.secondary" }}
66
+ />
67
+ </InputAdornment>
68
+ ),
69
+ endAdornment: (
70
+ <InputAdornment position="end">
71
+ <Stack direction="row" spacing={2} alignItems="center">
72
+ <Box sx={{ display: "flex", alignItems: "center" }}>
73
+ <Typography
74
+ variant="body2"
75
+ sx={{
76
+ color: debouncedSearch
77
+ ? "primary.main"
78
+ : "text.secondary",
79
+ fontWeight: 500,
80
+ }}
81
+ >
82
+ {currentFilteredCount}
83
+ </Typography>
84
+ <Box
85
+ sx={{
86
+ display: "flex",
87
+ alignItems: "center",
88
+ color: arenaOnly ? "secondary.main" : "text.secondary",
89
+ }}
90
+ >
91
+ <Typography
92
+ variant="body2"
93
+ sx={{
94
+ fontWeight: 500,
95
+ mx: 0.5,
96
+ }}
97
+ >
98
+ /
99
+ </Typography>
100
+ <Typography
101
+ variant="body2"
102
+ sx={{
103
+ fontWeight: 500,
104
+ }}
105
+ >
106
+ {arenaOnly ? totalArenaCount : totalCount}
107
+ </Typography>
108
+ </Box>
109
+ <Typography
110
+ variant="body2"
111
+ sx={{
112
+ color: "text.secondary",
113
+ fontWeight: 400,
114
+ ml: 0.5,
115
+ }}
116
+ >
117
+ leaderboards
118
+ </Typography>
119
+ </Box>
120
+
121
+ <Divider orientation="vertical" flexItem />
122
+ <FormControlLabel
123
+ control={
124
+ <Switch
125
+ checked={arenaOnly}
126
+ onChange={(e) => setArenaOnly(e.target.checked)}
127
+ size="small"
128
+ color="secondary"
129
+ sx={{
130
+ "&.Mui-checked": {
131
+ color: "secondary.light",
132
+ "& .MuiSwitch-track": {
133
+ backgroundColor: "secondary.light",
134
+ },
135
+ },
136
+ }}
137
+ />
138
+ }
139
+ label={isMobile ? "Arena only" : "Show arena only"}
140
+ sx={{
141
+ userSelect: "none!important",
142
+ mr: 0,
143
+ "& .MuiFormControlLabel-label": {
144
+ color: arenaOnly ? "secondary.light" : "inherit",
145
+ userSelect: arenaOnly ? "none" : "auto",
146
+ },
147
+ }}
148
+ />
149
+ </Stack>
150
+ </InputAdornment>
151
+ ),
152
+ }}
153
+ />
154
+ </Box>
155
+ );
156
+ };
157
+
158
+ SearchBar.propTypes = {
159
+ searchQuery: PropTypes.string,
160
+ setSearchQuery: PropTypes.func.isRequired,
161
+ arenaOnly: PropTypes.bool.isRequired,
162
+ setArenaOnly: PropTypes.func.isRequired,
163
+ currentFilteredCount: PropTypes.number.isRequired,
164
+ totalCount: PropTypes.number.isRequired,
165
+ totalArenaCount: PropTypes.number.isRequired,
166
+ isMobile: PropTypes.bool.isRequired,
167
+ };
168
+
169
+ export default SearchBar;
client/src/context/LeaderboardContext.jsx CHANGED
@@ -36,9 +36,12 @@ const getURLParams = () => {
36
  // Constantes pour les tags de catégorisation
37
  const CATEGORIZATION_TAGS = [
38
  "modality:agent",
 
 
39
  "eval:code",
40
  "eval:math",
41
  "eval:reasoning",
 
42
  "modality:video",
43
  "modality:image",
44
  "modality:3d",
@@ -49,6 +52,8 @@ const CATEGORIZATION_TAGS = [
49
  "domain:biology",
50
  "domain:translation",
51
  "domain:chemistry",
 
 
52
  "eval:safety",
53
  "eval:performance",
54
  "eval:rag",
@@ -201,12 +206,20 @@ export const LeaderboardProvider = ({ children }) => {
201
  switch (selectedCategory) {
202
  case "agentic":
203
  return tags.includes("modality:agent");
 
 
 
 
 
 
204
  case "code":
205
  return tags.includes("eval:code");
206
  case "math":
207
  return tags.includes("eval:math");
208
  case "reasoning":
209
  return tags.includes("eval:reasoning");
 
 
210
  case "rag":
211
  return tags.includes("eval:rag");
212
  case "language":
@@ -227,6 +240,8 @@ export const LeaderboardProvider = ({ children }) => {
227
  return tags.includes("domain:legal");
228
  case "biology":
229
  return tags.includes("domain:biology");
 
 
230
  case "translation":
231
  return tags.includes("domain:translation");
232
  case "chemistry":
@@ -312,44 +327,6 @@ export const LeaderboardProvider = ({ children }) => {
312
  );
313
  }, []);
314
 
315
- const filterByVision = useCallback((boards) => {
316
- return (
317
- boards?.filter((board) =>
318
- board.tags?.some(
319
- (tag) => tag === "modality:video" || tag === "modality:image"
320
- )
321
- ) || []
322
- );
323
- }, []);
324
-
325
- // Helper function to get the category group of a section
326
- const getSectionGroup = (id) => {
327
- const groups = {
328
- agentic: ["agentic"],
329
- capabilities: ["code", "math", "rag", "reasoning"],
330
- languages: ["language"],
331
- modalities: ["vision", "audio"],
332
- threeD: ["threeD"],
333
- domains: [
334
- "financial",
335
- "medical",
336
- "legal",
337
- "biology",
338
- "translation",
339
- "chemistry",
340
- ],
341
- evaluation: ["safety", "performance"],
342
- misc: ["uncategorized"],
343
- };
344
-
345
- for (const [group, ids] of Object.entries(groups)) {
346
- if (ids.includes(id)) {
347
- return group;
348
- }
349
- }
350
- return "misc";
351
- };
352
-
353
  // Define sections with raw data
354
  const allSections = useMemo(() => {
355
  if (!leaderboards) return [];
@@ -358,14 +335,7 @@ export const LeaderboardProvider = ({ children }) => {
358
  const categorizedIds = new Set();
359
 
360
  const sections = [
361
- {
362
- id: "agentic",
363
- title: "Agentic",
364
- data: filterByTag("modality:agent", leaderboards).map((board) => {
365
- categorizedIds.add(board.id);
366
- return board;
367
- }),
368
- },
369
  {
370
  id: "code",
371
  title: "Code",
@@ -383,33 +353,42 @@ export const LeaderboardProvider = ({ children }) => {
383
  }),
384
  },
385
  {
386
- id: "reasoning",
387
- title: "Reasoning",
388
- data: filterByTag("eval:reasoning", leaderboards).map((board) => {
389
  categorizedIds.add(board.id);
390
  return board;
391
  }),
392
  },
393
  {
394
- id: "rag",
395
- title: "RAG",
396
- data: filterByTag("eval:rag", leaderboards).map((board) => {
397
  categorizedIds.add(board.id);
398
  return board;
399
  }),
400
  },
401
  {
402
- id: "language",
403
- title: "Language Specific",
404
- data: filterByLanguage(leaderboards).map((board) => {
405
  categorizedIds.add(board.id);
406
  return board;
407
  }),
408
  },
 
409
  {
410
- id: "vision",
411
- title: "Vision",
412
- data: filterByVision(leaderboards).map((board) => {
 
 
 
 
 
 
 
 
413
  categorizedIds.add(board.id);
414
  return board;
415
  }),
@@ -422,6 +401,14 @@ export const LeaderboardProvider = ({ children }) => {
422
  return board;
423
  }),
424
  },
 
 
 
 
 
 
 
 
425
  {
426
  id: "threeD",
427
  title: "3D",
@@ -431,13 +418,63 @@ export const LeaderboardProvider = ({ children }) => {
431
  }),
432
  },
433
  {
434
- id: "financial",
435
- title: "Financial",
436
- data: filterByTag("domain:financial", leaderboards).map((board) => {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
437
  categorizedIds.add(board.id);
438
  return board;
439
  }),
440
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
441
  {
442
  id: "medical",
443
  title: "Medical",
@@ -447,9 +484,9 @@ export const LeaderboardProvider = ({ children }) => {
447
  }),
448
  },
449
  {
450
- id: "biology",
451
- title: "Biology",
452
- data: filterByTag("domain:biology", leaderboards).map((board) => {
453
  categorizedIds.add(board.id);
454
  return board;
455
  }),
@@ -463,37 +500,31 @@ export const LeaderboardProvider = ({ children }) => {
463
  }),
464
  },
465
  {
466
- id: "translation",
467
- title: "Translation",
468
- data: filterByTag("domain:translation", leaderboards).map((board) => {
469
- categorizedIds.add(board.id);
470
- return board;
471
- }),
472
- },
473
- {
474
- id: "chemistry",
475
- title: "Chemistry",
476
- data: filterByTag("domain:chemistry", leaderboards).map((board) => {
477
  categorizedIds.add(board.id);
478
  return board;
479
  }),
480
  },
 
481
  {
482
- id: "safety",
483
- title: "Safety",
484
- data: filterByTag("eval:safety", leaderboards).map((board) => {
485
  categorizedIds.add(board.id);
486
  return board;
487
  }),
488
  },
489
  {
490
- id: "performance",
491
- title: "Performance",
492
- data: filterByTag("eval:performance", leaderboards).map((board) => {
493
  categorizedIds.add(board.id);
494
  return board;
495
  }),
496
  },
 
497
  {
498
  id: "uncategorized",
499
  title: "Uncategorized",
@@ -504,7 +535,7 @@ export const LeaderboardProvider = ({ children }) => {
504
  ];
505
 
506
  return sections;
507
- }, [leaderboards, filterByTag, filterByLanguage, filterByVision]);
508
 
509
  // Get sections with data
510
  const sections = useMemo(() => {
 
36
  // Constantes pour les tags de catégorisation
37
  const CATEGORIZATION_TAGS = [
38
  "modality:agent",
39
+ "modality:artefacts",
40
+ "modality:text",
41
  "eval:code",
42
  "eval:math",
43
  "eval:reasoning",
44
+ "eval:hallucination",
45
  "modality:video",
46
  "modality:image",
47
  "modality:3d",
 
52
  "domain:biology",
53
  "domain:translation",
54
  "domain:chemistry",
55
+ "domain:physics",
56
+ "domain:commercial",
57
  "eval:safety",
58
  "eval:performance",
59
  "eval:rag",
 
206
  switch (selectedCategory) {
207
  case "agentic":
208
  return tags.includes("modality:agent");
209
+ case "text":
210
+ return tags.includes("modality:text");
211
+ case "image":
212
+ return tags.includes("modality:image");
213
+ case "video":
214
+ return tags.includes("modality:video");
215
  case "code":
216
  return tags.includes("eval:code");
217
  case "math":
218
  return tags.includes("eval:math");
219
  case "reasoning":
220
  return tags.includes("eval:reasoning");
221
+ case "hallucination":
222
+ return tags.includes("eval:hallucination");
223
  case "rag":
224
  return tags.includes("eval:rag");
225
  case "language":
 
240
  return tags.includes("domain:legal");
241
  case "biology":
242
  return tags.includes("domain:biology");
243
+ case "commercial":
244
+ return tags.includes("domain:commercial");
245
  case "translation":
246
  return tags.includes("domain:translation");
247
  case "chemistry":
 
327
  );
328
  }, []);
329
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
330
  // Define sections with raw data
331
  const allSections = useMemo(() => {
332
  if (!leaderboards) return [];
 
335
  const categorizedIds = new Set();
336
 
337
  const sections = [
338
+ // Science
 
 
 
 
 
 
 
339
  {
340
  id: "code",
341
  title: "Code",
 
353
  }),
354
  },
355
  {
356
+ id: "biology",
357
+ title: "Biology",
358
+ data: filterByTag("domain:biology", leaderboards).map((board) => {
359
  categorizedIds.add(board.id);
360
  return board;
361
  }),
362
  },
363
  {
364
+ id: "chemistry",
365
+ title: "Chemistry",
366
+ data: filterByTag("domain:chemistry", leaderboards).map((board) => {
367
  categorizedIds.add(board.id);
368
  return board;
369
  }),
370
  },
371
  {
372
+ id: "physics",
373
+ title: "Physics",
374
+ data: filterByTag("domain:physics", leaderboards).map((board) => {
375
  categorizedIds.add(board.id);
376
  return board;
377
  }),
378
  },
379
+ // Modalities
380
  {
381
+ id: "image",
382
+ title: "Image",
383
+ data: filterByTag("modality:image", leaderboards).map((board) => {
384
+ categorizedIds.add(board.id);
385
+ return board;
386
+ }),
387
+ },
388
+ {
389
+ id: "video",
390
+ title: "Video",
391
+ data: filterByTag("modality:video", leaderboards).map((board) => {
392
  categorizedIds.add(board.id);
393
  return board;
394
  }),
 
401
  return board;
402
  }),
403
  },
404
+ {
405
+ id: "text",
406
+ title: "Text",
407
+ data: filterByTag("modality:text", leaderboards).map((board) => {
408
+ categorizedIds.add(board.id);
409
+ return board;
410
+ }),
411
+ },
412
  {
413
  id: "threeD",
414
  title: "3D",
 
418
  }),
419
  },
420
  {
421
+ id: "embeddings",
422
+ title: "Embeddings",
423
+ data: filterByTag("modality:artefacts", leaderboards).map((board) => {
424
+ categorizedIds.add(board.id);
425
+ return board;
426
+ }),
427
+ },
428
+ // LLM Capabilities
429
+ {
430
+ id: "rag",
431
+ title: "RAG",
432
+ data: filterByTag("eval:rag", leaderboards).map((board) => {
433
+ categorizedIds.add(board.id);
434
+ return board;
435
+ }),
436
+ },
437
+ {
438
+ id: "reasoning",
439
+ title: "Reasoning",
440
+ data: filterByTag("eval:reasoning", leaderboards).map((board) => {
441
+ categorizedIds.add(board.id);
442
+ return board;
443
+ }),
444
+ },
445
+ {
446
+ id: "agentic",
447
+ title: "Agentic",
448
+ data: filterByTag("modality:agent", leaderboards).map((board) => {
449
  categorizedIds.add(board.id);
450
  return board;
451
  }),
452
  },
453
+ {
454
+ id: "safety",
455
+ title: "Safety",
456
+ data: filterByTag("eval:safety", leaderboards).map((board) => {
457
+ categorizedIds.add(board.id);
458
+ return board;
459
+ }),
460
+ },
461
+ {
462
+ id: "performance",
463
+ title: "Performance",
464
+ data: filterByTag("eval:performance", leaderboards).map((board) => {
465
+ categorizedIds.add(board.id);
466
+ return board;
467
+ }),
468
+ },
469
+ {
470
+ id: "hallucination",
471
+ title: "Hallucination",
472
+ data: filterByTag("eval:hallucination", leaderboards).map((board) => {
473
+ categorizedIds.add(board.id);
474
+ return board;
475
+ }),
476
+ },
477
+ // Domain Specific
478
  {
479
  id: "medical",
480
  title: "Medical",
 
484
  }),
485
  },
486
  {
487
+ id: "financial",
488
+ title: "Financial",
489
+ data: filterByTag("domain:financial", leaderboards).map((board) => {
490
  categorizedIds.add(board.id);
491
  return board;
492
  }),
 
500
  }),
501
  },
502
  {
503
+ id: "commercial",
504
+ title: "Commercial",
505
+ data: filterByTag("domain:commercial", leaderboards).map((board) => {
 
 
 
 
 
 
 
 
506
  categorizedIds.add(board.id);
507
  return board;
508
  }),
509
  },
510
+ // Language Related
511
  {
512
+ id: "language",
513
+ title: "Language Specific",
514
+ data: filterByLanguage(leaderboards).map((board) => {
515
  categorizedIds.add(board.id);
516
  return board;
517
  }),
518
  },
519
  {
520
+ id: "translation",
521
+ title: "Translation",
522
+ data: filterByTag("domain:translation", leaderboards).map((board) => {
523
  categorizedIds.add(board.id);
524
  return board;
525
  }),
526
  },
527
+ // Misc
528
  {
529
  id: "uncategorized",
530
  title: "Uncategorized",
 
535
  ];
536
 
537
  return sections;
538
+ }, [leaderboards, filterByTag, filterByLanguage]);
539
 
540
  // Get sections with data
541
  const sections = useMemo(() => {
client/src/pages/HowToSubmitPage/HowToSubmitPage.jsx CHANGED
@@ -211,10 +211,10 @@ const getTagEmoji = (tag) => {
211
  text: "📝",
212
  image: "🖼️",
213
  audio: "🎵",
214
- audio: "🎵",
215
  video: "🎥",
216
  tools: "🛠️",
217
  artefacts: "🏺",
 
218
  },
219
  eval: {
220
  generation: "✨",
@@ -239,6 +239,8 @@ const getTagEmoji = (tag) => {
239
  biology: "🧬",
240
  translation: "🔄",
241
  chemistry: "🧪",
 
 
242
  },
243
  };
244
 
@@ -679,7 +681,8 @@ const HowToSubmitPage = () => {
679
  "",
680
  "",
681
  "requires added <strong>tool usage</strong> - mostly for <strong>assistant models</strong> (a bit outside of usual modalities)",
682
- "the leaderboard concerns itself with <strong>machine learning artefacts</strong> as themselves, for example, quality evaluation of <strong>text embeddings</strong> (a bit outside of usual modalities)",
 
683
  ]}
684
  />
685
 
@@ -731,6 +734,8 @@ const HowToSubmitPage = () => {
731
  "domain:biology",
732
  "domain:translation",
733
  "domain:chemistry",
 
 
734
  ]}
735
  />
736
 
 
211
  text: "📝",
212
  image: "🖼️",
213
  audio: "🎵",
 
214
  video: "🎥",
215
  tools: "🛠️",
216
  artefacts: "🏺",
217
+ embeddings: "🔤",
218
  },
219
  eval: {
220
  generation: "✨",
 
239
  biology: "🧬",
240
  translation: "🔄",
241
  chemistry: "🧪",
242
+ physics: "⚛️",
243
+ commercial: "🏢",
244
  },
245
  };
246
 
 
681
  "",
682
  "",
683
  "requires added <strong>tool usage</strong> - mostly for <strong>assistant models</strong> (a bit outside of usual modalities)",
684
+ "the leaderboard concerns itself with <strong>machine learning artefacts</strong> as themselves, for example, quality evaluation of <strong>text embeddings</strong>",
685
+ "",
686
  ]}
687
  />
688
 
 
734
  "domain:biology",
735
  "domain:translation",
736
  "domain:chemistry",
737
+ "domain:physics",
738
+ "domain:commercial",
739
  ]}
740
  />
741