Skip to content

Commit

Permalink
Implement a half decent top loading bar
Browse files Browse the repository at this point in the history
Before we were using a full screen opacity change and that's proving
disruptive to the user experience. I think it's better to simply show
the loader on the top after ~500 milliseconds of waiting for navigation
to go idle
  • Loading branch information
dvnrsn committed Dec 6, 2023
1 parent e642d2a commit 5c4aa14
Show file tree
Hide file tree
Showing 5 changed files with 47 additions and 17 deletions.
28 changes: 28 additions & 0 deletions app/components/global-loading-bar.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { useNavigation } from "@remix-run/react";
import { useEffect, useRef } from "react";
import LoadingBar, { LoadingBarRef } from "react-top-loading-bar";

export function GlobalLoadingBar() {
const navigation = useNavigation();

const loadingBarRef = useRef<LoadingBarRef>(null);
const loaderStarted = useRef(false);

useEffect(() => {
let timeout: ReturnType<typeof setTimeout> | undefined;
if (navigation.state !== "idle") {
timeout = setTimeout(() => {
if (!loadingBarRef.current) return;
loaderStarted.current = true;
loadingBarRef.current.continuousStart();
}, 400);
} else if (loaderStarted.current == true) {
loaderStarted.current = false;
loadingBarRef.current?.complete();
}
return () => {
if (timeout) clearTimeout(timeout);
};
}, [navigation.state]);
return <LoadingBar ref={loadingBarRef} />;
}
17 changes: 6 additions & 11 deletions app/root.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@ import {
Scripts,
ScrollRestoration,
useLoaderData,
useNavigation,
} from "@remix-run/react";
import { HoneypotProvider } from "remix-utils/honeypot/react";

import stylesheet from "~/tailwind.css";

import { GlobalLoadingBar } from "./components/global-loading-bar";
import { honeypot } from "./honeypot.server";
import { authenticator } from "./session.server";

Expand All @@ -32,7 +32,7 @@ export const loader = async ({ request }: LoaderFunctionArgs) => {

export default function App() {
const { honeypotInputProps } = useLoaderData<typeof loader>();
const navigation = useNavigation();

return (
<html lang="en" className="h-full">
<head>
Expand All @@ -42,15 +42,10 @@ export default function App() {
<Links />
</head>
<body className="h-full">
<div
className={`h-full ${
navigation.state === "loading" ? "loading" : ""
}`}
>
<HoneypotProvider {...honeypotInputProps}>
<Outlet />
</HoneypotProvider>
</div>
<GlobalLoadingBar />
<HoneypotProvider {...honeypotInputProps}>
<Outlet />
</HoneypotProvider>
<ScrollRestoration />
<Scripts />
<LiveReload />
Expand Down
6 changes: 0 additions & 6 deletions app/tailwind.css
Original file line number Diff line number Diff line change
Expand Up @@ -99,9 +99,3 @@ input[type="search"]::-webkit-search-results-decoration {
transform-origin: bottom left;
animation-delay: 0.5s;
}

.loading {
opacity: 0.25;
transition: opacity 200ms;
transition-delay: 200ms;
}
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-icons": "^4.11.0",
"react-top-loading-bar": "^2.3.1",
"remix-auth": "^3.6.0",
"remix-auth-form": "^1.4.0",
"remix-auth-socials": "^2.0.5",
Expand Down
12 changes: 12 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 5c4aa14

Please sign in to comment.