Die Seite hieß Setup und listete 15 Bereiche flach untereinander. Wer nicht wusste, dass Geburtstage unter „Community" stecken und Willkommens- Texte unter „Support", hat geklickt bis er es fand. Die Seitenleiste gruppiert jetzt nach Überblick, Auftritt, Inhalte, Community, Technik und Zugang. Darüber steht ein Suchfeld, das nicht nur Beschriftungen durchsucht, sondern auch Stichwörter je Bereich — „geburtstag" führt zu Community, „ticket" zu Support. Enter springt zum ersten Treffer. Der aktive Bereich steht in der Adresse (/settings#texte). Damit überlebt er das Neuladen, und man kann jemandem einen Link auf genau die Stelle schicken. Der Status-Bereich war die leerste Seite im ganzen Panel: sechs Zahlen. Er ist jetzt der Einstieg und beantwortet die Frage, die man beim Öffnen wirklich hat — was läuft noch nicht? Eingeschaltete Module, denen ein Kanal oder eine Rolle fehlt, stehen dort mit einem Knopf, der direkt an die richtige Stelle springt. Ist alles eingerichtet, sagt die Seite genau das. Umbenannt in „Config", weil „Setup" nach einmaliger Einrichtung klingt — die Seite ist aber der Ort, an dem man dauerhaft alles einstellt. Schmale Bildschirme: die Leiste wird zur umbrechenden Zeile ohne Gruppen-Überschriften, das Suchfeld nimmt die volle Breite. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
54 lines
2.3 KiB
JavaScript
54 lines
2.3 KiB
JavaScript
// Release-Ankündigungen: großes Embed in den konfigurierten Kanal (Config-Seite)
|
|
import { ActionRowBuilder, ButtonBuilder, ButtonStyle, EmbedBuilder } from 'discord.js';
|
|
import { releaseChannelId, publicUrl, brandColor2, brandFooter } from '../runtime-settings.js';
|
|
import { config } from '../config.js';
|
|
import { moduleEnabled } from '../modules.js';
|
|
|
|
|
|
/**
|
|
* Release ankündigen (falls ein Kanal konfiguriert ist).
|
|
* @param {import('discord.js').Client} client
|
|
* @param {{ repo: string, tag: string, name: string|null, body: string|null,
|
|
* url: string|null, prerelease: boolean }} release
|
|
* @returns {Promise<boolean>} true, wenn gepostet
|
|
*/
|
|
export async function postReleaseEmbed(client, release) {
|
|
if (!moduleEnabled('releases')) return false;
|
|
const channelId = releaseChannelId();
|
|
if (!channelId) return false;
|
|
|
|
const channel = await client.channels.fetch(channelId);
|
|
if (!channel?.isTextBased()) {
|
|
throw new Error(`Release-Kanal ${channelId} nicht gefunden oder kein Textkanal`);
|
|
}
|
|
|
|
let body = (release.body ?? '').trim();
|
|
if (body.length > 3500) body = `${body.slice(0, 3500)}\n… (gekürzt)`;
|
|
|
|
const title = release.name?.trim() || release.tag;
|
|
const embed = new EmbedBuilder()
|
|
.setColor(brandColor2())
|
|
.setTitle(`🚀 ${title}${release.prerelease ? ' (Pre-Release)' : ''}`)
|
|
.setDescription(body || '*Keine Release-Notes.*')
|
|
.addFields({ name: 'Version', value: `\`${release.tag}\``, inline: true },
|
|
{ name: 'Projekt', value: release.repo, inline: true })
|
|
.setFooter({ text: brandFooter('RELEASE'), iconURL: client?.user?.displayAvatarURL?.({ size: 64 }) })
|
|
.setTimestamp();
|
|
|
|
const buttons = new ActionRowBuilder().addComponents(
|
|
new ButtonBuilder().setStyle(ButtonStyle.Link).setLabel('Changelog').setEmoji('📋')
|
|
.setURL(`${publicUrl()}/changelog`)
|
|
);
|
|
if (release.url) {
|
|
buttons.addComponents(
|
|
new ButtonBuilder().setStyle(ButtonStyle.Link).setLabel('Release ansehen').setEmoji('🔗')
|
|
.setURL(release.url)
|
|
);
|
|
}
|
|
|
|
const message = await channel.send({ embeds: [embed], components: [buttons] });
|
|
const { maybeCrosspost } = await import('../embeds.js');
|
|
await maybeCrosspost(message);
|
|
return true;
|
|
}
|