intento 3

This commit is contained in:
David Itehua Xalamihua 2025-05-24 13:11:57 -06:00
parent fab7a4ac95
commit b15b7093b1

View File

@ -8,10 +8,9 @@
display: flex; display: flex;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
cursor: move; cursor: move; /* Indica que es arrastrable */
user-select: none; user-select: none; /* Evita selección de texto al arrastrar */
z-index: 1; z-index: 1000; /* Asegura que esté por encima de otros elementos */
/* z-index: 1000; */
transition: transition:
background-color 0.3s, background-color 0.3s,
left 0.3s ease, left 0.3s ease,
@ -20,11 +19,11 @@
} }
.floating-btn:active { .floating-btn:active {
cursor: grabbing; cursor: grabbing; /* Cambia el cursor mientras se arrastra */
} }
</style> </style>
<div class="floating-btn border border-light shadow-lg" id="floatingBtn"> <div class="floating-btn border border-light shadow-lg" id="floatingBtn">
<a id="floatingBtnLink" target="_blank" href="https://chatgpt.com/g/g-6828126fba608191a2803ac89f54f504-formha-rh-para-pymes"> <a id="floatingBtnLink" target="_blank" href="https://chatgpt.com/g/g-6828126fba608191a2803ac89f54f504-formha-rh-para-pymes">
<img src="{{ url_for('static', filename='y_img/logos/chat_ia_formha.svg') }}" <img src="{{ url_for('static', filename='y_img/logos/chat_ia_formha.svg') }}"
@ -34,174 +33,154 @@
</a> </a>
</div> </div>
<script> <script>
document.addEventListener('DOMContentLoaded', function () { document.addEventListener('DOMContentLoaded', function () {
const btn = document.getElementById('floatingBtn'); const btn = document.getElementById('floatingBtn');
const link = document.getElementById('floatingBtnLink'); const link = document.getElementById('floatingBtnLink');
let offsetX, offsetY; let offsetX, offsetY; // Desplazamiento del puntero/dedo dentro del botón
let isDragging = false; let isDragging = false; // Estado de arrastre
let hasMoved = false; let hasMoved = false; // Indica si el botón se ha movido lo suficiente para ser considerado arrastre
let touchStartTimer; let startClientX, startClientY; // Coordenadas iniciales del toque/clic
const tapThreshold = 200; // Tiempo en milisegundos para considerar un "tap" const moveThreshold = 5; // Distancia en píxeles para considerar un "move"
const moveThreshold = 10; // Distancia en píxeles para considerar un "move"
let initialTouchX, initialTouchY;
// --- Cargar y aplicar la posición guardada ---
const savedPosition = localStorage.getItem('floatingBtnPosition'); const savedPosition = localStorage.getItem('floatingBtnPosition');
if (savedPosition) { if (savedPosition) {
const { x, y } = JSON.parse(savedPosition); const { x, y } = JSON.parse(savedPosition);
btn.style.left = x; btn.style.left = x;
btn.style.top = y; btn.style.top = y;
setTimeout(() => stickToNearestSide(parseInt(x), parseInt(y)), 10); // Usamos requestAnimationFrame para asegurar que la posición se aplique después del renderizado.
// Esto evita posibles glitches al inicio.
requestAnimationFrame(() => stickToNearestSide(parseInt(x), parseInt(y)));
} else { } else {
// Posición inicial por defecto si no hay nada guardado
btn.style.right = '20px'; btn.style.right = '20px';
btn.style.top = '20px'; btn.style.top = '20px';
} }
// Eventos para mouse // --- Eventos para mouse (click y arrastre) ---
btn.addEventListener('mousedown', startDrag); btn.addEventListener('mousedown', startInteraction);
document.addEventListener('mousemove', drag); document.addEventListener('mousemove', moveInteraction);
document.addEventListener('mouseup', stopDrag); document.addEventListener('mouseup', endInteraction);
// --- Eventos para touch (tap y arrastre) ---
// passive: false es CRUCIAL para poder usar e.preventDefault() en touchmove y evitar el scroll no deseado.
btn.addEventListener('touchstart', startInteraction, { passive: false });
document.addEventListener('touchmove', moveInteraction, { passive: false });
document.addEventListener('touchend', endInteraction);
// Eventos para touch // --- Evitar que el enlace se abra si se ha arrastrado el botón ---
btn.addEventListener('touchstart', startTouch, { passive: false });
btn.addEventListener('touchmove', moveTouch, { passive: false });
btn.addEventListener('touchend', endTouch);
link.addEventListener('click', function (e) { link.addEventListener('click', function (e) {
if (hasMoved) { if (hasMoved) {
e.preventDefault(); e.preventDefault(); // Si se movió, previene el click
hasMoved = false;
} }
hasMoved = false; // Resetear para la siguiente interacción
}); });
function startDrag(e) { // --- Función para iniciar la interacción (mousedown o touchstart) ---
isDragging = true; function startInteraction(e) {
hasMoved = false; // Prevenir el comportamiento por defecto del navegador (ej. arrastrar imágenes)
e.preventDefault();
isDragging = false; // Resetear estado de arrastre
hasMoved = false; // Resetear estado de movimiento
// Obtener las coordenadas iniciales del evento (mouse o touch)
const clientX = e.clientX || e.touches[0].clientX;
const clientY = e.clientY || e.touches[0].clientY;
startClientX = clientX;
startClientY = clientY;
// Calcular el desplazamiento dentro del botón
const rect = btn.getBoundingClientRect(); const rect = btn.getBoundingClientRect();
offsetX = e.clientX - rect.left; offsetX = clientX - rect.left;
offsetY = e.clientY - rect.top; offsetY = clientY - rect.top;
btn.style.cursor = 'grabbing'; // Asegurar que la posición del botón se base en left/top para el arrastre
btn.style.left = `${rect.left}px`; btn.style.left = `${rect.left}px`;
btn.style.top = `${rect.top}px`; btn.style.top = `${rect.top}px`;
btn.style.right = 'auto'; btn.style.right = 'auto'; // Desactivar 'right' para evitar conflictos
btn.style.bottom = 'auto'; // Desactivar 'bottom' si estuviera activo
e.preventDefault(); btn.style.cursor = 'grabbing'; // Cambiar cursor mientras se "agarra"
} }
function drag(e) { // --- Función para mover (mousemove o touchmove) ---
if (!isDragging) return; function moveInteraction(e) {
if (!startClientX) return; // Si no hay inicio de interacción, salimos
const x = e.clientX - offsetX; const clientX = e.clientX || e.touches[0].clientX;
const y = e.clientY - offsetY; const clientY = e.clientY || e.touches[0].clientY;
btn.style.left = `${x}px`; const currentX = clientX - offsetX;
btn.style.top = `${y}px`; const currentY = clientY - offsetY;
hasMoved = true; // Detectar si el movimiento supera el umbral
} const deltaX = Math.abs(clientX - startClientX);
const deltaY = Math.abs(clientY - startClientY);
function stopDrag() { if (deltaX > moveThreshold || deltaY > moveThreshold) {
if (!isDragging) return; isDragging = true; // Confirmamos que es un arrastre
hasMoved = true; // Se ha movido significativamente
}
isDragging = false; if (isDragging) {
btn.style.cursor = 'move'; // Mover el botón
btn.style.left = `${currentX}px`;
const rect = btn.getBoundingClientRect(); btn.style.top = `${currentY}px`;
const x = rect.left; // Prevenir el scroll de la página solo si estamos arrastrando
const y = rect.top;
stickToNearestSide(x, y);
savePosition(x, y);
}
function startTouch(e) {
if (e.touches.length !== 1) return;
e.preventDefault(); // Prevenir comportamiento por defecto
const touch = e.touches[0];
initialTouchX = touch.clientX;
initialTouchY = touch.clientY;
const rect = btn.getBoundingClientRect();
offsetX = initialTouchX - rect.left;
offsetY = initialTouchY - rect.top;
hasMoved = false;
touchStartTimer = setTimeout(() => {
if (!isDragging) {
link.click();
}
}, tapThreshold);
}
function moveTouch(e) {
if (!touchStartTimer || e.touches.length !== 1 || !initialTouchX) return;
const touch = e.touches[0];
const currentX = touch.clientX;
const currentY = touch.clientY;
// Verificar si el movimiento supera el umbral
if (Math.abs(currentX - initialTouchX) > moveThreshold ||
Math.abs(currentY - initialTouchY) > moveThreshold) {
clearTimeout(touchStartTimer);
isDragging = true;
hasMoved = true;
btn.style.cursor = 'grabbing';
btn.style.left = `${currentX - offsetX}px`;
btn.style.top = `${currentY - offsetY}px`;
btn.style.right = 'auto';
e.preventDefault(); e.preventDefault();
} }
} }
// --- Función para finalizar la interacción (mouseup o touchend) ---
function endInteraction() {
// Resetear las coordenadas iniciales del toque
startClientX = null;
startClientY = null;
function endTouch(e) {
clearTimeout(touchStartTimer);
if (isDragging) { if (isDragging) {
isDragging = false; isDragging = false; // Finalizar el estado de arrastre
btn.style.cursor = 'move'; btn.style.cursor = 'move'; // Restaurar cursor
const rect = btn.getBoundingClientRect(); const rect = btn.getBoundingClientRect();
stickToNearestSide(rect.left, rect.top); stickToNearestSide(rect.left, rect.top); // Anclar a la posición final
savePosition(rect.left, rect.top); savePosition(rect.left, rect.top); // Guardar la posición
} }
initialTouchX = null; // hasMoved se reseteará en el evento 'click' del enlace o en la siguiente 'startInteraction'
initialTouchY = null;
} }
// --- Función para anclar el botón al lado más cercano ---
function stickToNearestSide(x, y) { function stickToNearestSide(x, y) {
const windowWidth = window.innerWidth; const windowWidth = window.innerWidth;
const windowHeight = window.innerHeight;
const btnWidth = btn.offsetWidth; const btnWidth = btn.offsetWidth;
const btnHeight = btn.offsetHeight;
const padding = 10; // Espacio de separación de los bordes
if (x < windowWidth / 2) { // Anclar al lado izquierdo o derecho
btn.style.left = '10px'; if (x < windowWidth / 2 - btnWidth / 2) { // Considera el centro del botón
btn.style.left = `${padding}px`;
btn.style.right = 'auto'; btn.style.right = 'auto';
} else { } else {
btn.style.left = 'auto'; btn.style.left = 'auto';
btn.style.right = '10px'; btn.style.right = `${padding}px`;
} }
const windowHeight = window.innerHeight; // Asegurarse de que el botón no salga por arriba o por abajo
const btnHeight = btn.offsetHeight; let newY = y;
if (y < padding) {
if (y < 0) { newY = padding;
btn.style.top = '10px'; } else if (y + btnHeight > windowHeight - padding) {
} else if (y + btnHeight > windowHeight) { newY = windowHeight - btnHeight - padding;
btn.style.top = `${windowHeight - btnHeight - 10}px`;
} else {
btn.style.top = `${y}px`;
} }
btn.style.top = `${newY}px`;
} }
// --- Función para guardar la posición en localStorage ---
function savePosition(x, y) { function savePosition(x, y) {
localStorage.setItem('floatingBtnPosition', JSON.stringify({ localStorage.setItem('floatingBtnPosition', JSON.stringify({
x: btn.style.left, x: btn.style.left,
@ -209,11 +188,16 @@
})); }));
} }
// --- Ajustar posición al redimensionar la ventana ---
window.addEventListener('resize', function () { window.addEventListener('resize', function () {
const savedPosition = localStorage.getItem('floatingBtnPosition'); const saved = localStorage.getItem('floatingBtnPosition');
if (savedPosition) { if (saved) {
const { x, y } = JSON.parse(savedPosition); const { x, y } = JSON.parse(saved);
// Volver a anclar el botón a su lado más cercano según la nueva ventana
stickToNearestSide(parseInt(x), parseInt(y)); stickToNearestSide(parseInt(x), parseInt(y));
} else {
// Si no hay posición guardada, anclar a la posición por defecto
stickToNearestSide(btn.getBoundingClientRect().left, btn.getBoundingClientRect().top);
} }
}); });
}); });