tfrere HF Staff commited on
Commit
5e00009
·
1 Parent(s): 84ac2bd

feat: add release notes section to download page

Browse files

- Fetch releases from GitHub API
- Display last 3 releases with expandable view
- Parse markdown headers and lists

Files changed (1) hide show
  1. src/pages/Download.jsx +149 -6
src/pages/Download.jsx CHANGED
@@ -15,6 +15,8 @@ import DownloadIcon from '@mui/icons-material/Download';
15
  import AppleIcon from '@mui/icons-material/Apple';
16
  import CheckCircleIcon from '@mui/icons-material/CheckCircle';
17
  import OpenInNewIcon from '@mui/icons-material/OpenInNew';
 
 
18
 
19
  import Layout from '../components/Layout';
20
 
@@ -56,6 +58,7 @@ const PLATFORMS = {
56
 
57
  // URL to fetch latest release info (using GitHub API for CORS support)
58
  const GITHUB_RELEASES_API = 'https://api.github.com/repos/pollen-robotics/reachy-mini-desktop-app/releases/latest';
 
59
 
60
 
61
  // Detect user's platform
@@ -194,8 +197,10 @@ function PlatformCard({ platformKey, url, isActive, onClick }) {
194
 
195
  export default function Download() {
196
  const [releaseData, setReleaseData] = useState(null);
 
197
  const [detectedPlatform, setDetectedPlatform] = useState(null);
198
  const [loading, setLoading] = useState(true);
 
199
 
200
  const [error, setError] = useState(null);
201
 
@@ -203,11 +208,16 @@ export default function Download() {
203
  setDetectedPlatform(detectPlatform());
204
 
205
  // Fetch latest release info from GitHub API
206
- async function fetchLatestRelease() {
207
  try {
208
- const response = await fetch(GITHUB_RELEASES_API);
209
- if (response.ok) {
210
- const data = await response.json();
 
 
 
 
 
211
 
212
  // Transform GitHub API response to our format
213
  const version = data.tag_name?.replace('v', '') || '';
@@ -251,6 +261,12 @@ export default function Download() {
251
  } else {
252
  setError('Failed to fetch release info');
253
  }
 
 
 
 
 
 
254
  } catch (err) {
255
  console.error('Error fetching release:', err);
256
  setError('Failed to fetch release info');
@@ -259,7 +275,7 @@ export default function Download() {
259
  }
260
  }
261
 
262
- fetchLatestRelease();
263
  }, []);
264
 
265
  if (loading) {
@@ -543,7 +559,7 @@ export default function Download() {
543
  </Box>
544
 
545
  {/* Requirements */}
546
- <Box sx={{ textAlign: 'center' }}>
547
  <Typography
548
  variant="body2"
549
  sx={{ color: 'rgba(255,255,255,0.4)', mb: 2 }}
@@ -565,6 +581,133 @@ export default function Download() {
565
  View all releases on GitHub
566
  </Button>
567
  </Box>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
568
  </Container>
569
  </Box>
570
  </Layout>
 
15
  import AppleIcon from '@mui/icons-material/Apple';
16
  import CheckCircleIcon from '@mui/icons-material/CheckCircle';
17
  import OpenInNewIcon from '@mui/icons-material/OpenInNew';
18
+ import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
19
+ import ExpandLessIcon from '@mui/icons-material/ExpandLess';
20
 
21
  import Layout from '../components/Layout';
22
 
 
58
 
59
  // URL to fetch latest release info (using GitHub API for CORS support)
60
  const GITHUB_RELEASES_API = 'https://api.github.com/repos/pollen-robotics/reachy-mini-desktop-app/releases/latest';
61
+ const GITHUB_RELEASES_LIST_API = 'https://api.github.com/repos/pollen-robotics/reachy-mini-desktop-app/releases?per_page=10';
62
 
63
 
64
  // Detect user's platform
 
197
 
198
  export default function Download() {
199
  const [releaseData, setReleaseData] = useState(null);
200
+ const [allReleases, setAllReleases] = useState([]);
201
  const [detectedPlatform, setDetectedPlatform] = useState(null);
202
  const [loading, setLoading] = useState(true);
203
+ const [showAllReleases, setShowAllReleases] = useState(false);
204
 
205
  const [error, setError] = useState(null);
206
 
 
208
  setDetectedPlatform(detectPlatform());
209
 
210
  // Fetch latest release info from GitHub API
211
+ async function fetchReleases() {
212
  try {
213
+ // Fetch latest release for download buttons
214
+ const latestResponse = await fetch(GITHUB_RELEASES_API);
215
+
216
+ // Fetch all releases for changelog
217
+ const allResponse = await fetch(GITHUB_RELEASES_LIST_API);
218
+
219
+ if (latestResponse.ok) {
220
+ const data = await latestResponse.json();
221
 
222
  // Transform GitHub API response to our format
223
  const version = data.tag_name?.replace('v', '') || '';
 
261
  } else {
262
  setError('Failed to fetch release info');
263
  }
264
+
265
+ // Set all releases for changelog
266
+ if (allResponse.ok) {
267
+ const releases = await allResponse.json();
268
+ setAllReleases(releases.filter(r => !r.draft));
269
+ }
270
  } catch (err) {
271
  console.error('Error fetching release:', err);
272
  setError('Failed to fetch release info');
 
275
  }
276
  }
277
 
278
+ fetchReleases();
279
  }, []);
280
 
281
  if (loading) {
 
559
  </Box>
560
 
561
  {/* Requirements */}
562
+ <Box sx={{ textAlign: 'center', mb: 8 }}>
563
  <Typography
564
  variant="body2"
565
  sx={{ color: 'rgba(255,255,255,0.4)', mb: 2 }}
 
581
  View all releases on GitHub
582
  </Button>
583
  </Box>
584
+
585
+ {/* Release Notes */}
586
+ {allReleases.length > 0 && (
587
+ <Box
588
+ sx={{
589
+ background: 'rgba(255, 255, 255, 0.02)',
590
+ border: '1px solid rgba(255, 255, 255, 0.06)',
591
+ borderRadius: 4,
592
+ p: 4,
593
+ }}
594
+ >
595
+ <Typography
596
+ variant="h6"
597
+ sx={{ mb: 3, color: 'white', fontWeight: 600 }}
598
+ >
599
+ Release Notes
600
+ </Typography>
601
+
602
+ <Stack spacing={3}>
603
+ {(showAllReleases ? allReleases : allReleases.slice(0, 3)).map((release) => (
604
+ <Box
605
+ key={release.id}
606
+ sx={{
607
+ borderLeft: '2px solid rgba(255, 149, 0, 0.4)',
608
+ pl: 3,
609
+ py: 1,
610
+ }}
611
+ >
612
+ <Stack direction="row" spacing={2} alignItems="center" sx={{ mb: 1 }}>
613
+ <Typography
614
+ variant="subtitle1"
615
+ sx={{ color: 'white', fontWeight: 600 }}
616
+ >
617
+ {release.name || release.tag_name}
618
+ </Typography>
619
+ <Chip
620
+ label={formatDate(release.published_at)}
621
+ size="small"
622
+ sx={{
623
+ backgroundColor: 'rgba(255, 255, 255, 0.05)',
624
+ color: 'rgba(255,255,255,0.5)',
625
+ fontSize: 11,
626
+ height: 22,
627
+ }}
628
+ />
629
+ {release.prerelease && (
630
+ <Chip
631
+ label="Pre-release"
632
+ size="small"
633
+ sx={{
634
+ backgroundColor: 'rgba(255, 149, 0, 0.15)',
635
+ color: '#FF9500',
636
+ fontSize: 11,
637
+ height: 22,
638
+ }}
639
+ />
640
+ )}
641
+ </Stack>
642
+
643
+ {release.body ? (
644
+ <Typography
645
+ variant="body2"
646
+ sx={{
647
+ color: 'rgba(255,255,255,0.6)',
648
+ whiteSpace: 'pre-line',
649
+ lineHeight: 1.7,
650
+ '& strong, & b': { color: 'rgba(255,255,255,0.8)' },
651
+ }}
652
+ >
653
+ {release.body.split('\n').map((line, i) => {
654
+ // Simple markdown parsing for headers and lists
655
+ if (line.startsWith('### ')) {
656
+ return (
657
+ <Box
658
+ key={i}
659
+ component="span"
660
+ sx={{
661
+ display: 'block',
662
+ fontWeight: 600,
663
+ color: 'rgba(255,255,255,0.8)',
664
+ mt: i > 0 ? 1.5 : 0,
665
+ mb: 0.5,
666
+ }}
667
+ >
668
+ {line.replace('### ', '')}
669
+ </Box>
670
+ );
671
+ }
672
+ if (line.startsWith('- ')) {
673
+ return (
674
+ <Box key={i} component="span" sx={{ display: 'block', pl: 2 }}>
675
+ • {line.replace('- ', '')}
676
+ </Box>
677
+ );
678
+ }
679
+ if (line.trim() === '') return null;
680
+ return <Box key={i} component="span" sx={{ display: 'block' }}>{line}</Box>;
681
+ })}
682
+ </Typography>
683
+ ) : (
684
+ <Typography
685
+ variant="body2"
686
+ sx={{ color: 'rgba(255,255,255,0.4)', fontStyle: 'italic' }}
687
+ >
688
+ No release notes available
689
+ </Typography>
690
+ )}
691
+ </Box>
692
+ ))}
693
+ </Stack>
694
+
695
+ {allReleases.length > 3 && (
696
+ <Button
697
+ variant="text"
698
+ onClick={() => setShowAllReleases(!showAllReleases)}
699
+ endIcon={showAllReleases ? <ExpandLessIcon /> : <ExpandMoreIcon />}
700
+ sx={{
701
+ mt: 3,
702
+ color: 'rgba(255,255,255,0.5)',
703
+ '&:hover': { color: 'white' },
704
+ }}
705
+ >
706
+ {showAllReleases ? 'Show less' : `Show ${allReleases.length - 3} more releases`}
707
+ </Button>
708
+ )}
709
+ </Box>
710
+ )}
711
  </Container>
712
  </Box>
713
  </Layout>