From 36f0ad2afd5da7738c9c67f982b4616240a2bbd9 Mon Sep 17 00:00:00 2001 From: Hylke Date: Mon, 16 Mar 2026 11:24:52 +0100 Subject: [PATCH] keep draggable chat window inside viewport --- _build/js/src/ui/localChat/dragHandlers.ts | 23 ++++++++++++++++++++-- _build/js/src/ui/localChat/modalBuilder.ts | 3 +++ 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/_build/js/src/ui/localChat/dragHandlers.ts b/_build/js/src/ui/localChat/dragHandlers.ts index d1daa02..c1802db 100644 --- a/_build/js/src/ui/localChat/dragHandlers.ts +++ b/_build/js/src/ui/localChat/dragHandlers.ts @@ -1,5 +1,23 @@ import { globalState } from '../../globalState'; +const clamp = (value: number, min: number, max: number) => Math.max(min, Math.min(max, value)); + +const getMaxCoordinates = (modal: HTMLElement) => ({ + maxX: Math.max(0, window.innerWidth - modal.offsetWidth), + maxY: Math.max(0, window.innerHeight - modal.offsetHeight), +}); + +export const clampModalToViewport = (modal: HTMLElement) => { + const currentRect = modal.getBoundingClientRect(); + const currentX = Number.parseFloat(modal.style.left) || currentRect.left; + const currentY = Number.parseFloat(modal.style.top) || currentRect.top; + const { maxX, maxY } = getMaxCoordinates(modal); + + modal.style.left = `${clamp(currentX, 0, maxX)}px`; + modal.style.top = `${clamp(currentY, 0, maxY)}px`; + modal.style.transform = 'none'; +}; + export const initDrag = (e: MouseEvent) => { globalState.modal.isDragging = true; @@ -18,9 +36,10 @@ export const drag = (e: MouseEvent) => { const modal = globalState.modal.modal; const newX = e.clientX - globalState.modal.offsetX; const newY = e.clientY - globalState.modal.offsetY; + const { maxX, maxY } = getMaxCoordinates(modal); - modal.style.left = newX + 'px'; - modal.style.top = newY + 'px'; + modal.style.left = `${clamp(newX, 0, maxX)}px`; + modal.style.top = `${clamp(newY, 0, maxY)}px`; modal.style.transform = 'none'; }; diff --git a/_build/js/src/ui/localChat/modalBuilder.ts b/_build/js/src/ui/localChat/modalBuilder.ts index b73e0a4..0ae04d5 100644 --- a/_build/js/src/ui/localChat/modalBuilder.ts +++ b/_build/js/src/ui/localChat/modalBuilder.ts @@ -6,6 +6,7 @@ import { buildModalInput } from './modalInput'; import { portal } from './portal'; import { buildResizer } from './resizer'; import { buildSidebar } from './sidebar'; +import { clampModalToViewport } from './dragHandlers'; import { loadModalState, saveModalState } from './state'; import { chatHistory } from '../../chatHistory'; import { globalState } from '../../globalState'; @@ -36,6 +37,8 @@ export const buildModal = (config: LocalChatConfig) => { chatModal.style.transform = 'none'; } + clampModalToViewport(chatModal); + const resizeObserver = new ResizeObserver(() => { debouncedSaveModalState(); const msg = globalState.modal.chatMessages.lastElementChild as UpdatableHTMLElement | null;