MVP Build
This commit is contained in:
130
frontend/src/components/Layout.tsx
Normal file
130
frontend/src/components/Layout.tsx
Normal file
@@ -0,0 +1,130 @@
|
||||
/**
|
||||
* @ai-summary Main layout component with navigation
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { useAuth0 } from '@auth0/auth0-react';
|
||||
import { Link, useLocation } from 'react-router-dom';
|
||||
import { useAppStore } from '../core/store';
|
||||
import { Button } from '../shared-minimal/components/Button';
|
||||
import { clsx } from 'clsx';
|
||||
|
||||
interface LayoutProps {
|
||||
children: React.ReactNode;
|
||||
}
|
||||
|
||||
export const Layout: React.FC<LayoutProps> = ({ children }) => {
|
||||
const { user, logout } = useAuth0();
|
||||
const { sidebarOpen, toggleSidebar } = useAppStore();
|
||||
const location = useLocation();
|
||||
|
||||
const navigation = [
|
||||
{ name: 'Vehicles', href: '/vehicles', icon: '🚗' },
|
||||
{ name: 'Fuel Logs', href: '/fuel-logs', icon: '⛽' },
|
||||
{ name: 'Maintenance', href: '/maintenance', icon: '🔧' },
|
||||
{ name: 'Gas Stations', href: '/stations', icon: '🏪' },
|
||||
];
|
||||
|
||||
return (
|
||||
<div className="min-h-screen bg-gray-50">
|
||||
{/* Sidebar */}
|
||||
<div className={clsx(
|
||||
'fixed inset-y-0 left-0 z-50 w-64 bg-white shadow-lg transform transition-transform duration-200 ease-in-out',
|
||||
sidebarOpen ? 'translate-x-0' : '-translate-x-full'
|
||||
)}>
|
||||
<div className="flex items-center justify-between h-16 px-6 border-b border-gray-200">
|
||||
<h1 className="text-xl font-bold text-gray-900">MotoVaultPro</h1>
|
||||
<button
|
||||
onClick={toggleSidebar}
|
||||
className="p-2 rounded-md text-gray-400 hover:text-gray-500 hover:bg-gray-100"
|
||||
>
|
||||
<span className="sr-only">Close sidebar</span>
|
||||
✕
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<nav className="mt-6">
|
||||
<div className="px-3">
|
||||
{navigation.map((item) => (
|
||||
<Link
|
||||
key={item.name}
|
||||
to={item.href}
|
||||
className={clsx(
|
||||
'group flex items-center px-3 py-2 text-sm font-medium rounded-md mb-1 transition-colors',
|
||||
location.pathname.startsWith(item.href)
|
||||
? 'bg-primary-50 text-primary-700'
|
||||
: 'text-gray-600 hover:bg-gray-50 hover:text-gray-900'
|
||||
)}
|
||||
>
|
||||
<span className="mr-3 text-lg">{item.icon}</span>
|
||||
{item.name}
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div className="absolute bottom-0 left-0 right-0 p-4 border-t border-gray-200">
|
||||
<div className="flex items-center">
|
||||
<div className="flex-shrink-0">
|
||||
<div className="w-8 h-8 bg-primary-100 rounded-full flex items-center justify-center">
|
||||
<span className="text-primary-600 font-medium text-sm">
|
||||
{user?.name?.charAt(0) || user?.email?.charAt(0)}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className="ml-3 flex-1 min-w-0">
|
||||
<p className="text-sm font-medium text-gray-900 truncate">
|
||||
{user?.name || user?.email}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<Button
|
||||
variant="secondary"
|
||||
size="sm"
|
||||
className="w-full mt-3"
|
||||
onClick={() => logout({ logoutParams: { returnTo: window.location.origin } })}
|
||||
>
|
||||
Sign Out
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Main content */}
|
||||
<div className={clsx(
|
||||
'transition-all duration-200 ease-in-out',
|
||||
sidebarOpen ? 'ml-64' : 'ml-0'
|
||||
)}>
|
||||
{/* Top bar */}
|
||||
<header className="bg-white shadow-sm border-b border-gray-200">
|
||||
<div className="flex items-center justify-between h-16 px-6">
|
||||
<button
|
||||
onClick={toggleSidebar}
|
||||
className="p-2 rounded-md text-gray-400 hover:text-gray-500 hover:bg-gray-100"
|
||||
>
|
||||
<span className="sr-only">Open sidebar</span>
|
||||
☰
|
||||
</button>
|
||||
<div className="text-sm text-gray-500">
|
||||
Welcome back, {user?.name || user?.email}
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
{/* Page content */}
|
||||
<main className="p-6">
|
||||
<div className="max-w-7xl mx-auto">
|
||||
{children}
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
|
||||
{/* Backdrop */}
|
||||
{sidebarOpen && (
|
||||
<div
|
||||
className="fixed inset-0 z-40 bg-gray-600 bg-opacity-75 lg:hidden"
|
||||
onClick={toggleSidebar}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
Reference in New Issue
Block a user