@djangocfg/layouts 2.1.218 → 2.1.221
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 +133 -678
- package/package.json +17 -16
- package/src/layouts/AppLayout/AppLayout.tsx +10 -0
- package/src/layouts/AppLayout/BaseApp.tsx +20 -1
- package/src/layouts/types/layout.types.ts +6 -0
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @djangocfg/layouts
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Layout components and providers for Next.js apps.
|
|
4
4
|
|
|
5
5
|
**Part of [DjangoCFG](https://djangocfg.com)** — modern Django framework for production-ready SaaS applications.
|
|
6
6
|
|
|
@@ -10,26 +10,33 @@ Simple, straightforward layout components for Next.js - import and use with prop
|
|
|
10
10
|
pnpm add @djangocfg/layouts
|
|
11
11
|
```
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
Add to `globals.css` (before `@import "tailwindcss"`):
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
```css
|
|
16
|
+
@import "@djangocfg/ui-nextjs/styles";
|
|
17
|
+
@import "@djangocfg/layouts/styles";
|
|
18
|
+
@import "@djangocfg/ui-tools/styles";
|
|
19
|
+
@import "@djangocfg/debuger/styles";
|
|
20
|
+
@import "tailwindcss";
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## BaseApp
|
|
16
24
|
|
|
17
|
-
Core providers wrapper
|
|
25
|
+
Core providers wrapper. Use directly when you don't need route-based layout switching.
|
|
18
26
|
|
|
19
27
|
```tsx
|
|
20
28
|
import { BaseApp } from '@djangocfg/layouts';
|
|
21
29
|
|
|
22
|
-
// app/layout.tsx
|
|
23
30
|
export default function RootLayout({ children }) {
|
|
24
31
|
return (
|
|
25
32
|
<html lang="en" suppressHydrationWarning>
|
|
26
33
|
<body>
|
|
27
34
|
<BaseApp
|
|
28
|
-
|
|
35
|
+
project="my-app"
|
|
36
|
+
theme={{ defaultTheme: 'dark', storageKey: 'my-theme' }}
|
|
37
|
+
auth={{ apiUrl: process.env.NEXT_PUBLIC_API_URL }}
|
|
29
38
|
analytics={{ googleTrackingId: 'G-XXXXXXXXXX' }}
|
|
30
|
-
|
|
31
|
-
pwaInstall={{ enabled: true, showInstallHint: true }}
|
|
32
|
-
mcpChat={{ enabled: true, autoDetectEnvironment: true }}
|
|
39
|
+
debug={true}
|
|
33
40
|
>
|
|
34
41
|
{children}
|
|
35
42
|
</BaseApp>
|
|
@@ -39,29 +46,35 @@ export default function RootLayout({ children }) {
|
|
|
39
46
|
}
|
|
40
47
|
```
|
|
41
48
|
|
|
42
|
-
**
|
|
43
|
-
- **ThemeProvider** - Light/dark/system theme management
|
|
44
|
-
- **TooltipProvider** - Tooltip positioning context
|
|
45
|
-
- **SWRConfig** - Data fetching configuration
|
|
46
|
-
- **AuthProvider** - Authentication context (from `@djangocfg/api`)
|
|
47
|
-
- **AnalyticsProvider** - Google Analytics (optional)
|
|
48
|
-
- **CentrifugoProvider** - WebSocket real-time (optional)
|
|
49
|
-
- **PwaProvider** - PWA installation (optional)
|
|
50
|
-
- **ErrorTrackingProvider** - Error handling and tracking
|
|
51
|
-
- **ErrorBoundary** - React error boundary
|
|
52
|
-
- **MonitorProvider** - Frontend error monitoring via `@djangocfg/monitor` (optional)
|
|
53
|
-
- **MCP Chat Widget** - AI chat assistant (optional)
|
|
54
|
-
|
|
55
|
-
**Global components:**
|
|
56
|
-
- **PageProgress** - NProgress bar for route changes
|
|
57
|
-
- **Toaster** - Toast notifications container
|
|
58
|
-
- **A2HSHint** - PWA install hint (if enabled)
|
|
59
|
-
|
|
60
|
-
> **Note:** Auth functionality is provided by `@djangocfg/api` package. See [@djangocfg/api documentation](../api/README.md) for auth usage.
|
|
61
|
-
|
|
62
|
-
### AppLayout
|
|
49
|
+
**Props:**
|
|
63
50
|
|
|
64
|
-
|
|
51
|
+
| Prop | Type | Default | Description |
|
|
52
|
+
|------|------|---------|-------------|
|
|
53
|
+
| `project` | `string` | — | App name — auto-passed to `MonitorProvider` and debug panel |
|
|
54
|
+
| `theme` | `ThemeConfig` | — | Theme config (defaultTheme, storageKey) |
|
|
55
|
+
| `auth` | `AuthConfig` | — | Auth provider config |
|
|
56
|
+
| `analytics` | `AnalyticsConfig` | — | Google Analytics config |
|
|
57
|
+
| `centrifugo` | `CentrifugoConfig` | — | WebSocket real-time config |
|
|
58
|
+
| `errorTracking` | `ErrorTrackingConfig` | — | Validation/CORS/network error capture |
|
|
59
|
+
| `errorBoundary` | `ErrorBoundaryConfig` | enabled | React error boundary |
|
|
60
|
+
| `swr` | `SWRConfigOptions` | — | SWR data fetching config |
|
|
61
|
+
| `pwaInstall` | `PwaInstallConfig` | — | PWA install prompt |
|
|
62
|
+
| `mcpChat` | `McpChatConfig` | — | AI chat widget |
|
|
63
|
+
| `monitor` | `MonitorConfig` | — | Override monitor config (project/environment come from `project` prop by default) |
|
|
64
|
+
| `debug` | `boolean` | `true` | Debug panel — `Cmd+D` or `?debug=1` to open |
|
|
65
|
+
|
|
66
|
+
**Included automatically:**
|
|
67
|
+
- ThemeProvider, TooltipProvider, SWRConfig, DialogProvider
|
|
68
|
+
- AuthProvider + AuthDialog
|
|
69
|
+
- AnalyticsProvider, CentrifugoProvider, PwaProvider
|
|
70
|
+
- ErrorTrackingProvider, ErrorBoundary
|
|
71
|
+
- MonitorProvider (auto-enabled via `project` prop)
|
|
72
|
+
- DebugButton from `@djangocfg/debuger` (disable with `debug={false}`)
|
|
73
|
+
- NextTopLoader, Toaster
|
|
74
|
+
|
|
75
|
+
## AppLayout
|
|
76
|
+
|
|
77
|
+
Smart layout router — selects layout based on current route. Wraps `BaseApp`, accepts all its props.
|
|
65
78
|
|
|
66
79
|
```tsx
|
|
67
80
|
import { AppLayout } from '@djangocfg/layouts';
|
|
@@ -69,32 +82,20 @@ import { PublicLayout } from './_layouts/PublicLayout';
|
|
|
69
82
|
import { PrivateLayout } from './_layouts/PrivateLayout';
|
|
70
83
|
import { AdminLayout } from './_layouts/AdminLayout';
|
|
71
84
|
|
|
72
|
-
// app/layout.tsx
|
|
73
85
|
export default function RootLayout({ children }) {
|
|
74
86
|
return (
|
|
75
87
|
<html lang="en" suppressHydrationWarning>
|
|
76
88
|
<body>
|
|
77
89
|
<AppLayout
|
|
78
|
-
|
|
90
|
+
project="my-app"
|
|
79
91
|
theme={{ defaultTheme: 'system' }}
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
}}
|
|
88
|
-
privateLayout={{
|
|
89
|
-
component: PrivateLayout,
|
|
90
|
-
enabledPath: ['/dashboard', '/profile']
|
|
91
|
-
}}
|
|
92
|
-
adminLayout={{
|
|
93
|
-
component: AdminLayout,
|
|
94
|
-
enabledPath: '/admin'
|
|
95
|
-
}}
|
|
96
|
-
|
|
97
|
-
// Skip layout for fullscreen pages (providers still applied)
|
|
92
|
+
auth={{ apiUrl: process.env.NEXT_PUBLIC_API_URL }}
|
|
93
|
+
debug={true}
|
|
94
|
+
|
|
95
|
+
publicLayout={{ component: PublicLayout, enabledPath: ['/', '/legal', '/contact'] }}
|
|
96
|
+
privateLayout={{ component: PrivateLayout, enabledPath: ['/dashboard', '/profile'] }}
|
|
97
|
+
adminLayout={{ component: AdminLayout, enabledPath: '/admin' }}
|
|
98
|
+
|
|
98
99
|
noLayoutPaths={['/private/terminal', '/embed']}
|
|
99
100
|
>
|
|
100
101
|
{children}
|
|
@@ -105,709 +106,163 @@ export default function RootLayout({ children }) {
|
|
|
105
106
|
}
|
|
106
107
|
```
|
|
107
108
|
|
|
108
|
-
**Monitor prop** — pass `monitor` to enable frontend error monitoring (installs `window.monitor` in DevTools):
|
|
109
|
-
|
|
110
|
-
```tsx
|
|
111
|
-
<AppLayout
|
|
112
|
-
monitor={{
|
|
113
|
-
project: 'my-app',
|
|
114
|
-
environment: process.env.NODE_ENV,
|
|
115
|
-
}}
|
|
116
|
-
// ...
|
|
117
|
-
>
|
|
118
|
-
{children}
|
|
119
|
-
</AppLayout>
|
|
120
|
-
```
|
|
121
|
-
|
|
122
|
-
After mount, `window.monitor.error(...)`, `.warn(...)`, `.flush()`, `.status()` are available in the browser console.
|
|
123
|
-
|
|
124
109
|
**Layout priority:** Admin → Private → Public → Fallback
|
|
125
110
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
## Layouts
|
|
129
|
-
|
|
130
|
-
Simple, props-based layout components. No complex configs needed!
|
|
111
|
+
**`noLayoutPaths`** — render without layout wrapper (providers still active). Useful for fullscreen pages.
|
|
131
112
|
|
|
132
|
-
###
|
|
113
|
+
### i18n
|
|
133
114
|
|
|
134
115
|
```tsx
|
|
135
|
-
import {
|
|
116
|
+
import { useLocaleSwitcher } from '@djangocfg/nextjs/i18n/client';
|
|
136
117
|
|
|
137
|
-
|
|
138
|
-
<PublicLayout
|
|
139
|
-
logo="/logo.svg"
|
|
140
|
-
siteName="My App"
|
|
141
|
-
navigation={navItems}
|
|
142
|
-
>
|
|
143
|
-
{children}
|
|
144
|
-
</PublicLayout>
|
|
145
|
-
|
|
146
|
-
// Private page
|
|
147
|
-
<PrivateLayout
|
|
148
|
-
sidebar={{
|
|
149
|
-
groups: [
|
|
150
|
-
{ label: 'Main', items: menuItems }
|
|
151
|
-
]
|
|
152
|
-
}}
|
|
153
|
-
header={{ title: 'Dashboard' }}
|
|
154
|
-
>
|
|
155
|
-
{children}
|
|
156
|
-
</PrivateLayout>
|
|
118
|
+
const { locale, locales, changeLocale } = useLocaleSwitcher();
|
|
157
119
|
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
logo="/logo.svg"
|
|
161
|
-
title="Sign In"
|
|
162
|
-
subtitle="Welcome back"
|
|
120
|
+
<AppLayout
|
|
121
|
+
i18n={{ locale, locales, onLocaleChange: changeLocale }}
|
|
163
122
|
>
|
|
164
|
-
|
|
165
|
-
</
|
|
123
|
+
{children}
|
|
124
|
+
</AppLayout>
|
|
166
125
|
```
|
|
167
126
|
|
|
168
|
-
|
|
169
|
-
|--------|-------------|
|
|
170
|
-
| `BaseApp` | Core providers wrapper (Theme, Auth, SWR, ErrorTracking, Toaster) |
|
|
171
|
-
| `AppLayout` | Smart layout router with route-based layout switching |
|
|
172
|
-
| `PublicLayout` | Public pages (home, docs, contact, legal) |
|
|
173
|
-
| `PrivateLayout` | Authenticated user pages (dashboard, profile) |
|
|
174
|
-
| `AuthLayout` | Authentication pages (login, signup, password reset) |
|
|
175
|
-
| `AdminLayout` | Admin panel layout |
|
|
176
|
-
| `ProfileLayout` | User profile pages |
|
|
177
|
-
|
|
178
|
-
### i18n Support
|
|
179
|
-
|
|
180
|
-
Pass `i18n` config to AppLayout for locale switching in all layouts:
|
|
127
|
+
## Built-in Layouts
|
|
181
128
|
|
|
182
129
|
```tsx
|
|
183
|
-
import {
|
|
184
|
-
import { useLocaleSwitcher } from '@djangocfg/nextjs/i18n/client';
|
|
185
|
-
|
|
186
|
-
function RootLayout({ children }) {
|
|
187
|
-
const { locale, locales, changeLocale } = useLocaleSwitcher();
|
|
188
|
-
|
|
189
|
-
return (
|
|
190
|
-
<AppLayout
|
|
191
|
-
// ... other configs
|
|
192
|
-
i18n={{
|
|
193
|
-
locale,
|
|
194
|
-
locales,
|
|
195
|
-
onLocaleChange: changeLocale,
|
|
196
|
-
}}
|
|
197
|
-
>
|
|
198
|
-
{children}
|
|
199
|
-
</AppLayout>
|
|
200
|
-
);
|
|
201
|
-
}
|
|
130
|
+
import { PublicLayout, PrivateLayout, AuthLayout, AdminLayout, ProfileLayout } from '@djangocfg/layouts';
|
|
202
131
|
```
|
|
203
132
|
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
133
|
+
| Layout | Description |
|
|
134
|
+
|--------|-------------|
|
|
135
|
+
| `PublicLayout` | Public pages with nav (home, docs, contact, legal) |
|
|
136
|
+
| `PrivateLayout` | Authenticated pages with sidebar |
|
|
137
|
+
| `AuthLayout` | OTP + OAuth + 2FA authentication flow |
|
|
138
|
+
| `AdminLayout` | Admin panel |
|
|
139
|
+
| `ProfileLayout` | User profile with 2FA management |
|
|
207
140
|
|
|
208
|
-
|
|
141
|
+
### AuthLayout
|
|
209
142
|
|
|
210
143
|
```tsx
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
/>
|
|
219
|
-
|
|
220
|
-
// With custom labels and styling
|
|
221
|
-
<LocaleSwitcher
|
|
222
|
-
locale={currentLocale}
|
|
223
|
-
locales={['en', 'ru', 'ko']}
|
|
224
|
-
onChange={handleLocaleChange}
|
|
225
|
-
labels={{ en: 'English', ru: 'Русский', ko: '한국어' }}
|
|
226
|
-
variant="outline"
|
|
227
|
-
size="sm"
|
|
228
|
-
showIcon={true}
|
|
144
|
+
<AuthLayout
|
|
145
|
+
sourceUrl="https://example.com"
|
|
146
|
+
redirectUrl="/dashboard"
|
|
147
|
+
logoUrl="/logo.svg"
|
|
148
|
+
enableGithubAuth={true}
|
|
149
|
+
termsUrl="/terms"
|
|
150
|
+
privacyUrl="/privacy"
|
|
229
151
|
/>
|
|
230
152
|
```
|
|
231
153
|
|
|
232
|
-
|
|
233
|
-
| Prop | Type | Default | Description |
|
|
234
|
-
|------|------|---------|-------------|
|
|
235
|
-
| `locale` | `string` | - | Current locale code |
|
|
236
|
-
| `locales` | `string[]` | - | Available locale codes |
|
|
237
|
-
| `onChange` | `(locale: string) => void` | - | Callback when locale changes |
|
|
238
|
-
| `labels` | `Record<string, string>` | Built-in | Custom labels for locales |
|
|
239
|
-
| `showCode` | `boolean` | `false` | Show locale code with label |
|
|
240
|
-
| `variant` | `'ghost' \| 'outline' \| 'default'` | `'ghost'` | Button variant |
|
|
241
|
-
| `size` | `'sm' \| 'default' \| 'lg' \| 'icon'` | `'sm'` | Button size |
|
|
242
|
-
| `showIcon` | `boolean` | `true` | Show globe icon |
|
|
243
|
-
| `className` | `string` | - | Custom CSS class |
|
|
244
|
-
|
|
245
|
-
> **Smart version:** For automatic locale detection with next-intl hooks, use `@djangocfg/nextjs/i18n/components` which wraps this component.
|
|
246
|
-
|
|
247
|
-
> **Extension Layouts:** Additional layouts like `SupportLayout` and `PaymentsLayout` are available in extension packages:
|
|
248
|
-
> - `@djangocfg/ext-support` - Support ticket layouts
|
|
249
|
-
> - `@djangocfg/ext-payments` - Payment flow layouts
|
|
250
|
-
|
|
251
|
-
## Analytics
|
|
252
|
-
|
|
253
|
-
Google Analytics integration via `react-ga4`. Auto-tracks pageviews and user sessions.
|
|
254
|
-
|
|
255
|
-
### Setup
|
|
256
|
-
|
|
257
|
-
Add tracking ID to your config:
|
|
154
|
+
### ProfileLayout
|
|
258
155
|
|
|
259
156
|
```tsx
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
googleTrackingId: 'G-XXXXXXXXXX',
|
|
265
|
-
},
|
|
266
|
-
};
|
|
157
|
+
<ProfileLayout
|
|
158
|
+
enable2FA={true}
|
|
159
|
+
showMemberSince={true}
|
|
160
|
+
/>
|
|
267
161
|
```
|
|
268
162
|
|
|
269
|
-
|
|
163
|
+
## Monitor & Debug
|
|
270
164
|
|
|
271
|
-
|
|
165
|
+
Both are auto-enabled via `project` prop — no extra config needed.
|
|
272
166
|
|
|
273
167
|
```tsx
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
event(AnalyticsEvent.THEME_CHANGE, {
|
|
280
|
-
category: AnalyticsCategory.ENGAGEMENT,
|
|
281
|
-
label: 'dark',
|
|
282
|
-
});
|
|
283
|
-
|
|
284
|
-
// Outside React (utilities, handlers)
|
|
285
|
-
Analytics.event('button_click', { category: 'engagement', label: 'signup' });
|
|
286
|
-
Analytics.setUser('user-123');
|
|
168
|
+
// Monitor auto-starts, window.monitor available in DevTools:
|
|
169
|
+
window.monitor.error('Something broke', { context: 'checkout' })
|
|
170
|
+
window.monitor.warn('Slow response', { ms: 2500 })
|
|
171
|
+
window.monitor.flush() // send buffer immediately
|
|
172
|
+
window.monitor.status() // show current state
|
|
287
173
|
```
|
|
288
174
|
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
| Category | Events |
|
|
292
|
-
|----------|--------|
|
|
293
|
-
| **Auth** | `AUTH_LOGIN_SUCCESS`, `AUTH_LOGOUT`, `AUTH_SESSION_EXPIRED`, `AUTH_TOKEN_REFRESH` |
|
|
294
|
-
| **OAuth** | `AUTH_OAUTH_START`, `AUTH_OAUTH_SUCCESS`, `AUTH_OAUTH_FAIL` |
|
|
295
|
-
| **Error** | `ERROR_BOUNDARY`, `ERROR_API`, `ERROR_VALIDATION`, `ERROR_NETWORK` |
|
|
296
|
-
| **Navigation** | `NAV_ADMIN_ENTER`, `NAV_DASHBOARD_ENTER`, `NAV_PAGE_VIEW` |
|
|
297
|
-
| **Engagement** | `THEME_CHANGE`, `SIDEBAR_TOGGLE`, `MOBILE_MENU_OPEN` |
|
|
298
|
-
|
|
299
|
-
### Auto-tracking
|
|
300
|
-
|
|
301
|
-
Built-in tracking for:
|
|
302
|
-
- **Page views** - on every route change
|
|
303
|
-
- **User ID** - automatically set when user is authenticated
|
|
304
|
-
- **Auth events** - login, logout, session expiry (from `@djangocfg/api`)
|
|
305
|
-
- **OAuth events** - GitHub OAuth start, success, failure
|
|
306
|
-
- **Errors** - React ErrorBoundary errors
|
|
307
|
-
|
|
308
|
-
## PWA Installation
|
|
309
|
-
|
|
310
|
-
Enable PWA installation prompts with `pwaInstall` config:
|
|
175
|
+
Override monitor defaults:
|
|
311
176
|
|
|
312
177
|
```tsx
|
|
313
|
-
import { BaseApp } from '@djangocfg/layouts';
|
|
314
|
-
|
|
315
178
|
<BaseApp
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
showInstallHint: true, // Show A2HS hint
|
|
319
|
-
resetAfterDays: 3, // Re-show after dismissal
|
|
320
|
-
delayMs: 1000, // Delay before showing
|
|
321
|
-
logo: '/logo192.png', // PWA logo
|
|
322
|
-
resumeLastPage: true, // Resume last page on PWA launch
|
|
323
|
-
}}
|
|
179
|
+
project="my-app"
|
|
180
|
+
monitor={{ baseUrl: 'https://api.example.com', captureConsole: false }}
|
|
324
181
|
>
|
|
325
|
-
{children}
|
|
326
|
-
</BaseApp>
|
|
327
182
|
```
|
|
328
183
|
|
|
329
|
-
|
|
330
|
-
- **A2HSHint** - Platform-specific install hints (iOS Safari/Chrome/Firefox, Android Chrome, Desktop)
|
|
331
|
-
- **Page Resume** - Automatically navigate to last viewed page when PWA is launched
|
|
332
|
-
- **Auto-detection** - Detects if running as PWA
|
|
333
|
-
- **Dismissal tracking** - Respects user dismissal with localStorage
|
|
334
|
-
- **Custom timing** - Configurable delay and reset periods
|
|
184
|
+
Debug panel: `Cmd+D` or `?debug=1` in URL. Disable: `debug={false}`.
|
|
335
185
|
|
|
336
|
-
|
|
337
|
-
When `resumeLastPage: true`, the app saves the current pathname on every navigation and restores it when the PWA is launched. Pages like `/auth`, `/login`, `/error` are automatically excluded. Data expires after 24 hours.
|
|
338
|
-
|
|
339
|
-
### Usage
|
|
186
|
+
## Error Tracking
|
|
340
187
|
|
|
341
188
|
```tsx
|
|
342
|
-
import {
|
|
343
|
-
|
|
344
|
-
// PWA status
|
|
345
|
-
const { isPWA, isInstallable } = usePwa();
|
|
346
|
-
```
|
|
189
|
+
import { useErrorEmitter, emitRuntimeError } from '@djangocfg/layouts';
|
|
347
190
|
|
|
348
|
-
|
|
191
|
+
// In components
|
|
192
|
+
const { emitError } = useErrorEmitter('MyComponent');
|
|
193
|
+
emitError('Something failed', error);
|
|
349
194
|
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
```tsx
|
|
353
|
-
import {
|
|
354
|
-
Breadcrumbs,
|
|
355
|
-
AuthDialog,
|
|
356
|
-
usePwa,
|
|
357
|
-
} from '@djangocfg/layouts/snippets';
|
|
195
|
+
// Outside React
|
|
196
|
+
emitRuntimeError('MyUtil', 'Operation failed', error);
|
|
358
197
|
```
|
|
359
198
|
|
|
360
|
-
|
|
361
|
-
|---------|-------------|
|
|
362
|
-
| `Breadcrumbs` | Navigation breadcrumbs with automatic path generation |
|
|
363
|
-
| `AuthDialog` | Auth modal (login/register) with event-based triggers |
|
|
364
|
-
| `AnalyticsProvider` | Analytics wrapper component |
|
|
365
|
-
| `usePwa` | PWA status hook (isPWA, isInstallable, etc.) |
|
|
366
|
-
| `usePWAPageResume` | Resume last page on PWA launch |
|
|
367
|
-
| `A2HSHint` | Add to Home Screen hint component |
|
|
368
|
-
| `PWAPageResumeManager` | Component for PWA page resume (use via BaseApp config) |
|
|
369
|
-
|
|
370
|
-
> **Extension Snippets:** Additional components are available in extension packages:
|
|
371
|
-
> - `@djangocfg/ext-leads` - ContactForm, ContactPage, ContactInfo
|
|
372
|
-
> - `@djangocfg/ext-knowbase` - KnowledgeChat, ChatWidget, ChatUIProvider
|
|
373
|
-
> - `@djangocfg/ext-newsletter` - Hero (with newsletter subscription)
|
|
374
|
-
|
|
375
|
-
### Breadcrumbs
|
|
376
|
-
|
|
377
|
-
```tsx
|
|
378
|
-
import Breadcrumbs from '@djangocfg/layouts/snippets';
|
|
379
|
-
|
|
380
|
-
// Auto-generate from current path
|
|
381
|
-
<Breadcrumbs />
|
|
382
|
-
|
|
383
|
-
// Or provide custom items
|
|
384
|
-
<Breadcrumbs
|
|
385
|
-
items={[
|
|
386
|
-
{ path: '/', label: 'Home', isActive: false },
|
|
387
|
-
{ path: '/products', label: 'Products', isActive: true },
|
|
388
|
-
]}
|
|
389
|
-
/>
|
|
390
|
-
```
|
|
391
|
-
|
|
392
|
-
### AuthDialog
|
|
393
|
-
|
|
394
|
-
```tsx
|
|
395
|
-
import { AuthDialog, openAuthDialog } from '@djangocfg/layouts/snippets';
|
|
396
|
-
|
|
397
|
-
// Add to layout
|
|
398
|
-
<AuthDialog authPath="/auth" />
|
|
399
|
-
|
|
400
|
-
// Trigger from anywhere
|
|
401
|
-
openAuthDialog({ message: 'Sign in to continue' });
|
|
402
|
-
```
|
|
403
|
-
|
|
404
|
-
## Components
|
|
405
|
-
|
|
406
|
-
Utility components organized by category.
|
|
407
|
-
|
|
408
|
-
### Core Components
|
|
409
|
-
|
|
410
|
-
```tsx
|
|
411
|
-
import {
|
|
412
|
-
JsonLd,
|
|
413
|
-
LucideIcon,
|
|
414
|
-
PageProgress,
|
|
415
|
-
Suspense
|
|
416
|
-
} from '@djangocfg/layouts/components/core';
|
|
417
|
-
```
|
|
418
|
-
|
|
419
|
-
| Component | Description |
|
|
420
|
-
|-----------|-------------|
|
|
421
|
-
| `JsonLd` | JSON-LD structured data component |
|
|
422
|
-
| `LucideIcon` | Lucide icon wrapper component |
|
|
423
|
-
| `PageProgress` | Page loading progress indicator |
|
|
424
|
-
| `Suspense` | Suspense wrapper component |
|
|
425
|
-
|
|
426
|
-
### Error Components
|
|
199
|
+
## Error Pages
|
|
427
200
|
|
|
428
201
|
```tsx
|
|
429
|
-
import {
|
|
430
|
-
ErrorBoundary,
|
|
431
|
-
ErrorLayout,
|
|
432
|
-
getErrorContent,
|
|
433
|
-
ERROR_CODES
|
|
434
|
-
} from '@djangocfg/layouts/components/errors';
|
|
435
|
-
```
|
|
436
|
-
|
|
437
|
-
| Component | Description |
|
|
438
|
-
|-----------|-------------|
|
|
439
|
-
| `ErrorBoundary` | React error boundary component |
|
|
440
|
-
| `ErrorLayout` | Reusable error page layout (404, 500, etc.) |
|
|
441
|
-
| `getErrorContent` | Get error content by status code |
|
|
442
|
-
| `ERROR_CODES` | Common HTTP error code constants |
|
|
443
|
-
|
|
444
|
-
**ErrorLayout Usage:**
|
|
445
|
-
|
|
446
|
-
```tsx
|
|
447
|
-
// app/not-found.tsx
|
|
448
202
|
import { ErrorLayout } from '@djangocfg/layouts/components/errors';
|
|
449
203
|
|
|
204
|
+
// app/not-found.tsx
|
|
450
205
|
export default function NotFound() {
|
|
451
206
|
return <ErrorLayout code={404} supportEmail="support@example.com" />;
|
|
452
207
|
}
|
|
208
|
+
```
|
|
453
209
|
|
|
454
|
-
|
|
455
|
-
'use client';
|
|
456
|
-
import { ErrorLayout } from '@djangocfg/layouts/components/errors';
|
|
210
|
+
## PWA
|
|
457
211
|
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
212
|
+
```tsx
|
|
213
|
+
<BaseApp
|
|
214
|
+
pwaInstall={{
|
|
215
|
+
enabled: true,
|
|
216
|
+
showInstallHint: true,
|
|
217
|
+
logo: '/logo192.png',
|
|
218
|
+
delayMs: 3000,
|
|
219
|
+
resetAfterDays: 7,
|
|
220
|
+
resumeLastPage: true,
|
|
221
|
+
}}
|
|
222
|
+
>
|
|
461
223
|
```
|
|
462
224
|
|
|
463
|
-
|
|
225
|
+
## Redirect
|
|
464
226
|
|
|
465
227
|
```tsx
|
|
466
228
|
import { RedirectPage } from '@djangocfg/layouts/components/RedirectPage';
|
|
467
229
|
|
|
468
|
-
// app/page.tsx
|
|
469
230
|
export default function Page() {
|
|
470
|
-
return
|
|
471
|
-
<RedirectPage
|
|
472
|
-
authenticatedPath="/dashboard"
|
|
473
|
-
unauthenticatedPath="/auth"
|
|
474
|
-
loadingText="Loading..."
|
|
475
|
-
/>
|
|
476
|
-
);
|
|
231
|
+
return <RedirectPage authenticatedPath="/dashboard" unauthenticatedPath="/auth" />;
|
|
477
232
|
}
|
|
478
233
|
```
|
|
479
234
|
|
|
480
|
-
|
|
235
|
+
## Legal Pages
|
|
481
236
|
|
|
482
237
|
```tsx
|
|
483
|
-
import {
|
|
484
|
-
ErrorTrackingProvider,
|
|
485
|
-
useErrors,
|
|
486
|
-
useErrorEmitter,
|
|
487
|
-
emitRuntimeError,
|
|
488
|
-
} from '@djangocfg/layouts';
|
|
489
|
-
|
|
490
|
-
// Wrap your app
|
|
491
|
-
<ErrorTrackingProvider>
|
|
492
|
-
<YourApp />
|
|
493
|
-
</ErrorTrackingProvider>
|
|
494
|
-
|
|
495
|
-
// In React components - use hook
|
|
496
|
-
function MyComponent() {
|
|
497
|
-
const { emitError } = useErrorEmitter('MyComponent');
|
|
498
|
-
|
|
499
|
-
try {
|
|
500
|
-
doSomething();
|
|
501
|
-
} catch (error) {
|
|
502
|
-
emitError('Something failed', error);
|
|
503
|
-
}
|
|
504
|
-
}
|
|
505
|
-
|
|
506
|
-
// Outside React (utilities, libraries) - use standalone function
|
|
507
|
-
import { emitRuntimeError } from '@djangocfg/layouts';
|
|
238
|
+
import { PrivacyPage, TermsPage, CookiesPage, SecurityPage } from '@djangocfg/layouts/pages/legal';
|
|
508
239
|
|
|
509
|
-
try {
|
|
510
|
-
doSomething();
|
|
511
|
-
} catch (error) {
|
|
512
|
-
emitRuntimeError('MyUtility', 'Something failed', error);
|
|
513
|
-
}
|
|
514
|
-
|
|
515
|
-
// Access errors
|
|
516
|
-
const { errors, clearErrors } = useErrors();
|
|
517
|
-
```
|
|
518
|
-
|
|
519
|
-
### Update Notifier
|
|
520
|
-
|
|
521
|
-
```tsx
|
|
522
|
-
import { UpdateNotifier } from '@djangocfg/layouts/components/UpdateNotifier';
|
|
523
|
-
|
|
524
|
-
<UpdateNotifier />
|
|
525
|
-
```
|
|
526
|
-
|
|
527
|
-
## Pages
|
|
528
|
-
|
|
529
|
-
Ready-to-use page components.
|
|
530
|
-
|
|
531
|
-
### Legal Pages
|
|
532
|
-
|
|
533
|
-
Pre-built legal page components with default configurations.
|
|
534
|
-
|
|
535
|
-
```tsx
|
|
536
|
-
import {
|
|
537
|
-
PrivacyPage,
|
|
538
|
-
TermsPage,
|
|
539
|
-
CookiesPage,
|
|
540
|
-
SecurityPage
|
|
541
|
-
} from '@djangocfg/layouts/pages/legal';
|
|
542
|
-
|
|
543
|
-
// app/legal/privacy/page.tsx
|
|
544
240
|
export default PrivacyPage;
|
|
545
|
-
|
|
546
|
-
// Or customize
|
|
547
|
-
import { PrivacyPage, privacyConfig } from '@djangocfg/layouts/pages/legal';
|
|
548
|
-
|
|
549
|
-
export default function CustomPrivacy() {
|
|
550
|
-
return <PrivacyPage config={{
|
|
551
|
-
...privacyConfig,
|
|
552
|
-
lastUpdated: '2024-01-01',
|
|
553
|
-
}} />;
|
|
554
|
-
}
|
|
555
241
|
```
|
|
556
242
|
|
|
557
|
-
| Page | Description |
|
|
558
|
-
|------|-------------|
|
|
559
|
-
| `PrivacyPage` | Privacy policy page |
|
|
560
|
-
| `TermsPage` | Terms of service page |
|
|
561
|
-
| `CookiesPage` | Cookie policy page |
|
|
562
|
-
| `SecurityPage` | Security policy page |
|
|
563
|
-
|
|
564
|
-
## Utils
|
|
565
|
-
|
|
566
|
-
Utility functions and helpers.
|
|
567
|
-
|
|
568
|
-
```tsx
|
|
569
|
-
import {
|
|
570
|
-
generateOgImageUrl,
|
|
571
|
-
getAbsoluteOgImageUrl,
|
|
572
|
-
createOgImageUrlBuilder
|
|
573
|
-
} from '@djangocfg/layouts/utils/og-image';
|
|
574
|
-
|
|
575
|
-
// Generate OG image URL
|
|
576
|
-
const ogUrl = generateOgImageUrl('/api/og', {
|
|
577
|
-
title: 'My Page',
|
|
578
|
-
description: 'Page description',
|
|
579
|
-
siteName: 'My Site',
|
|
580
|
-
});
|
|
581
|
-
```
|
|
582
|
-
|
|
583
|
-
| Utility | Description |
|
|
584
|
-
|---------|-------------|
|
|
585
|
-
| `generateOgImageUrl` | Generate OG image URL with base64 encoding |
|
|
586
|
-
| `getAbsoluteOgImageUrl` | Get absolute OG image URL |
|
|
587
|
-
| `createOgImageUrlBuilder` | Create OG image URL builder with defaults |
|
|
588
|
-
|
|
589
243
|
## Exports
|
|
590
244
|
|
|
591
245
|
| Path | Content |
|
|
592
246
|
|------|---------|
|
|
593
|
-
| `@djangocfg/layouts` |
|
|
247
|
+
| `@djangocfg/layouts` | All exports |
|
|
594
248
|
| `@djangocfg/layouts/layouts` | Layout components |
|
|
595
|
-
| `@djangocfg/layouts/snippets` | Reusable components
|
|
596
|
-
| `@djangocfg/layouts/components` |
|
|
597
|
-
| `@djangocfg/layouts/pages` |
|
|
598
|
-
| `@djangocfg/layouts/
|
|
599
|
-
| `@djangocfg/layouts/utils` | Utilities (og-image, logger) |
|
|
249
|
+
| `@djangocfg/layouts/snippets` | Reusable components |
|
|
250
|
+
| `@djangocfg/layouts/components` | Utility components |
|
|
251
|
+
| `@djangocfg/layouts/pages/legal` | Legal pages |
|
|
252
|
+
| `@djangocfg/layouts/utils` | OG image utils |
|
|
600
253
|
| `@djangocfg/layouts/styles` | CSS |
|
|
601
|
-
| `@djangocfg/layouts/styles/dashboard` | Dashboard
|
|
602
|
-
|
|
603
|
-
> **Auth Exports:** For authentication, use `@djangocfg/api/auth` - See [@djangocfg/api documentation](../api/README.md)
|
|
254
|
+
| `@djangocfg/layouts/styles/dashboard` | Dashboard CSS |
|
|
604
255
|
|
|
605
256
|
## Extension Packages
|
|
606
257
|
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
|
610
|
-
|
|
611
|
-
|
|
|
612
|
-
|
|
|
613
|
-
|
|
|
614
|
-
| **Payments** | `@djangocfg/ext-payments` | Payment processing and subscriptions |
|
|
615
|
-
| **Support** | `@djangocfg/ext-support` | Support tickets and helpdesk |
|
|
616
|
-
|
|
617
|
-
Each extension has its own layouts, contexts, and components. See individual extension documentation for details.
|
|
618
|
-
|
|
619
|
-
## Requirements
|
|
620
|
-
|
|
621
|
-
- Next.js >= 15
|
|
622
|
-
- React >= 19
|
|
623
|
-
- Tailwind CSS >= 4
|
|
624
|
-
- react-ga4 (bundled)
|
|
625
|
-
- @djangocfg/ui-nextjs (peer dependency)
|
|
626
|
-
- @djangocfg/api (peer dependency)
|
|
627
|
-
|
|
628
|
-
## Philosophy
|
|
629
|
-
|
|
630
|
-
This package follows a **simple, props-based approach**:
|
|
631
|
-
|
|
632
|
-
- ✅ **No complex configs** - just pass props
|
|
633
|
-
- ✅ **Type-safe** - full TypeScript support
|
|
634
|
-
- ✅ **Flexible** - compose layouts as needed
|
|
635
|
-
- ✅ **Production-ready** - built for real apps
|
|
636
|
-
- ✅ **Modular** - core layouts in one package, extensions separate
|
|
637
|
-
|
|
638
|
-
## Examples
|
|
639
|
-
|
|
640
|
-
### Complete App Setup
|
|
641
|
-
|
|
642
|
-
```tsx
|
|
643
|
-
// app/layout.tsx
|
|
644
|
-
import { AppLayout } from '@djangocfg/layouts';
|
|
645
|
-
import { appLayoutConfig } from './_config/appLayoutConfig';
|
|
646
|
-
|
|
647
|
-
export default function RootLayout({ children }) {
|
|
648
|
-
return (
|
|
649
|
-
<AppLayout config={appLayoutConfig}>
|
|
650
|
-
{children}
|
|
651
|
-
</AppLayout>
|
|
652
|
-
);
|
|
653
|
-
}
|
|
654
|
-
```
|
|
655
|
-
|
|
656
|
-
### Public Page
|
|
657
|
-
|
|
658
|
-
```tsx
|
|
659
|
-
// app/page.tsx
|
|
660
|
-
import { PublicLayout } from '@djangocfg/layouts';
|
|
661
|
-
|
|
662
|
-
export default function HomePage() {
|
|
663
|
-
return (
|
|
664
|
-
<PublicLayout
|
|
665
|
-
logo="/logo.svg"
|
|
666
|
-
siteName="My App"
|
|
667
|
-
navigation={[
|
|
668
|
-
{ label: 'Home', href: '/' },
|
|
669
|
-
{ label: 'Docs', href: '/docs' },
|
|
670
|
-
{ label: 'Contact', href: '/contact' }
|
|
671
|
-
]}
|
|
672
|
-
>
|
|
673
|
-
<h1>Welcome</h1>
|
|
674
|
-
</PublicLayout>
|
|
675
|
-
);
|
|
676
|
-
}
|
|
677
|
-
```
|
|
678
|
-
|
|
679
|
-
### Private Dashboard
|
|
680
|
-
|
|
681
|
-
```tsx
|
|
682
|
-
// app/dashboard/page.tsx
|
|
683
|
-
import { PrivateLayout } from '@djangocfg/layouts';
|
|
684
|
-
|
|
685
|
-
export default function DashboardPage() {
|
|
686
|
-
return (
|
|
687
|
-
<PrivateLayout
|
|
688
|
-
sidebar={{
|
|
689
|
-
groups: [
|
|
690
|
-
{
|
|
691
|
-
label: 'Main',
|
|
692
|
-
items: [
|
|
693
|
-
{ label: 'Dashboard', href: '/dashboard', icon: 'LayoutDashboard' },
|
|
694
|
-
{ label: 'Settings', href: '/settings', icon: 'Settings' }
|
|
695
|
-
]
|
|
696
|
-
}
|
|
697
|
-
],
|
|
698
|
-
homeHref: '/dashboard'
|
|
699
|
-
}}
|
|
700
|
-
header={{ title: 'Dashboard' }}
|
|
701
|
-
>
|
|
702
|
-
<h1>Dashboard</h1>
|
|
703
|
-
</PrivateLayout>
|
|
704
|
-
);
|
|
705
|
-
}
|
|
706
|
-
```
|
|
707
|
-
|
|
708
|
-
### Auth Page (OTP + 2FA Authentication)
|
|
709
|
-
|
|
710
|
-
```tsx
|
|
711
|
-
// app/auth/page.tsx
|
|
712
|
-
'use client';
|
|
713
|
-
|
|
714
|
-
import { AuthLayout } from '@djangocfg/layouts';
|
|
715
|
-
|
|
716
|
-
export default function AuthPage() {
|
|
717
|
-
return (
|
|
718
|
-
<AuthLayout
|
|
719
|
-
sourceUrl="https://example.com"
|
|
720
|
-
supportUrl="/support"
|
|
721
|
-
termsUrl="/terms"
|
|
722
|
-
privacyUrl="/privacy"
|
|
723
|
-
enablePhoneAuth={false}
|
|
724
|
-
enableGithubAuth={true}
|
|
725
|
-
logoUrl="/logo.svg"
|
|
726
|
-
redirectUrl="/dashboard"
|
|
727
|
-
onOTPSuccess={() => {
|
|
728
|
-
console.log('Authentication successful');
|
|
729
|
-
}}
|
|
730
|
-
onOAuthSuccess={(user, isNewUser, provider) => {
|
|
731
|
-
console.log('OAuth success:', { user, isNewUser, provider });
|
|
732
|
-
}}
|
|
733
|
-
>
|
|
734
|
-
<div className="text-center mb-6">
|
|
735
|
-
<h2 className="text-2xl font-bold">Welcome to My App</h2>
|
|
736
|
-
<p className="text-muted-foreground mt-2">
|
|
737
|
-
Sign in with your email or phone
|
|
738
|
-
</p>
|
|
739
|
-
</div>
|
|
740
|
-
</AuthLayout>
|
|
741
|
-
);
|
|
742
|
-
}
|
|
743
|
-
```
|
|
744
|
-
|
|
745
|
-
**Authentication Flow:**
|
|
746
|
-
1. **Identifier** → Enter email/phone or click GitHub OAuth
|
|
747
|
-
2. **OTP** → Enter 6-digit verification code
|
|
748
|
-
3. **2FA** → Enter TOTP code (if 2FA enabled for user)
|
|
749
|
-
4. **Success** → Show logo animation, then redirect
|
|
750
|
-
|
|
751
|
-
**AuthLayout Props:**
|
|
752
|
-
| Prop | Type | Description |
|
|
753
|
-
|------|------|-------------|
|
|
754
|
-
| `sourceUrl` | `string` | Application URL for OTP emails |
|
|
755
|
-
| `redirectUrl` | `string` | URL to redirect after successful auth (default: `/dashboard`) |
|
|
756
|
-
| `logoUrl` | `string` | Logo URL for success screen (SVG recommended) |
|
|
757
|
-
| `enablePhoneAuth` | `boolean` | Enable phone number authentication |
|
|
758
|
-
| `enableGithubAuth` | `boolean` | Enable GitHub OAuth |
|
|
759
|
-
| `enable2FASetup` | `boolean` | Enable 2FA setup prompt after login (default: `true`). Set to `false` to skip 2FA setup prompt - users can then configure 2FA from ProfileLayout instead. |
|
|
760
|
-
| `termsUrl` | `string` | Terms of service URL (shows checkbox if provided) |
|
|
761
|
-
| `privacyUrl` | `string` | Privacy policy URL |
|
|
762
|
-
| `supportUrl` | `string` | Support page URL |
|
|
763
|
-
| `onOTPSuccess` | `() => void` | Callback after successful authentication |
|
|
764
|
-
| `onOAuthSuccess` | `(user, isNewUser, provider) => void` | Callback after successful OAuth |
|
|
765
|
-
| `onError` | `(message: string) => void` | Error callback |
|
|
766
|
-
|
|
767
|
-
### Profile Page (with 2FA Management)
|
|
768
|
-
|
|
769
|
-
```tsx
|
|
770
|
-
// app/profile/page.tsx
|
|
771
|
-
'use client';
|
|
772
|
-
|
|
773
|
-
import { ProfileLayout } from '@djangocfg/layouts';
|
|
774
|
-
|
|
775
|
-
export default function ProfilePage() {
|
|
776
|
-
return (
|
|
777
|
-
<ProfileLayout
|
|
778
|
-
title="Profile Settings"
|
|
779
|
-
description="Manage your account"
|
|
780
|
-
enable2FA={true} // Show 2FA management section
|
|
781
|
-
showMemberSince={true}
|
|
782
|
-
showLastLogin={true}
|
|
783
|
-
onUnauthenticated={() => {
|
|
784
|
-
// Redirect to login
|
|
785
|
-
}}
|
|
786
|
-
/>
|
|
787
|
-
);
|
|
788
|
-
}
|
|
789
|
-
```
|
|
790
|
-
|
|
791
|
-
**ProfileLayout Props:**
|
|
792
|
-
| Prop | Type | Description |
|
|
793
|
-
|------|------|-------------|
|
|
794
|
-
| `title` | `string` | Page title (default: "Profile Settings") |
|
|
795
|
-
| `description` | `string` | Page description |
|
|
796
|
-
| `enable2FA` | `boolean` | Show 2FA management section (default: `false`). When enabled, users can enable/disable Two-Factor Authentication from their profile. |
|
|
797
|
-
| `showMemberSince` | `boolean` | Show member since date (default: `true`) |
|
|
798
|
-
| `showLastLogin` | `boolean` | Show last login date (default: `true`) |
|
|
799
|
-
| `onUnauthenticated` | `() => void` | Callback when user is not authenticated |
|
|
800
|
-
|
|
801
|
-
**2FA Configuration Strategy:**
|
|
802
|
-
- Use `enable2FASetup={false}` in AuthLayout to skip post-login 2FA setup prompt
|
|
803
|
-
- Use `enable2FA={true}` in ProfileLayout to allow users to manage 2FA from settings
|
|
804
|
-
- This gives users control over when to enable 2FA instead of forcing it during login
|
|
258
|
+
| Package | Description |
|
|
259
|
+
|---------|-------------|
|
|
260
|
+
| `@djangocfg/ext-newsletter` | Newsletter subscription |
|
|
261
|
+
| `@djangocfg/ext-knowbase` | Knowledge base + AI chat |
|
|
262
|
+
| `@djangocfg/ext-leads` | Lead capture forms |
|
|
263
|
+
| `@djangocfg/ext-payments` | Payments & subscriptions |
|
|
264
|
+
| `@djangocfg/ext-support` | Support tickets |
|
|
805
265
|
|
|
806
266
|
## License
|
|
807
267
|
|
|
808
|
-
MIT
|
|
809
|
-
|
|
810
|
-
## Links
|
|
811
|
-
|
|
812
|
-
- [DjangoCFG Documentation](https://djangocfg.com)
|
|
813
|
-
- [GitHub](https://github.com/markolofsen/django-cfg)
|
|
268
|
+
MIT — [DjangoCFG](https://djangocfg.com) · [GitHub](https://github.com/markolofsen/django-cfg)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@djangocfg/layouts",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.221",
|
|
4
4
|
"description": "Simple, straightforward layout components for Next.js - import and use with props",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"layouts",
|
|
@@ -74,13 +74,13 @@
|
|
|
74
74
|
"check": "tsc --noEmit"
|
|
75
75
|
},
|
|
76
76
|
"peerDependencies": {
|
|
77
|
-
"@djangocfg/api": "^2.1.
|
|
78
|
-
"@djangocfg/centrifugo": "^2.1.
|
|
79
|
-
"@djangocfg/i18n": "^2.1.
|
|
80
|
-
"@djangocfg/monitor": "^2.1.
|
|
81
|
-
"@djangocfg/ui-core": "^2.1.
|
|
82
|
-
"@djangocfg/ui-nextjs": "^2.1.
|
|
83
|
-
"@djangocfg/ui-tools": "^2.1.
|
|
77
|
+
"@djangocfg/api": "^2.1.221",
|
|
78
|
+
"@djangocfg/centrifugo": "^2.1.221",
|
|
79
|
+
"@djangocfg/i18n": "^2.1.221",
|
|
80
|
+
"@djangocfg/monitor": "^2.1.221",
|
|
81
|
+
"@djangocfg/ui-core": "^2.1.221",
|
|
82
|
+
"@djangocfg/ui-nextjs": "^2.1.221",
|
|
83
|
+
"@djangocfg/ui-tools": "^2.1.221",
|
|
84
84
|
"@hookform/resolvers": "^5.2.2",
|
|
85
85
|
"consola": "^3.4.2",
|
|
86
86
|
"lucide-react": "^0.545.0",
|
|
@@ -102,20 +102,21 @@
|
|
|
102
102
|
}
|
|
103
103
|
},
|
|
104
104
|
"dependencies": {
|
|
105
|
+
"@djangocfg/debuger": "^2.1.221",
|
|
105
106
|
"nextjs-toploader": "^3.9.17",
|
|
106
107
|
"qrcode.react": "^4.2.0",
|
|
107
108
|
"react-ga4": "^2.1.0",
|
|
108
109
|
"uuid": "^11.1.0"
|
|
109
110
|
},
|
|
110
111
|
"devDependencies": {
|
|
111
|
-
"@djangocfg/api": "^2.1.
|
|
112
|
-
"@djangocfg/i18n": "^2.1.
|
|
113
|
-
"@djangocfg/centrifugo": "^2.1.
|
|
114
|
-
"@djangocfg/monitor": "^2.1.
|
|
115
|
-
"@djangocfg/typescript-config": "^2.1.
|
|
116
|
-
"@djangocfg/ui-core": "^2.1.
|
|
117
|
-
"@djangocfg/ui-nextjs": "^2.1.
|
|
118
|
-
"@djangocfg/ui-tools": "^2.1.
|
|
112
|
+
"@djangocfg/api": "^2.1.221",
|
|
113
|
+
"@djangocfg/i18n": "^2.1.221",
|
|
114
|
+
"@djangocfg/centrifugo": "^2.1.221",
|
|
115
|
+
"@djangocfg/monitor": "^2.1.221",
|
|
116
|
+
"@djangocfg/typescript-config": "^2.1.221",
|
|
117
|
+
"@djangocfg/ui-core": "^2.1.221",
|
|
118
|
+
"@djangocfg/ui-nextjs": "^2.1.221",
|
|
119
|
+
"@djangocfg/ui-tools": "^2.1.221",
|
|
119
120
|
"@types/node": "^24.7.2",
|
|
120
121
|
"@types/react": "^19.1.0",
|
|
121
122
|
"@types/react-dom": "^19.1.0",
|
|
@@ -91,6 +91,9 @@ interface LayoutConfig {
|
|
|
91
91
|
export interface AppLayoutProps {
|
|
92
92
|
children: ReactNode;
|
|
93
93
|
|
|
94
|
+
/** Project name — used as default for monitor.project and debug panel title */
|
|
95
|
+
project?: string;
|
|
96
|
+
|
|
94
97
|
/** Public layout component with enabled paths */
|
|
95
98
|
publicLayout?: LayoutConfig;
|
|
96
99
|
|
|
@@ -139,6 +142,9 @@ export interface AppLayoutProps {
|
|
|
139
142
|
|
|
140
143
|
/** Monitor configuration — initialises window.monitor + auto-captures JS errors & console */
|
|
141
144
|
monitor?: MonitorConfig;
|
|
145
|
+
|
|
146
|
+
/** Debug panel — set false to disable. Default: true */
|
|
147
|
+
debug?: boolean;
|
|
142
148
|
}
|
|
143
149
|
|
|
144
150
|
/**
|
|
@@ -251,6 +257,7 @@ function AppLayoutContent({
|
|
|
251
257
|
*/
|
|
252
258
|
export function AppLayout(props: AppLayoutProps) {
|
|
253
259
|
const {
|
|
260
|
+
project,
|
|
254
261
|
theme,
|
|
255
262
|
auth,
|
|
256
263
|
analytics,
|
|
@@ -261,10 +268,12 @@ export function AppLayout(props: AppLayoutProps) {
|
|
|
261
268
|
mcpChat,
|
|
262
269
|
pwaInstall,
|
|
263
270
|
monitor,
|
|
271
|
+
debug,
|
|
264
272
|
} = props;
|
|
265
273
|
|
|
266
274
|
return (
|
|
267
275
|
<BaseApp
|
|
276
|
+
project={project}
|
|
268
277
|
theme={theme}
|
|
269
278
|
auth={auth}
|
|
270
279
|
analytics={analytics}
|
|
@@ -275,6 +284,7 @@ export function AppLayout(props: AppLayoutProps) {
|
|
|
275
284
|
mcpChat={mcpChat}
|
|
276
285
|
pwaInstall={pwaInstall}
|
|
277
286
|
monitor={monitor}
|
|
287
|
+
debug={debug}
|
|
278
288
|
>
|
|
279
289
|
<AppLayoutContent {...props} />
|
|
280
290
|
</BaseApp>
|
|
@@ -57,12 +57,19 @@ import { A2HSHint, PWAPageResumeManager, PwaProvider } from '../../snippets/PWAI
|
|
|
57
57
|
|
|
58
58
|
import type { BaseLayoutProps } from '../types/layout.types';
|
|
59
59
|
|
|
60
|
+
// Lazy load DebugButton from @djangocfg/debuger
|
|
61
|
+
const DebugButton = dynamic(
|
|
62
|
+
() => import('@djangocfg/debuger').then(mod => ({ default: mod.DebugButton })),
|
|
63
|
+
{ ssr: false }
|
|
64
|
+
);
|
|
65
|
+
|
|
60
66
|
// Lazy load MCP Chat Widget with dynamic import
|
|
61
67
|
const AIChatWidget = dynamic(
|
|
62
68
|
() => import('../../snippets/McpChat/components/AIChatWidget').then(mod => ({ default: mod.AIChatWidget })),
|
|
63
69
|
{ ssr: false }
|
|
64
70
|
);
|
|
65
71
|
|
|
72
|
+
|
|
66
73
|
// For backwards compatibility, re-export as BaseAppProps
|
|
67
74
|
export type BaseAppProps = BaseLayoutProps;
|
|
68
75
|
|
|
@@ -76,6 +83,7 @@ export type BaseAppProps = BaseLayoutProps;
|
|
|
76
83
|
*/
|
|
77
84
|
export function BaseApp({
|
|
78
85
|
children,
|
|
86
|
+
project,
|
|
79
87
|
theme,
|
|
80
88
|
auth,
|
|
81
89
|
analytics,
|
|
@@ -86,6 +94,7 @@ export function BaseApp({
|
|
|
86
94
|
mcpChat,
|
|
87
95
|
pwaInstall,
|
|
88
96
|
monitor,
|
|
97
|
+
debug,
|
|
89
98
|
}: BaseAppProps) {
|
|
90
99
|
// ErrorBoundary is enabled by default
|
|
91
100
|
const enableErrorBoundary = errorBoundary?.enabled !== false;
|
|
@@ -98,6 +107,13 @@ export function BaseApp({
|
|
|
98
107
|
const centrifugoUrl = centrifugo?.url || process.env.NEXT_PUBLIC_CENTRIFUGO_URL;
|
|
99
108
|
const centrifugoEnabled = centrifugo?.enabled !== false;
|
|
100
109
|
|
|
110
|
+
// Monitor — project prop as default, override with monitor config
|
|
111
|
+
const monitorConfig = {
|
|
112
|
+
project,
|
|
113
|
+
environment: process.env.NODE_ENV,
|
|
114
|
+
...monitor,
|
|
115
|
+
};
|
|
116
|
+
|
|
101
117
|
const content = (
|
|
102
118
|
<ThemeProvider
|
|
103
119
|
defaultTheme={theme?.defaultTheme || 'system'}
|
|
@@ -130,7 +146,7 @@ export function BaseApp({
|
|
|
130
146
|
network={errorTracking?.network}
|
|
131
147
|
onError={errorTracking?.onError}
|
|
132
148
|
>
|
|
133
|
-
|
|
149
|
+
<MonitorProvider {...monitorConfig} />
|
|
134
150
|
{children}
|
|
135
151
|
<NextTopLoader
|
|
136
152
|
color="hsl(var(--primary))"
|
|
@@ -171,6 +187,9 @@ export function BaseApp({
|
|
|
171
187
|
|
|
172
188
|
{/* Auth Dialog - global auth prompt */}
|
|
173
189
|
<AuthDialog authPath={auth?.routes?.auth} />
|
|
190
|
+
|
|
191
|
+
{/* Debug Panel — enabled by default, disable with debug={false} */}
|
|
192
|
+
{debug !== false && <DebugButton />}
|
|
174
193
|
</ErrorTrackingProvider>
|
|
175
194
|
</PwaProvider>
|
|
176
195
|
</CentrifugoProvider>
|
|
@@ -29,6 +29,9 @@ import type { MonitorConfig } from '@djangocfg/monitor';
|
|
|
29
29
|
export interface BaseLayoutProps {
|
|
30
30
|
children: ReactNode;
|
|
31
31
|
|
|
32
|
+
/** Project name — used as default for monitor.project and debug panel title */
|
|
33
|
+
project?: string;
|
|
34
|
+
|
|
32
35
|
/** Theme configuration */
|
|
33
36
|
theme?: ThemeConfig;
|
|
34
37
|
|
|
@@ -58,4 +61,7 @@ export interface BaseLayoutProps {
|
|
|
58
61
|
|
|
59
62
|
/** Monitor configuration — initialises window.monitor + auto-captures JS errors & console */
|
|
60
63
|
monitor?: MonitorConfig;
|
|
64
|
+
|
|
65
|
+
/** Debug panel — set false to disable. Default: true */
|
|
66
|
+
debug?: boolean;
|
|
61
67
|
}
|