@djangocfg/layouts 2.1.37 → 2.1.39
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/README.md +204 -18
- package/package.json +5 -5
- package/src/components/errors/index.ts +9 -0
- package/src/components/errors/types.ts +38 -0
- package/src/layouts/AppLayout/AppLayout.tsx +33 -45
- package/src/layouts/AppLayout/BaseApp.tsx +104 -33
- package/src/layouts/AuthLayout/AuthContext.tsx +7 -1
- package/src/layouts/AuthLayout/OAuthProviders.tsx +1 -10
- package/src/layouts/AuthLayout/OTPForm.tsx +1 -0
- package/src/layouts/PrivateLayout/PrivateLayout.tsx +1 -1
- package/src/layouts/PublicLayout/PublicLayout.tsx +1 -1
- package/src/layouts/PublicLayout/components/PublicMobileDrawer.tsx +1 -1
- package/src/layouts/PublicLayout/components/PublicNavigation.tsx +1 -1
- package/src/layouts/_components/UserMenu.tsx +1 -1
- package/src/layouts/index.ts +1 -1
- package/src/layouts/types/index.ts +47 -0
- package/src/layouts/types/layout.types.ts +61 -0
- package/src/layouts/types/providers.types.ts +65 -0
- package/src/layouts/types/ui.types.ts +103 -0
- package/src/snippets/Analytics/index.ts +1 -0
- package/src/snippets/Analytics/types.ts +10 -0
- package/src/snippets/PWAInstall/@docs/README.md +92 -0
- package/src/snippets/PWAInstall/README.md +185 -0
- package/src/snippets/{PWA → PWAInstall}/components/A2HSHint.tsx +85 -84
- package/src/snippets/PWAInstall/components/DesktopGuide.tsx +229 -0
- package/src/snippets/PWAInstall/context/InstallContext.tsx +102 -0
- package/src/snippets/{PWA → PWAInstall}/hooks/useInstallPrompt.ts +3 -0
- package/src/snippets/{PWA → PWAInstall}/index.ts +12 -31
- package/src/snippets/{PWA → PWAInstall}/types/components.ts +0 -6
- package/src/snippets/PWAInstall/types/config.ts +22 -0
- package/src/snippets/{PWA → PWAInstall}/types/index.ts +4 -4
- package/src/snippets/{PWA → PWAInstall}/utils/localStorage.ts +1 -23
- package/src/snippets/PushNotifications/@docs/README.md +191 -0
- package/src/snippets/PushNotifications/@docs/guides/django-integration.md +648 -0
- package/src/snippets/PushNotifications/@docs/guides/service-worker.md +467 -0
- package/src/snippets/PushNotifications/@docs/guides/vapid-setup.md +352 -0
- package/src/snippets/PushNotifications/README.md +328 -0
- package/src/snippets/{PWA → PushNotifications}/config.ts +2 -2
- package/src/snippets/PushNotifications/context/DjangoPushContext.tsx +190 -0
- package/src/snippets/{PWA → PushNotifications}/hooks/useDjangoPush.ts +63 -81
- package/src/snippets/{PWA → PushNotifications}/hooks/usePushNotifications.ts +12 -8
- package/src/snippets/PushNotifications/index.ts +87 -0
- package/src/snippets/PushNotifications/types/config.ts +28 -0
- package/src/snippets/PushNotifications/types/index.ts +9 -0
- package/src/snippets/PushNotifications/utils/localStorage.ts +60 -0
- package/src/snippets/PushNotifications/utils/logger.ts +149 -0
- package/src/snippets/PushNotifications/utils/platform.ts +151 -0
- package/src/snippets/index.ts +37 -12
- package/src/layouts/shared/index.ts +0 -21
- package/src/layouts/shared/types.ts +0 -247
- package/src/snippets/PWA/@refactoring/ARCHITECTURE_ANALYSIS.md +0 -1179
- package/src/snippets/PWA/@refactoring/EXECUTIVE_SUMMARY.md +0 -271
- package/src/snippets/PWA/@refactoring/README.md +0 -204
- package/src/snippets/PWA/@refactoring/REFACTORING_PROPOSALS.md +0 -1109
- package/src/snippets/PWA/@refactoring2/COMPARISON-WITH-NEXTJS.md +0 -718
- package/src/snippets/PWA/@refactoring2/P1-FIXES-COMPLETED.md +0 -188
- package/src/snippets/PWA/@refactoring2/POST-P0-ANALYSIS.md +0 -362
- package/src/snippets/PWA/@refactoring2/README.md +0 -85
- package/src/snippets/PWA/@refactoring2/RECOMMENDATIONS.md +0 -1321
- package/src/snippets/PWA/@refactoring2/REMAINING-ISSUES.md +0 -557
- package/src/snippets/PWA/README.md +0 -387
- package/src/snippets/PWA/context/DjangoPushContext.tsx +0 -105
- package/src/snippets/PWA/context/InstallContext.tsx +0 -118
- package/src/snippets/PWA/context/PushContext.tsx +0 -156
- /package/src/layouts/{shared → types}/README.md +0 -0
- /package/src/snippets/{PWA/@docs/research.md → PWAInstall/@docs/research/ios-android-install-flows.md} +0 -0
- /package/src/snippets/{PWA → PWAInstall}/components/IOSGuide.tsx +0 -0
- /package/src/snippets/{PWA → PWAInstall}/components/IOSGuideDrawer.tsx +0 -0
- /package/src/snippets/{PWA → PWAInstall}/components/IOSGuideModal.tsx +0 -0
- /package/src/snippets/{PWA → PWAInstall}/hooks/useIsPWA.ts +0 -0
- /package/src/snippets/{PWA → PWAInstall}/types/install.ts +0 -0
- /package/src/snippets/{PWA → PWAInstall}/types/platform.ts +0 -0
- /package/src/snippets/{PWA → PWAInstall}/utils/logger.ts +0 -0
- /package/src/snippets/{PWA → PWAInstall}/utils/platform.ts +0 -0
- /package/src/snippets/{PWA → PushNotifications}/components/PushPrompt.tsx +0 -0
- /package/src/snippets/{PWA → PushNotifications}/types/push.ts +0 -0
- /package/src/snippets/{PWA → PushNotifications}/utils/vapid.ts +0 -0
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LocalStorage utilities for Push Notifications state persistence
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Storage keys
|
|
7
|
+
*/
|
|
8
|
+
export const STORAGE_KEYS = {
|
|
9
|
+
PUSH_DISMISSED: 'pwa_push_dismissed_at',
|
|
10
|
+
} as const;
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Check if push prompt was dismissed recently
|
|
14
|
+
* @param resetDays Number of days before re-showing (default: 7)
|
|
15
|
+
*/
|
|
16
|
+
export function isPushDismissedRecently(resetDays: number = 7): boolean {
|
|
17
|
+
return isDismissedRecentlyHelper(resetDays, STORAGE_KEYS.PUSH_DISMISSED);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Mark push prompt as dismissed
|
|
22
|
+
*/
|
|
23
|
+
export function markPushDismissed(): void {
|
|
24
|
+
if (typeof window === 'undefined') return;
|
|
25
|
+
try {
|
|
26
|
+
localStorage.setItem(STORAGE_KEYS.PUSH_DISMISSED, Date.now().toString());
|
|
27
|
+
} catch {
|
|
28
|
+
// Fail silently
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Helper: Check if a key was dismissed recently
|
|
34
|
+
* @internal
|
|
35
|
+
*/
|
|
36
|
+
function isDismissedRecentlyHelper(resetDays: number, key: string): boolean {
|
|
37
|
+
if (typeof window === 'undefined') return false;
|
|
38
|
+
try {
|
|
39
|
+
const dismissed = localStorage.getItem(key);
|
|
40
|
+
if (!dismissed) return false;
|
|
41
|
+
const dismissedAt = parseInt(dismissed, 10);
|
|
42
|
+
const daysSince = (Date.now() - dismissedAt) / (1000 * 60 * 60 * 24);
|
|
43
|
+
return daysSince < resetDays;
|
|
44
|
+
} catch {
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Clear all push notification data
|
|
51
|
+
*/
|
|
52
|
+
export function clearAllPushData(): void {
|
|
53
|
+
if (typeof window === 'undefined') return;
|
|
54
|
+
|
|
55
|
+
try {
|
|
56
|
+
localStorage.removeItem(STORAGE_KEYS.PUSH_DISMISSED);
|
|
57
|
+
} catch {
|
|
58
|
+
// Fail silently
|
|
59
|
+
}
|
|
60
|
+
}
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PWA Logger with Conditional Logging
|
|
3
|
+
*
|
|
4
|
+
* Provides logging utilities that respect environment and debug settings:
|
|
5
|
+
* - In production: Only errors are logged
|
|
6
|
+
* - In development: All levels are logged
|
|
7
|
+
* - Debug mode: Can be enabled in production via localStorage
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```typescript
|
|
11
|
+
* import { pwaLogger } from '../utils/logger';
|
|
12
|
+
*
|
|
13
|
+
* pwaLogger.info('Info message'); // Only in dev
|
|
14
|
+
* pwaLogger.warn('Warning message'); // Only in dev
|
|
15
|
+
* pwaLogger.error('Error message'); // Always logged
|
|
16
|
+
* pwaLogger.debug('Debug message'); // Only when debug enabled
|
|
17
|
+
* ```
|
|
18
|
+
*
|
|
19
|
+
* Enable debug mode in production:
|
|
20
|
+
* ```typescript
|
|
21
|
+
* import { enablePWADebug } from '../utils/logger';
|
|
22
|
+
* enablePWADebug();
|
|
23
|
+
* // or in console:
|
|
24
|
+
* localStorage.setItem('pwa_debug', 'true');
|
|
25
|
+
* ```
|
|
26
|
+
*/
|
|
27
|
+
|
|
28
|
+
import { consola } from 'consola';
|
|
29
|
+
|
|
30
|
+
const isDevelopment = process.env.NODE_ENV === 'development';
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Check if debug mode is enabled via localStorage
|
|
34
|
+
*/
|
|
35
|
+
function isDebugEnabled(): boolean {
|
|
36
|
+
if (typeof window === 'undefined') return false;
|
|
37
|
+
try {
|
|
38
|
+
return localStorage.getItem('pwa_debug') === 'true';
|
|
39
|
+
} catch {
|
|
40
|
+
return false;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* PWA Logger instance with conditional logging
|
|
46
|
+
*/
|
|
47
|
+
export const pwaLogger = {
|
|
48
|
+
/**
|
|
49
|
+
* Info level logging
|
|
50
|
+
* Only logs in development or when debug is enabled
|
|
51
|
+
*/
|
|
52
|
+
info: (...args: Parameters<typeof consola.info>): void => {
|
|
53
|
+
if (isDevelopment || isDebugEnabled()) {
|
|
54
|
+
consola.info(...args);
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Warning level logging
|
|
60
|
+
* Only logs in development or when debug is enabled
|
|
61
|
+
*/
|
|
62
|
+
warn: (...args: Parameters<typeof consola.warn>): void => {
|
|
63
|
+
if (isDevelopment || isDebugEnabled()) {
|
|
64
|
+
consola.warn(...args);
|
|
65
|
+
}
|
|
66
|
+
},
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Error level logging
|
|
70
|
+
* Always logs (production + development)
|
|
71
|
+
*/
|
|
72
|
+
error: (...args: Parameters<typeof consola.error>): void => {
|
|
73
|
+
consola.error(...args);
|
|
74
|
+
},
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Debug level logging
|
|
78
|
+
* Only logs when debug is explicitly enabled
|
|
79
|
+
*/
|
|
80
|
+
debug: (...args: Parameters<typeof consola.debug>): void => {
|
|
81
|
+
if (isDebugEnabled()) {
|
|
82
|
+
consola.debug(...args);
|
|
83
|
+
}
|
|
84
|
+
},
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Success level logging
|
|
88
|
+
* Only logs in development or when debug is enabled
|
|
89
|
+
*/
|
|
90
|
+
success: (...args: Parameters<typeof consola.success>): void => {
|
|
91
|
+
if (isDevelopment || isDebugEnabled()) {
|
|
92
|
+
consola.success(...args);
|
|
93
|
+
}
|
|
94
|
+
},
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Enable debug mode
|
|
99
|
+
*
|
|
100
|
+
* This allows seeing debug logs in production.
|
|
101
|
+
* Call this function or set localStorage manually:
|
|
102
|
+
* `localStorage.setItem('pwa_debug', 'true')`
|
|
103
|
+
*
|
|
104
|
+
* @example
|
|
105
|
+
* ```typescript
|
|
106
|
+
* import { enablePWADebug } from '@djangocfg/layouts/snippets';
|
|
107
|
+
* enablePWADebug();
|
|
108
|
+
* // Reload page to see debug logs
|
|
109
|
+
* ```
|
|
110
|
+
*/
|
|
111
|
+
export function enablePWADebug(): void {
|
|
112
|
+
if (typeof window !== 'undefined') {
|
|
113
|
+
try {
|
|
114
|
+
localStorage.setItem('pwa_debug', 'true');
|
|
115
|
+
consola.info('[PWA] Debug mode enabled. Reload page to see debug logs.');
|
|
116
|
+
} catch (e) {
|
|
117
|
+
consola.error('[PWA] Failed to enable debug mode:', e);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Disable debug mode
|
|
124
|
+
*
|
|
125
|
+
* @example
|
|
126
|
+
* ```typescript
|
|
127
|
+
* import { disablePWADebug } from '@djangocfg/layouts/snippets';
|
|
128
|
+
* disablePWADebug();
|
|
129
|
+
* ```
|
|
130
|
+
*/
|
|
131
|
+
export function disablePWADebug(): void {
|
|
132
|
+
if (typeof window !== 'undefined') {
|
|
133
|
+
try {
|
|
134
|
+
localStorage.removeItem('pwa_debug');
|
|
135
|
+
consola.info('[PWA] Debug mode disabled.');
|
|
136
|
+
} catch (e) {
|
|
137
|
+
consola.error('[PWA] Failed to disable debug mode:', e);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Check if debug mode is currently active
|
|
144
|
+
*
|
|
145
|
+
* @returns true if debug mode is enabled
|
|
146
|
+
*/
|
|
147
|
+
export function isPWADebugEnabled(): boolean {
|
|
148
|
+
return isDebugEnabled();
|
|
149
|
+
}
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Platform Detection Utilities
|
|
3
|
+
*
|
|
4
|
+
* Centralized utilities for detecting PWA state, platform, and capabilities.
|
|
5
|
+
* Used by hooks to avoid code duplication.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Check if running as PWA (standalone mode)
|
|
10
|
+
*
|
|
11
|
+
* Checks if the app is running in standalone mode (added to home screen).
|
|
12
|
+
* This is the primary indicator that a PWA has been installed.
|
|
13
|
+
*
|
|
14
|
+
* @returns true if app is running in standalone mode
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```typescript
|
|
18
|
+
* if (isStandalone()) {
|
|
19
|
+
* console.log('Running as PWA');
|
|
20
|
+
* }
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
export function isStandalone(): boolean {
|
|
24
|
+
if (typeof window === 'undefined') return false;
|
|
25
|
+
|
|
26
|
+
// Fallback for older browsers without matchMedia
|
|
27
|
+
if (!window.matchMedia) {
|
|
28
|
+
// Use legacy iOS check only
|
|
29
|
+
const nav = navigator as Navigator & { standalone?: boolean };
|
|
30
|
+
return nav.standalone === true;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Check display-mode media query (modern approach)
|
|
34
|
+
const isStandaloneDisplay = window.matchMedia('(display-mode: standalone)').matches;
|
|
35
|
+
|
|
36
|
+
// Legacy iOS check (navigator.standalone)
|
|
37
|
+
const nav = navigator as Navigator & { standalone?: boolean };
|
|
38
|
+
const isStandaloneNavigator = nav.standalone === true;
|
|
39
|
+
|
|
40
|
+
return isStandaloneDisplay || isStandaloneNavigator;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Check if device is mobile
|
|
45
|
+
*
|
|
46
|
+
* @returns true if device is mobile (iOS, Android, etc.)
|
|
47
|
+
*/
|
|
48
|
+
export function isMobileDevice(): boolean {
|
|
49
|
+
if (typeof window === 'undefined') return false;
|
|
50
|
+
return /iPhone|iPad|iPod|Android/i.test(navigator.userAgent);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Check if web app manifest exists and is valid
|
|
55
|
+
*
|
|
56
|
+
* @returns true if manifest link exists in document head
|
|
57
|
+
*/
|
|
58
|
+
export function hasValidManifest(): boolean {
|
|
59
|
+
if (typeof document === 'undefined') return false;
|
|
60
|
+
const manifestLink = document.querySelector('link[rel="manifest"]');
|
|
61
|
+
return !!manifestLink;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Reliable check for PWA mode with edge case handling
|
|
66
|
+
*
|
|
67
|
+
* This function provides additional validation for desktop browsers
|
|
68
|
+
* to avoid false positives (e.g., Safari macOS "Add to Dock").
|
|
69
|
+
*
|
|
70
|
+
* For mobile devices, standard standalone check is sufficient.
|
|
71
|
+
* For desktop, additionally validates that a manifest exists.
|
|
72
|
+
*
|
|
73
|
+
* @returns true if app is running as a genuine PWA
|
|
74
|
+
*
|
|
75
|
+
* @example
|
|
76
|
+
* ```typescript
|
|
77
|
+
* // Use this for more reliable detection
|
|
78
|
+
* if (isStandaloneReliable()) {
|
|
79
|
+
* console.log('Definitely running as PWA');
|
|
80
|
+
* }
|
|
81
|
+
* ```
|
|
82
|
+
*/
|
|
83
|
+
export function isStandaloneReliable(): boolean {
|
|
84
|
+
const standalone = isStandalone();
|
|
85
|
+
if (!standalone) return false;
|
|
86
|
+
|
|
87
|
+
// For mobile devices, standalone check is sufficient
|
|
88
|
+
if (isMobileDevice()) return true;
|
|
89
|
+
|
|
90
|
+
// For desktop browsers, additionally check for valid manifest
|
|
91
|
+
// This prevents false positives like Safari macOS "Add to Dock"
|
|
92
|
+
return hasValidManifest();
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Get display mode from media query
|
|
97
|
+
*
|
|
98
|
+
* @returns Current display mode: 'standalone', 'fullscreen', 'minimal-ui', or 'browser'
|
|
99
|
+
*/
|
|
100
|
+
export function getDisplayMode(): 'standalone' | 'fullscreen' | 'minimal-ui' | 'browser' {
|
|
101
|
+
if (typeof window === 'undefined') return 'browser';
|
|
102
|
+
|
|
103
|
+
if (!window.matchMedia) return 'browser';
|
|
104
|
+
|
|
105
|
+
const modes: Array<'standalone' | 'fullscreen' | 'minimal-ui'> = [
|
|
106
|
+
'fullscreen',
|
|
107
|
+
'standalone',
|
|
108
|
+
'minimal-ui',
|
|
109
|
+
];
|
|
110
|
+
|
|
111
|
+
for (const mode of modes) {
|
|
112
|
+
if (window.matchMedia(`(display-mode: ${mode})`).matches) {
|
|
113
|
+
return mode;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
return 'browser';
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Create a media query listener for display-mode changes
|
|
122
|
+
*
|
|
123
|
+
* @param callback - Function to call when display mode changes
|
|
124
|
+
* @returns Cleanup function to remove listener
|
|
125
|
+
*
|
|
126
|
+
* @example
|
|
127
|
+
* ```typescript
|
|
128
|
+
* const cleanup = onDisplayModeChange((isStandalone) => {
|
|
129
|
+
* console.log('Display mode changed:', isStandalone);
|
|
130
|
+
* });
|
|
131
|
+
*
|
|
132
|
+
* // Later: cleanup();
|
|
133
|
+
* ```
|
|
134
|
+
*/
|
|
135
|
+
export function onDisplayModeChange(callback: (isStandalone: boolean) => void): () => void {
|
|
136
|
+
if (typeof window === 'undefined' || !window.matchMedia) {
|
|
137
|
+
return () => {}; // No-op cleanup
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
const mediaQuery = window.matchMedia('(display-mode: standalone)');
|
|
141
|
+
|
|
142
|
+
const handleChange = (e: MediaQueryListEvent) => {
|
|
143
|
+
callback(e.matches);
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
mediaQuery.addEventListener('change', handleChange);
|
|
147
|
+
|
|
148
|
+
return () => {
|
|
149
|
+
mediaQuery.removeEventListener('change', handleChange);
|
|
150
|
+
};
|
|
151
|
+
}
|
package/src/snippets/index.ts
CHANGED
|
@@ -44,32 +44,57 @@ export type {
|
|
|
44
44
|
AskAIButtonProps,
|
|
45
45
|
} from './McpChat';
|
|
46
46
|
|
|
47
|
-
// PWA (Progressive Web App)
|
|
47
|
+
// PWA Install (Progressive Web App Installation)
|
|
48
48
|
export {
|
|
49
49
|
PwaProvider,
|
|
50
50
|
useInstall,
|
|
51
|
-
PushProvider,
|
|
52
|
-
usePush,
|
|
53
51
|
A2HSHint,
|
|
54
|
-
|
|
52
|
+
IOSGuide,
|
|
53
|
+
DesktopGuide,
|
|
55
54
|
useIsPWA,
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
55
|
+
clearIsPWACache,
|
|
56
|
+
clearAllPWAInstallData,
|
|
57
|
+
isStandalone,
|
|
58
|
+
isStandaloneReliable,
|
|
59
|
+
isMobileDevice,
|
|
60
|
+
hasValidManifest,
|
|
61
|
+
getDisplayMode,
|
|
62
|
+
onDisplayModeChange,
|
|
63
|
+
} from './PWAInstall';
|
|
60
64
|
export type {
|
|
61
65
|
PlatformInfo,
|
|
62
66
|
InstallPromptState,
|
|
63
67
|
BeforeInstallPromptEvent,
|
|
64
68
|
InstallOutcome,
|
|
65
69
|
IOSGuideState,
|
|
66
|
-
PushNotificationState,
|
|
67
|
-
PushNotificationOptions,
|
|
68
70
|
InstallContextType,
|
|
69
71
|
InstallManagerProps,
|
|
70
72
|
AndroidInstallButtonProps,
|
|
71
73
|
IOSGuideModalProps,
|
|
72
74
|
InstallStep,
|
|
75
|
+
UseIsPWAOptions,
|
|
76
|
+
} from './PWAInstall';
|
|
77
|
+
|
|
78
|
+
// Push Notifications
|
|
79
|
+
export {
|
|
80
|
+
PushProvider,
|
|
81
|
+
usePush,
|
|
82
|
+
DjangoPushProvider,
|
|
83
|
+
useDjangoPushContext,
|
|
84
|
+
PushPrompt,
|
|
85
|
+
usePushNotifications,
|
|
86
|
+
useDjangoPush,
|
|
87
|
+
DEFAULT_VAPID_PUBLIC_KEY,
|
|
88
|
+
urlBase64ToUint8Array,
|
|
89
|
+
isValidVapidKey,
|
|
90
|
+
getVapidKeyInfo,
|
|
91
|
+
safeUrlBase64ToUint8Array,
|
|
92
|
+
VapidKeyError,
|
|
93
|
+
clearAllPushData,
|
|
94
|
+
} from './PushNotifications';
|
|
95
|
+
export type {
|
|
96
|
+
PushNotificationState,
|
|
97
|
+
PushNotificationOptions,
|
|
73
98
|
PushMessage,
|
|
74
|
-
|
|
75
|
-
} from './
|
|
99
|
+
VapidKeyErrorCode,
|
|
100
|
+
} from './PushNotifications';
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Shared Layouts Exports
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
export type {
|
|
6
|
-
ThemeConfig,
|
|
7
|
-
LayoutErrorTrackingConfig,
|
|
8
|
-
ErrorBoundaryConfig,
|
|
9
|
-
SWRConfigOptions,
|
|
10
|
-
McpChatConfig,
|
|
11
|
-
BaseLayoutProps,
|
|
12
|
-
NavigationItem,
|
|
13
|
-
NavigationSection,
|
|
14
|
-
FooterLink,
|
|
15
|
-
FooterMenuSection,
|
|
16
|
-
FooterSocialLinks,
|
|
17
|
-
FooterConfig,
|
|
18
|
-
UserMenuItem,
|
|
19
|
-
UserMenuGroup,
|
|
20
|
-
UserMenuConfig,
|
|
21
|
-
} from './types';
|
|
@@ -1,247 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Shared Types for All Layouts
|
|
3
|
-
*
|
|
4
|
-
* Universal type system to avoid duplication across layouts
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import type { ReactNode } from 'react';
|
|
8
|
-
import type { LucideIcon } from 'lucide-react';
|
|
9
|
-
import type { AuthConfig } from '@djangocfg/api/auth';
|
|
10
|
-
|
|
11
|
-
// ============================================================================
|
|
12
|
-
// Theme Configuration
|
|
13
|
-
// ============================================================================
|
|
14
|
-
|
|
15
|
-
export interface ThemeConfig {
|
|
16
|
-
defaultTheme?: 'light' | 'dark' | 'system';
|
|
17
|
-
storageKey?: string;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
// ============================================================================
|
|
21
|
-
// Error Tracking Configuration
|
|
22
|
-
// ============================================================================
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* Error tracking configuration for layouts
|
|
26
|
-
* Note: Import detailed types from @djangocfg/layouts/components if needed
|
|
27
|
-
*/
|
|
28
|
-
export interface LayoutErrorTrackingConfig {
|
|
29
|
-
validation?: {
|
|
30
|
-
enabled?: boolean;
|
|
31
|
-
showToast?: boolean;
|
|
32
|
-
};
|
|
33
|
-
cors?: {
|
|
34
|
-
enabled?: boolean;
|
|
35
|
-
showToast?: boolean;
|
|
36
|
-
};
|
|
37
|
-
network?: {
|
|
38
|
-
enabled?: boolean;
|
|
39
|
-
showToast?: boolean;
|
|
40
|
-
};
|
|
41
|
-
onError?: (error: any) => boolean | void;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
// ============================================================================
|
|
45
|
-
// Error Boundary Configuration
|
|
46
|
-
// ============================================================================
|
|
47
|
-
|
|
48
|
-
export interface ErrorBoundaryConfig {
|
|
49
|
-
enabled?: boolean;
|
|
50
|
-
supportEmail?: string;
|
|
51
|
-
onError?: (error: Error, errorInfo: React.ErrorInfo) => void;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
// ============================================================================
|
|
55
|
-
// SWR Configuration
|
|
56
|
-
// ============================================================================
|
|
57
|
-
|
|
58
|
-
export interface SWRConfigOptions {
|
|
59
|
-
revalidateOnFocus?: boolean;
|
|
60
|
-
revalidateOnReconnect?: boolean;
|
|
61
|
-
dedupingInterval?: number;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
// ============================================================================
|
|
65
|
-
// MCP Chat Configuration
|
|
66
|
-
// ============================================================================
|
|
67
|
-
|
|
68
|
-
export interface McpChatConfig {
|
|
69
|
-
/** Enable MCP chat widget */
|
|
70
|
-
enabled?: boolean;
|
|
71
|
-
/** API endpoint for chat */
|
|
72
|
-
apiEndpoint?: string;
|
|
73
|
-
/** Chat widget title */
|
|
74
|
-
title?: string;
|
|
75
|
-
/** Input placeholder */
|
|
76
|
-
placeholder?: string;
|
|
77
|
-
/** Greeting message */
|
|
78
|
-
greeting?: string;
|
|
79
|
-
/** Widget position */
|
|
80
|
-
position?: 'bottom-right' | 'bottom-left';
|
|
81
|
-
/** Widget variant */
|
|
82
|
-
variant?: 'default' | 'minimal';
|
|
83
|
-
/** Enable streaming responses */
|
|
84
|
-
enableStreaming?: boolean;
|
|
85
|
-
/** Auto-detect environment (dev/prod) */
|
|
86
|
-
autoDetectEnvironment?: boolean;
|
|
87
|
-
/** Custom class name */
|
|
88
|
-
className?: string;
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
// ============================================================================
|
|
92
|
-
// PWA Configuration
|
|
93
|
-
// ============================================================================
|
|
94
|
-
|
|
95
|
-
export interface PwaConfig {
|
|
96
|
-
/** Enable PWA provider and features */
|
|
97
|
-
enabled?: boolean;
|
|
98
|
-
|
|
99
|
-
/** Show A2HS hint (enabled by default when pwa.enabled is true) */
|
|
100
|
-
showInstallHint?: boolean;
|
|
101
|
-
|
|
102
|
-
/** Number of days before re-showing dismissed hint */
|
|
103
|
-
resetAfterDays?: number | null;
|
|
104
|
-
|
|
105
|
-
/** Delay before showing hint (ms) */
|
|
106
|
-
delayMs?: number;
|
|
107
|
-
|
|
108
|
-
/** App logo URL to display in hint */
|
|
109
|
-
logo?: string;
|
|
110
|
-
|
|
111
|
-
/** Push notifications configuration */
|
|
112
|
-
pushNotifications?: {
|
|
113
|
-
/** VAPID public key for push notifications */
|
|
114
|
-
vapidPublicKey: string;
|
|
115
|
-
/** API endpoint for subscription */
|
|
116
|
-
subscribeEndpoint?: string;
|
|
117
|
-
/** Delay before showing push prompt after PWA install (ms) */
|
|
118
|
-
delayMs?: number;
|
|
119
|
-
/** Number of days before re-showing dismissed push prompt */
|
|
120
|
-
resetAfterDays?: number;
|
|
121
|
-
};
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
// ============================================================================
|
|
125
|
-
// Base Layout Props
|
|
126
|
-
// ============================================================================
|
|
127
|
-
|
|
128
|
-
export interface BaseLayoutProps {
|
|
129
|
-
children: ReactNode;
|
|
130
|
-
|
|
131
|
-
/** Theme configuration */
|
|
132
|
-
theme?: ThemeConfig;
|
|
133
|
-
|
|
134
|
-
/** Auth configuration */
|
|
135
|
-
auth?: AuthConfig;
|
|
136
|
-
|
|
137
|
-
/** Error tracking configuration */
|
|
138
|
-
errorTracking?: LayoutErrorTrackingConfig;
|
|
139
|
-
|
|
140
|
-
/** SWR configuration */
|
|
141
|
-
swr?: SWRConfigOptions;
|
|
142
|
-
|
|
143
|
-
/** Error boundary configuration (enabled by default) */
|
|
144
|
-
errorBoundary?: ErrorBoundaryConfig;
|
|
145
|
-
|
|
146
|
-
/** MCP chat configuration */
|
|
147
|
-
mcpChat?: McpChatConfig;
|
|
148
|
-
|
|
149
|
-
/** PWA configuration */
|
|
150
|
-
pwa?: PwaConfig;
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
// ============================================================================
|
|
154
|
-
// Navigation Types
|
|
155
|
-
// ============================================================================
|
|
156
|
-
|
|
157
|
-
export interface NavigationItem {
|
|
158
|
-
label: string;
|
|
159
|
-
href: string;
|
|
160
|
-
icon?: LucideIcon | string;
|
|
161
|
-
badge?: string | number;
|
|
162
|
-
external?: boolean;
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
export interface NavigationSection {
|
|
166
|
-
title?: string;
|
|
167
|
-
items: NavigationItem[];
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
// ============================================================================
|
|
171
|
-
// Footer Types
|
|
172
|
-
// ============================================================================
|
|
173
|
-
|
|
174
|
-
export interface FooterLink {
|
|
175
|
-
label: string;
|
|
176
|
-
path: string;
|
|
177
|
-
external?: boolean;
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
export interface FooterMenuSection {
|
|
181
|
-
title: string;
|
|
182
|
-
items: FooterLink[];
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
export interface FooterSocialLinks {
|
|
186
|
-
github?: string;
|
|
187
|
-
linkedin?: string;
|
|
188
|
-
twitter?: string;
|
|
189
|
-
telegram?: string;
|
|
190
|
-
youtube?: string;
|
|
191
|
-
facebook?: string;
|
|
192
|
-
instagram?: string;
|
|
193
|
-
whatsapp?: string;
|
|
194
|
-
email?: string;
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
export interface FooterConfig {
|
|
198
|
-
siteName?: string;
|
|
199
|
-
description?: string;
|
|
200
|
-
logo?: string;
|
|
201
|
-
badge?: {
|
|
202
|
-
icon: LucideIcon;
|
|
203
|
-
text: string;
|
|
204
|
-
};
|
|
205
|
-
socialLinks?: FooterSocialLinks;
|
|
206
|
-
links?: FooterLink[];
|
|
207
|
-
menuSections?: FooterMenuSection[];
|
|
208
|
-
copyright?: string;
|
|
209
|
-
credits?: {
|
|
210
|
-
text: string;
|
|
211
|
-
url?: string;
|
|
212
|
-
};
|
|
213
|
-
variant?: 'full' | 'simple';
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
// ============================================================================
|
|
217
|
-
// User Menu Types
|
|
218
|
-
// ============================================================================
|
|
219
|
-
|
|
220
|
-
export interface UserMenuItem {
|
|
221
|
-
/** Menu item label */
|
|
222
|
-
label: string;
|
|
223
|
-
/** Link href (optional if onClick is provided) */
|
|
224
|
-
href?: string;
|
|
225
|
-
/** Icon component */
|
|
226
|
-
icon?: LucideIcon;
|
|
227
|
-
/** Visual variant */
|
|
228
|
-
variant?: 'default' | 'destructive';
|
|
229
|
-
/** Click handler (optional if href is provided) */
|
|
230
|
-
onClick?: () => void;
|
|
231
|
-
/** Open link in new tab */
|
|
232
|
-
external?: boolean;
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
export interface UserMenuGroup {
|
|
236
|
-
/** Optional group title (renders DropdownMenuLabel) */
|
|
237
|
-
title?: string;
|
|
238
|
-
/** Menu items in this group */
|
|
239
|
-
items: UserMenuItem[];
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
export interface UserMenuConfig {
|
|
243
|
-
/** Menu groups for authenticated users */
|
|
244
|
-
groups?: UserMenuGroup[];
|
|
245
|
-
/** Auth page path (for sign in button) */
|
|
246
|
-
authPath?: string;
|
|
247
|
-
}
|