Nuxt.js + Vuetify でポートフォリオ作りたい その2

# はじめに

前回はこちら
[Nuxt.js + Vuetify でポートフォリオ作りたい その1](https://qiita.com/h-ueno2/items/0f6b98851b4297de6743)

だいぶ前回から間が空いてしまいました…。単純に本業であまり時間がとれなかったり、~~[世界救ってたり](https://jp.finalfantasyxiv.com/shadowbringers/)~~、~~[一狩りしてたり](http://www.capcom.co.jp/monsterhunter/world-iceborne/)~~でなかなか手が動かなかったのですが、ちょこちょことポートフォリオの続きを進めてみました。

前回から手を加えたのは以下のポイントです。

> + ツールバー周りを少しオシャレにする。
> + コンテンツをざっくりと作り込む。
>   * プロフィール用のページを作成。
>   * GitHubとQiitaのAPIから自分のアウトプットを取得して一覧表示。

ここまででできたページが以下となります。
~~https://my-portfolio-31932.web.app/~~
<img width="1280" alt="スクリーンショット 2019-08-18 22.43.48.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/83511/e5eefafc-ff19-4d3c-4f23-853ecd22eccb.png">

[GitHub リポジトリ](https://github.com/h-ueno2/my-portfolio)

# ツールバーを弄る

ツールバー周りをデフォルトのデザインから少し弄ってみました。
修正するソースは`layouts/default.js`となります。

```vue:default.js

<template>
  <v-app>
    <v-navigation-drawer
      v-model="drawer"
      :mini-variant="miniVariant"
      :clipped="clipped"
      :fixed="fixed"
      floating
      app
      height="auto"
    >
      <v-list>
        <v-list-tile
          v-for="(item, i) in items"
          :key="i"
          :to="item.to"
          router
          exact
          @click="drawer = !drawer"
        >
          <v-list-tile-action>
            <v-icon>{{ item.icon }}</v-icon>
          </v-list-tile-action>
          <v-list-tile-content>
            <v-list-tile-title v-text="item.title" />
          </v-list-tile-content>
        </v-list-tile>
      </v-list>
    </v-navigation-drawer>
    <v-toolbar :clipped-left="clipped" app :color="barColor">
      <v-toolbar-side-icon class="hidden-md-and-up" @click="drawer = !drawer" />
      <v-spacer />
      <v-toolbar-items class="hidden-sm-and-down">
        <v-btn
          v-for="(item, i) in items"
          :key="i"
          :to="item.to"
          text
          small
          color="transparent"
        >
          {{ item.title }}
        </v-btn>
      </v-toolbar-items>
      <v-spacer />
    </v-toolbar>
    <nuxt />
    <v-footer :fixed="fixed" app :color="barColor">
      <span>&copy; 2019 h-ueno</span>
    </v-footer>
  </v-app>
</template>

<script>
export default {
  data() {
    return {
      barColor: 'rgba(240,240,240,0.4)',
      clipped: true,
      drawer: false,
      fixed: false,
      items: [
        {
          icon: 'home',
          title: 'Home',
          to: '/'
        },
        {
          icon: 'person',
          title: 'Profile',
          to: '/profile'
        },
        {
          icon: 'list_alt',
          title: 'Articles',
          to: '/articles'
        }
      ],
      miniVariant: false,
      title: 'H-UENO'
    }
  }
}
</script>

<style lang="scss">
.v-content {
  background: hsl(0, 0%, 97%) url('~assets/cat.jpg');
  background-position: center center;
  background-repeat: no-repeat;
  background-size: cover;
  height: 100vh;
}
</style>
```

* ツールバーのカラーは`v-toolbar`コンポーネントの`color`属性に設定することで変更できます。

```vue
    <v-toolbar :clipped-left="clipped" app :color="barColor">
```

# コンテンツを作る

とりあえずガワは出来てきたような気がするので次にポートフォリオの中身となるコンテンツを作っていきたいと思います。
ひとまずサクッと出来そうなのは

* 自分の簡単なプロフィール
* アウトプットとしてこれまでの成果物があったほうが良いかも
 + 今はまだ少ないけど今後増やしていこう！という意思表示を込めてGitHubリポジトリとQiitaの投稿一覧を表示してみる。

の2点を作ってみました。

## プロフィールページ

とりあえずプロフィールページを作っていきます。

* 簡単な個人の情報
 + 生年月日とかなのでとりあえず固定で良いことにします。
* 履歴書がわりのこれまでの経歴
 + 形式化出来そうなので今後のメンテのことを考えてテキストファイルのJSONから引っ張ってくるようにします。

大元のページを`pages/profile.vue`として作成します。

```pages/profile.vue

<template>
  <v-content>
    <v-container class="contents-container">
      <v-layout wrap justify-center>
        <v-flex xs12 md10>
          <pesonal-info class="mb-2" />
          <history-info :histories="histories" />
        </v-flex>
      </v-layout>
    </v-container>
  </v-content>
</template>

<script>
import PersonalInfo from '~/components/molecule/PersonalInfo.vue'
import HistoryInfo from '~/components/molecule/HistoryInfo.vue'

export default {
  components: {
    'pesonal-info': PersonalInfo,
    'history-info': HistoryInfo
  },
  asyncData({ store }) {
    return {
      histories: store.getters['json/getHistories']
    }
  }
}
</script>

```

大きく分けて2つのコンポーネントに分けています。

* 個人情報を扱う`PersonalInfo`
* 経歴を扱う`HistoryInfo`

jsonデータの読み取りは[Nuxt.js(v2)で静的なJSONファイルを読み込み、いろんな所で使う。
](https://qiita.com/amishiro/items/b09f9038ee3ebfee33d4)の記事を参考にさせていただいています。


```javascript
asyncData({ store }) {
    return {
      histories: store.getters['json/getHistories']
    }
```

```json.js
import historyJson from '~/assets/json/history.json'

// State
export const state = () => ({
  histories: historyJson
})

// getters
export const getters = {
  getHistories(state) {
    return state.histories
  }
}
```

JSONファイルから読み込んだ情報は`HistoryInfo`コンポーネントに渡して表示させます。

```HistoryInfo.vue
<template>
  <v-card class="rounded-card pa-1" color="rgba(255, 167, 38, 0.7)">
    <v-card-title class="font-weight-bold display-1 my-0">History</v-card-title>
    <history-card
      v-for="(history, index) in histories"
      :key="index"
      :year="history.year"
      :month="history.month"
      :title="history.title"
      :description="history.description"
    />
  </v-card>
</template>

<script>
import HistoryCard from '~/components/atom/HistoryCard.vue'

export default {
  components: {
    'history-card': HistoryCard
  },
  props: {
    histories: {
      type: Array,
      required: true
    }
  }
}
</script>
```

```HistoryCard.vue
<template>
  <v-card class="ma-40" color="rgba(238, 238, 238, 0.8)">
    <v-card-title class="mb-0 pb-0 title">
      {{ year }}年{{ month }}月
    </v-card-title>
    <v-card-title class="title">
      {{ title }}
    </v-card-title>
    <v-card-text class="subtitle-1">{{ description }}</v-card-text>
  </v-card>
</template>

<script>
export default {
  name: 'HistoryCard',
  props: {
    year: {
      type: String,
      default: ''
    },
    month: {
      type: String,
      default: ''
    },
    title: {
      type: String,
      default: ''
    },
    description: {
      type: String,
      default: ''
    }
  }
}
</script>
```

作ってみて思った課題としては以下となります。

* 履歴情報に外部リンクを貼るなど詳細を表示できるようにしたい。
 + 在学時代の論文や特許情報へのリンクを貼りたい。
* スキルシート見たいなのがあったほうがよさそう。

## 記事ページ

記事ページではGitHubとQiitaのAPIを叩いて取得した情報を表示してみます。

<img width="1280" alt="スクリーンショット 2019-10-06 13.09.26.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/83511/54429fca-5d6f-fe9e-fb71-4c08ba0d458b.png">

まずは`pages/artcles.vue`を作成します。

```articles.vue
<template>
  <v-content>
    <v-container class="contents-container">
      <qiita-articles class="mb-2"></qiita-articles>
      <git-repositories></git-repositories>
    </v-container>
  </v-content>
</template>

<script>
import GitRepositories from '~/components/molecule/GitRepositories.vue'
import QiitaArticles from '~/components/molecule/QiitaArticles.vue'
export default {
  components: {
    'git-repositories': GitRepositories,
    'qiita-articles': QiitaArticles
  }
}
</script>
```

構成としては次の二つのコンポーネントに分かれています。

* Gitのリポジトリ情報の取得と表示を行う`GitRepositories`
* Qiitaの記事情報の取得と表示を行う`QiitaArticles`

両者ともAPIへのアクセスは`axios`を使用しています。

```GitRepositories.vue

<template>
  <v-card v-if="hasData" class="rounded-card" color="rgba(79, 195, 247, 0.7)">
    <v-card-title class="font-weight-bold display-1">
      GitHub Repositories
    </v-card-title>
    <v-layout row wrap>
      <v-flex v-for="(item, index) in items" :key="index" md4 sm6 xs12>
        <git-repository :item="item"></git-repository>
      </v-flex>
    </v-layout>
  </v-card>
</template>

<script>
import axios from 'axios'
import GitRepository from '~/components/atom/GitRepository.vue'
const baseUri = 'https://api.github.com/users/h-ueno2/repos'
export default {
  components: {
    'git-repository': GitRepository
  },
  data() {
    return {
      items: []
    }
  },
  computed: {
    hasData() {
      return this.items.length > 0
    }
  },
  async created() {
    // GitのAPIにアクセス
    this.items = await axios.get(baseUri).then(res => {
      return res.data
    })
  }
}
</script>
 ```


```QiitaArticles.vue
<template>
  <v-card v-if="hasData" class="rounded-card" color="rgba(165, 214, 167, 0.7)">
    <v-card-title class="font-weight-bold display-1">
      Qiita 投稿記事
    </v-card-title>
    <v-layout row wrap>
      <v-flex v-for="(item, index) in items" :key="index" md4 sm6 xs12>
        <qiita-article :item="item"></qiita-article>
      </v-flex>
    </v-layout>
  </v-card>
</template>

<script>
import QiitaArticle from '~/components/atom/QiitaArticle.vue'
import axios from 'axios'
// qiita api URL
const baseUri = 'https://qiita.com/api/v2/users/h-ueno2/items'
export default {
  components: {
    'qiita-article': QiitaArticle
  },
  data() {
    return {
      items: []
    }
  },
  computed: {
    hasData() {
      return this.items.length > 0
    }
  },
  async created() {
    // APIへのアクセス
    this.items = await axios.get(baseUri).then(res => {
      return res.data
    })
  }
}
</script>
```

作ってみての課題としては`async`周りがまだあまり理解しきれていない感がありますなぁ。とりあえず動いてみたけど、どういう仕組みなのか人に説明できるほど理解しきれていない状態...。
余力があれば読み込み中のクルクルとかつけてみたい。

# 参考資料

作成する上で表示に助けていただいた記事の方々になります！

+ [Vuetifyチュートリアル。CSSを書かないマテリアルデザイン](https://windii.jp/frontend/nuxt/vuetify-tutorial)
+ [Nuxt.jsでQiita API取得して一覧表示するアプリをFirebaseへデプロイするチュートリアル](https://thr3a.hatenablog.com/entry/20190407/1554621409)
+ [GitHubのレポジトリ一覧を取ってくるワンライナー](https://rcmdnk.com/blog/2017/10/03/computer-github/)