💄 add toploader navigation

This commit is contained in:
Fred KISSIE
2025-10-23 23:10:21 +02:00
parent 90ddffce0e
commit 23b13f0a0e
5 changed files with 88 additions and 4 deletions

34
package-lock.json generated
View File

@@ -72,10 +72,12 @@
"next": "15.5.6",
"next-intl": "^4.3.12",
"next-themes": "0.4.6",
"nextjs-toploader": "^3.9.17",
"node-cache": "5.1.2",
"node-fetch": "3.3.2",
"nodemailer": "7.0.9",
"npm": "^11.6.2",
"nprogress": "^0.2.0",
"oslo": "1.2.1",
"pg": "^8.16.2",
"posthog-node": "^5.9.5",
@@ -118,6 +120,7 @@
"@types/jsonwebtoken": "^9.0.10",
"@types/node": "24.8.1",
"@types/nodemailer": "7.0.2",
"@types/nprogress": "^0.2.3",
"@types/pg": "8.15.5",
"@types/react": "19.2.2",
"@types/react-dom": "19.2.2",
@@ -8691,6 +8694,13 @@
"dev": true,
"license": "MIT"
},
"node_modules/@types/nprogress": {
"version": "0.2.3",
"resolved": "https://registry.npmjs.org/@types/nprogress/-/nprogress-0.2.3.tgz",
"integrity": "sha512-k7kRA033QNtC+gLc4VPlfnue58CM1iQLgn1IMAU8VPHGOj7oIHPp9UlhedEnD/Gl8evoCjwkZjlBORtZ3JByUA==",
"dev": true,
"license": "MIT"
},
"node_modules/@types/pg": {
"version": "8.15.5",
"resolved": "https://registry.npmjs.org/@types/pg/-/pg-8.15.5.tgz",
@@ -15197,6 +15207,24 @@
"node": "^10 || ^12 || >=14"
}
},
"node_modules/nextjs-toploader": {
"version": "3.9.17",
"resolved": "https://registry.npmjs.org/nextjs-toploader/-/nextjs-toploader-3.9.17.tgz",
"integrity": "sha512-9OF0KSSLtoSAuNg2LZ3aTl4hR9mBDj5L9s9DZiFCbMlXehyICGjkIz5dVGzuATU2bheJZoBdFgq9w07AKSuQQw==",
"license": "MIT",
"dependencies": {
"nprogress": "^0.2.0",
"prop-types": "^15.8.1"
},
"funding": {
"url": "https://buymeacoffee.com/thesgj"
},
"peerDependencies": {
"next": ">= 6.0.0",
"react": ">= 16.0.0",
"react-dom": ">= 16.0.0"
}
},
"node_modules/node-abi": {
"version": "3.78.0",
"resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.78.0.tgz",
@@ -17727,6 +17755,12 @@
"inBundle": true,
"license": "ISC"
},
"node_modules/nprogress": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/nprogress/-/nprogress-0.2.0.tgz",
"integrity": "sha512-I19aIingLgR1fmhftnbWWO3dXc0hSxqHQHQb3H8m+K3TnEn/iSeTZZOyvKXWqQESMwuUVnatlCnZdLBZZt2VSA==",
"license": "MIT"
},
"node_modules/nth-check": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz",

View File

@@ -95,10 +95,12 @@
"next": "15.5.6",
"next-intl": "^4.3.12",
"next-themes": "0.4.6",
"nextjs-toploader": "^3.9.17",
"node-cache": "5.1.2",
"node-fetch": "3.3.2",
"nodemailer": "7.0.9",
"npm": "^11.6.2",
"nprogress": "^0.2.0",
"oslo": "1.2.1",
"pg": "^8.16.2",
"posthog-node": "^5.9.5",
@@ -141,6 +143,7 @@
"@types/jsonwebtoken": "^9.0.10",
"@types/node": "24.8.1",
"@types/nodemailer": "7.0.2",
"@types/nprogress": "^0.2.3",
"@types/pg": "8.15.5",
"@types/react": "19.2.2",
"@types/react-dom": "19.2.2",

View File

@@ -40,7 +40,7 @@
}
.dark {
--background: oklch(0.20 0.006 285.885);
--background: oklch(0.2 0.006 285.885);
--foreground: oklch(0.985 0 0);
--card: oklch(0.21 0.006 285.885);
--card-foreground: oklch(0.985 0 0);
@@ -140,3 +140,7 @@ p {
word-break: keep-all;
white-space: normal;
}
#nprogress .bar {
background: var(--color-primary) !important;
}

View File

@@ -18,6 +18,7 @@ import { NextIntlClientProvider } from "next-intl";
import { getLocale } from "next-intl/server";
import { Toaster } from "@app/components/ui/toaster";
import { build } from "@server/build";
import { TopLoader } from "@app/components/Toploader";
export const metadata: Metadata = {
title: `Dashboard - ${process.env.BRANDING_APP_NAME || "Pangolin"}`,
@@ -62,9 +63,9 @@ export default async function RootLayout({
if (build === "enterprise") {
const licenseStatusRes = await cache(
async () =>
await priv.get<AxiosResponse<GetLicenseStatusResponse>>(
"/license/status"
)
await priv.get<AxiosResponse<GetLicenseStatusResponse>>(
"/license/status"
)
)();
licenseStatus = licenseStatusRes.data.data;
} else if (build === "saas") {
@@ -84,6 +85,7 @@ export default async function RootLayout({
return (
<html suppressHydrationWarning lang={locale}>
<body className={`${font.className} h-screen overflow-hidden`}>
<TopLoader />
<NextIntlClientProvider>
<ThemeProvider
attribute="class"

View File

@@ -0,0 +1,41 @@
"use client";
import * as React from "react";
import * as NProgress from "nprogress";
import NextTopLoader from "nextjs-toploader";
import { usePathname, useRouter, useSearchParams } from "next/navigation";
export function TopLoader() {
return (
<>
<NextTopLoader showSpinner={false} />
<FinishingLoader />
</>
);
}
function FinishingLoader() {
const pathname = usePathname();
const router = useRouter();
const searchParams = useSearchParams();
React.useEffect(() => {
NProgress.done();
}, [pathname, router, searchParams]);
React.useEffect(() => {
const linkClickListener = (ev: MouseEvent) => {
const element = ev.target as HTMLElement;
const closestlink = element.closest("a");
const isOpenToNewTabClick =
ev.ctrlKey ||
ev.shiftKey ||
ev.metaKey || // apple
(ev.button && ev.button == 1); // middle click, >IE9 + everyone else
if (closestlink && isOpenToNewTabClick) {
NProgress.done();
}
};
window.addEventListener("click", linkClickListener);
return () => window.removeEventListener("click", linkClickListener);
}, []);
return null;
}