improve router

This commit is contained in:
SrGooglo 2023-01-12 20:23:59 +00:00
parent d53b27425f
commit 72166574c0
4 changed files with 109 additions and 179 deletions

View File

@ -45,13 +45,12 @@
"electron-is": "^3.0.0",
"electron-log": "^4.4.8",
"electron-squirrel-startup": "^1.0.0",
"evite": "0.13.7",
"evite": "0.13.9",
"fast-average-color": "^9.2.0",
"faye": "1.4.0",
"feather-reactjs": "2.0.13",
"fuse.js": "6.5.3",
"global": "4.4.0",
"history": "5.2.0",
"hls.js": "^1.1.5",
"howler": "2.2.3",
"i18next": "21.6.6",
@ -59,7 +58,9 @@
"jwt-decode": "3.1.2",
"less": "4.1.2",
"linebridge": "0.13.0",
"localforage": "^1.10.0",
"luxon": "^3.0.4",
"match-sorter": "^6.3.1",
"moment": "2.29.4",
"moment-timezone": "^0.5.37",
"mpegts.js": "^1.6.10",
@ -89,10 +90,12 @@
"react-responsive-carousel": "^3.2.23",
"react-reveal": "1.2.2",
"react-rnd": "10.3.5",
"react-router-dom": "^6.6.2",
"react-ticker": "^1.3.2",
"react-transition-group": "^4.4.5",
"remark-gfm": "^3.0.1",
"rxjs": "^7.5.5",
"sort-by": "^1.2.0",
"store": "^2.0.12",
"uuid": "^9.0.0",
"wait-on": "^6.0.1"

View File

@ -53,6 +53,7 @@ import { EviteRuntime } from "evite"
import { Helmet } from "react-helmet"
import * as antd from "antd"
import { Toast } from "antd-mobile"
import { BrowserRouter } from "react-router-dom"
import { StatusBar, Style } from "@capacitor/status-bar"
import { App as CapacitorApp } from "@capacitor/app"
import { Translation } from "react-i18next"
@ -455,15 +456,14 @@ class App extends React.Component {
})
StatusBar.setOverlaysWebView({ overlay: true })
//window.app.hideStatusBar()
CapacitorApp.addListener('backButton', ({ canGoBack }) => {
CapacitorApp.addListener("backButton", ({ canGoBack }) => {
if (!canGoBack) {
CapacitorApp.exitApp();
CapacitorApp.exitApp()
} else {
window.history.back();
window.history.back()
}
});
})
}
const userAgentPlatform = window.navigator.userAgent.toLowerCase()
@ -532,6 +532,7 @@ class App extends React.Component {
async () => {
try {
await this.__SessionInit()
await this.__UserInit()
app.eventBus.emit("app.initialization.session_success")
} catch (error) {
@ -543,20 +544,6 @@ class App extends React.Component {
}
}
},
async () => {
try {
await this.__UserInit()
app.eventBus.emit("app.initialization.user_success")
} catch (error) {
app.eventBus.emit("app.initialization.user_error", error)
throw {
cause: "Cannot initialize user data",
details: error.message,
}
}
},
]
await Promise.tasked(initializationTasks).catch((reason) => {
@ -607,8 +594,8 @@ class App extends React.Component {
<meta name="og:description" content={config.app.siteDescription} />
<meta property="og:title" content={config.app.siteName} />
</Helmet>
<antd.ConfigProvider>
<Router.InternalRouter>
<BrowserRouter>
<antd.ConfigProvider>
<Layout
user={this.state.user}
staticRenders={App.staticRenders}
@ -622,8 +609,8 @@ class App extends React.Component {
>
<Router.PageRender />
</Layout>
</Router.InternalRouter>
</antd.ConfigProvider>
</antd.ConfigProvider>
</BrowserRouter>
</React.Fragment>
}
}

View File

@ -54,35 +54,8 @@ export default class Layout extends React.PureComponent {
document.querySelector("#transitionLayer").classList.add("fade-opacity-leave")
},
"router.transitionStart": () => {
this.progressBar.start()
if (!app.settings.get("reduceAnimations")) {
// add "fade-transverse-leave" class to `transitionLayer`
const transitionLayer = document.getElementById("transitionLayer")
if (!transitionLayer) {
console.warn("transitionLayer not found, no animation will be played")
return
}
transitionLayer.classList.add("fade-transverse-leave")
}
},
"router.transitionFinish": () => {
this.progressBar.done()
if (!app.settings.get("reduceAnimations")) {
// remove "fade-transverse-leave" class to `transitionLayer`
const transitionLayer = document.getElementById("transitionLayer")
if (!transitionLayer) {
console.warn("transitionLayer not found, no animation will be played")
return
}
transitionLayer.classList.remove("fade-transverse-leave")
}
"router.navigate": (path, options) => {
this.makePageTransition(path, options)
},
}
@ -112,6 +85,31 @@ export default class Layout extends React.PureComponent {
this.setState({ renderError: { info, stack } })
}
makePageTransition(path, options = {}) {
this.progressBar.start()
if (app.settings.get("reduceAnimations") || options.state.noTransition) {
this.progressBar.done()
return false
}
const transitionLayer = document.getElementById("transitionLayer")
if (!transitionLayer) {
console.warn("transitionLayer not found, no animation will be played")
return false
}
transitionLayer.classList.add("fade-transverse-leave")
setTimeout(() => {
this.progressBar.done()
transitionLayer.classList.remove("fade-transverse-leave")
}, options.state.transitionDelay ?? 250)
}
setLayout = (layout) => {
if (typeof Layouts[layout] === "function") {
return this.setState({

View File

@ -1,12 +1,17 @@
import React from "react"
import { Switch, Route, BrowserRouter, withRouter } from "react-router-dom"
import { Route, Routes, Navigate, useLocation, useNavigate, useParams } from "react-router-dom"
import { Skeleton } from "antd"
import loadable from "@loadable/component"
const NotFoundRender = () => {
return <div>Not found</div>
}
const LoadingRender = () => {
return <Skeleton active />
}
const paths = {
...import.meta.glob("/src/debug/components/**/[a-z[]*.jsx"),
...import.meta.glob("/src/pages/**/[a-z[]*.jsx"),
...import.meta.glob("/src/pages/**/[a-z[]*.tsx"),
}
@ -16,166 +21,103 @@ const pathsMobile = {
...import.meta.glob("/src/pages/**/[a-z[]*.mobile.tsx"),
}
function generateElementWrapper(route, element, bindProps) {
return React.createElement((props) => {
const params = useParams()
return React.createElement(
loadable(element, {
fallback: React.createElement(LoadingRender),
}),
{
...props,
...bindProps,
params: params,
})
})
}
const routes = Object.keys(paths).map((route) => {
const path = route
.replace(/\/src\/pages|index|\.jsx$/g, "")
.replace(/\/src\/pages|index|\.tsx$/g, "")
.replace(/\/src\/debug\/components/g, "/debug")
.replace(/\[\.{3}.+\]/, "*")
.replace(/\[(.+)\]/, ":$1")
return { path, component: React.lazy(paths[route]) }
return {
path,
element: paths[route]
}
})
const mobileComponents = Object.fromEntries(Object.keys(pathsMobile).map((route) => {
const mobileRoutes = Object.keys(pathsMobile).map((route) => {
const path = route
.replace(/\/src\/pages|index|\.mobile|\.jsx$/g, "")
.replace(/\/src\/pages|index|\.mobile|\.tsx$/g, "")
.replace(/\/src\/debug\/components/g, "/debug")
.replace(/\[\.{3}.+\]/, "*")
.replace(/\[(.+)\]/, ":$1")
return [path, React.lazy(pathsMobile[route])]
}))
export function BindContexts(component) {
let contexts = {
main: {},
app: {},
return {
path,
element: pathsMobile[path]
}
})
if (typeof component.bindApp === "string") {
if (component.bindApp === "all") {
Object.keys(app).forEach((key) => {
contexts.app[key] = app[key]
})
}
} else {
if (Array.isArray(component.bindApp)) {
component.bindApp.forEach((key) => {
contexts.app[key] = app[key]
})
}
}
if (typeof component.bindMain === "string") {
if (component.bindMain === "all") {
Object.keys(main).forEach((key) => {
contexts.main[key] = main[key]
})
}
} else {
if (Array.isArray(component.bindMain)) {
component.bindMain.forEach((key) => {
contexts.main[key] = main[key]
})
}
}
return (props) => React.createElement(component, { ...props, contexts })
}
export const Router = withRouter((props) => {
const defaultTransitionDelay = 150
const forceUpdate = React.useReducer(() => ({}))[1]
export const PageRender = React.memo((props) => {
const navigate = useNavigate()
app.location = useLocation()
React.useEffect(() => {
props.history.listen((event) => {
if (typeof props.onTransitionFinish === "function") {
props.onTransitionFinish(event)
}
window.app.eventBus.emit("router.transitionFinish", event)
})
props.history.setLocation = (to, state = {}, delay = 150) => {
app.setLocation = async (to, state = {}) => {
// clean double slashes
to = to.replace(/\/{2,}/g, "/")
// if state is a number, it's a delay
if (typeof state !== "object") {
delay = state
state = {}
}
const lastLocation = props.history.lastLocation
state.transitionDelay = Number((app.style.getValue("page-transition-duration") ?? "250ms").replace("ms", ""))
if (typeof lastLocation !== "undefined" && lastLocation?.pathname === to && lastLocation?.state === state) {
return false
app.eventBus.emit("router.navigate", to, {
state,
})
if (state.transitionDelay >= 100) {
await new Promise((resolve) => {
setTimeout(() => {
resolve()
}, state.transitionDelay)
})
}
if (typeof props.onTransitionStart === "function") {
props.onTransitionStart(delay)
}
window.app.eventBus.emit("router.transitionStart", delay)
setTimeout(() => {
props.history.push({
pathname: to,
}, state)
props.history.lastLocation = window.location
}, delay ?? defaultTransitionDelay)
return navigate(to, {
state
})
}
window.app.eventBus.on(`router.forceUpdate`, forceUpdate)
props.history.lastLocation = window.location
window.app.setLocation = props.history.setLocation
}, [])
const router = {
history: props.history,
lastLocation: props.history.lastLocation,
forceUpdate,
}
return <Routes>
{
routes.map((route, index) => {
let Element = route.element
// return children with router in props
return React.cloneElement(props.children, { router })
})
export const InternalRouter = (props) => {
return <BrowserRouter>
<Router {...props} />
</BrowserRouter>
}
export const PageRender = (props) => {
return <React.Suspense fallback={props.staticRenders?.PageLoad ? React.createElement(props.staticRenders?.PageLoad) : "Loading..."}>
<Switch>
{routes.map(({ path, component: Component = React.Fragment }) => {
if (window.isMobile) {
if (mobileComponents[path]) {
Component = mobileComponents[path]
} else {
console.warn(`No mobile component for ${path}, using default`)
const mobileElement = mobileRoutes.find((r) => r.path === route.path)
if (mobileElement) {
Element = mobileElement
}
}
const generateRenderComponent = (props) => {
return React.createElement(BindContexts(Component), {
...props,
history: props.history,
})
}
return <Route
key={path}
path={path}
component={generateRenderComponent}
exact={true}
key={index}
path={route.path}
element={generateElementWrapper(route.path, route.element, props)}
exact
/>
})}
<Route path="*" component={props.staticRenders?.NotFound ?? NotFoundRender} />
</Switch>
</React.Suspense>
}
export default {
routes,
BindContexts,
InternalRouter,
PageRender,
}
})
}
<Route path="*" element={React.createElement(props.staticRenders?.NotFound) ?? <NotFoundRender />} />
</Routes>
})