fix: Separate mobile/desktop sidebar components
- Mobile: fixed overlay sidebar with proper z-index - Desktop: sticky sidebar with correct top offset - Extracted SidebarContent component to avoid duplication - Matches App.tsx submenu bar positioning logic
This commit is contained in:
@@ -27,14 +27,15 @@ export default function Help() {
|
||||
const currentSlug = searchParams.get('doc') || 'getting-started';
|
||||
|
||||
// Calculate sticky top position based on mode
|
||||
// Standalone/fullscreen mode: top-16 (below 64px header)
|
||||
// WP Admin mode: top-[calc(7rem+32px)] (header + topnav + wp-admin bar)
|
||||
const sidebarTopClass = isStandalone
|
||||
? 'top-16'
|
||||
// This matches the submenu bar logic in App.tsx:
|
||||
// - Standalone/fullscreen: top-0 (header already handles offset)
|
||||
// - WP Admin: top-[calc(7rem+32px)] = 144px (header 64px + topnav 48px + wp-admin bar 32px)
|
||||
const sidebarStickyTop = isStandalone
|
||||
? 'top-0'
|
||||
: 'top-[calc(7rem+32px)]';
|
||||
|
||||
// Height calculation: full height minus header
|
||||
const sidebarHeightClass = isStandalone
|
||||
// Height calculation matches App.tsx Sidebar pattern
|
||||
const sidebarHeight = isStandalone
|
||||
? 'h-[calc(100vh-64px)]'
|
||||
: 'h-[calc(100vh-7rem-32px)]';
|
||||
|
||||
@@ -53,7 +54,6 @@ export default function Help() {
|
||||
|
||||
if (data.success) {
|
||||
setSections(data.sections);
|
||||
// Expand all sections by default
|
||||
const expanded: Record<string, boolean> = {};
|
||||
data.sections.forEach((section: DocSection) => {
|
||||
expanded[section.key] = true;
|
||||
@@ -85,8 +85,8 @@ export default function Help() {
|
||||
const isActive = (slug: string) => slug === currentSlug;
|
||||
|
||||
return (
|
||||
<div className="flex min-h-0">
|
||||
{/* Mobile menu button */}
|
||||
<div className="flex">
|
||||
{/* Mobile menu button - only show on small screens */}
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
@@ -96,20 +96,80 @@ export default function Help() {
|
||||
{sidebarOpen ? <X className="w-5 h-5" /> : <Menu className="w-5 h-5" />}
|
||||
</Button>
|
||||
|
||||
{/* Sidebar - sticky on desktop, fixed on mobile */}
|
||||
{/* Backdrop for mobile sidebar */}
|
||||
{sidebarOpen && (
|
||||
<div
|
||||
className="fixed inset-0 bg-black/50 z-30 lg:hidden"
|
||||
onClick={() => setSidebarOpen(false)}
|
||||
/>
|
||||
)}
|
||||
|
||||
{/* Mobile sidebar - fixed overlay */}
|
||||
<aside
|
||||
className={cn(
|
||||
"w-72 border-r bg-muted/30 flex-shrink-0 overflow-y-auto",
|
||||
// Mobile: fixed position covering from below header
|
||||
"fixed left-0 z-40",
|
||||
sidebarTopClass,
|
||||
sidebarHeightClass,
|
||||
// Desktop: sticky instead of fixed
|
||||
"lg:sticky",
|
||||
sidebarOpen ? "block" : "hidden lg:block"
|
||||
"lg:hidden fixed left-0 z-40 w-72 bg-background border-r overflow-y-auto",
|
||||
sidebarStickyTop,
|
||||
sidebarHeight,
|
||||
sidebarOpen ? "block" : "hidden"
|
||||
)}
|
||||
>
|
||||
<div className="p-4 border-b bg-muted/30">
|
||||
<SidebarContent
|
||||
loading={loading}
|
||||
sections={sections}
|
||||
expandedSections={expandedSections}
|
||||
toggleSection={toggleSection}
|
||||
selectDoc={selectDoc}
|
||||
isActive={isActive}
|
||||
/>
|
||||
</aside>
|
||||
|
||||
{/* Desktop sidebar - sticky */}
|
||||
<aside
|
||||
className={cn(
|
||||
"hidden lg:block w-72 flex-shrink-0 border-r bg-muted/30 overflow-y-auto sticky",
|
||||
sidebarStickyTop,
|
||||
sidebarHeight
|
||||
)}
|
||||
>
|
||||
<SidebarContent
|
||||
loading={loading}
|
||||
sections={sections}
|
||||
expandedSections={expandedSections}
|
||||
toggleSection={toggleSection}
|
||||
selectDoc={selectDoc}
|
||||
isActive={isActive}
|
||||
/>
|
||||
</aside>
|
||||
|
||||
{/* Main content - uses page scroll */}
|
||||
<main className="flex-1 min-w-0">
|
||||
<div className="max-w-4xl mx-auto py-6 px-6 lg:px-10">
|
||||
<DocContent slug={currentSlug} />
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// Extracted sidebar content to avoid duplication
|
||||
function SidebarContent({
|
||||
loading,
|
||||
sections,
|
||||
expandedSections,
|
||||
toggleSection,
|
||||
selectDoc,
|
||||
isActive,
|
||||
}: {
|
||||
loading: boolean;
|
||||
sections: DocSection[];
|
||||
expandedSections: Record<string, boolean>;
|
||||
toggleSection: (key: string) => void;
|
||||
selectDoc: (slug: string) => void;
|
||||
isActive: (slug: string) => boolean;
|
||||
}) {
|
||||
return (
|
||||
<>
|
||||
<div className="p-4 border-b bg-muted/30 sticky top-0">
|
||||
<h2 className="text-lg font-semibold flex items-center gap-2">
|
||||
<Book className="w-5 h-5" />
|
||||
Documentation
|
||||
@@ -161,22 +221,6 @@ export default function Help() {
|
||||
))
|
||||
)}
|
||||
</nav>
|
||||
</aside>
|
||||
|
||||
{/* Backdrop for mobile */}
|
||||
{sidebarOpen && (
|
||||
<div
|
||||
className="fixed inset-0 bg-black/50 z-30 lg:hidden"
|
||||
onClick={() => setSidebarOpen(false)}
|
||||
/>
|
||||
)}
|
||||
|
||||
{/* Main content - uses page scroll, not internal overflow */}
|
||||
<main className="flex-1 min-w-0">
|
||||
<div className="max-w-4xl mx-auto py-6 px-6 lg:px-10">
|
||||
<DocContent slug={currentSlug} />
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user