DEV Community

Cover image for Creando un sencillo sistema de notificaciones en Vue3 con TailwindCSS (MerakiUI)
Dennis Quesada Cruz
Dennis Quesada Cruz

Posted on

Creando un sencillo sistema de notificaciones en Vue3 con TailwindCSS (MerakiUI)

Hola a todos, dicen por ahí que es bueno escribir artículos técnicos porque así reafirmas lo aprendido, pues, en esta ocasión, voy a seguir con Vue3 y hoy particularmente con TailwindCSS y MerakiUI, creando un sencillo sistema de notificaciones para tu app.

TailwindCSS

Es una potente librería de utilidades para CSS, te ahorrará mucho tiempo a la hora de escribir tus estilos, aunque, NO reemplaza al CSS puro.

MerakiUI

Una librería de componentes responsivos y limpios, basada en Flexbox y Grid, completamente responsiva.

Motivación

En mi tiempo libre por las noches, he estado ¨rehaciendo¨ una app que tengo online y en producción desde principios de año, he querido hacerla lo mas ligera posible y por eso la estoy rediseñando y reescribiendo desde 0 con Vue3 y TailwindCSS, actualmente esta con Vue2 y Vuetify + otras deps, y no por hecharle tierra a Vuetify, pero está bastante pesadita.

Notificar o no notificar?

Una de las cosas mas importantes en tu app y UX es la interacción con el usuario, las buenas prácticas dictan de informar al usuario qué esta pasando con sus acciones, si se completaron o si terminaron en un error, aquí entran las alertas, hay N+1 librerías open source que te permiten gestionarlas, pero quiero depender lo menos de 3ros, asi que me puse a intentar construir mi propio sistema.

Manos a la obra

Lo primero que tuve en mente fue armar un composable que gestionara todo lo de las alertas

Archivo: useToast.ts

import { ref } from 'vue';

// Este arreglo contendrá las notificaciones
const messages = ref<ToastOptions[]>([]);

const useToast = () => {
    // Empuja una nueva alerta al arreglo
    const addAlert = (options: ToastOptions) => {
        messages.value.push({
            id: options.id,
            message: options.message,
            type: options.type || 'success',
        });
       // A los 3 segundos, que se disipe.
        setTimeout(() => {
            messages.value.length > 0 ? removeAlert(messages.value.findIndex((item) => item.id === options.id)) : null;
        }, 3000);
    };
    // Remueve el elemento del arreglo de mensajes
    const removeAlert = (index: number) => {
        if (index > -1) {
            messages.value.splice(index, 1);
        }
    };

    return {
        messages,
        addAlert,
        removeAlert,
    };
};

export default useToast;
Enter fullscreen mode Exit fullscreen mode

De esa forma podemos traernos useToast() a cualquier parte de nuestra app.

Continuamos con el componente:
Archivo: alert.vue

<template>
  <div
    v-for="alert, index in messages"
    :key="index"
    ref="item"
    class="absolute right-5 top-5 flex w-full max-w-sm mx-auto overflow-hidden bg-white rounded-lg shadow-lg dark:bg-gray-800 animate-fadeIn"
  >
    <div
      :class="`flex items-center justify-center w-12  ${alert.type === 'error' ? 'bg-red-500' : 'bg-green-500'}`"
    >
      <svg
        class="w-6 h-6 text-white fill-current"
        viewBox="0 0 40 40"
        xmlns="http://www.w3.org/2000/svg"
      >
        <path
          d="M20 3.36667C10.8167 3.36667 3.3667 10.8167 3.3667 20C3.3667 29.1833 10.8167 36.6333 20 36.6333C29.1834 36.6333 36.6334 29.1833 36.6334 20C36.6334 10.8167 29.1834 3.36667 20 3.36667ZM19.1334 33.3333V22.9H13.3334L21.6667 6.66667V17.1H27.25L19.1334 33.3333Z"
        />
      </svg>
    </div>

    <div class="px-4 py-2 -mx-3">
      <div class="mx-3 w-11/12">
        <span
          :class="`font-semibold ${alert.type === 'error' ? 'text-red-500' : 'text-green-500'} dark:text-red-400`"
        >{{ alert.type === 'error' ? 'Error' : 'Completado' }}</span>
        <p class="text-sm text-gray-600 dark:text-gray-200 w-full">{{ alert.message }}</p>
      </div>
    </div>
  </div>
</template>


<script lang="ts">
import { defineComponent, PropType } from "vue"; export default defineComponent({
  props: {

    messages: {
      type: [] as PropType<ToastOptions[] | null>,
      default: []
    }
  },
})
</script>
Enter fullscreen mode Exit fullscreen mode

El componente recibirá como props el arreglo de mensajes que habíamos definido en useToast(), ya luego solo queda usarlo en App.vue

Archivo: App.vue

<template>
  <Alert :messages="messages" />
  <default-vue />
</template>

<script lang="ts">
import DefaultVue from "./layouts/Default.vue";
import Alert from "./components/common/alert.vue"
import { defineComponent } from "vue";
import useToast from "./utils/useToast";

export default defineComponent({
  components: {
    DefaultVue, Alert
  },
  name: "App",
  setup() {
    const { messages } = useToast()
    return {
      messages,
    }
  }
})
</script>
Enter fullscreen mode Exit fullscreen mode

Para llamar a la alerta desde cualquier lado:

import useToast from './useToast';
const { addAlert } = useToast();

addAlert({id: generateGuid(),
message: error.message,
type: 'error',
});
Enter fullscreen mode Exit fullscreen mode

Resultando en:
Alertas con MerakUI

Y hasta aquí este sencillo artículo, espero les haya servido de algo

¿Para mejorarlo?:

  • Hacer que una alerta este por debajo de la otra y se acumulen
  • Adicionar un boton de cerrar la alerta.

Cualquier comentario y/o crítica es bienvenida!

Discussion (0)