+ {/* Dropdown Menu */}
+ {isDropdownOpen && (
+ <>
+ {/* Backdrop */}
+
setIsDropdownOpen(false)}
+ />
+
+ {/* Menu */}
+
+
+ {profileMenuItems.map((item) => (
+
+
{
+ setIsDropdownOpen(false);
+ onMobileMenuClose();
+ }}
+ >
+ {getProfileIcon(item.icon)}
+ {item.name}
+
+
+ ))}
+
+
+ >
+ )}
+
+ {/* Profile Button */}
+
setIsDropdownOpen(!isDropdownOpen)}
+ className="w-full flex items-center px-4 py-3 rounded-2xl transition-all duration-200 focus:outline-none focus:ring-2 focus:ring-offset-2 nav-item-hover"
+ style={{
+ backgroundColor: 'transparent',
+ color: 'var(--text-secondary)',
+ '--tw-ring-color': 'var(--accent-ember)',
+ '--tw-ring-offset-color': 'var(--bg-secondary)'
+ }}
+ aria-expanded={isDropdownOpen}
+ aria-haspopup="menu"
+ >
+
+
+ {user?.email?.charAt(0).toUpperCase() || 'G'}
+
+
+
+
+ {user?.email || 'Guest'}
+
+
+ {user?.role || 'visitor'}
+
+
+
+
+
+
+
+ );
+}
+
+export default function Layout({ children, user = { email: 'me@randallstillwell.com', role: 'user' }, showSearch = false }) {
+ const router = useRouter();
+ const { theme, toggleTheme } = useTheme();
+ const [searchQuery, setSearchQuery] = useState('');
+ const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false);
+ const [isCommunityExpanded, setIsCommunityExpanded] = useState(
+ router.pathname.startsWith('/community')
+ );
+
+ // Auto-expand Community section when navigating to community pages
+ useEffect(() => {
+ if (router.pathname.startsWith('/community')) {
+ setIsCommunityExpanded(true);
+ }
+ }, [router.pathname]);
+
+ // Navigation structure for authenticated users
+ const authenticatedNavigation = user ? [
+ { name: 'Activity', href: '/activity', icon: 'activity', active: router.pathname === '/activity', isPlaceholder: true }
+ ] : [];
+
+ // My Collection section (only for authenticated users)
+ const myCollectionNavigation = user ? {
+ name: 'My Collection',
+ href: '/dashboard', // My Collection itself links to dashboard
+ icon: 'collection',
+ active: router.pathname === '/dashboard' || router.pathname === '/collections' || router.pathname === '/my-cards' || router.pathname === '/decks' || router.pathname === '/analytics',
+ expanded: true, // Always expanded for now
+ items: [
+ { name: 'Collections', href: '/collections', active: router.pathname === '/collections' },
+ { name: 'Cards', href: '/my-cards', active: router.pathname === '/my-cards' },
+ { name: 'Decks', href: '/decks', active: router.pathname === '/decks' },
+ { name: 'Analytics', href: '/analytics', active: router.pathname === '/analytics', isPlaceholder: true }
+ ]
+ } : null;
+
+ // Always visible navigation (public + authenticated)
+ const publicNavigation = [
+ { name: 'Cards', href: '/cards', icon: 'card', active: router.pathname === '/cards' },
+ { name: 'Scanner', href: '/scanner', icon: 'scanner', active: router.pathname === '/scanner' },
+ { name: 'Deck Builder', href: '/deck-builder', icon: 'deck', active: router.pathname === '/deck-builder', isPlaceholder: true }
+ ];
+
+ // Admin navigation (only for admin users)
+ const adminNavigation = (user?.role === 'admin') ? [
+ { name: 'Admin Tools', href: '/admin/card-editor', icon: 'admin', active: router.pathname.startsWith('/admin'), badge: 'ADMIN' }
+ ] : [];
+
+ const communityNavigation = {
+ name: 'Community',
+ icon: 'community',
+ active: router.pathname.startsWith('/community'),
+ expanded: isCommunityExpanded,
+ items: [
+ { name: 'Collections', href: '/community/collections', active: router.pathname === '/community/collections' },
+ { name: 'Decks', href: '/community/decks', active: router.pathname === '/community/decks' },
+ { name: 'Forums', href: '/community/forums', active: router.pathname === '/community/forums' }
+ ]
+ };
+
+ const bottomNavigation = [
+ { name: 'Notifications', href: '/notifications', icon: 'notifications', active: router.pathname === '/notifications' },
+ { name: 'Settings', href: '/settings', icon: 'settings', active: router.pathname === '/settings' },
+ { name: 'Logout', href: '/logout', icon: 'logout', active: router.pathname === '/logout' }
+ ];
+
+ const getIcon = (iconName) => {
+ const icons = {
+ grid: (
+
+
+
+ ),
+ collection: (
+
+
+
+ ),
+ card: (
+
+
+
+ ),
+ deck: (
+
+
+
+ ),
+ analytics: (
+
+
+
+ ),
+ community: (
+
+
+
+ ),
+ settings: (
+
+
+
+
+ ),
+ logout: (
+
+
+
+ ),
+ admin: (
+
+
+
+
+ ),
+ notifications: (
+
+
+
+ ),
+ activity: (
+
+
+
+ ),
+ scanner: (
+
+
+
+
+ )
+ };
+ return icons[iconName] || icons.grid;
+ };
+
+ return (
+
+ {/* Mobile Navigation - Only show on mobile */}
+
setIsMobileMenuOpen(true)}
+ />
+
+ {/* Mobile Overlay */}
+ {isMobileMenuOpen && (
+ setIsMobileMenuOpen(false)}
+ />
+ )}
+
+ {/* Mobile Menu Drawer - Only visible when menu is open */}
+
+
+ {/* Mobile Header with Close Button */}
+
+
+
setIsMobileMenuOpen(false)}
+ className="p-2 rounded-lg focus:outline-none focus:ring-2 focus:ring-offset-2"
+ style={{
+ color: 'var(--text-secondary)',
+ '--tw-ring-color': 'var(--accent-ember)',
+ '--tw-ring-offset-color': 'var(--bg-secondary)'
+ }}
+ aria-label="Close navigation menu"
+ >
+
+
+
+
+
+
+ {/* Mobile Navigation Content - Same as desktop but in mobile drawer */}
+
+ {/* Authenticated User Navigation - Activity */}
+ {authenticatedNavigation.map((item) => (
+
+ {item.isPlaceholder ? (
+
+
+ {getIcon(item.icon)}
+ {item.name}
+
+
+ Coming Soon
+
+
+ ) : (
+
+
setIsMobileMenuOpen(false)}
+ >
+
+ {getIcon(item.icon)}
+ {item.name}
+
+
+
+ )}
+
+ ))}
+
+ {/* My Collection Section (only for authenticated users) */}
+ {myCollectionNavigation && (
+
+ {/* My Collection Header - Clickable */}
+
+
setIsMobileMenuOpen(false)}
+ >
+
+ {getIcon(myCollectionNavigation.icon)}
+ {myCollectionNavigation.name}
+
+
+
+
+ {/* My Collection Sub-items */}
+ {myCollectionNavigation.expanded && (
+
+ {myCollectionNavigation.items.map((subItem) => (
+
+ {subItem.isPlaceholder ? (
+
+ {subItem.name}
+
+ Soon
+
+
+ ) : (
+
+
setIsMobileMenuOpen(false)}
+ >
+ {subItem.name}
+
+
+ )}
+
+ ))}
+
+ )}
+
+ )}
+
+ {/* Separator */}
+
+
+ {/* Public Navigation (always visible) */}
+ {publicNavigation.map((item) => (
+
+ {item.isPlaceholder ? (
+
+
+ {getIcon(item.icon)}
+ {item.name}
+
+
+ Coming Soon
+
+
+ ) : (
+
+
setIsMobileMenuOpen(false)}
+ >
+
+ {getIcon(item.icon)}
+ {item.name}
+
+
+
+ )}
+
+ ))}
+
+ {/* Community Section with Sub-items */}
+
+
setIsCommunityExpanded(!isCommunityExpanded)}
+ role="menuitem"
+ aria-expanded={isCommunityExpanded}
+ aria-haspopup="menu"
+ tabIndex={0}
+ onKeyDown={(e) => {
+ if (e.key === 'Enter' || e.key === ' ') {
+ e.preventDefault();
+ setIsCommunityExpanded(!isCommunityExpanded);
+ }
+ }}
+ >
+
+ {getIcon(communityNavigation.icon)}
+ {communityNavigation.name}
+
+
+
+
+
+
+ {/* Community Sub-items */}
+ {isCommunityExpanded && (
+
+ {communityNavigation.items.map((subItem) => (
+
+
setIsMobileMenuOpen(false)}
+ role="menuitem"
+ aria-current={subItem.active ? 'page' : undefined}
+ tabIndex={0}
+ onKeyDown={(e) => {
+ if (e.key === 'Enter' || e.key === ' ') {
+ e.preventDefault();
+ setIsMobileMenuOpen(false);
+ }
+ }}
+ >
+ {subItem.name}
+
+
+ ))}
+
+ )}
+
+
+
+ {/* Bottom Section */}
+
+ {/* Admin Navigation (if admin user) */}
+ {adminNavigation.map((item) => (
+
+
setIsMobileMenuOpen(false)}
+ >
+
+ {getIcon(item.icon)}
+ {item.name}
+
+ {item.badge && (
+
+ {item.badge}
+
+ )}
+
+
+ ))}
+
+ {/* User Profile Dropdown */}
+
setIsMobileMenuOpen(false)}
+ />
+
+ {/* Icon Buttons Row - Support and Dark Mode */}
+
+ {/* Support Icon Button */}
+
+
setIsMobileMenuOpen(false)}
+ aria-label="Support"
+ title="Support"
+ >
+
+
+
+
+
+
+ {/* Theme Toggle Icon Button */}
+
+ {theme === 'light' ? (
+
+
+
+ ) : (
+
+
+
+ )}
+
+
+
+
+
+
+ {/* Main Content */}
+
+ {/* Top Header - Only show search on dashboard */}
+ {showSearch && (
+
+
+
+
+
setSearchQuery(e.target.value)}
+ />
+
+ ⌘F
+
+
+
+
+
+
+ )}
+
+ {/* Page Content */}
+
+ {children}
+
+
+
+ );
+}
\ No newline at end of file
diff --git a/components/MobileNavigation.js b/components/MobileNavigation.js
new file mode 100644
index 0000000..c492495
--- /dev/null
+++ b/components/MobileNavigation.js
@@ -0,0 +1,171 @@
+import { useRouter } from 'next/router';
+import Link from 'next/link';
+import { useState } from 'react';
+
+export default function MobileNavigation({ user, onMenuOpen }) {
+ const router = useRouter();
+
+ // Navigation items for the bottom bar
+ const navigationItems = [
+ {
+ name: 'Cards',
+ href: '/cards',
+ icon: 'cards',
+ active: router.pathname === '/cards'
+ },
+ {
+ name: 'Decks',
+ href: '/decks',
+ icon: 'decks',
+ active: router.pathname === '/decks'
+ },
+ {
+ name: 'Dashboard',
+ href: '/dashboard',
+ icon: 'dashboard',
+ active: router.pathname === '/dashboard' || router.pathname === '/collections' || router.pathname === '/my-cards' || router.pathname === '/analytics',
+ isPrimary: true // This will be the raised center button
+ },
+ {
+ name: 'Community',
+ href: '/community',
+ icon: 'community',
+ active: router.pathname.startsWith('/community')
+ },
+ {
+ name: 'More',
+ href: '#',
+ icon: 'more',
+ onClick: onMenuOpen,
+ active: false
+ }
+ ];
+
+ const getIcon = (iconName, isActive = false, isPrimary = false) => {
+ const iconClass = isPrimary ? "h-7 w-7" : "h-6 w-6";
+ const strokeWidth = isActive ? 2.5 : 2;
+
+ const icons = {
+ cards: (
+
+
+
+ ),
+ decks: (
+
+
+
+ ),
+ dashboard: (
+
+
+
+ ),
+ community: (
+
+
+
+ ),
+ more: (
+
+
+
+ )
+ };
+
+ return icons[iconName] || icons.dashboard;
+ };
+
+ return (
+
+ {/* Background with blur effect */}
+
+
+ {/* Navigation Content */}
+
+
+ {navigationItems.map((item) => {
+ if (item.isPrimary) {
+ // Primary/Dashboard button - raised and prominent
+ return (
+
+
+ {/* Raised background circle */}
+
+
+ {/* Button content */}
+
+ {getIcon(item.icon, item.active, true)}
+
+
+ {/* Label below raised button */}
+
+ {item.name}
+
+
+
+ );
+ } else {
+ // Regular navigation buttons
+ const ButtonComponent = item.onClick ? 'button' : Link;
+ const buttonProps = item.onClick
+ ? { onClick: item.onClick }
+ : { href: item.href };
+
+ return (
+
+
+
+ {getIcon(item.icon, item.active)}
+
+
+ {item.name}
+
+
+
+ );
+ }
+ })}
+
+
+
+ {/* Safe area padding for devices with home indicator */}
+
+
+ );
+}
\ No newline at end of file
diff --git a/styles/globals.css b/styles/globals.css
index 05ecc20..b6ea534 100644
--- a/styles/globals.css
+++ b/styles/globals.css
@@ -789,4 +789,32 @@ body {
.animate-ember-float {
animation: ember-float 10s linear infinite;
+}
+
+/* Mobile Navigation Styles */
+.h-safe-area-inset-bottom {
+ height: env(safe-area-inset-bottom, 0px);
+}
+
+/* Mobile responsive adjustments */
+@media (max-width: 768px) {
+ /* Ensure content doesn't get hidden behind mobile nav */
+ .mobile-content-padding {
+ padding-bottom: 80px; /* Space for mobile navigation */
+ }
+
+ /* Mobile navigation backdrop blur support */
+ @supports (backdrop-filter: blur(16px)) {
+ .mobile-nav-backdrop {
+ backdrop-filter: blur(16px);
+ -webkit-backdrop-filter: blur(16px);
+ }
+ }
+
+ /* Fallback for browsers without backdrop-filter */
+ @supports not (backdrop-filter: blur(16px)) {
+ .mobile-nav-backdrop {
+ background-color: rgba(var(--bg-secondary-rgb), 0.95) !important;
+ }
+ }
}
\ No newline at end of file