2023.02.25
Headerコンポーネント
と Headerコンポーネントで構成されるLaytoutコンポーネント
を作成します。// components/Header.tsx
import { AppBar, Box, Typography, Container, Divider } from '@mui/material';
import { NextMuiLink } from 'components/NextMuiLink';
export const Header = () => {
return (
<div>
<AppBar position='static' sx={{ boxShadow: `none`, backgroundColor: `#062127` }}>
<Container maxWidth='xl'>
<Box
sx={{
display: `flex`,
alignItems: `center`,
height: `70px`,
}}
>
<NextMuiLink href='/'>
<Typography sx={{ fontSize: `25px` }}>Wenpe Playground</Typography>
</NextMuiLink>
</Box>
</Container>
</AppBar>
<Divider light sx={{ borderColor: `rgba(211, 211, 211, .3)` }} />
</div>
);
};
// components/Layouts.tsx
import { ReactElement } from 'react';
import { Header } from 'components/Header';
type LayoutProps = Required<{
readonly children: ReactElement;
}>;
export const Layout = ({ children }: LayoutProps) => (
<>
<Header />
{children}
</>
);
// types/layout.ts
import type { ReactElement, ReactNode } from 'react';
import type { NextPage } from 'next';
import type { AppProps } from 'next/app';
export type NextPageWithLayout<P = {}, IP = P> = NextPage<P, IP> & {
getLayout?: (page: ReactElement) => ReactNode;
};
export type AppPropsWithLayout = AppProps & {
Component: NextPageWithLayout;
};
_app.tsx
を修正し、ページごとにレイアウトを変更できるようにします// pages/_app.tsx
import type { AppPropsWithLayout } from 'types/layout';
import PropTypes from 'prop-types';
import { ThemeProvider } from '@mui/material/styles';
import CssBaseline from '@mui/material/CssBaseline';
import { CacheProvider, EmotionCache } from '@emotion/react';
import theme from 'styles/theme';
import createEmotionCache from 'styles/createEmotionCache';
import nextSeoConfig from 'nextSeoConfig';
import { DefaultSeo } from 'next-seo';
// Client-side cache, shared for the whole session of the user in the browser.
const clientSideEmotionCache = createEmotionCache();
interface MyAppProps extends AppPropsWithLayout {
emotionCache?: EmotionCache;
}
function MyApp(props: MyAppProps) {
const { Component, emotionCache = clientSideEmotionCache, pageProps } = props;
const getLayout = Component.getLayout ?? ((page) => page);
return getLayout(
<CacheProvider value={emotionCache}>
<DefaultSeo {...nextSeoConfig} />
<ThemeProvider theme={theme}>
{/* CssBaseline kickstart an elegant, consistent, and simple baseline to build upon. */}
<CssBaseline />
<Component {...pageProps} />
</ThemeProvider>
</CacheProvider>,
);
}
MyApp.propTypes = {
Component: PropTypes.elementType.isRequired,
emotionCache: PropTypes.object,
pageProps: PropTypes.object.isRequired,
};
export default MyApp;
getLayout
を呼び出し、ページごとのレイアウトを定義しますimport type { ReactElement } from 'react';
import type { InferGetStaticPropsType } from 'next';
import type { NextPageWithLayout } from 'types/layout';
import { client } from 'libs/client';
import type { Blog, Tag } from 'types/blog';
import { Container, Grid } from '@mui/material';
import { BlogCard } from 'components/BlogCard';
import { NextMuiLink } from 'components/NextMuiLink';
import { Layout } from 'components/Laytout';
// Get blog and tags data
export const getStaticProps = async () => {
const blog = await client.get({ endpoint: 'blog' });
const tag = await client.get({ endpoint: 'tag' });
return {
props: {
blogs: blog.contents,
tags: tag.contents,
},
};
};
type Props = {
blogs: Blog[];
tags: Tag[];
};
const Home: NextPageWithLayout<InferGetStaticPropsType<typeof getStaticProps>> = ({
blogs,
}: Props) => {
return (
<div>
<Container maxWidth='xl' sx={{ marginTop: `20px` }}>
<Grid container rowSpacing={2} columnSpacing={2}>
{blogs.map((blog) => (
<Grid key={blog.id} item xs={12} md={6} lg={4}>
<NextMuiLink href={`/blog/${blog.id}`}>
<BlogCard
imagePath={blog.image.image.url}
imageAlt='Image Not Found'
title={blog.title}
tags={blog.tags}
></BlogCard>
</NextMuiLink>
</Grid>
))}
</Grid>
</Container>
</div>
);
};
Home.getLayout = function getLayout(page: ReactElement) {
return <Layout>{page}</Layout>;
};
export default Home;
© 2023 Wenpe