diff --git a/src/commands/generals/help.ts b/src/commands/generals/help.ts index 261f3a3..cb25f46 100644 --- a/src/commands/generals/help.ts +++ b/src/commands/generals/help.ts @@ -1,7 +1,14 @@ +import type { CategoryByEnglish } from '../../lib/commandCategory' import type { Context } from '../../lib/context' import { ApplyOptions } from '@sapphire/decorators' import { Args, Command } from '@sapphire/framework' -import type { ChatInputCommandInteraction, Message } from 'discord.js' +import { + Message, + ChatInputCommandInteraction, + EmbedBuilder, + codeBlock, + inlineCode, +} from 'discord.js' @ApplyOptions({ name: '도움말', @@ -9,6 +16,27 @@ import type { ChatInputCommandInteraction, Message } from 'discord.js' description: '기본적인 사용ㅂ법이에요.', }) export default class HelpCommand extends Command { + public registerApplicationCommands(registry: Command.Registry) { + const commands = this.container.stores.get('commands').map(command => { + return { + name: command.name, + value: command.name, + } + }) + + registry.registerChatInputCommand(builder => + builder + .setName(this.name) + .setDescription(this.description) + .addStringOption(option => + option + .setName('명령어') + .setDescription('해당 명령어에 대ㅎ한 도움말을 볼 수 있어요.') + .addChoices(commands), + ), + ) + } + public async messageRun(msg: Message, args: Args) { return await this._run(msg, args) } @@ -19,5 +47,92 @@ export default class HelpCommand extends Command { return await this._run(interaction) } - private async _run(ctx: Context, args?: Args) {} + private async _run(ctx: Context, args?: Args) { + const commands = this.container.stores.get('commands') + const commandName = + ctx instanceof Message + ? await args!.rest('string').catch(() => null) + : ctx.options.getString('명령어') + + const embed = new EmbedBuilder() + .setColor(this.container.embedColors.default) + .setFooter({ text: `버전: ${this.container.version}` }) + .setThumbnail(ctx.client.user.displayAvatarURL()) + + if (!commandName || !commands.get(commandName)) + return await ctx.reply({ + embeds: [ + embed.setTitle(`${ctx.client.user.username}의 도움말`).setDescription( + codeBlock( + 'md', + '# 일반\n' + + this._getCommandsByCategory('generals') + .map(command => `- ${command?.name}: ${command?.description}`) + .join('\n') + + '\n\n' + + '# 채팅\n' + + this._getCommandsByCategory('chattings') + .map(command => `- ${command?.name}: ${command?.description}`) + .join('\n'), + ), + ), + ], + }) + + const { name, aliases, description, detailedDescription } = + commands.get(commandName)! + + if (typeof detailedDescription === 'string') return + + return await ctx.reply({ + embeds: [ + embed + .setTitle(`${ctx.client.user.username}의 ${name} 도움말`) + .addFields( + { + name: '설명', + value: inlineCode(description), + inline: true, + }, + { + name: '사용법', + value: inlineCode(detailedDescription.usage), + inline: true, + }, + aliases.length < 1 + ? { + name: '별칭', + value: '없음', + } + : { + name: '별칭', + value: codeBlock( + 'md', + aliases.map(alias => `- ${alias}`).join('\n'), + ), + }, + !detailedDescription.examples + ? { + name: '예시', + value: '없음', + } + : { + name: '예시', + value: codeBlock( + 'md', + detailedDescription.examples + ?.map(example => `- ${example}`) + .join('\n'), + ), + }, + ), + ], + }) + } + + private _getCommandsByCategory(category: CategoryByEnglish) { + return this.container.stores.get('commands').filter(command => { + if (command.fullCategory.includes(category)) return command + }) + } } diff --git a/src/init.ts b/src/init.ts index ec41927..b201ce2 100644 --- a/src/init.ts +++ b/src/init.ts @@ -31,7 +31,7 @@ declare module '@sapphire/framework' { container.dbDisconnect = async () => await disconnect() container.config = new Config() container.prefix = container.config.bot.prefix -container.version = '5.0.0-yogurt_canary.250315a' +container.version = '5.0.0-yogurt_canary.250317a' container.embedColors = { default: 0xaddb87, fail: 0xff0000,