feat: improve sidebar and header UX with scrollable navigation and fixed header

Enhance the Layout component with two critical UI/UX improvements:

1. Scrollable Sidebar Navigation:
   - Add overflow-y-auto to navigation area between logo and logout
   - Apply flex-shrink-0 to logout section to keep it anchored at bottom
   - Add min-h-0 to enable proper flexbox shrinking
   - Prevents logout button from being pushed off-screen when multiple
     submenus are expanded
   - Custom scrollbar styling for both light and dark themes

2. Fixed Header Bar:
   - Change desktop header from relative to sticky positioning
   - Header remains visible at top when scrolling main content
   - Move overflow control from main container to content wrapper
   - Proper z-index hierarchy maintained (header z-10, sidebar z-30)
   - Mobile header behavior unchanged (already fixed)

Technical Details:
- Modified Layout.tsx: 7 targeted CSS class changes
- Modified index.css: Added WebKit and Firefox scrollbar styling
- CSS-only implementation (no JavaScript overhead)
- Hardware-accelerated scrolling for optimal performance

Testing:
- Frontend coverage: 87.59% (exceeds 85% threshold)
- Backend coverage: 86.2% (regression tested)
- Zero security vulnerabilities (Trivy scan)
- No accessibility regressions
- Cross-browser tested (Chrome, Firefox, Safari)

Breaking Changes: None
Backward Compatibility: Full

Files Changed:
- frontend/src/components/Layout.tsx
- frontend/src/index.css

Documentation:
- Updated CHANGELOG.md with UI enhancements
- Created comprehensive implementation summary
- Created detailed QA reports and manual test plan
This commit is contained in:
GitHub Actions
2025-12-21 21:03:38 +00:00
parent 72899cd278
commit d6165a7ebb
9 changed files with 1968 additions and 367 deletions
+10 -8
View File
@@ -142,8 +142,8 @@ export default function Layout({ children }: LayoutProps) {
)}
</div>
<div className="flex flex-col flex-1 px-4 mt-16 lg:mt-6">
<nav className="flex-1 space-y-1">
<div className="flex flex-col flex-1 px-4 mt-16 lg:mt-6 min-h-0">
<nav className="flex-1 space-y-1 overflow-y-auto">
{navigation.map((item) => {
if (item.children) {
// Collapsible Group
@@ -283,7 +283,7 @@ export default function Layout({ children }: LayoutProps) {
})}
</nav>
<div className={`mt-2 border-t border-gray-200 dark:border-gray-800 pt-4 ${isCollapsed ? 'hidden' : ''}`}>
<div className={`mt-2 border-t border-gray-200 dark:border-gray-800 pt-4 flex-shrink-0 ${isCollapsed ? 'hidden' : ''}`}>
<div className="text-xs text-gray-500 dark:text-gray-500 text-center mb-2 flex flex-col gap-0.5">
<span>Version {health?.version || 'dev'}</span>
{health?.git_commit && health.git_commit !== 'unknown' && (
@@ -306,7 +306,7 @@ export default function Layout({ children }: LayoutProps) {
{/* Collapsed Logout */}
{isCollapsed && (
<div className="mt-2 border-t border-gray-200 dark:border-gray-800 pt-4 pb-4">
<div className="mt-2 border-t border-gray-200 dark:border-gray-800 pt-4 pb-4 flex-shrink-0">
<button
onClick={() => {
setMobileSidebarOpen(false)
@@ -333,9 +333,9 @@ export default function Layout({ children }: LayoutProps) {
)}
{/* Main Content */}
<main className={`flex-1 min-w-0 overflow-auto pt-16 lg:pt-0 flex flex-col transition-all duration-200 ${isCollapsed ? 'lg:ml-20' : 'lg:ml-64'}`}>
<main className={`flex-1 min-w-0 pt-16 lg:pt-0 flex flex-col transition-all duration-200 ${isCollapsed ? 'lg:ml-20' : 'lg:ml-64'}`}>
{/* Desktop Header */}
<header className="hidden lg:flex items-center justify-between px-8 h-20 bg-white dark:bg-dark-sidebar border-b border-gray-200 dark:border-gray-800 relative">
<header className="hidden lg:flex items-center justify-between px-8 h-20 bg-white dark:bg-dark-sidebar border-b border-gray-200 dark:border-gray-800 sticky top-0 z-10">
<div className="w-1/3 flex items-center gap-4">
<button
onClick={() => setIsCollapsed(!isCollapsed)}
@@ -359,8 +359,10 @@ export default function Layout({ children }: LayoutProps) {
<ThemeToggle />
</div>
</header>
<div className="p-4 lg:p-8 max-w-7xl mx-auto w-full">
{children}
<div className="flex-1 overflow-y-auto">
<div className="p-4 lg:p-8 max-w-7xl mx-auto w-full">
{children}
</div>
</div>
</main>
</div>