Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 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 | 1x 1x 1x 1x 1x 1x 1x 1x 1x 25x 25x 25x 25x 12x 12x 12x 12x 12x 12x 12x 12x 12x 12x 25x 25x 25x 25x 25x 25x 25x 25x 25x 25x 25x 25x 25x 25x 25x 25x 25x 25x 25x 25x 25x 25x 25x 25x 25x 25x 25x 25x 25x 25x 25x 25x 25x 25x 25x 25x 25x 25x 25x 25x 25x 25x 25x 25x 25x 25x 25x 25x 25x 25x 25x 25x | import { i18n } from '@/helpers/i18n';
import { ThemeContext } from '@/themes';
import Box from '@mui/material/Box';
import Modal from '@mui/material/Modal';
import Typography from '@mui/material/Typography';
import { useContext, useEffect, useState } from 'react';
/**
* Full-screen overlay shown whenever the browser reports it is offline. It
* listens for the `window` `offline`/`online` events and covers the whole UI
* with a "network connection issue" message that clears itself once the
* connection returns. The Chrome offline dino (theme-matched) sits across the
* bottom.
* @component
* @category Components
* @returns The offline overlay (renders nothing while online).
* @example
* ```tsx
* <ThemeProvider>
* <OfflineOverlay />
* <App />
* </ThemeProvider>
* ```
* @source
*/
export default function OfflineOverlay() {
const themeContext = useContext(ThemeContext);
const [offline, setOffline] = useState(
() => typeof navigator !== 'undefined' && !navigator.onLine,
);
useEffect(() => {
const handleOffline = () => setOffline(true);
const handleOnline = () => setOffline(false);
window.addEventListener('offline', handleOffline);
window.addEventListener('online', handleOnline);
// Reconcile in case connectivity changed between the initial render and mount.
setOffline(!navigator.onLine);
return () => {
window.removeEventListener('offline', handleOffline);
window.removeEventListener('online', handleOnline);
};
}, []);
const dinoSrc =
themeContext?.mode === 'dark'
? '/static/images/dino-dark-theme.png'
: '/static/images/dino-light-theme.png';
return (
<Modal
open={offline}
aria-labelledby="offline-overlay-title"
aria-describedby="offline-overlay-message"
>
<Box
sx={{
position: 'fixed',
inset: 0,
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
textAlign: 'center',
bgcolor: 'background.default',
color: 'text.primary',
p: 3,
outline: 'none',
}}
>
<Box
sx={{
flex: 1,
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
justifyContent: 'center',
gap: 1,
}}
>
<Typography id="offline-overlay-title" variant="h6" component="h2">
{i18n('offline_title')}
</Typography>
<Typography
id="offline-overlay-message"
variant="body2"
sx={{ maxWidth: 320, color: 'text.secondary' }}
>
{i18n('offline_message')}
</Typography>
</Box>
<Box
component="img"
data-testid="offline-dino"
src={dinoSrc}
alt=""
sx={{
width: '100%',
//maxWidth: 260,
height: 'auto',
imageRendering: 'pixelated',
mt: 'auto',
pb: 1,
}}
/>
</Box>
</Modal>
);
}
|