-
+
} />
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 */}
+
+
+ {/* 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