Bot Discord - Commit completo con todos los cambios

This commit is contained in:
Admin
2026-01-16 20:24:38 -06:00
commit cf8ecfcf64
151 changed files with 28808 additions and 0 deletions

BIN
assets/css/font/summernote.ttf Executable file

Binary file not shown.

BIN
assets/css/font/summernote.woff Executable file

Binary file not shown.

BIN
assets/css/font/summernote.woff2 Executable file

Binary file not shown.

162
assets/css/style.css Executable file
View File

@@ -0,0 +1,162 @@
/* General Styles */
body {
overflow-x: hidden;
}
/* Estilos para el chat */
#chat-history {
height: 70vh;
overflow-y: auto;
padding: 1rem;
display: flex;
flex-direction: column;
gap: 0.75rem;
}
.message {
max-width: 80%;
padding: 0.75rem 1rem;
border-radius: 1rem;
word-wrap: break-word;
position: relative;
line-height: 1.4;
}
/* Mensajes entrantes */
.message.in {
background-color: #f0f0f0;
color: #333;
align-self: flex-start;
border-bottom-left-radius: 0.25rem;
}
/* Mensajes salientes */
.message.out {
background-color: #007bff;
color: white;
align-self: flex-end;
border-bottom-right-radius: 0.25rem;
}
/* Estilo para el nombre del remitente en grupos */
.message-sender {
font-weight: bold;
font-size: 0.85rem;
margin-bottom: 0.25rem;
}
/* Estilo para el texto del mensaje */
.message-text {
word-wrap: break-word;
}
/* Estilo para el contenedor del formulario de mensajes */
#message-form-container {
padding: 1rem;
border-top: 1px solid #dee2e6;
background-color: #f8f9fa;
}
/* Estilos para la lista de usuarios */
.user-list {
max-height: 80vh;
overflow-y: auto;
}
.user-list .list-group-item {
cursor: pointer;
transition: background-color 0.2s;
}
.user-list .list-group-item:hover {
background-color: #f8f9fa;
}
.user-list .list-group-item.active {
background-color: #007bff;
border-color: #007bff;
}
#wrapper {
display: flex;
transition: all 0.3s ease;
}
#sidebar-wrapper {
min-height: 100vh;
width: 250px;
margin-left: -250px;
transition: margin .25s ease-out;
position: fixed; /* Added for mobile responsiveness */
z-index: 1000; /* Added for mobile responsiveness */
}
#wrapper.toggled #sidebar-wrapper {
margin-left: 0;
}
#page-content-wrapper {
min-width: 100vw;
flex-grow: 1; /* Added for mobile responsiveness */
}
#wrapper.toggled #page-content-wrapper {
min-width: calc(100vw - 250px);
}
.sidebar-heading {
padding: 0.875rem 1.25rem;
font-size: 1.2rem;
}
@media (min-width: 768px) {
#sidebar-wrapper {
margin-left: 0;
position: relative; /* Changed for desktop */
z-index: 1; /* Changed for desktop */
}
#page-content-wrapper {
min-width: 0;
width: 100%;
}
#wrapper.toggled #sidebar-wrapper {
margin-left: -250px;
}
}
/* Overlay for mobile when sidebar is open */
.overlay {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.5);
z-index: 999;
display: none;
opacity: 0; /* Initial opacity */
transition: opacity 0.3s ease-in-out; /* Smooth transition */
}
.overlay.show {
display: block;
opacity: 1; /* Full opacity when shown */
}
/* Estilos para el logo en el sidebar */
#sidebar-logo {
width: 40px; /* Tamaño fijo para el ancho */
height: auto; /* Mantiene la proporción de aspecto */
vertical-align: middle; /* Alinea verticalmente con el texto */
margin-left: 8px; /* Espaciado a la izquierda del logo */
}
.sidebar-heading {
display: flex;
align-items: center; /* Centra verticalmente el texto y el logo */
padding: 0.875rem 1.25rem;
font-size: 1.2rem;
white-space: nowrap; /* Evita que el texto se rompa en varias líneas */
}

1
assets/css/summernote-bs5.min.css vendored Executable file

File diff suppressed because one or more lines are too long

BIN
assets/images/logo.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 MiB

2
assets/js/jquery-3.6.0.min.js vendored Executable file

File diff suppressed because one or more lines are too long

10
assets/js/main.js Executable file
View File

@@ -0,0 +1,10 @@
$(document).ready(function(){
$("#menu-toggle").click(function(e) {
e.preventDefault();
$("#wrapper").toggleClass("toggled");
});
$(".overlay").click(function() {
$("#wrapper").removeClass("toggled");
});
});

2
assets/js/summernote-bs5.min.js vendored Executable file

File diff suppressed because one or more lines are too long

114
assets/js/translate_frontend.js Executable file
View File

@@ -0,0 +1,114 @@
document.addEventListener('DOMContentLoaded', () => {
const languageSelector = document.getElementById('language-selector');
const currentLang = localStorage.getItem('appLang') || 'es'; // Default to Spanish
const translatableElements = document.querySelectorAll('[data-translate="true"]');
// Function to translate text
async function translateText(text, sourceLang, targetLang) {
try {
const response = await fetch('/translate_proxy.php', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
action: 'translate',
text: text,
source: sourceLang,
target: targetLang
}),
});
const data = await response.json();
if (response.ok) {
return data.translatedText; // LibreTranslate returns { translatedText: "..." }
} else {
console.error('Error translating:', data.error);
return text; // Return original text on error
}
} catch (error) {
console.error('Network error during translation:', error);
return text; // Return original text on network error
}
}
async function applyTranslation(targetLang) {
for (const element of translatableElements) {
const originalText = element.dataset.originalText || element.textContent;
if (!element.dataset.originalText) {
element.dataset.originalText = originalText;
}
const icon = element.querySelector('i.bi');
const textToTranslate = originalText.trim();
let newText;
if (targetLang === 'es') {
newText = textToTranslate;
} else {
newText = await translateText(textToTranslate, 'es', targetLang);
}
if (icon) {
element.textContent = ' ' + newText;
element.insertAdjacentHTML('afterbegin', icon.outerHTML);
} else {
element.textContent = newText;
}
}
localStorage.setItem('appLang', targetLang);
if (languageSelector) {
languageSelector.value = targetLang;
}
}
// Function to fetch and populate languages
async function fetchAndPopulateLanguages() {
try {
const response = await fetch('/translate_proxy.php?action=languages'); // Assuming translate_proxy.php can handle a 'languages' action
const languages = await response.json();
if (response.ok && Array.isArray(languages)) {
languageSelector.innerHTML = ''; // Clear existing options
languages.forEach(lang => {
const option = document.createElement('option');
option.value = lang.code;
option.textContent = `${lang.flag_emoji} ${lang.name}`;
languageSelector.appendChild(option);
});
// Set the selector to the current language
languageSelector.value = currentLang;
} else {
console.error('Error fetching languages:', languages.error || 'Unknown error');
// Fallback to default options if fetching fails
languageSelector.innerHTML = `
<option value="es">🇪🇸 Español</option>
<option value="en">🇬🇧 English</option>
<option value="pt">🇧🇷 Português</option>
`;
languageSelector.value = currentLang;
}
} catch (error) {
console.error('Network error fetching languages:', error);
// Fallback to default options if network error
languageSelector.innerHTML = `
<option value="es">🇪🇸 Español</option>
<option value="en">🇬🇧 English</option>
<option value="pt">🇧🇷 Português</option>
`;
languageSelector.value = currentLang;
}
}
// Initial application of language based on stored preference
fetchAndPopulateLanguages().then(() => {
applyTranslation(currentLang);
});
// Event listener for the language selector
if (languageSelector) {
languageSelector.addEventListener('change', (event) => {
const newLang = event.target.value;
applyTranslation(newLang);
});
}
});