Agent Grow Tech Notes
😽

TypeScript & GraphQL でToDoアプリを開発する #6

に公開

⬅️前回の記事はこちら

https://zenn.dev/agent_grow/articles/b9fae76d86be49

ダークモード/ライトモード & 日本語/英語 切り替え機能を実装

⭐️ダークモード/ライトモード 切り替え機能を実装

index.vueのscript setupに追記

index.vue
import { useTheme } from 'vuetify'

const theme = useTheme()

const toggleTheme = () => {
  theme.global.name.value = theme.global.name.value === 'dark' ? 'light' : 'dark'
}

index.vueのv-card-titleを修正

index.vue
<v-card-title class="d-flex justify-space-between align-center text-h6">
    新しいタスク
    <v-btn icon @click="toggleTheme">
        <v-icon>{{ theme.global.name.value === 'dark' ? 'mdi-white-balance-sunny' : 'mdi-weather-night' }}</v-icon>
    </v-btn>
</v-card-title>

vuetify.tsに icons: と theme: を追記

vuetify.ts
import { createVuetify } from 'vuetify'
import * as components from 'vuetify/components'
import * as directives from 'vuetify/directives'
import { aliases, mdi } from 'vuetify/iconsets/mdi'

// Nuxtプラグインとして Vuetify を定義
export default defineNuxtPlugin((nuxtApp) => {
    // Vuetify インスタンスの作成
    const vuetify = createVuetify({
        components,       // 全てのVuetifyコンポーネントを登録
        directives,       // 全てのVuetifyディレクティブを登録
        ssr: true,        // SSR(サーバーサイドレンダリング)対応を有効にする
        icons: {          // アイコン設定(mdi)
            defaultSet: 'mdi',
            aliases,
            sets: { mdi },
        },
        theme: {          // テーマ設定(ダーク/ライトモード切り替え)
            defaultTheme: 'light',
            themes: {
                light: {
                    dark: false,
                    colors: {
                        background: '#FFFFFF',
                        surface: '#FFFFFF',
                        primary: '#1976D2',
                        secondary: '#424242',
                        error: '#FF5252',
                        info: '#2196F3',
                        success: '#4CAF50',
                        warning: '#FB8C00',
                    },
                },
                dark: {
                    dark: true,
                    colors: {
                        background: '#121212',
                        surface: '#1E1E1E',
                        primary: '#90CAF9',
                        secondary: '#EEEEEE',
                        error: '#FF5252',
                        info: '#2196F3',
                        success: '#4CAF50',
                        warning: '#FB8C00',
                    },
                },
            },
        },

    })

    // 作成したVuetifyインスタンスを Nuxt アプリに組み込む
    nuxtApp.vueApp.use(vuetify)
})

動作確認

🚀ダークモード/ライトモード 切り替え機能の実装が完了!!!

#6のおわりに

ダークモード/ライトモード 切り替え機能の実装 お疲れさまでした。
次回は日本語/英語の切り替え機能を実装します。
https://zenn.dev/agent_grow/articles/34e1fba0f7aa01

〜UIテーマは“状態”として扱うべきという話〜

今回の実装では、VuetifyのuseTheme()を用いて、UIテーマの切り替えを行いました。一見すると単純なトグル処理に見えますが、これはVueのリアクティブシステムに組み込まれた「状態管理」の一部です。
theme.global.name.value は ref と同様のリアクティブな値であり、この値を更新するとVuetifyは内部的に現在のテーマ情報(ダークモード/ライトモード)を再評価し、全コンポーネントのスタイルを即時に再描画します。
これは裏側でCSSクラスの差し替えやVuetifyのデザイントークンの切り替えが自動的に行われており、開発者は明示的にCSSを操作する必要がありません。たとえば以下のような挙動が自動的に発生します。

  • <v-card>や<v-btn>などの色や背景、影の変更
  • カラーパレット(primary, secondaryなど)の自動切り替え
  • ダークテーマ特有のアクセントやタイポグラフィの最適化

このような「状態によるスタイル制御」は、単なる見た目の変更に留まらず、以下の観点でも有効です。

  • コンポーネント設計:見た目をpropsやcomputedではなく「テーマの状態」に委ねられるため再利用性が高い
  • アクセシビリティ:背景と文字色のコントラスト管理がVuetifyによって保証される
  • SSR対応:初回レンダリング時にテーマ状態を考慮してスタイルが決定されるため、表示ブレが起こりにくい

テーマは見た目を切り替えるだけの機能ではなく、アプリケーションの状態として管理することで、設計の一貫性やメンテナンス性が向上します。

Agent Grow Tech Notes
Agent Grow Tech Notes

Discussion