tfrere commited on
Commit
65829de
·
1 Parent(s): 5c2e213

update mobile view for submit vote and quote pages

Browse files
frontend/src/components/shared/AuthContainer.js CHANGED
@@ -7,6 +7,8 @@ import {
7
  Stack,
8
  Paper,
9
  CircularProgress,
 
 
10
  } from "@mui/material";
11
  import HFLogo from "../Logo/HFLogo";
12
  import { useAuth } from "../../hooks/useAuth";
@@ -16,6 +18,8 @@ import { useNavigate } from "react-router-dom";
16
  function AuthContainer({ actionText = "DO_ACTION" }) {
17
  const { isAuthenticated, user, login, logout, loading } = useAuth();
18
  const navigate = useNavigate();
 
 
19
 
20
  const handleLogout = () => {
21
  if (isAuthenticated && logout) {
@@ -63,7 +67,14 @@ function AuthContainer({ actionText = "DO_ACTION" }) {
63
  <Typography variant="h6" align="center">
64
  Login to {actionText}
65
  </Typography>
66
- <Typography variant="body2" color="text.secondary" align="center">
 
 
 
 
 
 
 
67
  You need to be logged in with your Hugging Face account to{" "}
68
  {actionText.toLowerCase()}
69
  </Typography>
@@ -87,6 +98,7 @@ function AuthContainer({ actionText = "DO_ACTION" }) {
87
  fontWeight: 600,
88
  py: 1,
89
  px: 2,
 
90
  }}
91
  >
92
  Sign in with Hugging Face
@@ -101,13 +113,22 @@ function AuthContainer({ actionText = "DO_ACTION" }) {
101
  sx={{ p: 2, border: "1px solid", borderColor: "grey.300", mb: 4 }}
102
  >
103
  <Stack
104
- direction="row"
105
  spacing={2}
106
- alignItems="center"
107
  justifyContent="space-between"
108
  >
109
- <Stack direction="row" spacing={1} alignItems="center">
110
- <Typography variant="body1">
 
 
 
 
 
 
 
 
 
111
  Connected as <strong>{user?.username}</strong>
112
  </Typography>
113
  <Chip
@@ -115,6 +136,13 @@ function AuthContainer({ actionText = "DO_ACTION" }) {
115
  color="success"
116
  size="small"
117
  variant="outlined"
 
 
 
 
 
 
 
118
  />
119
  </Stack>
120
  <Button
@@ -127,6 +155,7 @@ function AuthContainer({ actionText = "DO_ACTION" }) {
127
  height: 36,
128
  textTransform: "none",
129
  fontSize: "0.9375rem",
 
130
  }}
131
  >
132
  Logout
 
7
  Stack,
8
  Paper,
9
  CircularProgress,
10
+ useTheme,
11
+ useMediaQuery,
12
  } from "@mui/material";
13
  import HFLogo from "../Logo/HFLogo";
14
  import { useAuth } from "../../hooks/useAuth";
 
18
  function AuthContainer({ actionText = "DO_ACTION" }) {
19
  const { isAuthenticated, user, login, logout, loading } = useAuth();
20
  const navigate = useNavigate();
21
+ const theme = useTheme();
22
+ const isMobile = useMediaQuery(theme.breakpoints.down("sm"));
23
 
24
  const handleLogout = () => {
25
  if (isAuthenticated && logout) {
 
67
  <Typography variant="h6" align="center">
68
  Login to {actionText}
69
  </Typography>
70
+ <Typography
71
+ variant="body2"
72
+ color="text.secondary"
73
+ align="center"
74
+ sx={{
75
+ px: isMobile ? 2 : 0,
76
+ }}
77
+ >
78
  You need to be logged in with your Hugging Face account to{" "}
79
  {actionText.toLowerCase()}
80
  </Typography>
 
98
  fontWeight: 600,
99
  py: 1,
100
  px: 2,
101
+ width: isMobile ? "100%" : "auto",
102
  }}
103
  >
104
  Sign in with Hugging Face
 
113
  sx={{ p: 2, border: "1px solid", borderColor: "grey.300", mb: 4 }}
114
  >
115
  <Stack
116
+ direction={isMobile ? "column" : "row"}
117
  spacing={2}
118
+ alignItems={isMobile ? "stretch" : "center"}
119
  justifyContent="space-between"
120
  >
121
+ <Stack
122
+ direction={isMobile ? "column" : "row"}
123
+ spacing={1}
124
+ alignItems={isMobile ? "stretch" : "center"}
125
+ sx={{ width: "100%" }}
126
+ >
127
+ <Typography
128
+ variant="body1"
129
+ align={isMobile ? "center" : "left"}
130
+ sx={{ mb: isMobile ? 1 : 0 }}
131
+ >
132
  Connected as <strong>{user?.username}</strong>
133
  </Typography>
134
  <Chip
 
136
  color="success"
137
  size="small"
138
  variant="outlined"
139
+ sx={{
140
+ width: isMobile ? "100%" : "auto",
141
+ height: isMobile ? 32 : 24,
142
+ "& .MuiChip-label": {
143
+ px: isMobile ? 2 : 1,
144
+ },
145
+ }}
146
  />
147
  </Stack>
148
  <Button
 
155
  height: 36,
156
  textTransform: "none",
157
  fontSize: "0.9375rem",
158
+ width: isMobile ? "100%" : "auto",
159
  }}
160
  >
161
  Logout
frontend/src/pages/AddModelPage/components/EvaluationQueues/EvaluationQueues.js CHANGED
@@ -17,6 +17,8 @@ import {
17
  AccordionDetails,
18
  Stack,
19
  Tooltip,
 
 
20
  } from "@mui/material";
21
  import AccessTimeIcon from "@mui/icons-material/AccessTime";
22
  import CheckCircleIcon from "@mui/icons-material/CheckCircle";
@@ -359,90 +361,133 @@ const QueueAccordion = ({
359
  expanded,
360
  onChange,
361
  loading,
362
- }) => (
363
- <Accordion
364
- expanded={expanded}
365
- onChange={onChange}
366
- disabled={loading}
367
- sx={{
368
- "&:before": { display: "none" },
369
- boxShadow: "none",
370
- border: "none",
371
- }}
372
- >
373
- <AccordionSummary expandIcon={<ExpandMoreIcon />}>
374
- <Stack direction="row" spacing={2} alignItems="center">
375
- <Typography>{title}</Typography>
376
- <Stack direction="row" spacing={1} alignItems="center">
377
- <Chip
378
- label={models.length}
379
- size="small"
380
- color={
381
- status === "finished"
382
- ? "success"
383
- : status === "evaluating"
384
- ? "warning"
385
- : "info"
386
- }
387
- variant="outlined"
388
- sx={(theme) => ({
389
- borderWidth: 2,
390
- fontWeight: 600,
391
- bgcolor:
392
- status === "finished"
393
- ? theme.palette.success[100]
394
- : status === "evaluating"
395
- ? theme.palette.warning[100]
396
- : theme.palette.info[100],
397
- borderColor:
398
- status === "finished"
399
- ? theme.palette.success[400]
400
- : status === "evaluating"
401
- ? theme.palette.warning[400]
402
- : theme.palette.info[400],
403
- color:
 
 
 
 
 
 
 
 
 
 
 
404
  status === "finished"
405
- ? theme.palette.success[700]
406
  : status === "evaluating"
407
- ? theme.palette.warning[700]
408
- : theme.palette.info[700],
409
- "& .MuiChip-label": {
410
- px: 1.2,
411
- },
412
- "&:hover": {
 
 
 
 
413
  bgcolor:
414
  status === "finished"
415
- ? theme.palette.success[200]
416
  : status === "evaluating"
417
- ? theme.palette.warning[200]
418
- : theme.palette.info[200],
419
- },
420
- })}
421
- />
422
- {loading && (
423
- <CircularProgress size={16} color="inherit" sx={{ opacity: 0.5 }} />
424
- )}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
425
  </Stack>
426
- </Stack>
427
- </AccordionSummary>
428
- <AccordionDetails sx={{ p: 2 }}>
429
- <Box
430
- sx={{
431
- border: "1px solid",
432
- borderColor: "grey.200",
433
- borderRadius: 1,
434
- overflow: "hidden",
435
- }}
436
- >
437
- <ModelTable
438
- models={models}
439
- emptyMessage={emptyMessage}
440
- status={status}
441
- />
442
- </Box>
443
- </AccordionDetails>
444
- </Accordion>
445
- );
446
 
447
  const EvaluationQueues = ({ defaultExpanded = true }) => {
448
  const [expanded, setExpanded] = useState(defaultExpanded);
@@ -454,6 +499,8 @@ const EvaluationQueues = ({ defaultExpanded = true }) => {
454
  });
455
  const [loading, setLoading] = useState(true);
456
  const [error, setError] = useState(null);
 
 
457
 
458
  useEffect(() => {
459
  const fetchModels = async () => {
@@ -534,11 +581,12 @@ const EvaluationQueues = ({ defaultExpanded = true }) => {
534
  opacity: 0.9,
535
  },
536
  "& .MuiAccordionSummary-root": {
537
- minHeight: 64,
538
  bgcolor: "background.paper",
539
  borderRadius: "8px",
 
540
  "&.Mui-expanded": {
541
- minHeight: 64,
542
  borderRadius: "8px 8px 0 0",
543
  },
544
  },
@@ -553,52 +601,74 @@ const EvaluationQueues = ({ defaultExpanded = true }) => {
553
  <AccordionSummary
554
  expandIcon={<ExpandMoreIcon />}
555
  sx={{
556
- px: 3,
557
  "& .MuiAccordionSummary-expandIconWrapper": {
558
  color: "text.secondary",
559
  transform: "rotate(0deg)",
560
  transition: "transform 150ms",
 
561
  "&.Mui-expanded": {
562
  transform: "rotate(180deg)",
563
  },
564
  },
565
  }}
566
  >
567
- <Stack direction="row" spacing={2} alignItems="center">
 
 
 
 
 
568
  <Typography
569
  variant="h6"
570
  sx={{
571
  fontWeight: 600,
572
  color: "text.primary",
573
  letterSpacing: "-0.01em",
 
574
  }}
575
  >
576
  Evaluation Status
577
  </Typography>
578
  {!loading && (
579
  <Stack
580
- direction="row"
581
  spacing={1}
582
  sx={{
583
  transition: "opacity 0.2s",
584
  ".Mui-expanded &": {
585
  opacity: 0,
 
 
 
 
 
 
 
 
 
586
  },
587
  }}
588
  >
589
  <Chip
590
  label={`${models.pending.length} In Queue`}
591
- size="small"
592
  color="info"
593
  variant="outlined"
594
  sx={{
595
  borderWidth: 2,
596
  fontWeight: 600,
 
 
597
  bgcolor: "info.100",
598
  borderColor: "info.400",
599
  color: "info.700",
 
600
  "& .MuiChip-label": {
601
- px: 1.2,
 
 
 
602
  },
603
  "&:hover": {
604
  bgcolor: "info.200",
@@ -607,17 +677,23 @@ const EvaluationQueues = ({ defaultExpanded = true }) => {
607
  />
608
  <Chip
609
  label={`${models.evaluating.length} Evaluating`}
610
- size="small"
611
  color="warning"
612
  variant="outlined"
613
  sx={{
614
  borderWidth: 2,
615
  fontWeight: 600,
 
 
616
  bgcolor: "warning.100",
617
  borderColor: "warning.400",
618
  color: "warning.700",
 
619
  "& .MuiChip-label": {
620
- px: 1.2,
 
 
 
621
  },
622
  "&:hover": {
623
  bgcolor: "warning.200",
@@ -626,17 +702,23 @@ const EvaluationQueues = ({ defaultExpanded = true }) => {
626
  />
627
  <Chip
628
  label={`${models.finished.length} Evaluated`}
629
- size="small"
630
  color="success"
631
  variant="outlined"
632
  sx={{
633
  borderWidth: 2,
634
  fontWeight: 600,
 
 
635
  bgcolor: "success.100",
636
  borderColor: "success.400",
637
  color: "success.700",
 
638
  "& .MuiChip-label": {
639
- px: 1.2,
 
 
 
640
  },
641
  "&:hover": {
642
  bgcolor: "success.200",
@@ -647,7 +729,7 @@ const EvaluationQueues = ({ defaultExpanded = true }) => {
647
  )}
648
  {loading && (
649
  <CircularProgress
650
- size={20}
651
  sx={{
652
  color: "primary.main",
653
  }}
 
17
  AccordionDetails,
18
  Stack,
19
  Tooltip,
20
+ useTheme,
21
+ useMediaQuery,
22
  } from "@mui/material";
23
  import AccessTimeIcon from "@mui/icons-material/AccessTime";
24
  import CheckCircleIcon from "@mui/icons-material/CheckCircle";
 
361
  expanded,
362
  onChange,
363
  loading,
364
+ }) => {
365
+ const theme = useTheme();
366
+ const isMobile = useMediaQuery(theme.breakpoints.down("sm"));
367
+
368
+ return (
369
+ <Accordion
370
+ expanded={expanded}
371
+ onChange={onChange}
372
+ disabled={loading}
373
+ sx={{
374
+ "&:before": { display: "none" },
375
+ boxShadow: "none",
376
+ border: "none",
377
+ }}
378
+ >
379
+ <AccordionSummary
380
+ expandIcon={<ExpandMoreIcon />}
381
+ sx={{
382
+ px: { xs: 2, sm: 3 },
383
+ py: { xs: 1.5, sm: 2 },
384
+ alignItems: { xs: "flex-start", sm: "center" },
385
+ "& .MuiAccordionSummary-expandIconWrapper": {
386
+ marginTop: { xs: "4px", sm: 0 },
387
+ },
388
+ }}
389
+ >
390
+ <Stack
391
+ direction={{ xs: "column", sm: "row" }}
392
+ spacing={{ xs: 1, sm: 2 }}
393
+ alignItems={{ xs: "flex-start", sm: "center" }}
394
+ sx={{ width: "100%" }}
395
+ >
396
+ <Typography
397
+ sx={{
398
+ fontSize: { xs: "0.95rem", sm: "1rem" },
399
+ fontWeight: 500,
400
+ }}
401
+ >
402
+ {title}
403
+ </Typography>
404
+ <Stack
405
+ direction={{ xs: "column", sm: "row" }}
406
+ spacing={1}
407
+ alignItems={{ xs: "stretch", sm: "center" }}
408
+ sx={{
409
+ ml: { xs: 0, sm: "auto" },
410
+ width: { xs: "100%", sm: "auto" },
411
+ }}
412
+ >
413
+ <Chip
414
+ label={models.length}
415
+ size={isMobile ? "small" : "medium"}
416
+ color={
417
  status === "finished"
418
+ ? "success"
419
  : status === "evaluating"
420
+ ? "warning"
421
+ : "info"
422
+ }
423
+ variant="outlined"
424
+ sx={(theme) => ({
425
+ borderWidth: 2,
426
+ fontWeight: 600,
427
+ fontSize: { xs: "0.75rem", sm: "0.875rem" },
428
+ height: { xs: "24px", sm: "32px" },
429
+ width: { xs: "100%", sm: "auto" },
430
  bgcolor:
431
  status === "finished"
432
+ ? theme.palette.success[100]
433
  : status === "evaluating"
434
+ ? theme.palette.warning[100]
435
+ : theme.palette.info[100],
436
+ borderColor:
437
+ status === "finished"
438
+ ? theme.palette.success[400]
439
+ : status === "evaluating"
440
+ ? theme.palette.warning[400]
441
+ : theme.palette.info[400],
442
+ color:
443
+ status === "finished"
444
+ ? theme.palette.success[700]
445
+ : status === "evaluating"
446
+ ? theme.palette.warning[700]
447
+ : theme.palette.info[700],
448
+ "& .MuiChip-label": {
449
+ px: { xs: 1, sm: 1.2 },
450
+ width: "100%",
451
+ },
452
+ "&:hover": {
453
+ bgcolor:
454
+ status === "finished"
455
+ ? theme.palette.success[200]
456
+ : status === "evaluating"
457
+ ? theme.palette.warning[200]
458
+ : theme.palette.info[200],
459
+ },
460
+ })}
461
+ />
462
+ {loading && (
463
+ <CircularProgress
464
+ size={isMobile ? 14 : 16}
465
+ color="inherit"
466
+ sx={{ opacity: 0.5 }}
467
+ />
468
+ )}
469
+ </Stack>
470
  </Stack>
471
+ </AccordionSummary>
472
+ <AccordionDetails sx={{ p: { xs: 1, sm: 2 } }}>
473
+ <Box
474
+ sx={{
475
+ border: "1px solid",
476
+ borderColor: "grey.200",
477
+ borderRadius: 1,
478
+ overflow: "hidden",
479
+ }}
480
+ >
481
+ <ModelTable
482
+ models={models}
483
+ emptyMessage={emptyMessage}
484
+ status={status}
485
+ />
486
+ </Box>
487
+ </AccordionDetails>
488
+ </Accordion>
489
+ );
490
+ };
491
 
492
  const EvaluationQueues = ({ defaultExpanded = true }) => {
493
  const [expanded, setExpanded] = useState(defaultExpanded);
 
499
  });
500
  const [loading, setLoading] = useState(true);
501
  const [error, setError] = useState(null);
502
+ const theme = useTheme();
503
+ const isMobile = useMediaQuery(theme.breakpoints.down("sm"));
504
 
505
  useEffect(() => {
506
  const fetchModels = async () => {
 
581
  opacity: 0.9,
582
  },
583
  "& .MuiAccordionSummary-root": {
584
+ minHeight: { xs: 56, sm: 64 },
585
  bgcolor: "background.paper",
586
  borderRadius: "8px",
587
+ alignItems: { xs: "flex-start", sm: "center" },
588
  "&.Mui-expanded": {
589
+ minHeight: { xs: 56, sm: 64 },
590
  borderRadius: "8px 8px 0 0",
591
  },
592
  },
 
601
  <AccordionSummary
602
  expandIcon={<ExpandMoreIcon />}
603
  sx={{
604
+ px: { xs: 2, sm: 3 },
605
  "& .MuiAccordionSummary-expandIconWrapper": {
606
  color: "text.secondary",
607
  transform: "rotate(0deg)",
608
  transition: "transform 150ms",
609
+ marginTop: { xs: "4px", sm: 0 },
610
  "&.Mui-expanded": {
611
  transform: "rotate(180deg)",
612
  },
613
  },
614
  }}
615
  >
616
+ <Stack
617
+ direction={{ xs: "column", sm: "row" }}
618
+ spacing={{ xs: 1, sm: 2 }}
619
+ alignItems={{ xs: "flex-start", sm: "center" }}
620
+ sx={{ width: "100%" }}
621
+ >
622
  <Typography
623
  variant="h6"
624
  sx={{
625
  fontWeight: 600,
626
  color: "text.primary",
627
  letterSpacing: "-0.01em",
628
+ fontSize: { xs: "1.1rem", sm: "1.25rem" },
629
  }}
630
  >
631
  Evaluation Status
632
  </Typography>
633
  {!loading && (
634
  <Stack
635
+ direction={{ xs: "column", sm: "row" }}
636
  spacing={1}
637
  sx={{
638
  transition: "opacity 0.2s",
639
  ".Mui-expanded &": {
640
  opacity: 0,
641
+ height: 0,
642
+ m: 0,
643
+ overflow: "hidden",
644
+ },
645
+ width: { xs: "100%", sm: "auto" },
646
+ alignItems: { xs: "stretch", sm: "center" },
647
+ mb: { xs: 1, sm: 0 },
648
+ ".Mui-expanded &": {
649
+ mb: 0,
650
  },
651
  }}
652
  >
653
  <Chip
654
  label={`${models.pending.length} In Queue`}
655
+ size={isMobile ? "small" : "medium"}
656
  color="info"
657
  variant="outlined"
658
  sx={{
659
  borderWidth: 2,
660
  fontWeight: 600,
661
+ fontSize: { xs: "0.75rem", sm: "0.875rem" },
662
+ height: { xs: "24px", sm: "32px" },
663
  bgcolor: "info.100",
664
  borderColor: "info.400",
665
  color: "info.700",
666
+ width: { xs: "100%", sm: "auto" },
667
  "& .MuiChip-label": {
668
+ px: { xs: 1, sm: 1.2 },
669
+ width: "100%",
670
+ display: "flex",
671
+ justifyContent: "center",
672
  },
673
  "&:hover": {
674
  bgcolor: "info.200",
 
677
  />
678
  <Chip
679
  label={`${models.evaluating.length} Evaluating`}
680
+ size={isMobile ? "small" : "medium"}
681
  color="warning"
682
  variant="outlined"
683
  sx={{
684
  borderWidth: 2,
685
  fontWeight: 600,
686
+ fontSize: { xs: "0.75rem", sm: "0.875rem" },
687
+ height: { xs: "24px", sm: "32px" },
688
  bgcolor: "warning.100",
689
  borderColor: "warning.400",
690
  color: "warning.700",
691
+ width: { xs: "100%", sm: "auto" },
692
  "& .MuiChip-label": {
693
+ px: { xs: 1, sm: 1.2 },
694
+ width: "100%",
695
+ display: "flex",
696
+ justifyContent: "center",
697
  },
698
  "&:hover": {
699
  bgcolor: "warning.200",
 
702
  />
703
  <Chip
704
  label={`${models.finished.length} Evaluated`}
705
+ size={isMobile ? "small" : "medium"}
706
  color="success"
707
  variant="outlined"
708
  sx={{
709
  borderWidth: 2,
710
  fontWeight: 600,
711
+ fontSize: { xs: "0.75rem", sm: "0.875rem" },
712
+ height: { xs: "24px", sm: "32px" },
713
  bgcolor: "success.100",
714
  borderColor: "success.400",
715
  color: "success.700",
716
+ width: { xs: "100%", sm: "auto" },
717
  "& .MuiChip-label": {
718
+ px: { xs: 1, sm: 1.2 },
719
+ width: "100%",
720
+ display: "flex",
721
+ justifyContent: "center",
722
  },
723
  "&:hover": {
724
  bgcolor: "success.200",
 
729
  )}
730
  {loading && (
731
  <CircularProgress
732
+ size={isMobile ? 18 : 20}
733
  sx={{
734
  color: "primary.main",
735
  }}
frontend/src/pages/VoteModelPage/VoteModelPage.js CHANGED
@@ -13,6 +13,8 @@ import {
13
  IconButton,
14
  Stack,
15
  Link,
 
 
16
  } from "@mui/material";
17
  import AccessTimeIcon from "@mui/icons-material/AccessTime";
18
  import PersonIcon from "@mui/icons-material/Person";
@@ -75,6 +77,8 @@ function VoteModelPage() {
75
  const [error, setError] = useState(null);
76
  const [userVotes, setUserVotes] = useState(new Set());
77
  const [loadingVotes, setLoadingVotes] = useState({});
 
 
78
 
79
  // Create a unique identifier for a model
80
  const getModelUniqueId = (model) => {
@@ -447,7 +451,7 @@ function VoteModelPage() {
447
  borderBottom: "1px solid",
448
  borderColor: "divider",
449
  bgcolor: "background.paper",
450
- display: "grid",
451
  gridTemplateColumns: "1fr 200px 160px",
452
  gap: 3,
453
  alignItems: "center",
@@ -498,9 +502,9 @@ function VoteModelPage() {
498
  py: 2.5,
499
  px: 3,
500
  display: "grid",
501
- gridTemplateColumns: "1fr 200px 160px",
502
- gap: 3,
503
- alignItems: "center",
504
  position: "relative",
505
  "&:hover": {
506
  bgcolor: "action.hover",
@@ -511,7 +515,11 @@ function VoteModelPage() {
511
  <Box>
512
  <Stack spacing={1}>
513
  {/* Model name and link */}
514
- <Stack direction="row" spacing={1} alignItems="center">
 
 
 
 
515
  <Stack
516
  direction="row"
517
  spacing={1}
@@ -529,6 +537,8 @@ function VoteModelPage() {
529
  "&:hover": {
530
  textDecoration: "underline",
531
  },
 
 
532
  }}
533
  >
534
  {model.name}
@@ -550,7 +560,19 @@ function VoteModelPage() {
550
  <OpenInNewIcon sx={{ fontSize: "1rem" }} />
551
  </IconButton>
552
  </Stack>
553
- <Stack direction="row" spacing={1}>
 
 
 
 
 
 
 
 
 
 
 
 
554
  <Chip
555
  label={model.precision}
556
  size="small"
@@ -582,7 +604,11 @@ function VoteModelPage() {
582
  </Stack>
583
  </Stack>
584
  {/* Metadata row */}
585
- <Stack direction="row" spacing={2} alignItems="center">
 
 
 
 
586
  <Stack
587
  direction="row"
588
  spacing={0.5}
@@ -618,17 +644,22 @@ function VoteModelPage() {
618
  </Box>
619
 
620
  {/* Vote Column */}
621
- <Box sx={{ textAlign: "right" }}>
 
 
 
 
 
622
  <Stack
623
- direction="row"
624
  spacing={2.5}
625
- justifyContent="flex-end"
626
  alignItems="center"
627
  >
628
  <Stack
629
- alignItems="center"
630
  sx={{
631
- minWidth: "90px",
632
  }}
633
  >
634
  <Typography
@@ -637,7 +668,7 @@ function VoteModelPage() {
637
  sx={{
638
  fontWeight: 700,
639
  lineHeight: 1,
640
- fontSize: "2rem",
641
  display: "flex",
642
  alignItems: "center",
643
  justifyContent: "center",
@@ -646,7 +677,7 @@ function VoteModelPage() {
646
  <Typography
647
  component="span"
648
  sx={{
649
- fontSize: "1.5rem",
650
  fontWeight: 600,
651
  color: "primary.main",
652
  lineHeight: 1,
@@ -686,7 +717,7 @@ function VoteModelPage() {
686
  </Stack>
687
  <Button
688
  variant={model.hasVoted ? "contained" : "outlined"}
689
- size="large"
690
  onClick={() => handleVote(model)}
691
  disabled={
692
  !isAuthenticated ||
@@ -695,11 +726,11 @@ function VoteModelPage() {
695
  }
696
  color="primary"
697
  sx={{
698
- minWidth: "100px",
699
- height: "40px",
700
  textTransform: "none",
701
  fontWeight: 600,
702
- fontSize: "0.95rem",
703
  ...(model.hasVoted
704
  ? {
705
  bgcolor: "primary.main",
@@ -721,7 +752,7 @@ function VoteModelPage() {
721
  }}
722
  >
723
  {loadingVotes[getModelUniqueId(model)] ? (
724
- <CircularProgress size={24} color="inherit" />
725
  ) : model.hasVoted ? (
726
  <Stack
727
  direction="row"
@@ -739,7 +770,13 @@ function VoteModelPage() {
739
  </Box>
740
 
741
  {/* Priority Column */}
742
- <Box sx={{ textAlign: "right" }}>
 
 
 
 
 
 
743
  <Chip
744
  label={
745
  <Stack
 
13
  IconButton,
14
  Stack,
15
  Link,
16
+ useTheme,
17
+ useMediaQuery,
18
  } from "@mui/material";
19
  import AccessTimeIcon from "@mui/icons-material/AccessTime";
20
  import PersonIcon from "@mui/icons-material/Person";
 
77
  const [error, setError] = useState(null);
78
  const [userVotes, setUserVotes] = useState(new Set());
79
  const [loadingVotes, setLoadingVotes] = useState({});
80
+ const theme = useTheme();
81
+ const isMobile = useMediaQuery(theme.breakpoints.down("sm"));
82
 
83
  // Create a unique identifier for a model
84
  const getModelUniqueId = (model) => {
 
451
  borderBottom: "1px solid",
452
  borderColor: "divider",
453
  bgcolor: "background.paper",
454
+ display: { xs: "none", sm: "grid" },
455
  gridTemplateColumns: "1fr 200px 160px",
456
  gap: 3,
457
  alignItems: "center",
 
502
  py: 2.5,
503
  px: 3,
504
  display: "grid",
505
+ gridTemplateColumns: { xs: "1fr", sm: "1fr 200px 160px" },
506
+ gap: { xs: 2, sm: 3 },
507
+ alignItems: "start",
508
  position: "relative",
509
  "&:hover": {
510
  bgcolor: "action.hover",
 
515
  <Box>
516
  <Stack spacing={1}>
517
  {/* Model name and link */}
518
+ <Stack
519
+ direction={{ xs: "column", sm: "row" }}
520
+ spacing={1}
521
+ alignItems={{ xs: "stretch", sm: "center" }}
522
+ >
523
  <Stack
524
  direction="row"
525
  spacing={1}
 
537
  "&:hover": {
538
  textDecoration: "underline",
539
  },
540
+ fontSize: { xs: "0.9rem", sm: "inherit" },
541
+ wordBreak: "break-word",
542
  }}
543
  >
544
  {model.name}
 
560
  <OpenInNewIcon sx={{ fontSize: "1rem" }} />
561
  </IconButton>
562
  </Stack>
563
+ <Stack
564
+ direction="row"
565
+ spacing={1}
566
+ sx={{
567
+ width: { xs: "100%", sm: "auto" },
568
+ justifyContent: {
569
+ xs: "flex-start",
570
+ sm: "flex-end",
571
+ },
572
+ flexWrap: "wrap",
573
+ gap: 1,
574
+ }}
575
+ >
576
  <Chip
577
  label={model.precision}
578
  size="small"
 
604
  </Stack>
605
  </Stack>
606
  {/* Metadata row */}
607
+ <Stack
608
+ direction={{ xs: "column", sm: "row" }}
609
+ spacing={{ xs: 1, sm: 2 }}
610
+ alignItems={{ xs: "flex-start", sm: "center" }}
611
+ >
612
  <Stack
613
  direction="row"
614
  spacing={0.5}
 
644
  </Box>
645
 
646
  {/* Vote Column */}
647
+ <Box
648
+ sx={{
649
+ textAlign: { xs: "left", sm: "right" },
650
+ mt: { xs: 2, sm: 0 },
651
+ }}
652
+ >
653
  <Stack
654
+ direction={{ xs: "row", sm: "row" }}
655
  spacing={2.5}
656
+ justifyContent={{ xs: "space-between", sm: "flex-end" }}
657
  alignItems="center"
658
  >
659
  <Stack
660
+ alignItems={{ xs: "flex-start", sm: "center" }}
661
  sx={{
662
+ minWidth: { xs: "auto", sm: "90px" },
663
  }}
664
  >
665
  <Typography
 
668
  sx={{
669
  fontWeight: 700,
670
  lineHeight: 1,
671
+ fontSize: { xs: "1.75rem", sm: "2rem" },
672
  display: "flex",
673
  alignItems: "center",
674
  justifyContent: "center",
 
677
  <Typography
678
  component="span"
679
  sx={{
680
+ fontSize: { xs: "1.25rem", sm: "1.5rem" },
681
  fontWeight: 600,
682
  color: "primary.main",
683
  lineHeight: 1,
 
717
  </Stack>
718
  <Button
719
  variant={model.hasVoted ? "contained" : "outlined"}
720
+ size={isMobile ? "medium" : "large"}
721
  onClick={() => handleVote(model)}
722
  disabled={
723
  !isAuthenticated ||
 
726
  }
727
  color="primary"
728
  sx={{
729
+ minWidth: { xs: "80px", sm: "100px" },
730
+ height: { xs: "36px", sm: "40px" },
731
  textTransform: "none",
732
  fontWeight: 600,
733
+ fontSize: { xs: "0.875rem", sm: "0.95rem" },
734
  ...(model.hasVoted
735
  ? {
736
  bgcolor: "primary.main",
 
752
  }}
753
  >
754
  {loadingVotes[getModelUniqueId(model)] ? (
755
+ <CircularProgress size={20} color="inherit" />
756
  ) : model.hasVoted ? (
757
  <Stack
758
  direction="row"
 
770
  </Box>
771
 
772
  {/* Priority Column */}
773
+ <Box
774
+ sx={{
775
+ textAlign: { xs: "left", sm: "right" },
776
+ mt: { xs: 2, sm: 0 },
777
+ display: { xs: "none", sm: "block" },
778
+ }}
779
+ >
780
  <Chip
781
  label={
782
  <Stack