つづき。
おい!ダークモードどうやるんだよ!の声が聞こえてくるので、そちらも解説します。
なんと PrimeVue はダークモードにも標準対応しています。
デフォルトでは、OSのテーマに依存するようになってます。
でも実際の挙動を考えると、テーマを切り替えるためのトグルスイッチを設けたいですよね。
Laravel 標準の実装
Laravel は認証込みのスターターキットを入れるといろいろ入っています。
-
useAppearance.ts
- フロント側でモード設定を Cookie や LocalStorage に書き込む
-
HandleAppearance.php
- Middleware で Cookie を読み込んで、blade 側に渡す
-
app.blade.php
- 現在のモード設定を受け取り
<html>タグに反映させる <html class="dark">
- 現在のモード設定を受け取り
テンプレートなのでこれを採用してもよいのですが、こんなちゃんとしなくてもよいです!
LocalStorage を用いた実装
Tailwind と PrimeVue 双方、任意のクラスに反応してくれる仕組みがあります。
今回は .dark に反応してくれるようにそれぞれを設定します。
まずは app.css に @custom-variant dark の設定を行います。
@import 'tailwindcss';
@import "tailwindcss-primeui";
+ @custom-variant dark (&:where(.dark, .dark *));
次に app.ts の設定に darkModeSelector を登録します。
setup({ el, App, props, plugin }) {
createApp({ render: () => h(App, props) })
.use(plugin)
.use(PrimeVue, {
theme: {
preset: Aura,
+ options: {
+ darkModeSelector: '.dark',
+ },
},
locale: Ja,
})
.mount(el)
},
そして app.blade.php にある $appearance の残骸を削除します。
(これがテンプレートにあるの消し忘れなんじゃないかなぁ...?)
<!DOCTYPE html>
- <html lang="{{ str_replace('_', '-', app()->getLocale()) }}" @class(['dark' => ($appearance ?? 'system') == 'dark'])>
+ <html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
そしたら DarkMode を制御する Composable を作成していきます。
LocalStorage を利用していて、 dark と watch() はシングルトンとして動作させます。
初回に
localStorage.setItem('dark', String(value))が動いちゃうのが嫌だけど、、、
シンプルさ重視で!まぁ LocalStorage なので、値のサニタイズをやってると思えば無駄ではないか。
もし初期状態を OS のテーマにしたい場合は、以下の設定を読み出すと良いです。
window.matchMedia("(prefers-color-scheme: dark)").matches
import { ref, watch } from 'vue'
// 初期状態を LocalStorage から読み出す
const dark = ref<boolean>(localStorage.getItem('dark') === 'true')
// 状態が変わったら LocalStorage と HTML 属性を同期する
watch(dark, (value) => {
localStorage.setItem('dark', String(value))
document.documentElement.classList.toggle('dark', value)
}, { immediate: true })
export const useDarkMode = () => {
return { dark }
}
これを app.ts の setup() で呼び出してあげると、常にダークモードが実行されます。
実はここって Vue 最上位の setup エリアなので、コンポーネントで書けることは何でも書けるんですよね。
各レイアウトの共通処理は、ここに書くと良いです。
+ import { useDarkMode } from '@/composable/useDarkMode'
setup({ el, App, props, plugin }) {
createApp({ render: () => h(App, props) })
//...
.mount(el)
+ useDarkMode()
},
ダークモードを操作する処理はこのように書きます。
<template>
<div class="m-4">
<ToggleSwitch v-model="dark" />
</div>
</template>
<script setup lang="ts">
import ToggleSwitch from 'primevue/toggleswitch'
import { useDarkMode } from '@/composable/useDarkMode'
const { dark } = useDarkMode()
</script>
スイッチを押すとダークモードが切り替わります!!
ちゃんと再読み込みしても、モードが維持されてます!
追伸:Tailwind のダークモード
Tailwind でダークモードを扱うには dark: というプレフィックスを付ける必要があります。
なので light で背景色を薄くした場合には、dark で濃くするクラスを忘れずに付与しましょう
<template>
<div class="
bg-primary-100 p-4
dark:bg-primary-900
">
<div>両テーマ対応!</div>
<ToggleSwitch v-model="dark" />
</div>
</template>
もし light と dark の組み合わせを記録したい場合は、Theme をいじくりましょう。

