From f09f695b467ec7fa2b0f5c5623042a65c4063ee2 Mon Sep 17 00:00:00 2001 From: SrGooglo Date: Thu, 12 Jan 2023 20:23:59 +0000 Subject: [PATCH] improve router --- packages/app/package.json | 7 +- packages/app/src/App.jsx | 33 ++----- packages/app/src/layout.jsx | 56 +++++------ packages/app/src/router.jsx | 192 +++++++++++++----------------------- 4 files changed, 109 insertions(+), 179 deletions(-) diff --git a/packages/app/package.json b/packages/app/package.json index 2a5dbe48..9652abf4 100755 --- a/packages/app/package.json +++ b/packages/app/package.json @@ -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" diff --git a/packages/app/src/App.jsx b/packages/app/src/App.jsx index 56f42e3a..1f75f357 100755 --- a/packages/app/src/App.jsx +++ b/packages/app/src/App.jsx @@ -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 { - - + + - - + + } } diff --git a/packages/app/src/layout.jsx b/packages/app/src/layout.jsx index b1747c70..fdf789fd 100755 --- a/packages/app/src/layout.jsx +++ b/packages/app/src/layout.jsx @@ -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({ diff --git a/packages/app/src/router.jsx b/packages/app/src/router.jsx index 9b7f4cea..10456da1 100755 --- a/packages/app/src/router.jsx +++ b/packages/app/src/router.jsx @@ -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
Not found
} +const LoadingRender = () => { + return +} + 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.map((route, index) => { + let Element = route.element - // return children with router in props - return React.cloneElement(props.children, { router }) -}) - -export const InternalRouter = (props) => { - return - - -} - -export const PageRender = (props) => { - return - - {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 - })} - - - -} - -export default { - routes, - BindContexts, - InternalRouter, - PageRender, -} \ No newline at end of file + }) + } + } /> + +}) \ No newline at end of file