Layouts
Layout components and patterns for consistent page structure and responsive design
Layout Architecture
WI-CARPOOL uses a flexible layout system that adapts to different user types and screen sizes, providing consistent navigation and content organization.
📱 Responsive Design
Mobile-first approach with breakpoints for all screen sizes.
🎛️ Dashboard Layouts
Specialized layouts for passenger and driver dashboards.
🧭 Consistent Navigation
Unified navigation patterns across all application areas.
🔄 State Management
Layout state persistence and responsive sidebar management.
Main Layout Components
Root Layout
The main application layout that wraps all pages with navigation and theme providers.
App Layout Structure
import { Outlet } from "react-router-dom"
import { Navbar } from "@/components/Navbar"
import { Footer } from "@/components/Footer"
import { Toaster } from "@/components/ui/sonner"
import { ThemeProvider } from "@/components/ThemeProvider"
function RootLayout() {
return (
<ThemeProvider defaultTheme="system" storageKey="carpool-theme">
<div className="min-h-screen flex flex-col">
<Navbar />
<main className="flex-1">
<Outlet />
</main>
<Footer />
<Toaster />
</div>
</ThemeProvider>
)
}
Dashboard Layout
Specialized layout for user dashboards with sidebar navigation.
Dashboard Layout Implementation
import { SidebarProvider, SidebarInset } from "@/components/ui/sidebar"
import { DashboardSidebar } from "@/components/dashboard/DashboardSidebar"
import { DashboardHeader } from "@/components/dashboard/DashboardHeader"
interface DashboardLayoutProps {
children: React.ReactNode
userType: "passenger" | "driver"
}
function DashboardLayout({ children, userType }: DashboardLayoutProps) {
return (
<SidebarProvider>
<div className="min-h-screen flex w-full">
<DashboardSidebar userType={userType} />
<SidebarInset>
<DashboardHeader />
<div className="flex-1 space-y-4 p-4 md:p-8">
{children}
</div>
</SidebarInset>
</div>
</SidebarProvider>
)
}
Responsive Layout Patterns
Container Patterns
Standardized container components for consistent content width and spacing.
Container Component
import { cn } from "@/lib/utils"
interface ContainerProps {
children: React.ReactNode
className?: string
size?: "sm" | "md" | "lg" | "xl" | "full"
}
function Container({ children, className, size = "lg" }: ContainerProps) {
const sizeClasses = {
sm: "max-w-2xl",
md: "max-w-4xl",
lg: "max-w-6xl",
xl: "max-w-7xl",
full: "max-w-full"
}
return (
<div className={cn(
"mx-auto px-4 sm:px-6 lg:px-8",
sizeClasses[size],
className
)}>
{children}
</div>
)
}
Grid Layouts
Responsive grid systems for organizing content cards and lists.
Responsive Grid Component
interface GridProps {
children: React.ReactNode
cols?: {
default?: number
sm?: number
md?: number
lg?: number
xl?: number
}
gap?: number
className?: string
}
function Grid({
children,
cols = { default: 1, md: 2, lg: 3 },
gap = 4,
className
}: GridProps) {
const gridClasses = [
`grid`,
`gap-${gap}`,
cols.default && `grid-cols-${cols.default}`,
cols.sm && `sm:grid-cols-${cols.sm}`,
cols.md && `md:grid-cols-${cols.md}`,
cols.lg && `lg:grid-cols-${cols.lg}`,
cols.xl && `xl:grid-cols-${cols.xl}`,
].filter(Boolean).join(" ")
return (
<div className={cn(gridClasses, className)}>
{children}
</div>
)
}
// Usage example
function RidesList({ rides }) {
return (
<Container>
<Grid cols={{ default: 1, md: 2, xl: 3 }}>
{rides.map(ride => (
<RideCard key={ride.id} ride={ride} />
))}
</Grid>
</Container>
)
}
Sidebar Layouts
Dashboard Sidebar
Navigation sidebar with collapsible sections and user-specific menu items.
Dashboard Sidebar Component
import {
Sidebar,
SidebarContent,
SidebarGroup,
SidebarHeader,
SidebarMenu,
SidebarMenuButton,
SidebarMenuItem,
} from "@/components/ui/sidebar"
import {
Car,
Calendar,
CreditCard,
MessageSquare,
Settings,
User
} from "lucide-react"
interface DashboardSidebarProps {
userType: "passenger" | "driver"
}
export function DashboardSidebar({ userType }: DashboardSidebarProps) {
const passengerItems = [
{ title: "Dashboard", url: "/passenger/dashboard", icon: User },
{ title: "Find Rides", url: "/passenger/find-ride", icon: Car },
{ title: "My Trips", url: "/passenger/trips", icon: Calendar },
{ title: "Messages", url: "/passenger/messages", icon: MessageSquare },
{ title: "Wallet", url: "/passenger/wallet", icon: CreditCard },
{ title: "Settings", url: "/passenger/settings", icon: Settings },
]
const driverItems = [
{ title: "Dashboard", url: "/driver/dashboard", icon: User },
{ title: "Post Ride", url: "/driver/post-ride", icon: Car },
{ title: "My Rides", url: "/driver/rides", icon: Calendar },
{ title: "Messages", url: "/driver/messages", icon: MessageSquare },
{ title: "Earnings", url: "/driver/earnings", icon: CreditCard },
{ title: "Vehicle", url: "/driver/vehicle", icon: Car },
{ title: "Settings", url: "/driver/settings", icon: Settings },
]
const items = userType === "passenger" ? passengerItems : driverItems
return (
<Sidebar variant="inset">
<SidebarHeader>
<div className="flex items-center gap-2 px-4 py-2">
<Car className="h-6 w-6" />
<span className="font-semibold">WI-CARPOOL</span>
</div>
</SidebarHeader>
<SidebarContent>
<SidebarGroup>
<SidebarMenu>
{items.map((item) => (
<SidebarMenuItem key={item.title}>
<SidebarMenuButton asChild>
<Link to={item.url}>
<item.icon />
<span>{item.title}</span>
</Link>
</SidebarMenuButton>
</SidebarMenuItem>
))}
</SidebarMenu>
</SidebarGroup>
</SidebarContent>
</Sidebar>
)
}
Mobile Navigation
Mobile-optimized navigation with bottom tab bar.
Mobile Bottom Navigation
import { Link, useLocation } from "react-router-dom"
import { cn } from "@/lib/utils"
import {
Home,
Search,
Calendar,
MessageSquare,
User
} from "lucide-react"
const navigationItems = [
{ name: "Home", href: "/", icon: Home },
{ name: "Search", href: "/search", icon: Search },
{ name: "Trips", href: "/trips", icon: Calendar },
{ name: "Messages", href: "/messages", icon: MessageSquare },
{ name: "Profile", href: "/profile", icon: User },
]
function MobileNavigation() {
const location = useLocation()
return (
<nav className="fixed bottom-0 left-0 right-0 bg-white border-t border-gray-200 md:hidden">
<div className="grid grid-cols-5">
{navigationItems.map((item) => {
const isActive = location.pathname === item.href
return (
<Link
key={item.name}
to={item.href}
className={cn(
"flex flex-col items-center py-2 px-1 text-xs",
isActive
? "text-primary bg-primary/10"
: "text-gray-600 hover:text-primary"
)}
>
<item.icon className="h-5 w-5 mb-1" />
<span>{item.name}</span>
</Link>
)
})}
</div>
</nav>
)
}
Page Layout Patterns
Split Layout
Two-column layout with sidebar content and main content area.
Split Layout Component
interface SplitLayoutProps {
sidebar: React.ReactNode
children: React.ReactNode
sidebarWidth?: "sm" | "md" | "lg"
}
function SplitLayout({
sidebar,
children,
sidebarWidth = "md"
}: SplitLayoutProps) {
const widthClasses = {
sm: "w-64",
md: "w-80",
lg: "w-96"
}
return (
<div className="flex h-full">
<aside className={cn(
"hidden lg:block border-r border-gray-200 bg-gray-50",
widthClasses[sidebarWidth]
)}>
{sidebar}
</aside>
<main className="flex-1 overflow-hidden">
{children}
</main>
</div>
)
}
Card Layout
Card-based layout for organizing related content sections.
Card Layout Example
function ProfilePage() {
return (
<Container>
<div className="space-y-6">
<div className="flex items-center justify-between">
<h1 className="text-3xl font-bold">Profile</h1>
<Button>Edit Profile</Button>
</div>
<Grid cols={{ default: 1, lg: 3 }} gap={6}>
<div className="lg:col-span-2 space-y-6">
<Card>
<CardHeader>
<CardTitle>Personal Information</CardTitle>
</CardHeader>
<CardContent>
<!-- Personal info form -->
</CardContent>
</Card>
<Card>
<CardHeader>
<CardTitle>Preferences</CardTitle>
</CardHeader>
<CardContent>
<!-- Preferences form -->
</CardContent>
</Card>
</div>
<div className="space-y-6">
<Card>
<CardHeader>
<CardTitle>Profile Picture</CardTitle>
</CardHeader>
<CardContent>
<!-- Profile picture upload -->
</CardContent>
</Card>
<Card>
<CardHeader>
<CardTitle>Quick Stats</CardTitle>
</CardHeader>
<CardContent>
<!-- Stats display -->
</CardContent>
</Card>
</div>
</Grid>
</div>
</Container>
)
}
Layout Utilities
Layout Context
Context for managing layout state across components.
Layout Context Implementation
import { createContext, useContext, useState } from "react"
interface LayoutContextType {
isSidebarOpen: boolean
toggleSidebar: () => void
isMobile: boolean
setIsMobile: (mobile: boolean) => void
}
const LayoutContext = createContext<LayoutContextType | undefined>(undefined)
export function LayoutProvider({ children }: { children: React.ReactNode }) {
const [isSidebarOpen, setIsSidebarOpen] = useState(true)
const [isMobile, setIsMobile] = useState(false)
const toggleSidebar = () => setIsSidebarOpen(!isSidebarOpen)
return (
<LayoutContext.Provider value={{
isSidebarOpen,
toggleSidebar,
isMobile,
setIsMobile
}}>
{children}
</LayoutContext.Provider>
)
}
export function useLayout() {
const context = useContext(LayoutContext)
if (!context) {
throw new Error("useLayout must be used within a LayoutProvider")
}
return context
}
Responsive Hooks
Custom hooks for responsive layout management.
Responsive Layout Hooks
import { useState, useEffect } from "react"
export function useBreakpoint() {
const [breakpoint, setBreakpoint] = useState("lg")
useEffect(() => {
const updateBreakpoint = () => {
const width = window.innerWidth
if (width < 640) setBreakpoint("sm")
else if (width < 768) setBreakpoint("md")
else if (width < 1024) setBreakpoint("lg")
else if (width < 1280) setBreakpoint("xl")
else setBreakpoint("2xl")
}
updateBreakpoint()
window.addEventListener("resize", updateBreakpoint)
return () => window.removeEventListener("resize", updateBreakpoint)
}, [])
return breakpoint
}
export function useViewport() {
const [viewport, setViewport] = useState({
width: window.innerWidth,
height: window.innerHeight
})
useEffect(() => {
const updateViewport = () => {
setViewport({
width: window.innerWidth,
height: window.innerHeight
})
}
window.addEventListener("resize", updateViewport)
return () => window.removeEventListener("resize", updateViewport)
}, [])
return viewport
}
Best Practices
Performance
- Use CSS Grid and Flexbox for layout instead of JavaScript calculations
- Implement virtual scrolling for long lists
- Lazy load off-screen content
- Optimize layout shifts with consistent dimensions
Accessibility
- Use semantic HTML elements for proper structure
- Implement skip links for keyboard navigation
- Ensure focus management in complex layouts
- Provide alternative navigation methods
Responsive Design
- Follow mobile-first design principles
- Use relative units for flexible layouts
- Test across different screen sizes and orientations
- Implement progressive enhancement