mirror of
https://github.com/ragestudio/comty.git
synced 2025-06-11 03:24:16 +00:00
improve router and page transition logic
This commit is contained in:
parent
1c534a3946
commit
ef5ef4c90f
@ -57,7 +57,7 @@ import { NotFound, RenderError, Crash, Settings, Navigation, Login } from "compo
|
|||||||
import { Icons } from "components/Icons"
|
import { Icons } from "components/Icons"
|
||||||
|
|
||||||
import Layout from "./layout"
|
import Layout from "./layout"
|
||||||
import Router from "./router"
|
import * as Router from "./router"
|
||||||
|
|
||||||
import "theme/index.less"
|
import "theme/index.less"
|
||||||
|
|
||||||
@ -423,19 +423,21 @@ class App extends React.Component {
|
|||||||
</Helmet>
|
</Helmet>
|
||||||
<antd.ConfigProvider>
|
<antd.ConfigProvider>
|
||||||
<div className="backgroundDecorator" />
|
<div className="backgroundDecorator" />
|
||||||
<Layout
|
<Router.InternalRouter>
|
||||||
user={this.state.user}
|
<Layout
|
||||||
staticRenders={App.staticRenders}
|
user={this.state.user}
|
||||||
bindProps={{
|
staticRenders={App.staticRenders}
|
||||||
staticRenders: App.staticRenders,
|
bindProps={{
|
||||||
user: this.state.user,
|
staticRenders: App.staticRenders,
|
||||||
session: this.state.session,
|
user: this.state.user,
|
||||||
sessionController: this.sessionController,
|
session: this.state.session,
|
||||||
userController: this.userController,
|
sessionController: this.sessionController,
|
||||||
}}
|
userController: this.userController,
|
||||||
>
|
}}
|
||||||
<Router />
|
>
|
||||||
</Layout>
|
<Router.PageRender />
|
||||||
|
</Layout>
|
||||||
|
</Router.InternalRouter>
|
||||||
</antd.ConfigProvider>
|
</antd.ConfigProvider>
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,8 @@ import Drawer from "./drawer"
|
|||||||
import Sidedrawer from "./sidedrawer"
|
import Sidedrawer from "./sidedrawer"
|
||||||
import BottomBar from "./bottomBar"
|
import BottomBar from "./bottomBar"
|
||||||
|
|
||||||
|
import config from "config"
|
||||||
|
|
||||||
import routes from "schemas/routes"
|
import routes from "schemas/routes"
|
||||||
|
|
||||||
const LayoutRenders = {
|
const LayoutRenders = {
|
||||||
@ -15,7 +17,7 @@ const LayoutRenders = {
|
|||||||
return <antd.Layout className={classnames("app_layout", ["mobile"])} style={{ height: "100%" }}>
|
return <antd.Layout className={classnames("app_layout", ["mobile"])} style={{ height: "100%" }}>
|
||||||
<antd.Layout className="content_layout">
|
<antd.Layout className="content_layout">
|
||||||
<antd.Layout.Content className={classnames("layout_page", ...props.layoutPageModesClassnames ?? [])}>
|
<antd.Layout.Content className={classnames("layout_page", ...props.layoutPageModesClassnames ?? [])}>
|
||||||
<div className={classnames("fade-transverse-active", { "fade-transverse-leave": props.isOnTransition })}>
|
<div id="transitionLayer" className="fade-transverse-active">
|
||||||
{React.cloneElement(props.children, props)}
|
{React.cloneElement(props.children, props)}
|
||||||
</div>
|
</div>
|
||||||
</antd.Layout.Content>
|
</antd.Layout.Content>
|
||||||
@ -31,7 +33,7 @@ const LayoutRenders = {
|
|||||||
<Sidedrawer />
|
<Sidedrawer />
|
||||||
<antd.Layout className="content_layout">
|
<antd.Layout className="content_layout">
|
||||||
<antd.Layout.Content className={classnames("layout_page", ...props.layoutPageModesClassnames ?? [])}>
|
<antd.Layout.Content className={classnames("layout_page", ...props.layoutPageModesClassnames ?? [])}>
|
||||||
<div className={classnames("fade-transverse-active", { "fade-transverse-leave": props.isOnTransition })}>
|
<div id="transitionLayer" className="fade-transverse-active">
|
||||||
{React.cloneElement(props.children, props)}
|
{React.cloneElement(props.children, props)}
|
||||||
</div>
|
</div>
|
||||||
</antd.Layout.Content>
|
</antd.Layout.Content>
|
||||||
@ -40,16 +42,70 @@ const LayoutRenders = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default class Layout extends React.PureComponent {
|
export default class Layout extends React.Component {
|
||||||
progressBar = progressBar.configure({ parent: "html", showSpinner: false })
|
progressBar = progressBar.configure({ parent: "html", showSpinner: false })
|
||||||
|
|
||||||
state = {
|
state = {
|
||||||
layoutType: "default",
|
layoutType: "default",
|
||||||
isOnTransition: false,
|
|
||||||
renderLock: true,
|
renderLock: true,
|
||||||
renderError: null,
|
renderError: null,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
events = {
|
||||||
|
"app.initialization.start": () => {
|
||||||
|
this.setState({
|
||||||
|
renderLock: true,
|
||||||
|
})
|
||||||
|
},
|
||||||
|
"app.initialization.finish": () => {
|
||||||
|
this.setState({
|
||||||
|
renderLock: false,
|
||||||
|
})
|
||||||
|
},
|
||||||
|
"router.transitionStart": () => {
|
||||||
|
this.progressBar.start()
|
||||||
|
|
||||||
|
if (!app.settings.get("reduceAnimations")) {
|
||||||
|
// add "fade-transverse-leave" class to `transitionLayer`
|
||||||
|
document.getElementById("transitionLayer").classList.add("fade-transverse-leave")
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"router.transitionFinish": () => {
|
||||||
|
this.progressBar.done()
|
||||||
|
|
||||||
|
if (!app.settings.get("reduceAnimations")) {
|
||||||
|
// remove "fade-transverse-leave" class to `transitionLayer`
|
||||||
|
document.getElementById("transitionLayer").classList.remove("fade-transverse-leave")
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
if (window.app.settings.get("forceMobileMode") || window.app.isAppCapacitor() || Math.min(window.screen.width, window.screen.height) < 768 || navigator.userAgent.indexOf("Mobi") > -1) {
|
||||||
|
window.isMobile = true
|
||||||
|
|
||||||
|
this.setLayout("mobile")
|
||||||
|
} else {
|
||||||
|
window.isMobile = false
|
||||||
|
}
|
||||||
|
|
||||||
|
// register events
|
||||||
|
Object.keys(this.events).forEach((event) => {
|
||||||
|
window.app.eventBus.on(event, this.events[event])
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillUnmount() {
|
||||||
|
// unregister events
|
||||||
|
Object.keys(this.events).forEach((event) => {
|
||||||
|
window.app.eventBus.off(event, this.events[event])
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidCatch(info, stack) {
|
||||||
|
this.setState({ renderError: { info, stack } })
|
||||||
|
}
|
||||||
|
|
||||||
setLayout = (layout) => {
|
setLayout = (layout) => {
|
||||||
if (typeof LayoutRenders[layout] === "function") {
|
if (typeof LayoutRenders[layout] === "function") {
|
||||||
return this.setState({
|
return this.setState({
|
||||||
@ -60,66 +116,8 @@ export default class Layout extends React.PureComponent {
|
|||||||
return console.error("Layout type not found")
|
return console.error("Layout type not found")
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
|
||||||
window.app.eventBus.on("app.initialization.start", () => {
|
|
||||||
this.setState({
|
|
||||||
renderLock: true,
|
|
||||||
})
|
|
||||||
})
|
|
||||||
window.app.eventBus.on("app.initialization.finish", () => {
|
|
||||||
this.setState({
|
|
||||||
renderLock: false,
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
if (window.app.settings.get("forceMobileMode") || window.app.isAppCapacitor() || Math.min(window.screen.width, window.screen.height) < 768 || navigator.userAgent.indexOf("Mobi") > -1) {
|
|
||||||
window.isMobile = true
|
|
||||||
this.setLayout("mobile")
|
|
||||||
} else {
|
|
||||||
window.isMobile = false
|
|
||||||
}
|
|
||||||
|
|
||||||
window.app.eventBus.on("forceMobileMode", (to) => {
|
|
||||||
if (to) {
|
|
||||||
window.isMobile = true
|
|
||||||
this.setLayout("mobile")
|
|
||||||
} else {
|
|
||||||
window.isMobile = false
|
|
||||||
this.setLayout("default")
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
// this is a hacky one to fix app.setLocation not working on when app not render a router
|
|
||||||
window.app.setLocation = (location) => {
|
|
||||||
// update history
|
|
||||||
window.history.pushState(null, null, location)
|
|
||||||
|
|
||||||
// reload page
|
|
||||||
window.location.reload()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
onTransitionStart = () => {
|
|
||||||
progressBar.start()
|
|
||||||
|
|
||||||
if (!app.settings.get("reduceAnimations")) {
|
|
||||||
this.setState({ isOnTransition: true })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
onTransitionFinish = () => {
|
|
||||||
progressBar.done()
|
|
||||||
|
|
||||||
if (!app.settings.get("reduceAnimations")) {
|
|
||||||
this.setState({ isOnTransition: false })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
componentDidCatch(info, stack) {
|
|
||||||
this.setState({ renderError: { info, stack } })
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
let layoutType = this.state.layoutType
|
||||||
const InitializationComponent = this.props.staticRenders?.Initialization ? React.createElement(this.props.staticRenders.Initialization) : null
|
const InitializationComponent = this.props.staticRenders?.Initialization ? React.createElement(this.props.staticRenders.Initialization) : null
|
||||||
|
|
||||||
if (this.state.renderError) {
|
if (this.state.renderError) {
|
||||||
@ -148,16 +146,24 @@ export default class Layout extends React.PureComponent {
|
|||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (typeof routeDeclaration.useLayout !== "undefined") {
|
||||||
|
layoutType = routeDeclaration.useLayout
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof routeDeclaration.webTitleAddition !== "undefined") {
|
||||||
|
document.title = `${routeDeclaration.webTitleAddition} - ${config.app.siteName}`
|
||||||
|
} else {
|
||||||
|
document.title = config.app.siteName
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const layoutComponentProps = {
|
const layoutComponentProps = {
|
||||||
...this.props.bindProps,
|
...this.props.bindProps,
|
||||||
...this.state,
|
...this.state,
|
||||||
onTransitionStart: this.onTransitionStart,
|
|
||||||
onTransitionFinish: this.onTransitionFinish,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const Layout = LayoutRenders[this.state.layoutType]
|
const Layout = LayoutRenders[layoutType]
|
||||||
|
|
||||||
return <Layout {...layoutComponentProps}>
|
return <Layout {...layoutComponentProps}>
|
||||||
{this.state.renderLock ? InitializationComponent : this.props.children}
|
{this.state.renderLock ? InitializationComponent : this.props.children}
|
||||||
|
@ -59,7 +59,7 @@ export function BindContexts(component) {
|
|||||||
return (props) => React.createElement(component, { ...props, contexts })
|
return (props) => React.createElement(component, { ...props, contexts })
|
||||||
}
|
}
|
||||||
|
|
||||||
export const InternalRouter = withRouter((props) => {
|
export const Router = withRouter((props) => {
|
||||||
const defaultTransitionDelay = 150
|
const defaultTransitionDelay = 150
|
||||||
const forceUpdate = React.useReducer(() => ({}))[1]
|
const forceUpdate = React.useReducer(() => ({}))[1]
|
||||||
|
|
||||||
@ -69,7 +69,7 @@ export const InternalRouter = withRouter((props) => {
|
|||||||
props.onTransitionFinish(event)
|
props.onTransitionFinish(event)
|
||||||
}
|
}
|
||||||
|
|
||||||
window.app.eventBus.emit("transitionDone", event)
|
window.app.eventBus.emit("router.transitionFinish", event)
|
||||||
})
|
})
|
||||||
|
|
||||||
props.history.setLocation = (to, state = {}, delay = 150) => {
|
props.history.setLocation = (to, state = {}, delay = 150) => {
|
||||||
@ -92,7 +92,7 @@ export const InternalRouter = withRouter((props) => {
|
|||||||
props.onTransitionStart(delay)
|
props.onTransitionStart(delay)
|
||||||
}
|
}
|
||||||
|
|
||||||
window.app.eventBus.emit("transitionStart", delay)
|
window.app.eventBus.emit("router.transitionStart", delay)
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
props.history.push({
|
props.history.push({
|
||||||
@ -110,6 +110,26 @@ export const InternalRouter = withRouter((props) => {
|
|||||||
window.app.setLocation = props.history.setLocation
|
window.app.setLocation = props.history.setLocation
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
|
const router = {
|
||||||
|
history: props.history,
|
||||||
|
lastLocation: props.history.lastLocation,
|
||||||
|
forceUpdate,
|
||||||
|
}
|
||||||
|
|
||||||
|
// return children with router in props
|
||||||
|
return React.cloneElement(props.children, { router })
|
||||||
|
})
|
||||||
|
|
||||||
|
export const InternalRouter = (props) => {
|
||||||
|
console.log(props)
|
||||||
|
return <BrowserRouter>
|
||||||
|
<Router {...props} />
|
||||||
|
</BrowserRouter>
|
||||||
|
}
|
||||||
|
|
||||||
|
export const PageRender = (props) => {
|
||||||
|
console.log(props)
|
||||||
|
|
||||||
return <React.Suspense fallback={props.staticRenders?.PageLoad ? React.createElement(props.staticRenders?.PageLoad) : "Loading..."}>
|
return <React.Suspense fallback={props.staticRenders?.PageLoad ? React.createElement(props.staticRenders?.PageLoad) : "Loading..."}>
|
||||||
<Switch>
|
<Switch>
|
||||||
{routes.map(({ path, component: Component = React.Fragment }) => (
|
{routes.map(({ path, component: Component = React.Fragment }) => (
|
||||||
@ -127,14 +147,11 @@ export const InternalRouter = withRouter((props) => {
|
|||||||
<Route path="*" component={props.staticRenders?.NotFound ?? NotFoundRender} />
|
<Route path="*" component={props.staticRenders?.NotFound ?? NotFoundRender} />
|
||||||
</Switch>
|
</Switch>
|
||||||
</React.Suspense>
|
</React.Suspense>
|
||||||
})
|
|
||||||
|
|
||||||
export const Router = (props) => {
|
|
||||||
return <BrowserRouter>
|
|
||||||
<InternalRouter
|
|
||||||
{...props}
|
|
||||||
/>
|
|
||||||
</BrowserRouter>
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Router
|
export default {
|
||||||
|
routes,
|
||||||
|
BindContexts,
|
||||||
|
InternalRouter,
|
||||||
|
PageRender,
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user