feat: Mobile-only contextual headers + consistent button sizing
Implemented 3 key improvements based on user feedback: 1. ✅ PageHeader Mobile-Only Problem: Contextual header showing on desktop was redundant Solution: Added md:hidden to PageHeader component Before: Desktop: Shows "Store Details" header (redundant with nav) Mobile: Shows "Store Details" header (good!) After: Desktop: No contextual header (clean!) Mobile: Shows "Store Details" header (perfect!) Result: Cleaner desktop UI, mobile gets contextual clarity 2. ✅ Contextual Headers on All Pages Problem: Dashboard and Payments pages missing contextual headers Solution: - Added usePageHeader to Dashboard - Fixed SettingsLayout to always set header (not just when onSave exists) Before: - Dashboard: No header (confusing) - Payments: No header (confusing) - Store Details: Has header (only one working) After: - Dashboard: "Dashboard" header ✓ - Payments: "Payments" header ✓ - Store Details: "Store Details" header ✓ - All settings pages: Contextual headers ✓ Result: Consistent UX across all pages! 3. ✅ Re-added .ui-ctrl to Button Problem: Removed .ui-ctrl earlier, but it's needed for mobile sizing Solution: Added .ui-ctrl back to Button component Why .ui-ctrl is Good: - Mobile: 44px height (good touch target) - Desktop: 36px height (compact, efficient) - Responsive by default - Follows UI/UX best practices Result: Buttons properly sized for touch on mobile! Mobile Layout (Final): ┌─────────────────────────────────┐ │ Dashboard │ ← Contextual header! ├─────────────────────────────────┤ │ Overview | Revenue | Orders ... │ ← Submenu ├─────────────────────────────────┤ │ Last 7 days [Refresh] │ ├─────────────────────────────────┤ │ Revenue │ │ Rp64.500 │ │ 99.9% vs previous 7 days │ │ ( + ) │ ← FAB ├─────────────────────────────────┤ │ Bottom Nav │ └─────────────────────────────────┘ Desktop Layout (Final): ┌─────────────────────────────────┐ │ Header │ ├─────────────────────────────────┤ │ Dashboard | Orders | Products │ ← Top Nav ├─────────────────────────────────┤ │ Overview | Revenue | Orders ... │ ← Submenu ├─────────────────────────────────┤ │ (No contextual header) │ ← Clean! ├─────────────────────────────────┤ │ Revenue │ │ Rp64.500 │ └─────────────────────────────────┘ Files Modified: - PageHeader.tsx: Added md:hidden for mobile-only - Dashboard/index.tsx: Added contextual header - SettingsLayout.tsx: Always set header (not just with onSave) - button.tsx: Re-added .ui-ctrl class Result: ✅ Mobile: Contextual headers on all pages ✅ Desktop: Clean, no redundant headers ✅ Buttons: Proper touch targets (44px mobile, 36px desktop) ✅ Consistent UX across all pages! 🎉
This commit is contained in:
@@ -12,8 +12,9 @@ export function PageHeader({ fullscreen = false }: PageHeaderProps) {
|
|||||||
|
|
||||||
// PageHeader is now ABOVE submenu in DOM order
|
// PageHeader is now ABOVE submenu in DOM order
|
||||||
// z-20 ensures it stays on top when both are sticky
|
// z-20 ensures it stays on top when both are sticky
|
||||||
|
// Mobile-only: hidden on desktop (md:hidden)
|
||||||
return (
|
return (
|
||||||
<div className="sticky top-0 z-20 border-b bg-background">
|
<div className="sticky top-0 z-20 border-b bg-background md:hidden">
|
||||||
<div className="w-full max-w-5xl mx-auto px-4 py-3 flex items-center justify-between min-w-0">
|
<div className="w-full max-w-5xl mx-auto px-4 py-3 flex items-center justify-between min-w-0">
|
||||||
<div className="min-w-0 flex-1">
|
<div className="min-w-0 flex-1">
|
||||||
<h1 className="text-lg font-semibold truncate">{title}</h1>
|
<h1 className="text-lg font-semibold truncate">{title}</h1>
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
|
|||||||
const Comp = asChild ? Slot : "button"
|
const Comp = asChild ? Slot : "button"
|
||||||
return (
|
return (
|
||||||
<Comp
|
<Comp
|
||||||
className={cn(buttonVariants({ variant, size, className }))}
|
className={cn('ui-ctrl', buttonVariants({ variant, size, className }))}
|
||||||
ref={ref}
|
ref={ref}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import { useOverviewAnalytics } from '@/hooks/useAnalytics';
|
|||||||
import { ErrorCard } from '@/components/ErrorCard';
|
import { ErrorCard } from '@/components/ErrorCard';
|
||||||
import { getPageLoadErrorMessage } from '@/lib/errorHandling';
|
import { getPageLoadErrorMessage } from '@/lib/errorHandling';
|
||||||
import { useFABConfig } from '@/hooks/useFABConfig';
|
import { useFABConfig } from '@/hooks/useFABConfig';
|
||||||
|
import { usePageHeader } from '@/contexts/PageHeaderContext';
|
||||||
|
|
||||||
// Dummy data for visualization
|
// Dummy data for visualization
|
||||||
const DUMMY_DATA = {
|
const DUMMY_DATA = {
|
||||||
@@ -160,12 +161,19 @@ function MetricCard({ title, value, change, icon: Icon, format = 'number', perio
|
|||||||
|
|
||||||
export default function Dashboard() {
|
export default function Dashboard() {
|
||||||
useFABConfig('dashboard'); // Add FAB for quick actions
|
useFABConfig('dashboard'); // Add FAB for quick actions
|
||||||
|
const { setPageHeader, clearPageHeader } = usePageHeader();
|
||||||
const { period } = useDashboardPeriod();
|
const { period } = useDashboardPeriod();
|
||||||
const store = getStoreCurrency();
|
const store = getStoreCurrency();
|
||||||
const [hoverIndex, setHoverIndex] = useState<number | undefined>(undefined);
|
const [hoverIndex, setHoverIndex] = useState<number | undefined>(undefined);
|
||||||
const [chartMetric, setChartMetric] = useState<'both' | 'revenue' | 'orders'>('both');
|
const [chartMetric, setChartMetric] = useState<'both' | 'revenue' | 'orders'>('both');
|
||||||
const chartRef = useRef<any>(null);
|
const chartRef = useRef<any>(null);
|
||||||
|
|
||||||
|
// Set contextual header
|
||||||
|
useEffect(() => {
|
||||||
|
setPageHeader(__('Dashboard'));
|
||||||
|
return () => clearPageHeader();
|
||||||
|
}, [setPageHeader, clearPageHeader]);
|
||||||
|
|
||||||
// Fetch real data or use dummy data based on toggle
|
// Fetch real data or use dummy data based on toggle
|
||||||
const { data, isLoading, error, refetch } = useOverviewAnalytics(DUMMY_DATA);
|
const { data, isLoading, error, refetch } = useOverviewAnalytics(DUMMY_DATA);
|
||||||
|
|
||||||
|
|||||||
@@ -55,12 +55,16 @@ export function SettingsLayout({
|
|||||||
)}
|
)}
|
||||||
</Button>
|
</Button>
|
||||||
);
|
);
|
||||||
|
} else if (action) {
|
||||||
|
// If there's a custom action, use it
|
||||||
|
setPageHeader(title, action);
|
||||||
} else {
|
} else {
|
||||||
clearPageHeader();
|
// Always set the title, even without action
|
||||||
|
setPageHeader(title);
|
||||||
}
|
}
|
||||||
|
|
||||||
return () => clearPageHeader();
|
return () => clearPageHeader();
|
||||||
}, [title, onSave, isSaving, isLoading, saveLabel]);
|
}, [title, onSave, isSaving, isLoading, saveLabel, action, setPageHeader, clearPageHeader]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="space-y-6 min-w-0">
|
<div className="space-y-6 min-w-0">
|
||||||
|
|||||||
Reference in New Issue
Block a user