refonte css of site

This commit is contained in:
Arthur Puechberty
2026-01-17 20:59:52 +01:00
parent 90339f9323
commit 95cd796839
20 changed files with 2951 additions and 1109 deletions
+28 -16
View File
@@ -1,8 +1,8 @@
const autoroleNewUserForm = document.getElementById("autorole-newuser-form");
const autoroleEnabled = document.getElementById("autorole-enabled");
const autoroleRole = document.getElementById("autorole-role");
const statusAutoroleForm = document.getElementById("status-autorole-form");
const saveAutorole = document.getElementById("save-autorole");
// Charger la config
fetch(`/api/bot/get-autorole-newuser-config/${guildId}`)
.then(res => res.json())
.then(cfg => {
@@ -10,20 +10,32 @@ fetch(`/api/bot/get-autorole-newuser-config/${guildId}`)
autoroleRole.value = cfg.roleId;
});
autoroleNewUserForm.addEventListener("submit", async e => {
e.preventDefault();
// Sauvegarder
saveAutorole.addEventListener("click", async () => {
saveAutorole.disabled = true;
saveAutorole.textContent = "Sauvegarde...";
const res = await fetch("/api/bot/save-autorole-newuser-config", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
guildId,
enabled: autoroleEnabled.checked,
roleId: autoroleRole.value
})
});
try {
const res = await fetch("/api/bot/save-autorole-newuser-config", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
guildId,
enabled: autoroleEnabled.checked,
roleId: autoroleRole.value
})
});
statusAutoroleForm.textContent = (await res.json()).success
? "Auto-rôle sauvegardé ✅"
: "Erreur ❌";
const data = await res.json();
if (data.success) {
showStatus("status-autorole-form", "Configuration sauvegardée ✅", "success");
} else {
showStatus("status-autorole-form", "Erreur lors de la sauvegarde ❌", "error");
}
} catch (error) {
showStatus("status-autorole-form", "Erreur de connexion ❌", "error");
}
saveAutorole.disabled = false;
saveAutorole.textContent = "Sauvegarder";
});
+41 -34
View File
@@ -1,43 +1,50 @@
const autoroleVocalForm = document.getElementById("autorole-vocal-form");
const autoroleVocalEnabled = document.getElementById("autorole-vocal-enabled");
const autoroleVocalRole = document.getElementById("autorole-vocal-role");
const excludeSelect = document.getElementById("autorole-vocal-exclude-channel");
const statusAutoroleVocalForm = document.getElementById("status-autorole-vocal-form");
const saveAutoroleVocal = document.getElementById("save-autorole-vocal");
fetch(`/api/bot/get-voice-channels/${guildId}`)
.then(res => res.json())
.then(channels => {
channels.forEach(c => {
excludeSelect.appendChild(new Option(`#${c.name}`, c.id));
// Charger la config après que les channels soient chargés
setTimeout(() => {
fetch(`/api/bot/get-autorole-vocal-config/${guildId}`)
.then(res => res.json())
.then(cfg => {
autoroleVocalEnabled.checked = cfg.enabled;
autoroleVocalRole.value = cfg.roleId;
Array.from(excludeSelect.options).forEach(opt => {
opt.selected = cfg.excludeChannelIds?.includes(opt.value);
});
});
return fetch(`/api/bot/get-autorole-vocal-config/${guildId}`);
})
.then(res => res.json())
.then(cfg => {
autoroleVocalEnabled.checked = cfg.enabled;
autoroleVocalRole.value = cfg.roleId;
Array.from(excludeSelect.options).forEach(opt => {
opt.selected = cfg.excludeChannelIds?.includes(opt.value);
}, 500);
// Sauvegarder
saveAutoroleVocal.addEventListener("click", async () => {
saveAutoroleVocal.disabled = true;
saveAutoroleVocal.textContent = "Sauvegarde...";
try {
const exclude = Array.from(excludeSelect.selectedOptions).map(o => o.value);
const res = await fetch("/api/bot/save-autorole-vocal-config", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
guildId,
enabled: autoroleVocalEnabled.checked,
roleId: autoroleVocalRole.value,
excludeChannelId: exclude
})
});
});
autoroleVocalForm.addEventListener("submit", async e => {
e.preventDefault();
const data = await res.json();
if (data.success) {
showStatus("status-autorole-vocal-form", "Configuration sauvegardée ✅", "success");
} else {
showStatus("status-autorole-vocal-form", "Erreur lors de la sauvegarde ❌", "error");
}
} catch (error) {
showStatus("status-autorole-vocal-form", "Erreur de connexion ❌", "error");
}
const exclude = Array.from(excludeSelect.selectedOptions).map(o => o.value);
const res = await fetch("/api/bot/save-autorole-vocal-config", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
guildId,
enabled: autoroleVocalEnabled.checked,
roleId: autoroleVocalRole.value,
excludeChannelId: exclude
})
});
statusAutoroleVocalForm.textContent = (await res.json()).success
? "Auto-rôle vocal sauvegardé ✅"
: "Erreur ❌";
saveAutoroleVocal.disabled = false;
saveAutoroleVocal.textContent = "Sauvegarder";
});
+60 -50
View File
@@ -1,4 +1,3 @@
const economyForm = document.getElementById("economy-form");
const economyEnabled = document.getElementById("economy-enabled");
const currencyName = document.getElementById("economy-currency-name");
const currencySymbol = document.getElementById("economy-currency-symbol");
@@ -42,7 +41,7 @@ const voiceMoneyMin = document.getElementById("economy-voice-money-min");
const voiceMoneyMax = document.getElementById("economy-voice-money-max");
const voiceMoneyInterval = document.getElementById("economy-voice-money-interval");
const statusEconomyForm = document.getElementById("status-economy-form");
const saveEconomy = document.getElementById("save-economy");
// Charger la config existante
fetch(`/api/bot/get-economy-config/${guildId}`)
@@ -94,60 +93,71 @@ fetch(`/api/bot/get-economy-config/${guildId}`)
.catch(console.error);
// Sauvegarder la config
economyForm.addEventListener("submit", async e => {
e.preventDefault();
saveEconomy.addEventListener("click", async () => {
saveEconomy.disabled = true;
saveEconomy.textContent = "Sauvegarde...";
const res = await fetch("/api/bot/save-economy-config", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
guildId,
economyEnabled: economyEnabled.checked,
currencyName: currencyName.value,
currencySymbol: currencySymbol.value,
startingBalance: parseInt(startingBalance.value, 10),
try {
const res = await fetch("/api/bot/save-economy-config", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
guildId,
economyEnabled: economyEnabled.checked,
currencyName: currencyName.value,
currencySymbol: currencySymbol.value,
startingBalance: parseInt(startingBalance.value, 10),
// Daily
dailyEnabled: dailyEnabled.checked,
dailyAmount: parseInt(dailyAmount.value, 10),
dailyCooldownHours: parseInt(dailyCooldown.value, 10),
// Daily
dailyEnabled: dailyEnabled.checked,
dailyAmount: parseInt(dailyAmount.value, 10),
dailyCooldownHours: parseInt(dailyCooldown.value, 10),
// Work
workEnabled: workEnabled.checked,
workMinAmount: parseInt(workMin.value, 10),
workMaxAmount: parseInt(workMax.value, 10),
workCooldownMinutes: parseInt(workCooldown.value, 10),
// Work
workEnabled: workEnabled.checked,
workMinAmount: parseInt(workMin.value, 10),
workMaxAmount: parseInt(workMax.value, 10),
workCooldownMinutes: parseInt(workCooldown.value, 10),
// Crime
crimeEnabled: crimeEnabled.checked,
crimeMinAmount: parseInt(crimeMin.value, 10),
crimeMaxAmount: parseInt(crimeMax.value, 10),
crimeSuccessRate: parseInt(crimeSuccess.value, 10),
crimeFinePercent: parseInt(crimeFine.value, 10),
crimeCooldownMinutes: parseInt(crimeCooldown.value, 10),
// Crime
crimeEnabled: crimeEnabled.checked,
crimeMinAmount: parseInt(crimeMin.value, 10),
crimeMaxAmount: parseInt(crimeMax.value, 10),
crimeSuccessRate: parseInt(crimeSuccess.value, 10),
crimeFinePercent: parseInt(crimeFine.value, 10),
crimeCooldownMinutes: parseInt(crimeCooldown.value, 10),
// Steal
stealEnabled: stealEnabled.checked,
stealSuccessRate: parseInt(stealSuccess.value, 10),
stealMaxPercent: parseInt(stealMaxPercent.value, 10),
stealFinePercent: parseInt(stealFine.value, 10),
stealCooldownMinutes: parseInt(stealCooldown.value, 10),
// Steal
stealEnabled: stealEnabled.checked,
stealSuccessRate: parseInt(stealSuccess.value, 10),
stealMaxPercent: parseInt(stealMaxPercent.value, 10),
stealFinePercent: parseInt(stealFine.value, 10),
stealCooldownMinutes: parseInt(stealCooldown.value, 10),
// Message Money
messageMoneyEnabled: messageMoneyEnabled.checked,
messageMoneyMin: parseInt(messageMoneyMin.value, 10),
messageMoneyMax: parseInt(messageMoneyMax.value, 10),
messageMoneyCooldownSeconds: parseInt(messageMoneyCooldown.value, 10),
// Message Money
messageMoneyEnabled: messageMoneyEnabled.checked,
messageMoneyMin: parseInt(messageMoneyMin.value, 10),
messageMoneyMax: parseInt(messageMoneyMax.value, 10),
messageMoneyCooldownSeconds: parseInt(messageMoneyCooldown.value, 10),
// Voice Money
voiceMoneyEnabled: voiceMoneyEnabled.checked,
voiceMoneyMin: parseInt(voiceMoneyMin.value, 10),
voiceMoneyMax: parseInt(voiceMoneyMax.value, 10),
voiceMoneyIntervalMinutes: parseInt(voiceMoneyInterval.value, 10)
})
});
// Voice Money
voiceMoneyEnabled: voiceMoneyEnabled.checked,
voiceMoneyMin: parseInt(voiceMoneyMin.value, 10),
voiceMoneyMax: parseInt(voiceMoneyMax.value, 10),
voiceMoneyIntervalMinutes: parseInt(voiceMoneyInterval.value, 10)
})
});
statusEconomyForm.textContent = (await res.json()).success
? "Config économie sauvegardée ✅"
: "Erreur ❌";
const data = await res.json();
if (data.success) {
showStatus("status-economy-form", "Configuration sauvegardée ✅", "success");
} else {
showStatus("status-economy-form", "Erreur lors de la sauvegarde ❌", "error");
}
} catch (error) {
showStatus("status-economy-form", "Erreur de connexion ❌", "error");
}
saveEconomy.disabled = false;
saveEconomy.textContent = "Sauvegarder";
});
+33 -18
View File
@@ -1,32 +1,47 @@
const goodbyeForm = document.getElementById("goodbye-form");
const goodbyeEnabled = document.getElementById("goodbye-enabled");
const goodbyeChannel = document.getElementById("goodbye-channel");
const goodbyeMessage = document.getElementById("goodbye-message");
const statusGoodbyeForm = document.getElementById("status-goodbye-form");
const saveGoodbye = document.getElementById("save-goodbye");
// Message par défaut
const defaultGoodbyeMessage = "Au revoir **{user}**, on espère te revoir sur **{server}** ! 👋";
// Charger la config
fetch(`/api/bot/get-goodbye-config/${guildId}`)
.then(res => res.json())
.then(cfg => {
goodbyeEnabled.checked = cfg.enabled;
goodbyeChannel.value = cfg.channelId;
goodbyeMessage.value = cfg.message;
goodbyeMessage.value = cfg.message || defaultGoodbyeMessage;
});
goodbyeForm.addEventListener("submit", async e => {
e.preventDefault();
// Sauvegarder
saveGoodbye.addEventListener("click", async () => {
saveGoodbye.disabled = true;
saveGoodbye.textContent = "Sauvegarde...";
const res = await fetch("/api/bot/save-goodbye-config", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
guildId,
goodbyeEnabled: goodbyeEnabled.checked,
channelId: goodbyeChannel.value,
goodbyeMessage: goodbyeMessage.value
})
});
try {
const res = await fetch("/api/bot/save-goodbye-config", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
guildId,
goodbyeEnabled: goodbyeEnabled.checked,
channelId: goodbyeChannel.value,
goodbyeMessage: goodbyeMessage.value
})
});
statusGoodbyeForm.textContent = (await res.json()).success
? "Config au revoir sauvegardée ✅"
: "Erreur ❌";
const data = await res.json();
if (data.success) {
showStatus("status-goodbye-form", "Configuration sauvegardée ✅", "success");
} else {
showStatus("status-goodbye-form", "Erreur lors de la sauvegarde ❌", "error");
}
} catch (error) {
showStatus("status-goodbye-form", "Erreur de connexion ❌", "error");
}
saveGoodbye.disabled = false;
saveGoodbye.textContent = "Sauvegarder";
});
+62 -3
View File
@@ -1,12 +1,55 @@
window.guildId = window.location.pathname.split("/")[2];
// Nom du serveur
// Charger les infos du bot
fetch("/api/bot-info")
.then(res => res.json())
.then(bot => {
const botAvatar = document.getElementById("bot-avatar");
if (botAvatar) {
botAvatar.src = `https://cdn.discordapp.com/avatars/${bot.id}/${bot.avatar}.png`;
}
})
.catch(() => {});
// Charger les infos utilisateur
fetch("/api/user")
.then(res => {
if (!res.ok) throw new Error("Non connecté");
return res.json();
})
.then(user => {
const avatarUrl = `https://cdn.discordapp.com/avatars/${user.id}/${user.avatar}.png`;
const userAvatar = document.getElementById("user-avatar");
const userName = document.getElementById("user-name");
if (userAvatar) userAvatar.src = avatarUrl;
if (userName) userName.textContent = user.username;
})
.catch(() => {
window.location.href = "/auth/login";
});
// Nom et icône du serveur
fetch("/api/guilds")
.then(res => res.json())
.then(guilds => {
const guild = guilds.find(g => g.id === guildId);
document.getElementById("guild-name").textContent =
guild ? `Dashboard : ${guild.name}` : "Serveur introuvable";
const guildName = document.getElementById("guild-name");
const guildIcon = document.getElementById("guild-icon");
const guildIdEl = document.getElementById("guild-id");
const breadcrumbGuild = document.getElementById("breadcrumb-guild");
if (guild) {
if (guildName) guildName.textContent = guild.name;
if (breadcrumbGuild) breadcrumbGuild.textContent = guild.name;
if (guildIdEl) guildIdEl.textContent = `ID: ${guild.id}`;
if (guildIcon && guild.icon) {
guildIcon.src = `https://cdn.discordapp.com/icons/${guild.id}/${guild.icon}.png`;
}
document.title = `${guild.name} - LazyBot`;
} else {
if (guildName) guildName.textContent = "Serveur introuvable";
}
});
// Channels texte
@@ -16,12 +59,26 @@ fetch(`/api/bot/get-text-channels/${guildId}`)
const welcome = document.getElementById("welcome-channel");
const goodbye = document.getElementById("goodbye-channel");
const levelAnnouncements = document.getElementById("level-announcements-channel");
const levelChannelRestrict = document.getElementById("level-channel-with-or-without-xp");
channels.forEach(c => {
const opt = new Option(`#${c.name}`, c.id);
welcome?.appendChild(opt);
goodbye?.appendChild(opt.cloneNode(true));
levelAnnouncements?.appendChild(opt.cloneNode(true));
levelChannelRestrict?.appendChild(opt.cloneNode(true));
});
});
// Channels vocaux
fetch(`/api/bot/get-voice-channels/${guildId}`)
.then(res => res.json())
.then(channels => {
const vocalExclude = document.getElementById("autorole-vocal-exclude-channel");
channels.forEach(c => {
const opt = new Option(`🔊 ${c.name}`, c.id);
vocalExclude?.appendChild(opt);
});
});
@@ -31,10 +88,12 @@ fetch(`/api/bot/get-roles/${guildId}`)
.then(roles => {
const newUser = document.getElementById("autorole-role");
const vocal = document.getElementById("autorole-vocal-role");
const levelRoleRestrict = document.getElementById("level-role-with-or-without-xp");
roles.forEach(r => {
const opt = new Option(r.name, r.id);
newUser?.appendChild(opt);
vocal?.appendChild(opt.cloneNode(true));
levelRoleRestrict?.appendChild(opt.cloneNode(true));
});
});
+78 -90
View File
@@ -1,4 +1,3 @@
const levelForm = document.getElementById("level-form");
const levelEnabled = document.getElementById("level-enabled");
const levelAnnouncementsEnabled = document.getElementById("level-announcement-enabled");
const levelAnnouncementsChannel = document.getElementById("level-announcements-channel");
@@ -18,102 +17,91 @@ const cooldownXpMessageSeconds = document.getElementById("level-xp-cooldown");
const gainXpOnVoice = document.getElementById("voice-xp-enabled");
const gainVoiceXpLowerBound = document.getElementById("level-xp-per-voice-min");
const gainVoiceXpUpperBound = document.getElementById("level-xp-per-voice-max");
const statusLevelForm = document.getElementById("status-level-form");
const saveLevel = document.getElementById("save-level");
// 1️⃣ RÔLES
fetch(`/api/bot/get-roles/${guildId}`)
.then(res => res.json())
.then(roles => {
roles.forEach(r => {
roleWithWithoutXp?.appendChild(new Option(r.name, r.id));
});
// Message par défaut
const defaultLevelMessage = "Félicitations {mention}, tu es maintenant niveau **{level}** ! 🎉";
// 2️⃣ SALONS TEXTE
return fetch(`/api/bot/get-text-channels/${guildId}`);
})
.then(res => res.json())
.then(textSalons => {
textSalons.forEach(c => {
salonWithWithoutXp?.appendChild(new Option(`#${c.name}`, c.id));
});
// Charger la config après que les channels/roles soient chargés
setTimeout(() => {
fetch(`/api/bot/get-level-config/${guildId}`)
.then(res => res.json())
.then(cfg => {
levelEnabled.checked = cfg.enabled;
levelAnnouncementsEnabled.checked = cfg.levelAnnouncementsEnabled;
levelAnnouncementsChannel.value = cfg.levelAnnouncementsChannelId;
levelAnnouncementsMessage.value = cfg.levelAnnouncementsMessage || defaultLevelMessage;
// 3️⃣ SALONS VOCAUX
return fetch(`/api/bot/get-voice-channels/${guildId}`);
})
.then(res => res.json())
.then(voiceSalons => {
voiceSalons.forEach(c => {
salonWithWithoutXp?.appendChild(new Option(`🔊 ${c.name}`, c.id));
});
xpCourbeType.value = cfg.xpCourbeType;
multiplierCourbeForLevel.value = cfg.multiplierCourbeForLevel;
levelAnnouncementEveryLevel.value = cfg.levelAnnouncementEveryLevel;
levelMax.value = cfg.levelMax;
// 4️⃣ CONFIG (APRÈS QUE TOUT EST CHARGÉ)
return fetch(`/api/bot/get-level-config/${guildId}`);
})
.then(res => res.json())
.then(cfg => {
levelEnabled.checked = cfg.enabled;
levelAnnouncementsEnabled.checked = cfg.levelAnnouncementsEnabled;
levelAnnouncementsChannel.value = cfg.levelAnnouncementsChannelId;
levelAnnouncementsMessage.value = cfg.levelAnnouncementsMessage;
roleWithWithoutType.value = cfg.roleWithWithoutType;
Array.from(roleWithWithoutXp.options).forEach(opt => {
opt.selected = cfg.roleWithWithoutXp?.includes(opt.value);
});
xpCourbeType.value = cfg.xpCourbeType;
multiplierCourbeForLevel.value = cfg.multiplierCourbeForLevel;
levelAnnouncementEveryLevel.value = cfg.levelAnnouncementEveryLevel;
levelMax.value = cfg.levelMax;
salonWithWithoutType.value = cfg.salonWithWithoutType;
Array.from(salonWithWithoutXp.options).forEach(opt => {
opt.selected = cfg.salonWithWithoutXp?.includes(opt.value);
});
roleWithWithoutType.value = cfg.roleWithWithoutType;
Array.from(roleWithWithoutXp.options).forEach(opt => {
opt.selected = cfg.roleWithWithoutXp?.includes(opt.value);
});
gainXpOnMessage.checked = cfg.gainXpOnMessage;
gainXpMessageLowerBound.value = cfg.gainXpMessageLowerBound;
gainXpMessageUpperBound.value = cfg.gainXpMessageUpperBound;
cooldownXpMessageSeconds.value = cfg.cooldownXpMessageSeconds;
salonWithWithoutType.value = cfg.salonWithWithoutType;
Array.from(salonWithWithoutXp.options).forEach(opt => {
opt.selected = cfg.salonWithWithoutXp?.includes(opt.value);
});
gainXpOnMessage.checked = cfg.gainXpOnMessage;
gainXpMessageLowerBound.value = cfg.gainXpMessageLowerBound;
gainXpMessageUpperBound.value = cfg.gainXpMessageUpperBound;
cooldownXpMessageSeconds.value = cfg.cooldownXpMessageSeconds;
gainXpOnVoice.checked = cfg.gainXpOnVoice;
gainVoiceXpLowerBound.value = cfg.gainVoiceXpLowerBound;
gainVoiceXpUpperBound.value = cfg.gainVoiceXpUpperBound;
})
.catch(console.error);
levelForm.addEventListener("submit", async e => {
e.preventDefault();
const res = await fetch("/api/bot/save-level-config", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
guildId,
levelEnabled: levelEnabled.checked,
levelAnnouncementsEnabled: levelAnnouncementsEnabled.checked,
levelAnnouncementsChannelId: levelAnnouncementsChannel.value,
levelAnnouncementsMessage: levelAnnouncementsMessage.value,
xpCourbeType: xpCourbeType.value,
multiplierCourbeForLevel: parseInt(multiplierCourbeForLevel.value, 10),
levelAnnouncementEveryLevel: parseInt(levelAnnouncementEveryLevel.value, 10),
levelMax: parseInt(levelMax.value, 10),
roleWithWithoutType: roleWithWithoutType.value,
roleWithWithoutXp: Array.from(roleWithWithoutXp.selectedOptions).map(opt => opt.value),
salonWithWithoutType: salonWithWithoutType.value,
salonWithWithoutXp: Array.from(salonWithWithoutXp.selectedOptions).map(opt => opt.value),
gainXpOnMessage: gainXpOnMessage.checked,
gainXpMessageLowerBound: parseInt(gainXpMessageLowerBound.value, 10),
gainXpMessageUpperBound: parseInt(gainXpMessageUpperBound.value, 10),
cooldownXpMessageSeconds: parseInt(cooldownXpMessageSeconds.value, 10),
gainXpOnVoice: gainXpOnVoice.checked,
gainVoiceXpLowerBound: parseInt(gainVoiceXpLowerBound.value, 10),
gainVoiceXpUpperBound: parseInt(gainVoiceXpUpperBound.value, 10)
gainXpOnVoice.checked = cfg.gainXpOnVoice;
gainVoiceXpLowerBound.value = cfg.gainVoiceXpLowerBound;
gainVoiceXpUpperBound.value = cfg.gainVoiceXpUpperBound;
})
});
.catch(console.error);
}, 500);
statusLevelForm.textContent = (await res.json()).success
? "Config niveaux sauvegardée ✅"
: "Erreur ❌";
// Sauvegarder
saveLevel.addEventListener("click", async () => {
saveLevel.disabled = true;
saveLevel.textContent = "Sauvegarde...";
try {
const res = await fetch("/api/bot/save-level-config", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
guildId,
levelEnabled: levelEnabled.checked,
levelAnnouncementsEnabled: levelAnnouncementsEnabled.checked,
levelAnnouncementsChannelId: levelAnnouncementsChannel.value,
levelAnnouncementsMessage: levelAnnouncementsMessage.value,
xpCourbeType: xpCourbeType.value,
multiplierCourbeForLevel: parseInt(multiplierCourbeForLevel.value, 10),
levelAnnouncementEveryLevel: parseInt(levelAnnouncementEveryLevel.value, 10),
levelMax: parseInt(levelMax.value, 10),
roleWithWithoutType: roleWithWithoutType.value,
roleWithWithoutXp: Array.from(roleWithWithoutXp.selectedOptions).map(opt => opt.value),
salonWithWithoutType: salonWithWithoutType.value,
salonWithWithoutXp: Array.from(salonWithWithoutXp.selectedOptions).map(opt => opt.value),
gainXpOnMessage: gainXpOnMessage.checked,
gainXpMessageLowerBound: parseInt(gainXpMessageLowerBound.value, 10),
gainXpMessageUpperBound: parseInt(gainXpMessageUpperBound.value, 10),
cooldownXpMessageSeconds: parseInt(cooldownXpMessageSeconds.value, 10),
gainXpOnVoice: gainXpOnVoice.checked,
gainVoiceXpLowerBound: parseInt(gainVoiceXpLowerBound.value, 10),
gainVoiceXpUpperBound: parseInt(gainVoiceXpUpperBound.value, 10)
})
});
const data = await res.json();
if (data.success) {
showStatus("status-level-form", "Configuration sauvegardée ✅", "success");
} else {
showStatus("status-level-form", "Erreur lors de la sauvegarde ❌", "error");
}
} catch (error) {
showStatus("status-level-form", "Erreur de connexion ❌", "error");
}
saveLevel.disabled = false;
saveLevel.textContent = "Sauvegarder";
});
+100
View File
@@ -0,0 +1,100 @@
// Navigation sidebar avec hash routing
document.addEventListener('DOMContentLoaded', () => {
const navItems = document.querySelectorAll('.nav-item[data-section]');
const sections = document.querySelectorAll('.config-section');
const sidebar = document.getElementById('sidebar');
const mobileToggle = document.getElementById('mobile-toggle');
// Fonction pour changer de section
function showSection(sectionId) {
// Masquer toutes les sections
sections.forEach(section => {
section.classList.remove('active');
});
// Retirer la classe active de tous les nav items
navItems.forEach(item => {
item.classList.remove('active');
});
// Afficher la section cible
const targetSection = document.getElementById(`section-${sectionId}`);
if (targetSection) {
targetSection.classList.add('active');
}
// Activer le nav item correspondant
const targetNav = document.querySelector(`.nav-item[data-section="${sectionId}"]`);
if (targetNav) {
targetNav.classList.add('active');
}
// Fermer la sidebar sur mobile
if (window.innerWidth <= 900) {
sidebar.classList.remove('open');
}
// Mettre à jour l'URL
window.location.hash = sectionId;
}
// Ajouter les listeners sur les nav items
navItems.forEach(item => {
item.addEventListener('click', (e) => {
e.preventDefault();
const sectionId = item.dataset.section;
showSection(sectionId);
});
});
// Gérer le hash au chargement de la page
function handleHash() {
const hash = window.location.hash.slice(1); // Enlever le #
if (hash && document.getElementById(`section-${hash}`)) {
showSection(hash);
} else {
// Par défaut, afficher la première section
const firstNavItem = navItems[0];
if (firstNavItem) {
showSection(firstNavItem.dataset.section);
}
}
}
// Écouter les changements de hash
window.addEventListener('hashchange', handleHash);
// Charger la section initiale
handleHash();
// Toggle sidebar sur mobile
if (mobileToggle) {
mobileToggle.addEventListener('click', () => {
sidebar.classList.toggle('open');
});
}
// Fermer la sidebar en cliquant à l'extérieur sur mobile
document.addEventListener('click', (e) => {
if (window.innerWidth <= 900) {
if (!sidebar.contains(e.target) && !mobileToggle.contains(e.target)) {
sidebar.classList.remove('open');
}
}
});
});
// Helper function pour afficher les messages de statut
window.showStatus = function(elementId, message, type = 'success') {
const element = document.getElementById(elementId);
if (element) {
element.textContent = message;
element.className = `status-message show ${type}`;
// Masquer après 5 secondes
setTimeout(() => {
element.classList.remove('show');
}, 5000);
}
};
+33 -18
View File
@@ -1,32 +1,47 @@
const welcomeForm = document.getElementById("welcome-form");
const welcomeEnabled = document.getElementById("welcome-enabled");
const welcomeChannel = document.getElementById("welcome-channel");
const welcomeMessage = document.getElementById("welcome-message");
const statusWelcomeForm = document.getElementById("status-welcome-form");
const saveWelcome = document.getElementById("save-welcome");
// Message par défaut
const defaultWelcomeMessage = "Bienvenue {mention} sur **{server}** ! 🎉";
// Charger la config
fetch(`/api/bot/get-welcome-config/${guildId}`)
.then(res => res.json())
.then(cfg => {
welcomeEnabled.checked = cfg.enabled;
welcomeChannel.value = cfg.channelId;
welcomeMessage.value = cfg.message;
welcomeMessage.value = cfg.message || defaultWelcomeMessage;
});
welcomeForm.addEventListener("submit", async e => {
e.preventDefault();
// Sauvegarder
saveWelcome.addEventListener("click", async () => {
saveWelcome.disabled = true;
saveWelcome.textContent = "Sauvegarde...";
const res = await fetch("/api/bot/save-welcome-config", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
guildId,
welcomeEnabled: welcomeEnabled.checked,
channelId: welcomeChannel.value,
welcomeMessage: welcomeMessage.value
})
});
try {
const res = await fetch("/api/bot/save-welcome-config", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
guildId,
welcomeEnabled: welcomeEnabled.checked,
channelId: welcomeChannel.value,
welcomeMessage: welcomeMessage.value
})
});
statusWelcomeForm.textContent = (await res.json()).success
? "Config bienvenue sauvegardée ✅"
: "Erreur ❌";
const data = await res.json();
if (data.success) {
showStatus("status-welcome-form", "Configuration sauvegardée ✅", "success");
} else {
showStatus("status-welcome-form", "Erreur lors de la sauvegarde ❌", "error");
}
} catch (error) {
showStatus("status-welcome-form", "Erreur de connexion ❌", "error");
}
saveWelcome.disabled = false;
saveWelcome.textContent = "Sauvegarder";
});