@djangocfg/layouts 1.4.30 → 2.0.2

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,242 +0,0 @@
1
- /**
2
- * Footer Component
3
- *
4
- * Responsive footer with Desktop and Mobile variants
5
- * Refactored from _old/MainLayout - uses context only!
6
- */
7
-
8
- 'use client';
9
-
10
- import React from 'react';
11
- import Link from 'next/link';
12
- import { useIsMobile } from '@djangocfg/ui/hooks';
13
- import { useAppContext } from '../../../context';
14
-
15
- /**
16
- * Footer Component
17
- *
18
- * Features:
19
- * - Responsive (Desktop/Mobile variants)
20
- * - Project info with logo and description
21
- * - Badge (optional)
22
- * - Social links (GitHub, LinkedIn, Twitter, Telegram)
23
- * - Menu sections (single items or grouped)
24
- * - Legal links (Privacy, Terms, Security, Cookies, etc.)
25
- * - Copyright and branding
26
- *
27
- * All data from context!
28
- */
29
- export function Footer() {
30
- const { config } = useAppContext();
31
- const isMobile = useIsMobile();
32
-
33
- const { app, publicLayout } = config;
34
- const footer = publicLayout.footer;
35
- const currentYear = new Date().getFullYear();
36
-
37
- if (isMobile) {
38
- return (
39
- <footer className="lg:hidden bg-background border-t border-border mt-auto">
40
- <div className="w-full px-4 py-8">
41
- {/* Project Info */}
42
- <div className="text-center space-y-4 mb-6">
43
- <div className="flex items-center justify-center gap-2">
44
- <div className="w-6 h-6 flex items-center justify-center">
45
- <img
46
- src={app.logoPath}
47
- alt={`${app.name} Logo`}
48
- className="w-full h-full object-contain"
49
- />
50
- </div>
51
- <span className="text-lg font-bold text-foreground">{app.name}</span>
52
- </div>
53
- {app.description && (
54
- <p className="text-muted-foreground text-sm leading-relaxed max-w-md mx-auto">
55
- {app.description}
56
- </p>
57
- )}
58
- </div>
59
-
60
- {/* Quick Links */}
61
- <div className="flex flex-wrap justify-center gap-4 mb-6 items-center">
62
- {footer.links.docs && (
63
- <a
64
- href={footer.links.docs}
65
- target="_blank"
66
- rel="noopener noreferrer"
67
- className="text-sm text-muted-foreground hover:text-primary transition-colors"
68
- title="Documentation"
69
- >
70
- Docs
71
- </a>
72
- )}
73
- {footer.links.privacy && (
74
- <Link
75
- href={footer.links.privacy}
76
- className="text-sm text-muted-foreground hover:text-primary transition-colors"
77
- >
78
- Privacy
79
- </Link>
80
- )}
81
- {footer.links.terms && (
82
- <Link
83
- href={footer.links.terms}
84
- className="text-sm text-muted-foreground hover:text-primary transition-colors"
85
- >
86
- Terms
87
- </Link>
88
- )}
89
- </div>
90
-
91
- {/* Bottom Section */}
92
- <div className="border-t border-border pt-4">
93
- <div className="text-center space-y-2">
94
- <div className="text-xs text-muted-foreground">
95
- © {currentYear} {app.name}. All rights reserved.
96
- </div>
97
- <div className="text-xs text-muted-foreground flex items-center justify-center gap-1">
98
- Made with ❤️ by{' '}
99
- <a
100
- href="https://reforms.ai"
101
- target="_blank"
102
- rel="noopener noreferrer"
103
- className="hover:text-primary transition-colors"
104
- >
105
- ReformsAI
106
- </a>
107
- </div>
108
- </div>
109
- </div>
110
- </div>
111
- </footer>
112
- );
113
- }
114
-
115
- // Desktop Footer
116
- return (
117
- <footer className="max-lg:hidden bg-background border-t border-border mt-auto">
118
- <div className="w-full px-8 lg:px-16 xl:px-24 py-12">
119
- <div className="flex flex-col gap-8">
120
- {/* Top Section - Two Column Layout */}
121
- <div className="flex gap-8">
122
- {/* Left Column - Project Info */}
123
- <div className="space-y-4" style={{ width: '30%', minWidth: '300px' }}>
124
- <div className="flex items-center gap-2">
125
- <div className="w-8 h-8 flex items-center justify-center">
126
- <img
127
- src={app.logoPath}
128
- alt={`${app.name} Logo`}
129
- className="w-full h-full object-contain"
130
- />
131
- </div>
132
- <span className="text-xl font-bold text-foreground">{app.name}</span>
133
- </div>
134
- {app.description && (
135
- <p className="text-muted-foreground text-sm leading-relaxed">
136
- {app.description}
137
- </p>
138
- )}
139
- {/* Badge */}
140
- {footer.badge && (
141
- <div className="pt-2">
142
- <span className="inline-flex items-center gap-2 px-3 py-1.5 rounded-sm bg-primary/10 hover:bg-primary/15 border border-primary/20 text-xs font-medium text-primary transition-colors">
143
- <footer.badge.icon className="w-3.5 h-3.5" />
144
- {footer.badge.text}
145
- </span>
146
- </div>
147
- )}
148
- </div>
149
-
150
- {/* Right Column - Footer Menu Sections (max 4 columns, rest wraps) */}
151
- <div className="flex flex-wrap gap-8 flex-1">
152
- {footer.menuSections.map((section) => (
153
- <div key={section.title} className="flex-1 basis-[calc(25%-1.5rem)] min-w-[140px] max-w-[200px]">
154
- <h3 className="text-sm font-semibold text-foreground mb-3">
155
- {section.title}
156
- </h3>
157
- <ul className="space-y-2">
158
- {section.items.map((item) => (
159
- <li key={item.path}>
160
- <Link
161
- href={item.path}
162
- className="text-muted-foreground hover:text-primary text-sm transition-colors"
163
- >
164
- {item.label}
165
- </Link>
166
- </li>
167
- ))}
168
- </ul>
169
- </div>
170
- ))}
171
- </div>
172
- </div>
173
-
174
- {/* Bottom Section */}
175
- <div className="border-t border-border" style={{ marginTop: '2rem', paddingTop: '2rem' }}>
176
- <div className="flex justify-between items-center gap-4">
177
- <div className="text-xs text-muted-foreground">
178
- © {currentYear} {app.name}. All rights reserved.
179
- </div>
180
- <div className="text-xs text-muted-foreground flex items-center gap-1">
181
- Made with ❤️ by{' '}
182
- <a
183
- href="https://reforms.ai"
184
- target="_blank"
185
- rel="noopener noreferrer"
186
- className="hover:text-primary transition-colors"
187
- >
188
- ReformsAI
189
- </a>
190
- </div>
191
- <div className="flex flex-wrap items-center gap-4">
192
- {footer.links.docs && (
193
- <a
194
- href={footer.links.docs}
195
- target="_blank"
196
- rel="noopener noreferrer"
197
- className="text-xs text-muted-foreground hover:text-primary transition-colors"
198
- title="Documentation"
199
- >
200
- Docs
201
- </a>
202
- )}
203
- {footer.links.privacy && (
204
- <Link
205
- href={footer.links.privacy}
206
- className="text-xs text-muted-foreground hover:text-primary transition-colors"
207
- >
208
- Privacy Policy
209
- </Link>
210
- )}
211
- {footer.links.terms && (
212
- <Link
213
- href={footer.links.terms}
214
- className="text-xs text-muted-foreground hover:text-primary transition-colors"
215
- >
216
- Terms of Service
217
- </Link>
218
- )}
219
- {footer.links.security && (
220
- <Link
221
- href={footer.links.security}
222
- className="text-xs text-muted-foreground hover:text-primary transition-colors"
223
- >
224
- Security
225
- </Link>
226
- )}
227
- {footer.links.cookies && (
228
- <Link
229
- href={footer.links.cookies}
230
- className="text-xs text-muted-foreground hover:text-primary transition-colors"
231
- >
232
- Cookies
233
- </Link>
234
- )}
235
- </div>
236
- </div>
237
- </div>
238
- </div>
239
- </div>
240
- </footer>
241
- );
242
- }
@@ -1,150 +0,0 @@
1
- /**
2
- * Mobile Drawer
3
- *
4
- * Full-screen slide-in drawer for mobile navigation
5
- * Uses @djangocfg/ui Drawer component (Vaul-based)
6
- */
7
-
8
- 'use client';
9
-
10
- import React from 'react';
11
- import Link from 'next/link';
12
- import { X } from 'lucide-react';
13
- import {
14
- Drawer,
15
- DrawerContent,
16
- DrawerHeader,
17
- DrawerTitle,
18
- DrawerClose,
19
- } from '@djangocfg/ui/components';
20
- import { useAppContext } from '../../../context';
21
- import { useNavigation } from '../../../hooks';
22
- import { UserMenu } from '../../../components';
23
-
24
- /**
25
- * Mobile Drawer Component
26
- *
27
- * Features:
28
- * - Slide-in drawer from right (using Vaul)
29
- * - UserMenu component (authenticated/guest)
30
- * - Navigation sections
31
- * - Smooth animations via Vaul library
32
- *
33
- * All data from context!
34
- */
35
- export function MobileDrawer() {
36
- const { config, mobileDrawerOpen, closeMobileDrawer } = useAppContext();
37
- const { isActive } = useNavigation();
38
-
39
- const { app, publicLayout } = config;
40
-
41
- const handleNavigate = () => {
42
- closeMobileDrawer();
43
- };
44
-
45
- // Prepare menu sections before render
46
- const singleItemSections = React.useMemo(
47
- () => publicLayout.navigation.menuSections.filter(s => s.items.length === 1),
48
- [publicLayout.navigation.menuSections]
49
- );
50
-
51
- const multipleItemsSections = React.useMemo(
52
- () => publicLayout.navigation.menuSections.filter(s => s.items.length > 1),
53
- [publicLayout.navigation.menuSections]
54
- );
55
-
56
- return (
57
- <Drawer
58
- open={mobileDrawerOpen}
59
- onOpenChange={(open) => !open && closeMobileDrawer()}
60
- direction="right"
61
- >
62
- <DrawerContent direction="right" className="w-80 lg:hidden">
63
- {/* Header */}
64
- <DrawerHeader className="flex flex-row items-center justify-between p-4 border-b border-border/30">
65
- <div className="flex items-center gap-3">
66
- <img
67
- src={app.logoPath}
68
- alt={`${app.name} Logo`}
69
- className="h-8 w-auto object-contain"
70
- />
71
- <DrawerTitle className="text-lg font-bold text-foreground">
72
- {app.name}
73
- </DrawerTitle>
74
- </div>
75
- <DrawerClose className="p-2 rounded-sm transition-colors hover:bg-accent/50">
76
- <X className="size-5" />
77
- <span className="sr-only">Close menu</span>
78
- </DrawerClose>
79
- </DrawerHeader>
80
-
81
- {/* Scrollable Content */}
82
- <div className="flex-1 overflow-y-auto p-4 space-y-6">
83
- {/* User Menu Card */}
84
- <UserMenu variant="mobile" onNavigate={handleNavigate} />
85
-
86
- {/* Navigation Sections */}
87
- <div className="space-y-6">
88
- {/* Group all single-item sections into "Menu" */}
89
- {singleItemSections.length > 0 && (
90
- <div className="space-y-3">
91
- <h3 className="px-2 text-xs font-semibold uppercase tracking-wider text-muted-foreground">
92
- Menu
93
- </h3>
94
- <div className="space-y-1">
95
- {singleItemSections.map((section) => {
96
- const item = section.items[0];
97
- if (!item) return null;
98
-
99
- return (
100
- <Link
101
- key={item.path}
102
- href={item.path}
103
- className={`block px-4 py-3 rounded-sm text-base font-medium transition-colors ${
104
- isActive(item.path)
105
- ? 'bg-accent text-accent-foreground'
106
- : 'text-foreground hover:bg-accent hover:text-accent-foreground'
107
- }`}
108
- onClick={handleNavigate}
109
- >
110
- {item.label}
111
- </Link>
112
- );
113
- })}
114
- </div>
115
- </div>
116
- )}
117
-
118
- {/* Render multiple-items sections normally */}
119
- {multipleItemsSections.map((section) => (
120
- <div key={section.title} className="space-y-3">
121
- <h3 className="px-2 text-xs font-semibold uppercase tracking-wider text-muted-foreground">
122
- {section.title}
123
- </h3>
124
- <div className="space-y-1">
125
- {section.items.map((item) => (
126
- <Link
127
- key={item.path}
128
- href={item.path}
129
- className={`block px-4 py-3 rounded-sm text-base font-medium transition-colors ${
130
- isActive(item.path)
131
- ? 'bg-accent text-accent-foreground'
132
- : 'text-foreground hover:bg-accent hover:text-accent-foreground'
133
- }`}
134
- onClick={handleNavigate}
135
- >
136
- {item.label}
137
- </Link>
138
- ))}
139
- </div>
140
- </div>
141
- ))}
142
- </div>
143
-
144
- {/* Bottom spacer */}
145
- <div style={{ height: '15vh' }}></div>
146
- </div>
147
- </DrawerContent>
148
- </Drawer>
149
- );
150
- }
@@ -1,169 +0,0 @@
1
- /**
2
- * Public Layout Navigation
3
- *
4
- * Full-featured navigation using @djangocfg/ui components
5
- * Refactored from _old/MainLayout - uses context only!
6
- */
7
-
8
- 'use client';
9
-
10
- import React from 'react';
11
- import Link from 'next/link';
12
- import { Menu, ChevronDown } from 'lucide-react';
13
- import {
14
- DropdownMenu,
15
- DropdownMenuTrigger,
16
- DropdownMenuContent,
17
- DropdownMenuItem,
18
- } from '@djangocfg/ui/components';
19
- import { ThemeToggle } from '@djangocfg/ui/theme';
20
- import { cn } from '@djangocfg/ui/lib';
21
- import { useIsMobile } from '@djangocfg/ui/hooks';
22
- import { useAppContext } from '../../../context';
23
- import { useNavigation } from '../../../hooks';
24
- import { UserMenu } from '../../../components';
25
- import { MobileDrawer } from './MobileDrawer';
26
-
27
- /**
28
- * Navigation Component
29
- *
30
- * Features:
31
- * - Logo and branding
32
- * - NavigationMenu from @djangocfg/ui (Radix UI based)
33
- * - Theme toggle
34
- * - User menu (desktop)
35
- * - Mobile menu button
36
- *
37
- * All data from context - zero prop drilling!
38
- */
39
- export function Navigation() {
40
- const { config, toggleMobileDrawer } = useAppContext();
41
- const { isActive } = useNavigation();
42
- const isMobile = useIsMobile();
43
- const [openDropdown, setOpenDropdown] = React.useState<string | null>(null);
44
-
45
- const { app, publicLayout } = config;
46
-
47
- return (
48
- <nav className="sticky top-0 w-full backdrop-blur-xl z-50 isolate" style={{ backgroundColor: 'hsl(var(--background) / 0.8)', boxShadow: '0 1px 0 0 hsl(var(--border))', zIndex: 50 }}>
49
- <div className="w-full px-4 sm:px-6 lg:px-8">
50
- <div className="flex items-center justify-between py-2 min-h-[40px]">
51
- {/* Left side - Logo and Navigation Menu */}
52
- <div className="flex items-center gap-6">
53
- {/* Logo */}
54
- <Link
55
- href={publicLayout.navigation.homePath}
56
- className="flex items-center gap-3 group"
57
- >
58
- <img
59
- src={app.logoPath}
60
- alt={`${app.name} Logo`}
61
- className="h-8 w-auto object-contain transition-transform duration-300 group-hover:scale-105"
62
- />
63
- <span className="text-xl font-bold transition-colors duration-300 text-foreground group-hover:text-primary">
64
- {app.name}
65
- </span>
66
- </Link>
67
-
68
- {/* Desktop Navigation Menu */}
69
- {!isMobile && (
70
- <div className="flex items-center gap-1">
71
- {publicLayout.navigation.menuSections.map((section) => {
72
- // Single item section - render as direct link
73
- if (section.items.length === 1) {
74
- const item = section.items[0];
75
- if (!item) return null;
76
-
77
- return (
78
- <Link
79
- key={section.title}
80
- href={item.path}
81
- className={cn(
82
- 'inline-flex h-9 items-center justify-center rounded-md px-4 py-2 text-sm font-medium transition-colors hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground focus:outline-none disabled:pointer-events-none disabled:opacity-50',
83
- isActive(item.path) && 'bg-accent text-accent-foreground'
84
- )}
85
- >
86
- {item.label}
87
- </Link>
88
- );
89
- }
90
-
91
- // Multiple items - render as dropdown menu
92
- return (
93
- <div
94
- key={section.title}
95
- onMouseEnter={() => setOpenDropdown(section.title)}
96
- onMouseLeave={() => setOpenDropdown(null)}
97
- >
98
- <DropdownMenu
99
- open={openDropdown === section.title}
100
- onOpenChange={(open) => setOpenDropdown(open ? section.title : null)}
101
- modal={false}
102
- >
103
- <DropdownMenuTrigger
104
- className={cn(
105
- "inline-flex h-9 items-center justify-center gap-1 rounded-md px-4 py-2 text-sm font-medium transition-colors focus:bg-accent focus:text-accent-foreground focus:outline-none disabled:pointer-events-none disabled:opacity-50",
106
- openDropdown === section.title ? "bg-accent text-accent-foreground" : "hover:bg-accent hover:text-accent-foreground"
107
- )}
108
- >
109
- {section.title}
110
- <ChevronDown className="h-3 w-3 transition-transform duration-200 group-data-[state=open]:rotate-180" />
111
- </DropdownMenuTrigger>
112
- <DropdownMenuContent
113
- align="start"
114
- sideOffset={0}
115
- className="p-2"
116
- style={{
117
- minWidth: '250px',
118
- backdropFilter: 'blur(24px)',
119
- WebkitBackdropFilter: 'blur(24px)'
120
- }}
121
- >
122
- {section.items.map((item) => (
123
- <DropdownMenuItem key={item.path} asChild>
124
- <Link
125
- href={item.path}
126
- className={cn(
127
- 'cursor-pointer w-full hover:bg-accent hover:text-accent-foreground transition-colors text-base px-4 py-3 rounded-md',
128
- isActive(item.path) && 'bg-accent/50'
129
- )}
130
- >
131
- {item.label}
132
- </Link>
133
- </DropdownMenuItem>
134
- ))}
135
- </DropdownMenuContent>
136
- </DropdownMenu>
137
- </div>
138
- );
139
- })}
140
- </div>
141
- )}
142
- </div>
143
-
144
- {/* Right side - Theme Toggle & User Menu */}
145
- {!isMobile && (
146
- <div className="flex items-center gap-2">
147
- <ThemeToggle />
148
- <UserMenu variant="desktop" />
149
- </div>
150
- )}
151
-
152
- {/* Mobile Menu Button - Only visible on mobile */}
153
- {isMobile && (
154
- <button
155
- onClick={toggleMobileDrawer}
156
- className="p-2 rounded-md transition-colors hover:bg-accent text-foreground hover:text-primary"
157
- aria-label="Toggle mobile menu"
158
- >
159
- <Menu className="size-6" />
160
- </button>
161
- )}
162
- </div>
163
- </div>
164
-
165
- {/* Mobile Drawer */}
166
- <MobileDrawer />
167
- </nav>
168
- );
169
- }
@@ -1,5 +0,0 @@
1
- /**
2
- * PublicLayout Module
3
- */
4
-
5
- export * from './PublicLayout';
@@ -1,7 +0,0 @@
1
- /**
2
- * Layouts Module
3
- */
4
-
5
- export * from './PublicLayout';
6
- export * from './PrivateLayout';
7
- export * from './AuthLayout';
@@ -1,80 +0,0 @@
1
- // @ts-nocheck
2
- /**
3
- * Core Providers
4
- *
5
- * Wraps application with all necessary providers
6
- */
7
-
8
- 'use client';
9
-
10
- import React, { ReactNode } from 'react';
11
- import { ThemeProvider, Toaster } from '@djangocfg/ui';
12
- import { AuthProvider } from '../../../auth';
13
- import { ErrorTrackingProvider } from '../../../validation';
14
- import type { AppLayoutConfig } from '../types';
15
- import type { ValidationErrorConfig, CORSErrorConfig, NetworkErrorConfig } from '../../../validation';
16
-
17
- export interface CoreProvidersProps {
18
- children: ReactNode;
19
- config: AppLayoutConfig;
20
- /**
21
- * Validation error tracking configuration
22
- * @default { enabled: true, showToast: true, maxErrors: 50 }
23
- */
24
- validation?: Partial<ValidationErrorConfig>;
25
- /**
26
- * CORS error tracking configuration
27
- * @default { enabled: true, showToast: true }
28
- */
29
- cors?: Partial<CORSErrorConfig>;
30
- /**
31
- * Network error tracking configuration
32
- * @default { enabled: false }
33
- */
34
- network?: Partial<NetworkErrorConfig>;
35
- /**
36
- * Custom error handler for all error types
37
- */
38
- onError?: (error: any) => boolean | void;
39
- }
40
-
41
- /**
42
- * Core Providers Wrapper
43
- *
44
- * Provides:
45
- * - ThemeProvider (dark/light mode)
46
- * - AuthProvider (authentication)
47
- * - ErrorTrackingProvider (validation, CORS & network error tracking)
48
- * - Toaster (notifications)
49
- */
50
- export function CoreProviders({ children, config, validation, cors, network, onError }: CoreProvidersProps) {
51
- return (
52
- <ThemeProvider
53
- defaultTheme={config.theme?.defaultTheme}
54
- storageKey={config.theme?.storageKey}
55
- >
56
- <AuthProvider
57
- config={{
58
- apiUrl: config.api.baseUrl,
59
- routes: {
60
- auth: config.routes.auth,
61
- defaultCallback: config.routes.defaultCallback,
62
- defaultAuthCallback: config.routes.defaultAuthCallback || config.routes.defaultCallback,
63
- },
64
- }}
65
- >
66
- <ErrorTrackingProvider
67
- validation={validation}
68
- cors={cors}
69
- network={network}
70
- onError={onError}
71
- >
72
- {children}
73
- </ErrorTrackingProvider>
74
- </AuthProvider>
75
-
76
- {/* Global toast notifications */}
77
- <Toaster />
78
- </ThemeProvider>
79
- );
80
- }
@@ -1,5 +0,0 @@
1
- /**
2
- * Providers Module
3
- */
4
-
5
- export * from './CoreProviders';