Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions public/logo.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
10 changes: 8 additions & 2 deletions src/app/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { Metadata } from "next";
import { Geist, Geist_Mono } from "next/font/google";
import { Geist, Geist_Mono, Roboto } from "next/font/google";
import "./globals.css";

const geistSans = Geist({
Expand All @@ -12,6 +12,12 @@ const geistMono = Geist_Mono({
subsets: ["latin"],
});

const roboto = Roboto({
weight: ['400', '700'],
subsets: ['latin'],
display: 'swap',
});

export const metadata: Metadata = {
title: "Create Next App",
description: "Generated by create next app",
Expand All @@ -24,7 +30,7 @@ export default function RootLayout({
}>) {
return (
<html lang="en">
<body className={`${geistSans.variable} ${geistMono.variable}`}>
<body className={`${geistSans.variable} ${geistMono.variable} ${roboto.className}`}>
{children}
</body>
</html>
Expand Down
11 changes: 7 additions & 4 deletions src/app/page.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
import { Container } from '@mui/material';
import HeroSection from '../components/features/landing/HeroSection';

import Navbar from '../components/features/landing/Navbar';

export default function LandingPage() {
return (
<Container>
<HeroSection />
</Container>
<>
<Navbar />
<Container>
<HeroSection />
</Container>
</>
);
}
152 changes: 152 additions & 0 deletions src/components/features/landing/Navbar.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
'use client';

import Image from 'next/image';
import Link from 'next/link';
import { useState } from 'react';

import {
AppBar,
Toolbar,
Box,
Stack,
IconButton,
Drawer,
useMediaQuery,
useTheme,
} from '@mui/material';
import MenuIcon from '@mui/icons-material/Menu';
import CloseIcon from '@mui/icons-material/Close';
import { NavItemProps } from './navbar/NavItem';
import { MobileDrawer } from './navbar/MobileDrawer';
import { DesktopNavItems } from './navbar/DesktopNavItems';
import { AuthButton } from './navbar/AuthButton';

const navItems: NavItemProps[] = [
{ href: '/home', text: 'Home', width: 75, textWidth: 43 },
{ href: '/products', text: 'Products', width: 98, textWidth: 66 },
{ href: '/pricing', text: 'Pricing', width: 83, textWidth: 51 },
{ href: '/blogs', text: 'Blogs', width: 73, textWidth: 41 },
{ href: '/features', text: 'Features', width: 95, textWidth: 63 },
{ href: '/about', text: 'About Us', width: 98, textWidth: 66 },
];

export default function Navbar() {
const [mobileOpen, setMobileOpen] = useState(false);
const theme = useTheme();
const isMobile = useMediaQuery(theme.breakpoints.down('md'));

const handleDrawerToggle = () => {
setMobileOpen(!mobileOpen);
};

return (
<AppBar
position="static"
color="transparent"
elevation={0}
sx={{
height: 80,
backgroundColor: '#fff',
mb: '100px',
}}
>
<Toolbar
disableGutters
sx={{
width: '100%',
maxWidth: 1920,
px: { xs: '20px', md: '240px' },
py: '20px',
mx: 'auto'
}}
>
{/* Logo */}
<Box
sx={{
display: 'flex',
alignItems: 'center',
margin: '2px 0',
}}
>
<Link href="/" aria-label="Dispatch AI Home">
<Image
src="/logo.svg"
alt="Dispatch AI logo"
width={152}
height={36}
style={{
cursor: 'pointer',
display: 'block',
}}
/>
</Link>
</Box>

{/* Desktop Nav */}
{!isMobile && <DesktopNavItems navItems={navItems} />}

{/* Desktop Buttons */}
{!isMobile && (
<Stack
direction="row"
spacing={0}
sx={{
alignItems: 'center',
marginLeft: 'auto'
}}
>
<AuthButton variant="login" />
<AuthButton variant="signup" />
</Stack>
)}

{/* Mobile Menu Button */}
{isMobile && (
<IconButton
color="inherit"
aria-label="toggle drawer"
edge="start"
onClick={handleDrawerToggle}
sx={{
ml: 'auto',
zIndex: (theme) => theme.zIndex.drawer + 1,
transition: 'transform 0.3s ease',
transform: mobileOpen ? 'rotate(90deg)' : 'rotate(0deg)',
backgroundColor: '#f5f5f5',
borderRadius: '12px',
width: 40,
height: 40,
'&:hover': {
backgroundColor: '#F5F5F5',
},
}}
>
{mobileOpen ? <CloseIcon fontSize="medium" /> : <MenuIcon fontSize="medium" />}
</IconButton>
)}
</Toolbar>

{/* Mobile Drawer */}
<Drawer
variant="temporary"
anchor="right"
open={mobileOpen}
onClose={handleDrawerToggle}
ModalProps={{
keepMounted: true,
}}
sx={{
display: { xs: 'block', md: 'none' },
'& .MuiDrawer-paper': {
boxSizing: 'border-box',
width: 240,
padding: '20px',
transition: 'transform 0.3s ease-in-out',
},
}}
>
<MobileDrawer handleDrawerToggle={handleDrawerToggle} navItems={navItems} />
</Drawer>
</AppBar>
);
}
98 changes: 98 additions & 0 deletions src/components/features/landing/navbar/AuthButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
'use client';

import { Button, Typography } from '@mui/material';
import NextLink from 'next/link';

interface AuthButtonProps {
variant: 'login' | 'signup';
isMobile?: boolean;
onClick?: () => void;
}

export function AuthButton({
variant,
isMobile = false,
onClick,
}: AuthButtonProps) {
const isLogin = variant === 'login';

const desktopStyles = {
login: {
wrapper: {
width: 73,
height: 40,
padding: '10px 16px',
borderRadius: '12px',
backgroundColor: '#fff',
marginRight: '12px',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
'&:hover': { backgroundColor: '#F5F5F5' },
},
text: {
width: 41,
height: 20,
fontFamily: 'Roboto',
fontSize: 16,
fontWeight: 'bold',
lineHeight: 1.25,
color: '#060606',
},
},
signup: {
wrapper: {
width: 89,
height: 40,
padding: '10px 16px',
borderRadius: '12px',
backgroundColor: '#060606',
marginLeft: '12px',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
'&:hover': { backgroundColor: '#333' },
},
text: {
maxWidth: 57,
fontFamily: 'Roboto',
fontSize: 16,
fontWeight: 'bold',
lineHeight: 1.25,
color: '#fff',
},
},
};

const mobileWrapper = {
px: 2,
py: 1,
borderRadius: '12px',
backgroundColor: isLogin ? '#fff' : '#060606',
color: isLogin ? '#060606' : '#fff',
fontSize: 16,
fontWeight: 'bold',
textTransform: 'none',
};

return (
<Button
component={NextLink}
href={`/${variant}`}
disableRipple
onClick={onClick}
sx={{
...(isMobile ? mobileWrapper : desktopStyles[variant].wrapper),
textTransform: 'none',
}}
>
{isMobile ? (
isLogin ? 'Login' : 'Sign Up'
) : (
<Typography sx={desktopStyles[variant].text}>
{isLogin ? 'Login' : 'Sign Up'}
</Typography>
)}
</Button>
);
}
24 changes: 24 additions & 0 deletions src/components/features/landing/navbar/DesktopNavItems.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { Stack } from '@mui/material';
import { NavItem, NavItemProps } from './NavItem';

interface DesktopNavItemsProps {
navItems: NavItemProps[];
}

export function DesktopNavItems({ navItems }: DesktopNavItemsProps) {
return (
<Stack
direction="row"
spacing={0}
sx={{
flex: 1,
justifyContent: 'center',
alignItems: 'center'
}}
>
{navItems.map((item) => (
<NavItem key={item.href} {...item} />
))}
</Stack>
);
}
37 changes: 37 additions & 0 deletions src/components/features/landing/navbar/MobileDrawer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { Box, List, ListItem} from '@mui/material';
import { NavItem, NavItemProps } from './NavItem';
import { AuthButton } from './AuthButton';

interface MobileDrawerProps {
handleDrawerToggle: () => void;
navItems: NavItemProps[];
}

export function MobileDrawer({ handleDrawerToggle, navItems }: MobileDrawerProps) {
return (
<Box
sx={{
textAlign: 'center',
height: '100%',
display: 'flex',
flexDirection: 'column',
justifyContent: 'center',
paddingTop: 6,
paddingBottom: 6,
}}
>
<List sx={{ flexGrow: 1 }}>
{navItems.map((item) => (
<ListItem key={item.href} sx={{ justifyContent: 'center', mb: 1.5 }}>
<NavItem {...item} handleDrawerToggle={handleDrawerToggle} />
</ListItem>
))}
</List>

<Box sx={{ display: 'flex', flexDirection: 'column', gap: 2, alignItems: 'center', mb: 6 }}>
<AuthButton variant="login" isMobile onClick={handleDrawerToggle} />
<AuthButton variant="signup" isMobile onClick={handleDrawerToggle} />
</Box>
</Box>
);
}
Loading