Skip to content

Commit 90e1348

Browse files
committed
feat: sayfa geçişlerinde modern loading bar eklendi
- NProgress kütüphanesi entegre edildi - Gradient animasyonlu loading bar tasarımı - Dark mode desteği ile uyumlu (siyah/beyaz) - Tüm sayfa geçişlerinde otomatik çalışıyor - Browser back/forward butonları desteği - Suspense boundary ile SSG uyumlu - Smooth animasyonlar ve efektler
1 parent 5128fea commit 90e1348

File tree

6 files changed

+166
-0
lines changed

6 files changed

+166
-0
lines changed

app/layout.tsx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
import type { Metadata } from "next";
22
import { Inter } from "next/font/google";
33
import "./globals.css";
4+
import "./nprogress.css";
45
import Header from "@/components/Header";
56
import Footer from "@/components/Footer";
67
import StructuredData from "@/components/StructuredData";
78
import { ThemeProvider } from "@/components/ThemeProvider";
9+
import PageLoadingBar from "@/components/PageLoadingBar";
10+
import NavigationEvents from "@/components/NavigationEvents";
811

912
const inter = Inter({ subsets: ["latin"] });
1013

@@ -83,6 +86,8 @@ export default function RootLayout({
8386
</head>
8487
<body className={inter.className}>
8588
<ThemeProvider>
89+
<PageLoadingBar />
90+
<NavigationEvents />
8691
<Header />
8792
<main className="min-h-screen bg-white dark:bg-gray-900">
8893
{children}

app/nprogress.css

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
/* NProgress Loading Bar Styles */
2+
#nprogress {
3+
pointer-events: none;
4+
}
5+
6+
#nprogress .bar {
7+
background: linear-gradient(90deg, #000000 0%, #333333 50%, #000000 100%);
8+
background-size: 200% 100%;
9+
animation: gradient-shift 2s ease infinite;
10+
11+
position: fixed;
12+
z-index: 9999;
13+
top: 0;
14+
left: 0;
15+
16+
width: 100%;
17+
height: 3px;
18+
}
19+
20+
/* Dark mode için */
21+
.dark #nprogress .bar {
22+
background: linear-gradient(90deg, #ffffff 0%, #cccccc 50%, #ffffff 100%);
23+
background-size: 200% 100%;
24+
animation: gradient-shift 2s ease infinite;
25+
}
26+
27+
@keyframes gradient-shift {
28+
0% {
29+
background-position: 0% 50%;
30+
}
31+
50% {
32+
background-position: 100% 50%;
33+
}
34+
100% {
35+
background-position: 0% 50%;
36+
}
37+
}
38+
39+
/* Peg (loading bar'ın sağ ucu) */
40+
#nprogress .peg {
41+
display: block;
42+
position: absolute;
43+
right: 0px;
44+
width: 100px;
45+
height: 100%;
46+
box-shadow: 0 0 10px #000000, 0 0 5px #000000;
47+
opacity: 1.0;
48+
49+
transform: rotate(3deg) translate(0px, -4px);
50+
}
51+
52+
.dark #nprogress .peg {
53+
box-shadow: 0 0 10px #ffffff, 0 0 5px #ffffff;
54+
}
55+
56+
/* Fancy blur effect */
57+
#nprogress .bar {
58+
box-shadow: 0 0 2px rgba(0, 0, 0, 0.5);
59+
}
60+
61+
.dark #nprogress .bar {
62+
box-shadow: 0 0 2px rgba(255, 255, 255, 0.5);
63+
}
64+
65+
/* Remove spinner */
66+
#nprogress .spinner {
67+
display: none;
68+
}

components/NavigationEvents.tsx

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
'use client'
2+
3+
import { useEffect } from 'react'
4+
import NProgress from 'nprogress'
5+
6+
export default function NavigationEvents() {
7+
useEffect(() => {
8+
// Link tıklamalarını dinle
9+
const handleAnchorClick = (event: MouseEvent) => {
10+
const target = event.currentTarget as HTMLAnchorElement
11+
const href = target.getAttribute('href')
12+
13+
// Eğer internal link ise ve yeni sekmede açılmıyorsa
14+
if (href && href.startsWith('/') && !event.ctrlKey && !event.metaKey) {
15+
NProgress.start()
16+
}
17+
}
18+
19+
// Tüm linkleri dinle
20+
const links = document.querySelectorAll('a[href^="/"]')
21+
links.forEach(link => {
22+
link.addEventListener('click', handleAnchorClick as EventListener)
23+
})
24+
25+
// Browser back/forward butonları için
26+
const handlePopState = () => {
27+
NProgress.start()
28+
setTimeout(() => NProgress.done(), 500)
29+
}
30+
31+
window.addEventListener('popstate', handlePopState)
32+
33+
return () => {
34+
links.forEach(link => {
35+
link.removeEventListener('click', handleAnchorClick as EventListener)
36+
})
37+
window.removeEventListener('popstate', handlePopState)
38+
}
39+
}, [])
40+
41+
return null
42+
}

components/PageLoadingBar.tsx

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
'use client'
2+
3+
import { useEffect, Suspense } from 'react'
4+
import { usePathname, useSearchParams } from 'next/navigation'
5+
import NProgress from 'nprogress'
6+
7+
function LoadingBarContent() {
8+
const pathname = usePathname()
9+
const searchParams = useSearchParams()
10+
11+
useEffect(() => {
12+
NProgress.configure({
13+
showSpinner: false,
14+
trickleSpeed: 200,
15+
minimum: 0.08,
16+
easing: 'ease',
17+
speed: 500,
18+
})
19+
}, [])
20+
21+
useEffect(() => {
22+
NProgress.done()
23+
}, [pathname, searchParams])
24+
25+
return null
26+
}
27+
28+
export default function PageLoadingBar() {
29+
return (
30+
<Suspense fallback={null}>
31+
<LoadingBarContent />
32+
</Suspense>
33+
)
34+
}

package-lock.json

Lines changed: 15 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
"lucide-react": "^0.548.0",
3434
"next": "16.0.0",
3535
"next-themes": "^0.4.6",
36+
"nprogress": "^0.2.0",
3637
"prismjs": "^1.30.0",
3738
"react": "19.2.0",
3839
"react-dom": "19.2.0",
@@ -42,6 +43,7 @@
4243
"devDependencies": {
4344
"@tailwindcss/postcss": "^4",
4445
"@types/node": "^20",
46+
"@types/nprogress": "^0.2.3",
4547
"@types/react": "^19",
4648
"@types/react-dom": "^19",
4749
"eslint": "^9",

0 commit comments

Comments
 (0)