@djangocfg/layouts 1.4.30 → 2.0.1

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.
Files changed (119) hide show
  1. package/README.md +277 -18
  2. package/package.json +15 -24
  3. package/src/auth/context/AuthContext.tsx +5 -5
  4. package/src/auth/hooks/useAuthGuard.ts +1 -1
  5. package/src/auth/hooks/useAutoAuth.ts +8 -7
  6. package/src/components/ErrorBoundary.tsx +78 -0
  7. package/src/components/JsonLd.tsx +31 -0
  8. package/src/components/LucideIcon.tsx +91 -0
  9. package/src/components/PageProgress.tsx +127 -0
  10. package/src/components/Suspense.tsx +29 -0
  11. package/src/{layouts/AppLayout/components → components}/UpdateNotifier/UpdateNotifier.tsx +56 -49
  12. package/src/components/index.ts +10 -0
  13. package/src/index.ts +25 -7
  14. package/src/layouts/AdminLayout/AdminLayout.tsx +46 -0
  15. package/src/layouts/AdminLayout/index.ts +7 -0
  16. package/src/layouts/AppLayout/AppLayout.tsx +278 -326
  17. package/src/layouts/AppLayout/index.ts +2 -39
  18. package/src/layouts/{AppLayout/layouts/AuthLayout → AuthLayout}/AuthContext.tsx +3 -2
  19. package/src/layouts/{AppLayout/layouts/AuthLayout → AuthLayout}/AuthHelp.tsx +1 -0
  20. package/src/layouts/AuthLayout/AuthLayout.tsx +61 -0
  21. package/src/layouts/{AppLayout/layouts/AuthLayout → AuthLayout}/IdentifierForm.tsx +47 -34
  22. package/src/layouts/{AppLayout/layouts/AuthLayout → AuthLayout}/OTPForm.tsx +2 -3
  23. package/src/layouts/AuthLayout/index.ts +24 -0
  24. package/src/layouts/{AppLayout/layouts/AuthLayout → AuthLayout}/types.ts +1 -0
  25. package/src/layouts/PrivateLayout/PrivateLayout.tsx +144 -0
  26. package/src/layouts/PrivateLayout/components/PrivateContent.tsx +32 -0
  27. package/src/layouts/PrivateLayout/components/PrivateHeader.tsx +57 -0
  28. package/src/layouts/PrivateLayout/components/PrivateSidebar.tsx +141 -0
  29. package/src/layouts/PrivateLayout/components/index.ts +8 -0
  30. package/src/layouts/PrivateLayout/index.ts +7 -0
  31. package/src/layouts/ProfileLayout/ProfileLayout.tsx +15 -7
  32. package/src/layouts/PublicLayout/PublicLayout.tsx +121 -0
  33. package/src/layouts/PublicLayout/components/PublicFooter.tsx +190 -0
  34. package/src/layouts/PublicLayout/components/PublicMobileDrawer.tsx +117 -0
  35. package/src/layouts/PublicLayout/components/PublicNavigation.tsx +101 -0
  36. package/src/layouts/PublicLayout/components/index.ts +8 -0
  37. package/src/layouts/PublicLayout/index.ts +7 -0
  38. package/src/layouts/_components/UserMenu.tsx +160 -0
  39. package/src/layouts/_components/index.ts +7 -0
  40. package/src/layouts/index.ts +15 -8
  41. package/src/snippets/Analytics/AnalyticsProvider.tsx +8 -4
  42. package/src/snippets/Analytics/useAnalytics.ts +11 -21
  43. package/src/snippets/Chat/ChatWidget.tsx +4 -4
  44. package/src/snippets/ContactForm/ContactFormProvider.tsx +32 -19
  45. package/src/snippets/ContactForm/ContactPage.tsx +2 -4
  46. package/src/snippets/ContactForm/types.ts +3 -2
  47. package/src/snippets/index.ts +0 -1
  48. package/src/layouts/AppLayout/README.md +0 -204
  49. package/src/layouts/AppLayout/SUMMARY.md +0 -240
  50. package/src/layouts/AppLayout/USAGE.md +0 -312
  51. package/src/layouts/AppLayout/components/ErrorBoundary.tsx +0 -112
  52. package/src/layouts/AppLayout/components/PageProgress.tsx +0 -123
  53. package/src/layouts/AppLayout/components/Seo.tsx +0 -171
  54. package/src/layouts/AppLayout/components/UserMenu.tsx +0 -385
  55. package/src/layouts/AppLayout/components/index.ts +0 -11
  56. package/src/layouts/AppLayout/context/AppContext.tsx +0 -151
  57. package/src/layouts/AppLayout/context/index.ts +0 -5
  58. package/src/layouts/AppLayout/hooks/index.ts +0 -8
  59. package/src/layouts/AppLayout/hooks/useLayoutMode.ts +0 -26
  60. package/src/layouts/AppLayout/hooks/useNavigation.ts +0 -51
  61. package/src/layouts/AppLayout/layouts/AdminLayout/AdminLayout.tsx +0 -224
  62. package/src/layouts/AppLayout/layouts/AdminLayout/README.md +0 -409
  63. package/src/layouts/AppLayout/layouts/AdminLayout/components/PagePreloader.example.tsx +0 -98
  64. package/src/layouts/AppLayout/layouts/AdminLayout/components/PagePreloader.tsx +0 -149
  65. package/src/layouts/AppLayout/layouts/AdminLayout/components/ParentSync.tsx +0 -146
  66. package/src/layouts/AppLayout/layouts/AdminLayout/components/index.ts +0 -3
  67. package/src/layouts/AppLayout/layouts/AdminLayout/context/CfgAppContext.tsx +0 -48
  68. package/src/layouts/AppLayout/layouts/AdminLayout/context/index.ts +0 -2
  69. package/src/layouts/AppLayout/layouts/AdminLayout/hooks/index.ts +0 -6
  70. package/src/layouts/AppLayout/layouts/AdminLayout/hooks/useApp.ts +0 -279
  71. package/src/layouts/AppLayout/layouts/AdminLayout/index.ts +0 -24
  72. package/src/layouts/AppLayout/layouts/AdminLayout/lottie/energizing.json +0 -1
  73. package/src/layouts/AppLayout/layouts/AdminLayout/types/index.ts +0 -45
  74. package/src/layouts/AppLayout/layouts/AuthLayout/AuthLayout.tsx +0 -41
  75. package/src/layouts/AppLayout/layouts/AuthLayout/index.ts +0 -15
  76. package/src/layouts/AppLayout/layouts/PrivateLayout/PrivateLayout.tsx +0 -82
  77. package/src/layouts/AppLayout/layouts/PrivateLayout/components/DashboardContent.tsx +0 -62
  78. package/src/layouts/AppLayout/layouts/PrivateLayout/components/DashboardHeader.tsx +0 -89
  79. package/src/layouts/AppLayout/layouts/PrivateLayout/components/DashboardSidebar.tsx +0 -181
  80. package/src/layouts/AppLayout/layouts/PrivateLayout/components/index.ts +0 -9
  81. package/src/layouts/AppLayout/layouts/PrivateLayout/index.ts +0 -5
  82. package/src/layouts/AppLayout/layouts/PublicLayout/PublicLayout.tsx +0 -44
  83. package/src/layouts/AppLayout/layouts/PublicLayout/components/Footer.tsx +0 -242
  84. package/src/layouts/AppLayout/layouts/PublicLayout/components/MobileDrawer.tsx +0 -150
  85. package/src/layouts/AppLayout/layouts/PublicLayout/components/Navigation.tsx +0 -169
  86. package/src/layouts/AppLayout/layouts/PublicLayout/index.ts +0 -5
  87. package/src/layouts/AppLayout/layouts/index.ts +0 -7
  88. package/src/layouts/AppLayout/providers/CoreProviders.tsx +0 -80
  89. package/src/layouts/AppLayout/providers/index.ts +0 -5
  90. package/src/layouts/AppLayout/types/config.ts +0 -79
  91. package/src/layouts/AppLayout/types/index.ts +0 -11
  92. package/src/layouts/AppLayout/types/layout.ts +0 -54
  93. package/src/layouts/AppLayout/types/navigation.ts +0 -43
  94. package/src/layouts/AppLayout/types/page.ts +0 -80
  95. package/src/layouts/AppLayout/types/routes.ts +0 -43
  96. package/src/layouts/AppLayout/utils/index.ts +0 -5
  97. package/src/layouts/AppLayout/utils/routeDetection.ts +0 -31
  98. package/src/layouts/ErrorLayout/ErrorLayout.tsx +0 -173
  99. package/src/layouts/ErrorLayout/errorConfig.tsx +0 -152
  100. package/src/layouts/ErrorLayout/index.ts +0 -8
  101. package/src/layouts/SimpleLayout/SimpleLayout.tsx +0 -72
  102. package/src/layouts/SimpleLayout/index.ts +0 -3
  103. package/src/snippets/VideoPlayer/README.md +0 -238
  104. package/src/snippets/VideoPlayer/VideoControls.tsx +0 -137
  105. package/src/snippets/VideoPlayer/VideoPlayer.tsx +0 -248
  106. package/src/snippets/VideoPlayer/index.ts +0 -8
  107. package/src/snippets/VideoPlayer/types.ts +0 -61
  108. package/src/types/index.ts +0 -2
  109. package/src/types/pageConfig.ts +0 -100
  110. /package/src/{validation → components/ErrorsTracker}/README.md +0 -0
  111. /package/src/{validation → components/ErrorsTracker}/components/ErrorButtons.tsx +0 -0
  112. /package/src/{validation → components/ErrorsTracker}/components/ErrorToast.tsx +0 -0
  113. /package/src/{validation → components/ErrorsTracker}/hooks.ts +0 -0
  114. /package/src/{validation → components/ErrorsTracker}/index.ts +0 -0
  115. /package/src/{validation → components/ErrorsTracker}/providers/ErrorTrackingProvider.tsx +0 -0
  116. /package/src/{validation → components/ErrorsTracker}/types.ts +0 -0
  117. /package/src/{validation → components/ErrorsTracker}/utils/curl-generator.ts +0 -0
  118. /package/src/{validation → components/ErrorsTracker}/utils/formatters.ts +0 -0
  119. /package/src/{layouts/AppLayout/components → components}/UpdateNotifier/index.ts +0 -0
@@ -1,409 +0,0 @@
1
- # AdminLayout - Django CFG Layout with iframe Integration
2
-
3
- Universal layout component for Django CFG applications that handles iframe embedding, theme synchronization, and authentication communication.
4
-
5
- **Note:** AdminLayout is now integrated into AppLayout. For most use cases, use `AppLayout` with `isCfgAdmin={true}` instead of using AdminLayout directly.
6
-
7
- ## Features
8
-
9
- - 🖼️ **iframe Embedding Detection** - Automatically detects when running inside an iframe
10
- - 🎨 **Theme Synchronization** - Syncs theme from Django Unfold parent window
11
- - 🔐 **Auth Token Passing** - Receives JWT tokens from parent window via postMessage
12
- - 📤 **Auth Status Reporting** - Sends authentication status to parent window
13
- - 📏 **Auto Resize** - Automatically adjusts iframe height based on content
14
- - 🔒 **Secure Communication** - Origin validation for postMessage security
15
- - ⚡ **Lightweight** - Minimal overhead, works with any layout system
16
-
17
- ## Installation
18
-
19
- Already included in `@djangocfg/layouts` package.
20
-
21
- ## Recommended Usage (via AppLayout)
22
-
23
- ### Simple - Enable Django CFG Admin Mode
24
-
25
- ```tsx
26
- // apps/admin/src/pages/_app.tsx
27
- import { AppLayout } from '@djangocfg/layouts';
28
-
29
- function MyApp({ Component, pageProps }) {
30
- return (
31
- <AppProviders>
32
- <AppLayout config={appLayoutConfig} isCfgAdmin={true}>
33
- <Component {...pageProps} />
34
- </AppLayout>
35
- </AppProviders>
36
- );
37
- }
38
- ```
39
-
40
- **That's it!** Setting `isCfgAdmin={true}` automatically:
41
- - Wraps your app with AdminLayout
42
- - Sets up iframe communication
43
- - Handles auth token passing
44
- - Syncs theme from parent window
45
-
46
- ## Direct Usage (Advanced)
47
-
48
- If you need more control, you can use AdminLayout directly:
49
-
50
- ### 1. Wrap your app with AdminLayout (Zero Config!)
51
-
52
- ```tsx
53
- // apps/admin/src/pages/_app.tsx
54
- import { AdminLayout, AppLayout } from '@djangocfg/layouts';
55
-
56
- function MyApp({ Component, pageProps }) {
57
- return (
58
- <AdminLayout>
59
- <AppLayout config={appLayoutConfig}>
60
- <Component {...pageProps} />
61
- </AppLayout>
62
- </AdminLayout>
63
- );
64
- }
65
- ```
66
-
67
- **That's it!** Auth tokens are automatically set in the API client when received from parent window.
68
-
69
- ### 2. With custom auth handler (optional)
70
-
71
- ```tsx
72
- // Only if you need additional logic when tokens are received
73
- <AdminLayout
74
- config={{
75
- onAuthTokenReceived: (authToken, refreshToken) => {
76
- // Tokens are already set in API client automatically
77
- console.log('Tokens received!');
78
- // Your custom logic here
79
- }
80
- }}
81
- >
82
- <AppLayout config={appLayoutConfig}>
83
- <Component {...pageProps} />
84
- </AppLayout>
85
- </AdminLayout>
86
- ```
87
-
88
- ## Hook Usage
89
-
90
- ### Use useCfgApp hook to access embedding state
91
-
92
- ```tsx
93
- import { useCfgApp } from '@djangocfg/layouts';
94
-
95
- function MyComponent() {
96
- const { isEmbedded, disableLayout, parentTheme } = useCfgApp();
97
-
98
- return (
99
- <div>
100
- {isEmbedded && <p>Running in iframe mode</p>}
101
- <p>Current theme from parent: {parentTheme}</p>
102
- </div>
103
- );
104
- }
105
- ```
106
-
107
- ### Use with AppLayout's disableLayout prop
108
-
109
- ```tsx
110
- import { AppLayout, useCfgApp } from '@djangocfg/layouts';
111
-
112
- function MyApp({ Component, pageProps }) {
113
- const { disableLayout } = useCfgApp();
114
-
115
- return (
116
- <AppLayout
117
- config={config}
118
- disableLayout={disableLayout}
119
- isCfgAdmin={true}
120
- >
121
- <Component {...pageProps} />
122
- </AppLayout>
123
- );
124
- }
125
- ```
126
-
127
- ## API Reference
128
-
129
- ### AppLayout with isCfgAdmin
130
-
131
- **Recommended approach:**
132
-
133
- ```typescript
134
- <AppLayout
135
- config={appLayoutConfig}
136
- isCfgAdmin={true} // ← Enables Django CFG admin mode
137
- fontFamily={manrope.style.fontFamily}
138
- >
139
- {children}
140
- </AppLayout>
141
- ```
142
-
143
- ### AdminLayout Props
144
-
145
- | Prop | Type | Default | Description |
146
- |------|------|---------|-------------|
147
- | `children` | `ReactNode` | Required | Your app content |
148
- | `config` | `AdminLayoutConfig` | `{}` | Configuration object |
149
- | `enableParentSync` | `boolean` | `true` | Enable automatic theme/auth sync |
150
-
151
- ### AdminLayoutConfig
152
-
153
- **All options are optional!** AdminLayout works with zero configuration.
154
-
155
- ```typescript
156
- interface AdminLayoutConfig {
157
- // Optional: Called when auth tokens are received from parent
158
- // Note: Tokens are ALWAYS automatically set in API client
159
- // Use this only if you need additional custom logic
160
- onAuthTokenReceived?: (authToken, refreshToken?) => void;
161
-
162
- // Enable/disable theme sync (default: true)
163
- enableThemeSync?: boolean;
164
-
165
- // Enable/disable auth status sync (default: true)
166
- enableAuthStatusSync?: boolean;
167
- }
168
- ```
169
-
170
- ### useCfgApp Hook
171
-
172
- ```typescript
173
- const {
174
- isEmbedded, // true if running in iframe
175
- isStandalone, // true if running as PWA
176
- disableLayout, // true if layout should be disabled
177
- referrer, // parent URL if embedded
178
- isMounted, // true after client-side mount
179
- parentTheme, // 'light' | 'dark' | null
180
- parentThemeMode, // 'auto' | 'light' | 'dark' | null
181
- } = useCfgApp({
182
- onAuthTokenReceived: (authToken, refreshToken) => {
183
- // Handle tokens (optional - tokens are auto-set in API client)
184
- }
185
- });
186
- ```
187
-
188
- **Note:** `useApp` is also exported as an alias for backward compatibility.
189
-
190
- ## postMessage Communication Protocol
191
-
192
- ### Parent → iframe
193
-
194
- | Message Type | Data | Description |
195
- |-------------|------|-------------|
196
- | `parent-theme` | `{ theme: 'dark'\|'light', themeMode: 'auto'\|'dark'\|'light' }` | Theme from Django Unfold |
197
- | `parent-auth` | `{ authToken, refreshToken }` | JWT authentication tokens |
198
-
199
- ### iframe → Parent
200
-
201
- | Message Type | Data | Description |
202
- |-------------|------|-------------|
203
- | `iframe-ready` | `{ url, referrer }` | iframe loaded successfully |
204
- | `iframe-auth-status` | `{ isAuthenticated, isLoading, hasUser }` | Auth status update (sent on auth state change) |
205
- | `iframe-resize` | `{ height }` | Content height changed (sent on ResizeObserver trigger) |
206
- | `iframe-navigation` | `{ path }` | User navigated to new page (sent via Next.js Router.events) |
207
-
208
- ## Advanced Usage
209
-
210
- ### Manual Theme Sync
211
-
212
- ```tsx
213
- import { useCfgApp } from '@djangocfg/layouts';
214
- import { useThemeContext } from '@djangocfg/ui';
215
-
216
- function MyThemeSync() {
217
- const { isEmbedded, parentTheme } = useCfgApp();
218
- const { setTheme } = useThemeContext();
219
-
220
- useEffect(() => {
221
- if (isEmbedded && parentTheme) {
222
- setTheme(parentTheme);
223
- }
224
- }, [isEmbedded, parentTheme, setTheme]);
225
-
226
- return null;
227
- }
228
- ```
229
-
230
- ### Disable Auto Sync
231
-
232
- ```tsx
233
- <AdminLayout enableParentSync={false}>
234
- {/* Handle sync manually */}
235
- </AdminLayout>
236
- ```
237
-
238
- ### URL Override
239
-
240
- Force iframe mode via URL:
241
- ```
242
- https://example.com/admin/?embed=true
243
- ```
244
-
245
- Disable iframe mode:
246
- ```
247
- https://example.com/admin/?embed=false
248
- ```
249
-
250
- ## Integration with Django
251
-
252
- See Django template at: `src/django_cfg/templates/admin/index.html`
253
-
254
- The Django template uses an iframe to load the Next.js app:
255
- ```html
256
- <iframe
257
- id="nextjs-dashboard-iframe"
258
- src="{% nextjs_admin_url 'private' %}"
259
- title="Next.js Dashboard"
260
- ></iframe>
261
- ```
262
-
263
- ## Components
264
-
265
- ### ParentSync
266
-
267
- Handles bidirectional communication with parent window. Automatically included when using `isCfgAdmin={true}`.
268
-
269
- ```tsx
270
- import { ParentSync } from '@djangocfg/layouts';
271
-
272
- // Usually placed inside AppLayout (automatic with isCfgAdmin={true})
273
- <AuthProvider>
274
- <ThemeProvider>
275
- <ParentSync />
276
- {children}
277
- </ThemeProvider>
278
- </AuthProvider>
279
- ```
280
-
281
- **What ParentSync does:**
282
-
283
- 1. **Theme Sync** (Parent → iframe): Receives theme updates from Django Unfold and applies them
284
- 2. **Auth Status Sync** (iframe → Parent): Sends authentication status when it changes
285
- 3. **Auto Resize** (iframe → Parent): Sends content height for iframe resizing
286
- 4. **Navigation Tracking** (iframe → Parent): Sends route changes for "Open in New Window" button
287
-
288
- **Navigation Tracking:**
289
- ParentSync automatically tracks route changes using Next.js Router and sends them to the parent window:
290
-
291
- ```typescript
292
- // Automatically sent on every route change
293
- window.parent.postMessage({
294
- type: 'iframe-navigation',
295
- data: { path: '/admin/stocks' }
296
- }, '*');
297
- ```
298
-
299
- This enables the "Open in New Window" button in the Django admin to open the exact page the user is currently viewing, not just the home page.
300
-
301
- ## Security Considerations
302
-
303
- - All postMessage communications validate origins
304
- - Tokens are only accepted from expected parent origins
305
- - iframe uses sandbox attribute with specific permissions
306
- - localStorage is used for token persistence (XSS protection needed)
307
-
308
- ## Migration from Old API
309
-
310
- **Old approach:**
311
- ```tsx
312
- import { AppLayout, AdminLayout, useCfgApp } from '@djangocfg/layouts';
313
-
314
- function AppLayoutWrapper() {
315
- const { disableLayout, isEmbedded } = useCfgApp();
316
- return (
317
- <AppLayout disableLayout={disableLayout}>
318
- {children}
319
- </AppLayout>
320
- );
321
- }
322
-
323
- export default function App() {
324
- return (
325
- <AdminLayout>
326
- <AppLayoutWrapper>
327
- {children}
328
- </AppLayoutWrapper>
329
- </AdminLayout>
330
- );
331
- }
332
- ```
333
-
334
- **New approach:**
335
- ```tsx
336
- import { AppLayout } from '@djangocfg/layouts';
337
-
338
- export default function App({ Component, pageProps }) {
339
- return (
340
- <AppLayout config={appLayoutConfig} isCfgAdmin={true}>
341
- <Component {...pageProps} />
342
- </AppLayout>
343
- );
344
- }
345
- ```
346
-
347
- ## Troubleshooting
348
-
349
- ### Theme not syncing
350
- - Check parent window is sending `parent-theme` messages
351
- - Verify ThemeProvider is in component tree
352
- - Enable debug logging in `useApp.ts`
353
-
354
- ### Auth tokens not working
355
- - Tokens are automatically set in API client
356
- - Check parent window sends `parent-auth` message
357
- - Inspect localStorage for tokens: `auth_token`, `refresh_token`
358
-
359
- ### Layout not hiding in iframe
360
- - Use `isCfgAdmin={true}` on AppLayout (recommended)
361
- - Or manually pass `disableLayout` from `useCfgApp()` hook
362
- - Try URL override: `?embed=true`
363
-
364
- ### Static export build fails
365
- - Make sure ParentSync is wrapped with SSR protection (already handled)
366
- - Check that `useAuth()` is only called on client-side
367
- - Verify `'use client'` directive is present in components
368
-
369
- ## Examples
370
-
371
- **Simple Django CFG Admin:**
372
- ```tsx
373
- <AppLayout config={config} isCfgAdmin={true}>
374
- <Component {...pageProps} />
375
- </AppLayout>
376
- ```
377
-
378
- **With custom font:**
379
- ```tsx
380
- <AppLayout
381
- config={config}
382
- isCfgAdmin={true}
383
- fontFamily={manrope.style.fontFamily}
384
- >
385
- <Component {...pageProps} />
386
- </AppLayout>
387
- ```
388
-
389
- **With custom auth logic:**
390
- ```tsx
391
- <AdminLayout
392
- config={{
393
- onAuthTokenReceived: (token, refresh) => {
394
- console.log('Tokens received from parent');
395
- // Additional custom logic
396
- }
397
- }}
398
- >
399
- <AppLayout config={config}>
400
- <Component {...pageProps} />
401
- </AppLayout>
402
- </AdminLayout>
403
- ```
404
-
405
- ## Related Files
406
-
407
- - Django Template: `src/django_cfg/templates/admin/index.html`
408
- - Django Views: `src/django_cfg/apps/frontend/views.py`
409
- - Example App: `src/django_admin/apps/admin/src/pages/_app.tsx`
@@ -1,98 +0,0 @@
1
- /**
2
- * PagePreloader - Usage Examples
3
- *
4
- * This file contains examples of how to use the PagePreloader component
5
- */
6
-
7
- import { PagePreloader, PagePreloaderDark } from './PagePreloader';
8
-
9
- // ============================================================================
10
- // Example 1: Basic Usage
11
- // ============================================================================
12
- export function Example1_Basic() {
13
- return <PagePreloader />;
14
- }
15
-
16
- // ============================================================================
17
- // Example 2: Custom Text
18
- // ============================================================================
19
- export function Example2_CustomText() {
20
- return <PagePreloader text="Loading your dashboard..." />;
21
- }
22
-
23
- // ============================================================================
24
- // Example 3: Different Sizes
25
- // ============================================================================
26
- export function Example3_DifferentSizes() {
27
- return (
28
- <>
29
- <PagePreloader size="sm" text="Small" />
30
- <PagePreloader size="md" text="Medium" />
31
- <PagePreloader size="lg" text="Large" />
32
- <PagePreloader size="xl" text="Extra Large" />
33
- </>
34
- );
35
- }
36
-
37
- // ============================================================================
38
- // Example 4: Dark Variant
39
- // ============================================================================
40
- export function Example4_Dark() {
41
- return <PagePreloaderDark text="Loading..." />;
42
- }
43
-
44
- // ============================================================================
45
- // Example 5: No Text
46
- // ============================================================================
47
- export function Example5_NoText() {
48
- return <PagePreloader showText={false} />;
49
- }
50
-
51
- // ============================================================================
52
- // Example 6: No Backdrop
53
- // ============================================================================
54
- export function Example6_NoBackdrop() {
55
- return <PagePreloader backdrop={false} />;
56
- }
57
-
58
- // ============================================================================
59
- // Example 7: Custom Backdrop Opacity
60
- // ============================================================================
61
- export function Example7_CustomBackdropOpacity() {
62
- return <PagePreloader backdropOpacity={50} text="50% opacity backdrop" />;
63
- }
64
-
65
- // ============================================================================
66
- // Example 8: Conditional Loading
67
- // ============================================================================
68
- export function Example8_ConditionalLoading({ isLoading }: { isLoading: boolean }) {
69
- if (!isLoading) return null;
70
- return <PagePreloader text="Loading data..." />;
71
- }
72
-
73
- // ============================================================================
74
- // Example 9: With Custom Styling
75
- // ============================================================================
76
- export function Example9_CustomStyling() {
77
- return (
78
- <PagePreloader
79
- className="bg-gradient-to-br from-blue-500 to-purple-600"
80
- text="Loading..."
81
- />
82
- );
83
- }
84
-
85
- // ============================================================================
86
- // Example 10: In AdminLayout
87
- // ============================================================================
88
- export function Example10_InAdminLayout() {
89
- // Usage in AdminLayout component
90
- const isLoading = true; // Replace with actual loading state
91
-
92
- return (
93
- <>
94
- {isLoading && <PagePreloader text="Loading application..." />}
95
- {/* Rest of your app */}
96
- </>
97
- );
98
- }
@@ -1,149 +0,0 @@
1
- /**
2
- * PagePreloader Component
3
- *
4
- * Full-page loading indicator with Lottie animation
5
- */
6
-
7
- 'use client';
8
-
9
- import React from 'react';
10
- import { LottiePlayer } from '@djangocfg/ui/tools';
11
- import energizingAnimation from '../lottie/energizing.json';
12
-
13
- export interface PagePreloaderProps {
14
- /**
15
- * Custom loading text
16
- * @default 'Loading...'
17
- */
18
- text?: string;
19
-
20
- /**
21
- * Show loading text
22
- * @default true
23
- */
24
- showText?: boolean;
25
-
26
- /**
27
- * Animation size
28
- * @default 'lg'
29
- */
30
- size?: 'sm' | 'md' | 'lg' | 'xl';
31
-
32
- /**
33
- * Whether to show backdrop
34
- * @default true
35
- */
36
- backdrop?: boolean;
37
-
38
- /**
39
- * Backdrop opacity (0-100)
40
- * @default 80
41
- */
42
- backdropOpacity?: number;
43
-
44
- /**
45
- * Additional CSS classes
46
- */
47
- className?: string;
48
- }
49
-
50
- /**
51
- * PagePreloader - Full-page loading indicator with energizing animation
52
- *
53
- * Features:
54
- * - Lottie animation with energizing effect
55
- * - Customizable text and size
56
- * - Optional backdrop
57
- * - Smooth fade-in animation
58
- *
59
- * Usage:
60
- * ```tsx
61
- * // Basic usage
62
- * <PagePreloader />
63
- *
64
- * // With custom text
65
- * <PagePreloader text="Loading your data..." />
66
- *
67
- * // Different size
68
- * <PagePreloader size="xl" />
69
- *
70
- * // Without backdrop
71
- * <PagePreloader backdrop={false} />
72
- *
73
- * // Custom styling
74
- * <PagePreloader className="bg-gradient-to-br from-blue-500 to-purple-600" />
75
- * ```
76
- */
77
- export function PagePreloader({
78
- text = 'Loading...',
79
- showText = true,
80
- size = 'lg',
81
- backdrop = true,
82
- backdropOpacity = 80,
83
- className,
84
- }: PagePreloaderProps) {
85
- // Generate backdrop opacity classes based on opacity value with explicit light/dark variants
86
- const getBackdropClasses = () => {
87
- if (!backdrop) return 'bg-transparent';
88
-
89
- // Use explicit light/dark classes for reliable theme support
90
- if (backdropOpacity >= 90) {
91
- return 'bg-white dark:bg-gray-950'; // Full opacity
92
- } else if (backdropOpacity >= 70) {
93
- return 'bg-white/90 dark:bg-gray-950/90'; // 90% opacity
94
- } else if (backdropOpacity >= 50) {
95
- return 'bg-white/80 dark:bg-gray-950/80'; // 80% opacity
96
- } else {
97
- return 'bg-white/60 dark:bg-gray-950/60'; // 60% opacity
98
- }
99
- };
100
-
101
- return (
102
- <div
103
- className={`fixed inset-0 z-50 flex items-center justify-center ${getBackdropClasses()} ${className || ''}`}
104
- >
105
- <div className="flex flex-col items-center gap-6 animate-in fade-in duration-300">
106
- {/* Lottie Animation */}
107
- <div className="relative">
108
- <LottiePlayer
109
- src={energizingAnimation}
110
- size={size}
111
- autoplay
112
- loop
113
- speed={1}
114
- />
115
- </div>
116
-
117
- {/* Loading Text */}
118
- {showText && (
119
- <div className="flex flex-col items-center gap-2">
120
- <p className="text-lg font-medium text-gray-900 dark:text-gray-100">
121
- {text}
122
- </p>
123
- <div className="flex gap-1">
124
- <span className="h-2 w-2 animate-bounce rounded-full bg-blue-600 dark:bg-blue-400" style={{ animationDelay: '0ms' }} />
125
- <span className="h-2 w-2 animate-bounce rounded-full bg-blue-600 dark:bg-blue-400" style={{ animationDelay: '150ms' }} />
126
- <span className="h-2 w-2 animate-bounce rounded-full bg-blue-600 dark:bg-blue-400" style={{ animationDelay: '300ms' }} />
127
- </div>
128
- </div>
129
- )}
130
- </div>
131
- </div>
132
- );
133
- }
134
-
135
- /**
136
- * PagePreloaderDark - Dark variant of PagePreloader
137
- *
138
- * Same as PagePreloader but forces dark backdrop
139
- * Note: Regular PagePreloader now uses semantic theme colors,
140
- * so this is only needed for specific dark-only use cases
141
- */
142
- export function PagePreloaderDark(props: Omit<PagePreloaderProps, 'className'>) {
143
- return (
144
- <PagePreloader
145
- {...props}
146
- className="bg-gray-950/95"
147
- />
148
- );
149
- }