tfrere HF Staff commited on
Commit
5876642
·
1 Parent(s): 911357d
client/src/components/LeaderboardSection.jsx CHANGED
@@ -34,11 +34,115 @@ const LeaderboardSection = ({
34
  } = useLeaderboard();
35
  const isExpanded = expandedSections.has(id);
36
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
37
  // Extraire la liste des langues si c'est la section Language Specific
38
- // Cette liste ne doit JAMAIS changer, peu importe les filtres
39
  const languages = useMemo(() => {
40
  if (id !== "language") return null;
41
  const langSet = new Set();
 
 
42
  leaderboards.forEach((board) => {
43
  board.tags?.forEach((tag) => {
44
  if (tag.startsWith("language:")) {
@@ -49,7 +153,31 @@ const LeaderboardSection = ({
49
  }
50
  });
51
  });
52
- return Array.from(langSet).sort();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
53
  }, [id, leaderboards]);
54
 
55
  // Calculer le nombre de leaderboards par langue
@@ -186,6 +314,7 @@ const LeaderboardSection = ({
186
  <Accordion
187
  defaultExpanded={false}
188
  elevation={0}
 
189
  sx={{
190
  mb: approvedLeaderboards.length > 0 ? 4 : 2,
191
  "&:before": {
@@ -195,101 +324,138 @@ const LeaderboardSection = ({
195
  }}
196
  >
197
  <AccordionSummary
198
- expandIcon={<ExpandMoreIcon sx={{ fontSize: 20 }} />}
 
 
199
  sx={{
200
- padding: 0,
201
- "& .MuiAccordionSummary-content": {
202
- margin: 0,
 
 
 
 
 
203
  },
204
- "& .MuiAccordionSummary-expandIconWrapper": {
205
- position: "relative",
206
- right: "unset",
207
- marginLeft: 1,
208
- transform: "none",
209
  },
210
  }}
211
  >
212
- <Box sx={{ display: "flex", alignItems: "center" }}>
213
- <Typography
214
- variant="body2"
215
- color="text.secondary"
216
- sx={{ fontWeight: 500 }}
217
- >
218
- Languages represented in this category
219
- </Typography>
220
- </Box>
221
  </AccordionSummary>
222
  <AccordionDetails sx={{ padding: 0 }}>
223
- <Box
224
- sx={{
225
- display: "flex",
226
- flexWrap: "wrap",
227
- gap: 1,
228
- mx: -0.5,
229
- }}
230
- >
231
- {languages.map((lang) => {
232
- const isActive = selectedLanguage === lang;
233
- const count = languageStats?.get(lang) || 0;
234
 
235
- return (
236
- <Button
237
- key={lang}
238
- onClick={() => setSelectedLanguage(isActive ? null : lang)}
239
- variant={isActive ? "contained" : "outlined"}
240
- size="small"
241
  sx={{
242
- textTransform: "none",
243
- m: 0.125,
244
- backgroundColor: (theme) =>
245
- isActive
246
- ? undefined
247
- : theme.palette.mode === "dark"
248
- ? "background.paper"
249
- : "white",
250
- "&:hover": {
251
- backgroundColor: (theme) =>
252
- isActive
253
- ? undefined
254
- : theme.palette.mode === "dark"
255
- ? "background.paper"
256
- : "white",
257
- },
258
- "& .MuiTouchRipple-root": {
259
- transition: "none",
260
- },
261
- transition: "none",
262
  }}
263
  >
264
- {lang}
265
- <Box
266
- component="span"
267
- sx={{
268
- display: "inline-flex",
269
- alignItems: "center",
270
- gap: 0.75,
271
- color: isActive ? "inherit" : "text.secondary",
272
- ml: 0.75,
273
- }}
274
- >
275
- <Box
276
- component="span"
277
- sx={(theme) => ({
278
- width: "4px",
279
- height: "4px",
280
- borderRadius: "100%",
281
- backgroundColor: alpha(
282
- theme.palette.text.primary,
283
- theme.palette.mode === "dark" ? 0.2 : 0.15
284
- ),
285
- })}
286
- />
287
- {count}
288
- </Box>
289
- </Button>
290
- );
291
- })}
292
- </Box>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
293
  </AccordionDetails>
294
  </Accordion>
295
  )}
 
34
  } = useLeaderboard();
35
  const isExpanded = expandedSections.has(id);
36
 
37
+ // Définition des familles de langues
38
+ const LANGUAGE_FAMILIES = {
39
+ "European Languages": {
40
+ Main: [
41
+ "English",
42
+ "French",
43
+ "Spanish",
44
+ "German",
45
+ "Italian",
46
+ "Portuguese",
47
+ "Dutch",
48
+ "Romanian",
49
+ "Polish",
50
+ "Greek",
51
+ "Swedish",
52
+ "Danish",
53
+ "Norwegian",
54
+ "Finnish",
55
+ "Hungarian",
56
+ "Czech",
57
+ "Slovak",
58
+ "Croatian",
59
+ "Serbian",
60
+ "Bulgarian",
61
+ "Ukrainian",
62
+ "Russian",
63
+ "Lithuanian",
64
+ "Latvian",
65
+ "Estonian",
66
+ "Basque",
67
+ "Catalan",
68
+ "Albanian",
69
+ "Slovenian",
70
+ "Icelandic",
71
+ "Galician",
72
+ "Armenian",
73
+ ],
74
+ },
75
+ "Asian Languages": {
76
+ Main: [
77
+ "Chinese",
78
+ "Japanese",
79
+ "Korean",
80
+ "Vietnamese",
81
+ "Thai",
82
+ "Indonesian",
83
+ "Malay",
84
+ "Tagalog",
85
+ "Mandarin",
86
+ "Cantonese",
87
+ "日本語",
88
+ "Taiwanese",
89
+ "Filipino",
90
+ "Singlish",
91
+ ],
92
+ },
93
+ "Indian Languages": {
94
+ Main: [
95
+ "Hindi",
96
+ "Bengali",
97
+ "Tamil",
98
+ "Telugu",
99
+ "Marathi",
100
+ "Gujarati",
101
+ "Kannada",
102
+ "Malayalam",
103
+ "Nepali",
104
+ "Urdu",
105
+ "Indic",
106
+ ],
107
+ },
108
+ "Middle Eastern & African": {
109
+ Main: [
110
+ "Arabic",
111
+ "Hebrew",
112
+ "Turkish",
113
+ "Persian",
114
+ "Darija",
115
+ "Swahili",
116
+ "Amharic",
117
+ "Hausa",
118
+ "Yoruba",
119
+ ],
120
+ },
121
+ "Other Languages": {
122
+ Main: [], // Pour les langues non listées
123
+ },
124
+ };
125
+
126
+ // Helper pour trouver la famille d'une langue
127
+ const findLanguageFamily = (language) => {
128
+ for (const [familyName, subFamilies] of Object.entries(LANGUAGE_FAMILIES)) {
129
+ for (const [subFamilyName, languages] of Object.entries(subFamilies)) {
130
+ if (languages.includes(language)) {
131
+ return { family: familyName, subFamily: subFamilyName };
132
+ }
133
+ }
134
+ }
135
+ // Si la langue n'est pas trouvée, on la met dans Other Languages
136
+ console.log(`Language not categorized: ${language}`);
137
+ return { family: "Other Languages", subFamily: "Main" };
138
+ };
139
+
140
  // Extraire la liste des langues si c'est la section Language Specific
 
141
  const languages = useMemo(() => {
142
  if (id !== "language") return null;
143
  const langSet = new Set();
144
+
145
+ // Compter toutes les langues uniques
146
  leaderboards.forEach((board) => {
147
  board.tags?.forEach((tag) => {
148
  if (tag.startsWith("language:")) {
 
153
  }
154
  });
155
  });
156
+
157
+ // Créer un tableau de paires [langue, nombre de leaderboards, famille]
158
+ const langArray = Array.from(langSet).map((lang) => {
159
+ const count = leaderboards.filter((board) =>
160
+ board.tags?.some(
161
+ (tag) => tag.toLowerCase() === `language:${lang.toLowerCase()}`
162
+ )
163
+ ).length;
164
+ const { family, subFamily } = findLanguageFamily(lang);
165
+ return [lang, count, family, subFamily];
166
+ });
167
+
168
+ // Trier d'abord par famille, puis par nombre de leaderboards
169
+ return langArray
170
+ .sort((a, b) => {
171
+ // Si les familles sont différentes
172
+ if (a[2] !== b[2]) {
173
+ if (a[2] === "Other Languages") return 1; // Other Languages toujours à la fin
174
+ if (b[2] === "Other Languages") return -1;
175
+ return a[2].localeCompare(b[2]);
176
+ }
177
+ // Si même famille, trier par nombre de leaderboards
178
+ return b[1] - a[1];
179
+ })
180
+ .map(([lang]) => lang);
181
  }, [id, leaderboards]);
182
 
183
  // Calculer le nombre de leaderboards par langue
 
314
  <Accordion
315
  defaultExpanded={false}
316
  elevation={0}
317
+ disableGutters
318
  sx={{
319
  mb: approvedLeaderboards.length > 0 ? 4 : 2,
320
  "&:before": {
 
324
  }}
325
  >
326
  <AccordionSummary
327
+ expandIcon={
328
+ <ExpandMoreIcon sx={{ fontSize: 20, color: "text.secondary" }} />
329
+ }
330
  sx={{
331
+ p: 0,
332
+ minHeight: 32,
333
+ height: 32,
334
+ "&.MuiAccordionSummary-root": {
335
+ "&.Mui-expanded": {
336
+ minHeight: 32,
337
+ height: 32,
338
+ },
339
  },
340
+ "& .MuiAccordionSummary-content": {
341
+ m: 0,
342
+ "&.Mui-expanded": {
343
+ m: 0,
344
+ },
345
  },
346
  }}
347
  >
348
+ <Typography
349
+ variant="body2"
350
+ color="text.secondary"
351
+ sx={{ fontWeight: 500 }}
352
+ >
353
+ Filter by language
354
+ </Typography>
 
 
355
  </AccordionSummary>
356
  <AccordionDetails sx={{ padding: 0 }}>
357
+ {/* Grouper les langues par famille */}
358
+ {Object.entries(LANGUAGE_FAMILIES).map(([family, subFamilies]) => {
359
+ const familyLanguages = languages.filter((lang) => {
360
+ const { family: langFamily } = findLanguageFamily(lang);
361
+ return langFamily === family;
362
+ });
363
+
364
+ // Ne pas retourner si pas de langues, SAUF pour Other Languages qui doit toujours être affiché
365
+ if (familyLanguages.length === 0 && family !== "Other Languages")
366
+ return null;
 
367
 
368
+ return (
369
+ <Box key={family} sx={{ mb: 3 }}>
370
+ <Typography
371
+ variant="subtitle2"
 
 
372
  sx={{
373
+ color: "text.secondary",
374
+ mb: 1,
375
+ fontWeight: 500,
376
+ opacity: 0.8,
377
+ }}
378
+ >
379
+ {family}{" "}
380
+ {familyLanguages.length > 0
381
+ ? `(${familyLanguages.length})`
382
+ : ""}
383
+ </Typography>
384
+ <Box
385
+ sx={{
386
+ display: "flex",
387
+ flexWrap: "wrap",
388
+ gap: 1,
389
+ mx: -0.5,
 
 
 
390
  }}
391
  >
392
+ {familyLanguages.map((lang) => {
393
+ const isActive = selectedLanguage === lang;
394
+ const count = languageStats?.get(lang) || 0;
395
+
396
+ return (
397
+ <Button
398
+ key={lang}
399
+ onClick={() =>
400
+ setSelectedLanguage(isActive ? null : lang)
401
+ }
402
+ variant={isActive ? "contained" : "outlined"}
403
+ size="small"
404
+ sx={{
405
+ textTransform: "none",
406
+ m: 0.125,
407
+ backgroundColor: (theme) =>
408
+ isActive
409
+ ? undefined
410
+ : theme.palette.mode === "dark"
411
+ ? "background.paper"
412
+ : "white",
413
+ "&:hover": {
414
+ backgroundColor: (theme) =>
415
+ isActive
416
+ ? undefined
417
+ : theme.palette.mode === "dark"
418
+ ? "background.paper"
419
+ : "white",
420
+ },
421
+ "& .MuiTouchRipple-root": {
422
+ transition: "none",
423
+ },
424
+ transition: "none",
425
+ }}
426
+ >
427
+ {lang}
428
+ <Box
429
+ component="span"
430
+ sx={{
431
+ display: "inline-flex",
432
+ alignItems: "center",
433
+ gap: 0.75,
434
+ color: isActive ? "inherit" : "text.secondary",
435
+ ml: 0.75,
436
+ }}
437
+ >
438
+ <Box
439
+ component="span"
440
+ sx={(theme) => ({
441
+ width: "4px",
442
+ height: "4px",
443
+ borderRadius: "100%",
444
+ backgroundColor: alpha(
445
+ theme.palette.text.primary,
446
+ theme.palette.mode === "dark" ? 0.2 : 0.15
447
+ ),
448
+ })}
449
+ />
450
+ {count}
451
+ </Box>
452
+ </Button>
453
+ );
454
+ })}
455
+ </Box>
456
+ </Box>
457
+ );
458
+ })}
459
  </AccordionDetails>
460
  </Accordion>
461
  )}