From f40cbcb7990b378599963e7f86944932933fb23d Mon Sep 17 00:00:00 2001 From: mpabarca Date: Mon, 9 Sep 2024 14:16:36 +0200 Subject: [PATCH] Create CustomTopLoader & Add it to RaisedMainContent --- src/app/(authed)/layout.tsx | 28 +---- src/app/layout.tsx | 6 +- src/common/ui/CustomTopLoader/index.tsx | 115 ++++++++++++++++++ .../sidebar/view/internal/ClientSplitView.tsx | 9 +- .../view/internal/secondary/Container.tsx | 51 +++++--- 5 files changed, 162 insertions(+), 47 deletions(-) create mode 100644 src/common/ui/CustomTopLoader/index.tsx diff --git a/src/app/(authed)/layout.tsx b/src/app/(authed)/layout.tsx index 72f56799..4f004aa8 100644 --- a/src/app/(authed)/layout.tsx +++ b/src/app/(authed)/layout.tsx @@ -1,7 +1,6 @@ import { redirect } from "next/navigation" import { SessionProvider } from "next-auth/react" import { session, projectRepository } from "@/composition" -import { Box } from "@mui/material" import ErrorHandler from "@/common/ui/ErrorHandler" import SessionBarrier from "@/features/auth/view/SessionBarrier" import ProjectsContextProvider from "@/features/projects/view/ProjectsContextProvider" @@ -20,9 +19,7 @@ export default async function Layout({ children }: { children: React.ReactNode } - - {children} - + {children} @@ -31,26 +28,3 @@ export default async function Layout({ children }: { children: React.ReactNode } ) } - -const RaisedMainContent = ({ children }: { children?: React.ReactNode }) => { - return ( -
- - - {children} - - -
- ) -} diff --git a/src/app/layout.tsx b/src/app/layout.tsx index 73daefdf..26a9d612 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -5,7 +5,6 @@ import { CssBaseline } from "@mui/material" import ThemeRegistry from "@/common/theme/ThemeRegistry" import "@fortawesome/fontawesome-svg-core/styles.css" import { env } from "@/common" -import NextTopLoader from 'nextjs-toploader' fontAwesomeConfig.autoAddCss = false @@ -19,9 +18,8 @@ export default function RootLayout({ children }: { children: React.ReactNode }) - - - {children} + + {children} diff --git a/src/common/ui/CustomTopLoader/index.tsx b/src/common/ui/CustomTopLoader/index.tsx new file mode 100644 index 00000000..c310c1c7 --- /dev/null +++ b/src/common/ui/CustomTopLoader/index.tsx @@ -0,0 +1,115 @@ +'use client' + +import { useRouter as useNextRouter, usePathname } from 'next/navigation'; +import Router from 'next/router'; +import 'node_modules/nprogress/nprogress.css'; +import NProgress from 'nprogress'; +import { useEffect } from 'react'; + +type CustomTopLoaderProps = { + color?: string; + initialPosition?: number; + crawlSpeed?: number; + height?: number; + crawl?: boolean; + showSpinner?: boolean; + easing?: string; + speed?: number; + shadow?: string | false; + template?: string; + zIndex?: number; + parentSelector?: string; +}; + +const CustomTopLoader: React.FC = ({ + color = '#000', + showSpinner = false, + crawl = true, + crawlSpeed = 600, + easing = 'ease', + speed = 600, + template = '
', + zIndex = 100000000, + parentSelector = 'body', +}) => { + const router = useNextRouter(); + const pathname = usePathname(); + + useEffect(() => { + const initNProgress = () => { + // Ensure the parent exists before configuring NProgress + const parentElement = document.querySelector(parentSelector); + if (!parentElement) { + return; + } + + NProgress.configure({ + parent: parentSelector, + showSpinner, + trickle: crawl, + trickleSpeed: crawlSpeed, + easing, + speed, + template, + }); + + const handleStart = () => { + if (document.querySelector(parentSelector)) { + NProgress.start(); + } + }; + const handleComplete = () => NProgress.done(); + + Router.events.on('routeChangeStart', handleStart); + Router.events.on('routeChangeComplete', handleComplete); + Router.events.on('routeChangeError', handleComplete); + + return () => { + Router.events.off('routeChangeStart', handleStart); + Router.events.off('routeChangeComplete', handleComplete); + Router.events.off('routeChangeError', handleComplete); + NProgress.remove(); // Ensure NProgress cleans up + }; + }; + + // Wait until the parent element appears before initializing NProgress + const waitForParent = setInterval(() => { + if (document.querySelector(parentSelector)) { + clearInterval(waitForParent); + initNProgress(); + } + }, 100); // Checks every 100ms + + return () => clearInterval(waitForParent); + }, [ + router, + parentSelector, + showSpinner, + crawl, + crawlSpeed, + easing, + speed, + template, + ]); + + // Re-run when the pathname changes to ensure progress bar finishes loading + useEffect(() => { + NProgress.done(); + }, [pathname]); + + return ( + + ) +}; + +export default CustomTopLoader; \ No newline at end of file diff --git a/src/features/sidebar/view/internal/ClientSplitView.tsx b/src/features/sidebar/view/internal/ClientSplitView.tsx index 209e5800..38c6735f 100644 --- a/src/features/sidebar/view/internal/ClientSplitView.tsx +++ b/src/features/sidebar/view/internal/ClientSplitView.tsx @@ -1,7 +1,7 @@ "use client" import { useEffect, useContext } from "react" -import { Stack } from "@mui/material" +import { Stack, useMediaQuery, useTheme } from "@mui/material" import { isMac, useKeyboardShortcut, SidebarTogglableContext } from "@/common" import { useSidebarOpen } from "../../data" import PrimaryContainer from "./primary/Container" @@ -16,6 +16,10 @@ const ClientSplitView = ({ }) => { const [isSidebarOpen, setSidebarOpen] = useSidebarOpen() const isSidebarTogglable = useContext(SidebarTogglableContext) + const theme = useTheme() + // Determine if the screen size is small or larger + const isSM = useMediaQuery(theme.breakpoints.up("sm")) + useEffect(() => { if (!isSidebarTogglable && !isSidebarOpen) { setSidebarOpen(true) @@ -31,6 +35,7 @@ const ClientSplitView = ({ } }, [isSidebarTogglable, setSidebarOpen]) const sidebarWidth = 320 + return ( {sidebar} - + {children} diff --git a/src/features/sidebar/view/internal/secondary/Container.tsx b/src/features/sidebar/view/internal/secondary/Container.tsx index 7de24922..999b61a6 100644 --- a/src/features/sidebar/view/internal/secondary/Container.tsx +++ b/src/features/sidebar/view/internal/secondary/Container.tsx @@ -1,30 +1,26 @@ import { SxProps } from "@mui/system" -import { Stack } from "@mui/material" +import { Box, Stack } from "@mui/material" import { styled } from "@mui/material/styles" +import CustomTopLoader from "@/common/ui/CustomTopLoader" const SecondaryContainer = ({ sidebarWidth, offsetContent, - children + children, + isSM, }: { sidebarWidth: number offsetContent: boolean - children?: React.ReactNode + children?: React.ReactNode, + isSM: boolean, }) => { const sx = { overflow: "hidden" } return ( <> <_SecondaryContainer - sidebarWidth={0} - isSidebarOpen={false} - sx={{ ...sx, display: { xs: "flex", sm: "none" } }} - > - {children} - - <_SecondaryContainer - sidebarWidth={sidebarWidth} - isSidebarOpen={offsetContent} - sx={{ ...sx, display: { xs: "none", sm: "flex" } }} + sidebarWidth={isSM ? sidebarWidth : 0} + isSidebarOpen={isSM ? offsetContent: false} + sx={{ ...sx }} > {children} @@ -74,8 +70,35 @@ const _SecondaryContainer = ({ sidebarWidth={sidebarWidth} isSidebarOpen={isSidebarOpen} sx={{ ...sx, width: "100%", overflowY: "auto" }} + > - {children} + + {children} + ) } + +const RaisedMainContent = ({ children }: { children?: React.ReactNode }) => { + return ( +
+ + + + {children} + + +
+ ) +}