diff --git a/packages/island/package.json b/packages/island/package.json
index f9e940a3..b3fe22f4 100644
--- a/packages/island/package.json
+++ b/packages/island/package.json
@@ -77,6 +77,7 @@
"lodash-es": "4.17.21",
"mdast-util-mdxjs-esm": "1.3.0",
"medium-zoom": "1.0.6",
+ "nprogress": "^0.2.0",
"ora": "6.1.2",
"picocolors": "1.0.0",
"polka": "0.5.2",
@@ -117,6 +118,7 @@
"@types/koa": "^2.13.5",
"@types/koa-router": "^7.4.4",
"@types/lodash-es": "^4.17.6",
+ "@types/nprogress": "^0.2.0",
"@types/polka": "^0.5.4",
"@types/react": "^18.0.17",
"@types/react-dom": "^18.0.6",
diff --git a/packages/island/src/runtime/Content.tsx b/packages/island/src/runtime/Content.tsx
index ef8634e6..9f577e2d 100644
--- a/packages/island/src/runtime/Content.tsx
+++ b/packages/island/src/runtime/Content.tsx
@@ -1,19 +1,8 @@
-import { useRoutes, useLocation } from 'react-router-dom';
+import { useRoutes } from 'react-router-dom';
import { routes } from 'virtual:routes';
import { Suspense } from 'react';
-interface LocationState {
- from?: string;
-}
-
export const Content = () => {
const routesElement = useRoutes(routes);
- const location = useLocation();
- let prevRouteElement: React.ReactNode = null;
- if (import.meta.env.ENABLE_SPA) {
- const prevRoute = (location.state as LocationState)?.from;
- // eslint-disable-next-line react-hooks/rules-of-hooks
- prevRouteElement = prevRoute ? useRoutes(routes, prevRoute) : null;
- }
- return {routesElement};
+ return {routesElement};
};
diff --git a/packages/island/src/runtime/utils.ts b/packages/island/src/runtime/utils.ts
index 902b5a83..70b6a6f2 100644
--- a/packages/island/src/runtime/utils.ts
+++ b/packages/island/src/runtime/utils.ts
@@ -49,4 +49,8 @@ export function normalizeHref(url?: string) {
return addLeadingSlash(`${url}${suffix}`);
}
+export function normalizeRoutePath(routePath: string) {
+ return routePath.replace(/\.html$/, '').replace(/\/index$/, '/');
+}
+
export { addLeadingSlash, removeTrailingSlash, normalizeSlash };
diff --git a/packages/island/src/theme-default/components/Aside/index.tsx b/packages/island/src/theme-default/components/Aside/index.tsx
index b671300c..28cd4c87 100644
--- a/packages/island/src/theme-default/components/Aside/index.tsx
+++ b/packages/island/src/theme-default/components/Aside/index.tsx
@@ -32,7 +32,6 @@ export function Aside(
}, [headers]);
}
useEffect(() => {
- console.log(props.headers);
setHeaders(props.headers);
}, [props.headers, setHeaders, props.pagePath]);
diff --git a/packages/island/src/theme-default/components/Link/index.tsx b/packages/island/src/theme-default/components/Link/index.tsx
index 69899496..dd5c66f3 100644
--- a/packages/island/src/theme-default/components/Link/index.tsx
+++ b/packages/island/src/theme-default/components/Link/index.tsx
@@ -1,10 +1,16 @@
import React from 'react';
import styles from './index.module.scss';
-import { Link as RouterLink } from 'react-router-dom';
-import { withBase } from '@runtime';
+import {
+ matchRoutes,
+ normalizeRoutePath,
+ useNavigate,
+ withBase
+} from '@runtime';
import { TARGET_BLANK_WHITE_LIST } from '@shared/constants';
-import { inBrowser } from '@shared/utils';
import { EXTERNAL_URL_RE } from '@shared/constants';
+import nprogress from 'nprogress';
+import { routes } from 'virtual:routes';
+import { Route } from 'node/plugin-routes';
export interface LinkProps {
href?: string;
@@ -12,6 +18,8 @@ export interface LinkProps {
className?: string;
}
+nprogress.configure({ showSpinner: false });
+
export function Link(props: LinkProps) {
const { href = '/', children, className = '' } = props;
const isExternal = EXTERNAL_URL_RE.test(href);
@@ -20,19 +28,35 @@ export function Link(props: LinkProps) {
);
const target = isExternal && !isWhiteList ? '_blank' : '';
const rel = isExternal ? 'noopener noreferrer' : undefined;
- const pathname = inBrowser() ? window.location.pathname : '';
const withBaseUrl = isExternal ? href : withBase(href);
+ const navigate = useNavigate();
+
+ const handleNavigate = async (
+ e: React.MouseEvent
+ ) => {
+ e.preventDefault();
+ const matchedRoutes = matchRoutes(routes, normalizeRoutePath(withBaseUrl));
+ if (matchedRoutes?.length) {
+ const timer = setTimeout(() => {
+ nprogress.start();
+ }, 200);
+ await (matchedRoutes[0].route as Route).preload();
+ clearTimeout(timer);
+ nprogress.done();
+ }
+ navigate(withBaseUrl, { replace: false });
+ };
if (import.meta.env.ENABLE_SPA && !isExternal) {
return (
-
{children}
-
+
);
} else {
return (
diff --git a/packages/island/src/theme-default/layout/Layout/index.tsx b/packages/island/src/theme-default/layout/Layout/index.tsx
index 1550fad1..44d13b3d 100644
--- a/packages/island/src/theme-default/layout/Layout/index.tsx
+++ b/packages/island/src/theme-default/layout/Layout/index.tsx
@@ -9,6 +9,7 @@ import { DocLayoutProps } from '../DocLayout/index';
import { HomeLayoutProps } from '../HomeLayout/index';
import type { NavProps } from '../../components/Nav/index';
import { BackTop } from '@back-top';
+import 'nprogress/nprogress.css';
import 'virtual:custom-styles';
export type LayoutProps = {
diff --git a/packages/island/src/theme-default/styles/base.css b/packages/island/src/theme-default/styles/base.css
index bdf1b2d9..cf9ebd84 100644
--- a/packages/island/src/theme-default/styles/base.css
+++ b/packages/island/src/theme-default/styles/base.css
@@ -223,3 +223,12 @@ fieldset {
.medium-zoom-image--opened {
z-index: 999;
}
+
+#nprogress .bar {
+ background: var(--island-c-brand);
+ position: fixed;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 2px;
+}
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index f19d7cb5..28fec581 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -130,6 +130,7 @@ importers:
'@types/koa': ^2.13.5
'@types/koa-router': ^7.4.4
'@types/lodash-es': ^4.17.6
+ '@types/nprogress': ^0.2.0
'@types/polka': ^0.5.4
'@types/react': ^18.0.17
'@types/react-dom': ^18.0.6
@@ -157,6 +158,7 @@ importers:
lodash-es: 4.17.21
mdast-util-mdxjs-esm: 1.3.0
medium-zoom: 1.0.6
+ nprogress: ^0.2.0
ora: 6.1.2
picocolors: 1.0.0
polka: 0.5.2
@@ -218,6 +220,7 @@ importers:
lodash-es: 4.17.21
mdast-util-mdxjs-esm: 1.3.0
medium-zoom: 1.0.6
+ nprogress: 0.2.0
ora: 6.1.2
picocolors: 1.0.0
polka: 0.5.2
@@ -257,6 +260,7 @@ importers:
'@types/koa': 2.13.5
'@types/koa-router': 7.4.4
'@types/lodash-es': 4.17.6
+ '@types/nprogress': 0.2.0
'@types/polka': 0.5.4
'@types/react': 18.0.17
'@types/react-dom': 18.0.6
@@ -1451,6 +1455,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/parse-json/4.0.0:
resolution: {integrity: sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==}
@@ -5613,6 +5621,10 @@ packages:
path-key: 4.0.0
dev: true
+ /nprogress/0.2.0:
+ resolution: {integrity: sha512-I19aIingLgR1fmhftnbWWO3dXc0hSxqHQHQb3H8m+K3TnEn/iSeTZZOyvKXWqQESMwuUVnatlCnZdLBZZt2VSA==}
+ dev: false
+
/object-assign/4.1.1:
resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==}
engines: {node: '>=0.10.0'}