今回達成すること
プロジェクトページを作成します。
プロジェクト内の各メニューは、Vuetifyのナビゲーションドロワーを使って表示します。
完成イメージ

メインコンテンツを表示するコンポーネントを作成する
コンテンツを表示する際の余白を各ページ同じ幅にしたいので、コンテナの役割をするコンポーネントファイルを作成します。
「components/loggedIn」ディレクトリ直下に、
root $ touch front/components/loggedIn/loggedInContainer.vue
v-containerを導入します。
front/components/loggedIn/loggedInContainer.vue
<template>
  <v-container fluid>
    <slot name="my-content" />
  </v-container>
</template>
<script>
export default {
}
</script>
slot... このスロット内にプロジェクトのコンテンツを差し込みます。
プロジェクトのメニューページを作成する
続いてプロジェクトの各メニューページを作成します。
Nuxt.jsが生成するリンク
Nuxt.jsでパラメーターによって表示する内容を動的に変更したい場合、アンダーバー(_)を付けたVueファイル、もしくはディレクトリを用意することで動的なリンクが生成されます。
params.id が「1」の場合、生成されるリンク
front/pages/project
└── _id
    ├── components.vue  # /project/1/components
    ├── dashboard.vue   # /project/1/dashboard
    ├── help.vue        # /project/1/help
    ├── layouts.vue     # /project/1/layouts
    ├── pages.vue       # /project/1/pages
    └── settings.vue    # /project/1/settings
プロジェクトメニューのディレクトリ構造
このリンクを生成するために、
- 「pages」ディレクトリ内に
 - 「project」ディレクトリを作成し、
 - さらにその下に「_id」ディレクトリを作成します。
 
「_id」ディレクトリ内には、上記に記載した6つのプロジェクトメニューページを用意します。
root $ mkdir -p front/pages/project/_id && touch $_/{components.vue,dashboard.vue,help.vue,layouts.vue,pages.vue,settings.vue}
作成した6つのファイルは、ここでは編集しないので仮編集だけしておきましょう。
front/pages/project/_id/components.vue, dashboard.vue, help.vue, layouts.vue, pages.vue, settings.vue
<template>
  <logged-in-container #my-content>
    {{ $route.fullPath }}
  </logged-in-container>
</template>
<script>
export default {
}
</script>
確認してみよう
コンテナを起動して、トップページからプロジェクトリンクをクリックしてください。
ちゃんとページが表示されていますね。OK!次へ進みましょう。

プロジェクトページ用のヘッダーを作成する
プロジェクトページで表示するヘッダーコンポーネントを作成します。
このヘッダーには、
- ツールバーと
 - ナビゲーションドロワーを
 
設置します。
「components/loggedIn」ディレクトリ内に
root $ touch front/components/loggedIn/loggedInHeader.vue
front/components/loggedIn/loggedInHeader.vue
<template>
  <div>
    <logged-in-nav-drawer />
    <logged-in-app-bar />
  </div>
</template>
<script>
export default {
}
</script>
レイアウトファイルにヘッダーを追加する
プロジェクトページで使用するレイアウトファイルの
まるっと書き換えてください。
front/layouts/default.vue
<template>
  <v-app>
    <logged-in-header />
    <v-main>
      <nuxt />
    </v-main>
  </v-app>
</template>
<script>
export default {
}
</script>
- 
<v-main>... コンテンツ領域を指定する。このタグで囲まないと、コンテンツがドロワーやツールバーに隠れてしまいます。
 
ナビゲーションドロワーを作成する
プロジェクトメニューを表示するナビゲーションドロワーを作成します。
「components」ディレクトリ内の「loggedIn/header」に、
root $ touch front/components/loggedIn/header/loggedInNavDrawer.vue
作成したファイルにVuetifyの<v-navigation-drawer>を導入します。
front/components/loggedIn/header/loggedInNavDrawer.vue
<template>
  <v-navigation-drawer
    app
    clipped
    mobile-breakpoint="960"
  >
    <v-list>
      <v-divider />
      <v-list-item
        href="https://blog.cloud-acct.com/categories/udemy"
        target="_blank"
      >
        <v-list-item-icon>
          <v-icon>
            mdi-open-in-new
          </v-icon>
        </v-list-item-icon>
        <v-list-item-content>
          <v-list-item-title>
            このアプリの作り方
          </v-list-item-title>
        </v-list-item-content>
      </v-list-item>
    </v-list>
  </v-navigation-drawer>
</template>
<script>
export default {
}
</script>
- 
clipped... ナビゲーションドロワーをツールバーの下に表示する。このキーを付けていないと下のようにツールバーの横に表示されます。

 - 
mobile-breakpoint="960"... ウィンドウ幅が960px未満の場合にドロワーを閉じる。デフォルトは1264pxでドロワーが開閉します。
 
確認してみよう
ここまでに、プロジェクトページの
- コンテナコンポーネント
 - ツールバー
 - ナビゲーションドロワー
 - ツールバーとナビゲーションドロワーをまとめたヘッダーコンポーネント
 
を作成しました。
これらが正しく表示されているかブラウザで確認してみましょう。
ウィンドウ幅が960px以上で http://localhost:8080/project/2/dashboard にアクセスしてください。

おお!いい感じ♩
ナビゲーションドロワーの開閉ボタンを追加する
このままではナビゲーションドロワーが閉じたまま開くことができません。
そこでナビゲーションドロワーを開いたり閉じたりするボタンを追加します。
手順としては、
- ツールバーにボタンの追加し、
 - ヘッダーに
drawerフラグを用意。 - ナビゲーションドロワーに開閉を指示する、
v-modelを追加します。 
1. ツールバーにボタンを追加する
ツールバーにボタンを差し込むため、slotを追加しましょう。
front/components/loggedIn/header/loggedInAppBar.vue
<template>
  <v-app-bar
    app
    dense
    elevation="1"
    clipped-left
    color="white"
  >
    <!-- 追加 -->
    <slot name="nav-icon" />
    <nuxt-link
      to="/"
      class="text-decoration-none"
    >
    ...
slotを使用して、<v-app-bar-nav-icon>を追加します。
front/components/loggedIn/loggedInHeader.vue
<template>
  <div>
    <logged-in-nav-drawer />
    <!-- 書き換え -->
    <logged-in-app-bar #nav-icon>
      <v-app-bar-nav-icon />
    </logged-in-app-bar>
    <!-- <logged-in-app-bar /> -->
  </div>
</template>
...
ロゴの隣にボタンが表示されました。

2. ヘッダーにドロワー開閉フラグを用意する
ボタンをクリックすることで、開閉するクリックイベントも追加します。
front/components/loggedIn/loggedInHeader.vue
<template>
  <div>
    <logged-in-nav-drawer />
    <!-- @click 追加 -->
    <logged-in-app-bar #nav-icon>
      <v-app-bar-nav-icon
        @click="drawer = !drawer"
      />
    </logged-in-app-bar>
  </div>
</template>
<script>
export default {
  // 追加
  data () {
    return {
      drawer: null
    }
  }
}
</script>
まだこれではナビゲーションドロワーの開閉イベントは動きません。
このフラグとドロワーを連動させる必要があります。
3. ナビゲーションドロワーにv-modelを追加する
用意したdrawerフラグを、ナビゲーションドロワーに送ってv-modelに追加します。
まずは、
front/components/loggedIn/loggedInHeader.vue
<template>
  <div>
    <!-- drawer.sync 追加 -->
    <logged-in-nav-drawer
      :drawer.sync="drawer"
    />
    ...
  </div>
</template>
...
フラグを受け取るpropsとv-modelを追加します。
front/components/loggedIn/header/loggedInNavDrawer.vue
<template>
  <!-- v-model 追加 -->
  <v-navigation-drawer
    v-model="setDrawer"
    app
    clipped
    mobile-breakpoint="960"
  >
    ...
</template>
<script>
export default {
  // 以下、追加
  props: {
    drawer: {
      type: Boolean,
      default: null
    }
  },
  computed: {
    setDrawer: {
      get () { return this.drawer },
      set (val) { return this.$emit('update:drawer', val) }
    }
  }
}
</script>
親子コンポーネント間の双方向データバインディングについてはこちらの記事で解説しています。
確認してみよう
ボタンをクリックして、ナビゲーションドロワーが開閉しているか確認してみましょう。
またウィンドウ幅が960px未満になった場合でも、ドロワーが開くかを確認してください。
ナビゲーションドロワーにメニューリンクを表示する
最後の作業です。
ナビゲーションドロワーにメニューリンクを追加しましょう。
メニューリストを追加する
front/components/loggedIn/header/loggedInNavDrawer.vue
<template>
  <v-navigation-drawer
    v-model="setDrawer"
    app
    clipped
    mobile-breakpoint="960"
  >
    <v-list>
      <!-- 追加 -->
      <v-list-item
        v-for="(nav, i) in navMenus"
        :key="`nav-${i}`"
        :to="$my.projectLinkTo($route.params.id, nav.name)"
      >
        <v-list-item-icon>
          <v-icon v-text="nav.icon" />
        </v-list-item-icon>
        <v-list-item-content>
          <v-list-item-title>
            {{ $my.pageTitle(nav.name) }}
          </v-list-item-title>
        </v-list-item-content>
      </v-list-item>
      <!-- ここまで -->
      <v-divider />
      ...
  </v-navigation-drawer>
</template>
<script>
export default {
  props: {
    drawer: {
      type: Boolean,
      default: null
    }
  },
  // data () 追加
  data () {
    return {
      navMenus: [
        { name: 'project-id-dashboard', icon: 'mdi-view-dashboard' },
        { name: 'project-id-layouts', icon: 'mdi-view-compact' },
        { name: 'project-id-pages', icon: 'mdi-image' },
        { name: 'project-id-components', icon: 'mdi-view-comfy' },
        { name: 'project-id-settings', icon: 'mdi-cog' },
        { name: 'project-id-help', icon: 'mdi-help-circle' }
      ]
    }
  },
  // ここまで
  computed: {
    ...
}
</script>
i18nの日本語化データを追加する
このままでは、メニュー名が正しく表示されないので、
front/locales/ja.json
{
  ...
  "pages": {
    ...
    "account": {
      "settings": "アカウント設定",
      "password": "パスワード変更"
    },
    // 追加
    "project": {
      "id": {
        "dashboard": "ダッシュボード",
        "layouts": "レイアウト",
        "pages": "ページ",
        "components": "コンポーネント",
        "settings": "設定",
        "help": "ヘルプ"
      }
    }
  }
}
上手くいきましたねー。

5時です。家に帰りましょう。
コミットしとく
今回の作業は以上です。
コミットしておきましょう。
root $ cd front
front $ git add -A
front $ git commit -m "add_navigation_drawer"
front $ cd ..
root $
まとめ
今回はプロジェクトページを作成し、ナビゲーションドロワーを追加しました。
長かった。うん、長かったの一言です。
次回は?
今回作成したプロジェクトページの共通設定ファイルを作成します。
あとはパンくずリストも追加しましょうね。
それではまた明日。