Skip to main content

Chapitre 11 - Les embeds / Boutons / Listes de sélection

Nous rejoindre sur Discord

Les embeds

Les embeds sont une forme particulière de message. Voici un exemple d'embed :

const { SlashCommandBuilder, EmbedBuilder } = require('discord.js');

/* ... */

const embed = new EmbedBuilder() // Initialisation de notre Embeds
    .setColor(0x0099ff) // Définition de la couleur de notre embeds
    .setTitle("Titre de l'embeds") // Ajout d'un titre
    .setURL('https://xelyos.fr') // URL de redirection quand on clique sur le titre
    .setAuthor({
        // Information sur l'auteur
        name: interaction.member.user.username, // Nom de l'auteur
        iconURL: interaction.member.user.avatarURL({ dynamic: true }), // URL de l'image de l'auteur, ici on prend en compte si c'est un gif
        url: 'https://xelyos.fr/members/' + interaction.member.user.username, // URL de redirection quand on clique sur l'auteur
    })
    .setDescription('Description de notre embed') // Description de notre embeds
    .setThumbnail(config.icon.bot) // Ajout d'une vignette
    .addFields([
        // Ajout de champs dans notre embed
        { name: 'Champ régulier', value: 'Valeur du champ' }, // Champ normal
        { name: '\u200B', value: '\u200B' }, // Ajouter un champ vide dans le embeds
        { name: 'Champ en ligne', value: 'Valeur du champ en ligne 1', inline: true }, // champ en ligne
    ])
    .addFields({
        name: 'Champ en ligne',
        value: 'Valeur du champ en ligne 1',
        inline: true,
    }) // D'autre champ peuvent être ajouté par la suite
    .setImage(config.icon.bot) // Ajouter une image dans le
    .setTimestamp() // Ajouter une information sur la date à laquelle l'embeds a été envoyé
    .setFooter({ text: 'Formation Bot Discord', iconURL: config.icon.bot }); // Information dans le footer (même principe que pour l'auteur)

Tous les éléments présenter ci-dessous ne sont pas nécessaire, ne mettez uniquement ceux dont vous avez besoin.

Une fois que notre embeds il suffit de l'envoi dans un message ou alors dans une réponse. La structure de notre réponse aura donc cette forme :

const response = {
  embeds: [embed], // Même si on a qu'un seul embed, il faut le mettre dans un tableau
};

Ajouter un fichier

Il est possible d'ajouter un fichier dans un message. Plusieurs moyens sont disponible pour cela. On peut par exemple mettre directement le lien de celui ci afin de le rendre téléchargeable. On peut également envoyer un fichier depuis les ressources de notre bot (une image par exemple). C'est ce que nous allons voir maintenant, nous allons voir comment ajouter notre image dans un embed ou directement dans le contenu du message (sans lien URL).

Dans notre répertoire src nous allons créer un répertoire images. Dans ce répertoire, nous allons ajouter une image que l'on va appeler logo.png.

const { SlashCommandBuilder, EmbedBuilder } = require('discord.js');

/* ... */

// Étape 1 : Récupérer notre image
const file = new AttachmentBuilder('src/images/logo.png'); // Chemin vers notre image depuis la racine de notre bot

// Étape 2 : intégration de notre image dans l'embeds
const embed = new EmbedBuilder()
    .setTitle("Ajout d'une image")
    .setImage('attachment://logo.png'); // Voici comment ajouter notre image

Les Boutons

Les boutons nous permettent d'effectuer une action lorsqu'un utilisateur va l'utiliser. On est donc sur le principe d'une interaction. Pour utiliser cette interaction, nous allons dans un premier temps dans notre répertoire reactions créer un répertoire buttons dans lequel on pourra mettre tous les protocoles aux interactions par les boutons.

Avant de commancer l'écriture de nos boutons, il faut que notre bot ait enregistré les boutons. On va modifier notre fichier app.js afin de prendre en compte la liste des intéractions par bouton.

Détection des boutons par le bot

client.buttons = new Collection(); // On créé une nouvelle collection qui va contenir tous nos boutons

const buttonsPath = path.join(reactionsPath, 'buttons'); // On indique le répertoire qui contient les instructions pour nos boutons

const buttonsFile = fs.readdirSync(buttonsPath).filter((file) => file.endsWith('.js')); // On récupère tous les fichiers js dans notre répertoire

La configuration de notre fichier app.js était de sorte à ce que les réactions soient toutes présentes dans le répertoire reactions. Sauf que nous allons modifier ça. On va donc remplacer :

/* Initialisation réactions */
for (const file of reactionsFiles) {
    const filePath = path.join(reactionsPath, file);
    const reaction = require(filePath);
    client.reactions.set(reaction.data.name, reaction);
    console.log(`Réaction ${reaction.data.name} => chargée`);
}
/* Initialisation commandes */

Par :

/* Initialisation réactions par bouton */
for (const file of buttonsFile) {
    const filePath = path.join(buttonsPath, file);
    const button = require(filePath);
    client.buttons.set(button.data.name, button);
    console.log(`Bouton ${button.data.name} => chargé`);
}
/* Initialisation réactions par bouton */

Cette modification de stockage de nos boutons nous permet d'améliorer la séparation de notre code et ainsi améliorer la maintenabilité de notre bot.

Pour récupérer l'évènement de l'interaction avec notre bouton, il faut également modifier le fichier src/events/interactionCreate.js pour prendre en compte ses interactions. Dans les intructions de notre évènement, ajouter à la suite :

/* Interaction avec un bouton */
if (interaction.isButton()) {
    if (interaction.message.author.id !== client.user.id) return; // On ne réagit pas à nous même
    const button = client.buttons.get(interaction.customId);
    if (!button) return;
    button.execute(interaction, client);
}
/* Interaction avec un bouton */

Ajouter un bouton à un message

Pour ajouter un bouton dans un message, il faut dans un premier temps le créer. Nous allons créer une commande button qui aura pour but de répondre par un bouton. Ce bouton va nous permettre de recevoir en MP l'URL d'un site

Création de la commande button :

module.exports = {
    data: new SlashCommandBuilder().setName('button').setDescription('Réponse par un bouton'),
    async execute(interaction) {
        const button = new ButtonBuilder()
            .setCustomId('showURL') // Id unique de notre bouton, cela correspond à son nom
            .setLabel("Recevoir en MP l'URL du site")
            .setStyle(ButtonStyle.Primary);

        const row = new ActionRowBuilder().addComponents(button); // On ajoute notre bouton dans un ligne

        await interaction.reply({
            content: 'Notre bouton',
            components: [row],
        });
    },
};

A compléter avec les options disponibles

Réponse au bouton :

module.exports = {
    name: 'showURL',
    async execute(interaction) {
        interaction.member.send({
            content: config.url.site,
        });

        interaction.reply({
            content: "L'URL vous a été envoyé en privé",
            ephemeral: true,
        });
    },
};

Avantage, le bouton peut être réutiliser même après redémarrage du bot


Les listes de sélection

client.selects = new Collection();

const selectsPath = path.join(reactionsPath, 'selects');

const selectsFile = fs.readdirSync(selectsPath).filter((file) => file.endsWith('.js'));
/* Initialisation réactions par liste */
for (const file of selectsFile) {
    const filePath = path.join(selectsPath, file);
    const select = require(filePath);
    client.selects.set(select.name, select);
    console.log(`Liste ${select.name} => chargée`);
}
/* Initialisation réactions par liste */
/* Interaction avec un menu */
if (interaction.isSelectMenu()) {
    if (interaction.message.author.id !== client.user.id) return; // On ne réagit pas à nous même
    const select = client.selects.get(interaction.customId);
    if (!select) return;
    select.execute(interaction, client);
}
/* Interaction avec un menu */
module.exports = {
    data: new SlashCommandBuilder().setName('select').setDescription('Réponse par une liste'),
    async execute(interaction) {
        const menuSelect = new SelectMenuBuilder()
            .setCustomId('notreList')
            .setPlaceholder('Sélectionner un élément')
            .setMinValues(1)
            .setMaxValues(1)
            .setOptions([
                { label: "Titre de l'option", description: 'description', value: 'option 1' },
                { label: "Titre de l'option 2", description: 'description 2', value: 'option 2' },
            ]);
        const row = new ActionRowBuilder().addComponents(menuSelect);

        await interaction.reply({
            content: 'Notre menu',
            components: [row],
        });
    },
};
module.exports = {
    name: 'notreList',
    async execute(interaction) {
        const values = interaction.values;

        const value = values[0];

        interaction.reply({
            content: "Vous avez sélectionné l'option : **" + value + '**',
        });
    },
};