Skip to content

Commit

Permalink
Create CustomTopLoader & Add it to RaisedMainContent
Browse files Browse the repository at this point in the history
  • Loading branch information
mpabarca committed Sep 10, 2024
1 parent e3adc46 commit f40cbcb
Show file tree
Hide file tree
Showing 5 changed files with 162 additions and 47 deletions.
28 changes: 1 addition & 27 deletions src/app/(authed)/layout.tsx
Original file line number Diff line number Diff line change
@@ -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"
Expand All @@ -20,9 +19,7 @@ export default async function Layout({ children }: { children: React.ReactNode }
<ProjectsContextProvider initialProjects={projects}>
<SidebarTogglableContextProvider>
<SplitView>
<RaisedMainContent>
{children}
</RaisedMainContent>
{children}
</SplitView>
</SidebarTogglableContextProvider>
</ProjectsContextProvider>
Expand All @@ -31,26 +28,3 @@ export default async function Layout({ children }: { children: React.ReactNode }
</ErrorHandler>
)
}

const RaisedMainContent = ({ children }: { children?: React.ReactNode }) => {
return (
<main style={{ flexGrow: "1" }}>
<Box sx={{
height: "100%",
paddingTop: { xs: 0, sm: 2 },
marginLeft: { xs: 0, sm: 2 },
marginRight: { xs: 0, sm: 2 }
}}>
<Box sx={{
height: "100%",
background: "white",
boxShadow: { xs: 0, sm: "0 4px 8px rgba(0, 0, 0, 0.08)" },
borderTopLeftRadius: { xs: 0, sm: "18px" },
borderTopRightRadius: { xs: 0, sm: "18px" }
}}>
{children}
</Box>
</Box>
</main>
)
}
6 changes: 2 additions & 4 deletions src/app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -19,9 +18,8 @@ export default function RootLayout({ children }: { children: React.ReactNode })
<html lang="en">
<ThemeRegistry options={{ key: "mui" }}>
<body>
<CssBaseline/>
<NextTopLoader color="#000" height={1} showSpinner={false} speed={600} zIndex={10000} />
{children}
<CssBaseline/>
{children}
</body>
</ThemeRegistry>
</html>
Expand Down
115 changes: 115 additions & 0 deletions src/common/ui/CustomTopLoader/index.tsx
Original file line number Diff line number Diff line change
@@ -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<CustomTopLoaderProps> = ({
color = '#000',
showSpinner = false,
crawl = true,
crawlSpeed = 600,
easing = 'ease',
speed = 600,
template = '<div class="bar" role="bar"><div class="peg"></div></div><div class="spinner" role="spinner"><div class="spinner-icon"></div></div>',
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 (
<style>
{`
#nprogress .bar {
background-color: ${color};
z-index: ${zIndex}
}
#nprogress .peg {
display: none;
}
`}
</style>
)
};

export default CustomTopLoader;
9 changes: 7 additions & 2 deletions src/features/sidebar/view/internal/ClientSplitView.tsx
Original file line number Diff line number Diff line change
@@ -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"
Expand All @@ -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)
Expand All @@ -31,6 +35,7 @@ const ClientSplitView = ({
}
}, [isSidebarTogglable, setSidebarOpen])
const sidebarWidth = 320

return (
<Stack direction="row" spacing={0} sx={{ width: "100%", height: "100%" }}>
<PrimaryContainer
Expand All @@ -40,7 +45,7 @@ const ClientSplitView = ({
>
{sidebar}
</PrimaryContainer>
<SecondaryContainer sidebarWidth={sidebarWidth} offsetContent={isSidebarOpen}>
<SecondaryContainer isSM={isSM} sidebarWidth={sidebarWidth} offsetContent={isSidebarOpen}>
{children}
</SecondaryContainer>
</Stack>
Expand Down
51 changes: 37 additions & 14 deletions src/features/sidebar/view/internal/secondary/Container.tsx
Original file line number Diff line number Diff line change
@@ -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>
<_SecondaryContainer
sidebarWidth={sidebarWidth}
isSidebarOpen={offsetContent}
sx={{ ...sx, display: { xs: "none", sm: "flex" } }}
sidebarWidth={isSM ? sidebarWidth : 0}
isSidebarOpen={isSM ? offsetContent: false}
sx={{ ...sx }}
>
{children}
</_SecondaryContainer>
Expand Down Expand Up @@ -74,8 +70,35 @@ const _SecondaryContainer = ({
sidebarWidth={sidebarWidth}
isSidebarOpen={isSidebarOpen}
sx={{ ...sx, width: "100%", overflowY: "auto" }}

>
{children}
<RaisedMainContent>
{children}
</RaisedMainContent>
</WrapperStack>
)
}

const RaisedMainContent = ({ children }: { children?: React.ReactNode }) => {
return (
<main style={{ flexGrow: "1" }}>
<Box sx={{
height: "100%",
paddingTop: { xs: 0, sm: 2 },
marginLeft: { xs: 0, sm: 2 },
marginRight: { xs: 0, sm: 2 }
}}>
<Box id="border-content" sx={{
height: "100%",
background: "white",
boxShadow: { xs: 0, sm: "0 4px 8px rgba(0, 0, 0, 0.08)" },
borderTopLeftRadius: { xs: 0, sm: "18px" },
borderTopRightRadius: { xs: 0, sm: "18px" }
}}>
<CustomTopLoader parentSelector="#border-content" color="#e0e0e0" />
{children}
</Box>
</Box>
</main>
)
}

0 comments on commit f40cbcb

Please sign in to comment.