@djangocfg/layouts 1.0.2 → 1.0.4

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 (24) hide show
  1. package/package.json +5 -5
  2. package/src/layouts/AppLayout/layouts/AuthLayout/AuthHelp.tsx +7 -5
  3. package/src/layouts/AppLayout/layouts/AuthLayout/IdentifierForm.tsx +3 -3
  4. package/src/layouts/AppLayout/layouts/AuthLayout/OTPForm.tsx +26 -10
  5. package/src/layouts/AppLayout/layouts/PrivateLayout/components/DashboardSidebar.tsx +1 -1
  6. package/src/layouts/AppLayout/layouts/PublicLayout/components/DesktopUserMenu.tsx +6 -6
  7. package/src/layouts/AppLayout/layouts/PublicLayout/components/Footer.tsx +1 -1
  8. package/src/layouts/AppLayout/layouts/PublicLayout/components/MobileMenu.tsx +43 -133
  9. package/src/layouts/AppLayout/layouts/PublicLayout/components/MobileMenuUserCard.tsx +150 -0
  10. package/src/layouts/AppLayout/layouts/PublicLayout/components/Navigation.tsx +2 -2
  11. package/src/layouts/PaymentsLayout/PaymentsLayout.tsx +41 -57
  12. package/src/layouts/PaymentsLayout/components/CreatePaymentDialog.tsx +188 -57
  13. package/src/layouts/PaymentsLayout/components/PaymentDetailsDialog.tsx +323 -0
  14. package/src/layouts/PaymentsLayout/components/index.ts +1 -0
  15. package/src/layouts/PaymentsLayout/context/RootPaymentsContext.tsx +129 -0
  16. package/src/layouts/PaymentsLayout/views/apikeys/components/ApiKeysList.tsx +2 -2
  17. package/src/layouts/PaymentsLayout/views/overview/components/BalanceCard.tsx +6 -6
  18. package/src/layouts/PaymentsLayout/views/overview/components/RecentPayments.tsx +2 -2
  19. package/src/layouts/PaymentsLayout/views/payments/components/PaymentsList.tsx +9 -4
  20. package/src/layouts/SupportLayout/hooks/useInfiniteMessages.ts +2 -3
  21. package/src/layouts/SupportLayout/hooks/useInfiniteTickets.ts +2 -3
  22. package/src/snippets/Chat/components/SessionList.tsx +1 -1
  23. package/src/snippets/Chat/hooks/useInfiniteSessions.ts +2 -2
  24. package/src/snippets/VideoPlayer/VideoPlayer.tsx +1 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@djangocfg/layouts",
3
- "version": "1.0.2",
3
+ "version": "1.0.4",
4
4
  "description": "Layout system and components for Unrealon applications",
5
5
  "author": {
6
6
  "name": "DjangoCFG",
@@ -53,10 +53,10 @@
53
53
  "check": "tsc --noEmit"
54
54
  },
55
55
  "peerDependencies": {
56
+ "@djangocfg/api": "^1.0.4",
57
+ "@djangocfg/og-image": "^1.0.4",
58
+ "@djangocfg/ui": "^1.0.4",
56
59
  "@hookform/resolvers": "^5.2.0",
57
- "@djangocfg/api": "^1.0.2",
58
- "@djangocfg/og-image": "^1.0.2",
59
- "@djangocfg/ui": "^1.0.2",
60
60
  "consola": "^3.4.2",
61
61
  "lucide-react": "^0.468.0",
62
62
  "next": "^15.4.4",
@@ -76,10 +76,10 @@
76
76
  "vidstack": "0.6.15"
77
77
  },
78
78
  "devDependencies": {
79
+ "@djangocfg/typescript-config": "^1.0.4",
79
80
  "@types/node": "^24.7.2",
80
81
  "@types/react": "19.2.2",
81
82
  "@types/react-dom": "19.2.1",
82
- "@djangocfg/typescript-config": "^1.0.2",
83
83
  "eslint": "^9.37.0",
84
84
  "typescript": "^5.9.3"
85
85
  }
@@ -1,4 +1,4 @@
1
- import { Mail, MessageCircle } from 'lucide-react';
1
+ import { Mail, MessageCircle, HelpCircle } from 'lucide-react';
2
2
  import React from 'react';
3
3
 
4
4
  import { Button } from '@djangocfg/ui/components';
@@ -51,7 +51,7 @@ export const AuthHelp: React.FC<AuthHelpProps> = ({
51
51
  if (variant === 'compact') {
52
52
  return (
53
53
  <div
54
- className={`flex items-center justify-between p-3 bg-muted/30 rounded-lg border border-border ${className}`}
54
+ className={`flex items-center justify-between p-3 bg-muted/30 rounded-sm border border-border ${className}`}
55
55
  >
56
56
  <div className="flex items-center space-x-2">
57
57
  {getChannelIcon()}
@@ -64,7 +64,8 @@ export const AuthHelp: React.FC<AuthHelpProps> = ({
64
64
  size="sm"
65
65
  className="text-xs"
66
66
  >
67
- <a href={supportUrl} target="_blank" rel="noopener noreferrer">
67
+ <a href={supportUrl} target="_blank" rel="noopener noreferrer" className="flex items-center gap-1">
68
+ <HelpCircle className="w-3 h-3" />
68
69
  Need help?
69
70
  </a>
70
71
  </Button>
@@ -77,7 +78,7 @@ export const AuthHelp: React.FC<AuthHelpProps> = ({
77
78
 
78
79
  return (
79
80
  <div
80
- className={`space-y-3 p-3 bg-muted/30 rounded-lg border border-border ${className}`}
81
+ className={`space-y-3 p-3 bg-muted/30 rounded-sm border border-border ${className}`}
81
82
  >
82
83
  <div className="flex items-start space-x-2">
83
84
  {getChannelIcon()}
@@ -100,7 +101,8 @@ export const AuthHelp: React.FC<AuthHelpProps> = ({
100
101
  size="sm"
101
102
  className="text-xs h-7 px-2"
102
103
  >
103
- <a href={supportUrl} target="_blank" rel="noopener noreferrer">
104
+ <a href={supportUrl} target="_blank" rel="noopener noreferrer" className="flex items-center gap-1">
105
+ <HelpCircle className="w-3 h-3" />
104
106
  Get Help
105
107
  </a>
106
108
  </Button>
@@ -1,5 +1,5 @@
1
1
  import React, { useState, useEffect } from 'react';
2
- import { Mail, Phone, User } from 'lucide-react';
2
+ import { Mail, Phone, User, Send } from 'lucide-react';
3
3
 
4
4
  import {
5
5
  Button,
@@ -231,7 +231,7 @@ export const IdentifierForm: React.FC = () => {
231
231
  </div>
232
232
  ) : (
233
233
  <div className="flex items-center gap-2">
234
- {getChannelIcon()}
234
+ <Send className="w-4 h-4" />
235
235
  Send verification code
236
236
  </div>
237
237
  )}
@@ -314,7 +314,7 @@ export const IdentifierForm: React.FC = () => {
314
314
  </div>
315
315
  ) : (
316
316
  <div className="flex items-center gap-2">
317
- {getChannelIcon()}
317
+ <Send className="w-4 h-4" />
318
318
  Send verification code
319
319
  </div>
320
320
  )}
@@ -1,5 +1,5 @@
1
1
  import React from 'react';
2
- import { Mail, MessageCircle } from 'lucide-react';
2
+ import { Mail, MessageCircle, ArrowLeft, RotateCw, ShieldCheck } from 'lucide-react';
3
3
 
4
4
  import {
5
5
  Button,
@@ -80,27 +80,27 @@ export const OTPForm: React.FC = () => {
80
80
  <InputOTPGroup className="gap-2">
81
81
  <InputOTPSlot
82
82
  index={0}
83
- className="h-12 w-12 text-lg font-semibold border-2 border-border bg-background rounded-lg shadow-sm"
83
+ className="h-12 w-12 text-lg font-semibold border-2 border-border bg-background rounded-sm shadow-sm"
84
84
  />
85
85
  <InputOTPSlot
86
86
  index={1}
87
- className="h-12 w-12 text-lg font-semibold border-2 border-border bg-background rounded-lg shadow-sm"
87
+ className="h-12 w-12 text-lg font-semibold border-2 border-border bg-background rounded-sm shadow-sm"
88
88
  />
89
89
  <InputOTPSlot
90
90
  index={2}
91
- className="h-12 w-12 text-lg font-semibold border-2 border-border bg-background rounded-lg shadow-sm"
91
+ className="h-12 w-12 text-lg font-semibold border-2 border-border bg-background rounded-sm shadow-sm"
92
92
  />
93
93
  <InputOTPSlot
94
94
  index={3}
95
- className="h-12 w-12 text-lg font-semibold border-2 border-border bg-background rounded-lg shadow-sm"
95
+ className="h-12 w-12 text-lg font-semibold border-2 border-border bg-background rounded-sm shadow-sm"
96
96
  />
97
97
  <InputOTPSlot
98
98
  index={4}
99
- className="h-12 w-12 text-lg font-semibold border-2 border-border bg-background rounded-lg shadow-sm"
99
+ className="h-12 w-12 text-lg font-semibold border-2 border-border bg-background rounded-sm shadow-sm"
100
100
  />
101
101
  <InputOTPSlot
102
102
  index={5}
103
- className="h-12 w-12 text-lg font-semibold border-2 border-border bg-background rounded-lg shadow-sm"
103
+ className="h-12 w-12 text-lg font-semibold border-2 border-border bg-background rounded-sm shadow-sm"
104
104
  />
105
105
  </InputOTPGroup>
106
106
  </InputOTP>
@@ -113,7 +113,17 @@ export const OTPForm: React.FC = () => {
113
113
  className="w-full h-11 text-base font-medium"
114
114
  disabled={isLoading || otp.length < 6}
115
115
  >
116
- {isLoading ? 'Verifying...' : 'Verify Code'}
116
+ {isLoading ? (
117
+ <div className="flex items-center gap-2">
118
+ <div className="w-4 h-4 border-2 border-current border-t-transparent rounded-full animate-spin" />
119
+ Verifying...
120
+ </div>
121
+ ) : (
122
+ <div className="flex items-center gap-2">
123
+ <ShieldCheck className="w-5 h-5" />
124
+ Verify Code
125
+ </div>
126
+ )}
117
127
  </Button>
118
128
 
119
129
  <div className="flex gap-3">
@@ -124,7 +134,10 @@ export const OTPForm: React.FC = () => {
124
134
  disabled={isLoading}
125
135
  className="flex-1 h-10"
126
136
  >
127
- Back
137
+ <div className="flex items-center gap-2">
138
+ <ArrowLeft className="w-4 h-4" />
139
+ Back
140
+ </div>
128
141
  </Button>
129
142
 
130
143
  <Button
@@ -134,7 +147,10 @@ export const OTPForm: React.FC = () => {
134
147
  disabled={isLoading}
135
148
  className="flex-1 h-10"
136
149
  >
137
- Resend
150
+ <div className="flex items-center gap-2">
151
+ <RotateCw className="w-4 h-4" />
152
+ Resend
153
+ </div>
138
154
  </Button>
139
155
  </div>
140
156
  </div>
@@ -81,7 +81,7 @@ export function DashboardSidebar() {
81
81
  className={isMobile ? "h-10 w-10 flex-shrink-0" : "h-8 w-8 flex-shrink-0"}
82
82
  />
83
83
  ) : (
84
- <div className={isMobile ? "h-10 w-10 bg-primary rounded-lg flex items-center justify-center flex-shrink-0" : "h-8 w-8 bg-primary rounded-lg flex items-center justify-center flex-shrink-0"}>
84
+ <div className={isMobile ? "h-10 w-10 bg-primary rounded-sm flex items-center justify-center flex-shrink-0" : "h-8 w-8 bg-primary rounded-sm flex items-center justify-center flex-shrink-0"}>
85
85
  <span className="text-primary-foreground font-bold text-sm">
86
86
  {app.name.charAt(0).toUpperCase()}
87
87
  </span>
@@ -61,7 +61,7 @@ export function DesktopUserMenu() {
61
61
  {/* User Dropdown */}
62
62
  <div className="relative">
63
63
  <button
64
- className="flex items-center gap-2 px-3 py-2 rounded-lg text-sm font-medium transition-colors text-foreground hover:text-primary hover:bg-accent/50"
64
+ className="flex items-center gap-2 px-3 py-2 rounded-sm text-sm font-medium transition-colors text-foreground hover:text-primary hover:bg-accent/50"
65
65
  onClick={toggleUserMenu}
66
66
  aria-haspopup="true"
67
67
  aria-expanded={userMenuOpen}
@@ -85,15 +85,15 @@ export function DesktopUserMenu() {
85
85
  />
86
86
  {/* Dropdown */}
87
87
  <div
88
- className="absolute top-full right-0 mt-2 w-48 rounded-lg shadow-lg backdrop-blur-xl z-[9996] bg-card/95 border border-border/50"
88
+ className="absolute top-full right-0 mt-2 w-48 rounded-sm shadow-sm backdrop-blur-xl z-[9996] bg-popover border border-border"
89
89
  role="menu"
90
90
  aria-label="User menu"
91
91
  >
92
92
  <div className="p-2">
93
93
  {/* User info */}
94
- <div className="px-3 py-2 text-sm mb-2 border-b text-muted-foreground border-border/30">
95
- Signed in as:
96
- <div className="font-medium truncate text-foreground">
94
+ <div className="px-3 py-2 text-sm mb-2 border-b border-border">
95
+ <div className="text-muted-foreground">Signed in as:</div>
96
+ <div className="font-medium truncate text-popover-foreground mt-1">
97
97
  {user?.email}
98
98
  </div>
99
99
  </div>
@@ -113,7 +113,7 @@ export function DesktopUserMenu() {
113
113
  {/* Logout button */}
114
114
  <button
115
115
  onClick={handleLogout}
116
- className="w-full flex items-center gap-2 px-3 py-2 text-sm rounded-lg transition-colors text-destructive hover:bg-destructive/[0.1]"
116
+ className="w-full flex items-center gap-2 px-3 py-2 text-sm rounded-sm transition-colors text-destructive hover:bg-destructive/[0.1]"
117
117
  >
118
118
  <LogOut className="size-4" />
119
119
  <span>Sign out</span>
@@ -139,7 +139,7 @@ export function Footer() {
139
139
  {/* Badge */}
140
140
  {footer.badge && (
141
141
  <div className="pt-2">
142
- <span className="inline-flex items-center gap-2 px-3 py-1.5 rounded-lg bg-primary/10 hover:bg-primary/15 border border-primary/20 text-xs font-medium text-primary transition-colors">
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
143
  <footer.badge.icon className="w-3.5 h-3.5" />
144
144
  {footer.badge.text}
145
145
  </span>
@@ -10,12 +10,11 @@
10
10
  import React from 'react';
11
11
  import { createPortal } from 'react-dom';
12
12
  import Link from 'next/link';
13
- import { Crown, LogOut, Settings, User, X } from 'lucide-react';
14
- import { ButtonLink, Card, CardContent } from '@djangocfg/ui/components';
15
- import { ThemeToggle } from '@djangocfg/ui/theme';
13
+ import { X } from 'lucide-react';
16
14
  import { useAppContext } from '../../../context';
17
15
  import { useAuth } from '../../../../../auth';
18
16
  import { useNavigation } from '../../../hooks';
17
+ import { MobileMenuUserCard } from './MobileMenuUserCard';
19
18
 
20
19
  /**
21
20
  * Mobile Menu Component
@@ -37,34 +36,47 @@ export function MobileMenu() {
37
36
 
38
37
  const { app, publicLayout, routes } = config;
39
38
 
40
- // Animation state
41
- const [isAnimating, setIsAnimating] = React.useState(false);
39
+ // Track if we should render (stays true during close animation)
40
+ const [shouldRender, setShouldRender] = React.useState(false);
42
41
 
43
- // Trigger animation when menu opens
42
+ // Track animation state separately
43
+ const [isOpen, setIsOpen] = React.useState(false);
44
+
45
+ // Handle opening
44
46
  React.useEffect(() => {
45
47
  if (mobileMenuOpen) {
46
- // Small delay to trigger animation
47
- setTimeout(() => setIsAnimating(true), 10);
48
+ setShouldRender(true);
49
+ // Trigger animation after render
50
+ requestAnimationFrame(() => {
51
+ requestAnimationFrame(() => {
52
+ setIsOpen(true);
53
+ });
54
+ });
48
55
  } else {
49
- setIsAnimating(false);
56
+ // Start close animation
57
+ setIsOpen(false);
58
+ // Wait for animation to finish before unmounting
59
+ const timer = setTimeout(() => {
60
+ setShouldRender(false);
61
+ }, 300);
62
+ return () => clearTimeout(timer);
50
63
  }
51
64
  }, [mobileMenuOpen]);
52
65
 
53
66
  const handleLogout = () => {
54
67
  logout();
55
- handleClose();
68
+ closeMobileMenu();
56
69
  };
57
70
 
58
71
  const handleClose = () => {
59
- setIsAnimating(false);
60
- setTimeout(closeMobileMenu, 300); // Wait for animation
72
+ closeMobileMenu();
61
73
  };
62
74
 
63
75
  const handleNavigate = () => {
64
- handleClose();
76
+ closeMobileMenu();
65
77
  };
66
78
 
67
- if (!mobileMenuOpen) return null;
79
+ if (!shouldRender) return null;
68
80
 
69
81
  // Portal to body to avoid z-index and positioning issues
70
82
  if (typeof window === 'undefined') return null;
@@ -73,8 +85,8 @@ export function MobileMenu() {
73
85
  <>
74
86
  {/* Backdrop with fade animation */}
75
87
  <div
76
- className={`fixed inset-0 z-[9998] bg-black/50 backdrop-blur-sm transition-opacity duration-300 lg:hidden ${
77
- isAnimating ? 'opacity-100' : 'opacity-0'
88
+ className={`fixed inset-0 z-[150] bg-black/50 backdrop-blur-sm transition-opacity duration-300 ease-in-out lg:hidden ${
89
+ isOpen ? 'opacity-100' : 'opacity-0'
78
90
  }`}
79
91
  onClick={handleClose}
80
92
  aria-hidden="true"
@@ -82,8 +94,8 @@ export function MobileMenu() {
82
94
 
83
95
  {/* Menu Content with slide animation */}
84
96
  <div
85
- className={`fixed top-0 right-0 bottom-0 w-80 z-[9999] bg-card backdrop-blur-xl border-l border-border shadow-2xl transition-transform duration-300 ease-out lg:hidden ${
86
- isAnimating ? 'translate-x-0' : 'translate-x-full'
97
+ className={`fixed top-0 right-0 bottom-0 w-80 z-[200] bg-popover border-l border-border shadow-2xl transition-transform duration-300 ease-in-out lg:hidden ${
98
+ isOpen ? 'translate-x-0' : 'translate-x-full'
87
99
  }`}
88
100
  role="dialog"
89
101
  aria-modal="true"
@@ -104,7 +116,7 @@ export function MobileMenu() {
104
116
  </div>
105
117
  <button
106
118
  onClick={handleClose}
107
- className="p-2 rounded-lg transition-colors hover:bg-accent/50"
119
+ className="p-2 rounded-sm transition-colors hover:bg-accent/50"
108
120
  aria-label="Close menu"
109
121
  >
110
122
  <X className="size-5" />
@@ -113,118 +125,16 @@ export function MobileMenu() {
113
125
 
114
126
  {/* Scrollable Content */}
115
127
  <div className="flex-1 overflow-y-auto p-4 space-y-6">
116
- {/* User Menu Card - Authenticated */}
117
- {isAuthenticated ? (
118
- <Card className="border-primary/20 shadow-lg bg-accent/30">
119
- <CardContent className="p-4">
120
- {/* User Info Header */}
121
- <div className="flex items-center gap-3 mb-4 p-3 rounded-lg border border-border bg-accent/50">
122
- <div className="w-10 h-10 rounded-full flex items-center justify-center bg-primary flex-shrink-0 overflow-hidden">
123
- {user?.avatar ? (
124
- <img
125
- src={user.avatar}
126
- alt={user?.email || 'User'}
127
- className="w-10 h-10 rounded-full object-cover"
128
- />
129
- ) : (
130
- <User className="w-5 h-5 text-primary-foreground" />
131
- )}
132
- </div>
133
- <div className="flex-1 min-w-0">
134
- <p className="text-xs font-medium uppercase tracking-wider text-muted-foreground">
135
- Signed in as
136
- </p>
137
- <p className="text-sm font-semibold truncate text-foreground">
138
- {user?.email}
139
- </p>
140
- </div>
141
- <div className="flex items-center gap-1">
142
- <div className="size-2 rounded-full animate-pulse bg-green-500"></div>
143
- <span className="text-xs font-medium text-green-600 dark:text-green-400">
144
- Active
145
- </span>
146
- </div>
147
- </div>
148
-
149
- {/* Action Buttons */}
150
- <div className="space-y-3">
151
- {/* Dashboard link */}
152
- {publicLayout.userMenu.dashboardPath && (
153
- <ButtonLink
154
- href={publicLayout.userMenu.dashboardPath}
155
- variant="default"
156
- size="sm"
157
- className="w-full justify-center"
158
- onClick={handleNavigate}
159
- >
160
- <Crown className="w-4 h-4 mr-2" />
161
- Dashboard
162
- </ButtonLink>
163
- )}
164
-
165
- {/* Profile link */}
166
- <ButtonLink
167
- href={publicLayout.userMenu.profilePath}
168
- variant="outline"
169
- size="sm"
170
- className="w-full justify-center"
171
- onClick={handleNavigate}
172
- >
173
- <Settings className="w-4 h-4 mr-2" />
174
- Profile Settings
175
- </ButtonLink>
176
-
177
- {/* Logout */}
178
- <button
179
- onClick={handleLogout}
180
- className="w-full flex items-center justify-center gap-2 px-3 py-2 text-sm rounded-lg transition-colors border text-destructive border-destructive/30 hover:bg-destructive/10"
181
- >
182
- <LogOut className="w-4 h-4" />
183
- Sign Out
184
- </button>
185
-
186
- {/* Theme toggle */}
187
- <div className="flex justify-center pt-2 border-t border-border/30">
188
- <ThemeToggle />
189
- </div>
190
- </div>
191
- </CardContent>
192
- </Card>
193
- ) : (
194
- /* Guest Card */
195
- <Card className="border-border bg-accent/30">
196
- <CardContent className="p-4">
197
- <div className="text-center space-y-4">
198
- <div className="w-12 h-12 rounded-full flex items-center justify-center mx-auto bg-muted flex-shrink-0">
199
- <User className="w-6 h-6 text-muted-foreground" />
200
- </div>
201
- <div>
202
- <p className="text-sm font-medium mb-1 text-foreground">
203
- Welcome!
204
- </p>
205
- <p className="text-xs text-muted-foreground">
206
- Sign in to access your dashboard
207
- </p>
208
- </div>
209
- <ButtonLink
210
- href={routes.auth}
211
- variant="default"
212
- size="lg"
213
- className="w-full justify-center"
214
- onClick={handleNavigate}
215
- >
216
- <User className="w-5 h-5 mr-2" />
217
- Sign In
218
- </ButtonLink>
219
-
220
- {/* Theme toggle */}
221
- <div className="flex justify-center pt-2 border-t border-border/30">
222
- <ThemeToggle />
223
- </div>
224
- </div>
225
- </CardContent>
226
- </Card>
227
- )}
128
+ {/* User Menu Card */}
129
+ <MobileMenuUserCard
130
+ isAuthenticated={isAuthenticated}
131
+ user={user}
132
+ dashboardPath={publicLayout.userMenu.dashboardPath}
133
+ profilePath={publicLayout.userMenu.profilePath}
134
+ authPath={routes.auth}
135
+ onLogout={handleLogout}
136
+ onNavigate={handleNavigate}
137
+ />
228
138
 
229
139
  {/* Navigation Sections */}
230
140
  <div className="space-y-6">
@@ -238,7 +148,7 @@ export function MobileMenu() {
238
148
  <div key={section.title} className="space-y-2">
239
149
  <Link
240
150
  href={item.path}
241
- className={`block px-4 py-3 rounded-lg text-base font-medium transition-colors ${
151
+ className={`block px-4 py-3 rounded-sm text-base font-medium transition-colors ${
242
152
  isActive(item.path)
243
153
  ? 'text-primary border border-primary/20 bg-primary/[0.1]'
244
154
  : 'text-muted-foreground hover:text-primary hover:bg-accent/50'
@@ -262,7 +172,7 @@ export function MobileMenu() {
262
172
  <Link
263
173
  key={item.path}
264
174
  href={item.path}
265
- className={`block px-4 py-3 rounded-lg text-base font-medium transition-colors ${
175
+ className={`block px-4 py-3 rounded-sm text-base font-medium transition-colors ${
266
176
  isActive(item.path)
267
177
  ? 'bg-accent text-accent-foreground'
268
178
  : 'text-foreground hover:bg-accent hover:text-accent-foreground'
@@ -0,0 +1,150 @@
1
+ /**
2
+ * Mobile Menu User Card Component
3
+ *
4
+ * Displays user information and action buttons in mobile menu
5
+ * - Authenticated: shows user info with dashboard, profile, and logout
6
+ * - Guest: shows welcome message with sign in button
7
+ */
8
+
9
+ 'use client';
10
+
11
+ import React from 'react';
12
+ import { Crown, LogOut, Settings, User } from 'lucide-react';
13
+ import { Button, ButtonLink, Card, CardContent } from '@djangocfg/ui/components';
14
+ import { ThemeToggle } from '@djangocfg/ui/theme';
15
+
16
+ interface MobileMenuUserCardProps {
17
+ isAuthenticated: boolean;
18
+ user?: {
19
+ email?: string;
20
+ avatar?: string;
21
+ } | null;
22
+ dashboardPath?: string;
23
+ profilePath: string;
24
+ authPath: string;
25
+ onLogout: () => void;
26
+ onNavigate: () => void;
27
+ }
28
+
29
+ export function MobileMenuUserCard({
30
+ isAuthenticated,
31
+ user,
32
+ dashboardPath,
33
+ profilePath,
34
+ authPath,
35
+ onLogout,
36
+ onNavigate,
37
+ }: MobileMenuUserCardProps) {
38
+ if (isAuthenticated) {
39
+ return (
40
+ <Card className="border-primary/20 shadow-lg !bg-accent/50">
41
+ <CardContent className="p-4">
42
+ {/* User Info Header */}
43
+ <div className="flex items-center gap-3 mb-4 p-3 rounded-sm border border-border bg-accent/70">
44
+ <div className="w-10 h-10 rounded-full flex items-center justify-center bg-primary flex-shrink-0 overflow-hidden relative">
45
+ {user?.avatar ? (
46
+ <img
47
+ src={user.avatar}
48
+ alt={user?.email || 'User'}
49
+ className="w-10 h-10 rounded-full object-cover"
50
+ />
51
+ ) : (
52
+ <User className="w-5 h-5 text-primary-foreground" />
53
+ )}
54
+ {/* Active indicator */}
55
+ <div className="absolute -bottom-0.5 -right-0.5 size-3 rounded-full bg-green-500 border-2 border-background" />
56
+ </div>
57
+ <div className="flex-1 min-w-0">
58
+ <p className="text-xs font-medium uppercase tracking-wider text-muted-foreground">
59
+ Signed in as
60
+ </p>
61
+ <p className="text-sm font-semibold truncate text-foreground">
62
+ {user?.email}
63
+ </p>
64
+ </div>
65
+ </div>
66
+
67
+ {/* Action Buttons */}
68
+ <div className="space-y-3">
69
+ {/* Dashboard link */}
70
+ {dashboardPath && (
71
+ <ButtonLink
72
+ href={dashboardPath}
73
+ variant="default"
74
+ size="sm"
75
+ className="w-full h-9"
76
+ onClick={onNavigate}
77
+ >
78
+ <Crown className="w-4 h-4 mr-2" />
79
+ Dashboard
80
+ </ButtonLink>
81
+ )}
82
+
83
+ {/* Quick Actions - Icons only */}
84
+ <div className="flex items-center justify-center gap-2 pt-3 mt-1 border-t border-border/30">
85
+ {/* Profile Settings */}
86
+ <ButtonLink
87
+ href={profilePath}
88
+ variant="ghost"
89
+ size="icon"
90
+ className="h-9 w-9"
91
+ onClick={onNavigate}
92
+ aria-label="Profile Settings"
93
+ >
94
+ <Settings className="h-5 w-5" />
95
+ </ButtonLink>
96
+
97
+ {/* Theme Toggle */}
98
+ <ThemeToggle />
99
+
100
+ {/* Sign Out */}
101
+ <Button
102
+ onClick={onLogout}
103
+ variant="ghost"
104
+ size="icon"
105
+ className="h-9 w-9 text-destructive hover:bg-destructive/10 hover:text-destructive"
106
+ aria-label="Sign Out"
107
+ >
108
+ <LogOut className="h-5 w-5" />
109
+ </Button>
110
+ </div>
111
+ </div>
112
+ </CardContent>
113
+ </Card>
114
+ );
115
+ }
116
+
117
+ // Guest Card
118
+ return (
119
+ <Card className="border-border !bg-accent/50">
120
+ <CardContent className="p-4">
121
+ <div className="text-center space-y-4">
122
+ <div className="w-12 h-12 rounded-full flex items-center justify-center mx-auto bg-muted">
123
+ <User className="w-6 h-6 text-muted-foreground" />
124
+ </div>
125
+ <div>
126
+ <p className="text-sm font-medium mb-1 text-foreground">Welcome!</p>
127
+ <p className="text-xs text-muted-foreground">
128
+ Sign in to access your dashboard
129
+ </p>
130
+ </div>
131
+ <ButtonLink
132
+ href={authPath}
133
+ variant="default"
134
+ size="default"
135
+ className="w-full"
136
+ onClick={onNavigate}
137
+ >
138
+ <User className="w-5 h-5 mr-2" />
139
+ Sign In
140
+ </ButtonLink>
141
+
142
+ {/* Theme toggle */}
143
+ <div className="flex justify-center pt-2 border-t border-border/30">
144
+ <ThemeToggle />
145
+ </div>
146
+ </div>
147
+ </CardContent>
148
+ </Card>
149
+ );
150
+ }
@@ -49,7 +49,7 @@ export function Navigation() {
49
49
  const { app, publicLayout } = config;
50
50
 
51
51
  return (
52
- <nav className="sticky top-0 w-full border-b backdrop-blur-xl z-[9990] bg-surface-gradient border-border/30">
52
+ <nav className="sticky top-0 w-full border-b backdrop-blur-xl z-[100] bg-background/80 border-border/30">
53
53
  <div className="w-full px-4 sm:px-6 lg:px-8">
54
54
  <div className="flex items-center justify-between h-16">
55
55
  {/* Left side - Logo and Navigation Menu */}
@@ -143,7 +143,7 @@ export function Navigation() {
143
143
  {isMobile && (
144
144
  <button
145
145
  onClick={toggleMobileMenu}
146
- className="p-3 rounded-lg border shadow-sm transition-all duration-200 bg-card/50 hover:bg-card border-border/50 hover:border-primary/50 text-foreground hover:text-primary"
146
+ className="p-3 rounded-sm border shadow-sm transition-all duration-200 bg-card/50 hover:bg-card border-border/50 hover:border-primary/50 text-foreground hover:text-primary"
147
147
  aria-label="Toggle mobile menu"
148
148
  >
149
149
  <Menu className="size-5" />