Next.js + Chakra UI で簡易ダッシュボード構築してみた

# 概要
Next.js に UIコンポーネントライブラリの Chakra UI を導入し、簡単なダッシュボードの作成をやってみるという内容の記事です。
※ 今回は、どちらかというと Chakra UI のコンポーネントの使い方を中心に確認したものですので、外部との通信などはありませんし、コンポーネントの分け方などのアーキテクチャについても詳しくは触れません。

以下サイトを調べまくりながら構築していきましたので貼っておきます！
- [Chakra UI 公式サイト](https://chakra-ui.com/)
- [React Icons 公式サイト](https://react-icons.github.io/react-icons)

完成イメージ
![スクリーンショット 2021-08-14 9.38.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1815178/bdc84146-639a-301b-4fe8-74ec7016b99f.png)


## 実行環境

- Node.js 16.5.0
- yarn 1.22.11
- React 17.0.2
- Next.js 11.0.1
- Chakra UI 1.6.6
- React Icons 4.2.0

## 環境構築
まずは開発環境から

1 . Next.js のインストール
（今回はnext-chakra-dashboard というプロジェクト名で作成しました）

```zsh
% yarn create next-app　next-chakra-dashboard
```
2 . Chakra UI のインストール及びセットアップ
`cd next-chakra-dashboard` でプロジェクト直下に入り

```zsh
% yarn add @chakra-ui/react @emotion/react@^11 @emotion/styled@^11 framer-motion@^4
```

`pages`ディレクトリ内にある`_app.js`を以下のように編集

```pages/_app.js
import { ChakraProvider } from "@chakra-ui/react"

function MyApp({ Component, pageProps }) {
  return (
    <ChakraProvider>
      <Component {...pageProps} />
    </ChakraProvider>
  )
}

export default MyApp
```
これでChakra UIの設定は完了です。

3 . React Icons のインストール
後々にアイコンを使う予定なので、この時点でインストールしておきましょう！

```zsh
% yarn add react-icons
```
４ . 設定がうまくいっているか確認
確認のために `pages/index.js`を以下のように編集（少し影のある青い正方形の角を丸くした箱の中にGitHubのアイコンを設置したものを記述）

```pages/index.js
import { Flex } from "@chakra-ui/react";
import { FaGithub } from "react-icons/fa";

export default function Home() {
  return (
    <Flex
      m="10"
      w="100px"
      h="10vh"
      bg="blue.500"
      boxShadow="md"
      rounded="lg"
      align="center"
      justify="center"
    >
      <FaGithub color="white" size="3em" />
    </Flex>
  );
}
```
確認のためサーバーを起動（プロジェクトディレクトリ直下で実行）

```zsh
% yarn dev
```
ターミナルに`compiled successfully`が表示されてから、ブラウザで`localhost:3000`にアクセスすると以下のような画面が見ることが出来るかと思います。確認ができましたら初期設定が完了です！
![スクリーンショット 2021-08-10 17.01.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1815178/53954c51-0b46-1d6b-b67c-ce5483bb870a.png)

# ダッシュボードっぽいもの構築開始

再度、目標物の確認

![スクリーンショット 2021-08-14 9.38.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1815178/bdc84146-639a-301b-4fe8-74ec7016b99f.png)


サイドナビがある２カラムのダッシュボードを作ってみましょう！
それぞれのコンポーネント内の文言やアイコンは架空のものも含まれますので、細かな部分はご容赦ください。

## サイドナビから作っていきましょう！
プロジェクトの直下に `components`ディレクトリを作成して、その中に`SideNav.js`ファイルを作成してください。
サイドナビでは、[Flex](https://chakra-ui.com/docs/layout/flex) 、[Heading](https://chakra-ui.com/docs/typography/heading)、[Text](https://chakra-ui.com/docs/typography/text)、[Image](https://chakra-ui.com/docs/media-and-icons/image)　コンポーネントをを使っています。各種コンポーネントには `<Box m="2">Tomato</Box>` の `m="2"` のような形でスタイルのプロップを渡すことでデザインの編集を行うことができます。
どういったプロップがあるかについては [公式サイト-StyleProps-](https://chakra-ui.com/docs/features/style-props) を参照ください。
では、先程作成した`SideNav.js`を以下のように記述してください。

```components/SideNav.js
import { Flex, Heading, Text, Image } from "@chakra-ui/react";
import { BsPlusSquare, BsNewspaper } from "react-icons/bs";
import { RiDoorOpenLine, RiMailStarLine } from "react-icons/ri";
import { CgProfile } from "react-icons/cg";
import companyIcon from "../public/hogehoge.png";

export default function SideNav() {
  return (
    <Flex w="20%" direction="column" align="center">
      <Flex direction="column" justify="space-between">
        <Flex mt="50" mb="100">
          <Image
            borderRadius="full"
            boxSize="60px"
            src={companyIcon.src}
            fallbackSrc="https://via.placeholder.com/150"
            alt="company icon"
          />
          <Heading ml="3" fontWeight="800" fontSize="xl" alignSelf="center">
            The Earth
          </Heading>
        </Flex>
        <Flex h="65vh" direction="column" justify="space-between">
          <Flex fontSize="xl" color="gray" align="center">
            <BsPlusSquare />
            <Text ml="3">Add Resume</Text>
          </Flex>
          <Flex
            h="20vh"
            mb="32"
            direction="column"
            align="flex-start"
            justify="space-around"
          >
            <Flex
              fontSize="xl"
              color="gray"
              align="center"
              fontWeight="800"
              bg="pink.50"
              p="3"
              m="-3"
              rounded="full"
            >
              <CgProfile color="pink" />
              <Text ml="3">My Profile</Text>
            </Flex>

            <Flex fontSize="xl" color="gray" align="center">
              <BsNewspaper color="#63B3ED" />
              <Text ml="3">Jobs</Text>
            </Flex>
            <Flex fontSize="xl" color="gray" align="center">
              <RiMailStarLine color="#ECC94B" />
              <Text ml="3">Employee</Text>
            </Flex>
          </Flex>
          <Flex fontSize="2xl" mb={30} color="gray" align="center">
            <RiDoorOpenLine />
            <Text ml={3} fontSize="md">
              Log out
            </Text>
          </Flex>
        </Flex>
      </Flex>
    </Flex>
  );
}
```
最初のImageコンポーネントに src として companyIcon を引き渡しているのですが、ご自身で public 直下に hogehoge.png を設置してください。無い場合は fallbackSrc が適用されるようになっておりますので、無くても大丈夫です。

では作成したSideNavを表示させてみましょう！
pages ディレクトリにある`index.js`を以下のように修正してください。

```pages/index.js
import { Flex, Divider, Center, Spacer } from "@chakra-ui/react";
import SideNav from "../components/SideNav";

export default function Home() {
  return (
    <Flex maxW="2000px" direction="row" overflow="hidden">
      <SideNav />
      <Center my="10" mr="8">
        <Divider orientation="vertical" />
      </Center>
    </Flex>
  );
}
```
ここでは、[Divider](https://chakra-ui.com/docs/data-display/divider)、[Center](https://chakra-ui.com/docs/layout/center)、[Spacer](https://chakra-ui.com/docs/layout/flex#flex-and-spacer-vs-grid-vs-stack) を新たに使っています。Divider は分割用の仕切り線です。
ではブラウザで、サイドナビが表示されていること確認してください。

### ここからは早送り
ここまでくると、後の要領は同じようなものなので、駆け足で作成していきます！
作るコンポーネントは次の５つです。

   - SearchBox : 検索用のインプットフィールド
   - BlogPostWithImage : サムネイル付きのブログ記事のダイジェストカード
   - ProfileCard : 丸いアバター付きのプロフィールカード
   - CompanyCard : 四角の会社ロゴがある情報を記述したカード
   - JobDescription : ３カラム構成でそれぞれに情報が書かれているカード
  
では早速それぞれのコンポーネントを`components`ディレクトリに作成していきましょう！
まずは `SearchBox.js`から

```components/SearchBox.js
import { Input } from "@chakra-ui/react";

export default function SearchBox() {
  return (
    <Input
      w="30%"
      type="text"
      placeholder="Search"
      color="blue.800"
      bg="blue.50"
      rounded="2xl"
      border="0"
      _focus={{
        bg: "blue.200",
        outline: "none",
      }}
    />
  );
}

```

続いて、`BlogPostWithImage.js`

```components/BlogPostWithImage.js
import pcImg from "../public/pc.jpg";
import { Box, Flex, Heading, Text, Stack, Avatar, Image } from "@chakra-ui/react";

export default function blogPostWithImage() {
  return (
    <Flex py="6" w="full" maxW="350px">
      <Box bg="white" boxShadow="xl" rounded="xl" p="6" overflow="hidden">
        <Box h="230px" mt="-6" mx="-6" pos="relative">
          <Image 
            src={pcImg.src} 
            fallbackSrc="https://via.placeholder.com/300x200"
            layout="fill" 
          />
        </Box>
        <Stack>
          <Text
            color="blue.500"
            fontWeight="800"
            fontSize="xs"
            letterSpacing="wide"
          >
            BLOG
          </Text>
          <Heading color="gray.700" fontSize="lg" fontFamily="body">
            Next.js + ChakraUI Dashboard
          </Heading>
          <Text color={"gray.500"} fontSize="sm">
            Chakra UI is a simple, modular and accessible component library that
            gives you the building blocks you need to build your React
            applications.
          </Text>
        </Stack>
        <Stack mt="6" direction="row" spacing="4" align="center">
          <Avatar
            src="https://gravatar.com/avatar/456e6f4841d1935a5383bd73a77a5a16?s=400&d=robohash&r=x"
            alt="Author"
          />
          <Stack direction="column" spacing="0" fontSize="sm">
            <Text fontWeight="600">Daisuke</Text>
            <Text color="gray.500">Aug 12, 2021 · 15min read</Text>
          </Stack>
        </Stack>
      </Box>
    </Flex>
  );
}
```
SideNav 同様に画像ファイルの設置が必要ですが、無い場合は `fallbackSrc` を適用します。

続いて、`ProfileCard.js`

```components/ProfileCard.js
import { Avatar, Text, Heading, Flex, Box } from "@chakra-ui/react";
import { BsPencil, BsPeopleFill, BsLink45Deg, BsBuilding } from "react-icons/bs";
import { FiMapPin } from "react-icons/fi";
import bgImg from "../public/hugahuga.png";

export default function ProfileCard() {
  return (
    <Flex w="full" h="160px" bg="blue.50" rounded="xl" boxShadow="md" mb="2">
      <Flex align="center" w="20%">
        <Avatar size="xl" mx="auto" src="https://bit.ly/kent-c-dodds" />
      </Flex>
      <Box
        w="70%"
        bgImage={bgImg.src}
        bgPosition="right"
        bgSize="220px"
        bgRepeat="no-repeat"
        mr="4"
      >
        <Flex align="center" my="5">
          <Heading pr="4" fontSize="2xl" color="gray.600">
            Daisuke Matsuura
          </Heading>
          <BsPencil color="#4d4d4d" />
        </Flex>
        <Flex mb="3" color="gray.500">
          <Flex align="center" w="35%">
            <FiMapPin />
            <Text pl="2">Osaka, JAPAN</Text>
          </Flex>
          <Flex align="center">
            <BsPeopleFill />
            <Text pl="2">1800+ connection </Text>
          </Flex>
        </Flex>
        <Flex mb="5" color="gray.500">
          <Flex align="center" w="35%">
            <BsLink45Deg />
            <Text pl="2">https://biz.can-ly.com/</Text>
          </Flex>
          <Flex align="center">
            <BsBuilding />
            <Text pl="2">Canly Co.,Ltd </Text>
          </Flex>
        </Flex>
      </Box>
    </Flex>
  );
}
```
今回、Box の背景画像として hugahuga.png を指定しているのですが、こちらの画像もご自身で用意いただいて設置お願いします。
そういえば、画像の読み込みをするときに、シンプルに `src={bgImg}` と記述していたのですが、読み込まれなくて、結構ハマりました... 
`src={bgImg.src}` と書かないといけないようです！気をつけましょう！！

では、最後に `JobDescription.js`です！

```components/JobDescription.js
import {Stack, Flex, Text, Box, Heading, SimpleGrid, Icon} from "@chakra-ui/react";
import { FcAssistant, FcBullish, FcCommandLine } from "react-icons/fc";

const Feature = ({ title, text, icon, bgColor }) => {
  return (
    <Stack align="center" shadow="md" p="5" rounded="md" bg={bgColor}>
      <Flex
        w="16"
        h="16"
        align="center"
        justify="center"
        rounded="full"
        bg="gray.100"
        mb="1"
      >
        {icon}
      </Flex>
      <Text fontWeight="600">{title}</Text>
      <Text color="gray.600" textAlign="justify" fontSize="xs" p="2">
        {text}
      </Text>
    </Stack>
  );
};

export default function JobDescription() {
  return (
    <Box
      w="full"
      mt="6"
      ml="5"
      p="6"
      boxShadow="xl"
      rounded="md"
      border="1px"
      borderColor="gray.50"
    >
      <Heading ml="2" mb="5" fontSize="xl">
        Job Description
      </Heading>
      <SimpleGrid columns="3" spacing="6">
        <Feature
          icon={<Icon as={FcAssistant} w="10" h="10" />}
          title="Customer Success"
          text="This is a position where you will work with customers who have implemented Canly to help them implement,
                 utilize, and create successful experiences, as well as solve problems. "
          bgColor="red.50"
        />
        <Feature
          icon={<Icon as={FcBullish} w="10" h="10" />}
          title="Marketing"
          text="This is a marketing position that will be responsible for generating leads for our company,
                which is rapidly growing in terms of users, and is in the phase of creating a marketing system from scratch with a focus on web marketing. "
          bgColor="cyan.50"
        />
        <Feature
          icon={<Icon as={FcCommandLine} w="10" h="10" />}
          title="Development"
          text="We are rebuilding our website into a SPA structure using Next.js. Along with that, we will be changing the server-side language from Laravel to Go.
                There will temporarily be two systems, one old and one new, but we are looking for someone to drive ..."
          bgColor="orange.50"
        />
      </SimpleGrid>
    </Box>
  );
};
```

以上で必要なコンポーネントの作成は終了です！
あとは　index.js で読み込んであげればOKですね！

```pages/index.js
import { Flex, Divider, Center, Spacer } from "@chakra-ui/react";
import { FaBell } from "react-icons/fa";
import SideNav from "../components/SideNav";
import SearchBox from "../components/SearchBox";
import BlogPostWithImage from "../components/BlogPostWithImage";
import ProfileCard from "../components/ProfileCard";
import CompanyCard from "../components/CompanyCard";
import JobDescription from "../components/JobDescription";

export default function Home() {
  return (
    <Flex maxW="2000px" direction="row" overflow="hidden">
      <SideNav />
      <Center my="10" mr="8">
        <Divider orientation="vertical" />
      </Center>
      <Flex direction="column" h="100vh" w="75%">
        <Flex direction="row" direction="space-between" my="10" align="center">
          <SearchBox />
          <Spacer />
          <FaBell size="2rem" color="#fcba03" />
        </Flex>
        <ProfileCard />
        <Flex mt="4" mr="6" templateColumns="repeat(6, 1fr)">
          <Flex direction="column" w="30%" mx="auto">
            <BlogPostWithImage />
            <BlogPostWithImage />
          </Flex>
          <Flex direction="column" w="70%">
            <CompanyCard />
            <JobDescription />
          </Flex>
        </Flex>
      </Flex>
    </Flex>
  );
}
```
以上で完成です！！一度ブラウザで確認してみてください！

# まとめ
今回は Chakra UI をお試しで触ってみるということを目標に簡易ダッシュボードのコーディングをやってみました！　ご覧の通りですが、レスポンシブ対応もやっていないし、デザイン部分でサボっている部分もたくさんあるため、画面スクロールできないように細工を施してありますw　一枚絵だと思ってください..
今回で全ての Chakura UI のコンポーネントを試せたわけではありませんし、全てのプロップを使えたわけではありませんでしたが、なんとなくどういうものなのかの感じが掴めたかなと思います！
皆さんも是非使ってみてください！
最後まで読んで頂きありがとうございました！