diff --git a/apps/web/src/lib/components/ErrorModal.svelte b/apps/web/src/lib/components/ErrorModal.svelte index 8367d76..a0a2bb4 100644 --- a/apps/web/src/lib/components/ErrorModal.svelte +++ b/apps/web/src/lib/components/ErrorModal.svelte @@ -11,6 +11,103 @@ let { open = $bindable(false), title = 'Erro', message, details, onClose }: Props = $props(); + let modalPosition = $state<{ top: number; left: number } | null>(null); + + // Função para calcular a posição baseada no relógio sincronizado + function calcularPosicaoModal() { + // Procurar pelo elemento do relógio sincronizado + const relogioRef = document.getElementById('relogio-sincronizado-ref'); + + if (relogioRef) { + const rect = relogioRef.getBoundingClientRect(); + const viewportWidth = window.innerWidth; + const viewportHeight = window.innerHeight; + + // Posicionar o modal na mesma posição do relógio sincronizado + // Centralizado horizontalmente no card do relógio + const left = rect.left + (rect.width / 2); + // Posicionar abaixo do card do relógio com um pequeno espaçamento + const top = rect.bottom + 20; + + return { + top: top, + left: left + }; + } + + // Se não encontrar, usar posição padrão (centro da tela) + return null; + } + + $effect(() => { + if (open) { + // Usar requestAnimationFrame para garantir que o DOM está completamente renderizado + const updatePosition = () => { + requestAnimationFrame(() => { + const pos = calcularPosicaoModal(); + if (pos) { + modalPosition = pos; + } + }); + }; + + // Aguardar um pouco mais para garantir que o DOM está atualizado + setTimeout(updatePosition, 50); + + // Adicionar listener de scroll para atualizar posição + const handleScroll = () => { + updatePosition(); + }; + + window.addEventListener('scroll', handleScroll, true); + window.addEventListener('resize', handleScroll); + + return () => { + window.removeEventListener('scroll', handleScroll, true); + window.removeEventListener('resize', handleScroll); + }; + } else { + // Limpar posição quando o modal for fechado + modalPosition = null; + } + }); + + // Função para obter estilo do modal baseado na posição calculada + function getModalStyle() { + if (modalPosition) { + // Garantir que o modal não saia da viewport + const viewportWidth = window.innerWidth; + const viewportHeight = window.innerHeight; + const modalWidth = 700; // Aproximadamente max-w-2xl + const modalHeight = Math.min(viewportHeight * 0.9, 600); + + let left = modalPosition.left; + let top = modalPosition.top; + + // Ajustar se o modal sair da viewport à direita + if (left + (modalWidth / 2) > viewportWidth - 20) { + left = viewportWidth - (modalWidth / 2) - 20; + } + // Ajustar se o modal sair da viewport à esquerda + if (left - (modalWidth / 2) < 20) { + left = (modalWidth / 2) + 20; + } + // Ajustar se o modal sair da viewport abaixo + if (top + modalHeight > viewportHeight - 20) { + top = viewportHeight - modalHeight - 20; + } + // Ajustar se o modal sair da viewport acima + if (top < 20) { + top = 20; + } + + // Usar transform para centralizar horizontalmente baseado no left calculado + return `position: fixed; top: ${top}px; left: ${left}px; transform: translateX(-50%); max-width: ${Math.min(modalWidth, viewportWidth - 40)}px;`; + } + // Se não houver posição calculada, centralizar na tela + return 'position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%);'; + } + // Verificar se details contém instruções ou apenas detalhes técnicos const temInstrucoes = $derived.by(() => { if (!details) return false; @@ -31,22 +128,22 @@ {#if open}