Implement PlaceholderHelp component across various forms for enhanced user guidance

- Integrated PlaceholderHelp component into multiple forms including WelcomeForm, TagsManager, and StatsForm to provide contextual hints for available placeholders.
- Updated DiscordEmbedBuilder to support placeholder presets, improving user experience when creating embeds.
- Enhanced localization files to include new placeholder descriptions, ensuring clarity in both English and German.
- Refactored related components to maintain consistency in placeholder handling across the application.
This commit is contained in:
TheOnlyMace
2026-07-22 22:07:08 +02:00
parent 55a4f7bf09
commit 8cfb149a18
21 changed files with 583 additions and 98 deletions

View File

@@ -17,6 +17,16 @@ describe('phase2 helpers', () => {
expect(result).toBe('Hello <@1> on Nexumi');
});
it('expands bracket channel mentions', () => {
const result = applyWelcomePlaceholders('Join ["123456789012345678"] please', {});
expect(result).toBe('Join <#123456789012345678> please');
});
it('keeps native discord channel mentions', () => {
const result = applyWelcomePlaceholders('Join <#123456789012345678> please', {});
expect(result).toBe('Join <#123456789012345678> please');
});
it('detects discord invites', () => {
expect(isDiscordInvite('join https://discord.gg/test')).toBe(true);
expect(isDiscordInvite('hello world')).toBe(false);

View File

@@ -162,14 +162,23 @@ export const WELCOME_PLACEHOLDERS = [
'{memberCount}'
] as const;
/**
* Expands dashboard-friendly channel mentions `["123…"]` into Discord's
* native `<#123…>` mention format. Raw `<#id>` mentions are left untouched.
*/
export function expandBracketChannelMentions(template: string): string {
return template.replace(/\["(\d{17,20})"\]/g, '<#$1>');
}
export function applyWelcomePlaceholders(
template: string,
vars: Record<string, string | number>
): string {
return Object.entries(vars).reduce(
const withVars = Object.entries(vars).reduce(
(acc, [name, value]) => acc.replaceAll(`{${name}}`, String(value)),
template
);
return expandBracketChannelMentions(withVars);
}
export function countEmojis(content: string): number {

View File

@@ -38,14 +38,17 @@ export const SuggestionStatusSchema = z.enum([
]);
export type SuggestionStatus = z.infer<typeof SuggestionStatusSchema>;
import { expandBracketChannelMentions } from './phase2.js';
export function applyTagPlaceholders(
template: string,
vars: Record<string, string>
): string {
return Object.entries(vars).reduce(
const withVars = Object.entries(vars).reduce(
(acc, [key, value]) => acc.replaceAll(`{${key}}`, value),
template
);
return expandBracketChannelMentions(withVars);
}
export function pickRandomWinners<T>(items: T[], count: number): T[] {