当サイトの右上にあるアイコンをクリックするとカラーモードの変更ができる。
設定をLocal Storageに保存してあるので次回アクセスしたときも同じカラーモードで表示できるようになる。
まず、Atomの設定。
あとでLocal Storageの値をセットするため初期値はnullにしておく。
export const colorModeAtom = atom<PaletteMode|null>({ key: 'colorModeAtom', default: null});
カラーモードを切り替えるためのボタンを作成する。
ここではMaterial UIのIconを使用している。
export const ColorModeSwitch = () => { const [colorMode, setColorMode] = useRecoilState(colorModeAtom); const toggleColorMode = () => { setColorMode(colorMode === 'light' ? 'dark' : 'light'); }; return ( <IconButton onClick={toggleColorMode} > {colorMode === 'dark' ? <Brightness7 /> : <Brightness4 />} </IconButton> );};
ライトモードとダークモードで使用するカラーの設定をする。
デフォルトカラーのまま使用する場合は、modeだけの切り替えでOK。
export const darkPalette: PaletteOptions = { mode: 'dark', primary: { main: purple[900], }, background: { default: grey[800], heading: blueGrey[900] }};export const lightPalette: PaletteOptions = { mode: 'light', primary: { main: purple[800], }, background: { default: grey[300], heading: blueGrey[50] },};
ThemeProviderに渡すthemeをatomの値で切り替える。
export const defaultColorMode = 'dark';export function Provider({ children }: PropsWithChildren) { const colorMode = useRecoilValue(colorModeAtom)||defaultColorMode; const theme = useMemo(() => createTheme({ palette: colorMode === 'dark' ? darkPalette : lightPalette }), [colorMode]); return ( <Provider theme={theme}> {children} </Provider> );}
RecoilでLocal Storageに設定を保存する方法としてはAtomEffectを使用する方法もあるが、Next.jsを使用する場合、初期カラーを反映させるのがうまくいかなかったためuseEffectを使うことにする。
カラー切り替えボタンのuseEffect内でLocal Storageの読み込みや保存を行う。
export const ColorModeSwitch = () => { const [colorMode, setColorMode] = useRecoilState(colorModeAtom); const toggleColorMode = () => { setColorMode(colorMode === 'light' ? 'dark' : 'light'); }; useEffect(() => { const strageKey = 'mui_color_mode'; // 初回時にlocalStorageにあるカラーモードあるいはdefaultColorModeをセットする if (colorMode === null) { const savedColorMode = (window.localStorage.getItem(strageKey) || defaultColorMode) as PaletteMode; setColorMode(savedColorMode); // colorModeが変更されるたびにlocalStorageに保存する } else { localStorage.setItem(strageKey, colorMode); } }, [colorMode]); return ( <IconButton onClick={toggleColorMode} > {colorMode === 'dark' ? <Brightness7 /> : <Brightness4 />} </IconButton> );};
Local Storageにライトモードの設定を保存したとしても、デフォルトをダークモードにしていると一瞬ダークモードで表示されたのちライトモードへと変わる。
これは公式サイトでもそのような挙動になっているため、今のところ修正できない模様。