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