VIcon 
🌟 Introduction 
Le composant VIcon est un composant Vue.js permettant d'afficher des icônes avec une large gamme d'options de personnalisation, y compris des animations, des couleurs, et des tailles. Il est conçu pour être flexible et performant, avec une prise en charge des différentes options d'affichage, de flip, et de titres accessibles.
Il a exactement la même API que OhVueIcon, et utilise @iconify/vue sous le capot.
Attention
Les noms des icônes doivent être ceux de Iconify-vue.
📐 Structure 
Le composant VIcon s'intègre facilement en utilisant la syntaxe suivante :
<VIcon name="nom-collection:nom-de-l-icone" :scale="1.5" color="#FF5733" animation="spin" /><VIcon name="ri:alert-fill" :scale="1.5" color="#FF5733" animation="ring" />Migration depuis 5.x
Pour les noms de collection qui ne contiennent pas de tiret (-), il est accepté de séparer le nom de la collection du nom de l’icône avec un tiret -.
<VIcon name="ri-alert-fill" :scale="1.5" color="#FF5733" animation="ring" />Ceci rend le composant VIcon totalement compatible avec OhVueIcon si n’étaient utilisées que les icônes RemixIcon et quelques autres collections.
DX
Pour l’expérience développeur, il est conseillé d’utiliser l’extension vscode antfu.iconify.
🛠️ Props 
Voici les différentes propriétés que vous pouvez utiliser avec ce composant :
| Prop | Type | Défaut | Description | 
|---|---|---|---|
| name | string | Obligatoire | Le nom de l'icône à afficher. | 
| scale | string | number | 1 | Échelle de l'icône, avec un facteur multiplicateur de la taille par défaut. | 
| verticalAlign | string | '-0.2em' | Alignement vertical de l'icône par rapport à la ligne de base. | 
| animation | 'spin' | 'wrench' | 'pulse' | 'spin-pulse' | 'flash' | 'float' | undefined | Type d'animation appliqué à l'icône. | 
| speed | 'fast' | 'slow' | undefined | Vitesse de l'animation si elle est définie. | 
| flip | 'horizontal' | 'vertical' | 'both' | undefined | Inverse l'icône horizontalement, verticalement ou les deux. | 
| label | string | undefined | Étiquette ARIA pour l'accessibilité. | 
| title | string | undefined | Titre de l'icône (balise <title>), utilisé pour l'accessibilité et les info-bulles. | 
| color | string | undefined | Couleur principale de l'icône. | 
| fill | string | undefined | Couleur de remplissage de l'icône (utilise in fine colorcomme conseillé dans la doc de @iconify/vue). Cette prop n’existe que pour la rétrocompatibilité avec OhVueIcon, préférer l’utilisation de la propcolor. | 
| inverse | boolean | false | Applique une couleur inversée à l'icône. | 
| ssr | boolean | false | Active le rendu côté serveur (Server-Side Rendering). | 
| display | 'block' | 'inline-block' | 'inline' | 'inline-block' | Définit le mode d'affichage de l'icône. | 
📡Événements 
Ce composant ne déclenche pas d'événements personnalisés.
🧩 Slots 
Ce composant ne contient pas de slots.
⚙️ Code source du composant 
<script lang="ts" setup>
import VIcon from '../VIcon.vue'
</script>
<template>
  <div class="flex  justify-between p-4">
    <section>
      <header class="fr-text--lg">
        Simple :
      </header>
      <p>
        <VIcon
          name="ri-close-line"
        />
        <VIcon
          name="ri-checkbox-circle-line"
        />
      </p>
    </section>
    <section>
      <header class="fr-text--lg">
        Plus grande :
      </header>
      <p>
        <VIcon
          name="ri-close-line"
          scale="2"
        />
        <VIcon
          name="ri-checkbox-circle-line"
          scale="2"
        />
      </p>
    </section>
    <section>
      <header class="fr-text--lg">
        Animée :
      </header>
      <p>
        spin :
        <VIcon
          name="ri-loader-4-line"
          animation="spin"
        />
      </p>
      <p>
        spin-pulse :
        <VIcon
          name="ri-loader-4-line"
          animation="spin-pulse"
        />
      </p>
      <p>
        pulse :
        <VIcon
          name="ri-checkbox-circle-line"
          animation="pulse"
        />
      </p>
      <p>
        flash :
        <VIcon
          name="ri-close-line"
          animation="flash"
        />
      </p>
      <p>
        float :
        <VIcon
          name="ri-close-line"
          animation="float"
        />
      </p>
      <p>
        ring :
        <VIcon
          name="fa6-regular:bell"
          animation="ring"
        />
      </p>
      <p>
        wrench :
        <VIcon
          name="twemoji:rolling-on-the-floor-laughing"
          animation="wrench"
        />
      </p>
    </section>
    <section>
      <header class="fr-text--lg">
        Colorée :
      </header>
      <p>
        lightgreen :
        <VIcon
          name="ri-checkbox-circle-line"
          color="lightgreen"
        />
      </p>
      <p>
        #f90 :
        <VIcon
          name="ri-checkbox-circle-line"
          color="#f90"
        />
      </p>
      <p>
        var(--blue-france-main-525) :
        <VIcon
          name="ri-checkbox-circle-line"
          color="var(--blue-france-main-525)"
        />
      </p>
    </section>
  </div>
</template><script lang="ts" setup>
import type { VIconProps } from './VIcon.types'
import { Icon } from '@iconify/vue'
import { computed, nextTick, onMounted, ref, watch } from 'vue'
export type { VIconProps }
const props = withDefaults(defineProps<VIconProps>(), {
  scale: 1,
  verticalAlign: '-0.2em',
  display: 'inline-block',
})
const icon = ref<{ $el: SVGElement } | null>(null)
const fontSize = computed(() => `${+props.scale * 1.2}rem`)
const flip = computed(() => {
  if (props.flip === 'both') {
    return 'horizontal,vertical'
  }
  return props.flip
})
watch(() => props.title, setTitle)
async function setTitle () {
  if (!(icon.value?.$el)) {
    return
  }
  const titleExists = !!(icon.value?.$el).querySelector('title')
  const titleEl = document.createElement('title')
  if (!props.title) {
    titleEl.remove()
    return
  }
  titleEl.innerHTML = props.title
  await nextTick()
  if (!titleExists) {
    (icon.value?.$el as SVGElement).firstChild?.before(titleEl)
  }
}
onMounted(setTitle)
const finalName = computed(() => {
  return props.name?.startsWith('vi-') ? props.name.replace(/vi-(.*)/, 'vscode-icons:$1') : props.name ?? ''
})
const finalColor = computed(() => {
  return props.color ?? props.fill ?? 'inherit'
})
</script>
<template>
  <Icon
    ref="icon"
    :icon="finalName"
    :style="{ fontSize, verticalAlign, display, color: finalColor }"
    :aria-label="label"
    class="vicon"
    :class="{
      'vicon-spin': props.animation === 'spin',
      'vicon-wrench': props.animation === 'wrench',
      'vicon-pulse': props.animation === 'pulse',
      'vicon-spin-pulse': props.animation === 'spin-pulse',
      'vicon-flash': props.animation === 'flash',
      'vicon-float': props.animation === 'float',
      'vicon-ring': props.animation === 'ring',
      'vicon-slow': props.speed === 'slow',
      'vicon-fast': props.speed === 'fast',
      'vicon-inverse': props.inverse,
    }"
    :flip
    :ssr
  />
</template>
<style scoped>
.vicon-inverse {
  color: #fff;
}
/* ---------------- spin ---------------- */
.vicon-spin:not(.vicon-hover),
.vicon-spin.vicon-hover:hover,
.vicon-parent.vicon-hover:hover > .vicon-spin {
  animation: vicon-spin 1s linear infinite;
}
.vicon-spin:not(.vicon-hover).vicon-fast,
.vicon-spin.vicon-hover.vicon-fast:hover,
.vicon-parent.vicon-hover:hover > .vicon-spin.vicon-fast {
  animation: vicon-spin 0.7s linear infinite;
}
.vicon-spin:not(.vicon-hover).vicon-slow,
.vicon-spin.vicon-hover.vicon-slow:hover,
.vicon-parent.vicon-hover:hover > .vicon-spin.vicon-slow {
  animation: vicon-spin 2s linear infinite;
}
/* ---------------- spin-pulse ---------------- */
.vicon-spin-pulse:not(.vicon-hover),
.vicon-spin-pulse.vicon-hover:hover,
.vicon-parent.vicon-hover:hover > .vicon-spin-pulse {
  animation: vicon-spin 1s infinite steps(8);
}
.vicon-spin-pulse:not(.vicon-hover).vicon-fast,
.vicon-spin-pulse.vicon-hover.vicon-fast:hover,
.vicon-parent.vicon-hover:hover > .vicon-spin-pulse.vicon-fast {
  animation: vicon-spin 0.7s infinite steps(8);
}
.vicon-spin-pulse:not(.vicon-hover).vicon-slow,
.vicon-spin-pulse.vicon-hover.vicon-slow:hover,
.vicon-parent.vicon-hover:hover > .vicon-spin-pulse.vicon-slow {
  animation: vicon-spin 2s infinite steps(8);
}
@keyframes vicon-spin {
  0% {
    transform: rotate(0deg);
  }
  100% {
    transform: rotate(360deg);
  }
}
/* ---------------- wrench ---------------- */
.vicon-wrench:not(.vicon-hover),
.vicon-wrench.vicon-hover:hover,
.vicon-parent.vicon-hover:hover > .vicon-wrench {
  animation: vicon-wrench 2.5s ease infinite;
}
.vicon-wrench:not(.vicon-hover).vicon-fast,
.vicon-wrench.vicon-hover.vicon-fast:hover,
.vicon-parent.vicon-hover:hover > .vicon-wrench.vicon-fast {
  animation: vicon-wrench 1.2s ease infinite;
}
.vicon-wrench:not(.vicon-hover).vicon-slow,
.vicon-wrench.vicon-hover.vicon-slow:hover,
.vicon-parent.vicon-hover:hover > .vicon-wrench.vicon-slow {
  animation: vicon-wrench 3.7s ease infinite;
}
@keyframes vicon-wrench {
  0% {
    transform: rotate(-12deg);
  }
  8% {
    transform: rotate(12deg);
  }
  10%, 28%, 30%, 48%, 50%, 68% {
    transform: rotate(24deg);
  }
  18%, 20%, 38%, 40%, 58%, 60% {
    transform: rotate(-24deg);
  }
  75%, 100% {
    transform: rotate(0deg);
  }
}
/* ---------------- ring ---------------- */
.vicon-ring:not(.vicon-hover),
.vicon-ring.vicon-hover:hover,
.vicon-parent.vicon-hover:hover > .vicon-ring {
  animation: vicon-ring 2s ease infinite;
}
.vicon-ring:not(.vicon-hover).vicon-fast,
.vicon-ring.vicon-hover.vicon-fast:hover,
.vicon-parent.vicon-hover:hover > .vicon-ring.vicon-fast {
  animation: vicon-ring 1s ease infinite;
}
.vicon-ring:not(.vicon-hover).vicon-slow,
.vicon-ring.vicon-hover.vicon-slow:hover,
.vicon-parent.vicon-hover:hover > .vicon-ring.vicon-slow {
  animation: vicon-ring 3s ease infinite;
}
@keyframes vicon-ring {
  0% {
    transform: rotate(-15deg);
  }
  2% {
    transform: rotate(15deg);
  }
  4%, 12% {
    transform: rotate(-18deg);
  }
  6% {
    transform: rotate(18deg);
  }
  8% {
    transform: rotate(-22deg);
  }
  10% {
    transform: rotate(22deg);
  }
  12% {
    transform: rotate(-18deg);
  }
  14% {
    transform: rotate(18deg);
  }
  16% {
    transform: rotate(-12deg);
  }
  18% {
    transform: rotate(12deg);
  }
  20%, 100% {
    transform: rotate(0deg);
  }
}
/* ---------------- pulse ---------------- */
.vicon-pulse:not(.vicon-hover),
.vicon-pulse.vicon-hover:hover,
.vicon-parent.vicon-hover:hover > .vicon-pulse {
  animation: vicon-pulse 2s linear infinite;
}
.vicon-pulse:not(.vicon-hover).vicon-fast,
.vicon-pulse.vicon-hover.vicon-fast:hover,
.vicon-parent.vicon-hover:hover > .vicon-pulse.vicon-fast {
  animation: vicon-pulse 1s linear infinite;
}
.vicon-pulse:not(.vicon-hover).vicon-slow,
.vicon-pulse.vicon-hover.vicon-slow:hover,
.vicon-parent.vicon-hover:hover > .vicon-pulse.vicon-slow {
  animation: vicon-pulse 3s linear infinite;
}
@keyframes vicon-pulse {
  0% {
    transform: scale(1.1);
  }
  50% {
    transform: scale(0.8);
  }
  100% {
    transform: scale(1.1);
  }
}
/* ---------------- flash ---------------- */
.vicon-flash:not(.vicon-hover),
.vicon-flash.vicon-hover:hover,
.vicon-parent.vicon-hover:hover > .vicon-flash {
  animation: vicon-flash 2s ease infinite;
}
.vicon-flash:not(.vicon-hover).vicon-fast,
.vicon-flash.vicon-hover.vicon-fast:hover,
.vicon-parent.vicon-hover:hover > .vicon-flash.vicon-fast {
  animation: vicon-flash 1s ease infinite;
}
.vicon-flash:not(.vicon-hover).vicon-slow,
.vicon-flash.vicon-hover.vicon-slow:hover,
.vicon-parent.vicon-hover:hover > .vicon-flash.vicon-slow {
  animation: vicon-flash 3s ease infinite;
}
@keyframes vicon-flash {
  0%, 100%, 50%{
    opacity: 1;
  }
  25%, 75%{
    opacity: 0;
  }
}
/* ---------------- float ---------------- */
.vicon-float:not(.vicon-hover),
.vicon-float.vicon-hover:hover,
.vicon-parent.vicon-hover:hover > .vicon-float {
  animation: vicon-float 2s linear infinite;
}
.vicon-float:not(.vicon-hover).vicon-fast,
.vicon-float.vicon-hover.vicon-fast:hover,
.vicon-parent.vicon-hover:hover > .vicon-float.vicon-fast {
  animation: vicon-float 1s linear infinite;
}
.vicon-float:not(.vicon-hover).vicon-slow,
.vicon-float.vicon-hover.vicon-slow:hover,
.vicon-parent.vicon-hover:hover > .vicon-float.vicon-slow {
  animation: vicon-float 3s linear infinite;
}
@keyframes vicon-float {
  0%, 100% {
    transform: translateY(-3px);
  }
  50% {
    transform: translateY(3px);
  }
}
</style>