fix: Help page scroll and sidebar positioning
- Remove internal overflow (use wp-admin page scroll) - Sidebar sticky under topbar with correct positioning - Standalone mode: top-16 (below 64px header) - WP Admin mode: top-[calc(7rem+32px)] (header+topnav+wp-admin bar) - Uses useApp() to detect mode
This commit is contained in:
@@ -3,6 +3,7 @@ import { useSearchParams } from 'react-router-dom';
|
||||
import { Book, ChevronRight, FileText, Settings, Layers, Puzzle, Menu, X } from 'lucide-react';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { cn } from '@/lib/utils';
|
||||
import { useApp } from '@/contexts/AppContext';
|
||||
import DocContent from './DocContent';
|
||||
import type { DocSection } from './types';
|
||||
|
||||
@@ -21,8 +22,22 @@ export default function Help() {
|
||||
const [expandedSections, setExpandedSections] = useState<Record<string, boolean>>({});
|
||||
const [sidebarOpen, setSidebarOpen] = useState(false);
|
||||
|
||||
const { isStandalone } = useApp();
|
||||
|
||||
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'
|
||||
: 'top-[calc(7rem+32px)]';
|
||||
|
||||
// Height calculation: full height minus header
|
||||
const sidebarHeightClass = isStandalone
|
||||
? 'h-[calc(100vh-64px)]'
|
||||
: 'h-[calc(100vh-7rem-32px)]';
|
||||
|
||||
// Fetch documentation registry
|
||||
useEffect(() => {
|
||||
const fetchDocs = async () => {
|
||||
@@ -64,32 +79,35 @@ export default function Help() {
|
||||
|
||||
const selectDoc = (slug: string) => {
|
||||
setSearchParams({ doc: slug });
|
||||
setSidebarOpen(false); // Close mobile sidebar
|
||||
setSidebarOpen(false);
|
||||
};
|
||||
|
||||
const isActive = (slug: string) => slug === currentSlug;
|
||||
|
||||
return (
|
||||
<div className="flex h-[calc(100vh-64px)] bg-background">
|
||||
<div className="flex min-h-0">
|
||||
{/* Mobile menu button */}
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
className="lg:hidden fixed bottom-4 right-4 z-50 bg-primary text-primary-foreground shadow-lg rounded-full w-12 h-12"
|
||||
className="lg:hidden fixed bottom-20 right-4 z-50 bg-primary text-primary-foreground shadow-lg rounded-full w-12 h-12"
|
||||
onClick={() => setSidebarOpen(!sidebarOpen)}
|
||||
>
|
||||
{sidebarOpen ? <X className="w-5 h-5" /> : <Menu className="w-5 h-5" />}
|
||||
</Button>
|
||||
|
||||
{/* Sidebar */}
|
||||
{/* Sidebar - sticky, positioned below header */}
|
||||
<aside
|
||||
className={cn(
|
||||
"w-72 border-r bg-muted/30 flex-shrink-0 transition-transform duration-300",
|
||||
"fixed lg:relative inset-y-0 left-0 z-40 lg:translate-x-0",
|
||||
sidebarOpen ? "translate-x-0" : "-translate-x-full"
|
||||
"w-72 border-r bg-muted/30 flex-shrink-0",
|
||||
"fixed lg:sticky inset-y-0 left-0 z-40",
|
||||
sidebarTopClass,
|
||||
sidebarHeightClass,
|
||||
"lg:block overflow-y-auto",
|
||||
sidebarOpen ? "block" : "hidden lg:block"
|
||||
)}
|
||||
>
|
||||
<div className="p-4 border-b">
|
||||
<div className="p-4 border-b bg-muted/30">
|
||||
<h2 className="text-lg font-semibold flex items-center gap-2">
|
||||
<Book className="w-5 h-5" />
|
||||
Documentation
|
||||
@@ -97,52 +115,50 @@ export default function Help() {
|
||||
<p className="text-sm text-muted-foreground">Help & Guides</p>
|
||||
</div>
|
||||
|
||||
<div className="h-[calc(100vh-180px)] overflow-y-auto">
|
||||
<nav className="p-2">
|
||||
{loading ? (
|
||||
<div className="p-4 text-sm text-muted-foreground">Loading...</div>
|
||||
) : sections.length === 0 ? (
|
||||
<div className="p-4 text-sm text-muted-foreground">No documentation available</div>
|
||||
) : (
|
||||
sections.map((section) => (
|
||||
<div key={section.key} className="mb-2">
|
||||
<button
|
||||
onClick={() => toggleSection(section.key)}
|
||||
className="w-full flex items-center gap-2 px-3 py-2 text-sm font-medium text-foreground hover:bg-muted rounded-md"
|
||||
>
|
||||
{iconMap[section.icon] || <FileText className="w-4 h-4" />}
|
||||
<span className="flex-1 text-left">{section.label}</span>
|
||||
<ChevronRight
|
||||
className={cn(
|
||||
"w-4 h-4 transition-transform",
|
||||
expandedSections[section.key] && "rotate-90"
|
||||
)}
|
||||
/>
|
||||
</button>
|
||||
<nav className="p-2">
|
||||
{loading ? (
|
||||
<div className="p-4 text-sm text-muted-foreground">Loading...</div>
|
||||
) : sections.length === 0 ? (
|
||||
<div className="p-4 text-sm text-muted-foreground">No documentation available</div>
|
||||
) : (
|
||||
sections.map((section) => (
|
||||
<div key={section.key} className="mb-2">
|
||||
<button
|
||||
onClick={() => toggleSection(section.key)}
|
||||
className="w-full flex items-center gap-2 px-3 py-2 text-sm font-medium text-foreground hover:bg-muted rounded-md"
|
||||
>
|
||||
{iconMap[section.icon] || <FileText className="w-4 h-4" />}
|
||||
<span className="flex-1 text-left">{section.label}</span>
|
||||
<ChevronRight
|
||||
className={cn(
|
||||
"w-4 h-4 transition-transform",
|
||||
expandedSections[section.key] && "rotate-90"
|
||||
)}
|
||||
/>
|
||||
</button>
|
||||
|
||||
{expandedSections[section.key] && (
|
||||
<div className="ml-4 mt-1 space-y-1">
|
||||
{section.items.map((item) => (
|
||||
<button
|
||||
key={item.slug}
|
||||
onClick={() => selectDoc(item.slug)}
|
||||
className={cn(
|
||||
"w-full text-left px-3 py-1.5 text-sm rounded-md transition-colors",
|
||||
isActive(item.slug)
|
||||
? "bg-primary text-primary-foreground"
|
||||
: "text-muted-foreground hover:bg-muted hover:text-foreground"
|
||||
)}
|
||||
>
|
||||
{item.title}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
))
|
||||
)}
|
||||
</nav>
|
||||
</div>
|
||||
{expandedSections[section.key] && (
|
||||
<div className="ml-4 mt-1 space-y-1">
|
||||
{section.items.map((item) => (
|
||||
<button
|
||||
key={item.slug}
|
||||
onClick={() => selectDoc(item.slug)}
|
||||
className={cn(
|
||||
"w-full text-left px-3 py-1.5 text-sm rounded-md transition-colors",
|
||||
isActive(item.slug)
|
||||
? "bg-primary text-primary-foreground"
|
||||
: "text-muted-foreground hover:bg-muted hover:text-foreground"
|
||||
)}
|
||||
>
|
||||
{item.title}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
))
|
||||
)}
|
||||
</nav>
|
||||
</aside>
|
||||
|
||||
{/* Backdrop for mobile */}
|
||||
@@ -153,9 +169,9 @@ export default function Help() {
|
||||
/>
|
||||
)}
|
||||
|
||||
{/* Main content */}
|
||||
<main className="flex-1 overflow-y-auto">
|
||||
<div className="max-w-4xl mx-auto p-6 lg:p-10">
|
||||
{/* 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>
|
||||
|
||||
Reference in New Issue
Block a user