From a86819ea3da36cba074cd24b5bf65336ab321f5b Mon Sep 17 00:00:00 2001 From: Hakim Gueye Date: Sat, 23 Sep 2023 12:16:49 +0000 Subject: [PATCH 1/5] Adding NProgress for Improved Loading Progress Management This PR aims to enhance the user experience by adding the NProgress library to our project. NProgress is a lightweight tool that provides an elegant and responsive loading progress bar, which will help users better understand the status of ongoing operations. --- app/root.tsx | 18 ++++++++++++------ package-lock.json | 13 +++++++++++++ package.json | 2 ++ 3 files changed, 27 insertions(+), 6 deletions(-) diff --git a/app/root.tsx b/app/root.tsx index 851617e7..2cf10e3c 100644 --- a/app/root.tsx +++ b/app/root.tsx @@ -1,3 +1,5 @@ +import 'nprogress/nprogress.css' + import { useForm } from '@conform-to/react' import { parse } from '@conform-to/zod' import { cssBundleHref } from '@remix-run/css-bundle' @@ -21,10 +23,12 @@ import { useFetchers, useLoaderData, useMatches, + useNavigation, useSubmit, } from '@remix-run/react' import { withSentry } from '@sentry/remix' -import { useRef } from 'react' +import NProgress from 'nprogress' +import { useEffect, useRef } from 'react' import { z } from 'zod' import { Confetti } from './components/confetti.tsx' import { GeneralErrorBoundary } from './components/error-boundary.tsx' @@ -47,11 +51,7 @@ import { ClientHintCheck, getHints, useHints } from './utils/client-hints.tsx' import { getConfetti } from './utils/confetti.server.ts' import { prisma } from './utils/db.server.ts' import { getEnv } from './utils/env.server.ts' -import { - combineHeaders, - getDomainUrl, - getUserImgSrc, -} from './utils/misc.tsx' +import { combineHeaders, getDomainUrl, getUserImgSrc } from './utils/misc.tsx' import { useNonce } from './utils/nonce-provider.ts' import { useRequestInfo } from './utils/request-info.ts' import { type Theme, setTheme, getTheme } from './utils/theme.server.ts' @@ -231,8 +231,14 @@ function App() { const user = useOptionalUser() const theme = useTheme() const matches = useMatches() + const transition = useNavigation() const isOnSearchPage = matches.find(m => m.id === 'routes/users+/index') + useEffect(() => { + if (transition.state === 'idle') NProgress.done() + else NProgress.start() + }, [transition.state]) + return (
diff --git a/package-lock.json b/package-lock.json index 3f4cdb9d..2b10aa8e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -53,6 +53,7 @@ "litefs-js": "^1.1.2", "lru-cache": "^10.0.1", "morgan": "^1.10.0", + "nprogress": "^0.2.0", "prisma": "^5.3.1", "qrcode": "^1.5.3", "react": "^18.2.0", @@ -93,6 +94,7 @@ "@types/glob": "^8.1.0", "@types/morgan": "^1.9.5", "@types/node": "^20.6.2", + "@types/nprogress": "^0.2.0", "@types/qrcode": "^1.5.2", "@types/react": "^18.2.22", "@types/react-dom": "^18.2.7", @@ -5184,6 +5186,12 @@ "integrity": "sha512-Y+/1vGBHV/cYk6OI1Na/LHzwnlNCAfU3ZNGrc1LdRe/LAIbdDPTTv/HU3M7yXN448aTVDq3eKRm2cg7iKLb8gw==", "dev": true }, + "node_modules/@types/nprogress": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@types/nprogress/-/nprogress-0.2.0.tgz", + "integrity": "sha512-1cYJrqq9GezNFPsWTZpFut/d4CjpZqA0vhqDUPFWYKF1oIyBz5qnoYMzR+0C/T96t3ebLAC1SSnwrVOm5/j74A==", + "dev": true + }, "node_modules/@types/prop-types": { "version": "15.7.5", "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz", @@ -13942,6 +13950,11 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/nprogress": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/nprogress/-/nprogress-0.2.0.tgz", + "integrity": "sha512-I19aIingLgR1fmhftnbWWO3dXc0hSxqHQHQb3H8m+K3TnEn/iSeTZZOyvKXWqQESMwuUVnatlCnZdLBZZt2VSA==" + }, "node_modules/nth-check": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", diff --git a/package.json b/package.json index c7a53691..072181fc 100644 --- a/package.json +++ b/package.json @@ -86,6 +86,7 @@ "litefs-js": "^1.1.2", "lru-cache": "^10.0.1", "morgan": "^1.10.0", + "nprogress": "^0.2.0", "prisma": "^5.3.1", "qrcode": "^1.5.3", "react": "^18.2.0", @@ -126,6 +127,7 @@ "@types/glob": "^8.1.0", "@types/morgan": "^1.9.5", "@types/node": "^20.6.2", + "@types/nprogress": "^0.2.0", "@types/qrcode": "^1.5.2", "@types/react": "^18.2.22", "@types/react-dom": "^18.2.7", From 9cd63a858488fa9f4372851c3e104fd86a771196 Mon Sep 17 00:00:00 2001 From: Hakim Gueye Date: Sun, 24 Sep 2023 02:13:43 +0000 Subject: [PATCH 2/5] remove nprogress --- app/root.tsx | 12 +----------- package-lock.json | 13 ------------- package.json | 2 -- 3 files changed, 1 insertion(+), 26 deletions(-) diff --git a/app/root.tsx b/app/root.tsx index 2cf10e3c..77081641 100644 --- a/app/root.tsx +++ b/app/root.tsx @@ -1,5 +1,3 @@ -import 'nprogress/nprogress.css' - import { useForm } from '@conform-to/react' import { parse } from '@conform-to/zod' import { cssBundleHref } from '@remix-run/css-bundle' @@ -23,12 +21,10 @@ import { useFetchers, useLoaderData, useMatches, - useNavigation, useSubmit, } from '@remix-run/react' import { withSentry } from '@sentry/remix' -import NProgress from 'nprogress' -import { useEffect, useRef } from 'react' +import { useRef } from 'react' import { z } from 'zod' import { Confetti } from './components/confetti.tsx' import { GeneralErrorBoundary } from './components/error-boundary.tsx' @@ -231,14 +227,8 @@ function App() { const user = useOptionalUser() const theme = useTheme() const matches = useMatches() - const transition = useNavigation() const isOnSearchPage = matches.find(m => m.id === 'routes/users+/index') - useEffect(() => { - if (transition.state === 'idle') NProgress.done() - else NProgress.start() - }, [transition.state]) - return (
diff --git a/package-lock.json b/package-lock.json index 2b10aa8e..3f4cdb9d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -53,7 +53,6 @@ "litefs-js": "^1.1.2", "lru-cache": "^10.0.1", "morgan": "^1.10.0", - "nprogress": "^0.2.0", "prisma": "^5.3.1", "qrcode": "^1.5.3", "react": "^18.2.0", @@ -94,7 +93,6 @@ "@types/glob": "^8.1.0", "@types/morgan": "^1.9.5", "@types/node": "^20.6.2", - "@types/nprogress": "^0.2.0", "@types/qrcode": "^1.5.2", "@types/react": "^18.2.22", "@types/react-dom": "^18.2.7", @@ -5186,12 +5184,6 @@ "integrity": "sha512-Y+/1vGBHV/cYk6OI1Na/LHzwnlNCAfU3ZNGrc1LdRe/LAIbdDPTTv/HU3M7yXN448aTVDq3eKRm2cg7iKLb8gw==", "dev": true }, - "node_modules/@types/nprogress": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/@types/nprogress/-/nprogress-0.2.0.tgz", - "integrity": "sha512-1cYJrqq9GezNFPsWTZpFut/d4CjpZqA0vhqDUPFWYKF1oIyBz5qnoYMzR+0C/T96t3ebLAC1SSnwrVOm5/j74A==", - "dev": true - }, "node_modules/@types/prop-types": { "version": "15.7.5", "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz", @@ -13950,11 +13942,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/nprogress": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/nprogress/-/nprogress-0.2.0.tgz", - "integrity": "sha512-I19aIingLgR1fmhftnbWWO3dXc0hSxqHQHQb3H8m+K3TnEn/iSeTZZOyvKXWqQESMwuUVnatlCnZdLBZZt2VSA==" - }, "node_modules/nth-check": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", diff --git a/package.json b/package.json index 072181fc..c7a53691 100644 --- a/package.json +++ b/package.json @@ -86,7 +86,6 @@ "litefs-js": "^1.1.2", "lru-cache": "^10.0.1", "morgan": "^1.10.0", - "nprogress": "^0.2.0", "prisma": "^5.3.1", "qrcode": "^1.5.3", "react": "^18.2.0", @@ -127,7 +126,6 @@ "@types/glob": "^8.1.0", "@types/morgan": "^1.9.5", "@types/node": "^20.6.2", - "@types/nprogress": "^0.2.0", "@types/qrcode": "^1.5.2", "@types/react": "^18.2.22", "@types/react-dom": "^18.2.7", From c233ce56949097c3da21f5973a8c0af2ba449208 Mon Sep 17 00:00:00 2001 From: Hakim Gueye Date: Sun, 24 Sep 2023 02:18:01 +0000 Subject: [PATCH 3/5] add epic progress bar example --- docs/examples.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/examples.md b/docs/examples.md index 6f6892d3..ee801728 100644 --- a/docs/examples.md +++ b/docs/examples.md @@ -59,6 +59,8 @@ This page links to examples of how to implement some things with the Epic Stack. [@rperon](https://github.com/rperon): An example of the Epic Stack with i18n using [i18next](https://www.i18next.com/) and [remix-18next](https://github.com/sergiodxa/remix-i18next) +- [Epic Stack + Progress Bar](https://github.com/hakimLyon/epic-stack-progress-bar) + by [@hakimLyon](https://github.com/hakimLyon): An example of the Epic Stack with Progress Bar ## How to contribute From e3e0993566d36c613d77d15d7beab90785c075b6 Mon Sep 17 00:00:00 2001 From: Hakim Gueye Date: Tue, 26 Sep 2023 10:19:31 +0000 Subject: [PATCH 4/5] remove epic progress example --- docs/examples.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/docs/examples.md b/docs/examples.md index c1eff0bf..79eb0524 100644 --- a/docs/examples.md +++ b/docs/examples.md @@ -64,8 +64,6 @@ This page links to examples of how to implement some things with the Epic Stack. with [Argos](https://www.argos-ci.com/) for visual testing - [Epic Stack monorepo with pnpm + turbo](https://github.com/PhilDL/epic-stack-monorepo): An example of the Epic Stack in a monorepo setup, configs packages, UI package, and "client-hints" example package. -- [Epic Stack + Progress Bar](https://github.com/hakimLyon/epic-stack-progress-bar) - by [@hakimLyon](https://github.com/hakimLyon): An example of the Epic Stack with Progress Bar ## How to contribute From ccaa5853539935cd6bd501203c41faf3b7d74289 Mon Sep 17 00:00:00 2001 From: Hakim Gueye Date: Tue, 26 Sep 2023 10:31:11 +0000 Subject: [PATCH 5/5] add epic progress bar --- app/components/progess-bar.tsx | 58 ++++++++++++++++++++++++++++++++++ app/components/spinner.tsx | 12 +++++-- app/root.tsx | 2 ++ 3 files changed, 70 insertions(+), 2 deletions(-) create mode 100644 app/components/progess-bar.tsx diff --git a/app/components/progess-bar.tsx b/app/components/progess-bar.tsx new file mode 100644 index 00000000..be000b28 --- /dev/null +++ b/app/components/progess-bar.tsx @@ -0,0 +1,58 @@ +import { useNavigation } from '@remix-run/react' +import React, { useEffect, useRef, useState } from 'react' +import { useSpinDelay } from 'spin-delay' +import { cn } from '#app/utils/misc.tsx' +import { Spinner } from './spinner.tsx' + +function EpicProgress() { + const transition = useNavigation() + const busy = transition.state !== 'idle' + const delayedPending = useSpinDelay(busy, { + delay: 400, + minDuration: 300, + }) + const ref = useRef(null) + const [animationComplete, setAnimationComplete] = useState(true) + + useEffect(() => { + if (!ref.current) return + if (delayedPending) setAnimationComplete(false) + + const animationPromises = ref.current + .getAnimations() + .map(({ finished }) => finished) + + Promise.allSettled(animationPromises).then(() => { + if (!delayedPending) setAnimationComplete(true) + }) + }, [delayedPending]) + + return ( +
+
+ {delayedPending && ( +
+ +
+ )} +
+ ) +} + +export { EpicProgress } diff --git a/app/components/spinner.tsx b/app/components/spinner.tsx index c8b0d7b5..d7a4c324 100644 --- a/app/components/spinner.tsx +++ b/app/components/spinner.tsx @@ -1,4 +1,12 @@ -export function Spinner({ showSpinner }: { showSpinner: boolean }) { +import { cn } from '#app/utils/misc.tsx' + +export function Spinner({ + showSpinner, + className = '', +}: { + showSpinner: boolean + className?: string +}) { return (
+ ) }