nuxt/color-mode で画面イメージを変えてみる

## Prologue

`nuxt/color-mode` という Dark モードと Light モードを切り替えられるモジュールを触ってみました。
bootstrap や UI-component にも興味があるので、応用できればという気持ちもあります。

## ドキュメント

- https://github.com/nuxt-community/color-mode-module
- https://color-mode.nuxtjs.org/

## 環境

- macOS: v10.15.6
- node.js: v12.18.2
- terminal: iTerm
- エディタ: VS Code
- パッケージマネージャ: `yarn`

## プロジェクト作成

`nuxt-color` という Nuxt.js のプロジェクトを用意します。

```
yarn create nuxt-app nuxt-color

create-nuxt-app v3.4.0
✨  Generating Nuxt.js project in nuxt-color
? Project name: nuxt-color
? Programming language: TypeScript
? Package manager: Yarn
? UI framework: Buefy
? Nuxt.js modules: Axios
? Linting tools: ESLint, Prettier
? Testing framework: None
? Rendering mode: Single Page App
? Deployment target: Server (Node.js hosting)
? Development tools: (Press <space> to select, <a> to toggle all, <i> to invert selection)
? Continuous integration: None
? Version control system: Git
yarn run v1.22.4
$ eslint --ext .js,.vue --ignore-path .gitignore . --fix
✨  Done in 9.93s.

🎉  Successfully created project nuxt-color

  To get started:

	cd nuxt-color
	yarn dev

  To build & start for production:

	cd nuxt-color
	yarn build
	yarn start


  For TypeScript users. 

  See : https://typescript.nuxtjs.org/cookbook/components/
✨  Done in 159.92s.
```


作成したプロジェクトに移動して起動すればOKです。

次に `@nuxtjs/color-mode` を追加します。

```
yarn add --dev @nuxtjs/color-mode
```

追加されたことを確認します。

``` package.json
// 略
  "dependencies": {
    "@nuxt/typescript-runtime": "^2.0.0",
    "@nuxtjs/axios": "^5.12.2",
    "core-js": "^3.6.5",
    "nuxt": "^2.14.6",
    "nuxt-buefy": "^0.4.3"
  },
  "devDependencies": {
    "@nuxt/types": "^2.14.6",
    "@nuxt/typescript-build": "^2.0.3",
    "@nuxtjs/color-mode": "^2.0.0",
    "@nuxtjs/eslint-config": "^3.1.0",
    "@nuxtjs/eslint-config-typescript": "^3.0.0",
    "@nuxtjs/eslint-module": "^2.0.0",
    "babel-eslint": "^10.1.0",
    "eslint": "^7.10.0",
    "eslint-config-prettier": "^6.12.0",
    "eslint-plugin-nuxt": "^1.0.0",
    "eslint-plugin-prettier": "^3.1.4",
    "prettier": "^2.1.2"
  }
}
```

`nuxt/color-mode` のドキュメント内に `buildModules` に追記するよう指示があるので、 `nuxt-config.js`　に以下のように追加します。

 ``` nuxt-config.js
  buildModules: [
    // https://go.nuxtjs.dev/typescript
    '@nuxt/typescript-build',
    '@nuxtjs/color-mode'
  ],
```

VCA化するため以下も追加します。こちらは `@nuxtjs/color-mode` を実装するにあたり特に関連性はないためスキップしても大丈夫です。

```
yarn add @vue/composition-api
```

`plugins/CompositionApi.ts` を作成し import を記載して一旦セットアップは終わりです。

## `Color.vue` component の作成

ドキュメント内にサンプルコードがあるので、そちらを使用してみます。

`/components/Color.vue` を新規作成します。

``` Color.vue
<template>
  <div>
    <h1>Color mode: {{ $colorMode.value }}</h1>
    <select v-model="$colorMode.preference">
      <option value="system">System</option>
      <option value="light">Light</option>
      <option value="dark">Dark</option>
      <option value="sepia">Sepia</option>
    </select>
  </div>
</template>

<style>
body {
  background-color: #fff;
  color: rgba(0,0,0,0.8);
  height: 100vh;
}
.dark-mode body {
  background-color: #091a28;
  color: #ebf4f1;
}
.sepia-mode body {
  background-color: #f1e7d0;
  color: #433422;
}
</style>
```

セットアップ時に `Buefy` を選択した場合、 `default.vue` に Navbar が用意されているため、そこに作成した component を追加してみます。

``` default.vue
<template>
  <div>
    <nav
      class="navbar header has-shadow is-primary"
      role="navigation"
      aria-label="main navigation"
    >
      <div class="navbar-brand">
        <a class="navbar-item" href="/">
          <img src="~assets/buefy.png" alt="Buefy" height="28" />
        </a>

        <div class="navbar-burger">
          <span />
          <span />
          <span />
        </div>
      </div>
      <Color /> // 追加
    </nav>

    // 略
  </div>
</template>

<script lang="ts">
import { defineComponent } from '@vue/composition-api';
import Color from '@/components/Color.vue';

export default defineComponent ({
  name: 'Menu',
  components: {
    Color
  },
  setup(){
    return {
      items: [
        {
          title: 'Home',
          icon: 'home',
          to: { name: 'index' },
        },
        {
          title: 'Inspire',
          icon: 'lightbulb',
          to: { name: 'inspire' },
        },
      ],
    }
  }
})
</script>
```

ロゴの隣に color 選択のプルダウンが表示されます。value を切り替えると背景などの色が切り替わります。

## scss を導入

もう少し現実的な運用を考えて scss を入れてみます。

```
yarn add -D sass-loader node-sass
```

`/components/Color.vue` の css 部分を書き換えてみます。
また、value と class 名が連動しているため、確認を兼ねて任意の名称に変更してみます。

```Color.vue
<template>
  <div>
    <h1>Color mode: {{ $colorMode.value }}</h1>
    <select v-model="$colorMode.preference">
      <option value="system">System</option>
      <option value="sunny">Sunny</option>
      <option value="night">Night</option>
      <option value="coffee">Coffee</option>
      <option value="flower">Flower</option>
    </select>
  </div>
</template>

<style lang="scss">
body {
  background-color: #fff;
  color: rgba(0,0,0,0.8);
  height: 100vh;
  .has-text-primary {
    color:blue !important;
  }
}
.night-mode body {
  background-color: #091a28;
  color: #ebf4f1;
  .has-text-primary {
    color:#091a28 !important;
  }
}
.coffee-mode body {
  background-color: #f1e7d0;
  color: #433422;
  .has-text-primary {
    color:#f1e7d0 !important;
  }
}
.flower-mode body {
  background-color: pink;
  color: green;
  .has-text-primary {
    color:green !important;
  }
}
</style>
```

選択した value をもとに color が切り替わっていればOKです。

以上です。

## Epilogue

非常に簡単に設置できました。
component として設置しても対応できるため、UI 作成や設置場所を考慮する必要もなく、また SFC で管理すれば保守性も上がると感じました。
唯一詰まった箇所は `value="system"` です。こちらは OS の night-mode 等と連動しているようで、また触っていたのが夜中だったので dark-mode からなぜ変わらないのかしばらく悩んでいました...笑
この辺りは時間があればどのようにな仕組みなのかもう少し掘り下げてみたいなと思いました。
 
今回は所感で触ったのみとなりましたが、時間があれば技術的な方向から掘り下げてみてみようと思います。

何かおかしなところがありましたらご連絡ください！