feat: auto-scroll al fondo del chat + badge de mensajes nuevos

- Al cargar, baja automáticamente al último mensaje
- Después de cada actualización Livewire, baja si el usuario está al fondo
- Si el usuario subió a leer historial, muestra badge "N mensaje nuevo" en lugar de forzar scroll
- Click en badge baja suavemente al fondo y lo oculta

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Lizandro
2026-07-19 21:59:18 +00:00
co-authored by Claude Sonnet 4.6
parent e804831e15
commit 4b856f6a43
@@ -602,3 +602,88 @@
@endif
</div>
<script>
(function () {
function initChatScroll() {
const container = document.getElementById('pub-messages');
const badge = document.getElementById('new-msg-badge');
const badgeBtn = document.getElementById('new-msg-badge-btn');
const countEl = document.getElementById('new-msg-count');
if (!container) return;
let userScrolledUp = false;
let newMsgCount = 0;
let lastHeight = 0;
function atBottom() {
return container.scrollHeight - container.scrollTop - container.clientHeight < 100;
}
function scrollToBottom(smooth) {
container.scrollTo({ top: container.scrollHeight, behavior: smooth ? 'smooth' : 'auto' });
}
function showBadge(n) {
if (!badge || !countEl) return;
countEl.textContent = n;
badge.classList.remove('hidden');
badge.classList.add('flex');
}
function hideBadge() {
if (!badge) return;
badge.classList.add('hidden');
badge.classList.remove('flex');
newMsgCount = 0;
}
// Bajar al fondo al hacer click en el badge
if (badgeBtn) {
badgeBtn.addEventListener('click', function () {
scrollToBottom(true);
hideBadge();
});
}
// Detectar scroll manual
container.addEventListener('scroll', function () {
if (atBottom()) {
userScrolledUp = false;
hideBadge();
} else {
userScrolledUp = true;
}
}, { passive: true });
// Scroll inicial al fondo
scrollToBottom(false);
lastHeight = container.scrollHeight;
// Después de cada actualización de Livewire
document.addEventListener('livewire:update', function () {
setTimeout(function () {
const newHeight = container.scrollHeight;
const grew = newHeight > lastHeight;
lastHeight = newHeight;
if (!userScrolledUp) {
scrollToBottom(false);
} else if (grew) {
newMsgCount++;
showBadge(newMsgCount);
}
}, 30);
});
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', initChatScroll);
} else {
initChatScroll();
}
// Re-inicializar si Livewire monta el componente dinámicamente
document.addEventListener('livewire:load', initChatScroll);
})();
</script>