diff --git a/src/App.tsx b/src/App.tsx index 9618257..5aac322 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -5,7 +5,7 @@ import { Analytics } from '@vercel/analytics/react'; import { SpeedInsights } from '@vercel/speed-insights/react'; import { AuthProvider, useAuth } from './contexts/AuthContext'; import { ThemeProvider } from './contexts/ThemeContext'; -import MobileNavbar from './components/MobileNavbar'; +import ResponsiveLayout from './components/ResponsiveLayout'; import Dashboard from './pages/Dashboard'; import Collections from './pages/Collections'; import Decks from './pages/Decks'; @@ -77,17 +77,12 @@ const PublicRoute: React.FC<{ children: React.ReactNode }> = ({ children }) => { return <>{children}; }; -// Mobile Layout Component -const MobileLayout: React.FC<{ children: React.ReactNode }> = ({ children }) => { +// Responsive Layout Component +const AppLayout: React.FC<{ children: React.ReactNode }> = ({ children }) => { return ( -
- -
-
- {children} -
-
-
+ + {children} + ); }; @@ -128,58 +123,58 @@ function App() { {/* Protected Routes */} - + - + } /> - + - + } /> - + - + } /> - + - + } /> - + - + } /> - + - + } /> {/* Admin Routes */} - + - + } /> @@ -188,7 +183,7 @@ function App() { {/* 404 fallback */} +
@@ -204,7 +199,7 @@ function App() { Go Back
- + } /> diff --git a/src/components/ResponsiveLayout.tsx b/src/components/ResponsiveLayout.tsx new file mode 100644 index 0000000..bd63799 --- /dev/null +++ b/src/components/ResponsiveLayout.tsx @@ -0,0 +1,520 @@ +import React, { useState } from 'react'; +import { Link, useLocation, useNavigate } from 'react-router-dom'; +import { useAuth } from '../contexts/AuthContext'; +import { useTheme } from '../contexts/ThemeContext'; + +const ResponsiveLayout: React.FC<{ children: React.ReactNode }> = ({ children }) => { + const { user, logout, isAdmin } = useAuth(); + const { toggleTheme, effectiveTheme } = useTheme(); + const location = useLocation(); + const navigate = useNavigate(); + const [showUserMenu, setShowUserMenu] = useState(false); + const [sidebarOpen, setSidebarOpen] = useState(false); + + const handleLogout = () => { + logout(); + setShowUserMenu(false); + setSidebarOpen(false); + navigate('/login'); + }; + + const isActive = (path: string) => location.pathname === path; + + const navigation = [ + { name: 'Dashboard', href: '/dashboard', icon: '📊', mobileIcon: '🏠' }, + { name: 'Cards', href: '/cards', icon: '🃏', mobileIcon: '🃏' }, + { name: 'Collections', href: '/collections', icon: '📚', mobileIcon: '📚' }, + { name: 'Decks', href: '/decks', icon: '🎯', mobileIcon: '🎯' }, + { name: 'Scanner', href: '/scanner', icon: '📷', mobileIcon: '📷' }, + ]; + + return ( +
+ {/* Desktop Layout */} +
+ {/* Sidebar */} +
+ {/* Logo */} +
+ +
+ + + +
+
+

TCG Vault

+

+ Hi, {user?.firstName || user?.username} +

+
+ +
+ + {/* Navigation */} + + + {/* User Section */} +
+
+
+ {user?.firstName?.[0] || user?.username?.[0]?.toUpperCase() || 'U'} +
+
+

+ {user?.firstName && user?.lastName + ? `${user.firstName} ${user.lastName}` + : user?.username} +

+

{user?.email}

+
+ +
+ + {/* User Menu Dropdown */} + {showUserMenu && ( +
+
+ setShowUserMenu(false)} + className="flex items-center space-x-3 px-4 py-2 text-sm text-surface-700 dark:text-surface-300 hover:bg-surface-100 dark:hover:bg-surface-700" + > + ⚙️ + Settings + + + {isAdmin() && ( + setShowUserMenu(false)} + className="flex items-center space-x-3 px-4 py-2 text-sm text-yellow-700 dark:text-yellow-300 hover:bg-yellow-50 dark:hover:bg-yellow-900/20" + > + 👑 + Admin Panel + + )} + +
+ + +
+
+ )} +
+
+ + {/* Main Content */} +
+ {/* Top Header */} +
+
+
+

+ {navigation.find(item => isActive(item.href))?.name || 'TCG Vault'} +

+ {isAdmin() && ( + + ⚡ Admin + + )} +
+ +
+ {/* Theme Toggle */} + +
+
+
+ + {/* Page Content */} +
+
+ {children} +
+
+
+
+ + {/* Mobile Layout */} +
+ {/* Top Header */} +
+
+
+ +
+ + + +
+
+

TCG Vault

+

+ Hi, {user?.firstName || user?.username} +

+
+
+ +
+ {/* Theme Toggle */} + + + {/* User Avatar */} + +
+
+
+ + {/* Mobile Sidebar */} + {sidebarOpen && ( +
+
setSidebarOpen(false)}>
+
+
+
+ setSidebarOpen(false)}> +
+ + + +
+
+

TCG Vault

+

+ Hi, {user?.firstName || user?.username} +

+
+ + +
+
+ + + +
+
+
+ {user?.firstName?.[0] || user?.username?.[0]?.toUpperCase() || 'U'} +
+
+

+ {user?.firstName && user?.lastName + ? `${user.firstName} ${user.lastName}` + : user?.username} +

+

{user?.email}

+
+
+
+
+
+ )} + + {/* Bottom Navigation */} + + + {/* Page Content */} +
+
+ {children} +
+
+ + {/* User Menu Modal */} + {showUserMenu && ( +
setShowUserMenu(false)}> +
+
+ +
+
+ {user?.firstName?.[0] || user?.username?.[0]?.toUpperCase() || 'U'} +
+
+

+ {user?.firstName && user?.lastName + ? `${user.firstName} ${user.lastName}` + : user?.username} +

+

{user?.email}

+
+ {user?.roles.map((role) => ( + + {role} + + ))} +
+
+
+ +
+ setShowUserMenu(false)} + className="flex items-center space-x-3 p-3 rounded-xl hover:bg-surface-100 dark:hover:bg-surface-800 transition-colors" + > + + + + Decks + + + setShowUserMenu(false)} + className="flex items-center space-x-3 p-3 rounded-xl hover:bg-surface-100 dark:hover:bg-surface-800 transition-colors" + > + + + + + Settings + + + {isAdmin() && ( + setShowUserMenu(false)} + className="flex items-center space-x-3 p-3 rounded-xl hover:bg-yellow-50 dark:hover:bg-yellow-900/20 transition-colors" + > + + + + Admin Panel + + )} +
+ + +
+
+ )} +
+ + {/* Click outside to close menus */} + {(showUserMenu || sidebarOpen) && ( +
{ + setShowUserMenu(false); + setSidebarOpen(false); + }} + /> + )} +
+ ); +}; + +export default ResponsiveLayout; \ No newline at end of file