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:
dwindown
2025-11-06 20:21:12 +07:00
parent 4be283c4a4
commit 76624bb473
6 changed files with 261 additions and 6 deletions

View 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>
);
}