discord-container-builder
Version:
A simplified, developer-friendly API for Discord.js v2 Components that reduces boilerplate and improves code readability.
348 lines (312 loc) • 14.4 kB
JavaScript
const { Client, GatewayIntentBits, ApplicationCommandOptionType } = require('discord.js');
const {
ContainerBuilder,
TextDisplayBuilder,
SeparatorBuilder,
ActionRowBuilder,
ButtonBuilder,
StringSelectMenuBuilder,
SeparatorSpacingSize,
MessageFlags,
EMOJIS,
BUTTON_STYLES
} = require('discord-container-builder');
const client = new Client({
intents: [
GatewayIntentBits.Guilds,
GatewayIntentBits.GuildMessages,
GatewayIntentBits.MessageContent
]
});
// Mock data for demonstration
const mockUsers = new Map();
const mockProducts = [
{ id: 'prod_1', name: 'Premium Bot', price: 9.99, category: 'Discord Bots' },
{ id: 'prod_2', name: 'Music Player', price: 14.99, category: 'Entertainment' },
{ id: 'prod_3', name: 'Moderation Suite', price: 19.99, category: 'Security' }
];
client.on('ready', () => {
console.log(`${client.user.tag} is ready with advanced examples!`);
});
// Example 1: Shopping Cart System
client.on('interactionCreate', async (interaction) => {
if (!interaction.isChatInputCommand()) return;
if (interaction.commandName === 'shop') {
const container = new ContainerBuilder()
.addText(`${EMOJIS.SHOPPING_CART} **Discord Bot Store**`)
.addText("Browse our premium Discord bots and services:")
.addSeparator({ spacing: SeparatorSpacingSize.Medium, divider: true });
// Add product listings
mockProducts.forEach((product, index) => {
container
.addText(`**${product.name}** - $${product.price}`)
.addText(`Category: ${product.category}`)
.addActionRow((row) => {
row.addButton((btn) => btn.asPrimary(`add_to_cart_${product.id}`, 'Add to Cart'))
.addButton((btn) => btn.asSecondary(`view_details_${product.id}`, 'View Details'))
.addButton((btn) => btn.asLink('https://example.com/demo', 'Try Demo'));
});
if (index < mockProducts.length - 1) {
container.addSeparator({ spacing: SeparatorSpacingSize.Small });
}
});
container
.addSeparator({ spacing: SeparatorSpacingSize.Large, divider: true })
.addActionRow((row) => {
row.addButton((btn) => btn.asSuccess('view_cart', 'View Cart'))
.addButton((btn) => btn.asSecondary('filter_products', 'Filter Products'))
.addButton((btn) => btn.asLink('https://example.com/support', 'Contact Support'));
});
await interaction.reply({
components: [container.build()],
flags: MessageFlags.IsComponentsV2,
});
}
// Example 2: Music Player Interface
if (interaction.commandName === 'music') {
const container = new ContainerBuilder()
.addText(`${EMOJIS.MUSICAL_NOTE} **Music Player Dashboard**`)
.addText("Now Playing: **Never Gonna Give You Up** - Rick Astley")
.addText(`${EMOJIS.CLOCK} 2:45 / 3:33`)
.addSeparator({ spacing: SeparatorSpacingSize.Small, divider: true })
.addActionRow((row) => {
row.addButton((btn) => btn.asSecondary('previous_track', '⏮️'))
.addButton((btn) => btn.asPrimary('play_pause', '⏸️'))
.addButton((btn) => btn.asSecondary('next_track', '⏭️'))
.addButton((btn) => btn.asSecondary('shuffle', '🔀'))
.addButton((btn) => btn.asSecondary('repeat', '🔁'));
})
.addActionRow((row) => {
row.addSelectMenu((menu) => {
menu.setCustomId('volume_control')
.setPlaceholder('Volume: 75%')
.addOptions([
{ label: 'Mute', value: 'volume_0', emoji: '🔇' },
{ label: '25%', value: 'volume_25', emoji: '🔈' },
{ label: '50%', value: 'volume_50', emoji: '🔉' },
{ label: '75%', value: 'volume_75', emoji: '🔊' },
{ label: '100%', value: 'volume_100', emoji: '🔊' }
]);
});
})
.addActionRow((row) => {
row.addButton((btn) => btn.asSuccess('add_to_playlist', 'Add to Playlist'))
.addButton((btn) => btn.asSecondary('view_queue', 'View Queue'))
.addButton((btn) => btn.asDanger('clear_queue', 'Clear Queue'));
});
await interaction.reply({
components: [container.build()],
flags: MessageFlags.IsComponentsV2,
});
}
// Example 3: Poll/Voting System
if (interaction.commandName === 'poll') {
const question = interaction.options.getString('question') || 'What should we do next?';
const options = [
interaction.options.getString('option1') || 'Option 1',
interaction.options.getString('option2') || 'Option 2',
interaction.options.getString('option3') || 'Option 3'
].filter(Boolean);
const container = new ContainerBuilder()
.addText(`${EMOJIS.BALLOT_BOX} **Poll: ${question}**`)
.addText(`Created by ${interaction.user.displayName || interaction.user.username}`)
.addSeparator({ spacing: SeparatorSpacingSize.Small, divider: true })
.addText('Vote for your preferred option:')
.addSeparator({ spacing: SeparatorSpacingSize.Small });
// Add voting buttons for each option
const voteRow = new ActionRowBuilder();
options.forEach((option, index) => {
voteRow.addButton((btn) => btn.asPrimary(`vote_${index}`, `${index + 1}. ${option}`));
});
container.addActionRowComponents(voteRow.build());
container
.addSeparator({ spacing: SeparatorSpacingSize.Medium })
.addActionRow((row) => {
row.addButton((btn) => btn.asSecondary('view_results', 'View Results'))
.addButton((btn) => btn.asDanger('end_poll', 'End Poll'))
.addButton((btn) => btn.asSecondary('poll_settings', 'Poll Settings'));
});
await interaction.reply({
components: [container.build()],
flags: MessageFlags.IsComponentsV2,
});
}
// Example 4: Server Management Dashboard
if (interaction.commandName === 'dashboard') {
const guild = interaction.guild;
const container = new ContainerBuilder()
.addText(`${EMOJIS.SHIELD} **${guild.name} Management Dashboard**`)
.addText(`Server ID: ${guild.id} • Members: ${guild.memberCount}`)
.addSeparator({ spacing: SeparatorSpacingSize.Medium, divider: true })
.addText(`${EMOJIS.CHART} **Quick Stats:**`)
.addText(`Online Members: ${guild.members.cache.filter(m => m.presence?.status === 'online').size || 'N/A'}`)
.addText(`Text Channels: ${guild.channels.cache.filter(c => c.type === 0).size}`)
.addText(`Voice Channels: ${guild.channels.cache.filter(c => c.type === 2).size}`)
.addSeparator({ spacing: SeparatorSpacingSize.Small, divider: true })
.addActionRow((row) => {
row.addSelectMenu((menu) => {
menu.setCustomId('dashboard_section')
.setPlaceholder('Select management section...')
.addOptions([
{ label: 'Member Management', value: 'members', emoji: '👥' },
{ label: 'Channel Management', value: 'channels', emoji: '📝' },
{ label: 'Role Management', value: 'roles', emoji: '🎭' },
{ label: 'Moderation Logs', value: 'moderation', emoji: '🛡️' },
{ label: 'Server Analytics', value: 'analytics', emoji: '📊' }
]);
});
})
.addActionRow((row) => {
row.addButton((btn) => btn.asPrimary('quick_setup', 'Quick Setup'))
.addButton((btn) => btn.asSecondary('backup_server', 'Backup Settings'))
.addButton((btn) => btn.asDanger('emergency_lockdown', 'Emergency Lockdown'));
});
await interaction.reply({
components: [container.build()],
flags: MessageFlags.IsComponentsV2,
});
}
});
// Complex button interaction handling
client.on('interactionCreate', async (interaction) => {
if (!interaction.isButton()) return;
// Shopping cart system
if (interaction.customId.startsWith('add_to_cart_')) {
const productId = interaction.customId.replace('add_to_cart_', '');
const product = mockProducts.find(p => p.id === productId);
if (!mockUsers.has(interaction.user.id)) {
mockUsers.set(interaction.user.id, { cart: [], favorites: [] });
}
const userData = mockUsers.get(interaction.user.id);
userData.cart.push(product);
const container = new ContainerBuilder()
.addText(`${EMOJIS.SUCCESS} **Added to Cart!**`)
.addText(`**${product.name}** has been added to your cart.`)
.addSeparator({ spacing: SeparatorSpacingSize.Small, divider: true })
.addText(`${EMOJIS.SHOPPING_CART} Cart Items: ${userData.cart.length}`)
.addText(`${EMOJIS.MONEY_BAG} Total: $${userData.cart.reduce((sum, p) => sum + p.price, 0).toFixed(2)}`)
.addActionRow((row) => {
row.addButton((btn) => btn.asPrimary('view_cart', 'View Cart'))
.addButton((btn) => btn.asSuccess('checkout', 'Checkout'))
.addButton((btn) => btn.asSecondary('continue_shopping', 'Continue Shopping'));
});
await interaction.update({
components: [container.build()],
flags: MessageFlags.IsComponentsV2,
});
}
// Music player controls
if (interaction.customId === 'play_pause') {
const isPlaying = Math.random() > 0.5; // Mock state
const container = new ContainerBuilder()
.addText(`${EMOJIS.MUSICAL_NOTE} **Music Player Dashboard**`)
.addText(`Now Playing: **Never Gonna Give You Up** - Rick Astley`)
.addText(`${EMOJIS.CLOCK} 2:45 / 3:33 ${isPlaying ? '⏸️ Paused' : '▶️ Playing'}`)
.addSeparator({ spacing: SeparatorSpacingSize.Small, divider: true })
.addActionRow((row) => {
row.addButton((btn) => btn.asSecondary('previous_track', '⏮️'))
.addButton((btn) => btn.asPrimary('play_pause', isPlaying ? '▶️' : '⏸️'))
.addButton((btn) => btn.asSecondary('next_track', '⏭️'))
.addButton((btn) => btn.asSecondary('shuffle', '🔀'))
.addButton((btn) => btn.asSecondary('repeat', '🔁'));
})
.addActionRow((row) => {
row.addButton((btn) => btn.asSuccess('add_to_playlist', 'Add to Playlist'))
.addButton((btn) => btn.asSecondary('view_queue', 'View Queue'))
.addButton((btn) => btn.asDanger('clear_queue', 'Clear Queue'));
});
await interaction.update({
components: [container.build()],
flags: MessageFlags.IsComponentsV2,
});
}
// Poll voting
if (interaction.customId.startsWith('vote_')) {
const optionIndex = parseInt(interaction.customId.replace('vote_', ''));
const container = new ContainerBuilder()
.addText(`${EMOJIS.SUCCESS} **Vote Recorded!**`)
.addText(`You voted for option ${optionIndex + 1}`)
.addSeparator({ spacing: SeparatorSpacingSize.Small, divider: true })
.addText(`${EMOJIS.CHART} **Current Results:**`)
.addText('Option 1: ████████░░ 45%')
.addText('Option 2: ██████░░░░ 30%')
.addText('Option 3: █████░░░░░ 25%')
.addSeparator({ spacing: SeparatorSpacingSize.Small })
.addText(`Total votes: 127`)
.addActionRow((row) => {
row.addButton((btn) => btn.asSecondary('change_vote', 'Change Vote'))
.addButton((btn) => btn.asPrimary('share_poll', 'Share Poll'))
.addButton((btn) => btn.asSecondary('poll_details', 'Poll Details'));
});
await interaction.update({
components: [container.build()],
flags: MessageFlags.IsComponentsV2,
});
}
});
// Select menu interaction handling
client.on('interactionCreate', async (interaction) => {
if (!interaction.isStringSelectMenu()) return;
if (interaction.customId === 'dashboard_section') {
const section = interaction.values[0];
const sectionData = {
members: {
title: 'Member Management',
emoji: '👥',
stats: 'Active: 1,234 • New Today: 45 • Banned: 12'
},
channels: {
title: 'Channel Management',
emoji: '📝',
stats: 'Text: 25 • Voice: 8 • Categories: 5'
},
roles: {
title: 'Role Management',
emoji: '🎭',
stats: 'Total Roles: 15 • Hoisted: 8 • Mentionable: 6'
}
};
const data = sectionData[section] || sectionData.members;
const container = new ContainerBuilder()
.addText(`${data.emoji} **${data.title}**`)
.addText(`Server: ${interaction.guild.name}`)
.addSeparator({ spacing: SeparatorSpacingSize.Small, divider: true })
.addText(`${EMOJIS.CHART} **Statistics:**`)
.addText(data.stats)
.addSeparator({ spacing: SeparatorSpacingSize.Medium })
.addActionRow((row) => {
row.addButton((btn) => btn.asPrimary(`manage_${section}`, 'Manage'))
.addButton((btn) => btn.asSecondary(`view_${section}`, 'View All'))
.addButton((btn) => btn.asSecondary(`export_${section}`, 'Export Data'));
})
.addActionRow((row) => {
row.addButton((btn) => btn.asSecondary('back_to_dashboard', 'Back to Dashboard'))
.addButton((btn) => btn.asLink('https://example.com/docs', 'Documentation'));
});
await interaction.update({
components: [container.build()],
flags: MessageFlags.IsComponentsV2,
});
}
if (interaction.customId === 'volume_control') {
const volume = interaction.values[0].replace('volume_', '');
const container = new ContainerBuilder()
.addText(`${EMOJIS.MUSICAL_NOTE} **Music Player Dashboard**`)
.addText("Now Playing: **Never Gonna Give You Up** - Rick Astley")
.addText(`${EMOJIS.CLOCK} 2:45 / 3:33 • Volume: ${volume}%`)
.addSeparator({ spacing: SeparatorSpacingSize.Small, divider: true })
.addText(`${EMOJIS.SUCCESS} Volume updated to ${volume}%`)
.addActionRow((row) => {
row.addButton((btn) => btn.asSecondary('previous_track', '⏮️'))
.addButton((btn) => btn.asPrimary('play_pause', '⏸️'))
.addButton((btn) => btn.asSecondary('next_track', '⏭️'))
.addButton((btn) => btn.asSecondary('shuffle', '🔀'))
.addButton((btn) => btn.asSecondary('repeat', '🔁'));
});
await interaction.update({
components: [container.build()],
flags: MessageFlags.IsComponentsV2,
});
}
});
client.login(process.env.DISCORD_TOKEN);