Branding-Tab: Name/Farben/Bot-Status/Avatar/Banner + Button-Farben für Rollen-Menüs
- Alle Embeds nutzen jetzt brandName/brandColor/brandColor2/brandFooter aus den Settings (Codemod über 20 Module) — Farbe & Name serverweit per Klick änderbar - Bot-Status (Presence): Typ (Spielt/Schaut/Hört/Status) + Text, sofort angewendet; Server-Monitor nutzt die Presence nur noch, wenn kein eigener Status gesetzt ist - Avatar-/Banner-Upload direkt aufs Bot-Profil (Base64, 8-MB-Limit, Discord-Rate-Limit sauber gemeldet) - Env-Verlagerung: GITEA_API_TOKEN (write-only Setting) und DISCORD_GUILD_ID jetzt auch über den Brand-Tab pflegbar — weniger Redeploys - Rollen-Menüs: Button-Farbe pro Eintrag wählbar (Grau/Blau/Grün/Rot) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
// /bug — Bug-Report aus Discord: erstellt ein Gitea-Issue (inkl. Screenshot-Upload)
|
||||
import { SlashCommandBuilder, MessageFlags } from 'discord.js';
|
||||
import { config } from '../../config.js';
|
||||
import { bugReportRepo } from '../../runtime-settings.js';
|
||||
|
||||
import { bugReportRepo, giteaApiToken } from '../../runtime-settings.js';
|
||||
import { createIssue, uploadIssueAsset } from '../../gitea-api.js';
|
||||
import { saveBugReport } from '../../db.js';
|
||||
|
||||
@@ -24,7 +24,7 @@ export const data = new SlashCommandBuilder()
|
||||
export async function execute(interaction) {
|
||||
await interaction.deferReply({ flags: MessageFlags.Ephemeral });
|
||||
|
||||
if (!config.giteaApiToken) {
|
||||
if (!giteaApiToken()) {
|
||||
await interaction.editReply('❌ Bug-Reports sind gerade nicht konfiguriert (kein Gitea-Token).');
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import {
|
||||
ActionRowBuilder, ButtonBuilder, ButtonStyle, EmbedBuilder,
|
||||
} from 'discord.js';
|
||||
import { saveGiveaway } from '../../db.js';
|
||||
import { brandColor, brandFooter } from '../../runtime-settings.js';
|
||||
|
||||
/** "30m" / "2h" / "1d" → Millisekunden (null bei Unsinn) */
|
||||
export function parseDuration(input) {
|
||||
@@ -36,13 +37,13 @@ export async function execute(interaction) {
|
||||
const endsAt = new Date(Date.now() + duration);
|
||||
|
||||
const embed = new EmbedBuilder()
|
||||
.setColor(0xf5c518)
|
||||
.setColor(brandColor())
|
||||
.setTitle(`🎉 Giveaway: ${prize}`)
|
||||
.setDescription(
|
||||
`Klick auf den Button zum Teilnehmen!\n\n` +
|
||||
`🏆 **${winners}** Gewinner · ⏰ Ziehung <t:${Math.floor(endsAt.getTime() / 1000)}:R>`
|
||||
)
|
||||
.setFooter({ text: 'D4RKST3R // GIVEAWAY' })
|
||||
.setFooter({ text: brandFooter('GIVEAWAY') })
|
||||
.setTimestamp(endsAt);
|
||||
|
||||
const row = new ActionRowBuilder().addComponents(
|
||||
|
||||
@@ -3,7 +3,7 @@ import {
|
||||
SlashCommandBuilder, PermissionFlagsBits, MessageFlags,
|
||||
ActionRowBuilder, ButtonBuilder, ButtonStyle, EmbedBuilder,
|
||||
} from 'discord.js';
|
||||
import { playtesterRoleId } from '../../runtime-settings.js';
|
||||
import { playtesterRoleId, brandColor, brandFooter } from '../../runtime-settings.js';
|
||||
|
||||
export const data = new SlashCommandBuilder()
|
||||
.setName('playtester-setup')
|
||||
@@ -20,7 +20,7 @@ export async function execute(interaction) {
|
||||
}
|
||||
|
||||
const embed = new EmbedBuilder()
|
||||
.setColor(0xf5c518)
|
||||
.setColor(brandColor())
|
||||
.setTitle('🧪 Playtester werden')
|
||||
.setDescription(
|
||||
'Du willst **EcoGame** vor allen anderen spielen und mit deinem Feedback ' +
|
||||
@@ -29,7 +29,7 @@ export async function execute(interaction) {
|
||||
'sobald die Alpha startet, bekommst du deinen Zugang direkt per DM. ' +
|
||||
'Abmelden geht jederzeit mit einem zweiten Klick.'
|
||||
)
|
||||
.setFooter({ text: 'D4RKST3R // PLAYTEST' });
|
||||
.setFooter({ text: brandFooter('PLAYTEST') });
|
||||
|
||||
const row = new ActionRowBuilder().addComponents(
|
||||
new ButtonBuilder()
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// /purge — Nachrichten im aktuellen Kanal massenlöschen (max 100, jünger als 14 Tage)
|
||||
import { SlashCommandBuilder, PermissionFlagsBits, MessageFlags, EmbedBuilder } from 'discord.js';
|
||||
import { modlogChannelId } from '../../runtime-settings.js';
|
||||
import { modlogChannelId, brandColor2 } from '../../runtime-settings.js';
|
||||
|
||||
export const data = new SlashCommandBuilder()
|
||||
.setName('purge')
|
||||
@@ -29,7 +29,7 @@ export async function execute(interaction) {
|
||||
await channel?.send({
|
||||
embeds: [
|
||||
new EmbedBuilder()
|
||||
.setColor(0xff4d00)
|
||||
.setColor(brandColor2())
|
||||
.setTitle('🧹 Purge')
|
||||
.setDescription(
|
||||
`**${deleted.size}** Nachrichten in <#${interaction.channelId}> gelöscht von **${interaction.user.username}**`
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
import { SlashCommandBuilder, EmbedBuilder } from 'discord.js';
|
||||
import { getLevelRow, rankOf } from '../../db.js';
|
||||
import { xpForLevel } from '../levels.js';
|
||||
import { levelsEnabled, publicUrl } from '../../runtime-settings.js';
|
||||
import { levelsEnabled, publicUrl, brandColor, brandFooter } from '../../runtime-settings.js';
|
||||
|
||||
export const data = new SlashCommandBuilder()
|
||||
.setName('rank')
|
||||
@@ -32,12 +32,12 @@ export async function execute(interaction) {
|
||||
await interaction.reply({
|
||||
embeds: [
|
||||
new EmbedBuilder()
|
||||
.setColor(0xf5c518)
|
||||
.setColor(brandColor())
|
||||
.setAuthor({ name: user.username, iconURL: user.displayAvatarURL({ size: 64 }) })
|
||||
.setTitle(`Level ${row.level} · Platz #${rankOf(user.id)}`)
|
||||
.setDescription(`\`${bar}\` ${pct}%\n**${progress} / ${needed} XP** bis Level ${row.level + 1} · gesamt ${row.xp} XP`)
|
||||
.setURL(`${publicUrl()}/level`)
|
||||
.setFooter({ text: 'D4RKST3R // LEVEL' }),
|
||||
.setFooter({ text: brandFooter('LEVEL') }),
|
||||
],
|
||||
});
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ import {
|
||||
SlashCommandBuilder, PermissionFlagsBits, MessageFlags,
|
||||
ActionRowBuilder, ButtonBuilder, ButtonStyle, EmbedBuilder,
|
||||
} from 'discord.js';
|
||||
import { ticketChannelId } from '../../runtime-settings.js';
|
||||
import { ticketChannelId, brandColor, brandFooter } from '../../runtime-settings.js';
|
||||
|
||||
export const data = new SlashCommandBuilder()
|
||||
.setName('ticket-setup')
|
||||
@@ -20,14 +20,14 @@ export async function execute(interaction) {
|
||||
}
|
||||
|
||||
const embed = new EmbedBuilder()
|
||||
.setColor(0xf5c518)
|
||||
.setColor(brandColor())
|
||||
.setTitle('🎫 Support-Ticket')
|
||||
.setDescription(
|
||||
'Du hast eine Frage, ein Problem oder ein privates Anliegen?\n\n' +
|
||||
'Klick auf den Button — es öffnet sich ein **privater Thread**, ' +
|
||||
'den nur du und das Team sehen können.'
|
||||
)
|
||||
.setFooter({ text: 'D4RKST3R // SUPPORT' });
|
||||
.setFooter({ text: brandFooter('SUPPORT') });
|
||||
|
||||
const row = new ActionRowBuilder().addComponents(
|
||||
new ButtonBuilder()
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// /timeout — Member stummschalten (Discord-Timeout) mit Mod-Log
|
||||
import { SlashCommandBuilder, PermissionFlagsBits, MessageFlags, EmbedBuilder } from 'discord.js';
|
||||
import { parseDuration } from './giveaway.js';
|
||||
import { modlogChannelId } from '../../runtime-settings.js';
|
||||
import { modlogChannelId, brandColor2 } from '../../runtime-settings.js';
|
||||
|
||||
const MAX_TIMEOUT_MS = 28 * 86_400_000; // Discord-Limit
|
||||
|
||||
@@ -42,7 +42,7 @@ export async function execute(interaction) {
|
||||
await channel?.send({
|
||||
embeds: [
|
||||
new EmbedBuilder()
|
||||
.setColor(0xff4d00)
|
||||
.setColor(brandColor2())
|
||||
.setTitle('🔇 Timeout')
|
||||
.addFields(
|
||||
{ name: 'Member', value: `${user.username} (<@${user.id}>)`, inline: true },
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// /warn — Member verwarnen: DB-Eintrag, DM an den User, Mod-Log (Moderatoren)
|
||||
import { SlashCommandBuilder, PermissionFlagsBits, MessageFlags, EmbedBuilder } from 'discord.js';
|
||||
import { addWarn, warnsOf } from '../../db.js';
|
||||
import { modlogChannelId } from '../../runtime-settings.js';
|
||||
import { modlogChannelId, brandColor2 } from '../../runtime-settings.js';
|
||||
|
||||
export const data = new SlashCommandBuilder()
|
||||
.setName('warn')
|
||||
@@ -34,7 +34,7 @@ export async function execute(interaction) {
|
||||
await channel?.send({
|
||||
embeds: [
|
||||
new EmbedBuilder()
|
||||
.setColor(0xff4d00)
|
||||
.setColor(brandColor2())
|
||||
.setTitle(`⚠️ Verwarnung #${count}`)
|
||||
.addFields(
|
||||
{ name: 'Member', value: `${user.username} (<@${user.id}>)`, inline: true },
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// /warns — Verwarnungs-Historie eines Members einsehen / Eintrag löschen (Moderatoren)
|
||||
import { SlashCommandBuilder, PermissionFlagsBits, MessageFlags, EmbedBuilder } from 'discord.js';
|
||||
import { warnsOf, deleteWarn } from '../../db.js';
|
||||
import { brandColor } from '../../runtime-settings.js';
|
||||
|
||||
export const data = new SlashCommandBuilder()
|
||||
.setName('warns')
|
||||
@@ -34,7 +35,7 @@ export async function execute(interaction) {
|
||||
await interaction.reply({
|
||||
embeds: [
|
||||
new EmbedBuilder()
|
||||
.setColor(0xf5c518)
|
||||
.setColor(brandColor())
|
||||
.setTitle(`⚠️ Verwarnungen: ${user.username} (${warns.length})`)
|
||||
.setDescription(lines.join('\n'))
|
||||
.setFooter({ text: 'Löschen: /warns member:<user> loeschen:<ID>' }),
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// /wunsch — Feature-Wunsch einreichen: Voting-Post mit 👍, Rangliste auf der Webseite
|
||||
import { SlashCommandBuilder, MessageFlags, EmbedBuilder } from 'discord.js';
|
||||
import { votingChannelId, publicUrl } from '../../runtime-settings.js';
|
||||
import { votingChannelId, publicUrl, brandColor, brandFooter } from '../../runtime-settings.js';
|
||||
import { saveWish } from '../../db.js';
|
||||
|
||||
export const data = new SlashCommandBuilder()
|
||||
@@ -25,7 +25,7 @@ export async function execute(interaction) {
|
||||
const channel = await interaction.client.channels.fetch(channelId);
|
||||
|
||||
const embed = new EmbedBuilder()
|
||||
.setColor(0xf5c518)
|
||||
.setColor(brandColor())
|
||||
.setAuthor({
|
||||
name: interaction.member?.displayName ?? interaction.user.username,
|
||||
iconURL: interaction.user.displayAvatarURL({ size: 64 }),
|
||||
@@ -33,7 +33,7 @@ export async function execute(interaction) {
|
||||
.setTitle('💡 Feature-Wunsch')
|
||||
.setDescription(idea)
|
||||
.setURL(`${publicUrl()}/roadmap`)
|
||||
.setFooter({ text: 'D4RKST3R // VOTING • 👍 = will ich!' });
|
||||
.setFooter({ text: `${brandFooter('VOTING')} • 👍 = will ich!` });
|
||||
|
||||
const message = await channel.send({ embeds: [embed] });
|
||||
await message.react('👍');
|
||||
|
||||
Reference in New Issue
Block a user