Spaces:
Sleeping
Sleeping
| import React from 'react'; | |
| import { Outlet, NavLink, useLocation } from 'react-router-dom'; | |
| import { | |
| LayoutDashboard, | |
| Map, | |
| FileText, | |
| MessageSquare, | |
| Settings, | |
| Bell, | |
| Search, | |
| Droplets, | |
| HelpCircle, | |
| FileSearch | |
| } from 'lucide-react'; | |
| import { cn } from '@/src/utils/cn'; | |
| import { Button } from './ui/Button'; | |
| import { Input } from './ui/Input'; | |
| export function Layout() { | |
| const location = useLocation(); | |
| const isAIAssistant = location.pathname === '/ai-assistant'; | |
| const isGisMap = location.pathname === '/map'; | |
| const navItems = [ | |
| { name: 'Dashboard', path: '/', icon: LayoutDashboard }, | |
| { name: 'GIS Map', path: '/map', icon: Map }, | |
| { name: 'GR Finder', path: '/gr-finder', icon: FileSearch }, | |
| { name: 'GR Helper', path: '/ai-assistant', icon: MessageSquare }, | |
| { name: 'FAQ', path: '/faq', icon: HelpCircle }, | |
| { name: 'Repository', path: '/repository', icon: FileText }, | |
| ]; | |
| return ( | |
| <div className="flex h-screen w-full bg-slate-50 overflow-hidden"> | |
| {/* Desktop Sidebar */} | |
| <aside className="hidden md:flex w-64 flex-col border-r border-slate-200 bg-white shrink-0"> | |
| <div className="flex h-16 items-center px-6 border-b border-slate-200"> | |
| <Droplets className="h-6 w-6 text-blue-600 mr-2" /> | |
| <span className="text-xl font-bold text-slate-900 tracking-tight">JalDrishti</span> | |
| </div> | |
| <nav className="flex-1 space-y-1 px-3 py-4 overflow-y-auto"> | |
| {navItems.map((item) => { | |
| const Icon = item.icon; | |
| const isActive = location.pathname === item.path; | |
| return ( | |
| <NavLink | |
| key={item.name} | |
| to={item.path} | |
| className={cn( | |
| "flex items-center px-3 py-2.5 text-sm font-medium rounded-md transition-colors", | |
| isActive | |
| ? "bg-blue-50 text-blue-700" | |
| : "text-slate-700 hover:bg-slate-100 hover:text-slate-900" | |
| )} | |
| > | |
| <Icon className={cn("mr-3 h-5 w-5", isActive ? "text-blue-700" : "text-slate-400")} /> | |
| {item.name} | |
| </NavLink> | |
| ); | |
| })} | |
| </nav> | |
| <div className="p-4 border-t border-slate-200"> | |
| <div className="flex items-center"> | |
| <div className="h-8 w-8 rounded-full bg-blue-100 flex items-center justify-center text-blue-700 font-bold text-xs"> | |
| SD | |
| </div> | |
| <div className="ml-3"> | |
| <p className="text-sm font-medium text-slate-900">Swapnil Joshi</p> | |
| <p className="text-xs text-slate-500">WRD Main Incharge</p> | |
| </div> | |
| </div> | |
| </div> | |
| </aside> | |
| {/* Main Content */} | |
| <main className="flex-1 flex flex-col min-w-0 overflow-hidden pb-16 md:pb-0"> | |
| {/* Header */} | |
| <header className="flex h-14 md:h-16 items-center justify-between border-b border-slate-200 bg-white px-4 sm:px-6 lg:px-8 shrink-0"> | |
| <div className="flex items-center flex-1"> | |
| <div className="md:hidden flex items-center mr-4"> | |
| <Droplets className="h-6 w-6 text-blue-600 mr-2" /> | |
| <span className="text-lg font-bold text-slate-900 tracking-tight">JalDrishti</span> | |
| </div> | |
| <div className="w-full max-w-lg hidden sm:flex items-center relative"> | |
| <Search className="absolute left-2.5 top-2.5 h-4 w-4 text-slate-400" /> | |
| <Input | |
| type="search" | |
| placeholder="Search GRs, Acts, Circulars..." | |
| className="w-full bg-slate-50 pl-9 border-none focus-visible:ring-1 focus-visible:ring-blue-500" | |
| /> | |
| </div> | |
| </div> | |
| <div className="flex items-center space-x-2 md:space-x-4"> | |
| <Button variant="ghost" size="icon" className="relative text-slate-500 h-9 w-9"> | |
| <Bell className="h-5 w-5" /> | |
| <span className="absolute top-1.5 right-1.5 h-2 w-2 rounded-full bg-red-500 ring-2 ring-white"></span> | |
| </Button> | |
| <Button variant="ghost" size="icon" className="text-slate-500 h-9 w-9 hidden sm:flex"> | |
| <Settings className="h-5 w-5" /> | |
| </Button> | |
| <div className="h-8 w-8 rounded-full bg-blue-100 flex items-center justify-center text-blue-700 font-bold text-xs md:hidden ml-2"> | |
| SD | |
| </div> | |
| </div> | |
| </header> | |
| {/* Page Content */} | |
| <div | |
| className={cn( | |
| 'flex-1 bg-slate-50/50', | |
| (isAIAssistant || isGisMap) ? 'overflow-hidden p-0 sm:p-0 lg:p-0' : 'overflow-auto p-3 sm:p-6 lg:p-8' | |
| )} | |
| > | |
| <Outlet /> | |
| </div> | |
| </main> | |
| {/* Mobile Bottom Navigation */} | |
| <nav className="md:hidden fixed bottom-0 left-0 right-0 bg-white border-t border-slate-200 flex justify-around items-center h-16 z-50 pb-safe"> | |
| {navItems.map((item) => { | |
| const Icon = item.icon; | |
| const isActive = location.pathname === item.path; | |
| return ( | |
| <NavLink | |
| key={item.name} | |
| to={item.path} | |
| className={cn( | |
| "flex flex-col items-center justify-center w-full h-full space-y-1 transition-colors", | |
| isActive ? "text-blue-600" : "text-slate-500 hover:text-slate-900" | |
| )} | |
| > | |
| <Icon className={cn("h-5 w-5", isActive ? "fill-blue-50/50" : "")} /> | |
| <span className="text-[10px] font-medium">{item.name}</span> | |
| </NavLink> | |
| ); | |
| })} | |
| </nav> | |
| </div> | |
| ); | |
| } | |