Archived course lesson
Add MainNavbar
Objective: Create a navigation bar for the top of the webapp.
Now that we have a footer, let’s make our navbar which will be the primary way that users can switch between different pages. Our navbar will have to sections that we divide with a flexbox, the left side will have a logo, title, and description while the right side will have a set of menu buttons that will take us to different pages.
We import our <Header> component from the <Layout> component just like we did with the <Footer>. We created a styled version of our header that we call <StyledHeader>. We use flexbox so that the title and menu sections of our navbar will dynamically stretch with the browser size and we also set a bottom border to create a nice visual divide between the navbar and the content section of our page.
Our <TitleContainer> component contains the logo image, title and description. We use @media queries so that when the size gets too small, it will disappear to leave room for the menu bar to take up the entire space.
The <StyledMenu> component has a single menu item that goes to the home page when clicked. We can add most of our styles there, but due to some issues I had with getting the menu line-height property to work in the styled component, I was forced to add it as a style prop to the component itself.
For any links I use which are internal to the site, I use the next/link package instead of using an <a> tag. This ensures that we can get nice client-side navigation without any hard refreshes or page flashes.
import styled from 'styled-components';
import { Layout, Menu } from 'antd';
import Link from 'next/link';
const { Header } = Layout;
const TitleContainer = styled.div`
${({ theme }) => `
background-color: ${theme['header-color']};
width: 50%;
display: flex;
align-items: center;
@media (max-width: 890px){
visibility: hidden;
width: 0;
}
`}
`;
const Title = styled.div`
${({ theme }) => `
text-align: left;
display: flex;
line-height: 50px;
div {
width: 100%;
padding-left: ${theme['padding-small']};
}
h2 {
display: inline;
color: inherit;
}
img {
width: 64px;
}
p {
line-height: 0;
}
`}
`;
const StyledHeader = styled(Header)`
${({ theme }) => `
background-color: ${theme['header-color']};
border-bottom-color: ${theme['header-border-color']};
border-bottom-right: 1px;
border-bottom-style: solid;
text-align: right;
display: flex;
li {
font-size: ${theme['font-size-md']};
}
`}
`;
const StyledMenu = styled(Menu)`
border-bottom-width: 0px;
width: 50%;
@media (max-width: 890px) {
width: 100%;
}
`;
export const MainNavbar = () => (
<StyledHeader>
<TitleContainer>
<Title>
<img src="/logo.svg" alt="Next Chop Logo" />
<div>
<h2>The Next Chop</h2>
<p>A recipe discovery app powered by Next.js</p>
</div>
</Title>
</TitleContainer>
<StyledMenu theme="light" mode="horizontal" style={{ lineHeight: '64px' }}>
<Menu.Item key="/">
<Link href="/">
<a>Home</a>
</Link>
</Menu.Item>
</StyledMenu>
</StyledHeader>
);
Now that we’ve created the MainNavbar we need to import it in the MainLayout like so:
import { ThemeProvider } from 'styled-components';
import { Component, ReactNode } from 'react';
import { theme } from '../../utils/theme';
import { GlobalStyle } from '../../utils/globalStyle';
import Head from 'next/head';
import { Layout } from 'antd';
import { MainFooter } from './MainFooter';
import { MainNavbar } from './MainNavbar';
const { Content } = Layout;
const MainHead = ({ title }: { title: string }) => (
<Head>
<title>{title}</title>
<meta charSet="utf-8" />
<meta name="viewport" content="initial-scale=1.0, width=device-width" />
<meta
name="description"
content="A recipe discovery app powered by Next.js."
/>
<meta name="author" content="codemochi" />
<meta name="keyword" content="next, react, typescript, js" />
<meta property="og:type" content="website" />
<meta property="og:title" content={title} />
<meta property="og:url" content="https://next-chop.codemochi.com" />
<meta property="og:image" content="/logo.svg" />
<meta
property="og:description"
content="A recipe discovery app powered by Next.js."
/>
<link
rel="apple-touch-icon"
sizes="180x180"
href="/favicon/apple-touch-icon.png"
/>
<link
rel="icon"
sizes="32x32"
type="image/png"
href="/favicon/favicon-32x32.png"
/>
<link
rel="icon"
sizes="16x16"
type="image/png"
href="/favicon/favicon-16x16.png"
/>
<link rel="manifest" href="/favicon/site.webmanifest" />
</Head>
);
type Props = {
children: ReactNode;
title?: string;
};
export class MainLayout extends Component<Props> {
render() {
const { title, children } = this.props;
return (
<ThemeProvider theme={theme}>
<MainHead title={title} />
<GlobalStyle />
<Layout>
<MainNavbar />
<Content>{children}</Content>
<MainFooter />
</Layout>
</ThemeProvider>
);
}
}