tfrere HF Staff commited on
Commit
0286a05
·
1 Parent(s): 3dd9c75

fix: show desktop-only notice on mobile and prevent .sig file downloads

Browse files

- Replace download buttons with a "desktop only" message on mobile devices
- Fix parseReleasePlatforms to skip .sig signature files entirely
- Use endsWith('.deb') instead of includes('amd64.deb') for Linux assets
- Add mobile detection to both Download and GettingStarted pages

Made-with: Cursor

Files changed (2) hide show
  1. src/pages/Download.jsx +122 -79
  2. src/pages/GettingStarted.jsx +91 -36
src/pages/Download.jsx CHANGED
@@ -18,6 +18,7 @@ import CheckCircleIcon from '@mui/icons-material/CheckCircle';
18
  import OpenInNewIcon from '@mui/icons-material/OpenInNew';
19
  import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
20
  import ExpandLessIcon from '@mui/icons-material/ExpandLess';
 
21
 
22
  import Layout from '../components/Layout';
23
 
@@ -65,6 +66,11 @@ function detectPlatform() {
65
  return 'darwin-aarch64';
66
  }
67
 
 
 
 
 
 
68
  // Format date
69
  function formatDate(dateString) {
70
  const date = new Date(dateString);
@@ -174,6 +180,9 @@ function parseReleasePlatforms(assets) {
174
  const name = asset.name.toLowerCase();
175
  const url = asset.browser_download_url;
176
 
 
 
 
177
  // macOS Apple Silicon - prefer .dmg
178
  if (name.includes('arm64.dmg')) {
179
  platforms['darwin-aarch64'] = { url };
@@ -181,13 +190,13 @@ function parseReleasePlatforms(assets) {
181
  platforms['darwin-aarch64'] = { url };
182
  }
183
 
184
- // Windows - .msi (exclude .sig signature files)
185
  if (name.endsWith('.msi')) {
186
  platforms['windows-x86_64'] = { url };
187
  }
188
 
189
  // Linux - .deb
190
- if (name.includes('amd64.deb')) {
191
  platforms['linux-x86_64'] = { url };
192
  }
193
  });
@@ -312,11 +321,13 @@ export default function Download() {
312
  const [detectedPlatform, setDetectedPlatform] = useState(null);
313
  const [loading, setLoading] = useState(true);
314
  const [showAllReleases, setShowAllReleases] = useState(false);
 
315
 
316
  const [error, setError] = useState(null);
317
 
318
  useEffect(() => {
319
  setDetectedPlatform(detectPlatform());
 
320
 
321
  // Fetch latest release info from GitHub API
322
  async function fetchReleases() {
@@ -521,67 +532,97 @@ export default function Download() {
521
  </Typography>
522
  </Stack>
523
 
524
- {/* Primary download button */}
525
- <Button
526
- variant="contained"
527
- size="large"
528
- href={currentUrl}
529
- startIcon={<DownloadIcon />}
530
- sx={{
531
- px: 6,
532
- py: 2,
533
- fontSize: 17,
534
- fontWeight: 600,
535
- borderRadius: 3,
536
- background: 'linear-gradient(135deg, #FF9500 0%, #764ba2 100%)',
537
- boxShadow: '0 8px 32px rgba(255, 149, 0, 0.35)',
538
- transition: 'all 0.3s ease',
539
- '&:hover': {
540
- boxShadow: '0 12px 48px rgba(59, 130, 246, 0.5)',
541
- transform: 'translateY(-2px)',
542
- },
543
- }}
544
- >
545
- Download for {currentPlatform?.name}
546
- </Button>
547
-
548
- <Typography
549
- variant="body2"
550
- sx={{
551
- color: 'rgba(255,255,255,0.4)',
552
- mt: 2,
553
- fontSize: 13,
554
- }}
555
- >
556
- {currentPlatform?.subtitle} • {currentPlatform?.format?.replace('.', '').toUpperCase()} package
557
- </Typography>
558
-
559
- {/* Beta Warning for Windows and Linux */}
560
- {(detectedPlatform?.startsWith('windows') || detectedPlatform?.includes('linux')) && (
561
  <Box
562
  sx={{
563
- mt: 3,
564
- p: 2.5,
565
- background: 'linear-gradient(135deg, rgba(59, 130, 246, 0.1) 0%, rgba(139, 92, 246, 0.08) 100%)',
566
- border: '1px solid rgba(59, 130, 246, 0.3)',
567
- borderRadius: 2,
568
  maxWidth: 500,
569
  mx: 'auto',
570
  }}
571
  >
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
572
  <Typography
573
  variant="body2"
574
  sx={{
575
- color: 'rgba(255,255,255,0.8)',
576
- fontWeight: 500,
 
577
  }}
578
  >
579
- {detectedPlatform?.startsWith('windows')
580
- ? <>⚠️ Windows version is currently in Beta — installation requires <strong style={{ color: 'rgba(255,255,255,0.9)' }}>administrator privileges</strong>.</>
581
- : <>⚠️ Linux version is currently in Beta — please report any issues on <a href="https://github.com/pollen-robotics/reachy-mini-desktop-app/issues" target="_blank" rel="noopener noreferrer" style={{ color: '#3b82f6', textDecoration: 'underline' }}>GitHub</a> or <a href="https://discord.gg/HDrGY9eJHt" target="_blank" rel="noopener noreferrer" style={{ color: '#3b82f6', textDecoration: 'underline' }}>Discord</a>.</>
582
- }
583
  </Typography>
584
- </Box>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
585
  )}
586
 
587
  {/* App screenshot */}
@@ -600,35 +641,37 @@ export default function Download() {
600
  />
601
  </Box>
602
 
603
- {/* All platforms */}
604
- <Box sx={{ mb: 8 }}>
605
- <Typography
606
- variant="overline"
607
- sx={{
608
- color: 'rgba(255,255,255,0.4)',
609
- display: 'block',
610
- textAlign: 'center',
611
- mb: 3,
612
- letterSpacing: 2,
613
- }}
614
- >
615
- Available for all platforms
616
- </Typography>
 
617
 
618
- <Grid container spacing={2}>
619
- {['darwin-aarch64', 'windows-x86_64', 'linux-x86_64'].map((key) => (
620
- <Grid size={{ xs: 12, sm: 4 }} key={key}>
621
- <PlatformCard
622
- platformKey={key}
623
- url={releaseData?.platforms[key]?.url}
624
- isActive={key === detectedPlatform}
625
- onClick={() => setDetectedPlatform(key)}
626
- />
627
- </Grid>
628
- ))}
629
- </Grid>
630
-
631
- </Box>
 
632
 
633
  {/* Features / What's included */}
634
  <Box
 
18
  import OpenInNewIcon from '@mui/icons-material/OpenInNew';
19
  import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
20
  import ExpandLessIcon from '@mui/icons-material/ExpandLess';
21
+ import DesktopWindowsIcon from '@mui/icons-material/DesktopWindows';
22
 
23
  import Layout from '../components/Layout';
24
 
 
66
  return 'darwin-aarch64';
67
  }
68
 
69
+ function isMobileDevice() {
70
+ const ua = navigator.userAgent;
71
+ return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(ua);
72
+ }
73
+
74
  // Format date
75
  function formatDate(dateString) {
76
  const date = new Date(dateString);
 
180
  const name = asset.name.toLowerCase();
181
  const url = asset.browser_download_url;
182
 
183
+ // Skip signature files entirely
184
+ if (name.endsWith('.sig')) return;
185
+
186
  // macOS Apple Silicon - prefer .dmg
187
  if (name.includes('arm64.dmg')) {
188
  platforms['darwin-aarch64'] = { url };
 
190
  platforms['darwin-aarch64'] = { url };
191
  }
192
 
193
+ // Windows - .msi
194
  if (name.endsWith('.msi')) {
195
  platforms['windows-x86_64'] = { url };
196
  }
197
 
198
  // Linux - .deb
199
+ if (name.endsWith('.deb')) {
200
  platforms['linux-x86_64'] = { url };
201
  }
202
  });
 
321
  const [detectedPlatform, setDetectedPlatform] = useState(null);
322
  const [loading, setLoading] = useState(true);
323
  const [showAllReleases, setShowAllReleases] = useState(false);
324
+ const [isMobile, setIsMobile] = useState(false);
325
 
326
  const [error, setError] = useState(null);
327
 
328
  useEffect(() => {
329
  setDetectedPlatform(detectPlatform());
330
+ setIsMobile(isMobileDevice());
331
 
332
  // Fetch latest release info from GitHub API
333
  async function fetchReleases() {
 
532
  </Typography>
533
  </Stack>
534
 
535
+ {/* Primary download button or mobile notice */}
536
+ {isMobile ? (
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
537
  <Box
538
  sx={{
539
+ mt: 2,
540
+ p: 3,
541
+ background: 'linear-gradient(135deg, rgba(255, 149, 0, 0.1) 0%, rgba(139, 92, 246, 0.08) 100%)',
542
+ border: '1px solid rgba(255, 149, 0, 0.3)',
543
+ borderRadius: 3,
544
  maxWidth: 500,
545
  mx: 'auto',
546
  }}
547
  >
548
+ <DesktopWindowsIcon sx={{ fontSize: 40, color: 'rgba(255,255,255,0.5)', mb: 1.5 }} />
549
+ <Typography
550
+ variant="body1"
551
+ sx={{ color: 'rgba(255,255,255,0.9)', fontWeight: 600, mb: 1 }}
552
+ >
553
+ Desktop only
554
+ </Typography>
555
+ <Typography
556
+ variant="body2"
557
+ sx={{ color: 'rgba(255,255,255,0.6)' }}
558
+ >
559
+ Reachy Mini Control is a desktop application available for macOS, Windows, and Linux. Please visit this page from a computer to download it.
560
+ </Typography>
561
+ </Box>
562
+ ) : (
563
+ <>
564
+ <Button
565
+ variant="contained"
566
+ size="large"
567
+ href={currentUrl}
568
+ startIcon={<DownloadIcon />}
569
+ sx={{
570
+ px: 6,
571
+ py: 2,
572
+ fontSize: 17,
573
+ fontWeight: 600,
574
+ borderRadius: 3,
575
+ background: 'linear-gradient(135deg, #FF9500 0%, #764ba2 100%)',
576
+ boxShadow: '0 8px 32px rgba(255, 149, 0, 0.35)',
577
+ transition: 'all 0.3s ease',
578
+ '&:hover': {
579
+ boxShadow: '0 12px 48px rgba(59, 130, 246, 0.5)',
580
+ transform: 'translateY(-2px)',
581
+ },
582
+ }}
583
+ >
584
+ Download for {currentPlatform?.name}
585
+ </Button>
586
+
587
  <Typography
588
  variant="body2"
589
  sx={{
590
+ color: 'rgba(255,255,255,0.4)',
591
+ mt: 2,
592
+ fontSize: 13,
593
  }}
594
  >
595
+ {currentPlatform?.subtitle} • {currentPlatform?.format?.replace('.', '').toUpperCase()} package
 
 
 
596
  </Typography>
597
+
598
+ {/* Beta Warning for Windows and Linux */}
599
+ {(detectedPlatform?.startsWith('windows') || detectedPlatform?.includes('linux')) && (
600
+ <Box
601
+ sx={{
602
+ mt: 3,
603
+ p: 2.5,
604
+ background: 'linear-gradient(135deg, rgba(59, 130, 246, 0.1) 0%, rgba(139, 92, 246, 0.08) 100%)',
605
+ border: '1px solid rgba(59, 130, 246, 0.3)',
606
+ borderRadius: 2,
607
+ maxWidth: 500,
608
+ mx: 'auto',
609
+ }}
610
+ >
611
+ <Typography
612
+ variant="body2"
613
+ sx={{
614
+ color: 'rgba(255,255,255,0.8)',
615
+ fontWeight: 500,
616
+ }}
617
+ >
618
+ {detectedPlatform?.startsWith('windows')
619
+ ? <>⚠️ Windows version is currently in Beta - installation requires <strong style={{ color: 'rgba(255,255,255,0.9)' }}>administrator privileges</strong>.</>
620
+ : <>⚠️ Linux version is currently in Beta - please report any issues on <a href="https://github.com/pollen-robotics/reachy-mini-desktop-app/issues" target="_blank" rel="noopener noreferrer" style={{ color: '#3b82f6', textDecoration: 'underline' }}>GitHub</a> or <a href="https://discord.gg/HDrGY9eJHt" target="_blank" rel="noopener noreferrer" style={{ color: '#3b82f6', textDecoration: 'underline' }}>Discord</a>.</>
621
+ }
622
+ </Typography>
623
+ </Box>
624
+ )}
625
+ </>
626
  )}
627
 
628
  {/* App screenshot */}
 
641
  />
642
  </Box>
643
 
644
+ {/* All platforms - hidden on mobile */}
645
+ {!isMobile && (
646
+ <Box sx={{ mb: 8 }}>
647
+ <Typography
648
+ variant="overline"
649
+ sx={{
650
+ color: 'rgba(255,255,255,0.4)',
651
+ display: 'block',
652
+ textAlign: 'center',
653
+ mb: 3,
654
+ letterSpacing: 2,
655
+ }}
656
+ >
657
+ Available for all platforms
658
+ </Typography>
659
 
660
+ <Grid container spacing={2}>
661
+ {['darwin-aarch64', 'windows-x86_64', 'linux-x86_64'].map((key) => (
662
+ <Grid size={{ xs: 12, sm: 4 }} key={key}>
663
+ <PlatformCard
664
+ platformKey={key}
665
+ url={releaseData?.platforms[key]?.url}
666
+ isActive={key === detectedPlatform}
667
+ onClick={() => setDetectedPlatform(key)}
668
+ />
669
+ </Grid>
670
+ ))}
671
+ </Grid>
672
+
673
+ </Box>
674
+ )}
675
 
676
  {/* Features / What's included */}
677
  <Box
src/pages/GettingStarted.jsx CHANGED
@@ -1,4 +1,4 @@
1
- import { useState } from 'react';
2
  import { Link as RouterLink, useLocation } from 'react-router-dom';
3
  import {
4
  Box,
@@ -18,6 +18,7 @@ import {
18
  } from '@mui/material';
19
  import OpenInNewIcon from '@mui/icons-material/OpenInNew';
20
  import DownloadIcon from '@mui/icons-material/Download';
 
21
  import WifiIcon from '@mui/icons-material/Wifi';
22
  import UsbIcon from '@mui/icons-material/Usb';
23
  import CheckCircleIcon from '@mui/icons-material/CheckCircle';
@@ -141,6 +142,11 @@ function YouTubeEmbed({ videoId, title, version = 'wireless' }) {
141
  );
142
  }
143
 
 
 
 
 
 
144
  export default function GettingStarted() {
145
  const location = useLocation();
146
  const params = new URLSearchParams(location.search);
@@ -148,6 +154,11 @@ export default function GettingStarted() {
148
  const [version, setVersion] = useState(
149
  urlVersion === 'lite' ? 'lite' : 'wireless'
150
  );
 
 
 
 
 
151
 
152
  return (
153
  <Layout transparentHeader>
@@ -328,23 +339,45 @@ export default function GettingStarted() {
328
  <Typography variant="caption" sx={{ display: 'block', mb: 2, color: 'warning.main' }}>
329
  Desktop App available for macOS (Apple Silicon), Windows & Linux (beta).
330
  </Typography>
331
- <Button
332
- variant="contained"
333
- component={RouterLink}
334
- to="/download"
335
- startIcon={<DownloadIcon/>}
336
- >
337
- Download Desktop App
338
- </Button>
339
-
340
- <Button
341
- variant="outlined"
342
- href="https://huggingface.co/docs/reachy_mini/SDK/installation"
343
- target="_blank"
344
- startIcon={<OpenInNewIcon/>}
345
- >
346
- Alternative: Python SDK
347
- </Button>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
348
 
349
  </StepContent>
350
  </Step>
@@ -400,7 +433,7 @@ export default function GettingStarted() {
400
 
401
  <Typography variant="body1" color="text.secondary" sx={{ mb: 4, maxWidth: 600, mx: 'auto' }}>
402
  Follow our visual guide to put together your Reachy Mini.
403
- Most people finish in <strong>2-3 hours</strong> our record is 43 minutes! 🏆
404
  </Typography>
405
 
406
  <Box
@@ -479,23 +512,45 @@ export default function GettingStarted() {
479
  <Typography variant="caption" sx={{ display: 'block', mb: 2, color: 'warning.main' }}>
480
  Desktop App available for macOS (Apple Silicon), Windows & Linux (beta).
481
  </Typography>
482
- <Button
483
- variant="contained"
484
- component={RouterLink}
485
- to="/download"
486
- startIcon={<DownloadIcon/>}
487
- >
488
- Download Desktop App
489
- </Button>
490
-
491
- <Button
492
- variant="outlined"
493
- href="https://huggingface.co/docs/reachy_mini/SDK/installation"
494
- target="_blank"
495
- startIcon={<OpenInNewIcon/>}
496
- >
497
- Alternative: Python SDK
498
- </Button>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
499
  </StepContent>
500
  </Step>
501
  <Step active completed={false}>
 
1
+ import { useState, useEffect } from 'react';
2
  import { Link as RouterLink, useLocation } from 'react-router-dom';
3
  import {
4
  Box,
 
18
  } from '@mui/material';
19
  import OpenInNewIcon from '@mui/icons-material/OpenInNew';
20
  import DownloadIcon from '@mui/icons-material/Download';
21
+ import DesktopWindowsIcon from '@mui/icons-material/DesktopWindows';
22
  import WifiIcon from '@mui/icons-material/Wifi';
23
  import UsbIcon from '@mui/icons-material/Usb';
24
  import CheckCircleIcon from '@mui/icons-material/CheckCircle';
 
142
  );
143
  }
144
 
145
+ function isMobileDevice() {
146
+ const ua = navigator.userAgent;
147
+ return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(ua);
148
+ }
149
+
150
  export default function GettingStarted() {
151
  const location = useLocation();
152
  const params = new URLSearchParams(location.search);
 
154
  const [version, setVersion] = useState(
155
  urlVersion === 'lite' ? 'lite' : 'wireless'
156
  );
157
+ const [isMobile, setIsMobile] = useState(false);
158
+
159
+ useEffect(() => {
160
+ setIsMobile(isMobileDevice());
161
+ }, []);
162
 
163
  return (
164
  <Layout transparentHeader>
 
339
  <Typography variant="caption" sx={{ display: 'block', mb: 2, color: 'warning.main' }}>
340
  Desktop App available for macOS (Apple Silicon), Windows & Linux (beta).
341
  </Typography>
342
+ {isMobile ? (
343
+ <Box
344
+ sx={{
345
+ p: 2,
346
+ bgcolor: 'action.hover',
347
+ borderRadius: 2,
348
+ border: '1px solid',
349
+ borderColor: 'divider',
350
+ display: 'flex',
351
+ alignItems: 'center',
352
+ gap: 1.5,
353
+ }}
354
+ >
355
+ <DesktopWindowsIcon sx={{ color: 'text.secondary', fontSize: 20 }} />
356
+ <Typography variant="body2" color="text.secondary">
357
+ The desktop app can only be downloaded from a computer.
358
+ </Typography>
359
+ </Box>
360
+ ) : (
361
+ <>
362
+ <Button
363
+ variant="contained"
364
+ component={RouterLink}
365
+ to="/download"
366
+ startIcon={<DownloadIcon/>}
367
+ >
368
+ Download Desktop App
369
+ </Button>
370
+
371
+ <Button
372
+ variant="outlined"
373
+ href="https://huggingface.co/docs/reachy_mini/SDK/installation"
374
+ target="_blank"
375
+ startIcon={<OpenInNewIcon/>}
376
+ >
377
+ Alternative: Python SDK
378
+ </Button>
379
+ </>
380
+ )}
381
 
382
  </StepContent>
383
  </Step>
 
433
 
434
  <Typography variant="body1" color="text.secondary" sx={{ mb: 4, maxWidth: 600, mx: 'auto' }}>
435
  Follow our visual guide to put together your Reachy Mini.
436
+ Most people finish in <strong>2-3 hours</strong> - our record is 43 minutes! 🏆
437
  </Typography>
438
 
439
  <Box
 
512
  <Typography variant="caption" sx={{ display: 'block', mb: 2, color: 'warning.main' }}>
513
  Desktop App available for macOS (Apple Silicon), Windows & Linux (beta).
514
  </Typography>
515
+ {isMobile ? (
516
+ <Box
517
+ sx={{
518
+ p: 2,
519
+ bgcolor: 'action.hover',
520
+ borderRadius: 2,
521
+ border: '1px solid',
522
+ borderColor: 'divider',
523
+ display: 'flex',
524
+ alignItems: 'center',
525
+ gap: 1.5,
526
+ }}
527
+ >
528
+ <DesktopWindowsIcon sx={{ color: 'text.secondary', fontSize: 20 }} />
529
+ <Typography variant="body2" color="text.secondary">
530
+ The desktop app can only be downloaded from a computer.
531
+ </Typography>
532
+ </Box>
533
+ ) : (
534
+ <>
535
+ <Button
536
+ variant="contained"
537
+ component={RouterLink}
538
+ to="/download"
539
+ startIcon={<DownloadIcon/>}
540
+ >
541
+ Download Desktop App
542
+ </Button>
543
+
544
+ <Button
545
+ variant="outlined"
546
+ href="https://huggingface.co/docs/reachy_mini/SDK/installation"
547
+ target="_blank"
548
+ startIcon={<OpenInNewIcon/>}
549
+ >
550
+ Alternative: Python SDK
551
+ </Button>
552
+ </>
553
+ )}
554
  </StepContent>
555
  </Step>
556
  <Step active completed={false}>