mirror of
https://github.com/ragestudio/comty.git
synced 2025-06-09 10:34:17 +00:00
improve router
This commit is contained in:
parent
d53b27425f
commit
72166574c0
@ -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"
|
||||
|
@ -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>
|
||||
}
|
||||
}
|
||||
|
@ -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({
|
||||
|
@ -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>
|
||||
})
|
Loading…
x
Reference in New Issue
Block a user