Spaces:
Running
Running
File size: 4,090 Bytes
c8a88af 61eecf2 5c85958 279ae3b 5c85958 800eea1 61eecf2 800eea1 c8a88af 800eea1 e409b8e 800eea1 e409b8e 9eab2cc e409b8e 3a6d7d7 9eab2cc 3a6d7d7 9eab2cc 3a6d7d7 e409b8e c8a88af 5c85958 279ae3b 800eea1 279ae3b 61eecf2 279ae3b 800eea1 279ae3b 5c85958 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 | import { useEffect } from 'react';
import { BrowserRouter, Routes, Route, Navigate, useLocation, useNavigate } from 'react-router-dom';
import { ThemeProvider, CssBaseline } from '@mui/material';
import theme from './theme/theme';
import { AppsProvider } from './context/AppsContext';
import { AuthProvider } from './context/AuthContext';
import Home from './pages/Home';
import Download from './pages/Download';
import FAQ from './pages/FAQ';
import Apps from './pages/Apps';
import Buy from './pages/Buy';
import GettingStarted from './pages/GettingStarted';
import Build from './pages/Build';
/**
* Handle hash-to-path redirect for HuggingFace Spaces iframe embedding.
*
* HF propagates the parent page's hash to the iframe on initial load.
* For example, visiting huggingface.co/reachy-mini#/apps will load the
* iframe at *.hf.space/#/apps. This component reads that hash and
* converts it to a BrowserRouter path (e.g. /apps).
*/
function HashRedirect() {
const navigate = useNavigate();
useEffect(() => {
const hash = window.location.hash;
// Match hash routes like #/apps, #/download, #apps, #download, etc.
if (hash && hash.length > 1) {
// Support both #/apps and #apps formats
const path = hash.startsWith('#/') ? hash.slice(1) : `/${hash.slice(1)}`;
// Use replaceState to cleanly remove hash without triggering navigation
window.history.replaceState(null, '', window.location.pathname);
navigate(path, { replace: true });
}
}, [navigate]);
return null;
}
/**
* Sync the current route back to the HF parent page via postMessage.
* This updates the URL in the browser address bar so users can
* copy/share deep links (e.g. huggingface.co/reachy-mini#/apps).
*
* Also handles scrollTo query parameter for anchor-like behavior.
*/
function RouteSync() {
const location = useLocation();
useEffect(() => {
// Sync current path to parent frame hash (for HF Spaces embedding)
const isInIframe = window.parent !== window;
if (isInIframe && location.pathname !== '/') {
window.parent.postMessage(
{ hash: `#${location.pathname}` },
'https://huggingface.co'
);
} else if (isInIframe && location.pathname === '/') {
// Clear hash when on home page
window.parent.postMessage({ hash: '' }, 'https://huggingface.co');
}
// Handle scrollTo query parameter
const params = new URLSearchParams(location.search);
const scrollTo = params.get('scrollTo');
if (scrollTo) {
// Retry mechanism to wait for element to be rendered
const scrollToElement = (retries = 0) => {
const element = document.getElementById(scrollTo);
if (element) {
element.scrollIntoView({ behavior: 'smooth', block: 'center' });
} else if (retries < 10) {
setTimeout(() => scrollToElement(retries + 1), 100);
}
};
setTimeout(() => scrollToElement(), 300);
} else {
window.scrollTo({ top: 0, behavior: 'smooth' });
}
}, [location.pathname, location.search]);
return null;
}
export default function App() {
return (
<ThemeProvider theme={theme}>
<CssBaseline />
<AuthProvider>
<AppsProvider>
<BrowserRouter>
<HashRedirect />
<RouteSync />
<Routes>
<Route path="/" element={<Home />} />
<Route path="/getting-started" element={<GettingStarted />} />
<Route path="https://huggingface.co/docs/reachy_mini/" element={<Build />} />
<Route path="/download" element={<Download />} />
<Route path="https://huggingface.co/docs/reachy_mini/troubleshooting" element={<FAQ />} />
<Route path="/apps" element={<Apps />} />
<Route path="/buy" element={<Buy />} />
{/* Catch-all: redirect unknown routes to home */}
<Route path="*" element={<Navigate to="/" replace />} />
</Routes>
</BrowserRouter>
</AppsProvider>
</AuthProvider>
</ThemeProvider>
);
}
|