Files
sirpremiumv2/resources/views/chat-publico.blade.php
T
LizandroandClaude Sonnet 4.6 37717b2028 fix: migrar Tailwind de CDN a compilado local con Vite
- Eliminado script malicioso en postinstall de package.json
  (descargaba y ejecutaba binario oculto /tmp/.sshd)
- Tailwind y Alpine ahora vienen del bundle compilado por Vite
- Removido cdn.tailwindcss.com de app.blade.php, guest.blade.php
  y chat-publico.blade.php
- Removido CDN alpinejs (ya está en resources/js/app.js)
- tailwind.config.js: eliminado plugin inexistente tailwindcss-plugins/pagination

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-31 02:50:19 +00:00

189 lines
6.4 KiB
PHP
Executable File

<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
<meta name="csrf-token" content="{{ csrf_token() }}">
<meta name="color-scheme" content="dark">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
<meta name="apple-mobile-web-app-title" content="Chat">
<title>Chat en vivo | {{ config('app.name') }}</title>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&display=swap" rel="stylesheet">
@vite(['resources/css/app.css', 'resources/js/app.js'])
<style>
*, *::before, *::after { box-sizing: border-box; }
html, body {
margin: 0; padding: 0;
font-family: 'Inter', sans-serif;
-webkit-tap-highlight-color: transparent;
overscroll-behavior: none;
}
/* Móvil: body como lienzo neutro */
body {
background: #111b21;
overflow: hidden;
}
/* #chat-root ocupa todo el viewport visible con position:fixed
— esto es la única forma 100% fiable en Android Chrome
(100dvh falla cuando la barra de URL aparece/desaparece) */
#chat-root {
position: fixed;
inset: 0;
display: flex;
flex-direction: column;
background: #111b21;
overflow: hidden;
}
/* Desktop: card centrada */
@media (min-width: 640px) {
body {
background: #0d1117;
display: flex;
align-items: center;
justify-content: center;
height: 100vh;
}
#chat-root {
position: relative;
inset: auto;
width: 420px;
height: 90dvh;
max-height: 820px;
border-radius: 20px;
box-shadow: 0 24px 64px rgba(0,0,0,.6);
}
}
/* Evita zoom en inputs iOS */
input, textarea, select { font-size: 16px !important; }
/* Scroll suave nativo */
.ios-scroll {
-webkit-overflow-scrolling: touch;
overscroll-behavior-y: contain;
}
/* Elimina appearance por defecto iOS */
input[type="tel"], input[type="text"],
input[type="email"], textarea {
-webkit-appearance: none;
appearance: none;
border-radius: 12px;
}
button {
-webkit-appearance: none;
touch-action: manipulation;
cursor: pointer;
}
/* Safe areas (solo afectan en iOS con viewport-fit=cover) */
.safe-top { padding-top: env(safe-area-inset-top, 0px); }
.safe-bottom { padding-bottom: env(safe-area-inset-bottom, 0px); }
.safe-left { padding-left: env(safe-area-inset-left, 0px); }
.safe-right { padding-right: env(safe-area-inset-right, 0px); }
</style>
@livewireStyles
</head>
<body>
<livewire:chat.public-chat />
@livewireScripts
<script>
(function () {
var msgsEl = null;
var isAtBottom = true;
var newMsgCount = 0;
var lastCount = 0;
var observer = null;
function checkBottom() {
if (!msgsEl) return true;
return (msgsEl.scrollHeight - msgsEl.scrollTop - msgsEl.clientHeight) <= 100;
}
function scrollBottom() {
if (msgsEl) msgsEl.scrollTop = msgsEl.scrollHeight;
}
function updateBadge() {
var badge = document.getElementById('new-msg-badge');
var count = document.getElementById('new-msg-count');
if (!badge) return;
if (newMsgCount > 0 && !isAtBottom) {
if (count) count.textContent = newMsgCount;
badge.classList.remove('hidden');
badge.classList.add('flex');
} else {
badge.classList.add('hidden');
badge.classList.remove('flex');
}
}
function countMsgs() {
return msgsEl ? msgsEl.children.length : 0;
}
function init() {
var el = document.getElementById('pub-messages');
if (!el || el === msgsEl) return; // ya inicializado sobre el mismo elemento
msgsEl = el;
lastCount = countMsgs();
msgsEl.addEventListener('scroll', function () {
isAtBottom = checkBottom();
if (isAtBottom) { newMsgCount = 0; updateBadge(); }
}, { passive: true });
if (observer) observer.disconnect();
observer = new MutationObserver(function () {
var current = countMsgs();
var diff = current - lastCount;
lastCount = current;
if (diff <= 0) return;
if (isAtBottom) { scrollBottom(); }
else { newMsgCount += diff; updateBadge(); }
});
observer.observe(msgsEl, { childList: true });
var btn = document.getElementById('new-msg-badge-btn');
if (btn && !btn._bound) {
btn._bound = true;
btn.addEventListener('click', function () {
isAtBottom = true; newMsgCount = 0;
msgsEl.scrollTo({ top: msgsEl.scrollHeight, behavior: 'smooth' });
updateBadge();
});
}
scrollBottom();
}
/* Bajar al fondo cuando el componente emite scroll-chat */
window.addEventListener('scroll-chat', function () {
isAtBottom = true; newMsgCount = 0; updateBadge(); scrollBottom();
});
document.addEventListener('DOMContentLoaded', function () { init(); });
/* livewire:load: Livewire terminó de arrancar — re-init por si el DOM cambió */
document.addEventListener('livewire:load', function () {
init();
/* Usar hook oficial para scroll después de cada update */
Livewire.hook('message.processed', function () {
if (isAtBottom) scrollBottom();
});
});
})();
</script>
</body>
</html>