forked from Rosetta/landing
Фикс ошибок
This commit is contained in:
@@ -13,6 +13,7 @@ server {
|
||||
}
|
||||
|
||||
location / {
|
||||
add_header Cache-Control "no-cache" always;
|
||||
try_files $uri $uri/ /index.html;
|
||||
}
|
||||
}
|
||||
|
||||
73
src/App.tsx
73
src/App.tsx
@@ -1,7 +1,7 @@
|
||||
import '@mantine/core/styles.css';
|
||||
|
||||
import { Center, createTheme, Loader, MantineProvider } from '@mantine/core';
|
||||
import { lazy, Suspense } from 'react';
|
||||
import { Button, Center, createTheme, Loader, MantineProvider, Stack, Text, Title } from '@mantine/core';
|
||||
import { Component, lazy, Suspense, type ReactNode } from 'react';
|
||||
import { Route, Routes } from 'react-router-dom';
|
||||
import { ScrollToTop } from './components/ScrollToTop/ScrollToTop';
|
||||
import './style.css';
|
||||
@@ -39,27 +39,60 @@ const theme = createTheme({
|
||||
},
|
||||
});
|
||||
|
||||
class PageErrorBoundary extends Component<
|
||||
{ children: ReactNode },
|
||||
{ hasError: boolean }
|
||||
> {
|
||||
state = { hasError: false };
|
||||
|
||||
static getDerivedStateFromError() {
|
||||
return { hasError: true };
|
||||
}
|
||||
|
||||
render() {
|
||||
if (this.state.hasError) {
|
||||
return (
|
||||
<Center mih="100vh" p="xl">
|
||||
<Stack align="center" gap="md" maw={460}>
|
||||
<Title order={2} ta="center">
|
||||
This page could not be loaded
|
||||
</Title>
|
||||
<Text c="dimmed" ta="center">
|
||||
Rosetta may have been updated while this tab was open. Reload the page to continue.
|
||||
</Text>
|
||||
<Button onClick={() => window.location.reload()}>Reload page</Button>
|
||||
</Stack>
|
||||
</Center>
|
||||
);
|
||||
}
|
||||
|
||||
return this.props.children;
|
||||
}
|
||||
}
|
||||
|
||||
export default function App() {
|
||||
return (
|
||||
<MantineProvider theme={theme}>
|
||||
<ScrollToTop />
|
||||
<Suspense
|
||||
fallback={
|
||||
<Center mih="100vh">
|
||||
<Loader aria-label="Loading page" />
|
||||
</Center>
|
||||
}
|
||||
>
|
||||
<Routes>
|
||||
<Route path="/" element={<LandingPage />} />
|
||||
<Route path="/encryption" element={<EncryptionPage />} />
|
||||
<Route path="/proto" element={<ProtoPage />} />
|
||||
<Route path="/proto/docs" element={<ProtoDocsPage />} />
|
||||
<Route path="/support" element={<SupportPage />} />
|
||||
<Route path="/privacy" element={<PrivacyPage />} />
|
||||
<Route path="/terms" element={<TermsPage />} />
|
||||
</Routes>
|
||||
</Suspense>
|
||||
<PageErrorBoundary>
|
||||
<ScrollToTop />
|
||||
<Suspense
|
||||
fallback={
|
||||
<Center mih="100vh">
|
||||
<Loader aria-label="Loading page" />
|
||||
</Center>
|
||||
}
|
||||
>
|
||||
<Routes>
|
||||
<Route path="/" element={<LandingPage />} />
|
||||
<Route path="/encryption" element={<EncryptionPage />} />
|
||||
<Route path="/proto" element={<ProtoPage />} />
|
||||
<Route path="/proto/docs" element={<ProtoDocsPage />} />
|
||||
<Route path="/support" element={<SupportPage />} />
|
||||
<Route path="/privacy" element={<PrivacyPage />} />
|
||||
<Route path="/terms" element={<TermsPage />} />
|
||||
</Routes>
|
||||
</Suspense>
|
||||
</PageErrorBoundary>
|
||||
</MantineProvider>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,18 +1,22 @@
|
||||
.page {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-width: 0;
|
||||
min-height: 100vh;
|
||||
background: light-dark(var(--mantine-color-gray-0), var(--mantine-color-dark-9));
|
||||
}
|
||||
|
||||
.shell {
|
||||
flex: 1;
|
||||
width: 100%;
|
||||
min-width: 0;
|
||||
padding-top: 72px;
|
||||
padding-bottom: 96px;
|
||||
}
|
||||
|
||||
.main {
|
||||
width: 100%;
|
||||
min-width: 0;
|
||||
max-width: 900px;
|
||||
margin-inline: auto;
|
||||
padding: clamp(30px, 5vw, 60px);
|
||||
@@ -21,6 +25,7 @@
|
||||
}
|
||||
|
||||
.intro {
|
||||
min-width: 0;
|
||||
max-width: 760px;
|
||||
padding-bottom: 36px;
|
||||
border-bottom: 1px solid light-dark(var(--mantine-color-gray-2), var(--mantine-color-dark-5));
|
||||
@@ -69,6 +74,7 @@
|
||||
}
|
||||
|
||||
.section {
|
||||
min-width: 0;
|
||||
margin-top: 44px;
|
||||
padding-top: 36px;
|
||||
border-top: 1px solid light-dark(var(--mantine-color-gray-2), var(--mantine-color-dark-5));
|
||||
|
||||
36
src/main.tsx
36
src/main.tsx
@@ -2,6 +2,42 @@ import { createRoot } from 'react-dom/client'
|
||||
import { BrowserRouter } from 'react-router-dom'
|
||||
import App from './App.tsx'
|
||||
|
||||
const PRELOAD_RELOAD_KEY = 'rosetta:preload-reload-at'
|
||||
const PRELOAD_RELOAD_COOLDOWN = 10_000
|
||||
|
||||
if (import.meta.env.PROD) {
|
||||
window.addEventListener('vite:preloadError', (event) => {
|
||||
let lastReload = 0
|
||||
|
||||
try {
|
||||
lastReload = Number(window.sessionStorage.getItem(PRELOAD_RELOAD_KEY) || 0)
|
||||
} catch {
|
||||
// Storage can be unavailable in restricted browser modes.
|
||||
}
|
||||
|
||||
if (Date.now() - lastReload < PRELOAD_RELOAD_COOLDOWN) {
|
||||
return
|
||||
}
|
||||
|
||||
event.preventDefault()
|
||||
|
||||
try {
|
||||
window.sessionStorage.setItem(PRELOAD_RELOAD_KEY, String(Date.now()))
|
||||
} catch {
|
||||
// Reload recovery still works when storage is unavailable.
|
||||
}
|
||||
|
||||
window.location.reload()
|
||||
})
|
||||
|
||||
window.setTimeout(() => {
|
||||
try {
|
||||
window.sessionStorage.removeItem(PRELOAD_RELOAD_KEY)
|
||||
} catch {
|
||||
// Nothing to clear when storage is unavailable.
|
||||
}
|
||||
}, PRELOAD_RELOAD_COOLDOWN)
|
||||
}
|
||||
|
||||
createRoot(document.getElementById('root')!).render(
|
||||
<BrowserRouter>
|
||||
|
||||
@@ -1,3 +1,18 @@
|
||||
function withFreshHtml(response) {
|
||||
if (!response.headers.get('content-type')?.includes('text/html')) {
|
||||
return response;
|
||||
}
|
||||
|
||||
const headers = new Headers(response.headers);
|
||||
headers.set('Cache-Control', 'no-cache');
|
||||
|
||||
return new Response(response.body, {
|
||||
status: response.status,
|
||||
statusText: response.statusText,
|
||||
headers,
|
||||
});
|
||||
}
|
||||
|
||||
const worker = {
|
||||
async fetch(request, env) {
|
||||
const response = await env.ASSETS.fetch(request);
|
||||
@@ -7,11 +22,12 @@ const worker = {
|
||||
request.method !== 'GET' ||
|
||||
!request.headers.get('accept')?.includes('text/html')
|
||||
) {
|
||||
return response;
|
||||
return withFreshHtml(response);
|
||||
}
|
||||
|
||||
const indexUrl = new URL('/index.html', request.url);
|
||||
return env.ASSETS.fetch(new Request(indexUrl, request));
|
||||
const indexResponse = await env.ASSETS.fetch(new Request(indexUrl, request));
|
||||
return withFreshHtml(indexResponse);
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user