feat: finished shitty but functional help command
This commit is contained in:
parent
82d66ffbe8
commit
a96b36e1d7
7 changed files with 131 additions and 16 deletions
|
@ -15,9 +15,10 @@
|
||||||
* along with ArgonBot. If not, see <https: //www.gnu.org/licenses/>.
|
* along with ArgonBot. If not, see <https: //www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
import Command from '@structures/command';
|
import Command from '@structures/command';
|
||||||
|
import config from 'config';
|
||||||
|
import { MessageButton } from 'discord.js';
|
||||||
import { Client, Message, MessageEmbed } from 'discord.js';
|
import { Client, Message, MessageEmbed } from 'discord.js';
|
||||||
import i18next from 'i18next';
|
import i18next from 'i18next';
|
||||||
import path from 'path';
|
|
||||||
|
|
||||||
export default class extends Command {
|
export default class extends Command {
|
||||||
public constructor(client: Client, file: string) {
|
public constructor(client: Client, file: string) {
|
||||||
|
@ -36,7 +37,7 @@ export default class extends Command {
|
||||||
|
|
||||||
public async run(message: Message, command: string): Promise<void> {
|
public async run(message: Message, command: string): Promise<void> {
|
||||||
if(!command) {
|
if(!command) {
|
||||||
const commandGroups: { name: string; embeds: MessageEmbed, commands: Command[] }[] = [];
|
const commandGroups: { name: string; embed: MessageEmbed, commands: Command[] }[] = [];
|
||||||
|
|
||||||
this.client.commands.forEach((command) => {
|
this.client.commands.forEach((command) => {
|
||||||
const findCommand = commandGroups.find((val) => val.name === command.options.group);
|
const findCommand = commandGroups.find((val) => val.name === command.options.group);
|
||||||
|
@ -46,13 +47,113 @@ export default class extends Command {
|
||||||
} else {
|
} else {
|
||||||
commandGroups.push({
|
commandGroups.push({
|
||||||
name: command.options.group!,
|
name: command.options.group!,
|
||||||
embeds: new MessageEmbed(),
|
embed: new MessageEmbed(),
|
||||||
commands: [command],
|
commands: [command],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
console.log(path.basename(this.file));
|
commandGroups.forEach((val, index) => {
|
||||||
|
val.embed = new MessageEmbed();
|
||||||
|
val.embed.setAuthor(i18next.t('commands:help.embedName'));
|
||||||
|
val.embed.setTitle(val.name.toUpperCase());
|
||||||
|
val.embed.setColor(message.member?.roles.highest.color ?? 0xFFFFFF);
|
||||||
|
val.embed.setFooter(`Page ${index+1}/${commandGroups.length}`);
|
||||||
|
val.embed.setTimestamp();
|
||||||
|
|
||||||
|
val.commands.forEach((command) => {
|
||||||
|
val.embed.addField(`${config.get('prefix')}${command.options.name}`, command.options.shortDescription ?? i18next.t('commands:generic.noShortDescription').toUpperCase(), false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
let currentPage = 0;
|
||||||
|
|
||||||
|
const nextCategoryBtn = new MessageButton();
|
||||||
|
nextCategoryBtn.setCustomID('nextCategoryBtn');
|
||||||
|
nextCategoryBtn.setLabel(i18next.t('commands:help.nextCategoryBtn'));
|
||||||
|
nextCategoryBtn.setStyle('PRIMARY');
|
||||||
|
|
||||||
|
const previousCategoryBtn = new MessageButton();
|
||||||
|
previousCategoryBtn.setCustomID('previousCategoryBtn');
|
||||||
|
previousCategoryBtn.setLabel(i18next.t('commands:help.previousCategoryBtn'));
|
||||||
|
previousCategoryBtn.setStyle('SECONDARY');
|
||||||
|
previousCategoryBtn.setDisabled(true);
|
||||||
|
|
||||||
|
const helpMsg = await message.channel.send({
|
||||||
|
content: i18next.t('commands:help.helpScreenBtnHelp'),
|
||||||
|
embeds: [commandGroups[0]!.embed],
|
||||||
|
components: [[previousCategoryBtn, nextCategoryBtn]],
|
||||||
|
});
|
||||||
|
|
||||||
|
const buttonCollector = helpMsg.channel.createMessageComponentInteractionCollector({ time: 60000 });
|
||||||
|
|
||||||
|
buttonCollector.on('collect', async (interaction) => {
|
||||||
|
if(interaction.customID === 'nextCategoryBtn') {
|
||||||
|
currentPage++;
|
||||||
|
|
||||||
|
if(currentPage+1 === commandGroups.length) {
|
||||||
|
nextCategoryBtn.setDisabled(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(currentPage !== 0) {
|
||||||
|
previousCategoryBtn.setDisabled(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
await interaction.update({
|
||||||
|
content: i18next.t('commands:help.helpScreenBtnHelp'),
|
||||||
|
embeds: [commandGroups[currentPage]!.embed],
|
||||||
|
components: [[previousCategoryBtn, nextCategoryBtn]],
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
currentPage--;
|
||||||
|
|
||||||
|
if(currentPage === 0) {
|
||||||
|
previousCategoryBtn.setDisabled(true);
|
||||||
|
nextCategoryBtn.setDisabled(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(currentPage !== 0) {
|
||||||
|
nextCategoryBtn.setDisabled(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
await interaction.update({
|
||||||
|
content: i18next.t('commands:help.helpScreenBtnHelp'),
|
||||||
|
embeds: [commandGroups[currentPage]!.embed],
|
||||||
|
components: [[previousCategoryBtn, nextCategoryBtn]],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
buttonCollector.on('end', async () => {
|
||||||
|
nextCategoryBtn.setDisabled(true);
|
||||||
|
previousCategoryBtn.setDisabled(true);
|
||||||
|
|
||||||
|
await helpMsg.edit({
|
||||||
|
content: i18next.t('commands:help.helpTimedOut'),
|
||||||
|
embeds: [commandGroups[currentPage]!.embed],
|
||||||
|
components: [[previousCategoryBtn, nextCategoryBtn]],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
const findCommand = this.client.commands.find((cmd) => cmd.options.name === command);
|
||||||
|
|
||||||
|
if(findCommand) {
|
||||||
|
const commandEmbed = new MessageEmbed();
|
||||||
|
commandEmbed.setAuthor(i18next.t('commands:help.embedName'));
|
||||||
|
commandEmbed.setTitle(findCommand.options.name!.toUpperCase());
|
||||||
|
commandEmbed.setColor(message.member?.roles.highest.color ?? 0xFFFFFF);
|
||||||
|
commandEmbed.setTimestamp();
|
||||||
|
|
||||||
|
commandEmbed.setDescription(i18next.t('commands:help.commandDescription', {
|
||||||
|
name: findCommand.options.name,
|
||||||
|
description: findCommand.options.extendedDescription ?? i18next.t('commands:generic.noExtendedDescription'),
|
||||||
|
usage: findCommand.options.usage ? `!${findCommand.options.name} ${findCommand.options.usage}` : i18next.t('commands:generic.noUsage'),
|
||||||
|
}));
|
||||||
|
|
||||||
|
await message.channel.send({ embeds: [commandEmbed] });
|
||||||
|
} else {
|
||||||
|
await message.reply(i18next.t('commands:help.unknownCommand'));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
* along with ArgonBot. If not, see <https: //www.gnu.org/licenses/>.
|
* along with ArgonBot. If not, see <https: //www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
import 'module-alias/register';
|
import 'module-alias/register';
|
||||||
|
import '@utils/augments';
|
||||||
|
|
||||||
import ArgonClient from '@lib/ArgonClient';
|
import ArgonClient from '@lib/ArgonClient';
|
||||||
import { Defaults } from '@utils/defaults';
|
import { Defaults } from '@utils/defaults';
|
||||||
|
@ -33,7 +34,6 @@ import Fluent from 'i18next-fluent';
|
||||||
import FSBackend from 'i18next-fs-backend';
|
import FSBackend from 'i18next-fs-backend';
|
||||||
import { Validator } from 'jsonschema';
|
import { Validator } from 'jsonschema';
|
||||||
import { DateTime } from 'luxon';
|
import { DateTime } from 'luxon';
|
||||||
import path from 'path';
|
|
||||||
import process from 'process';
|
import process from 'process';
|
||||||
|
|
||||||
let isBotReady = false;
|
let isBotReady = false;
|
||||||
|
@ -146,7 +146,7 @@ client.on('ready', async () => {
|
||||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||||
const fileCommand = require(file);
|
const fileCommand = require(file);
|
||||||
|
|
||||||
const command = new fileCommand['default'](client, path.basename(file, path.extname(file)));
|
const command = new fileCommand['default'](client, file);
|
||||||
|
|
||||||
client.commands.set(command.options.name, command);
|
client.commands.set(command.options.name, command);
|
||||||
|
|
||||||
|
@ -156,6 +156,7 @@ client.on('ready', async () => {
|
||||||
|
|
||||||
info(`Finished loading commands! Found ${client.commands.size} commands.`, ELoggingScope.Startup);
|
info(`Finished loading commands! Found ${client.commands.size} commands.`, ELoggingScope.Startup);
|
||||||
} catch(err) {
|
} catch(err) {
|
||||||
|
console.log(err);
|
||||||
fatal(`An error has occurred while attempting to load command files! Please see error below\n${err.message}`, ELoggingScope.Startup);
|
fatal(`An error has occurred while attempting to load command files! Please see error below\n${err.message}`, ELoggingScope.Startup);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,7 @@ import type Command from '@structures/command';
|
||||||
import { Client, ClientOptions, Collection } from 'discord.js';
|
import { Client, ClientOptions, Collection } from 'discord.js';
|
||||||
|
|
||||||
export default class extends Client {
|
export default class extends Client {
|
||||||
public readonly commands: Collection<string, Command> = new Collection();
|
public override readonly commands: Collection<string, Command> = new Collection();
|
||||||
|
|
||||||
public constructor(options: ClientOptions) {
|
public constructor(options: ClientOptions) {
|
||||||
super(options);
|
super(options);
|
||||||
|
|
|
@ -15,7 +15,6 @@
|
||||||
* along with ArgonBot. If not, see <https: //www.gnu.org/licenses/>.
|
* along with ArgonBot. If not, see <https: //www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
import type { ICommandOptions } from '@utils/types';
|
import type { ICommandOptions } from '@utils/types';
|
||||||
import { ECommandRunIn } from '@utils/types';
|
|
||||||
import config from 'config';
|
import config from 'config';
|
||||||
import type { Client, Message } from 'discord.js';
|
import type { Client, Message } from 'discord.js';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
|
@ -31,11 +30,7 @@ export default abstract class Command {
|
||||||
|
|
||||||
const defaultOptions: ICommandOptions = {
|
const defaultOptions: ICommandOptions = {
|
||||||
name: path.basename(this.file, path.extname(this.file)),
|
name: path.basename(this.file, path.extname(this.file)),
|
||||||
group: path.dirname(this.file) === 'commands' ? '' : path.dirname(this.file),
|
group: path.basename(path.dirname(this.file)) === 'commands' ? '' : path.basename(path.dirname(this.file)),
|
||||||
ownerOnly: false,
|
|
||||||
runIn: ECommandRunIn.Both,
|
|
||||||
shortDescription: '',
|
|
||||||
extendedDescription: '',
|
|
||||||
};
|
};
|
||||||
|
|
||||||
this.options = config.util.extendDeep(defaultOptions, options);
|
this.options = config.util.extendDeep(defaultOptions, options);
|
||||||
|
|
|
@ -14,3 +14,13 @@
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with ArgonBot. If not, see <https: //www.gnu.org/licenses/>.
|
* along with ArgonBot. If not, see <https: //www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import type ArgonClient from '@lib/ArgonClient';
|
||||||
|
import type Command from '@structures/command';
|
||||||
|
|
||||||
|
declare module 'discord.js' {
|
||||||
|
export interface Client {
|
||||||
|
constructor: typeof ArgonClient;
|
||||||
|
readonly commands: Collection<string, Command>;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -32,9 +32,10 @@ export enum ECommandRunIn {
|
||||||
// Interfaces
|
// Interfaces
|
||||||
export interface ICommandOptions {
|
export interface ICommandOptions {
|
||||||
name?: string;
|
name?: string;
|
||||||
|
group?: string;
|
||||||
shortDescription?: string;
|
shortDescription?: string;
|
||||||
extendedDescription?: string;
|
extendedDescription?: string;
|
||||||
group?: string;
|
usage?: string;
|
||||||
ownerOnly?: boolean;
|
ownerOnly?: boolean;
|
||||||
runIn?: ECommandRunIn;
|
runIn?: ECommandRunIn;
|
||||||
args?: {
|
args?: {
|
||||||
|
|
|
@ -12,7 +12,13 @@
|
||||||
"shortDescription": "Shows help menu",
|
"shortDescription": "Shows help menu",
|
||||||
"extendedDescription": "Shows an advanced help menu for commands to show usage",
|
"extendedDescription": "Shows an advanced help menu for commands to show usage",
|
||||||
"commandArg": "The command to see",
|
"commandArg": "The command to see",
|
||||||
"unknownCommand": "Unknown command given!"
|
"unknownCommand": "Unknown command given!",
|
||||||
|
"embedName": "Help Menu!",
|
||||||
|
"helpScreenBtnHelp": "Press the \"Forward\" or \"Back\" Button to move categories!",
|
||||||
|
"nextCategoryBtn": "Next Category",
|
||||||
|
"previousCategoryBtn": "Previous Category",
|
||||||
|
"helpTimedOut": "Timed Out",
|
||||||
|
"commandDescription": "Name: { $name }\nCategory: { $category }\nDescription: { $description }\nUsage: { $usage }"
|
||||||
},
|
},
|
||||||
"errors": {
|
"errors": {
|
||||||
"ownerOnly": "Only the bot owner can run this command!",
|
"ownerOnly": "Only the bot owner can run this command!",
|
||||||
|
@ -23,6 +29,7 @@
|
||||||
"generic": {
|
"generic": {
|
||||||
"noShortDescription": "No short description given!",
|
"noShortDescription": "No short description given!",
|
||||||
"noExtendedDescription": "No extended description given!",
|
"noExtendedDescription": "No extended description given!",
|
||||||
"noArgsDescription": "No description for { $arg } has been given!"
|
"noArgsDescription": "No description for { $arg } has been given!",
|
||||||
|
"noUsage": "No usage given!"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Reference in a new issue