fix: replace nprogress with hooks and qier-progress (#509)

This commit is contained in:
Innei 2023-05-08 18:49:01 +08:00 committed by GitHub
parent fcf4f580d3
commit 5b8a022078
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 217 additions and 36 deletions

View File

@ -87,9 +87,9 @@
"mdast-util-toc": "6.1.1",
"medium-zoom": "1.0.8",
"mermaid": "10.1.0",
"qier-progress": "1.0.4",
"nanoid": "4.0.2",
"next": "13.4.1",
"nextjs-toploader": "^1.3.2",
"node-id3": "^0.2.6",
"pangu": "^4.0.7",
"pinyin": "3.0.0-alpha.5",

View File

@ -187,9 +187,6 @@ dependencies:
next:
specifier: 13.4.1
version: 13.4.1(@babel/core@7.21.8)(react-dom@18.2.0)(react@18.2.0)
nextjs-toploader:
specifier: ^1.3.2
version: 1.3.2(next@13.4.1)(react-dom@18.2.0)(react@18.2.0)
node-id3:
specifier: ^0.2.6
version: 0.2.6
@ -202,6 +199,9 @@ dependencies:
prismjs:
specifier: 1.29.0
version: 1.29.0
qier-progress:
specifier: 1.0.4
version: 1.0.4
react:
specifier: 18.2.0
version: 18.2.0
@ -4806,10 +4806,6 @@ packages:
/@types/node@20.1.0:
resolution: {integrity: sha512-O+z53uwx64xY7D6roOi4+jApDGFg0qn6WHcxe5QeqjMaTezBO/mxdfFXIVAVVyNWKx84OmPB3L8kbVYOTeN34A==}
/@types/nprogress@0.2.0:
resolution: {integrity: sha512-1cYJrqq9GezNFPsWTZpFut/d4CjpZqA0vhqDUPFWYKF1oIyBz5qnoYMzR+0C/T96t3ebLAC1SSnwrVOm5/j74A==}
dev: false
/@types/pangu@4.0.0:
resolution: {integrity: sha512-da3b6P7QDH41VdfF2xRE8/KgL06nX3RawfiIMAvJ/sYzLWQCQtxc+B3qWVtrIlrNlSgV/e1oG2SZYUpN6gvmhQ==}
dev: true
@ -10880,21 +10876,6 @@ packages:
- '@babel/core'
- babel-plugin-macros
/nextjs-toploader@1.3.2(next@13.4.1)(react-dom@18.2.0)(react@18.2.0):
resolution: {integrity: sha512-vvFObZvjMC/KNhqFG+pUgLW5/TNpz74wo9Vn/pweg7+tfwK+PCIxArTjpmD60jmUUHPmYgXy1w5qUuw8x3tSow==}
peerDependencies:
next: '>= 6.0.0'
react: '>= 16.0.0'
react-dom: '>= 16.0.0'
dependencies:
'@types/nprogress': 0.2.0
next: 13.4.1(@babel/core@7.21.8)(react-dom@18.2.0)(react@18.2.0)
nprogress: 0.2.0
prop-types: 15.8.1
react: 18.2.0
react-dom: 18.2.0(react@18.2.0)
dev: false
/node-abi@3.40.0:
resolution: {integrity: sha512-zNy02qivjjRosswoYmPi8hIKJRr8MpQyeKT6qlcq/OnOgA3Rhoae+IYOqsM9V5+JnHWmxKnWOT2GxvtqdtOCXA==}
engines: {node: '>=10'}
@ -11015,10 +10996,6 @@ packages:
dev: false
optional: true
/nprogress@0.2.0:
resolution: {integrity: sha512-I19aIingLgR1fmhftnbWWO3dXc0hSxqHQHQb3H8m+K3TnEn/iSeTZZOyvKXWqQESMwuUVnatlCnZdLBZZt2VSA==}
dev: false
/nth-check@2.1.1:
resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==}
dependencies:
@ -11634,6 +11611,11 @@ packages:
resolution: {integrity: sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==}
engines: {node: '>=6'}
/qier-progress@1.0.4:
resolution: {integrity: sha512-gCxgoM2wxW7GCo/iEpOlaunVo2cf+/AJfG6wtYIbYz18GXtUhFjgZjX2s+otWh/P8ppVgGULASkWtXfZQEd2FQ==}
engines: {node: '>=6.0.0'}
dev: false
/qrcode@1.5.3:
resolution: {integrity: sha512-puyri6ApkEHYiVl4CFzo1tDkAZ+ATcnbJrJ6RiBM1Fhctdn/ix9MTE3hRph33omisEbC/2fcfemsseiKgBPKZg==}
engines: {node: '>=10.13.0'}

View File

@ -1,6 +1,5 @@
"use client"
import NextTopLoader from "nextjs-toploader"
import { useState } from "react"
import { WagmiConfig, createClient } from "wagmi"
@ -18,6 +17,7 @@ import { PersistQueryClientProvider } from "@tanstack/react-query-persist-client
// eslint-disable-next-line import/no-unresolved
import { useDarkMode } from "~/hooks/useDarkMode"
import { useMobileLayout } from "~/hooks/useMobileLayout"
import { useNProgress } from "~/hooks/useNProgress"
import { APP_NAME } from "~/lib/env"
import { toGateway } from "~/lib/ipfs-parser"
import { createIDBPersister } from "~/lib/persister.client"
@ -44,6 +44,7 @@ export default function Providers({
}) {
useDarkMode()
useMobileLayout()
useNProgress()
const [queryClient] = useState(
() =>
@ -81,7 +82,6 @@ export default function Providers({
signInStrategy="simple"
ignoreWalletDisconnectEvent={true}
>
<NextTopLoader easing="linear" speed={500} />
<LangProvider lang={lang}>{children}</LangProvider>
<NotificationModal colorScheme={colorScheme} />
</ConnectKitProvider>

View File

@ -371,17 +371,92 @@ textarea.input {
background-color: var(--banner-bg-color);
}
#nprogress .bar {
@apply bg-accent !important;
/* Fancy blur effect */
#qprogress .peg {
display: block;
position: absolute;
right: 0px;
width: 100px;
height: 100%;
opacity: 1;
-webkit-transform: rotate(3deg) translate(0px, -4px);
-ms-transform: rotate(3deg) translate(0px, -4px);
transform: rotate(3deg) translate(0px, -4px);
}
#nprogress .peg {
@apply shadow-none !important;
.qprogress-custom-parent {
overflow: hidden;
position: relative;
}
#nprogress .spinner-icon {
@apply border-t-accent !important;
@apply border-l-accent !important;
.qprogress-custom-parent #qprogress .bar {
position: absolute;
}
/* Colorful effect */
#qprogress .colorful-bar {
background: -webkit-gradient(
linear,
left top,
right top,
from(#1890ff),
color-stop(#13c2c2),
color-stop(#52c41a),
color-stop(#fa8c16),
color-stop(#fa541c),
color-stop(#f5222d),
to(#1890ff)
);
background: -webkit-linear-gradient(
left,
#1890ff,
#13c2c2,
#52c41a,
#fa8c16,
#fa541c,
#f5222d,
#1890ff
);
background: linear-gradient(
to right,
#1890ff,
#13c2c2,
#52c41a,
#fa8c16,
#fa541c,
#f5222d,
#1890ff
);
-webkit-animation: 2s linear infinite ins;
animation: 2s linear infinite ins;
-webkit-transition: opacity 0.2s ease-in-out;
transition: opacity 0.2s ease-in-out;
-webkit-transform-origin: left;
transform-origin: left;
background-size: 500%;
}
@-webkit-keyframes ins {
0% {
background-position: 0% 0;
}
to {
background-position: 125% 0;
}
}
@keyframes ins {
0% {
background-position: 0% 0;
}
to {
background-position: 125% 0;
}
}
.loading:before {

26
src/hooks/useNProgress.ts Normal file
View File

@ -0,0 +1,26 @@
"use client"
import Progress from "qier-progress"
import { useEffect, useRef } from "react"
import { useAppRouterEventerListener } from "./useRouterEvents"
export const useNProgress = () => {
const events = useAppRouterEventerListener()
const instance = useRef(
new Progress({ color: "var(--theme-color)", colorful: false }),
)
useEffect(() => {
const disposers = [] as any[]
disposers.push(
events.onStart(() => {
console.log("start")
instance.current.start()
}),
)
disposers.push(events.onComplete(() => instance.current.finish()))
return () => disposers.forEach((disposer) => disposer())
}, [])
}

View File

@ -0,0 +1,98 @@
import { usePathname, useRouter, useSearchParams } from "next/navigation"
import { useEffect, useRef, useState } from "react"
import { pick } from "~/lib/utils"
interface RouterNavigationEvent {}
type RouterEventFunction = (e: RouterNavigationEvent) => void
// TODO detect error event
export const useAppRouterEventerListener = () => {
const [isRouterComplete, setIsRouterComplete] = useState(false)
const startChangeCallback = () => {
setIsRouterComplete(false)
eventsRegisters.current.onStartQ.forEach(($) => $(buildEvent()))
}
const router = useRouter()
useEffect(() => {
const rawPush = router.push
const rawReplace = router.replace
const popstateHandler = () => {
startChangeCallback()
}
window.addEventListener("popstate", popstateHandler)
router.push = (...rest) => {
startChangeCallback()
// eslint-disable-next-line prefer-spread
rawPush.apply(null, rest)
}
router.replace = (...rest) => {
startChangeCallback()
// eslint-disable-next-line prefer-spread
rawReplace.apply(null, rest)
}
return () => {
router.push = rawPush
router.replace = rawReplace
window.removeEventListener("popstate", popstateHandler)
}
}, [])
const eventsRegisters = useRef({
onStartQ: [] as RouterEventFunction[],
// onErrorQ: [] as RouterEventFunction[],
onCompleteQ: [] as RouterEventFunction[],
onStart(cb: RouterEventFunction) {
eventsRegisters.current.onStartQ.push(cb)
return () => {
eventsRegisters.current.onStartQ =
eventsRegisters.current.onStartQ.filter(($) => $ !== cb)
}
},
onComplete(cb: RouterEventFunction) {
eventsRegisters.current.onCompleteQ.push(cb)
return () => {
eventsRegisters.current.onCompleteQ =
eventsRegisters.current.onCompleteQ.filter(($) => $ !== cb)
}
},
})
const buildEvent = (): RouterNavigationEvent => {
return {
url: location.pathname + location.search,
}
}
useEffect(() => {
if (!isRouterComplete) return
eventsRegisters.current.onCompleteQ.forEach(($) => $(buildEvent()))
}, [isRouterComplete])
const currentPathname = usePathname()
const searchParams = useSearchParams()
useEffect(() => {
if (
currentPathname === location.pathname &&
searchParams?.toString() ===
new URLSearchParams(location.search).toString()
) {
setIsRouterComplete(true)
}
}, [currentPathname, searchParams])
return pick(eventsRegisters.current, ["onStart", "onComplete"])
}