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 へのデプロイを扱います。
この記事が気に入ったらサポートをしてみませんか?