App.tsx 5.1 KB
Newer Older
P
Peter Pan 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
/**
 * Copyright 2020 Baidu Inc. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

P
Peter Pan 已提交
17
// cSpell:words pageview inited
R
RotPublic 已提交
18
import 'antd/dist/antd.css';
19 20
import React, {FunctionComponent, Suspense, useCallback, useEffect, useMemo, useState} from 'react';
import {Redirect, Route, BrowserRouter as Router, Switch, useLocation, useHistory} from 'react-router-dom';
P
Peter Pan 已提交
21
import {THEME, matchMedia} from '~/utils/theme';
22
import {actions, selectors} from '~/store';
R
RotPublic 已提交
23
import {headerHeight, position, size, zIndexes, setRem} from '~/utils/style';
24
import {useDispatch, useSelector} from 'react-redux';
P
Peter Pan 已提交
25 26
import ErrorBoundary from '~/components/ErrorBoundary';
import ErrorPage from '~/pages/error';
27 28 29 30
import {Helmet} from 'react-helmet';
import NProgress from 'nprogress';
import Navbar from '~/components/Navbar';
import {SWRConfig} from 'swr';
P
Peter Pan 已提交
31
import {ToastContainer} from 'react-toastify';
32 33 34
import {fetcher} from '~/utils/fetch';
import routes from '~/routes';
import styled from 'styled-components';
35
import {setDefaults, useTranslation} from 'react-i18next';
36

37
const BASE_URI: string = import.meta.env.SNOWPACK_PUBLIC_BASE_URI;
38 39 40 41 42 43

const Main = styled.main`
    padding-top: ${headerHeight};
`;

const Header = styled.header`
44
    z-index: ${zIndexes.header};
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

    ${size(headerHeight, '100%')}
    ${position('fixed', 0, 0, null, 0)}
`;

const routers = routes.reduce<Omit<typeof routes[number], 'children'>[]>((m, route) => {
    if (route.children) {
        m.push(...route.children);
    } else {
        m.push(route);
    }
    return m;
}, []);

const Progress: FunctionComponent = () => {
    useEffect(() => {
        NProgress.start();
        return () => {
            NProgress.done();
        };
    }, []);

    return null;
};

const Telemetry: FunctionComponent = () => {
    const location = useLocation();
    useEffect(() => {
P
Peter Pan 已提交
73
        window._hmt.push(['_trackPageview', BASE_URI + location.pathname]);
74 75 76 77 78
    }, [location.pathname]);
    return null;
};

const App: FunctionComponent = () => {
P
Peter Pan 已提交
79
    const {t, i18n} = useTranslation('errors');
80
    const [defaultRoute, setDefaultRoute] = useState('');
81 82
    const dir = useMemo(() => (i18n.language ? i18n.dir(i18n.language) : ''), [i18n]);

P
Peter Pan 已提交
83
    const dispatch = useDispatch();
84
    const selectedTheme = useSelector(selectors.theme.selected);
P
Peter Pan 已提交
85 86

    const toggleTheme = useCallback(
87 88 89 90 91 92
        (e: MediaQueryListEvent) => {
            if (selectedTheme === 'auto') {
                dispatch(actions.theme.setTheme(e.matches ? 'dark' : 'light'));
            }
        },
        [dispatch, selectedTheme]
P
Peter Pan 已提交
93
    );
R
RotPublic 已提交
94 95 96 97 98 99
    // useEffect(() => {
    //     setRem();
    //     window.onresize = function () {
    //         setRem();
    //     };
    // }, []);
P
Peter Pan 已提交
100 101 102 103 104 105 106 107
    useEffect(() => {
        if (!THEME) {
            matchMedia.addEventListener('change', toggleTheme);
            return () => {
                matchMedia.removeEventListener('change', toggleTheme);
            };
        }
    }, [toggleTheme]);
108 109 110 111 112 113 114 115 116 117 118 119
    return (
        <div className="app">
            <Helmet defaultTitle="VisualDL" titleTemplate="%s - VisualDL">
                <html lang={i18n.language} dir={dir} />
            </Helmet>
            <SWRConfig
                value={{
                    fetcher,
                    revalidateOnFocus: false,
                    revalidateOnReconnect: false
                }}
            >
P
Peter Pan 已提交
120 121 122 123 124 125 126 127 128
                <Main>
                    <Router basename={BASE_URI || '/'}>
                        <Telemetry />
                        <Header>
                            <Navbar />
                        </Header>
                        <ErrorBoundary fallback={<ErrorPage />}>
                            <Suspense fallback={<Progress />}>
                                <Switch>
129
                                    <Redirect exact from="/" to={defaultRoute ?? '/index'} />
P
Peter Pan 已提交
130 131 132 133 134 135 136 137 138 139 140
                                    {routers.map(route => (
                                        <Route key={route.id} path={route.path} component={route.component} />
                                    ))}
                                    <Route path="*">
                                        <ErrorPage title={t('errors:page-not-found')} />
                                    </Route>
                                </Switch>
                            </Suspense>
                        </ErrorBoundary>
                    </Router>
                </Main>
R
RotPublic 已提交
141 142 143 144 145 146
                <ToastContainer
                    autoClose={100000}
                    style={{wordBreak: 'break-all'}}
                    draggable={false}
                    closeOnClick={false}
                />
147 148 149 150 151 152
            </SWRConfig>
        </div>
    );
};

export default App;