Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,6 @@ MODERATORS_ROLE_IDS= # Comma separated list of role IDs that are Moderators(Mods
REPEL_LOG_CHANNEL_ID= # Channel ID where the bot will log repel actions
REPEL_ROLE_ID= # Role ID assigned to users who can use the repel command
GUIDES_CHANNEL_ID="" # The ID of the channel where guides will be posted

ONBOARDING_CHANNEL_ID= # Channel ID where onboarding messages will be sent
ONBOARDING_ROLE_ID= # Role ID assigned to new members upon onboarding
2 changes: 2 additions & 0 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ jobs:
REPEL_LOG_CHANNEL_ID=${{ secrets.REPEL_LOG_CHANNEL_ID }}
REPEL_ROLE_ID=${{ secrets.REPEL_ROLE_ID }}
MODERATORS_ROLE_IDS=${{ secrets.MODERATORS_ROLE_IDS }}
ONBOARDING_CHANNEL_ID=${{ secrets.ONBOARDING_CHANNEL_ID }}
ONBOARDING_ROLE_ID=${{ secrets.ONBOARDING_ROLE_ID }}
EOF

# Stop any existing containers
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
"dependencies": {
"discord.js": "^14.22.1",
"typescript": "^5.9.3",
"web-features": "^3.3.0"
"web-features": "^3.7.0"
},
"devDependencies": {
"@biomejs/biome": "2.2.4",
Expand Down
10 changes: 5 additions & 5 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 5 additions & 1 deletion src/commands/docs/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,11 @@ export const executeDocCommand = async (
}
};

export const NON_BASELINE_FEATURES = ['numeric-seperators', 'single-color-gradients'];
export const NON_BASELINE_FEATURES = [
'numeric-seperators',
'open-closed',
'single-color-gradients',
];
export const getBaselineFeatures = (
originalFeatures: Record<string, unknown>,
nonFeatureKeys: string[] = NON_BASELINE_FEATURES
Expand Down
11 changes: 10 additions & 1 deletion src/commands/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,21 @@ import { docsCommands } from './docs/index.js';
import { guidesCommand } from './guides/index.js';
import cacheMessages from './moderation/cache-messages.js';
import { repelCommand } from './moderation/repel.js';
import { onboardingCommand } from './onboarding/index.js';
import { pingCommand } from './ping.js';
import { tipsCommands } from './tips/index.js';
import type { Command } from './types.js';

export const commands = new Map<string, Command>(
[pingCommand, guidesCommand, docsCommands, tipsCommands, repelCommand, cacheMessages]
[
pingCommand,
guidesCommand,
docsCommands,
tipsCommands,
repelCommand,
cacheMessages,
onboardingCommand,
]
.flat()
.map((cmd) => [cmd.data.name, cmd])
);
2 changes: 1 addition & 1 deletion src/commands/moderation/repel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ import {
} from 'discord.js';
import { HOUR, MINUTE, timeToString } from '../../constants/time.js';
import { config } from '../../env.js';
import { logToChannel } from '../../util/channel-logging.js';
import { getPublicChannels } from '../../util/channel.js';
import { logToChannel } from '../../util/channel-logging.js';
import { buildCommandString, createCommand } from '../../util/commands.js';

const DEFAULT_LOOK_BACK_MS = 10 * MINUTE;
Expand Down
21 changes: 21 additions & 0 deletions src/commands/onboarding/component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import {
ActionRowBuilder,
ButtonBuilder,
ButtonStyle,
ContainerBuilder,
type MessageActionRowComponentBuilder,
} from 'discord.js';

const containerComponent = new ContainerBuilder();

const actionRowComponent = new ActionRowBuilder<MessageActionRowComponentBuilder>();

const buttonComponent = new ButtonBuilder()
.setCustomId('onboarding_add_role')
.setLabel('Add role')
.setStyle(ButtonStyle.Primary);

actionRowComponent.addComponents(buttonComponent);
containerComponent.addActionRowComponents(actionRowComponent);

export { containerComponent };
65 changes: 65 additions & 0 deletions src/commands/onboarding/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import { ApplicationCommandType, MessageFlags } from 'discord.js';
import { config } from '../../env.js';
import { createCommand } from '../../util/commands.js';
import { containerComponent } from './component.js';

export const onboardingCommand = createCommand({
data: {
name: 'onboarding',
description: 'Manage onboarding settings',
type: ApplicationCommandType.ChatInput,
},
execute: async (interaction) => {
const guild = interaction.guild;
if (!guild) {
await interaction.reply({
content: 'This command can only be used in a server.',
flags: MessageFlags.Ephemeral,
});
return;
}
Comment on lines +15 to +21
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

idea for future: should add a custom function that does exactly this check.

const onboardingRole = guild.roles.cache.get(config.onboarding.roleId);
if (!onboardingRole) {
await interaction.reply({
content: 'Onboarding role not found. Please check the configuration.',
flags: MessageFlags.Ephemeral,
});
return;
}
const onboardingChannel = guild.channels.cache.get(config.onboarding.channelId);
if (!onboardingChannel || !onboardingChannel.isSendable()) {
await interaction.reply({
content:
'Onboarding channel not found or is not a text channel. Please check the configuration.',
flags: MessageFlags.Ephemeral,
});
return;
}

const onboardingMessage = await interaction.reply({
components: [containerComponent],
flags: MessageFlags.IsComponentsV2,
});

const collector = onboardingMessage.createMessageComponentCollector({});

collector.on('collect', async (componentInteraction) => {
if (componentInteraction.customId === 'onboarding_add_role') {
const member = await guild.members.fetch(componentInteraction.user.id);
const hasRole = member.roles.cache.has(onboardingRole.id);
if (hasRole) {
await componentInteraction.reply({
content: `You already have the ${onboardingRole.name} role.`,
flags: MessageFlags.Ephemeral,
});
} else {
await member.roles.add(onboardingRole);
await componentInteraction.reply({
content: `You have been given the ${onboardingRole.name} role!`,
flags: MessageFlags.Ephemeral,
});
}
}
});
},
});
4 changes: 4 additions & 0 deletions src/env.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@ export const config = {
channelId: requireEnv('GUIDES_CHANNEL_ID'),
trackerPath: optionalEnv('GUIDES_TRACKER_PATH'),
},
onboarding: {
channelId: requireEnv('ONBOARDING_CHANNEL_ID'),
roleId: requireEnv('ONBOARDING_ROLE_ID'),
},
// Add more config sections as needed:
// database: {
// url: requireEnv('DATABASE_URL'),
Expand Down