feat: Implement mobile-first navigation with bottom bar and FAB
Implemented mobile-optimized navigation structure: 1. Bottom Navigation (Mobile Only) - 5 items: Dashboard, Orders, Products, Customers, More - Fixed at bottom, always visible - Thumb-friendly positioning - Active state indication - Hidden on desktop (md:hidden) 2. More Menu Page - Overflow menu for Coupons and Settings - Clean list layout with icons - Descriptions for each item - Chevron indicators 3. FAB (Floating Action Button) - Context-aware system via FABContext - Fixed bottom-right (72px from bottom) - Hidden on desktop (md:hidden) - Ready for contextual actions per page 4. FAB Context System - Global state for FAB configuration - setFAB() / clearFAB() methods - Supports icon, label, onClick, visibility - Allows pages to control FAB behavior 5. Layout Updates - Added pb-14 to main for bottom nav spacing - BottomNav and FAB in mobile fullscreen layout - Wrapped app with FABProvider Structure (Mobile): ┌─────────────────────────────────┐ │ App Bar (will hide on scroll) │ ├─────────────────────────────────┤ │ Page Header (sticky, contextual)│ ├─────────────────────────────────┤ │ Submenu (sticky) │ ├─────────────────────────────────┤ │ Content (scrollable) │ │ [+] FAB │ ├─────────────────────────────────┤ │ Bottom Nav (fixed) │ └─────────────────────────────────┘ Next Steps: - Implement scroll-hide for app bar - Add contextual FAB per page - Test on real devices Files Created: - BottomNav.tsx: Bottom navigation component - More/index.tsx: More menu page - FABContext.tsx: FAB state management - FAB.tsx: Floating action button component - useScrollDirection.ts: Scroll detection hook Files Modified: - App.tsx: Added bottom nav, FAB, More route, providers
This commit is contained in:
66
admin-spa/src/routes/More/index.tsx
Normal file
66
admin-spa/src/routes/More/index.tsx
Normal file
@@ -0,0 +1,66 @@
|
||||
import React from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { Tag, Settings as SettingsIcon, ChevronRight } from 'lucide-react';
|
||||
import { __ } from '@/lib/i18n';
|
||||
|
||||
interface MenuItem {
|
||||
icon: React.ReactNode;
|
||||
label: string;
|
||||
description: string;
|
||||
to: string;
|
||||
}
|
||||
|
||||
const menuItems: MenuItem[] = [
|
||||
{
|
||||
icon: <Tag className="w-5 h-5" />,
|
||||
label: __('Coupons'),
|
||||
description: __('Manage discount codes and promotions'),
|
||||
to: '/coupons'
|
||||
},
|
||||
{
|
||||
icon: <SettingsIcon className="w-5 h-5" />,
|
||||
label: __('Settings'),
|
||||
description: __('Configure your store settings'),
|
||||
to: '/settings'
|
||||
}
|
||||
];
|
||||
|
||||
export default function MorePage() {
|
||||
const navigate = useNavigate();
|
||||
|
||||
return (
|
||||
<div className="min-h-screen bg-background pb-20">
|
||||
{/* Header */}
|
||||
<div className="sticky top-0 z-10 bg-background border-b">
|
||||
<div className="px-4 py-4">
|
||||
<h1 className="text-2xl font-bold">{__('More')}</h1>
|
||||
<p className="text-sm text-muted-foreground mt-1">
|
||||
{__('Additional features and settings')}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Menu Items */}
|
||||
<div className="divide-y">
|
||||
{menuItems.map((item) => (
|
||||
<button
|
||||
key={item.to}
|
||||
onClick={() => navigate(item.to)}
|
||||
className="w-full flex items-center gap-4 px-4 py-4 hover:bg-accent transition-colors"
|
||||
>
|
||||
<div className="flex-shrink-0 w-10 h-10 rounded-lg bg-primary/10 text-primary flex items-center justify-center">
|
||||
{item.icon}
|
||||
</div>
|
||||
<div className="flex-1 text-left min-w-0">
|
||||
<div className="font-medium">{item.label}</div>
|
||||
<div className="text-sm text-muted-foreground truncate">
|
||||
{item.description}
|
||||
</div>
|
||||
</div>
|
||||
<ChevronRight className="w-5 h-5 text-muted-foreground flex-shrink-0" />
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user