refactor: Move page header outside content container using context
Problem: - Page header inside scrollable content container - Complex sticky positioning logic - Different behavior in different modes Better Architecture: Move page header to same level as submenu, outside scroll container Structure: <main flex flex-col> <SubmenuBar sticky> ← Sticky outside scroll <PageHeader sticky> ← Sticky outside scroll ✅ <div overflow-auto> ← Only content scrolls <AppRoutes /> Implementation: 1. PageHeaderContext - Global state for page header - title: string - action: ReactNode (e.g., Save button) - setPageHeader() / clearPageHeader() 2. PageHeader Component - Renders at app level - Positioned after submenu - Sticky top-[49px] (below submenu) - Boxed layout (max-w-5xl, centered) - Consumes context 3. SettingsLayout - Sets header via context - useEffect to set/clear header - No inline sticky header - Cleaner component Benefits: ✅ Page header outside scroll container ✅ Sticky works consistently (no mode detection) ✅ Submenu layout preserved (justify-start) ✅ Page header uses page layout (boxed, centered) ✅ Separation of concerns ✅ Reusable for any page that needs sticky header Layout Hierarchy: ┌─────────────────────────────────────┐ │ <main flex flex-col> │ │ ┌─────────────────────────────┐ │ │ │ SubmenuBar (sticky) │ │ ← justify-start │ ├─────────────────────────────┤ │ │ │ PageHeader (sticky) │ │ ← max-w-5xl centered │ ├─────────────────────────────┤ │ │ │ <div overflow-auto> │ │ │ │ Content (scrolls) │ │ │ └─────────────────────────────┘ │ └─────────────────────────────────────┘ Files Created: - PageHeaderContext.tsx: Context provider - PageHeader.tsx: Header component Files Modified: - App.tsx: Added PageHeader after submenu in all layouts - SettingsLayout.tsx: Use context instead of inline header Result: ✅ Clean architecture ✅ Consistent sticky behavior ✅ No mode-specific logic ✅ Reusable pattern
This commit is contained in:
@@ -29,6 +29,8 @@ import { useCommandStore } from "@/lib/useCommandStore";
|
||||
import SubmenuBar from './components/nav/SubmenuBar';
|
||||
import DashboardSubmenuBar from './components/nav/DashboardSubmenuBar';
|
||||
import { DashboardProvider } from '@/contexts/DashboardContext';
|
||||
import { PageHeaderProvider } from '@/contexts/PageHeaderContext';
|
||||
import { PageHeader } from '@/components/PageHeader';
|
||||
import { useActiveSection } from '@/hooks/useActiveSection';
|
||||
import { NAV_TREE_VERSION } from '@/nav/tree';
|
||||
import { __ } from '@/lib/i18n';
|
||||
@@ -420,6 +422,7 @@ function Shell() {
|
||||
) : (
|
||||
<SubmenuBar items={main.children} fullscreen={true} />
|
||||
)}
|
||||
<PageHeader />
|
||||
<div className="flex-1 overflow-auto p-4">
|
||||
<AppRoutes />
|
||||
</div>
|
||||
@@ -434,6 +437,7 @@ function Shell() {
|
||||
<SubmenuBar items={main.children} fullscreen={true} />
|
||||
)}
|
||||
<main className="flex-1 flex flex-col min-h-0">
|
||||
<PageHeader />
|
||||
<div className="flex-1 overflow-auto p-4">
|
||||
<AppRoutes />
|
||||
</div>
|
||||
@@ -448,6 +452,7 @@ function Shell() {
|
||||
) : (
|
||||
<SubmenuBar items={main.children} fullscreen={false} />
|
||||
)}
|
||||
<PageHeader />
|
||||
<main className="flex-1 flex flex-col min-h-0">
|
||||
<div className="flex-1 overflow-auto p-4">
|
||||
<AppRoutes />
|
||||
@@ -505,9 +510,11 @@ function AuthWrapper() {
|
||||
}
|
||||
|
||||
return (
|
||||
<DashboardProvider>
|
||||
<Shell />
|
||||
</DashboardProvider>
|
||||
<PageHeaderProvider>
|
||||
<DashboardProvider>
|
||||
<Shell />
|
||||
</DashboardProvider>
|
||||
</PageHeaderProvider>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user