From ecf5515bd453eca20946339a56be9180f6dca2c1 Mon Sep 17 00:00:00 2001 From: wxsm Date: Thu, 1 Sep 2022 15:17:36 +0800 Subject: [PATCH] feat(theme): add page load progress bar (#1264) --- package.json | 2 ++ pnpm-lock.yaml | 14 +++++++++++++- src/client/app/router.ts | 18 ++++++++++++------ src/client/theme-default/index.ts | 17 +++++++++++++++-- .../styles/lib-override/nprogress.css | 12 ++++++++++++ theme.d.ts | 2 ++ 6 files changed, 56 insertions(+), 9 deletions(-) create mode 100644 src/client/theme-default/styles/lib-override/nprogress.css diff --git a/package.json b/package.json index d3521e40..14dc308d 100644 --- a/package.json +++ b/package.json @@ -87,6 +87,7 @@ "@vue/devtools-api": "^6.2.1", "@vueuse/core": "^9.1.1", "body-scroll-lock": "^4.0.0-beta.0", + "nprogress": "^0.2.0", "shiki": "^0.11.1", "vite": "^3.0.9", "vue": "^3.2.38" @@ -120,6 +121,7 @@ "@types/micromatch": "^4.0.2", "@types/minimist": "^1.2.2", "@types/node": "^18.7.14", + "@types/nprogress": "^0.2.0", "@types/polka": "^0.5.4", "@types/prompts": "^2.0.14", "chokidar": "^3.5.3", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 1adcc33d..a1f077c3 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -34,6 +34,7 @@ importers: '@types/micromatch': ^4.0.2 '@types/minimist': ^1.2.2 '@types/node': ^18.7.14 + '@types/nprogress': ^0.2.0 '@types/polka': ^0.5.4 '@types/prompts': ^2.0.14 '@vitejs/plugin-vue': ^3.0.3 @@ -62,6 +63,7 @@ importers: micromatch: ^4.0.5 minimist: ^1.2.6 npm-run-all: ^4.1.5 + nprogress: ^0.2.0 ora: ^5.4.1 picocolors: ^1.0.0 playwright-chromium: ^1.25.1 @@ -90,6 +92,7 @@ importers: '@vue/devtools-api': 6.2.1 '@vueuse/core': 9.1.1_vue@3.2.38 body-scroll-lock: 4.0.0-beta.0 + nprogress: 0.2.0 shiki: 0.11.1 vite: 3.0.9 vue: 3.2.38 @@ -122,6 +125,7 @@ importers: '@types/micromatch': 4.0.2 '@types/minimist': 1.2.2 '@types/node': 18.7.14 + '@types/nprogress': 0.2.0 '@types/polka': 0.5.4 '@types/prompts': 2.0.14 chokidar: 3.5.3 @@ -786,6 +790,10 @@ packages: resolution: {integrity: sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw==} dev: true + /@types/nprogress/0.2.0: + resolution: {integrity: sha512-1cYJrqq9GezNFPsWTZpFut/d4CjpZqA0vhqDUPFWYKF1oIyBz5qnoYMzR+0C/T96t3ebLAC1SSnwrVOm5/j74A==} + dev: true + /@types/polka/0.5.4: resolution: {integrity: sha512-mLo6Mfa6lAvBrG1guj6HVxa1LpXw6ud4c93d2XQOHtADJv+VgiyXErmnjyVWre/r2oGSn1pcqO5IYaK0nv5b0g==} dependencies: @@ -1507,8 +1515,8 @@ packages: engines: {node: '>=10'} hasBin: true dependencies: - JSONStream: 1.3.5 is-text-path: 1.0.1 + JSONStream: 1.3.5 lodash: 4.17.21 meow: 8.1.2 split2: 3.2.2 @@ -3010,6 +3018,10 @@ packages: path-key: 4.0.0 dev: true + /nprogress/0.2.0: + resolution: {integrity: sha512-I19aIingLgR1fmhftnbWWO3dXc0hSxqHQHQb3H8m+K3TnEn/iSeTZZOyvKXWqQESMwuUVnatlCnZdLBZZt2VSA==} + dev: false + /object-inspect/1.12.2: resolution: {integrity: sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==} dev: true diff --git a/src/client/app/router.ts b/src/client/app/router.ts index 1d85d493..aaebbfaf 100644 --- a/src/client/app/router.ts +++ b/src/client/app/router.ts @@ -14,6 +14,8 @@ export interface Route { export interface Router { route: Route go: (href?: string) => Promise + onBeforeRouteChange?: (to: string) => void | Promise + onAfterRouteChanged?: (to: string) => void | Promise } export const RouterSymbol: InjectionKey = Symbol() @@ -39,7 +41,13 @@ export function createRouter( ): Router { const route = reactive(getDefaultRoute()) - function go(href: string = inBrowser ? location.href : '/') { + const router: Router = { + route, + go + } + + async function go(href: string = inBrowser ? location.href : '/') { + await router.onBeforeRouteChange?.(href) const url = new URL(href, fakeHost) if (siteDataRef.value.cleanUrls === 'disabled') { // ensure correct deep link so page refresh lands on correct files. @@ -54,7 +62,8 @@ export function createRouter( history.replaceState({ scrollPosition: window.scrollY }, document.title) history.pushState(null, '', href) } - return loadPage(href) + await loadPage(href) + await router.onAfterRouteChanged?.(href) } let latestPendingPath: string | null = null @@ -181,10 +190,7 @@ export function createRouter( handleHMR(route) - return { - route, - go - } + return router } export function useRouter(): Router { diff --git a/src/client/theme-default/index.ts b/src/client/theme-default/index.ts index 7b792128..ff23ef38 100644 --- a/src/client/theme-default/index.ts +++ b/src/client/theme-default/index.ts @@ -6,10 +6,13 @@ import './styles/components/custom-block.css' import './styles/components/vp-code.css' import './styles/components/vp-doc.css' import './styles/components/vp-sponsor.css' +import 'nprogress/nprogress.css' +import './styles/lib-override/nprogress.css' -import { Theme } from 'vitepress' +import { Theme, inBrowser } from 'vitepress' import Layout from './Layout.vue' import NotFound from './NotFound.vue' +import nprogress from 'nprogress' export { default as VPHomeHero } from './components/VPHomeHero.vue' export { default as VPHomeFeatures } from './components/VPHomeFeatures.vue' @@ -22,7 +25,17 @@ export { default as VPTeamMembers } from './components/VPTeamMembers.vue' const theme: Theme = { Layout, - NotFound + NotFound, + enhanceApp: ({ router }) => { + if (inBrowser) { + router.onBeforeRouteChange = () => { + nprogress.start() + } + router.onAfterRouteChanged = () => { + nprogress.done(true) + } + } + } } export default theme diff --git a/src/client/theme-default/styles/lib-override/nprogress.css b/src/client/theme-default/styles/lib-override/nprogress.css new file mode 100644 index 00000000..477703ce --- /dev/null +++ b/src/client/theme-default/styles/lib-override/nprogress.css @@ -0,0 +1,12 @@ +#nprogress .bar { + background: var(--vp-c-brand); +} + +#nprogress .spinner-icon { + border-top-color: var(--vp-c-brand); + border-left-color: var(--vp-c-brand); +} + +#nprogress .peg { + box-shadow: 0 0 10px var(--vp-c-brand), 0 0 5px var(--vp-c-brand); +} diff --git a/theme.d.ts b/theme.d.ts index cbb9cdf9..3d0fac10 100644 --- a/theme.d.ts +++ b/theme.d.ts @@ -1,5 +1,6 @@ // so that users can do `import DefaultTheme from 'vitepress/theme'` import type { ComponentOptions } from 'vue' +import { EnhanceAppContext } from './dist/client/index.js' export const VPHomeHero: ComponentOptions export const VPHomeFeatures: ComponentOptions @@ -13,6 +14,7 @@ export const VPTeamMembers: ComponentOptions declare const theme: { Layout: ComponentOptions NotFound: ComponentOptions + enhanceApp: EnhanceAppContext } export default theme