Modo Claro / Oscuro
Es una funcionalidad que permite establecer toda la página web a modo claro o modo oscuro.
Índice
- Variables y Constantes.
- Store.
- Componente de vue.
- Aplicar en css.
Archivos que se requieren: - colors.ts : contiene constantes de colores. - mode.ts : contiene constantes de modo. - Mode.client.ts : contiene variables de colores. - Mode.global.ts : guarda el modo en localStorage. - mode.js : store que gestiona el modo. - DayNight.vue : componente para importar el boton de cambio de modo.
Variables y constantes
Constantes
Se crea un archivo colors.ts donde se van a declarar los colores que se van a utilizar en la página.
Se crean constantes para cada color de la paleta de colores.
export const useWhiteColor = () => useState<String>("cWhite", () => "#ffffff");export const useBlackColor = () => useState<String>("cBlack", () => "#000000");export const useLightGray = () => useState<String>("cLightGrey", () => "#f0f0f0");Además se crea un objeto que contiene los colores para el modo claro y el modo oscuro.
Cada modo tiene los mismos nombres para cada color que se va a utilizar pero con distinto color, esto en función del modo se usa un color u otro.
export const modes = { dark: { cWhite: "#ffffff", cBlack: "#000000", cLightGrey: "#f0f0f0", }, light: { cWhite: "#000000", cBlack: "#ffffff", cLightGrey: "#f0f0f0", },};Tambien, se crea un archivo mode.ts que contiene la constante de cada modo.
export const MODE = "mode";export const LIGHT_MODE = "light";export const DARK_MODE = "dark";Variables
El archivo Mode.client.ts sirve para crear variables de color donde se va a almacenar el color que se va a usar dentro del css.
Cada variable de color se actualiza si detecta que el modo se ha cambiado y obtiene el color del objeto modes y devuelve el color del modo que se le pase.
export default defineNuxtPlugin((nuxtApp) => { // Se obtiene la variable reactiva del modo del Store const { getMode } = storeToRefs(useModeStore()); const root = document.documentElement; // Se define la función que establece la variable que se va a usar en el css const setMode = (mode: ModeType) => { // Se establece el nombre que se va a usar en el css (--c-white) y se le guarda el color root.style.setProperty("--c-white", modes[mode].cWhite); root.style.setProperty("--c-black", modes[mode].cBlack); root.style.setProperty("--c-light-grey", modes[mode].cLightGrey); }; setMode(getMode.value as ModeType); // Cuando se cambia de modo se ejecuta setMode() watch(getMode, () => setMode(getMode.value as ModeType));});Store
Se utiliza una store para almacenar el modo y que el modo cambie de forma reactiva, actualizando todos los componentes al cambiar el modo.
Se crea un archivo mode.js donde se va a almacenar el modo y se va a actualizar de forma reactiva.
export const useModeStore = defineStore("mode", () => { // Declarar variable const mode = ref(DARK_MODE); // Crear un getter para obtener el modo const getMode = computed(() => mode.value); // Crear una función que cambie entre modo claro y oscuro const changeMode = () => { mode.value = mode.value === DARK_MODE ? LIGHT_MODE : DARK_MODE; localStorage.setItem(MODE, mode.value); }; // Función pra establecer el modo const setMode = (newMode) => { mode.value = newMode; };
return { getMode, changeMode, setMode };});Además, en el archivo mode.global.ts se utiliza el localStorage para almacenar la preferencia del usuario y cada vez que entre en la página se carga el modo de la ultima vez, si es la primera vez que entra en la página se le crea y se le aplica por defecto el modo oscuro.
export default defineNuxtRouteMiddleware((to, from) => { const { setMode } = useModeStore(); // Obtener el item del localStorage const mode = localStorage.getItem(MODE); if (!mode) { // Si no existe el item se crea y se establece modo oscuro setMode(DARK_MODE); localStorage.setItem(MODE, DARK_MODE); } else if (mode === DARK_MODE || mode === LIGHT_MODE) setMode(mode); else localStorage.setItem(MODE, DARK_MODE);});Componente de vue
Para crear el boton de cambio de modo se crea un componente de vue DayNight.vue en el cual se crea un bloque que al pulsar encima se ejecuta la función de la store “changeMode” para que se cambie de modo.
Además, el bloque contiene otros componente que son svg que cambia en función del modo.
<script setup>import { useModeStore } from '@/stores/mode'import { storeToRefs } from 'pinia'import { LIGHT_MODE, DARK_MODE } from '@/constants/mode'
const Sun = defineAsyncComponent(() => import('@/components/svg/Sun.vue'))const Moon = defineAsyncComponent(() => import('@/components/svg/Moon.vue'))
// Se define el método para obtener el modo en el que se encuentraconst { getMode } = storeToRefs(useModeStore())// Se define el método para cambiar de modoconst { changeMode } = useModeStore()</script>
<template> <div class="switch-mode" @click="changeMode"> <Transition name="mode-transition"> <Sun v-if="getMode === LIGHT_MODE" :width="'2em'" :height="'2em'" /> <Moon v-else-if="getMode === DARK_MODE" :width="'2em'" :height="'2em'" /> </Transition> </div></template>Aplicar colores en función del modo.
Para aplicar los colores en el proyecto se puede aplicar de dos formas distintas, una pasando el color por props o aplicando directamente en el css.
Pasar por props
Para pasar el color por props, primero hay que declarar los colores que se van a usar, por ejemplo:
const blackColor = useBlackColor();const whiteColor = useWhiteColor();También, hay que definir la funcion “getMode” de la store y hay que utilizar storeToRefs para que sea reactivo.
import { useModeStore } from "@/stores/mode";import { storeToRefs } from "pinia";import { DARK_MODE } from "@/constants/mode";
const { getMode } = storeToRefs(useModeStore());Con esto se usa un condicional ternario que comprueba si se está en el modo oscuro y devuelve un color u otro.
:bgColor="getMode === DARK_MODE ? blackColor : whiteColor"Aplicar en css
La otra manera para aplicar colores que en función del modo se cambie automaticamente, es aplicando directamente en el css.
Para esto, en la propiedad css que queramos aplicar un color, se usa var() y dentro indicamos el color del archivo Mode.client.ts que se ha definido.
color: var(--c-white);