見出し画像

Nuxt × TypeScript でTodoListとユーザ認証を実装してFirebase Hostingにデプロイ [Tutorial - Part 3/5 - Bulmaを使ってデザインを整える]

概要

Nuxt×TypeScriptでTodoListを実装し、Firebase Hostingにデプロイするチュートリアルです。簡単なCRUD(Create, Read, Update, Delete)アプリを作成することで、NuxtとTypeScriptの概要を掴んでもらうことが目的です。


Part2までに、環境構築とTodoListの実装を行いました。このPart3では、BulmaというCSSフレームワークを使ってデザインを整えていきます。


上がPart2までの完成物で、このPart3の完成物は下記です。



1. 環境構築

Part2までのソースーコードは下記です。必要な方は適宜cloneして下さい。

今回は feature/design というブランチ名で開発します。

# ブランチを切る
$ git checkout -b feature/design
# VS Code でディレクトリを開く
$ code .

create-nuxt-app でプロジェクトを作成する段階で bulma をインストールしていましたが、更に FontAwesome (アイコンを簡単に使えるようになるツール)と node-sass、sass-loader (CSSが綺麗に書けるようなるツール) も一応入れておきます。package.json の全体を下記に示します。

# package.json
{
  "name": "nuxt-ts-app-tkugimot",
  "version": "1.0.0",
  "description": "My breathtaking Nuxt.js project",
  "author": "tkugimot",
  "private": true,
  "scripts": {
    "dev": "nuxt",
    "build": "nuxt build",
    "start": "nuxt start",
    "generate": "nuxt generate",
    "lint": "eslint --ext .js,.vue --ignore-path .gitignore .",
    "precommit": "npm run lint",
    "test": "jest"
  },
  "dependencies": {
    "@nuxtjs/axios": "^5.3.6",
    "@nuxtjs/bulma": "^1.2.1",
    "@nuxtjs/pwa": "^2.6.0",
    "cross-env": "^5.2.0",
    "node-sass": "^4.5.2",
    "nuxt": "^2.4.0",
    "vuex-class": "^0.3.2",
    "nuxt-fontawesome": "^0.4.0",
    "@fortawesome/free-solid-svg-icons": "^5.8.1",
    "@fortawesome/fontawesome-svg-core": "^1.2.17",
    "@fortawesome/vue-fontawesome": "^0.1.6",
    "sass-loader": "^7.1.0",
    "ts-node": "^8.1.0",
    "vue-property-decorator": "^7.3.0"
  },
  "devDependencies": {
    "@nuxt/typescript": "^2.6.3",
    "@nuxtjs/eslint-config": "^0.0.1",
    "@vue/test-utils": "^1.0.0-beta.27",
    "babel-core": "7.0.0-bridge.0",
    "babel-eslint": "^10.0.1",
    "babel-jest": "^24.1.0",
    "eslint": "^5.15.1",
    "eslint-config-prettier": "^4.1.0",
    "eslint-config-standard": ">=12.0.0",
    "eslint-loader": "^2.1.2",
    "eslint-plugin-import": ">=2.16.0",
    "eslint-plugin-jest": ">=22.3.0",
    "eslint-plugin-node": ">=8.0.1",
    "eslint-plugin-nuxt": ">=0.4.2",
    "eslint-plugin-prettier": "^3.0.1",
    "eslint-plugin-promise": ">=4.0.1",
    "eslint-plugin-standard": ">=4.0.0",
    "eslint-plugin-vue": "^5.2.2",
    "jest": "^24.1.0",
    "nodemon": "^1.19.0",
    "prettier": "^1.16.4",
    "vue-jest": "^3.0.3"
  }
}

package.json の修正を終えたら、npm update を実行します。

その後、nuxt.config.ts を下記のように修正します。

# nuxt.config.ts
import NuxtConfiguration from '@nuxt/config'

const config: NuxtConfiguration = {
  head: {
    title: 'nuxt-ts-app-tkugimot',
    meta: [
      { charset: 'utf-8' },
      { name: 'viewport', content: 'width=device-width, initial-scale=1' },
      { hid: 'description', name: 'description', content: 'Nuxt TS project' }
    ],
    link: [{ rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' }]
  },
  loading: { color: '#3B8070' },
  css: [
  ],
  modules: [
    '@nuxtjs/bulma',
    'nuxt-fontawesome'
  ],
  fontawesome: {
    imports: [
      {
        set: '@fortawesome/free-solid-svg-icons',
        icons: ['fas']
      }
    ]
  }
}

export default config;


これで bulma, fontAwesome, sass を使う準備は終わりです。


2. layout の準備とデザインの適用

layout/default.vue にデフォルトのデザインを準備します。このレイアウトは全ての pages/ 以下のデザインに適用されます。

# layouts/default.vue
<template>
  <div>
    <section class="hero is-primary">
        <div class="hero-body">
            <div class="container">
                <h1 class="title">
                    Nuxt TS App - tkugimot
                </h1>
                <p class="subtitle">
                    Very Easy Todo List
                </p>
                <font-awesome-icon icon="coffee" />
            </div>
        </div>
    </section>
    <Nuxt />
  </div>
</template>

<style lang="scss">
    .hero {
        .hero-body {
            .container {
                .subtitle {
                    font-weight: bold;
                    display: inline;
                }
            }
        }
    }
</style>

上記のファイルを準備して npm run dev を実行します。

localhost:3000 にブラウザからアクセスして下記のように正常に表示されれば、無事にきちんと環境構築を終えていることが分かります。(fontAwesomeとsassに関してはわりと無理矢理使ってる感じはありますが...)


これだけでもかなり綺麗になりました。


3. TodoList 部分へのデザインの適用

まずTodoを追加する部分である NewTodo.vue のデザインを修正します。

# components/NewTodo.vue
<template>
    <div class="container">
        <div class="field is-three-fifths">
          <div class="control">
            <input class="input new-todo-input is-rounded" type="text" @keyup.enter="addTodo" placeholder="Write new TODO..." />
          </div>
        </div>
    </div>
</template>

<script lang="ts">
import { Component, Vue, Prop } from 'vue-property-decorator'
import * as todos from '~/store/modules/todos'
import { namespace } from 'vuex-class'
const Todos = namespace(todos.name)

@Component
export default class NewTodo extends Vue {
  @Todos.Action addTodo
}
</script>

<style lang="scss">
  .field {
    margin-top: 20px;
  }
  .new-todo-input {
    display: block;
    width: 80%;
    margin: 0 auto;
  }
</style>

するとこんな感じになります。


次に、TodoList.vue を修正します。

# components/TodoList.vue
<template>
    <div class="colmuns">
        <div class="column is-inline-block-desktop is-one-quarter" v-for="todo in allTodos" :key='todo.id'>
            <Todo :todo="todo" />
        </div>
    </div>
</template>

<script lang="ts">
import { Component, Vue } from 'vue-property-decorator';
import Todo from '~/components/Todo.vue';
import { namespace } from 'vuex-class';
import * as todos from '~/store/modules/todos';

const Todos = namespace(todos.name);

@Component({
    components: {
        Todo
    }
})
export default class TodoList extends Vue {
    @Todos.Getter allTodos
}
</script>

最後に、Todo.vue を修正します。

# components/Todo.vue
<template>
  <div class="card has-background-white-bis">
    <div class="card-content">
      <div class="field">
        <div class="control">
          <input class="input todo is-rounded" v-show="todo.isEditing" :id="todo.id" type="text" @keyup.enter="updateTodo" :value="todo.content" />
          <input disabled class="input todo is-rounded" v-show="!todo.isEditing" :id="todo.id" type="text" @keyup.enter="updateTodo" :value="todo.content" />
          <!-- <p v-show="!todo.isEditing">{{ todo.content }}</p> -->
        </div>
      </div>
    </div>
    <footer class="card-footer">
      <p class="card-footer-item">
        <button class="button is-info" v-show="!todo.isEditing" @click="editTodo(todo.id)">Edit</button>
        <button class="button is-info" v-show="todo.isEditing" @click="editTodo(todo.id)" disabled>Edit</button>
      </p>
      <p class="card-footer-item">
        <button class="button is-success" @click="removeTodo(todo.id)">DONE</button>
      </p>
    </footer>
  </div>
</template>

<script lang="ts">
import { Component, Vue, Prop } from 'vue-property-decorator'
import * as todos from '~/store/modules/todos'
import { namespace } from 'vuex-class'

const Todos = namespace(todos.name)

@Component
export default class Todo extends Vue {
  @Prop() todo

  @Todos.Action removeTodo
  @Todos.Action editTodo
  @Todos.Action updateTodo
}
</script>

<style lang="scss">
  .card {
    margin-top: 25px;
    
    .todo {
      font-size: 18px;
    }
  }
</style>


以上で終わりです。完成物はこのページの上部に貼ってあります。デザインセンスのない僕でも、非常に簡単にそこそこ綺麗なページを作成することが出来ました!( ͡° ͜ʖ ͡°)


次回の Part4 では、Firebase Hosting へのデプロイを扱います。












この記事が気に入ったらサポートをしてみませんか?