Update conversations.php
This commit is contained in:
+203
-101
@@ -556,20 +556,59 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 768px) {
|
@media (max-width: 768px) {
|
||||||
|
/* Fullscreen sidebar that can slide in/out */
|
||||||
|
.chat-container { padding: 0; gap: 0; }
|
||||||
.chat-sidebar {
|
.chat-sidebar {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
position: absolute;
|
position: fixed;
|
||||||
z-index: 1000;
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
z-index: 1100;
|
||||||
height: 100vh;
|
height: 100vh;
|
||||||
|
transform: translateX(0);
|
||||||
|
transition: transform 240ms ease;
|
||||||
|
box-shadow: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Hidden by default on mobile. .open will show it */
|
||||||
|
.chat-sidebar.mobile-hidden { transform: translateX(-110%); }
|
||||||
|
|
||||||
.chat-main {
|
.chat-main {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
margin-left: 0;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
height: 100vh;
|
||||||
}
|
}
|
||||||
|
|
||||||
.chat-sidebar.show-chat {
|
/* Header adjustment */
|
||||||
transform: translateX(-100%);
|
.chat-header { padding: 10px 12px; gap: 8px; }
|
||||||
|
.chat-header-avatar { width: 38px; height: 38px; }
|
||||||
|
|
||||||
|
/* Fix input to bottom to emulate mobile chat apps */
|
||||||
|
.chat-input {
|
||||||
|
position: fixed;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
padding: 10px;
|
||||||
|
background: #fff;
|
||||||
|
z-index: 1200;
|
||||||
|
border-top: 1px solid #e9eef2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Give chat area bottom padding so messages are not hidden under input */
|
||||||
|
.chat-conversations { padding-bottom: 120px; }
|
||||||
|
|
||||||
|
/* Compact avatars and message bubble width */
|
||||||
|
.conversation-avatar { width: 40px; height: 40px; }
|
||||||
|
.message-bubble { max-width: 85%; font-size: 15px; }
|
||||||
|
|
||||||
|
/* Quick replies panel adapt */
|
||||||
|
.quick-replies-panel { left: 8px; right: 8px; bottom: 70px; max-height: 160px; }
|
||||||
|
|
||||||
|
/* Show a small back button in header to open sidebar */
|
||||||
|
#sidebar-toggle { display: inline-flex; }
|
||||||
}
|
}
|
||||||
|
|
||||||
.reply-preview {
|
.reply-preview {
|
||||||
@@ -652,6 +691,7 @@
|
|||||||
|
|
||||||
<div id="chat-area" style="display: none; height: 100%; flex-direction: column;">
|
<div id="chat-area" style="display: none; height: 100%; flex-direction: column;">
|
||||||
<div class="chat-header">
|
<div class="chat-header">
|
||||||
|
<button id="sidebar-toggle" class="btn btn-sm btn-outline-light d-md-none me-2" style="display:none; border-radius:8px; padding:6px 8px;" title="Volver a conversaciones"><i class="fas fa-bars"></i></button>
|
||||||
<div class="chat-header-avatar" id="chat-avatar">
|
<div class="chat-header-avatar" id="chat-avatar">
|
||||||
<i class="fas fa-user"></i>
|
<i class="fas fa-user"></i>
|
||||||
</div>
|
</div>
|
||||||
@@ -966,25 +1006,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
openBtn.className = notification.cool ? 'btn btn-sm btn-light' : 'btn btn-sm btn-primary';
|
|
||||||
openBtn.textContent = 'Abrir';
|
|
||||||
openBtn.onclick = async () => {
|
|
||||||
try {
|
|
||||||
await fetch('api/mark_notification_read.php', {method:'POST', headers:{'Content-Type':'application/json'}, body: JSON.stringify({id: notification.id})});
|
|
||||||
} catch(e) { console.warn('mark_notification_read failed', e); }
|
|
||||||
let data = {};
|
|
||||||
try { data = notification.data ? JSON.parse(notification.data) : {}; } catch(e) {}
|
|
||||||
const userId = data.user_id || notification.user_id;
|
|
||||||
if (userId) {
|
|
||||||
const conv = this.conversations.find(c => c.user_id == userId);
|
|
||||||
if (conv) {
|
|
||||||
this.openConversation(conv.user_id, conv.name, conv.phone_number);
|
|
||||||
} else {
|
|
||||||
this.openConversation(userId, 'Usuario', '');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
removeToast();
|
|
||||||
};
|
|
||||||
|
|
||||||
const dismiss = document.createElement('button');
|
const dismiss = document.createElement('button');
|
||||||
dismiss.className = 'btn btn-sm btn-outline-secondary';
|
dismiss.className = 'btn btn-sm btn-outline-secondary';
|
||||||
@@ -1100,6 +1121,27 @@
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Mobile: sidebar toggle
|
||||||
|
const sidebar = document.querySelector('.chat-sidebar');
|
||||||
|
const sidebarToggle = document.getElementById('sidebar-toggle');
|
||||||
|
if (sidebarToggle && sidebar) {
|
||||||
|
sidebarToggle.addEventListener('click', (ev) => {
|
||||||
|
ev.preventDefault();
|
||||||
|
// toggle mobile-hidden class
|
||||||
|
sidebar.classList.toggle('mobile-hidden');
|
||||||
|
});
|
||||||
|
// ensure sidebar hidden by default on small screens
|
||||||
|
const applyInitialMobile = () => {
|
||||||
|
if (window.innerWidth <= 768) {
|
||||||
|
sidebar.classList.add('mobile-hidden');
|
||||||
|
} else {
|
||||||
|
sidebar.classList.remove('mobile-hidden');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
applyInitialMobile();
|
||||||
|
window.addEventListener('resize', applyInitialMobile);
|
||||||
|
}
|
||||||
|
|
||||||
const stopRecBtn = document.getElementById('stop-recording');
|
const stopRecBtn = document.getElementById('stop-recording');
|
||||||
if (stopRecBtn) stopRecBtn.addEventListener('click', () => this.stopRecording());
|
if (stopRecBtn) stopRecBtn.addEventListener('click', () => this.stopRecording());
|
||||||
const cancelRecBtn = document.getElementById('cancel-recording');
|
const cancelRecBtn = document.getElementById('cancel-recording');
|
||||||
@@ -1415,6 +1457,12 @@
|
|||||||
const releaseBtn = document.getElementById('release-hold-btn');
|
const releaseBtn = document.getElementById('release-hold-btn');
|
||||||
const markUnreadBtn = document.getElementById('mark-unread-btn');
|
const markUnreadBtn = document.getElementById('mark-unread-btn');
|
||||||
|
|
||||||
|
// On mobile, hide the sidebar when opening a conversation so chat occupies full screen
|
||||||
|
const sidebar = document.querySelector('.chat-sidebar');
|
||||||
|
if (sidebar && window.innerWidth <= 768) {
|
||||||
|
sidebar.classList.add('mobile-hidden');
|
||||||
|
}
|
||||||
|
|
||||||
if (markUnreadBtn) {
|
if (markUnreadBtn) {
|
||||||
markUnreadBtn.style.display = 'inline-block';
|
markUnreadBtn.style.display = 'inline-block';
|
||||||
markUnreadBtn.onclick = async () => {
|
markUnreadBtn.onclick = async () => {
|
||||||
@@ -2353,84 +2401,66 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
renderMediaMessage(message) {
|
renderMediaMessage(message) {
|
||||||
if (!message.media_url) return '';
|
if (!message) return '';
|
||||||
|
const mediaType = message.message_type || message.media_type || 'text';
|
||||||
|
const mediaUrl = message.media_url || message.media_url_external || '';
|
||||||
|
const caption = message.content || '';
|
||||||
|
const localFile = message.local_file || '';
|
||||||
|
const localThumb = message.local_thumb || '';
|
||||||
|
const thumb = localThumb ? (`/${localThumb}`) : (localFile ? (`/${localFile}`) : (message.media_url_external || mediaUrl));
|
||||||
|
|
||||||
const mediaType = message.message_type;
|
let full = '';
|
||||||
const mediaUrl = message.media_url;
|
if (localFile) {
|
||||||
const caption = message.content;
|
full = `/api/version/media-url.php?local=${encodeURIComponent(localFile)}`;
|
||||||
|
} else if (message.media_url_external) {
|
||||||
|
if (message.media_url_external.indexOf('api/get_media.php?id=') !== -1) {
|
||||||
|
const parts = message.media_url_external.split('id=');
|
||||||
|
const mid = parts[1] ? decodeURIComponent(parts[1]) : '';
|
||||||
|
full = `/api/version/media-url.php?id=${encodeURIComponent(mid)}`;
|
||||||
|
} else if (/^https?:\/\//i.test(message.media_url_external)) {
|
||||||
|
full = message.media_url_external;
|
||||||
|
} else {
|
||||||
|
full = `/api/version/media-url.php?url=${encodeURIComponent(message.media_url_external)}`;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
full = mediaUrl || '';
|
||||||
|
}
|
||||||
|
|
||||||
switch (mediaType) {
|
switch (mediaType) {
|
||||||
case 'image':
|
case 'image':
|
||||||
// Usar miniatura local si existe, al abrir expandir con el archivo local completo o con media-url redirect
|
|
||||||
const thumb = msg.local_thumb ? (`/${msg.local_thumb}`) : (msg.local_file ? (`/${msg.local_file}`) : (msg.media_url_external || mediaUrl));
|
|
||||||
let full = '';
|
|
||||||
if (msg.local_file) {
|
|
||||||
full = `/api/version/media-url.php?local=${encodeURIComponent(msg.local_file)}`;
|
|
||||||
} else if (msg.media_url_external) {
|
|
||||||
// Si viene una ruta del tipo api/get_media.php?id=XXX extraer id
|
|
||||||
if (msg.media_url_external.indexOf('api/get_media.php?id=') !== -1) {
|
|
||||||
const parts = msg.media_url_external.split('id=');
|
|
||||||
const mid = parts[1] ? decodeURIComponent(parts[1]) : '';
|
|
||||||
full = `/api/version/media-url.php?id=${encodeURIComponent(mid)}`;
|
|
||||||
} else if (/^https?:\/\//i.test(msg.media_url_external)) {
|
|
||||||
// URL directa
|
|
||||||
full = msg.media_url_external;
|
|
||||||
} else {
|
|
||||||
// fallback: pasar como url
|
|
||||||
full = `/api/version/media-url.php?url=${encodeURIComponent(msg.media_url_external)}`;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
full = mediaUrl || '';
|
|
||||||
}
|
|
||||||
return `
|
return `
|
||||||
<div class="message-media">
|
<div class="message-media">
|
||||||
<a href="#" onclick="openImageLightbox(${JSON.stringify(full)}); return false;" title="Abrir imagen">
|
<a href="#" data-full="${escapeHtml(full)}" data-type="image" data-caption="${escapeHtml(caption)}" onclick="openMediaLightbox(this.dataset.full, this.dataset.type, this.dataset.caption); return false;" title="Abrir imagen">
|
||||||
<img src="${thumb}" alt="Imagen" style="cursor:zoom-in">
|
<img src="${escapeHtml(thumb)}" alt="Imagen" style="cursor:zoom-in">
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
${caption ? `<div>${caption}</div>` : ''}
|
${caption ? `<div>${escapeHtml(caption)}</div>` : ''}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
case 'video':
|
case 'video':
|
||||||
let videoSrc = '';
|
|
||||||
if (msg.local_file) {
|
|
||||||
videoSrc = `/${msg.local_file}`;
|
|
||||||
} else if (msg.media_url_external) {
|
|
||||||
if (msg.media_url_external.indexOf('api/get_media.php?id=') !== -1) {
|
|
||||||
const parts = msg.media_url_external.split('id=');
|
|
||||||
const mid = parts[1] ? decodeURIComponent(parts[1]) : '';
|
|
||||||
videoSrc = `/api/version/media-url.php?id=${encodeURIComponent(mid)}`;
|
|
||||||
} else if (/^https?:\/\//i.test(msg.media_url_external)) {
|
|
||||||
videoSrc = msg.media_url_external;
|
|
||||||
} else {
|
|
||||||
videoSrc = `/api/version/media-url.php?url=${encodeURIComponent(msg.media_url_external)}`;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
videoSrc = mediaUrl;
|
|
||||||
}
|
|
||||||
return `
|
return `
|
||||||
<div class="message-media">
|
<div class="message-media">
|
||||||
<video controls>
|
<a href="#" data-full="${escapeHtml(full)}" data-type="video" data-caption="${escapeHtml(caption)}" onclick="openMediaLightbox(this.dataset.full, this.dataset.type, this.dataset.caption); return false;" title="Abrir video">
|
||||||
<source src="${videoSrc}" type="video/mp4">
|
<div style="position:relative; display:inline-block;">
|
||||||
Tu navegador no soporta video.
|
<img src="${escapeHtml(thumb)}" alt="Video" style="cursor:zoom-in; max-width:100%; border-radius:6px;">
|
||||||
</video>
|
<div style="position:absolute; left:50%; top:50%; transform:translate(-50%,-50%); font-size:28px; color:white; text-shadow:0 1px 6px rgba(0,0,0,0.6);"><i class="fas fa-play-circle"></i></div>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
</div>
|
</div>
|
||||||
${caption ? `<div>${caption}</div>` : ''}
|
${caption ? `<div>${escapeHtml(caption)}</div>` : ''}
|
||||||
`;
|
`;
|
||||||
|
case 'audio': {
|
||||||
case 'audio':
|
|
||||||
let audioSrc = '';
|
let audioSrc = '';
|
||||||
if (msg.local_file) {
|
if (localFile) {
|
||||||
audioSrc = `/${msg.local_file}`;
|
audioSrc = `/${localFile}`;
|
||||||
} else if (msg.media_url_external) {
|
} else if (message.media_url_external) {
|
||||||
if (msg.media_url_external.indexOf('api/get_media.php?id=') !== -1) {
|
if (message.media_url_external.indexOf('api/get_media.php?id=') !== -1) {
|
||||||
const parts = msg.media_url_external.split('id=');
|
const parts = message.media_url_external.split('id=');
|
||||||
const mid = parts[1] ? decodeURIComponent(parts[1]) : '';
|
const mid = parts[1] ? decodeURIComponent(parts[1]) : '';
|
||||||
audioSrc = `/api/version/media-url.php?id=${encodeURIComponent(mid)}`;
|
audioSrc = `/api/version/media-url.php?id=${encodeURIComponent(mid)}`;
|
||||||
} else if (/^https?:\/\//i.test(msg.media_url_external)) {
|
} else if (/^https?:\/\//i.test(message.media_url_external)) {
|
||||||
audioSrc = msg.media_url_external;
|
audioSrc = message.media_url_external;
|
||||||
} else {
|
} else {
|
||||||
audioSrc = `/api/version/media-url.php?url=${encodeURIComponent(msg.media_url_external)}`;
|
audioSrc = `/api/version/media-url.php?url=${encodeURIComponent(message.media_url_external)}`;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
audioSrc = mediaUrl;
|
audioSrc = mediaUrl;
|
||||||
@@ -2438,27 +2468,25 @@
|
|||||||
return `
|
return `
|
||||||
<div class="message-media">
|
<div class="message-media">
|
||||||
<audio controls>
|
<audio controls>
|
||||||
<source src="${audioSrc}" type="audio/mpeg">
|
<source src="${escapeHtml(audioSrc)}" type="audio/mpeg">
|
||||||
Tu navegador no soporta audio.
|
Tu navegador no soporta audio.
|
||||||
</audio>
|
</audio>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
|
}
|
||||||
case 'document':
|
case 'document': {
|
||||||
// Para documentos no descargamos automáticamente; abrir la URL externa (o la redirección por media id) para descargar
|
|
||||||
let docUrl = '';
|
let docUrl = '';
|
||||||
if (msg.local_file) {
|
if (localFile) {
|
||||||
docUrl = `/api/version/media-url.php?local=${encodeURIComponent(msg.local_file)}&download=1`;
|
docUrl = `/api/version/media-url.php?local=${encodeURIComponent(localFile)}&download=1`;
|
||||||
} else if (msg.media_url_external) {
|
} else if (message.media_url_external) {
|
||||||
if (msg.media_url_external.indexOf('api/get_media.php?id=') !== -1) {
|
if (message.media_url_external.indexOf('api/get_media.php?id=') !== -1) {
|
||||||
const parts = msg.media_url_external.split('id=');
|
const parts = message.media_url_external.split('id=');
|
||||||
const mid = parts[1] ? decodeURIComponent(parts[1]) : '';
|
const mid = parts[1] ? decodeURIComponent(parts[1]) : '';
|
||||||
docUrl = `/api/version/media-url.php?id=${encodeURIComponent(mid)}&download=1`;
|
docUrl = `/api/version/media-url.php?id=${encodeURIComponent(mid)}&download=1`;
|
||||||
} else if (/^https?:\/\//i.test(msg.media_url_external)) {
|
} else if (/^https?:\/\//i.test(message.media_url_external)) {
|
||||||
docUrl = `/api/version/media-url.php?url=${encodeURIComponent(msg.media_url_external)}&download=1`;
|
docUrl = `/api/version/media-url.php?url=${encodeURIComponent(message.media_url_external)}&download=1`;
|
||||||
} else {
|
} else {
|
||||||
// fallback
|
docUrl = `/api/version/media-url.php?url=${encodeURIComponent(message.media_url_external)}&download=1`;
|
||||||
docUrl = `/api/version/media-url.php?url=${encodeURIComponent(msg.media_url_external)}&download=1`;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!docUrl) {
|
if (!docUrl) {
|
||||||
@@ -2466,7 +2494,7 @@
|
|||||||
<div class="message-document disabled">
|
<div class="message-document disabled">
|
||||||
<i class="fas fa-file-pdf"></i>
|
<i class="fas fa-file-pdf"></i>
|
||||||
<div class="document-info">
|
<div class="document-info">
|
||||||
<div class="document-name">${caption || 'Documento'}</div>
|
<div class="document-name">${escapeHtml(caption || 'Documento')}</div>
|
||||||
<div class="document-size text-muted">No disponible para descargar</div>
|
<div class="document-size text-muted">No disponible para descargar</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -2476,17 +2504,17 @@
|
|||||||
<div class="message-document">
|
<div class="message-document">
|
||||||
<i class="fas fa-file-pdf"></i>
|
<i class="fas fa-file-pdf"></i>
|
||||||
<div class="document-info">
|
<div class="document-info">
|
||||||
<div class="document-name">${caption || 'Documento'}</div>
|
<div class="document-name">${escapeHtml(caption || 'Documento')}</div>
|
||||||
<div class="document-size">
|
<div class="document-size">
|
||||||
<a href="${docUrl}" target="_blank" rel="noopener noreferrer" ${docUrl && docUrl.indexOf('download=1') !== -1 ? 'download' : ''}>Descargar</a>
|
<a href="${escapeHtml(docUrl)}" target="_blank" rel="noopener noreferrer" ${docUrl && docUrl.indexOf('download=1') !== -1 ? 'download' : ''}>Descargar</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<i class="fas fa-download"></i>
|
<i class="fas fa-download"></i>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
return caption || '';
|
return escapeHtml(caption) || '';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2498,6 +2526,63 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Helper para iconos de archivos (copiado de chat_window)
|
||||||
|
function getFileIcon(filename) {
|
||||||
|
if (!filename) return 'fas fa-file text-muted';
|
||||||
|
const ext = String(filename).split('.').pop().toLowerCase();
|
||||||
|
const iconMap = {
|
||||||
|
'pdf': 'fas fa-file-pdf text-danger',
|
||||||
|
'doc': 'fas fa-file-word text-primary',
|
||||||
|
'docx': 'fas fa-file-word text-primary',
|
||||||
|
'xls': 'fas fa-file-excel text-success',
|
||||||
|
'xlsx': 'fas fa-file-excel text-success',
|
||||||
|
'ppt': 'fas fa-file-powerpoint text-warning',
|
||||||
|
'pptx': 'fas fa-file-powerpoint text-warning',
|
||||||
|
'zip': 'fas fa-file-archive text-secondary',
|
||||||
|
'rar': 'fas fa-file-archive text-secondary',
|
||||||
|
'txt': 'fas fa-file-alt text-muted',
|
||||||
|
'csv': 'fas fa-file-csv text-success'
|
||||||
|
};
|
||||||
|
return iconMap[ext] || 'fas fa-file text-muted';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Media lightbox helper (image/video with download)
|
||||||
|
function openMediaLightbox(url, type = 'image', caption = '') {
|
||||||
|
if (!url) {
|
||||||
|
showAlert && showAlert('Media no disponible', 'warning');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const body = document.getElementById('imageLightboxBody');
|
||||||
|
const cap = document.getElementById('imageLightboxCaption');
|
||||||
|
const downloadBtn = document.getElementById('imageLightboxDownload');
|
||||||
|
if (!body || !cap) return;
|
||||||
|
// clear existing content
|
||||||
|
body.innerHTML = '';
|
||||||
|
|
||||||
|
// Decide rendering by type or by URL extension
|
||||||
|
const isVideo = (type === 'video') || /\.(mp4|webm|ogg)(\?|$)/i.test(url);
|
||||||
|
if (isVideo) {
|
||||||
|
body.innerHTML = `<video controls class="w-100" style="border-radius:10px;"><source src="${escapeHtml(url)}" type="video/mp4">Tu navegador no soporta video.</video>`;
|
||||||
|
} else {
|
||||||
|
body.innerHTML = `<img src="${escapeHtml(url)}" class="img-fluid w-100" style="border-radius:10px;">`;
|
||||||
|
}
|
||||||
|
|
||||||
|
cap.textContent = caption || '';
|
||||||
|
if (downloadBtn) {
|
||||||
|
downloadBtn.href = url;
|
||||||
|
downloadBtn.style.display = 'inline-block';
|
||||||
|
}
|
||||||
|
|
||||||
|
const modalEl = document.getElementById('imageLightboxModal');
|
||||||
|
const bsModal = new bootstrap.Modal(modalEl);
|
||||||
|
bsModal.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
// backward compatibility wrapper
|
||||||
|
function openImageLightbox(url, caption = '') {
|
||||||
|
openMediaLightbox(url, 'image', caption);
|
||||||
|
}
|
||||||
|
|
||||||
// Inicializar cuando la página cargue
|
// Inicializar cuando la página cargue
|
||||||
let chat;
|
let chat;
|
||||||
document.addEventListener('DOMContentLoaded', () => {
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
@@ -2505,5 +2590,22 @@
|
|||||||
window.chatApp = chat; // Exponer globalmente para funciones auxiliares
|
window.chatApp = chat; // Exponer globalmente para funciones auxiliares
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<!-- Lightbox Modal -->
|
||||||
|
<div class="modal fade" id="imageLightboxModal" tabindex="-1" aria-hidden="true">
|
||||||
|
<div class="modal-dialog modal-dialog-centered modal-lg">
|
||||||
|
<div class="modal-content bg-transparent border-0">
|
||||||
|
<div class="modal-body p-0 position-relative">
|
||||||
|
<button type="button" class="btn-close btn-close-white position-absolute top-0 end-0 m-3" data-bs-dismiss="modal" aria-label="Cerrar" style="z-index:10;"></button>
|
||||||
|
<div id="imageLightboxBody" style="max-height:75vh; overflow:auto;"></div>
|
||||||
|
<div id="imageLightboxCaption" class="mt-2 text-center text-white small"></div>
|
||||||
|
<div class="position-absolute bottom-0 end-0 m-3">
|
||||||
|
<a id="imageLightboxDownload" class="btn btn-sm btn-light" href="#" target="_blank" download style="display:none;"><i class="fas fa-download"></i> Descargar</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
Reference in New Issue
Block a user