From 218ee462f040ffaaf647ce35db5ad4dc46f9d4d5 Mon Sep 17 00:00:00 2001 From: Alvalen Date: Sun, 3 Sep 2023 13:23:39 +0700 Subject: [PATCH] [feat] add loading screen and bar --- app/(root)/layout.js | 6 +- app/(root)/loading.js | 16 ++- app/(root)/page.js | 21 ++-- app/about/loading.js | 11 ++ app/about/page.js | 19 ++-- app/globals.css | 6 +- app/layout.js | 8 +- app/nprogress.css | 84 ++++++++++++++ app/projects/loading.js | 11 ++ app/projects/page.js | 33 +++--- components/Hr.jsx | 2 +- components/Navbar.js | 199 ++++++++++++++++++++-------------- components/TopProgressbar.jsx | 64 +++++++++++ package.json | 1 + pnpm-lock.yaml | 7 ++ 15 files changed, 354 insertions(+), 134 deletions(-) create mode 100644 app/about/loading.js create mode 100644 app/nprogress.css create mode 100644 app/projects/loading.js create mode 100644 components/TopProgressbar.jsx diff --git a/app/(root)/layout.js b/app/(root)/layout.js index ec2d245..9855954 100644 --- a/app/(root)/layout.js +++ b/app/(root)/layout.js @@ -1,9 +1,5 @@ -import "../globals.css"; +"use client" import Sidebar from "@/components/Sidebar"; -import { config } from "@fortawesome/fontawesome-svg-core"; -import "@fortawesome/fontawesome-svg-core/styles.css"; -config.autoAddCss = false; - export const metadata = { title: "Create Next App", description: "Generated by create next app", diff --git a/app/(root)/loading.js b/app/(root)/loading.js index 80435f8..1e45184 100644 --- a/app/(root)/loading.js +++ b/app/(root)/loading.js @@ -1,7 +1,11 @@ export default function Loading() { - return ( -
-

Loading...

-
- ) -} \ No newline at end of file + return ( + <> + ( +
+

Loading...

+
+ ) + + ); +} diff --git a/app/(root)/page.js b/app/(root)/page.js index 2bccf85..2b91656 100644 --- a/app/(root)/page.js +++ b/app/(root)/page.js @@ -4,6 +4,7 @@ import Image from "next/image"; import "../globals.css"; import { motion } from "framer-motion"; import Link from "next/link"; + // components import Button from "@/components/Button"; import Me from "../../public/img/me.jpg"; @@ -23,6 +24,8 @@ const MyPage = () => { scrollingSpeed: 1000, licenseKey: "gplv3-license", menu: "#sidebar", + lockAnchors: false, + }; return ( @@ -168,7 +171,7 @@ const MyPage = () => { interest. { type: "spring", }}> -
+
{ done and currently working on. {
-
+
{ { { { { + ( +
+

Loading...

+
+ ) + + ); +} diff --git a/app/about/page.js b/app/about/page.js index d7349da..4063578 100644 --- a/app/about/page.js +++ b/app/about/page.js @@ -1,4 +1,5 @@ "use client"; +import { useEffect } from "react"; import Link from "next/link"; import { motion } from "framer-motion"; import Button from "@/components/Button"; @@ -11,9 +12,9 @@ import Me1 from "@/public/img/me1.jpg"; import Me2 from "@/public/img/me2.jpg"; import Me3 from "@/public/img/me3.jpg"; export default function Page() { - // useEffect(() => { - // window.scrollTo(0, 0); - // }, []); + useEffect(() => { + window.scrollTo(0, 0); + }, []); return ( <> @@ -21,9 +22,9 @@ export default function Page() {
@@ -38,9 +39,9 @@ export default function Page() { A brief introduction about me and my interest.

{ window.scrollTo({ top: 1000, diff --git a/app/globals.css b/app/globals.css index 4738127..d94326b 100644 --- a/app/globals.css +++ b/app/globals.css @@ -26,6 +26,7 @@ html { body { font-family: 'Poppins', sans-serif !important; color: black; + background-color: #f6f6f6; } h1, h2, h3, h4, h5, h6 { @@ -82,5 +83,6 @@ a[title]:hover:after { border-radius: 4px; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2); font-size: 0.8rem; - -} \ No newline at end of file + +} + diff --git a/app/layout.js b/app/layout.js index 7d9f371..9b27e21 100644 --- a/app/layout.js +++ b/app/layout.js @@ -1,20 +1,22 @@ +"use client"; import "./globals.css"; import Navbar from "@/components/Navbar"; -import Sidebar from "@/components/Sidebar"; import { config } from '@fortawesome/fontawesome-svg-core' import '@fortawesome/fontawesome-svg-core/styles.css' config.autoAddCss = false + +import TopProgressBar from "@/components/TopProgressBar"; +import "./nprogress.css"; export const metadata = { title: "Create Next App", description: "Generated by create next app", }; - export default function RootLayout({ children }) { - return ( + {children} diff --git a/app/nprogress.css b/app/nprogress.css new file mode 100644 index 0000000..79bf222 --- /dev/null +++ b/app/nprogress.css @@ -0,0 +1,84 @@ +/* Make clicks pass-through */ +#nprogress { + pointer-events: none; +} + +#nprogress .bar { + background: rgb(42, 42, 42); + + position: fixed; + z-index: 1031; + top: 0; + left: 0; + + width: 100%; + height: 5px; +} + +/* Fancy blur effect */ +#nprogress .peg { + display: block; + position: absolute; + right: 0px; + width: 100px; + height: 100%; + box-shadow: 0 0 10px rgb(147, 147, 147), 0 0 5px rgb(147, 147, 147); + opacity: 1.0; + + -webkit-transform: rotate(3deg) translate(0px, -4px); + -ms-transform: rotate(3deg) translate(0px, -4px); + transform: rotate(3deg) translate(0px, -4px); +} + +/* Remove these to get rid of the spinner */ +#nprogress .spinner { + display: block; + position: fixed; + z-index: 1031; + top: 15px; + right: 15px; +} + +#nprogress .spinner-icon { + width: 18px; + height: 18px; + box-sizing: border-box; + + border: solid 2px transparent; + border-top-color: rgb(73, 73, 73); + border-left-color: rgb(67, 67, 67); + border-radius: 50%; + + -webkit-animation: nprogress-spinner 400ms linear infinite; + animation: nprogress-spinner 400ms linear infinite; +} + +.nprogress-custom-parent { + overflow: hidden; + position: fixed; +} + +.nprogress-custom-parent #nprogress .spinner, +.nprogress-custom-parent #nprogress .bar { + position: absolute; +} + +@-webkit-keyframes nprogress-spinner { + 0% { + -webkit-transform: rotate(0deg); + } + + 100% { + -webkit-transform: rotate(360deg); + } +} + +@keyframes nprogress-spinner { + 0% { + transform: rotate(0deg); + } + + 100% { + transform: rotate(360deg); + } +} \ No newline at end of file diff --git a/app/projects/loading.js b/app/projects/loading.js new file mode 100644 index 0000000..1e45184 --- /dev/null +++ b/app/projects/loading.js @@ -0,0 +1,11 @@ +export default function Loading() { + return ( + <> + ( +
+

Loading...

+
+ ) + + ); +} diff --git a/app/projects/page.js b/app/projects/page.js index 044bcca..3543b1b 100644 --- a/app/projects/page.js +++ b/app/projects/page.js @@ -1,4 +1,5 @@ "use client"; +import { useEffect } from "react"; import Link from "next/link"; import { motion } from "framer-motion"; import Button from "@/components/Button"; @@ -14,9 +15,9 @@ const projects = () => { }; export default function Page() { - // useEffect(() => { - // window.scrollTo(0, 0); - // }, []); + useEffect(() => { + window.scrollTo(0, 0); + }, []); return ( <> @@ -24,9 +25,9 @@ export default function Page() {
@@ -44,7 +45,7 @@ export default function Page() { { window.scrollTo({ top: 1000, @@ -122,7 +123,6 @@ export default function Page() { }} transition={{ delay: 0.5, - }} className="w-full h-full">

@@ -184,7 +184,7 @@ export default function Page() { }} transition={{ delay: 0.5, - + type: "spring", }}> Other Note Worthy Projects @@ -283,13 +283,10 @@ export default function Page() {

{/* view in archive btn */}
- +
- ); diff --git a/components/Hr.jsx b/components/Hr.jsx index 84ab90e..6625452 100644 --- a/components/Hr.jsx +++ b/components/Hr.jsx @@ -7,7 +7,7 @@ export default function Hr() { className="bg-gray-700 w-20 h-1 rounded-full mb-2" initial={{ opacity: 0, - x: -100, + x: -50, }} whileInView={{ opacity: 1, diff --git a/components/Navbar.js b/components/Navbar.js index 739934b..a728369 100644 --- a/components/Navbar.js +++ b/components/Navbar.js @@ -3,8 +3,12 @@ import { useRef, useState, useEffect } from "react"; import { motion } from "framer-motion"; import Link from "next/link"; -const NavItems = ({ isNavOpen }) => { -const [isMobile, setIsMobile] = useState(false); +const NavItems = ({ isNavOpen, setIsNavOpen }) => { + const [isMobile, setIsMobile] = useState(false); + + const handleItemClick = () => { + setIsNavOpen(false); + }; const navVariant = { open: (height = 1000) => ({ clipPath: `circle(${height + 400}px at calc(100% - 40px) 40px)`, @@ -24,43 +28,43 @@ const [isMobile, setIsMobile] = useState(false); }, }, }; -useEffect(() => { - const updateScreenWidth = () => { - setIsMobile(window.innerWidth <= 768); - }; + useEffect(() => { + const updateScreenWidth = () => { + setIsMobile(window.innerWidth <= 768); + }; - // Initial check and event listener - updateScreenWidth(); - window.addEventListener("resize", updateScreenWidth); + // Initial check and event listener + updateScreenWidth(); + window.addEventListener("resize", updateScreenWidth); - // Clean up the event listener on unmount - return () => { - window.removeEventListener("resize", updateScreenWidth); - }; -}, []); + // Clean up the event listener on unmount + return () => { + window.removeEventListener("resize", updateScreenWidth); + }; + }, []); -// Check screen width and adjust clipPath for smaller screens -if (isMobile) { - navVariant.closed = { - clipPath: "circle(0px at calc(100% - 35px) 35px)", // Adjusted value for mobile screens - transition: { - delay: 0.5, - type: "spring", - stiffness: 400, - damping: 40, - }, - }; -} else { - navVariant.closed = { - clipPath: "circle(0px at calc(100% - 120px) 35px)", - transition: { - delay: 0.5, - type: "spring", - stiffness: 400, - damping: 40, - }, - }; -} + // Check screen width and adjust clipPath for smaller screens + if (isMobile) { + navVariant.closed = { + clipPath: "circle(0px at calc(100% - 35px) 35px)", // Adjusted value for mobile screens + transition: { + delay: 0.5, + type: "spring", + stiffness: 400, + damping: 40, + }, + }; + } else { + navVariant.closed = { + clipPath: "circle(0px at calc(100% - 120px) 35px)", + transition: { + delay: 0.5, + type: "spring", + stiffness: 400, + damping: 40, + }, + }; + } const itemVariants = { open: { opacity: 1, @@ -74,9 +78,6 @@ if (isMobile) { }, }; - - - return ( <>
-
- {/* title */} - - Menu - - -
- - Home - -
- - -
- - About - -
- - -
- - Projects - -
- - -
- - Contact - -
- -
-
+
+ {/* title */} + + Menu + + +
+ + Home + +
+
+ +
+ + About + +
+ + +
+ + Projects + +
+ + +
+ + Contact + +
+
+
+
); @@ -141,11 +174,12 @@ const Navbar = () => { <> {/* items */} - + ); }; diff --git a/components/TopProgressbar.jsx b/components/TopProgressbar.jsx new file mode 100644 index 0000000..9851b85 --- /dev/null +++ b/components/TopProgressbar.jsx @@ -0,0 +1,64 @@ +import Router from "next/router"; +import NProgress from "nprogress"; + +let timer; +let state; +let activeRequests = 0; + +function load() { + if (state === "loading") { + return; + } + + state = "loading"; + + timer = setTimeout(() => { + NProgress.start(); + }, 1); +} + +function stop() { + if (activeRequests > 0) { + return; + } + + state = "stop"; + + clearTimeout(timer); + NProgress.done(); +} + +function routeChangeStart() { + if (window.location.pathname !== Router.pathname) { + load(); + } +} + +Router.events.on("routeChangeStart", routeChangeStart); +Router.events.on("routeChangeComplete", stop); +Router.events.on("routeChangeError", stop); + +const originalFetch = window.fetch; +window.fetch = async function (...args) { + if (activeRequests === 0) { + load(); + } + + activeRequests++; + + try { + const response = await originalFetch(...args); + return response; + } catch (error) { + return Promise.reject(error); + } finally { + activeRequests -= 1; + if (activeRequests === 0) { + stop(); + } + } +}; + +export default function TopProgressbar() { + return null; +} diff --git a/package.json b/package.json index 2870ffd..13d0c8f 100644 --- a/package.json +++ b/package.json @@ -20,6 +20,7 @@ "eslint-config-next": "13.4.19", "framer-motion": "^10.16.2", "next": "13.4.19", + "nprogress": "^0.2.0", "postcss": "8.4.28", "react": "18.2.0", "react-dom": "18.2.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 6aac832..20db1fe 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -38,6 +38,9 @@ dependencies: next: specifier: 13.4.19 version: 13.4.19(react-dom@18.2.0)(react@18.2.0) + nprogress: + specifier: ^0.2.0 + version: 0.2.0 postcss: specifier: 8.4.28 version: 8.4.28 @@ -1896,6 +1899,10 @@ packages: engines: {node: '>=0.10.0'} dev: false + /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'}