diff --git a/admin-spa/src/App.tsx b/admin-spa/src/App.tsx index 40ca763..b3506ae 100644 --- a/admin-spa/src/App.tsx +++ b/admin-spa/src/App.tsx @@ -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() { ) : ( )} +
@@ -434,6 +437,7 @@ function Shell() { )}
+
@@ -448,6 +452,7 @@ function Shell() { ) : ( )} +
@@ -505,9 +510,11 @@ function AuthWrapper() { } return ( - - - + + + + + ); } diff --git a/admin-spa/src/components/PageHeader.tsx b/admin-spa/src/components/PageHeader.tsx new file mode 100644 index 0000000..6db3e99 --- /dev/null +++ b/admin-spa/src/components/PageHeader.tsx @@ -0,0 +1,19 @@ +import React from 'react'; +import { usePageHeader } from '@/contexts/PageHeaderContext'; + +export function PageHeader() { + const { title, action } = usePageHeader(); + + if (!title) return null; + + return ( +
+
+
+

{title}

+
+ {action &&
{action}
} +
+
+ ); +} diff --git a/admin-spa/src/contexts/PageHeaderContext.tsx b/admin-spa/src/contexts/PageHeaderContext.tsx new file mode 100644 index 0000000..041e5ef --- /dev/null +++ b/admin-spa/src/contexts/PageHeaderContext.tsx @@ -0,0 +1,39 @@ +import React, { createContext, useContext, useState, ReactNode } from 'react'; + +interface PageHeaderContextType { + title: string | null; + action: ReactNode | null; + setPageHeader: (title: string | null, action?: ReactNode) => void; + clearPageHeader: () => void; +} + +const PageHeaderContext = createContext(undefined); + +export function PageHeaderProvider({ children }: { children: ReactNode }) { + const [title, setTitle] = useState(null); + const [action, setAction] = useState(null); + + const setPageHeader = (newTitle: string | null, newAction?: ReactNode) => { + setTitle(newTitle); + setAction(newAction || null); + }; + + const clearPageHeader = () => { + setTitle(null); + setAction(null); + }; + + return ( + + {children} + + ); +} + +export function usePageHeader() { + const context = useContext(PageHeaderContext); + if (!context) { + throw new Error('usePageHeader must be used within PageHeaderProvider'); + } + return context; +} diff --git a/admin-spa/src/routes/Settings/components/SettingsLayout.tsx b/admin-spa/src/routes/Settings/components/SettingsLayout.tsx index a771052..1cf53bb 100644 --- a/admin-spa/src/routes/Settings/components/SettingsLayout.tsx +++ b/admin-spa/src/routes/Settings/components/SettingsLayout.tsx @@ -1,6 +1,7 @@ -import React, { useState } from 'react'; +import React, { useState, useEffect } from 'react'; import { Button } from '@/components/ui/button'; import { Loader2 } from 'lucide-react'; +import { usePageHeader } from '@/contexts/PageHeaderContext'; interface SettingsLayoutProps { title: string; @@ -22,6 +23,7 @@ export function SettingsLayout({ action, }: SettingsLayoutProps) { const [isSaving, setIsSaving] = useState(false); + const { setPageHeader, clearPageHeader } = usePageHeader(); const handleSave = async () => { if (!onSave) return; @@ -33,32 +35,35 @@ export function SettingsLayout({ } }; + // Set page header when component mounts + useEffect(() => { + if (onSave) { + setPageHeader( + title, + + ); + } else { + clearPageHeader(); + } + + return () => clearPageHeader(); + }, [title, onSave, isSaving, isLoading, saveLabel]); + return (
- {/* Sticky Header with Save Button - Edge to edge */} - {onSave && ( -
-
-
-

{title}

-
- -
-
- )} {/* Content */}