Enhance welcome module with embed text rendering and autorole management

- Updated the welcome embed functionality to allow for user mentions in titles, authors, and footers, while maintaining clickable mentions in descriptions.
- Implemented autorole assignment logic with checks for role manageability and hierarchy, including detailed logging for skipped roles.
- Improved the WebUI to display real user and guild data in the welcome embed preview, enhancing user experience.
- Refactored the welcome text rendering to support additional options for mention handling based on the context of the embed fields.
This commit is contained in:
smueller
2026-07-24 10:54:33 +02:00
parent ccdf9aafe8
commit 0ebe540c3f
9 changed files with 234 additions and 52 deletions

View File

@@ -171,32 +171,47 @@ export function embedHasContent(embed: WelcomeEmbed | null | undefined): boolean
);
}
/** Text/URL fields of {@link WelcomeEmbed} that pass through {@link mapEmbedTextFields}. */
export type EmbedTextField =
| 'title'
| 'description'
| 'url'
| 'authorName'
| 'authorIconUrl'
| 'authorUrl'
| 'thumbnailUrl'
| 'imageUrl'
| 'footerText'
| 'footerIconUrl';
/**
* Applies a string renderer to every text/URL field of an embed payload.
* Used by Welcome/Tags/Scheduler before handing data to discord.js.
* The second argument names the field so callers can e.g. avoid Discord
* mentions in title/author/footer (Discord does not resolve them there).
*/
export function mapEmbedTextFields(
embed: WelcomeEmbed,
render: (value: string) => string
render: (value: string, field: EmbedTextField) => string
): WelcomeEmbed {
const map = (value: string | undefined): string | undefined => {
const map = (value: string | undefined, field: EmbedTextField): string | undefined => {
if (!value?.trim()) {
return undefined;
}
return render(value);
return render(value, field);
};
return {
title: map(embed.title),
description: map(embed.description),
url: map(embed.url),
title: map(embed.title, 'title'),
description: map(embed.description, 'description'),
url: map(embed.url, 'url'),
color: embed.color,
authorName: map(embed.authorName),
authorIconUrl: map(embed.authorIconUrl),
authorUrl: map(embed.authorUrl),
thumbnailUrl: map(embed.thumbnailUrl),
imageUrl: map(embed.imageUrl),
footerText: map(embed.footerText),
footerIconUrl: map(embed.footerIconUrl),
authorName: map(embed.authorName, 'authorName'),
authorIconUrl: map(embed.authorIconUrl, 'authorIconUrl'),
authorUrl: map(embed.authorUrl, 'authorUrl'),
thumbnailUrl: map(embed.thumbnailUrl, 'thumbnailUrl'),
imageUrl: map(embed.imageUrl, 'imageUrl'),
footerText: map(embed.footerText, 'footerText'),
footerIconUrl: map(embed.footerIconUrl, 'footerIconUrl'),
timestamp: embed.timestamp
};
}