@djangocfg/layouts 2.1.48 → 2.1.49
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@djangocfg/layouts",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.49",
|
|
4
4
|
"description": "Simple, straightforward layout components for Next.js - import and use with props",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"layouts",
|
|
@@ -92,12 +92,13 @@
|
|
|
92
92
|
"check": "tsc --noEmit"
|
|
93
93
|
},
|
|
94
94
|
"peerDependencies": {
|
|
95
|
-
"@djangocfg/api": "^2.1.
|
|
96
|
-
"@djangocfg/centrifugo": "^2.1.
|
|
97
|
-
"@djangocfg/ui-nextjs": "^2.1.
|
|
95
|
+
"@djangocfg/api": "^2.1.49",
|
|
96
|
+
"@djangocfg/centrifugo": "^2.1.49",
|
|
97
|
+
"@djangocfg/ui-nextjs": "^2.1.49",
|
|
98
98
|
"@hookform/resolvers": "^5.2.0",
|
|
99
99
|
"consola": "^3.4.2",
|
|
100
100
|
"lucide-react": "^0.545.0",
|
|
101
|
+
"moment": "^2.30.1",
|
|
101
102
|
"next": ">=15.0.0",
|
|
102
103
|
"p-retry": "^7.0.0",
|
|
103
104
|
"react": "^19.1.0",
|
|
@@ -107,15 +108,15 @@
|
|
|
107
108
|
"swr": "^2.3.7",
|
|
108
109
|
"tailwindcss": "^4.1.14",
|
|
109
110
|
"tailwindcss-animate": "^1.0.7",
|
|
110
|
-
"zod": "^4.1.13"
|
|
111
|
-
"moment": "^2.30.1"
|
|
111
|
+
"zod": "^4.1.13"
|
|
112
112
|
},
|
|
113
113
|
"dependencies": {
|
|
114
|
+
"nextjs-toploader": "^3.9.17",
|
|
114
115
|
"react-ga4": "^2.1.0",
|
|
115
116
|
"uuid": "^11.1.0"
|
|
116
117
|
},
|
|
117
118
|
"devDependencies": {
|
|
118
|
-
"@djangocfg/typescript-config": "^2.1.
|
|
119
|
+
"@djangocfg/typescript-config": "^2.1.49",
|
|
119
120
|
"@types/node": "^24.7.2",
|
|
120
121
|
"@types/react": "^19.1.0",
|
|
121
122
|
"@types/react-dom": "^19.1.0",
|
|
@@ -126,4 +127,3 @@
|
|
|
126
127
|
"access": "public"
|
|
127
128
|
}
|
|
128
129
|
}
|
|
129
|
-
|
|
@@ -7,6 +7,5 @@ export type { ClientOnlyProps } from './ClientOnly';
|
|
|
7
7
|
export { JsonLd } from './JsonLd';
|
|
8
8
|
export { LucideIcon } from './LucideIcon';
|
|
9
9
|
export type { LucideIconProps } from './LucideIcon';
|
|
10
|
-
export { PageProgress } from './PageProgress';
|
|
11
10
|
export { Suspense } from './Suspense';
|
|
12
11
|
|
package/src/index.ts
CHANGED
|
@@ -28,6 +28,10 @@
|
|
|
28
28
|
// Layout components
|
|
29
29
|
export * from './layouts';
|
|
30
30
|
|
|
31
|
+
// Re-export useRouter from nextjs-toploader for progress bar support
|
|
32
|
+
// Use this instead of 'next/navigation' useRouter for router.push() to trigger progress
|
|
33
|
+
export { useRouter } from 'nextjs-toploader/app';
|
|
34
|
+
|
|
31
35
|
// Snippets - Reusable UI components (includes Analytics)
|
|
32
36
|
export * from './snippets';
|
|
33
37
|
|
|
@@ -45,6 +45,7 @@
|
|
|
45
45
|
'use client';
|
|
46
46
|
|
|
47
47
|
import dynamic from 'next/dynamic';
|
|
48
|
+
import NextTopLoader from 'nextjs-toploader';
|
|
48
49
|
import { ReactNode } from 'react';
|
|
49
50
|
import { SWRConfig } from 'swr';
|
|
50
51
|
|
|
@@ -52,8 +53,6 @@ import { getCentrifugoAuthTokenRetrieve } from '@djangocfg/api';
|
|
|
52
53
|
import { AuthProvider } from '@djangocfg/api/auth';
|
|
53
54
|
import { CentrifugoProvider } from '@djangocfg/centrifugo';
|
|
54
55
|
import { SonnerToaster, ThemeProvider, TooltipProvider } from '@djangocfg/ui-nextjs';
|
|
55
|
-
|
|
56
|
-
import { PageProgress } from '../../components/core/PageProgress';
|
|
57
56
|
import { ErrorBoundary } from '../../components/errors/ErrorBoundary';
|
|
58
57
|
import { ErrorTrackingProvider } from '../../components/errors/ErrorsTracker';
|
|
59
58
|
import { AnalyticsProvider } from '../../snippets/Analytics';
|
|
@@ -143,7 +142,12 @@ export function BaseApp({
|
|
|
143
142
|
onError={errorTracking?.onError}
|
|
144
143
|
>
|
|
145
144
|
{children}
|
|
146
|
-
<
|
|
145
|
+
<NextTopLoader
|
|
146
|
+
color="hsl(var(--primary))"
|
|
147
|
+
height={3}
|
|
148
|
+
showSpinner={false}
|
|
149
|
+
shadow="0 0 10px hsl(var(--primary)), 0 0 5px hsl(var(--primary))"
|
|
150
|
+
/>
|
|
147
151
|
<SonnerToaster />
|
|
148
152
|
|
|
149
153
|
{/* PWA Install Hint */}
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
import { Bell, X } from 'lucide-react';
|
|
11
11
|
import React, { useEffect, useState } from 'react';
|
|
12
12
|
|
|
13
|
+
import { useAuth } from '@djangocfg/api/auth';
|
|
13
14
|
import { Button } from '@djangocfg/ui-nextjs';
|
|
14
15
|
|
|
15
16
|
import { usePushNotifications } from '../hooks/usePushNotifications';
|
|
@@ -60,6 +61,7 @@ export function PushPrompt({
|
|
|
60
61
|
onEnabled,
|
|
61
62
|
onDismissed,
|
|
62
63
|
}: PushPromptProps) {
|
|
64
|
+
const { isAuthenticated, isLoading: isAuthLoading } = useAuth();
|
|
63
65
|
const { isSupported, permission, isSubscribed, subscribe } = usePushNotifications({
|
|
64
66
|
vapidPublicKey,
|
|
65
67
|
subscribeEndpoint,
|
|
@@ -70,6 +72,11 @@ export function PushPrompt({
|
|
|
70
72
|
|
|
71
73
|
// Check if should show
|
|
72
74
|
useEffect(() => {
|
|
75
|
+
// Wait for auth to complete, don't show for unauthenticated users
|
|
76
|
+
if (isAuthLoading || !isAuthenticated) {
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
|
|
73
80
|
if (!isSupported || isSubscribed || permission === 'denied') {
|
|
74
81
|
return;
|
|
75
82
|
}
|
|
@@ -89,7 +96,7 @@ export function PushPrompt({
|
|
|
89
96
|
// Show after delay
|
|
90
97
|
const timer = setTimeout(() => setShow(true), delayMs);
|
|
91
98
|
return () => clearTimeout(timer);
|
|
92
|
-
}, [isSupported, isSubscribed, permission, requirePWA, resetAfterDays, delayMs]);
|
|
99
|
+
}, [isAuthLoading, isAuthenticated, isSupported, isSubscribed, permission, requirePWA, resetAfterDays, delayMs]);
|
|
93
100
|
|
|
94
101
|
const handleEnable = async () => {
|
|
95
102
|
setEnabling(true);
|
|
@@ -1,127 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* PageProgress - Loading progress bar
|
|
3
|
-
*
|
|
4
|
-
* Shows a progress bar at the top of the page during route transitions
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
'use client';
|
|
8
|
-
|
|
9
|
-
import { usePathname } from 'next/navigation';
|
|
10
|
-
import { useEffect, useRef, useState } from 'react';
|
|
11
|
-
|
|
12
|
-
export function PageProgress() {
|
|
13
|
-
const pathname = usePathname();
|
|
14
|
-
const [loading, setLoading] = useState(false);
|
|
15
|
-
const [progress, setProgress] = useState(0);
|
|
16
|
-
const [mounted, setMounted] = useState(false);
|
|
17
|
-
const progressTimer = useRef<NodeJS.Timeout | null>(null);
|
|
18
|
-
const prevPathname = useRef<string | null>(null);
|
|
19
|
-
|
|
20
|
-
useEffect(() => {
|
|
21
|
-
setMounted(true);
|
|
22
|
-
}, []);
|
|
23
|
-
|
|
24
|
-
// Simulate realistic progress
|
|
25
|
-
const startFakeProgress = () => {
|
|
26
|
-
// Clear any existing timer
|
|
27
|
-
if (progressTimer.current) {
|
|
28
|
-
clearInterval(progressTimer.current);
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
setProgress(0);
|
|
32
|
-
|
|
33
|
-
// Quickly go to 20% to show immediate feedback
|
|
34
|
-
setTimeout(() => setProgress(20), 50);
|
|
35
|
-
|
|
36
|
-
// Then slowly increase to 90% (never reach 100% until actually complete)
|
|
37
|
-
progressTimer.current = setInterval(() => {
|
|
38
|
-
setProgress((prevProgress) => {
|
|
39
|
-
if (prevProgress >= 90) {
|
|
40
|
-
if (progressTimer.current) {
|
|
41
|
-
clearInterval(progressTimer.current);
|
|
42
|
-
}
|
|
43
|
-
return 90;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
// Slow down as we get closer to 90%
|
|
47
|
-
const increment = 90 - prevProgress;
|
|
48
|
-
return prevProgress + (increment / 10);
|
|
49
|
-
});
|
|
50
|
-
}, 300);
|
|
51
|
-
};
|
|
52
|
-
|
|
53
|
-
const completeProgress = () => {
|
|
54
|
-
// Clear any existing timer
|
|
55
|
-
if (progressTimer.current) {
|
|
56
|
-
clearInterval(progressTimer.current);
|
|
57
|
-
progressTimer.current = null;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
// Jump to 100% and then hide after showing completion
|
|
61
|
-
setProgress(100);
|
|
62
|
-
setTimeout(() => {
|
|
63
|
-
setLoading(false);
|
|
64
|
-
setTimeout(() => {
|
|
65
|
-
setProgress(0);
|
|
66
|
-
}, 300); // Wait for fade out animation
|
|
67
|
-
}, 500); // Show 100% for half a second
|
|
68
|
-
};
|
|
69
|
-
|
|
70
|
-
// Track pathname changes (App Router equivalent of routeChangeStart/Complete)
|
|
71
|
-
useEffect(() => {
|
|
72
|
-
// Skip on initial mount
|
|
73
|
-
if (prevPathname.current === null) {
|
|
74
|
-
prevPathname.current = pathname;
|
|
75
|
-
return;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
// Only trigger if pathname actually changed
|
|
79
|
-
if (prevPathname.current !== pathname) {
|
|
80
|
-
setLoading(true);
|
|
81
|
-
startFakeProgress();
|
|
82
|
-
|
|
83
|
-
// Complete progress after a short delay (simulating route change)
|
|
84
|
-
const timeout = setTimeout(() => {
|
|
85
|
-
completeProgress();
|
|
86
|
-
prevPathname.current = pathname;
|
|
87
|
-
}, 100);
|
|
88
|
-
|
|
89
|
-
return () => {
|
|
90
|
-
clearTimeout(timeout);
|
|
91
|
-
if (progressTimer.current) {
|
|
92
|
-
clearInterval(progressTimer.current);
|
|
93
|
-
}
|
|
94
|
-
};
|
|
95
|
-
}
|
|
96
|
-
}, [pathname]);
|
|
97
|
-
|
|
98
|
-
if (!mounted) {
|
|
99
|
-
return null;
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
return (
|
|
103
|
-
<div
|
|
104
|
-
data-page-progress="root"
|
|
105
|
-
data-loading={loading}
|
|
106
|
-
data-progress={progress}
|
|
107
|
-
className={`fixed top-0 left-0 w-full transition-opacity duration-300 ${
|
|
108
|
-
loading ? 'opacity-100' : 'opacity-0'
|
|
109
|
-
}`}
|
|
110
|
-
style={{
|
|
111
|
-
zIndex: 99999,
|
|
112
|
-
height: '3px',
|
|
113
|
-
}}
|
|
114
|
-
>
|
|
115
|
-
<div
|
|
116
|
-
className="h-full transition-all duration-200 ease-linear"
|
|
117
|
-
style={{
|
|
118
|
-
width: `${progress}%`,
|
|
119
|
-
background: 'linear-gradient(90deg, #3b82f6 0%, #60a5fa 50%, #3b82f6 100%)',
|
|
120
|
-
boxShadow: '0 0 10px rgba(59, 130, 246, 0.6), 0 0 20px rgba(59, 130, 246, 0.4), 0 0 30px rgba(59, 130, 246, 0.2)',
|
|
121
|
-
filter: 'drop-shadow(0 0 8px rgba(59, 130, 246, 0.8))',
|
|
122
|
-
}}
|
|
123
|
-
/>
|
|
124
|
-
</div>
|
|
125
|
-
);
|
|
126
|
-
}
|
|
127
|
-
|